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 int FAST_FUNC
setsockopt_int(int fd
, int level
, int optname
, int optval
)
19 return setsockopt(fd
, level
, optname
, &optval
, sizeof(int));
21 int FAST_FUNC
setsockopt_1(int fd
, int level
, int optname
)
23 return setsockopt_int(fd
, level
, optname
, 1);
25 int FAST_FUNC
setsockopt_SOL_SOCKET_int(int fd
, int optname
, int optval
)
27 return setsockopt_int(fd
, SOL_SOCKET
, optname
, optval
);
29 int FAST_FUNC
setsockopt_SOL_SOCKET_1(int fd
, int optname
)
31 return setsockopt_SOL_SOCKET_int(fd
, optname
, 1);
34 void FAST_FUNC
setsockopt_reuseaddr(int fd
)
36 setsockopt_SOL_SOCKET_1(fd
, SO_REUSEADDR
);
38 int FAST_FUNC
setsockopt_broadcast(int fd
)
40 return setsockopt_SOL_SOCKET_1(fd
, SO_BROADCAST
);
42 int FAST_FUNC
setsockopt_keepalive(int fd
)
44 return setsockopt_SOL_SOCKET_1(fd
, SO_KEEPALIVE
);
47 #ifdef SO_BINDTODEVICE
48 int FAST_FUNC
setsockopt_bindtodevice(int fd
, const char *iface
)
52 strncpy_IFNAMSIZ(ifr
.ifr_name
, iface
);
53 /* NB: passing (iface, strlen(iface) + 1) does not work!
54 * (maybe it works on _some_ kernels, but not on 2.6.26)
55 * Actually, ifr_name is at offset 0, and in practice
56 * just giving char[IFNAMSIZ] instead of struct ifreq works too.
57 * But just in case it's not true on some obscure arch... */
58 r
= setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, &ifr
, sizeof(ifr
));
60 bb_perror_msg("can't bind to interface %s", iface
);
64 int FAST_FUNC
setsockopt_bindtodevice(int fd UNUSED_PARAM
,
65 const char *iface UNUSED_PARAM
)
67 bb_error_msg("SO_BINDTODEVICE is not supported on this system");
72 static len_and_sockaddr
* get_lsa(int fd
, int (*get_name
)(int fd
, struct sockaddr
*addr
, socklen_t
*addrlen
))
75 len_and_sockaddr
*lsa_ptr
;
77 lsa
.len
= LSA_SIZEOF_SA
;
78 if (get_name(fd
, &lsa
.u
.sa
, &lsa
.len
) != 0)
81 lsa_ptr
= xzalloc(LSA_LEN_SIZE
+ lsa
.len
);
82 if (lsa
.len
> LSA_SIZEOF_SA
) { /* rarely (if ever) happens */
83 lsa_ptr
->len
= lsa
.len
;
84 get_name(fd
, &lsa_ptr
->u
.sa
, &lsa_ptr
->len
);
86 memcpy(lsa_ptr
, &lsa
, LSA_LEN_SIZE
+ lsa
.len
);
91 len_and_sockaddr
* FAST_FUNC
get_sock_lsa(int fd
)
93 return get_lsa(fd
, getsockname
);
96 len_and_sockaddr
* FAST_FUNC
get_peer_lsa(int fd
)
98 return get_lsa(fd
, getpeername
);
101 void FAST_FUNC
xconnect(int s
, const struct sockaddr
*s_addr
, socklen_t addrlen
)
103 if (connect(s
, s_addr
, addrlen
) < 0) {
104 if (ENABLE_FEATURE_CLEAN_UP
)
106 if (s_addr
->sa_family
== AF_INET
)
107 bb_perror_msg_and_die("%s (%s)",
108 "can't connect to remote host",
109 inet_ntoa(((struct sockaddr_in
*)s_addr
)->sin_addr
));
110 bb_perror_msg_and_die("can't connect to remote host");
114 /* Return port number for a service.
115 * If "port" is a number use it as the port.
116 * If "port" is a name it is looked up in /etc/services,
117 * if it isnt found return default_port
119 unsigned FAST_FUNC
bb_lookup_port(const char *port
, const char *protocol
, unsigned default_port
)
121 unsigned port_nr
= default_port
;
125 /* Since this is a lib function, we're not allowed to reset errno to 0.
126 * Doing so could break an app that is deferring checking of errno. */
128 port_nr
= bb_strtou(port
, NULL
, 10);
129 if (errno
|| port_nr
> 65535) {
130 struct servent
*tserv
= getservbyname(port
, protocol
);
131 port_nr
= default_port
;
133 port_nr
= ntohs(tserv
->s_port
);
137 return (uint16_t)port_nr
;
141 /* "New" networking API */
144 int FAST_FUNC
get_nport(const struct sockaddr
*sa
)
146 #if ENABLE_FEATURE_IPV6
147 if (sa
->sa_family
== AF_INET6
) {
148 return ((struct sockaddr_in6
*)sa
)->sin6_port
;
151 if (sa
->sa_family
== AF_INET
) {
152 return ((struct sockaddr_in
*)sa
)->sin_port
;
154 /* What? UNIX socket? IPX?? :) */
158 void FAST_FUNC
set_nport(struct sockaddr
*sa
, unsigned port
)
160 #if ENABLE_FEATURE_IPV6
161 if (sa
->sa_family
== AF_INET6
) {
162 struct sockaddr_in6
*sin6
= (void*) sa
;
163 sin6
->sin6_port
= port
;
167 if (sa
->sa_family
== AF_INET
) {
168 struct sockaddr_in
*sin
= (void*) sa
;
169 sin
->sin_port
= port
;
172 /* What? UNIX socket? IPX?? :) */
175 /* We hijack this constant to mean something else */
176 /* It doesn't hurt because we will remove this bit anyway */
177 #define DIE_ON_ERROR AI_CANONNAME
179 /* host: "1.2.3.4[:port]", "www.google.com[:port]"
180 * port: if neither of above specifies port # */
181 static len_and_sockaddr
* str2sockaddr(
182 const char *host
, int port
,
183 IF_FEATURE_IPV6(sa_family_t af
,)
186 IF_NOT_FEATURE_IPV6(sa_family_t af
= AF_INET
;)
189 struct addrinfo
*result
= NULL
;
190 struct addrinfo
*used_res
;
191 const char *org_host
= host
; /* only for error msg */
193 struct addrinfo hint
;
195 if (ENABLE_FEATURE_UNIX_LOCAL
&& is_prefixed_with(host
, "local:")) {
196 struct sockaddr_un
*sun
;
198 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_un
));
199 r
->len
= sizeof(struct sockaddr_un
);
200 r
->u
.sa
.sa_family
= AF_UNIX
;
201 sun
= (struct sockaddr_un
*)&r
->u
.sa
;
202 safe_strncpy(sun
->sun_path
, host
+ 6, sizeof(sun
->sun_path
));
208 /* Ugly parsing of host:addr */
209 if (ENABLE_FEATURE_IPV6
&& host
[0] == '[') {
210 /* Even uglier parsing of [xx]:nn */
212 cp
= strchr(host
, ']');
213 if (!cp
|| (cp
[1] != ':' && cp
[1] != '\0')) {
214 /* Malformed: must be [xx]:nn or [xx] */
215 bb_error_msg("bad address '%s'", org_host
);
216 if (ai_flags
& DIE_ON_ERROR
)
221 cp
= strrchr(host
, ':');
222 if (ENABLE_FEATURE_IPV6
&& cp
&& strchr(host
, ':') != cp
) {
223 /* There is more than one ':' (e.g. "::1") */
224 cp
= NULL
; /* it's not a port spec */
227 if (cp
) { /* points to ":" or "]:" */
228 int sz
= cp
- host
+ 1;
230 host
= safe_strncpy(alloca(sz
), host
, sz
);
231 if (ENABLE_FEATURE_IPV6
&& *cp
!= ':') {
233 if (*cp
== '\0') /* [xx] without port */
237 port
= bb_strtou(cp
, NULL
, 10);
238 if (errno
|| (unsigned)port
> 0xffff) {
239 bb_error_msg("bad port spec '%s'", org_host
);
240 if (ai_flags
& DIE_ON_ERROR
)
247 /* Next two if blocks allow to skip getaddrinfo()
248 * in case host name is a numeric IP(v6) address.
249 * getaddrinfo() initializes DNS resolution machinery,
250 * scans network config and such - tens of syscalls.
252 /* If we were not asked specifically for IPv6,
253 * check whether this is a numeric IPv4 */
254 IF_FEATURE_IPV6(if(af
!= AF_INET6
)) {
256 if (inet_aton(host
, &in4
) != 0) {
257 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_in
));
258 r
->len
= sizeof(struct sockaddr_in
);
259 r
->u
.sa
.sa_family
= AF_INET
;
260 r
->u
.sin
.sin_addr
= in4
;
264 #if ENABLE_FEATURE_IPV6
265 /* If we were not asked specifically for IPv4,
266 * check whether this is a numeric IPv6 */
269 if (inet_pton(AF_INET6
, host
, &in6
) > 0) {
270 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_in6
));
271 r
->len
= sizeof(struct sockaddr_in6
);
272 r
->u
.sa
.sa_family
= AF_INET6
;
273 r
->u
.sin6
.sin6_addr
= in6
;
279 memset(&hint
, 0 , sizeof(hint
));
281 /* Need SOCK_STREAM, or else we get each address thrice (or more)
282 * for each possible socket type (tcp,udp,raw...): */
283 hint
.ai_socktype
= SOCK_STREAM
;
284 hint
.ai_flags
= ai_flags
& ~DIE_ON_ERROR
;
285 rc
= getaddrinfo(host
, NULL
, &hint
, &result
);
287 bb_error_msg("bad address '%s'", org_host
);
288 if (ai_flags
& DIE_ON_ERROR
)
293 #if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
295 if (used_res
->ai_family
== AF_INET
)
297 used_res
= used_res
->ai_next
;
304 r
= xmalloc(LSA_LEN_SIZE
+ used_res
->ai_addrlen
);
305 r
->len
= used_res
->ai_addrlen
;
306 memcpy(&r
->u
.sa
, used_res
->ai_addr
, used_res
->ai_addrlen
);
309 set_nport(&r
->u
.sa
, htons(port
));
312 freeaddrinfo(result
);
315 #if !ENABLE_FEATURE_IPV6
316 #define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
319 #if ENABLE_FEATURE_IPV6
320 len_and_sockaddr
* FAST_FUNC
host_and_af2sockaddr(const char *host
, int port
, sa_family_t af
)
322 return str2sockaddr(host
, port
, af
, 0);
325 len_and_sockaddr
* FAST_FUNC
xhost_and_af2sockaddr(const char *host
, int port
, sa_family_t af
)
327 return str2sockaddr(host
, port
, af
, DIE_ON_ERROR
);
331 len_and_sockaddr
* FAST_FUNC
host2sockaddr(const char *host
, int port
)
333 return str2sockaddr(host
, port
, AF_UNSPEC
, 0);
336 len_and_sockaddr
* FAST_FUNC
xhost2sockaddr(const char *host
, int port
)
338 return str2sockaddr(host
, port
, AF_UNSPEC
, DIE_ON_ERROR
);
341 len_and_sockaddr
* FAST_FUNC
xdotted2sockaddr(const char *host
, int port
)
343 return str2sockaddr(host
, port
, AF_UNSPEC
, AI_NUMERICHOST
| DIE_ON_ERROR
);
346 int FAST_FUNC
xsocket_type(len_and_sockaddr
**lsap
, int family
, int sock_type
)
348 len_and_sockaddr
*lsa
;
352 if (family
== AF_UNSPEC
) {
353 #if ENABLE_FEATURE_IPV6
354 fd
= socket(AF_INET6
, sock_type
, 0);
363 fd
= xsocket(family
, sock_type
, 0);
365 len
= sizeof(struct sockaddr_in
);
366 if (family
== AF_UNIX
)
367 len
= sizeof(struct sockaddr_un
);
368 #if ENABLE_FEATURE_IPV6
369 if (family
== AF_INET6
) {
371 len
= sizeof(struct sockaddr_in6
);
374 lsa
= xzalloc(LSA_LEN_SIZE
+ len
);
376 lsa
->u
.sa
.sa_family
= family
;
381 int FAST_FUNC
xsocket_stream(len_and_sockaddr
**lsap
)
383 return xsocket_type(lsap
, AF_UNSPEC
, SOCK_STREAM
);
386 static int create_and_bind_or_die(const char *bindaddr
, int port
, int sock_type
)
389 len_and_sockaddr
*lsa
;
391 if (bindaddr
&& bindaddr
[0]) {
392 lsa
= xdotted2sockaddr(bindaddr
, port
);
393 /* user specified bind addr dictates family */
394 fd
= xsocket(lsa
->u
.sa
.sa_family
, sock_type
, 0);
396 fd
= xsocket_type(&lsa
, AF_UNSPEC
, sock_type
);
397 set_nport(&lsa
->u
.sa
, htons(port
));
399 setsockopt_reuseaddr(fd
);
400 xbind(fd
, &lsa
->u
.sa
, lsa
->len
);
405 int FAST_FUNC
create_and_bind_stream_or_die(const char *bindaddr
, int port
)
407 return create_and_bind_or_die(bindaddr
, port
, SOCK_STREAM
);
410 int FAST_FUNC
create_and_bind_dgram_or_die(const char *bindaddr
, int port
)
412 return create_and_bind_or_die(bindaddr
, port
, SOCK_DGRAM
);
416 int FAST_FUNC
create_and_connect_stream_or_die(const char *peer
, int port
)
419 len_and_sockaddr
*lsa
;
421 lsa
= xhost2sockaddr(peer
, port
);
422 fd
= xsocket(lsa
->u
.sa
.sa_family
, SOCK_STREAM
, 0);
423 setsockopt_reuseaddr(fd
);
424 xconnect(fd
, &lsa
->u
.sa
, lsa
->len
);
429 int FAST_FUNC
xconnect_stream(const len_and_sockaddr
*lsa
)
431 int fd
= xsocket(lsa
->u
.sa
.sa_family
, SOCK_STREAM
, 0);
432 xconnect(fd
, &lsa
->u
.sa
, lsa
->len
);
436 /* We hijack this constant to mean something else */
437 /* It doesn't hurt because we will add this bit anyway */
438 #define IGNORE_PORT NI_NUMERICSERV
439 static char* FAST_FUNC
sockaddr2str(const struct sockaddr
*sa
, int flags
)
446 if (ENABLE_FEATURE_UNIX_LOCAL
&& sa
->sa_family
== AF_UNIX
) {
447 struct sockaddr_un
*sun
= (struct sockaddr_un
*)sa
;
448 return xasprintf("local:%.*s",
449 (int) sizeof(sun
->sun_path
),
453 salen
= LSA_SIZEOF_SA
;
454 #if ENABLE_FEATURE_IPV6
455 if (sa
->sa_family
== AF_INET
)
456 salen
= sizeof(struct sockaddr_in
);
457 if (sa
->sa_family
== AF_INET6
)
458 salen
= sizeof(struct sockaddr_in6
);
460 rc
= getnameinfo(sa
, salen
,
462 /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
464 /* do not resolve port# into service _name_ */
465 flags
| NI_NUMERICSERV
469 if (flags
& IGNORE_PORT
)
470 return xstrdup(host
);
471 #if ENABLE_FEATURE_IPV6
472 if (sa
->sa_family
== AF_INET6
) {
473 if (strchr(host
, ':')) /* heh, it's not a resolved hostname */
474 return xasprintf("[%s]:%s", host
, serv
);
475 /*return xasprintf("%s:%s", host, serv);*/
476 /* - fall through instead */
479 /* For now we don't support anything else, so it has to be INET */
480 /*if (sa->sa_family == AF_INET)*/
481 return xasprintf("%s:%s", host
, serv
);
482 /*return xstrdup(host);*/
485 char* FAST_FUNC
xmalloc_sockaddr2host(const struct sockaddr
*sa
)
487 return sockaddr2str(sa
, 0);
490 char* FAST_FUNC
xmalloc_sockaddr2host_noport(const struct sockaddr
*sa
)
492 return sockaddr2str(sa
, IGNORE_PORT
);
495 char* FAST_FUNC
xmalloc_sockaddr2hostonly_noport(const struct sockaddr
*sa
)
497 return sockaddr2str(sa
, NI_NAMEREQD
| IGNORE_PORT
);
499 char* FAST_FUNC
xmalloc_sockaddr2dotted(const struct sockaddr
*sa
)
501 return sockaddr2str(sa
, NI_NUMERICHOST
);
504 char* FAST_FUNC
xmalloc_sockaddr2dotted_noport(const struct sockaddr
*sa
)
506 return sockaddr2str(sa
, NI_NUMERICHOST
| IGNORE_PORT
);