nmsg  0.9.0
dnsqr.c
1 /* dnsqr nmsg message module */
2 
3 /*
4  * Copyright (c) 2010-2013 by Farsight Security, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 /* Import. */
20 
21 #include <sys/mman.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <ctype.h>
27 #include <pthread.h>
28 #include <string.h>
29 
30 #include <pcap.h>
31 #include <wdns.h>
32 
33 #include "ipreasm.h"
34 
35 #include "dnsqr.pb-c.h"
36 
37 #include "libmy/list.h"
38 #include "libmy/lookup3.h"
39 #include "libmy/my_alloc.h"
40 #include "libmy/string_replace.h"
41 #include "libmy/ubuf.h"
42 
43 /* Macros. */
44 
45 #define DEFAULT_NUM_SLOTS 262144
46 #define DEFAULT_MAX_VALUES 131072
47 #define DEFAULT_QUERY_TIMEOUT 60
48 
49 #define DNS_FLAG_QR(flags) (((flags) >> 15) & 0x01)
50 #define DNS_FLAG_RD(flags) (((flags) >> 8) & 0x01)
51 #define DNS_FLAG_RCODE(flags) ((flags) & 0xf)
52 
53 /* Data structures. */
54 
55 typedef struct list_entry list_entry_t;
56 typedef struct hash_entry hash_entry_t;
57 
58 struct list_entry {
59  ISC_LINK(struct list_entry) link;
60  hash_entry_t *he;
61 };
62 
63 struct hash_entry {
64  Nmsg__Base__DnsQR *dnsqr;
65  list_entry_t *le;
66 };
67 
68 typedef struct {
69  pthread_mutex_t lock;
70 
71  hash_entry_t *table;
72  ISC_LIST(struct list_entry) list;
73  struct reasm_ip *reasm;
74 
75  size_t len_table;
76 
77  bool stop;
78  int capture_qr;
79  int capture_rd;
80  bool zero_resolver_address;
81 
82  uint32_t num_slots;
83  uint32_t max_values;
84  uint32_t query_timeout;
85  uint32_t count;
86 #ifdef DEBUG
87  uint32_t count_unanswered_query;
88  uint32_t count_unsolicited_response;
89  uint32_t count_query_response;
90  uint32_t count_packet;
91 #endif
92  struct timespec now;
93 
94  wdns_name_t **filter_qnames_exclude;
95  uint32_t filter_qnames_exclude_slots;
96 
97  wdns_name_t **filter_qnames_include;
98  uint32_t filter_qnames_include_slots;
99 } dnsqr_ctx_t;
100 
101 typedef struct {
102  uint32_t query_ip;
103  uint32_t response_ip;
104  uint16_t proto;
105  uint16_t query_port;
106  uint16_t response_port;
107  uint16_t id;
108 } dnsqr_key_t;
109 
110 typedef struct {
111  uint8_t query_ip6[16];
112  uint8_t response_ip6[16];
113  uint16_t proto;
114  uint16_t query_port;
115  uint16_t response_port;
116  uint16_t id;
117 } dnsqr_key6_t;
118 
119 typedef struct {
120  uint8_t src[4];
121  uint8_t dst[4];
122  uint8_t zero;
123  uint8_t proto;
124  uint16_t udp_len;
125  uint16_t src_port;
126  uint16_t dst_port;
127  uint16_t length;
128  uint16_t checksum;
129 } __attribute__((__packed__)) udp_pseudo_ipv4;
130 
131 typedef struct {
132  uint8_t src[16];
133  uint8_t dst[16];
134  uint32_t upper_len;
135  uint8_t zero[3];
136  uint8_t next;
137  uint16_t src_port;
138  uint16_t dst_port;
139  uint16_t length;
140  uint16_t checksum;
141 } __attribute__((__packed__)) udp_pseudo_ipv6;
142 
143 typedef nmsg_res (*dnsqr_append_fp)(Nmsg__Base__DnsQR *dnsqr,
144  const uint8_t *pkt, size_t pkt_len,
145  const struct timespec *ts);
146 
147 /* Exported via module context. */
148 
149 static nmsg_res dnsqr_init(void **clos);
150 static nmsg_res dnsqr_fini(void **clos);
151 static nmsg_res dnsqr_pcap_init(void *clos, nmsg_pcap_t pcap);
152 static nmsg_res dnsqr_pkt_to_payload(void *clos, nmsg_pcap_t pcap, nmsg_message_t *m);
153 
154 static NMSG_MSGMOD_FIELD_PRINTER(dnsqr_proto_print);
155 static NMSG_MSGMOD_FIELD_PRINTER(dnsqr_message_print);
156 static NMSG_MSGMOD_FIELD_PRINTER(dnsqr_rcode_print);
157 static NMSG_MSGMOD_FIELD_GETTER(dnsqr_get_delay);
158 static NMSG_MSGMOD_FIELD_GETTER(dnsqr_get_query);
159 static NMSG_MSGMOD_FIELD_GETTER(dnsqr_get_response);
160 static NMSG_MSGMOD_FIELD_GETTER(dnsqr_get_udp_checksum);
161 
162 /* Data. */
163 
164 struct nmsg_msgmod_field dnsqr_fields[] = {
165  {
167  .name = "type"
168  },
169  {
170  .type = nmsg_msgmod_ft_ip,
171  .name = "query_ip"
172  },
173  {
174  .type = nmsg_msgmod_ft_ip,
175  .name = "response_ip"
176  },
177  { .type = nmsg_msgmod_ft_uint16,
178  .name = "proto",
179  .print = dnsqr_proto_print
180  },
181  {
182  .type = nmsg_msgmod_ft_uint16,
183  .name = "query_port"
184  },
185  {
186  .type = nmsg_msgmod_ft_uint16,
187  .name = "response_port"
188  },
189  { .type = nmsg_msgmod_ft_uint16,
190  .name = "id"
191  },
192  {
193  .type = nmsg_msgmod_ft_bytes,
194  .name = "qname",
195  .print = dns_name_print
196  },
197  {
198  .type = nmsg_msgmod_ft_uint16,
199  .name = "qclass",
200  .print = dns_class_print
201  },
202  {
203  .type = nmsg_msgmod_ft_uint16,
204  .name = "qtype",
205  .print = dns_type_print
206  },
207  {
208  .type = nmsg_msgmod_ft_uint16,
209  .name = "rcode",
210  .print = dnsqr_rcode_print
211  },
212  {
213  .type = nmsg_msgmod_ft_bytes,
214  .name = "query_packet",
216  },
217  {
218  .type = nmsg_msgmod_ft_int64,
219  .name = "query_time_sec",
221  },
222  {
223  .type = nmsg_msgmod_ft_int32,
224  .name = "query_time_nsec",
226  },
227  {
228  .type = nmsg_msgmod_ft_bytes,
229  .name = "response_packet",
231  },
232  {
233  .type = nmsg_msgmod_ft_int64,
234  .name = "response_time_sec",
236  },
237  {
238  .type = nmsg_msgmod_ft_int32,
239  .name = "response_time_nsec",
241  },
242  {
243  .type = nmsg_msgmod_ft_double,
244  .name = "timeout",
245  },
246  {
247  .type = nmsg_msgmod_ft_double,
248  .name = "delay",
249  .get = dnsqr_get_delay
250  },
251  {
252  .type = nmsg_msgmod_ft_enum,
253  .name = "udp_checksum",
254  .get = dnsqr_get_udp_checksum
255  },
256  {
257  .type = nmsg_msgmod_ft_bool,
258  .name = "resolver_address_zeroed"
259  },
260  {
261  .type = nmsg_msgmod_ft_bytes,
262  .name = "query",
263  .get = dnsqr_get_query,
264  .print = dnsqr_message_print
265  },
266  {
267  .type = nmsg_msgmod_ft_bytes,
268  .name = "response",
269  .get = dnsqr_get_response,
270  .print = dnsqr_message_print
271  },
272  {
273  .type = nmsg_msgmod_ft_bytes,
274  .name = "dns",
275  .get = dnsqr_get_response,
277  },
278  {
279  .type = nmsg_msgmod_ft_bytes,
280  .name = "tcp",
282  },
283  {
284  .type = nmsg_msgmod_ft_bytes,
285  .name = "icmp",
287  },
288  NMSG_MSGMOD_FIELD_END
289 };
290 
291 /* Export. */
292 
293 struct nmsg_msgmod_plugin nmsg_msgmod_ctx = {
294  NMSG_MSGMOD_REQUIRED_INIT,
295  .vendor = NMSG_VENDOR_BASE,
296  .msgtype = { NMSG_VENDOR_BASE_DNSQR_ID, NMSG_VENDOR_BASE_DNSQR_NAME },
297 
298  .pbdescr = &nmsg__base__dns_qr__descriptor,
299  .fields = dnsqr_fields,
300  .init = dnsqr_init,
301  .fini = dnsqr_fini,
302  .pkt_to_payload = dnsqr_pkt_to_payload,
303  .pcap_init = dnsqr_pcap_init,
304 };
305 
306 /* Forward. */
307 
308 static void dnsqr_print_stats(dnsqr_ctx_t *ctx);
309 
310 /* Functions. */
311 
312 static int
313 dnsqr_checksum_verify(Nmsg__Base__DnsQR *dnsqr) {
314  nmsg_res res;
315  size_t ip_len;
316  struct nmsg_ipdg dg;
317  struct nmsg_iphdr *ip;
318  struct nmsg_udphdr *udp;
319  uint16_t word;
320  uint32_t sum = 0;
321  uint8_t *p = NULL;
322  udp_pseudo_ipv4 ph;
323  udp_pseudo_ipv6 ph6;
324  size_t pseudo_len = 0;
325 
326  /* if the resolver address was zeroed, it's now impossible to
327  * verify the checksum */
328  if (dnsqr->has_resolver_address_zeroed &&
329  dnsqr->resolver_address_zeroed)
330  {
331  return (NMSG__BASE__UDP_CHECKSUM__ERROR);
332  }
333 
334  /* locate the initial fragment and create the pseudo header */
335  for (unsigned r = 0; r < dnsqr->n_response_packet; r++) {
336  uint8_t *data = NULL;
337  ssize_t data_len = 0;
338 
339  ip = (struct nmsg_iphdr *) dnsqr->response_packet[r].data;
340  ip_len = dnsqr->response_packet[r].len;
341 
342  res = nmsg_ipdg_parse_pcap_raw(&dg, DLT_RAW, (uint8_t *) ip, ip_len);
343  if (res != nmsg_res_success)
344  return (NMSG__BASE__UDP_CHECKSUM__ERROR);
345 
346  if (dg.proto_network == PF_INET && dg.proto_transport == IPPROTO_UDP) {
347  data = (uint8_t *) dg.payload;
348  data_len = dg.len_payload;
349 
350  if (dg.transport != NULL) {
351  /* this is the initial fragment */
352  if (dg.len_transport < sizeof(struct nmsg_udphdr))
353  return (NMSG__BASE__UDP_CHECKSUM__ERROR);
354 
355  p = (uint8_t *) &ph;
356  pseudo_len = sizeof(ph);
357  memset(&ph, 0, sizeof(ph));
358  udp = (struct nmsg_udphdr *) (dg.transport);
359 
360  if (udp->uh_sum == 0)
361  return (NMSG__BASE__UDP_CHECKSUM__ABSENT);
362 
363  /* create the IPv4 UDP pseudo header */
364  memcpy(&ph.src[0], &ip->ip_src, 4);
365  memcpy(&ph.dst[0], &ip->ip_dst, 4);
366  memcpy(&ph.proto, &ip->ip_p, 1);
367  memcpy(&ph.udp_len, &udp->uh_ulen, 2);
368  memcpy(&ph.src_port, &udp->uh_sport, 2);
369  memcpy(&ph.dst_port, &udp->uh_dport, 2);
370  memcpy(&ph.length, &udp->uh_ulen, 2);
371  memcpy(&ph.checksum, &udp->uh_sum, 2);
372  }
373  } else if (dg.proto_network == PF_INET6 && dg.proto_transport == IPPROTO_UDP) {
374  data = (uint8_t *) dg.payload;
375  data_len = dg.len_payload;
376 
377  if (dg.transport != NULL) {
378  /* this is the initial fragment */
379  if (dg.len_transport < sizeof(struct nmsg_udphdr))
380  return (NMSG__BASE__UDP_CHECKSUM__ERROR);
381 
382  p = (uint8_t *) &ph6;
383  pseudo_len = sizeof(ph6);
384  udp = (struct nmsg_udphdr *) (dg.transport);
385  struct ip6_hdr *ip6 = (struct ip6_hdr *) (dg.network);
386  memset(&ph6, 0, sizeof(ph6));
387 
388  if (udp->uh_sum == 0)
389  return (NMSG__BASE__UDP_CHECKSUM__ABSENT);
390 
391  /* create the IPv6 UDP pseudo header */
392  memcpy(&ph6.src[0], &ip6->ip6_src, 16);
393  memcpy(&ph6.dst[0], &ip6->ip6_dst, 16);
394  memcpy(&ph6.src_port, &udp->uh_sport, 2);
395  memcpy(&ph6.dst_port, &udp->uh_dport, 2);
396  memcpy(&ph6.length, &udp->uh_ulen, 2);
397  memcpy(&ph6.checksum, &udp->uh_sum, 2);
398 
399  memcpy(&word, &udp->uh_ulen, 2);
400  ph6.upper_len = (uint32_t) word;
401  ph6.next = IPPROTO_UDP;
402  }
403  } else {
404  return (NMSG__BASE__UDP_CHECKSUM__ERROR);
405  }
406 
407  if (data_len < 0)
408  return (NMSG__BASE__UDP_CHECKSUM__ERROR);
409 
410  /* sum the payload, less the last octet if an odd number of octets */
411  for (int i = 0; i < data_len - 1; i += 2) {
412  memcpy(&word, data + i, 2);
413  sum += ntohs(word);
414  }
415 
416  /* sum the last octet of the payload if necessary */
417  if ((data_len & 1) == 1) {
418  word = (data[data_len - 1] << 8) & 0xff00;
419  sum += word;
420  }
421  }
422 
423  /* if p was not set, the initial fragment was not found
424  * (and thus the pseudo header could not be created) */
425  if (p == NULL)
426  return (NMSG__BASE__UDP_CHECKSUM__ERROR);
427 
428  /* sum the pseudo header */
429  for (int i = 0; i < (ssize_t) pseudo_len; i += 2) {
430  memcpy(&word, p + i, 2);
431  sum += ntohs(word);
432  }
433 
434  /* accumulate the 32 bit sum into 16 bits */
435  while (sum >> 16)
436  sum = (sum & 0xffff) + (sum >> 16);
437  sum = (uint16_t) ~sum;
438 
439  /* check if checksum is correct */
440  if (sum == 0)
441  return (NMSG__BASE__UDP_CHECKSUM__CORRECT);
442  return (NMSG__BASE__UDP_CHECKSUM__INCORRECT);
443 }
444 
445 static void
446 dnsqr_zero_resolver_address(Nmsg__Base__DnsQR *dnsqr) {
447  struct nmsg_iphdr *ip;
448  struct ip6_hdr *ip6;
449  size_t ip_len;
450 
451  dnsqr->resolver_address_zeroed = true;
452  dnsqr->has_resolver_address_zeroed = true;
453 
454  /* zero the protobuf query_ip field */
455  memset(dnsqr->query_ip.data, 0, dnsqr->query_ip.len);
456 
457  /* zero the query */
458  for (unsigned i = 0; i < dnsqr->n_query_packet; i++) {
459  ip = (struct nmsg_iphdr *) dnsqr->query_packet[i].data;
460  ip_len = dnsqr->query_packet[i].len;
461 
462  if (ip->ip_v == 4) {
463  if (ip_len >= sizeof(struct nmsg_iphdr))
464  memset(&ip->ip_src, 0, 4);
465  } else if (ip->ip_v == 6) {
466  ip6 = (struct ip6_hdr *) ip;
467  if (ip_len >= sizeof(struct ip6_hdr))
468  memset(&ip6->ip6_src, 0, 16);
469  }
470  }
471 
472  /* zero the response */
473  for (unsigned i = 0; i < dnsqr->n_response_packet; i++) {
474  ip = (struct nmsg_iphdr *) dnsqr->response_packet[i].data;
475  ip_len = dnsqr->response_packet[i].len;
476 
477  if (ip->ip_v == 4) {
478  if (ip_len >= sizeof(struct nmsg_iphdr))
479  memset(&ip->ip_dst, 0, 4);
480  } else if (ip->ip_v == 6) {
481  ip6 = (struct ip6_hdr *) ip;
482  if (ip_len >= sizeof(struct ip6_hdr))
483  memset(&ip6->ip6_dst, 0, 16);
484  }
485  }
486 }
487 
488 static bool
489 getenv_int(const char *name, int64_t *value) {
490  char *s, *t;
491 
492  s = getenv(name);
493  if (s == NULL)
494  return (false);
495 
496  *value = strtol(s, &t, 0);
497  if (*t != '\0')
498  return (false);
499  return (true);
500 }
501 
502 static bool
503 dnsqr_filter_lookup(wdns_name_t **table, uint32_t num_slots, wdns_name_t *name) {
504  unsigned slot, slot_stop;
505 
506  slot = my_hashlittle(name->data, name->len, 0) % num_slots;
507  if (slot > 0)
508  slot_stop = slot - 1;
509  else
510  slot_stop = num_slots - 1;
511 
512  for (;;) {
513  wdns_name_t *ent = table[slot];
514 
515  /* empty slot, not present */
516  if (ent == NULL)
517  return (false);
518 
519  /* hit */
520  if (ent != NULL &&
521  ent->len == name->len &&
522  memcmp(ent->data, name->data, name->len) == 0)
523  {
524  return (true);
525  }
526 
527  /* slot filled, but not our value */
528  assert(slot != slot_stop);
529  slot += 1;
530  if (slot >= num_slots)
531  slot = 0;
532  }
533 }
534 
535 static void
536 dnsqr_filter_insert(wdns_name_t **table, uint32_t num_slots, wdns_name_t *name) {
537  unsigned slot, slot_stop;
538  wdns_name_t **ent;
539 
540  slot = my_hashlittle(name->data, name->len, 0) % num_slots;
541  if (slot > 0)
542  slot_stop = slot - 1;
543  else
544  slot_stop = num_slots - 1;
545 
546  for (;;) {
547  ent = &table[slot];
548 
549  /* empty slot, insert */
550  if (*ent == NULL) {
551  *ent = name;
552  break;
553  }
554 
555  /* slot filled */
556  assert(slot != slot_stop);
557  slot += 1;
558  if (slot >= num_slots)
559  slot = 0;
560  }
561 }
562 
563 static void
564 dnsqr_filter_init(const char *env_var, wdns_name_t ***table, uint32_t *num_slots) {
565  char *names, *saveptr, *token;
566  uint32_t num_names;
567  unsigned i;
568 
569  if (getenv(env_var) == NULL)
570  return;
571 
572  num_names = 1;
573 
574  names = strdup(getenv(env_var));
575  assert(names != NULL);
576 
577  for (i = 0; i < strlen(names); i++) {
578  if (names[i] == ':')
579  num_names += 1;
580  }
581 
582  *num_slots = num_names * 2;
583 
584  *table = my_calloc(1, sizeof(void *) * *num_slots);
585 
586  token = strtok_r(names, ":", &saveptr);
587  do {
588  wdns_res res;
589  wdns_name_t *name;
590 
591  name = my_malloc(sizeof(*name));
592  res = wdns_str_to_name(token, name);
593  if (res == wdns_res_success) {
594  wdns_downcase_name(name);
595  dnsqr_filter_insert(*table, *num_slots, name);
596  } else {
597  if (nmsg_get_debug() >= 1)
598  fprintf(stderr,
599  "%s: wdns_str_to_name() failed, token='%s' res=%d\n",
600  __func__, token, res);
601  }
602 
603  } while ((token = strtok_r(NULL, ":", &saveptr)) != NULL);
604 
605  free(names);
606 }
607 
608 static void
609 dnsqr_filter_destroy(wdns_name_t **table, uint32_t num_slots) {
610  unsigned i;
611 
612  for (i = 0; i < num_slots; i++) {
613  if (table[i] != NULL) {
614  free(table[i]->data);
615  free(table[i]);
616  table[i] = NULL;
617  }
618  }
619 }
620 
621 static nmsg_res
622 dnsqr_init(void **clos) {
623  dnsqr_ctx_t *ctx;
624  int64_t qr, rd, max, timeout, zero;
625 
626  ctx = my_calloc(1, sizeof(*ctx));
627  pthread_mutex_init(&ctx->lock, NULL);
628 
629  ctx->reasm = reasm_ip_new();
630  assert(ctx->reasm != NULL);
631 
632  ISC_LIST_INIT(ctx->list);
633 
634  if (getenv_int("DNSQR_CAPTURE_QR", &qr) &&
635  (qr == 0 || qr == 1))
636  {
637  ctx->capture_qr = qr;
638  } else {
639  ctx->capture_qr = -1;
640  }
641 
642  if (getenv_int("DNSQR_CAPTURE_RD", &rd) &&
643  (rd == 0 || rd == 1))
644  {
645  ctx->capture_rd = rd;
646  } else {
647  ctx->capture_rd = -1;
648  }
649 
650  if (getenv_int("DNSQR_ZERO_RESOLVER_ADDRESS", &zero) && zero)
651  ctx->zero_resolver_address = true;
652 
653  if (getenv_int("DNSQR_STATE_TABLE_MAX", &max) && max > 0) {
654  ctx->max_values = max;
655  ctx->num_slots = ctx->max_values * 2;
656  } else {
657  ctx->num_slots = DEFAULT_NUM_SLOTS;
658  ctx->max_values = DEFAULT_MAX_VALUES;
659  }
660 
661  if (getenv_int("DNSQR_QUERY_TIMEOUT", &timeout) && timeout > 0)
662  ctx->query_timeout = timeout;
663  else
664  ctx->query_timeout = DEFAULT_QUERY_TIMEOUT;
665 
666  dnsqr_filter_init("DNSQR_FILTER_QNAMES_INCLUDE",
667  &ctx->filter_qnames_include,
668  &ctx->filter_qnames_include_slots);
669  dnsqr_filter_init("DNSQR_FILTER_QNAMES_EXCLUDE",
670  &ctx->filter_qnames_exclude,
671  &ctx->filter_qnames_exclude_slots);
672 
673  ctx->len_table = sizeof(hash_entry_t) * ctx->num_slots;
674 
675  ctx->table = mmap(NULL, ctx->len_table,
676  PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
677  assert(ctx->table != MAP_FAILED);
678 
679  *clos = ctx;
680  return (nmsg_res_success);
681 }
682 
683 static nmsg_res
684 dnsqr_fini(void **clos) {
685  size_t n;
686  dnsqr_ctx_t *ctx;
687 
688  ctx = (dnsqr_ctx_t *) *clos;
689 
690  for (n = 0; n < ctx->num_slots; n++) {
691  hash_entry_t *he = &ctx->table[n];
692  if (he->dnsqr != NULL)
693  nmsg__base__dns_qr__free_unpacked(he->dnsqr, NULL);
694  }
695 
696  dnsqr_filter_destroy(ctx->filter_qnames_include, ctx->filter_qnames_include_slots);
697  dnsqr_filter_destroy(ctx->filter_qnames_exclude, ctx->filter_qnames_exclude_slots);
698 
699  dnsqr_print_stats(ctx);
700 
701  reasm_ip_free(ctx->reasm);
702 
703  munmap(ctx->table, ctx->len_table);
704  free(ctx);
705  *clos = NULL;
706 
707  return (nmsg_res_success);
708 }
709 
710 static int
711 get_af(const char *addr) {
712  char *s, *slash;
713  char buf[16];
714  int af;
715 
716  s = strdup(addr);
717  assert(s != NULL);
718  slash = strchr(s, '/');
719  if (slash != NULL)
720  *slash = '\x00';
721  if (inet_pton(AF_INET, s, buf) == 1) {
722  af = AF_INET;
723  } else if (inet_pton(AF_INET6, s, buf) == 1) {
724  af = AF_INET6;
725  } else {
726  af = -1;
727  }
728  free(s);
729  return (af);
730 }
731 
732 static char *
733 addrs_to_bpf(const char *addrs, const char *bpfdir, int af) {
734  char *ret, *tok_addrs, *addr, *saveptr;
735  size_t retsz;
736  int addr_af;
737  ubuf *bpf;
738 
739  bpf = ubuf_new();
740  tok_addrs = strdup(addrs);
741  assert(tok_addrs != NULL);
742 
743  addr = strtok_r(tok_addrs, ",", &saveptr);
744  do {
745  /* strip leading spaces */
746  while (isspace(addr[0]))
747  addr++;
748  /* strip trailing spaces */
749  size_t i = strlen(addr);
750  while (i--) {
751  if (isspace(addr[i]))
752  addr[i] = '\x00';
753  else
754  break;
755  }
756 
757  addr_af = get_af(addr);
758  if (addr_af != af)
759  continue;
760  if (addr_af != AF_INET && addr_af != AF_INET6) {
761  ubuf_destroy(&bpf);
762  free(tok_addrs);
763  return (NULL);
764  }
765 
766  if (ubuf_size(bpf) > 0)
767  ubuf_add_cstr(bpf, " or ");
768  ubuf_add_cstr(bpf, bpfdir);
769  ubuf_add_cstr(bpf, " ");
770  if (strchr(addr, '/') != NULL)
771  ubuf_add_cstr(bpf, "net ");
772  ubuf_add_cstr(bpf, addr);
773  } while ((addr = strtok_r(NULL, ",", &saveptr)) != NULL);
774 
775  free(tok_addrs);
776  ubuf_cterm(bpf);
777  ubuf_detach(bpf, (uint8_t **) &ret, &retsz);
778  ubuf_destroy(&bpf);
779  return (ret);
780 }
781 
782 #define ipv4_frags "(ip[6:2] & 0x3fff != 0)"
783 #define udp_qr_query "(((udp[10:2] >> 15) & 0x01) == 0)"
784 #define udp_qr_response "(((udp[10:2] >> 15) & 0x01) == 1)"
785 
786 static const char *s_pattern_auth4 =
787  "("
788  "((@DST@) and udp dst port 53) or "
789  "((@SRC@) and udp src port 53) or "
790  "((@SRC@) and " ipv4_frags ") or "
791  "((@DST@) and icmp)"
792  ")";
793 static const char *s_pattern_auth4_queries =
794  "("
795  "(@DST@) and udp dst port 53 and " udp_qr_query
796  ")";
797 static const char *s_pattern_auth4_responses =
798  "("
799  "((@SRC@) and udp src port 53 and " udp_qr_response ") or "
800  "((@SRC@) and " ipv4_frags ")"
801  ")";
802 
803 static const char *s_pattern_res4 =
804  "("
805  "((@SRC@) and udp dst port 53) or "
806  "((@DST@) and udp src port 53) or "
807  "((@DST@) and " ipv4_frags ") or "
808  "((@SRC@) and icmp)"
809  ")";
810 static const char *s_pattern_res4_queries =
811  "((@SRC@) and udp dst port 53 and " udp_qr_query ")";
812 static const char *s_pattern_res4_responses =
813  "("
814  "((@DST@) and udp src port 53 and " udp_qr_response ") or "
815  "((@DST@) and " ipv4_frags ")"
816  ")";
817 
818 #undef ipv4_frags
819 #undef udp_qr_query
820 #undef udp_qr_response
821 
822 static const char *s_pattern_auth6 =
823  "((@DST@) or (@SRC@))";
824 
825 static const char *s_pattern_res6 =
826  "((@SRC@) or (@DST@))";
827 
828 static char *
829 bpf_replace(const char *s_pattern, const char *bpf_src, const char *bpf_dst) {
830  char *rep0, *rep1;
831  rep0 = string_replace(s_pattern, "@SRC@", bpf_src);
832  rep1 = string_replace(rep0, "@DST@", bpf_dst);
833  free(rep0);
834  return (rep1);
835 }
836 
837 static nmsg_res
838 dnsqr_pcap_init(void *clos, nmsg_pcap_t pcap) {
839  dnsqr_ctx_t *ctx = (dnsqr_ctx_t *) clos;
840  const char *auth_addrs = NULL;
841  const char *res_addrs = NULL;
842  nmsg_res res;
843 
844  bool do_auth4 = false;
845  bool do_auth6 = false;
846  bool do_res4 = false;
847  bool do_res6 = false;
848 
849  char *bpf = NULL;
850  char *bpf_auth = NULL;
851  char *bpf_auth4 = NULL;
852  char *bpf_auth4_dst = NULL;
853  char *bpf_auth4_src = NULL;
854  char *bpf_auth6 = NULL;
855  char *bpf_auth6_dst = NULL;
856  char *bpf_auth6_src = NULL;
857  char *bpf_res = NULL;
858  char *bpf_res4 = NULL;
859  char *bpf_res4_dst = NULL;
860  char *bpf_res4_src = NULL;
861  char *bpf_res6 = NULL;
862  char *bpf_res6_dst = NULL;
863  char *bpf_res6_src = NULL;
864 
865  res = nmsg_res_success;
866 
867  auth_addrs = getenv("DNSQR_AUTH_ADDRS");
868  if (auth_addrs) {
869  bpf_auth4_src = addrs_to_bpf(auth_addrs, "src", AF_INET);
870  bpf_auth4_dst = addrs_to_bpf(auth_addrs, "dst", AF_INET);
871  bpf_auth6_src = addrs_to_bpf(auth_addrs, "src", AF_INET6);
872  bpf_auth6_dst = addrs_to_bpf(auth_addrs, "dst", AF_INET6);
873 
874  if (bpf_auth4_src == NULL ||
875  bpf_auth4_dst == NULL ||
876  bpf_auth6_src == NULL ||
877  bpf_auth6_dst == NULL)
878  {
879  res = nmsg_res_failure;
880  goto out;
881  }
882 
883  do_auth4 = (strlen(bpf_auth4_src) > 0) ? true : false;
884  do_auth6 = (strlen(bpf_auth6_src) > 0) ? true : false;
885 
886  if (do_auth4) {
887  if (ctx->capture_qr == -1) {
888  bpf_auth4 = bpf_replace(s_pattern_auth4,
889  bpf_auth4_src,
890  bpf_auth4_dst);
891  } else if (ctx->capture_qr == 0) {
892  bpf_auth4 = bpf_replace(s_pattern_auth4_queries,
893  bpf_auth4_src,
894  bpf_auth4_dst);
895  } else if (ctx->capture_qr == 1) {
896  bpf_auth4 = bpf_replace(s_pattern_auth4_responses,
897  bpf_auth4_src,
898  bpf_auth4_dst);
899  }
900  }
901  if (do_auth6)
902  bpf_auth6 = bpf_replace(s_pattern_auth6, bpf_auth6_src, bpf_auth6_dst);
903 
904  nmsg_asprintf(&bpf_auth, "%s%s%s",
905  (do_auth4) ? bpf_auth4 : "",
906  (do_auth4 && do_auth6) ? " or " : "",
907  (do_auth6) ? bpf_auth6 : ""
908  );
909  assert(bpf_auth != NULL);
910  }
911 
912  res_addrs = getenv("DNSQR_RES_ADDRS");
913  if (res_addrs) {
914  bpf_res4_src = addrs_to_bpf(res_addrs, "src", AF_INET);
915  bpf_res4_dst = addrs_to_bpf(res_addrs, "dst", AF_INET);
916  bpf_res6_src = addrs_to_bpf(res_addrs, "src", AF_INET6);
917  bpf_res6_dst = addrs_to_bpf(res_addrs, "dst", AF_INET6);
918 
919  if (bpf_res4_src == NULL ||
920  bpf_res4_dst == NULL ||
921  bpf_res6_src == NULL ||
922  bpf_res6_dst == NULL)
923  {
924  res = nmsg_res_failure;
925  goto out;
926  }
927 
928  do_res4 = (strlen(bpf_res4_src) > 0) ? true : false;
929  do_res6 = (strlen(bpf_res6_src) > 0) ? true : false;
930 
931  if (do_res4) {
932  if (ctx->capture_qr == -1) {
933  bpf_res4 = bpf_replace(s_pattern_res4,
934  bpf_res4_src,
935  bpf_res4_dst);
936  } else if (ctx->capture_qr == 0) {
937  bpf_res4 = bpf_replace(s_pattern_res4_queries,
938  bpf_res4_src,
939  bpf_res4_dst);
940  } else if (ctx->capture_qr == 1) {
941  bpf_res4 = bpf_replace(s_pattern_res4_responses,
942  bpf_res4_src,
943  bpf_res4_dst);
944  }
945  }
946  if (do_res6)
947  bpf_res6 = bpf_replace(s_pattern_res6, bpf_res6_src, bpf_res6_dst);
948 
949  nmsg_asprintf(&bpf_res, "%s%s%s",
950  (do_res4) ? bpf_res4 : "",
951  (do_res4 && do_res6) ? " or " : "",
952  (do_res6) ? bpf_res6 : "");
953  assert(bpf_res != NULL);
954  }
955 
956  if (!auth_addrs && !res_addrs)
957  return (nmsg_res_success);
958 
959  nmsg_asprintf(&bpf, "%s%s%s",
960  (bpf_auth != NULL) ? bpf_auth : "",
961  ((bpf_auth != NULL) && (bpf_res != NULL)) ? " or " : "",
962  (bpf_res != NULL) ? bpf_res : "");
963  assert(bpf != NULL);
964 
965  res = nmsg_pcap_input_setfilter_raw(pcap, bpf);
966 
967 out:
968  free(bpf);
969  free(bpf_auth);
970  free(bpf_auth4);
971  free(bpf_auth4_dst);
972  free(bpf_auth4_src);
973  free(bpf_auth6);
974  free(bpf_auth6_dst);
975  free(bpf_auth6_src);
976  free(bpf_res);
977  free(bpf_res4);
978  free(bpf_res4_dst);
979  free(bpf_res4_src);
980  free(bpf_res6);
981  free(bpf_res6_dst);
982  free(bpf_res6_src);
983  return (res);
984 }
985 
986 static nmsg_res
987 dnsqr_proto_print(nmsg_message_t msg,
988  struct nmsg_msgmod_field *field,
989  void *ptr,
990  struct nmsg_strbuf *sb,
991  const char *endline)
992 {
993  uint16_t proto;
994 
995  proto = *((uint16_t *) ptr);
996 
997  switch (proto) {
998  case IPPROTO_UDP:
999  return (nmsg_strbuf_append(sb, "proto: UDP (17)\n"));
1000  case IPPROTO_TCP:
1001  return (nmsg_strbuf_append(sb, "proto: TCP (6)\n"));
1002  case IPPROTO_ICMP:
1003  return (nmsg_strbuf_append(sb, "proto: ICMP (1)\n"));
1004  default:
1005  return (nmsg_strbuf_append(sb, "proto: %hu\n", proto));
1006  }
1007 }
1008 
1009 static nmsg_res
1010 dnsqr_message_print(nmsg_message_t msg,
1011  struct nmsg_msgmod_field *field,
1012  void *ptr,
1013  struct nmsg_strbuf *sb,
1014  const char *endline)
1015 {
1016  ProtobufCBinaryData *bdata;
1017  nmsg_res res;
1018  wdns_message_t dns;
1019  wdns_res status;
1020 
1021  bdata = (ProtobufCBinaryData *) ptr;
1022  if (bdata == NULL)
1023  return (nmsg_res_failure);
1024 
1025  status = wdns_parse_message(&dns, bdata->data, bdata->len);
1026  if (status == wdns_res_success) {
1027  char *s;
1028 
1029  s = wdns_message_to_str(&dns);
1030  if (s != NULL) {
1031  res = nmsg_strbuf_append(sb, "%s: [%zd octets]%s%s---%s",
1032  field->name, bdata->len, endline, s, endline);
1033  free(s);
1034  wdns_clear_message(&dns);
1035  return (res);
1036  }
1037  wdns_clear_message(&dns);
1038  }
1039  nmsg_strbuf_append(sb, "%s: <PARSE ERROR>%s", field->name, endline);
1040  return (nmsg_res_success);
1041 }
1042 
1043 static nmsg_res
1044 dnsqr_rcode_print(nmsg_message_t msg,
1045  struct nmsg_msgmod_field *field,
1046  void *ptr,
1047  struct nmsg_strbuf *sb,
1048  const char *endline)
1049 {
1050  const char *s;
1051  uint16_t *rcode = ptr;
1052 
1053  s = wdns_rcode_to_str(*rcode);
1054  return (nmsg_strbuf_append(sb, "%s: %s (%hu)%s",
1055  field->name,
1056  s ? s : "<UNKNOWN>",
1057  *rcode, endline));
1058 }
1059 
1060 static nmsg_res
1061 dnsqr_get_udp_checksum(nmsg_message_t msg,
1062  struct nmsg_msgmod_field *field,
1063  unsigned val_idx,
1064  void **data,
1065  size_t *len,
1066  void *msg_clos)
1067 {
1068  Nmsg__Base__DnsQR *dnsqr = (Nmsg__Base__DnsQR *) nmsg_message_get_payload(msg);
1069 
1070  if (dnsqr == NULL || val_idx != 0 || dnsqr->n_response_packet <= 0)
1071  return (nmsg_res_failure);
1072 
1073  if (!dnsqr->has_udp_checksum)
1074  dnsqr->udp_checksum = dnsqr_checksum_verify(dnsqr);
1075  *data = (void *) &dnsqr->udp_checksum;
1076  if (len)
1077  *len = sizeof(dnsqr->udp_checksum);
1078 
1079  return (nmsg_res_success);
1080 }
1081 
1082 static nmsg_res
1083 dnsqr_get_delay(nmsg_message_t msg,
1084  struct nmsg_msgmod_field *field,
1085  unsigned val_idx,
1086  void **data,
1087  size_t *len,
1088  void *msg_clos)
1089 {
1090  Nmsg__Base__DnsQR *dnsqr = (Nmsg__Base__DnsQR *) nmsg_message_get_payload(msg);
1091  double delay;
1092  double *pdelay;
1093  struct timespec ts_delay;
1094 
1095  if (dnsqr == NULL || val_idx != 0 ||
1096  dnsqr->type != NMSG__BASE__DNS_QRTYPE__UDP_QUERY_RESPONSE)
1097  return (nmsg_res_failure);
1098 
1099  if ((dnsqr->n_query_time_sec != dnsqr->n_query_time_nsec) ||
1100  dnsqr->n_query_time_sec != 1)
1101  return (nmsg_res_failure);
1102 
1103  if ((dnsqr->n_response_time_sec != dnsqr->n_response_time_nsec) ||
1104  dnsqr->n_response_time_sec < 1)
1105  return (nmsg_res_failure);
1106 
1107  if (dnsqr->n_response_time_sec == 1) {
1108  ts_delay.tv_sec = dnsqr->response_time_sec[0] - dnsqr->query_time_sec[0];
1109  ts_delay.tv_nsec = dnsqr->response_time_nsec[0] - dnsqr->query_time_nsec[0];
1110  if (ts_delay.tv_nsec < 0) {
1111  ts_delay.tv_sec -= 1;
1112  ts_delay.tv_nsec += 1000000000;
1113  }
1114  delay = ts_delay.tv_sec + ts_delay.tv_nsec / 1E9;
1115  } else {
1116  double max_delay = 0.0;
1117 
1118  for (unsigned i = 0; i < dnsqr->n_response_time_sec; i++) {
1119  ts_delay.tv_sec = dnsqr->response_time_sec[i] - dnsqr->query_time_sec[0];
1120  ts_delay.tv_nsec = dnsqr->response_time_nsec[i] - dnsqr->query_time_nsec[0];
1121  if (ts_delay.tv_nsec < 0) {
1122  ts_delay.tv_sec -= 1;
1123  ts_delay.tv_nsec += 1000000000;
1124  }
1125  delay = ts_delay.tv_sec + ts_delay.tv_nsec / 1E9;
1126 
1127  if (delay > max_delay)
1128  max_delay = delay;
1129  }
1130  delay = max_delay;
1131  }
1132 
1133  pdelay = my_malloc(sizeof(double));
1134  *pdelay = delay;
1135 
1136  *data = (void *) pdelay;
1137  if (len)
1138  *len = sizeof(double);
1139 
1140  return (nmsg_message_add_allocation(msg, pdelay));
1141 }
1142 
1143 static nmsg_res
1144 dnsqr_get_query(nmsg_message_t msg,
1145  struct nmsg_msgmod_field *field,
1146  unsigned val_idx,
1147  void **data,
1148  size_t *len,
1149  void *msg_clos)
1150 {
1151  Nmsg__Base__DnsQR *dnsqr = (Nmsg__Base__DnsQR *) nmsg_message_get_payload(msg);
1152  nmsg_res res;
1153  struct nmsg_ipdg dg;
1154 
1155  res = nmsg_res_failure;
1156  if (dnsqr == NULL || val_idx != 0 || dnsqr->n_query_packet != 1)
1157  return (nmsg_res_failure);
1158 
1159  if (dnsqr->query_ip.data != NULL) {
1160  if (dnsqr->query_ip.len == 4)
1161  res = nmsg_ipdg_parse(&dg, ETHERTYPE_IP,
1162  dnsqr->query_packet[0].len,
1163  dnsqr->query_packet[0].data);
1164  else if (dnsqr->query_ip.len == 16)
1165  res = nmsg_ipdg_parse(&dg, ETHERTYPE_IPV6,
1166  dnsqr->query_packet[0].len,
1167  dnsqr->query_packet[0].data);
1168  }
1169 
1170  if (res != nmsg_res_success)
1171  return (nmsg_res_failure);
1172 
1173  *data = (void *) dg.payload;
1174  if (len)
1175  *len = dg.len_payload;
1176 
1177  return (nmsg_res_success);
1178 }
1179 
1180 static nmsg_res
1181 dnsqr_get_response(nmsg_message_t msg,
1182  struct nmsg_msgmod_field *field,
1183  unsigned val_idx,
1184  void **data,
1185  size_t *len,
1186  void *msg_clos)
1187 {
1188  Nmsg__Base__DnsQR *dnsqr = (Nmsg__Base__DnsQR *) nmsg_message_get_payload(msg);
1189  uint8_t *pkt;
1190  size_t pkt_len;
1191  nmsg_res res;
1192  struct nmsg_ipdg dg;
1193 
1194  res = nmsg_res_failure;
1195  if (dnsqr == NULL || val_idx != 0 || dnsqr->n_response_packet < 1)
1196  return (nmsg_res_failure);
1197 
1198  if (dnsqr->response_ip.data == NULL)
1199  return (nmsg_res_failure);
1200 
1201  if (dnsqr->n_response_packet > 1) {
1202  /* response is fragmented */
1203  enum reasm_proto proto;
1204  union reasm_id id;
1205  unsigned hash = 0;
1206  bool last_frag = 0;
1207  size_t n;
1208  struct timespec ts;
1209  struct reasm_frag_entry *frag, *list_head;
1210  struct reasm_ip_entry *entry;
1211 
1212  list_head = my_calloc(1, sizeof(*list_head));
1213  entry = my_calloc(1, sizeof(*entry));
1214 
1215  entry->frags = list_head;
1216  entry->holes = 1;
1217 
1218  for (n = 0; n < dnsqr->n_response_packet; n++) {
1219  ts.tv_sec = dnsqr->response_time_sec[n];
1220  ts.tv_nsec = dnsqr->response_time_nsec[n];
1221 
1222  frag = reasm_parse_packet(dnsqr->response_packet[n].data,
1223  dnsqr->response_packet[n].len,
1224  &ts, &proto, &id, &hash, &last_frag);
1225  entry->protocol = proto;
1226  if (frag == NULL ||
1227  reasm_add_fragment(entry, frag, last_frag) == false)
1228  {
1229  reasm_free_entry(entry);
1230  return (nmsg_res_memfail);
1231  }
1232  }
1233  if (reasm_is_complete(entry)) {
1234  pkt_len = NMSG_IPSZ_MAX;
1235  pkt = my_malloc(NMSG_IPSZ_MAX);
1236  res = nmsg_message_add_allocation(msg, pkt);
1237  if (res != nmsg_res_success) {
1238  free(pkt);
1239  reasm_free_entry(entry);
1240  return (nmsg_res_memfail);
1241  }
1242 
1243  reasm_assemble(entry, pkt, &pkt_len);
1244  if (pkt_len == 0) {
1245  free(pkt);
1246  reasm_free_entry(entry);
1247  return (nmsg_res_failure);
1248  }
1249 
1250  if (proto == PROTO_IPV4) {
1251  res = nmsg_ipdg_parse(&dg, ETHERTYPE_IP, pkt_len, pkt);
1252  } else if (proto == PROTO_IPV6) {
1253  res = nmsg_ipdg_parse(&dg, ETHERTYPE_IPV6, pkt_len, pkt);
1254  } else {
1255  assert(0);
1256  }
1257 
1258  reasm_free_entry(entry);
1259  } else {
1260  reasm_free_entry(entry);
1261  return (nmsg_res_failure);
1262  }
1263 
1264  } else {
1265  pkt = dnsqr->response_packet[0].data;
1266  pkt_len = dnsqr->response_packet[0].len;
1267  if (dnsqr->response_ip.len == 4)
1268  res = nmsg_ipdg_parse(&dg, ETHERTYPE_IP, pkt_len, pkt);
1269  else if (dnsqr->response_ip.len == 16)
1270  res = nmsg_ipdg_parse(&dg, ETHERTYPE_IPV6, pkt_len, pkt);
1271  }
1272 
1273  if (res != nmsg_res_success)
1274  return (nmsg_res_failure);
1275 
1276  *data = (void *) dg.payload;
1277  if (len)
1278  *len = dg.len_payload;
1279 
1280  return (nmsg_res_success);
1281 }
1282 
1283 static bool
1284 dnsqr_eq6(Nmsg__Base__DnsQR *d1, Nmsg__Base__DnsQR *d2) {
1285  if (d1->id == d2->id &&
1286  d1->query_port == d2->query_port &&
1287  d1->response_port == d2->response_port &&
1288  d1->proto == d2->proto &&
1289  d1->query_ip.len == d2->query_ip.len &&
1290  d1->response_ip.len == d2->response_ip.len)
1291  {
1292  if (memcmp(d1->query_ip.data, d2->query_ip.data, d1->query_ip.len) == 0 &&
1293  memcmp(d1->response_ip.data, d2->response_ip.data, d1->response_ip.len) == 0)
1294  {
1295  return (true);
1296  }
1297  }
1298 
1299  return (false);
1300 }
1301 
1302 static bool
1303 dnsqr_eq9(Nmsg__Base__DnsQR *d1, Nmsg__Base__DnsQR *d2) {
1304  if (d1->id == d2->id &&
1305  d1->query_port == d2->query_port &&
1306  d1->response_port == d2->response_port &&
1307  d1->qname.len == d2->qname.len &&
1308  d1->qtype == d2->qtype &&
1309  d1->qclass == d2->qclass &&
1310  d1->proto == d2->proto &&
1311  d1->query_ip.len == d2->query_ip.len &&
1312  d1->response_ip.len == d2->response_ip.len)
1313  {
1314  if (memcmp(d1->query_ip.data, d2->query_ip.data, d1->query_ip.len) == 0 &&
1315  memcmp(d1->response_ip.data, d2->response_ip.data, d1->response_ip.len) == 0 &&
1316  memcmp(d1->qname.data, d2->qname.data, d1->qname.len) == 0)
1317  {
1318  return (true);
1319  }
1320  }
1321 
1322  return (false);
1323 }
1324 
1325 static bool
1326 dnsqr_eq(Nmsg__Base__DnsQR *d1, Nmsg__Base__DnsQR *d2, uint16_t rcode) {
1327  if (d1->qname.data != NULL && d2->qname.data != NULL) {
1328  return (dnsqr_eq9(d1, d2));
1329  } else {
1330  switch (rcode) {
1331  case WDNS_R_FORMERR:
1332  case WDNS_R_SERVFAIL:
1333  case WDNS_R_NOTIMP:
1334  case WDNS_R_REFUSED:
1335  return (dnsqr_eq6(d1, d2));
1336  }
1337  }
1338  return (false);
1339 }
1340 
1341 static uint32_t
1342 dnsqr_hash(Nmsg__Base__DnsQR *dnsqr) {
1343  dnsqr_key_t key;
1344  dnsqr_key6_t key6;
1345  size_t len;
1346  void *k;
1347  uint32_t hash;
1348 
1349  assert(dnsqr->query_ip.len == 4 || dnsqr->query_ip.len == 16);
1350  assert(dnsqr->response_ip.len == 4 || dnsqr->response_ip.len == 16);
1351 
1352  if (dnsqr->query_ip.len == 4) {
1353  memcpy(&key.query_ip, dnsqr->query_ip.data, 4);
1354  memcpy(&key.response_ip, dnsqr->response_ip.data, 4);
1355  key.proto = dnsqr->proto;
1356  key.query_port = dnsqr->query_port;
1357  key.response_port = dnsqr->response_port;
1358  key.id = dnsqr->id;
1359  k = &key;
1360  len = sizeof(key);
1361  } else if (dnsqr->query_ip.len == 16) {
1362  memcpy(&key6.query_ip6, dnsqr->query_ip.data, 16);
1363  memcpy(&key6.response_ip6, dnsqr->response_ip.data, 16);
1364  key6.proto = dnsqr->proto;
1365  key6.query_port = dnsqr->query_port;
1366  key6.response_port = dnsqr->response_port;
1367  key6.id = dnsqr->id;
1368  k = &key6;
1369  len = sizeof(key6);
1370  } else {
1371  assert(0);
1372  }
1373 
1374  hash = my_hashlittle(k, len, 0);
1375  return (hash);
1376 }
1377 
1378 static void
1379 dnsqr_insert_query(dnsqr_ctx_t *ctx, Nmsg__Base__DnsQR *dnsqr) {
1380  list_entry_t *le;
1381  uint32_t hash;
1382  unsigned slot, slot_stop;
1383 
1384  hash = dnsqr_hash(dnsqr);
1385  slot = hash % ctx->num_slots;
1386 
1387  if (slot > 0)
1388  slot_stop = slot - 1;
1389  else
1390  slot_stop = ctx->num_slots - 1;
1391 
1392  /* lock hash table */
1393  pthread_mutex_lock(&ctx->lock);
1394 
1395  for (;;) {
1396  hash_entry_t *he = &ctx->table[slot];
1397 
1398  /* empty slot, insert entry */
1399  if (he->dnsqr == NULL) {
1400  ctx->count += 1;
1401  he->dnsqr = dnsqr;
1402 
1403  le = my_calloc(1, sizeof(*le));
1404  le->he = he;
1405  he->le = le;
1406  ISC_LINK_INIT(le, link);
1407  ISC_LIST_APPEND(ctx->list, le, link);
1408  break;
1409  }
1410 
1411  /* slot filled */
1412  assert(slot != slot_stop);
1413  slot += 1;
1414  if (slot >= ctx->num_slots)
1415  slot = 0;
1416  }
1417 
1418  /* unlock hash table */
1419  pthread_mutex_unlock(&ctx->lock);
1420 }
1421 
1422 static void
1423 dnsqr_remove(dnsqr_ctx_t *ctx, hash_entry_t *he) {
1424  unsigned slot;
1425  unsigned i, j, k;
1426 
1427  i = j = slot = (he - ctx->table);
1428 
1429  assert(he->dnsqr != NULL);
1430  he->dnsqr = NULL;
1431  ctx->count -= 1;
1432  ISC_LIST_UNLINK(ctx->list, he->le, link);
1433  free(he->le);
1434  he->le = NULL;
1435 
1436  for (;;) {
1437  /* j is the current slot of the next value */
1438  j = (j + 1) % ctx->num_slots;
1439  if (ctx->table[j].dnsqr == NULL) {
1440  /* slot is unoccupied */
1441  break;
1442  }
1443 
1444  /* k is the natural slot of the value at slot j */
1445  k = dnsqr_hash(ctx->table[j].dnsqr) % ctx->num_slots;
1446  if ((j > i && (k <= i || k > j)) ||
1447  (j < i && (k <= i && k > j)))
1448  {
1449  /* this value needs to be moved up,
1450  * as k is cyclically between i and j */
1451  memcpy(&ctx->table[i], &ctx->table[j], sizeof(hash_entry_t));
1452 
1453  /* delete the value at the old slot */
1454  memset(&ctx->table[j], 0, sizeof(hash_entry_t));
1455 
1456  /* fix up the list pointer */
1457  ctx->table[i].le->he = &ctx->table[i];
1458 
1459  /* check the next slot */
1460  i = j;
1461  }
1462  }
1463 }
1464 
1465 static Nmsg__Base__DnsQR *
1466 dnsqr_trim(dnsqr_ctx_t *ctx) {
1467  Nmsg__Base__DnsQR *dnsqr = NULL;
1468  list_entry_t *le;
1469  hash_entry_t *he;
1470  struct timespec timeout;
1471 
1472  /* lock hash table */
1473  pthread_mutex_lock(&ctx->lock);
1474 
1475  le = ISC_LIST_HEAD(ctx->list);
1476 
1477  if (le != NULL) {
1478  assert(le->he != NULL);
1479  he = le->he;
1480  assert(he->dnsqr != NULL);
1481  assert(he->dnsqr->n_query_time_sec > 0);
1482  assert(he->dnsqr->n_query_time_nsec > 0);
1483  if (ctx->count > ctx->max_values ||
1484  ctx->stop == true ||
1485  ctx->now.tv_sec - he->dnsqr->query_time_sec[0] > ctx->query_timeout)
1486  {
1487  dnsqr = he->dnsqr;
1488  dnsqr_remove(ctx, he);
1489 
1490  timeout.tv_sec = ctx->now.tv_sec - dnsqr->query_time_sec[0];
1491  timeout.tv_nsec = ctx->now.tv_nsec - dnsqr->query_time_nsec[0];
1492  if (timeout.tv_nsec < 0) {
1493  timeout.tv_sec -= 1;
1494  timeout.tv_nsec += 1000000000;
1495  }
1496  dnsqr->timeout = timeout.tv_sec + (((double) timeout.tv_nsec) / 1E9);
1497  dnsqr->has_timeout = true;
1498 
1499 #ifdef DEBUG
1500  ctx->count_unanswered_query += 1;
1501 #endif
1502  }
1503  }
1504 
1505  /* unlock hash table */
1506  pthread_mutex_unlock(&ctx->lock);
1507 
1508  return (dnsqr);
1509 }
1510 
1511 static Nmsg__Base__DnsQR *
1512 dnsqr_retrieve(dnsqr_ctx_t *ctx, Nmsg__Base__DnsQR *dnsqr, uint16_t rcode) {
1513  Nmsg__Base__DnsQR *query = NULL;
1514  uint32_t hash;
1515  unsigned slot, slot_stop;
1516 
1517  hash = dnsqr_hash(dnsqr);
1518  slot = hash % ctx->num_slots;
1519 
1520  if (slot > 0)
1521  slot_stop = slot - 1;
1522  else
1523  slot_stop = ctx->num_slots - 1;
1524 
1525  /* lock hash table */
1526  pthread_mutex_lock(&ctx->lock);
1527 
1528  for (;;) {
1529  hash_entry_t *he = &ctx->table[slot];
1530 
1531  /* empty slot, return failure */
1532  if (he->dnsqr == NULL) {
1533  query = NULL;
1534  goto out;
1535  }
1536 
1537  /* slot filled, compare */
1538  if (dnsqr_eq(dnsqr, he->dnsqr, rcode) == true) {
1539  query = he->dnsqr;
1540  dnsqr_remove(ctx, he);
1541  goto out;
1542  }
1543 
1544  /* slot filled, but not our slot */
1545  assert(slot != slot_stop);
1546  slot += 1;
1547  if (slot >= ctx->num_slots)
1548  slot = 0;
1549  }
1550 
1551 out:
1552  /* unlock hash table */
1553  pthread_mutex_unlock(&ctx->lock);
1554 
1555  return (query);
1556 }
1557 
1558 static nmsg_message_t
1559 dnsqr_to_message(dnsqr_ctx_t *ctx, Nmsg__Base__DnsQR *dnsqr) {
1560  ProtobufCBufferSimple sbuf;
1561  nmsg_message_t m;
1562  size_t buf_sz;
1563  struct timespec ts;
1564 
1565  if (dnsqr->n_response_packet > 0) {
1566  dnsqr->udp_checksum = dnsqr_checksum_verify(dnsqr);
1567  dnsqr->has_udp_checksum = true;
1568  }
1569 
1570  if (ctx->zero_resolver_address)
1571  dnsqr_zero_resolver_address(dnsqr);
1572 
1573  sbuf.base.append = protobuf_c_buffer_simple_append;
1574  sbuf.len = 0;
1575  sbuf.data = my_malloc(1024);
1576  sbuf.must_free_data = 1;
1577  sbuf.alloced = 1024;
1578 
1579  buf_sz = protobuf_c_message_pack_to_buffer((ProtobufCMessage *) dnsqr,
1580  (ProtobufCBuffer *) &sbuf);
1581  if (sbuf.data == NULL)
1582  return (NULL);
1583 
1584  m = nmsg_message_from_raw_payload(NMSG_VENDOR_BASE_ID,
1585  NMSG_VENDOR_BASE_DNSQR_ID,
1586  sbuf.data, buf_sz, NULL);
1587  assert(m != NULL);
1588 
1589  if (dnsqr->n_query_time_sec > 0) {
1590  ts.tv_sec = dnsqr->query_time_sec[0];
1591  ts.tv_nsec = dnsqr->query_time_nsec[0];
1592  nmsg_message_set_time(m, &ts);
1593  } else if (dnsqr->n_response_time_sec > 0) {
1594  ts.tv_sec = dnsqr->response_time_sec[0];
1595  ts.tv_nsec = dnsqr->response_time_nsec[0];
1596  nmsg_message_set_time(m, &ts);
1597  }
1598 
1599  return (m);
1600 }
1601 
1602 static nmsg_res
1603 do_packet_dns(Nmsg__Base__DnsQR *dnsqr, struct nmsg_ipdg *dg, uint16_t *flags) {
1604  const uint8_t *p;
1605  size_t len;
1606  uint16_t qdcount;
1607  uint16_t qtype;
1608  uint16_t qclass;
1609 
1610  p = dg->payload;
1611  len = dg->len_payload;
1612 
1613  if (len < 12)
1614  return (nmsg_res_again);
1615 
1616  load_net16(p, &dnsqr->id);
1617  load_net16(p + 2, flags);
1618  load_net16(p + 4, &qdcount);
1619 
1620  p += 12;
1621  len -= 12;
1622 
1623  if (qdcount == 1 && len > 0) {
1624  dnsqr->qname.len = wdns_skip_name(&p, p + len);
1625  dnsqr->qname.data = my_malloc(dnsqr->qname.len);
1626  len -= dnsqr->qname.len;
1627  p = dg->payload + 12;
1628 
1629  if (len < 4)
1630  return (nmsg_res_again);
1631 
1632  memcpy(dnsqr->qname.data, p, dnsqr->qname.len);
1633  dnsqr->has_qname = true;
1634  p += dnsqr->qname.len;
1635 
1636  memcpy(&qtype, p, 2);
1637  p += 2;
1638  memcpy(&qclass, p, 2);
1639  p += 2;
1640 
1641  dnsqr->qtype = ntohs(qtype);
1642  dnsqr->has_qtype = true;
1643  dnsqr->qclass = ntohs(qclass);
1644  dnsqr->has_qclass = true;
1645  }
1646 
1647  return (nmsg_res_success);
1648 }
1649 
1650 static nmsg_res
1651 do_packet_udp(Nmsg__Base__DnsQR *dnsqr, struct nmsg_ipdg *dg, uint16_t *flags) {
1652  const struct nmsg_udphdr *udp;
1653  nmsg_res res;
1654  uint16_t src_port;
1655  uint16_t dst_port;
1656 
1657  udp = (const struct nmsg_udphdr *) dg->transport;
1658  if (udp == NULL)
1659  return (nmsg_res_again);
1660  src_port = ntohs(udp->uh_sport);
1661  dst_port = ntohs(udp->uh_dport);
1662 
1663  if (!(src_port == 53 || src_port == 5353 || dst_port == 53 || dst_port == 5353))
1664  return (nmsg_res_again);
1665 
1666  res = do_packet_dns(dnsqr, dg, flags);
1667  if (res != nmsg_res_success)
1668  return (res);
1669 
1670  if (DNS_FLAG_QR(*flags) == false) {
1671  /* message is a query */
1672  dnsqr->query_port = src_port;
1673  dnsqr->response_port = dst_port;
1674  } else {
1675  /* message is a response */
1676  dnsqr->query_port = dst_port;
1677  dnsqr->response_port = src_port;
1678  }
1679 
1680  return (nmsg_res_success);
1681 }
1682 
1683 static nmsg_res
1684 do_packet_tcp(Nmsg__Base__DnsQR *dnsqr, struct nmsg_ipdg *dg, uint16_t *flags) {
1685  const struct nmsg_tcphdr *tcp;
1686  uint16_t src_port;
1687  uint16_t dst_port;
1688 
1689  tcp = (const struct nmsg_tcphdr *) dg->transport;
1690  if (tcp == NULL)
1691  return (nmsg_res_again);
1692  src_port = ntohs(tcp->th_sport);
1693  dst_port = ntohs(tcp->th_dport);
1694 
1695  if (!(src_port == 53 || dst_port == 53))
1696  return (nmsg_res_again);
1697 
1698  dnsqr->tcp.data = my_malloc(dg->len_network);
1699  memcpy(dnsqr->tcp.data, dg->network, dg->len_network);
1700  dnsqr->tcp.len = dg->len_network;
1701  dnsqr->has_tcp = true;
1702 
1703  dnsqr->type = NMSG__BASE__DNS_QRTYPE__TCP;
1704 
1705  return (nmsg_res_success);
1706 }
1707 
1708 static nmsg_res
1709 do_packet_icmp(Nmsg__Base__DnsQR *dnsqr, struct nmsg_ipdg *dg, uint16_t *flags) {
1710  struct nmsg_ipdg icmp_dg;
1711  nmsg_res res;
1712  uint16_t src_port;
1713  uint16_t dst_port;
1714 
1715  res = nmsg_ipdg_parse_pcap_raw(&icmp_dg, DLT_RAW, dg->payload, dg->len_payload);
1716  if (res != nmsg_res_success)
1717  return (res);
1718  if (icmp_dg.transport == NULL)
1719  return (nmsg_res_again);
1720  if (icmp_dg.proto_transport == IPPROTO_UDP) {
1721  const struct nmsg_udphdr *udp;
1722 
1723  udp = (const struct nmsg_udphdr *) icmp_dg.transport;
1724  src_port = ntohs(udp->uh_sport);
1725  dst_port = ntohs(udp->uh_dport);
1726 
1727  if (!(src_port == 53 || src_port == 5353 || dst_port == 53 || dst_port == 5353))
1728  return (nmsg_res_again);
1729  } else if (icmp_dg.proto_transport == IPPROTO_TCP) {
1730  const struct nmsg_tcphdr *tcp;
1731 
1732  tcp = (const struct nmsg_tcphdr *) icmp_dg.transport;
1733  src_port = ntohs(tcp->th_sport);
1734  dst_port = ntohs(tcp->th_dport);
1735 
1736  if (!(src_port == 53 || dst_port == 53))
1737  return (nmsg_res_again);
1738  } else {
1739  return (nmsg_res_again);
1740  }
1741 
1742  dnsqr->icmp.data = my_malloc(dg->len_network);
1743  memcpy(dnsqr->icmp.data, dg->network, dg->len_network);
1744  dnsqr->icmp.len = dg->len_network;
1745  dnsqr->has_icmp = true;
1746 
1747  dnsqr->type = NMSG__BASE__DNS_QRTYPE__ICMP;
1748 
1749  return (nmsg_res_success);
1750 }
1751 
1752 static nmsg_res
1753 do_packet_v4(Nmsg__Base__DnsQR *dnsqr, struct nmsg_ipdg *dg, uint16_t *flags) {
1754  const struct nmsg_iphdr *ip;
1755  nmsg_res res;
1756 
1757  switch (dg->proto_transport) {
1758  case IPPROTO_UDP:
1759  res = do_packet_udp(dnsqr, dg, flags);
1760  break;
1761  case IPPROTO_TCP:
1762  return (do_packet_tcp(dnsqr, dg, flags));
1763  case IPPROTO_ICMP:
1764  return (do_packet_icmp(dnsqr, dg, flags));
1765  default:
1766  res = nmsg_res_again;
1767  break;
1768  }
1769 
1770  if (res != nmsg_res_success)
1771  return (res);
1772 
1773  /* allocate query_ip */
1774  dnsqr->query_ip.len = 4;
1775  dnsqr->query_ip.data = my_malloc(4);
1776 
1777  /* allocate response_ip */
1778  dnsqr->response_ip.len = 4;
1779  dnsqr->response_ip.data = my_malloc(4);
1780 
1781  ip = (const struct nmsg_iphdr *) dg->network;
1782 
1783  if (DNS_FLAG_QR(*flags) == false) {
1784  /* message is a query */
1785  memcpy(dnsqr->query_ip.data, &ip->ip_src, 4);
1786  memcpy(dnsqr->response_ip.data, &ip->ip_dst, 4);
1787  } else {
1788  /* message is a response */
1789  memcpy(dnsqr->query_ip.data, &ip->ip_dst, 4);
1790  memcpy(dnsqr->response_ip.data, &ip->ip_src, 4);
1791  }
1792 
1793  return (nmsg_res_success);
1794 }
1795 
1796 static nmsg_res
1797 do_packet_v6(Nmsg__Base__DnsQR *dnsqr, struct nmsg_ipdg *dg, uint16_t *flags) {
1798  const struct ip6_hdr *ip6;
1799  nmsg_res res;
1800 
1801  switch (dg->proto_transport) {
1802  case IPPROTO_UDP:
1803  res = do_packet_udp(dnsqr, dg, flags);
1804  break;
1805  case IPPROTO_TCP:
1806  return (do_packet_tcp(dnsqr, dg, flags));
1807  case IPPROTO_ICMP:
1808  return (do_packet_icmp(dnsqr, dg, flags));
1809  default:
1810  res = nmsg_res_again;
1811  break;
1812  }
1813 
1814  if (res != nmsg_res_success)
1815  return (res);
1816 
1817  /* allocate query_ip */
1818  dnsqr->query_ip.len = 16;
1819  dnsqr->query_ip.data = my_malloc(16);
1820 
1821  /* allocate response_ip */
1822  dnsqr->response_ip.len = 16;
1823  dnsqr->response_ip.data = my_malloc(16);
1824 
1825  ip6 = (const struct ip6_hdr *) dg->network;
1826 
1827  if (DNS_FLAG_QR(*flags) == false) {
1828  /* message is a query */
1829  memcpy(dnsqr->query_ip.data, &ip6->ip6_src, 16);
1830  memcpy(dnsqr->response_ip.data, &ip6->ip6_dst, 16);
1831  } else {
1832  /* message is a response */
1833  memcpy(dnsqr->query_ip.data, &ip6->ip6_dst, 16);
1834  memcpy(dnsqr->response_ip.data, &ip6->ip6_src, 16);
1835  }
1836 
1837  return (nmsg_res_success);
1838 }
1839 
1840 static bool
1841 get_query_flags(Nmsg__Base__DnsQR *dnsqr, uint16_t *flags) {
1842  nmsg_res res;
1843  struct nmsg_ipdg dg;
1844 
1845  if (dnsqr->query_ip.data != NULL && dnsqr->n_query_packet > 0) {
1846  if (dnsqr->query_ip.len == 4) {
1847  res = nmsg_ipdg_parse(&dg, ETHERTYPE_IP,
1848  dnsqr->query_packet[0].len,
1849  dnsqr->query_packet[0].data);
1850  if (res != nmsg_res_success)
1851  return (false);
1852  } else if (dnsqr->query_ip.len == 16) {
1853  res = nmsg_ipdg_parse(&dg, ETHERTYPE_IPV6,
1854  dnsqr->query_packet[0].len,
1855  dnsqr->query_packet[0].data);
1856  if (res != nmsg_res_success)
1857  return (false);
1858  } else {
1859  return (false);
1860  }
1861  } else {
1862  return (false);
1863  }
1864 
1865  if (dg.len_payload >= 12) {
1866  memcpy(flags, dg.payload + 2, sizeof(*flags));
1867  *flags = htons(*flags);
1868  return (true);
1869  }
1870 
1871  return (false);
1872 }
1873 
1874 static void
1875 dnsqr_merge(Nmsg__Base__DnsQR *d1, Nmsg__Base__DnsQR *d2) {
1876  assert(d2->n_query_packet == 0 &&
1877  d2->n_query_time_sec == 0 &&
1878  d2->n_query_time_nsec == 0 &&
1879  d2->query_packet == NULL &&
1880  d2->query_time_sec == NULL &&
1881  d2->query_time_nsec == NULL);
1882 
1883  d2->n_query_packet = d1->n_query_packet;
1884  d2->n_query_time_sec = d1->n_query_time_sec;
1885  d2->n_query_time_nsec = d1->n_query_time_nsec;
1886  d2->query_packet = d1->query_packet;
1887  d2->query_time_sec = d1->query_time_sec;
1888  d2->query_time_nsec = d1->query_time_nsec;
1889 
1890  d1->n_query_packet = 0;
1891  d1->n_query_time_sec = 0;
1892  d1->n_query_time_nsec = 0;
1893  d1->query_packet = NULL;
1894  d1->query_time_sec = NULL;
1895  d1->query_time_nsec = NULL;
1896 
1897  if (d2->has_qname == false && d1->has_qname == true) {
1898  memcpy(&d2->qname, &d1->qname, sizeof(ProtobufCBinaryData));
1899  memset(&d1->qname, 0, sizeof(ProtobufCBinaryData));
1900  d2->has_qname = true;
1901  }
1902  if (d2->has_qtype == false && d1->has_qtype == true) {
1903  d2->qtype = d1->qtype;
1904  d2->has_qtype = true;
1905  }
1906  if (d2->has_qclass == false && d1->has_qclass == true) {
1907  d2->qclass = d1->qclass;
1908  d2->has_qclass = true;
1909  }
1910 
1911  nmsg__base__dns_qr__free_unpacked(d1, NULL);
1912 }
1913 
1914 #define extend_field_array(x, n) do { \
1915  (x) = realloc((x), (n) * sizeof(*(x))); \
1916  assert((x) != NULL); \
1917 } while (0)
1918 
1919 static nmsg_res
1920 dnsqr_append_query_packet(Nmsg__Base__DnsQR *dnsqr,
1921  const uint8_t *pkt, size_t pkt_len,
1922  const struct timespec *ts)
1923 {
1924  size_t n, idx;
1925  uint8_t *pkt_copy;
1926 
1927  n = idx = dnsqr->n_query_packet;
1928  n += 1;
1929 
1930  extend_field_array(dnsqr->query_packet, n);
1931  extend_field_array(dnsqr->query_time_sec, n);
1932  extend_field_array(dnsqr->query_time_nsec, n);
1933 
1934  pkt_copy = my_malloc(pkt_len);
1935  memcpy(pkt_copy, pkt, pkt_len);
1936 
1937  dnsqr->n_query_packet += 1;
1938  dnsqr->n_query_time_sec += 1;
1939  dnsqr->n_query_time_nsec += 1;
1940 
1941  dnsqr->query_packet[idx].len = pkt_len;
1942  dnsqr->query_packet[idx].data = pkt_copy;
1943  dnsqr->query_time_sec[idx] = ts->tv_sec;
1944  dnsqr->query_time_nsec[idx] = ts->tv_nsec;
1945 
1946  return (nmsg_res_success);
1947 }
1948 
1949 static nmsg_res
1950 dnsqr_append_response_packet(Nmsg__Base__DnsQR *dnsqr,
1951  const uint8_t *pkt, size_t pkt_len,
1952  const struct timespec *ts)
1953 {
1954  size_t n, idx;
1955  uint8_t *pkt_copy;
1956 
1957  n = idx = dnsqr->n_response_packet;
1958  n += 1;
1959 
1960  extend_field_array(dnsqr->response_packet, n);
1961  extend_field_array(dnsqr->response_time_sec, n);
1962  extend_field_array(dnsqr->response_time_nsec, n);
1963 
1964  pkt_copy = my_malloc(pkt_len);
1965  memcpy(pkt_copy, pkt, pkt_len);
1966 
1967  dnsqr->n_response_packet += 1;
1968  dnsqr->n_response_time_sec += 1;
1969  dnsqr->n_response_time_nsec += 1;
1970 
1971  dnsqr->response_packet[idx].len = pkt_len;
1972  dnsqr->response_packet[idx].data = pkt_copy;
1973  dnsqr->response_time_sec[idx] = ts->tv_sec;
1974  dnsqr->response_time_nsec[idx] = ts->tv_nsec;
1975 
1976  return (nmsg_res_success);
1977 }
1978 
1979 static nmsg_res
1980 dnsqr_append_frag(dnsqr_append_fp func,
1981  Nmsg__Base__DnsQR *dnsqr,
1982  struct reasm_ip_entry *entry)
1983 {
1984  nmsg_res res;
1985  struct reasm_frag_entry *frag = entry->frags->next;
1986 
1987  while (frag != NULL) {
1988  res = func(dnsqr, frag->data, frag->len + frag->data_offset, &frag->ts);
1989  if (res != nmsg_res_success)
1990  return (res);
1991  frag = frag->next;
1992  }
1993  return (nmsg_res_success);
1994 }
1995 
1996 static void
1997 dnsqr_print_stats(dnsqr_ctx_t *ctx) {
1998 #ifdef DEBUG
1999  fprintf(stderr, "%s: c= %u qr= %u uq= %u ur= %u p= %u\n", __func__,
2000  ctx->count,
2001  ctx->count_query_response,
2002  ctx->count_unanswered_query,
2003  ctx->count_unsolicited_response,
2004  ctx->count_packet);
2005  ctx->count_query_response = 0;
2006  ctx->count_unanswered_query = 0;
2007  ctx->count_unsolicited_response = 0;
2008 #endif
2009 }
2010 
2011 static bool
2012 do_filter_query_rd(dnsqr_ctx_t *ctx, Nmsg__Base__DnsQR *dnsqr) {
2013  if (ctx->capture_rd == 0 || ctx->capture_rd == 1) {
2014  uint16_t qflags;
2015  if (get_query_flags(dnsqr, &qflags))
2016  if (DNS_FLAG_RD(qflags) != ctx->capture_rd)
2017  return (true);
2018  }
2019  return (false);
2020 }
2021 
2022 static bool
2023 do_filter_rd(dnsqr_ctx_t *ctx, uint16_t flags) {
2024  if (ctx->capture_rd == 0 || ctx->capture_rd == 1) {
2025  if (DNS_FLAG_RD(flags) != ctx->capture_rd)
2026  return (true);
2027  }
2028  return (false);
2029 }
2030 
2031 static bool
2032 do_filter_query_name(dnsqr_ctx_t *ctx, Nmsg__Base__DnsQR *dnsqr) {
2033  wdns_name_t name;
2034  wdns_res res;
2035 
2036  if (dnsqr->has_qname == false)
2037  return (false);
2038 
2039  if (ctx->filter_qnames_include != NULL) {
2040  name.len = dnsqr->qname.len;
2041  name.data = alloca(name.len);
2042  assert(name.data != NULL);
2043  memcpy(name.data, dnsqr->qname.data, name.len);
2044  wdns_downcase_name(&name);
2045 
2046  for (;;) {
2047  if (dnsqr_filter_lookup(ctx->filter_qnames_include,
2048  ctx->filter_qnames_include_slots,
2049  &name))
2050  {
2051  return (false);
2052  }
2053  if (name.len == 1)
2054  break;
2055  res = wdns_left_chop(&name, &name);
2056  if (res != wdns_res_success)
2057  break;
2058  }
2059  }
2060 
2061  if (ctx->filter_qnames_exclude != NULL) {
2062  name.len = dnsqr->qname.len;
2063  name.data = alloca(name.len);
2064  assert(name.data != NULL);
2065  memcpy(name.data, dnsqr->qname.data, name.len);
2066  wdns_downcase_name(&name);
2067 
2068  for (;;) {
2069  if (dnsqr_filter_lookup(ctx->filter_qnames_exclude,
2070  ctx->filter_qnames_exclude_slots,
2071  &name))
2072  {
2073  return (true);
2074  }
2075  if (name.len == 1)
2076  break;
2077  res = wdns_left_chop(&name, &name);
2078  if (res != wdns_res_success)
2079  break;
2080  }
2081  }
2082 
2083  return (false);
2084 }
2085 
2086 static bool
2087 do_filter(dnsqr_ctx_t *ctx, Nmsg__Base__DnsQR *dnsqr) {
2088  return (do_filter_query_rd(ctx, dnsqr) ||
2089  do_filter_query_name(ctx, dnsqr));
2090 }
2091 
2092 static nmsg_res
2093 do_packet(dnsqr_ctx_t *ctx, nmsg_pcap_t pcap, nmsg_message_t *m,
2094  const uint8_t *pkt, const struct pcap_pkthdr *pkt_hdr,
2095  const struct timespec *ts)
2096 {
2097  Nmsg__Base__DnsQR *dnsqr = NULL;
2098  bool is_frag;
2099  nmsg_res res;
2100  struct nmsg_ipdg dg;
2101  struct reasm_ip_entry *reasm_entry = NULL;
2102  uint16_t flags;
2103  uint8_t *new_pkt = NULL;
2104  size_t new_pkt_len;
2105 
2106  /* only operate on complete packets */
2107  if (pkt_hdr->caplen != pkt_hdr->len)
2108  return (nmsg_res_again);
2109 
2110  res = nmsg_ipdg_parse_pcap_raw(&dg, nmsg_pcap_get_datalink(pcap), pkt, pkt_hdr->caplen);
2111  if (res != nmsg_res_success)
2112  return (res);
2113 
2114  pthread_mutex_lock(&ctx->lock);
2115  ctx->now.tv_sec = ts->tv_sec;
2116  ctx->now.tv_nsec = ts->tv_nsec;
2117 #ifdef DEBUG
2118  ctx->count_packet += 1;
2119  if ((ctx->count_packet % 100000) == 0)
2120  dnsqr_print_stats(ctx);
2121 #endif
2122  is_frag = reasm_ip_next(ctx->reasm, dg.network, dg.len_network, ts, &reasm_entry);
2123  pthread_mutex_unlock(&ctx->lock);
2124 
2125  if (is_frag) {
2126  if (reasm_entry != NULL) {
2127  new_pkt_len = NMSG_IPSZ_MAX;
2128  new_pkt = my_malloc(NMSG_IPSZ_MAX);
2129  reasm_assemble(reasm_entry, new_pkt, &new_pkt_len);
2130  res = nmsg_ipdg_parse_pcap_raw(&dg, DLT_RAW, new_pkt, new_pkt_len);
2131  if (res != nmsg_res_success)
2132  goto out;
2133  if (nmsg_pcap_filter(pcap, dg.network, dg.len_network) == false) {
2134  res = nmsg_res_again;
2135  goto out;
2136  }
2137  } else {
2138  return (nmsg_res_again);
2139  }
2140  }
2141 
2142  if (dg.transport == NULL)
2143  return (nmsg_res_again);
2144 
2145  dnsqr = my_calloc(1, sizeof(*dnsqr));
2146  nmsg__base__dns_qr__init(dnsqr);
2147 
2148  dnsqr->proto = dg.proto_transport;
2149 
2150  switch (dg.proto_network) {
2151  case PF_INET:
2152  res = do_packet_v4(dnsqr, &dg, &flags);
2153  break;
2154  case PF_INET6:
2155  /* refilter since nmsg_pcap_setfilter() results in a filter that
2156  * accepts all IPv6 packets */
2157  if (nmsg_pcap_filter(pcap, dg.network, dg.len_network) == false) {
2158  res = nmsg_res_again;
2159  goto out;
2160  }
2161  res = do_packet_v6(dnsqr, &dg, &flags);
2162  break;
2163  default:
2164  res = nmsg_res_again;
2165  break;
2166  }
2167 
2168  if (res != nmsg_res_success)
2169  goto out;
2170 
2171  if (dg.proto_transport == IPPROTO_UDP && ctx->capture_qr != -1) {
2172  /* udp query-response state reconstruction disabled */
2173 
2174  if (ctx->capture_qr == 0 && DNS_FLAG_QR(flags) == false) {
2175  /* udp query */
2176  dnsqr->type = NMSG__BASE__DNS_QRTYPE__UDP_QUERY_ONLY;
2177 
2178  res = dnsqr_append_query_packet(dnsqr, dg.network, dg.len_network, ts);
2179  if (res != nmsg_res_success)
2180  goto out;
2181 
2182  *m = dnsqr_to_message(ctx, dnsqr);
2183  res = nmsg_res_success;
2184  } else if (ctx->capture_qr == 1 && DNS_FLAG_QR(flags) == true) {
2185  /* udp response */
2186  dnsqr->type = NMSG__BASE__DNS_QRTYPE__UDP_RESPONSE_ONLY;
2187  dnsqr->rcode = DNS_FLAG_RCODE(flags);
2188  dnsqr->has_rcode = true;
2189 
2190  if (is_frag)
2191  res = dnsqr_append_frag(dnsqr_append_response_packet,
2192  dnsqr,
2193  reasm_entry);
2194  else
2195  res = dnsqr_append_response_packet(dnsqr,
2196  dg.network,
2197  dg.len_network,
2198  ts);
2199  if (res != nmsg_res_success)
2200  goto out;
2201 
2202  *m = dnsqr_to_message(ctx, dnsqr);
2203  res = nmsg_res_success;
2204  } else {
2205  res = nmsg_res_again;
2206  }
2207  } else if (dg.proto_transport == IPPROTO_UDP && DNS_FLAG_QR(flags) == false) {
2208  /* message is a query */
2209  dnsqr->type = NMSG__BASE__DNS_QRTYPE__UDP_UNANSWERED_QUERY;
2210  if (is_frag)
2211  res = dnsqr_append_frag(dnsqr_append_query_packet, dnsqr, reasm_entry);
2212  else
2213  res = dnsqr_append_query_packet(dnsqr, dg.network, dg.len_network, ts);
2214  if (res != nmsg_res_success)
2215  goto out;
2216  dnsqr_insert_query(ctx, dnsqr);
2217  dnsqr = NULL;
2218  res = nmsg_res_again;
2219  } else if (dg.proto_transport == IPPROTO_UDP) {
2220  /* message is a response */
2221  Nmsg__Base__DnsQR *query;
2222 
2223  dnsqr->rcode = DNS_FLAG_RCODE(flags);
2224  dnsqr->has_rcode = true;
2225 
2226  if (is_frag)
2227  res = dnsqr_append_frag(dnsqr_append_response_packet, dnsqr, reasm_entry);
2228  else
2229  res = dnsqr_append_response_packet(dnsqr, dg.network, dg.len_network, ts);
2230  if (res != nmsg_res_success)
2231  goto out;
2232 
2233  query = dnsqr_retrieve(ctx, dnsqr, DNS_FLAG_RCODE(flags));
2234  if (query == NULL) {
2235  /* no corresponding query, this is an unsolicited response */
2236 
2237  dnsqr->type = NMSG__BASE__DNS_QRTYPE__UDP_UNSOLICITED_RESPONSE;
2238 
2239  if (do_filter_rd(ctx, flags)) {
2240  res = nmsg_res_again;
2241  goto out;
2242  }
2243 
2244  *m = dnsqr_to_message(ctx, dnsqr);
2245  res = nmsg_res_success;
2246 #ifdef DEBUG
2247  pthread_mutex_lock(&ctx->lock);
2248  ctx->count_unsolicited_response += 1;
2249  pthread_mutex_unlock(&ctx->lock);
2250 #endif
2251  } else {
2252  /* corresponding query, merge query and response */
2253 
2254  dnsqr->type = NMSG__BASE__DNS_QRTYPE__UDP_QUERY_RESPONSE;
2255  dnsqr_merge(query, dnsqr);
2256 
2257  if (do_filter(ctx, dnsqr)) {
2258  res = nmsg_res_again;
2259  goto out;
2260  }
2261 
2262  *m = dnsqr_to_message(ctx, dnsqr);
2263  res = nmsg_res_success;
2264 #ifdef DEBUG
2265  pthread_mutex_lock(&ctx->lock);
2266  ctx->count_query_response += 1;
2267  pthread_mutex_unlock(&ctx->lock);
2268 #endif
2269  }
2270  } else if (dg.proto_transport == IPPROTO_TCP ||
2271  dg.proto_transport == IPPROTO_ICMP)
2272  {
2273  *m = dnsqr_to_message(ctx, dnsqr);
2274  nmsg_message_set_time(*m, ts);
2275  }
2276 
2277 out:
2278  if (dnsqr != NULL)
2279  nmsg__base__dns_qr__free_unpacked(dnsqr, NULL);
2280  if (new_pkt != NULL)
2281  free(new_pkt);
2282  if (reasm_entry != NULL)
2283  reasm_free_entry(reasm_entry);
2284  return (res);
2285 }
2286 
2287 static nmsg_res
2288 dnsqr_pkt_to_payload(void *clos, nmsg_pcap_t pcap, nmsg_message_t *m) {
2289  Nmsg__Base__DnsQR *dnsqr;
2290  dnsqr_ctx_t *ctx = (dnsqr_ctx_t *) clos;
2291  nmsg_res res;
2292  struct timespec ts;
2293  struct pcap_pkthdr *pkt_hdr;
2294  const uint8_t *pkt_data;
2295 
2296  dnsqr = dnsqr_trim(ctx);
2297  if (dnsqr != NULL) {
2298  if (do_filter(ctx, dnsqr)) {
2299  nmsg__base__dns_qr__free_unpacked(dnsqr, NULL);
2300  } else {
2301  *m = dnsqr_to_message(ctx, dnsqr);
2302  nmsg__base__dns_qr__free_unpacked(dnsqr, NULL);
2303  return (nmsg_res_success);
2304  }
2305  } else {
2306  bool stop;
2307 
2308  pthread_mutex_lock(&ctx->lock);
2309  stop = ctx->stop;
2310  pthread_mutex_unlock(&ctx->lock);
2311 
2312  if (stop == true)
2313  return (nmsg_res_eof);
2314  }
2315 
2316  res = nmsg_pcap_input_read_raw(pcap, &pkt_hdr, &pkt_data, &ts);
2317  if (res == nmsg_res_success) {
2318  return (do_packet(ctx, pcap, m, pkt_data, pkt_hdr, &ts));
2319  } else if (res == nmsg_res_eof) {
2320  pthread_mutex_lock(&ctx->lock);
2321  ctx->stop = true;
2322  pthread_mutex_unlock(&ctx->lock);
2323  return (nmsg_res_again);
2324  }
2325 
2326  return (res);
2327 }
Structure exported by message modules to implement a new message type.
bool nmsg_pcap_filter(nmsg_pcap_t pcap, const uint8_t *pkt, size_t len)
Return the result of filtering a packet.
Definition: pcap_input.c:351
nmsg_res
nmsg result code
Definition: res.h:25
success
Definition: res.h:26
int nmsg_pcap_get_datalink(nmsg_pcap_t pcap)
Get the datalink type of the underlying pcap handle.
Definition: pcap_input.c:346
Protobuf enum.
Definition: msgmod.h:75
nmsg_res nmsg_ipdg_parse_pcap_raw(struct nmsg_ipdg *dg, int datalink, const uint8_t *pkt, size_t len)
Like nmsg_ipdg_parse_pcap(), but performs no fragment handling.
Definition: ipdg.c:266
out of memory
Definition: res.h:29
caller should try again
Definition: res.h:35
Protobuf byte array.
Definition: msgmod.h:78
unsigned len_network
length starting from network
Definition: ipdg.h:37
int proto_transport
transport protocol
Definition: ipdg.h:36
Parsed IP datagram.
Definition: ipdg.h:34
Protobuf int32.
Definition: msgmod.h:111
Protobuf byte array.
Definition: msgmod.h:96
unsigned len_payload
length starting from payload
Definition: ipdg.h:39
#define NMSG_IPSZ_MAX
Maximize size of an IP datagram.
Definition: constants.h:102
nmsg_res nmsg_ipdg_parse(struct nmsg_ipdg *dg, unsigned etype, size_t len, const u_char *pkt)
Parse IP packets from the network layer, discarding fragments.
Definition: ipdg.c:33
Protobuf int64.
Definition: msgmod.h:114
Structure mapping protocol buffer schema fields to nmsg_msgmod_field_type values for "transparent" mo...
const u_char * payload
pointer to application payload
Definition: ipdg.h:42
const u_char * transport
pointer to transport header
Definition: ipdg.h:41
Protobuf double.
Definition: msgmod.h:117
generic failure
Definition: res.h:27
void nmsg_message_set_time(nmsg_message_t msg, const struct timespec *ts)
Set the timestamp of a message object.
const u_char * network
pointer to network header
Definition: ipdg.h:40
Protobuf uint32.
Definition: msgmod.h:99
nmsg_msgmod_field_type type
Intended (nmsg) type of this protobuf field.
const char * name
Name of the field.
void * nmsg_message_get_payload(nmsg_message_t msg)
WARNING: experts only.
Protobuf bool.
Definition: msgmod.h:120
int proto_network
PF_* value.
Definition: ipdg.h:35
nmsg_message_t nmsg_message_from_raw_payload(unsigned vid, unsigned msgtype, uint8_t *data, size_t sz, const struct timespec *ts)
Initialize a new message object from an opaque payload blob.
#define NMSG_MSGMOD_FIELD_REPEATED
field is repeated
Definition: msgmod.h:123
#define NMSG_MSGMOD_FIELD_NOPRINT
don't print the field
Definition: msgmod.h:126
int nmsg_get_debug(void)
Retrieve the current debug level.
Definition: nmsg.c:71
nmsg_res nmsg_strbuf_append(struct nmsg_strbuf *sb, const char *fmt,...)
Append to a string buffer.
Definition: strbuf.c:44
nmsg_res nmsg_pcap_input_read_raw(nmsg_pcap_t pcap, struct pcap_pkthdr **pkt_hdr, const uint8_t **pkt_data, struct timespec *ts)
Read a raw packet from an nmsg_pcap_t input.
Definition: pcap_input.c:100
String buffer.
Definition: strbuf.h:32
nmsg_res nmsg_message_add_allocation(nmsg_message_t msg, void *ptr)
Add an allocated object to a message object.
nmsg_res nmsg_pcap_input_setfilter_raw(nmsg_pcap_t pcap, const char *bpfstr)
Set a bpf filter on an nmsg_pcap_t object.
Definition: pcap_input.c:132
end of file
Definition: res.h:28