Nmap Development mailing list archives

Re: [PATCH] New output format (-oP): Pcap savefile


From: Barry Myles <nmap () smyles plus com>
Date: Tue, 01 Jan 2008 22:19:00 +0000

Kris Katterjohn wrote:
1) It only handles raw IP packets, no ARP or connect() calls. Connect() doesn't work for obvious reasons. ARP doesn't work because the savefile must be set up initially with a DLT type, and we can't switch between the two different protocols with it. There's no "catch-all" type that I see that works like Nmap does. ARP is only used for pinging on a local network, so this isn't a huge downside. Any ideas on this is appreciated.
I've been lurking for a while, but this patch prompted me to dust off my rather rusty C and make a little enhancement to this. By changing the pcap encapsulation type from DLT_RAW to DLT_LINUX_SLL it should be possible to put both types of packets in the same capture file. DLT_LINUX_SLL is the encapsulation used when capturing on a linux special device like 'any' but is just a packet encapsulation format so should be usable on any platform.

This still doesn't deal with connect() type scans though. Perhaps this option should throw an error if an attempt is made to combine the two?

Should we also consider putting DNS packets in the pcap file if --system-dns is not specified?

The attached patch implements the change of encapsulation and there's an example capture attached showing both ARP and IP.

--
Barry Myles
Index: nmap.cc
===================================================================
--- nmap.cc     (revision 6662)
+++ nmap.cc     (working copy)
@@ -290,8 +290,8 @@
        "  --spoof-mac <mac address/prefix/vendor name>: Spoof your MAC address\n"
        "  --badsum: Send packets with a bogus TCP/UDP checksum\n"
        "OUTPUT:\n"
-       "  -oN/-oX/-oS/-oG <file>: Output scan in normal, XML, s|<rIpt kIddi3,\n"
-       "     and Grepable format, respectively, to the given filename.\n"
+       "  -oN/-oX/-oS/-oG/-oP <file>: Output scan in normal, XML, s|<rIpt kIddi3,\n"
+       "     Grepable, and Pcap format, respectively, to the given filename.\n"
        "  -oA <basename>: Output in the three major formats at once\n"
        "  -v: Increase verbosity level (use twice for more effect)\n"
        "  -d[level]: Set or increase debugging level (Up to 9 is meaningful)\n"
@@ -471,7 +471,7 @@
   char *idleProxy = NULL; /* The idle host used to "Proxy" an idle scan */
   int num_host_exp_groups;
   char *machinefilename = NULL, *kiddiefilename = NULL, 
-    *normalfilename = NULL, *xmlfilename = NULL;
+    *normalfilename = NULL, *xmlfilename = NULL, *pcapfilename = NULL;
   time_t now;
   struct tm *tm;
   HostGroupState *hstate = NULL;
@@ -563,6 +563,7 @@
       {"oS", required_argument, 0, 0},
       {"oH", required_argument, 0, 0},  
       {"oX", required_argument, 0, 0},  
+      {"oP", required_argument, 0, 0},  
       {"iL", required_argument, 0, 'i'},  
       {"iR", required_argument, 0, 0},
       {"sI", required_argument, 0, 0},  
