Coverage Report

Created: 2025-11-16 07:09

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