• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OISF / suricata / 23374838686

21 Mar 2026 07:29AM UTC coverage: 59.341% (-20.0%) from 79.315%
23374838686

Pull #15075

github

web-flow
Merge 90b4e834f into 6587e363a
Pull Request #15075: Stack 8001 v16.4

38 of 70 new or added lines in 10 files covered. (54.29%)

34165 existing lines in 563 files now uncovered.

119621 of 201584 relevant lines covered (59.34%)

650666.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.36
/src/source-pcap.c
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-private.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
#define PCAP_STATE_DOWN 0
×
UNCOV
49
#define PCAP_STATE_UP 1
×
50

51
#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
    StatsCounterId capture_kernel_packets;
93
    StatsCounterId capture_kernel_drops;
94
    StatsCounterId 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
{
2✔
137
    tmm_modules[TMM_RECEIVEPCAP].name = "ReceivePcap";
2✔
138
    tmm_modules[TMM_RECEIVEPCAP].ThreadInit = ReceivePcapThreadInit;
2✔
139
    tmm_modules[TMM_RECEIVEPCAP].ThreadDeinit = ReceivePcapThreadDeinit;
2✔
140
    tmm_modules[TMM_RECEIVEPCAP].PktAcqLoop = ReceivePcapLoop;
2✔
141
    tmm_modules[TMM_RECEIVEPCAP].PktAcqBreakLoop = ReceivePcapBreakLoop;
2✔
142
    tmm_modules[TMM_RECEIVEPCAP].ThreadExitPrintStats = ReceivePcapThreadExitStats;
2✔
143
    tmm_modules[TMM_RECEIVEPCAP].cap_flags = SC_CAP_NET_RAW;
2✔
144
    tmm_modules[TMM_RECEIVEPCAP].flags = TM_FLAG_RECEIVE_TM;
2✔
145
#ifdef UNITTESTS
146
    tmm_modules[TMM_RECEIVEPCAP].RegisterTests = SourcePcapRegisterTests;
147
#endif
148
}
2✔
149

150
/**
151
 * \brief Registration Function for DecodePcap.
152
 */
153
void TmModuleDecodePcapRegister (void)
154
{
2✔
155
    tmm_modules[TMM_DECODEPCAP].name = "DecodePcap";
2✔
156
    tmm_modules[TMM_DECODEPCAP].ThreadInit = DecodePcapThreadInit;
2✔
157
    tmm_modules[TMM_DECODEPCAP].Func = DecodePcap;
2✔
158
    tmm_modules[TMM_DECODEPCAP].ThreadDeinit = DecodePcapThreadDeinit;
2✔
159
    tmm_modules[TMM_DECODEPCAP].flags = TM_FLAG_DECODE_TM;
2✔
160
}
2✔
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)
UNCOV
167
{
×
168
    /* uint64_t -> uint32_t is defined behaviour. It slices lower 32bits. */
UNCOV
169
    uint32_t last32 = (uint32_t)*last;
×
170

171
    /* Branchless code as wrap-around is defined for unsigned */
UNCOV
172
    *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
    */
UNCOV
181
}
×
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)
UNCOV
189
{
×
UNCOV
190
    UpdatePcapStatsValue64(&last->ps_recv, current->ps_recv);
×
UNCOV
191
    UpdatePcapStatsValue64(&last->ps_drop, current->ps_drop);
×
UNCOV
192
    UpdatePcapStatsValue64(&last->ps_ifdrop, current->ps_ifdrop);
×
UNCOV
193
}
×
194

