From 8b5be26f496b79f2f6c5523f4bff3536d7183daa Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Thu, 20 Jun 2013 09:29:10 +0200 Subject: [PATCH] pcap-file: add checksum-checks configuration variable This patch adds support for checksum-checks in the pcap-file running mode. This is the same functionnality as the one already existing for live interface. It can be setup in the YAML: pcap-file: checksum-checks: auto A message is displayed for small pcap to warn that invalid checksum rate is big on the pcap file and that checksum-check could be set to no. --- src/source-pcap-file.c | 51 ++++++++++++++++++++++++++++++++++++++++++ src/source-pcap-file.h | 2 ++ src/stream-tcp.c | 4 ++++ suricata.yaml.in | 9 ++++++++ 4 files changed, 66 insertions(+) diff --git a/src/source-pcap-file.c b/src/source-pcap-file.c index 6c951a9a26..f88cb4517d 100644 --- a/src/source-pcap-file.c +++ b/src/source-pcap-file.c @@ -42,6 +42,8 @@ #include "flow-manager.h" #include "util-profiling.h" #include "runmode-unix-socket.h" +#include "util-checksum.h" +#include "util-atomic.h" #ifdef __SC_CUDA_SUPPORT__ @@ -66,6 +68,10 @@ typedef struct PcapFileGlobalVars_ { int datalink; struct bpf_program filter; uint64_t cnt; /** packet counter */ + ChecksumValidationMode conf_checksum_mode; + ChecksumValidationMode checksum_mode; + SC_ATOMIC_DECLARE(unsigned int, invalid_checksums); + } PcapFileGlobalVars; /** max packets < 65536 */ @@ -149,6 +155,18 @@ void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) { PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE); SCReturn; } + + /* We only check for checksum disable */ + if (pcap_g.checksum_mode == CHECKSUM_VALIDATION_DISABLE) { + p->flags |= PKT_IGNORE_CHECKSUM; + } else if (pcap_g.checksum_mode == CHECKSUM_VALIDATION_AUTO) { + if (ChecksumAutoModeCheck(ptv->pkts, p->pcap_cnt, + SC_ATOMIC_GET(pcap_g.invalid_checksums))) { + pcap_g.checksum_mode = CHECKSUM_VALIDATION_DISABLE; + p->flags |= PKT_IGNORE_CHECKSUM; + } + } + PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE); if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { @@ -236,6 +254,7 @@ TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) { SCEnter(); char *tmpbpfstring = NULL; + char *tmpstring = NULL; if (initdata == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "error: initdata == NULL"); SCReturnInt(TM_ECODE_FAILED); @@ -310,6 +329,19 @@ TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) { } } + if (ConfGet("pcap-file.checksum-checks", &tmpstring) != 1) { + pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO; + } else { + if (strcmp(tmpstring, "auto") == 0) { + pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO; + } else if (strcmp(tmpstring, "yes") == 0) { + pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_ENABLE; + } else if (strcmp(tmpstring, "no") == 0) { + pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_DISABLE; + } + } + pcap_g.checksum_mode = pcap_g.conf_checksum_mode; + ptv->tv = tv; *data = (void *)ptv; SCReturnInt(TM_ECODE_OK); @@ -319,6 +351,19 @@ void ReceivePcapFileThreadExitStats(ThreadVars *tv, void *data) { SCEnter(); PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; + if (pcap_g.conf_checksum_mode == CHECKSUM_VALIDATION_AUTO && + pcap_g.cnt < CHECKSUM_SAMPLE_COUNT && + SC_ATOMIC_GET(pcap_g.invalid_checksums)) { + uint64_t chrate = pcap_g.cnt / SC_ATOMIC_GET(pcap_g.invalid_checksums); + if (chrate < CHECKSUM_INVALID_RATIO) + SCLogWarning(SC_ERR_INVALID_CHECKSUM, + "1/%" PRIu64 "th of packets have an invalid checksum," + " consider setting pcap-file.checksum-checks variable to no", + chrate); + else + SCLogInfo("1/%" PRIu64 "th of packets have an invalid checksum", + chrate); + } SCLogInfo("Pcap-file module read %" PRIu32 " packets, %" PRIu64 " bytes", ptv->pkts, ptv->bytes); return; } @@ -395,5 +440,11 @@ TmEcode DecodePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_OK); } + +void PcapIncreaseInvalidChecksum() +{ + (void) SC_ATOMIC_ADD(pcap_g.invalid_checksums, 1); +} + /* eof */ diff --git a/src/source-pcap-file.h b/src/source-pcap-file.h index 67bd261b60..636cbdeb6d 100644 --- a/src/source-pcap-file.h +++ b/src/source-pcap-file.h @@ -27,5 +27,7 @@ void TmModuleReceivePcapFileRegister (void); void TmModuleDecodePcapFileRegister (void); +void PcapIncreaseInvalidChecksum(); + #endif /* __SOURCE_PCAP_FILE_H__ */ diff --git a/src/stream-tcp.c b/src/stream-tcp.c index 7abf72276c..cc3ed39866 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -71,6 +71,8 @@ #include "util-misc.h" #include "util-validate.h" +#include "source-pcap-file.h" + //#define DEBUG #define STREAMTCP_DEFAULT_PREALLOC 2048 @@ -4429,6 +4431,8 @@ static inline int StreamTcpValidateChecksum(Packet *p) SCLogDebug("Checksum of received packet %p is invalid",p); if (p->livedev) { (void) SC_ATOMIC_ADD(p->livedev->invalid_checksums, 1); + } else if (p->pcap_cnt) { + PcapIncreaseInvalidChecksum(); } } diff --git a/suricata.yaml.in b/suricata.yaml.in index d10186315d..dbbffb6cb5 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -797,6 +797,15 @@ pcap: - interface: default #checksum-checks: auto +pcap-file: + # Possible values are: + # - yes: checksum validation is forced + # - no: checksum validation is disabled + # - auto: suricata uses a statistical approach to detect when + # checksum off-loading is used. (default) + # Warning: 'checksum-validation' must be set to yes to have checksum tested + checksum-checks: auto + # For FreeBSD ipfw(8) divert(4) support. # Please make sure you have ipfw_load="YES" and ipdivert_load="YES" # in /etc/loader.conf or kldload'ing the appropriate kernel modules.