Wireshark-dev: [Wireshark-dev] Adding support for pcap-ng to dumpcap or reading from pipes

From: Richard Sharpe <realrichardsharpe@xxxxxxxxx>
Date: Mon, 7 May 2012 08:24:10 -0700
Hi folks,

I am looking at adding support for pcap-ng to dumpcap.c so it can be
read directly from pipes.

Is anyone else working on this?

In any event, I have an initial patch that moves the relevant pcap
stuff into a separate structure, and it currently works, but it is a
bit ugly and does not yet handle pcap-ng. That is, I can still load a
multi-record pcap file via a pipe.

Does anyone have any feedback on the approach or concerns?

Index: dumpcap.c
===================================================================
--- dumpcap.c	(revision 42332)
+++ dumpcap.c	(working copy)
@@ -84,6 +84,7 @@
 #endif /* _WIN32 */

 #include "pcapio.h"
+#include "wtap.h"

 #ifdef _WIN32
 #include "capture-wpcap.h"
@@ -215,6 +216,29 @@
     INITFILTER_OTHER_ERROR
 } initfilter_status_t;

+/*
+ * Allow us to handle both pcap and pcapng records through a pipe
+ */
+typedef struct _pcap_pipe_info {
+    struct pcap_hdr cap_pipe_hdr;
+    struct pcaprec_modified_hdr cap_pipe_rechdr;
+    gboolean cap_pipe_modified;
+    enum {
+        PCAP_STATE_EXPECT_REC_HDR,
+        PCAP_STATE_READ_REC_HDR,
+        PCAP_STATE_EXPECT_DATA,
+        PCAP_STATE_READ_DATA
+    } cap_pipe_state;
+} pcap_pipe_info;
+
+typedef struct _pcapng_pipe_info {
+    struct wtap_pkthdr capng_pipe_hdr;
+    enum {
+        PCAPNG_STATE_EXPECT_SHB_REC,
+        PCAPNG_STATE_READ_SHB_REC
+    } capng_pipe_state;
+} pcapng_pipe_info;
+
 typedef struct _pcap_options {
     guint32        received;
     guint32        dropped;
@@ -230,26 +254,21 @@
     gboolean       ts_nsec;               /* TRUE if we're using
nanosecond precision. */
     /* capture pipe (unix only "input file") */
     gboolean       from_cap_pipe;         /* TRUE if we are capturing
data from a capture pipe */
-    struct pcap_hdr cap_pipe_hdr;         /* Pcap header when
capturing from a pipe */
-    struct pcaprec_modified_hdr cap_pipe_rechdr;  /* Pcap record
header when capturing from a pipe */
+    union {
+        pcap_pipe_info pcap;
+        pcapng_pipe_info pcapng;
+    } u;
 #ifdef _WIN32
     HANDLE         cap_pipe_h;            /* The handle of the capture pipe */
 #else
     int            cap_pipe_fd;           /* the file descriptor of
the capture pipe */
 #endif
-    gboolean       cap_pipe_modified;     /* TRUE if data in the pipe
uses modified pcap headers */
     gboolean       cap_pipe_byte_swapped; /* TRUE if data in the pipe
is byte swapped */
 #if defined(_WIN32)
     char *         cap_pipe_buf;          /* Pointer to the data
buffer we read into */
 #endif
     int            cap_pipe_bytes_to_read;/* Used by cap_pipe_dispatch */
     int            cap_pipe_bytes_read;   /* Used by cap_pipe_dispatch */
-    enum {
-        STATE_EXPECT_REC_HDR,
-        STATE_READ_REC_HDR,
-        STATE_EXPECT_DATA,
-        STATE_READ_DATA
-    } cap_pipe_state;
     enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err;
 #if defined(_WIN32)
     GMutex *cap_pipe_read_mtx;
@@ -1998,14 +2017,14 @@
         /* Host that wrote it has our byte order, and was running
            a program using either standard or ss990417 libpcap. */
         pcap_opts->cap_pipe_byte_swapped = FALSE;
-        pcap_opts->cap_pipe_modified = FALSE;
+        pcap_opts->u.pcap.cap_pipe_modified = FALSE;
         pcap_opts->ts_nsec = magic == PCAP_NSEC_MAGIC;
         break;
     case PCAP_MODIFIED_MAGIC:
         /* Host that wrote it has our byte order, but was running
            a program using either ss990915 or ss991029 libpcap. */
         pcap_opts->cap_pipe_byte_swapped = FALSE;
-        pcap_opts->cap_pipe_modified = TRUE;
+        pcap_opts->u.pcap.cap_pipe_modified = TRUE;
         break;
     case PCAP_SWAPPED_MAGIC:
     case PCAP_SWAPPED_NSEC_MAGIC:
@@ -2013,7 +2032,7 @@
            and was running a program using either standard or
            ss990417 libpcap. */
         pcap_opts->cap_pipe_byte_swapped = TRUE;
-        pcap_opts->cap_pipe_modified = FALSE;
+        pcap_opts->u.pcap.cap_pipe_modified = FALSE;
         pcap_opts->ts_nsec = magic == PCAP_SWAPPED_NSEC_MAGIC;
         break;
     case PCAP_SWAPPED_MODIFIED_MAGIC:
@@ -2021,7 +2040,7 @@
            ours, and was running a program using either ss990915
            or ss991029 libpcap. */
         pcap_opts->cap_pipe_byte_swapped = TRUE;
-        pcap_opts->cap_pipe_modified = TRUE;
+        pcap_opts->u.pcap.cap_pipe_modified = TRUE;
         break;
     default:
         /* Not a "libpcap" type we know about. */
@@ -2082,7 +2101,7 @@
         goto error;
     }

