1 /* Copyright (C) 2007-2019 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18 /**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 *
23 * Live pcap packet acquisition support
24 */
25
26 #include "suricata-common.h"
27 #include "suricata.h"
28 #include "decode.h"
29 #include "packet-queue.h"
30 #include "threads.h"
31 #include "threadvars.h"
32 #include "tm-queuehandlers.h"
33 #include "tm-threads.h"
34 #include "source-pcap.h"
35 #include "conf.h"
36 #include "util-debug.h"
37 #include "util-error.h"
38 #include "util-privs.h"
39 #include "util-device.h"
40 #include "util-optimize.h"
41 #include "util-checksum.h"
42 #include "util-ioctl.h"
43 #include "tmqh-packetpool.h"
44
45 #define PCAP_STATE_DOWN 0
46 #define PCAP_STATE_UP 1
47
48 #define PCAP_RECONNECT_TIMEOUT 500000
49
50 /**
51 * \brief 64bit pcap stats counters.
52 *
53 * libpcap only supports 32bit counters. They will eventually wrap around.
54 *
55 * Keep track of libpcap counters as 64bit counters to keep on counting even
56 * if libpcap's 32bit counters wrap around.
57 * Requires pcap_stats() to be called before 32bit stats wrap around twice,
58 * which we do.
59 */
60 typedef struct PcapStats64_ {
61 uint64_t ps_recv;
62 uint64_t ps_drop;
63 uint64_t ps_ifdrop;
64 } PcapStats64;
65
66 /**
67 * \brief Structure to hold thread specific variables.
68 */
69 typedef struct PcapThreadVars_
70 {
71 /* thread specific handle */
72 pcap_t *pcap_handle;
73 /* handle state */
74 unsigned char pcap_state;
75 /* thread specific bpf */
76 struct bpf_program filter;
77 /* ptr to string from config */
78 const char *bpf_filter;
79
80 time_t last_stats_dump;
81
82 /* data link type for the thread */
83 int datalink;
84
85 /* counters */
86 uint64_t pkts;
87 uint64_t bytes;
88
89 uint16_t capture_kernel_packets;
90 uint16_t capture_kernel_drops;
91 uint16_t capture_kernel_ifdrops;
92
93 ThreadVars *tv;
94 TmSlot *slot;
95
96 /** callback result -- set if one of the thread module failed. */
97 int cb_result;
98
99 /* pcap buffer size */
100 int pcap_buffer_size;
101 int pcap_snaplen;
102
103 ChecksumValidationMode checksum_mode;
104
105 LiveDevice *livedev;
106
107 PcapStats64 last_stats64;
108 } PcapThreadVars;
109
110 static TmEcode ReceivePcapThreadInit(ThreadVars *, const void *, void **);
111 static void ReceivePcapThreadExitStats(ThreadVars *, void *);
112 static TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot);
113 static TmEcode ReceivePcapBreakLoop(ThreadVars *tv, void *data);
114
115 static TmEcode DecodePcapThreadInit(ThreadVars *, const void *, void **);
116 static TmEcode DecodePcapThreadDeinit(ThreadVars *tv, void *data);
117 static TmEcode DecodePcap(ThreadVars *, Packet *, void *);
118
119 #ifdef UNITTESTS
120 static void SourcePcapRegisterTests(void);
121 #endif
122
123 /** protect pcap_compile and pcap_setfilter, as they are not thread safe:
124 * http://seclists.org/tcpdump/2009/q1/62 */
125 static SCMutex pcap_bpf_compile_lock = SCMUTEX_INITIALIZER;
126
127 /**
128 * \brief Registration Function for ReceivePcap.
129 */
TmModuleReceivePcapRegister(void)130 void TmModuleReceivePcapRegister (void)
131 {
132 tmm_modules[TMM_RECEIVEPCAP].name = "ReceivePcap";
133 tmm_modules[TMM_RECEIVEPCAP].ThreadInit = ReceivePcapThreadInit;
134 tmm_modules[TMM_RECEIVEPCAP].PktAcqLoop = ReceivePcapLoop;
135 tmm_modules[TMM_RECEIVEPCAP].PktAcqBreakLoop = ReceivePcapBreakLoop;
136 tmm_modules[TMM_RECEIVEPCAP].ThreadExitPrintStats = ReceivePcapThreadExitStats;
137 tmm_modules[TMM_RECEIVEPCAP].cap_flags = SC_CAP_NET_RAW;
138 tmm_modules[TMM_RECEIVEPCAP].flags = TM_FLAG_RECEIVE_TM;
139 #ifdef UNITTESTS
140 tmm_modules[TMM_RECEIVEPCAP].RegisterTests = SourcePcapRegisterTests;
141 #endif
142 }
143
144 /**
145 * \brief Registration Function for DecodePcap.
146 */
TmModuleDecodePcapRegister(void)147 void TmModuleDecodePcapRegister (void)
148 {
149 tmm_modules[TMM_DECODEPCAP].name = "DecodePcap";
150 tmm_modules[TMM_DECODEPCAP].ThreadInit = DecodePcapThreadInit;
151 tmm_modules[TMM_DECODEPCAP].Func = DecodePcap;
152 tmm_modules[TMM_DECODEPCAP].ThreadDeinit = DecodePcapThreadDeinit;
153 tmm_modules[TMM_DECODEPCAP].flags = TM_FLAG_DECODE_TM;
154 }
155
156 /**
157 * \brief Update 64 bit |last| value from |current32| value taking one
158 * wrap-around into account.
159 */
UpdatePcapStatsValue64(uint64_t * last,uint32_t current32)160 static inline void UpdatePcapStatsValue64(uint64_t *last, uint32_t current32)
161 {
162 /* uint64_t -> uint32_t is defined behaviour. It slices lower 32bits. */
163 uint32_t last32 = *last;
164
165 /* Branchless code as wrap-around is defined for unsigned */
166 *last += (uint32_t)(current32 - last32);
167
168 /* Same calculation as:
169 if (likely(current32 >= last32)) {
170 *last += current32 - last32;
171 } else {
172 *last += (1ull << 32) + current32 - last32;
173 }
174 */
175 }
176
177 /**
178 * \brief Update 64 bit |last| stat values with values from |current|
179 * 32 bit pcap_stat.
180 */
UpdatePcapStats64(PcapStats64 * last,const struct pcap_stat * current)181 static inline void UpdatePcapStats64(
182 PcapStats64 *last, const struct pcap_stat *current)
183 {
184 UpdatePcapStatsValue64(&last->ps_recv, current->ps_recv);
185 UpdatePcapStatsValue64(&last->ps_drop, current->ps_drop);
186 UpdatePcapStatsValue64(&last->ps_ifdrop, current->ps_ifdrop);
187 }
188
PcapDumpCounters(PcapThreadVars * ptv)189 static inline void PcapDumpCounters(PcapThreadVars *ptv)
190 {
191 struct pcap_stat pcap_s;
192 if (likely((pcap_stats(ptv->pcap_handle, &pcap_s) >= 0))) {
193 UpdatePcapStats64(&ptv->last_stats64, &pcap_s);
194
195 StatsSetUI64(ptv->tv, ptv->capture_kernel_packets,
196 ptv->last_stats64.ps_recv);
197 StatsSetUI64(
198 ptv->tv, ptv->capture_kernel_drops, ptv->last_stats64.ps_drop);
199 (void)SC_ATOMIC_SET(ptv->livedev->drop, ptv->last_stats64.ps_drop);
200 StatsSetUI64(ptv->tv, ptv->capture_kernel_ifdrops,
201 ptv->last_stats64.ps_ifdrop);
202 }
203 }
204
PcapTryReopen(PcapThreadVars * ptv)205 static int PcapTryReopen(PcapThreadVars *ptv)
206 {
207 ptv->pcap_state = PCAP_STATE_DOWN;
208
209 int pcap_activate_r = pcap_activate(ptv->pcap_handle);
210 if (pcap_activate_r != 0) {
211 return pcap_activate_r;
212 }
213
214 /* set bpf filter if we have one */
215 if (ptv->bpf_filter != NULL) {
216 if (pcap_compile(ptv->pcap_handle, &ptv->filter,
217 (char *)ptv->bpf_filter, 1, 0) < 0)
218 {
219 SCLogError(SC_ERR_BPF, "bpf compilation error %s",
220 pcap_geterr(ptv->pcap_handle));
221 return -1;
222 }
223
224 if (pcap_setfilter(ptv->pcap_handle, &ptv->filter) < 0) {
225 SCLogError(SC_ERR_BPF, "could not set bpf filter %s",
226 pcap_geterr(ptv->pcap_handle));
227 return -1;
228 }
229 }
230
231 SCLogInfo("Recovering interface listening");
232 ptv->pcap_state = PCAP_STATE_UP;
233 return 0;
234 }
235
PcapCallbackLoop(char * user,struct pcap_pkthdr * h,u_char * pkt)236 static void PcapCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt)
237 {
238 SCEnter();
239
240 PcapThreadVars *ptv = (PcapThreadVars *)user;
241 Packet *p = PacketGetFromQueueOrAlloc();
242 struct timeval current_time;
243
244 if (unlikely(p == NULL)) {
245 SCReturn;
246 }
247
248 PKT_SET_SRC(p, PKT_SRC_WIRE);
249 p->ts.tv_sec = h->ts.tv_sec;
250 p->ts.tv_usec = h->ts.tv_usec;
251 SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec);
252 p->datalink = ptv->datalink;
253
254 ptv->pkts++;
255 ptv->bytes += h->caplen;
256 (void) SC_ATOMIC_ADD(ptv->livedev->pkts, 1);
257 p->livedev = ptv->livedev;
258
259 if (unlikely(PacketCopyData(p, pkt, h->caplen))) {
260 TmqhOutputPacketpool(ptv->tv, p);
261 SCReturn;
262 }
263
264 switch (ptv->checksum_mode) {
265 case CHECKSUM_VALIDATION_AUTO:
266 if (ChecksumAutoModeCheck(ptv->pkts,
267 SC_ATOMIC_GET(ptv->livedev->pkts),
268 SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) {
269 ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE;
270 p->flags |= PKT_IGNORE_CHECKSUM;
271 }
272 break;
273 case CHECKSUM_VALIDATION_DISABLE:
274 p->flags |= PKT_IGNORE_CHECKSUM;
275 break;
276 default:
277 break;
278 }
279
280 if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
281 pcap_breakloop(ptv->pcap_handle);
282 ptv->cb_result = TM_ECODE_FAILED;
283 }
284
285 /* Trigger one dump of stats every second */
286 TimeGet(¤t_time);
287 if (current_time.tv_sec != ptv->last_stats_dump) {
288 PcapDumpCounters(ptv);
289 ptv->last_stats_dump = current_time.tv_sec;
290 }
291
292 SCReturn;
293 }
294
295 #ifndef PCAP_ERROR_BREAK
296 #define PCAP_ERROR_BREAK -2
297 #endif
298
299 /**
300 * \brief Main PCAP reading Loop function
301 */
ReceivePcapLoop(ThreadVars * tv,void * data,void * slot)302 static TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot)
303 {
304 SCEnter();
305
306 int packet_q_len = 64;
307 PcapThreadVars *ptv = (PcapThreadVars *)data;
308 TmSlot *s = (TmSlot *)slot;
309
310 ptv->slot = s->slot_next;
311 ptv->cb_result = TM_ECODE_OK;
312
313 while (1) {
314 if (suricata_ctl_flags & SURICATA_STOP) {
315 SCReturnInt(TM_ECODE_OK);
316 }
317
318 /* make sure we have at least one packet in the packet pool, to prevent
319 * us from alloc'ing packets at line rate */
320 PacketPoolWait();
321
322 int r = pcap_dispatch(ptv->pcap_handle, packet_q_len,
323 (pcap_handler)PcapCallbackLoop, (u_char *)ptv);
324 if (unlikely(r == 0 || r == PCAP_ERROR_BREAK)) {
325 if (r == PCAP_ERROR_BREAK && ptv->cb_result == TM_ECODE_FAILED) {
326 SCReturnInt(TM_ECODE_FAILED);
327 }
328 TmThreadsCaptureHandleTimeout(tv, NULL);
329 } else if (unlikely(r < 0)) {
330 int dbreak = 0;
331 SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s",
332 r, pcap_geterr(ptv->pcap_handle));
333 do {
334 usleep(PCAP_RECONNECT_TIMEOUT);
335 if (suricata_ctl_flags != 0) {
336 dbreak = 1;
337 break;
338 }
339 r = PcapTryReopen(ptv);
340 } while (r < 0);
341 if (dbreak) {
342 break;
343 }
344 } else if (ptv->cb_result == TM_ECODE_FAILED) {
345 SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapCallbackLoop failed");
346 SCReturnInt(TM_ECODE_FAILED);
347 }
348
349 StatsSyncCountersIfSignalled(tv);
350 }
351
352 PcapDumpCounters(ptv);
353 StatsSyncCountersIfSignalled(tv);
354 SCReturnInt(TM_ECODE_OK);
355 }
356
357 /**
358 * \brief PCAP Break Loop function.
359 */
ReceivePcapBreakLoop(ThreadVars * tv,void * data)360 static TmEcode ReceivePcapBreakLoop(ThreadVars *tv, void *data)
361 {
362 SCEnter();
363 PcapThreadVars *ptv = (PcapThreadVars *)data;
364 if (ptv->pcap_handle == NULL) {
365 SCReturnInt(TM_ECODE_FAILED);
366 }
367 pcap_breakloop(ptv->pcap_handle);
368 SCReturnInt(TM_ECODE_OK);
369 }
370
371 /**
372 * \brief Init function for ReceivePcap.
373 *
374 * This is a setup function for recieving packets
375 * via libpcap. There are two versions of this function
376 * depending on the major version of libpcap used.
377 * For versions prior to 1.x we use open_pcap_live,
378 * for versions 1.x and greater we use pcap_create + pcap_activate.
379 *
380 * \param tv pointer to ThreadVars
381 * \param initdata pointer to the interface passed from the user
382 * \param data pointer gets populated with PcapThreadVars
383 *
384 * \todo Create a general pcap setup function.
385 */
ReceivePcapThreadInit(ThreadVars * tv,const void * initdata,void ** data)386 static TmEcode ReceivePcapThreadInit(ThreadVars *tv, const void *initdata, void **data)
387 {
388 SCEnter();
389 PcapIfaceConfig *pcapconfig = (PcapIfaceConfig *)initdata;
390
391 if (initdata == NULL) {
392 SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL");
393 SCReturnInt(TM_ECODE_FAILED);
394 }
395
396 PcapThreadVars *ptv = SCCalloc(1, sizeof(PcapThreadVars));
397 if (unlikely(ptv == NULL)) {
398 pcapconfig->DerefFunc(pcapconfig);
399 SCReturnInt(TM_ECODE_FAILED);
400 }
401
402 ptv->tv = tv;
403
404 ptv->livedev = LiveGetDevice(pcapconfig->iface);
405 if (ptv->livedev == NULL) {
406 SCLogError(SC_ERR_INVALID_VALUE, "unable to find Live device");
407 SCFree(ptv);
408 SCReturnInt(TM_ECODE_FAILED);
409 }
410 SCLogInfo("using interface %s", (char *)pcapconfig->iface);
411
412 if (LiveGetOffload() == 0) {
413 (void)GetIfaceOffloading((char *)pcapconfig->iface, 1, 1);
414 } else {
415 DisableIfaceOffloading(ptv->livedev, 1, 1);
416 }
417
418 ptv->checksum_mode = pcapconfig->checksum_mode;
419 if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) {
420 SCLogInfo("running in 'auto' checksum mode. Detection of interface "
421 "state will require " xstr(CHECKSUM_SAMPLE_COUNT) " packets");
422 }
423
424 char errbuf[PCAP_ERRBUF_SIZE];
425 ptv->pcap_handle = pcap_create((char *)pcapconfig->iface, errbuf);
426 if (ptv->pcap_handle == NULL) {
427 if (strlen(errbuf)) {
428 SCLogError(SC_ERR_PCAP_CREATE, "could not create a new "
429 "pcap handler for %s, error %s",
430 (char *)pcapconfig->iface, errbuf);
431 } else {
432 SCLogError(SC_ERR_PCAP_CREATE, "could not create a new "
433 "pcap handler for %s",
434 (char *)pcapconfig->iface);
435 }
436 SCFree(ptv);
437 pcapconfig->DerefFunc(pcapconfig);
438 SCReturnInt(TM_ECODE_FAILED);
439 }
440
441 if (pcapconfig->snaplen == 0) {
442 /* We set snaplen if we can get the MTU */
443 ptv->pcap_snaplen = GetIfaceMaxPacketSize(pcapconfig->iface);
444 } else {
445 ptv->pcap_snaplen = pcapconfig->snaplen;
446 }
447 if (ptv->pcap_snaplen > 0) {
448 /* set Snaplen. Must be called before pcap_activate */
449 int pcap_set_snaplen_r = pcap_set_snaplen(ptv->pcap_handle, ptv->pcap_snaplen);
450 if (pcap_set_snaplen_r != 0) {
451 SCLogError(SC_ERR_PCAP_SET_SNAPLEN, "could not set snaplen, "
452 "error: %s", pcap_geterr(ptv->pcap_handle));
453 SCFree(ptv);
454 pcapconfig->DerefFunc(pcapconfig);
455 SCReturnInt(TM_ECODE_FAILED);
456 }
457 SCLogInfo("Set snaplen to %d for '%s'", ptv->pcap_snaplen,
458 pcapconfig->iface);
459 }
460
461 /* set Promisc, and Timeout. Must be called before pcap_activate */
462 int pcap_set_promisc_r = pcap_set_promisc(ptv->pcap_handle, pcapconfig->promisc);
463 if (pcap_set_promisc_r != 0) {
464 SCLogError(SC_ERR_PCAP_SET_PROMISC, "could not set promisc mode, "
465 "error %s", pcap_geterr(ptv->pcap_handle));
466 SCFree(ptv);
467 pcapconfig->DerefFunc(pcapconfig);
468 SCReturnInt(TM_ECODE_FAILED);
469 }
470
471 int pcap_set_timeout_r = pcap_set_timeout(ptv->pcap_handle, LIBPCAP_COPYWAIT);
472 if (pcap_set_timeout_r != 0) {
473 SCLogError(SC_ERR_PCAP_SET_TIMEOUT, "could not set timeout, "
474 "error %s", pcap_geterr(ptv->pcap_handle));
475 SCFree(ptv);
476 pcapconfig->DerefFunc(pcapconfig);
477 SCReturnInt(TM_ECODE_FAILED);
478 }
479 #ifdef HAVE_PCAP_SET_BUFF
480 ptv->pcap_buffer_size = pcapconfig->buffer_size;
481 if (ptv->pcap_buffer_size > 0) {
482 SCLogInfo("going to use pcap buffer size of %" PRId32,
483 ptv->pcap_buffer_size);
484
485 int pcap_set_buffer_size_r = pcap_set_buffer_size(ptv->pcap_handle,
486 ptv->pcap_buffer_size);
487 if (pcap_set_buffer_size_r != 0) {
488 SCLogError(SC_ERR_PCAP_SET_BUFF_SIZE, "could not set "
489 "pcap buffer size, error %s", pcap_geterr(ptv->pcap_handle));
490 SCFree(ptv);
491 pcapconfig->DerefFunc(pcapconfig);
492 SCReturnInt(TM_ECODE_FAILED);
493 }
494 }
495 #endif /* HAVE_PCAP_SET_BUFF */
496
497 /* activate the handle */
498 int pcap_activate_r = pcap_activate(ptv->pcap_handle);
499 if (pcap_activate_r != 0) {
500 SCLogError(SC_ERR_PCAP_ACTIVATE_HANDLE, "could not activate the "
501 "pcap handler, error %s", pcap_geterr(ptv->pcap_handle));
502 SCFree(ptv);
503 pcapconfig->DerefFunc(pcapconfig);
504 SCReturnInt(TM_ECODE_FAILED);
505 }
506 ptv->pcap_state = PCAP_STATE_UP;
507
508 /* set bpf filter if we have one */
509 if (pcapconfig->bpf_filter) {
510 SCMutexLock(&pcap_bpf_compile_lock);
511
512 ptv->bpf_filter = pcapconfig->bpf_filter;
513
514 if (pcap_compile(ptv->pcap_handle, &ptv->filter,
515 (char *)ptv->bpf_filter, 1, 0) < 0)
516 {
517 SCLogError(SC_ERR_BPF, "bpf compilation error %s",
518 pcap_geterr(ptv->pcap_handle));
519
520 SCMutexUnlock(&pcap_bpf_compile_lock);
521 SCFree(ptv);
522 pcapconfig->DerefFunc(pcapconfig);
523 return TM_ECODE_FAILED;
524 }
525
526 if (pcap_setfilter(ptv->pcap_handle, &ptv->filter) < 0) {
527 SCLogError(SC_ERR_BPF, "could not set bpf filter %s",
528 pcap_geterr(ptv->pcap_handle));
529
530 SCMutexUnlock(&pcap_bpf_compile_lock);
531 SCFree(ptv);
532 pcapconfig->DerefFunc(pcapconfig);
533 return TM_ECODE_FAILED;
534 }
535
536 SCMutexUnlock(&pcap_bpf_compile_lock);
537 }
538
539 /* no offloading supported at all */
540 (void)GetIfaceOffloading(pcapconfig->iface, 1, 1);
541
542 ptv->datalink = pcap_datalink(ptv->pcap_handle);
543
544 pcapconfig->DerefFunc(pcapconfig);
545
546 ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets",
547 ptv->tv);
548 ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops",
549 ptv->tv);
550 ptv->capture_kernel_ifdrops = StatsRegisterCounter("capture.kernel_ifdrops",
551 ptv->tv);
552
553 *data = (void *)ptv;
554 SCReturnInt(TM_ECODE_OK);
555 }
556
557 /**
558 * \brief This function prints stats to the screen at exit.
559 * \param tv pointer to ThreadVars
560 * \param data pointer that gets cast into PcapThreadVars for ptv
561 */
ReceivePcapThreadExitStats(ThreadVars * tv,void * data)562 static void ReceivePcapThreadExitStats(ThreadVars *tv, void *data)
563 {
564 SCEnter();
565 PcapThreadVars *ptv = (PcapThreadVars *)data;
566 struct pcap_stat pcap_s;
567
568 if (pcap_stats(ptv->pcap_handle, &pcap_s) < 0) {
569 SCLogError(SC_ERR_STAT,"(%s) Failed to get pcap_stats: %s",
570 tv->name, pcap_geterr(ptv->pcap_handle));
571 SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name,
572 ptv->pkts, ptv->bytes);
573 } else {
574 SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name,
575 ptv->pkts, ptv->bytes);
576
577 /* these numbers are not entirely accurate as ps_recv contains packets
578 * that are still waiting to be processed at exit. ps_drop only contains
579 * packets dropped by the driver and not any packets dropped by the interface.
580 * Additionally see http://tracker.icir.org/bro/ticket/18
581 *
582 * Note: ps_recv includes dropped packets and should be considered total.
583 * Unless we start to look at ps_ifdrop which isn't supported everywhere.
584 */
585 UpdatePcapStats64(&ptv->last_stats64, &pcap_s);
586 float drop_percent =
587 likely(ptv->last_stats64.ps_recv > 0)
588 ? (((float)ptv->last_stats64.ps_drop) /
589 (float)ptv->last_stats64.ps_recv) *
590 100
591 : 0;
592 SCLogInfo("(%s) Pcap Total:%" PRIu64 " Recv:%" PRIu64 " Drop:%" PRIu64
593 " (%02.1f%%).",
594 tv->name, ptv->last_stats64.ps_recv,
595 ptv->last_stats64.ps_recv - ptv->last_stats64.ps_drop,
596 ptv->last_stats64.ps_drop, drop_percent);
597 }
598 }
599
600 /**
601 * \brief This function passes off to link type decoders.
602 *
603 * DecodePcap decodes packets from libpcap and passes
604 * them off to the proper link type decoder.
605 *
606 * \param t pointer to ThreadVars
607 * \param p pointer to the current packet
608 * \param data pointer that gets cast into PcapThreadVars for ptv
609 */
DecodePcap(ThreadVars * tv,Packet * p,void * data)610 static TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data)
611 {
612 SCEnter();
613 DecodeThreadVars *dtv = (DecodeThreadVars *)data;
614
615 BUG_ON(PKT_IS_PSEUDOPKT(p));
616
617 /* update counters */
618 DecodeUpdatePacketCounters(tv, dtv, p);
619
620 DecodeLinkLayer(tv, dtv, p->datalink, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
621
622 PacketDecodeFinalize(tv, dtv, p);
623
624 SCReturnInt(TM_ECODE_OK);
625 }
626
DecodePcapThreadInit(ThreadVars * tv,const void * initdata,void ** data)627 static TmEcode DecodePcapThreadInit(ThreadVars *tv, const void *initdata, void **data)
628 {
629 SCEnter();
630
631 DecodeThreadVars *dtv = DecodeThreadVarsAlloc(tv);
632 if (dtv == NULL)
633 SCReturnInt(TM_ECODE_FAILED);
634
635 DecodeRegisterPerfCounters(dtv, tv);
636
637 *data = (void *)dtv;
638
639 SCReturnInt(TM_ECODE_OK);
640 }
641
DecodePcapThreadDeinit(ThreadVars * tv,void * data)642 static TmEcode DecodePcapThreadDeinit(ThreadVars *tv, void *data)
643 {
644 if (data != NULL)
645 DecodeThreadVarsFree(tv, data);
646 SCReturnInt(TM_ECODE_OK);
647 }
648
PcapTranslateIPToDevice(char * pcap_dev,size_t len)649 void PcapTranslateIPToDevice(char *pcap_dev, size_t len)
650 {
651 char errbuf[PCAP_ERRBUF_SIZE];
652 pcap_if_t *alldevsp = NULL;
653
654 struct addrinfo ai_hints;
655 struct addrinfo *ai_list = NULL;
656
657 memset(&ai_hints, 0, sizeof(ai_hints));
658 ai_hints.ai_family = AF_UNSPEC;
659 ai_hints.ai_flags = AI_NUMERICHOST;
660
661 /* try to translate IP */
662 if (getaddrinfo(pcap_dev, NULL, &ai_hints, &ai_list) != 0) {
663 return;
664 }
665
666 if (pcap_findalldevs(&alldevsp, errbuf)) {
667 freeaddrinfo(ai_list);
668 return;
669 }
670
671 for (pcap_if_t *devsp = alldevsp; devsp ; devsp = devsp->next) {
672 for (pcap_addr_t *ip = devsp->addresses; ip ; ip = ip->next) {
673
674 if (ai_list->ai_family != ip->addr->sa_family) {
675 continue;
676 }
677
678 if (ip->addr->sa_family == AF_INET) {
679 if (memcmp(&((struct sockaddr_in*)ai_list->ai_addr)->sin_addr,
680 &((struct sockaddr_in*)ip->addr)->sin_addr,
681 sizeof(struct in_addr)))
682 {
683 continue;
684 }
685 } else if (ip->addr->sa_family == AF_INET6) {
686 if (memcmp(&((struct sockaddr_in6*)ai_list->ai_addr)->sin6_addr,
687 &((struct sockaddr_in6*)ip->addr)->sin6_addr,
688 sizeof(struct in6_addr)))
689 {
690 continue;
691 }
692 } else {
693 continue;
694 }
695
696 freeaddrinfo(ai_list);
697
698 memset(pcap_dev, 0, len);
699 strlcpy(pcap_dev, devsp->name, len);
700
701 pcap_freealldevs(alldevsp);
702 return;
703 }
704 }
705
706 freeaddrinfo(ai_list);
707
708 pcap_freealldevs(alldevsp);
709 }
710
711 /*
712 * unittests
713 */
714
715 #ifdef UNITTESTS
716 #include "tests/source-pcap.c"
717 /**
718 * \brief Register the Unit tests for pcap source
719 */
SourcePcapRegisterTests(void)720 static void SourcePcapRegisterTests(void)
721 {
722 SourcePcapRegisterStatsTests();
723 }
724 #endif /* UNITTESTS */
725