Nmap Development mailing list archives

Re: Errors with -sV and -PE using IPv6


From: Kris Katterjohn <katterjohn () gmail com>
Date: Sun, 13 Jan 2008 01:05:42 -0600

Fyodor wrote:
On Wed, Jan 09, 2008 at 12:49:58PM -0500, Will Cladek wrote:
After breaking out my rusty programming skills, I figured out what was causing the seg fault with the -sV option in IPv6.  
It's the following code in scan_engine.cc, starting at line 5101, and then the same code again at 5129:

Thanks for your research!  As you note, the right way to fix this is
to fix send_rpc_query() to handle IPv6 addresses.  It shouldn't be too
hard, since it isn't generating raw packets and Nmap already has the
code to handle TCP and UDP communication over IPv6.  Anyone want to
give it a try?  We support IPv6 for the rest of version detection, so
we should do so for RPC scan, unless there is some major difficulty
with doing so.


Hey Fyodor!

I've attached a patch which adds this. I must warn that, while the IPv6 code I've added has compiled fine for me, I haven't tested that the actual connect() and things work properly for IPv6 as I don't have a portmap that supports it.

I /have/ tested it using TCP and UDP over IPv4 on my system, and it gives the same results as before the patch. Since the code is pretty much the same between IPv4 and IPv6, I'm betting that it will work fine as well.

I'd appreciate anybody testing this (IPv4 and IPv6) and letting me know how it goes.

Cheers,
-F


Thanks,
Kris Katterjohn
Index: nmap_rpc.cc
===================================================================
--- nmap_rpc.cc (revision 6686)
+++ nmap_rpc.cc (working copy)
@@ -212,13 +212,17 @@
 /* Send an RPC query to the specified host/port on the specified protocol
    looking for the specified RPC program.  We cache our sending sockets
    to avoid recreating and (with TCP) reconnect()'ing them each time */
