[Oisf-devel] [PATCH] pcap: do not leave if interface goes down

Eric Leblond eric at regit.org
Mon Mar 21 20:56:30 UTC 2011


This patch changes suricata behaviour to support interface like
ppp. Prior to this patch, a suricata listening to an interface
was leaving when the interface goes down. This patch modifies
the behaviour to automatically reconnect. Suricata retries to
open the interface every 0,5s until it succeeds.
---
 src/source-pcap.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 109 insertions(+), 4 deletions(-)

diff --git a/src/source-pcap.c b/src/source-pcap.c
index 26cabd8..a78f9f9 100644
--- a/src/source-pcap.c
+++ b/src/source-pcap.c
@@ -63,6 +63,12 @@ static TAILQ_HEAD(, PcapDevice_) pcap_devices =
 
 /** max packets < 65536 */
 #define PCAP_FILE_MAX_PKTS 256
+#define PCAP_IFACE_NAME_LENGTH 48
+
+#define PCAP_STATE_DOWN 0
+#define PCAP_STATE_UP 1
+
+#define PCAP_RECONNECT_TIMEOUT 500000
 
 /**
  * \brief Structure to hold thread specific variables.
@@ -71,7 +77,11 @@ typedef struct PcapThreadVars_
 {
     /* thread specific handle */
     pcap_t *pcap_handle;
-
+    /* handle state */
+    unsigned char pcap_state;
+#if LIBPCAP_VERSION_MAJOR == 0
+    char iface[PCAP_IFACE_NAME_LENGTH];
+#endif
     /* thread specific bpf */
     struct bpf_program filter;
 
@@ -173,6 +183,77 @@ void PcapCallback(char *user, struct pcap_pkthdr *h, u_char *pkt) {
     ptv->array_idx++;
 }
 
+#if LIBPCAP_VERSION_MAJOR == 1
+static int PcapTryReopen(PcapThreadVars *ptv)
+{
+    int pcap_activate_r;
+    char *tmpbpfstring;
+
+    ptv->pcap_state = PCAP_STATE_DOWN;
+    pcap_activate_r = pcap_activate(ptv->pcap_handle);
+    if (pcap_activate_r != 0) {
+        return -1;
+    }
+    /* set bpf filter if we have one */
+    if (ConfGet("bpf-filter", &tmpbpfstring) != 1) {
+        SCLogDebug("could not get bpf or none specified");
+    } else {
+        SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring);
+
+        if(pcap_compile(ptv->pcap_handle,&ptv->filter,tmpbpfstring,1,0) < 0) {
+            SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(ptv->pcap_handle));
+            return -1;
+        }
+
+        if(pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) {
+            SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(ptv->pcap_handle));
+            return -1;
+        }
+    }
+
+    SCLogInfo("Recovering interface listening");
+    ptv->pcap_state = PCAP_STATE_UP;
+    return 0;
+}
+#else /* implied LIBPCAP_VERSION_MAJOR == 0 */
+static int PcapTryReopen(PcapThreadVars *ptv)
+{
+    char errbuf[PCAP_ERRBUF_SIZE] = "";
+
+    ptv->pcap_state = PCAP_STATE_DOWN;
+    pcap_close(ptv->pcap_handle);
+
+    ptv->pcap_handle = pcap_open_live((char *)ptv->iface, LIBPCAP_SNAPLEN,
+            LIBPCAP_PROMISC, LIBPCAP_COPYWAIT, errbuf);
+    if (ptv->pcap_handle == NULL) {
+        SCLogError(SC_ERR_PCAP_OPEN_LIVE, "Problem creating pcap handler for live mode, error %s", errbuf);
+        return -1;
+    }
+
+    /* set bpf filter if we have one */
+    if (ConfGet("bpf-filter", &tmpbpfstring) != 1) {
+        SCLogDebug("could not get bpf or none specified");
+    } else {
+        SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring);
+
+        if(pcap_compile(ptv->pcap_handle,&ptv->filter,tmpbpfstring,1,0) < 0) {
+            SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(ptv->pcap_handle));
+            return -1;
+        }
+
+        if(pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) {
+            SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(ptv->pcap_handle));
+            return -1;
+        }
+    }
+
+    SCLogInfo("Recovering interface listening");
+    ptv->pcap_state = PCAP_STATE_UP;
+    return 0;
+}
+
+#endif
+
 /**
  * \brief Recieves packets from an interface via libpcap.
  *
@@ -190,6 +271,14 @@ TmEcode ReceivePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack
 
     PcapThreadVars *ptv = (PcapThreadVars *)data;
 
+    /* test pcap handle */
+    if (ptv->pcap_state == PCAP_STATE_DOWN) {
+        int r = PcapTryReopen(ptv);
+        if (r < 0) {
+            usleep(PCAP_RECONNECT_TIMEOUT);
+        }
+        SCReturnInt(TM_ECODE_OK);
+    }
     /* make sure we have at least one packet in the packet pool, to prevent
      * us from alloc'ing packets at line rate */
     while (packet_q_len == 0) {
@@ -229,8 +318,9 @@ TmEcode ReceivePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Pack
         SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s",
                 r, pcap_geterr(ptv->pcap_handle));
 
-        EngineStop();
-        SCReturnInt(TM_ECODE_FAILED);
+        /* try to reopen */
+        PcapTryReopen(ptv);
+        SCReturnInt(TM_ECODE_OK);
     }
 
     if (suricata_ctl_flags != 0) {
@@ -278,7 +368,6 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) {
     ptv->tv = tv;
 
     SCLogInfo("using interface %s", (char *)initdata);
-
     /* XXX create a general pcap setup function */
     char errbuf[PCAP_ERRBUF_SIZE];
     ptv->pcap_handle = pcap_create((char *)initdata, errbuf);
@@ -339,6 +428,9 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) {
         SCLogError(SC_ERR_PCAP_ACTIVATE_HANDLE, "Couldn't activate the pcap handler, error %s", pcap_geterr(ptv->pcap_handle));
         SCFree(ptv);
         SCReturnInt(TM_ECODE_FAILED);
+        ptv->pcap_state = PCAP_STATE_DOWN;
+    } else {
+        ptv->pcap_state = PCAP_STATE_UP;
     }
 
     /* set bpf filter if we have one */
@@ -389,12 +481,18 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) {
     ptv->tv = tv;
 
     SCLogInfo("using interface %s", (char *)initdata);
+    if(strlen(initdata)>PCAP_IFACE_NAME_LENGTH) {
+        SCFree(ptv);
+        SCReturnInt(TM_ECODE_FAILED);
+    }
+    strncpy(ptv->iface, PCAP_IFACE_NAME_LENGTH, initdata);
 
     char errbuf[PCAP_ERRBUF_SIZE] = "";
     ptv->pcap_handle = pcap_open_live((char *)initdata, LIBPCAP_SNAPLEN,
                                         LIBPCAP_PROMISC, LIBPCAP_COPYWAIT, errbuf);
     if (ptv->pcap_handle == NULL) {
         SCLogError(SC_ERR_PCAP_OPEN_LIVE, "Problem creating pcap handler for live mode, error %s", errbuf);
+        SCFree(ptv);
         SCReturnInt(TM_ECODE_FAILED);
     }
 
@@ -406,11 +504,13 @@ TmEcode ReceivePcapThreadInit(ThreadVars *tv, void *initdata, void **data) {
 
         if(pcap_compile(ptv->pcap_handle,&ptv->filter,tmpbpfstring,1,0) < 0) {
             SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(ptv->pcap_handle));
+            SCFree(ptv);
             return TM_ECODE_FAILED;
         }
 
         if(pcap_setfilter(ptv->pcap_handle,&ptv->filter) < 0) {
             SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(ptv->pcap_handle));
+            SCFree(ptv);
             return TM_ECODE_FAILED;
         }
     }
@@ -481,6 +581,11 @@ TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, Packe
     SCEnter();
     DecodeThreadVars *dtv = (DecodeThreadVars *)data;
 
+    /* packet is not a real one */
+    if (p->datalink == 0) {
+        SCReturnInt(TM_ECODE_OK);
+    }
+
     /* update counters */
     SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca);
     SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca);
-- 
1.7.1




More information about the Oisf-devel mailing list