195
static inline void PcapDumpCounters(PcapThreadVars *ptv)
UNCOV
196
{
×
UNCOV
197
    struct pcap_stat pcap_s;
×
UNCOV
198
    if (likely((pcap_stats(ptv->pcap_handle, &pcap_s) >= 0))) {
×
UNCOV
199
        UpdatePcapStats64(&ptv->last_stats64, &pcap_s);
×
200

UNCOV
201
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_kernel_packets, ptv->last_stats64.ps_recv);
×
UNCOV
202
        StatsCounterSetI64(&ptv->tv->stats, ptv->capture_kernel_drops, ptv->last_stats64.ps_drop);
×
UNCOV
203
        (void)SC_ATOMIC_SET(ptv->livedev->drop, ptv->last_stats64.ps_drop);
×
UNCOV
204
        StatsCounterSetI64(
×
UNCOV
205
                &ptv->tv->stats, ptv->capture_kernel_ifdrops, ptv->last_stats64.ps_ifdrop);
×
UNCOV
206
    }
×
UNCOV
207
}
×
208

209
static int PcapOpenInterface(PcapThreadVars *ptv)
UNCOV
210
{
×
UNCOV
211
    const char *iface = ptv->livedev->dev;
×
212

UNCOV
213
    if (ptv->pcap_handle) {
×
214
        pcap_close(ptv->pcap_handle);
×
215
        ptv->pcap_handle = NULL;
×
216
        if (ptv->filter.bf_insns) {
×
217
            SCBPFFree(&ptv->filter);
×
218
        }
×
219
    }
×
220

UNCOV
221
    if (LiveGetOffload() == 0) {
×
222
        (void)GetIfaceOffloading(iface, 1, 1);
×
UNCOV
223
    } else {
×
UNCOV
224
        DisableIfaceOffloading(ptv->livedev, 1, 1);
×
UNCOV
225
    }
×
226

UNCOV
227
    char errbuf[PCAP_ERRBUF_SIZE];
×
UNCOV
228
    ptv->pcap_handle = pcap_create(iface, errbuf);
×
UNCOV
229
    if (ptv->pcap_handle == NULL) {
×
230
        if (strlen(errbuf)) {
×
231
            SCLogError("%s: could not create a new pcap handler, error %s", iface, errbuf);
×
232
        } else {
×
233
            SCLogError("%s: could not create a new pcap handler", iface);
×
234
        }
×
235
        SCReturnInt(TM_ECODE_FAILED);
×
236
    }
×
237

UNCOV
238
    if (ptv->pcap_snaplen > 0) {
×
239
        /* set Snaplen. Must be called before pcap_activate */
UNCOV
240
        int pcap_set_snaplen_r = pcap_set_snaplen(ptv->pcap_handle, ptv->pcap_snaplen);
×
UNCOV
241
        if (pcap_set_snaplen_r != 0) {
×
242
            SCLogError(
×
243
                    "%s: could not set snaplen, error: %s", iface, pcap_geterr(ptv->pcap_handle));
×
244
            SCReturnInt(TM_ECODE_FAILED);
×
245
        }
×
UNCOV
246
        SCLogInfo("%s: snaplen set to %d", iface, ptv->pcap_snaplen);
×
UNCOV
247
    }
×
248

UNCOV
249
    if (ptv->promisc) {
×
250
        /* set Promisc, and Timeout. Must be called before pcap_activate */
UNCOV
251
        int pcap_set_promisc_r = pcap_set_promisc(ptv->pcap_handle, ptv->promisc);
×
UNCOV
252
        if (pcap_set_promisc_r != 0) {
×
253
            SCLogError("%s: could not set promisc mode, error %s", iface,
×
254
                    pcap_geterr(ptv->pcap_handle));
×
255
            SCReturnInt(TM_ECODE_FAILED);
×
256
        }
×
UNCOV
257
    }
×
258

UNCOV
259
    int pcap_set_timeout_r = pcap_set_timeout(ptv->pcap_handle, LIBPCAP_COPYWAIT);
×
UNCOV
260
    if (pcap_set_timeout_r != 0) {
×
261
        SCLogError("%s: could not set timeout, error %s", iface, pcap_geterr(ptv->pcap_handle));
×
262
        SCReturnInt(TM_ECODE_FAILED);
×
263
    }
×
UNCOV
264
#ifdef HAVE_PCAP_SET_BUFF
×
UNCOV
265
    if (ptv->pcap_buffer_size > 0) {
×
266
        SCLogInfo("%s: going to use pcap buffer size of %" PRId32, iface, ptv->pcap_buffer_size);
×
267

268
        int pcap_set_buffer_size_r = pcap_set_buffer_size(ptv->pcap_handle, ptv->pcap_buffer_size);
×
269
        if (pcap_set_buffer_size_r != 0) {
×
270
            SCLogError("%s: could not set pcap buffer size, error %s", iface,
×
271
                    pcap_geterr(ptv->pcap_handle));
×
272
            SCReturnInt(TM_ECODE_FAILED);
×
273
        }
×
274
    }
×
UNCOV
275
#endif /* HAVE_PCAP_SET_BUFF */
×
276

277
    /* activate the handle */
UNCOV
278
    int pcap_activate_r = pcap_activate(ptv->pcap_handle);
×
UNCOV
279
    if (pcap_activate_r != 0) {
×
280
        SCLogError("%s: could not activate the pcap handler, error %s", iface,
×
281
                pcap_geterr(ptv->pcap_handle));
×
282
        pcap_close(ptv->pcap_handle);
×
283
        ptv->pcap_handle = NULL;
×
284
        SCReturnInt(TM_ECODE_FAILED);
×
285
    }
×
UNCOV
286
    ptv->pcap_state = PCAP_STATE_UP;
×
287

288
    /* set bpf filter if we have one */
UNCOV
289
    if (ptv->bpf_filter) {
×
290
        SCMutexLock(&pcap_bpf_compile_lock);
×
291

292
        if (pcap_compile(ptv->pcap_handle, &ptv->filter, (char *)ptv->bpf_filter, 1, 0) < 0) {
×
293
            SCLogError("%s: bpf compilation error %s", iface, pcap_geterr(ptv->pcap_handle));
×
294
            SCMutexUnlock(&pcap_bpf_compile_lock);
×
295
            return TM_ECODE_FAILED;
×
296
        }
×
297

298
        if (pcap_setfilter(ptv->pcap_handle, &ptv->filter) < 0) {
×
299
            SCLogError("%s: could not set bpf filter %s", iface, pcap_geterr(ptv->pcap_handle));
×
300
            SCMutexUnlock(&pcap_bpf_compile_lock);
×
301
            return TM_ECODE_FAILED;
×
302
        }
×
303

304
        SCMutexUnlock(&pcap_bpf_compile_lock);
×
305
    }
×
306

307
    /* no offloading supported at all */
UNCOV
308
    (void)GetIfaceOffloading(iface, 1, 1);
×
UNCOV
309
    return TM_ECODE_OK;
×
UNCOV
310
}
×
311

312
static int PcapTryReopen(PcapThreadVars *ptv)
313
{
×
314
    ptv->pcap_state = PCAP_STATE_DOWN;
×
315

316
    if (PcapOpenInterface(ptv) != TM_ECODE_OK)
×
317
        return -1;
×
318

319
    SCLogInfo("%s: interface recovered, state is now \"up\"", ptv->livedev->dev);
×
320
    ptv->pcap_state = PCAP_STATE_UP;
×
321
    return 0;
×
322
}
×
323

324
static void PcapCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt)
UNCOV
325
{
×
UNCOV
326
    SCEnter();
×
327

UNCOV
328
    PcapThreadVars *ptv = (PcapThreadVars *)user;
×
UNCOV
329
    Packet *p = PacketGetFromQueueOrAlloc();
×
330

UNCOV
331
    if (unlikely(p == NULL)) {
×
332
        SCReturn;
×
333
    }
×
334

UNCOV
335
    PKT_SET_SRC(p, PKT_SRC_WIRE);
×
UNCOV
336
    p->ts = SCTIME_FROM_TIMEVAL(&h->ts);
×
UNCOV
337
    SCLogDebug("p->ts.tv_sec %" PRIuMAX "", (uintmax_t)SCTIME_SECS(p->ts));
×
UNCOV
338
    p->datalink = ptv->datalink;
×
339

UNCOV
340
    ptv->pkts++;
×
UNCOV
341
    ptv->bytes += h->caplen;
×
UNCOV
342
    (void) SC_ATOMIC_ADD(ptv->livedev->pkts, 1);
×
UNCOV
343
    p->livedev = ptv->livedev;
×
344

UNCOV
345
    if (unlikely(PacketCopyData(p, pkt, h->caplen))) {
×
346
        TmqhOutputPacketpool(ptv->tv, p);
×
347
        SCReturn;
×
348
    }
×
349

UNCOV
350
    switch (ptv->checksum_mode) {
×
UNCOV
351
        case CHECKSUM_VALIDATION_AUTO:
×
UNCOV
352
            if (ChecksumAutoModeCheck(ptv->pkts,
×
UNCOV
353
                        SC_ATOMIC_GET(ptv->livedev->pkts),
×
UNCOV
354
                        SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) {
×
355
                ptv->checksum_mode = CHECKSUM_VALIDATION_DISABLE;
×
356
                p->flags |= PKT_IGNORE_CHECKSUM;
×
357
            }
×
UNCOV
358
            break;
×
359
        case CHECKSUM_VALIDATION_DISABLE:
×
360
            p->flags |= PKT_IGNORE_CHECKSUM;
×
361
            break;
×
362
        default:
×
363
            break;
×
UNCOV
364
    }
×
365

UNCOV
366
    if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
×
367
        pcap_breakloop(ptv->pcap_handle);
×
368
        ptv->cb_result = TM_ECODE_FAILED;
×
369
    }
×
370

371
    /* Trigger one dump of stats every second */
UNCOV
372
    SCTime_t current_time = TimeGet();
×
UNCOV
373
    if ((time_t)SCTIME_SECS(current_time) != ptv->last_stats_dump) {
×
UNCOV
374
        PcapDumpCounters(ptv);
×
UNCOV
375
        ptv->last_stats_dump = SCTIME_SECS(current_time);
×
UNCOV
376
    }
×
377

UNCOV
378
    SCReturn;
×
UNCOV
379
}
×
380

381
#ifndef PCAP_ERROR_BREAK
382
#define PCAP_ERROR_BREAK -2
383
#endif
384

385
/**
386
 *  \brief Main PCAP reading Loop function
387
 */
388
static TmEcode ReceivePcapLoop(ThreadVars *tv, void *data, void *slot)
UNCOV
389
{
×
UNCOV
390
    SCEnter();
×
391

UNCOV
392
    int packet_q_len = 64;
×
UNCOV
393
    PcapThreadVars *ptv = (PcapThreadVars *)data;
×
UNCOV
394
    TmSlot *s = (TmSlot *)slot;
×
395

UNCOV
396
    ptv->slot = s->slot_next;
×
UNCOV
397
    ptv->cb_result = TM_ECODE_OK;
×
398

399
    // Indicate that the thread is actually running its application level code (i.e., it can poll
400
    // packets)
UNCOV
401
    TmThreadsSetFlag(tv, THV_RUNNING);
×
402

UNCOV
403
    while (1) {
×
UNCOV
404
        if (suricata_ctl_flags & SURICATA_STOP) {
×
UNCOV
405
            SCReturnInt(TM_ECODE_OK);
×
UNCOV
406
        }
×
407

408
        /* make sure we have at least one packet in the packet pool, to prevent
409
         * us from alloc'ing packets at line rate */
UNCOV
410
        PacketPoolWait();
×
411

UNCOV
412
        int r = pcap_dispatch(ptv->pcap_handle, packet_q_len,
×
UNCOV
413
                          (pcap_handler)PcapCallbackLoop, (u_char *)ptv);
×
UNCOV
414
        if (unlikely(r == 0 || r == PCAP_ERROR_BREAK || (r > 0 && r < packet_q_len))) {
×
UNCOV
415
            if (r == PCAP_ERROR_BREAK && ptv->cb_result == TM_ECODE_FAILED) {
×
416
                SCReturnInt(TM_ECODE_FAILED);
×
417
            }
×
UNCOV
418
            TmThreadsCaptureHandleTimeout(tv, NULL);
×
UNCOV
419
        } else if (unlikely(r < 0)) {
×
420
            int dbreak = 0;
×
421
            SCLogError("error code %" PRId32 " %s", r, pcap_geterr(ptv->pcap_handle));
×
422
            do {
×
423
                SleepUsec(PCAP_RECONNECT_TIMEOUT);
×
424
                if (suricata_ctl_flags != 0) {
×
425
                    dbreak = 1;
×
426
                    break;
×
427
                }
×
428
                r = PcapTryReopen(ptv);
×
429
            } while (r < 0);
×
430
            if (dbreak) {
×
431
                break;
×
432
            }
×
433
        } else if (ptv->cb_result == TM_ECODE_FAILED) {
×
434
            SCLogError("Pcap callback PcapCallbackLoop failed");
×
435
            SCReturnInt(TM_ECODE_FAILED);
×
436
        }
×
437

UNCOV
438
        StatsSyncCountersIfSignalled(&tv->stats);
×
UNCOV
439
    }
×
440

441
    PcapDumpCounters(ptv);
×
442
    StatsSyncCountersIfSignalled(&tv->stats);
×
443
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
444
}
×
445

446
/**
447
 * \brief PCAP Break Loop function.
448
 */
449
static TmEcode ReceivePcapBreakLoop(ThreadVars *tv, void *data)
UNCOV
450
{
×
UNCOV
451
    SCEnter();
×
UNCOV
452
    PcapThreadVars *ptv = (PcapThreadVars *)data;
×
UNCOV
453
    if (ptv->pcap_handle == NULL) {
×
454
        SCReturnInt(TM_ECODE_FAILED);
×
455
    }
×
UNCOV
456
    pcap_breakloop(ptv->pcap_handle);
×
UNCOV
457
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
458
}
×
459

460
/**
461
 * \brief Init function for ReceivePcap.
462
 *
463
 * This is a setup function for receiving packets
464
 * via libpcap. There are two versions of this function
465
 * depending on the major version of libpcap used.
466
 * For versions prior to 1.x we use open_pcap_live,
467
 * for versions 1.x and greater we use pcap_create + pcap_activate.
468
 *
469
 * \param tv pointer to ThreadVars
470
 * \param initdata pointer to the interface passed from the user
471
 * \param data pointer gets populated with PcapThreadVars
472
 *
473
 * \todo Create a general pcap setup function.
474
 */
475
static TmEcode ReceivePcapThreadInit(ThreadVars *tv, const void *initdata, void **data)
UNCOV
476
{
×
UNCOV
477
    SCEnter();
×
UNCOV
478
    PcapIfaceConfig *pcapconfig = (PcapIfaceConfig *)initdata;
×
479

UNCOV
480
    if (initdata == NULL) {
×
481
        SCLogError("initdata == NULL");
×
482
        SCReturnInt(TM_ECODE_FAILED);
×
483
    }
×
484

UNCOV
485
    PcapThreadVars *ptv = SCCalloc(1, sizeof(PcapThreadVars));
×
UNCOV
486
    if (unlikely(ptv == NULL)) {
×
487
        pcapconfig->DerefFunc(pcapconfig);
×
488
        SCReturnInt(TM_ECODE_FAILED);
×
489
    }
×
490

UNCOV
491
    ptv->tv = tv;
×
492

UNCOV
493
    ptv->livedev = LiveGetDevice(pcapconfig->iface);
×
UNCOV
494
    if (ptv->livedev == NULL) {
×
495
        SCLogError("unable to find Live device");
×
496
        ReceivePcapThreadDeinit(tv, ptv);
×
497
        SCReturnInt(TM_ECODE_FAILED);
×
498
    }
×
499

UNCOV
500
    if (LiveGetOffload() == 0) {
×
501
        (void)GetIfaceOffloading((char *)pcapconfig->iface, 1, 1);
×
UNCOV
502
    } else {
×
UNCOV
503
        DisableIfaceOffloading(ptv->livedev, 1, 1);
×
UNCOV
504
    }
×
505

UNCOV
506
    ptv->checksum_mode = pcapconfig->checksum_mode;
×
UNCOV
507
    if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) {
×
UNCOV
508
        SCLogInfo("%s: running in 'auto' checksum mode. Detection of interface "
×
UNCOV
509
                  "state will require %llu packets",
×
UNCOV
510
                ptv->livedev->dev, CHECKSUM_SAMPLE_COUNT);
×
UNCOV
511
    }