-int send_rpc_query(const struct in_addr *target_host, unsigned short portno,
+int send_rpc_query(Target *target_host, unsigned short portno,
                   int ipproto, unsigned long program, int scan_offset, 
                   int trynum) {
-  static struct in_addr last_target_host;
+  static struct sockaddr_storage last_target;
+  struct sockaddr_storage sock;
+  size_t socklen;
   static int last_ipproto = -1;
-  static unsigned short last_portno = 0; 
-  struct sockaddr_in sock;
+  struct sockaddr_in *sin = NULL, *lastsin = NULL;
+#ifdef HAVE_IPV6
+  struct sockaddr_in6 *sin6 = NULL, *lastsin6 = NULL;
+#endif
   char rpch_buf[256]; 
   struct rpc_hdr *rpch;
   int res, err = 0;
@@ -238,38 +242,57 @@
     log_write(LOG_PLAIN, "Sending RPC probe for program %li to %hu/%s -- scan_offset=%d trynum=%d xid=%lX\n", program, 
portno, proto2ascii(ipproto), scan_offset, trynum, rpc_xid_base + ((portno & 0x3FFF) << 16) + (trynum << 30) +  
scan_offset);
   }
 
+  memset(&sock, 0, sizeof(sock));
+  target_host->TargetSockAddr(&sock, &socklen);
+
+  if (sock.ss_family == AF_INET) {
+    sin = (struct sockaddr_in *) &sock;
+    lastsin = (struct sockaddr_in *) &last_target;
+
+    sin->sin_port = htons(portno);
+  }
+#ifdef HAVE_IPV6
+  else {
+    sin6 = (struct sockaddr_in6 *) &sock;
+    lastsin6 = (struct sockaddr_in6 *) &last_target;
+
+    sin6->sin6_port = htons(portno);
+  }
+#endif
+
   /* First we check whether we have to create a new connection -- we 
      need to if we have a new target_host, or a new portno, or the socket
      we want to use is -1 */
-  if (ipproto == IPPROTO_TCP && 
-      (last_target_host.s_addr != target_host->s_addr ||
-       last_portno != portno || last_ipproto != IPPROTO_TCP)) {
-    /* New host or port -- kill our old tcp socket */
-    if (tcp_rpc_socket != -1) {
-      close(tcp_rpc_socket);
-      tcp_rpc_socket = -1;
-      tcp_readlen = 0;
+  if (ipproto == IPPROTO_TCP) {
+    if ((sock.ss_family == AF_INET &&
+         memcmp(sin, lastsin, sizeof(struct sockaddr_in)))
+#ifdef HAVE_IPV6
+     || (sock.ss_family == AF_INET6 &&
+         memcmp(sin6, lastsin6, sizeof(struct sockaddr_in6)))
+#endif
+     || last_ipproto != IPPROTO_TCP) {
+      /* New host or port -- kill our old tcp socket */
+      if (tcp_rpc_socket != -1) {
+        close(tcp_rpc_socket);
+        tcp_rpc_socket = -1;
+        tcp_readlen = 0;
+      }
     }
   }
+  
+  last_target = sock;
   last_ipproto = ipproto;
-  last_target_host.s_addr = target_host->s_addr;
-  last_portno = portno;
-  
-  memset(&sock, 0, sizeof(sock));
-  sock.sin_family = AF_INET;
-  sock.sin_addr.s_addr = target_host->s_addr;
-  sock.sin_port = htons(portno);
-    
+
   if (ipproto == IPPROTO_TCP && tcp_rpc_socket == -1) {
-    if ((tcp_rpc_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
+    if ((tcp_rpc_socket = socket(sock.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
       pfatal("Socket troubles in %s", __func__);
     /* I should unblock the socket here and timeout the connect() */
     res = connect(tcp_rpc_socket, (struct sockaddr *) &sock, 
-                 sizeof(struct sockaddr_in));
+                 sizeof(struct sockaddr_storage));
     if (res == -1) {
       if (o.debugging) {
        gh_perror("Failed to connect to port %d of %s in %s",
-                 portno, inet_ntoa(*target_host), __func__);
+                 portno, target_host->targetipstr(), __func__);
       }
       close(tcp_rpc_socket);
       tcp_rpc_socket = -1;
@@ -277,7 +300,7 @@
     }
     unblock_socket(tcp_rpc_socket);
   } else if (ipproto == IPPROTO_UDP && udp_rpc_socket == -1) {
-    if ((udp_rpc_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+    if ((udp_rpc_socket = socket(sock.ss_family, SOCK_DGRAM, 0)) == -1)
       pfatal("UDP socket troubles in %s", __func__);
     unblock_socket(udp_rpc_socket);
   }
@@ -306,7 +329,7 @@
       if (o.debugging > 1)
        hdump((unsigned char *) rpch, sizeof(struct rpc_hdr));
       res = sendto(udp_rpc_socket, (char *)rpch, sizeof(struct rpc_hdr), 0,
-                  (struct sockaddr *) &sock, sizeof(struct sockaddr_in));
+                  (struct sockaddr *) &sock, sizeof(struct sockaddr_storage));
       if (res == -1)
        err = socket_errno();
      } while(res == -1 && (err == EINTR || err == ENOBUFS));
Index: nmap_rpc.h
===================================================================
--- nmap_rpc.h  (revision 6686)
+++ nmap_rpc.h  (working copy)
@@ -176,7 +176,7 @@
 
 int get_rpc_procs(unsigned long **programs, unsigned long *num_programs);
 char *nmap_getrpcnamebynum(unsigned long num);
-int send_rpc_query(const struct in_addr *target_host, unsigned short portno,
+int send_rpc_query(Target *target_host, unsigned short portno,
                   int ipproto, unsigned long program, int scan_offset, 
                   int trynum);
 void get_rpc_results(Target *target, struct portinfo *scan,
Index: scan_engine.cc
===================================================================
--- scan_engine.cc      (revision 6686)
+++ scan_engine.cc      (working copy)
@@ -5098,7 +5098,7 @@
                current->trynum++;
                gettimeofday(&current->sent[current->trynum], NULL);
                now = current->sent[current->trynum];
-               if (send_rpc_query(target->v4hostip(), rsi.rpc_current_port->portno,
+               if (send_rpc_query(target, rsi.rpc_current_port->portno,
                                   rsi.rpc_current_port->proto, 
                                   current->portno, current - scan, 
                                   current->trynum) == -1) {
@@ -5126,7 +5126,7 @@
            /*  if (!testinglist) testinglist = current; */
            ss.numqueries_outstanding++;
            gettimeofday(&current->sent[0], NULL);
-           if (send_rpc_query(target->v4hostip(), 
+           if (send_rpc_query(target, 
                               rsi.rpc_current_port->portno,
                               rsi.rpc_current_port->proto, current->portno,
                               current - scan, current->trynum) == -1) {

_______________________________________________
Sent through the nmap-dev mailing list
http://cgi.insecure.org/mailman/listinfo/nmap-dev
Archived at http://SecLists.Org

Current thread: