next part of ipv6-ization is here: wget & httpd
No binary (build failed)
—
(log yok)
| @@ -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); | |
| @@ -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); | |
| } | |
| @@ -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); |
| - | |
| - | 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); |
| + | union { |
| + | struct sockaddr sa; |
| + | struct sockaddr_in sin; |
| + | USE_FEATURE_IPV6(struct sockaddr_in6 sin6;) |
| + | } fromAddr; |
| + | socklen_t fromAddrLen = sizeof(fromAddr); |
| + | |
| + | 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 */ | |
| @@ -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; | |
| @@ -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); | |
| @@ -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 */ | |
| @@ -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"); | |
| @@ -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 | |