×
512

UNCOV
513
    if (pcapconfig->snaplen == 0) {
×
514
        /* We set snaplen if we can get the MTU */
UNCOV
515
        ptv->pcap_snaplen = GetIfaceMaxPacketSize(ptv->livedev);
×
UNCOV
516
    } else {
×
517
        ptv->pcap_snaplen = pcapconfig->snaplen;
×
518
    }
×
519

UNCOV
520
    ptv->promisc = pcapconfig->promisc;
×
UNCOV
521
    ptv->pcap_buffer_size = pcapconfig->buffer_size;
×
UNCOV
522
    ptv->bpf_filter = pcapconfig->bpf_filter;
×
523

UNCOV
524
    if (PcapOpenInterface(ptv) != TM_ECODE_OK) {
×
525
        ReceivePcapThreadDeinit(tv, ptv);
×
526
        pcapconfig->DerefFunc(pcapconfig);
×
527
        SCReturnInt(TM_ECODE_FAILED);
×
528
    }
×
UNCOV
529
    ptv->pcap_state = PCAP_STATE_UP;
×
530

UNCOV
531
    ptv->datalink = pcap_datalink(ptv->pcap_handle);
×
UNCOV
532
    DatalinkSetGlobalType(ptv->datalink);
×
533

UNCOV
534
    pcapconfig->DerefFunc(pcapconfig);
×
535

UNCOV
536
    ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", &ptv->tv->stats);
×
UNCOV
537
    ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", &ptv->tv->stats);
×
UNCOV
538
    ptv->capture_kernel_ifdrops = StatsRegisterCounter("capture.kernel_ifdrops", &ptv->tv->stats);
×
539

UNCOV
540
    *data = (void *)ptv;
×
UNCOV
541
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
542
}
×
543

544
/**
545
 * \brief This function prints stats to the screen at exit.
546
 * \param tv pointer to ThreadVars
547
 * \param data pointer that gets cast into PcapThreadVars for ptv
548
 */
