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(len_and_sockaddr
*lsa
, unsigned port
)
139 #if ENABLE_FEATURE_IPV6
140 if (lsa
->u
.sa
.sa_family
== AF_INET6
) {
141 lsa
->u
.sin6
.sin6_port
= port
;
145 if (lsa
->u
.sa
.sa_family
== AF_INET
) {
146 lsa
->u
.sin
.sin_port
= port
;
149 /* What? UNIX socket? IPX?? :) */
152 /* We hijack this constant to mean something else */
153 /* It doesn't hurt because we will remove this bit anyway */
154 #define DIE_ON_ERROR AI_CANONNAME
156 /* host: "1.2.3.4[:port]", "www.google.com[:port]"
157 * port: if neither of above specifies port # */
158 static len_and_sockaddr
* str2sockaddr(
159 const char *host
, int port
,
160 IF_FEATURE_IPV6(sa_family_t af
,)
163 IF_NOT_FEATURE_IPV6(sa_family_t af
= AF_INET
;)
166 struct addrinfo
*result
= NULL
;
167 struct addrinfo
*used_res
;
168 const char *org_host
= host
; /* only for error msg */
170 struct addrinfo hint
;
172 if (ENABLE_FEATURE_UNIX_LOCAL
&& strncmp(host
, "local:", 6) == 0) {
173 struct sockaddr_un
*sun
;
175 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_un
));
176 r
->len
= sizeof(struct sockaddr_un
);
177 r
->u
.sa
.sa_family
= AF_UNIX
;
178 sun
= (struct sockaddr_un
*)&r
->u
.sa
;
179 safe_strncpy(sun
->sun_path
, host
+ 6, sizeof(sun
->sun_path
));
185 /* Ugly parsing of host:addr */
186 if (ENABLE_FEATURE_IPV6
&& host
[0] == '[') {
187 /* Even uglier parsing of [xx]:nn */
189 cp
= strchr(host
, ']');
190 if (!cp
|| (cp
[1] != ':' && cp
[1] != '\0')) {
191 /* Malformed: must be [xx]:nn or [xx] */
192 bb_error_msg("bad address '%s'", org_host
);
193 if (ai_flags
& DIE_ON_ERROR
)
198 cp
= strrchr(host
, ':');
199 if (ENABLE_FEATURE_IPV6
&& cp
&& strchr(host
, ':') != cp
) {
200 /* There is more than one ':' (e.g. "::1") */
201 cp
= NULL
; /* it's not a port spec */
204 if (cp
) { /* points to ":" or "]:" */
205 int sz
= cp
- host
+ 1;
207 host
= safe_strncpy(alloca(sz
), host
, sz
);
208 if (ENABLE_FEATURE_IPV6
&& *cp
!= ':') {
210 if (*cp
== '\0') /* [xx] without port */
214 port
= bb_strtou(cp
, NULL
, 10);
215 if (errno
|| (unsigned)port
> 0xffff) {
216 bb_error_msg("bad port spec '%s'", org_host
);
217 if (ai_flags
& DIE_ON_ERROR
)
224 /* Next two if blocks allow to skip getaddrinfo()
225 * in case host name is a numeric IP(v6) address.
226 * getaddrinfo() initializes DNS resolution machinery,
227 * scans network config and such - tens of syscalls.
229 /* If we were not asked specifically for IPv6,
230 * check whether this is a numeric IPv4 */
231 IF_FEATURE_IPV6(if(af
!= AF_INET6
)) {
233 if (inet_aton(host
, &in4
) != 0) {
234 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_in
));
235 r
->len
= sizeof(struct sockaddr_in
);
236 r
->u
.sa
.sa_family
= AF_INET
;
237 r
->u
.sin
.sin_addr
= in4
;
241 #if ENABLE_FEATURE_IPV6
242 /* If we were not asked specifically for IPv4,
243 * check whether this is a numeric IPv6 */
246 if (inet_pton(AF_INET6
, host
, &in6
) > 0) {
247 r
= xzalloc(LSA_LEN_SIZE
+ sizeof(struct sockaddr_in6
));
248 r
->len
= sizeof(struct sockaddr_in6
);
249 r
->u
.sa
.sa_family
= AF_INET6
;
250 r
->u
.sin6
.sin6_addr
= in6
;
256 memset(&hint
, 0 , sizeof(hint
));
258 /* Needed. Or else we will get each address thrice (or more)
259 * for each possible socket type (tcp,udp,raw...): */
260 hint
.ai_socktype
= SOCK_STREAM
;
261 hint
.ai_flags
= ai_flags
& ~DIE_ON_ERROR
;
262 rc
= getaddrinfo(host
, NULL
, &hint
, &result
);
264 bb_error_msg("bad address '%s'", org_host
);
265 if (ai_flags
& DIE_ON_ERROR
)
270 #if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
272 if (used_res
->ai_family
== AF_INET
)
274 used_res
= used_res
->ai_next
;
281 r
= xmalloc(LSA_LEN_SIZE
+ used_res
->ai_addrlen
);
282 r
->len
= used_res
->ai_addrlen
;
283 memcpy(&r
->u
.sa
, used_res
->ai_addr
, used_res
->ai_addrlen
);
286 set_nport(r
, htons(port
));
288 freeaddrinfo(result
);
291 #if !ENABLE_FEATURE_IPV6
292 #define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
295 #if ENABLE_FEATURE_IPV6
296 len_and_sockaddr
* FAST_FUNC
host_and_af2sockaddr(const char *host
, int port
, sa_family_t af
)
298 return str2sockaddr(host
, port
, af
, 0);
301 len_and_sockaddr
* FAST_FUNC
xhost_and_af2sockaddr(const char *host
, int port
, sa_family_t af
)
303 return str2sockaddr(host
, port
, af
, DIE_ON_ERROR
);
307 len_and_sockaddr
* FAST_FUNC
host2sockaddr(const char *host
, int port
)
309 return str2sockaddr(host
, port
, AF_UNSPEC
, 0);
312 len_and_sockaddr
* FAST_FUNC
xhost2sockaddr(const char *host
, int port
)
314 return str2sockaddr(host
, port
, AF_UNSPEC
, DIE_ON_ERROR
);
317 len_and_sockaddr
* FAST_FUNC
xdotted2sockaddr(const char *host
, int port
)
319 return str2sockaddr(host
, port
, AF_UNSPEC
, AI_NUMERICHOST
| DIE_ON_ERROR
);
323 int FAST_FUNC
xsocket_type(len_and_sockaddr
**lsap
, IF_FEATURE_IPV6(int family
,) int sock_type
)
325 IF_NOT_FEATURE_IPV6(enum { family
= AF_INET
};)
326 len_and_sockaddr
*lsa
;
330 #if ENABLE_FEATURE_IPV6
331 if (family
== AF_UNSPEC
) {
332 fd
= socket(AF_INET6
, sock_type
, 0);
340 fd
= xsocket(family
, sock_type
, 0);
341 len
= sizeof(struct sockaddr_in
);
342 #if ENABLE_FEATURE_IPV6
343 if (family
== AF_INET6
) {
345 len
= sizeof(struct sockaddr_in6
);
348 lsa
= xzalloc(LSA_LEN_SIZE
+ len
);
350 lsa
->u
.sa
.sa_family
= family
;
355 int FAST_FUNC
xsocket_stream(len_and_sockaddr
**lsap
)
357 return xsocket_type(lsap
, IF_FEATURE_IPV6(AF_UNSPEC
,) SOCK_STREAM
);
360 static int create_and_bind_or_die(const char *bindaddr
, int port
, int sock_type
)
363 len_and_sockaddr
*lsa
;
365 if (bindaddr
&& bindaddr
[0]) {
366 lsa
= xdotted2sockaddr(bindaddr
, port
);
367 /* user specified bind addr dictates family */
368 fd
= xsocket(lsa
->u
.sa
.sa_family
, sock_type
, 0);
370 fd
= xsocket_type(&lsa
, IF_FEATURE_IPV6(AF_UNSPEC
,) sock_type
);
371 set_nport(lsa
, htons(port
));
373 setsockopt_reuseaddr(fd
);
374 xbind(fd
, &lsa
->u
.sa
, lsa
->len
);
379 int FAST_FUNC
create_and_bind_stream_or_die(const char *bindaddr
, int port
)
381 return create_and_bind_or_die(bindaddr
, port
, SOCK_STREAM
);
384 int FAST_FUNC
create_and_bind_dgram_or_die(const char *bindaddr
, int port
)
386 return create_and_bind_or_die(bindaddr
, port
, SOCK_DGRAM
);
390 int FAST_FUNC
create_and_connect_stream_or_die(const char *peer
, int port
)
393 len_and_sockaddr
*lsa
;
395 lsa
= xhost2sockaddr(peer
, port
);
396 fd
= xsocket(lsa
->u
.sa
.sa_family
, SOCK_STREAM
, 0);
397 setsockopt_reuseaddr(fd
);
398 xconnect(fd
, &lsa
->u
.sa
, lsa
->len
);
403 int FAST_FUNC
xconnect_stream(const len_and_sockaddr
*lsa
)
405 int fd
= xsocket(lsa
->u
.sa
.sa_family
, SOCK_STREAM
, 0);
406 xconnect(fd
, &lsa
->u
.sa
, lsa
->len
);
410 /* We hijack this constant to mean something else */
411 /* It doesn't hurt because we will add this bit anyway */
412 #define IGNORE_PORT NI_NUMERICSERV
413 static char* FAST_FUNC
sockaddr2str(const struct sockaddr
*sa
, int flags
)
420 if (ENABLE_FEATURE_UNIX_LOCAL
&& sa
->sa_family
== AF_UNIX
) {
421 struct sockaddr_un
*sun
= (struct sockaddr_un
*)sa
;
422 return xasprintf("local:%.*s",
423 (int) sizeof(sun
->sun_path
),
427 salen
= LSA_SIZEOF_SA
;
428 #if ENABLE_FEATURE_IPV6
429 if (sa
->sa_family
== AF_INET
)
430 salen
= sizeof(struct sockaddr_in
);
431 if (sa
->sa_family
== AF_INET6
)
432 salen
= sizeof(struct sockaddr_in6
);
434 rc
= getnameinfo(sa
, salen
,
436 /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
438 /* do not resolve port# into service _name_ */
439 flags
| NI_NUMERICSERV
443 if (flags
& IGNORE_PORT
)
444 return xstrdup(host
);
445 #if ENABLE_FEATURE_IPV6
446 if (sa
->sa_family
== AF_INET6
) {
447 if (strchr(host
, ':')) /* heh, it's not a resolved hostname */
448 return xasprintf("[%s]:%s", host
, serv
);
449 /*return xasprintf("%s:%s", host, serv);*/
450 /* - fall through instead */
453 /* For now we don't support anything else, so it has to be INET */
454 /*if (sa->sa_family == AF_INET)*/
455 return xasprintf("%s:%s", host
, serv
);
456 /*return xstrdup(host);*/
459 char* FAST_FUNC
xmalloc_sockaddr2host(const struct sockaddr
*sa
)
461 return sockaddr2str(sa
, 0);
464 char* FAST_FUNC
xmalloc_sockaddr2host_noport(const struct sockaddr
*sa
)
466 return sockaddr2str(sa
, IGNORE_PORT
);
469 char* FAST_FUNC
xmalloc_sockaddr2hostonly_noport(const struct sockaddr
*sa
)
471 return sockaddr2str(sa
, NI_NAMEREQD
| IGNORE_PORT
);
473 char* FAST_FUNC
xmalloc_sockaddr2dotted(const struct sockaddr
*sa
)
475 return sockaddr2str(sa
, NI_NUMERICHOST
);
478 char* FAST_FUNC
xmalloc_sockaddr2dotted_noport(const struct sockaddr
*sa
)
480 return sockaddr2str(sa
, NI_NUMERICHOST
| IGNORE_PORT
);