00001 /*
00002 ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
00003 ** Copyright (C) 2010-2013 Sourcefire, Inc.
00004 ** Author: Michael R. Altizer <mialtize@cisco.com>
00005 **
00006 ** This program is free software; you can redistribute it and/or modify
00007 ** it under the terms of the GNU General Public License Version 2 as
00008 ** published by the Free Software Foundation. You may not use, modify or
00009 ** distribute this program under any other version of the GNU General
00010 ** Public License.
00011 **
00012 ** This program is distributed in the hope that it will be useful,
00013 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015 ** GNU General Public License for more details.
00016 **
00017 ** You should have received a copy of the GNU General Public License
00018 ** along with this program; if not, write to the Free Software
00019 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 */
00021
00022 #ifdef HAVE_CONFIG_H
00023 #include "config.h"
00024 #endif
00025
00026 #ifndef WIN32
00027 #include <sys/types.h>
00028 #include <netinet/in.h>
00029 #endif
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <stdint.h>
00033 #include <pcap.h>
00034 #ifndef PCAP_OLDSTYLE
00035 # ifdef HAVE_LINUX_IF_PACKET_H
00036 #include <linux/if_packet.h>
00037 # endif /* HAVE_LINUX_IF_PACKET_H */
00038 #include <unistd.h>
00039 #endif /* PCAP_OLDSTYLE */
00040
00041 #include "daq_api.h"
00042
00043 #define DAQ_PCAP_VERSION 4
00044 #define DAQ_PCAP_ROLLOVER_LIM 1000000000 //Check for rollover every billionth packet
00045
00046 typedef struct _pcap_context
00047 {
00048 char *device;
00049 char *file;
00050 char *filter_string;
00051 int snaplen;
00052 pcap_t *handle;
00053 char errbuf[PCAP_ERRBUF_SIZE];
00054 int promisc_flag;
00055 int immediate_flag;
00056 int timeout;
00057 int buffer_size;
00058 int packets;
00059 int delayed_open;
00060 DAQ_Analysis_Func_t analysis_func;
00061 u_char *user_data;
00062 uint32_t netmask;
00063 DAQ_Stats_t stats;
00064 uint32_t base_recv;
00065 uint32_t base_drop;
00066 uint64_t rollover_recv;
00067 uint64_t rollover_drop;
00068 uint32_t wrap_recv;
00069 uint32_t wrap_drop;
00070 DAQ_State state;
00071 uint32_t hwupdate_count;
00072 } Pcap_Context_t;
00073
00074 static void pcap_daq_reset_stats(void *handle);
00075
00076 #ifndef PCAP_OLDSTYLE
00077 /* Attempt to convert from the PCAP_FRAMES environment variable used by Phil Wood's PCAP-Ring
00078 to a buffer size I can pass to PCAP 1.0.0's pcap_set_buffer_size(). */
00079 static int translate_PCAP_FRAMES(int snaplen)
00080 {
00081 # ifdef HAVE_LINUX_IF_PACKET_H
00082 char *frames_str = getenv("PCAP_FRAMES");
00083 int frame_size, block_size, frames_per_block;
00084 int frames;
00085
00086 if (!frames_str)
00087 return 0;
00088
00089 /* Look, I didn't make these numbers and calculations up, I'm just using them. */
00090 frame_size = TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_HDRLEN) + sizeof(struct sockaddr_ll));
00091 block_size = getpagesize();
00092 while (block_size < frame_size)
00093 block_size <<= 1;
00094 frames_per_block = block_size / frame_size;
00095
00096 if (strncmp(frames_str, "max", 3) && strncmp(frames_str, "MAX", 3))
00097 frames = strtol(frames_str, NULL, 10);
00098 else
00099 frames = 0x8000; /* Default maximum of 32k frames. */
00100
00101 printf("PCAP_FRAMES -> %d * %d / %d = %d (%d)\n", frames, block_size, frames_per_block, frames * block_size / frames_per_block, frame_size);
00102 return frames * block_size / frames_per_block;
00103 # else
00104 return 0;
00105 # endif
00106 }
00107 #endif /* PCAP_OLDSTYLE */
00108
00109 static int pcap_daq_open(Pcap_Context_t *context)
00110 {
00111 uint32_t localnet, netmask;
00112 uint32_t defaultnet = 0xFFFFFF00;
00113 #ifndef PCAP_OLDSTYLE
00114 int status;
00115 #endif /* PCAP_OLDSTYLE */
00116
00117 if (context->handle)
00118 return DAQ_SUCCESS;
00119
00120 if (context->device)
00121 {
00122 #ifndef PCAP_OLDSTYLE
00123 context->handle = pcap_create(context->device, context->errbuf);
00124 if (!context->handle)
00125 return DAQ_ERROR;
00126 if ((status = pcap_set_immediate_mode(context->handle, context->immediate_flag ? 1 : 0)) < 0)
00127 goto fail;
00128 if ((status = pcap_set_snaplen(context->handle, context->snaplen)) < 0)
00129 goto fail;
00130 if ((status = pcap_set_promisc(context->handle, context->promisc_flag ? 1 : 0)) < 0)
00131 goto fail;
00132 if ((status = pcap_set_timeout(context->handle, context->timeout)) < 0)
00133 goto fail;
00134 if ((status = pcap_set_buffer_size(context->handle, context->buffer_size)) < 0)
00135 goto fail;
00136 if ((status = pcap_activate(context->handle)) < 0)
00137 goto fail;
00138 #else
00139 context->handle = pcap_open_live(context->device, context->snaplen,
00140 context->promisc_flag ? 1 : 0, context->timeout, context->errbuf);
00141 if (!context->handle)
00142 return DAQ_ERROR;
00143 #endif /* PCAP_OLDSTYLE */
00144 if (pcap_lookupnet(context->device, &localnet, &netmask, context->errbuf) < 0)
00145 netmask = htonl(defaultnet);
00146 }
00147 else
00148 {
00149 context->handle = pcap_open_offline(context->file, context->errbuf);
00150 if (!context->handle)
00151 return DAQ_ERROR;
00152
00153 netmask = htonl(defaultnet);
00154 }
00155 context->netmask = htonl(defaultnet);
00156
00157 return DAQ_SUCCESS;
00158
00159 #ifndef PCAP_OLDSTYLE
00160 fail:
00161 if (status == PCAP_ERROR || status == PCAP_ERROR_NO_SUCH_DEVICE || status == PCAP_ERROR_PERM_DENIED)
00162 DPE(context->errbuf, "%s", pcap_geterr(context->handle));
00163 else
00164 DPE(context->errbuf, "%s: %s", context->device, pcap_statustostr(status));
00165 pcap_close(context->handle);
00166 context->handle = NULL;
00167 return DAQ_ERROR;
00168 #endif /* PCAP_OLDSTYLE */
00169 }
00170
00171 static int update_hw_stats(Pcap_Context_t *context)
00172 {
00173 struct pcap_stat ps;
00174
00175 if (context->handle && context->device)
00176 {
00177 memset(&ps, 0, sizeof(struct pcap_stat));
00178 if (pcap_stats(context->handle, &ps) == -1)
00179 {
00180 DPE(context->errbuf, "%s", pcap_geterr(context->handle));
00181 return DAQ_ERROR;
00182 }
00183
00184 /* PCAP receive counter wrapped */
00185 if (ps.ps_recv < context->wrap_recv)
00186 context->rollover_recv += UINT32_MAX;
00187
00188 /* PCAP drop counter wrapped */
00189 if (ps.ps_drop < context->wrap_drop)
00190 context->rollover_drop += UINT32_MAX;
00191
00192 context->wrap_recv = ps.ps_recv;
00193 context->wrap_drop = ps.ps_drop;
00194
00195 context->stats.hw_packets_received = context->rollover_recv + context->wrap_recv - context->base_recv;
00196 context->stats.hw_packets_dropped = context->rollover_drop + context->wrap_drop - context->base_drop;
00197 context->hwupdate_count = 0;
00198 }
00199
00200 return DAQ_SUCCESS;
00201 }
00202
00203 static int pcap_daq_initialize(const DAQ_Config_t *config, void **ctxt_ptr, char *errbuf, size_t len)
00204 {
00205 Pcap_Context_t *context;
00206 #ifndef PCAP_OLDSTYLE
00207 DAQ_Dict *entry;
00208 #endif
00209
00210 context = calloc(1, sizeof(Pcap_Context_t));
00211 if (!context)
00212 {
00213 snprintf(errbuf, len, "%s: Couldn't allocate memory for the new PCAP context!", __func__);
00214 return DAQ_ERROR_NOMEM;
00215 }
00216
00217 context->snaplen = config->snaplen;
00218 context->promisc_flag = (config->flags & DAQ_CFG_PROMISC);
00219 context->timeout = config->timeout;
00220
00221 #ifndef PCAP_OLDSTYLE
00222 /* Retrieve the requested buffer size (default = 0) */
00223 for (entry = config->values; entry; entry = entry->next)
00224 {
00225 if (!strcmp(entry->key, "buffer_size"))
00226 context->buffer_size = strtol(entry->value, NULL, 10);
00227 else if (!strcmp(entry->key, "immediate"))
00228 context->immediate_flag = strtol(entry->value, NULL, 10);
00229 }
00230 /* Try to account for legacy PCAP_FRAMES environment variable if we weren't passed a buffer size. */
00231 if (context->buffer_size == 0)
00232 context->buffer_size = translate_PCAP_FRAMES(context->snaplen);
00233 #endif
00234
00235 if (config->mode == DAQ_MODE_READ_FILE)
00236 {
00237 context->file = strdup(config->name);
00238 if (!context->file)
00239 {
00240 snprintf(errbuf, len, "%s: Couldn't allocate memory for the filename string!", __func__);
00241 free(context);
00242 return DAQ_ERROR_NOMEM;
00243 }
00244 context->delayed_open = 0;
00245 }
00246 else
00247 {
00248 context->device = strdup(config->name);
00249 if (!context->device)
00250 {
00251 snprintf(errbuf, len, "%s: Couldn't allocate memory for the device string!", __func__);
00252 free(context);
00253 return DAQ_ERROR_NOMEM;
00254 }
00255 context->delayed_open = 1;
00256 }
00257
00258 if (!context->delayed_open)
00259 {
00260 if (pcap_daq_open(context) != DAQ_SUCCESS)
00261 {
00262 snprintf(errbuf, len, "%s", context->errbuf);
00263 free(context->file);
00264 free(context);
00265 return DAQ_ERROR;
00266 }
00267 }
00268
00269 context->hwupdate_count = 0;
00270 context->state = DAQ_STATE_INITIALIZED;
00271
00272 *ctxt_ptr = context;
00273 return DAQ_SUCCESS;
00274 }
00275
00276 static int pcap_daq_set_filter(void *handle, const char *filter)
00277 {
00278 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00279 struct bpf_program fcode;
00280 pcap_t *dead_handle;
00281
00282 if (context->handle)
00283 {
00284 if (pcap_compile(context->handle, &fcode, (char *)filter, 1, context->netmask) < 0)
00285 {
00286 DPE(context->errbuf, "%s: pcap_compile: %s", __func__, pcap_geterr(context->handle));
00287 return DAQ_ERROR;
00288 }
00289
00290 if (pcap_setfilter(context->handle, &fcode) < 0)
00291 {
00292 pcap_freecode(&fcode);
00293 DPE(context->errbuf, "%s: pcap_setfilter: %s", __func__, pcap_geterr(context->handle));
00294 return DAQ_ERROR;
00295 }
00296
00297 pcap_freecode(&fcode);
00298 }
00299 else
00300 {
00301 /* Try to validate the BPF with a dead PCAP handle. */
00302 dead_handle = pcap_open_dead(DLT_EN10MB, context->snaplen);
00303 if (!dead_handle)
00304 {
00305 DPE(context->errbuf, "%s: Could not allocate a dead PCAP handle!", __func__);
00306 return DAQ_ERROR_NOMEM;
00307 }
00308 if (pcap_compile(dead_handle, &fcode, (char *)filter, 1, context->netmask) < 0)
00309 {
00310 DPE(context->errbuf, "%s: pcap_compile: %s", __func__, pcap_geterr(dead_handle));
00311 return DAQ_ERROR;
00312 }
00313 pcap_freecode(&fcode);
00314 pcap_close(dead_handle);
00315
00316 /* Store the BPF string for later. */
00317 if (context->filter_string)
00318 free(context->filter_string);
00319 context->filter_string = strdup(filter);
00320 if (!context->filter_string)
00321 {
00322 DPE(context->errbuf, "%s: Could not allocate space to store a copy of the filter string!", __func__);
00323 return DAQ_ERROR_NOMEM;
00324 }
00325 }
00326
00327 return DAQ_SUCCESS;
00328 }
00329
00330 static int pcap_daq_start(void *handle)
00331 {
00332 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00333
00334 if (pcap_daq_open(context) != DAQ_SUCCESS)
00335 return DAQ_ERROR;
00336
00337 pcap_daq_reset_stats(handle);
00338
00339 if (context->filter_string)
00340 {
00341 if (pcap_daq_set_filter(handle, context->filter_string))
00342 return DAQ_ERROR;
00343 free(context->filter_string);
00344 context->filter_string = NULL;
00345 }
00346
00347 context->state = DAQ_STATE_STARTED;
00348
00349 return DAQ_SUCCESS;
00350 }
00351
00352 static void pcap_process_loop(u_char *user, const struct pcap_pkthdr *pkth, const u_char *data)
00353 {
00354 Pcap_Context_t *context = (Pcap_Context_t *) user;
00355 DAQ_PktHdr_t hdr;
00356 DAQ_Verdict verdict;
00357
00358 hdr.caplen = pkth->caplen;
00359 hdr.pktlen = pkth->len;
00360 hdr.ts = pkth->ts;
00361 hdr.ingress_index = -1;
00362 hdr.egress_index = -1;
00363 hdr.ingress_group = -1;
00364 hdr.egress_group = -1;
00365 hdr.flags = 0;
00366 hdr.address_space_id = 0;
00367
00368 /* Increment the current acquire loop's packet counter. */
00369 context->packets++;
00370 /* ...and then the module instance's packet counter. */
00371 context->stats.packets_received++;
00372 /* Update hw packet counters to make sure we detect counter overflow */
00373 if (context->hwupdate_count++ == DAQ_PCAP_ROLLOVER_LIM)
00374 update_hw_stats(context);
00375
00376 verdict = context->analysis_func(context->user_data, &hdr, data);
00377 if (verdict >= MAX_DAQ_VERDICT)
00378 verdict = DAQ_VERDICT_PASS;
00379 context->stats.verdicts[verdict]++;
00380 }
00381
00382 static int pcap_daq_acquire(
00383 void *handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t metaback, void *user)
00384 {
00385 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00386 int ret;
00387
00388 context->analysis_func = callback;
00389 context->user_data = user;
00390
00391 context->packets = 0;
00392 while (context->packets < cnt || cnt <= 0)
00393 {
00394 ret = pcap_dispatch(
00395 context->handle, (cnt <= 0) ? -1 : cnt-context->packets, pcap_process_loop, (void *) context);
00396 if (ret == -1)
00397 {
00398 DPE(context->errbuf, "%s", pcap_geterr(context->handle));
00399 return ret;
00400 }
00401 /* In read-file mode, PCAP returns 0 when it hits the end of the file. */
00402 else if (context->file && ret == 0)
00403 return DAQ_READFILE_EOF;
00404 /* If we hit a breakloop call or timed out without reading any packets, break out. */
00405 else if (ret == -2 || ret == 0)
00406 break;
00407 }
00408
00409 return 0;
00410 }
00411
00412 static int pcap_daq_inject(void *handle, const DAQ_PktHdr_t *hdr, const uint8_t *packet_data, uint32_t len, int reverse)
00413 {
00414 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00415
00416 if (pcap_inject(context->handle, packet_data, len) < 0)
00417 {
00418 DPE(context->errbuf, "%s", pcap_geterr(context->handle));
00419 return DAQ_ERROR;
00420 }
00421
00422 context->stats.packets_injected++;
00423 return DAQ_SUCCESS;
00424 }
00425
00426 static int pcap_daq_breakloop(void *handle)
00427 {
00428 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00429
00430 if (!context->handle)
00431 return DAQ_ERROR;
00432
00433 pcap_breakloop(context->handle);
00434
00435 return DAQ_SUCCESS;
00436 }
00437
00438 static int pcap_daq_stop(void *handle)
00439 {
00440 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00441
00442 if (context->handle)
00443 {
00444 /* Store the hardware stats for post-stop stat calls. */
00445 update_hw_stats(context);
00446 pcap_close(context->handle);
00447 context->handle = NULL;
00448 }
00449
00450 context->state = DAQ_STATE_STOPPED;
00451
00452 return DAQ_SUCCESS;
00453 }
00454
00455 static void pcap_daq_shutdown(void *handle)
00456 {
00457 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00458
00459 if (context->handle)
00460 pcap_close(context->handle);
00461 if (context->device)
00462 free(context->device);
00463 if (context->file)
00464 free(context->file);
00465 if (context->filter_string)
00466 free(context->filter_string);
00467 free(context);
00468 }
00469
00470 static DAQ_State pcap_daq_check_status(void *handle)
00471 {
00472 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00473
00474 return context->state;
00475 }
00476
00477 static int pcap_daq_get_stats(void *handle, DAQ_Stats_t *stats)
00478 {
00479 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00480
00481 if (update_hw_stats(context) != DAQ_SUCCESS)
00482 return DAQ_ERROR;
00483
00484 memcpy(stats, &context->stats, sizeof(DAQ_Stats_t));
00485
00486 return DAQ_SUCCESS;
00487 }
00488
00489 static void pcap_daq_reset_stats(void *handle)
00490 {
00491 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00492 struct pcap_stat ps;
00493
00494 memset(&context->stats, 0, sizeof(DAQ_Stats_t));
00495
00496 if (!context->handle)
00497 return;
00498
00499 memset(&ps, 0, sizeof(struct pcap_stat));
00500 if (context->handle && context->device && pcap_stats(context->handle, &ps) == 0)
00501 {
00502 context->base_recv = context->wrap_recv = ps.ps_recv;
00503 context->base_drop = context->wrap_drop = ps.ps_drop;
00504 }
00505 }
00506
00507 static int pcap_daq_get_snaplen(void *handle)
00508 {
00509 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00510
00511 if (context->handle)
00512 return pcap_snapshot(context->handle);
00513
00514 return context->snaplen;
00515 }
00516
00517 static uint32_t pcap_daq_get_capabilities(void *handle)
00518 {
00519 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00520 uint32_t capabilities = DAQ_CAPA_BPF;
00521
00522 if (context->device)
00523 capabilities |= DAQ_CAPA_INJECT;
00524
00525 capabilities |= DAQ_CAPA_BREAKLOOP;
00526
00527 if (!context->delayed_open)
00528 capabilities |= DAQ_CAPA_UNPRIV_START;
00529
00530 return capabilities;
00531 }
00532
00533 static int pcap_daq_get_datalink_type(void *handle)
00534 {
00535 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00536
00537 if (context->handle)
00538 return pcap_datalink(context->handle);
00539
00540 return DLT_NULL;
00541 }
00542
00543 static const char *pcap_daq_get_errbuf(void *handle)
00544 {
00545 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00546
00547 return context->errbuf;
00548 }
00549
00550 static void pcap_daq_set_errbuf(void *handle, const char *string)
00551 {
00552 Pcap_Context_t *context = (Pcap_Context_t *) handle;
00553
00554 if (!string)
00555 return;
00556
00557 DPE(context->errbuf, "%s", string);
00558 }
00559
00560 static int pcap_daq_get_device_index(void *handle, const char *device)
00561 {
00562 return DAQ_ERROR_NOTSUP;
00563 }
00564
00565 #ifdef BUILDING_SO
00566 DAQ_SO_PUBLIC const DAQ_Module_t DAQ_MODULE_DATA =
00567 #else
00568 const DAQ_Module_t pcap_daq_module_data =
00569 #endif
00570 {
00571 #ifndef WIN32
00572 .api_version = DAQ_API_VERSION,
00573 .module_version = DAQ_PCAP_VERSION,
00574 .name = "pcap",
00575 .type = DAQ_TYPE_FILE_CAPABLE | DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_MULTI_INSTANCE,
00576 .initialize = pcap_daq_initialize,
00577 .set_filter = pcap_daq_set_filter,
00578 .start = pcap_daq_start,
00579 .acquire = pcap_daq_acquire,
00580 .inject = pcap_daq_inject,
00581 .breakloop = pcap_daq_breakloop,
00582 .stop = pcap_daq_stop,
00583 .shutdown = pcap_daq_shutdown,
00584 .check_status = pcap_daq_check_status,
00585 .get_stats = pcap_daq_get_stats,
00586 .reset_stats = pcap_daq_reset_stats,
00587 .get_snaplen = pcap_daq_get_snaplen,
00588 .get_capabilities = pcap_daq_get_capabilities,
00589 .get_datalink_type = pcap_daq_get_datalink_type,
00590 .get_errbuf = pcap_daq_get_errbuf,
00591 .set_errbuf = pcap_daq_set_errbuf,
00592 .get_device_index = pcap_daq_get_device_index,
00593 .modify_flow = NULL,
00594 .hup_prep = NULL,
00595 .hup_apply = NULL,
00596 .hup_post = NULL,
00597 #else
00598 DAQ_API_VERSION,
00599 DAQ_PCAP_VERSION,
00600 "pcap",
00601 DAQ_TYPE_FILE_CAPABLE | DAQ_TYPE_INTF_CAPABLE | DAQ_TYPE_MULTI_INSTANCE,
00602 pcap_daq_initialize,
00603 pcap_daq_set_filter,
00604 pcap_daq_start,
00605 pcap_daq_acquire,
00606 pcap_daq_inject,
00607 pcap_daq_breakloop,
00608 pcap_daq_stop,
00609 pcap_daq_shutdown,
00610 pcap_daq_check_status,
00611 pcap_daq_get_stats,
00612 pcap_daq_reset_stats,
00613 pcap_daq_get_snaplen,
00614 pcap_daq_get_capabilities,
00615 pcap_daq_get_datalink_type,
00616 pcap_daq_get_errbuf,
00617 pcap_daq_set_errbuf,
00618 pcap_daq_get_device_index,
00619 NULL,
00620 NULL,
00621 NULL,
00622 NULL,
00623 #endif
00624 };
END OF CODE