1 /****************************************************************************
2 *
3 * Copyright (C) 2007-2013 Sourcefire, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License Version 2 as
7 * published by the Free Software Foundation. You may not use, modify or
8 * distribute this program under any other version of the GNU General
9 * Public License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 ****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <arpa/inet.h>
26 #include <pcap.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined __DragonFly__
31 #include <sys/socket.h>
32 #endif
33
34 #include "daq.h"
35 #include "daq_api.h"
36
37 #define DAQ_MOD_VERSION 4
38
39 #define DAQ_NAME "dump"
40 #define DAQ_TYPE (DAQ_TYPE_FILE_CAPABLE | DAQ_TYPE_INTF_CAPABLE | \
41 DAQ_TYPE_INLINE_CAPABLE | DAQ_TYPE_MULTI_INSTANCE)
42
43 #define DAQ_DUMP_PCAP_FILE "inline-out.pcap"
44 #define DAQ_DUMP_TEXT_FILE "inline-out.txt"
45
46 typedef enum {
47 DUMP_OUTPUT_NONE = 0x0,
48 DUMP_OUTPUT_PCAP = 0x1,
49 DUMP_OUTPUT_TEXT = 0x2,
50 DUMP_OUTPUT_BOTH = 0x3
51 } DumpOutputType;
52
53 typedef struct {
54 // delegate most stuff to daq_pcap
55 DAQ_Module_t* module;
56 void* handle;
57
58 // but write all output packets here
59 pcap_dumper_t* dump;
60 char* pcap_filename;
61
62 // and write other textual output here
63 FILE *text_out;
64 char* text_filename;
65
66 DumpOutputType output_type;
67
68 // by linking in with these
69 DAQ_Analysis_Func_t callback;
70 void* user;
71
72 DAQ_Stats_t stats;
73 } DumpImpl;
74
75 static int dump_daq_stop(void*);
76
daq_dump_get_vars(DumpImpl * impl,DAQ_Config_t * cfg,char * errBuf,size_t errMax)77 static int daq_dump_get_vars (
78 DumpImpl* impl, DAQ_Config_t* cfg, char* errBuf, size_t errMax
79 ) {
80 const char* s = NULL;
81 DAQ_Dict* entry;
82
83 for ( entry = cfg->values; entry; entry = entry->next)
84 {
85 if ( !strcmp(entry->key, "load-mode") )
86 {
87 s = entry->value;
88 }
89 else if ( !strcmp(entry->key, "file") )
90 {
91 impl->pcap_filename = strdup(entry->value);
92 }
93 else if ( !strcmp(entry->key, "text-file") )
94 {
95 impl->text_filename = strdup(entry->value);
96 }
97 else if ( !strcmp(entry->key, "output") )
98 {
99 if ( !strcmp(entry->value, "none") )
100 impl->output_type = DUMP_OUTPUT_NONE;
101 else if ( !strcmp(entry->value, "pcap") )
102 impl->output_type = DUMP_OUTPUT_PCAP;
103 else if ( !strcmp(entry->value, "text") )
104 impl->output_type = DUMP_OUTPUT_TEXT;
105 else if ( !strcmp(entry->value, "both") )
106 impl->output_type = DUMP_OUTPUT_BOTH;
107 else
108 {
109 snprintf(errBuf, errMax, "invalid output type (%s)", entry->value);
110 }
111 }
112 }
113 if ( !s )
114 return 1;
115
116 if ( !strcasecmp(s, "read-file") )
117 {
118 cfg->mode = DAQ_MODE_READ_FILE;
119 return 1;
120 }
121 else if ( !strcasecmp(s, "passive") )
122 {
123 cfg->mode = DAQ_MODE_PASSIVE;
124 return 1;
125 }
126 else if ( !strcasecmp(s, "inline") )
127 {
128 cfg->mode = DAQ_MODE_INLINE;
129 return 1;
130 }
131 snprintf(errBuf, errMax, "invalid load-mode (%s)", s);
132 return 0;
133 }
134
hexdump(FILE * fp,const uint8_t * data,unsigned int len,const char * prefix)135 static void hexdump(FILE *fp, const uint8_t *data, unsigned int len, const char *prefix)
136 {
137 unsigned int i;
138 for (i = 0; i < len; i++)
139 {
140 if (i % 16 == 0)
141 fprintf(fp, "\n%s", prefix ? prefix : "");
142 else if (i % 2 == 0)
143 fprintf(fp, " ");
144 fprintf(fp, "%02x", data[i]);
145 }
146 fprintf(fp, "\n");
147 }
148
149 //-------------------------------------------------------------------------
150 // constructor / destructor
151
dump_daq_initialize(const DAQ_Config_t * cfg,void ** handle,char * errBuf,size_t errMax)152 static int dump_daq_initialize (
153 const DAQ_Config_t* cfg, void** handle, char* errBuf, size_t errMax)
154 {
155 DumpImpl* impl;
156 impl = calloc(1, sizeof(*impl));
157 DAQ_Module_t* mod = (DAQ_Module_t*)cfg->extra;
158 DAQ_Config_t sub_cfg = *cfg;
159 int err;
160
161 if ( !impl )
162 {
163 snprintf(errBuf, errMax,
164 "%s: Couldn't allocate memory for the DAQ context",
165 __func__);
166 return DAQ_ERROR_NOMEM;
167 }
168 if ( !mod || !(mod->type & DAQ_TYPE_FILE_CAPABLE) )
169 {
170 snprintf(errBuf, errMax, "%s: no file capable daq provided", __func__);
171 free(impl);
172 return DAQ_ERROR;
173 }
174
175 impl->output_type = DUMP_OUTPUT_PCAP;
176 if ( !daq_dump_get_vars(impl, &sub_cfg, errBuf, errMax) )
177 {
178 free(impl);
179 return DAQ_ERROR;
180 }
181 err = mod->initialize(&sub_cfg, &impl->handle, errBuf, errMax);
182
183 if ( err )
184 {
185 free(impl);
186 return err;
187 }
188 impl->module = mod;
189 *handle = impl;
190
191 return DAQ_SUCCESS;
192 }
193
dump_daq_shutdown(void * handle)194 static void dump_daq_shutdown (void* handle)
195 {
196 DumpImpl* impl = (DumpImpl*)handle;
197 impl->module->shutdown(impl->handle);
198 if ( impl->pcap_filename )
199 free(impl->pcap_filename);
200 if ( impl->text_filename )
201 free(impl->text_filename);
202 free(impl);
203 }
204
205 //-------------------------------------------------------------------------
206 // packet processing functions:
207 // forward all but blocks, retries and blacklists:
208 static const int s_fwd[MAX_DAQ_VERDICT] = { 1, 0, 1, 1, 0, 1, 0 };
209 // We don't have access to daq_verdict_string() because we're not linking
210 // against LibDAQ, so pack our own copy.
211 static const char *daq_verdict_strings[MAX_DAQ_VERDICT] = {
212 "Pass", // DAQ_VERDICT_PASS
213 "Block", // DAQ_VERDICT_BLOCK
214 "Replace", // DAQ_VERDICT_REPLACE
215 "Whitelist", // DAQ_VERDICT_WHITELIST
216 "Blacklist", // DAQ_VERDICT_BLACKLIST
217 "Ignore", // DAQ_VERDICT_IGNORE
218 "Retry" // DAQ_VERDICT_RETRY
219 };
220
daq_dump_capture(void * user,const DAQ_PktHdr_t * hdr,const uint8_t * pkt)221 static DAQ_Verdict daq_dump_capture (
222 void* user, const DAQ_PktHdr_t* hdr, const uint8_t* pkt)
223 {
224 DumpImpl* impl = (DumpImpl*)user;
225 DAQ_Verdict verdict = impl->callback(impl->user, hdr, pkt);
226
227 if ( verdict >= MAX_DAQ_VERDICT )
228 verdict = DAQ_VERDICT_BLOCK;
229
230 impl->stats.verdicts[verdict]++;
231
232 if ( impl->dump && s_fwd[verdict] )
233 pcap_dump((u_char*)impl->dump, (struct pcap_pkthdr*)hdr, pkt);
234
235 if (impl->text_out)
236 {
237 fprintf(impl->text_out, "PV: %lu.%lu(%u): %s\n", (unsigned long) hdr->ts.tv_sec,
238 (unsigned long) hdr->ts.tv_usec, hdr->caplen, daq_verdict_strings[verdict]);
239 if (verdict == DAQ_VERDICT_REPLACE)
240 hexdump(impl->text_out, pkt, hdr->caplen, " ");
241 }
242
243 return verdict;
244 }
245
dump_daq_acquire(void * handle,int cnt,DAQ_Analysis_Func_t callback,DAQ_Meta_Func_t metaback,void * user)246 static int dump_daq_acquire (
247 void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t metaback, void* user)
248 {
249 DumpImpl* impl = (DumpImpl*)handle;
250 impl->callback = callback;
251 impl->user = user;
252 return impl->module->acquire(impl->handle, cnt, daq_dump_capture, metaback, impl);
253 }
254
dump_daq_inject(void * handle,const DAQ_PktHdr_t * hdr,const uint8_t * data,uint32_t len,int reverse)255 static int dump_daq_inject (
256 void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* data, uint32_t len,
257 int reverse)
258 {
259 DumpImpl* impl = (DumpImpl*)handle;
260
261 if (impl->text_out)
262 {
263 fprintf(impl->text_out, "%cI: %lu.%lu(%u): %u\n", reverse ? 'R' : 'F',
264 (unsigned long) hdr->ts.tv_sec, (unsigned long) hdr->ts.tv_usec, hdr->caplen, len);
265 hexdump(impl->text_out, data, len, " ");
266 fprintf(impl->text_out, "\n");
267 }
268
269 if (impl->dump)
270 {
271 // copy the original header to get the same
272 // timestamps but overwrite the lengths
273 DAQ_PktHdr_t h = *hdr;
274 h.pktlen = h.caplen = len;
275 pcap_dump((u_char*)impl->dump, (struct pcap_pkthdr*)&h, data);
276 if ( ferror(pcap_dump_file(impl->dump)) )
277 {
278 impl->module->set_errbuf(impl->handle, "inject can't write to dump file");
279 return DAQ_ERROR;
280 }
281 }
282
283 impl->stats.packets_injected++;
284 return DAQ_SUCCESS;
285 }
286
287 //-------------------------------------------------------------------------
288
dump_daq_start(void * handle)289 static int dump_daq_start (void* handle)
290 {
291 DumpImpl* impl = (DumpImpl*)handle;
292 int dlt;
293 int snap;
294
295 int ret = impl->module->start(impl->handle);
296
297 if ( ret )
298 return ret;
299
300 dlt = impl->module->get_datalink_type(impl->handle);
301 snap = impl->module->get_snaplen(impl->handle);
302
303 if ( impl->output_type & DUMP_OUTPUT_PCAP )
304 {
305 const char* pcap_filename = impl->pcap_filename ? impl->pcap_filename : DAQ_DUMP_PCAP_FILE;
306 pcap_t* pcap;
307
308 pcap = pcap_open_dead(dlt, snap);
309 impl->dump = pcap ? pcap_dump_open(pcap, pcap_filename) : NULL;
310 if ( !impl->dump )
311 {
312 impl->module->stop(impl->handle);
313 impl->module->set_errbuf(impl->handle, "can't open dump file");
314 return DAQ_ERROR;
315 }
316 pcap_close(pcap);
317 }
318
319 if ( impl->output_type & DUMP_OUTPUT_TEXT )
320 {
321 const char* text_filename = impl->text_filename ? impl->text_filename : DAQ_DUMP_TEXT_FILE;
322
323 impl->text_out = fopen(text_filename, "w");
324 if ( !impl->text_out )
325 {
326 impl->module->stop(impl->handle);
327 impl->module->set_errbuf(impl->handle, "can't open text output file");
328 return DAQ_ERROR;
329 }
330 }
331
332 return DAQ_SUCCESS;
333 }
334
dump_daq_stop(void * handle)335 static int dump_daq_stop (void* handle)
336 {
337 DumpImpl* impl = (DumpImpl*)handle;
338 int err = impl->module->stop(impl->handle);
339
340 if ( err )
341 return err;
342
343 if ( impl->dump )
344 {
345 pcap_dump_close(impl->dump);
346 impl->dump = NULL;
347 }
348
349 if ( impl->text_out )
350 {
351 fclose(impl->text_out);
352 impl->text_out = NULL;
353 }
354
355 return DAQ_SUCCESS;
356 }
357
358 //-------------------------------------------------------------------------
359 // these methods are delegated to the pcap daq
360
dump_daq_set_filter(void * handle,const char * filter)361 static int dump_daq_set_filter (void* handle, const char* filter)
362 {
363 DumpImpl* impl = (DumpImpl*)handle;
364 return impl->module->set_filter(impl->handle, filter);
365 }
366
dump_daq_breakloop(void * handle)367 static int dump_daq_breakloop (void* handle)
368 {
369 DumpImpl* impl = (DumpImpl*)handle;
370 return impl->module->breakloop(impl->handle);
371 }
372
dump_daq_check_status(void * handle)373 static DAQ_State dump_daq_check_status (void* handle)
374 {
375 DumpImpl* impl = (DumpImpl*)handle;
376 return impl->module->check_status(impl->handle);
377 }
378
dump_daq_get_stats(void * handle,DAQ_Stats_t * stats)379 static int dump_daq_get_stats (void* handle, DAQ_Stats_t* stats)
380 {
381 DumpImpl* impl = (DumpImpl*)handle;
382 int ret = impl->module->get_stats(impl->handle, stats);
383 int i;
384
385 for ( i = 0; i < MAX_DAQ_VERDICT; i++ )
386 stats->verdicts[i] = impl->stats.verdicts[i];
387
388 stats->packets_injected = impl->stats.packets_injected;
389 return ret;
390 }
391
dump_daq_reset_stats(void * handle)392 static void dump_daq_reset_stats (void* handle)
393 {
394 DumpImpl* impl = (DumpImpl*)handle;
395 impl->module->reset_stats(impl->handle);
396 memset(&impl->stats, 0, sizeof(impl->stats));
397 }
398
dump_daq_get_snaplen(void * handle)399 static int dump_daq_get_snaplen (void* handle)
400 {
401 DumpImpl* impl = (DumpImpl*)handle;
402 return impl->module->get_snaplen(impl->handle);
403 }
404
dump_daq_get_capabilities(void * handle)405 static uint32_t dump_daq_get_capabilities (void* handle)
406 {
407 DumpImpl* impl = (DumpImpl*)handle;
408 uint32_t caps = impl->module->get_capabilities(impl->handle);
409 caps |= DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT;
410 return caps;
411 }
412
dump_daq_get_datalink_type(void * handle)413 static int dump_daq_get_datalink_type (void *handle)
414 {
415 DumpImpl* impl = (DumpImpl*)handle;
416 return impl->module->get_datalink_type(impl->handle);
417 }
418
dump_daq_get_errbuf(void * handle)419 static const char* dump_daq_get_errbuf (void* handle)
420 {
421 DumpImpl* impl = (DumpImpl*)handle;
422 return impl->module->get_errbuf(impl->handle);
423 }
424
dump_daq_set_errbuf(void * handle,const char * s)425 static void dump_daq_set_errbuf (void* handle, const char* s)
426 {
427 DumpImpl* impl = (DumpImpl*)handle;
428 impl->module->set_errbuf(impl->handle, s ? s : "");
429 }
430
dump_daq_get_device_index(void * handle,const char * device)431 static int dump_daq_get_device_index(void* handle, const char* device)
432 {
433 DumpImpl* impl = (DumpImpl*)handle;
434 return impl->module->get_device_index(impl->handle, device);
435 }
436
dump_daq_modify_flow(void * handle,const DAQ_PktHdr_t * hdr,const DAQ_ModFlow_t * modify)437 static int dump_daq_modify_flow(void *handle, const DAQ_PktHdr_t *hdr, const DAQ_ModFlow_t *modify)
438 {
439 DumpImpl* impl = (DumpImpl*)handle;
440
441 if (impl->text_out)
442 {
443 fprintf(impl->text_out, "MF: %lu.%lu(%u): %d %u \n", (unsigned long) hdr->ts.tv_sec,
444 (unsigned long) hdr->ts.tv_usec, hdr->caplen, modify->type, modify->length);
445 hexdump(impl->text_out, modify->value, modify->length, " ");
446 }
447 return DAQ_SUCCESS;
448 }
449
dump_daq_dp_add_dc(void * handle,const DAQ_PktHdr_t * hdr,DAQ_DP_key_t * dp_key,const uint8_t * packet_data,DAQ_Data_Channel_Params_t * params)450 static int dump_daq_dp_add_dc(void *handle, const DAQ_PktHdr_t *hdr, DAQ_DP_key_t *dp_key,
451 const uint8_t *packet_data, DAQ_Data_Channel_Params_t *params)
452 {
453 DumpImpl* impl = (DumpImpl*)handle;
454
455 if (impl->text_out)
456 {
457 char src_addr_str[INET6_ADDRSTRLEN], dst_addr_str[INET6_ADDRSTRLEN];
458
459 fprintf(impl->text_out, "DP: %lu.%lu(%u):\n", (unsigned long) hdr->ts.tv_sec,
460 (unsigned long) hdr->ts.tv_usec, hdr->caplen);
461 if (dp_key->src_af == AF_INET)
462 inet_ntop(AF_INET, &dp_key->sa.src_ip4, src_addr_str, sizeof(src_addr_str));
463 else
464 inet_ntop(AF_INET6, &dp_key->sa.src_ip6, src_addr_str, sizeof(src_addr_str));
465 if (dp_key->dst_af == AF_INET)
466 inet_ntop(AF_INET, &dp_key->da.dst_ip4, dst_addr_str, sizeof(dst_addr_str));
467 else
468 inet_ntop(AF_INET6, &dp_key->da.dst_ip6, dst_addr_str, sizeof(dst_addr_str));
469 fprintf(impl->text_out, " %s:%hu -> %s:%hu (%hhu)\n", src_addr_str, dp_key->src_port,
470 dst_addr_str, dp_key->dst_port, dp_key->protocol);
471 fprintf(impl->text_out, " %hu %hu %hu %hu 0x%X %u\n", dp_key->address_space_id, dp_key->tunnel_type,
472 dp_key->vlan_id, dp_key->vlan_cnots, params ? params->flags : 0, params ? params->timeout_ms : 0);
473 }
474 return DAQ_SUCCESS;
475 }
476
477 //-------------------------------------------------------------------------
478
479 #ifdef BUILDING_SO
480 DAQ_SO_PUBLIC DAQ_Module_t DAQ_MODULE_DATA =
481 #else
482 DAQ_Module_t dump_daq_module_data =
483 #endif
484 {
485 .api_version = DAQ_API_VERSION,
486 .module_version = DAQ_MOD_VERSION,
487 .name = DAQ_NAME,
488 .type = DAQ_TYPE,
489 .initialize = dump_daq_initialize,
490 .set_filter = dump_daq_set_filter,
491 .start = dump_daq_start,
492 .acquire = dump_daq_acquire,
493 .inject = dump_daq_inject,
494 .breakloop = dump_daq_breakloop,
495 .stop = dump_daq_stop,
496 .shutdown = dump_daq_shutdown,
497 .check_status = dump_daq_check_status,
498 .get_stats = dump_daq_get_stats,
499 .reset_stats = dump_daq_reset_stats,
500 .get_snaplen = dump_daq_get_snaplen,
501 .get_capabilities = dump_daq_get_capabilities,
502 .get_datalink_type = dump_daq_get_datalink_type,
503 .get_errbuf = dump_daq_get_errbuf,
504 .set_errbuf = dump_daq_set_errbuf,
505 .get_device_index = dump_daq_get_device_index,
506 .modify_flow = dump_daq_modify_flow,
507 .hup_prep = NULL,
508 .hup_apply = NULL,
509 .hup_post = NULL,
510 .dp_add_dc = dump_daq_dp_add_dc,
511 .query_flow = NULL,
512 };
513
514