549
static void ReceivePcapThreadExitStats(ThreadVars *tv, void *data)
UNCOV
550
{
×
UNCOV
551
    SCEnter();
×
UNCOV
552
    PcapThreadVars *ptv = (PcapThreadVars *)data;
×
UNCOV
553
    struct pcap_stat pcap_s;
×
554

UNCOV
555
    if (pcap_stats(ptv->pcap_handle, &pcap_s) < 0) {
×
556
        SCLogError("%s: failed to get pcap_stats: %s", ptv->livedev->dev,
×
557
                pcap_geterr(ptv->pcap_handle));
×
558
        SCLogInfo("%s: packets %" PRIu64 ", bytes %" PRIu64 "", ptv->livedev->dev, ptv->pkts,
×
559
                ptv->bytes);
×
UNCOV
560
    } else {
×
UNCOV
561
        SCLogInfo("%s: packets %" PRIu64 ", bytes %" PRIu64 "", ptv->livedev->dev, ptv->pkts,
×
UNCOV
562
                ptv->bytes);
×
563

564
        /* these numbers are not entirely accurate as ps_recv contains packets
565
         * that are still waiting to be processed at exit. ps_drop only contains
566
         * packets dropped by the driver and not any packets dropped by the interface.
567
         * Additionally see http://tracker.icir.org/bro/ticket/18
568
         *
569
         * Note: ps_recv includes dropped packets and should be considered total.
570
         * Unless we start to look at ps_ifdrop which isn't supported everywhere.
571
         */
UNCOV
572
        UpdatePcapStats64(&ptv->last_stats64, &pcap_s);
×
UNCOV
573
        float drop_percent =
×
UNCOV
574
                likely(ptv->last_stats64.ps_recv > 0)
×
UNCOV
575
                        ? (((float)ptv->last_stats64.ps_drop) /
×
UNCOV
576
                                  (float)ptv->last_stats64.ps_recv) *
×
UNCOV
577
                                  100
×
UNCOV
578
                        : 0;
×
UNCOV
579
        SCLogInfo("%s: pcap total:%" PRIu64 " recv:%" PRIu64 " drop:%" PRIu64 " (%02.1f%%)",
×
UNCOV
580
                ptv->livedev->dev, ptv->last_stats64.ps_recv,
×
UNCOV
581
                ptv->last_stats64.ps_recv - ptv->last_stats64.ps_drop, ptv->last_stats64.ps_drop,
×
UNCOV
582
                drop_percent);
×
UNCOV
583
    }
×
UNCOV
584
}
×
585

586
static TmEcode ReceivePcapThreadDeinit(ThreadVars *tv, void *data)
UNCOV
587
{
×
UNCOV
588
    SCEnter();
×
UNCOV
589
    PcapThreadVars *ptv = (PcapThreadVars *)data;
×
UNCOV
590
    if (ptv != NULL) {
×
UNCOV
591
        if (ptv->pcap_handle != NULL) {
×
UNCOV
592
            pcap_close(ptv->pcap_handle);
×
UNCOV
593
        }
×
UNCOV
594
        if (ptv->filter.bf_insns) {
×
595
            SCBPFFree(&ptv->filter);
×
596
        }
×
UNCOV
597
        SCFree(ptv);
×
UNCOV
598
    }
×
UNCOV
599
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
600
}
×
601

602
/**
603
 * \brief This function passes off to link type decoders.
604
 *
605
 * DecodePcap decodes packets from libpcap and passes
606
 * them off to the proper link type decoder.
607
 *
608
 * \param t pointer to ThreadVars
609
 * \param p pointer to the current packet
610
 * \param data pointer that gets cast into PcapThreadVars for ptv
611
 */
612
static TmEcode DecodePcap(ThreadVars *tv, Packet *p, void *data)
UNCOV
613
{
×
UNCOV
614
    SCEnter();
×
UNCOV
615
    DecodeThreadVars *dtv = (DecodeThreadVars *)data;
×
616

UNCOV
617
    BUG_ON(PKT_IS_PSEUDOPKT(p));
×
618

619
    /* update counters */
UNCOV
620
    DecodeUpdatePacketCounters(tv, dtv, p);
×
621

UNCOV
622
    DecodeLinkLayer(tv, dtv, p->datalink, p, GET_PKT_DATA(p), GET_PKT_LEN(p));
×
623

UNCOV
624
    PacketDecodeFinalize(tv, dtv, p);
×
625

UNCOV
626
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
627
}
×
628

