Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/libbb/xconnect.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/libbb/xconnect.c
r1765 r2725 5 5 * Connect to host at port using address resolution from getaddrinfo 6 6 * 7 * Licensed under GPLv2, see file LICENSE in this source tree. 7 8 */ 8 9 10 #include <sys/types.h> 11 #include <sys/socket.h> /* netinet/in.h needs it */ 9 12 #include <netinet/in.h> 13 #include <net/if.h> 14 #include <sys/un.h> 10 15 #include "libbb.h" 11 16 12 void setsockopt_reuseaddr(int fd)17 void FAST_FUNC setsockopt_reuseaddr(int fd) 13 18 { 14 19 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1)); 15 20 } 16 int setsockopt_broadcast(int fd)21 int FAST_FUNC setsockopt_broadcast(int fd) 17 22 { 18 23 return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1)); 19 24 } 20 25 21 void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) 26 #ifdef SO_BINDTODEVICE 27 int FAST_FUNC setsockopt_bindtodevice(int fd, const char *iface) 28 { 29 int r; 30 struct ifreq ifr; 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)); 38 if (r) 39 bb_perror_msg("can't bind to interface %s", iface); 40 return r; 41 } 42 #else 43 int FAST_FUNC setsockopt_bindtodevice(int fd UNUSED_PARAM, 44 const char *iface UNUSED_PARAM) 45 { 46 bb_error_msg("SO_BINDTODEVICE is not supported on this system"); 47 return -1; 48 } 49 #endif 50 51 static len_and_sockaddr* get_lsa(int fd, int (*get_name)(int fd, struct sockaddr *addr, socklen_t *addrlen)) 52 { 53 len_and_sockaddr lsa; 54 len_and_sockaddr *lsa_ptr; 55 56 lsa.len = LSA_SIZEOF_SA; 57 if (get_name(fd, &lsa.u.sa, &lsa.len) != 0) 58 return NULL; 59 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); 64 } else { 65 memcpy(lsa_ptr, &lsa, LSA_LEN_SIZE + lsa.len); 66 } 67 return lsa_ptr; 68 } 69 70 len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd) 71 { 72 return get_lsa(fd, getsockname); 73 } 74 75 len_and_sockaddr* FAST_FUNC get_peer_lsa(int fd) 76 { 77 return get_lsa(fd, getpeername); 78 } 79 80 void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) 22 81 { 23 82 if (connect(s, s_addr, addrlen) < 0) { … … 26 85 if (s_addr->sa_family == AF_INET) 27 86 bb_perror_msg_and_die("%s (%s)", 28 "can not connect to remote host",87 "can't connect to remote host", 29 88 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr)); 30 bb_perror_msg_and_die("can not connect to remote host");89 bb_perror_msg_and_die("can't connect to remote host"); 31 90 } 32 91 } … … 34 93 /* Return port number for a service. 35 94 * If "port" is a number use it as the port. 36 * If "port" is a name it is looked up in /etc/services, if it isnt found return 37 * default_port */ 38 unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) 95 * If "port" is a name it is looked up in /etc/services, 96 * if it isnt found return default_port 97 */ 98 unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port) 39 99 { 40 100 unsigned port_nr = default_port; … … 58 118 59 119 60 /* "Old" networking API - only IPv4 */61 62 /*63 void bb_lookup_host(struct sockaddr_in *s_in, const char *host)64 {65 struct hostent *he;66 67 memset(s_in, 0, sizeof(struct sockaddr_in));68 s_in->sin_family = AF_INET;69 he = xgethostbyname(host);70 memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);71 }72 73 74 int xconnect_tcp_v4(struct sockaddr_in *s_addr)75 {76 int s = xsocket(AF_INET, SOCK_STREAM, 0);77 xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));78 return s;79 }80 */81 82 120 /* "New" networking API */ 83 121 84 122 85 int get_nport(const struct sockaddr *sa)123 int FAST_FUNC get_nport(const struct sockaddr *sa) 86 124 { 87 125 #if ENABLE_FEATURE_IPV6 … … 97 135 } 98 136 99 void set_nport(len_and_sockaddr *lsa, unsigned port)100 { 101 #if ENABLE_FEATURE_IPV6 102 if (lsa-> sa.sa_family == AF_INET6) {103 lsa-> sin6.sin6_port = port;137 void FAST_FUNC set_nport(len_and_sockaddr *lsa, unsigned port) 138 { 139 #if ENABLE_FEATURE_IPV6 140 if (lsa->u.sa.sa_family == AF_INET6) { 141 lsa->u.sin6.sin6_port = port; 104 142 return; 105 143 } 106 144 #endif 107 if (lsa-> sa.sa_family == AF_INET) {108 lsa-> sin.sin_port = port;145 if (lsa->u.sa.sa_family == AF_INET) { 146 lsa->u.sin.sin_port = port; 109 147 return; 110 148 } … … 120 158 static len_and_sockaddr* str2sockaddr( 121 159 const char *host, int port, 122 USE_FEATURE_IPV6(sa_family_t af,)160 IF_FEATURE_IPV6(sa_family_t af,) 123 161 int ai_flags) 124 162 { 163 IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;) 125 164 int rc; 126 len_and_sockaddr *r = NULL;165 len_and_sockaddr *r; 127 166 struct addrinfo *result = NULL; 167 struct addrinfo *used_res; 128 168 const char *org_host = host; /* only for error msg */ 129 169 const char *cp; 130 170 struct addrinfo hint; 131 171 172 if (ENABLE_FEATURE_UNIX_LOCAL && strncmp(host, "local:", 6) == 0) { 173 struct sockaddr_un *sun; 174 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)); 180 return r; 181 } 182 183 r = NULL; 184 132 185 /* Ugly parsing of host:addr */ 133 186 if (ENABLE_FEATURE_IPV6 && host[0] == '[') { 187 /* Even uglier parsing of [xx]:nn */ 134 188 host++; 135 189 cp = strchr(host, ']'); 136 if (!cp || cp[1] != ':') /* Malformed: must have [xx]:nn */ 137 bb_error_msg_and_die("bad address '%s'", org_host); 138 //return r; /* return NULL */ 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) 194 xfunc_die(); 195 return NULL; 196 } 139 197 } else { 140 198 cp = strrchr(host, ':'); … … 144 202 } 145 203 } 146 if (cp) { 204 if (cp) { /* points to ":" or "]:" */ 147 205 int sz = cp - host + 1; 206 148 207 host = safe_strncpy(alloca(sz), host, sz); 149 if (ENABLE_FEATURE_IPV6 && *cp != ':') 208 if (ENABLE_FEATURE_IPV6 && *cp != ':') { 150 209 cp++; /* skip ']' */ 210 if (*cp == '\0') /* [xx] without port */ 211 goto skip; 212 } 151 213 cp++; /* skip ':' */ 152 port = xatou16(cp); 153 } 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) 218 xfunc_die(); 219 return NULL; 220 } 221 skip: ; 222 } 223 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. 228 */ 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)) { 232 struct in_addr in4; 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; 238 goto set_port; 239 } 240 } 241 #if ENABLE_FEATURE_IPV6 242 /* If we were not asked specifically for IPv4, 243 * check whether this is a numeric IPv6 */ 244 if (af != AF_INET) { 245 struct in6_addr in6; 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; 251 goto set_port; 252 } 253 } 254 #endif 154 255 155 256 memset(&hint, 0 , sizeof(hint)); 156 #if !ENABLE_FEATURE_IPV6157 hint.ai_family = AF_INET; /* do not try to find IPv6 */158 #else159 257 hint.ai_family = af; 160 #endif161 258 /* Needed. Or else we will get each address thrice (or more) 162 259 * for each possible socket type (tcp,udp,raw...): */ … … 170 267 goto ret; 171 268 } 172 r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen); 173 r->len = result->ai_addrlen; 174 memcpy(&r->sa, result->ai_addr, result->ai_addrlen); 269 used_res = result; 270 #if ENABLE_FEATURE_PREFER_IPV4_ADDRESS 271 while (1) { 272 if (used_res->ai_family == AF_INET) 273 break; 274 used_res = used_res->ai_next; 275 if (!used_res) { 276 used_res = result; 277 break; 278 } 279 } 280 #endif 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); 284 285 set_port: 175 286 set_nport(r, htons(port)); 176 287 ret: … … 183 294 184 295 #if ENABLE_FEATURE_IPV6 185 len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af)296 len_and_sockaddr* FAST_FUNC host_and_af2sockaddr(const char *host, int port, sa_family_t af) 186 297 { 187 298 return str2sockaddr(host, port, af, 0); 188 299 } 189 300 190 len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af)301 len_and_sockaddr* FAST_FUNC xhost_and_af2sockaddr(const char *host, int port, sa_family_t af) 191 302 { 192 303 return str2sockaddr(host, port, af, DIE_ON_ERROR); … … 194 305 #endif 195 306 196 len_and_sockaddr* host2sockaddr(const char *host, int port)307 len_and_sockaddr* FAST_FUNC host2sockaddr(const char *host, int port) 197 308 { 198 309 return str2sockaddr(host, port, AF_UNSPEC, 0); 199 310 } 200 311 201 len_and_sockaddr* xhost2sockaddr(const char *host, int port)312 len_and_sockaddr* FAST_FUNC xhost2sockaddr(const char *host, int port) 202 313 { 203 314 return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR); 204 315 } 205 316 206 len_and_sockaddr* xdotted2sockaddr(const char *host, int port)317 len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port) 207 318 { 208 319 return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); 209 320 } 210 321 211 int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type) 212 { 213 SKIP_FEATURE_IPV6(enum { family = AF_INET };) 322 #undef xsocket_type 323 int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type) 324 { 325 IF_NOT_FEATURE_IPV6(enum { family = AF_INET };) 214 326 len_and_sockaddr *lsa; 215 327 int fd; … … 234 346 } 235 347 #endif 236 lsa = xzalloc( offsetof(len_and_sockaddr, sa)+ len);348 lsa = xzalloc(LSA_LEN_SIZE + len); 237 349 lsa->len = len; 238 lsa-> sa.sa_family = family;350 lsa->u.sa.sa_family = family; 239 351 *lsap = lsa; 240 352 return fd; 241 353 } 242 354 243 int xsocket_stream(len_and_sockaddr **lsap)244 { 245 return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);355 int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap) 356 { 357 return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM); 246 358 } 247 359 … … 254 366 lsa = xdotted2sockaddr(bindaddr, port); 255 367 /* user specified bind addr dictates family */ 256 fd = xsocket(lsa-> sa.sa_family, sock_type, 0);368 fd = xsocket(lsa->u.sa.sa_family, sock_type, 0); 257 369 } else { 258 fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type);370 fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type); 259 371 set_nport(lsa, htons(port)); 260 372 } 261 373 setsockopt_reuseaddr(fd); 262 xbind(fd, &lsa-> sa, lsa->len);374 xbind(fd, &lsa->u.sa, lsa->len); 263 375 free(lsa); 264 376 return fd; 265 377 } 266 378 267 int create_and_bind_stream_or_die(const char *bindaddr, int port)379 int FAST_FUNC create_and_bind_stream_or_die(const char *bindaddr, int port) 268 380 { 269 381 return create_and_bind_or_die(bindaddr, port, SOCK_STREAM); 270 382 } 271 383 272 int create_and_bind_dgram_or_die(const char *bindaddr, int port)384 int FAST_FUNC create_and_bind_dgram_or_die(const char *bindaddr, int port) 273 385 { 274 386 return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM); … … 276 388 277 389 278 int create_and_connect_stream_or_die(const char *peer, int port)390 int FAST_FUNC create_and_connect_stream_or_die(const char *peer, int port) 279 391 { 280 392 int fd; … … 282 394 283 395 lsa = xhost2sockaddr(peer, port); 284 fd = xsocket(lsa-> sa.sa_family, SOCK_STREAM, 0);396 fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0); 285 397 setsockopt_reuseaddr(fd); 286 xconnect(fd, &lsa-> sa, lsa->len);398 xconnect(fd, &lsa->u.sa, lsa->len); 287 399 free(lsa); 288 400 return fd; 289 401 } 290 402 291 int xconnect_stream(const len_and_sockaddr *lsa)292 { 293 int fd = xsocket(lsa-> sa.sa_family, SOCK_STREAM, 0);294 xconnect(fd, &lsa-> sa, lsa->len);403 int FAST_FUNC xconnect_stream(const len_and_sockaddr *lsa) 404 { 405 int fd = xsocket(lsa->u.sa.sa_family, SOCK_STREAM, 0); 406 xconnect(fd, &lsa->u.sa, lsa->len); 295 407 return fd; 296 408 } … … 299 411 /* It doesn't hurt because we will add this bit anyway */ 300 412 #define IGNORE_PORT NI_NUMERICSERV 301 static char* sockaddr2str(const struct sockaddr *sa, int flags)413 static char* FAST_FUNC sockaddr2str(const struct sockaddr *sa, int flags) 302 414 { 303 415 char host[128]; … … 305 417 int rc; 306 418 socklen_t salen; 419 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), 424 sun->sun_path); 425 } 307 426 308 427 salen = LSA_SIZEOF_SA; … … 338 457 } 339 458 340 char* xmalloc_sockaddr2host(const struct sockaddr *sa)459 char* FAST_FUNC xmalloc_sockaddr2host(const struct sockaddr *sa) 341 460 { 342 461 return sockaddr2str(sa, 0); 343 462 } 344 463 345 char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa)464 char* FAST_FUNC xmalloc_sockaddr2host_noport(const struct sockaddr *sa) 346 465 { 347 466 return sockaddr2str(sa, IGNORE_PORT); 348 467 } 349 468 350 char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa)469 char* FAST_FUNC xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa) 351 470 { 352 471 return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT); 353 472 } 354 char* xmalloc_sockaddr2dotted(const struct sockaddr *sa)473 char* FAST_FUNC xmalloc_sockaddr2dotted(const struct sockaddr *sa) 355 474 { 356 475 return sockaddr2str(sa, NI_NUMERICHOST); 357 476 } 358 477 359 char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa)478 char* FAST_FUNC xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa) 360 479 { 361 480 return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT);
Note:
See TracChangeset
for help on using the changeset viewer.