Blob Blame Raw
diff -up nmap-6.40/ncat/ncat_connect.c.allresolve nmap-6.40/ncat/ncat_connect.c
--- nmap-6.40/ncat/ncat_connect.c.allresolve	2015-07-07 09:47:11.527409563 +0200
+++ nmap-6.40/ncat/ncat_connect.c	2015-07-07 09:47:11.529409551 +0200
@@ -165,6 +165,7 @@ static struct conn_state cs = {
     0
 };
 
+static void try_nsock_connect(nsock_pool nsp, struct sockaddr_list *conn_addr);
 static void connect_handler(nsock_pool nsp, nsock_event evt, void *data);
 static void post_connect(nsock_pool nsp, nsock_iod iod);
 static void read_stdin_handler(nsock_pool nsp, nsock_event evt, void *data);
@@ -586,7 +587,7 @@ int ncat_connect(void)
 
             if (o.af != AF_INET)
                 bye("Sorry, -g can only currently be used with IPv4.");
-            ipopts = buildsrcrte(targetss.in.sin_addr, o.srcrtes, o.numsrcrtes, o.srcrteptr, &ipoptslen);
+            ipopts = buildsrcrte(targetaddrs->addr.in.sin_addr, o.srcrtes, o.numsrcrtes, o.srcrteptr, &ipoptslen);
 
             nsi_set_ipoptions(cs.sock_nsi, ipopts, ipoptslen);
             free(ipopts); /* Nsock has its own copy */
@@ -596,49 +597,18 @@ int ncat_connect(void)
         if (o.af == AF_UNIX) {
             if (o.proto == IPPROTO_UDP) {
                 nsock_connect_unixsock_datagram(mypool, cs.sock_nsi, connect_handler, NULL,
-                                                &targetss.sockaddr,
-                                                SUN_LEN((struct sockaddr_un *)&targetss.sockaddr));
+                                                &targetaddrs->addr.sockaddr,
+                                                SUN_LEN((struct sockaddr_un *)&targetaddrs->addr.sockaddr));
             } else {
                 nsock_connect_unixsock_stream(mypool, cs.sock_nsi, connect_handler, o.conntimeout,
-                                              NULL, &targetss.sockaddr,
-                                              SUN_LEN((struct sockaddr_un *)&targetss.sockaddr));
+                                              NULL, &targetaddrs->addr.sockaddr,
+                                              SUN_LEN((struct sockaddr_un *)&targetaddrs->addr.sockaddr));
             }
         } else
 #endif
