1 /*
2 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2010-2013 Sourcefire, Inc.
4 ** Author: Michael R. Altizer <mialtize@cisco.com>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation. You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <errno.h>
27 #include <pcap.h>
28 #include <pthread.h>
29 #include <stdbool.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "daq_module_api.h"
34
35 #define DAQ_PCAP_VERSION 4
36
37 #define PCAP_DEFAULT_POOL_SIZE 16
38 #define DAQ_PCAP_ROLLOVER_LIM 1000000000 //Check for rollover every billionth packet
39
40 #define SET_ERROR(modinst, ...) daq_base_api.set_errbuf(modinst, __VA_ARGS__)
41
42 typedef struct _pcap_pkt_desc
43 {
44 DAQ_Msg_t msg;
45 DAQ_PktHdr_t pkthdr;
46 uint8_t *data;
47 struct _pcap_pkt_desc *next;
48 } PcapPktDesc;
49
50 typedef struct _pcap_msg_pool
51 {
52 PcapPktDesc *pool;
53 PcapPktDesc *freelist;
54 DAQ_MsgPoolInfo_t info;
55 } PcapMsgPool;
56
57 typedef struct _pcap_context
58 {
59 /* Configuration */
60 char *device;
61 char *filter_string;
62 unsigned snaplen;
63 bool promisc_mode;
64 bool immediate_mode;
65 int timeout;
66 struct timeval timeout_tv;
67 int buffer_size;
68 DAQ_Mode mode;
69 bool readback_timeout;
70 /* State */
71 DAQ_ModuleInstance_h modinst;
72 DAQ_Stats_t stats;
73 char pcap_errbuf[PCAP_ERRBUF_SIZE];
74 PcapMsgPool pool;
75 pcap_t *handle;
76 FILE *fp;
77 uint32_t netmask;
78 bool nonblocking;
79 volatile bool interrupted;
80 /* Readback timeout state */
81 struct timeval last_recv;
82 PcapPktDesc *pending_desc;
83 bool final_readback_timeout;
84 /* Stats tracking */
85 uint32_t base_recv;
86 uint32_t base_drop;
87 uint64_t rollover_recv;
88 uint64_t rollover_drop;
89 uint32_t wrap_recv;
90 uint32_t wrap_drop;
91 uint32_t hwupdate_count;
92 } Pcap_Context_t;
93
94 static void pcap_daq_reset_stats(void *handle);
95
96 static DAQ_VariableDesc_t pcap_variable_descriptions[] = {
97 { "buffer_size", "Packet buffer space to allocate in bytes", DAQ_VAR_DESC_REQUIRES_ARGUMENT },
98 { "no_promiscuous", "Disables opening the interface in promiscuous mode", DAQ_VAR_DESC_FORBIDS_ARGUMENT },
99 { "no_immediate", "Disables immediate mode for traffic capture (may cause unbounded blocking)", DAQ_VAR_DESC_FORBIDS_ARGUMENT },
100 { "readback_timeout", "Return timeout receive status in file readback mode", DAQ_VAR_DESC_FORBIDS_ARGUMENT },
101 };
102
103 static DAQ_BaseAPI_t daq_base_api;
104 static pthread_mutex_t bpf_mutex = PTHREAD_MUTEX_INITIALIZER;
105
destroy_packet_pool(Pcap_Context_t * pc)106 static void destroy_packet_pool(Pcap_Context_t *pc)
107 {
108 PcapMsgPool *pool = &pc->pool;
109 if (pool->pool)
110 {
111 while (pool->info.size > 0)
112 free(pool->pool[--pool->info.size].data);
113 free(pool->pool);
114 pool->pool = NULL;
115 }
116 pool->freelist = NULL;
117 pool->info.available = 0;
118 pool->info.mem_size = 0;
119 }
120
create_packet_pool(Pcap_Context_t * pc,unsigned size)121 static int create_packet_pool(Pcap_Context_t *pc, unsigned size)
122 {
123 PcapMsgPool *pool = &pc->pool;
124 pool->pool = calloc(sizeof(PcapPktDesc), size);
125 if (!pool->pool)
126 {
127 SET_ERROR(pc->modinst, "%s: Could not allocate %zu bytes for a packet descriptor pool!",
128 __func__, sizeof(PcapPktDesc) * size);
129 return DAQ_ERROR_NOMEM;
130 }
131 pool->info.mem_size = sizeof(PcapPktDesc) * size;
132 while (pool->info.size < size)
133 {
134 /* Allocate packet data and set up descriptor */
135 PcapPktDesc *desc = &pool->pool[pool->info.size];
136 desc->data = malloc(pc->snaplen);
137 if (!desc->data)
138 {
139 SET_ERROR(pc->modinst, "%s: Could not allocate %d bytes for a packet descriptor message buffer!",
140 __func__, pc->snaplen);
141 return DAQ_ERROR_NOMEM;
142 }
143 pool->info.mem_size += pc->snaplen;
144
145 /* Initialize non-zero invariant packet header fields. */
146 DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
147 pkthdr->ingress_index = DAQ_PKTHDR_UNKNOWN;
148 pkthdr->egress_index = DAQ_PKTHDR_UNKNOWN;
149 pkthdr->ingress_group = DAQ_PKTHDR_UNKNOWN;
150 pkthdr->egress_group = DAQ_PKTHDR_UNKNOWN;
151
152 /* Initialize non-zero invariant message header fields. */
153 DAQ_Msg_t *msg = &desc->msg;
154 msg->type = DAQ_MSG_TYPE_PACKET;
155 msg->hdr_len = sizeof(desc->pkthdr);
156 msg->hdr = &desc->pkthdr;
157 msg->data = desc->data;
158 msg->owner = pc->modinst;
159 msg->priv = desc;
160
161 /* Place it on the free list */
162 desc->next = pool->freelist;
163 pool->freelist = desc;
164
165 pool->info.size++;
166 }
167 pool->info.available = pool->info.size;
168 return DAQ_SUCCESS;
169 }
170
update_hw_stats(Pcap_Context_t * pc)171 static int update_hw_stats(Pcap_Context_t *pc)
172 {
173 struct pcap_stat ps;
174
175 if (pc->handle && pc->device)
176 {
177 memset(&ps, 0, sizeof(struct pcap_stat));
178 if (pcap_stats(pc->handle, &ps) == -1)
179 {
180 SET_ERROR(pc->modinst, "%s", pcap_geterr(pc->handle));
181 return DAQ_ERROR;
182 }
183
184 /* PCAP receive counter wrapped */
185 if (ps.ps_recv < pc->wrap_recv)
186 pc->rollover_recv += UINT32_MAX;
187
188 /* PCAP drop counter wrapped */
189 if (ps.ps_drop < pc->wrap_drop)
190 pc->rollover_drop += UINT32_MAX;
191
192 pc->wrap_recv = ps.ps_recv;
193 pc->wrap_drop = ps.ps_drop;
194
195 pc->stats.hw_packets_received = pc->rollover_recv + pc->wrap_recv - pc->base_recv;
196 pc->stats.hw_packets_dropped = pc->rollover_drop + pc->wrap_drop - pc->base_drop;
197 pc->hwupdate_count = 0;
198 }
199
200 return DAQ_SUCCESS;
201 }
202
set_nonblocking(Pcap_Context_t * pc,bool nonblocking)203 static inline int set_nonblocking(Pcap_Context_t *pc, bool nonblocking)
204 {
205 if (nonblocking != pc->nonblocking)
206 {
207 int status;
208 if ((status = pcap_setnonblock(pc->handle, nonblocking ? 1 : 0, pc->pcap_errbuf)) < 0)
209 {
210 SET_ERROR(pc->modinst, "%s", pc->pcap_errbuf);
211 return status;
212 }
213 pc->nonblocking = nonblocking;
214 }
215 return 0;
216 }
217
pcap_daq_module_load(const DAQ_BaseAPI_t * base_api)218 static int pcap_daq_module_load(const DAQ_BaseAPI_t *base_api)
219 {
220 if (base_api->api_version != DAQ_BASE_API_VERSION || base_api->api_size != sizeof(DAQ_BaseAPI_t))
221 return DAQ_ERROR;
222
223 daq_base_api = *base_api;
224
225 return DAQ_SUCCESS;
226 }
227
pcap_daq_module_unload(void)228 static int pcap_daq_module_unload(void)
229 {
230 memset(&daq_base_api, 0, sizeof(daq_base_api));
231 return DAQ_SUCCESS;
232 }
233
pcap_daq_get_variable_descs(const DAQ_VariableDesc_t ** var_desc_table)234 static int pcap_daq_get_variable_descs(const DAQ_VariableDesc_t **var_desc_table)
235 {
236 *var_desc_table = pcap_variable_descriptions;
237
238 return sizeof(pcap_variable_descriptions) / sizeof(DAQ_VariableDesc_t);
239 }
240
pcap_daq_instantiate(const DAQ_ModuleConfig_h modcfg,DAQ_ModuleInstance_h modinst,void ** ctxt_ptr)241 static int pcap_daq_instantiate(const DAQ_ModuleConfig_h modcfg, DAQ_ModuleInstance_h modinst, void **ctxt_ptr)
242 {
243 Pcap_Context_t *pc;
244
245 pc = calloc(1, sizeof(Pcap_Context_t));
246 if (!pc)
247 {
248 SET_ERROR(modinst, "%s: Couldn't allocate memory for the new PCAP context!", __func__);
249 return DAQ_ERROR_NOMEM;
250 }
251 pc->modinst = modinst;
252
253 pc->snaplen = daq_base_api.config_get_snaplen(modcfg);
254 pc->timeout = daq_base_api.config_get_timeout(modcfg);
255 pc->timeout_tv.tv_sec = pc->timeout / 1000;
256 pc->timeout_tv.tv_usec = (pc->timeout % 1000) * 1000;
257 pc->promisc_mode = true;
258 pc->immediate_mode = true;
259 pc->readback_timeout = false;
260
261 const char *varKey, *varValue;
262 daq_base_api.config_first_variable(modcfg, &varKey, &varValue);
263 while (varKey)
264 {
265 /* Retrieve the requested buffer size (default = 0) */
266 if (!strcmp(varKey, "buffer_size"))
267 pc->buffer_size = strtol(varValue, NULL, 10);
268 else if (!strcmp(varKey, "no_promiscuous"))
269 pc->promisc_mode = false;
270 else if (!strcmp(varKey, "no_immediate"))
271 pc->immediate_mode = false;
272 else if (!strcmp(varKey, "readback_timeout"))
273 pc->readback_timeout = true;
274
275 daq_base_api.config_next_variable(modcfg, &varKey, &varValue);
276 }
277
278 uint32_t pool_size = daq_base_api.config_get_msg_pool_size(modcfg);
279 int rval = create_packet_pool(pc, pool_size ? pool_size : PCAP_DEFAULT_POOL_SIZE);
280 if (rval != DAQ_SUCCESS)
281 {
282 destroy_packet_pool(pc);
283 free(pc);
284 return rval;
285 }
286
287 pc->mode = daq_base_api.config_get_mode(modcfg);
288 if (pc->mode == DAQ_MODE_READ_FILE)
289 {
290 const char *fname = daq_base_api.config_get_input(modcfg);
291 /* Special case: "-" is an alias for stdin */
292 if (fname[0] == '-' && fname[1] == '\0')
293 pc->fp = stdin;
294 else
295 {
296 pc->fp = fopen(daq_base_api.config_get_input(modcfg), "rb");
297 if (!pc->fp)
298 {
299 SET_ERROR(modinst, "%s: Couldn't open file '%s' for reading: %s", __func__,
300 daq_base_api.config_get_input(modcfg), strerror(errno));
301 destroy_packet_pool(pc);
302 free(pc);
303 return DAQ_ERROR_NOMEM;
304 }
305 }
306 }
307 else
308 {
309 pc->device = strdup(daq_base_api.config_get_input(modcfg));
310 if (!pc->device)
311 {
312 SET_ERROR(modinst, "%s: Couldn't allocate memory for the device string!", __func__);
313 destroy_packet_pool(pc);
314 free(pc);
315 return DAQ_ERROR_NOMEM;
316 }
317 }
318
319 pc->hwupdate_count = 0;
320
321 *ctxt_ptr = pc;
322
323 return DAQ_SUCCESS;
324 }
325
pcap_daq_destroy(void * handle)326 static void pcap_daq_destroy(void *handle)
327 {
328 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
329
330 if (pc->handle)
331 pcap_close(pc->handle);
332 if (pc->fp)
333 fclose(pc->fp);
334 if (pc->device)
335 free(pc->device);
336 if (pc->filter_string)
337 free(pc->filter_string);
338 destroy_packet_pool(pc);
339 free(pc);
340 }
341
pcap_daq_install_filter(Pcap_Context_t * pc,const char * filter)342 static int pcap_daq_install_filter(Pcap_Context_t *pc, const char *filter)
343 {
344 struct bpf_program fcode;
345
346 pthread_mutex_lock(&bpf_mutex);
347 if (pcap_compile(pc->handle, &fcode, filter, 1, pc->netmask) < 0)
348 {
349 pthread_mutex_unlock(&bpf_mutex);
350 SET_ERROR(pc->modinst, "%s: pcap_compile: %s", __func__, pcap_geterr(pc->handle));
351 return DAQ_ERROR;
352 }
353 pthread_mutex_unlock(&bpf_mutex);
354
355 if (pcap_setfilter(pc->handle, &fcode) < 0)
356 {
357 pcap_freecode(&fcode);
358 SET_ERROR(pc->modinst, "%s: pcap_setfilter: %s", __func__, pcap_geterr(pc->handle));
359 return DAQ_ERROR;
360 }
361
362 pcap_freecode(&fcode);
363
364 return DAQ_SUCCESS;
365 }
366
pcap_daq_set_filter(void * handle,const char * filter)367 static int pcap_daq_set_filter(void *handle, const char *filter)
368 {
369 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
370
371 if (pc->handle)
372 {
373 int rval = pcap_daq_install_filter(handle, filter);
374 if (rval != DAQ_SUCCESS)
375 return rval;
376 }
377 else
378 {
379 /* Try to validate the BPF with a dead PCAP handle. */
380 pcap_t *dead_handle = pcap_open_dead(DLT_EN10MB, pc->snaplen);
381 if (!dead_handle)
382 {
383 SET_ERROR(pc->modinst, "%s: Could not allocate a dead PCAP handle!", __func__);
384 return DAQ_ERROR_NOMEM;
385 }
386 struct bpf_program fcode;
387 pthread_mutex_lock(&bpf_mutex);
388 if (pcap_compile(dead_handle, &fcode, filter, 1, pc->netmask) < 0)
389 {
390 pthread_mutex_unlock(&bpf_mutex);
391 SET_ERROR(pc->modinst, "%s: pcap_compile: %s", __func__, pcap_geterr(dead_handle));
392 return DAQ_ERROR;
393 }
394 pthread_mutex_unlock(&bpf_mutex);
395 pcap_freecode(&fcode);
396 pcap_close(dead_handle);
397
398 /* Store the BPF string for later. */
399 if (pc->filter_string)
400 free(pc->filter_string);
401 pc->filter_string = strdup(filter);
402 if (!pc->filter_string)
403 {
404 SET_ERROR(pc->modinst, "%s: Could not allocate space to store a copy of the filter string!", __func__);
405 return DAQ_ERROR_NOMEM;
406 }
407 }
408
409 return DAQ_SUCCESS;
410 }
411
pcap_daq_start(void * handle)412 static int pcap_daq_start(void *handle)
413 {
414 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
415 uint32_t localnet, netmask;
416 uint32_t defaultnet = 0xFFFFFF00;
417 int status;
418
419 if (pc->device)
420 {
421 pc->handle = pcap_create(pc->device, pc->pcap_errbuf);
422 if (!pc->handle)
423 goto fail;
424 if ((status = pcap_set_immediate_mode(pc->handle, pc->immediate_mode ? 1 : 0)) < 0)
425 goto fail;
426 if ((status = pcap_set_snaplen(pc->handle, pc->snaplen)) < 0)
427 goto fail;
428 if ((status = pcap_set_promisc(pc->handle, pc->promisc_mode ? 1 : 0)) < 0)
429 goto fail;
430 if ((status = pcap_set_timeout(pc->handle, pc->timeout)) < 0)
431 goto fail;
432 if ((status = pcap_set_buffer_size(pc->handle, pc->buffer_size)) < 0)
433 goto fail;
434 if ((status = pcap_activate(pc->handle)) < 0)
435 goto fail;
436 if ((status = set_nonblocking(pc, true)) < 0)
437 goto fail;
438 if (pcap_lookupnet(pc->device, &localnet, &netmask, pc->pcap_errbuf) < 0)
439 netmask = htonl(defaultnet);
440 }
441 else
442 {
443 pc->handle = pcap_fopen_offline(pc->fp, pc->pcap_errbuf);
444 if (!pc->handle)
445 goto fail;
446 pc->fp = NULL;
447
448 netmask = htonl(defaultnet);
449 }
450 pc->netmask = netmask;
451
452 if (pc->filter_string)
453 {
454 if ((status = pcap_daq_install_filter(pc, pc->filter_string)) != DAQ_SUCCESS)
455 {
456 pcap_close(pc->handle);
457 pc->handle = NULL;
458 return status;
459 }
460 free(pc->filter_string);
461 pc->filter_string = NULL;
462 }
463
464 pcap_daq_reset_stats(handle);
465
466 return DAQ_SUCCESS;
467
468 fail:
469 if (pc->handle)
470 {
471 if (status == PCAP_ERROR || status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED)
472 SET_ERROR(pc->modinst, "%s", pcap_geterr(pc->handle));
473 else
474 SET_ERROR(pc->modinst, "%s: %s", pc->device, pcap_statustostr(status));
475 pcap_close(pc->handle);
476 pc->handle = NULL;
477 }
478 else
479 SET_ERROR(pc->modinst, "%s", pc->pcap_errbuf);
480 return DAQ_ERROR;
481 }
482
pcap_daq_inject(void * handle,DAQ_MsgType type,const void * hdr,const uint8_t * data,uint32_t data_len)483 static int pcap_daq_inject(void *handle, DAQ_MsgType type, const void *hdr, const uint8_t *data, uint32_t data_len)
484 {
485 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
486
487 if (type != DAQ_MSG_TYPE_PACKET)
488 return DAQ_ERROR_NOTSUP;
489
490 if (pcap_inject(pc->handle, data, data_len) < 0)
491 {
492 SET_ERROR(pc->modinst, "%s", pcap_geterr(pc->handle));
493 return DAQ_ERROR;
494 }
495
496 pc->stats.packets_injected++;
497 return DAQ_SUCCESS;
498 }
499
pcap_daq_interrupt(void * handle)500 static int pcap_daq_interrupt(void *handle)
501 {
502 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
503
504 pc->interrupted = true;
505
506 return DAQ_SUCCESS;
507 }
508
pcap_daq_stop(void * handle)509 static int pcap_daq_stop(void *handle)
510 {
511 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
512
513 if (pc->handle)
514 {
515 /* Store the hardware stats for post-stop stat calls. */
516 update_hw_stats(pc);
517 pcap_close(pc->handle);
518 pc->handle = NULL;
519 }
520
521 return DAQ_SUCCESS;
522 }
523
pcap_daq_get_stats(void * handle,DAQ_Stats_t * stats)524 static int pcap_daq_get_stats(void *handle, DAQ_Stats_t *stats)
525 {
526 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
527
528 if (update_hw_stats(pc) != DAQ_SUCCESS)
529 return DAQ_ERROR;
530
531 memcpy(stats, &pc->stats, sizeof(DAQ_Stats_t));
532
533 return DAQ_SUCCESS;
534 }
535
pcap_daq_reset_stats(void * handle)536 static void pcap_daq_reset_stats(void *handle)
537 {
538 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
539 struct pcap_stat ps;
540
541 memset(&pc->stats, 0, sizeof(DAQ_Stats_t));
542
543 if (!pc->handle)
544 return;
545
546 memset(&ps, 0, sizeof(struct pcap_stat));
547 if (pc->handle && pc->device && pcap_stats(pc->handle, &ps) == 0)
548 {
549 pc->base_recv = pc->wrap_recv = ps.ps_recv;
550 pc->base_drop = pc->wrap_drop = ps.ps_drop;
551 }
552 }
553
pcap_daq_get_snaplen(void * handle)554 static int pcap_daq_get_snaplen(void *handle)
555 {
556 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
557
558 return pc->snaplen;
559 }
560
pcap_daq_get_capabilities(void * handle)561 static uint32_t pcap_daq_get_capabilities(void *handle)
562 {
563 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
564 uint32_t capabilities = DAQ_CAPA_BPF | DAQ_CAPA_INTERRUPT;
565
566 if (pc->device)
567 capabilities |= DAQ_CAPA_INJECT;
568 else
569 capabilities |= DAQ_CAPA_UNPRIV_START;
570
571 return capabilities;
572 }
573
pcap_daq_get_datalink_type(void * handle)574 static int pcap_daq_get_datalink_type(void *handle)
575 {
576 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
577
578 if (pc->handle)
579 return pcap_datalink(pc->handle);
580
581 return DLT_NULL;
582 }
583
pcap_daq_msg_receive(void * handle,const unsigned max_recv,const DAQ_Msg_t * msgs[],DAQ_RecvStatus * rstat)584 static unsigned pcap_daq_msg_receive(void *handle, const unsigned max_recv, const DAQ_Msg_t *msgs[], DAQ_RecvStatus *rstat)
585 {
586 struct pcap_pkthdr *pcaphdr;
587 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
588 const u_char *data;
589 unsigned idx;
590
591 *rstat = DAQ_RSTAT_OK;
592 for (idx = 0; idx < max_recv; idx++)
593 {
594 /* Check to see if the receive has been canceled. If so, reset it and return appropriately. */
595 if (pc->interrupted)
596 {
597 pc->interrupted = false;
598 *rstat = DAQ_RSTAT_INTERRUPTED;
599 break;
600 }
601
602 /* If there is a pending descriptor from the readback timeout feature, check if it's ready
603 to be realized. If it is, finish receiving it and carry on. */
604 if (pc->pending_desc)
605 {
606 struct timeval delta;
607 timersub(&pc->pending_desc->pkthdr.ts, &pc->last_recv, &delta);
608 if (timercmp(&delta, &pc->timeout_tv, >))
609 {
610 timeradd(&pc->last_recv, &pc->timeout_tv, &pc->last_recv);
611 *rstat = DAQ_RSTAT_TIMEOUT;
612 break;
613 }
614 pc->last_recv = pc->pending_desc->pkthdr.ts;
615 pc->pool.info.available--;
616 msgs[idx] = &pc->pending_desc->msg;
617 pc->stats.packets_received++;
618 pc->pending_desc = NULL;
619 continue;
620 }
621
622 /* Make sure that we have a packet descriptor available to populate *before*
623 calling into libpcap. */
624 PcapPktDesc *desc = pc->pool.freelist;
625 if (!desc)
626 {
627 *rstat = DAQ_RSTAT_NOBUF;
628 break;
629 }
630
631 /* When dealing with a live interface, try to get the first packet in non-blocking mode.
632 If there's nothing to receive, switch to blocking mode. */
633 int pcap_rval;
634 if (pc->mode != DAQ_MODE_READ_FILE && idx == 0)
635 {
636 if (set_nonblocking(pc, true) != DAQ_SUCCESS)
637 {
638 *rstat = DAQ_RSTAT_ERROR;
639 break;
640 }
641 pcap_rval = pcap_next_ex(pc->handle, &pcaphdr, &data);
642 if (pcap_rval == 0)
643 {
644 if (set_nonblocking(pc, false) != DAQ_SUCCESS)
645 {
646 *rstat = DAQ_RSTAT_ERROR;
647 break;
648 }
649 pcap_rval = pcap_next_ex(pc->handle, &pcaphdr, &data);
650 }
651 }
652 else
653 pcap_rval = pcap_next_ex(pc->handle, &pcaphdr, &data);
654
655 if (pcap_rval <= 0)
656 {
657 if (pcap_rval == 0)
658 *rstat = (idx == 0) ? DAQ_RSTAT_TIMEOUT : DAQ_RSTAT_WOULD_BLOCK;
659 else if (pcap_rval == -1)
660 {
661 SET_ERROR(pc->modinst, "%s", pcap_geterr(pc->handle));
662 *rstat = DAQ_RSTAT_ERROR;
663 }
664 else if (pcap_rval == -2)
665 {
666 /* LibPCAP brilliantly decides to return -2 if it hit EOF in readback OR pcap_breakloop()
667 was called. Let's try to differentiate by checking to see if we asked for a break. */
668 if (!pc->interrupted && pc->mode == DAQ_MODE_READ_FILE)
669 {
670 /* Insert a final timeout receive status when readback timeout mode is enabled. */
671 if (pc->readback_timeout && !pc->final_readback_timeout)
672 {
673 pc->final_readback_timeout = true;
674 *rstat = DAQ_RSTAT_TIMEOUT;
675 }
676 else
677 *rstat = DAQ_RSTAT_EOF;
678 }
679 else
680 {
681 pc->interrupted = false;
682 *rstat = DAQ_RSTAT_INTERRUPTED;
683 }
684 }
685 break;
686 }
687
688 /* Update hw packet counters to make sure we detect counter overflow */
689 if (++pc->hwupdate_count == DAQ_PCAP_ROLLOVER_LIM)
690 update_hw_stats(pc);
691
692 /* Populate the packet descriptor */
693 int caplen = (pcaphdr->caplen > pc->snaplen) ? pc->snaplen : pcaphdr->caplen;
694 memcpy(desc->data, data, caplen);
695
696 /* Next, set up the DAQ message. Most fields are prepopulated and unchanging. */
697 DAQ_Msg_t *msg = &desc->msg;
698 msg->data_len = caplen;
699
700 /* Then, set up the DAQ packet header. */
701 DAQ_PktHdr_t *pkthdr = &desc->pkthdr;
702 pkthdr->pktlen = pcaphdr->len;
703 pkthdr->ts.tv_sec = pcaphdr->ts.tv_sec;
704 pkthdr->ts.tv_usec = pcaphdr->ts.tv_usec;
705
706 /* Last, but not least, extract this descriptor from the free list and
707 place the message in the return vector. */
708 pc->pool.freelist = desc->next;
709 desc->next = NULL;
710 /* If the readback timeout feature is enabled, check to see if the configured timeout has
711 elapsed between the previous packet and this one. If it has, store the descriptor for
712 later without modifying counters and return the timeout receive status. */
713 if (pc->mode == DAQ_MODE_READ_FILE && pc->readback_timeout && pc->timeout > 0)
714 {
715 if (timerisset(&pc->last_recv) && timercmp(&pkthdr->ts, &pc->last_recv, >))
716 {
717 struct timeval delta;
718 timersub(&pkthdr->ts, &pc->last_recv, &delta);
719 if (timercmp(&delta, &pc->timeout_tv, >))
720 {
721 pc->pending_desc = desc;
722 timeradd(&pc->last_recv, &pc->timeout_tv, &pc->last_recv);
723 *rstat = DAQ_RSTAT_TIMEOUT;
724 break;
725 }
726 }
727 pc->last_recv = pkthdr->ts;
728 }
729 pc->pool.info.available--;
730 msgs[idx] = &desc->msg;
731
732 /* Finally, increment the module instance's packet counter. */
733 pc->stats.packets_received++;
734 }
735
736 return idx;
737 }
738
pcap_daq_msg_finalize(void * handle,const DAQ_Msg_t * msg,DAQ_Verdict verdict)739 static int pcap_daq_msg_finalize(void *handle, const DAQ_Msg_t *msg, DAQ_Verdict verdict)
740 {
741 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
742 PcapPktDesc *desc = (PcapPktDesc *) msg->priv;
743
744 /* Sanitize the verdict. */
745 if (verdict >= MAX_DAQ_VERDICT)
746 verdict = DAQ_VERDICT_PASS;
747 pc->stats.verdicts[verdict]++;
748
749 /* Toss the descriptor back on the free list for reuse. */
750 desc->next = pc->pool.freelist;
751 pc->pool.freelist = desc;
752 pc->pool.info.available++;
753
754 return DAQ_SUCCESS;
755 }
756
pcap_daq_get_msg_pool_info(void * handle,DAQ_MsgPoolInfo_t * info)757 static int pcap_daq_get_msg_pool_info(void *handle, DAQ_MsgPoolInfo_t *info)
758 {
759 Pcap_Context_t *pc = (Pcap_Context_t *) handle;
760
761 *info = pc->pool.info;
762
763 return DAQ_SUCCESS;
764 }
765
766 #ifdef BUILDING_SO
767 DAQ_SO_PUBLIC const DAQ_ModuleAPI_t DAQ_MODULE_DATA =
768 #else
769 const DAQ_ModuleAPI_t pcap_daq_module_data =
770 #endif
771 {
772 /* .api_version = */ DAQ_MODULE_API_VERSION,
773 /* .api_size = */ sizeof(DAQ_ModuleAPI_t),
774 /* .module_version = */ DAQ_PCAP_VERSION,
775 /* .name = */ "pcap",
776 /* .type = */ DAQ_TYPE_FILE_CAPABLE | DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_MULTI_INSTANCE,
777 /* .load = */ pcap_daq_module_load,
778 /* .unload = */ pcap_daq_module_unload,
779 /* .get_variable_descs = */ pcap_daq_get_variable_descs,
780 /* .instantiate = */ pcap_daq_instantiate,
781 /* .destroy = */ pcap_daq_destroy,
782 /* .set_filter = */ pcap_daq_set_filter,
783 /* .start = */ pcap_daq_start,
784 /* .inject = */ pcap_daq_inject,
785 /* .inject_relative = */ NULL,
786 /* .interrupt = */ pcap_daq_interrupt,
787 /* .stop = */ pcap_daq_stop,
788 /* .ioctl = */ NULL,
789 /* .get_stats = */ pcap_daq_get_stats,
790 /* .reset_stats = */ pcap_daq_reset_stats,
791 /* .get_snaplen = */ pcap_daq_get_snaplen,
792 /* .get_capabilities = */ pcap_daq_get_capabilities,
793 /* .get_datalink_type = */ pcap_daq_get_datalink_type,
794 /* .config_load = */ NULL,
795 /* .config_swap = */ NULL,
796 /* .config_free = */ NULL,
797 /* .msg_receive = */ pcap_daq_msg_receive,
798 /* .msg_finalize = */ pcap_daq_msg_finalize,
799 /* .get_msg_pool_info = */ pcap_daq_get_msg_pool_info,
800 };
801