1 /*
2 * ldns-dpa inspects the (udp) DNS packets found in a pcap file
3 * and provides statistics about them
4 *
5 * (C) NLnet Labs 2006 - 2008
6 *
7 * See the file LICENSE for the license
8 */
9 #include "config.h"
10
11 #include <ldns/ldns.h>
12
13 #ifdef HAVE_PCAP_H
14 #ifdef HAVE_LIBPCAP
15 #include "ldns-dpa.h"
16
17 #ifdef HAVE_NETINET_IP6_H
18 #include <netinet/ip6.h>
19 #endif
20 #include <errno.h>
21
22 #ifndef IP_OFFMASK
23 #define IP_OFFMASK 0x1fff
24 #endif
25
26 int verbosity = 1;
27
28 #define ETHER_HEADER_LENGTH 14
29 #define UDP_HEADER_LENGTH 8
30 #define IP6_HEADER_LENGTH 40
31
32 /* some systems don't have this? */
33 #ifndef ETHERTYPE_IPV6
34 #define ETHERTYPE_IPV6 0x86dd
35 #endif
36
37 #define MAX_MATCHES 20
38 #define MAX_OPERATORS 7
39
40
41 /* global options */
42 bool show_filter_matches = false;
43 size_t total_nr_of_dns_packets = 0;
44 size_t total_nr_of_filtered_packets = 0;
45 size_t not_ip_packets = 0;
46 size_t bad_dns_packets = 0;
47 size_t arp_packets = 0;
48 size_t udp_packets = 0;
49 size_t tcp_packets = 0;
50 size_t fragmented_packets = 0;
51 size_t lost_packet_fragments = 0;
52 FILE *hexdumpfile = NULL;
53 pcap_dumper_t *dumper = NULL;
54 pcap_dumper_t *not_ip_dump = NULL;
55 pcap_dumper_t *bad_dns_dump = NULL;
56
57
58 struct
59 fragment_part {
60 uint16_t ip_id;
61 uint8_t data[65536];
62 size_t cur_len;
63 };
64
65 struct fragment_part *fragment_p;
66
67 /* To add a match,
68 * - add it to the enum
69 * - add it to the table_matches const
70 * - add a handler to value_matches
71 * - tell in get_string_value() where in the packet the data lies
72 * - add to parser?
73 * - add to show_match_ function
74 */
75 enum enum_match_ids {
76 MATCH_ID,
77 MATCH_OPCODE,
78 MATCH_RCODE,
79 MATCH_PACKETSIZE,
80 MATCH_QR,
81 MATCH_TC,
82 MATCH_AD,
83 MATCH_CD,
84 MATCH_RD,
85 MATCH_EDNS,
86 MATCH_EDNS_PACKETSIZE,
87 MATCH_DO,
88 MATCH_QUESTION_SIZE,
89 MATCH_ANSWER_SIZE,
90 MATCH_AUTHORITY_SIZE,
91 MATCH_ADDITIONAL_SIZE,
92 MATCH_SRC_ADDRESS,
93 MATCH_DST_ADDRESS,
94 MATCH_TIMESTAMP,
95 MATCH_QUERY,
96 MATCH_QTYPE,
97 MATCH_QNAME,
98 MATCH_ANSWER,
99 MATCH_AUTHORITY,
100 MATCH_ADDITIONAL,
101 MATCH_LAST
102 };
103 typedef enum enum_match_ids match_id;
104
105 enum enum_counter_types {
106 TYPE_INT,
107 TYPE_BOOL,
108 TYPE_OPCODE,
109 TYPE_RCODE,
110 TYPE_STRING,
111 TYPE_TIMESTAMP,
112 TYPE_ADDRESS,
113 TYPE_RR,
114 TYPE_RR_TYPE,
115 TYPE_LAST
116 };
117 typedef enum enum_counter_types counter_type;
118
119 const ldns_lookup_table lt_types[] = {
120 {TYPE_INT, "int" },
121 {TYPE_BOOL, "bool" },
122 {TYPE_OPCODE, "opcode" },
123 {TYPE_RCODE, "rcode" },
124 {TYPE_STRING, "string" },
125 {TYPE_TIMESTAMP, "timestamp" },
126 {TYPE_ADDRESS, "address" },
127 {TYPE_RR, "rr" },
128 { 0, NULL }
129 };
130
131 enum enum_type_operators {
132 OP_EQUAL,
133 OP_NOTEQUAL,
134 OP_GREATER,
135 OP_LESSER,
136 OP_GREATEREQUAL,
137 OP_LESSEREQUAL,
138 OP_CONTAINS,
139 OP_LAST
140 };
141 typedef enum enum_type_operators type_operator;
142
143 const ldns_lookup_table lt_operators[] = {
144 { OP_EQUAL, "=" },
145 { OP_NOTEQUAL, "!=" },
146 { OP_GREATER, ">" },
147 { OP_LESSER, "<" },
148 { OP_GREATEREQUAL, ">=" },
149 { OP_LESSEREQUAL, "<=" },
150 { OP_CONTAINS, "~=" },
151 { 0, NULL }
152 };
153
get_op_str(type_operator op)154 static const char *get_op_str(type_operator op) {
155 const ldns_lookup_table *lt;
156 lt = ldns_lookup_by_id((ldns_lookup_table *) lt_operators, op);
157 if (lt) {
158 return lt->name;
159 } else {
160 fprintf(stderr, "Unknown operator id: %u\n", op);
161 exit(1);
162 }
163 }
164
165 static type_operator
get_op_id(char * op_str)166 get_op_id(char *op_str)
167 {
168 const ldns_lookup_table *lt;
169 lt = ldns_lookup_by_name((ldns_lookup_table *) lt_operators, op_str);
170 if (lt) {
171 return (type_operator) lt->id;
172 } else {
173 fprintf(stderr, "Unknown operator: %s\n", op_str);
174 exit(1);
175 }
176 }
177
178 struct struct_type_operators {
179 counter_type type;
180 size_t operator_count;
181 type_operator operators[10];
182 };
183 typedef struct struct_type_operators type_operators;
184
185 const type_operators const_type_operators[] = {
186 { TYPE_INT, 6, { OP_EQUAL, OP_NOTEQUAL, OP_GREATER, OP_LESSER, OP_GREATEREQUAL, OP_LESSEREQUAL, 0, 0, 0, 0 } },
187 { TYPE_BOOL, 2, { OP_EQUAL, OP_NOTEQUAL, 0, 0, 0, 0, 0, 0, 0, 0} },
188 { TYPE_OPCODE, 2, { OP_EQUAL, OP_NOTEQUAL, 0, 0, 0, 0, 0, 0, 0, 0} },
189 { TYPE_RCODE, 2, { OP_EQUAL, OP_NOTEQUAL, 0, 0, 0, 0, 0, 0, 0, 0} },
190 { TYPE_STRING, 3, { OP_EQUAL, OP_NOTEQUAL, OP_CONTAINS, 0, 0, 0, 0, 0, 0, 0} },
191 { TYPE_TIMESTAMP, 6, { OP_EQUAL, OP_NOTEQUAL, OP_GREATER, OP_LESSER, OP_GREATEREQUAL, OP_LESSEREQUAL, 0, 0, 0, 0 } },
192 { TYPE_ADDRESS, 3, { OP_EQUAL, OP_NOTEQUAL, OP_CONTAINS, 0, 0, 0, 0, 0, 0, 0} },
193 { TYPE_RR, 3, { OP_EQUAL, OP_NOTEQUAL, OP_CONTAINS, 0, 0, 0, 0, 0, 0, 0} },
194 { TYPE_RR_TYPE, 6, { OP_EQUAL, OP_NOTEQUAL, OP_GREATER, OP_LESSER, OP_GREATEREQUAL, OP_LESSEREQUAL, 0, 0, 0, 0 } },
195 { 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
196 };
197
198 const type_operators *
get_type_operators(counter_type type)199 get_type_operators(counter_type type) {
200 const type_operators *to = const_type_operators;
201 while (to) {
202 if (to->type == type) {
203 return to;
204 }
205 to++;
206 }
207 return NULL;
208 }
209
210 struct struct_match_table {
211 match_id id;
212 const char *name;
213 const char *description;
214 const counter_type type;
215 };
216 typedef struct struct_match_table match_table;
217
218 /* order of entries has been changed after gprof analysis, and reasoning
219 * about the uses of -u arguments
220 */
221 const match_table matches[] = {
222 { MATCH_QUERY, "query", "String representation of the query RR", TYPE_RR },
223 { MATCH_QTYPE, "qtype", "RR Type of the question RR, if present", TYPE_RR_TYPE },
224 { MATCH_QNAME, "qname", "Owner name of the question RR, if present", TYPE_STRING },
225 { MATCH_SRC_ADDRESS, "srcaddress", "address the packet was sent from", TYPE_ADDRESS },
226 { MATCH_TIMESTAMP, "timestamp", "time the packet was sent", TYPE_TIMESTAMP },
227 { MATCH_DST_ADDRESS, "dstaddress", "address the packet was sent to", TYPE_ADDRESS },
228 { MATCH_EDNS_PACKETSIZE, "edns-packetsize", "packets size specified in edns rr", TYPE_INT },
229 { MATCH_ID, "id", "id of the packet", TYPE_INT },
230 { MATCH_OPCODE, "opcode", "opcode of packet (rfc1035)", TYPE_OPCODE },
231 { MATCH_RCODE, "rcode", "response code of packet", TYPE_RCODE },
232 { MATCH_PACKETSIZE, "packetsize", "size of packet in bytes", TYPE_INT },
233 { MATCH_QR, "qr", "value of qr bit", TYPE_BOOL },
234 { MATCH_TC, "tc", "value of tc bit", TYPE_BOOL },
235 { MATCH_AD, "ad", "value of ad bit", TYPE_BOOL },
236 { MATCH_CD, "cd", "value of cd bit", TYPE_BOOL },
237 { MATCH_RD, "rd", "value of rd bit", TYPE_BOOL },
238 { MATCH_EDNS, "edns", "existence of edns rr", TYPE_BOOL },
239 { MATCH_DO, "do", "value of do bit", TYPE_BOOL },
240 { MATCH_QUESTION_SIZE, "questionsize", "number of rrs in the question section", TYPE_INT },
241 { MATCH_ANSWER_SIZE, "answersize", "number of rrs in the answer section", TYPE_INT },
242 { MATCH_AUTHORITY_SIZE, "authoritysize", "number of rrs in the authority section", TYPE_INT },
243 { MATCH_ADDITIONAL_SIZE, "additionalsize", "number of rrs in the additional section", TYPE_INT },
244 { MATCH_ANSWER, "answer", "String representation of the answer RRs", TYPE_RR },
245 { MATCH_AUTHORITY, "authority", "String representation of the authority RRs", TYPE_RR },
246 { MATCH_ADDITIONAL, "additional", "String representation of the additional RRs", TYPE_RR },
247 { 0, NULL , NULL, TYPE_INT}
248 };
249
250 enum enum_match_expression_operators {
251 MATCH_EXPR_OR,
252 MATCH_EXPR_AND,
253 MATCH_EXPR_LEAF
254 };
255 typedef enum enum_match_expression_operators match_expression_operator;
256
257 struct struct_match_operation {
258 match_id id;
259 type_operator operator;
260 char *value;
261 };
262 typedef struct struct_match_operation match_operation;
263
264 typedef struct struct_match_expression match_expression;
265 struct struct_match_expression {
266 /* and or or, or leaf (in which case there are no subtrees, but only a match_table */
267 match_expression_operator op;
268 match_expression *left;
269 match_expression *right;
270 match_operation *match;
271 size_t count;
272 };
273
274 typedef struct struct_match_counters match_counters;
275 struct struct_match_counters {
276 /*
277 match_expression **counter;
278 size_t size;
279 */
280 match_expression *match;
281 match_counters *left;
282 match_counters *right;
283 };
284
285 match_table *
get_match_by_name(char * name)286 get_match_by_name(char *name) {
287 match_table *mt = (match_table *) matches;
288 if (name) {
289 while (mt->name != NULL) {
290 if (strcasecmp(name, mt->name) == 0) {
291 return mt;
292 }
293 mt++;
294 }
295 }
296 return NULL;
297 }
298
299 static match_table *
get_match_by_id(match_id id)300 get_match_by_id(match_id id) {
301 match_table *mt = (match_table *) matches;
302
303 while (mt->name != NULL) {
304 if (mt->id == id) {
305 return mt;
306 }
307 mt++;
308 }
309 return NULL;
310 }
311
312 static const char *
get_match_name_str(match_id id)313 get_match_name_str(match_id id) {
314 match_table *mt = get_match_by_id(id);
315 if (mt) {
316 return mt->name;
317 } else {
318 fprintf(stderr, "Unknown match id: %u\n", id);
319 exit(1);
320 return "Unknown match id";
321 }
322 }
323
324 static void
print_match_operation(FILE * output,match_operation * mc)325 print_match_operation(FILE *output, match_operation *mc)
326 {
327 match_table *mt = NULL;
328 ldns_lookup_table *lt;
329 struct timeval time;
330 time_t time_tt;
331 int value;
332 size_t pos;
333 char *tmp, *tmp2;
334
335 if (mc) {
336 mt = get_match_by_id(mc->id);
337
338 if (mt) {
339 fprintf(output, "%s %s ",mt->name, get_op_str(mc->operator));
340
341 switch (mt->type) {
342 case TYPE_INT:
343 case TYPE_STRING:
344 case TYPE_ADDRESS:
345 case TYPE_RR:
346 fprintf(output, "'%s'", mc->value);
347 break;
348 case TYPE_BOOL:
349 if (strncmp(mc->value, "1", 2) == 0) {
350 fprintf(output,"'true'");
351 } else {
352 fprintf(output,"'false'");
353 }
354 break;
355 case TYPE_OPCODE:
356 value = atoi(mc->value);
357 lt = ldns_lookup_by_id(ldns_opcodes, value);
358 if (lt) {
359 fprintf(output, "%s", lt->name);
360 } else {
361 fprintf(output, "%s", mc->value);
362 }
363 break;
364 case TYPE_RCODE:
365 value = atoi(mc->value);
366 lt = ldns_lookup_by_id(ldns_rcodes, value);
367 if (lt) {
368 fprintf(output, "%s", lt->name);
369 } else {
370 fprintf(output, "%s", mc->value);
371 }
372 break;
373 case TYPE_TIMESTAMP:
374 #ifndef S_SPLINT_S
375 time.tv_sec = (long int) atol(mc->value);
376 #endif
377 time_tt = (time_t)time.tv_sec;
378 tmp = ctime(&time_tt);
379 tmp2 = malloc(strlen(tmp) + 1);
380 for (pos = 0; pos < strlen(tmp); pos++) {
381 if (tmp[pos] == '\n') {
382 tmp2[pos] = '\0';
383 } else {
384 tmp2[pos] = tmp[pos];
385 }
386 }
387 tmp2[pos] = '\0';
388 fprintf(output, "%s", tmp2);
389 free(tmp2);
390 break;
391 default:
392 fprintf(output, "'%s'", mc->value);
393 }
394
395 } else {
396 fprintf(output, "%u %s '%s'", mc->id, get_op_str(mc->operator), mc->value);
397 }
398 } else {
399 fprintf(output, "(nil)");
400 }
401 }
402
403 static void
print_match_expression(FILE * output,match_expression * expr)404 print_match_expression(FILE *output, match_expression *expr)
405 {
406 if (expr) {
407 switch (expr->op) {
408 case MATCH_EXPR_OR:
409 fprintf(output, "(");
410 print_match_expression(output, expr->left);
411 fprintf(output, " | ");
412 print_match_expression(output, expr->right);
413 fprintf(output, ")");
414 break;
415 case MATCH_EXPR_AND:
416 fprintf(output, "(");
417 print_match_expression(output, expr->left);
418 fprintf(output, " & ");
419 print_match_expression(output, expr->right);
420 fprintf(output, ")");
421 break;
422 case MATCH_EXPR_LEAF:
423 print_match_operation(output, expr->match);
424 break;
425 default:
426 /*
427 fprintf(output, "ERROR PRINTING MATCH: unknown op: %u\n", expr->op);
428 exit(1);
429 */
430 fprintf(output, "(");
431 if (expr->left) {
432 print_match_expression(output, expr->left);
433 }
434 fprintf(output, " ? ");
435 if (expr->right) {
436 print_match_expression(output, expr->right);
437 }
438 fprintf(output, ") _");
439 if (expr->match) {
440 print_match_operation(output, expr->match);
441 }
442 fprintf(output, "_");
443 }
444 } else {
445 printf("(nil)");
446 }
447 }
448
449 static void
print_counters(FILE * output,match_counters * counters,bool show_percentages,size_t total,int count_minimum)450 print_counters(FILE *output, match_counters *counters, bool show_percentages, size_t total, int count_minimum)
451 {
452 double percentage;
453
454 if (!counters || !output) {
455 return;
456 }
457
458 if (counters->left) {
459 print_counters(output, counters->left, show_percentages, total, count_minimum);
460 }
461 if (counters->match) {
462 if (count_minimum < (int) counters->match->count) {
463 print_match_expression(output, counters->match);
464 printf(": %u", (unsigned int) counters->match->count);
465 if (show_percentages) {
466 percentage = (double) counters->match->count / (double) total * 100.0;
467 printf(" (%.2f%%)", percentage);
468 }
469 printf("\n");
470 }
471 }
472 if (counters->right) {
473 print_counters(output, counters->right, show_percentages, total, count_minimum);
474 }
475
476 return;
477 }
478
479 static void
ldns_pkt2file_hex(FILE * fp,const ldns_pkt * pkt)480 ldns_pkt2file_hex(FILE *fp, const ldns_pkt *pkt)
481 {
482 uint8_t *wire;
483 size_t size, i;
484 ldns_status status;
485
486 status = ldns_pkt2wire(&wire, pkt, &size);
487
488 if (status != LDNS_STATUS_OK) {
489 fprintf(stderr, "Unable to convert packet: error code %u", status);
490 return;
491 }
492
493 fprintf(fp, "; 0");
494 for (i = 1; i < 20; i++) {
495 fprintf(fp, " %2u", (unsigned int) i);
496 }
497 fprintf(fp, "\n");
498 fprintf(fp, ";--");
499 for (i = 1; i < 20; i++) {
500 fprintf(fp, " --");
501 }
502 fprintf(fp, "\n");
503 for (i = 0; i < size; i++) {
504 if (i % 20 == 0 && i > 0) {
505 fprintf(fp, "\t; %4u-%4u\n", (unsigned int) i-19, (unsigned int) i);
506 }
507 fprintf(fp, " %02x", (unsigned int)wire[i]);
508 }
509 fprintf(fp, "\n\n");
510 }
511
512 /*
513 * Calculate the total for all match operations with the same id as this one
514 * (if they are 'under' this one in the tree, which should be the case in
515 * the unique counter tree
516 */
517 static size_t
calculate_total_value(match_counters * counters,match_operation * cur)518 calculate_total_value(match_counters *counters, match_operation *cur)
519 {
520 size_t result = 0;
521
522 if (!counters) {
523 return 0;
524 }
525
526 if (counters->match->match->id == cur->id) {
527 result = (size_t) atol(counters->match->match->value) * counters->match->count;
528 }
529
530 if (counters->left) {
531 result += calculate_total_value(counters->left, cur);
532 }
533 if (counters->right) {
534 result += calculate_total_value(counters->right, cur);
535 }
536
537 return result;
538 }
539
540 static size_t
calculate_total_count_matches(match_counters * counters,match_operation * cur)541 calculate_total_count_matches(match_counters *counters, match_operation *cur)
542 {
543 size_t result = 0;
544
545 if (!counters) {
546 return 0;
547 }
548
549 if (counters->match->match->id == cur->id) {
550 result = 1;
551 }
552
553 if (counters->left) {
554 /* In some cases, you don't want the number of actual
555 counted matches, for instance when calculating the
556 average number of queries per second. In this case
557 you want the number of seconds */
558 if (cur->id == MATCH_TIMESTAMP) {
559 result += (size_t) abs((int) (atol(counters->match->match->value) - atol(counters->left->match->match->value))) - 1;
560 }
561 result += calculate_total_count_matches(counters->left, cur);
562 }
563 if (counters->right) {
564 if (cur->id == MATCH_TIMESTAMP) {
565 result += (size_t) abs((int) (atol(counters->right->match->match->value) - atol(counters->match->match->value))) - 1;
566 }
567 result += calculate_total_count_matches(counters->right, cur);
568 }
569
570 return result;
571 }
572
573 /**
574 * Returns true if there is a previous match operation with the given type
575 * in the counters structure
576 */
577 static bool
has_previous_match(match_counters * counters,match_operation * cur)578 has_previous_match(match_counters *counters, match_operation *cur)
579 {
580 if (!counters) {
581 return false;
582 }
583
584 if (counters->left) {
585 if (counters->left->match->match->id == cur->id) {
586 return true;
587 } else if (has_previous_match(counters->left, cur)) {
588 return true;
589 } else if (counters->left->right) {
590 if (counters->left->right->match->match->id == cur->id) {
591 return true;
592 } else if (has_previous_match(counters->left->right, cur)) {
593 return true;
594 }
595 }
596 }
597 return false;
598 }
599
600 /**
601 * Returns true if there is a later match operation with the given type
602 * in the counters structure
603 */
604 static bool
has_next_match(match_counters * counters,match_operation * cur)605 has_next_match(match_counters *counters, match_operation *cur)
606 {
607 if (!counters) {
608 return false;
609 }
610
611 if (counters->right) {
612 if (counters->right->match->match->id == cur->id) {
613 return true;
614 } else if (has_next_match(counters->right, cur)) {
615 return true;
616 } else if (counters->right->left) {
617 if (counters->right->left->match->match->id == cur->id) {
618 return true;
619 } else if (has_next_match(counters->right->left, cur)) {
620 return true;
621 }
622 }
623 }
624 return false;
625 }
626
627 /**
628 * Returns the first match with the same type at *cur in
629 * the counter list, or NULL if it is not found
630 */
631 static match_expression *
get_first_match_expression(match_counters * counters,match_operation * cur)632 get_first_match_expression(match_counters *counters, match_operation *cur)
633 {
634 if (!counters) {
635 return NULL;
636 }
637
638 if (has_previous_match(counters, cur)) {
639 return get_first_match_expression(counters->left, cur);
640 } else if (counters->match->match->id == cur->id) {
641 return counters->match;
642 } else if (counters->right) {
643 return get_first_match_expression(counters->right, cur);
644 } else {
645 return NULL;
646 }
647 }
648
649 /**
650 * Returns the second match expression with the same type at *cur in
651 * the counter list, or NULL if it is not found
652 */
653 static match_expression *
get_second_match_expression(match_counters * counters,match_operation * cur)654 get_second_match_expression(match_counters *counters, match_operation *cur)
655 {
656 if (!counters) {
657 return NULL;
658 }
659
660 if (has_previous_match(counters, cur)) {
661 if (has_previous_match(counters->left, cur)) {
662 return get_second_match_expression(counters->left, cur);
663 } else {
664 return counters->left->match;
665 }
666 /*
667 } else if (counters->match->match->id == cur->id) {
668 return counters->match->match->value;
669 */ } else if (counters->right) {
670 return get_first_match_expression(counters->right, cur);
671 } else {
672 return NULL;
673 }
674 }
675
676 /**
677 * Returns the last match expression with the same type at *cur in
678 * the counter list, or NULL if it is not found
679 */
680 static match_expression *
get_last_match_expression(match_counters * counters,match_operation * cur)681 get_last_match_expression(match_counters *counters, match_operation *cur)
682 {
683 if (!counters) {
684 return NULL;
685 }
686
687 if (has_next_match(counters, cur)) {
688 return get_last_match_expression(counters->right, cur);
689 } else if (counters->match->match->id == cur->id) {
690 return counters->match;
691 } else if (counters->left) {
692 return get_last_match_expression(counters->left, cur);
693 } else {
694 return NULL;
695 }
696 }
697
698 /**
699 * Returns the last but one match expression with the same type at *cur in
700 * the counter list, or NULL if it is not found
701 */
702 static match_expression *
get_last_but_one_match_expression(match_counters * counters,match_operation * cur)703 get_last_but_one_match_expression(match_counters *counters, match_operation *cur)
704 {
705 if (!counters) {
706 return NULL;
707 }
708
709 if (has_next_match(counters, cur)) {
710 if (has_next_match(counters->right, cur)) {
711 return get_last_but_one_match_expression(counters->right, cur);
712 } else {
713 return counters->match;
714 }
715 /*
716 } else if (counters->match->match->id == cur->id) {
717 return counters->match->match->value;
718 */ } else if (counters->left) {
719 return get_last_match_expression(counters->right, cur);
720 } else {
721 return NULL;
722 }
723 }
724
725 static size_t
get_first_count(match_counters * counters,match_operation * cur)726 get_first_count(match_counters *counters, match_operation *cur)
727 {
728 match_expression *o = get_first_match_expression(counters, cur);
729 if (o) {
730 return o->count;
731 } else {
732 return 0;
733 }
734 }
735
736 static size_t
get_last_count(match_counters * counters,match_operation * cur)737 get_last_count(match_counters *counters, match_operation *cur)
738 {
739 match_expression *o = get_last_match_expression(counters, cur);
740 if (o) {
741 return o->count;
742 } else {
743 return 0;
744 }
745 }
746
747
748 static size_t
calculate_total_count(match_counters * counters,match_operation * cur)749 calculate_total_count(match_counters *counters, match_operation *cur)
750 {
751 size_t result = 0;
752
753 if (!counters) {
754 return 0;
755 }
756
757 if (counters->match->match->id == cur->id) {
758 result = counters->match->count;
759 }
760
761 if (counters->left) {
762 result += calculate_total_count(counters->left, cur);
763 }
764 if (counters->right) {
765 result += calculate_total_count(counters->right, cur);
766 }
767
768 return result;
769 }
770
771 static void
print_counter_averages(FILE * output,match_counters * counters,match_operation * cur)772 print_counter_averages(FILE *output, match_counters *counters, match_operation *cur)
773 {
774 size_t total_value;
775 size_t total_count;
776 match_table *mt;
777
778 if (!counters || !output) {
779 return;
780 }
781
782 if (!cur) {
783 cur = counters->match->match;
784 mt = get_match_by_id(cur->id);
785 total_value = calculate_total_value(counters, cur);
786 total_count = calculate_total_count(counters, cur);
787 printf("Average for %s: (%u / %u) %.02f\n", mt->name, (unsigned int) total_value, (unsigned int) total_count, (float) total_value / (float) total_count);
788 if (counters->left) {
789 print_counter_averages(output, counters->left, cur);
790 }
791 if (counters->right) {
792 print_counter_averages(output, counters->right, cur);
793 }
794 } else {
795 if (counters->left) {
796 if (counters->left->match->match->id != cur->id) {
797 print_counter_averages(output, counters->left, NULL);
798 }
799 }
800 if (counters->right) {
801 if (counters->right->match->match->id != cur->id) {
802 print_counter_averages(output, counters->right, NULL);
803 }
804 }
805 }
806
807 return;
808 }
809
810 static void
print_counter_average_count(FILE * output,match_counters * counters,match_operation * cur,bool remove_first_last)811 print_counter_average_count(FILE *output, match_counters *counters, match_operation *cur, bool remove_first_last)
812 {
813 size_t total_matches;
814 size_t total_count;
815 match_table *mt;
816
817 if (!counters || !output) {
818 return;
819 }
820
821 if (!cur) {
822 cur = counters->match->match;
823 mt = get_match_by_id(cur->id);
824 total_matches = calculate_total_count_matches(counters, cur);
825 total_count = calculate_total_count(counters, cur);
826 /* Remove the first and last for instance for timestamp average counts (half seconds drag down the average) */
827 if (remove_first_last) {
828 total_count -= get_first_count(counters, cur);
829 total_count -= get_last_count(counters, cur);
830 printf("Removing first count from average: %u\n", (unsigned int) get_first_count(counters,cur));
831 printf("Removing last count from average: %u\n", (unsigned int) get_last_count(counters,cur));
832 /* in the case where we count the differences between match values too
833 * (like with timestamps) we need to subtract from the match count too
834 */
835 if (cur->id == MATCH_TIMESTAMP) {
836 if (get_first_match_expression(counters, cur) && get_second_match_expression(counters, cur)) {
837 total_matches -= atol(get_second_match_expression(counters, cur)->match->value) - atol(get_first_match_expression(counters, cur)->match->value);
838 }
839 if (get_last_match_expression(counters, cur) && get_last_but_one_match_expression(counters, cur)) {
840 total_matches -= atol(get_last_match_expression(counters, cur)->match->value) - atol(get_last_but_one_match_expression(counters, cur)->match->value);
841 }
842 } else {
843 total_matches -= 2;
844 }
845 }
846 printf("Average count for %s: (%u / %u) %.02f\n", mt->name, (unsigned int) total_count, (unsigned int) total_matches, (float) total_count / (float) total_matches);
847 if (counters->left) {
848 print_counter_averages(output, counters->left, cur);
849 }
850 if (counters->right) {
851 print_counter_averages(output, counters->right, cur);
852 }
853 } else {
854 if (counters->left) {
855 if (counters->left->match->match->id != cur->id) {
856 print_counter_averages(output, counters->left, NULL);
857 }
858 }
859 if (counters->right) {
860 if (counters->right->match->match->id != cur->id) {
861 print_counter_averages(output, counters->right, NULL);
862 }
863 }
864 }
865
866 return;
867 }
868
869 static bool
match_int(type_operator operator,char * value,char * mvalue)870 match_int(type_operator operator,
871 char *value,
872 char *mvalue)
873 {
874 int a, b;
875
876 if (!value || !mvalue) {
877 return false;
878 }
879
880 a = atoi(value);
881 b = atoi(mvalue);
882
883 switch (operator) {
884 case OP_EQUAL:
885 return a == b;
886 break;
887 case OP_NOTEQUAL:
888 return a != b;
889 break;
890 case OP_GREATER:
891 return a > b;
892 break;
893 case OP_LESSER:
894 return a < b;
895 break;
896 case OP_GREATEREQUAL:
897 return a >= b;
898 break;
899 case OP_LESSEREQUAL:
900 return a <= b;
901 break;
902 default:
903 fprintf(stderr, "Unknown operator: %u\n", operator);
904 exit(2);
905 }
906 }
907
908 static bool
match_opcode(type_operator operator,char * value,char * mvalue)909 match_opcode(type_operator operator,
910 char *value,
911 char *mvalue)
912 {
913 ldns_pkt_opcode a, b;
914 int i;
915 ldns_lookup_table *lt;
916
917 /* try parse name first, then parse as int */
918 lt = ldns_lookup_by_name(ldns_opcodes, value);
919 if (lt) {
920 a = lt->id;
921 } else {
922 i = atoi(value);
923 if (i >= 0 && isdigit((unsigned char)value[0])) {
924 lt = ldns_lookup_by_id(ldns_opcodes, i);
925 if (lt) {
926 a = lt->id;
927 } else {
928 fprintf(stderr, "Unknown opcode: %s\n", value);
929 exit(1);
930 return false;
931 }
932 } else {
933 fprintf(stderr, "Unknown opcode: %s\n", value);
934 exit(1);
935 return false;
936 }
937 }
938
939 lt = ldns_lookup_by_name(ldns_opcodes, mvalue);
940 if (lt) {
941 b = lt->id;
942 } else {
943 i = atoi(mvalue);
944 if (i >= 0 && isdigit((unsigned char)mvalue[0])) {
945 lt = ldns_lookup_by_id(ldns_opcodes, i);
946 if (lt) {
947 b = lt->id;
948 } else {
949 fprintf(stderr, "Unknown opcode: %s\n", mvalue);
950 exit(1);
951 return false;
952 }
953 } else {
954 fprintf(stderr, "Unknown opcode: %s\n", mvalue);
955 exit(1);
956 return false;
957 }
958 }
959
960 switch(operator) {
961 case OP_EQUAL:
962 return a == b;
963 break;
964 case OP_NOTEQUAL:
965 return a != b;
966 break;
967 default:
968 fprintf(stderr, "Error bad operator for opcode: %s\n", get_op_str(operator));
969 return false;
970 break;
971 }
972 }
973
974 static bool
match_str(type_operator operator,char * value,char * mvalue)975 match_str(type_operator operator,
976 char *value,
977 char *mvalue)
978 {
979 char *valuedup, *mvaluedup;
980 size_t i;
981 bool result;
982
983 if (operator == OP_CONTAINS) {
984 /* strcasestr is not C89
985 return strcasestr(value, mvalue) != 0;
986 */
987 valuedup = strdup(value);
988 mvaluedup = strdup(mvalue);
989 for (i = 0; i < strlen(valuedup); i++) {
990 valuedup[i] = tolower((unsigned char)valuedup[i]);
991 }
992 for (i = 0; i < strlen(mvaluedup); i++) {
993 mvaluedup[i] = tolower((unsigned char)mvaluedup[i]);
994 }
995 result = strstr(valuedup, mvaluedup) != 0;
996 free(valuedup);
997 free(mvaluedup);
998 return result;
999 } else if (operator == OP_EQUAL) {
1000 return strcmp(value, mvalue) == 0;
1001 } else {
1002 return strcmp(value, mvalue) != 0;
1003 }
1004 }
1005
1006 static bool
match_rr_type(type_operator operator,char * value,char * mvalue)1007 match_rr_type(type_operator operator,
1008 char *value,
1009 char *mvalue)
1010 {
1011 ldns_rr_type a,b;
1012
1013 a = ldns_get_rr_type_by_name(value);
1014 b = ldns_get_rr_type_by_name(mvalue);
1015
1016 switch (operator) {
1017 case OP_EQUAL:
1018 return a == b;
1019 break;
1020 case OP_NOTEQUAL:
1021 return a != b;
1022 break;
1023 case OP_GREATER:
1024 return a > b;
1025 break;
1026 case OP_LESSER:
1027 return a < b;
1028 break;
1029 case OP_GREATEREQUAL:
1030 return a >= b;
1031 break;
1032 case OP_LESSEREQUAL:
1033 return a <= b;
1034 break;
1035 default:
1036 fprintf(stderr, "Unknown operator: %u\n", operator);
1037 exit(2);
1038 }
1039 }
1040
1041 static bool
match_rcode(type_operator operator,char * value,char * mvalue)1042 match_rcode(type_operator operator,
1043 char *value,
1044 char *mvalue)
1045 {
1046 int a, b;
1047 int i;
1048 ldns_lookup_table *lt;
1049
1050 /* try parse name first, then parse as int */
1051 lt = ldns_lookup_by_name(ldns_rcodes, value);
1052 if (lt) {
1053 a = lt->id;
1054 } else {
1055 i = atoi(value);
1056 if (i >= 0 && isdigit((unsigned char)value[0])) {
1057 lt = ldns_lookup_by_id(ldns_rcodes, i);
1058 if (lt) {
1059 a = lt->id;
1060 } else {
1061 fprintf(stderr, "Unknown rcode: %s\n", value);
1062 exit(1);
1063 return false;
1064 }
1065 } else {
1066 fprintf(stderr, "Unknown rcode: %s\n", value);
1067 exit(1);
1068 return false;
1069 }
1070 }
1071
1072 lt = ldns_lookup_by_name(ldns_rcodes, mvalue);
1073 if (lt) {
1074 b = lt->id;
1075 } else {
1076 i = atoi(mvalue);
1077 if (i >= 0 && isdigit((unsigned char)mvalue[0])) {
1078 lt = ldns_lookup_by_id(ldns_rcodes, i);
1079 if (lt) {
1080 b = lt->id;
1081 } else {
1082 fprintf(stderr, "Unknown rcode: %s\n", mvalue);
1083 exit(1);
1084 return false;
1085 }
1086 } else {
1087 fprintf(stderr, "Unknown rcode: %s\n", mvalue);
1088 exit(1);
1089 return false;
1090 }
1091 }
1092
1093 switch(operator) {
1094 case OP_EQUAL:
1095 return a == b;
1096 break;
1097 case OP_NOTEQUAL:
1098 return a != b;
1099 break;
1100 default:
1101 fprintf(stderr, "Error bad operator for rcode: %s\n", get_op_str(operator));
1102 return false;
1103 break;
1104 }
1105 }
1106
1107 static bool
value_matches(match_id id,type_operator operator,char * value,char * mvalue)1108 value_matches(match_id id,
1109 type_operator operator,
1110 char *value,
1111 char *mvalue)
1112 {
1113 int result;
1114
1115 if (verbosity >= 5) {
1116 printf("Match %s: %s %s %s: ", get_match_name_str(id), value, get_op_str(operator), mvalue);
1117 }
1118 switch(id) {
1119 case MATCH_OPCODE:
1120 result = match_opcode(operator, value, mvalue);
1121 break;
1122 case MATCH_RCODE:
1123 result = match_rcode(operator, value, mvalue);
1124 break;
1125 case MATCH_ID:
1126 case MATCH_QR:
1127 case MATCH_TC:
1128 case MATCH_AD:
1129 case MATCH_CD:
1130 case MATCH_RD:
1131 case MATCH_DO:
1132 case MATCH_PACKETSIZE:
1133 case MATCH_EDNS:
1134 case MATCH_EDNS_PACKETSIZE:
1135 case MATCH_QUESTION_SIZE:
1136 case MATCH_ANSWER_SIZE:
1137 case MATCH_AUTHORITY_SIZE:
1138 case MATCH_ADDITIONAL_SIZE:
1139 case MATCH_TIMESTAMP:
1140 result = match_int(operator, value, mvalue);
1141 break;
1142 case MATCH_QUERY:
1143 case MATCH_QNAME:
1144 case MATCH_ANSWER:
1145 case MATCH_AUTHORITY:
1146 case MATCH_ADDITIONAL:
1147 result = match_str(operator, value, mvalue);
1148 break;
1149 case MATCH_SRC_ADDRESS:
1150 case MATCH_DST_ADDRESS:
1151 result = match_str(operator, value, mvalue);
1152 break;
1153 case MATCH_QTYPE:
1154 result = match_rr_type(operator, value, mvalue);
1155 break;
1156 default:
1157 fprintf(stderr, "Error: value_matches() for operator %s not implemented yet.\n", get_op_str((type_operator) id));
1158 exit(3);
1159 }
1160 if (verbosity >= 5) {
1161 if (result) {
1162 printf("true\n");
1163 } else {
1164 printf("false\n");
1165 }
1166 }
1167 return result;
1168 }
1169
1170 static char *
get_string_value(match_id id,ldns_pkt * pkt,ldns_rdf * src_addr,ldns_rdf * dst_addr)1171 get_string_value(match_id id, ldns_pkt *pkt, ldns_rdf *src_addr, ldns_rdf *dst_addr)
1172 {
1173 char *val;
1174 match_table *mt;
1175 size_t valsize = 100;
1176
1177 val = malloc(valsize);
1178 memset(val, 0, valsize);
1179
1180 switch(id) {
1181 case MATCH_QR:
1182 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_qr(pkt));
1183 break;
1184 case MATCH_ID:
1185 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_id(pkt));
1186 break;
1187 case MATCH_OPCODE:
1188 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_get_opcode(pkt));
1189 break;
1190 case MATCH_RCODE:
1191 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_get_rcode(pkt));
1192 break;
1193 case MATCH_PACKETSIZE:
1194 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_size(pkt));
1195 break;
1196 case MATCH_TC:
1197 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_tc(pkt));
1198 break;
1199 case MATCH_AD:
1200 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_ad(pkt));
1201 break;
1202 case MATCH_CD:
1203 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_cd(pkt));
1204 break;
1205 case MATCH_RD:
1206 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_rd(pkt));
1207 break;
1208 case MATCH_EDNS:
1209 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_edns(pkt));
1210 break;
1211 case MATCH_EDNS_PACKETSIZE:
1212 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_edns_udp_size(pkt));
1213 break;
1214 case MATCH_DO:
1215 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_edns_do(pkt));
1216 break;
1217 case MATCH_QUESTION_SIZE:
1218 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_qdcount(pkt));
1219 break;
1220 case MATCH_ANSWER_SIZE:
1221 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_ancount(pkt));
1222 break;
1223 case MATCH_AUTHORITY_SIZE:
1224 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_nscount(pkt));
1225 break;
1226 case MATCH_ADDITIONAL_SIZE:
1227 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_arcount(pkt));
1228 break;
1229 case MATCH_SRC_ADDRESS:
1230 free(val);
1231 val = ldns_rdf2str(src_addr);
1232 break;
1233 case MATCH_DST_ADDRESS:
1234 free(val);
1235 val = ldns_rdf2str(dst_addr);
1236 break;
1237 case MATCH_TIMESTAMP:
1238 snprintf(val, valsize, "%u", (unsigned int) ldns_pkt_timestamp(pkt).tv_sec);
1239 break;
1240 case MATCH_QUERY:
1241 if (ldns_pkt_qdcount(pkt) > 0) {
1242 free(val);
1243 val = ldns_rr2str(ldns_rr_list_rr(ldns_pkt_question(pkt), 0));
1244 /* replace \n for nicer printing later */
1245 if (strchr(val, '\n')) {
1246 *(strchr(val, '\n')) = '\0';
1247 }
1248 } else {
1249 val[0] = '\0';
1250 }
1251 break;
1252 case MATCH_QNAME:
1253 if (ldns_pkt_qdcount(pkt) > 0) {
1254 free(val);
1255 val = ldns_rdf2str(ldns_rr_owner(ldns_rr_list_rr(ldns_pkt_question(pkt), 0)));
1256 /* replace \n for nicer printing later */
1257 if (strchr(val, '\n')) {
1258 *(strchr(val, '\n')) = '\0';
1259 }
1260 } else {
1261 val[0] = '\0';
1262 }
1263 break;
1264 case MATCH_QTYPE:
1265 if (ldns_pkt_qdcount(pkt) > 0) {
1266 free(val);
1267 val = ldns_rr_type2str(ldns_rr_get_type(ldns_rr_list_rr(ldns_pkt_question(pkt), 0)));
1268 } else {
1269 val[0] = '\0';
1270 }
1271 break;
1272 case MATCH_ANSWER:
1273 if (ldns_pkt_ancount(pkt) > 0) {
1274 free(val);
1275 val = ldns_rr_list2str(ldns_pkt_answer(pkt));
1276 } else {
1277 val[0] = '\0';
1278 }
1279 break;
1280 case MATCH_AUTHORITY:
1281 if (ldns_pkt_nscount(pkt) > 0) {
1282 free(val);
1283 val = ldns_rr_list2str(ldns_pkt_authority(pkt));
1284 } else {
1285 val[0] = '\0';
1286 }
1287 break;
1288 case MATCH_ADDITIONAL:
1289 if (ldns_pkt_arcount(pkt) > 0) {
1290 free(val);
1291 val = ldns_rr_list2str(ldns_pkt_additional(pkt));
1292 } else {
1293 val[0] = '\0';
1294 }
1295 break;
1296 default:
1297 mt = get_match_by_id(id);
1298 if (!mt) {
1299 printf("ERROR UNKNOWN MATCH_TABLE ID %u\n", id);
1300 exit(1);
1301 }
1302 printf("Matcher for %s not implemented yet\n", mt->name);
1303 exit(1);
1304 return NULL;
1305 }
1306
1307 return val;
1308 }
1309
1310 static bool
match_packet_to_operation(ldns_pkt * pkt,ldns_rdf * src_addr,ldns_rdf * dst_addr,match_operation * operation)1311 match_packet_to_operation(ldns_pkt *pkt, ldns_rdf *src_addr, ldns_rdf *dst_addr, match_operation *operation)
1312 {
1313 bool result;
1314 char *val;
1315
1316 if (!pkt || !operation) {
1317 return false;
1318 } else {
1319 val = get_string_value(operation->id, pkt, src_addr, dst_addr);
1320 if (!val) {
1321 return false;
1322 }
1323 result = value_matches(operation->id, operation->operator, val, operation->value);
1324 free(val);
1325 return result;
1326 }
1327 }
1328
1329 static int
match_operation_compare(const void * a,const void * b)1330 match_operation_compare(const void *a, const void *b)
1331 {
1332 match_operation *moa, *mob;
1333 match_table *mt;
1334 long ia, ib;
1335
1336 if (!a) {
1337 return 1;
1338 } else if (!b) {
1339 return -1;
1340 } else {
1341 moa = (match_operation *) a;
1342 mob = (match_operation *) b;
1343
1344 if (moa->id < mob->id) {
1345 return -1;
1346 } else if (moa->id > mob->id) {
1347 return 1;
1348 } else {
1349 if (moa->operator < mob->operator) {
1350 return -1;
1351 } else if (moa->operator > mob->operator) {
1352 return 1;
1353 } else {
1354 mt = get_match_by_id(moa->id);
1355 if (mt) {
1356 switch (mt->type) {
1357 case TYPE_INT:
1358 case TYPE_TIMESTAMP:
1359 case TYPE_BOOL:
1360 case TYPE_OPCODE:
1361 case TYPE_RCODE:
1362 ia = atol(moa->value);
1363 ib = atol(mob->value);
1364 return ia - ib;
1365 break;
1366 case TYPE_STRING:
1367 case TYPE_ADDRESS:
1368 case TYPE_RR:
1369 default:
1370 return strcmp(moa->value, mob->value);
1371 break;
1372 }
1373 } else {
1374 return strcmp(moa->value, mob->value);
1375 }
1376 }
1377 }
1378 }
1379 }
1380
1381 static int
match_expression_compare(const void * a,const void * b)1382 match_expression_compare(const void *a, const void *b)
1383 {
1384 match_expression *mea, *meb;
1385
1386 if (!a) {
1387 return 1;
1388 } else if (!b) {
1389 return -1;
1390 } else {
1391 mea = (match_expression *) a;
1392 meb = (match_expression *) b;
1393
1394 if (mea->op < meb->op) {
1395 return -1;
1396 } else if (mea->op > meb->op) {
1397 return 1;
1398 } else {
1399 switch(mea->op) {
1400 case MATCH_EXPR_AND:
1401 case MATCH_EXPR_OR:
1402 if (match_expression_compare(mea->left, meb->left) < 0) {
1403 return -1;
1404 } else if (match_expression_compare(mea->left, meb->left) > 0) {
1405 return 1;
1406 } else {
1407 return match_expression_compare(mea->right, meb->right);
1408 }
1409 break;
1410 case MATCH_EXPR_LEAF:
1411 return match_operation_compare(mea->match, meb->match);
1412 break;
1413 default:
1414 fprintf(stderr, "Unknown Match Expression logic operator: %u\n", mea->op);
1415 exit(1);
1416 }
1417 }
1418 }
1419 }
1420
1421 /**
1422 * If count is true, and the counter is found, its count is increased by 1
1423 */
1424 static int
add_match_counter(match_counters * counters,match_expression * expr,bool count)1425 add_match_counter(match_counters *counters,
1426 match_expression *expr,
1427 bool count)
1428 {
1429 int cmp;
1430 match_counters *new;
1431
1432 if (!counters || !expr) {
1433 return -1;
1434 } else {
1435 if (counters->match) {
1436 cmp = match_expression_compare(counters->match,
1437 expr);
1438 if (cmp > 0) {
1439 if (counters->left) {
1440 return add_match_counter(counters->left,
1441 expr,
1442 count);
1443 } else {
1444 new = malloc(sizeof(match_counters));
1445 new->left = NULL;
1446 new->right = NULL;
1447 new->match = expr;
1448 counters->left = new;
1449 return 0;
1450 }
1451 } else if (cmp < 0) {
1452 if (counters->right) {
1453 return add_match_counter(counters->right,
1454 expr,
1455 count);
1456 } else {
1457 new = malloc(sizeof(match_counters));
1458 new->left = NULL;
1459 new->right = NULL;
1460 new->match = expr;
1461 counters->right = new;
1462 return 0;
1463 }
1464 } else {
1465 /* already there? */
1466 if (count) {
1467 counters->match->count++;
1468 }
1469 return 1;
1470 }
1471 } else {
1472 /* shouldn't happen but anyway */
1473 counters->match = expr;
1474 }
1475 }
1476 return 0;
1477 }
1478
1479 static bool
match_dns_packet_to_expr(ldns_pkt * pkt,ldns_rdf * src_addr,ldns_rdf * dst_addr,match_expression * expr)1480 match_dns_packet_to_expr(ldns_pkt *pkt, ldns_rdf *src_addr, ldns_rdf *dst_addr, match_expression *expr)
1481 {
1482 bool result;
1483
1484 if (!pkt || !expr) {
1485 return false;
1486 }
1487
1488 switch(expr->op) {
1489 case MATCH_EXPR_OR:
1490 result = (match_dns_packet_to_expr(pkt, src_addr, dst_addr, expr->left) ||
1491 match_dns_packet_to_expr(pkt, src_addr, dst_addr, expr->right));
1492 break;
1493 case MATCH_EXPR_AND:
1494 result = (match_dns_packet_to_expr(pkt, src_addr, dst_addr, expr->left) &&
1495 match_dns_packet_to_expr(pkt, src_addr, dst_addr, expr->right));
1496 break;
1497 case MATCH_EXPR_LEAF:
1498 result = match_packet_to_operation(pkt, src_addr, dst_addr, expr->match);
1499 break;
1500 default:
1501 fprintf(stderr, "Error, unknown expression operator %u\n", expr->op);
1502 fprintf(stderr, "full expression:\n");
1503 print_match_expression(stderr, expr);
1504 fprintf(stderr, "\n");
1505 exit(1);
1506 }
1507
1508 if (result) {
1509 if (verbosity >= 5) {
1510 printf("Found Match:\n");
1511 print_match_expression(stdout, expr);
1512 printf("\nCount now %u\n", (unsigned int) expr->count);
1513 }
1514 expr->count++;
1515 }
1516
1517 return result;
1518 }
1519
1520 static void
free_match_operation(match_operation * operation)1521 free_match_operation(match_operation *operation)
1522 {
1523 if (operation) {
1524 if (operation->value) {
1525 free(operation->value);
1526 }
1527 free(operation);
1528 }
1529 }
1530
1531 static void
free_match_expression(match_expression * expr)1532 free_match_expression(match_expression *expr)
1533 {
1534 if (expr) {
1535 switch(expr->op) {
1536 case MATCH_EXPR_OR:
1537 case MATCH_EXPR_AND:
1538 free_match_expression(expr->left);
1539 free_match_expression(expr->right);
1540 break;
1541 case MATCH_EXPR_LEAF:
1542 free_match_operation(expr->match);
1543 break;
1544 }
1545 free(expr);
1546 }
1547 }
1548
1549 static void
free_counters(match_counters * counters)1550 free_counters(match_counters *counters)
1551 {
1552 if (counters) {
1553 if (counters->left) {
1554 free_counters(counters->left);
1555 }
1556 if (counters->match) {
1557 free_match_expression(counters->match);
1558 }
1559 if (counters->right) {
1560 free_counters(counters->right);
1561 }
1562 free(counters);
1563 }
1564 }
1565
1566 static void
match_pkt_counters(ldns_pkt * pkt,ldns_rdf * src_addr,ldns_rdf * dst_addr,match_counters * counts)1567 match_pkt_counters(ldns_pkt *pkt, ldns_rdf *src_addr, ldns_rdf *dst_addr, match_counters *counts)
1568 {
1569 if (counts->left) {
1570 match_pkt_counters(pkt, src_addr, dst_addr, counts->left);
1571 }
1572 if (counts->match) {
1573 if (match_dns_packet_to_expr(pkt, src_addr, dst_addr, counts->match)) {
1574 /*
1575 counts->match->count++;
1576 */
1577 }
1578 }
1579 if (counts->right) {
1580 match_pkt_counters(pkt, src_addr, dst_addr, counts->right);
1581 }
1582 }
1583
1584 static void
match_pkt_uniques(ldns_pkt * pkt,ldns_rdf * src_addr,ldns_rdf * dst_addr,match_counters * uniques,match_id unique_ids[],size_t unique_id_count)1585 match_pkt_uniques(ldns_pkt *pkt, ldns_rdf *src_addr, ldns_rdf *dst_addr, match_counters *uniques, match_id unique_ids[], size_t unique_id_count)
1586 {
1587 match_expression *me;
1588 size_t i;
1589 match_operation *mo;
1590 int add_result;
1591
1592 for (i = 0; i < unique_id_count; i++) {
1593 mo = malloc(sizeof(match_operation));
1594 mo->id = unique_ids[i];
1595 mo->operator = OP_EQUAL;
1596 mo->value = get_string_value(mo->id, pkt, src_addr, dst_addr);
1597
1598 me = malloc(sizeof(match_expression));
1599 me->op = MATCH_EXPR_LEAF;
1600 me->left = NULL;
1601 me->right = NULL;
1602 me->match = mo;
1603 me->count = 1;
1604
1605 add_result = add_match_counter(uniques, me, true);
1606 /* if result=1 it was already found, so delete new one */
1607 if (add_result == 1) {
1608 free_match_expression(me);
1609 }
1610 }
1611
1612 #if 0
1613 size_t i, j;
1614 bool found;
1615 match_expression *me;
1616 match_operation *mo;
1617
1618 /* get the value, match uniques for that, if not match, add new */
1619 /* all unique values should be MATCH_EXPR_LEAF */
1620 found = false;
1621 for (j = 0; j < uniques->size; j++) {
1622 if (uniques->counter[j]->match->id == unique_ids[i]) {
1623 if (match_dns_packet_to_expr(pkt, src_addr, dst_addr, uniques->counter[j])) {
1624 found = true;
1625 }
1626 }
1627 }
1628 if (!found) {
1629 mo = malloc(sizeof(match_operation));
1630 mo->id = unique_ids[i];
1631 mo->operator = OP_EQUAL;
1632 mo->value = get_string_value(mo->id, pkt, src_addr, dst_addr);
1633
1634 me = malloc(sizeof(match_expression));
1635 me->match = mo;
1636 me->op = MATCH_EXPR_LEAF;
1637 me->left = NULL;
1638 me->right = NULL;
1639 me->count = 1;
1640
1641 add_counter(uniques, me);
1642 }
1643 }
1644 #endif
1645 }
1646
1647 static match_expression *
parse_match_expression(char * string)1648 parse_match_expression(char *string)
1649 {
1650 match_expression *expr;
1651 size_t i,j;
1652 size_t leftstart, leftend = 0;
1653 char *left_str, *op = NULL, *val;
1654 match_table *mt;
1655 match_operation *mo = NULL;
1656 const type_operators *tos;
1657 match_expression *result;
1658 ldns_lookup_table *lt = NULL;
1659
1660 /* remove whitespace */
1661 char *str = calloc(1, strlen(string) + 1);
1662
1663 j = 0;
1664 for (i = 0; i < strlen(string); i++) {
1665 if(!isspace((unsigned char)string[i])) {
1666 str[j] = string[i];
1667 j++;
1668 }
1669 }
1670 str[j] = '\0';
1671
1672 expr = malloc(sizeof(match_expression));
1673 expr->left = NULL;
1674 expr->right = NULL;
1675 expr->match = NULL;
1676 expr->count = 0;
1677 leftstart = 0;
1678 for (i = 0; i < strlen(str); i++) {
1679 if (str[i] == '&') {
1680 expr->op = MATCH_EXPR_AND;
1681 if (!expr->left) {
1682 left_str = malloc(leftend - leftstart + 2);
1683 strncpy(left_str, &str[leftstart], leftend-leftstart+1);
1684 left_str[leftend - leftstart + 1] = '\0';
1685 expr->left = parse_match_expression(left_str);
1686 free(left_str);
1687 }
1688 expr->right = parse_match_expression(&str[i+1]);
1689 if (expr->left && expr->right) {
1690 result = expr;
1691 goto done;
1692 } else {
1693 result = NULL;
1694 goto done;
1695 }
1696 } else if (str[i] == '|') {
1697 expr->op = MATCH_EXPR_OR;
1698 if (!expr->left) {
1699 left_str = malloc(leftend - leftstart + 2);
1700 strncpy(left_str, &str[leftstart], leftend-leftstart+1);
1701 left_str[leftend - leftstart + 1] = '\0';
1702 expr->left = parse_match_expression(left_str);
1703 free(left_str);
1704 }
1705 expr->right = parse_match_expression(&str[i+1]);
1706 expr->count = 0;
1707 if (expr->left && expr->right) {
1708 result = expr;
1709 goto done;
1710 } else {
1711 result = NULL;
1712 goto done;
1713 }
1714 } else if (str[i] == '(') {
1715 leftstart = i + 1;
1716 j = 1;
1717 while (j > 0) {
1718 i++;
1719 if (i > strlen(str)) {
1720 printf("parse error: no closing bracket: %s\n", str);
1721 printf(" ");
1722 for (j = 0; j < leftstart - 1; j++) {
1723 printf(" ");
1724 }
1725 printf("^\n");
1726 result = NULL;
1727 goto done;
1728 }
1729 if (str[i] == ')') {
1730 j--;
1731 } else if (str[i] == '(') {
1732 j++;
1733 } else {
1734 }
1735 }
1736 leftend = i-1;
1737 left_str = malloc(leftend - leftstart + 1);
1738 strncpy(left_str, &str[leftstart], leftend - leftstart + 1);
1739 expr->left = parse_match_expression(left_str);
1740 free(left_str);
1741 if (i >= strlen(str)-1) {
1742 result = expr->left;
1743 free_match_expression(expr);
1744 goto done;
1745 }
1746 } else if (str[i] == ')') {
1747 printf("parse error: ) without (\n");
1748 result = NULL;
1749 goto done;
1750 } else {
1751 leftend = i;
1752 }
1753 }
1754
1755 /* no operators or hooks left, expr should be of the form
1756 <name><operator><value> now */
1757 for (i = 0; i < strlen(str); i++) {
1758 if (str[i] == '=' ||
1759 str[i] == '>' ||
1760 str[i] == '<' ||
1761 str[i] == '!' ||
1762 str[i] == '~'
1763 ) {
1764 leftend = i-1;
1765 op = malloc(3);
1766 j = 0;
1767 op[j] = str[i];
1768 i++;
1769 j++;
1770
1771 if (i > strlen(str)) {
1772 printf("parse error no right hand side: %s\n", str);
1773 result = NULL;
1774 goto done;
1775 }
1776 if (str[i] == '=' ||
1777 str[i] == '>' ||
1778 str[i] == '<' ||
1779 str[i] == '!' ||
1780 str[i] == '~'
1781 ) {
1782 op[j] = str[i];
1783 i++;
1784 j++;
1785 if (i > strlen(str)) {
1786 printf("parse error no right hand side: %s\n", str);
1787 result = NULL;
1788 if (op)
1789 free(op);
1790 goto done;
1791 }
1792 }
1793 op[j] = '\0';
1794 left_str = malloc(leftend - leftstart + 2);
1795 strncpy(left_str, &str[leftstart], leftend - leftstart + 1);
1796 left_str[leftend - leftstart + 1] = '\0';
1797 mt = get_match_by_name(left_str);
1798 if (!mt) {
1799 printf("parse error: unknown match name: %s\n", left_str);
1800 if (op)
1801 free(op);
1802 result = NULL;
1803 goto done;
1804 } else {
1805 /* check if operator is allowed */
1806 tos = get_type_operators(mt->type);
1807 for (j = 0; j < tos->operator_count; j++) {
1808 if (get_op_id(op) == tos->operators[j]) {
1809 if (mo)
1810 free(mo);
1811 mo = malloc(sizeof(match_operation));
1812 mo->id = mt->id;
1813 mo->operator = get_op_id(op);
1814 switch (mt->type) {
1815 case TYPE_BOOL:
1816 val = malloc(2);
1817 if (strncmp(&str[i], "true", 5) == 0 ||
1818 strncmp(&str[i], "TRUE", 5) == 0 ||
1819 strncmp(&str[i], "True", 5) == 0 ||
1820 strncmp(&str[i], "1", 2) == 0
1821 ) {
1822 val[0] = '1';
1823 val[1] = '\0';
1824 } else if (strncmp(&str[i], "false", 5) == 0 ||
1825 strncmp(&str[i], "FALSE", 5) == 0 ||
1826 strncmp(&str[i], "False", 5) == 0 ||
1827 strncmp(&str[i], "0", 2) == 0
1828 ) {
1829
1830 val[0] = '0';
1831 } else {
1832 fprintf(stderr, "Bad value for bool: %s\n", &str[i]);
1833 exit(EXIT_FAILURE);
1834 }
1835 val[1] = '\0';
1836 break;
1837 case TYPE_RR:
1838 /* convert first so we have the same strings for the same rrs in match_ later */
1839 /*
1840 qrr = ldns_rr_new_frm_str(&str[i], LDNS_DEFAULT_TTL, NULL);
1841 if (!qrr) {
1842 fprintf(stderr, "Bad value for RR: %s\n", &str[i]);
1843 exit(EXIT_FAILURE);
1844 }
1845 val = ldns_rr2str(qrr);
1846 */
1847 /* remove \n for readability */
1848 /*
1849 if (strchr(val, '\n')) {
1850 *(strchr(val, '\n')) = '\0';
1851 }
1852 ldns_rr_free(qrr);
1853 */
1854 val = strdup(&str[i]);
1855 break;
1856 case TYPE_OPCODE:
1857 lt = ldns_lookup_by_name(ldns_opcodes, &str[i]);
1858 if (lt) {
1859 val = malloc(4);
1860 snprintf(val, 3, "%u", (unsigned int) lt->id);
1861 } else {
1862 val = strdup(&str[i]);
1863 }
1864 break;
1865 case TYPE_RCODE:
1866 lt = ldns_lookup_by_name(ldns_rcodes, &str[i]);
1867 if (lt) {
1868 val = malloc(4);
1869 snprintf(val, 3, "%u", (unsigned int) lt->id);
1870 } else {
1871 val = strdup(&str[i]);
1872 }
1873 break;
1874 default:
1875 val = strdup(&str[i]);
1876 break;
1877 }
1878 mo->value = val;
1879 }
1880 }
1881 if (!mo) {
1882 printf("parse error: operator %s not allowed for match %s\n", op, left_str);
1883 result = NULL;
1884 if (op)
1885 free(op);
1886 goto done;
1887 }
1888 }
1889 free(left_str);
1890 free(op);
1891 expr->match = mo;
1892 expr->op = MATCH_EXPR_LEAF;
1893 result = expr;
1894 goto done;
1895 }
1896 }
1897
1898 result = NULL;
1899
1900 done:
1901 free(str);
1902 if (!result) {
1903 free_match_expression(expr);
1904 }
1905 return result;
1906
1907 }
1908 /* end of matches and counts */
1909 void
usage(FILE * output)1910 usage(FILE *output)
1911 {
1912 fprintf(output, "Usage: ldns-dpa [OPTIONS] <pcap file>\n");
1913 fprintf(output, "Options:\n");
1914 fprintf(output, "\t-c <exprlist>:\tCount occurrences of matching expressions\n");
1915 fprintf(output, "\t-f <expression>:\tFilter occurrences of matching expressions\n");
1916 fprintf(output, "\t-h:\t\tshow this help\n");
1917 fprintf(output, "\t-p:\t\tshow percentage of -u and -c values (of the total of\n\t\t\tmatching on the -f filter. if no filter is given,\n\t\t\tpercentages are on all correct dns packets)\n");
1918 fprintf(output, "\t-of <file>:\tWrite pcap packets that match the -f flag to file\n");
1919 fprintf(output, "\t-ofh <file>:\tWrite pcap packets that match the -f flag to file\n\t\tin a hexadecimal format readable by drill\n");
1920 fprintf(output, "\t-s:\t\tshow possible match names\n");
1921 fprintf(output, "\t-s <matchname>:\tshow possible match operators and values for <name>\n");
1922 fprintf(output, "\t-sf:\t\tPrint packet that match -f. If no -f is given, print\n\t\t\tall dns packets\n");
1923 fprintf(output, "\t-u <matchnamelist>:\tCount all occurrences of matchname\n");
1924 fprintf(output, "\t-ua:\t\tShow average value of every -u matchname\n");
1925 fprintf(output, "\t-uac:\t\tShow average count of every -u matchname\n");
1926 fprintf(output, "\t-um <number>:\tOnly show -u results that occurred more than number times\n");
1927 fprintf(output, "\t-v <level>:\tbe more verbose\n");
1928 fprintf(output, "\t-notip <file>:\tDump pcap packets that were not recognized as\n\t\t\tIP packets to file\n");
1929 fprintf(output, "\t-baddns <file>:\tDump mangled dns packets to file\n");
1930 fprintf(output, "\t-version:\tShow the version and exit\n");
1931 fprintf(output, "\n");
1932 fprintf(output, "The filename '-' stands for stdin or stdout, so you can use \"-of -\" if you want to pipe the output to another process\n");
1933 fprintf(output, "\n");
1934 fprintf(output, "A <list> is a comma separated list of items\n");
1935 fprintf(output, "\n");
1936 fprintf(output, "An expression has the following form:\n");
1937 fprintf(output, "<expr>:\t(<expr>)\n");
1938 fprintf(output, "\t<expr> | <expr>\n");
1939 fprintf(output, "\t<expr> & <expr>\n");
1940 fprintf(output, "\t<match>\n");
1941 fprintf(output, "\n");
1942 fprintf(output, "<match>:\t<matchname> <operator> <value>\n");
1943 fprintf(output, "\n");
1944 fprintf(output, "See the -s option for possible matchnames, operators and values.\n");
1945 }
1946
1947 void
show_match_names(char * name)1948 show_match_names(char *name)
1949 {
1950 size_t j;
1951 match_table *mt;
1952 ldns_lookup_table *lt;
1953 const type_operators *tos;
1954 char *str;
1955 size_t i;
1956
1957 if (name) {
1958 mt = get_match_by_name(name);
1959 if (mt) {
1960 printf("%s:\n", mt->name);
1961 printf("\t%s.\n", mt->description);
1962 printf("\toperators: ");
1963 printf("\t");
1964 tos = get_type_operators(mt->type);
1965 if (tos) {
1966 for (j = 0; j < tos->operator_count; j++) {
1967 printf("%s ", get_op_str(tos->operators[j]));
1968 /*
1969 lt = ldns_lookup_by_id((ldns_lookup_table *) lt_operators, tos->operators[j]);
1970 if (lt) {
1971 printf("%s ", lt->name);
1972 } else {
1973 printf("? ");
1974 }
1975 */
1976 }
1977 } else {
1978 printf("unknown type");
1979 }
1980
1981 printf("\n");
1982 printf("\tValues:\n");
1983 switch (mt->type) {
1984 case TYPE_INT:
1985 printf("\t\t<Integer>\n");
1986 break;
1987 case TYPE_BOOL:
1988 printf("\t\t0\n");
1989 printf("\t\t1\n");
1990 printf("\t\ttrue\n");
1991 printf("\t\tfalse\n");
1992 break;
1993 case TYPE_OPCODE:
1994 printf("\t\t<Integer>\n");
1995 lt = ldns_opcodes;
1996 while (lt->name != NULL) {
1997 printf("\t\t%s\n", lt->name);
1998 lt++;
1999 }
2000 break;
2001 case TYPE_RCODE:
2002 printf("\t\t<Integer>\n");
2003 lt = ldns_rcodes;
2004 while (lt->name != NULL) {
2005 printf("\t\t%s\n", lt->name);
2006 lt++;
2007 }
2008 break;
2009 case TYPE_STRING:
2010 printf("\t\t<String>\n");
2011 break;
2012 case TYPE_TIMESTAMP:
2013 printf("\t\t<Integer> (seconds since epoch)\n");
2014 break;
2015 case TYPE_ADDRESS:
2016 printf("\t\t<IP address>\n");
2017 break;
2018 case TYPE_RR:
2019 printf("\t\t<Resource Record>\n");
2020 break;
2021 default:
2022 break;
2023 }
2024 } else {
2025 printf("Unknown match name: %s\n", name);
2026 }
2027 } else {
2028 mt = (match_table *) matches;
2029 while (mt->name != NULL) {
2030 str = (char *) mt->name;
2031 printf("%s:", str);
2032 i = strlen(str) + 1;
2033 while (i < 24) {
2034 printf(" ");
2035 i++;
2036 }
2037 printf("%s\n", mt->description);
2038 mt++;
2039 }
2040 }
2041 }
2042
2043 int
handle_ether_packet(const u_char * data,struct pcap_pkthdr cur_hdr,match_counters * count,match_expression * match_expr,match_counters * uniques,match_id unique_ids[],size_t unique_id_count)2044 handle_ether_packet(const u_char *data, struct pcap_pkthdr cur_hdr, match_counters *count, match_expression *match_expr, match_counters *uniques, match_id unique_ids[], size_t unique_id_count)
2045 {
2046 struct ether_header *eptr;
2047 struct ip *iptr;
2048 struct ip6_hdr *ip6_hdr;
2049 int ip_hdr_size;
2050 uint8_t protocol;
2051 size_t data_offset = 0;
2052 ldns_rdf *src_addr = NULL, *dst_addr = NULL;
2053 uint8_t *ap;
2054 char *astr;
2055 bpf_u_int32 len = cur_hdr.caplen;
2056 struct timeval timestamp;
2057 uint16_t ip_flags;
2058 uint16_t ip_len;
2059 uint16_t ip_id;
2060 uint16_t ip_f_offset;
2061 const u_char *newdata = NULL;
2062 /*
2063 printf("timeval: %u ; %u\n", cur_hdr.ts.tv_sec, cur_hdr.ts.tv_usec);
2064 */
2065
2066 uint8_t *dnspkt;
2067
2068 ldns_pkt *pkt;
2069 ldns_status status;
2070
2071 /* lets start with the ether header... */
2072 eptr = (struct ether_header *) data;
2073 /* Do a couple of checks to see what packet type we have..*/
2074 if (ntohs (eptr->ether_type) == ETHERTYPE_IP)
2075 {
2076 if (verbosity >= 5) {
2077 printf("Ethernet type hex:%x dec:%u is an IP packet\n",
2078 (unsigned int) ntohs(eptr->ether_type),
2079 (unsigned int) ntohs(eptr->ether_type));
2080 }
2081
2082 data_offset = ETHER_HEADER_LENGTH;
2083 iptr = (struct ip *) (data + data_offset);
2084 /*
2085 printf("IP_OFF: %u (%04x) %04x %04x (%d) (%d)\n", iptr->ip_off, iptr->ip_off, IP_MF, IP_DF, iptr->ip_off & 0x4000, iptr->ip_off & 0x2000);
2086 */
2087 ip_flags = ldns_read_uint16(&(iptr->ip_off));
2088 ip_id = ldns_read_uint16(&(iptr->ip_id));
2089 ip_len = ldns_read_uint16(&(iptr->ip_len));
2090 ip_f_offset = (ip_flags & IP_OFFMASK)*8;
2091 if (ip_flags & IP_MF && ip_f_offset == 0) {
2092 /*printf("First Frag id %u len\n", ip_id, ip_len);*/
2093 fragment_p->ip_id = ip_id;
2094 memset(fragment_p->data, 0, 65535);
2095 memcpy(fragment_p->data, iptr, ip_len);
2096 fragment_p->cur_len = ip_len + 20;
2097 /*
2098 for (ip_len = 0; ip_len < fragment_p->cur_len; ip_len++) {
2099 if (ip_len > 0 && ip_len % 20 == 0) {
2100 printf("\t; %u - %u\n", ip_len - 19, ip_len);
2101 }
2102 printf("%02x ", fragment_p->data[ip_len]);
2103 }
2104 printf("\t; ??? - %u\n", ip_len);
2105 */
2106 return 0;
2107 } else
2108 if (ip_flags & IP_MF && ip_f_offset != 0) {
2109 /*printf("Next frag\n");*/
2110 if (ip_id == fragment_p->ip_id) {
2111 /*printf("add fragment to current id %u len %u offset %u\n", ip_id, ip_len, ip_f_offset);*/
2112 memcpy(fragment_p->data + (ip_f_offset) + 20, data+data_offset+20, ip_len - (iptr->ip_hl)*4);
2113 /*printf("COPIED %u\n", ip_len);*/
2114 fragment_p->cur_len = fragment_p->cur_len + ip_len - 20;
2115 /*printf("cur len now %u\n", fragment_p->cur_len);*/
2116 /*
2117 for (ip_len = 0; ip_len < fragment_p->cur_len; ip_len++) {
2118 if (ip_len > 0 && ip_len % 20 == 0) {
2119 printf("\t; %u - %u\n", ip_len - 19, ip_len);
2120 }
2121 printf("%02x ", fragment_p->data[ip_len]);
2122 }
2123 printf("\t; ??? - %u\n", ip_len);
2124 */
2125 return 0;
2126 } else {
2127 /*printf("Lost fragment %u\n", iptr->ip_id);*/
2128 lost_packet_fragments++;
2129 return 1;
2130 }
2131 } else
2132 if (!(ip_flags & IP_MF) && ip_f_offset != 0) {
2133 /*printf("Last frag\n");*/
2134 if (ip_id == fragment_p->ip_id) {
2135 /*printf("add fragment to current id %u len %u offset %u\n", ip_id, ip_len, ip_f_offset);*/
2136 memcpy(fragment_p->data + ip_f_offset + 20, data+data_offset+20, ip_len - 20);
2137 fragment_p->cur_len = fragment_p->cur_len + ip_len - 20;
2138 iptr = (struct ip *) fragment_p->data;
2139 newdata = malloc(fragment_p->cur_len + data_offset);
2140 if (!newdata) {
2141 printf("Malloc failed, out of mem?\n");
2142 exit(4);
2143 }
2144 memcpy((char *) newdata, data, data_offset);
2145 memcpy((char *) newdata+data_offset, fragment_p->data, fragment_p->cur_len);
2146 iptr->ip_len = (u_short) ldns_read_uint16(&(fragment_p->cur_len));
2147 iptr->ip_off = 0;
2148 len = (bpf_u_int32) fragment_p->cur_len;
2149 cur_hdr.caplen = len;
2150 fragment_p->ip_id = 0;
2151 fragmented_packets++;
2152 /*
2153 for (ip_len = 0; ip_len < fragment_p->cur_len; ip_len++) {
2154 if (ip_len > 0 && ip_len % 20 == 0) {
2155 printf("\t; %u - %u\n", ip_len - 19, ip_len);
2156 }
2157 printf("%02x ", fragment_p->data[ip_len]);
2158 }
2159 printf("\t; ??? - %u\n", ip_len);
2160 */
2161 } else {
2162 /*printf("Lost fragment %u\n", iptr->ip_id);*/
2163 lost_packet_fragments++;
2164 return 1;
2165 }
2166 } else {
2167 newdata = data;
2168 }
2169 /*
2170 if (iptr->ip_off & 0x0040) {
2171 printf("Don't fragment\n");
2172 }
2173 */
2174
2175 /* in_addr portability woes, going manual for now */
2176 /* ipv4 */
2177 ap = (uint8_t *) &(iptr->ip_src);
2178 astr = malloc(INET_ADDRSTRLEN);
2179 if (inet_ntop(AF_INET, ap, astr, INET_ADDRSTRLEN)) {
2180 if (ldns_str2rdf_a(&src_addr, astr) == LDNS_STATUS_OK) {
2181
2182 }
2183 }
2184 free(astr);
2185 ap = (uint8_t *) &(iptr->ip_dst);
2186 astr = malloc(INET_ADDRSTRLEN);
2187 if (inet_ntop(AF_INET, ap, astr, INET_ADDRSTRLEN)) {
2188 if (ldns_str2rdf_a(&dst_addr, astr) == LDNS_STATUS_OK) {
2189
2190 }
2191 }
2192 free(astr);
2193
2194 ip_hdr_size = (int) iptr->ip_hl * 4;
2195 protocol = (uint8_t) iptr->ip_p;
2196
2197 data_offset += ip_hdr_size;
2198
2199 if (protocol == IPPROTO_UDP) {
2200 udp_packets++;
2201 data_offset += UDP_HEADER_LENGTH;
2202
2203 dnspkt = (uint8_t *) (newdata + data_offset);
2204
2205 /*printf("packet starts at byte %u\n", data_offset);*/
2206
2207 /*printf("Len: %u\n", len);*/
2208
2209 status = ldns_wire2pkt(&pkt, dnspkt, len - data_offset);
2210
2211 if (status != LDNS_STATUS_OK) {
2212 if (verbosity >= 3) {
2213 printf("No dns packet: %s\n", ldns_get_errorstr_by_id(status));
2214 }
2215 if (verbosity >= 5) {
2216 for (ip_len = 0; ip_len < len - data_offset; ip_len++) {
2217 if (ip_len > 0 && ip_len % 20 == 0) {
2218 printf("\t; %u - %u\n", (unsigned int) ip_len - 19, (unsigned int) ip_len);
2219 }
2220 printf("%02x ", (unsigned int) dnspkt[ip_len]);
2221 }
2222 printf("\t; ??? - %u\n", (unsigned int) ip_len);
2223
2224 }
2225 bad_dns_packets++;
2226 if (bad_dns_dump) {
2227 pcap_dump((u_char *)bad_dns_dump, &cur_hdr, newdata);
2228 }
2229 } else {
2230 timestamp.tv_sec = cur_hdr.ts.tv_sec;
2231 timestamp.tv_usec = cur_hdr.ts.tv_usec;
2232 ldns_pkt_set_timestamp(pkt, timestamp);
2233
2234 if (verbosity >= 4) {
2235 printf("DNS packet\n");
2236 ldns_pkt_print(stdout, pkt);
2237 printf("\n\n");
2238 }
2239
2240 total_nr_of_dns_packets++;
2241
2242 if (match_expr) {
2243 if (match_dns_packet_to_expr(pkt, src_addr, dst_addr, match_expr)) {
2244 /* if outputfile write */
2245 if (dumper) {
2246 pcap_dump((u_char *)dumper, &cur_hdr, data);
2247 }
2248 if (hexdumpfile) {
2249 fprintf(hexdumpfile, ";; %u\n", (unsigned int) total_nr_of_dns_packets);
2250 ldns_pkt2file_hex(hexdumpfile, pkt);
2251 }
2252 if (show_filter_matches) {
2253 printf(";; From: ");
2254 ldns_rdf_print(stdout, src_addr);
2255 printf("\n");
2256 printf(";; To: ");
2257 ldns_rdf_print(stdout, dst_addr);
2258 printf("\n");
2259 ldns_pkt_print(stdout, pkt);
2260 printf("------------------------------------------------------------\n\n");
2261 }
2262 } else {
2263 ldns_pkt_free(pkt);
2264 ldns_rdf_deep_free(src_addr);
2265 ldns_rdf_deep_free(dst_addr);
2266 if (newdata && newdata != data)
2267 free((void *)newdata);
2268 return 0;
2269 }
2270 } else {
2271 if (dumper) {
2272 pcap_dump((u_char *)dumper, &cur_hdr, data);
2273 }
2274 if (hexdumpfile) {
2275 fprintf(hexdumpfile, ";; %u\n", (unsigned int) total_nr_of_dns_packets);
2276 ldns_pkt2file_hex(hexdumpfile, pkt);
2277 }
2278 if (show_filter_matches) {
2279 printf(";; From: ");
2280 ldns_rdf_print(stdout, src_addr);
2281 printf("\n");
2282 printf(";; To: ");
2283 ldns_rdf_print(stdout, dst_addr);
2284 printf("\n");
2285 ldns_pkt_print(stdout, pkt);
2286 printf("------------------------------------------------------------\n\n");
2287 }
2288 }
2289
2290 /* General counters here */
2291 total_nr_of_filtered_packets++;
2292
2293 match_pkt_counters(pkt, src_addr, dst_addr, count);
2294 match_pkt_uniques(pkt, src_addr, dst_addr, uniques, unique_ids, unique_id_count);
2295
2296 ldns_pkt_free(pkt);
2297 pkt = NULL;
2298 }
2299 ldns_rdf_deep_free(src_addr);
2300 ldns_rdf_deep_free(dst_addr);
2301
2302 } else if (protocol == IPPROTO_TCP) {
2303 /* tcp packets are skipped */
2304 tcp_packets++;
2305 }
2306 if (newdata && newdata != data) {
2307 free((void *)newdata);
2308 newdata = NULL;
2309 }
2310 /* don't have a define for ethertype ipv6 */
2311 } else if (ntohs (eptr->ether_type) == ETHERTYPE_IPV6) {
2312 /*printf("IPv6!\n");*/
2313
2314
2315 /* copied from ipv4, move this to function? */
2316
2317 data_offset = ETHER_HEADER_LENGTH;
2318 ip6_hdr = (struct ip6_hdr *) (data + data_offset);
2319
2320 newdata = data;
2321
2322 /* in_addr portability woes, going manual for now */
2323 /* ipv6 */
2324 ap = (uint8_t *) &(ip6_hdr->ip6_src);
2325 astr = malloc(INET6_ADDRSTRLEN);
2326 if (inet_ntop(AF_INET6, ap, astr, INET6_ADDRSTRLEN)) {
2327 if (ldns_str2rdf_aaaa(&src_addr, astr) == LDNS_STATUS_OK) {
2328
2329 }
2330 }
2331 free(astr);
2332 ap = (uint8_t *) &(ip6_hdr->ip6_dst);
2333 astr = malloc(INET6_ADDRSTRLEN);
2334 if (inet_ntop(AF_INET6, ap, astr, INET6_ADDRSTRLEN)) {
2335 if (ldns_str2rdf_aaaa(&dst_addr, astr) == LDNS_STATUS_OK) {
2336
2337 }
2338 }
2339 free(astr);
2340
2341 ip_hdr_size = IP6_HEADER_LENGTH;
2342 protocol = (uint8_t) ip6_hdr->ip6_ctlun.ip6_un1.ip6_un1_nxt;
2343
2344 data_offset += ip_hdr_size;
2345
2346 if (protocol == IPPROTO_UDP) {
2347 udp_packets++;
2348 /*printf("V6 UDP!\n");*/
2349 data_offset += UDP_HEADER_LENGTH;
2350
2351 dnspkt = (uint8_t *) (newdata + data_offset);
2352
2353 /*printf("Len: %u\n", len);*/
2354
2355 status = ldns_wire2pkt(&pkt, dnspkt, len - data_offset);
2356
2357 if (status != LDNS_STATUS_OK) {
2358 if (verbosity >= 3) {
2359 printf("No dns packet: %s\n", ldns_get_errorstr_by_id(status));
2360 }
2361 bad_dns_packets++;
2362 if (bad_dns_dump) {
2363 pcap_dump((u_char *)bad_dns_dump, &cur_hdr, newdata);
2364 }
2365 } else {
2366 timestamp.tv_sec = cur_hdr.ts.tv_sec;
2367 timestamp.tv_usec = cur_hdr.ts.tv_usec;
2368 ldns_pkt_set_timestamp(pkt, timestamp);
2369
2370 if (verbosity >= 4) {
2371 printf("DNS packet\n");
2372 ldns_pkt_print(stdout, pkt);
2373 printf("\n\n");
2374 }
2375
2376 total_nr_of_dns_packets++;
2377
2378 if (match_expr) {
2379 if (match_dns_packet_to_expr(pkt, src_addr, dst_addr, match_expr)) {
2380 /* if outputfile write */
2381 if (dumper) {
2382 pcap_dump((u_char *)dumper, &cur_hdr, data);
2383 }
2384 if (show_filter_matches) {
2385 printf(";; From: ");
2386 ldns_rdf_print(stdout, src_addr);
2387 printf("\n");
2388 printf(";; To: ");
2389 ldns_rdf_print(stdout, dst_addr);
2390 printf("\n");
2391 ldns_pkt_print(stdout, pkt);
2392 printf("------------------------------------------------------------\n\n");
2393 }
2394 } else {
2395 ldns_pkt_free(pkt);
2396 ldns_rdf_deep_free(src_addr);
2397 ldns_rdf_deep_free(dst_addr);
2398 return 0;
2399 }
2400 } else {
2401 if (show_filter_matches) {
2402 printf(";; From: ");
2403 ldns_rdf_print(stdout, src_addr);
2404 printf("\n");
2405 printf(";; To: ");
2406 ldns_rdf_print(stdout, dst_addr);
2407 printf("\n");
2408 ldns_pkt_print(stdout, pkt);
2409 printf("------------------------------------------------------------\n\n");
2410 }
2411 }
2412
2413 /* General counters here */
2414 total_nr_of_filtered_packets++;
2415
2416 match_pkt_counters(pkt, src_addr, dst_addr, count);
2417 match_pkt_uniques(pkt, src_addr, dst_addr, uniques, unique_ids, unique_id_count);
2418
2419 ldns_pkt_free(pkt);
2420 pkt = NULL;
2421 }
2422 ldns_rdf_deep_free(src_addr);
2423 ldns_rdf_deep_free(dst_addr);
2424
2425 } else if (protocol == IPPROTO_TCP) {
2426 /* tcp packets are skipped */
2427 tcp_packets++;
2428 } else {
2429 printf("ipv6 unknown next header type: %u\n", (unsigned int) protocol);
2430 }
2431
2432
2433
2434 } else if (ntohs (eptr->ether_type) == ETHERTYPE_ARP) {
2435 if (verbosity >= 5) {
2436 printf("Ethernet type hex:%x dec:%u is an ARP packet\n",
2437 (unsigned int) ntohs(eptr->ether_type),
2438 (unsigned int) ntohs(eptr->ether_type));
2439 }
2440 arp_packets++;
2441 } else {
2442 printf("Ethernet type %x not IP\n", (unsigned int) ntohs(eptr->ether_type));
2443 if (verbosity >= 5) {
2444 printf("Ethernet type %x not IP\n", (unsigned int) ntohs(eptr->ether_type));
2445 }
2446 not_ip_packets++;
2447 if (not_ip_dump) {
2448 pcap_dump((u_char *)not_ip_dump, &cur_hdr, data);
2449 }
2450 }
2451
2452 return 0;
2453 }
2454
2455 bool
parse_match_list(match_counters * counters,char * string)2456 parse_match_list(match_counters *counters, char *string)
2457 {
2458 size_t i;
2459 match_expression *expr;
2460 /* match_counter *mc;*/
2461 size_t lastpos = 0;
2462 char *substring;
2463
2464 /*printf("Parsing match list: '%s'\n", string);*/
2465
2466 for (i = 0; i < strlen(string); i++) {
2467 if (string[i] == ',') {
2468 if (i<2) {
2469 fprintf(stderr, "Matchlist cannot start with ,\n");
2470 return false;
2471 } else {
2472 substring = malloc(strlen(string)+1);
2473 strncpy(substring, &string[lastpos], i - lastpos + 1);
2474 substring[i - lastpos] = '\0';
2475 expr = parse_match_expression(substring);
2476 free(substring);
2477 if (!expr) {
2478 return false;
2479 }
2480 /*
2481 if (expr->op != MATCH_EXPR_LEAF) {
2482 fprintf(stderr, "Matchlist can only contain <match>, not a logic expression\n");
2483 return false;
2484 }
2485 */
2486 add_match_counter(counters, expr, false);
2487 lastpos = i+1;
2488 }
2489 }
2490 }
2491 substring = malloc(strlen(string) + 1);
2492 strncpy(substring, &string[lastpos], i - lastpos + 1);
2493 substring[i - lastpos] = '\0';
2494 expr = parse_match_expression(substring);
2495
2496 if (!expr) {
2497 fprintf(stderr, "Bad match: %s\n", substring);
2498 free(substring);
2499 return false;
2500 }
2501 free(substring);
2502 /*
2503 if (expr->op != MATCH_EXPR_LEAF) {
2504 fprintf(stderr, "Matchlist can only contain <match>, not a logic expression\n");
2505 return false;
2506 }
2507 */
2508 add_match_counter(counters, expr, false);
2509 return true;
2510 }
2511
2512 bool
parse_uniques(match_id ids[],size_t * count,char * string)2513 parse_uniques(match_id ids[], size_t *count, char *string)
2514 {
2515 size_t i, j, lastpos;
2516 char *str, *strpart;
2517 match_table *mt;
2518
2519 /*printf("Parsing unique counts: '%s'\n", string);*/
2520 str = calloc(1, strlen(string) + 1);
2521 j = 0;
2522 for (i = 0; i < strlen(string); i++) {
2523 if (!isspace((unsigned char)string[i])) {
2524 str[j] = string[i];
2525 j++;
2526 }
2527 }
2528 str[j] = '\0';
2529
2530 lastpos = 0;
2531 for (i = 0; i <= strlen(str); i++) {
2532 if (str[i] == ',' || i >= strlen(str)) {
2533 if (!(strpart = malloc(i - lastpos + 1))) {
2534 free(str);
2535 return false;
2536 }
2537 strncpy(strpart, &str[lastpos], i - lastpos);
2538 strpart[i - lastpos] = '\0';
2539 if ((mt = get_match_by_name(strpart))) {
2540 ids[*count] = mt->id;
2541 *count = *count + 1;
2542 } else {
2543 printf("Error parsing match list; unknown match name: %s\n", strpart);
2544 free(strpart);
2545 free(str);
2546 return false;
2547 }
2548 free(strpart);
2549 lastpos = i + 1;
2550 }
2551 }
2552 if (i > lastpos) {
2553 strpart = malloc(i - lastpos + 1);
2554 strncpy(strpart, &str[lastpos], i - lastpos);
2555 strpart[i - lastpos] = '\0';
2556 if ((mt = get_match_by_name(strpart))) {
2557 ids[*count] = mt->id;
2558 *count = *count + 1;
2559 } else {
2560 printf("Error parsing match list; unknown match name: %s\n", strpart);
2561 return false;
2562 }
2563 free(strpart);
2564 }
2565 free(str);
2566 return true;
2567 }
2568
main(int argc,char * argv[])2569 int main(int argc, char *argv[]) {
2570
2571 int i;
2572 int status = EXIT_SUCCESS;
2573 match_counters *count = malloc(sizeof(match_counters));
2574 const char *inputfile = NULL;
2575 char errbuf[PCAP_ERRBUF_SIZE];
2576 pcap_t *pc = NULL;
2577 const u_char *cur;
2578 struct pcap_pkthdr cur_hdr;
2579 match_expression *expr = NULL;
2580 match_id unique_ids[MAX_MATCHES];
2581 size_t unique_id_count = 0; /* number of unique counters */
2582 match_counters *uniques = malloc(sizeof(match_counters));
2583 char *dumpfile = NULL;
2584 char *hexdumpfilename = NULL;
2585 char *not_ip_dumpfile = NULL;
2586 char *bad_dns_dumpfile = NULL;
2587
2588 bool show_percentages = false;
2589 bool show_averages = false;
2590 bool show_average_count = false;
2591 int unique_minimum = 0;
2592
2593 count->left = NULL;
2594 count->match = NULL;
2595 count->right = NULL;
2596 uniques->left = NULL;
2597 uniques->match = NULL;
2598 uniques->right = NULL;
2599
2600 fragment_p = malloc(sizeof(struct fragment_part));
2601 fragment_p->ip_id = 0;
2602 fragment_p->cur_len = 0;
2603
2604 for (i = 1; i < argc; i++) {
2605
2606 if (strncmp(argv[i], "-baddns", 8) == 0) {
2607 if (i + 1 < argc) {
2608 bad_dns_dumpfile = argv[i + 1];
2609 i++;
2610 } else {
2611 usage(stderr);
2612 status = EXIT_FAILURE;
2613 goto exit;
2614 }
2615 } else if (strncmp(argv[i], "-notip", 7) == 0) {
2616 if (i + 1 < argc) {
2617 not_ip_dumpfile = argv[i + 1];
2618 i++;
2619 } else {
2620 usage(stderr);
2621 status = EXIT_FAILURE;
2622 goto exit;
2623 }
2624 } else if (strncmp(argv[i], "-c", 3) == 0) {
2625 if (i + 1 < argc) {
2626 if (!parse_match_list(count, argv[i + 1])) {
2627 status = EXIT_FAILURE;
2628 goto exit;
2629 }
2630 i++;
2631 } else {
2632 usage(stderr);
2633 status = EXIT_FAILURE;
2634 goto exit;
2635 }
2636 } else if (strncmp(argv[i], "-f", 3) == 0) {
2637 if (i + 1 < argc) {
2638 if (expr || strchr(argv[i+1], ',')) {
2639 fprintf(stderr, "You can only specify 1 filter expression.\n");
2640 status = EXIT_FAILURE;
2641 goto exit;
2642 }
2643 expr = parse_match_expression(argv[i + 1]);
2644 i++;
2645 } else {
2646 usage(stderr);
2647 status = EXIT_FAILURE;
2648 goto exit;
2649 }
2650 } else if (strncmp(argv[i], "-h", 3) == 0) {
2651 usage(stdout);
2652 status = EXIT_SUCCESS;
2653 goto exit;
2654 } else if (strncmp(argv[i], "-p", 3) == 0) {
2655 show_percentages = true;
2656 } else if (strncmp(argv[i], "-of", 4) == 0) {
2657 if (i + 1 < argc) {
2658 dumpfile = argv[i + 1];
2659 i++;
2660 } else {
2661 usage(stderr);
2662 status = EXIT_FAILURE;
2663 goto exit;
2664 }
2665 } else if (strncmp(argv[i], "-ofh", 5) == 0) {
2666 if (i + 1 < argc) {
2667 hexdumpfilename = argv[i + 1];
2668 i++;
2669 } else {
2670 usage(stderr);
2671 status = EXIT_FAILURE;
2672 goto exit;
2673 }
2674 } else if (strncmp(argv[i], "-s", 3) == 0) {
2675 if (i + 1 < argc) {
2676 show_match_names(argv[i + 1]);
2677 } else {
2678 show_match_names(NULL);
2679 }
2680 status = EXIT_SUCCESS;
2681 goto exit;
2682 } else if (strncmp(argv[i], "-sf", 4) == 0) {
2683 show_filter_matches = true;
2684 } else if (strncmp(argv[i], "-u", 3) == 0) {
2685 if (i + 1 < argc) {
2686 if (!parse_uniques(unique_ids, &unique_id_count, argv[i + 1])) {
2687 status = EXIT_FAILURE;
2688 goto exit;
2689 }
2690 i++;
2691 } else {
2692 usage(stderr);
2693 status = EXIT_FAILURE;
2694 goto exit;
2695 }
2696 } else if (strcmp("-ua", argv[i]) == 0) {
2697 show_averages = true;
2698 } else if (strcmp("-uac", argv[i]) == 0) {
2699 show_average_count = true;
2700 } else if (strcmp("-um", argv[i]) == 0) {
2701 if (i + 1 < argc) {
2702 unique_minimum = atoi(argv[i+1]);
2703 i++;
2704 } else {
2705 fprintf(stderr, "-um requires an argument");
2706 usage(stderr);
2707 status = EXIT_FAILURE;
2708 goto exit;
2709 }
2710 } else if (strcmp("-v", argv[i]) == 0) {
2711 i++;
2712 if (i < argc) {
2713 verbosity = atoi(argv[i]);
2714 }
2715 } else if (strcmp("-version", argv[i]) == 0) {
2716 printf("dns packet analyzer, version %s (ldns version %s)\n", LDNS_VERSION, ldns_version());
2717 goto exit;
2718 } else {
2719 if (inputfile) {
2720 fprintf(stderr, "You can only specify 1 input file\n");
2721 exit(1);
2722 }
2723 inputfile = argv[i];
2724 }
2725 }
2726
2727 if (!inputfile) {
2728 inputfile = "-";
2729 }
2730
2731 if (verbosity >= 5) {
2732 printf("Filter:\n");
2733 print_match_expression(stdout, expr);
2734 printf("\n\n");
2735 }
2736
2737 pc = pcap_open_offline(inputfile, errbuf);
2738
2739 if (!pc) {
2740 if (errno != 0) {
2741 printf("Error opening pcap file %s: %s\n", inputfile, errbuf);
2742 exit(1);
2743 } else {
2744 goto showresult;
2745 }
2746 }
2747
2748 if (dumpfile) {
2749 dumper = pcap_dump_open(pc, dumpfile);
2750
2751 if (!dumper) {
2752 printf("Error opening pcap dump file %s: %s\n", dumpfile, errbuf);
2753 exit(1);
2754 }
2755 }
2756
2757 if (hexdumpfilename) {
2758 if (strncmp(hexdumpfilename, "-", 2) != 0) {
2759 printf("hexdump is file\n");
2760 hexdumpfile = fopen(hexdumpfilename, "w");
2761 } else {
2762 printf("hexdump is stdout\n");
2763 hexdumpfile = stdout;
2764 }
2765
2766 if (!hexdumpfile) {
2767 printf("Error opening hex dump file %s: %s\n", hexdumpfilename, strerror(errno));
2768 exit(1);
2769 }
2770 }
2771
2772 if (not_ip_dumpfile) {
2773 not_ip_dump = pcap_dump_open(pc, not_ip_dumpfile);
2774 if (!not_ip_dump) {
2775 printf("Error opening pcap dump file NOT_IP: %s\n", errbuf);
2776 }
2777 }
2778 if (bad_dns_dumpfile) {
2779 bad_dns_dump = pcap_dump_open(pc, bad_dns_dumpfile);
2780 if (!bad_dns_dump) {
2781 printf("Error opening pcap dump file NOT_IP: %s\n", errbuf);
2782 }
2783 }
2784
2785 while ((cur = pcap_next(pc, &cur_hdr))) {
2786 if (verbosity >= 5) {
2787 printf("\n\n\n[PKT_HDR] caplen: %u \tlen: %u\n", (unsigned int)cur_hdr.caplen, (unsigned int)cur_hdr.len);
2788 }
2789 handle_ether_packet(cur, cur_hdr, count, expr, uniques, unique_ids, unique_id_count);
2790 }
2791
2792 if (not_ip_dump) {
2793 pcap_dump_close(not_ip_dump);
2794 }
2795
2796 if (bad_dns_dump) {
2797 pcap_dump_close(bad_dns_dump);
2798 }
2799
2800 if (dumper) {
2801 pcap_dump_close(dumper);
2802 }
2803
2804 if (hexdumpfile && hexdumpfile != stdout) {
2805 fclose(hexdumpfile);
2806 }
2807
2808 pcap_close(pc);
2809
2810 showresult:
2811 if (show_percentages) {
2812 fprintf(stdout, "Packets that are not IP: %u\n", (unsigned int) not_ip_packets);
2813 fprintf(stdout, "bad dns packets: %u\n", (unsigned int) bad_dns_packets);
2814 fprintf(stdout, "arp packets: %u\n", (unsigned int) arp_packets);
2815 fprintf(stdout, "udp packets: %u\n", (unsigned int) udp_packets);
2816 fprintf(stdout, "tcp packets (skipped): %u\n", (unsigned int) tcp_packets);
2817 fprintf(stdout, "reassembled fragmented packets: %u\n", (unsigned int) fragmented_packets);
2818 fprintf(stdout, "packet fragments lost: %u\n", (unsigned int) lost_packet_fragments);
2819 fprintf(stdout, "Total number of DNS packets: %u\n", (unsigned int) total_nr_of_dns_packets);
2820 fprintf(stdout, "Total number of DNS packets after filter: %u\n", (unsigned int) total_nr_of_filtered_packets);
2821 }
2822 if (count->match) {
2823 print_counters(stdout, count, show_percentages, total_nr_of_filtered_packets, 0);
2824 }
2825 if (uniques->match) {
2826 print_counters(stdout, uniques, show_percentages, total_nr_of_filtered_packets, unique_minimum);
2827 if (show_averages) {
2828 print_counter_averages(stdout, uniques, NULL);
2829 }
2830 if (show_average_count) {
2831 print_counter_average_count(stdout, uniques, NULL, true);
2832 }
2833 }
2834
2835 exit:
2836
2837 free_match_expression(expr);
2838 free_counters(count);
2839 free_counters(uniques);
2840
2841 return status;
2842 }
2843
2844 #else
main(void)2845 int main(void) {
2846 fprintf(stderr, "ldns-dpa was not built because there is no pcap library on this system, or there was no pcap header file at compilation time. Please install pcap and rebuild.\n");
2847 return 1;
2848 }
2849 #endif
2850 #else
main(void)2851 int main(void) {
2852 fprintf(stderr, "ldns-dpa was not built because there is no pcap library on this system, or there was no pcap header file at compilation time. Please install pcap and rebuild.\n");
2853 return 1;
2854 }
2855 #endif
2856
2857
2858