-        if (o.proto == IPPROTO_UDP) {
-            nsock_connect_udp(mypool, cs.sock_nsi, connect_handler,
-                              NULL, &targetss.sockaddr, targetsslen,
-                              inet_port(&targetss));
-        }
-#ifdef HAVE_OPENSSL
-        else if (o.proto == IPPROTO_SCTP && o.ssl) {
-            nsock_connect_ssl(mypool, cs.sock_nsi, connect_handler,
-                              o.conntimeout, NULL,
-                              &targetss.sockaddr, targetsslen,
-                              IPPROTO_SCTP, inet_port(&targetss),
-                              NULL);
-        }
-#endif
-        else if (o.proto == IPPROTO_SCTP) {
-            nsock_connect_sctp(mypool, cs.sock_nsi, connect_handler,
-                              o.conntimeout, NULL,
-                              &targetss.sockaddr, targetsslen,
-                              inet_port(&targetss));
-        }
-#ifdef HAVE_OPENSSL
-        else if (o.ssl) {
-            nsock_connect_ssl(mypool, cs.sock_nsi, connect_handler,
-                              o.conntimeout, NULL,
-                              &targetss.sockaddr, targetsslen,
-                              IPPROTO_TCP, inet_port(&targetss),
-                              NULL);
-        }
-#endif
-        else {
-            nsock_connect_tcp(mypool, cs.sock_nsi, connect_handler,
-                              o.conntimeout, NULL,
-                              &targetss.sockaddr, targetsslen,
-                              inet_port(&targetss));
+        {
+            /* Add connection to first resolved address. */
+            try_nsock_connect(mypool, targetaddrs);
         }
     } else {
         /* A proxy connection. */
@@ -665,8 +635,8 @@ int ncat_connect(void)
             socket_buffer_init(&stateful_buf, connect_socket);
 
             if (o.verbose) {
-                loguser("Connected to proxy %s:%hu\n", inet_socktop(&targetss),
-                    inet_port(&targetss));
+                loguser("Connected to proxy %s:%hu\n", inet_socktop(&targetaddrs->addr),
+                    inet_port(&targetaddrs->addr));
             }
 
             /* Fill the socks4_data struct */
@@ -716,6 +686,8 @@ int ncat_connect(void)
     /* connect */
     rc = nsock_loop(mypool, -1);
 
+    free_sockaddr_list(targetaddrs);
+
     if (o.verbose) {
         struct timeval end_time;
         double time;
@@ -739,19 +711,73 @@ int ncat_connect(void)
     return rc == NSOCK_LOOP_ERROR ? 1 : 0;
 }
 
+static void try_nsock_connect(nsock_pool nsp, struct sockaddr_list *conn_addr)
+{
+    if (o.proto == IPPROTO_UDP) {
+        nsock_connect_udp(nsp, cs.sock_nsi, connect_handler, (void *)conn_addr->next,
+                          &conn_addr->addr.sockaddr, conn_addr->addrlen,
+                          inet_port(&conn_addr->addr));
+    }
+#ifdef HAVE_OPENSSL
+    else if (o.proto == IPPROTO_SCTP && o.ssl) {
+        nsock_connect_ssl(nsp, cs.sock_nsi, connect_handler,
+                          o.conntimeout, (void *)conn_addr->next,
+                          &conn_addr->addr.sockaddr, conn_addr->addrlen,
+                          IPPROTO_SCTP, inet_port(&conn_addr->addr),
+                          NULL);
+    }
+#endif
+    else if (o.proto == IPPROTO_SCTP) {
+        nsock_connect_sctp(nsp, cs.sock_nsi, connect_handler,
+                          o.conntimeout, (void *)conn_addr->next,
+                          &conn_addr->addr.sockaddr, conn_addr->addrlen,
+                          inet_port(&conn_addr->addr));
+    }
+#ifdef HAVE_OPENSSL
+    else if (o.ssl) {
+        nsock_connect_ssl(nsp, cs.sock_nsi, connect_handler,
+                          o.conntimeout, (void *)conn_addr->next,
+                          &conn_addr->addr.sockaddr, conn_addr->addrlen,
+                          IPPROTO_TCP, inet_port(&conn_addr->addr),
+                          NULL);
+    }
+#endif
+    else {
+        nsock_connect_tcp(nsp, cs.sock_nsi, connect_handler,
+                          o.conntimeout, (void *)conn_addr->next,
+                          &conn_addr->addr.sockaddr, conn_addr->addrlen,
+                          inet_port(&conn_addr->addr));
+    }
+}
+
 static void connect_handler(nsock_pool nsp, nsock_event evt, void *data)
 {
     enum nse_status status = nse_status(evt);
     enum nse_type type = nse_type(evt);
+    struct sockaddr_list *next_addr = (struct sockaddr_list *)data;
 
     ncat_assert(type == NSE_TYPE_CONNECT || type == NSE_TYPE_CONNECT_SSL);
 
-    if (status == NSE_STATUS_ERROR) {
-        loguser("%s.\n", socket_strerror(nse_errorcode(evt)));
-        exit(1);
-    } else if (status == NSE_STATUS_TIMEOUT) {
-        loguser("%s.\n", socket_strerror(ETIMEDOUT));
-        exit(1);
+    if (status == NSE_STATUS_ERROR || status == NSE_STATUS_TIMEOUT) {
+        int errcode = (status == NSE_STATUS_TIMEOUT)?ETIMEDOUT:nse_errorcode(evt);
+        /* If there are more resolved addresses, try connecting to next one */
+        if (next_addr != NULL) {
+            if (o.verbose) {
+                union sockaddr_u peer;
+                zmem(&peer, sizeof(peer.storage));
+                nsi_getlastcommunicationinfo(cs.sock_nsi, NULL, NULL, NULL,
+                    &peer.sockaddr, sizeof(peer.storage));
+                loguser("Connection to %s failed: %s.\n", inet_socktop(&peer), socket_strerror(errcode));
+                loguser("Trying next address...\n");
+            }
+            try_nsock_connect(nsp, next_addr);
+            return;
+        }
+        else {
+            free_sockaddr_list(targetaddrs);
+            loguser("%s.\n", socket_strerror(errcode));
+            exit(1);
+        }
     } else {
         ncat_assert(status == NSE_STATUS_SUCCESS);
     }
diff -up nmap-6.40/ncat/ncat_core.c.allresolve nmap-6.40/ncat/ncat_core.c
--- nmap-6.40/ncat/ncat_core.c.allresolve	2013-07-29 00:08:48.000000000 +0200
+++ nmap-6.40/ncat/ncat_core.c	2015-07-07 09:47:11.529409551 +0200
@@ -147,8 +147,7 @@ int num_listenaddrs = 0;
 union sockaddr_u srcaddr;
 size_t srcaddrlen;
 
-union sockaddr_u targetss;
-size_t targetsslen;
+struct sockaddr_list *targetaddrs;
 
 union sockaddr_u httpconnect, socksconnect;
 size_t httpconnectlen, socksconnectlen;
@@ -211,19 +210,23 @@ void options_init(void)
 #endif
 }
 
-/* Internal helper for resolve and resolve_numeric. addl_flags is ored into
-   hints.ai_flags, so you can add AI_NUMERICHOST. */
+/* Internal helper for resolve and resolve_numeric.
+   addl_flags is ored into hints.ai_flags, so you can add AI_NUMERICHOST.
+   sl is a pointer to first element of sockaddr linked list, which is always
+   statically allocated. Next list elements are dynamically allocated.
+   If multiple_addrs is false then only first address is returned. */
 static int resolve_internal(const char *hostname, unsigned short port,
-    struct sockaddr_storage *ss, size_t *sslen, int af, int addl_flags)
+    struct sockaddr_list *sl, int af, int addl_flags, int multiple_addrs)
 {
     struct addrinfo hints;
     struct addrinfo *result;
+    struct addrinfo *next;
+    struct sockaddr_list **item_ptr = &sl;
+    struct sockaddr_list *new_item;
     char portbuf[16];
     int rc;
 
     ncat_assert(hostname != NULL);
-    ncat_assert(ss != NULL);
-    ncat_assert(sslen != NULL);
 
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = af;
@@ -240,8 +243,19 @@ static int resolve_internal(const char *
     if (result == NULL)
         return EAI_NONAME;
     ncat_assert(result->ai_addrlen > 0 && result->ai_addrlen <= (int) sizeof(struct sockaddr_storage));
-    *sslen = result->ai_addrlen;
-    memcpy(ss, result->ai_addr, *sslen);
+    for (next = result; next != NULL; next = next->ai_next) {
+        if (*item_ptr == NULL)
+        {
+            *item_ptr = (struct sockaddr_list *)safe_malloc(sizeof(struct sockaddr_list));
+	    (**item_ptr).next = NULL;
+        }
+        new_item = *item_ptr;
+        new_item->addrlen = next->ai_addrlen;
+        memcpy(&new_item->addr.storage, next->ai_addr, next->ai_addrlen);
+        if (!multiple_addrs)
+            break;
+        item_ptr = &new_item->next;
+    }
     freeaddrinfo(result);
 
     return 0;
@@ -260,12 +274,42 @@ int resolve(const char *hostname, unsign
     struct sockaddr_storage *ss, size_t *sslen, int af)
 {
     int flags;
+    struct sockaddr_list sl;
+    int result;
 
     flags = 0;
     if (o.nodns)
         flags |= AI_NUMERICHOST;
 
-    return resolve_internal(hostname, port, ss, sslen, af, flags);
+    result = resolve_internal(hostname, port, &sl, af, flags, 0);
+    *ss = sl.addr.storage;
+    *sslen = sl.addrlen;
+    return result;
+}
+
+/* Resolves the given hostname or IP address with getaddrinfo, and stores
+   all results into a linked list.
+   The rest of the behavior is same as resolve(). */
+int resolve_multi(const char *hostname, unsigned short port,
+    struct sockaddr_list *sl, int af)
+{
+    int flags;
+
+    flags = 0;
+    if (o.nodns)
+        flags |= AI_NUMERICHOST;
+
+    return resolve_internal(hostname, port, sl, af, flags, 1);
+}
+
+void free_sockaddr_list(struct sockaddr_list *sl)
+{
+    struct sockaddr_list *current, *next = sl;
+    while (next != NULL) {
+        current = next;
+        next = current->next;
+        free(current);
+    }
 }
 
 int fdinfo_close(struct fdinfo *fdn)
diff -up nmap-6.40/ncat/ncat_core.h.allresolve nmap-6.40/ncat/ncat_core.h
--- nmap-6.40/ncat/ncat_core.h.allresolve	2013-07-29 00:08:48.000000000 +0200
+++ nmap-6.40/ncat/ncat_core.h	2015-07-07 09:47:11.529409551 +0200
@@ -130,14 +130,20 @@
    a IPV4 INADDR_ANY and a IPV6 in6addr_any at most or a user defined address */
 #define NUM_LISTEN_ADDRS 2
 
+/* Structure to store a linked list of resolved addresses. */
+struct sockaddr_list {
+    union sockaddr_u addr;
+    size_t addrlen;
+    struct sockaddr_list* next;
+};
+
 extern union sockaddr_u listenaddrs[NUM_LISTEN_ADDRS];
 extern int num_listenaddrs;
 
 extern union sockaddr_u srcaddr;
 extern size_t srcaddrlen;
 
-extern union sockaddr_u targetss;
-extern size_t targetsslen;
+extern struct sockaddr_list *targetaddrs;
 
 extern union sockaddr_u httpconnect, socksconnect;
 extern size_t httpconnectlen, socksconnectlen;
@@ -223,6 +229,14 @@ void options_init(void);
 int resolve(const char *hostname, unsigned short port,
             struct sockaddr_storage *ss, size_t *sslen, int af);
 
+/* Resolves the given hostname or IP address with getaddrinfo, and stores
+   all results into a linked list.
+   The rest of behavior is same as resolve(). */
+int resolve_multi(const char *hostname, unsigned short port,
+        struct sockaddr_list *sl, int af);
+
+void free_sockaddr_list(struct sockaddr_list *sl);
+
 int fdinfo_close(struct fdinfo *fdn);
 int fdinfo_recv(struct fdinfo *fdn, char *buf, size_t size);
 int fdinfo_send(struct fdinfo *fdn, const char *buf, size_t size);
diff -up nmap-6.40/ncat/ncat_main.c.allresolve nmap-6.40/ncat/ncat_main.c
--- nmap-6.40/ncat/ncat_main.c.allresolve	2015-07-07 09:47:11.519409609 +0200
+++ nmap-6.40/ncat/ncat_main.c	2015-07-07 09:50:12.924358800 +0200
@@ -648,15 +648,17 @@ int main(int argc, char *argv[])
     }
 #endif  /* HAVE_SYS_UN_H */
 
+    targetaddrs = (struct sockaddr_list *)safe_zalloc(sizeof(struct sockaddr_list));
+
     /* Will be AF_INET or AF_INET6 or AF_UNIX when valid */
-    memset(&targetss.storage, 0, sizeof(targetss.storage));
-    targetss.storage.ss_family = AF_UNSPEC;
-    httpconnect.storage = socksconnect.storage = srcaddr.storage = targetss.storage;
+    memset(&srcaddr.storage, 0, sizeof(srcaddr.storage));
+    srcaddr.storage.ss_family = AF_UNSPEC;
+    targetaddrs->addr.storage = httpconnect.storage = socksconnect.storage = srcaddr.storage;
 
     /* Clear the listenaddrs array */
     int i;
     for (i = 0; i < NUM_LISTEN_ADDRS; i++) {
-        listenaddrs[i].storage = targetss.storage;
+        listenaddrs[i].storage = srcaddr.storage;
     }
 
     if (proxyaddr) {
@@ -739,10 +741,10 @@ int main(int argc, char *argv[])
     } else {
 #if HAVE_SYS_UN_H
         if (o.af == AF_UNIX) {
-            memset(&targetss.storage, 0, sizeof(struct sockaddr_un));
-            targetss.un.sun_family = AF_UNIX;
-            strncpy(targetss.un.sun_path, argv[optind], sizeof(targetss.un.sun_path));
-            targetsslen = SUN_LEN(&targetss.un);
+            memset(&targetaddrs->addr.storage, 0, sizeof(struct sockaddr_un));
+            targetaddrs->addr.un.sun_family = AF_UNIX;
+            strncpy(targetaddrs->addr.un.sun_path, argv[optind], sizeof(targetaddrs->addr.un.sun_path));
+            targetaddrs->addrlen = SUN_LEN(&targetaddrs->addr.un);
             o.target = argv[optind];
             optind++;
         } else
@@ -753,7 +755,7 @@ int main(int argc, char *argv[])
 
             o.target = argv[optind];
             /* resolve hostname */
-            rc = resolve(o.target, 0, &targetss.storage, &targetsslen, o.af);
+            rc = resolve_multi(o.target, 0, targetaddrs, o.af);
             if (rc != 0)
                 bye("Could not resolve hostname \"%s\": %s.", o.target, gai_strerror(rc));
             optind++;
@@ -789,21 +791,26 @@ int main(int argc, char *argv[])
         o.portno = (unsigned short) long_port;
     }
 
-    if (targetss.storage.ss_family == AF_INET)
-        targetss.in.sin_port = htons(o.portno);
+    struct sockaddr_list *targetaddrs_item = targetaddrs;
+    while (targetaddrs_item != NULL)
+    {
+        if (targetaddrs_item->addr.storage.ss_family == AF_INET)
+            targetaddrs_item->addr.in.sin_port = htons(o.portno);
 #ifdef HAVE_IPV6
-    else if (targetss.storage.ss_family == AF_INET6)
-        targetss.in6.sin6_port = htons(o.portno);
+        else if (targetaddrs_item->addr.storage.ss_family == AF_INET6)
+            targetaddrs_item->addr.in6.sin6_port = htons(o.portno);
 #endif
 #if HAVE_SYS_UN_H
-    /* If we use Unix domain sockets, we have to count with them. */
-    else if (targetss.storage.ss_family == AF_UNIX)
-        ; /* Do nothing. */
+        /* If we use Unix domain sockets, we have to count with them. */
+        else if (targetaddrs_item->addr.storage.ss_family == AF_UNIX)
+            ; /* Do nothing. */
 #endif
-    else if (targetss.storage.ss_family == AF_UNSPEC)
-        ; /* Leave unspecified. */
-    else
-        bye("Unknown address family %d.", targetss.storage.ss_family);
+        else if (targetaddrs_item->addr.storage.ss_family == AF_UNSPEC)
+            ; /* Leave unspecified. */
+        else
+            bye("Unknown address family %d.", targetaddrs_item->addr.storage.ss_family);
+        targetaddrs_item = targetaddrs_item->next;
+    }
 
     if (srcport != -1) {
         if (o.listen) {
@@ -815,7 +822,7 @@ int main(int argc, char *argv[])
                 /* We have a source port but not an explicit source address;
                    fill in an unspecified address of the same family as the
                    target. */
-                srcaddr.storage.ss_family = targetss.storage.ss_family;
+                srcaddr.storage.ss_family = targetaddrs->addr.storage.ss_family;
                 if (srcaddr.storage.ss_family == AF_INET)
                     srcaddr.in.sin_addr.s_addr = INADDR_ANY;
                 else if (srcaddr.storage.ss_family == AF_INET6)
@@ -834,17 +841,17 @@ int main(int argc, char *argv[])
      * need to reverse these address structures to avoid any further confusion
      */
     if (httpconnect.storage.ss_family != AF_UNSPEC) {
-        union sockaddr_u tmp = targetss;
-        size_t tmplen = targetsslen;
-        targetss = httpconnect;
-        targetsslen = httpconnectlen;
+        union sockaddr_u tmp = targetaddrs->addr;
+        size_t tmplen = targetaddrs->addrlen;
+        targetaddrs->addr = httpconnect;
+        targetaddrs->addrlen = httpconnectlen;
         httpconnect = tmp;
         httpconnectlen = tmplen;
     } else if (socksconnect.storage.ss_family != AF_UNSPEC) {
-        union sockaddr_u tmp = targetss;
-        size_t tmplen = targetsslen;
-        targetss = socksconnect;
-        targetsslen = socksconnectlen;
+        union sockaddr_u tmp = targetaddrs->addr;
+        size_t tmplen = targetaddrs->addrlen;
+        targetaddrs->addr = socksconnect;
+        targetaddrs->addrlen = socksconnectlen;
         socksconnect = tmp;
         socksconnectlen = tmplen;
     }
@@ -926,8 +933,8 @@ static int ncat_listen_mode(void)
         bye("/bin/sh is not executable, so `-c' won't work.");
 #endif
 
-    if (targetss.storage.ss_family != AF_UNSPEC) {
-        listenaddrs[num_listenaddrs++] = targetss;
+    if (targetaddrs->addr.storage.ss_family != AF_UNSPEC) {
+        listenaddrs[num_listenaddrs++] = targetaddrs->addr;
     } else {
         size_t ss_len;
         int rc;
diff -up nmap-6.40/ncat/util.c.allresolve nmap-6.40/ncat/util.c
--- nmap-6.40/ncat/util.c.allresolve	2013-07-29 00:08:48.000000000 +0200
+++ nmap-6.40/ncat/util.c	2015-07-07 09:47:11.530409546 +0200
@@ -470,7 +470,7 @@ int do_connect(int type)
     /* We need a socket that can be inherited by child processes in
        ncat_exec_win.c, for --exec and --sh-exec. inheritable_socket is from
        nbase. */
-    sock = inheritable_socket(targetss.storage.ss_family, type, 0);
+    sock = inheritable_socket(targetaddrs->addr.storage.ss_family, type, 0);
 
     if (srcaddr.storage.ss_family != AF_UNSPEC) {
         size_t sa_len;
@@ -487,7 +487,7 @@ int do_connect(int type)
     }
 
     if (sock != -1) {
-        if (connect(sock, &targetss.sockaddr, (int) targetsslen) != -1)
+        if (connect(sock, &targetaddrs->addr.sockaddr, (int) targetaddrs->addrlen) != -1)
             return sock;
         else if (socket_errno() == EINPROGRESS || socket_errno() == EAGAIN)
             return sock;