629
static TmEcode DecodePcapThreadInit(ThreadVars *tv, const void *initdata, void **data)
UNCOV
630
{
×
UNCOV
631
    SCEnter();
×
632

UNCOV
633
    DecodeThreadVars *dtv = DecodeThreadVarsAlloc(tv);
×
UNCOV
634
    if (dtv == NULL)
×
635
        SCReturnInt(TM_ECODE_FAILED);
×
636

UNCOV
637
    DecodeRegisterPerfCounters(dtv, tv);
×
638

UNCOV
639
    *data = (void *)dtv;
×
640

UNCOV
641
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
642
}
×
643

644
static TmEcode DecodePcapThreadDeinit(ThreadVars *tv, void *data)
UNCOV
645
{
×
UNCOV
646
    if (data != NULL)
×
UNCOV
647
        DecodeThreadVarsFree(tv, data);
×
UNCOV
648
    SCReturnInt(TM_ECODE_OK);
×
UNCOV
649
}
×
650

651
void PcapTranslateIPToDevice(char *pcap_dev, size_t len)
UNCOV
652
{
×
UNCOV
653
    char errbuf[PCAP_ERRBUF_SIZE];
×
UNCOV
654
    pcap_if_t *alldevsp = NULL;
×
655

UNCOV
656
    struct addrinfo ai_hints;
×
UNCOV
657
    struct addrinfo *ai_list = NULL;
×
658

UNCOV
659
    memset(&ai_hints, 0, sizeof(ai_hints));
×
UNCOV
660
    ai_hints.ai_family = AF_UNSPEC;
×
UNCOV
661
    ai_hints.ai_flags = AI_NUMERICHOST;
×
662

663
    /* try to translate IP */
UNCOV
664
    if (getaddrinfo(pcap_dev, NULL, &ai_hints, &ai_list) != 0) {
×
UNCOV
665
        return;
×
UNCOV
666
    }
×
667

668
    if (pcap_findalldevs(&alldevsp, errbuf)) {
×
669
        freeaddrinfo(ai_list);
×
670
        return;
×
671
    }
×
672

673
    for (pcap_if_t *devsp = alldevsp; devsp ; devsp = devsp->next) {
×
674
        for (pcap_addr_t *ip = devsp->addresses; ip ; ip = ip->next) {
×
675

676
            if (ai_list->ai_family != ip->addr->sa_family) {
×
677
                continue;
×
678
            }
×
679

680
            if (ip->addr->sa_family == AF_INET) {
×
681
                if (memcmp(&((struct sockaddr_in*)ai_list->ai_addr)->sin_addr,
×
682
                            &((struct sockaddr_in*)ip->addr)->sin_addr,
×
683
                            sizeof(struct in_addr)))
×
684
                {
×
685
                    continue;
×
686
                }
×
687
            } else if (ip->addr->sa_family == AF_INET6) {
×
688
                if (memcmp(&((struct sockaddr_in6*)ai_list->ai_addr)->sin6_addr,
×
689
                            &((struct sockaddr_in6*)ip->addr)->sin6_addr,
×
690
                            sizeof(struct in6_addr)))
×
691
                {
×
692
                    continue;
×
693
                }
×
694
            } else {
×
695
                continue;
×
696
            }
×
697

698
            freeaddrinfo(ai_list);
×
699

700
            memset(pcap_dev, 0, len);
×
701
            strlcpy(pcap_dev, devsp->name, len);
×
702

703
            pcap_freealldevs(alldevsp);
×
704
            return;
×
705
        }
×
706
    }
×
707

708
    freeaddrinfo(ai_list);
×
709

710
    pcap_freealldevs(alldevsp);
×
711
}
×
712

713
/*
714
 *  unittests
715
 */
716

717
#ifdef UNITTESTS
718
#include "tests/source-pcap.c"
719
/**
720
 *  \brief  Register the Unit tests for pcap source
721
 */
722
static void SourcePcapRegisterTests(void)
723
{
724
    SourcePcapRegisterStatsTests();
725
}
726
#endif /* UNITTESTS */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc