nslookup: full circle. Here we started IPv6 work. Use "new API"
[oweals/busybox.git] / libbb / xconnect.c
index f5a7e6dc8aea255c135a064097a67861fb340fdb..188837e36e320650131f54946200fb13784c3c32 100644 (file)
@@ -9,14 +9,13 @@
 #include <netinet/in.h>
 #include "libbb.h"
 
-static const int one = 1;
 int setsockopt_reuseaddr(int fd)
 {
-       return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+       return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
 }
 int setsockopt_broadcast(int fd)
 {
-       return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
+       return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
 }
 
 void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
@@ -32,7 +31,7 @@ void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
        }
 }
 
-/* Return network byte ordered port number for a service.
+/* Return port number for a service.
  * If "port" is a number use it as the port.
  * If "port" is a name it is looked up in /etc/services, if it isnt found return
  * default_port */
@@ -48,6 +47,7 @@ unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default
                port_nr = bb_strtou(port, NULL, 10);
                if (errno || port_nr > 65535) {
                        struct servent *tserv = getservbyname(port, protocol);
+                       port_nr = default_port;
                        if (tserv)
                                port_nr = ntohs(tserv->s_port);
                }
@@ -59,7 +59,7 @@ unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default
 
 /* "Old" networking API - only IPv4 */
 
-
+/*
 void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
 {
        struct hostent *he;
@@ -70,18 +70,33 @@ void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
        memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
 }
 
+
 int xconnect_tcp_v4(struct sockaddr_in *s_addr)
 {
        int s = xsocket(AF_INET, SOCK_STREAM, 0);
        xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr));
        return s;
 }
-
+*/
 
 /* "New" networking API */
 
 
-void set_port(len_and_sockaddr *lsa, unsigned port)
+int get_nport(len_and_sockaddr *lsa)
+{
+#if ENABLE_FEATURE_IPV6
+       if (lsa->sa.sa_family == AF_INET6) {
+               return lsa->sin6.sin6_port;
+       }
+#endif
+       if (lsa->sa.sa_family == AF_INET) {
+               return lsa->sin.sin_port;
+       }
+       /* What? UNIX socket? IPX?? :) */
+       return -1;
+}
+
+void set_nport(len_and_sockaddr *lsa, unsigned port)
 {
 #if ENABLE_FEATURE_IPV6
        if (lsa->sa.sa_family == AF_INET6) {
@@ -96,7 +111,7 @@ void set_port(len_and_sockaddr *lsa, unsigned port)
        /* What? UNIX socket? IPX?? :) */
 }
 
-/* peer: "1.2.3.4[:port]", "www.google.com[:port]"
+/* host: "1.2.3.4[:port]", "www.google.com[:port]"
  * port: if neither of above specifies port #
  */
 static len_and_sockaddr* str2sockaddr(const char *host, int port, int ai_flags)
@@ -146,7 +161,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, htons(port));
+       set_nport(r, htons(port));
        freeaddrinfo(result);
        return r;
 }
@@ -161,19 +176,27 @@ static len_and_sockaddr* dotted2sockaddr(const char *host, int port)
        return str2sockaddr(host, port, NI_NUMERICHOST);
 }
 
-static int xsocket_stream(len_and_sockaddr *lsa)
+int xsocket_stream(len_and_sockaddr **lsap)
 {
+       len_and_sockaddr *lsa;
        int fd;
+       int len = sizeof(struct sockaddr_in);
+       int family = AF_INET;
+
 #if ENABLE_FEATURE_IPV6
        fd = socket(AF_INET6, SOCK_STREAM, 0);
-       lsa->sa.sa_family = AF_INET6;
-       lsa->len = sizeof(struct sockaddr_in6);
-       if (fd >= 0)
-               return fd;
+       if (fd >= 0) {
+               len = sizeof(struct sockaddr_in6);
+               family = AF_INET6;
+       } else
 #endif
-       fd = xsocket(AF_INET, SOCK_STREAM, 0);
-       lsa->sa.sa_family = AF_INET;
-       lsa->len = sizeof(struct sockaddr_in);
+       {
+               fd = xsocket(AF_INET, SOCK_STREAM, 0);
+       }
+       lsa = xzalloc(offsetof(len_and_sockaddr, sa) + len);
+       lsa->len = len;
+       lsa->sa.sa_family = family;
+       *lsap = lsa;
        return fd;
 }
 
@@ -190,11 +213,8 @@ int create_and_bind_stream_or_die(const char *bindaddr, int port)
                /* user specified bind addr dictates family */
                fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
        } else {
-               lsa = xzalloc(offsetof(len_and_sockaddr, sa) +
-                       USE_FEATURE_IPV6(sizeof(struct sockaddr_in6))
-                       SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in))
-               );
-               fd = xsocket_stream(lsa);
+               fd = xsocket_stream(&lsa);
+               set_nport(lsa, htons(port));
        }
        setsockopt_reuseaddr(fd);
        xbind(fd, &lsa->sa, lsa->len);
@@ -225,18 +245,36 @@ int xconnect_stream(const len_and_sockaddr *lsa)
        return fd;
 }
 
+/* We hijack this constant to mean something else */
+/* It doesn't hurt because we will add this bit anyway */
+#define IGNORE_PORT NI_NUMERICSERV
 static char* sockaddr2str(const struct sockaddr *sa, socklen_t salen, int flags)
 {
        char host[128];
        char serv[16];
        int rc = getnameinfo(sa, salen,
                        host, sizeof(host),
+       /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */
                        serv, sizeof(serv),
-                       flags | NI_NUMERICSERV /* do not resolve port# */
+                       /* do not resolve port# into service _name_ */
+                       flags | NI_NUMERICSERV
        );
-       if (rc) return NULL;
-// We probably need to use [%s]:%s for IPv6...
-       return xasprintf("%s:%s", host, serv);
+       if (rc)
+               return NULL;
+       if (flags & IGNORE_PORT)
+               return xstrdup(host);
+#if ENABLE_FEATURE_IPV6
+       if (sa->sa_family == AF_INET6) {
+               if (strchr(host, ':')) /* heh, it's not a resolved hostname */
+                       return xasprintf("[%s]:%s", host, serv);
+               /*return xasprintf("%s:%s", host, serv);*/
+               /* - fall through instead */
+       }
+#endif
+       /* For now we don't support anything else, so it has to be INET */
+       /*if (sa->sa_family == AF_INET)*/
+               return xasprintf("%s:%s", host, serv);
+       /*return xstrdup(host);*/
 }
 
 char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen)
@@ -244,7 +282,16 @@ char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen)
        return sockaddr2str(sa, salen, 0);
 }
 
+char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa, socklen_t salen)
+{
+       return sockaddr2str(sa, salen, NI_NAMEREQD | IGNORE_PORT);
+}
 char* xmalloc_sockaddr2dotted(const struct sockaddr *sa, socklen_t salen)
 {
        return sockaddr2str(sa, salen, NI_NUMERICHOST);
 }
+
+char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa, socklen_t salen)
+{
+       return sockaddr2str(sa, salen, NI_NUMERICHOST | IGNORE_PORT);
+}