Magellan Linux

Annotation of /tags/mkinitrd-6_2_0/busybox/libbb/xconnect.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 996 - (hide annotations) (download)
Sun May 30 11:54:28 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 12667 byte(s)
tagged 'mkinitrd-6_2_0'
1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * Utility routines.
4     *
5     * Connect to host at port using address resolution from getaddrinfo
6     *
7 niro 984 * Licensed under GPLv2, see file LICENSE in this tarball for details.
8 niro 532 */
9    
10 niro 984 #include <sys/socket.h> /* netinet/in.h needs it */
11 niro 532 #include <netinet/in.h>
12 niro 816 #include <net/if.h>
13 niro 984 #include <sys/un.h>
14 niro 532 #include "libbb.h"
15    
16 niro 816 void FAST_FUNC setsockopt_reuseaddr(int fd)
17 niro 532 {
18 niro 816 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
19 niro 532 }
20 niro 816 int FAST_FUNC setsockopt_broadcast(int fd)
21 niro 532 {
22 niro 816 return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
23 niro 532 }
24 niro 816 int FAST_FUNC setsockopt_bindtodevice(int fd, const char *iface)
25     {
26     int r;
27     struct ifreq ifr;
28 niro 984 strncpy_IFNAMSIZ(ifr.ifr_name, iface);
29     /* NB: passing (iface, strlen(iface) + 1) does not work!
30     * (maybe it works on _some_ kernels, but not on 2.6.26)
31     * Actually, ifr_name is at offset 0, and in practice
32 niro 816 * just giving char[IFNAMSIZ] instead of struct ifreq works too.
33     * But just in case it's not true on some obscure arch... */
34     r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
35     if (r)
36     bb_perror_msg("can't bind to interface %s", iface);
37     return r;
38     }
39 niro 532
40 niro 984 len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd)
41     {
42     len_and_sockaddr lsa;
43     len_and_sockaddr *lsa_ptr;
44 niro 816
45 niro 984 lsa.len = LSA_SIZEOF_SA;
46     if (getsockname(fd, &lsa.u.sa, &lsa.len) != 0)
47     return NULL;
48    
49     lsa_ptr = xzalloc(LSA_LEN_SIZE + lsa.len);
50     if (lsa.len > LSA_SIZEOF_SA) { /* rarely (if ever) happens */
51     lsa_ptr->len = lsa.len;
52     getsockname(fd, &lsa_ptr->u.sa, &lsa_ptr->len);
53     } else {
54     memcpy(lsa_ptr, &lsa, LSA_LEN_SIZE + lsa.len);
55     }
56     return lsa_ptr;
57     }
58    
59 niro 816 void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
60 niro 532 {
61     if (connect(s, s_addr, addrlen) < 0) {
62     if (ENABLE_FEATURE_CLEAN_UP)
63     close(s);
64     if (s_addr->sa_family == AF_INET)
65     bb_perror_msg_and_die("%s (%s)",
66 niro 984 "can't connect to remote host",
67 niro 532 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
68 niro 984 bb_perror_msg_and_die("can't connect to remote host");
69 niro 532 }
70     }
71    
72     /* Return port number for a service.
73     * If "port" is a number use it as the port.
74 niro 984 * If "port" is a name it is looked up in /etc/services,
75     * if it isnt found return default_port
76     */
77 niro 816 unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port)
78 niro 532 {
79     unsigned port_nr = default_port;
80     if (port) {
81     int old_errno;
82    
83     /* Since this is a lib function, we're not allowed to reset errno to 0.
84     * Doing so could break an app that is deferring checking of errno. */
85     old_errno = errno;
86     port_nr = bb_strtou(port, NULL, 10);
87     if (errno || port_nr > 65535) {
88     struct servent *tserv = getservbyname(port, protocol);
89     port_nr = default_port;
90     if (tserv)
91     port_nr = ntohs(tserv->s_port);
92     }
93     errno = old_errno;
94     }
95     return (uint16_t)port_nr;
96     }
97    
98    
99     /* "Old" networking API - only IPv4 */
100    
101 niro 816 /*
102     void FAST_FUNC bb_lookup_host(struct sockaddr_in *s_in, const char *host)
103 niro 532 {
104     struct hostent *he;
105    
106     memset(s_in, 0, sizeof(struct sockaddr_in));
107     s_in->sin_family = AF_INET;
108     he = xgethostbyname(host);
109     memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
110     }
111    
112 niro 816
113     int FAST_FUNC xconnect_tcp_v4(struct sockaddr_in *s_addr)
114 niro 532 {
115     int s = xsocket(AF_INET, SOCK_STREAM, 0);
116     xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
117     return s;
118     }
119 niro 816 */
120 niro 532
121     /* "New" networking API */
122    
123    
124 niro 816 int FAST_FUNC get_nport(const struct sockaddr *sa)
125 niro 532 {
126     #if ENABLE_FEATURE_IPV6
127 niro 816 if (sa->sa_family == AF_INET6) {
128     return ((struct sockaddr_in6*)sa)->sin6_port;
129 niro 532 }
130     #endif
131 niro 816 if (sa->sa_family == AF_INET) {
132     return ((struct sockaddr_in*)sa)->sin_port;
133 niro 532 }
134 niro 816 /* What? UNIX socket? IPX?? :) */
135 niro 532 return -1;
136     }
137    
138 niro 816 void FAST_FUNC set_nport(len_and_sockaddr *lsa, unsigned port)
139 niro 532 {
140     #if ENABLE_FEATURE_IPV6
141 niro 816 if (lsa->u.sa.sa_family == AF_INET6) {
142     lsa->u.sin6.sin6_port = port;
143 niro 532 return;
144     }
145     #endif
146 niro 816 if (lsa->u.sa.sa_family == AF_INET) {
147     lsa->u.sin.sin_port = port;
148 niro 532 return;
149     }
150     /* What? UNIX socket? IPX?? :) */
151     }
152    
153 niro 816 /* We hijack this constant to mean something else */
154     /* It doesn't hurt because we will remove this bit anyway */
155     #define DIE_ON_ERROR AI_CANONNAME
156    
157     /* host: "1.2.3.4[:port]", "www.google.com[:port]"
158     * port: if neither of above specifies port # */
159     static len_and_sockaddr* str2sockaddr(
160     const char *host, int port,
161 niro 984 IF_FEATURE_IPV6(sa_family_t af,)
162 niro 816 int ai_flags)
163 niro 532 {
164 niro 984 IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;)
165 niro 532 int rc;
166 niro 984 len_and_sockaddr *r;
167 niro 532 struct addrinfo *result = NULL;
168 niro 816 struct addrinfo *used_res;
169 niro 532 const char *org_host = host; /* only for error msg */
170     const char *cp;
171     struct addrinfo hint;
172    
173 niro 984 if (ENABLE_FEATURE_UNIX_LOCAL && strncmp(host, "local:", 6) == 0) {
174     struct sockaddr_un *sun;
175    
176     r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
177     r->len = sizeof(struct sockaddr_un);
178     r->u.sa.sa_family = AF_UNIX;
179     sun = (struct sockaddr_un *)&r->u.sa;
180     safe_strncpy(sun->sun_path, host + 6, sizeof(sun->sun_path));
181     return r;
182     }
183    
184     r = NULL;
185    
186 niro 532 /* Ugly parsing of host:addr */
187     if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
188 niro 816 /* Even uglier parsing of [xx]:nn */
189 niro 532 host++;
190     cp = strchr(host, ']');
191 niro 984 if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
192     /* Malformed: must be [xx]:nn or [xx] */
193 niro 816 bb_error_msg("bad address '%s'", org_host);
194     if (ai_flags & DIE_ON_ERROR)
195     xfunc_die();
196     return NULL;
197     }
198 niro 532 } else {
199     cp = strrchr(host, ':');
200     if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) {
201     /* There is more than one ':' (e.g. "::1") */
202     cp = NULL; /* it's not a port spec */
203     }
204     }
205 niro 816 if (cp) { /* points to ":" or "]:" */
206 niro 532 int sz = cp - host + 1;
207 niro 984
208 niro 532 host = safe_strncpy(alloca(sz), host, sz);
209 niro 984 if (ENABLE_FEATURE_IPV6 && *cp != ':') {
210 niro 532 cp++; /* skip ']' */
211 niro 984 if (*cp == '\0') /* [xx] without port */
212     goto skip;
213     }
214 niro 532 cp++; /* skip ':' */
215 niro 816 port = bb_strtou(cp, NULL, 10);
216     if (errno || (unsigned)port > 0xffff) {
217     bb_error_msg("bad port spec '%s'", org_host);
218     if (ai_flags & DIE_ON_ERROR)
219     xfunc_die();
220     return NULL;
221     }
222 niro 984 skip: ;
223 niro 532 }
224    
225 niro 984 /* Next two if blocks allow to skip getaddrinfo()
226     * in case host name is a numeric IP(v6) address.
227     * getaddrinfo() initializes DNS resolution machinery,
228     * scans network config and such - tens of syscalls.
229     */
230     /* If we were not asked specifically for IPv6,
231     * check whether this is a numeric IPv4 */
232     IF_FEATURE_IPV6(if(af != AF_INET6)) {
233     struct in_addr in4;
234     if (inet_aton(host, &in4) != 0) {
235     r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in));
236     r->len = sizeof(struct sockaddr_in);
237     r->u.sa.sa_family = AF_INET;
238     r->u.sin.sin_addr = in4;
239     goto set_port;
240     }
241     }
242     #if ENABLE_FEATURE_IPV6
243     /* If we were not asked specifically for IPv4,
244     * check whether this is a numeric IPv6 */
245     if (af != AF_INET) {
246     struct in6_addr in6;
247     if (inet_pton(AF_INET6, host, &in6) > 0) {
248     r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in6));
249     r->len = sizeof(struct sockaddr_in6);
250     r->u.sa.sa_family = AF_INET6;
251     r->u.sin6.sin6_addr = in6;
252     goto set_port;
253     }
254     }
255     #endif
256    
257 niro 532 memset(&hint, 0 , sizeof(hint));
258 niro 816 hint.ai_family = af;
259 niro 532 /* Needed. Or else we will get each address thrice (or more)
260     * for each possible socket type (tcp,udp,raw...): */
261     hint.ai_socktype = SOCK_STREAM;
262 niro 816 hint.ai_flags = ai_flags & ~DIE_ON_ERROR;
263 niro 532 rc = getaddrinfo(host, NULL, &hint, &result);
264 niro 816 if (rc || !result) {
265     bb_error_msg("bad address '%s'", org_host);
266     if (ai_flags & DIE_ON_ERROR)
267     xfunc_die();
268     goto ret;
269     }
270     used_res = result;
271     #if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
272     while (1) {
273     if (used_res->ai_family == AF_INET)
274     break;
275     used_res = used_res->ai_next;
276     if (!used_res) {
277     used_res = result;
278     break;
279     }
280     }
281     #endif
282 niro 984 r = xmalloc(LSA_LEN_SIZE + used_res->ai_addrlen);
283 niro 816 r->len = used_res->ai_addrlen;
284     memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
285 niro 984
286     set_port:
287 niro 532 set_nport(r, htons(port));
288 niro 816 ret:
289 niro 532 freeaddrinfo(result);
290     return r;
291     }
292 niro 816 #if !ENABLE_FEATURE_IPV6
293     #define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
294     #endif
295 niro 532
296 niro 816 #if ENABLE_FEATURE_IPV6
297     len_and_sockaddr* FAST_FUNC host_and_af2sockaddr(const char *host, int port, sa_family_t af)
298 niro 532 {
299 niro 816 return str2sockaddr(host, port, af, 0);
300 niro 532 }
301    
302 niro 816 len_and_sockaddr* FAST_FUNC xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)
303 niro 532 {
304 niro 816 return str2sockaddr(host, port, af, DIE_ON_ERROR);
305 niro 532 }
306 niro 816 #endif
307 niro 532
308 niro 816 len_and_sockaddr* FAST_FUNC host2sockaddr(const char *host, int port)
309 niro 532 {
310 niro 816 return str2sockaddr(host, port, AF_UNSPEC, 0);
311     }
312    
313     len_and_sockaddr* FAST_FUNC xhost2sockaddr(const char *host, int port)
314     {
315     return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
316     }
317    
318     len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port)
319     {
320     return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR);
321     }
322    
323     #undef xsocket_type
324 niro 984 int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type)
325 niro 816 {
326 niro 984 IF_NOT_FEATURE_IPV6(enum { family = AF_INET };)
327 niro 532 len_and_sockaddr *lsa;
328     int fd;
329 niro 816 int len;
330 niro 532
331     #if ENABLE_FEATURE_IPV6
332 niro 816 if (family == AF_UNSPEC) {
333     fd = socket(AF_INET6, sock_type, 0);
334     if (fd >= 0) {
335     family = AF_INET6;
336     goto done;
337     }
338     family = AF_INET;
339     }
340     #endif
341     fd = xsocket(family, sock_type, 0);
342     len = sizeof(struct sockaddr_in);
343     #if ENABLE_FEATURE_IPV6
344     if (family == AF_INET6) {
345     done:
346 niro 532 len = sizeof(struct sockaddr_in6);
347 niro 816 }
348 niro 532 #endif
349 niro 984 lsa = xzalloc(LSA_LEN_SIZE + len);
350 niro 532 lsa->len = len;
351 niro 816 lsa->u.sa.sa_family = family;
352 niro 532 *lsap = lsa;
353     return fd;
354     }
355    
356 niro 816 int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap)
357 niro 532 {
358 niro 984 return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
359 niro 816 }
360    
361     static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
362     {
363 niro 532 int fd;
364     len_and_sockaddr *lsa;
365    
366     if (bindaddr && bindaddr[0]) {
367 niro 816 lsa = xdotted2sockaddr(bindaddr, port);
368 niro 532 /* user specified bind addr dictates family */
369 niro 816 fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
370 niro 532 } else {
371 niro 984 fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type);
372 niro 532 set_nport(lsa, htons(port));
373     }
374     setsockopt_reuseaddr(fd);
375 niro 816 xbind(fd, &lsa->u.sa, lsa->len);
376 niro 532 free(lsa);
377     return fd;
378     }
379    
380 niro 816 int FAST_FUNC create_and_bind_stream_or_die(const char *bindaddr, int port)
381 niro 532 {
382 niro 816 return create_and_bind_or_die(bindaddr, port, SOCK_STREAM);
383     }
384    
385     int FAST_FUNC create_and_bind_dgram_or_die(const char *bindaddr, int port)
386     {
387     return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM);
388     }
389    
390    
391     int FAST_FUNC create_and_connect_stream_or_die(const char *peer, int port)
392     {
393 niro 532 int fd;
394     len_and_sockaddr *lsa;
395    
396 niro 816 lsa = xhost2sockaddr(peer, port);
397     fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
398 niro 532 setsockopt_reuseaddr(fd);
399 niro 816 xconnect(fd, &lsa->u.sa, lsa->len);
400 niro 532 free(lsa);
401     return fd;
402     }
403    
404 niro 816 int FAST_FUNC xconnect_stream(const len_and_sockaddr *lsa)
405 niro 532 {
406 niro 816 int fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0);
407     xconnect(fd, &lsa->u.sa, lsa->len);
408 niro 532 return fd;
409     }
410    
411 niro 816 /* We hijack this constant to mean something else */
412     /* It doesn't hurt because we will add this bit anyway */
413     #define IGNORE_PORT NI_NUMERICSERV
414     static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags)
415 niro 532 {
416     char host[128];
417     char serv[16];
418 niro 816 int rc;
419     socklen_t salen;
420    
421 niro 984 if (ENABLE_FEATURE_UNIX_LOCAL && sa->sa_family == AF_UNIX) {
422     struct sockaddr_un *sun = (struct sockaddr_un *)sa;
423     return xasprintf("local:%.*s",
424     (int) sizeof(sun->sun_path),
425     sun->sun_path);
426     }
427    
428 niro 816 salen = LSA_SIZEOF_SA;
429     #if ENABLE_FEATURE_IPV6
430     if (sa->sa_family == AF_INET)
431     salen = sizeof(struct sockaddr_in);
432     if (sa->sa_family == AF_INET6)
433     salen = sizeof(struct sockaddr_in6);
434     #endif
435     rc = getnameinfo(sa, salen,
436 niro 532 host, sizeof(host),
437 niro 816 /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
438 niro 532 serv, sizeof(serv),
439 niro 816 /* do not resolve port# into service _name_ */
440     flags | NI_NUMERICSERV
441 niro 532 );
442 niro 816 if (rc)
443     return NULL;
444     if (flags & IGNORE_PORT)
445     return xstrdup(host);
446     #if ENABLE_FEATURE_IPV6
447     if (sa->sa_family == AF_INET6) {
448     if (strchr(host, ':')) /* heh, it's not a resolved hostname */
449     return xasprintf("[%s]:%s", host, serv);
450     /*return xasprintf("%s:%s", host, serv);*/
451     /* - fall through instead */
452     }
453     #endif
454     /* For now we don't support anything else, so it has to be INET */
455     /*if (sa->sa_family == AF_INET)*/
456     return xasprintf("%s:%s", host, serv);
457     /*return xstrdup(host);*/
458 niro 532 }
459    
460 niro 816 char* FAST_FUNC xmalloc_sockaddr2host(const struct sockaddr *sa)
461 niro 532 {
462 niro 816 return sockaddr2str(sa, 0);
463 niro 532 }
464    
465 niro 816 char* FAST_FUNC xmalloc_sockaddr2host_noport(const struct sockaddr *sa)
466 niro 532 {
467 niro 816 return sockaddr2str(sa, IGNORE_PORT);
468 niro 532 }
469 niro 816
470     char* FAST_FUNC xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)
471     {
472     return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT);
473     }
474     char* FAST_FUNC xmalloc_sockaddr2dotted(const struct sockaddr *sa)
475     {
476     return sockaddr2str(sa, NI_NUMERICHOST);
477     }
478    
479     char* FAST_FUNC xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)
480     {
481     return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT);
482     }