[Oisf-devel] [PATCH] pcap: do not leave if interface goes down
Victor Julien
victor at inliniac.net
Thu Mar 24 12:05:22 UTC 2011
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?
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
---------------------------------------------
More information about the Oisf-devel
mailing list