-    pcap_opts->cap_pipe_state = STATE_EXPECT_REC_HDR;
+    pcap_opts->u.pcap.cap_pipe_state = PCAP_STATE_EXPECT_REC_HDR;
     pcap_opts->cap_pipe_err = PIPOK;
 #ifndef _WIN32
     pcap_opts->cap_pipe_fd = fd;
@@ -2125,15 +2144,15 @@
     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_dispatch");
 #endif

-    switch (pcap_opts->cap_pipe_state) {
+    switch (pcap_opts->u.pcap.cap_pipe_state) {

-    case STATE_EXPECT_REC_HDR:
+    case PCAP_STATE_EXPECT_REC_HDR:
 #ifdef _WIN32
         if (g_mutex_trylock(pcap_opts->cap_pipe_read_mtx)) {
 #endif

-            pcap_opts->cap_pipe_state = STATE_READ_REC_HDR;
-            pcap_opts->cap_pipe_bytes_to_read = pcap_opts->cap_pipe_modified ?
+            pcap_opts->u.pcap.cap_pipe_state = PCAP_STATE_READ_REC_HDR;
+            pcap_opts->cap_pipe_bytes_to_read =
pcap_opts->u.pcap.cap_pipe_modified ?
                 sizeof(struct pcaprec_modified_hdr) : sizeof(struct
pcaprec_hdr);
             pcap_opts->cap_pipe_bytes_read = 0;

@@ -2145,9 +2164,9 @@
 #endif
         /* Fall through */

-    case STATE_READ_REC_HDR:
+    case PCAP_STATE_READ_REC_HDR:
 #ifndef _WIN32
-        b = read(pcap_opts->cap_pipe_fd, ((char
*)&pcap_opts->cap_pipe_rechdr)+pcap_opts->cap_pipe_bytes_read,
+        b = read(pcap_opts->cap_pipe_fd, ((char
*)&pcap_opts->u.pcap.cap_pipe_rechdr)+pcap_opts->cap_pipe_bytes_read,
                  pcap_opts->cap_pipe_bytes_to_read -
pcap_opts->cap_pipe_bytes_read);
         if (b <= 0) {
             if (b == 0)
@@ -2181,13 +2200,13 @@
         result = PD_REC_HDR_READ;
         break;

-    case STATE_EXPECT_DATA:
+    case PCAP_STATE_EXPECT_DATA:
 #ifdef _WIN32
         if (g_mutex_trylock(pcap_opts->cap_pipe_read_mtx)) {
 #endif

-            pcap_opts->cap_pipe_state = STATE_READ_DATA;
-            pcap_opts->cap_pipe_bytes_to_read =
pcap_opts->cap_pipe_rechdr.hdr.incl_len;
+            pcap_opts->u.pcap.cap_pipe_state = PCAP_STATE_READ_DATA;
+            pcap_opts->cap_pipe_bytes_to_read =
pcap_opts->u.pcap.cap_pipe_rechdr.hdr.incl_len;
             pcap_opts->cap_pipe_bytes_read = 0;

 #ifdef _WIN32
@@ -2198,7 +2217,7 @@
 #endif
         /* Fall through */

-    case STATE_READ_DATA:
+    case PCAP_STATE_READ_DATA:
 #ifndef _WIN32
         b = read(pcap_opts->cap_pipe_fd, data+pcap_opts->cap_pipe_bytes_read,
                  pcap_opts->cap_pipe_bytes_to_read -
pcap_opts->cap_pipe_bytes_read);
@@ -2247,33 +2266,33 @@

     case PD_REC_HDR_READ:
         /* We've read the header. Take care of byte order. */
-        cap_pipe_adjust_header(pcap_opts->cap_pipe_byte_swapped,
&pcap_opts->cap_pipe_hdr,
-                               &pcap_opts->cap_pipe_rechdr.hdr);
-        if (pcap_opts->cap_pipe_rechdr.hdr.incl_len > WTAP_MAX_PACKET_SIZE) {
+        cap_pipe_adjust_header(pcap_opts->cap_pipe_byte_swapped,
&pcap_opts->u.pcap.cap_pipe_hdr,
+                               &pcap_opts->u.pcap.cap_pipe_rechdr.hdr);
+        if (pcap_opts->u.pcap.cap_pipe_rechdr.hdr.incl_len >
WTAP_MAX_PACKET_SIZE) {
             g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)",
-                       ld->packet_count+1,
pcap_opts->cap_pipe_rechdr.hdr.incl_len);
+                       ld->packet_count+1,
pcap_opts->u.pcap.cap_pipe_rechdr.hdr.incl_len);
             break;
         }

-        if (pcap_opts->cap_pipe_rechdr.hdr.incl_len) {
-            pcap_opts->cap_pipe_state = STATE_EXPECT_DATA;
+        if (pcap_opts->u.pcap.cap_pipe_rechdr.hdr.incl_len) {
+            pcap_opts->u.pcap.cap_pipe_state = PCAP_STATE_EXPECT_DATA;
             return 0;
         }
         /* no data to read? fall through */

     case PD_DATA_READ:
         /* Fill in a "struct pcap_pkthdr", and process the packet. */
-        phdr.ts.tv_sec = pcap_opts->cap_pipe_rechdr.hdr.ts_sec;
-        phdr.ts.tv_usec = pcap_opts->cap_pipe_rechdr.hdr.ts_usec;
-        phdr.caplen = pcap_opts->cap_pipe_rechdr.hdr.incl_len;
-        phdr.len = pcap_opts->cap_pipe_rechdr.hdr.orig_len;
+        phdr.ts.tv_sec = pcap_opts->u.pcap.cap_pipe_rechdr.hdr.ts_sec;
+        phdr.ts.tv_usec = pcap_opts->u.pcap.cap_pipe_rechdr.hdr.ts_usec;
+        phdr.caplen = pcap_opts->u.pcap.cap_pipe_rechdr.hdr.incl_len;
+        phdr.len = pcap_opts->u.pcap.cap_pipe_rechdr.hdr.orig_len;

         if (use_threads) {
             capture_loop_queue_packet_cb((u_char *)pcap_opts, &phdr, data);
         } else {
             capture_loop_write_packet_cb((u_char *)pcap_opts, &phdr, data);
         }
-        pcap_opts->cap_pipe_state = STATE_EXPECT_REC_HDR;
+        pcap_opts->u.pcap.cap_pipe_state = PCAP_STATE_EXPECT_REC_HDR;
         return 1;

     case PD_PIPE_EOF:
@@ -2397,21 +2416,21 @@
         pcap_opts->linktype = -1;
         pcap_opts->ts_nsec = FALSE;
         pcap_opts->from_cap_pipe = FALSE;
-        memset(&pcap_opts->cap_pipe_hdr, 0, sizeof(struct pcap_hdr));
-        memset(&pcap_opts->cap_pipe_rechdr, 0, sizeof(struct
pcaprec_modified_hdr));
+        memset(&pcap_opts->u.pcap.cap_pipe_hdr, 0, sizeof(struct pcap_hdr));
+        memset(&pcap_opts->u.pcap.cap_pipe_rechdr, 0, sizeof(struct
pcaprec_modified_hdr));
 #ifdef _WIN32
         pcap_opts->cap_pipe_h = INVALID_HANDLE_VALUE;
 #else
         pcap_opts->cap_pipe_fd = -1;
 #endif
-        pcap_opts->cap_pipe_modified = FALSE;
+        pcap_opts->u.pcap.cap_pipe_modified = FALSE;
         pcap_opts->cap_pipe_byte_swapped = FALSE;
 #ifdef _WIN32
         pcap_opts->cap_pipe_buf = NULL;
 #endif
         pcap_opts->cap_pipe_bytes_to_read = 0;
         pcap_opts->cap_pipe_bytes_read = 0;
-        pcap_opts->cap_pipe_state = 0;
+        pcap_opts->u.pcap.cap_pipe_state = 0;
         pcap_opts->cap_pipe_err = PIPOK;
 #ifdef _WIN32
 #if GLIB_CHECK_VERSION(2,31,0)
@@ -2487,7 +2506,7 @@
         } else {
             /* We couldn't open "iface" as a network device. */
             /* Try to open it as a pipe */
-            cap_pipe_open_live(interface_opts.name, pcap_opts,
&pcap_opts->cap_pipe_hdr, errmsg, (int) errmsg_len);
+            cap_pipe_open_live(interface_opts.name, pcap_opts,
&pcap_opts->u.pcap.cap_pipe_hdr, errmsg, (int) errmsg_len);

 #ifndef _WIN32
             if (pcap_opts->cap_pipe_fd == -1) {
@@ -2670,7 +2689,7 @@
                 interface_opts = g_array_index(capture_opts->ifaces,
interface_options, i);
                 pcap_opts = g_array_index(ld->pcaps, pcap_options *, i);
                 if (pcap_opts->from_cap_pipe) {
-                    pcap_opts->snaplen = pcap_opts->cap_pipe_hdr.snaplen;
+                    pcap_opts->snaplen =
pcap_opts->u.pcap.cap_pipe_hdr.snaplen;
                 } else {
                     pcap_opts->snaplen = pcap_snapshot(pcap_opts->pcap_h);
                 }
@@ -2693,7 +2712,7 @@
         } else {
             pcap_opts = g_array_index(ld->pcaps, pcap_options *, 0);
             if (pcap_opts->from_cap_pipe) {
-                pcap_opts->snaplen = pcap_opts->cap_pipe_hdr.snaplen;
+                pcap_opts->snaplen = pcap_opts->u.pcap.cap_pipe_hdr.snaplen;
             } else {
                 pcap_opts->snaplen = pcap_snapshot(pcap_opts->pcap_h);
             }


-- 
Regards,
Richard Sharpe
(何以解憂?唯有杜康。--曹操)