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

Victor Julien victor at inliniac.net
Thu Mar 24 12:26:19 UTC 2011


On 03/24/2011 01:16 PM, Eric Leblond wrote:
> 
> 
> Hi,
> 
> Victor Julien <victor at inliniac.net> a écrit :
> 
>> Good idea to address this Eric. I'm not completely convinced about the
>> approach yet though. My concern is that while the pcap interface is
>> down
>> we send an empty packet through the engine, which I don't like. Maybe
>> we
>> should make the thread modules capable of returning an error condition
>> without the thread restart mechanism kicking in... thoughts?
> 
> I clearly agree with the point on the empty packet. That's not sexy at all.
> 
> We could introduce a Continue/finish return that could be use to indicate that the thread module should stop the treatment.

What about a simple loop in the ReceivePcap function that just loops the
TryReopen function until it succeeds or we interrupt it?

Cheers,
Victor

> BR, 
> 
>>
>> Cheers,
>> Victor
>>
>> On 03/21/2011 09:56 PM, Eric Leblond wrote:
>>> 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);
>>
>>
>> -- 
>> ---------------------------------------------
>> Victor Julien
>> http://www.inliniac.net/
>> PGP: http://www.inliniac.net/victorjulien.asc
>> ---------------------------------------------
> 


-- 
---------------------------------------------
Victor Julien
http://www.inliniac.net/
PGP: http://www.inliniac.net/victorjulien.asc
---------------------------------------------




More information about the Oisf-devel mailing list