1 /* vi: set sw=4 ts=4: */
5 * Connect to host at port using address resolution from getaddrinfo
7 * Licensed under GPLv2, see file LICENSE in this source tree.
10 #include <sys/types.h>
11 #include <sys/socket.h> /* netinet/in.h needs it */
12 #include <netinet/in.h>
17 void FAST_FUNC
setsockopt_reuseaddr(int fd
)
19 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_1
, sizeof(const_int_1
));
21 int FAST_FUNC
setsockopt_broadcast(int fd
)
23 return setsockopt(fd
, SOL_SOCKET
, SO_BROADCAST
, &const_int_1
, sizeof(const_int_1
));
26 #ifdef SO_BINDTODEVICE
27 int FAST_FUNC
setsockopt_bindtodevice(int fd
, const char *iface
)
31 strncpy_IFNAMSIZ(ifr
.ifr_name
, iface
);
32 /* NB: passing (iface, strlen(iface) + 1) does not work!
33 * (maybe it works on _some_ kernels, but not on 2.6.26)
34 * Actually, ifr_name is at offset 0, and in practice
35 * just giving char[IFNAMSIZ] instead of struct ifreq works too.
36 * But just in case it's not true on some obscure arch... */
37 r
= setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, &ifr
, sizeof(ifr
));
39 bb_perror_msg("can't bind to interface %s", iface
);
43 int FAST_FUNC
setsockopt_bindtodevice(int fd UNUSED_PARAM
,
44 const char *iface UNUSED_PARAM
)
46 bb_error_msg("SO_BINDTODEVICE is not supported on this system");
51 static len_and_sockaddr
* get_lsa(int fd
, int (*get_name
)(int fd
, struct sockaddr
*addr
, socklen_t
*addrlen
))
54 len_and_sockaddr
*lsa_ptr
;
56 lsa
.len
= LSA_SIZEOF_SA
;
57 if (get_name(fd
, &lsa
.u
.sa
, &lsa
.len
) != 0)
60 lsa_ptr
= xzalloc(LSA_LEN_SIZE
+ lsa
.len
);
61 if (lsa
.len
> LSA_SIZEOF_SA
) { /* rarely (if ever) happens */
62 lsa_ptr
->len
= lsa
.len
;
63 get_name(fd
, &lsa_ptr
->u
.sa
, &lsa_ptr
->len
);
65 memcpy(lsa_ptr
, &lsa
, LSA_LEN_SIZE
+ lsa
.len
);
70 len_and_sockaddr
* FAST_FUNC
get_sock_lsa(int fd
)
72 return get_lsa(fd
, getsockname
);
75 len_and_sockaddr
* FAST_FUNC
get_peer_lsa(int fd
)
77 return get_lsa(fd
, getpeername
);
80 void FAST_FUNC
xconnect(int s
, const struct sockaddr
*s_addr
, socklen_t addrlen
)
82 if (connect(s
, s_addr
, addrlen
) < 0) {
83 if (ENABLE_FEATURE_CLEAN_UP
)
85 if (s_addr
->sa_family
== AF_INET
)
86 bb_perror_msg_and_die("%s (%s)",
87 "can't connect to remote host",
88 inet_ntoa(((struct sockaddr_in
*)s_addr
)->sin_addr
));
89 bb_perror_msg_and_die("can't connect to remote host");
93 /* Return port number for a service.
94 * If "port" is a number use it as the port.
95 * If "port" is a name it is looked up in /etc/services,
96 * if it isnt found return default_port
98 unsigned FAST_FUNC
bb_lookup_port(const char *port
, const char *protocol
, unsigned default_port
)
100 unsigned port_nr
= default_port
;
104 /* Since this is a lib function, we're not allowed to reset errno to 0.
105 * Doing so could break an app that is deferring checking of errno. */
107 port_nr
= bb_strtou(port
, NULL
, 10);
108 if (errno
|| port_nr
> 65535) {
109 struct servent
*tserv
= getservbyname(port
, protocol
);
110 port_nr
= default_port
;
112 port_nr
= ntohs(tserv
->s_port
);
116 return (uint16_t)port_nr
;
120 /* "New" networking API */
123 int FAST_FUNC
get_nport(const struct sockaddr
*sa
)
125 #if ENABLE_FEATURE_IPV6
126 if (sa
->sa_family
== AF_INET6
) {
127 return ((struct sockaddr_in6
*)sa
)->sin6_port
;
130 if (sa
->sa_family
== AF_INET
) {
131 return ((struct sockaddr_in
*)sa
)->sin_port
;
133 /* What? UNIX socket? IPX?? :) */
137 void FAST_FUNC
set_nport(struct sockaddr
*sa
, unsigned port
)
139 #if ENABLE_FEATURE_IPV6
140 if (sa
->sa_family
== AF_INET6
) {
141 struct sockaddr_in6
*sin6
= (void*) sa
;
142 sin6
->sin6_port
= port
;
146 if (sa
->sa_family
== AF_INET
) {
147 struct sockaddr_in
*sin
= (void*) sa
;
148 sin
->sin_port
= port
;
151 /* What? UNIX socket? IPX?? :) */
154 /* We hijack this constant to mean something else */
155 /* It doesn't hurt because we will remove this bit anyway */
156 #define DIE_ON_ERROR AI_CANONNAME
158 /* host: "1.2.3.4[:port]", "www.google.com[:port]"
159 * port: if neither of above specifies port # */
160 static len_and_sockaddr
* str2sockaddr(
161 const char *host
, int port
,
162 IF_FEATURE_IPV6(sa_family_t af
,)
165 IF_NOT_FEATURE_IPV6(sa_family_t af
= AF_INET
;)
168 struct addrinfo
*result
= NULL
;
169 struct addrinfo
*used_res
;
170 const char *org_host
= host
; /* only for error msg */
172 struct addrinfo hint
;
174 if (ENABLE_FEATURE_UNIX_LOCAL
&& strncmp(host
, "local:", 6) == 0) {
175 struct sockaddr_un
*sun
;
177 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_un
));
178 r
->len
= sizeof(struct sockaddr_un
);
179 r
->u
.sa
.sa_family
= AF_UNIX
;
180 sun
= (struct sockaddr_un
*)&r
->u
.sa
;
181 safe_strncpy(sun
->sun_path
, host
+ 6, sizeof(sun
->sun_path
));
187 /* Ugly parsing of host:addr */
188 if (ENABLE_FEATURE_IPV6
&& host
[0] == '[') {
189 /* Even uglier parsing of [xx]:nn */
191 cp
= strchr(host
, ']');
192 if (!cp
|| (cp
[1] != ':' && cp
[1] != '\0')) {
193 /* Malformed: must be [xx]:nn or [xx] */
194 bb_error_msg("bad address '%s'", org_host
);
195 if (ai_flags
& DIE_ON_ERROR
)
200 cp
= strrchr(host
, ':');
201 if (ENABLE_FEATURE_IPV6
&& cp
&& strchr(host
, ':') != cp
) {
202 /* There is more than one ':' (e.g. "::1") */
203 cp
= NULL
; /* it's not a port spec */
206 if (cp
) { /* points to ":" or "]:" */
207 int sz
= cp
- host
+ 1;
209 host
= safe_strncpy(alloca(sz
), host
, sz
);
210 if (ENABLE_FEATURE_IPV6
&& *cp
!= ':') {
212 if (*cp
== '\0') /* [xx] without port */
216 port
= bb_strtou(cp
, NULL
, 10);
217 if (errno
|| (unsigned)port
> 0xffff) {
218 bb_error_msg("bad port spec '%s'", org_host
);
219 if (ai_flags
& DIE_ON_ERROR
)
226 /* Next two if blocks allow to skip getaddrinfo()
227 * in case host name is a numeric IP(v6) address.
228 * getaddrinfo() initializes DNS resolution machinery,
229 * scans network config and such - tens of syscalls.
231 /* If we were not asked specifically for IPv6,
232 * check whether this is a numeric IPv4 */
233 IF_FEATURE_IPV6(if(af
!= AF_INET6
)) {
235 if (inet_aton(host
, &in4
) != 0) {
236 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_in
));
237 r
->len
= sizeof(struct sockaddr_in
);
238 r
->u
.sa
.sa_family
= AF_INET
;
239 r
->u
.sin
.sin_addr
= in4
;
243 #if ENABLE_FEATURE_IPV6
244 /* If we were not asked specifically for IPv4,
245 * check whether this is a numeric IPv6 */
248 if (inet_pton(AF_INET6
, host
, &in6
) > 0) {
249 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_in6
));
250 r
->len
= sizeof(struct sockaddr_in6
);
251 r
->u
.sa
.sa_family
= AF_INET6
;
252 r
->u
.sin6
.sin6_addr
= in6
;
258 memset(&hint
, 0 , sizeof(hint
));
260 /* Need SOCK_STREAM, or else we get each address thrice (or more)
261 * for each possible socket type (tcp,udp,raw...): */
262 hint
.ai_socktype
= SOCK_STREAM
;
263 hint
.ai_flags
= ai_flags
& ~DIE_ON_ERROR
;
264 rc
= getaddrinfo(host
, NULL
, &hint
, &result
);
266 bb_error_msg("bad address '%s'", org_host
);
267 if (ai_flags
& DIE_ON_ERROR
)
272 #if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
274 if (used_res
->ai_family
== AF_INET
)
276 used_res
= used_res
->ai_next
;
283 r
= xmalloc(LSA_LEN_SIZE
+ used_res
->ai_addrlen
);
284 r
->len
= used_res
->ai_addrlen
;
285 memcpy(&r
->u
.sa
, used_res
->ai_addr
, used_res
->ai_addrlen
);
288 set_nport(&r
->u
.sa
, htons(port
));
291 freeaddrinfo(result
);
294 #if !ENABLE_FEATURE_IPV6
295 #define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
298 #if ENABLE_FEATURE_IPV6
299 len_and_sockaddr
* FAST_FUNC
host_and_af2sockaddr(const char *host
, int port
, sa_family_t af
)
301 return str2sockaddr(host
, port
, af
, 0);
304 len_and_sockaddr
* FAST_FUNC
xhost_and_af2sockaddr(const char *host
, int port
, sa_family_t af
)
306 return str2sockaddr(host
, port
, af
, DIE_ON_ERROR
);
310 len_and_sockaddr
* FAST_FUNC
host2sockaddr(const char *host
, int port
)
312 return str2sockaddr(host
, port
, AF_UNSPEC
, 0);
315 len_and_sockaddr
* FAST_FUNC
xhost2sockaddr(const char *host
, int port
)
317 return str2sockaddr(host
, port
, AF_UNSPEC
, DIE_ON_ERROR
);
320 len_and_sockaddr
* FAST_FUNC
xdotted2sockaddr(const char *host
, int port
)
322 return str2sockaddr(host
, port
, AF_UNSPEC
, AI_NUMERICHOST
| DIE_ON_ERROR
);
325 int FAST_FUNC
xsocket_type(len_and_sockaddr
**lsap
, int family
, int sock_type
)
327 len_and_sockaddr
*lsa
;
331 if (family
== AF_UNSPEC
) {
332 #if ENABLE_FEATURE_IPV6
333 fd
= socket(AF_INET6
, sock_type
, 0);
342 fd
= xsocket(family
, sock_type
, 0);
344 len
= sizeof(struct sockaddr_in
);
345 if (family
== AF_UNIX
)
346 len
= sizeof(struct sockaddr_un
);
347 #if ENABLE_FEATURE_IPV6
348 if (family
== AF_INET6
) {
350 len
= sizeof(struct sockaddr_in6
);
353 lsa
= xzalloc(LSA_LEN_SIZE
+ len
);
355 lsa
->u
.sa
.sa_family
= family
;
360 int FAST_FUNC
xsocket_stream(len_and_sockaddr
**lsap
)
362 return xsocket_type(lsap
, AF_UNSPEC
, SOCK_STREAM
);
365 static int create_and_bind_or_die(const char *bindaddr
, int port
, int sock_type
)
368 len_and_sockaddr
*lsa
;
370 if (bindaddr
&& bindaddr
[0]) {
371 lsa
= xdotted2sockaddr(bindaddr
, port
);
372 /* user specified bind addr dictates family */
373 fd
= xsocket(lsa
->u
.sa
.sa_family
, sock_type
, 0);
375 fd
= xsocket_type(&lsa
, AF_UNSPEC
, sock_type
);
376 set_nport(&lsa
->u
.sa
, htons(port
));
378 setsockopt_reuseaddr(fd
);
379 xbind(fd
, &lsa
->u
.sa
, lsa
->len
);
384 int FAST_FUNC
create_and_bind_stream_or_die(const char *bindaddr
, int port
)
386 return create_and_bind_or_die(bindaddr
, port
, SOCK_STREAM
);
389 int FAST_FUNC
create_and_bind_dgram_or_die(const char *bindaddr
, int port
)
391 return create_and_bind_or_die(bindaddr
, port
, SOCK_DGRAM
);
395 int FAST_FUNC
create_and_connect_stream_or_die(const char *peer
, int port
)
398 len_and_sockaddr
*lsa
;
400 lsa
= xhost2sockaddr(peer
, port
);
401 fd
= xsocket(lsa
->u
.sa
.sa_family
, SOCK_STREAM
, 0);
402 setsockopt_reuseaddr(fd
);
403 xconnect(fd
, &lsa
->u
.sa
, lsa
->len
);
408 int FAST_FUNC
xconnect_stream(const len_and_sockaddr
*lsa
)
410 int fd
= xsocket(lsa
->u
.sa
.sa_family
, SOCK_STREAM
, 0);
411 xconnect(fd
, &lsa
->u
.sa
, lsa
->len
);
415 /* We hijack this constant to mean something else */
416 /* It doesn't hurt because we will add this bit anyway */
417 #define IGNORE_PORT NI_NUMERICSERV
418 static char* FAST_FUNC
sockaddr2str(const struct sockaddr
*sa
, int flags
)
425 if (ENABLE_FEATURE_UNIX_LOCAL
&& sa
->sa_family
== AF_UNIX
) {
426 struct sockaddr_un
*sun
= (struct sockaddr_un
*)sa
;
427 return xasprintf("local:%.*s",
428 (int) sizeof(sun
->sun_path
),
432 salen
= LSA_SIZEOF_SA
;
433 #if ENABLE_FEATURE_IPV6
434 if (sa
->sa_family
== AF_INET
)
435 salen
= sizeof(struct sockaddr_in
);
436 if (sa
->sa_family
== AF_INET6
)
437 salen
= sizeof(struct sockaddr_in6
);
439 rc
= getnameinfo(sa
, salen
,
441 /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
443 /* do not resolve port# into service _name_ */
444 flags
| NI_NUMERICSERV
448 if (flags
& IGNORE_PORT
)
449 return xstrdup(host
);
450 #if ENABLE_FEATURE_IPV6
451 if (sa
->sa_family
== AF_INET6
) {
452 if (strchr(host
, ':')) /* heh, it's not a resolved hostname */
453 return xasprintf("[%s]:%s", host
, serv
);
454 /*return xasprintf("%s:%s", host, serv);*/
455 /* - fall through instead */
458 /* For now we don't support anything else, so it has to be INET */
459 /*if (sa->sa_family == AF_INET)*/
460 return xasprintf("%s:%s", host
, serv
);
461 /*return xstrdup(host);*/
464 char* FAST_FUNC
xmalloc_sockaddr2host(const struct sockaddr
*sa
)
466 return sockaddr2str(sa
, 0);
469 char* FAST_FUNC
xmalloc_sockaddr2host_noport(const struct sockaddr
*sa
)
471 return sockaddr2str(sa
, IGNORE_PORT
);
474 char* FAST_FUNC
xmalloc_sockaddr2hostonly_noport(const struct sockaddr
*sa
)
476 return sockaddr2str(sa
, NI_NAMEREQD
| IGNORE_PORT
);
478 char* FAST_FUNC
xmalloc_sockaddr2dotted(const struct sockaddr
*sa
)
480 return sockaddr2str(sa
, NI_NUMERICHOST
);
483 char* FAST_FUNC
xmalloc_sockaddr2dotted_noport(const struct sockaddr
*sa
)
485 return sockaddr2str(sa
, NI_NUMERICHOST
| IGNORE_PORT
);