@@ -831,6 +832,8 @@
        fatal("HTML output is not directly supported, though Nmap includes an XSL for transforming XML output into 
HTML.  See the man page.");
       } else if (strcmp(long_options[option_index].name, "oX") == 0) {
        xmlfilename = logfilename(optarg, tm);
+      } else if (strcmp(long_options[option_index].name, "oP") == 0) {
+       pcapfilename = logfilename(optarg, tm);
       } else if (strcmp(long_options[option_index].name, "oA") == 0) {
        char buf[MAXPATHLEN];
        Snprintf(buf, sizeof(buf), "%s.nmap", logfilename(optarg, tm));
@@ -1246,6 +1249,11 @@
     log_open(LOG_SKID, o.append_output, kiddiefilename);
   if (xmlfilename)
     log_open(LOG_XML, o.append_output, xmlfilename);
+  if (pcapfilename) {
+    o.pcaplogfd = pcap_open_dead(DLT_LINUX_SLL, 1500);
+    if (!(o.pcaplog = pcap_dump_open(o.pcaplogfd, pcapfilename)))
+      fatal("Failed to open pcap savefile %s for writing", pcapfilename);
+  }
 
   if (!o.interactivemode) {
     char tbuf[128];
@@ -2624,6 +2632,11 @@
 
   fflush(stderr);
   log_close(LOG_MACHINE|LOG_NORMAL|LOG_SKID);
+  if (o.pcaplog) {
+    pcap_dump_flush(o.pcaplog);
+    pcap_dump_close(o.pcaplog);
+    pcap_close(o.pcaplogfd);
+  }
   if (abt) abort();
   exit(1);
 }
Index: NmapOps.cc
===================================================================
--- NmapOps.cc  (revision 6662)
+++ NmapOps.cc  (working copy)
@@ -242,6 +242,8 @@
   maimonscan = idlescan = finscan = udpscan = ipprotscan = noresolve = 0;
   append_output = 0;
   memset(logfd, 0, sizeof(FILE *) * LOG_NUM_FILES);
+  pcaplogfd = NULL;
+  pcaplog = NULL;
   ttl = -1;
   badsum = 0;
   nmap_stdout = stdout;
Index: tcpip.cc
===================================================================
--- tcpip.cc    (revision 6662)
+++ tcpip.cc    (working copy)
@@ -1353,6 +1353,9 @@
 
  PacketTrace::trace(PacketTrace::SENT, packet, len); 
 
+ if (o.pcaplog)
+   log_pcap(NULL, (u_char *) packet, len, 4, 0x0800);
+
 return res;
 }
 
@@ -1386,6 +1389,8 @@
     } else ethsd = eth->ethsd;
     res = eth_send(ethsd, eth_frame, 14 + packetlen);
     PacketTrace::trace(PacketTrace::SENT, packet, packetlen); 
+    if (o.pcaplog)
+      log_pcap(NULL, (u_char *) packet, packetlen, 4, 0x0800);
     /* No need to close ethsd due to caching */
     free(eth_frame);
     eth_frame = NULL;
@@ -2062,6 +2067,9 @@
    PacketTrace::trace(PacketTrace::RCVD, (u8 *) alignedbuf, *len, rcvdtime);
  else PacketTrace::trace(PacketTrace::RCVD, (u8 *) alignedbuf, *len);
 
+ if (o.pcaplog)
+   log_pcap(&head, (u_char *) alignedbuf, *len, 0, 0x0800);
+
  return alignedbuf;
 }
 
@@ -2277,6 +2285,9 @@
   }
   PacketTrace::traceArp(PacketTrace::RCVD, (u8 *) p, 42,  rcvdtime);
 
+  if(o.pcaplog)
+    log_pcap(&head, (u_char *)p+14, head.caplen-14, 0, 0x0806);
+
   return 1;
 }
 
@@ -2372,6 +2383,8 @@
       error("WARNING: %s: eth_send of ARP packet returned %u rather than expected %d bytes", __func__, rc, (int) 
sizeof(frame));
     }
     PacketTrace::traceArp(PacketTrace::SENT, (u8 *) frame, sizeof(frame), &now);
+    if(o.pcaplog)
+      log_pcap(NULL,(u_char *)frame,sizeof(frame),4,0x0806);
     num_sends++;
     
     listenrounds = 0;
Index: output.h
===================================================================
--- output.h    (revision 6662)
+++ output.h    (working copy)
@@ -124,6 +124,7 @@
 #include "portlist.h"
 #include "nmap.h"
 #include "global_structures.h"
+#include <pcap.h>
 
 /* Prints the familiar Nmap tabular output showing the "interesting"
    ports found on the machine.  It also handles the Machine/Greppable
@@ -169,6 +170,8 @@
    it already exists.  If the file does not exist, it will be created */
 int log_open(int logt, int append, char *filename);
 
+void log_pcap(struct pcap_pkthdr *, u_char *, int, u_int16_t, u_int16_t);
+
 /* Output the list of ports scanned to the top of machine parseable
    logs (in a comment, unfortunately).  The items in ports should be
    in sequential order for space savings and easier to read output */
Index: output.cc
===================================================================
--- output.cc   (revision 6662)
+++ output.cc   (working copy)
@@ -113,6 +113,7 @@
 #include "nmap_rpc.h"
 #include "Target.h"
 #include "utils.h"
+#include "libpcap/sll.h"
 
 #include <string>
 #include <vector>
@@ -1080,7 +1081,58 @@
   return 1;
 }
 
+/* Logs packet to pcap savefile.
+ *
+ * You can pass NULL for h: log_pcap will create a pcap_pkthdr based on the
+ * length and current time.  This is important for logging packets that are
+ * being sent.
+ *
+ * pkttype is the linux cooked packet type from libpcap/sll.h
+ *   LINUX_SLL_HOST=0 for incoming unicast.
+ *   LINUX_SLL_OUTGOING=4 for outgoing packets.
+ * len is the pkt length
+ * proto is the ethernet protocol [0x0800 for IPv4, 0x0806 for ARP]
+ */
+void log_pcap(struct pcap_pkthdr *h, u_char *pkt, int len, u_int16_t pkttype, u_int16_t proto)
+{
+  struct pcap_pkthdr th;
+  struct sll_header *sll;
 
+  if (!o.pcaplog)
+    return;
+
+  /* Add space for cooked header */
+  sll=(struct sll_header *)safe_zalloc(1024+len); /* Leave plenty of space for trailer too */
+  memcpy(sll+1,pkt,len);
+
+  /* Populate cooked header with data */
+  sll->sll_pkttype=htons(pkttype);
+  sll->sll_hatype=htons(1); /* Is a MAC address */
+  sll->sll_halen=htons(6);  /* and is 6 bytes long */
+  sll->sll_addr[0]=0; /* TODO: We may be able to put a proper MAC in here */
+  sll->sll_addr[1]=0; /*       rather than this dummy placeholder MAC     */
+  sll->sll_addr[2]=0; /*       address.                                   */
+  sll->sll_addr[3]=0;
+  sll->sll_addr[4]=0;
+  sll->sll_addr[5]=0;
+  sll->sll_protocol=htons(proto); /* Ethertype this packet would be if this was an ethernet frame */
+
+  if (!h) {
+    struct timeval tv;
+
+    h = &th;
+
+    gettimeofday(&tv, NULL);
+
+    th.ts = tv;
+    th.caplen = len+16;
+    th.len = len+16;
+}
+
+pcap_dump((u_char *) o.pcaplog, h, (u_char *)sll);
+free(sll);
+}
+
 /* The items in ports should be
    in sequential order for space savings and easier to read output.  Outputs
    the rangelist to the log stream given (such as LOG_MACHINE or LOG_XML) */
Index: scan_engine.cc
===================================================================
--- scan_engine.cc      (revision 6662)
+++ scan_engine.cc      (working copy)
@@ -2584,6 +2584,8 @@
     error("WARNING:  eth_send of ARP packet returned %i rather than expected %d (errno=%i: %s)", rc, (int) 
sizeof(frame), err, strerror(err));
   }
   PacketTrace::traceArp(PacketTrace::SENT, (u8 *) frame, sizeof(frame), &USI->now);
+  if(o.pcaplog)
+    log_pcap(NULL,(u_char *)frame+14,sizeof(frame)-14,4,0x0806);
   probe->tryno = tryno;
   probe->pingseq = pingseq;
   /* First build the probe */
Index: NmapOps.h
===================================================================
--- NmapOps.h   (revision 6662)
+++ NmapOps.h   (working copy)
@@ -102,6 +102,7 @@
 #include "nmap.h"
 #include "global_structures.h"
 #include "output.h"
+#include <pcap.h>
 #include <string>
 
 class NmapOps {
@@ -305,6 +306,8 @@
   int append_output; /* Append to any output files rather than overwrite */
   FILE *logfd[LOG_NUM_FILES];
   FILE *nmap_stdout; /* Nmap standard output */
+  pcap_t *pcaplogfd;
+  pcap_dumper_t *pcaplog;
   int ttl; // Time to live
   int badsum;
   char *datadir;

Attachment: test-2.pcap
Description:


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

Current thread: