next part of ipv6-ization is here: wget & httpd
authorDenis Vlasenko <vda.linux@googlemail.com>
Fri, 12 Jan 2007 10:35:23 +0000 (10:35 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Fri, 12 Jan 2007 10:35:23 +0000 (10:35 -0000)
include/libbb.h
libbb/xconnect.c
networking/httpd.c
networking/nc.c
networking/telnet.c
networking/tftp.c
networking/wget.c
scripts/defconfig

index 704f34e56b2421f781e5e7f3b1634ab955078884..07b1d1158e28247569bc67d042df42c1e42dbfd4 100644 (file)
@@ -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);
 
index a5b16d982ae4a27b6c5ba733e20a3f34f95d000a..f5a7e6dc8aea255c135a064097a67861fb340fdb 100644 (file)
@@ -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);
 }
 
index 818590f78ff92996e54a3f3a9028f8ffc31c65c3..f8773685e1983ed1d3ee2644305950472dd91a3a 100644 (file)
@@ -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 */
index 1419609e08c752d94f62944bfec4882e6c8f13a4..e1c22839c6d474631bba9cc4e46139bd120e5678 100644 (file)
@@ -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;
index 5ca64e1338449687d1272d2e183d9e125d00177a..86586600ba3b5b45d644cbc71bc895e3870617b1 100644 (file)
@@ -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);
index eaeb80857e9644949b4540f6a89a0a317296cb3b..43e835a5de0ec69672ceffb8f894ed8d1874939d 100644 (file)
@@ -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 */
index ee5aa63e9d6594e628ee4d5a6c2b2c66c6113761..22e610699222a22023217b3aa7855bb8f835a226 100644 (file)
@@ -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");
 
index 5ef6cff29c9e90224884cf3284a05ef12c3f107d..2c82ed47426f313bc4fd269a86c49611a7f1b766 100644 (file)
@@ -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