Nmap Development mailing list archives

[PATCH] Shortening scan time with SO_DONTROUTE


From: Kris Katterjohn <katterjohn () gmail com>
Date: Thu, 01 Jan 2009 02:10:50 -0600

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hey guys,

I got an idea flipping through UNP which I thought might be beneficial to
Nmap: setting SO_DONTROUTE on the raw sending socket when we're sending to
hosts that are directly connected (a very common situation I'm sure).  There
is the following comment and behavior in targets.cc which says that setting
this on the socket shouldn't cause any problems as opposed to having to set
MSG_DONTROUTE separately for each packet:

/* In some cases, we can only allow hosts that use the same
   device in a group.  Similarly, we don't mix
   directly-connected boxes with those that aren't */

While my tests unfortunately can't be foolproof, I've done scans varying in
the number of ports scanned and with different timing options.  Most of the
time I've been using a Ruby script to run the different Nmaps several times
(with delays between each run) and average out the times (which I had to hack
into the XML since accurate times aren't available from what I can see).  So
while one scan can skew the results, the Nmap that utilizes SO_DONTROUTE wins
the vast majority of the time for me with averaged results and not.  While the
"win" isn't dramatic, a lot of my scans lasted less than five seconds (many
thousand ports) and the DONTROUTE version tends to improve at least 1/5 second
and sometimes more than 1/2 second better both averaged and standalone.

I tried to do many tests with equal environments, but like I said I can't make
it anywhere near perfect in my situation.  Any testing is encouraged and much
appreciated.

So is there any reason not to put this in?  This doesn't fall in line with the
big improvements David's been making in his -perf branch, but this certainly
seems to help.

I've attached a patch for the SO_DONTROUTE changes, and one for adding the
probably misplaced/misnamed XML attribute for the scan time.  I would've
attached my Ruby script, but it would've been far more trouble than it's worth
since it uses a hacked version of my Nmap::Parser, etc, etc.

Thanks,
Kris Katterjohn

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iQIcBAEBAgAGBQJJXHqFAAoJEEQxgFs5kUfuY2cP/RfUt9vATsEgdR90ZzuFzszC
UGNhajAHnygoD7XnvOaPhqEaJnlU2rJXbP20wr3BuMb8LNAV34JNXi8zCZGmRrhL
ploUCrGQphsyoxrIMSCb/i294YJzJx8WVCCq8V0+cw3G+spg5jvpRp8NP+YZZNd+
aBla7nw88v2sqbVau31jqXyuT3PN7QyxnhPK/uKpj/tssuTu8OpUmr8pSe8ei4D+
niQmG61pKxHuKZUWKJFk4jVDuLCWoulW73vKfAyS6Nxd4TzdGhAAxRA1eo0pyAKc
pYL2CP9VTMS6lwbMBdxNcxWLeyroorMleF2auk3/rZG/yp9LjakKuFieKkerloDF
s6QmskiHYlFSVhmuxv+uuIr6Kmc6cq5o0Og5tkGoS7rNOZFUeN5njQundrPN1awy
3wGJS059Alf89Np+IxgblAtJ2BfOzyMfQeViug0mCDxREHnp8BUpPPrJzKsvMOgc
BmSxCasiyoEVNWS3HJ93sy0xgSd1no8/w11a4I3D2ttj1USdd/LmPXPS4eXQHKef
7XT5/mzg6oRPS2IZZvW113BZvaGQRziZFWj2DD5gpSrmIN1aPLJRWt9HRya8ObxS
dtePnTGHLbOumw6syuwUrX6jRgr74WjLrFsOIdlkfQpjqqutLHgna/Xcddjr6Pl3
P3LYC1wxknrDjrmZS2yC
=sbNP
-----END PGP SIGNATURE-----
Index: tcpip.cc
===================================================================
--- tcpip.cc    (revision 11589)
+++ tcpip.cc    (working copy)
@@ -181,6 +181,18 @@
 #endif
 }
 
+void setdontroute(int sd)
+{
+#ifdef SO_DONTROUTE
+       int one = 1;
+
+       if (sd == -1)
+               return;
+
+       setsockopt(sd, SOL_SOCKET, SO_DONTROUTE, (const char *) &one, sizeof one);
+#endif
+}
+
 // Takes a protocol number like IPPROTO_TCP, IPPROTO_UDP, or
 // IPPROTO_IP and returns a ascii representation (or "unknown" if it
 // doesn't recognize the number).  If uppercase is true, the returned
Index: tcpip.h
===================================================================
--- tcpip.h     (revision 11589)
+++ tcpip.h     (working copy)
@@ -667,6 +667,8 @@
 
 void set_ttl(int sd, int ttl);
 
+void setdontroute(int sd);
+
 /* Fill buf (up to buflen -- truncate if necessary but always
    terminate) with a short representation of the packet stats.
    Returns buf.  Aborts if there is a problem. */
Index: scan_engine.cc
===================================================================
--- scan_engine.cc      (revision 11589)
+++ scan_engine.cc      (working copy)
@@ -1551,6 +1551,11 @@
 #ifndef WIN32
       sethdrinclude(rawsd); 
 #endif
+      /* If these hosts are directly connected, tell the kernel not
+       * to bother routing these packets (seems to save some time)
+       */
+      if (Targets[0]->directlyConnected())
+        setdontroute(rawsd);
       ethsd = NULL;
     }
   }
Index: output.cc
===================================================================
--- output.cc   (revision 11589)
+++ output.cc   (working copy)
@@ -1957,7 +1957,7 @@
   Strncpy(mytime, ctime(&timep), sizeof(mytime));
   chomp(mytime);
   
-  log_write(LOG_XML, "<runstats><finished time=\"%lu\" timestr=\"%s\"/><hosts up=\"%d\" down=\"%d\" total=\"%d\" 
/>\n", (unsigned long) timep, mytime, o.numhosts_up, o.numhosts_scanned - o.numhosts_up, o.numhosts_scanned);
+  log_write(LOG_XML, "<runstats><finished time=\"%lu\" timestr=\"%s\" total=\"%.2f\"/><hosts up=\"%d\" down=\"%d\" 
total=\"%d\" />\n", (unsigned long) timep, mytime, o.TimeSinceStartMS(&tv) / 1000.0, o.numhosts_up, o.numhosts_scanned 
- o.numhosts_up, o.numhosts_scanned);
 
   log_write(LOG_XML, "<!-- Nmap done at %s; %d %s (%d %s up) scanned in %.2f seconds -->\n", mytime, 
o.numhosts_scanned, (o.numhosts_scanned == 1)? "IP address" : "IP addresses", o.numhosts_up, (o.numhosts_up == 1)? 
"host" : "hosts",  o.TimeSinceStartMS(&tv) / 1000.0 );
   log_write(LOG_NORMAL|LOG_MACHINE, "# Nmap done at %s -- %d %s (%d %s up) scanned in %.2f seconds\n", mytime, 
o.numhosts_scanned, (o.numhosts_scanned == 1)? "IP address" : "IP addresses", o.numhosts_up, (o.numhosts_up == 1)? 
"host" : "hosts", o.TimeSinceStartMS(&tv) / 1000.0 );

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

Current thread: