diff --git a/src/runmodes.c b/src/runmodes.c index 7d939f49ce..142cd5eeb6 100644 --- a/src/runmodes.c +++ b/src/runmodes.c @@ -2074,37 +2074,80 @@ int RunModeIdsPfring4(DetectEngineCtx *de_ctx, char *iface) { int RunModeIdsPcapAuto(DetectEngineCtx *de_ctx, char *iface) { SCEnter(); /* tname = Detect + cpuid, this is 11bytes length as max */ - char tname[12]; + char tname[16]; uint16_t cpu = 0; + TmModule *tm_module; + uint16_t thread; RunModeInitialize(); + TimeModeSetLive(); /* Available cpus */ uint16_t ncpus = UtilCpuGetNumProcessorsOnline(); + int npcap = PcapLiveGetDeviceCount(); - TimeModeSetLive(); - /* create the threads */ - ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler("ReceivePcap","packetpool","packetpool","pickup-queue","simple","1slot"); - if (tv_receivepcap == NULL) { - printf("ERROR: TmThreadsCreate failed\n"); - exit(EXIT_FAILURE); - } - TmModule *tm_module = TmModuleGetByName("ReceivePcap"); - if (tm_module == NULL) { - printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); - exit(EXIT_FAILURE); - } - Tm1SlotSetFunc(tv_receivepcap,tm_module,(void *)iface); + if (npcap == 1) { + /* create the threads */ + ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler("ReceivePcap","packetpool","packetpool","pickup-queue","simple","1slot"); + if (tv_receivepcap == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("ReceivePcap"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_receivepcap,tm_module,(void *)iface); - if (threading_set_cpu_affinity) { - TmThreadSetCPUAffinity(tv_receivepcap, 0); - if (ncpus > 1) - TmThreadSetThreadPriority(tv_receivepcap, PRIO_MEDIUM); - } + if (threading_set_cpu_affinity) { + TmThreadSetCPUAffinity(tv_receivepcap, 0); + if (ncpus > 1) + TmThreadSetThreadPriority(tv_receivepcap, PRIO_MEDIUM); + } + if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } else { + SCLogInfo("Using %d pcap device(s).", npcap); - if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { - printf("ERROR: TmThreadSpawn failed\n"); - exit(EXIT_FAILURE); + for (thread = 0; thread < npcap; thread++) { + char *pcap_dev = PcapLiveGetDevice(thread); + if (pcap_dev == NULL) { + printf("Failed to lookup pcap dev %d\n", thread); + exit(EXIT_FAILURE); + } + SCLogDebug("pcap_dev %s", pcap_dev); + + snprintf(tname, sizeof(tname),"RecvPcap-%s", pcap_dev); + char *tnamec = SCStrdup(tname); + char *pcap_devc = SCStrdup(pcap_dev); + + /* create the threads */ + ThreadVars *tv_receivepcap = TmThreadCreatePacketHandler(tnamec,"packetpool","packetpool","pickup-queue","simple","1slot"); + if (tv_receivepcap == NULL) { + printf("ERROR: TmThreadsCreate failed\n"); + exit(EXIT_FAILURE); + } + tm_module = TmModuleGetByName("ReceivePcap"); + if (tm_module == NULL) { + printf("ERROR: TmModuleGetByName failed for ReceivePcap\n"); + exit(EXIT_FAILURE); + } + Tm1SlotSetFunc(tv_receivepcap,tm_module,(void *)pcap_devc); + + if (threading_set_cpu_affinity) { + TmThreadSetCPUAffinity(tv_receivepcap, 0); + if (ncpus > 1) + TmThreadSetThreadPriority(tv_receivepcap, PRIO_MEDIUM); + } + + if (TmThreadSpawn(tv_receivepcap) != TM_ECODE_OK) { + printf("ERROR: TmThreadSpawn failed\n"); + exit(EXIT_FAILURE); + } + } } #if defined(__SC_CUDA_SUPPORT__) @@ -2265,7 +2308,6 @@ int RunModeIdsPcapAuto(DetectEngineCtx *de_ctx, char *iface) { if (thread_max < 1) thread_max = 1; - int thread; for (thread = 0; thread < thread_max; thread++) { snprintf(tname, sizeof(tname),"Detect%"PRIu16, thread+1); if (tname == NULL) diff --git a/src/source-pcap.c b/src/source-pcap.c index 68eda3f648..e04a52da56 100644 --- a/src/source-pcap.c +++ b/src/source-pcap.c @@ -48,8 +48,19 @@ extern uint8_t suricata_ctl_flags; extern int max_pending_packets; +/** control how many packet libpcap may read in one go */ static int pcap_max_read_packets = 0; +/** storage for pcap device names */ +typedef struct PcapDevice_ { + char *dev; /**< the device (e.g. "eth0") */ + TAILQ_ENTRY(PcapDevice_) next; +} PcapDevice; + +/** private device list */ +static TAILQ_HEAD(, PcapDevice_) pcap_devices = + TAILQ_HEAD_INITIALIZER(pcap_devices); + /** max packets < 65536 */ #define PCAP_FILE_MAX_PKTS 256 @@ -521,6 +532,66 @@ TmEcode DecodePcapThreadInit(ThreadVars *tv, void *initdata, void **data) SCReturnInt(TM_ECODE_OK); } +/** + * \brief Add a pcap device for monitoring + * + * \param dev string with the device name + * + * \retval 0 on success. + * \retval -1 on failure. + */ +int PcapLiveRegisterDevice(char *dev) +{ + PcapDevice *pd = SCMalloc(sizeof(PcapDevice)); + if (pd == NULL) { + return -1; + } + + pd->dev = SCStrdup(dev); + TAILQ_INSERT_TAIL(&pcap_devices, pd, next); + + SCLogDebug("Pcap device \"%s\" registered.", dev); + return 0; +} + +/** + * \brief Get the number of registered devices + * + * \retval cnt the number of registered devices + */ +int PcapLiveGetDeviceCount(void) { + int i = 0; + PcapDevice *pd; + + TAILQ_FOREACH(pd, &pcap_devices, next) { + i++; + } + + return i; +} + +/** + * \brief Get a pointer to the device at idx + * + * \param number idx of the device in our list + * + * \retval ptr pointer to the string containing the device + * \retval NULL on error + */ +char *PcapLiveGetDevice(int number) { + int i = 0; + PcapDevice *pd; + + TAILQ_FOREACH(pd, &pcap_devices, next) { + if (i == number) { + return pd->dev; + } + + i++; + } + return NULL; +} + void PcapTranslateIPToDevice(char *pcap_dev, size_t len) { char errbuf[PCAP_ERRBUF_SIZE]; diff --git a/src/source-pcap.h b/src/source-pcap.h index b60271c216..479fa8647e 100644 --- a/src/source-pcap.h +++ b/src/source-pcap.h @@ -28,6 +28,10 @@ void TmModuleReceivePcapRegister (void); void TmModuleDecodePcapRegister (void); void PcapTranslateIPToDevice(char *pcap_dev, size_t len); +int PcapLiveRegisterDevice(char *); +int PcapLiveGetDeviceCount(void); +char *PcapLiveGetDevice(int); + /* XXX replace with user configurable options */ #define LIBPCAP_SNAPLEN 1518 #define LIBPCAP_COPYWAIT 500 diff --git a/src/suricata.c b/src/suricata.c index 561655c05e..28367f3804 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -638,6 +638,17 @@ int main(int argc, char **argv) case 'i': if (run_mode == MODE_UNKNOWN) { run_mode = MODE_PCAP_DEV; + PcapLiveRegisterDevice(optarg); + } else if (run_mode == MODE_PCAP_DEV) { +#ifdef OS_WIN32 + SCLogError(SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, "pcap multi dev " + "support is not (yet) supported on Windows."); + exit(EXIT_FAILURE); +#else + SCLogWarning(SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, "using " + "multiple pcap devices to get packets is experimental."); + PcapLiveRegisterDevice(optarg); +#endif } else { SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode " "has been specified"); @@ -645,7 +656,7 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } memset(pcap_dev, 0, sizeof(pcap_dev)); - strncpy(pcap_dev, optarg, ((strlen(optarg) < sizeof(pcap_dev)) ? (strlen(optarg)) : (sizeof(pcap_dev)-1))); + strlcpy(pcap_dev, optarg, ((strlen(optarg) < sizeof(pcap_dev)) ? (strlen(optarg)+1) : (sizeof(pcap_dev)))); break; case 'l': if (ConfSet("default-log-dir", optarg, 0) != 1) { diff --git a/src/util-error.c b/src/util-error.c index 158433de83..67f870adba 100644 --- a/src/util-error.c +++ b/src/util-error.c @@ -192,6 +192,8 @@ const char * SCErrorToString(SCError err) CASE_CODE (SC_ERR_DCERPC); CASE_CODE (SC_ERR_AHO_CORASICK); CASE_CODE (SC_ERR_REFERENCE_CONFIG); + CASE_CODE (SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL); + CASE_CODE (SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT); default: return "UNKNOWN_ERROR"; diff --git a/src/util-error.h b/src/util-error.h index fbf1a57f16..4cca5d3395 100644 --- a/src/util-error.h +++ b/src/util-error.h @@ -203,6 +203,8 @@ typedef enum { SC_ERR_DETECT_PREPARE, /**< preparing the detection engine failed */ SC_ERR_AHO_CORASICK, SC_ERR_REFERENCE_CONFIG, + SC_WARN_PCAP_MULTI_DEV_EXPERIMENTAL, + SC_ERR_PCAP_MULTI_DEV_NO_SUPPORT, } SCError; const char *SCErrorToString(SCError);