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 tarball for details.
10 #include <netinet/in.h>
14 void FAST_FUNC
setsockopt_reuseaddr(int fd
)
16 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &const_int_1
, sizeof(const_int_1
));
18 int FAST_FUNC
setsockopt_broadcast(int fd
)
20 return setsockopt(fd
, SOL_SOCKET
, SO_BROADCAST
, &const_int_1
, sizeof(const_int_1
));
22 int FAST_FUNC
setsockopt_bindtodevice(int fd
, const char *iface
)
26 strncpy_IFNAMSIZ(ifr
.ifr_name
, iface
);
27 /* NB: passing (iface, strlen(iface) + 1) does not work!
28 * (maybe it works on _some_ kernels, but not on 2.6.26)
29 * Actually, ifr_name is at offset 0, and in practice
30 * just giving char[IFNAMSIZ] instead of struct ifreq works too.
31 * But just in case it's not true on some obscure arch... */
32 r
= setsockopt(fd
, SOL_SOCKET
, SO_BINDTODEVICE
, &ifr
, sizeof(ifr
));
34 bb_perror_msg("can't bind to interface %s", iface
);
38 len_and_sockaddr
* FAST_FUNC
get_sock_lsa(int fd
)
40 len_and_sockaddr
*lsa
;
43 /* Can be optimized to do only one getsockname() */
44 if (getsockname(fd
, NULL
, &len
) != 0)
46 lsa
= xzalloc(LSA_LEN_SIZE
+ len
);
48 getsockname(fd
, &lsa
->u
.sa
, &lsa
->len
);
52 void FAST_FUNC
xconnect(int s
, const struct sockaddr
*s_addr
, socklen_t addrlen
)
54 if (connect(s
, s_addr
, addrlen
) < 0) {
55 if (ENABLE_FEATURE_CLEAN_UP
)
57 if (s_addr
->sa_family
== AF_INET
)
58 bb_perror_msg_and_die("%s (%s)",
59 "cannot connect to remote host",
60 inet_ntoa(((struct sockaddr_in
*)s_addr
)->sin_addr
));
61 bb_perror_msg_and_die("cannot connect to remote host");
65 /* Return port number for a service.
66 * If "port" is a number use it as the port.
67 * If "port" is a name it is looked up in /etc/services,
68 * if it isnt found return default_port
70 unsigned FAST_FUNC
bb_lookup_port(const char *port
, const char *protocol
, unsigned default_port
)
72 unsigned port_nr
= default_port
;
76 /* Since this is a lib function, we're not allowed to reset errno to 0.
77 * Doing so could break an app that is deferring checking of errno. */
79 port_nr
= bb_strtou(port
, NULL
, 10);
80 if (errno
|| port_nr
> 65535) {
81 struct servent
*tserv
= getservbyname(port
, protocol
);
82 port_nr
= default_port
;
84 port_nr
= ntohs(tserv
->s_port
);
88 return (uint16_t)port_nr
;
92 /* "Old" networking API - only IPv4 */
95 void FAST_FUNC bb_lookup_host(struct sockaddr_in *s_in, const char *host)
99 memset(s_in, 0, sizeof(struct sockaddr_in));
100 s_in->sin_family = AF_INET;
101 he = xgethostbyname(host);
102 memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
106 int FAST_FUNC xconnect_tcp_v4(struct sockaddr_in *s_addr)
108 int s = xsocket(AF_INET, SOCK_STREAM, 0);
109 xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
114 /* "New" networking API */
117 int FAST_FUNC
get_nport(const struct sockaddr
*sa
)
119 #if ENABLE_FEATURE_IPV6
120 if (sa
->sa_family
== AF_INET6
) {
121 return ((struct sockaddr_in6
*)sa
)->sin6_port
;
124 if (sa
->sa_family
== AF_INET
) {
125 return ((struct sockaddr_in
*)sa
)->sin_port
;
127 /* What? UNIX socket? IPX?? :) */
131 void FAST_FUNC
set_nport(len_and_sockaddr
*lsa
, unsigned port
)
133 #if ENABLE_FEATURE_IPV6
134 if (lsa
->u
.sa
.sa_family
== AF_INET6
) {
135 lsa
->u
.sin6
.sin6_port
= port
;
139 if (lsa
->u
.sa
.sa_family
== AF_INET
) {
140 lsa
->u
.sin
.sin_port
= port
;
143 /* What? UNIX socket? IPX?? :) */
146 /* We hijack this constant to mean something else */
147 /* It doesn't hurt because we will remove this bit anyway */
148 #define DIE_ON_ERROR AI_CANONNAME
150 /* host: "1.2.3.4[:port]", "www.google.com[:port]"
151 * port: if neither of above specifies port # */
152 static len_and_sockaddr
* str2sockaddr(
153 const char *host
, int port
,
154 USE_FEATURE_IPV6(sa_family_t af
,)
158 len_and_sockaddr
*r
= NULL
;
159 struct addrinfo
*result
= NULL
;
160 struct addrinfo
*used_res
;
161 const char *org_host
= host
; /* only for error msg */
163 struct addrinfo hint
;
165 /* Ugly parsing of host:addr */
166 if (ENABLE_FEATURE_IPV6
&& host
[0] == '[') {
167 /* Even uglier parsing of [xx]:nn */
169 cp
= strchr(host
, ']');
170 if (!cp
|| (cp
[1] != ':' && cp
[1] != '\0')) {
171 /* Malformed: must be [xx]:nn or [xx] */
172 bb_error_msg("bad address '%s'", org_host
);
173 if (ai_flags
& DIE_ON_ERROR
)
178 cp
= strrchr(host
, ':');
179 if (ENABLE_FEATURE_IPV6
&& cp
&& strchr(host
, ':') != cp
) {
180 /* There is more than one ':' (e.g. "::1") */
181 cp
= NULL
; /* it's not a port spec */
184 if (cp
) { /* points to ":" or "]:" */
185 int sz
= cp
- host
+ 1;
186 host
= safe_strncpy(alloca(sz
), host
, sz
);
187 if (ENABLE_FEATURE_IPV6
&& *cp
!= ':') {
189 if (*cp
== '\0') /* [xx] without port */
193 port
= bb_strtou(cp
, NULL
, 10);
194 if (errno
|| (unsigned)port
> 0xffff) {
195 bb_error_msg("bad port spec '%s'", org_host
);
196 if (ai_flags
& DIE_ON_ERROR
)
203 memset(&hint
, 0 , sizeof(hint
));
204 #if !ENABLE_FEATURE_IPV6
205 hint
.ai_family
= AF_INET
; /* do not try to find IPv6 */
209 /* Needed. Or else we will get each address thrice (or more)
210 * for each possible socket type (tcp,udp,raw...): */
211 hint
.ai_socktype
= SOCK_STREAM
;
212 hint
.ai_flags
= ai_flags
& ~DIE_ON_ERROR
;
213 rc
= getaddrinfo(host
, NULL
, &hint
, &result
);
215 bb_error_msg("bad address '%s'", org_host
);
216 if (ai_flags
& DIE_ON_ERROR
)
221 #if ENABLE_FEATURE_PREFER_IPV4_ADDRESS
223 if (used_res
->ai_family
== AF_INET
)
225 used_res
= used_res
->ai_next
;
232 r
= xmalloc(offsetof(len_and_sockaddr
, u
.sa
) + used_res
->ai_addrlen
);
233 r
->len
= used_res
->ai_addrlen
;
234 memcpy(&r
->u
.sa
, used_res
->ai_addr
, used_res
->ai_addrlen
);
235 set_nport(r
, htons(port
));
237 freeaddrinfo(result
);
240 #if !ENABLE_FEATURE_IPV6
241 #define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags)
244 #if ENABLE_FEATURE_IPV6
245 len_and_sockaddr
* FAST_FUNC
host_and_af2sockaddr(const char *host
, int port
, sa_family_t af
)
247 return str2sockaddr(host
, port
, af
, 0);
250 len_and_sockaddr
* FAST_FUNC
xhost_and_af2sockaddr(const char *host
, int port
, sa_family_t af
)
252 return str2sockaddr(host
, port
, af
, DIE_ON_ERROR
);
256 len_and_sockaddr
* FAST_FUNC
host2sockaddr(const char *host
, int port
)
258 return str2sockaddr(host
, port
, AF_UNSPEC
, 0);
261 len_and_sockaddr
* FAST_FUNC
xhost2sockaddr(const char *host
, int port
)
263 return str2sockaddr(host
, port
, AF_UNSPEC
, DIE_ON_ERROR
);
266 len_and_sockaddr
* FAST_FUNC
xdotted2sockaddr(const char *host
, int port
)
268 return str2sockaddr(host
, port
, AF_UNSPEC
, AI_NUMERICHOST
| DIE_ON_ERROR
);
272 int FAST_FUNC
xsocket_type(len_and_sockaddr
**lsap
, USE_FEATURE_IPV6(int family
,) int sock_type
)
274 SKIP_FEATURE_IPV6(enum { family
= AF_INET
};)
275 len_and_sockaddr
*lsa
;
279 #if ENABLE_FEATURE_IPV6
280 if (family
== AF_UNSPEC
) {
281 fd
= socket(AF_INET6
, sock_type
, 0);
289 fd
= xsocket(family
, sock_type
, 0);
290 len
= sizeof(struct sockaddr_in
);
291 #if ENABLE_FEATURE_IPV6
292 if (family
== AF_INET6
) {
294 len
= sizeof(struct sockaddr_in6
);
297 lsa
= xzalloc(offsetof(len_and_sockaddr
, u
.sa
) + len
);
299 lsa
->u
.sa
.sa_family
= family
;
304 int FAST_FUNC
xsocket_stream(len_and_sockaddr
**lsap
)
306 return xsocket_type(lsap
, USE_FEATURE_IPV6(AF_UNSPEC
,) SOCK_STREAM
);
309 static int create_and_bind_or_die(const char *bindaddr
, int port
, int sock_type
)
312 len_and_sockaddr
*lsa
;
314 if (bindaddr
&& bindaddr
[0]) {
315 lsa
= xdotted2sockaddr(bindaddr
, port
);
316 /* user specified bind addr dictates family */
317 fd
= xsocket(lsa
->u
.sa
.sa_family
, sock_type
, 0);
319 fd
= xsocket_type(&lsa
, USE_FEATURE_IPV6(AF_UNSPEC
,) sock_type
);
320 set_nport(lsa
, htons(port
));
322 setsockopt_reuseaddr(fd
);
323 xbind(fd
, &lsa
->u
.sa
, lsa
->len
);
328 int FAST_FUNC
create_and_bind_stream_or_die(const char *bindaddr
, int port
)
330 return create_and_bind_or_die(bindaddr
, port
, SOCK_STREAM
);
333 int FAST_FUNC
create_and_bind_dgram_or_die(const char *bindaddr
, int port
)
335 return create_and_bind_or_die(bindaddr
, port
, SOCK_DGRAM
);
339 int FAST_FUNC
create_and_connect_stream_or_die(const char *peer
, int port
)
342 len_and_sockaddr
*lsa
;
344 lsa
= xhost2sockaddr(peer
, port
);
345 fd
= xsocket(lsa
->u
.sa
.sa_family
, SOCK_STREAM
, 0);
346 setsockopt_reuseaddr(fd
);
347 xconnect(fd
, &lsa
->u
.sa
, lsa
->len
);
352 int FAST_FUNC
xconnect_stream(const len_and_sockaddr
*lsa
)
354 int fd
= xsocket(lsa
->u
.sa
.sa_family
, SOCK_STREAM
, 0);
355 xconnect(fd
, &lsa
->u
.sa
, lsa
->len
);
359 /* We hijack this constant to mean something else */
360 /* It doesn't hurt because we will add this bit anyway */
361 #define IGNORE_PORT NI_NUMERICSERV
362 static char* FAST_FUNC
sockaddr2str(const struct sockaddr
*sa
, int flags
)
369 salen
= LSA_SIZEOF_SA
;
370 #if ENABLE_FEATURE_IPV6
371 if (sa
->sa_family
== AF_INET
)
372 salen
= sizeof(struct sockaddr_in
);
373 if (sa
->sa_family
== AF_INET6
)
374 salen
= sizeof(struct sockaddr_in6
);
376 rc
= getnameinfo(sa
, salen
,
378 /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
380 /* do not resolve port# into service _name_ */
381 flags
| NI_NUMERICSERV
385 if (flags
& IGNORE_PORT
)
386 return xstrdup(host
);
387 #if ENABLE_FEATURE_IPV6
388 if (sa
->sa_family
== AF_INET6
) {
389 if (strchr(host
, ':')) /* heh, it's not a resolved hostname */
390 return xasprintf("[%s]:%s", host
, serv
);
391 /*return xasprintf("%s:%s", host, serv);*/
392 /* - fall through instead */
395 /* For now we don't support anything else, so it has to be INET */
396 /*if (sa->sa_family == AF_INET)*/
397 return xasprintf("%s:%s", host
, serv
);
398 /*return xstrdup(host);*/
401 char* FAST_FUNC
xmalloc_sockaddr2host(const struct sockaddr
*sa
)
403 return sockaddr2str(sa
, 0);
406 char* FAST_FUNC
xmalloc_sockaddr2host_noport(const struct sockaddr
*sa
)
408 return sockaddr2str(sa
, IGNORE_PORT
);
411 char* FAST_FUNC
xmalloc_sockaddr2hostonly_noport(const struct sockaddr
*sa
)
413 return sockaddr2str(sa
, NI_NAMEREQD
| IGNORE_PORT
);
415 char* FAST_FUNC
xmalloc_sockaddr2dotted(const struct sockaddr
*sa
)
417 return sockaddr2str(sa
, NI_NUMERICHOST
);
420 char* FAST_FUNC
xmalloc_sockaddr2dotted_noport(const struct sockaddr
*sa
)
422 return sockaddr2str(sa
, NI_NUMERICHOST
| IGNORE_PORT
);