diff --git a/include/libbb.h b/include/libbb.h index 704f34e56..07b1d1158 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -531,6 +531,7 @@ USE_DESKTOP(long long) int uncompress(int fd_in, int fd_out); int inflate(int in, int out); +/* NB: returns port in host byte order */ unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port); void bb_lookup_host(struct sockaddr_in *s_in, const char *host); diff --git a/libbb/xconnect.c b/libbb/xconnect.c index a5b16d982..f5a7e6dc8 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c @@ -38,7 +38,7 @@ void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) * default_port */ unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) { - unsigned port_nr = htons(default_port); + unsigned port_nr = default_port; if (port) { int old_errno; @@ -49,13 +49,11 @@ unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default if (errno || port_nr > 65535) { struct servent *tserv = getservbyname(port, protocol); if (tserv) - port_nr = tserv->s_port; - } else { - port_nr = htons(port_nr); + port_nr = ntohs(tserv->s_port); } errno = old_errno; } - return port_nr; + return (uint16_t)port_nr; } @@ -148,7 +146,7 @@ static len_and_sockaddr* str2sockaddr(const char *host, int port, int ai_flags) r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen); r->len = result->ai_addrlen; memcpy(&r->sa, result->ai_addr, result->ai_addrlen); - set_port(r, port); + set_port(r, htons(port)); freeaddrinfo(result); return r; } @@ -237,6 +235,7 @@ static char* sockaddr2str(const struct sockaddr *sa, socklen_t salen, int flags) flags | NI_NUMERICSERV /* do not resolve port# */ ); if (rc) return NULL; +// We probably need to use [%s]:%s for IPv6... return xasprintf("%s:%s", host, serv); } diff --git a/networking/httpd.c b/networking/httpd.c index 818590f78..f8773685e 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -142,7 +142,7 @@ typedef struct { unsigned int rmt_ip; #if ENABLE_FEATURE_HTTPD_CGI || DEBUG - char rmt_ip_str[16]; /* for set env REMOTE_ADDR */ + char *rmt_ip_str; /* for set env REMOTE_ADDR */ #endif unsigned port; /* server initial port and for set env REMOTE_PORT */ @@ -817,30 +817,11 @@ static void decodeBase64(char *Data) ****************************************************************************/ static int openServer(void) { - struct sockaddr_in lsocket; int fd; /* create the socket right now */ - /* inet_addr() returns a value that is already in network order */ - memset(&lsocket, 0, sizeof(lsocket)); - lsocket.sin_family = AF_INET; - lsocket.sin_addr.s_addr = INADDR_ANY; - lsocket.sin_port = htons(config->port); - fd = xsocket(AF_INET, SOCK_STREAM, 0); - /* tell the OS it's OK to reuse a previous address even though */ - /* it may still be in a close down state. Allows bind to succeed. */ -#ifdef SO_REUSEPORT - { - static const int on = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, - (void *)&on, sizeof(on)); - } -#else - setsockopt_reuseaddr(fd); -#endif - xbind(fd, (struct sockaddr *)&lsocket, sizeof(lsocket)); + fd = create_and_bind_stream_or_die(NULL, config->port); xlisten(fd, 9); - signal(SIGCHLD, SIG_IGN); /* prevent zombie (defunct) processes */ return fd; } @@ -1070,7 +1051,19 @@ static int sendCgi(const char *url, setenv1("SERVER_SOFTWARE", httpdVersion); putenv("SERVER_PROTOCOL=HTTP/1.0"); putenv("GATEWAY_INTERFACE=CGI/1.1"); - setenv1("REMOTE_ADDR", config->rmt_ip_str); + /* Having _separate_ variables for IP and port defeats + * the purpose of having socket abstraction. Which "port" + * are you using on Unix domain socket? + * IOW - REMOTE_PEER="1.2.3.4:56" makes much more sense. + * Oh well... */ + { + char *p = config->rmt_ip_str ? : ""; + char *cp = strrchr(p, ':'); + if (ENABLE_FEATURE_IPV6 && cp && strchr(cp, ']')) + cp = NULL; + if (cp) *cp = '\0'; /* delete :PORT */ + setenv1("REMOTE_ADDR", p); + } #if ENABLE_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV setenv_long("REMOTE_PORT", config->port); #endif @@ -1330,17 +1323,17 @@ static int checkPermIP(void) for (cur = config->ip_a_d; cur; cur = cur->next) { #if DEBUG fprintf(stderr, "checkPermIP: '%s' ? ", config->rmt_ip_str); + fprintf(stderr, "'%u.%u.%u.%u/%u.%u.%u.%u'\n", + (unsigned char)(cur->ip >> 24), + (unsigned char)(cur->ip >> 16), + (unsigned char)(cur->ip >> 8), + (unsigned char)(cur->ip), + (unsigned char)(cur->mask >> 24), + (unsigned char)(cur->mask >> 16), + (unsigned char)(cur->mask >> 8), + (unsigned char)(cur->mask) + ); #endif - if (DEBUG) - fprintf(stderr, "'%u.%u.%u.%u/%u.%u.%u.%u'\n", - (unsigned char)(cur->ip >> 24), - (unsigned char)(cur->ip >> 16), - (unsigned char)(cur->ip >> 8), - cur->ip & 0xff, - (unsigned char)(cur->mask >> 24), - (unsigned char)(cur->mask >> 16), - (unsigned char)(cur->mask >> 8), - cur->mask & 0xff); if ((config->rmt_ip & cur->mask) == cur->ip) return cur->allow_deny == 'A'; /* Allow/Deny */ } @@ -1765,6 +1758,8 @@ static void handleIncoming(void) ****************************************************************************/ static int miniHttpd(int server) { + static const int on = 1; + fd_set readfd, portfd; FD_ZERO(&portfd); @@ -1772,9 +1767,13 @@ static int miniHttpd(int server) /* copy the ports we are watching to the readfd set */ while (1) { - int on, s; - socklen_t fromAddrLen; - struct sockaddr_in fromAddr; + int s; + union { + struct sockaddr sa; + struct sockaddr_in sin; + USE_FEATURE_IPV6(struct sockaddr_in6 sin6;) + } fromAddr; + socklen_t fromAddrLen = sizeof(fromAddr); /* Now wait INDEFINITELY on the set of sockets! */ readfd = portfd; @@ -1782,27 +1781,31 @@ static int miniHttpd(int server) continue; if (!FD_ISSET(server, &readfd)) continue; - fromAddrLen = sizeof(fromAddr); - s = accept(server, (struct sockaddr *)&fromAddr, &fromAddrLen); + s = accept(server, &fromAddr.sa, &fromAddrLen); if (s < 0) continue; config->accepted_socket = s; - config->rmt_ip = ntohl(fromAddr.sin_addr.s_addr); + config->rmt_ip = 0; + config->port = 0; #if ENABLE_FEATURE_HTTPD_CGI || DEBUG - sprintf(config->rmt_ip_str, "%u.%u.%u.%u", - (unsigned char)(config->rmt_ip >> 24), - (unsigned char)(config->rmt_ip >> 16), - (unsigned char)(config->rmt_ip >> 8), - config->rmt_ip & 0xff); - config->port = ntohs(fromAddr.sin_port); + free(config->rmt_ip_str); + config->rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddrLen); #if DEBUG - bb_error_msg("connection from IP=%s, port %u", - config->rmt_ip_str, config->port); + bb_error_msg("connection from '%s'", config->rmt_ip_str); #endif #endif /* FEATURE_HTTPD_CGI */ + if (fromAddr.sa.sa_family == AF_INET) { + config->rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); + config->port = ntohs(fromAddr.sin.sin_port); + } +#if ENABLE_FEATURE_IPV6 + if (fromAddr.sa.sa_family == AF_INET6) { + //config->rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); + config->port = ntohs(fromAddr.sin6.sin6_port); + } +#endif /* set the KEEPALIVE option to cull dead connections */ - on = 1; setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on)); if (DEBUG || fork() == 0) { @@ -1823,19 +1826,30 @@ static int miniHttpd(int server) /* from inetd */ static int miniHttpd_inetd(void) { - struct sockaddr_in fromAddrLen; - socklen_t sinlen = sizeof(struct sockaddr_in); + union { + struct sockaddr sa; + struct sockaddr_in sin; + USE_FEATURE_IPV6(struct sockaddr_in6 sin6;) + } fromAddr; + socklen_t fromAddrLen = sizeof(fromAddr); - getpeername(0, (struct sockaddr *)&fromAddrLen, &sinlen); - config->rmt_ip = ntohl(fromAddrLen.sin_addr.s_addr); -#if ENABLE_FEATURE_HTTPD_CGI - sprintf(config->rmt_ip_str, "%u.%u.%u.%u", - (unsigned char)(config->rmt_ip >> 24), - (unsigned char)(config->rmt_ip >> 16), - (unsigned char)(config->rmt_ip >> 8), - config->rmt_ip & 0xff); + getpeername(0, &fromAddr.sa, &fromAddrLen); + config->rmt_ip = 0; + config->port = 0; +#if ENABLE_FEATURE_HTTPD_CGI || DEBUG + free(config->rmt_ip_str); + config->rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr.sa, fromAddrLen); +#endif + if (fromAddr.sa.sa_family == AF_INET) { + config->rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); + config->port = ntohs(fromAddr.sin.sin_port); + } +#if ENABLE_FEATURE_IPV6 + if (fromAddr.sa.sa_family == AF_INET6) { + //config->rmt_ip = ntohl(fromAddr.sin.sin_addr.s_addr); + config->port = ntohs(fromAddr.sin6.sin6_port); + } #endif - config->port = ntohs(fromAddrLen.sin_port); handleIncoming(); return 0; } @@ -1945,6 +1959,7 @@ int httpd_main(int argc, char *argv[]) xchdir(home_httpd); if (!(opt & OPT_INETD)) { + signal(SIGCHLD, SIG_IGN); config->server_socket = openServer(); #if ENABLE_FEATURE_HTTPD_SETUID /* drop privileges */ diff --git a/networking/nc.c b/networking/nc.c index 1419609e0..e1c22839c 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -37,7 +37,10 @@ int nc_main(int argc, char **argv) "" USE_NC_SERVER("lp:") USE_NC_EXTRA("w:i:f:e:") )) > 0 ) { if (ENABLE_NC_SERVER && opt=='l') USE_NC_SERVER(do_listen++); - else if (ENABLE_NC_SERVER && opt=='p') USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); + else if (ENABLE_NC_SERVER && opt=='p') { + USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0)); + USE_NC_SERVER(lport = htons(lport)); + } else if (ENABLE_NC_EXTRA && opt=='w') USE_NC_EXTRA( wsecs = xatou(optarg)); else if (ENABLE_NC_EXTRA && opt=='i') USE_NC_EXTRA( delay = xatou(optarg)); else if (ENABLE_NC_EXTRA && opt=='f') USE_NC_EXTRA( cfd = xopen(optarg, O_RDWR)); @@ -119,6 +122,7 @@ int nc_main(int argc, char **argv) address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; address.sin_port = bb_lookup_port(argv[1], "tcp", 0); + address.sin_port = htons(address.sin_port); xconnect(sfd, (struct sockaddr *) &address, sizeof(address)); cfd = sfd; diff --git a/networking/telnet.c b/networking/telnet.c index 5ca64e133..86586600b 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -617,19 +617,17 @@ int telnet_main(int argc, char** argv) #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN if (1 & getopt32(argc, argv, "al:", &autologin)) autologin = getenv("USER"); - - if (optind < argc) { - host = argv[optind++]; - port = bb_lookup_port((optind < argc) ? argv[optind++] : - "telnet", "tcp", 23); - if (optind < argc) - bb_show_usage(); - } else - bb_show_usage(); + argv += optind; #else - host = argv[1]; - port = bb_lookup_port((argc > 2) ? argv[2] : "telnet", "tcp", 23); + argv++; #endif + if (!*argv) + bb_show_usage(); + host = *argv++; + port = bb_lookup_port(*argv ? *argv++ : "telnet", "tcp", 23); + if (*argv) /* extra params?? */ + bb_show_usage(); + G.netfd = create_and_connect_stream_or_die(host, port); setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); diff --git a/networking/tftp.c b/networking/tftp.c index eaeb80857..43e835a5d 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -132,7 +132,7 @@ static int tftp( #endif const len_and_sockaddr *peer_lsa, const char *remotefile, const int localfd, - const unsigned port, int tftp_bufsize) + unsigned port, int tftp_bufsize) { struct timeval tv; fd_set rfds; @@ -154,6 +154,8 @@ static int tftp( char *xbuf = xmalloc(tftp_bufsize += 4); char *rbuf = xmalloc(tftp_bufsize); + port = htons(port); + socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0); /* build opcode */ diff --git a/networking/wget.c b/networking/wget.c index ee5aa63e9..22e610699 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -24,7 +24,7 @@ struct host_info { }; static void parse_url(char *url, struct host_info *h); -static FILE *open_socket(struct sockaddr_in *s_in); +static FILE *open_socket(len_and_sockaddr *lsa); static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf); @@ -90,7 +90,7 @@ int wget_main(int argc, char **argv) { char buf[512]; struct host_info server, target; - struct sockaddr_in s_in; + len_and_sockaddr *lsa; int n, status; int port; int try = 5; @@ -189,7 +189,7 @@ int wget_main(int argc, char **argv) if (!fname_out) { // Dirty hack. Needed because bb_get_last_path_component // will destroy trailing / by storing '\0' in last byte! - if (*target.path && target.path[strlen(target.path)-1] != '/') { + if (!last_char_is(target.path, '/')) { fname_out = #if ENABLE_FEATURE_WGET_STATUSBAR curfile = @@ -233,11 +233,11 @@ int wget_main(int argc, char **argv) /* We want to do exactly _one_ DNS lookup, since some * sites (i.e. ftp.us.debian.org) use round-robin DNS * and we want to connect to only one IP... */ - bb_lookup_host(&s_in, server.host); - s_in.sin_port = server.port; + lsa = host2sockaddr(server.host, server.port); if (!(opt & WGET_OPT_QUIET)) { - fprintf(stderr, "Connecting to %s[%s]:%d\n", - server.host, inet_ntoa(s_in.sin_addr), ntohs(server.port)); + fprintf(stderr, "Connecting to %s [%s]\n", server.host, + xmalloc_sockaddr2dotted(&lsa->sa, lsa->len)); + /* We leak xmalloc_sockaddr2dotted result */ } if (use_proxy || !target.is_ftp) { @@ -254,26 +254,29 @@ int wget_main(int argc, char **argv) * Open socket to http server */ if (sfp) fclose(sfp); - sfp = open_socket(&s_in); + sfp = open_socket(lsa); /* * Send HTTP request. */ if (use_proxy) { - const char *format = "GET %stp://%s:%d/%s HTTP/1.1\r\n"; -#if ENABLE_FEATURE_WGET_IP6_LITERAL - if (strchr(target.host, ':')) - format = "GET %stp://[%s]:%d/%s HTTP/1.1\r\n"; -#endif - fprintf(sfp, format, +// const char *format = "GET %stp://%s:%d/%s HTTP/1.1\r\n"; +//#if ENABLE_FEATURE_WGET_IP6_LITERAL +// if (strchr(target.host, ':')) +// format = "GET %stp://[%s]:%d/%s HTTP/1.1\r\n"; +//#endif +// fprintf(sfp, format, +// target.is_ftp ? "f" : "ht", target.host, +// ntohs(target.port), target.path); + fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n", target.is_ftp ? "f" : "ht", target.host, - ntohs(target.port), target.path); + target.path); } else { fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); } - fprintf(sfp, "Host: %s:%u\r\nUser-Agent: %s\r\n", - target.host, target.port, user_agent); + fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", + target.host, user_agent); #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { @@ -357,8 +360,8 @@ int wget_main(int argc, char **argv) server.host = target.host; server.port = target.port; } - bb_lookup_host(&s_in, server.host); - s_in.sin_port = server.port; + free(lsa); + lsa = host2sockaddr(server.host, server.port); break; } } @@ -375,7 +378,7 @@ int wget_main(int argc, char **argv) if (!target.user) target.user = xstrdup("anonymous:busybox@"); - sfp = open_socket(&s_in); + sfp = open_socket(lsa); if (ftpcmd(NULL, NULL, sfp, buf) != 220) bb_error_msg_and_die("%s", buf+4); @@ -429,8 +432,8 @@ int wget_main(int argc, char **argv) s = strrchr(buf, ','); if (!s) goto pasv_error; port += xatou_range(s+1, 0, 255) * 256; - s_in.sin_port = htons(port); - dfp = open_socket(&s_in); + set_port(lsa, htons(port)); + dfp = open_socket(lsa); if (beg_range) { sprintf(buf, "REST %"OFF_FMT"d", beg_range); @@ -564,36 +567,37 @@ static void parse_url(char *src_url, struct host_info *h) sp = h->host; -#if ENABLE_FEATURE_WGET_IP6_LITERAL - if (sp[0] == '[') { - char *ep; - - ep = sp + 1; - while (*ep == ':' || isxdigit(*ep)) - ep++; - if (*ep == ']') { - h->host++; - *ep = '\0'; - sp = ep + 1; - } - } -#endif - - p = strchr(sp, ':'); - if (p != NULL) { - *p = '\0'; - h->port = htons(xatou16(p + 1)); - } +//host2sockaddr does this itself +//#if ENABLE_FEATURE_WGET_IP6_LITERAL +// if (sp[0] == '[') { +// char *ep; +// +// ep = sp + 1; +// while (*ep == ':' || isxdigit(*ep)) +// ep++; +// if (*ep == ']') { +// h->host++; +// *ep = '\0'; +// sp = ep + 1; +// } +// } +//#endif +// +// p = strchr(sp, ':'); +// if (p != NULL) { +// *p = '\0'; +// h->port = htons(xatou16(p + 1)); +// } } -static FILE *open_socket(struct sockaddr_in *s_in) +static FILE *open_socket(len_and_sockaddr *lsa) { FILE *fp; /* glibc 2.4 seems to try seeking on it - ??! */ /* hopefully it understands what ESPIPE means... */ - fp = fdopen(xconnect_tcp_v4(s_in), "r+"); + fp = fdopen(xconnect_stream(lsa), "r+"); if (fp == NULL) bb_perror_msg_and_die("fdopen"); diff --git a/scripts/defconfig b/scripts/defconfig index 5ef6cff29..2c82ed474 100644 --- a/scripts/defconfig +++ b/scripts/defconfig @@ -580,7 +580,6 @@ CONFIG_VCONFIG=y CONFIG_WGET=y CONFIG_FEATURE_WGET_STATUSBAR=y CONFIG_FEATURE_WGET_AUTHENTICATION=y -CONFIG_FEATURE_WGET_IP6_LITERAL=y CONFIG_FEATURE_WGET_LONG_OPTIONS=y CONFIG_ZCIP=y