Nmap Development mailing list archives

speed problems on freebsd, including patch


From: Guido van Rooij <guido () gvr org>
Date: Wed, 29 Sep 2010 21:35:09 +0200

I was tracking severe nmap performance problems on FreeBSD and noticed
a number of issues.

First of all, I notice that select() is used on the pcap filedescriptor,
before calling pcap_next(). On Linux this works, as a read on
the bpf device will allways return one packet. On BSD's, such
a read ny pcap might return more packets. These are stuck inside libpcap,
so a select() will not wakeup, even while there are packets waiting
in the libpcap internal buffers.
I read in the pcap source:
         * On the other hand, some platforms (e.g., Linux) don't support
         * timeouts, they just hand stuff to you as soon as it arrives;
         * if that doesn't cause a problem on those platforms, it may
         * be OK to have BIOCIMMEDIATE mode on BSD as well.
So for Linux, the select() seems necessary (for the timeout).

Another issue:
At least for FreeBSD 8, the BIOCIMMEDIATE is necessary:
Without BIOCIMMEDIATE (and without select):
  beck# ./nmap -rnv -sS -p1-2000 127.0.0.1

  Starting Nmap 5.35DC1 ( http://nmap.org ) at 2010-09-29 18:46 CEST
  Warning: File ./nmap-services exists, but Nmap is using /usr/local/share/nmap/nmap-services for security and 
consistency reasons.  set NMAPDIR=. to give priority to files in your local directory (may affect the other data files 
too).
  Initiating SYN Stealth Scan at 18:46
  Scanning 127.0.0.1 [2000 ports]
  Discovered open port 53/tcp on 127.0.0.1
  Discovered open port 631/tcp on 127.0.0.1
  Discovered open port 953/tcp on 127.0.0.1
  Discovered open port 1241/tcp on 127.0.0.1
  Completed SYN Stealth Scan at 18:46, 9.61s elapsed (2000 total ports)
  Nmap scan report for 127.0.0.1
  Host is up (0.0000090s latency).
  Not shown: 1996 closed ports
  PORT     STATE SERVICE
  53/tcp   open  domain
  631/tcp  open  ipp
  953/tcp  open  rndc
  1241/tcp open  nessus
  
  Read from .: nmap-payloads.
  Read from /usr/local/share/nmap: nmap-services.
  Nmap done: 1 IP address (1 host up) scanned in 9.65 seconds
           Raw packets sent: 2000 (88.000KB) | Rcvd: 4004 (168.176KB)

With BIOCIMMEDIATE (and withou select):
  beck# ./nmap -rnv -sS -p1-2000 127.0.0.1

  Starting Nmap 5.35DC1 ( http://nmap.org ) at 2010-09-29 18:47 CEST
  Warning: File ./nmap-services exists, but Nmap is using /usr/local/share/nmap/nmap-services for security and 
consistency reasons.  set NMAPDIR=. to give priority to files in your local directory (may affect the other data files 
too).
  Initiating SYN Stealth Scan at 18:47
  Scanning 127.0.0.1 [2000 ports]
  Discovered open port 53/tcp on 127.0.0.1
  Discovered open port 631/tcp on 127.0.0.1
  Discovered open port 953/tcp on 127.0.0.1
  Discovered open port 1241/tcp on 127.0.0.1
  Completed SYN Stealth Scan at 18:47, 0.05s elapsed (2000 total ports)
  Nmap scan report for 127.0.0.1
  Host is up (0.0000080s latency).
  Not shown: 1996 closed ports
  PORT     STATE SERVICE
  53/tcp   open  domain
  631/tcp  open  ipp
  953/tcp  open  rndc
  1241/tcp open  nessus

  Read from .: nmap-payloads.
  Read from /usr/local/share/nmap: nmap-services.
  Nmap done: 1 IP address (1 host up) scanned in 0.09 seconds
           Raw packets sent: 2000 (88.000KB) | Rcvd: 4004 (168.176KB)

Thus a speedup of a factor 100.

In the pcap source one can also read:
         * Setting BIOCIMMEDIATE mode on FreeBSD (and probably other
         * BSDs) causes the timeout to be ignored.
However this is not true (anymore probably) at (verifed it with a
simple test-program.
From the look at the CVS-tree, this is at least the case since FreeBSD5.

So I propose the following patch:
--- netutil.cc  2010-07-14 07:43:19.000000000 +0200
+++ /tmp/netutil.cc     2010-09-29 21:24:30.000000000 +0200
@@ -631,6 +631,17 @@
 #if defined(WIN32) || defined(MACOSX) || (defined(FREEBSD) && (__FreeBSD_version < 500000))
   return -1;
 #else
+  #if defined(FREEBSD)
+    int fd;
+    if ((fd = pcap_get_selectable_fd(p)) == -1) {
+      return -1;
+    }
+    int on=1;
+    if (ioctl(fd, BIOCIMMEDIATE, &on) <0) {
+      netutil_error("%s: %s", __func__, strerror(errno));
+    }
+    return -1;
+  #endif
   assert(pcap_selectable_fd_valid());
   return pcap_get_selectable_fd(p);
 #endif


Hope this helps,

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


Current thread: