summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Makefile.am42
-rw-r--r--src/args.c843
-rw-r--r--src/args.h48
-rw-r--r--src/assert.c54
-rw-r--r--src/bpft.c233
-rw-r--r--src/bpft.h45
-rw-r--r--src/daemon.c250
-rw-r--r--src/daemon.h43
-rw-r--r--src/dnscap.1.in1011
-rw-r--r--src/dnscap.c249
-rw-r--r--src/dnscap.h441
-rw-r--r--src/dnscap_common.h158
-rw-r--r--src/dump_cbor.c680
-rw-r--r--src/dump_cbor.h65
-rw-r--r--src/dump_cds.c1962
-rw-r--r--src/dump_cds.h218
-rw-r--r--src/dump_dns.c319
-rw-r--r--src/dump_dns.h47
-rw-r--r--src/dumper.c399
-rw-r--r--src/dumper.h50
-rw-r--r--src/endian_compat.h108
-rw-r--r--src/endpoint.c103
-rw-r--r--src/endpoint.h44
-rw-r--r--src/hashtbl.c161
-rw-r--r--src/hashtbl.h70
-rw-r--r--src/iaddr.c68
-rw-r--r--src/iaddr.h43
-rw-r--r--src/log.c52
-rw-r--r--src/log.h42
-rw-r--r--src/memzero.c62
-rw-r--r--src/memzero.h40
-rw-r--r--src/network.c1834
-rw-r--r--src/network.h52
-rw-r--r--src/options.c248
-rw-r--r--src/options.h121
-rw-r--r--src/pcap-thread/m4/ax_pcap_thread.m415
-rw-r--r--src/pcap-thread/m4/ax_pthread.m4485
-rw-r--r--src/pcap-thread/pcap_thread.c3818
-rw-r--r--src/pcap-thread/pcap_thread.h640
-rw-r--r--src/pcap-thread/pcap_thread_ext_frag.c1013
-rw-r--r--src/pcap-thread/pcap_thread_ext_frag.h131
-rw-r--r--src/pcaps.c236
-rw-r--r--src/pcaps.h47
-rw-r--r--src/sig.c102
-rw-r--r--src/sig.h45
-rw-r--r--src/tcpreasm.c547
-rw-r--r--src/tcpreasm.h44
-rw-r--r--src/tcpstate.c141
-rw-r--r--src/tcpstate.h46
-rw-r--r--src/test/.gitignore4
-rw-r--r--src/test/1qtcpnosyn.pcapbin0 -> 778 bytes
-rw-r--r--src/test/1qtcppadd.pcapbin0 -> 1028 bytes
-rw-r--r--src/test/Makefile.am68
-rw-r--r--src/test/dns.gold714
-rw-r--r--src/test/dns.pcapbin0 -> 20228 bytes
-rw-r--r--src/test/dns6.pcapbin0 -> 274 bytes
-rw-r--r--src/test/dnso1tcp-bighole.pcapbin0 -> 21212 bytes
-rw-r--r--src/test/dnso1tcp-midmiss.pcapbin0 -> 1843 bytes
-rw-r--r--src/test/dnso1tcp.pcapbin0 -> 22512 bytes
-rw-r--r--src/test/dnsotcp-many1pkt.pcapbin0 -> 1007 bytes
-rw-r--r--src/test/dnsotcp-manyopkts.pcapbin0 -> 704 bytes
-rw-r--r--src/test/dnspad.gold8
-rw-r--r--src/test/dnspad.pcapbin0 -> 113 bytes
-rw-r--r--src/test/do1t-nosyn-1nolen.pcapbin0 -> 1028 bytes
-rw-r--r--src/test/frags.pcapbin0 -> 28694 bytes
-rwxr-xr-xsrc/test/test1.sh9
-rw-r--r--src/test/test10.gold22
-rwxr-xr-xsrc/test/test10.sh6
-rwxr-xr-xsrc/test/test11.sh79
-rwxr-xr-xsrc/test/test12.sh6
-rwxr-xr-xsrc/test/test13.sh28
-rw-r--r--src/test/test14.gold2864
-rwxr-xr-xsrc/test/test14.sh25
-rwxr-xr-xsrc/test/test2.sh6
-rwxr-xr-xsrc/test/test3.sh13
-rwxr-xr-xsrc/test/test4.sh6
-rwxr-xr-xsrc/test/test5.sh20
-rwxr-xr-xsrc/test/test6.sh6
-rw-r--r--src/test/test7.gold1417
-rwxr-xr-xsrc/test/test7.sh33
-rw-r--r--src/test/test8.gold440
-rwxr-xr-xsrc/test/test8.sh16
-rw-r--r--src/test/test9.gold104
-rwxr-xr-xsrc/test/test9.sh6
-rw-r--r--src/test/vlan11.gold714
-rw-r--r--src/test/vlan11.pcapbin0 -> 20760 bytes
86 files changed, 24129 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..e194d95
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,42 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/config.h.in
+CLEANFILES = dnscap.1 *.gcda *.gcno *.gcov
+
+SUBDIRS = test
+
+AM_CFLAGS = -I$(srcdir) \
+ -I$(top_srcdir) \
+ $(SECCOMPFLAGS) \
+ $(PTHREAD_CFLAGS) \
+ $(libcrypto_CFLAGS) \
+ $(libldns_CFLAGS)
+
+EXTRA_DIST = dnscap.1.in
+
+bin_PROGRAMS = dnscap
+
+dnscap_SOURCES = args.c assert.c bpft.c daemon.c dnscap.c dump_cbor.c \
+ dump_cds.c dump_dns.c dumper.c endpoint.c hashtbl.c iaddr.c log.c \
+ network.c options.c pcaps.c sig.c tcpstate.c tcpreasm.c memzero.c \
+ pcap-thread/pcap_thread.c pcap-thread/pcap_thread_ext_frag.c
+dist_dnscap_SOURCES = args.h bpft.h daemon.h dnscap_common.h dnscap.h \
+ dump_cbor.h dump_cds.h dump_dns.h dumper.h endpoint.h hashtbl.h iaddr.h \
+ log.h network.h options.h pcaps.h sig.h tcpstate.h tcpreasm.h memzero.h \
+ endian_compat.h \
+ pcap-thread/pcap_thread.h pcap-thread/pcap_thread_ext_frag.h
+dnscap_LDADD = $(PTHREAD_LIBS) $(libcrypto_LIBS) $(libldns_LIBS)
+
+man1_MANS = dnscap.1
+
+dnscap.1: dnscap.1.in Makefile
+ sed -e 's,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g' \
+ -e 's,[@]PACKAGE_URL[@],$(PACKAGE_URL),g' \
+ -e 's,[@]PACKAGE_BUGREPORT[@],$(PACKAGE_BUGREPORT),g' \
+ -e 's,[@]pkglibdir[@],$(pkglibdir),g' \
+ < $(srcdir)/dnscap.1.in > dnscap.1
+
+if ENABLE_GCOV
+gcov-local:
+ for src in $(dnscap_SOURCES); do \
+ gcov -l -r -s "$(srcdir)" "$$src"; \
+ done
+endif
diff --git a/src/args.c b/src/args.c
new file mode 100644
index 0000000..a7dd500
--- /dev/null
+++ b/src/args.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "args.h"
+#include "endpoint.h"
+#include "iaddr.h"
+#include "log.h"
+#include "tcpstate.h"
+#include "network.h"
+
+#include <ldns/ldns.h>
+
+/*
+ * OpenBSD and Debian Stretch i386 need file local functions for export
+ * to loaded modules, so use this for all platforms.
+ */
+void* _tcpstate_getcurr(void)
+{
+ return (void*)tcpstate_getcurr();
+}
+
+void _tcpstate_reset(void* tcpstate, const char* msg)
+{
+ tcpstate_reset((tcpstate_ptr)tcpstate, msg);
+}
+
+const char* _ia_str(iaddr ia)
+{
+ return ia_str(ia);
+}
+
+extern struct ip6_hdr* network_ipv6;
+extern struct ip* network_ip;
+extern struct udphdr* network_udp;
+
+void set_iaddr(iaddr* from, iaddr* to)
+{
+ if (from) {
+ switch (from->af) {
+ case AF_INET:
+ if (network_ip) {
+ memcpy(&network_ip->ip_src, &from->u.a4, sizeof(struct in_addr));
+ }
+ break;
+ case AF_INET6:
+ if (network_ipv6) {
+ memcpy(&network_ipv6->ip6_src, &from->u.a6, sizeof(struct in6_addr));
+ }
+ break;
+ default:
+ from = 0;
+ break;
+ }
+ }
+ if (to) {
+ switch (to->af) {
+ case AF_INET:
+ if (network_ip) {
+ memcpy(&network_ip->ip_dst, &to->u.a4, sizeof(struct in_addr));
+ }
+ break;
+ case AF_INET6:
+ if (network_ipv6) {
+ memcpy(&network_ipv6->ip6_dst, &to->u.a6, sizeof(struct in6_addr));
+ }
+ break;
+ default:
+ to = 0;
+ break;
+ }
+ }
+ if (from || to) {
+ if (network_ip) {
+ network_ip->ip_sum = 0;
+ network_ip->ip_sum = ~in_checksum((u_char*)network_ip, sizeof *network_ip);
+ }
+ if (network_udp) {
+ network_udp->uh_sum = 0;
+ }
+ }
+}
+
+#ifdef __linux__
+extern char* strptime(const char*, const char*, struct tm*);
+#endif
+
+time_t xtimegm(struct tm* tmp)
+{
+#if defined(__SVR4) && defined(__sun)
+ char tz[3] = "TZ=";
+ putenv((char*)tz);
+ return mktime(tmp);
+#else
+ return timegm(tmp);
+#endif
+}
+
+void usage(const char* msg)
+{
+ struct plugin* p;
+
+ fprintf(stderr, "%s: usage error: %s\n", ProgramName, msg);
+ fprintf(stderr, "\n");
+
+ help_1();
+
+ for (p = HEAD(plugins); p != NULL; p = NEXT(p, link))
+ if (p->usage)
+ (*p->usage)();
+
+ fprintf(stderr,
+ "\nnote: the -? or -\\? option will display full help text\n");
+
+ exit(1);
+}
+
+void help_1(void)
+{
+ fprintf(stderr, "%s: version %s\n\n", ProgramName, PACKAGE_VERSION);
+ fprintf(stderr,
+ "usage: %s\n"
+ " [-?VbNpd1gfTI"
+#ifdef USE_SECCOMP
+ "y"
+#endif
+ "SMD] [-o option=value]+\n"
+ " [-i <if>]+ [-r <file>]+ [-l <vlan>]+ [-L <vlan>]+\n"
+ " [-u <port>] [-m [qun]] [-e [nytfsxir]] [-h [ir]] [-s [ir]]\n"
+ " [-a <host>]+ [-z <host>]+ [-A <host>]+ [-Z <host>]+ [-Y <host>]+\n"
+ " [-w <base> [-W <suffix>] [-k <cmd>] -F <format>]\n"
+ " [-t <lim>] [-c <lim>] [-C <lim>]\n"
+ " [-x <pat>]+ [-X <pat>]+\n"
+ " [-B <datetime>] [-E <datetime>]\n"
+ " [-U <str>] [-q <num|str>] [-Q <num|str>]\n"
+ " [-P plugin.so <plugin options...>]\n",
+ ProgramName);
+}
+
+void help_2(void)
+{
+ help_1();
+ fprintf(stderr,
+ "\noptions:\n"
+ " -? or -\\? print these instructions and exit\n"
+ " -V print version and exit\n"
+ " -o opt=val extended options, see man page for list of options\n"
+ " -b run in background as daemon\n"
+ " -N do not attempt to drop privileges, this is implicit\n"
+ " if only reading offline pcap files\n"
+ " -p do not put interface in promiscuous mode\n"
+ " -d dump verbose trace information to stderr, specify multiple\n"
+ " times to increase debugging\n"
+ " -1 flush output on every packet\n"
+ " -g dump packets dig-style on stderr\n"
+ " -f include fragmented packets\n"
+ " -T include TCP packets (DNS header filters will inspect only the\n"
+ " first DNS header, and the result will apply to all messages\n"
+ " in the TCP stream; DNS payload filters will not be applied.)\n"
+ " -I include ICMP and ICMPv6 packets\n"
+ " -i <if> select this live interface(s)\n"
+ " -r <file> read this pcap file\n"
+ " -l <vlan> select only these vlan(s) (4095 for all)\n"
+ " -L <vlan> select these vlan(s) and non-VLAN frames (4095 for all)\n"
+ " -u <port> dns port (default: 53)\n"
+ " -m [qun] select messages: query, update, notify\n"
+ " -e [nytfsxir] select error/response code\n"
+ " n = no error\n"
+ " y = any error\n"
+ " t = truncated response\n"
+ " f = format error (rcode 1)\n"
+ " s = server failure (rcode 2)\n"
+ " x = nxdomain (rcode 3)\n"
+ " i = not implemented (rcode 4)\n"
+ " r = refused (rcode 5)\n"
+ " -h [ir] hide initiators and/or responders\n"
+ " -s [ir] select sides: initiations, responses\n"
+ " -a <host> want messages from these initiator(s)\n"
+ " -z <host> want messages from these responder(s)\n"
+ " -A <host> want messages NOT to/from these initiator(s)\n"
+ " -Z <host> want messages NOT to/from these responder(s)\n"
+ " -Y <host> drop responses from these responder(s)\n"
+ " -w <base> dump to <base>.<timesec>.<timeusec>\n"
+ " -W <suffix> add suffix to dump file name, e.g. '.pcap'\n"
+ " -k <cmd> kick off <cmd> when each dump closes\n"
+ " -F <format> dump format: pcap (default), cbor, cds\n"
+ " -t <lim> close dump or exit every/after <lim> secs\n"
+ " -c <lim> close dump or exit every/after <lim> pkts\n"
+ " -C <lim> close dump or exit every/after <lim> bytes captured\n"
+ " -x <pat> select messages matching regex <pat>\n"
+ " -X <pat> select messages not matching regex <pat>\n"
+#ifdef USE_SECCOMP
+ " -y enable seccomp-bpf\n"
+#endif
+ " -S show summarized statistics\n"
+ " -B <datetime> begin collecting at this date and time\n"
+ " -E <datetime> end collecting at this date and time\n"
+ " -M set monitor mode on interfaces\n"
+ " -D set immediate mode on interfaces\n"
+ " -U <str> append 'and <str>' to the pcap filter\n"
+ " -q <num|str> select messages based on QTYPE\n"
+ " -Q <num|str> filter out messages based on QTYPE\n"
+ " -P <plugin.so> load plugin, any argument after this is sent to the plugin!\n");
+}
+
+void check_gzip()
+{
+ char* dot = strrchr(dump_suffix, '.');
+ if (dot) {
+ wantgzip = (strcmp(dot, ".gz") == 0) ? TRUE : FALSE;
+ }
+
+#if !(HAVE_GZOPEN && (HAVE_FUNOPEN || HAVE_FOPENCOOKIE))
+ if (wantgzip) {
+ fprintf(stderr, "error: gzip compression requested but not supported\n");
+ exit(1);
+ }
+#endif
+}
+
+int is_responder(iaddr ia)
+{
+ if (EMPTY(responders))
+ return 1;
+ if (ep_present(&responders, ia))
+ return 1;
+ return 0;
+}
+
+void parse_args(int argc, char* argv[])
+{
+ mypcap_ptr mypcap;
+ unsigned long ul;
+ vlan_ptr vlan;
+ unsigned u;
+ int ch;
+ char * p, *match_qtype_arg = 0;
+
+ if ((p = strrchr(argv[0], '/')) == NULL)
+ ProgramName = argv[0];
+ else
+ ProgramName = p + 1;
+ INIT_LIST(vlans_incl);
+ INIT_LIST(vlans_excl);
+ INIT_LIST(mypcaps);
+ INIT_LIST(initiators);
+ INIT_LIST(responders);
+ INIT_LIST(not_initiators);
+ INIT_LIST(not_responders);
+ INIT_LIST(drop_responders);
+ INIT_LIST(myregexes);
+ INIT_LIST(plugins);
+ while ((ch = getopt(argc, argv,
+ "a:bc:de:fgh:i:k:l:m:o:pr:s:t:u:w:x:yz:q:"
+ "A:B:C:DE:F:IL:MNP:STU:VW:X:Y:Z:Q:1?"))
+ != EOF) {
+ switch (ch) {
+ case 'o':
+ if (option_parse(&options, optarg)) {
+ fprintf(stderr, "%s: unknown or invalid extended -o option: %s\n", ProgramName, optarg);
+ exit(1);
+ }
+ break;
+ case 'b':
+ background = TRUE;
+ break;
+ case 'N':
+ dont_drop_privileges = TRUE;
+ break;
+ case 'p':
+ promisc = FALSE;
+ break;
+ case 'd':
+ dumptrace++;
+ break;
+ case '1':
+ flush = TRUE;
+ break;
+ case 'g':
+ preso = TRUE;
+ break;
+ case 'f':
+ wantfrags = TRUE;
+ break;
+ case 'I':
+ wanticmp = TRUE;
+ break;
+ case 'V':
+ printf("%s version %s\n", ProgramName, PACKAGE_VERSION);
+ exit(0);
+ case 'i':
+ if (pcap_offline != NULL)
+ usage("-i makes no sense after -r");
+ mypcap = calloc(1, sizeof *mypcap);
+ assert(mypcap != NULL);
+ INIT_LINK(mypcap, link);
+ mypcap->name = strdup(optarg);
+ assert(mypcap->name != NULL);
+ APPEND(mypcaps, mypcap, link);
+ break;
+ case 'r':
+ if (!EMPTY(mypcaps))
+ usage("-r makes no sense after -i");
+ pcap_offline = calloc(1, sizeof *pcap_offline);
+ assert(pcap_offline != NULL);
+ INIT_LINK(pcap_offline, link);
+ pcap_offline->name = strdup(optarg);
+ assert(pcap_offline->name != NULL);
+ APPEND(mypcaps, pcap_offline, link);
+ only_offline_pcaps = TRUE;
+ break;
+ case 'l':
+ ul = strtoul(optarg, &p, 0);
+ if (*p != '\0' || ul > MAX_VLAN)
+ usage("-l vlan must be an integer 0..4095");
+ vlan = calloc(1, sizeof *vlan);
+ assert(vlan != NULL);
+ INIT_LINK(vlan, link);
+ vlan->vlan = (unsigned)ul;
+ APPEND(vlans_excl, vlan, link);
+ if (0 == ul)
+ fprintf(stderr, "Warning: previous versions of %s "
+ "interpreted 0 as all VLANs. "
+ "If you want all VLANs now you must "
+ "specify %u.\n",
+ ProgramName, MAX_VLAN);
+ break;
+ case 'L':
+ ul = strtoul(optarg, &p, 0);
+ if (*p != '\0' || ul > MAX_VLAN)
+ usage("-L vlan must be an integer 0..4095");
+ vlan = calloc(1, sizeof *vlan);
+ assert(vlan != NULL);
+ INIT_LINK(vlan, link);
+ vlan->vlan = (unsigned)ul;
+ APPEND(vlans_incl, vlan, link);
+ if (0 == ul)
+ fprintf(stderr, "Warning: previous versions of %s "
+ "interpreted 0 as all VLANs. "
+ "If you want all VLANs now you must "
+ "specify %u.\n",
+ ProgramName, MAX_VLAN);
+ break;
+ case 'T':
+ wanttcp = TRUE;
+ break;
+ case 'u':
+ ul = strtoul(optarg, &p, 0);
+ if (*p != '\0' || ul < 1U || ul > 65535U)
+ usage("port must be an integer 1..65535");
+ dns_port = (unsigned)ul;
+ break;
+ case 'm':
+ u = 0;
+ for (p = optarg; *p; p++)
+ switch (*p) {
+ case 'q':
+ u |= MSG_QUERY;
+ break;
+ case 'u':
+ u |= MSG_UPDATE;
+ break;
+ case 'n':
+ u |= MSG_NOTIFY;
+ break;
+ default:
+ usage("-m takes only [qun]");
+ }
+ msg_wanted = u;
+ break;
+ case 's':
+ u = 0;
+ for (p = optarg; *p; p++)
+ switch (*p) {
+ case 'i':
+ u |= DIR_INITIATE;
+ break;
+ case 'r':
+ u |= DIR_RESPONSE;
+ break;
+ default:
+ usage("-s takes only [ir]");
+ }
+ dir_wanted = u;
+ break;
+ case 'h':
+ u = 0;
+ for (p = optarg; *p; p++)
+ switch (*p) {
+ case 'i':
+ u |= END_INITIATOR;
+ break;
+ case 'r':
+ u |= END_RESPONDER;
+ break;
+ default:
+ usage("-h takes only [ir]");
+ }
+ end_hide = u;
+ break;
+ case 'e':
+ u = 0;
+ for (p = optarg; *p; p++)
+ switch (*p) {
+ case 'n':
+ u |= ERR_NO;
+ break;
+ case 'y':
+ u |= ERR_YES;
+ break;
+ case 't':
+ u |= ERR_TRUNC;
+ break;
+ case 'f':
+ u |= ERR_FORMERR;
+ break;
+ case 's':
+ u |= ERR_SERVFAIL;
+ break;
+ case 'x':
+ u |= ERR_NXDOMAIN;
+ break;
+ case 'i':
+ u |= ERR_NOTIMPL;
+ break;
+ case 'r':
+ u |= ERR_REFUSED;
+ break;
+ default:
+ usage("-e takes only [nytfsxir]");
+ }
+ err_wanted = u;
+ break;
+ case 'a':
+ endpoint_arg(&initiators, optarg);
+ break;
+ case 'z':
+ endpoint_arg(&responders, optarg);
+ break;
+ case 'A':
+ endpoint_arg(&not_initiators, optarg);
+ break;
+ case 'Z':
+ endpoint_arg(&not_responders, optarg);
+ break;
+ case 'Y':
+ endpoint_arg(&drop_responders, optarg);
+ break;
+ case 'w':
+ dump_base = optarg;
+ if (strcmp(optarg, "-") == 0)
+ dump_type = to_stdout;
+ else
+ dump_type = to_file;
+ break;
+ case 'W':
+ if (dump_suffix)
+ free(dump_suffix);
+ dump_suffix = strdup(optarg);
+ check_gzip();
+ break;
+ case 'k':
+ if (dump_type != to_file)
+ usage("-k depends on -w"
+ " (note: can't be stdout)");
+ kick_cmd = optarg;
+ break;
+ case 'F':
+ if (!strcmp(optarg, "pcap")) {
+ options.dump_format = pcap;
+ } else if (!strcmp(optarg, "cbor")) {
+ options.dump_format = cbor;
+ } else if (!strcmp(optarg, "cds")) {
+ options.dump_format = cds;
+ } else {
+ usage("invalid output format for -F");
+ }
+ break;
+ case 't':
+ ul = strtoul(optarg, &p, 0);
+ if (*p != '\0')
+ usage("argument to -t must be an integer");
+ limit_seconds = (unsigned)ul;
+ break;
+ case 'c':
+ ul = strtoul(optarg, &p, 0);
+ if (*p != '\0')
+ usage("argument to -c must be an integer");
+ limit_packets = (unsigned)ul;
+ break;
+ case 'C':
+ ul = strtoul(optarg, &p, 0);
+ if (*p != '\0')
+ usage("argument to -C must be an integer");
+ limit_pcapfilesize = (unsigned)ul;
+ break;
+ case 'x':
+ /* FALLTHROUGH */
+ case 'X': {
+ int i;
+ myregex_ptr myregex = calloc(1, sizeof *myregex);
+ assert(myregex != NULL);
+ INIT_LINK(myregex, link);
+ myregex->str = strdup(optarg);
+ i = regcomp(&myregex->reg, myregex->str, REGEX_CFLAGS);
+ if (i != 0) {
+ regerror(i, &myregex->reg,
+ errbuf, sizeof errbuf);
+ usage(errbuf);
+ }
+ myregex->not = (ch == 'X');
+ APPEND(myregexes, myregex, link);
+ } break;
+ case 'B': {
+ struct tm tm;
+ memset(&tm, '\0', sizeof(tm));
+ if (NULL == strptime(optarg, "%F %T", &tm))
+ usage("-B arg must have format YYYY-MM-DD HH:MM:SS");
+ start_time = xtimegm(&tm);
+ } break;
+ case 'E': {
+ struct tm tm;
+ memset(&tm, '\0', sizeof(tm));
+ if (NULL == strptime(optarg, "%F %T", &tm))
+ usage("-E arg must have format YYYY-MM-DD HH:MM:SS");
+ stop_time = xtimegm(&tm);
+ } break;
+ case 'S':
+ print_pcap_stats = TRUE;
+ break;
+ case 'P': {
+ char* fn = strdup(optarg);
+ char* t;
+ char sn[256];
+ struct plugin* p = calloc(1, sizeof(*p));
+ assert(p != NULL);
+ INIT_LINK(p, link);
+ t = strrchr(fn, '/');
+ p->name = strdup(t ? t + 1 : fn);
+ if ((t = strstr(p->name, ".so")))
+ *t = 0;
+ p->handle = dlopen(fn, RTLD_NOW);
+ if (!p->handle) {
+ logerr("%s: %s", fn, dlerror());
+ exit(1);
+ }
+ snprintf(sn, sizeof(sn), "%s_type", p->name);
+ p->type = dlsym(p->handle, sn);
+ if (p->type) {
+ p->pt = (*p->type)();
+ switch (p->pt) {
+ case plugin_output:
+ case plugin_filter:
+ break;
+ default:
+ logerr("invalid plugin type for plugin '%s'", p->name);
+ exit(1);
+ }
+ } else {
+ p->pt = plugin_output;
+ }
+ snprintf(sn, sizeof(sn), "%s_start", p->name);
+ p->start = dlsym(p->handle, sn);
+ snprintf(sn, sizeof(sn), "%s_stop", p->name);
+ p->stop = dlsym(p->handle, sn);
+ snprintf(sn, sizeof(sn), "%s_open", p->name);
+ p->open = dlsym(p->handle, sn);
+ snprintf(sn, sizeof(sn), "%s_close", p->name);
+ p->close = dlsym(p->handle, sn);
+ snprintf(sn, sizeof(sn), "%s_output", p->name);
+ p->output = dlsym(p->handle, sn);
+ if (p->pt == plugin_output && !p->output) {
+ logerr("%s", dlerror());
+ exit(1);
+ }
+ snprintf(sn, sizeof(sn), "%s_filter", p->name);
+ p->filter = dlsym(p->handle, sn);
+ if (p->pt == plugin_filter && !p->filter) {
+ logerr("%s", dlerror());
+ exit(1);
+ }
+ snprintf(sn, sizeof(sn), "%s_usage", p->name);
+ p->usage = dlsym(p->handle, sn);
+ snprintf(sn, sizeof(sn), "%s_extension", p->name);
+ p->extension = dlsym(p->handle, sn);
+ if (p->extension) {
+ (*p->extension)(DNSCAP_EXT_IS_RESPONDER, (void*)is_responder);
+ (*p->extension)(DNSCAP_EXT_IA_STR, (void*)_ia_str);
+ (*p->extension)(DNSCAP_EXT_TCPSTATE_GETCURR, (void*)_tcpstate_getcurr);
+ (*p->extension)(DNSCAP_EXT_TCPSTATE_RESET, (void*)_tcpstate_reset);
+ (*p->extension)(DNSCAP_EXT_SET_IADDR, (void*)set_iaddr);
+ }
+ snprintf(sn, sizeof(sn), "%s_getopt", p->name);
+ p->getopt = dlsym(p->handle, sn);
+ if (p->getopt)
+ (*p->getopt)(&argc, &argv);
+ APPEND(plugins, p, link);
+ if (dumptrace)
+ fprintf(stderr, "Plugin '%s' loaded\n", p->name);
+ free(fn);
+ } break;
+ case 'U':
+ if (extra_bpf)
+ free(extra_bpf);
+ extra_bpf = strdup(optarg);
+ break;
+ case 'y':
+#ifdef USE_SECCOMP
+ use_seccomp = TRUE;
+ break;
+#else
+ usage("-y: seccomp-bpf not enabled");
+#endif
+ case 'M':
+ monitor_mode = TRUE;
+ break;
+ case 'D':
+ immediate_mode = TRUE;
+ break;
+ case 'q': {
+ if (nmatch_qtype) {
+ usage("-q and -Q can't be used together");
+ }
+ free(match_qtype_arg); // fix clang scan-build
+ match_qtype_arg = strdup(optarg);
+ match_qtype = ldns_get_rr_type_by_name(optarg);
+ if (!match_qtype) {
+ ul = strtoul(optarg, &p, 0);
+ if (*p != '\0' || ul < 1U || ul > 65535U)
+ usage("-q QTYPE must be a valid type or an integer 1..65535");
+ match_qtype = (ldns_rr_type)ul;
+ }
+ break;
+ }
+ case 'Q': {
+ if (match_qtype) {
+ usage("-q and -Q can't be used together");
+ }
+ free(match_qtype_arg); // fix clang scan-build
+ match_qtype_arg = strdup(optarg);
+ nmatch_qtype = ldns_get_rr_type_by_name(optarg);
+ if (!nmatch_qtype) {
+ ul = strtoul(optarg, &p, 0);
+ if (*p != '\0' || ul < 1U || ul > 65535U)
+ usage("-Q QTYPE must be a valid type or an integer 1..65535");
+ nmatch_qtype = (ldns_rr_type)ul;
+ }
+ break;
+ }
+ case '?':
+ if (!optopt || optopt == '?') {
+ help_2();
+ options_free(&options);
+ exit(0);
+ }
+ // fallthrough
+ default:
+ usage("unrecognized command line option");
+ }
+ }
+ assert(msg_wanted != 0U);
+ assert(err_wanted != 0U);
+ if (dump_type != nowhere && options.use_layers)
+ usage("use_layers is only compatible with -g so far");
+ if (dump_type == nowhere && !preso && EMPTY(plugins))
+ usage("without -w or -g, there would be no output");
+ if (end_hide != 0U && wantfrags)
+ usage("the -h and -f options are incompatible");
+ if (!EMPTY(vlans_incl) && !EMPTY(vlans_excl))
+ usage("the -L and -l options are mutually exclusive");
+ if (background && (dumptrace || preso))
+ usage("the -b option is incompatible with -d and -g");
+ if (dumptrace >= 1) {
+ endpoint_ptr ep;
+ const char* sep;
+ myregex_ptr mr;
+
+ fprintf(stderr, "%s: version %s\n", ProgramName, PACKAGE_VERSION);
+ fprintf(stderr,
+ "%s: msg %c%c%c, side %c%c, hide %c%c, err %c%c%c%c%c%c%c%c, t %u, c %u, C %zu, %sq %s\n",
+ ProgramName,
+ (msg_wanted & MSG_QUERY) != 0 ? 'Q' : '.',
+ (msg_wanted & MSG_UPDATE) != 0 ? 'U' : '.',
+ (msg_wanted & MSG_NOTIFY) != 0 ? 'N' : '.',
+ (dir_wanted & DIR_INITIATE) != 0 ? 'I' : '.',
+ (dir_wanted & DIR_RESPONSE) != 0 ? 'R' : '.',
+ (end_hide & END_INITIATOR) != 0 ? 'I' : '.',
+ (end_hide & END_RESPONDER) != 0 ? 'R' : '.',
+ (err_wanted & ERR_NO) != 0 ? 'N' : '.',
+ (err_wanted & ERR_YES) == ERR_YES ? 'Y' : '.',
+ (err_wanted & ERR_TRUNC) != 0 ? 't' : '.',
+ (err_wanted & ERR_FORMERR) != 0 ? 'f' : '.',
+ (err_wanted & ERR_SERVFAIL) != 0 ? 's' : '.',
+ (err_wanted & ERR_NXDOMAIN) != 0 ? 'x' : '.',
+ (err_wanted & ERR_NOTIMPL) != 0 ? 'i' : '.',
+ (err_wanted & ERR_REFUSED) != 0 ? 'r' : '.',
+ limit_seconds, limit_packets, limit_pcapfilesize,
+ nmatch_qtype ? "!" : "", match_qtype_arg);
+ sep = "\tinit";
+ for (ep = HEAD(initiators);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
+ sep = "";
+ }
+ if (!EMPTY(initiators))
+ fprintf(stderr, "\n");
+ sep = "\tresp";
+ for (ep = HEAD(responders);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
+ sep = "";
+ }
+ if (!EMPTY(responders))
+ fprintf(stderr, "\n");
+ sep = "\t!init";
+ for (ep = HEAD(not_initiators);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
+ sep = "";
+ }
+ if (!EMPTY(not_initiators))
+ fprintf(stderr, "\n");
+ sep = "\t!resp";
+ for (ep = HEAD(not_responders);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
+ sep = "";
+ }
+ if (!EMPTY(not_responders))
+ fprintf(stderr, "\n");
+ sep = "\t!dropresp";
+ for (ep = HEAD(drop_responders);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ fprintf(stderr, "%s %s", sep, ia_str(ep->ia));
+ sep = "";
+ }
+ if (!EMPTY(drop_responders))
+ fprintf(stderr, "\n");
+ if (!EMPTY(myregexes)) {
+ fprintf(stderr, "%s: pat:", ProgramName);
+ for (mr = HEAD(myregexes);
+ mr != NULL;
+ mr = NEXT(mr, link))
+ fprintf(stderr, " %s/%s/",
+ mr->not ? "!" : "", mr->str);
+ fprintf(stderr, "\n");
+ }
+ }
+ if (EMPTY(mypcaps)) {
+ pcap_if_t* pcapdev = 0;
+ int res;
+ res = pcap_findalldevs(&pcapdev, errbuf);
+ if (res == -1) {
+ fprintf(stderr, "%s: pcap_findalldevs: %s\n",
+ ProgramName, errbuf);
+ exit(1);
+ } else if (pcapdev == NULL) {
+ fprintf(stderr, "%s: pcap_findalldevs: no devices found\n",
+ ProgramName);
+ exit(1);
+ }
+ mypcap = calloc(1, sizeof *mypcap);
+ assert(mypcap != NULL);
+ INIT_LINK(mypcap, link);
+ mypcap->name = strdup(pcapdev->name);
+ APPEND(mypcaps, mypcap, link);
+ pcap_freealldevs(pcapdev);
+ }
+ if (start_time && stop_time && start_time >= stop_time)
+ usage("start time must be before stop time");
+
+ if (options.dump_format == cbor) {
+ if (!have_cbor_support()) {
+ usage("no built in cbor support");
+ }
+ cbor_set_size(options.cbor_chunk_size);
+ } else if (options.dump_format == cds) {
+ if (!have_cds_support()) {
+ usage("no built in cds support");
+ }
+ cds_set_cbor_size(options.cds_cbor_size);
+ cds_set_message_size(options.cds_message_size);
+ cds_set_max_rlabels(options.cds_max_rlabels);
+ cds_set_min_rlabel_size(options.cds_min_rlabel_size);
+ if (options.cds_use_rdata_index && options.cds_use_rdata_rindex) {
+ usage("can't use both CDS rdata index and rindex");
+ }
+ cds_set_use_rdata_index(options.cds_use_rdata_index);
+ cds_set_use_rdata_rindex(options.cds_use_rdata_rindex);
+ cds_set_rdata_index_min_size(options.cds_rdata_index_min_size);
+ cds_set_rdata_rindex_min_size(options.cds_rdata_rindex_min_size);
+ cds_set_rdata_rindex_size(options.cds_rdata_rindex_size);
+ }
+
+ if (!options.use_layers && (options.defrag_ipv4 || options.defrag_ipv6)) {
+ usage("can't defragment IP packets without use_layers=yes");
+ }
+
+ if (options.reassemble_tcp_bfbparsedns) {
+ if (!options.reassemble_tcp) {
+ usage("can't do byte for byte parsing of DNS without reassemble_tcp=yes");
+ }
+ }
+
+ free(match_qtype_arg);
+}
diff --git a/src/args.h b/src/args.h
new file mode 100644
index 0000000..6f3ab61
--- /dev/null
+++ b/src/args.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_args_h
+#define __dnscap_args_h
+
+time_t xtimegm(struct tm* tmp);
+void usage(const char* msg);
+void help_1(void);
+void help_2(void);
+void check_gzip();
+int is_responder(iaddr ia);
+void parse_args(int argc, char* argv[]);
+
+#endif /* __dnscap_args_h */
diff --git a/src/assert.c b/src/assert.c
new file mode 100644
index 0000000..32f2e3b
--- /dev/null
+++ b/src/assert.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "dnscap.h"
+
+#if !HAVE___ASSERTION_FAILED
+static void my_assertion_failed(const char* file, int line, assertion_type type, const char* msg, int something) __attribute__((noreturn));
+#endif
+
+#if !HAVE___ASSERTION_FAILED
+static void
+my_assertion_failed(const char* file, int line, assertion_type type, const char* msg, int something)
+{
+ (void)type;
+ (void)something;
+ fprintf(stderr, "assertion failed: %s(%d): %s\n", file, line, msg);
+ abort();
+}
+
+assertion_failure_callback __assertion_failed = my_assertion_failed;
+#endif
diff --git a/src/bpft.c b/src/bpft.c
new file mode 100644
index 0000000..e810910
--- /dev/null
+++ b/src/bpft.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "bpft.h"
+#include "iaddr.h"
+
+#include <ldns/ldns.h>
+
+void prepare_bpft(void)
+{
+ unsigned udp10_mbs, udp10_mbc, udp11_mbc; //udp11_mbs
+ text_list bpfl;
+ text_ptr text;
+ size_t len;
+ char* p;
+
+ /* Prepare the must-be-set and must-be-clear tests. */
+ udp10_mbs = udp10_mbc = udp11_mbc = 0U; // udp11_mbs
+ if ((dir_wanted & DIR_INITIATE) != 0) {
+ if ((dir_wanted & DIR_RESPONSE) == 0)
+ udp10_mbc |= UDP10_QR_MASK;
+ } else if ((dir_wanted & DIR_RESPONSE) != 0) {
+ udp10_mbs |= UDP10_QR_MASK;
+ }
+ if ((msg_wanted & MSG_UPDATE) != 0) {
+ if ((msg_wanted & (MSG_QUERY | MSG_NOTIFY)) == 0)
+ udp10_mbs |= (LDNS_PACKET_UPDATE << UDP10_OP_SHIFT);
+ } else if ((msg_wanted & MSG_NOTIFY) != 0) {
+ if ((msg_wanted & (MSG_QUERY | MSG_UPDATE)) == 0)
+ udp10_mbs |= (LDNS_PACKET_NOTIFY << UDP10_OP_SHIFT);
+ } else if ((msg_wanted & MSG_QUERY) != 0) {
+ udp10_mbc |= UDP10_OP_MASK;
+ }
+ if (err_wanted == ERR_NO) {
+ udp10_mbc |= UDP10_TC_MASK;
+ udp11_mbc |= UDP11_RC_MASK;
+ }
+
+ /*
+ * Model
+ * (vlan) and (transport)
+ * (vlan) and ((icmp) or (frags) or (dns))
+ * (vlan) and ((icmp) or (frags) or ((ports) and (hosts)))
+ * (vlan) and ((icmp) or (frags) or (((tcp) or (udp)) and (hosts)))
+ * [(vlan) and] ( [(icmp) or] [(frags) or] ( ( [(tcp) or] (udp) ) [and (hosts)] ) )
+ */
+
+ /* Make a BPF program to do early course kernel-level filtering. */
+ INIT_LIST(bpfl);
+ len = 0;
+ if (!EMPTY(vlans_excl))
+ len += text_add(&bpfl, "vlan and ("); /* vlan and ( transports ... */
+ else
+ len += text_add(&bpfl, "("); /* ( transports ... */
+ if (wanticmp) {
+ len += text_add(&bpfl, " ( ip proto 1 or ip proto 58 ) or");
+ }
+ if (wantfrags) {
+ len += text_add(&bpfl, " ( ip[6:2] & 0x1fff != 0 or ip6[6] = 44 ) or");
+ }
+ len += text_add(&bpfl, " ("); /* ( dns ... */
+ len += text_add(&bpfl, " ("); /* ( ports ... */
+ if (wanttcp) {
+ len += text_add(&bpfl, " ( tcp port %d ) or", dns_port);
+ /* tcp packets can be filtered by initiators/responders, but
+ * not mbs/mbc. */
+ }
+ len += text_add(&bpfl, " ( udp port %d and ( ip6 or ( ip", dns_port);
+
+ if (udp10_mbc != 0)
+ len += text_add(&bpfl, " and udp[10] & 0x%x = 0",
+ udp10_mbc);
+ if (udp10_mbs != 0)
+ len += text_add(&bpfl, " and udp[10] & 0x%x = 0x%x",
+ udp10_mbs, udp10_mbs);
+ if (udp11_mbc != 0)
+ len += text_add(&bpfl, " and udp[11] & 0x%x = 0",
+ udp11_mbc);
+ /* Dead code, udp11_mbs never set
+ if (udp11_mbs != 0)
+ len += text_add(&bpfl, " and udp[11] & 0x%x = 0x%x",
+ udp11_mbs, udp11_mbs);
+*/
+
+ if (err_wanted != ERR_NO) {
+ len += text_add(&bpfl, " and (");
+ if ((err_wanted & ERR_TRUNC) != 0) {
+ len += text_add(&bpfl, " udp[10] & 0x%x = 0x%x or", UDP10_TC_MASK, UDP10_TC_MASK);
+ }
+ len += text_add(&bpfl, " 0x%x << (udp[11] & 0xf) & 0x%x != 0 )", ERR_RCODE_BASE, err_wanted);
+ }
+
+ len += text_add(&bpfl, " )))"); /* ... udp 53 ) */
+ len += text_add(&bpfl, " )"); /* ... ports ) */
+ if (options.bpf_hosts_apply_all) {
+ len += text_add(&bpfl, " )"); /* ... dns ) */
+ len += text_add(&bpfl, " )"); /* ... transport ) */
+ }
+ if (!EMPTY(initiators) || !EMPTY(responders)) {
+ const char* or = "or", *lp = "(", *sep;
+ endpoint_ptr ep;
+
+ len += text_add(&bpfl, " and host");
+ sep = lp;
+ for (ep = HEAD(initiators);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ len += text_add(&bpfl, " %s %s", sep, ia_str(ep->ia));
+ sep = or ;
+ }
+ for (ep = HEAD(responders);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ len += text_add(&bpfl, " %s %s", sep, ia_str(ep->ia));
+ sep = or ;
+ }
+ len += text_add(&bpfl, " )");
+ }
+ if (!EMPTY(not_initiators) || !EMPTY(not_responders)) {
+ const char* or = "or", *lp = "(", *sep;
+ endpoint_ptr ep;
+
+ len += text_add(&bpfl, " and not host");
+ sep = lp;
+ for (ep = HEAD(not_initiators);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ len += text_add(&bpfl, " %s %s", sep, ia_str(ep->ia));
+ sep = or ;
+ }
+ for (ep = HEAD(not_responders);
+ ep != NULL;
+ ep = NEXT(ep, link)) {
+ len += text_add(&bpfl, " %s %s", sep, ia_str(ep->ia));
+ sep = or ;
+ }
+ len += text_add(&bpfl, " )");
+ }
+ if (!options.bpf_hosts_apply_all) {
+ len += text_add(&bpfl, " )"); /* ... dns ) */
+ len += text_add(&bpfl, " )"); /* ... transport ) */
+ }
+ if (extra_bpf)
+ len += text_add(&bpfl, " and ( %s )", extra_bpf);
+
+ bpft = calloc(len + 1, sizeof(char));
+ assert(bpft != NULL);
+ p = bpft;
+ for (text = HEAD(bpfl); text != NULL; text = NEXT(text, link)) {
+ memcpy(p, text->text, text->len);
+ p += text->len;
+ }
+ text_free(&bpfl);
+ if (!EMPTY(vlans_incl)) {
+ char* bpft_vlan;
+
+ len = (2 * len) + 64; /* add enough for the extra in snprintf() below */
+ bpft_vlan = calloc(len, sizeof(char));
+ assert(bpft_vlan != NULL);
+
+ snprintf(bpft_vlan, len, "( %s ) or ( vlan and ( %s ) )", bpft, bpft);
+ free(bpft);
+ bpft = bpft_vlan;
+ }
+ if (dumptrace >= 1)
+ fprintf(stderr, "%s: \"%s\"\n", ProgramName, bpft);
+}
+
+size_t text_add(text_list* list, const char* fmt, ...)
+{
+ text_ptr text;
+ va_list ap;
+ int len;
+
+ text = calloc(1, sizeof *text);
+ assert(text != NULL);
+ INIT_LINK(text, link);
+ va_start(ap, fmt);
+ len = vasprintf(&text->text, fmt, ap);
+ assert(len >= 0);
+ va_end(ap);
+ text->len = len;
+ APPEND(*list, text, link);
+ return (text->len);
+}
+
+void text_free(text_list* list)
+{
+ text_ptr at, text;
+
+ for (at = HEAD(*list); at;) {
+ text = at;
+ at = NEXT(text, link);
+
+ UNLINK(*list, text, link);
+ free(text->text);
+ assert(text != (void*)-1);
+ free(text);
+ }
+}
diff --git a/src/bpft.h b/src/bpft.h
new file mode 100644
index 0000000..88a272c
--- /dev/null
+++ b/src/bpft.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_bpft_h
+#define __dnscap_bpft_h
+
+void prepare_bpft(void);
+
+size_t text_add(text_list* list, const char* fmt, ...);
+void text_free(text_list* list);
+
+#endif /* __dnscap_bpft_h */
diff --git a/src/daemon.c b/src/daemon.c
new file mode 100644
index 0000000..67ef86e
--- /dev/null
+++ b/src/daemon.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "daemon.h"
+#include "log.h"
+#include "memzero.h"
+
+void drop_privileges(void)
+{
+ struct rlimit rss;
+ struct passwd pwd;
+ struct passwd* result = 0;
+ size_t pwdBufSize;
+ char* pwdBuf;
+ unsigned int s;
+ uid_t oldUID = getuid();
+ uid_t oldGID = getgid();
+ uid_t dropUID;
+ gid_t dropGID;
+ const char* user;
+ struct group* grp = 0;
+
+ /*
+ * Security: getting UID and GUID for nobody
+ */
+ pwdBufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (pwdBufSize == -1)
+ pwdBufSize = 16384;
+
+ pwdBuf = calloc(pwdBufSize, sizeof(char));
+ if (pwdBuf == NULL) {
+ fprintf(stderr, "unable to allocate buffer for pwdBuf\n");
+ exit(1);
+ }
+
+ user = options.user ? options.user : DROPTOUSER;
+ if (options.group) {
+ if (!(grp = getgrnam(options.group))) {
+ if (errno) {
+ fprintf(stderr, "Unable to get group %s: %s\n", options.group, strerror(errno));
+ } else {
+ fprintf(stderr, "Group %s not found, existing.\n", options.group);
+ }
+ exit(1);
+ }
+ }
+
+ s = getpwnam_r(user, &pwd, pwdBuf, pwdBufSize, &result);
+ if (result == NULL) {
+ if (s == 0) {
+ fprintf(stderr, "User %s not found, exiting.\n", user);
+ exit(1);
+ } else {
+ fprintf(stderr, "issue with getpwnnam_r call, exiting.\n");
+ exit(1);
+ }
+ }
+
+ dropUID = pwd.pw_uid;
+ dropGID = grp ? grp->gr_gid : pwd.pw_gid;
+ dnscap_memzero(pwdBuf, pwdBufSize);
+ free(pwdBuf);
+
+ /*
+ * Security section: setting memory limit and dropping privileges to nobody
+ */
+ getrlimit(RLIMIT_DATA, &rss);
+ if (mem_limit_set) {
+ rss.rlim_cur = mem_limit;
+ rss.rlim_max = mem_limit;
+ if (setrlimit(RLIMIT_DATA, &rss) == -1) {
+ fprintf(stderr, "Unable to set the memory limit, exiting\n");
+ exit(1);
+ }
+ }
+
+#if HAVE_SETRESGID
+ if (setresgid(dropGID, dropGID, dropGID) < 0) {
+ fprintf(stderr, "Unable to drop GID to %s: %s\n", options.group ? options.group : user, strerror(errno));
+ exit(1);
+ }
+#elif HAVE_SETREGID
+ if (setregid(dropGID, dropGID) < 0) {
+ fprintf(stderr, "Unable to drop GID to %s: %s\n", options.group ? options.group : user, strerror(errno));
+ exit(1);
+ }
+#elif HAVE_SETEGID
+ if (setegid(dropGID) < 0) {
+ fprintf(stderr, "Unable to drop GID to %s: %s\n", options.group ? options.group : user, strerror(errno));
+ exit(1);
+ }
+#endif
+
+#if HAVE_INITGROUPS
+ if (initgroups(pwd.pw_name, dropGID) < 0) {
+ fprintf(stderr, "Unable to init supplemental groups for %s: %s\n", user, strerror(errno));
+ exit(1);
+ }
+#elif HAVE_SETGROUPS
+ if (setgroups(0, NULL) < 0) {
+ fprintf(stderr, "Unable to drop supplemental groups: %s\n", strerror(errno));
+ exit(1);
+ }
+#endif
+
+#if HAVE_SETRESUID
+ if (setresuid(dropUID, dropUID, dropUID) < 0) {
+ fprintf(stderr, "Unable to drop UID to %s: %s\n", user, strerror(errno));
+ exit(1);
+ }
+#elif HAVE_SETREUID
+ if (setreuid(dropUID, dropUID) < 0) {
+ fprintf(stderr, "Unable to drop UID to %s: %s\n", user, strerror(errno));
+ exit(1);
+ }
+#elif HAVE_SETEUID
+ if (seteuid(dropUID) < 0) {
+ fprintf(stderr, "Unable to drop UID to %s: %s\n", user, strerror(errno));
+ exit(1);
+ }
+#endif
+
+ /*
+ * Testing if privileges are dropped
+ */
+ if (oldGID != getgid() && (setgid(oldGID) == 1 && setegid(oldGID) != 1)) {
+ fprintf(stderr, "Able to restore back to root, exiting.\n");
+ fprintf(stderr, "currentUID:%u currentGID:%u\n", getuid(), getgid());
+ exit(1);
+ }
+ if ((oldUID != getuid() && getuid() == 0) && (setuid(oldUID) != 1 && seteuid(oldUID) != 1)) {
+ fprintf(stderr, "Able to restore back to root, exiting.\n");
+ fprintf(stderr, "currentUID:%u currentGID:%u\n", getgid(), getgid());
+ exit(1);
+ }
+
+#ifdef USE_SECCOMP
+ if (use_seccomp == FALSE) {
+ return;
+ }
+
+#if 0
+ /*
+ * Setting SCMP_ACT_TRAP means the process will get
+ * a SIGSYS signal when a bad syscall is executed
+ * This is for debugging and should be monitored.
+ */
+
+ scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_TRAP);
+#endif
+
+ /*
+ * SCMP_ACT_KILL tells the kernel to kill the process
+ * when a syscall we did not filter on is called.
+ * This should be uncommented in production.
+ */
+ scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
+
+ if (ctx == NULL) {
+ fprintf(stderr, "Unable to create seccomp-bpf context\n");
+ exit(1);
+ }
+
+ int r = 0;
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(uname), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(munmap), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(close), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(lseek), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(select), 0);
+ r |= seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(stat), 0);
+
+ if (r != 0) {
+ fprintf(stderr, "Unable to apply seccomp-bpf filter\n");
+ seccomp_release(ctx);
+ exit(1);
+ }
+
+ r = seccomp_load(ctx);
+
+ if (r < 0) {
+ seccomp_release(ctx);
+ fprintf(stderr, "Unable to load seccomp-bpf filter\n");
+ exit(1);
+ }
+#endif
+}
+
+void daemonize(void)
+{
+ pid_t pid;
+#ifdef TIOCNOTTY
+ int i;
+#endif
+ if ((pid = fork()) < 0) {
+ logerr("fork failed: %s", strerror(errno));
+ exit(1);
+ } else if (pid > 0)
+ exit(0);
+ openlog("dnscap", 0, LOG_DAEMON);
+ if (setsid() < 0) {
+ logerr("setsid failed: %s", strerror(errno));
+ exit(1);
+ }
+#ifdef TIOCNOTTY
+ if ((i = open("/dev/tty", O_RDWR)) >= 0) {
+ ioctl(i, TIOCNOTTY, NULL);
+ close(i);
+ }
+#endif
+ logerr("Backgrounded as pid %u", getpid());
+}
diff --git a/src/daemon.h b/src/daemon.h
new file mode 100644
index 0000000..dc4fcc1
--- /dev/null
+++ b/src/daemon.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_daemon_h
+#define __dnscap_daemon_h
+
+void drop_privileges(void);
+void daemonize(void);
+
+#endif /* __dnscap_daemon_h */
diff --git a/src/dnscap.1.in b/src/dnscap.1.in
new file mode 100644
index 0000000..82a44fd
--- /dev/null
+++ b/src/dnscap.1.in
@@ -0,0 +1,1011 @@
+.\" Copyright (c) 2016-2021, OARC, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" 3. Neither the name of the copyright holder nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+.\" COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+.\" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.TH dnscap 1 "@PACKAGE_VERSION@" "dnscap"
+.SH NAME
+dnscap \- DNS network traffic capture utility
+.SH SYNOPSIS
+.SY dnscap
+.OP \-?VbNpd1g6fTIySMD
+.OP \-o option=value
+.OP \-i if
+.OP \-r file
+.OP \-l vlan
+.OP \-L vlan
+.OP \-u port
+.OP \-m [qun]
+.OP \-e [nytfsxir]
+.OP \-h [ir]
+.OP \-s [ir]
+.OP \-a host
+.OP \-z host
+.OP \-A host
+.OP \-Z host
+.OP \-Y host
+.OP \-w base
+.OP \-W suffix
+.OP \-k cmd
+.OP \-t lim
+.OP \-c lim
+.OP \-C lim
+.OP \-x pat
+.OP \-X pat
+.OP \-B datetime
+.OP \-E datetime
+.OP \-U str
+.OP \-q num|str
+.OP \-Q num|str
+.OP \-P "plugin.so ..."
+.SY dnscap
+.BR \-g " ..."
+.SY dnscap
+.BR \-w " ..."
+.YS
+.SH DESCRIPTION
+.B dnscap
+is a network capture utility designed specifically for DNS traffic.
+It normally produces binary data in
+.BR pcap (3)
+format, either on standard output or from files.
+This utility is similar to
+.BR tcpdump (1),
+but has finer grained packet recognition tailored to DNS transactions and
+protocol options.
+.B dnscap
+is expected to be used for gathering continuous research or audit traces.
+.SH OPTIONS
+.B dnscap
+has a large array of command line options and extended options
+.RB ( \-o
+.IR option=value ),
+and to make it easier to understand their usage they are categorized.
+.IP \(bu
+.I GENERIC
+section shows how to display help and version, and enable debugging.
+.IP \(bu
+.I RUNTIME
+section handles sandbox, privileges, start/stop and other runtime actions.
+.IP \(bu
+.I INPUT
+section deals with what interface to capture on, how to do it or if you want
+to read from a file.
+.IP \(bu
+.I OUTPUT
+section gives you options to do packet dumps, or get a diagnostic output,
+and to set limits or run external actions on intervals.
+.IP \(bu
+.I NETWORK
+section tweaks how and what is captured on the network and the individual
+layers.
+.IP \(bu
+.I DNS
+section lets you do filtering and modifications on the DNS message, along
+with pattern matching on the domain names.
+.IP \(bu
+Lastly,
+.I PLUGINS
+section gives you an overview on how
+.B dnscap
+can be extended by plugins and which plugins are bundled.
+.RE
+
+The only required options are
+.B \-g
+and
+.BR \-w ,
+at least one of them must be supplied to run.
+
+If neither
+.B \-r
+or
+.B \-i
+is used then the default is to capture on the first or all interfaces
+(depends on system, see
+.B \-i
+for more information).
+.\"
+.\"
+.\"
+.SS GENERIC
+.TP
+.B \-?
+Display short form help text about command line options and exit.
+.TP
+.B \-V
+Print version and exit.
+.TP
+.B \-d
+Tells a verbose story of options and patterns chosen, files opened, and so on.
+Multiple
+.B \-d
+options can be given to increase verbosity and frequency of trace messages.
+.\"
+.\"
+.\"
+.SS RUNTIME
+.TP
+.B \-y
+Enable Linux seccomp\-bpf sandbox if available (compile option).
+.TP
+.B \-b
+Run in background as daemon and drop privileges, using
+.IR set*uid() ,
+.I set*gid()
+functions, unless options
+.B \-N
+is given or only reading from files.
+.TP
+.BI "\-o user" =...
+Specify the user to drop privileges to (default nobody).
+.TP
+.BI "\-o group" =...
+Specify the group to drop privileges to (default nobody).
+.TP
+.B \-N
+Do not attempt to drop privileges, this is implicit if only reading
+offline pcap files.
+.TP
+.B \-S
+Print stats counters on standard error when closed the packet dump file
+(see
+.BR \-w ).
+.TP
+.BI "\-B " datetime
+Start collecting at a specific time.
+.I datetime
+should be specified as "YYYY\-MM\-DD HH:MM:SS".
+The program will
+.BR sleep (3)
+until the start time, or it will skip all packets related to an earlier
+time if used with an offline
+.BR pcap (3)
+file, and then begin capturing/processing packets.
+.TP
+.BI "\-E " datetime
+Stop collecting at a specific time.
+.I datetime
+should be specified as "YYYY\-MM\-DD HH:MM:SS".
+.B dnscap
+will exit when it sees a packet (live or offline
+.BR pcap (3)
+file) with timestamp greater or equal to it.
+.\"
+.\"
+.\"
+.SS INPUT
+.TP
+.BI "\-r " file
+Select an offline
+.BR pcap (3)
+file produced by this utility or by
+.BR tcpdump (1)
+(or simiar tools) as the input packet source.
+Can be given as "\-" to indicate standard input.
+.TP
+.BI "\-i " if
+Select an interface to be monitored.
+On BSD systems, the default is the first interface that was configured at
+system boot time.
+On Linux systems, the default is to monitor all interfaces.
+More than one interface may be selected which will cause output to be
+interleaved from all selected interfaces.
+.TP
+.B \-p
+Asks that the interface not be put into promiscuous mode.
+Note that even without this option, the interface could be in promiscuous
+mode for some other reason.
+.TP
+.B \-M
+Enable monitor mode on interfaces.
+.TP
+.B \-D
+Enable immediate mode on interfaces.
+
+Option
+.BR \-p ,
+.B \-M
+and
+.B \-D
+are libpcap specific options, see
+.BR pcap (3)
+for more information on their meaning.
+.TP
+.BI "\-o " pcap_buffer_size=num
+Set the
+.BR pcap (3)
+buffer size to
+.I num
+bytes when capturing packets.
+This can be used to increase the buffer so that packets are not missed/dropped
+while processing or rotating packet dumps.
+.TP
+.BI "\-o " use_layers=yes
+Enable pcap\-thread layers, this will let pcap\-thread parse the network layers
+and call back with UDP, TCP or ICMP traffic.
+
+This options is required for IP defragmentation (see
+.BI "\-o " defrag_ipv4=yes
+and
+.B \-o
+.IR defrag_ipv6=yes ),
+TCP reassembly (see
+.B \-o
+.IR reassemble_tcp=yes )
+and parsing ongoing TCP sessions (see
+.B \-o
+.IR parse_ongoing_tcp=yes ).
+.\"
+.\"
+.\"
+.SS OUTPUT
+For details on the diagnostic output and the different dump formats that
+exists, please see OUTPUT FORMATS below.
+Some formats have their own extended options, these are also listed in that
+section.
+.TP
+.BI "\-o " dump_format=format
+Specify the output
+.I format
+to use.
+Default is
+.IR pcap .
+.TP
+.B \-g
+Produce diagnostic output to standard error, showing the presentation form
+of DNS messages which passed through all of the filters.
+If
+.B \-w
+is also used, then every message will be dumped in both binary and
+presentation form.
+.TP
+.BI "\-w " base
+Dump the captured packets to successive binary files in
+.BR pcap (3)
+format with DLT_RAW datalink type.
+Each file will have a name like "%s.%s.%06u" where the first %s is
+.IR base ,
+second %s is the time as hours, minutes and seconds (%H%M%S), and %06u is
+the microseconds.
+The argument "\-" may be given to send the binary output to standard output.
+
+By default,
+.B dnscap
+will close its packet dump file only when interrupted.
+You can change that behavior with options
+.BR \-t ,
+.BR \-c ,
+and
+.BR \-C .
+.TP
+.BI "\-W " suffix
+The provided suffix is added to the dump file name, e. g.: ".pcap".
+If the suffix ends with ".gz" then files will be automatically gzip
+compressed.
+If gzip compression is requested but not supported (i.e. because of lack of
+system support) an error will be generated.
+.TP
+.B \-1
+Flush the output after every packet.
+Mostly this is useful when the packet dump is standard output, and has been
+piped to
+.BR tcpdump (1).
+.TP
+.BI "\-t " lim
+Set a time interval, specified in seconds.
+When writing to a file, the packet dump file will be closed and reopened
+(creating a new dump file) when time() %
+.I lim
+is zero.
+Note that the first file will usually be shorter than
+.I lim
+seconds.
+If the packet dump file is standard output or if
+.B \-g
+is used, then
+.B dnscap
+will exit after the first interval.
+.TP
+.BI "\-c " lim
+Set a size limit, measured in packets.
+When writing to a file, the packet dump file will be closed when
+.I lim
+number of packets has been written.
+If option
+.B \-k
+is
+.I "not used"
+(see below) or the packet dump file is standard output, or if
+.B \-g
+is used, then
+.B dnscap
+will exit after reaching the limit.
+.TP
+.BI "\-C " lim
+Set a size limit, measured in bytes.
+When writing to a file, the packet dump file will be closed when
+.I lim
+number of bytes (or larger then) has been written.
+If option
+.B \-k
+is
+.I "not used"
+or the packet dump file is standard output, or if
+.B \-g
+is used, then
+.B dnscap
+will exit after reaching the limit.
+
+When using the above options
+.BR \-t ,
+.BR \-c ,
+and
+.B \-C
+together, the order of applying them are
+.I 1)
+time interval,
+.I 2)
+number of packets and
+.I 3)
+number of bytes.
+.TP
+.BI "\-k " cmd
+After each dump file specified by
+.B \-w
+is closed, this command will be executed in a non\-blocking subprocess with
+the file name as its one argument.
+This can be used to submit the finished file to other processing systems.
+
+If this option is used together with
+.B \-c
+or
+.B \-C
+and the output is a packet dump file, then it will be reopened (creating
+a new dump file) before continuing.
+.\"
+.\"
+.\"
+.SS NETWORK
+.TP
+.BI "\-U " str
+Append "and
+.IR str """"
+to the BPF/pcap filter.
+.TP
+.BI "\-o " bpf_hosts_apply_all=yes
+This changes the BPF generation so that any host restriction will come
+after ICMP, fragments, ports or DNS section to allow it to apply for ICMP
+and fragments also.
+The default behavior is to only apply hosts to the ports or DNS section.
+.TP
+.B \-6
+Used to suppress the use of packet filter patterns that cause problems when
+processing IPv6 packets.
+As of version 2.0.0 this option is deprecated and filters have been reworked
+to only match IPv4 packets, IPv6 filtering are processed at a higher level.
+.TP
+.B \-f
+Selects fragments (which could include unrelated flows since fragments do not
+contain port numbers), and includes fragments in the binary output.
+Necessary if you intend to do IP Reassembly.
+Note that all fragments will be collected, not just those using the DNS port
+number, since fragments don't have port numbers.
+Beware this option if you also handle a lot of NFS traffic.
+.TP
+.B \-T
+Selects TCP packets.
+SYN, FIN, and RST packets are collected if they pass the layer 2, port, and
+host filters (although hosts need not be in the correct direction); they are
+not tested against filter options that require a DNS header such as
+.BR \-m ,
+.BR \-s ,
+or
+.BR \-e .
+All DNS messages in the stream is captured if it passes all filter options.
+
+Each TCP packet with payload will be tagged as DNS, unless
+.BI "\-o " reassemble_tcp=yes
+is used, with the support of having the DNS length arrive before the message
+in an own packet.
+Ongoing TCP connections can be inspected by using
+.B \-o
+.IR parse_ongoing_tcp=yes .
+TCP packets are processed as they arrive so missing, unaligned data or DNS
+message split over multiple packets will produce parsing errors.
+Using extended option
+.BI "\-o " allow_reset_tcpstate=yes
+may allow
+.B dnscap
+to recover from these scenarios.
+.TP
+.B \-I
+Select ICMP and ICMPv6 packets.
+.TP
+.BI "\-l " vlan
+Captures only 802.1Q encapsulated packets, and selects specific vlans to be
+monitored.
+Can be specified more than once to select multiple vlans.
+VLAN id 4095 can be used to specify all vlans.
+.TP
+.BI "\-L " vlan
+Captures 802.1Q encapsulated packets matching the specified vlans AND
+packets without VLAN tags.
+Can be specified more than one to select multiple vlans.
+VLAN id 4095 can be used to specify all vlans.
+.TP
+.BI "\-u " port
+Capture only packets on this UDP port, and treat as DNS traffic.
+The default port is 53.
+Note that there is no way to select multiple UDP ports, as would be
+necessary to capture both DNS (port 53) and mDNS (port 5353) traffic.
+
+.TP
+.BI "\-o " defrag_ipv4=yes
+.TQ
+.BI "\-o " defrag_ipv6=yes
+Enable IPv4/IPv6 defragmentation in pcap-thread, requires
+.B \-o
+.IR use_layers=yes .
+
+When enabled, the following options are also available:
+.RS
+.TP
+.BI "\-o " max_ipv4_fragments=num
+Set the maximum fragmented IPv4 packets
+.RI ( num )
+to track for reassembly, if the limit is reach then all other fragmented
+packets will not be reassembled.
+.TP
+.BI "\-o " max_ipv4_fragments_per_packet=num
+Set the maximum fragments
+.RI ( num )
+per tracked IPv4 packet to keep for reassembly.
+.TP
+.BI "\-o " max_ipv6_fragments=num
+Set the maximum fragmented IPv6 packets
+.RI ( num )
+to track for reassembly, if the limit is reach then all other fragmented
+packets will not be reassembled.
+.TP
+.BI "\-o " max_ipv6_fragments_per_packet=num
+Set the maximum fragments
+.RI ( num )
+per tracked IPv6 packet to keep for reassembly.
+.RE
+.TP
+.BI "\-o " parse_ongoing_tcp=yes
+.B dnscap
+will normally not look at TCP unless it sees the start of it.
+This enables state tracking when a new TCP stream is found but no SYN/ACK
+has been seen.
+Each TCP packet with payload will be tagged as DNS.
+.TP
+.BI "\-o " allow_reset_tcpstate=yes
+Allow the TCP state to be reseted, this is used in diagnostic output and
+plugins when parsing the DNS in a TCP packet fails to try and recover from
+missing or unaligned data.
+.TP
+.BI "\-o " reassemble_tcp=yes
+Enable reassembly of TCP packets, this will not parse each packet as an own
+DNS message but will store TCP segments until they can be reassembled.
+It will expect the DNS message length to come first and then wait for the
+full length of data to arrive until passing to outputs and plugins.
+
+Since the number of saved segments are limited and fixed, if the TCP steam
+becomes corrupt then processing may stop.
+Recovering from this can be done by enabling
+.Ar allow_reset_tcpstate=yes
+which will reset state and free all saved segments to try and start over.
+.TP
+.BI "\-o " reassemble_tcp_faultreset=num
+This controls the number of faults
+.RI ( num )
+that can happen before the state is reseted (as described above), faults
+are if the segments buffer are full or if the sequence is outside the
+TCP window.
+The default is zero which means it will reset the state as soon as the
+segment buffer is full.
+.TP
+.BI "\-o " reassemble_tcp_bfbparsedns=yes
+Enable an additional layer (experimental) of reassembly that uses LDNS to
+parse the payload before accepting it.
+If the DNS is invalid it will move 2 bytes within the payload and treat it
+as a new payload, taking the DNS length again and restart the process.
+.\"
+.\"
+.\"
+.SS DNS
+.TP
+.BI "\-m " [qun]
+Capture only messages of designated types;
+.IR q uery,
+.IR u pdate,
+and
+.IR n otify).
+Multiple types can be given at the same time, for example
+.B "\-m qn"
+will select query and notify messages.
+Multiple
+.B \-m
+can not be used to specify multiple types.
+Default is query.
+.TP
+.BI "\-e " [nytfsxir]
+Among responses, consider nonzero DNS TC or DNS RCODE to indicate an error,
+and select only responses which do not have
+.RI ( n ),
+or which have
+.RI ( y ),
+these conditions.
+The default is to only select non\-errors among responses.
+If both non\-error and error responses are to be selected, specify both the
+.I n
+and
+.I y
+options here.
+
+To be more specific, use one or more condition\-specific options, as follows:
+.RS
+.TP
+.B n
+no error
+.TP
+.B y
+some error
+.TP
+.B t
+truncated response (TC bit)
+.TP
+.B f
+format error (rcode 1)
+.TP
+.B s
+server failure (rcode 2)
+.TP
+.B x
+no such name (rcode 3)
+.TP
+.B i
+not implemented (rcode 4)
+.TP
+.B r
+refusal (rcode 5)
+.RE
+.TP
+.BI "\-h " ir
+Hide
+.IR i nitiator
+or
+.IR r esponder
+of each captured transaction.
+Hiding an initiator means wiping out the address and port number.
+Hiding a responder means to wipe out the address only.
+This wiping occurs on the copy of the packet sent to the
+.BR pcap (3)
+dump output, and both the IP and UDP checksums will be recomputed in that case.
+.TP
+.BI "\-s " ir
+Select messages which are
+.IR i nitiations
+and/or
+.IR r esponses.
+This is done by checking the DNS header flag QR and source/destination port
+against the DNS port (see
+.BR \-u ).
+Default is both.
+.TP
+.BI "\-a " host
+Capture only transactions having these initiators.
+Can be specified more than once to select multiple initiators.
+If a host name is used, then all of that host's addresses whether IPv4 or
+IPv6 are added to the recognition pattern.
+.TP
+.BI "\-z " host
+Capture only transactions having these responders.
+Can be specified more than once to select multiple responders.
+If a host name is used, then all of that host's addresses whether IPv4 or
+IPv6 are added to the recognition pattern.
+.TP
+.BI "\-A " host
+Capture only transactions NOT having these initiators.
+.TP
+.BI "\-Z " host
+Capture only transactions NOT having these responders.
+.TP
+.BI "\-Y " host
+Drop responses having these responders.
+Similar to
+.B \-Z
+in spirit.
+However,
+.B \-Y
+applies only to responses and does not cause any additions to the BPF filter
+string.
+.TP
+.BI "\-x " pat
+If one or more
+.B \-x
+options are provided, then DNS messages will only be selected if the
+printable representation of the QNAME or any RR matches at least one of the
+provided
+.I pat
+patterns.
+.TP
+.BI "\-X " pat
+If one or more
+.B \-X
+options are provided, then DNS messages matching these patterns will not
+be selected.
+
+If both options are used then the message must first be matched by
+.B \-x
+and then not matched by all
+.B \-X
+regex.
+See
+.BR regex (3)
+and
+.BR re_format (7)
+for more information about extended regular expression syntax.
+.TP
+.BI "\-q " num|str
+Only select DNS messages where QTYPE matches the specified type.
+Can not be used together with
+.BR \-Q .
+.TP
+.BI "\-Q " num|str
+Only select DNS messages where QTYPE does not matches the specified type.
+Can not be used together with
+.BR \-q .
+.\"
+.\"
+.\"
+.SS PLUGINS
+.TP
+.BI "\-P " "/path/to/plugin.so ..."
+Load and use the specified plugin, full path to plugin must be supplied.
+Any options given after this are sent to the plugin.
+
+Once a double dash, "\-\-", is encountered after
+.BR \-P ,
+processing of the command line options will go back to
+.BR dnscap .
+
+Using this you can chain and use multiple plugins at once:
+
+.EX
+ \-P /path/to/plugin_one.so \-a opt \-\- \-P /path/to/plugin_two.so \-b opt
+.EE
+
+To show the plugins option help, run it with
+.BR \-? :
+
+.EX
+ \-P /path/to/plugin_one.so \-?
+.EE
+
+Plugins are loaded, executed and given the packets to process in the
+order given on command line.
+
+These bundled plugins are installed in @pkglibdir@:
+.RS
+.TP
+.B anonaes128.so
+Anonymize IP addresses using AES128.
+.TP
+.B anonmask.so
+Pseudo\-anonymize IP addresses by masking them.
+.TP
+.B cryptopan.so
+Anonymize IP addresses using an extension to Crypto\-PAn (College of
+Computing, Georgia Tech) made by David Stott (Lucent).
+.TP
+.B cryptopant.so
+Anonymize IP addresses using cryptopANT, a different implementation of
+Crypto\-PAn made by the ANT project at USC/ISI.
+.TP
+.B eventlog.so
+Output DNS activity as log events, including IP addresses from query responses.
+.TP
+.B ipcrypt.so
+Anonymize IP addresses using ipcrypt create by Jean\-Philippe Aumasson.
+.TP
+.B pcapdump.so
+Dump DNS into a PCAP with some filtering options.
+.TP
+.B royparse.so
+Splits a PCAP into two streams; queries in PCAP format and responses in
+ASCII format.
+.TP
+.B rssm.so
+Root Server Scaling Measurement plugin.
+.TP
+.B rzkeychange.so
+RFC8145 key tag signal collection and reporting plugin.
+.TP
+.B txtout.so
+Dump DNS as one\-line text.
+.RE
+.\"
+.\"
+.\"
+.SH OUTPUT FORMATS
+Beside diagnostic and PCAP output, other output formats might be available
+depending on compile time support.
+
+Recognized formats are:
+.TP
+.B cbor
+Uses tinycbor library to write CBOR objects that are based on DNS\-in\-JSON
+draft by Paul Hoffman.
+.TP
+.B cds
+CBOR DNS Stream format, see
+.I https://github.com/DNS\-OARC/dnscap/blob/master/CBOR_DNS_STREAM.md
+for details and below for all extended options related to this format.
+.TP
+.B pcap
+This uses the pcap library to output the captured DNS packets. (default)
+.TP
+.B diagnostic
+This is the output produced by
+.BR \-g ,
+and is meant to be parse\-able.
+It is broken up into multiple lines with a backslash at the end to indicate
+that the line continues on the next.
+
+First line contains packet and capturing information:
+
+.EX
+ [<pktsize>] <date> <timestamp> [<pktnum> <file|interface> <vlanid>]
+.EE
+
+Second line shows IP information or if the packet is a fragment:
+
+.EX
+ [<srcip>].<srcport> \-> [<dstip>].<dstport>
+.EE
+.EX
+ ;: [<srcip>] \-> [<dstip>] (frag)
+.EE
+
+If the packet contains DNS information then the next line will show the DNS
+header information:
+
+.EX
+ dns <opcode>,<rcode>,<id>,<flags>
+.EE
+
+Next are the 4 sections of the DNS, each section is prefixed by the number
+of records and each record and section are separated by space.
+Below are a few example, first is just a query, second has just one answer
+and the last has also authority and additional records.
+
+.EX
+ 1 example.com.,IN,A 0 0 0
+.EE
+
+.EX
+ 1 example.com.,IN,A \\
+ 1 example.com.,IN,A,47,127.0.0.1 0 0
+.EE
+
+.EX
+ 1 example.com.,IN,A \\
+ 1 example.com.,IN,A,263,127.0.0.1 \\
+ 4 example.com.,IN,NS,157794,ns1.example.com. \\
+ example.com.,IN,NS,157794,ns4.example.com. \\
+ example.com.,IN,NS,157794,ns3.example.com. \\
+ example.com.,IN,NS,157794,ns2.example.com. \\
+ 4 ns2.example.com.,IN,A,157794,127.0.0.1 \\
+ ns1.example.com.,IN,A,331796,127.0.0.1 \\
+ ns3.example.com.,IN,A,157794,127.0.0.1 \\
+ ns4.example.com.,IN,A,157794,127.0.0.1
+.EE
+
+Each DNS record contains the following:
+
+.EX
+ <fqdn>,<class>,<type>[,<ttl>[,<additional information>]]
+.EE
+
+Additional information will be displayed for SOA, A, AAAA, MX, NS, PTR,
+CNAME and OPT records containing EDNS0.
+.SS CBOR
+.TP
+.BI "\-o " cbor_chunk_size=bytes
+Specify the number of
+.I bytes
+of CBOR to construct before flushing the output, must be a non zero
+positive number.
+.SS CBOR DNS STREAM (CDS)
+.TP
+.BI "\-o " cds_cbor_size=bytes
+Number of
+.I bytes
+of memory to use before flushing to file.
+.TP
+.BI "\-o " cds_message_size=bytes
+Number of
+.I bytes
+of memory to use for each DNS packet.
+.TP
+.BI "\-o " cds_max_rlabels=num
+Number of labels
+.RI ( num )
+to keep in the reverse label index.
+.TP
+.BI "\-o " cds_min_rlabel_size=num
+The minimum size of a label
+.RI ( num )
+to be able to use the reverse label index.
+.TP
+.BI "\-o " cds_use_rdata_index=yes
+Use the resource data index, default is no.
+.TP
+.BI "\-o " cds_rdata_index_min_size=num
+The minimum size of the data
+.RI ( num )
+to be able to use the resource data index.
+.TP
+.BI "\-o " cds_use_rdata_rindex=yes
+Use the resource data reverse index, default is no.
+.TP
+.BI "\-o " cds_rdata_rindex_size=num
+Number of resource data
+.RI ( num )
+to keep in the resource data reverse index.
+.TP
+.BI "\-o " cds_rdata_rindex_min_size=num
+The minimum size of the data
+.RI ( num )
+to be able to use the resource data reverse index.
+.SH EXAMPLES
+In
+.BR dnscap 's
+simplest form, the output can be piped to
+.BR tcpdump (1)
+as in:
+
+.EX
+ dnscap -w - | tcpdump -r -
+.EE
+
+You can safely add the
+.B \-d
+option since the diagnostic output resulting from
+.B \-d
+goes to standard error rather than standard output.
+
+The more interesting use for
+.B dnscap
+is long term or continuous data collection.
+Assuming a shell script called
+.I dnscap-upload
+whose function is to transfer a
+.BR pcap (3)
+format file to an analytics system and then remove the local copy of it,
+then a name server operating system startup could invoke
+.B dnscap
+for continuous DNS auditing using a command like:
+
+.EX
+ dnscap -m qun -h i -z f.root-servers.net \\
+ -w /var/local/dnscaps/f-root -t 1800 \\
+ -k /usr/local/sbin/dnscap-upload
+.EE
+
+This will capture all query, update and notify messages where the responder
+is f.root-servers.net and the initiators will be hidden.
+The dump files will be saved in /var/local/dnscaps/ on a 30 minute (1800
+seconds) interval.
+After each interval the
+.I dnscap-upload
+script will be executed.
+
+A bizarre but actual example which combines almost all features of
+.B dnscap
+is:
+
+.EX
+ dnscap -d -w - -1 -i em0 -l 0 -x ^7 | \\
+ dnscap -d -r - -X spamhaus -g -l 0
+.EE
+
+Here, we're looking for all messages having a QNAME or RR beginning with the
+decimal digit "7", but we don't want to see anything containing "spamhaus".
+The interface is tagged, and since only one interface is selected, the output
+stream from the first
+.B dnscap
+will also be tagged, thus we need
+.BI "\-l " 0
+on both
+.B dnscap
+commands.
+.SH COMPATIBILITY NOTES
+If
+.B dnscap
+produces no output, it's probably due to some kind of bug in the kernel's
+.BR bpf (4)
+module or in the
+.BR pcap (3)
+library.
+
+You may need the
+.BI "\-l " 0
+,
+.BI "\-l " 4095
+or
+.BI "\-L " 4095
+options.
+
+To diagnose "no output", use the
+.B \-d
+and
+.B \-g
+options to find out what BPF program is being internally generated, and
+then cut/paste this BPF program and use
+.BR tcpdump (1)
+to see if it likewise produces no output.
+
+You can also run
+.BR tcpdump (1)
+with
+.B \-e
+to see the link-level headers in order to see if the traffic is encapsulated.
+.SH SEE ALSO
+.BR tcpdump (1),
+.BR pcap (3),
+.BR regex (3),
+.BR bpf (4),
+.BR re_format (7)
+.SH AUTHORS
+.B dnscap
+was written by Paul Vixie (ISC) with help from Duane Wessels,
+Kevin Brintnall, and others too numerous to mention.
+It's currently maintained by Jerry Lundström, DNS\-OARC.
+.LP
+.RS
+.I https://www.dns\-oarc.net/
+.RE
+.LP
+.SH BUGS
+For issues and feature requests please use:
+.LP
+.RS
+\fI@PACKAGE_URL@\fP
+.RE
+.LP
+For question and help please use:
+.LP
+.RS
+\fI@PACKAGE_BUGREPORT@\fP
+.RE
+.LP
diff --git a/src/dnscap.c b/src/dnscap.c
new file mode 100644
index 0000000..56e1ac1
--- /dev/null
+++ b/src/dnscap.c
@@ -0,0 +1,249 @@
+/* dnscap - DNS capture utility
+ *
+ * By Paul Vixie (ISC) and Duane Wessels (Measurement Factory), 2007.
+ */
+
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "dnscap.h"
+#include "args.h"
+#include "bpft.h"
+#include "pcaps.h"
+#include "dumper.h"
+#include "daemon.h"
+#include "log.h"
+#include "sig.h"
+
+#if defined(HAVE_LIBCRYPTO) && defined(HAVE_OPENSSL_CONF_H) && defined(HAVE_OPENSSL_ERR_H) && defined(HAVE_OPENSSL_EVP_H)
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#define INIT_OPENSSL 1
+#endif
+
+plugin_list plugins;
+const char* ProgramName = "amnesia";
+int dumptrace = 0;
+int flush = FALSE;
+vlan_list vlans_excl;
+vlan_list vlans_incl;
+unsigned msg_wanted = MSG_QUERY;
+unsigned dir_wanted = DIR_INITIATE | DIR_RESPONSE;
+unsigned end_hide = 0U;
+unsigned err_wanted = ERR_NO | ERR_YES; /* accept all by default */
+tcpstate_list tcpstates;
+int tcpstate_count = 0;
+endpoint_list initiators, not_initiators;
+endpoint_list responders, not_responders;
+endpoint_list drop_responders; /* drops only responses from these hosts */
+myregex_list myregexes;
+mypcap_list mypcaps;
+mypcap_ptr pcap_offline = NULL;
+const char* dump_base = NULL;
+char* dump_suffix = 0;
+char* extra_bpf = NULL;
+enum dump_type dump_type = nowhere;
+enum dump_state dump_state = dumper_closed;
+const char* kick_cmd = NULL;
+unsigned limit_seconds = 0U;
+time_t next_interval = 0;
+unsigned limit_packets = 0U;
+size_t limit_pcapfilesize = 0U;
+pcap_t* pcap_dead;
+pcap_dumper_t* dumper;
+time_t dumpstart;
+unsigned msgcount;
+size_t capturedbytes = 0;
+char * dumpname, *dumpnamepart;
+char* bpft;
+unsigned dns_port = DNS_PORT;
+int promisc = TRUE;
+int monitor_mode = FALSE;
+int immediate_mode = FALSE;
+int background = FALSE;
+char errbuf[PCAP_ERRBUF_SIZE];
+int wantgzip = 0;
+int wantfrags = FALSE;
+int wanticmp = FALSE;
+int wanttcp = FALSE;
+int preso = FALSE;
+#ifdef USE_SECCOMP
+int use_seccomp = FALSE;
+#endif
+int main_exit = FALSE;
+int alarm_set = FALSE;
+time_t start_time = 0;
+time_t stop_time = 0;
+int print_pcap_stats = FALSE;
+uint64_t pcap_drops = 0;
+my_bpftimeval last_ts = { 0, 0 };
+unsigned long long mem_limit = (unsigned)MEM_MAX; /* process memory limit */
+int mem_limit_set = 1; /* TODO: Should be configurable */
+const char DROPTOUSER[] = "nobody";
+pcap_thread_t pcap_thread = PCAP_THREAD_T_INIT;
+int only_offline_pcaps = FALSE;
+int dont_drop_privileges = FALSE;
+options_t options = OPTIONS_T_DEFAULTS;
+
+ldns_rr_type match_qtype = 0, nmatch_qtype = 0;
+
+int main(int argc, char* argv[])
+{
+ struct plugin* p;
+ struct timeval now;
+
+#ifdef INIT_OPENSSL
+ ERR_load_crypto_strings();
+ OpenSSL_add_all_algorithms();
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ OPENSSL_config(0);
+#endif
+#endif
+
+ parse_args(argc, argv);
+ gettimeofday(&now, 0);
+ if (!only_offline_pcaps && start_time) {
+ if (now.tv_sec < start_time) {
+ char when[100];
+ struct tm tm;
+ gmtime_r(&start_time, &tm);
+ strftime(when, sizeof when, "%F %T", &tm);
+ fprintf(stderr, "Sleeping for %d seconds until %s UTC\n",
+ (int)(start_time - now.tv_sec), when);
+ sleep(start_time - now.tv_sec);
+ fprintf(stderr, "Awake.\n");
+ }
+ }
+ prepare_bpft();
+ open_pcaps();
+ if (dump_type == to_stdout) {
+ if (dumper_open(now)) {
+ fprintf(stderr, "%s: dumper_open() to stdout failed\n", ProgramName);
+ exit(1);
+ }
+ }
+ INIT_LIST(tcpstates);
+
+ if (!dont_drop_privileges && !only_offline_pcaps) {
+ drop_privileges();
+ }
+
+ for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
+ if (p->start)
+ if (0 != (*p->start)(logerr)) {
+ logerr("%s_start returned non-zero", p->name);
+ exit(1);
+ }
+ }
+ if (dump_type == nowhere)
+ dumpstart = time(NULL);
+ if (background)
+ daemonize();
+
+#if HAVE_PTHREAD
+ /*
+ * Defer signal setup until we have dropped privileges and daemonized,
+ * otherwise signals might not reach us because different threads
+ * are running under different users/access
+ */
+ {
+ sigset_t set;
+ int err;
+ pthread_t thread;
+
+ sigfillset(&set);
+ if ((err = pthread_sigmask(SIG_BLOCK, &set, 0))) {
+ logerr("pthread_sigmask: %s", strerror(err));
+ exit(1);
+ }
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGHUP);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGALRM);
+ sigaddset(&set, SIGTERM);
+ sigaddset(&set, SIGQUIT);
+
+ if ((err = pthread_create(&thread, 0, &sigthread, (void*)&set))) {
+ logerr("pthread_create: %s", strerror(err));
+ exit(1);
+ }
+ }
+#else
+ {
+ sigset_t set;
+
+ sigfillset(&set);
+ sigdelset(&set, SIGHUP);
+ sigdelset(&set, SIGINT);
+ sigdelset(&set, SIGALRM);
+ sigdelset(&set, SIGTERM);
+ sigdelset(&set, SIGQUIT);
+
+ if (sigprocmask(SIG_BLOCK, &set, 0)) {
+ logerr("sigprocmask: %s", strerror(errno));
+ exit(1);
+ }
+ }
+
+ setsig(SIGHUP, TRUE);
+ setsig(SIGINT, TRUE);
+ setsig(SIGALRM, FALSE);
+ setsig(SIGTERM, TRUE);
+ setsig(SIGQUIT, TRUE);
+#endif
+
+ while (!main_exit)
+ poll_pcaps();
+ /* close PCAPs after dumper_close() to have statistics still available during dumper_close() */
+ if (dumper_opened == dump_state)
+ (void)dumper_close(last_ts);
+ close_pcaps();
+ for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
+ if (p->stop)
+ (*p->stop)();
+ }
+ options_free(&options);
+
+#ifdef INIT_OPENSSL
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
+#endif
+
+ return 0;
+}
diff --git a/src/dnscap.h b/src/dnscap.h
new file mode 100644
index 0000000..dd03ddd
--- /dev/null
+++ b/src/dnscap.h
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __dnscap_dnscap_h
+#define __dnscap_dnscap_h
+
+#ifdef __linux__
+#define _GNU_SOURCE
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h> /* for open() */
+#include <sys/ioctl.h> /* for TIOCNOTTY */
+#include <stdarg.h>
+#include <syslog.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#if HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+#ifdef __linux__
+#define __FAVOR_BSD
+#include <net/ethernet.h>
+#ifdef USE_SECCOMP
+#include <seccomp.h>
+#endif
+#endif
+
+#ifdef __FreeBSD__
+#include <net/ethernet.h>
+#endif
+
+#ifdef __NetBSD__
+#include <net/ethertypes.h>
+#include <net/if.h>
+#include <net/if_ether.h>
+#endif
+
+#ifdef __OpenBSD__
+#include <net/ethertypes.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef __APPLE__
+#include <net/ethernet.h>
+#include <net/bpf.h>
+#endif
+
+#ifdef __hpux
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#define ETHER_HDR_LEN ETHER_HLEN
+#define __BIT_TYPES_DEFINED
+#define __HPLX
+#endif
+
+#ifdef __SVR4
+#include <stdarg.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/if_ether.h>
+#include "snprintf.h"
+#define IP_OFFMASK 0x1fff
+#define u_int32_t uint32_t
+#ifndef ETHER_HDR_LEN
+#define ETHER_HDR_LEN 14
+#endif
+#endif
+
+#ifndef MY_BPFTIMEVAL
+#define MY_BPFTIMEVAL timeval
+#endif
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <arpa/nameser.h>
+#if HAVE_ARPA_NAMESER_COMPAT_H
+#include <arpa/nameser_compat.h>
+#endif
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pcap.h>
+#include <regex.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+#if HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include <ldns/ldns.h>
+
+#ifndef IPV6_VERSION
+#define IPV6_VERSION 0x60
+#endif
+#ifndef IPV6_VERSION_MASK
+#define IPV6_VERSION_MASK 0xf0
+#endif
+
+#define UDP10_QR_MASK 0x80
+#define UDP10_QR_SHIFT 7
+#define UDP10_OP_MASK 0x78
+#define UDP10_OP_SHIFT 3
+#define UDP10_AA_MASK 0x04
+#define UDP10_AA_SHIFT 2
+#define UDP10_TC_MASK 0x02
+#define UDP10_TC_SHIFT 1
+#define UDP10_RD_MASK 0x01
+#define UDP10_RD_SHIFT 0
+
+#define UDP11_RC_MASK 0x0f
+#define UDP11_RC_SHIFT 0
+
+#define MSG_QUERY 0x0001
+#define MSG_UPDATE 0x0002
+#define MSG_NOTIFY 0x0004
+
+#define ERR_TRUNC 0x0001
+#define ERR_RCODE_BASE 0x0002
+#define ERR_NO (ERR_RCODE_BASE << 0)
+#define ERR_FORMERR (ERR_RCODE_BASE << 1)
+#define ERR_SERVFAIL (ERR_RCODE_BASE << 2)
+#define ERR_NXDOMAIN (ERR_RCODE_BASE << 3)
+#define ERR_NOTIMPL (ERR_RCODE_BASE << 4)
+#define ERR_REFUSED (ERR_RCODE_BASE << 5)
+#define ERR_YES (0xffffffff & ~ERR_NO)
+
+#define END_INITIATOR 0x0001
+#define END_RESPONDER 0x0002
+
+#define HIDE_INET "\177\177\177\177"
+#define HIDE_INET6 "\177\177\177\177\177\177\177\177" \
+ "\177\177\177\177\177\177\177\177"
+#define HIDE_PORT 54321
+
+#ifndef ETHERTYPE_VLAN
+#define ETHERTYPE_VLAN 0x8100
+#endif
+#ifndef ETHERTYPE_IPV6
+#define ETHERTYPE_IPV6 0x86DD
+#endif
+
+#define THOUSAND 1000
+#define MILLION (THOUSAND * THOUSAND)
+#define MAX_VLAN 4095
+#define DNS_PORT 53
+#define TO_MS 1
+#define SNAPLEN 65536
+#define TRUE 1
+#define FALSE 0
+#define REGEX_CFLAGS (REG_EXTENDED | REG_ICASE | REG_NOSUB | REG_NEWLINE)
+#define MAX_TCP_WINDOW (0xFFFF << 14)
+#define MEM_MAX 20000000000 /* SETTING MAX MEMORY USAGE TO 2GB */
+
+#define ISC_CHECK_NONE 1
+#include "isc/list.h"
+#include "isc/assertions.h"
+
+#include "dnscap_common.h"
+
+#include "dump_dns.h"
+#include "dump_cbor.h"
+#include "dump_cds.h"
+#include "options.h"
+#include "pcap-thread/pcap_thread.h"
+
+struct text {
+ LINK(struct text)
+ link;
+ size_t len;
+ char* text;
+};
+typedef struct text* text_ptr;
+typedef LIST(struct text) text_list;
+#define text_size(len) (sizeof(struct text) + len)
+
+struct mypcap {
+ LINK(struct mypcap)
+ link;
+ const char* name;
+ struct pcap_stat ps0, ps1;
+ uint64_t drops;
+};
+typedef struct mypcap* mypcap_ptr;
+typedef LIST(struct mypcap) mypcap_list;
+
+struct vlan {
+ LINK(struct vlan)
+ link;
+ unsigned vlan;
+};
+typedef struct vlan* vlan_ptr;
+typedef LIST(struct vlan) vlan_list;
+
+#define MAX_TCP_WINDOW_SIZE (0xFFFF << 14)
+#define MAX_TCP_MSGS 8
+#define MAX_TCP_SEGS 8
+#define MAX_TCP_HOLES 8
+#define MAX_TCP_DNS_MSG 8
+
+typedef struct tcphole tcphole_t;
+typedef struct tcp_msgbuf tcp_msgbuf_t;
+typedef struct tcp_segbuf tcp_segbuf_t;
+typedef struct tcpdnsmsg tcpdnsmsg_t;
+typedef struct tcpreasm tcpreasm_t;
+
+struct tcphole {
+ uint16_t start;
+ uint16_t len;
+};
+
+struct tcp_msgbuf {
+ uint32_t seq;
+ uint16_t dnslen;
+ tcphole_t hole[MAX_TCP_HOLES];
+ int holes;
+ u_char buf[];
+};
+
+struct tcp_segbuf {
+ uint32_t seq;
+ uint16_t len;
+ u_char buf[];
+};
+
+struct tcpdnsmsg {
+ size_t segments_seen;
+ uint16_t dnslen;
+ u_char dnspkt[];
+};
+
+struct tcpreasm {
+ uint32_t seq_start;
+ size_t msgbufs;
+ u_char dnslen_buf[2];
+ u_char dnslen_bytes_seen_mask;
+ tcp_msgbuf_t* msgbuf[MAX_TCP_MSGS];
+ tcp_segbuf_t* segbuf[MAX_TCP_SEGS];
+ size_t segments_seen;
+ size_t dnsmsgs;
+ tcpdnsmsg_t* dnsmsg[MAX_TCP_DNS_MSG];
+ uint32_t seq_bfb;
+ tcp_segbuf_t* bfb_seg[MAX_TCP_SEGS];
+ u_char* bfb_buf;
+ size_t bfb_at;
+};
+
+struct tcpstate {
+ LINK(struct tcpstate)
+ link;
+ iaddr saddr;
+ iaddr daddr;
+ uint16_t sport;
+ uint16_t dport;
+ uint32_t start; /* seq# of tcp payload start */
+ uint32_t maxdiff; /* maximum (seq# - start) */
+ uint16_t dnslen;
+ time_t last_use;
+ uint32_t lastdns;
+ uint32_t currseq;
+ size_t currlen;
+
+ tcpreasm_t* reasm;
+ size_t reasm_faults;
+};
+typedef struct tcpstate* tcpstate_ptr;
+typedef LIST(struct tcpstate) tcpstate_list;
+
+struct endpoint {
+ LINK(struct endpoint)
+ link;
+ iaddr ia;
+};
+typedef struct endpoint* endpoint_ptr;
+typedef LIST(struct endpoint) endpoint_list;
+
+struct myregex {
+ LINK(struct myregex)
+ link;
+ regex_t reg;
+ char* str;
+ int not ;
+};
+typedef struct myregex* myregex_ptr;
+typedef LIST(struct myregex) myregex_list;
+
+struct plugin {
+ LINK(struct plugin)
+ link;
+
+ char* name;
+ void* handle;
+ enum plugin_type pt;
+
+ type_t(*type);
+ int (*start)(logerr_t*);
+ void (*stop)();
+ int (*open)(my_bpftimeval);
+ int (*close)();
+ output_t(*output);
+ filter_t(*filter);
+ void (*getopt)(int*, char**[]);
+ void (*usage)();
+ void (*extension)(int, void*);
+};
+typedef LIST(struct plugin) plugin_list;
+
+enum dump_type {
+ nowhere,
+ to_stdout,
+ to_file
+};
+enum dump_state {
+ dumper_opened,
+ dumper_closed
+};
+
+extern plugin_list plugins;
+extern const char* ProgramName;
+extern char* dump_suffix;
+extern int wantgzip;
+
+extern plugin_list plugins;
+extern const char* ProgramName;
+extern int dumptrace;
+extern int flush;
+extern vlan_list vlans_excl;
+extern vlan_list vlans_incl;
+extern unsigned msg_wanted;
+extern unsigned dir_wanted;
+extern unsigned end_hide;
+extern unsigned err_wanted;
+extern tcpstate_list tcpstates;
+extern int tcpstate_count;
+extern endpoint_list initiators, not_initiators;
+extern endpoint_list responders, not_responders;
+extern endpoint_list drop_responders;
+extern myregex_list myregexes;
+extern mypcap_list mypcaps;
+extern mypcap_ptr pcap_offline;
+extern const char* dump_base;
+extern char* dump_suffix;
+extern char* extra_bpf;
+extern enum dump_type dump_type;
+extern enum dump_state dump_state;
+extern const char* kick_cmd;
+extern unsigned limit_seconds;
+extern time_t next_interval;
+extern unsigned limit_packets;
+extern size_t limit_pcapfilesize;
+extern pcap_t* pcap_dead;
+extern pcap_dumper_t* dumper;
+extern time_t dumpstart;
+extern unsigned msgcount;
+extern size_t capturedbytes;
+extern char * dumpname, *dumpnamepart;
+extern char* bpft;
+extern unsigned dns_port;
+extern int promisc;
+extern int monitor_mode;
+extern int immediate_mode;
+extern int background;
+extern char errbuf[PCAP_ERRBUF_SIZE];
+extern int wantgzip;
+extern int wantfrags;
+extern int wanticmp;
+extern int wanttcp;
+extern int preso;
+#ifdef USE_SECCOMP
+extern int use_seccomp;
+#endif
+extern int main_exit;
+extern int alarm_set;
+extern time_t start_time;
+extern time_t stop_time;
+extern int print_pcap_stats;
+extern uint64_t pcap_drops;
+extern my_bpftimeval last_ts;
+extern unsigned long long mem_limit;
+extern int mem_limit_set;
+extern const char DROPTOUSER[];
+extern pcap_thread_t pcap_thread;
+extern int only_offline_pcaps;
+extern int dont_drop_privileges;
+extern options_t options;
+
+extern ldns_rr_type match_qtype, nmatch_qtype;
+
+#endif /* __dnscap_dnscap_h */
diff --git a/src/dnscap_common.h b/src/dnscap_common.h
new file mode 100644
index 0000000..db1b88b
--- /dev/null
+++ b/src/dnscap_common.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __dnscap_dnscap_common_h
+#define __dnscap_dnscap_common_h
+
+#include <netinet/in.h>
+#include <sys/types.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+/*
+ * setup MY_BPFTIMEVAL as the timeval structure that bpf packets
+ * will be assoicated with packets from libpcap
+ */
+#ifndef MY_BPFTIMEVAL
+#define MY_BPFTIMEVAL timeval
+#endif
+typedef struct MY_BPFTIMEVAL my_bpftimeval;
+
+/*
+ * Structure to contain IP addresses
+ */
+typedef struct {
+ int af;
+ union {
+ struct in_addr a4;
+ struct in6_addr a6;
+ } u;
+} iaddr;
+
+/*
+ * Prototype for the plugin "type" function
+ *
+ * output - Will run plugin's "output" function last when outputting (default
+ * and same behavior before the existens of a plugin type)
+ * filter - Will run plugin's "filter" function before outputting and won't
+ * output if the return of that function is non-zero.
+ */
+enum plugin_type {
+ plugin_output,
+ plugin_filter,
+};
+typedef enum plugin_type type_t(void);
+
+/*
+ * plugins can call the logerr() function in the main dnscap
+ * process.
+ */
+typedef int logerr_t(const char* fmt, ...);
+
+/*
+ * Prototype for the plugin "output" function
+ */
+typedef void output_t(const char* descr,
+ iaddr from,
+ iaddr to,
+ uint8_t proto,
+ unsigned flags,
+ unsigned sport,
+ unsigned dport,
+ my_bpftimeval ts,
+ const u_char* pkt_copy,
+ const unsigned olen,
+ const u_char* payload,
+ const unsigned payloadlen);
+
+/*
+ * Prototype for the plugin "filter" function
+ */
+typedef int filter_t(const char* descr,
+ iaddr* from,
+ iaddr* to,
+ uint8_t proto,
+ unsigned flags,
+ unsigned sport,
+ unsigned dport,
+ my_bpftimeval ts,
+ const u_char* pkt_copy,
+ const unsigned olen,
+ const u_char* payload,
+ const unsigned payloadlen);
+
+/*
+ * Extensions
+ */
+
+#define DNSCAP_EXT_IS_RESPONDER 1
+typedef int (*is_responder_t)(iaddr ia);
+
+#define DNSCAP_EXT_IA_STR 2
+typedef const char* (*ia_str_t)(iaddr ia);
+
+#define DNSCAP_EXT_TCPSTATE_GETCURR 3
+typedef void* (*tcpstate_getcurr_t)(void);
+
+#define DNSCAP_EXT_TCPSTATE_RESET 4
+typedef void (*tcpstate_reset_t)(void* tcpstate, const char* msg);
+
+#define DNSCAP_EXT_SET_IADDR 5
+typedef void (*set_iaddr_t)(iaddr* from, iaddr* to);
+
+/*
+ * Flags
+ */
+
+#define DNSCAP_OUTPUT_ISFRAG (1 << 0)
+#define DNSCAP_OUTPUT_ISDNS (1 << 1)
+#define DNSCAP_OUTPUT_ISLAYER (1 << 2)
+
+/*
+ * Direction
+ */
+
+#define DIR_INITIATE 0x0001
+#define DIR_RESPONSE 0x0002
+
+#endif /* __dnscap_dnscap_common_h */
diff --git a/src/dump_cbor.c b/src/dump_cbor.c
new file mode 100644
index 0000000..1d2d848
--- /dev/null
+++ b/src/dump_cbor.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ DNS-in-JSON
+ - generally naming convention
+ - compressedNAME.length is there a point here? isn't the length in the
+ compressed data itself? Maybe have compressedNAME as just the data
+ of the compressed name
+ - 2.5 Additional Message Object Members
+ - IP stuff:
+ - ipProtocol: num
+ - sourceIpAddress: string
+ - sourcePort: num
+ - destinationIpAddress: string
+ - destinationPort: num
+ or
+ - ip: [ ipProtocol, sourceIpAddress, sourcePort, destinationIpAddress, destinationPort ]
+ - dateNanoFractions as addition to dateSeconds, specify the fraction of
+ nano seconds separatly to have better precision.
+*/
+
+#include "config.h"
+
+#include "dump_cbor.h"
+#include "dnscap.h"
+#include "iaddr.h"
+
+#if HAVE_LIBTINYCBOR
+
+#include <ldns/ldns.h>
+#if HAVE_CBOR_CBOR_H
+#include <cbor/cbor.h>
+#endif
+#if HAVE_CBOR_H
+#include <cbor.h>
+#endif
+
+static uint8_t* cbor_buf = 0;
+static size_t cbor_size = 128 * 1024;
+/*static size_t cbor_size = 1024;*/
+static size_t cbor_reserve = 64 * 1024;
+static CborEncoder cbor_root, cbor_pkts;
+/*static cbor_stringref_t *cbor_stringrefs = 0;*/
+/*static size_t cbor_stringref_size = 8192;*/
+static int cbor_flushed = 1;
+
+int cbor_set_size(size_t size)
+{
+ if (!size) {
+ return DUMP_CBOR_EINVAL;
+ }
+
+ cbor_size = size;
+
+ return DUMP_CBOR_OK;
+}
+
+int cbor_set_reserve(size_t reserve)
+{
+ if (!reserve) {
+ return DUMP_CBOR_EINVAL;
+ }
+
+ cbor_reserve = reserve;
+
+ return DUMP_CBOR_OK;
+}
+
+#define append_cbor(func, name, type) \
+ CborError func(CborEncoder* encoder, type value, int* should_flush) \
+ { \
+ CborError err; \
+ uint8_t* ptr = encoder->data.ptr; \
+ err = name(encoder, value); \
+ if (err == CborErrorOutOfMemory && !*should_flush) { \
+ *should_flush = 1; \
+ encoder->data.ptr = ptr; \
+ encoder->end = cbor_buf + cbor_size + cbor_reserve; \
+ err = name(encoder, value); \
+ } \
+ return err; \
+ }
+
+static append_cbor(append_cbor_text_stringz, cbor_encode_text_stringz, const char*);
+static append_cbor(append_cbor_boolean, cbor_encode_boolean, bool);
+static append_cbor(append_cbor_int, cbor_encode_int, int64_t);
+static append_cbor(append_cbor_uint, cbor_encode_uint, uint64_t);
+static append_cbor(append_cbor_double, cbor_encode_double, double);
+
+static CborError append_cbor_bytes(CborEncoder* encoder, uint8_t* bytes, size_t length, int* should_flush)
+{
+ CborError err;
+ uint8_t* ptr = encoder->data.ptr;
+ err = cbor_encode_byte_string(encoder, bytes, length);
+ if (err == CborErrorOutOfMemory && !*should_flush) {
+ *should_flush = 1;
+ encoder->data.ptr = ptr;
+ encoder->end = cbor_buf + cbor_size + cbor_reserve;
+ err = cbor_encode_byte_string(encoder, bytes, length);
+ }
+ return err;
+}
+
+/*CborError append_cbor_text_stringz2(CborEncoder *encoder, const char *value, int *should_flush) {*/
+/* CborError err;*/
+/* uint8_t *ptr = encoder->data.ptr;*/
+/* err = cbor_encode_byte_string(encoder, bytes, length);*/
+/* if (err == CborErrorOutOfMemory && !*should_flush) {*/
+/* *should_flush = 1;*/
+/* encoder->data.ptr = ptr;*/
+/* encoder->end = cbor_buf + cbor_size + cbor_reserve;*/
+/* err = cbor_encode_byte_string(encoder, bytes, length);*/
+/* }*/
+/* return err;*/
+/*}*/
+
+#define append_cbor_container(func, name) \
+ CborError func(CborEncoder* encoder, CborEncoder* container, size_t length, int* should_flush) \
+ { \
+ CborError err; \
+ uint8_t* ptr = encoder->data.ptr; \
+ err = name(encoder, container, length); \
+ if (err == CborErrorOutOfMemory && !*should_flush) { \
+ *should_flush = 1; \
+ encoder->data.ptr = ptr; \
+ encoder->end = cbor_buf + cbor_size + cbor_reserve; \
+ err = name(encoder, container, length); \
+ } \
+ return err; \
+ }
+
+static append_cbor_container(append_cbor_array, cbor_encoder_create_array);
+static append_cbor_container(append_cbor_map, cbor_encoder_create_map);
+
+static CborError close_cbor_container(CborEncoder* encoder, CborEncoder* container, int* should_flush)
+{
+ CborError err;
+ uint8_t* ptr = encoder->data.ptr;
+ err = cbor_encoder_close_container_checked(encoder, container);
+ if (err == CborErrorOutOfMemory && !*should_flush) {
+ *should_flush = 1;
+ encoder->data.ptr = ptr;
+ encoder->end = cbor_buf + cbor_size + cbor_reserve;
+ err = cbor_encoder_close_container_checked(encoder, container);
+ }
+ return err;
+}
+
+static CborError cbor_ldns_rr_list(CborEncoder* encoder, ldns_rr_list* list, size_t count, int* should_flush)
+{
+ CborError cbor_err = CborNoError;
+ size_t n;
+ ldns_buffer* dname;
+ char* dname_str;
+
+ if (!encoder) {
+ return CborErrorInternalError;
+ }
+ if (!list) {
+ return CborErrorInternalError;
+ }
+ if (!count) {
+ return CborErrorInternalError;
+ }
+ if (!should_flush) {
+ return CborErrorInternalError;
+ }
+
+ for (n = 0; cbor_err == CborNoError && n < count; n++) {
+ CborEncoder cbor_rr;
+ uint8_t* rdata_bytes;
+ ldns_buffer* rdata;
+ ldns_rr* rr = ldns_rr_list_rr(list, n);
+ size_t rd_count;
+
+ if (!rr) {
+ return CborErrorInternalError;
+ }
+ rd_count = ldns_rr_rd_count(rr);
+
+ if (!(dname = ldns_buffer_new(512))) {
+ return CborErrorOutOfMemory;
+ }
+ if (ldns_rdf2buffer_str_dname(dname, ldns_rr_owner(rr)) != LDNS_STATUS_OK) {
+ ldns_buffer_free(dname);
+ return CborErrorInternalError;
+ }
+ ldns_buffer_write_u8(dname, 0);
+ if (!(dname_str = ldns_buffer_export(dname))) {
+ ldns_buffer_free(dname);
+ return CborErrorOutOfMemory;
+ }
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_map(encoder, &cbor_rr, CborIndefiniteLength, should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor_rr, "NAME", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor_rr, dname_str, should_flush);
+ free(dname_str);
+ ldns_buffer_free(dname);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor_rr, "CLASS", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor_rr, ldns_rr_get_class(rr), should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor_rr, "TYPE", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor_rr, ldns_rr_get_type(rr), should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor_rr, "TTL", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor_rr, ldns_rr_ttl(rr), should_flush);
+
+ if (rd_count == 1) {
+ if (!(rdata = ldns_buffer_new(64 * 1024))) {
+ return CborErrorOutOfMemory;
+ }
+ if (ldns_rdf2buffer_wire(rdata, ldns_rr_rdf(rr, 0)) != LDNS_STATUS_OK) {
+ ldns_buffer_free(rdata);
+ return CborErrorInternalError;
+ }
+ if (!(rdata_bytes = ldns_buffer_export(rdata))) {
+ ldns_buffer_free(rdata);
+ return CborErrorOutOfMemory;
+ }
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor_rr, "RDLENGTH", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor_rr, ldns_buffer_position(rdata), should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor_rr, "RDATA", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_bytes(&cbor_rr, rdata_bytes, ldns_buffer_position(rdata), should_flush);
+ free(rdata_bytes);
+ ldns_buffer_free(rdata);
+ } else if (rd_count > 1) {
+ size_t n2;
+ CborEncoder rr_set;
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor_rr, "rrSet", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_array(&cbor_rr, &rr_set, CborIndefiniteLength, should_flush);
+ for (n2 = 0; n2 < rd_count; n2++) {
+ if (!(rdata = ldns_buffer_new(64 * 1024))) {
+ return CborErrorOutOfMemory;
+ }
+ if (ldns_rdf2buffer_wire(rdata, ldns_rr_rdf(rr, n2)) != LDNS_STATUS_OK) {
+ ldns_buffer_free(rdata);
+ return CborErrorInternalError;
+ }
+ if (!(rdata_bytes = ldns_buffer_export(rdata))) {
+ ldns_buffer_free(rdata);
+ return CborErrorOutOfMemory;
+ }
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&rr_set, "RDLENGTH", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&rr_set, ldns_buffer_position(rdata), should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&rr_set, "RDATA", should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_bytes(&rr_set, rdata_bytes, ldns_buffer_position(rdata), should_flush);
+ free(rdata_bytes);
+ ldns_buffer_free(rdata);
+ }
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(&cbor_rr, &rr_set, should_flush);
+ }
+
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(encoder, &cbor_rr, should_flush);
+ }
+
+ return cbor_err;
+}
+
+int output_cbor(iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char* payload, size_t payloadlen)
+{
+ ldns_pkt* pkt = 0;
+ ldns_status ldns_rc;
+
+ if (!payload) {
+ return DUMP_CBOR_EINVAL;
+ }
+ if (!payloadlen) {
+ return DUMP_CBOR_EINVAL;
+ }
+
+ /* if (!cbor_stringrefs) {*/
+ /* cbor_stringrefs = calloc(1, cbor_stringref_size);*/
+ /* }*/
+ if (!cbor_buf) {
+ if (!(cbor_buf = calloc(1, cbor_size + cbor_reserve))) {
+ return DUMP_CBOR_ENOMEM;
+ }
+ }
+ if (cbor_flushed) {
+ CborError cbor_err;
+
+ cbor_encoder_init(&cbor_root, cbor_buf, cbor_size, 0);
+ /* cbor_err = cbor_encode_tag(&cbor_root, 256);*/
+ /* if (cbor_err == CborNoError)*/
+ cbor_err = cbor_encoder_create_array(&cbor_root, &cbor_pkts, CborIndefiniteLength);
+ if (cbor_err != CborNoError) {
+ fprintf(stderr, "cbor init error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err));
+ return DUMP_CBOR_ECBOR;
+ }
+ cbor_flushed = 0;
+ }
+
+ ldns_rc = ldns_wire2pkt(&pkt, payload, payloadlen);
+
+ if (ldns_rc != LDNS_STATUS_OK) {
+ fprintf(stderr, "ldns error [%d]: %s\n", ldns_rc, ldns_get_errorstr_by_id(ldns_rc));
+ return DUMP_CBOR_ELDNS;
+ }
+ if (!pkt) {
+ return DUMP_CBOR_ELDNS;
+ }
+
+ CborEncoder cbor, ip;
+ CborError cbor_err = CborNoError;
+ int should_flush = 0;
+
+ cbor_err = append_cbor_map(&cbor_pkts, &cbor, CborIndefiniteLength, &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "dateSeconds", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_double(&cbor, (double)ts.tv_sec + ((double)ts.tv_usec / 1000000), &should_flush);
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "dateNanoFractions", &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, ts.tv_usec * 1000, &should_flush);*/
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "ip", &should_flush);
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, proto, &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "sourceIpAddress", &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, ia_str(from), &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "sourcePort", &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, sport, &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "destinationIpAddress", &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, ia_str(to), &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_text_stringz(&cbor, "destinationPort", &should_flush);*/
+ /* if (cbor_err == CborNoError) cbor_err = append_cbor_uint(&cbor, dport, &should_flush);*/
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_array(&cbor, &ip, CborIndefiniteLength, &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&ip, proto, &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&ip, ia_str(from), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&ip, sport, &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&ip, ia_str(to), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&ip, dport, &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(&cbor, &ip, &should_flush);
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "ID", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_pkt_id(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "QR", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_boolean(&cbor, ldns_pkt_qr(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "Opcode", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_pkt_get_opcode(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "AA", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_boolean(&cbor, ldns_pkt_aa(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "TC", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_boolean(&cbor, ldns_pkt_tc(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "RD", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_boolean(&cbor, ldns_pkt_rd(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "RA", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_boolean(&cbor, ldns_pkt_ra(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "AD", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_boolean(&cbor, ldns_pkt_ad(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "CD", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_boolean(&cbor, ldns_pkt_cd(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "RCODE", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_pkt_get_rcode(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "QDCOUNT", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_pkt_qdcount(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "ANCOUNT", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_pkt_ancount(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "NSCOUNT", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_pkt_nscount(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "ARCOUNT", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_pkt_arcount(pkt), &should_flush);
+
+ /* questionRRs */
+
+ if (ldns_pkt_qdcount(pkt) > 0) {
+ ldns_rr_list* list = ldns_pkt_question(pkt);
+ ldns_rr* rr;
+ size_t n, qdcount = ldns_pkt_qdcount(pkt);
+ ldns_buffer* dname;
+ char* dname_str;
+
+ if (!list) {
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ELDNS;
+ }
+ rr = ldns_rr_list_rr(list, 0);
+ if (!rr) {
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ELDNS;
+ }
+
+ if (!(dname = ldns_buffer_new(512))) {
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ENOMEM;
+ }
+ if (ldns_rdf2buffer_str_dname(dname, ldns_rr_owner(rr)) != LDNS_STATUS_OK) {
+ ldns_buffer_free(dname);
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ELDNS;
+ }
+ ldns_buffer_write_u8(dname, 0);
+ if (!(dname_str = ldns_buffer_export(dname))) {
+ ldns_buffer_free(dname);
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ENOMEM;
+ }
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "QNAME", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, dname_str, &should_flush);
+ free(dname_str);
+ ldns_buffer_free(dname);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "QCLASS", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_rr_get_class(rr), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "QTYPE", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&cbor, ldns_rr_get_type(rr), &should_flush);
+
+ if (qdcount > 1) {
+ CborEncoder queries;
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "questionRRs", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_array(&cbor, &queries, CborIndefiniteLength, &should_flush);
+ for (n = 1; cbor_err == CborNoError && n < qdcount; n++) {
+ CborEncoder query;
+
+ rr = ldns_rr_list_rr(list, n);
+ if (!rr) {
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ELDNS;
+ }
+
+ if (!(dname = ldns_buffer_new(512))) {
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ENOMEM;
+ }
+ if (ldns_rdf2buffer_str_dname(dname, ldns_rr_owner(rr)) != LDNS_STATUS_OK) {
+ ldns_buffer_free(dname);
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ELDNS;
+ }
+ ldns_buffer_write_u8(dname, 0);
+ if (!(dname_str = ldns_buffer_export(dname))) {
+ ldns_buffer_free(dname);
+ ldns_pkt_free(pkt);
+ return DUMP_CBOR_ENOMEM;
+ }
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_map(&queries, &query, CborIndefiniteLength, &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&query, "NAME", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&query, dname_str, &should_flush);
+ free(dname_str);
+ ldns_buffer_free(dname);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&query, "CLASS", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&query, ldns_rr_get_class(rr), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&query, "TYPE", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_uint(&query, ldns_rr_get_type(rr), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(&queries, &query, &should_flush);
+ }
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(&cbor, &queries, &should_flush);
+ }
+ }
+
+ /* answerRRs */
+
+ if (ldns_pkt_ancount(pkt) > 0) {
+ CborEncoder cbor_rrs;
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "answerRRs", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_array(&cbor, &cbor_rrs, CborIndefiniteLength, &should_flush);
+ cbor_ldns_rr_list(&cbor_rrs, ldns_pkt_answer(pkt), ldns_pkt_ancount(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(&cbor, &cbor_rrs, &should_flush);
+ }
+
+ /* authorityRRs */
+
+ if (ldns_pkt_nscount(pkt) > 0) {
+ CborEncoder cbor_rrs;
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "authorityRRs", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_array(&cbor, &cbor_rrs, CborIndefiniteLength, &should_flush);
+ cbor_ldns_rr_list(&cbor_rrs, ldns_pkt_authority(pkt), ldns_pkt_nscount(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(&cbor, &cbor_rrs, &should_flush);
+ }
+
+ /* additionalRRs */
+
+ if (ldns_pkt_arcount(pkt) > 0) {
+ CborEncoder cbor_rrs;
+
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_text_stringz(&cbor, "additionalRRs", &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = append_cbor_array(&cbor, &cbor_rrs, CborIndefiniteLength, &should_flush);
+ cbor_ldns_rr_list(&cbor_rrs, ldns_pkt_additional(pkt), ldns_pkt_arcount(pkt), &should_flush);
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(&cbor, &cbor_rrs, &should_flush);
+ }
+
+ ldns_pkt_free(pkt);
+
+ if (cbor_err == CborNoError)
+ cbor_err = close_cbor_container(&cbor_pkts, &cbor, &should_flush);
+
+ if (cbor_err != CborNoError) {
+ fprintf(stderr, "cbor error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err));
+ return DUMP_CBOR_ECBOR;
+ }
+
+ if (should_flush) {
+ if ((cbor_err = cbor_encoder_close_container_checked(&cbor_root, &cbor_pkts)) != CborNoError) {
+ fprintf(stderr, "cbor error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err));
+ return DUMP_CBOR_ECBOR;
+ }
+
+ fprintf(stderr, "cbor output: %lu bytes\n", cbor_encoder_get_buffer_size(&cbor_root, cbor_buf));
+
+ cbor_flushed = 1;
+ return DUMP_CBOR_FLUSH;
+ }
+
+ return DUMP_CBOR_OK;
+}
+
+int dump_cbor(FILE* fp)
+{
+ CborError cbor_err;
+
+ if (!fp) {
+ return DUMP_CBOR_EINVAL;
+ }
+
+ if ((cbor_err = cbor_encoder_close_container_checked(&cbor_root, &cbor_pkts)) != CborNoError) {
+ fprintf(stderr, "cbor error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err));
+ return DUMP_CBOR_ECBOR;
+ }
+
+ fprintf(stderr, "cbor output: %lu bytes\n", cbor_encoder_get_buffer_size(&cbor_root, cbor_buf));
+
+ if (fwrite(cbor_buf, cbor_encoder_get_buffer_size(&cbor_root, cbor_buf), 1, fp) != 1) {
+ return DUMP_CBOR_EWRITE;
+ }
+
+ return DUMP_CBOR_OK;
+}
+
+int have_cbor_support()
+{
+ return 1;
+}
+
+#else /* HAVE_LIBTINYCBOR */
+
+int cbor_set_size(size_t size)
+{
+ return DUMP_CBOR_ENOSUP;
+}
+
+int cbor_set_reserve(size_t reserve)
+{
+ return DUMP_CBOR_ENOSUP;
+}
+
+int output_cbor(iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char* payload, size_t payloadlen)
+{
+ return DUMP_CBOR_ENOSUP;
+}
+
+int dump_cbor(FILE* fp)
+{
+ return DUMP_CBOR_ENOSUP;
+}
+
+int have_cbor_support()
+{
+ return 0;
+}
+
+#endif
diff --git a/src/dump_cbor.h b/src/dump_cbor.h
new file mode 100644
index 0000000..cbe8f3f
--- /dev/null
+++ b/src/dump_cbor.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap_common.h"
+
+#include <stdio.h>
+
+#ifndef __dnscap_dump_cbor_h
+#define __dnscap_dump_cbor_h
+
+#define DUMP_CBOR_OK 0
+#define DUMP_CBOR_EINVAL 1
+#define DUMP_CBOR_ENOMEM 2
+#define DUMP_CBOR_ECBOR 3
+#define DUMP_CBOR_ELDNS 4
+#define DUMP_CBOR_EWRITE 5
+#define DUMP_CBOR_FLUSH 6
+#define DUMP_CBOR_ENOSUP 7
+
+/*
+typedef struct cbor_stringref cbor_stringref_t;
+struct cbor_stringref {
+ char *string;
+ size_t ref;
+};
+*/
+
+int cbor_set_size(size_t size);
+int cbor_set_reserve(size_t reserve);
+int output_cbor(iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char* payload, size_t payloadlen);
+int dump_cbor(FILE* fp);
+int have_cbor_support();
+
+#endif /* __dnscap_dump_cbor_h */
diff --git a/src/dump_cds.c b/src/dump_cds.c
new file mode 100644
index 0000000..e151d35
--- /dev/null
+++ b/src/dump_cds.c
@@ -0,0 +1,1962 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "dump_cds.h"
+#include "dnscap.h"
+#include "hashtbl.h"
+#include "iaddr.h"
+
+#if HAVE_LIBTINYCBOR
+
+#include <stdlib.h>
+#if HAVE_CBOR_CBOR_H
+#include <cbor/cbor.h>
+#endif
+#if HAVE_CBOR_H
+#include <cbor.h>
+#endif
+#include <assert.h>
+
+#define need8(v, p, l, d) \
+ if (l < 1) { \
+ if (sizeof(d) > 1) \
+ fprintf(stderr, "cds need 1B/8b, had %lu: %s\n", l, d); \
+ return 1; \
+ } \
+ v = *p; \
+ p += 1; \
+ l -= 1
+
+#define need16(v, p, l, d) \
+ if (l < 2) { \
+ if (sizeof(d) > 1) \
+ fprintf(stderr, "cds need 2B/16b, had %lu: %s\n", l, d); \
+ return 1; \
+ } \
+ v = (*p << 8) + *(p + 1); \
+ p += 2; \
+ l -= 2
+
+#define need32(v, p, l, d) \
+ if (l < 4) { \
+ if (sizeof(d) > 1) \
+ fprintf(stderr, "cds need 4B/32b, had %lu: %s\n", l, d); \
+ return 1; \
+ } \
+ v = (*p << 24) + (*(p + 1) << 16) + (*(p + 2) << 8) + *(p + 3); \
+ p += 4; \
+ l -= 4
+
+#define need64(v, p, l, d) \
+ if (l < 8) { \
+ if (sizeof(d) > 1) \
+ fprintf(stderr, "cds need 8B/64b, had %lu: %s\n", l, d); \
+ return 1; \
+ } \
+ v = (*p << 56) + (*(p + 1) << 48) + (*(p + 2) << 40) + (*(p + 3) << 32) + (*(p + 4) << 24) + (*(p + 5) << 16) + (*(p + 6) << 8) + *(p + 7); \
+ p += 8; \
+ l -= 8
+
+#define needxb(b, x, p, l, d) \
+ if (l < x) { \
+ if (sizeof(d) > 1) \
+ fprintf(stderr, "cds need %d bytes, had %lu: %s\n", x, l, d); \
+ return 1; \
+ } \
+ memcpy(b, p, x); \
+ p += x; \
+ l -= x
+
+#define advancexb(x, p, l, d) \
+ if (l < x) { \
+ if (sizeof(d) > 1) \
+ fprintf(stderr, "cds needed to advance %d bytes, had %lu: %s\n", x, l, d); \
+ return 1; \
+ } \
+ p += x; \
+ l -= x
+
+static uint8_t* cbor_buf = 0;
+static uint8_t* cbor_buf_p = 0;
+static size_t cbor_size = 1024 * 1024;
+static uint8_t* message_buf = 0;
+static size_t message_size = 64 * 1024;
+static int cbor_flushed = 1;
+static hashtbl* rdata_tbl = 0;
+static size_t MAX_RLABELS = CDS_DEFAULT_MAX_RLABELS;
+static size_t MIN_RLABEL_SIZE = CDS_DEFAULT_MIN_RLABEL_SIZE;
+static int use_rdata_index = 0;
+static int use_rdata_rindex = 0;
+static size_t RDATA_RINDEX_SIZE = CDS_DEFAULT_RDATA_RINDEX_SIZE;
+static size_t RDATA_RINDEX_MIN_SIZE = CDS_DEFAULT_RDATA_RINDEX_MIN_SIZE;
+static size_t RDATA_INDEX_MIN_SIZE = CDS_DEFAULT_RDATA_INDEX_MIN_SIZE;
+
+struct rdata;
+struct rdata {
+ struct rdata* prev;
+ struct rdata* next;
+ uint8_t* data;
+ size_t len;
+ size_t idx;
+};
+
+struct last {
+ my_bpftimeval ts;
+ ip_header_t ip;
+
+ uint16_t dns_type;
+ uint16_t dns_class;
+ uint32_t dns_ttl;
+
+ dns_rlabel_t* dns_rlabel;
+ dns_rlabel_t* dns_rlabel_last;
+ size_t dns_rlabels;
+
+ size_t rdata_index;
+ size_t rdata_num;
+ struct rdata* rdata;
+ struct rdata* rdata_last;
+};
+static struct last last;
+
+/*
+ * Set/Get
+ */
+
+int cds_set_cbor_size(size_t size)
+{
+ if (!size) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ cbor_size = size;
+ if (message_size > cbor_size) {
+ message_size = cbor_size;
+ }
+
+ return DUMP_CDS_OK;
+}
+
+int cds_set_message_size(size_t size)
+{
+ if (!size) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ message_size = size;
+ if (message_size > cbor_size) {
+ message_size = cbor_size;
+ }
+
+ return DUMP_CDS_OK;
+}
+
+int cds_set_max_rlabels(size_t size)
+{
+ if (!size) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ MAX_RLABELS = size;
+
+ return DUMP_CDS_OK;
+}
+
+int cds_set_min_rlabel_size(size_t size)
+{
+ if (!size) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ MIN_RLABEL_SIZE = size;
+
+ return DUMP_CDS_OK;
+}
+
+int cds_set_use_rdata_index(int use)
+{
+ use_rdata_index = use ? 1 : 0;
+
+ return DUMP_CDS_OK;
+}
+
+int cds_set_use_rdata_rindex(int use)
+{
+ use_rdata_rindex = use ? 1 : 0;
+
+ return DUMP_CDS_OK;
+}
+
+int cds_set_rdata_index_min_size(size_t size)
+{
+ if (!size) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ RDATA_INDEX_MIN_SIZE = size;
+
+ return DUMP_CDS_OK;
+}
+
+int cds_set_rdata_rindex_min_size(size_t size)
+{
+ if (!size) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ RDATA_RINDEX_MIN_SIZE = size;
+
+ return DUMP_CDS_OK;
+}
+
+int cds_set_rdata_rindex_size(size_t size)
+{
+ if (!size) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ RDATA_RINDEX_SIZE = size;
+
+ return DUMP_CDS_OK;
+}
+
+/*
+ * DNS
+ */
+
+static int check_dns_label(size_t* labels, uint8_t** p, size_t* l)
+{
+ uint8_t len;
+
+ while (1) {
+ need8(len, *p, *l, "");
+ *labels += 1;
+
+ if ((len & 0xc0) == 0xc0) {
+ advancexb(1, *p, *l, "");
+ break;
+ } else if (len & 0xc0) {
+ break;
+ } else if (len) {
+ advancexb(len, *p, *l, "");
+ } else {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int rdata_hash(const void* _item)
+{
+ const struct rdata* item = (const struct rdata*)_item;
+ size_t n, o, p;
+ unsigned int key = 0;
+
+ for (n = 0, o = 0, p = 0; n < item->len; n++) {
+ p |= item->data[n] << (o * 8);
+ o++;
+ if (o > 3) {
+ key ^= p;
+ p = 0;
+ o = 0;
+ }
+ }
+ if (o) {
+ key ^= p;
+ }
+
+ return key;
+}
+
+static int rdata_cmp(const void* _a, const void* _b)
+{
+ const struct rdata *a = (const struct rdata*)_a, *b = (const struct rdata*)_b;
+
+ if (a->len == b->len) {
+ return memcmp(a->data, b->data, a->len);
+ } else if (a->len < b->len)
+ return -1;
+ return 1;
+}
+
+static void rdata_free(void* d)
+{
+ struct rdata* item = (struct rdata*)d;
+
+ if (item) {
+ if (item->data) {
+ free(item->data);
+ }
+ free(item);
+ }
+}
+
+static int rdata_add(uint8_t* p, size_t len)
+{
+ struct rdata* key;
+
+ if (len < RDATA_INDEX_MIN_SIZE)
+ return 1;
+
+ if (!(key = calloc(1, sizeof(struct rdata)))) {
+ return 0;
+ }
+ if (!(key->data = calloc(1, len))) {
+ free(key);
+ return 0;
+ }
+
+ key->len = len;
+ memcpy(key->data, p, len);
+ key->idx = last.rdata_index++;
+
+ /* printf("rdata_add %u: ", rdata_hash(key));*/
+ /* {*/
+ /* size_t n = len;*/
+ /* uint8_t* x = p;*/
+ /* while (n--) {*/
+ /* printf("%02x", *x);*/
+ /* x++;*/
+ /* }*/
+ /* }*/
+ /* printf("\n");*/
+ hash_add(key, key, rdata_tbl);
+
+ return 0;
+}
+
+static size_t rdata_find(uint8_t* p, size_t len, size_t* found)
+{
+ struct rdata key;
+ struct rdata* r;
+
+ if (len < RDATA_INDEX_MIN_SIZE)
+ return 1;
+
+ key.data = p;
+ key.len = len;
+
+ /* printf("rdata_find %u: ", rdata_hash(&key));*/
+ /* {*/
+ /* size_t n = len;*/
+ /* uint8_t* x = p;*/
+ /* while (n--) {*/
+ /* printf("%02x", *x);*/
+ /* x++;*/
+ /* }*/
+ /* }*/
+ /* printf("\n");*/
+
+ if ((r = hash_find(&key, rdata_tbl))) {
+ /* printf("rdata found %lu at %lu\n", len, found->idx);*/
+ *found = r->idx;
+ return 0;
+ }
+
+ return 1;
+}
+
+int rdata_find2(uint8_t* p, size_t len, size_t* found)
+{
+ struct rdata* r = last.rdata;
+ size_t n = 0;
+
+ if (len < RDATA_RINDEX_MIN_SIZE)
+ return 1;
+
+ while (r) {
+ if (r->len == len && !memcmp(p, r->data, len)) {
+ break;
+ }
+ r = r->next;
+ n++;
+ }
+ if (r) {
+ /* printf("rdata found at %lu: ", n);*/
+ /* {*/
+ /* size_t n = len;*/
+ /* uint8_t* x = p;*/
+ /* while (n--) {*/
+ /* printf("%02x", *x);*/
+ /* x++;*/
+ /* }*/
+ /* }*/
+ /* printf("\n");*/
+
+ if (last.rdata != r) {
+ struct rdata *prev = r->prev, *next = r->next;
+
+ if (prev) {
+ prev->next = next;
+ }
+ if (next) {
+ next->prev = prev;
+ }
+
+ r->prev = 0;
+ r->next = last.rdata;
+ last.rdata->prev = r;
+ last.rdata = r;
+ }
+
+ *found = n;
+ return 0;
+ }
+
+ return 1;
+}
+
+int rdata_add2(uint8_t* p, size_t len)
+{
+ struct rdata* r;
+
+ if (len < RDATA_RINDEX_MIN_SIZE)
+ return 1;
+
+ if (!(r = calloc(1, sizeof(struct rdata)))) {
+ return -1;
+ }
+ if (!(r->data = calloc(1, len))) {
+ free(r);
+ return -1;
+ }
+
+ r->len = len;
+ memcpy(r->data, p, len);
+
+ /* printf("rdata_add: ");*/
+ /* {*/
+ /* size_t n = len;*/
+ /* uint8_t* x = p;*/
+ /* while (n--) {*/
+ /* printf("%02x", *x);*/
+ /* x++;*/
+ /* }*/
+ /* }*/
+ /* printf("\n");*/
+
+ if (last.rdata) {
+ last.rdata->prev = r;
+ }
+ r->next = last.rdata;
+ last.rdata = r;
+ last.rdata_num++;
+
+ if (last.rdata_last) {
+ if (last.rdata_num >= RDATA_RINDEX_SIZE) {
+ r = last.rdata_last;
+
+ last.rdata_last = r->prev;
+ last.rdata_last->next = 0;
+ last.rdata_num--;
+ free(r->data);
+ free(r);
+ }
+ } else {
+ last.rdata_last = r;
+ }
+
+ return 0;
+}
+
+static int parse_dns_rr(char is_q, dns_rr_t* rr, size_t expected_rrs, size_t* actual_rrs, uint8_t** p, size_t* l)
+{
+ uint8_t len;
+ uint8_t* p2;
+ size_t l2, idx;
+ dns_label_t* label;
+ size_t num_labels, offset;
+
+ while (expected_rrs--) {
+ /* first pass check number of labels */
+ p2 = *p;
+ l2 = *l;
+
+ if (check_dns_label(&(rr->labels), &p2, &l2)) {
+ if (!rr->labels) {
+ fprintf(stderr, "cds no labels\n");
+ return 1;
+ }
+ }
+
+ /* second pass, allocate labels and fill */
+ if (!(rr->label = calloc(rr->labels, sizeof(dns_label_t)))) {
+ fprintf(stderr, "cds out of memory\n");
+ return -1;
+ }
+
+ *actual_rrs += 1;
+
+ label = rr->label;
+ rr->have_labels = 1;
+
+ while (1) {
+ need8(len, *p, *l, "name length");
+
+ if ((len & 0xc0) == 0xc0) {
+ label->offset_p = *p;
+ need8(label->offset, *p, *l, "name offset");
+ label->offset |= (len & 0x3f) << 8;
+ label->have_offset = 1;
+ label->is_complete = 1;
+ break;
+ } else if (len & 0xc0) {
+ label->extension_bits = len;
+ label->have_extension_bits = 1;
+ label->is_complete = 1;
+ break;
+ } else if (len) {
+ label->size = len;
+ label->have_size = 1;
+ label->label = *p;
+ advancexb(len, *p, *l, "name label");
+ label->have_label = 1;
+ } else {
+ label->have_size = 1;
+ label->is_complete = 1;
+ break;
+ }
+
+ label->is_complete = 1;
+ label++;
+ }
+
+ need16(rr->type, *p, *l, "type");
+ rr->have_type = 1;
+ need16(rr->class, *p, *l, "class");
+ rr->have_class = 1;
+
+ if (!is_q) {
+ need32(rr->ttl, *p, *l, "ttl");
+ rr->have_ttl = 1;
+ need16(rr->rdlength, *p, *l, "rdlength");
+ rr->have_rdlength = 1;
+ rr->rdata = *p;
+ advancexb(rr->rdlength, *p, *l, "rdata");
+
+ if (use_rdata_index) {
+ if (!rdata_find(rr->rdata, rr->rdlength, &(rr->rdata_index))) {
+ rr->have_rdata_index = 1;
+ } else {
+ rdata_add(rr->rdata, rr->rdlength);
+ }
+ } else if (use_rdata_rindex) {
+ if (!rdata_find2(rr->rdata, rr->rdlength, &(rr->rdata_rindex))) {
+ rr->have_rdata_rindex = 1;
+ } else {
+ rdata_add2(rr->rdata, rr->rdlength);
+ }
+ }
+
+ num_labels = offset = 0;
+ switch (rr->type) {
+ case 2: /* NS */
+ case 3: /* MD */
+ case 4: /* MF */
+ case 5: /* CNAME */
+ case 7: /* MB */
+ case 8: /* MG */
+ case 9: /* MR */
+ case 12: /* PTR */
+ case 30: /* NXT */
+ case 39: /* DNAME */
+ case 47: /* NSEC */
+ case 249: /* TKEY */
+ case 250: /* TSIG */
+ num_labels = 1;
+ break;
+
+ case 6: /* SOA */
+ case 14: /* MINFO */
+ case 17: /* RP */
+ case 58: /* TALINK */
+ num_labels = 2;
+ break;
+
+ case 15: /* MX */
+ case 18: /* AFSDB */
+ case 21: /* RT */
+ case 36: /* KX */
+ case 107: /* LP */
+ num_labels = 1;
+ offset = 2;
+ break;
+
+ case 26: /* PX */
+ num_labels = 2;
+ offset = 2;
+ break;
+
+ case 24: /* SIG */
+ case 46: /* RRSIG */
+ num_labels = 1;
+ offset = 18;
+ break;
+
+ case 33: /* SRV */
+ num_labels = 1;
+ offset = 6;
+ break;
+
+ case 35: /* NAPTR */
+ num_labels = 1;
+ p2 = *p;
+ l2 = *l;
+ advancexb(2, p2, l2, "naptr int16 #1");
+ advancexb(2, p2, l2, "naptr int16 #2");
+ need8(len, p2, l2, "naptr str len #1");
+ advancexb(len, p2, l2, "naptr str #1");
+ need8(len, p2, l2, "naptr str len #2");
+ advancexb(len, p2, l2, "naptr str #2");
+ need8(len, p2, l2, "naptr str len #3");
+ advancexb(len, p2, l2, "naptr str #3");
+ offset = p2 - *p;
+ break;
+
+ case 55: /* HIP TODO */
+ break;
+ }
+
+ if (num_labels) {
+ dns_rdata_t* rdata;
+
+ rr->mixed_rdatas = num_labels + (offset ? 1 : 0) + 1;
+ if (!(rr->mixed_rdata = calloc(rr->mixed_rdatas, sizeof(dns_rdata_t)))) {
+ fprintf(stderr, "cds out of memory\n");
+ return -1;
+ }
+
+ p2 = rr->rdata;
+ l2 = rr->rdlength;
+ rdata = rr->mixed_rdata;
+ rr->have_mixed_rdata = 1;
+
+ if (offset) {
+ rdata->rdata_len = offset;
+ rdata->rdata = p2;
+ advancexb((int)offset, p2, l2, "mixed rdata");
+ rdata->have_rdata = 1;
+ rdata->is_complete = 1;
+ rdata++;
+ }
+ while (num_labels--) {
+ uint8_t* p3;
+ size_t l3;
+
+ /* first pass check number of rdata labels */
+
+ p3 = p2;
+ l3 = l2;
+
+ if (check_dns_label(&(rdata->labels), &p3, &l3)) {
+ if (!rdata->labels) {
+ fprintf(stderr, "cds mixed rdata no labels\n");
+ return 1;
+ }
+ }
+
+ /* second pass, allocate mixed rdata */
+ if (!(rdata->label = calloc(rdata->labels, sizeof(dns_label_t)))) {
+ fprintf(stderr, "cds out of memory\n");
+ return -1;
+ }
+
+ label = rdata->label;
+ rdata->have_labels = 1;
+ while (1) {
+ need8(len, p2, l2, "name length");
+
+ if ((len & 0xc0) == 0xc0) {
+ label->offset_p = p2;
+ need8(label->offset, p2, l2, "name offset");
+ label->offset |= (len & 0x3f) << 8;
+ label->have_offset = 1;
+ label->is_complete = 1;
+ break;
+ } else if (len & 0xc0) {
+ label->extension_bits = len;
+ label->have_extension_bits = 1;
+ label->is_complete = 1;
+ break;
+ } else if (len) {
+ label->size = len;
+ label->have_size = 1;
+ label->label = p2;
+ advancexb(len, p2, l2, "name label");
+ label->have_label = 1;
+ } else {
+ label->have_size = 1;
+ label->is_complete = 1;
+ break;
+ }
+
+ label->is_complete = 1;
+ label++;
+ }
+ rdata->is_complete = 1;
+ rdata++;
+ }
+ if (l2) {
+ /*printf("last rdata %lu\n", l2);*/
+ rdata->rdata_len = l2;
+ rdata->rdata = p2;
+ advancexb((int)l2, p2, l2, "mixed rdata");
+ rdata->have_rdata = 1;
+ rdata->is_complete = 1;
+ } else {
+ rr->mixed_rdatas--;
+ }
+ }
+ rr->have_rdata = 1;
+ }
+
+ rr->is_complete = 1;
+ rr++;
+ }
+
+ return 0;
+}
+
+int print_cbor = 0;
+
+static int parse_dns(dns_t* dns, uint8_t** p, size_t* l)
+{
+ int ret;
+
+ need16(dns->id, *p, *l, "dns id");
+ dns->have_id = 1;
+ need16(dns->raw, *p, *l, "raw dns bits");
+ dns->have_raw = 1;
+ need16(dns->qdcount, *p, *l, "qdcount");
+ dns->have_qdcount = 1;
+ need16(dns->ancount, *p, *l, "ancount");
+ dns->have_ancount = 1;
+ need16(dns->nscount, *p, *l, "nscount");
+ dns->have_nscount = 1;
+ need16(dns->arcount, *p, *l, "arcount");
+ dns->have_arcount = 1;
+
+ dns->header_is_complete = 1;
+
+ if (dns->qdcount) {
+ if (!(dns->question = calloc(dns->qdcount, sizeof(dns_rr_t)))) {
+ fprintf(stderr, "cds out of memory\n");
+ return -1;
+ }
+ ret = parse_dns_rr(1, dns->question, dns->qdcount, &(dns->questions), p, l);
+ /*if (ret) printf("qr %d\n", ret);*/
+ if (ret > -1 && dns->questions) {
+ dns->have_questions = 1;
+ }
+ if (ret) {
+ return ret;
+ }
+ }
+
+ if (dns->ancount) {
+ if (!(dns->answer = calloc(dns->ancount, sizeof(dns_rr_t)))) {
+ fprintf(stderr, "cds out of memory\n");
+ return -1;
+ }
+ ret = parse_dns_rr(0, dns->answer, dns->ancount, &(dns->answers), p, l);
+ /*if (ret) printf("an %d\n", ret);*/
+ if (ret > -1 && dns->answers) {
+ dns->have_answers = 1;
+ }
+ if (ret) {
+ return ret;
+ }
+ }
+
+ if (dns->nscount) {
+ if (!(dns->authority = calloc(dns->nscount, sizeof(dns_rr_t)))) {
+ fprintf(stderr, "cds out of memory\n");
+ return -1;
+ }
+ ret = parse_dns_rr(0, dns->authority, dns->nscount, &(dns->authorities), p, l);
+ /*if (ret) { printf("ns %d %lu\n", ret, dns->authorities);*/
+ /*{*/
+ /* size_t n;*/
+ /* for (n = 0; n < dns->authorities; n++) {*/
+ /* printf("%lu %d\n", n, dns->authority[n].is_complete);*/
+ /* if (!dns->authority[n].is_complete) print_cbor = 1;*/
+ /* }*/
+ /*} }*/
+ if (ret > -1 && dns->authorities) {
+ dns->have_authorities = 1;
+ }
+ if (ret) {
+ return ret;
+ }
+ }
+
+ if (dns->arcount) {
+ if (!(dns->additional = calloc(dns->arcount, sizeof(dns_rr_t)))) {
+ fprintf(stderr, "cds out of memory\n");
+ return -1;
+ }
+ ret = parse_dns_rr(0, dns->additional, dns->arcount, &(dns->additionals), p, l);
+ /*if (ret) printf("ar %d\n", ret);*/
+ if (ret > -1 && dns->additionals) {
+ dns->have_additionals = 1;
+ }
+ if (ret) {
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static CborError encode_label(CborEncoder* encoder, dns_label_t* label, size_t labels)
+{
+ CborError cbor_err = CborNoError;
+ CborEncoder array;
+
+ if (labels && label[labels - 1].have_size && !label[labels - 1].size) {
+ labels--;
+ }
+
+ cbor_err = cbor_encoder_create_array(encoder, &array, labels);
+ while (labels--) {
+ if (label->have_offset) {
+ if (label->have_n_offset) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&array, label->n_offset);
+ } else {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&array, label->offset);
+ }
+ } else if (label->have_extension_bits) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_simple_value(&array, label->extension_bits >> 6);
+ } else if (label->have_label) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_text_string(&array, (const char*)label->label, label->size);
+ } else {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_null(&array);
+ }
+
+ label++;
+ }
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(encoder, &array);
+
+ return cbor_err;
+}
+
+/*
+ * OUTPUT
+ */
+
+int print_label(dns_label_t* label, size_t labels)
+{
+ size_t n;
+
+ for (n = 0; n < labels; n++) {
+ if (label[n].have_offset) {
+ if (label[n].have_n_offset) {
+ printf(" %lu", label[n].n_offset);
+ } else {
+ printf(" %d", -label[n].offset);
+ }
+ } else if (label[n].have_extension_bits) {
+ printf(" %x", label[n].extension_bits);
+ } else if (label[n].have_label) {
+ printf(" %.*s", label[n].size, label[n].label);
+ } else {
+ printf(" $");
+ }
+ }
+ return 0;
+}
+
+int print_rlabel(dns_rlabel_t* label)
+{
+ size_t n;
+
+ for (n = 0; n < label->labels; n++) {
+ if (label->label[n].size) {
+ printf(" %.*s", label->label[n].size, label->label[n].label);
+ } else if (label->label[n].have_n_offset) {
+ printf(" %lu", label->label[n].n_offset);
+ } else {
+ printf(" $");
+ }
+ }
+ return 0;
+}
+
+int dns_rlabel_add(dns_label_t* label, size_t labels)
+{
+ dns_rlabel_t* copy;
+ size_t n, size = 0;
+
+ for (n = 0; n < labels; n++) {
+ if ((label[n].have_offset && !label[n].have_n_offset)
+ || label[n].have_extension_bits) {
+ return 1;
+ }
+ if (label[n].have_size) {
+ size += label[n].size;
+ }
+ }
+ /*printf("label size: %lu\n", size);*/
+ if (size < MIN_RLABEL_SIZE) {
+ return 1;
+ }
+
+ if (!(copy = calloc(1, sizeof(dns_rlabel_t)))) {
+ return -1;
+ }
+
+ assert(labels <= CDS_RLABEL_T_LABELS);
+ copy->labels = labels;
+
+ for (n = 0; n < labels; n++) {
+ if (label[n].have_n_offset) {
+ copy->label[n].have_n_offset = 1;
+ copy->label[n].n_offset = label[n].n_offset;
+ continue;
+ }
+ if (label[n].size) {
+ assert(label[n].size <= CDS_RLABEL_LABEL_T_LABEL);
+
+ copy->label[n].size = label[n].size;
+ memcpy(&(copy->label[n].label), label[n].label, label[n].size);
+ }
+ }
+
+ /*printf("add"); print_label(label, labels); printf("\n");*/
+
+ if (last.dns_rlabel) {
+ last.dns_rlabel->prev = copy;
+ }
+ copy->next = last.dns_rlabel;
+ last.dns_rlabel = copy;
+ last.dns_rlabels++;
+ if (last.dns_rlabel_last) {
+ if (last.dns_rlabels >= MAX_RLABELS) {
+ dns_rlabel_t* remove = last.dns_rlabel_last;
+
+ /*printf("remove %p %p\n", remove, remove->prev);*/
+
+ last.dns_rlabel_last = remove->prev;
+ last.dns_rlabel_last->next = 0;
+ free(remove);
+ last.dns_rlabels--;
+ }
+ } else {
+ last.dns_rlabel_last = copy;
+ }
+
+ return 0;
+}
+
+static size_t dns_rlabel_find(dns_label_t* label, size_t labels, size_t* rlabel_idx)
+{
+ size_t n, n2, size = 0;
+ dns_rlabel_t* rlabel;
+
+ for (n = 0; n < labels; n++) {
+ if ((label[n].have_offset && !label[n].have_n_offset)
+ || label[n].have_extension_bits) {
+ return 1;
+ }
+ if (label[n].have_size) {
+ size += label[n].size;
+ }
+ }
+ /*printf("label size: %lu\n", size);*/
+ if (size < MIN_RLABEL_SIZE) {
+ return 1;
+ }
+
+ /*printf("find"); print_label(label, labels); printf("\n");*/
+
+ n = 0;
+ rlabel = last.dns_rlabel;
+ while (rlabel) {
+ if (rlabel->labels == labels) {
+ /*printf("check"); print_rlabel(rlabel); printf("\n");*/
+
+ for (n2 = 0; n2 < labels; n2++) {
+ /*printf("%d %lu <> %d %lu\n", label[n2].have_n_offset, label[n2].n_offset, rlabel->label[n2].have_n_offset, rlabel->label[n2].n_offset);*/
+ if (label[n2].have_n_offset
+ || rlabel->label[n2].have_n_offset) {
+ if (label[n2].n_offset == rlabel->label[n2].n_offset)
+ continue;
+ } else if (label[n2].size == rlabel->label[n2].size
+ && !memcmp(label[n2].label, rlabel->label[n2].label, label[n2].size)) {
+ continue;
+ }
+ break;
+ }
+
+ if (n2 == labels) {
+ /*printf("found at %lu: ", n); print_rlabel(rlabel); printf("\n");*/
+ break;
+ }
+ }
+ rlabel = rlabel->next;
+ n++;
+ }
+ if (rlabel) {
+ if (last.dns_rlabel != rlabel) {
+ dns_rlabel_t *prev = rlabel->prev, *next = rlabel->next;
+
+ if (prev) {
+ prev->next = next;
+ }
+ if (next) {
+ next->prev = prev;
+ }
+
+ rlabel->prev = 0;
+ rlabel->next = last.dns_rlabel;
+ last.dns_rlabel->prev = rlabel;
+ last.dns_rlabel = rlabel;
+ }
+
+ *rlabel_idx = n;
+ return 0;
+ }
+
+ return 1;
+}
+
+static void free_rdata(dns_rdata_t* rdata)
+{
+ if (rdata->label) {
+ free(rdata->label);
+ }
+}
+
+static void free_rr(dns_rr_t* rr)
+{
+ size_t n;
+
+ if (rr->label) {
+ free(rr->label);
+ }
+ for (n = 0; n < rr->mixed_rdatas; n++) {
+ free_rdata(&(rr->mixed_rdata[n]));
+ }
+ if (rr->mixed_rdata) {
+ free(rr->mixed_rdata);
+ }
+}
+
+static void free_dns(dns_t* dns)
+{
+ size_t n;
+
+ for (n = 0; n < dns->questions; n++) {
+ free_rr(&(dns->question[n]));
+ }
+ for (n = 0; n < dns->answers; n++) {
+ free_rr(&(dns->answer[n]));
+ }
+ for (n = 0; n < dns->authorities; n++) {
+ free_rr(&(dns->authority[n]));
+ }
+ for (n = 0; n < dns->additionals; n++) {
+ free_rr(&(dns->additional[n]));
+ }
+}
+
+void dns_rr_build_offset(dns_rr_t* rr_list, size_t count, uint16_t* offset, size_t offsets, size_t* n_offset, const u_char* payload)
+{
+ dns_rr_t* rrp;
+ size_t rr, n, n2;
+
+ for (rr = 0; rr < count && *n_offset < offsets; rr++) {
+ rrp = &(rr_list[rr]);
+
+ for (n = 0; n < rrp->labels && *n_offset < offsets; n++) {
+ if (rrp->label[n].size) {
+ rrp->label[n].offset = rrp->label[n].label - payload - 1;
+ offset[*n_offset] = rrp->label[n].offset;
+ *n_offset += 1;
+ } else if (rrp->label[n].have_offset) {
+ offset[*n_offset] = rrp->label[n].offset_p - payload - 1;
+ *n_offset += 1;
+ }
+
+ /* printf("%u %u %u %.*s\n",*/
+ /* rrp->label[n].size,*/
+ /* rrp->label[n].extension_bits,*/
+ /* rrp->label[n].offset,*/
+ /* rrp->label[n].size ? rrp->label[n].size : 0,*/
+ /* rrp->label[n].size ? (char*)rrp->label[n].label : ""*/
+ /* );*/
+ }
+ for (n = 0; n < rrp->mixed_rdatas && *n_offset < offsets; n++) {
+ for (n2 = 0; n2 < rrp->mixed_rdata[n].labels; n2++) {
+ if (rrp->mixed_rdata[n].label[n2].size) {
+ rrp->mixed_rdata[n].label[n2].offset = rrp->mixed_rdata[n].label[n2].label - payload - 1;
+ offset[*n_offset] = rrp->mixed_rdata[n].label[n2].offset;
+ *n_offset += 1;
+ } else if (rrp->mixed_rdata[n].label[n2].have_offset) {
+ offset[*n_offset] = rrp->mixed_rdata[n].label[n2].offset_p - payload - 1;
+ *n_offset += 1;
+ }
+
+ /* printf(" %u %u %u %.*s\n",*/
+ /* rrp->mixed_rdata[n].label[n2].size,*/
+ /* rrp->mixed_rdata[n].label[n2].extension_bits,*/
+ /* rrp->mixed_rdata[n].label[n2].offset,*/
+ /* rrp->mixed_rdata[n].label[n2].size ? rrp->mixed_rdata[n].label[n2].size : 0,*/
+ /* rrp->mixed_rdata[n].label[n2].size ? (char*)rrp->mixed_rdata[n].label[n2].label : ""*/
+ /* );*/
+ }
+ }
+ }
+}
+
+void dns_rr_set_offset(dns_rr_t* rr_list, size_t count, uint16_t* offset, size_t n_offset)
+{
+ dns_rr_t* rrp;
+ size_t rr, n, n2, n3;
+
+ for (rr = 0; rr < count; rr++) {
+ rrp = &(rr_list[rr]);
+
+ for (n = 0; n < rrp->labels; n++) {
+ if (!rrp->label[n].size && rrp->label[n].offset) {
+ for (n3 = 0; n3 < n_offset; n3++) {
+ if (rrp->label[n].offset == offset[n3]) {
+ /* printf("%u => %lu\n", rrp->label[n].offset, n3);*/
+ rrp->label[n].n_offset = n3;
+ rrp->label[n].have_n_offset = 1;
+ break;
+ }
+ }
+ }
+ }
+ for (n = 0; n < rrp->mixed_rdatas; n++) {
+ for (n2 = 0; n2 < rrp->mixed_rdata[n].labels; n2++) {
+ if (!rrp->mixed_rdata[n].label[n2].size && rrp->mixed_rdata[n].label[n2].offset) {
+ for (n3 = 0; n3 < n_offset; n3++) {
+ if (rrp->mixed_rdata[n].label[n2].offset == offset[n3]) {
+ /* printf("%u => %lu\n", rrp->mixed_rdata[n].label[n2].offset, n3);*/
+ rrp->mixed_rdata[n].label[n2].n_offset = n3;
+ rrp->mixed_rdata[n].label[n2].have_n_offset = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void dns_rr_build_rlabel(dns_rr_t* rr_list, size_t count)
+{
+ dns_rr_t* rrp;
+ size_t rr, n;
+
+ for (rr = 0; rr < count; rr++) {
+ rrp = &(rr_list[rr]);
+
+ if (rrp->labels) {
+ if (!dns_rlabel_find(rrp->label, rrp->labels, &(rrp->rlabel_idx))) {
+ rrp->have_rlabel_idx = 1;
+ } else {
+ dns_rlabel_add(rrp->label, rrp->labels);
+ }
+ }
+
+ for (n = 0; n < rrp->mixed_rdatas; n++) {
+ if (rrp->mixed_rdata[n].labels) {
+ if (!dns_rlabel_find(rrp->mixed_rdata[n].label, rrp->mixed_rdata[n].labels, &(rrp->mixed_rdata[n].rlabel_idx))) {
+ rrp->mixed_rdata[n].have_rlabel_idx = 1;
+ } else {
+ dns_rlabel_add(rrp->mixed_rdata[n].label, rrp->mixed_rdata[n].labels);
+ }
+ }
+ }
+ }
+}
+
+CborError dns_build_rrs(CborEncoder* message, dns_rr_t* rr_list, size_t count)
+{
+ CborError cbor_err = CborNoError;
+ CborEncoder rrs;
+ dns_rr_t* rr = rr_list;
+ size_t n = count;
+
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_create_array(message, &rrs, n);
+ while (n--) {
+ CborEncoder item;
+ if (!(rr->have_type && rr->type == 41)) {
+ if (rr->have_type && rr->type == last.dns_type) {
+ rr->have_type = 0;
+ }
+ if (rr->have_class && rr->class == last.dns_class) {
+ rr->have_class = 0;
+ }
+ if (rr->have_ttl && rr->ttl == last.dns_ttl) {
+ rr->have_ttl = 0;
+ }
+ }
+ if (rr->have_rdlength && rr->have_rdata) {
+ rr->have_rdlength = 0;
+ }
+
+ rr->bits = rr->have_type
+ | rr->have_class << 1
+ | rr->have_ttl << 2
+ | rr->have_rdlength << 3;
+ if (rr->bits && rr->bits != 0xf) {
+ rr->have_bits = 1;
+ }
+
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_create_array(&rrs, &item,
+ (rr->is_complete ? 0 : 1) + rr->have_labels
+ + rr->have_bits + rr->have_type + rr->have_class + rr->have_ttl + rr->have_rdlength
+ + rr->have_rdata);
+ if (!rr->is_complete) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_boolean(&item, false);
+ }
+ if (rr->have_labels) {
+ if (rr->have_rlabel_idx) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&item, rr->rlabel_idx);
+ } else {
+ if (cbor_err == CborNoError)
+ cbor_err = encode_label(&item, rr->label, rr->labels);
+ }
+ }
+ if (rr->have_bits && cbor_err == CborNoError)
+ cbor_err = cbor_encode_simple_value(&item, rr->bits);
+ if (rr->have_type && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&item, rr->type);
+ if (rr->have_class && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&item, rr->class);
+ if (rr->have_ttl && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&item, rr->ttl);
+ if (rr->have_rdlength && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&item, rr->rdlength);
+ if (rr->have_rdata_index) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&item, rr->rdata_index);
+ } else if (rr->have_rdata_rindex) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&item, rr->rdata_rindex);
+ } else if (rr->have_mixed_rdata) {
+ CborEncoder rdatas;
+ size_t n2 = rr->mixed_rdatas;
+ dns_rdata_t* rdata = rr->mixed_rdata;
+
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_create_array(&item, &rdatas, rr->mixed_rdatas);
+ while (n2--) {
+ if (rdata->have_labels) {
+ if (rdata->have_rlabel_idx) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&rdatas, rdata->rlabel_idx);
+ } else {
+ if (cbor_err == CborNoError)
+ cbor_err = encode_label(&rdatas, rdata->label, rdata->labels);
+ }
+ } else if (rdata->have_rdata) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_byte_string(&rdatas, rdata->rdata, rdata->rdata_len);
+ }
+
+ rdata++;
+ }
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(&item, &rdatas);
+ } else if (rr->have_rdata && cbor_err == CborNoError)
+ cbor_err = cbor_encode_byte_string(&item, rr->rdata, rr->rdlength);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(&rrs, &item);
+
+ if (!(rr->have_type && rr->type == 41)) {
+ if (rr->have_type) {
+ last.dns_type = rr->type;
+ }
+ if (rr->have_class) {
+ last.dns_class = rr->class;
+ }
+ if (rr->have_ttl) {
+ last.dns_ttl = rr->ttl;
+ }
+ }
+ rr++;
+ }
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(message, &rrs);
+
+ return cbor_err;
+}
+
+int output_cds(iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char* pkt_copy, size_t olen, const u_char* payload, size_t payloadlen)
+{
+ CborEncoder cbor, message;
+ CborError cbor_err = CborNoError;
+ ip_header_t ip;
+ dns_t dns;
+ uint8_t* malformed = 0;
+ size_t malformed_size = 0;
+ size_t dns_parts = 0;
+
+ if (!payload) {
+ return DUMP_CDS_EINVAL;
+ }
+ if (!payloadlen) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ if (!cbor_buf) {
+ memset(&last, 0, sizeof(last));
+ if (!(cbor_buf = calloc(1, cbor_size + message_size))) {
+ return DUMP_CDS_ENOMEM;
+ }
+ }
+ if (!cbor_buf_p) {
+ cbor_buf_p = cbor_buf;
+ }
+ if (!message_buf) {
+ if (!(message_buf = calloc(1, message_size))) {
+ return DUMP_CDS_ENOMEM;
+ }
+ }
+ if (cbor_flushed) {
+ dns_rlabel_t* rlabel;
+ struct rdata* r;
+
+ cbor_buf_p = cbor_buf;
+ while ((rlabel = last.dns_rlabel)) {
+ last.dns_rlabel = rlabel->next;
+ free(rlabel);
+ }
+ while ((r = last.rdata)) {
+ last.rdata = r->next;
+ rdata_free(r);
+ }
+ memset(&last, 0, sizeof(last));
+ if (rdata_tbl) {
+ hash_free(rdata_tbl);
+ rdata_tbl = 0;
+ }
+
+ cbor_encoder_init(&cbor, message_buf, message_size, 0);
+ cbor_err = cbor_encoder_create_array(&cbor, &message, 5 + (use_rdata_index ? 3 : 0) + (use_rdata_rindex ? 4 : 0));
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_text_stringz(&message, "CDSv1");
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, CDS_OPTION_RLABELS);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, MAX_RLABELS);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, CDS_OPTION_RLABEL_MIN_SIZE);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, MIN_RLABEL_SIZE);
+ if (use_rdata_index) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, CDS_OPTION_USE_RDATA_INDEX);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, CDS_OPTION_RDATA_INDEX_MIN_SIZE);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, RDATA_INDEX_MIN_SIZE);
+ } else if (use_rdata_rindex) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, CDS_OPTION_RDATA_RINDEX_SIZE);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, RDATA_RINDEX_SIZE);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, CDS_OPTION_RDATA_RINDEX_MIN_SIZE);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, RDATA_RINDEX_MIN_SIZE);
+ }
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(&cbor, &message);
+ if (cbor_err != CborNoError) {
+ fprintf(stderr, "cbor error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err));
+ return DUMP_CDS_ECBOR;
+ }
+
+ /* *cbor_buf_p = 0x9f;*/
+ /* cbor_buf_p++;*/
+
+ if ((cbor_size - (cbor_buf_p - cbor_buf)) < cbor_encoder_get_buffer_size(&cbor, message_buf)) {
+ return DUMP_CDS_EBUF;
+ }
+ memcpy(cbor_buf_p, message_buf, cbor_encoder_get_buffer_size(&cbor, message_buf));
+ cbor_buf_p += cbor_encoder_get_buffer_size(&cbor, message_buf);
+
+ cbor_flushed = 0;
+ }
+ if (!rdata_tbl) {
+ if (!(rdata_tbl = hash_create(64 * 1024, rdata_hash, rdata_cmp, rdata_free))) {
+ return DUMP_CDS_ENOMEM;
+ }
+ }
+
+ /*
+ * IP Header
+ */
+
+ memset(&ip, 0, sizeof(ip_header_t));
+
+ /* fill ip */
+ if (from.af == AF_INET6) {
+ ip.is_v6 = 1;
+ memcpy(&(ip.src_addr6), &(from.u.a6), sizeof(struct in6_addr));
+ memcpy(&(ip.dest_addr6), &(to.u.a6), sizeof(struct in6_addr));
+ ip.src_port6 = sport;
+ ip.dest_port6 = dport;
+ } else {
+ memcpy(&(ip.src_addr4), &(from.u.a4), sizeof(struct in_addr));
+ memcpy(&(ip.dest_addr4), &(to.u.a4), sizeof(struct in_addr));
+ ip.src_port4 = sport;
+ ip.dest_port4 = dport;
+ }
+
+ /* deduplicate */
+ {
+ int dedup = 0;
+ ip_header_t reverse;
+
+ reverse = ip;
+
+ /* check last.ip */
+ if (ip.is_v6) {
+ if (!memcmp(&(ip.src_addr6), &(last.ip.src_addr6), sizeof(struct in6_addr)))
+ dedup++;
+ else
+ ip.have_src_addr = 1;
+
+ if (!memcmp(&(ip.dest_addr6), &(last.ip.dest_addr6), sizeof(struct in6_addr)))
+ dedup++;
+ else
+ ip.have_dest_addr = 1;
+
+ if (ip.src_port6 == last.ip.src_port6)
+ dedup++;
+ else
+ ip.have_src_port = 1;
+
+ if (ip.dest_port6 == last.ip.dest_port6)
+ dedup++;
+ else
+ ip.have_dest_port = 1;
+ } else {
+ if (!memcmp(&(ip.src_addr4), &(last.ip.src_addr4), sizeof(struct in_addr)))
+ dedup++;
+ else
+ ip.have_src_addr = 1;
+
+ if (!memcmp(&(ip.dest_addr4), &(last.ip.dest_addr4), sizeof(struct in_addr)))
+ dedup++;
+ else
+ ip.have_dest_addr = 1;
+
+ if (ip.src_port4 == last.ip.src_port4)
+ dedup++;
+ else
+ ip.have_src_port = 1;
+
+ if (ip.dest_port4 == last.ip.dest_port4)
+ dedup++;
+ else
+ ip.have_dest_port = 1;
+ }
+
+ /* check reverse last.ip */
+ if (ip.is_v6) {
+ if (!memcmp(&(ip.src_addr6), &(last.ip.dest_addr6), sizeof(struct in6_addr)))
+ dedup--;
+ else
+ reverse.have_src_addr = 1;
+
+ if (!memcmp(&(ip.dest_addr6), &(last.ip.src_addr6), sizeof(struct in6_addr)))
+ dedup--;
+ else
+ reverse.have_dest_addr = 1;
+
+ if (ip.src_port6 == last.ip.dest_port6)
+ dedup--;
+ else
+ reverse.have_src_port = 1;
+
+ if (ip.dest_port6 == last.ip.src_port6)
+ dedup--;
+ else
+ reverse.have_dest_port = 1;
+ } else {
+ if (!memcmp(&(ip.src_addr4), &(last.ip.dest_addr4), sizeof(struct in_addr)))
+ dedup--;
+ else
+ reverse.have_src_addr = 1;
+
+ if (!memcmp(&(ip.dest_addr4), &(last.ip.src_addr4), sizeof(struct in_addr)))
+ dedup--;
+ else
+ reverse.have_dest_addr = 1;
+
+ if (ip.src_port4 == last.ip.dest_port4)
+ dedup--;
+ else
+ reverse.have_src_port = 1;
+
+ if (ip.dest_port4 == last.ip.src_port4)
+ dedup--;
+ else
+ reverse.have_dest_port = 1;
+ }
+
+ if (dedup < 0) {
+ ip = reverse;
+ ip.is_reverse = 1;
+ /*fprintf(stderr, "reverse of last ip ");*/
+ }
+ /*fprintf(stderr, "v6:%d src:%d dest:%d sport:%d dport:%d\n", ip.is_v6, ip.have_src_addr, ip.have_dest_addr, ip.have_src_port, ip.have_dest_port);*/
+
+ ip.bits = ip.is_v6
+ | ip.have_src_addr << 1
+ | ip.have_dest_addr << 2
+ | (ip.have_src_port | ip.have_dest_port) << 3;
+
+ if (ip.is_v6) {
+ last.ip.src_addr6 = ip.src_addr6;
+ last.ip.dest_addr6 = ip.dest_addr6;
+ last.ip.src_port6 = ip.src_port6;
+ last.ip.dest_port6 = ip.dest_port6;
+ } else {
+ last.ip.src_addr4 = ip.src_addr4;
+ last.ip.dest_addr4 = ip.dest_addr4;
+ last.ip.src_port4 = ip.src_port4;
+ last.ip.dest_port4 = ip.dest_port4;
+ }
+ }
+
+ /*
+ * DNS Message
+ */
+
+ if (flags & DNSCAP_OUTPUT_ISDNS) {
+ uint8_t* p = (uint8_t*)payload;
+ size_t l = payloadlen, rr, n, n2, n3;
+ int ret;
+ dns_rr_t* rrp;
+
+ size_t n_offset = 0;
+ uint16_t offset[256]; /* TODO: Handle offsets better */
+
+ memset(&dns, 0, sizeof(dns));
+ ret = parse_dns(&dns, &p, &l);
+
+ if (ret < 0) {
+ free_dns(&dns);
+ return DUMP_CDS_ENOMEM;
+ } else if (ret > 0) {
+ malformed = p;
+ malformed_size = l;
+ }
+
+ if (dns.have_qdcount && dns.qdcount == dns.questions) {
+ dns.have_qdcount = 0;
+ }
+ if (dns.have_ancount && dns.ancount == dns.answers) {
+ dns.have_ancount = 0;
+ }
+ if (dns.have_nscount && dns.nscount == dns.authorities) {
+ dns.have_nscount = 0;
+ }
+ if (dns.have_arcount && dns.arcount == dns.additionals) {
+ dns.have_arcount = 0;
+ }
+
+ dns.cnt_bits = dns.have_qdcount
+ | dns.have_ancount << 1
+ | dns.have_nscount << 2
+ | dns.have_arcount << 3;
+ if (dns.cnt_bits && dns.cnt_bits != 0xf) {
+ dns.have_cnt_bits = 1;
+ }
+
+ dns.rr_bits = dns.have_questions
+ | dns.have_answers << 1
+ | dns.have_authorities << 2
+ | dns.have_additionals << 3;
+ if (dns.rr_bits && dns.rr_bits != 0xf) {
+ dns.have_rr_bits = 1;
+ }
+
+ dns_rr_build_offset(dns.question, dns.questions, &offset[0], sizeof(offset), &n_offset, payload);
+ dns_rr_build_offset(dns.answer, dns.answers, &offset[0], sizeof(offset), &n_offset, payload);
+ dns_rr_build_offset(dns.authority, dns.authorities, &offset[0], sizeof(offset), &n_offset, payload);
+ dns_rr_build_offset(dns.additional, dns.additionals, &offset[0], sizeof(offset), &n_offset, payload);
+
+ /* for (n = 0; n < n_offset; n++) {*/
+ /* printf("%lu: %u\n", n, offset[n]);*/
+ /* }*/
+
+ dns_rr_set_offset(dns.question, dns.questions, &offset[0], n_offset);
+ dns_rr_set_offset(dns.answer, dns.answers, &offset[0], n_offset);
+ dns_rr_set_offset(dns.authority, dns.authorities, &offset[0], n_offset);
+ dns_rr_set_offset(dns.additional, dns.additionals, &offset[0], n_offset);
+
+ dns_rr_build_rlabel(dns.question, dns.questions);
+ dns_rr_build_rlabel(dns.answer, dns.answers);
+ dns_rr_build_rlabel(dns.authority, dns.authorities);
+ dns_rr_build_rlabel(dns.additional, dns.additionals);
+ }
+
+ /*
+ * CBOR
+ */
+
+ cbor_encoder_init(&cbor, message_buf, message_size, 0);
+ cbor_err = cbor_encoder_create_array(&cbor, &message,
+ /* timestamp */
+ 1
+ /* message bits */
+ + 1
+ /* ip header */
+ + 1 + ip.have_src_addr + ip.have_dest_addr + (ip.have_src_port | ip.have_dest_port)
+ /* dns message */
+ + dns.have_id + dns.have_raw
+ + dns.have_cnt_bits + dns.have_qdcount + dns.have_ancount + dns.have_nscount + dns.have_arcount
+ + dns.have_rr_bits + dns.have_questions + dns.have_answers + dns.have_authorities + dns.have_additionals
+ + (malformed ? 1 : 0));
+
+ /*
+ * Encode timestamp
+ */
+
+ {
+ CborEncoder timestamp;
+
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_create_array(&message, &timestamp, 2);
+ if (last.ts.tv_sec && last.ts.tv_sec <= ts.tv_sec) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&timestamp, ts.tv_sec - last.ts.tv_sec);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_int(&timestamp, ts.tv_usec - last.ts.tv_usec);
+ } else {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&timestamp, ts.tv_sec);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&timestamp, ts.tv_usec);
+ }
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(&message, &timestamp);
+
+ last.ts = ts;
+ }
+
+ /*
+ * Encode message bits
+ */
+
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message,
+ (flags & DNSCAP_OUTPUT_ISDNS ? 1 : 0)
+ + (flags & DNSCAP_OUTPUT_ISDNS ? proto == IPPROTO_TCP ? 1 << 1 : 0
+ : 0)
+ + (flags & DNSCAP_OUTPUT_ISFRAG ? 1 << 2 : 0)
+ + (malformed ? 1 << 3 : 0));
+
+ /*
+ * Encode IP Header
+ */
+
+ if (ip.is_reverse) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&message, ip.bits);
+ } else {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, ip.bits);
+ }
+
+ if (ip.is_v6) {
+ if (ip.have_src_addr && cbor_err == CborNoError)
+ cbor_err = cbor_encode_byte_string(&message, (uint8_t*)&(ip.src_addr6), sizeof(struct in6_addr));
+ if (ip.have_dest_addr && cbor_err == CborNoError)
+ cbor_err = cbor_encode_byte_string(&message, (uint8_t*)&(ip.dest_addr6), sizeof(struct in6_addr));
+ if (ip.have_src_port && ip.have_dest_port) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, (ip.dest_port6 << 16) | ip.src_port6);
+ } else if (ip.have_src_port) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, ip.src_port6);
+ } else if (ip.have_dest_port) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&message, ip.dest_port6);
+ }
+ } else {
+ if (ip.have_src_addr && cbor_err == CborNoError)
+ cbor_err = cbor_encode_byte_string(&message, (uint8_t*)&(ip.src_addr4), sizeof(struct in_addr));
+ if (ip.have_dest_addr && cbor_err == CborNoError)
+ cbor_err = cbor_encode_byte_string(&message, (uint8_t*)&(ip.dest_addr4), sizeof(struct in_addr));
+ if (ip.have_src_port && ip.have_dest_port) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, (ip.dest_port4 << 16) | ip.src_port4);
+ } else if (ip.have_src_port) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, ip.src_port4);
+ } else if (ip.have_dest_port) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&message, ip.dest_port4);
+ }
+ }
+
+ /*
+ * Encode DNS Message
+ */
+ if (flags & DNSCAP_OUTPUT_ISDNS && !dns.header_is_complete) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_boolean(&message, false);
+ }
+ if (dns.have_id && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, dns.id);
+ if (dns.have_raw && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, dns.raw);
+ if (dns.have_cnt_bits && cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&message, dns.cnt_bits);
+ if (dns.have_qdcount && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, dns.qdcount);
+ if (dns.have_ancount && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, dns.ancount);
+ if (dns.have_nscount && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, dns.nscount);
+ if (dns.have_arcount && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&message, dns.arcount);
+ if (dns.have_rr_bits && cbor_err == CborNoError)
+ cbor_err = cbor_encode_simple_value(&message, dns.rr_bits);
+ if (dns.have_questions) {
+ CborEncoder rrs;
+ dns_rr_t* rr = dns.question;
+ size_t n = dns.questions;
+
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_create_array(&message, &rrs, n);
+ while (n--) {
+ CborEncoder item;
+
+ if (rr->have_type && rr->type == last.dns_type) {
+ rr->have_type = 0;
+ }
+ if (rr->have_class && rr->class == last.dns_class) {
+ rr->have_class = 0;
+ }
+
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_create_array(&rrs, &item,
+ (rr->is_complete ? 0 : 1) + rr->have_labels + rr->have_type + rr->have_class);
+ if (!rr->is_complete) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_boolean(&item, false);
+ }
+ if (rr->have_labels) {
+ if (rr->have_rlabel_idx) {
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&item, rr->rlabel_idx);
+ } else {
+ if (cbor_err == CborNoError)
+ cbor_err = encode_label(&item, rr->label, rr->labels);
+ }
+ }
+ if (rr->have_type && cbor_err == CborNoError)
+ cbor_err = cbor_encode_uint(&item, rr->type);
+ if (rr->have_class && cbor_err == CborNoError)
+ cbor_err = cbor_encode_negative_int(&item, rr->class);
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(&rrs, &item);
+
+ if (rr->have_type) {
+ last.dns_type = rr->type;
+ }
+ if (rr->have_class) {
+ last.dns_class = rr->class;
+ }
+
+ rr++;
+ }
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(&message, &rrs);
+ }
+ if (dns.have_answers && cbor_err == CborNoError)
+ cbor_err = dns_build_rrs(&message, dns.answer, dns.answers);
+ if (dns.have_authorities && cbor_err == CborNoError)
+ cbor_err = dns_build_rrs(&message, dns.authority, dns.authorities);
+ if (dns.have_additionals && cbor_err == CborNoError)
+ cbor_err = dns_build_rrs(&message, dns.additional, dns.additionals);
+
+ /*
+ * Encode malformed
+ */
+
+ if (malformed && cbor_err == CborNoError)
+ cbor_err = cbor_encode_byte_string(&message, (uint8_t*)malformed, malformed_size);
+
+ /*
+ * Close
+ */
+
+ free_dns(&dns);
+
+ if (cbor_err == CborNoError)
+ cbor_err = cbor_encoder_close_container_checked(&cbor, &message);
+ if (cbor_err != CborNoError) {
+ fprintf(stderr, "cbor error[%d]: %s\n", cbor_err, cbor_error_string(cbor_err));
+ return DUMP_CDS_ECBOR;
+ }
+
+ /* if (print_cbor>1)*/
+ /* {*/
+ /* uint8_t* p = message_buf;*/
+ /* size_t s = cbor_encoder_get_buffer_size(&cbor, message_buf);*/
+
+ /* while (s--) {*/
+ /* printf("%02x", *p++);*/
+ /* }*/
+ /* printf("\n");*/
+ /* }*/
+
+ if (((cbor_size + message_size) - (cbor_buf_p - cbor_buf)) < cbor_encoder_get_buffer_size(&cbor, message_buf)) {
+ return DUMP_CDS_EBUF;
+ }
+ memcpy(cbor_buf_p, message_buf, cbor_encoder_get_buffer_size(&cbor, message_buf));
+ cbor_buf_p += cbor_encoder_get_buffer_size(&cbor, message_buf);
+
+ if (cbor_buf_p < (cbor_buf + cbor_size)) {
+ return DUMP_CDS_OK;
+ }
+
+ cbor_flushed = 1;
+ return DUMP_CDS_FLUSH;
+}
+
+int dump_cds(FILE* fp)
+{
+ CborError cbor_err;
+
+ if (!fp) {
+ return DUMP_CDS_EINVAL;
+ }
+
+ /* *cbor_buf_p = 0xff;*/
+ /* cbor_buf_p++;*/
+
+ /* fprintf(stderr, "cds output: %lu bytes\n", cbor_buf_p - cbor_buf);*/
+
+ if (fwrite(cbor_buf, cbor_buf_p - cbor_buf, 1, fp) != 1) {
+ return DUMP_CDS_EWRITE;
+ }
+
+ return DUMP_CDS_OK;
+}
+
+int have_cds_support()
+{
+ return 1;
+}
+
+#else /* HAVE_LIBTINYCBOR */
+
+int cds_set_cbor_size(size_t size)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int cds_set_message_size(size_t size)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int cds_set_max_rlabels(size_t size)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int cds_set_min_rlabel_size(size_t size)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int cds_set_use_rdata_index(int use)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int cds_set_use_rdata_rindex(int use)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int cds_set_rdata_index_min_size(size_t size)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int cds_set_rdata_rindex_min_size(size_t size)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int cds_set_rdata_rindex_size(size_t size)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int output_cds(iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char* pkt_copy, size_t olen, const u_char* payload, size_t payloadlen)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int dump_cds(FILE* fp)
+{
+ return DUMP_CDS_ENOSUP;
+}
+
+int have_cds_support()
+{
+ return 0;
+}
+
+#endif
diff --git a/src/dump_cds.h b/src/dump_cds.h
new file mode 100644
index 0000000..a972e59
--- /dev/null
+++ b/src/dump_cds.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap_common.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+#ifndef __dnscap_dump_cds_h
+#define __dnscap_dump_cds_h
+
+#define DUMP_CDS_OK 0
+#define DUMP_CDS_EINVAL 1
+#define DUMP_CDS_ENOMEM 2
+#define DUMP_CDS_ECBOR 3
+#define DUMP_CDS_ELDNS 4
+#define DUMP_CDS_EWRITE 5
+#define DUMP_CDS_FLUSH 6
+#define DUMP_CDS_ENOSUP 7
+#define DUMP_CDS_EBUF 8
+
+#define CDS_OPTION_RLABELS 0
+#define CDS_OPTION_RLABEL_MIN_SIZE 1
+#define CDS_OPTION_RDATA_RINDEX_SIZE 2
+#define CDS_OPTION_RDATA_RINDEX_MIN_SIZE 3
+#define CDS_OPTION_USE_RDATA_INDEX 4
+#define CDS_OPTION_RDATA_INDEX_MIN_SIZE 5
+
+#define CDS_DEFAULT_MAX_RLABELS 255
+#define CDS_DEFAULT_MIN_RLABEL_SIZE 3
+#define CDS_DEFAULT_RDATA_INDEX_MIN_SIZE 5
+#define CDS_DEFAULT_RDATA_RINDEX_SIZE 255
+#define CDS_DEFAULT_RDATA_RINDEX_MIN_SIZE 5
+
+typedef struct ip_header ip_header_t;
+struct ip_header {
+ unsigned short is_v6 : 1;
+ unsigned short is_reverse : 1;
+ unsigned short have_src_addr : 1;
+ unsigned short have_src_port : 1;
+ unsigned short have_dest_addr : 1;
+ unsigned short have_dest_port : 1;
+
+ uint8_t bits;
+ struct in_addr src_addr4;
+ uint16_t src_port4;
+ struct in6_addr src_addr6;
+ uint16_t src_port6;
+ struct in_addr dest_addr4;
+ uint16_t dest_port4;
+ struct in6_addr dest_addr6;
+ uint16_t dest_port6;
+};
+
+typedef struct dns_label dns_label_t;
+struct dns_label {
+ unsigned short is_complete : 1;
+ unsigned short have_size : 1;
+ unsigned short have_extension_bits : 1;
+ unsigned short have_offset : 1;
+ unsigned short have_label : 1;
+ unsigned short have_n_offset : 1;
+
+ uint8_t size;
+ uint8_t extension_bits;
+ uint16_t offset;
+ uint8_t* offset_p;
+ uint8_t* label;
+ size_t n_offset;
+};
+
+#define CDS_RLABEL_LABEL_T_LABEL 64
+
+typedef struct dns_rlabel_label dns_rlabel_label_t;
+struct dns_rlabel_label {
+ unsigned short have_n_offset : 1;
+
+ uint8_t size;
+ uint8_t label[CDS_RLABEL_LABEL_T_LABEL];
+ size_t n_offset;
+};
+
+#define CDS_RLABEL_T_LABELS 256
+
+typedef struct dns_rlabel dns_rlabel_t;
+struct dns_rlabel {
+ dns_rlabel_t* next;
+ dns_rlabel_t* prev;
+
+ uint8_t labels;
+ dns_rlabel_label_t label[CDS_RLABEL_T_LABELS];
+};
+
+typedef struct dns_rdata dns_rdata_t;
+struct dns_rdata {
+ unsigned short is_complete : 1;
+ unsigned short have_labels : 1;
+ unsigned short have_rlabel_idx : 1;
+ unsigned short have_rdata : 1;
+
+ size_t rdata_len;
+ uint8_t* rdata;
+ size_t labels;
+ dns_label_t* label;
+ size_t rlabel_idx;
+};
+
+typedef struct dns_rr dns_rr_t;
+struct dns_rr {
+ unsigned short is_complete : 1;
+ unsigned short have_labels : 1;
+ unsigned short have_rlabel_idx : 1;
+ unsigned short have_bits : 1;
+ unsigned short have_type : 1;
+ unsigned short have_class : 1;
+ unsigned short have_ttl : 1;
+ unsigned short have_rdlength : 1;
+ unsigned short have_rdata : 1;
+ unsigned short have_mixed_rdata : 1;
+ unsigned short have_rdata_index : 1;
+ unsigned short have_rdata_rindex : 1;
+
+ size_t labels;
+ dns_label_t* label;
+ size_t rlabel_idx;
+ uint8_t bits;
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t rdlength;
+ uint8_t* rdata;
+ size_t mixed_rdatas;
+ dns_rdata_t* mixed_rdata;
+ size_t rdata_index;
+ size_t rdata_rindex;
+};
+
+typedef struct dns dns_t;
+struct dns {
+ unsigned short header_is_complete : 1;
+ unsigned short have_id : 1;
+ unsigned short have_raw : 1;
+ unsigned short have_cnt_bits : 1;
+ unsigned short have_qdcount : 1;
+ unsigned short have_ancount : 1;
+ unsigned short have_nscount : 1;
+ unsigned short have_arcount : 1;
+ unsigned short have_rr_bits : 1;
+ unsigned short have_questions : 1;
+ unsigned short have_answers : 1;
+ unsigned short have_authorities : 1;
+ unsigned short have_additionals : 1;
+
+ int id;
+ uint16_t raw;
+ uint8_t cnt_bits;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+ uint8_t rr_bits;
+ size_t questions;
+ dns_rr_t* question;
+ size_t answers;
+ dns_rr_t* answer;
+ size_t authorities;
+ dns_rr_t* authority;
+ size_t additionals;
+ dns_rr_t* additional;
+};
+
+int cds_set_cbor_size(size_t size);
+int cds_set_message_size(size_t size);
+int cds_set_max_rlabels(size_t size);
+int cds_set_min_rlabel_size(size_t size);
+int cds_set_use_rdata_index(int use);
+int cds_set_use_rdata_rindex(int use);
+int cds_set_rdata_index_min_size(size_t size);
+int cds_set_rdata_rindex_min_size(size_t size);
+int cds_set_rdata_rindex_size(size_t size);
+int output_cds(iaddr from, iaddr to, uint8_t proto, unsigned flags, unsigned sport, unsigned dport, my_bpftimeval ts, const u_char* pkt_copy, size_t olen, const u_char* payload, size_t payloadlen);
+int dump_cds(FILE* fp);
+int have_cds_support();
+
+#endif /* __dnscap_dump_cds_h */
diff --git a/src/dump_dns.c b/src/dump_dns.c
new file mode 100644
index 0000000..e03e33f
--- /dev/null
+++ b/src/dump_dns.c
@@ -0,0 +1,319 @@
+/* dump_dns.c - library function to emit decoded dns message on a FILE.
+ *
+ * By: Paul Vixie, ISC, October 2007
+ */
+
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "dnscap_common.h"
+
+#include "dump_dns.h"
+#include "network.h"
+#include "tcpstate.h"
+#include "endian_compat.h"
+
+#include <ldns/ldns.h>
+#include <netinet/in.h>
+
+static inline uint16_t _need16(const void* ptr)
+{
+ uint16_t v;
+ memcpy(&v, ptr, sizeof(v));
+ return be16toh(v);
+}
+
+static void dump_dns_rr(ldns_rr* rr, FILE* trace, ldns_buffer* lbuf, bool qsect)
+{
+ size_t rdlen, i;
+ ldns_rdf* rdf;
+
+ // owner
+ ldns_buffer_clear(lbuf);
+ if (ldns_rdf2buffer_str(lbuf, ldns_rr_owner(rr)) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ fprintf(trace, "%s", (char*)ldns_buffer_begin(lbuf));
+
+ // class
+ ldns_buffer_clear(lbuf);
+ if (ldns_rr_class2buffer_str(lbuf, ldns_rr_get_class(rr)) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ fprintf(trace, ",%s", (char*)ldns_buffer_begin(lbuf));
+
+ // type
+ ldns_buffer_clear(lbuf);
+ if (ldns_rr_type2buffer_str(lbuf, ldns_rr_get_type(rr)) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ fprintf(trace, ",%s", (char*)ldns_buffer_begin(lbuf));
+
+ if (qsect)
+ return;
+
+ fprintf(trace, ",%u", ldns_rr_ttl(rr));
+ switch (ldns_rr_get_type(rr)) {
+ case LDNS_RR_TYPE_SOA:
+ for (i = 0; i < 2; i++) {
+ if (!(rdf = ldns_rr_rdf(rr, i))) {
+ goto error;
+ }
+ ldns_buffer_clear(lbuf);
+ if (ldns_rdf2buffer_str(lbuf, rdf) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ fprintf(trace, ",%s", (char*)ldns_buffer_begin(lbuf));
+ }
+ for (; i < 7; i++) {
+ if (!(rdf = ldns_rr_rdf(rr, i))) {
+ goto error;
+ }
+ ldns_buffer_clear(lbuf);
+ if (ldns_rdf2buffer_str(lbuf, rdf) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ fprintf(trace, ",%s", (char*)ldns_buffer_begin(lbuf));
+ }
+ break;
+
+ case LDNS_RR_TYPE_A:
+ case LDNS_RR_TYPE_AAAA:
+ case LDNS_RR_TYPE_MX:
+ if (!(rdf = ldns_rr_rdf(rr, 0))) {
+ goto error;
+ }
+ ldns_buffer_clear(lbuf);
+ if (ldns_rdf2buffer_str(lbuf, rdf) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ fprintf(trace, ",%s", (char*)ldns_buffer_begin(lbuf));
+ break;
+
+ case LDNS_RR_TYPE_NS:
+ case LDNS_RR_TYPE_PTR:
+ case LDNS_RR_TYPE_CNAME:
+ if (!(rdf = ldns_rr_rdf(rr, 0))) {
+ goto error;
+ }
+ ldns_buffer_clear(lbuf);
+ if (ldns_rdf2buffer_str(lbuf, rdf) != LDNS_STATUS_OK) {
+ goto error;
+ }
+ fprintf(trace, ",%s", (char*)ldns_buffer_begin(lbuf));
+ break;
+
+ default:
+ goto error;
+ }
+ return;
+
+error:
+ for (rdlen = 0, i = 0, rdf = ldns_rr_rdf(rr, i); rdf; rdf = ldns_rr_rdf(rr, ++i)) {
+ rdlen += ldns_rdf_size(rdf);
+ }
+ fprintf(trace, ",[%zu]", rdlen);
+}
+
+static void dump_dns_sect(ldns_rr_list* rrs, FILE* trace, const char* endline, ldns_buffer* lbuf, bool qsect, bool ansect, ldns_pkt* pkt)
+{
+ size_t rrnum, rrmax;
+ const char* sep;
+
+ if (ansect && ldns_pkt_edns(pkt)) {
+ rrmax = ldns_rr_list_rr_count(rrs);
+ fprintf(trace, " %s%zu", endline, rrmax + 1);
+ sep = "";
+ for (rrnum = 0; rrnum < rrmax; rrnum++) {
+ fprintf(trace, " %s", sep);
+ dump_dns_rr(ldns_rr_list_rr(rrs, rrnum), trace, lbuf, qsect);
+ sep = endline;
+ }
+ ldns_rdf* edns_data = ldns_pkt_edns_data(pkt);
+ fprintf(trace, " %s.,%u,%u,0,edns0[len=%zu,UDP=%u,ver=%u,rcode=%u,DO=%u,z=%u]",
+ sep, ldns_pkt_edns_udp_size(pkt), ldns_pkt_edns_udp_size(pkt),
+ edns_data ? ldns_rdf_size(edns_data) : 0,
+ ldns_pkt_edns_udp_size(pkt),
+ ldns_pkt_edns_version(pkt),
+ ldns_pkt_edns_extended_rcode(pkt),
+ ldns_pkt_edns_do(pkt) ? 1 : 0,
+ ldns_pkt_edns_z(pkt));
+ if (edns_data) {
+ size_t len = ldns_rdf_size(edns_data);
+ uint8_t* d = ldns_rdf_data(edns_data);
+
+ while (len >= 4) {
+ uint16_t opcode = _need16(d);
+ uint16_t oplen = _need16(d + 2);
+ len -= 4;
+ d += 4;
+
+ if (oplen > len) {
+ break;
+ }
+ switch (opcode) {
+ case 8: {
+ if (oplen >= 4) {
+ uint16_t family = _need16(d);
+ uint8_t source_prefix_len = *(d + 2), scope_prefix_len = *(d + 3);
+ char addr[(INET_ADDRSTRLEN < INET6_ADDRSTRLEN ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN) + 1] = { 0 };
+ struct in_addr in4 = { .s_addr = INADDR_ANY };
+ struct in6_addr in6 = IN6ADDR_ANY_INIT;
+ void* in = 0;
+ int af;
+
+ switch (family) {
+ case 1: {
+ memcpy(&in4.s_addr, d + 4, oplen - 4 > sizeof(in4.s_addr) ? sizeof(in4.s_addr) : oplen - 4);
+ in = &in4;
+ af = AF_INET;
+ break;
+ }
+ case 2: {
+ memcpy(&in6.s6_addr, d + 4, oplen - 4 > sizeof(in6.s6_addr) ? sizeof(in6.s6_addr) : oplen - 4);
+ in = &in6;
+ af = AF_INET6;
+ break;
+ }
+ default:
+ break;
+ }
+
+ fprintf(trace, ",edns0opt[ECS,family=%u,source=%u,scope=%u,", family, source_prefix_len, scope_prefix_len);
+
+ if (!in || !inet_ntop(af, in, addr, sizeof(addr) - 1)) {
+ fprintf(trace, "addr=INVALID]");
+ } else {
+ fprintf(trace, "addr=%s]", addr);
+ }
+
+ break;
+ }
+ }
+
+ default:
+ fprintf(trace, ",edns0opt[code=%u,codelen=%u]", opcode, oplen);
+ break;
+ }
+
+ len -= oplen;
+ d += oplen;
+ }
+ }
+ return;
+ }
+
+ rrmax = ldns_rr_list_rr_count(rrs);
+ if (rrmax == 0) {
+ fputs(" 0", trace);
+ return;
+ }
+ fprintf(trace, " %s%zu", endline, rrmax);
+ sep = "";
+ for (rrnum = 0; rrnum < rrmax; rrnum++) {
+ fprintf(trace, " %s", sep);
+ dump_dns_rr(ldns_rr_list_rr(rrs, rrnum), trace, lbuf, qsect);
+ sep = endline;
+ }
+}
+
+void dump_dns(const u_char* payload, size_t paylen, FILE* trace, const char* endline)
+{
+ const char* sep;
+ tcpstate_ptr tcpstate;
+ ldns_pkt* pkt = 0;
+ ldns_buffer* lbuf = 0;
+ ldns_status ret;
+
+ fprintf(trace, " %sdns ", endline);
+ if ((ret = ldns_wire2pkt(&pkt, payload, paylen)) != LDNS_STATUS_OK) {
+ /* DNS message may have padding, try get actual size */
+ size_t dnslen = calcdnslen(payload, paylen);
+ if (dnslen > 0 && dnslen < paylen) {
+ if ((ret = ldns_wire2pkt(&pkt, payload, dnslen)) != LDNS_STATUS_OK) {
+ fputs(ldns_get_errorstr_by_id(ret), trace);
+ if ((tcpstate = tcpstate_getcurr()))
+ tcpstate_reset(tcpstate, strerror(errno));
+ return;
+ }
+ } else {
+ fputs(ldns_get_errorstr_by_id(ret), trace);
+ if ((tcpstate = tcpstate_getcurr()))
+ tcpstate_reset(tcpstate, strerror(errno));
+ return;
+ }
+ }
+
+ if (!(lbuf = ldns_buffer_new(512))) {
+ fprintf(stderr, "%s: out of memory", ProgramName);
+ exit(1);
+ }
+
+ if (ldns_pkt_opcode2buffer_str(lbuf, ldns_pkt_get_opcode(pkt)) != LDNS_STATUS_OK) {
+ fprintf(stderr, "%s: unable to covert opcode to str", ProgramName);
+ exit(1);
+ }
+ fprintf(trace, "%s,", (char*)ldns_buffer_begin(lbuf));
+ ldns_buffer_clear(lbuf);
+ if (ldns_pkt_rcode2buffer_str(lbuf, ldns_pkt_get_rcode(pkt)) != LDNS_STATUS_OK) {
+ fprintf(stderr, "%s: unable to covert rcode to str", ProgramName);
+ exit(1);
+ }
+ fprintf(trace, "%s,%u,", (char*)ldns_buffer_begin(lbuf), ldns_pkt_id(pkt));
+
+ sep = "";
+#define FLAG(t, f) \
+ if (f) { \
+ fprintf(trace, "%s%s", sep, t); \
+ sep = "|"; \
+ }
+ FLAG("qr", ldns_pkt_qr(pkt));
+ FLAG("aa", ldns_pkt_aa(pkt));
+ FLAG("tc", ldns_pkt_tc(pkt));
+ FLAG("rd", ldns_pkt_rd(pkt));
+ FLAG("ra", ldns_pkt_ra(pkt));
+ FLAG("z", LDNS_Z_WIRE(payload));
+ FLAG("ad", ldns_pkt_ad(pkt));
+ FLAG("cd", ldns_pkt_cd(pkt));
+#undef FLAG
+ dump_dns_sect(ldns_pkt_question(pkt), trace, endline, lbuf, true, false, 0);
+ dump_dns_sect(ldns_pkt_answer(pkt), trace, endline, lbuf, false, false, 0);
+ dump_dns_sect(ldns_pkt_authority(pkt), trace, endline, lbuf, false, false, 0);
+ dump_dns_sect(ldns_pkt_additional(pkt), trace, endline, lbuf, false, true, pkt);
+
+ ldns_buffer_free(lbuf);
+ ldns_pkt_free(pkt);
+}
diff --git a/src/dump_dns.h b/src/dump_dns.h
new file mode 100644
index 0000000..14c01a9
--- /dev/null
+++ b/src/dump_dns.h
@@ -0,0 +1,47 @@
+/* dump_dns.c - library function to emit decoded dns message on a FILE.
+ *
+ * By: Paul Vixie, ISC, October 2007
+ */
+
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __dnscap_dump_dns_h
+#define __dnscap_dump_dns_h
+
+#include <stdio.h>
+
+void dump_dns(const u_char* payload, size_t paylen, FILE* trace, const char* endline);
+
+#endif // __dnscap_dump_dns_h
diff --git a/src/dumper.c b/src/dumper.c
new file mode 100644
index 0000000..b5458f5
--- /dev/null
+++ b/src/dumper.c
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "dumper.h"
+#include "iaddr.h"
+#include "log.h"
+#include "pcaps.h"
+
+/*
+ * when flags & DNSCAP_OUTPUT_ISDNS, payload points to a DNS packet
+ */
+void output(const char* descr, iaddr from, iaddr to, uint8_t proto, unsigned flags,
+ unsigned sport, unsigned dport, my_bpftimeval ts,
+ const u_char* pkt_copy, const unsigned olen,
+ const u_char* payload, const unsigned payloadlen)
+{
+ struct plugin* p;
+
+ for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
+ if (p->filter && (*p->filter)(descr, &from, &to, proto, flags, sport, dport, ts, pkt_copy, olen, payload, payloadlen)) {
+ if (dumptrace >= 3) {
+ fprintf(stderr, "filtered: capturedbytes=%zu, proto=%d, isfrag=%s, isdns=%s, olen=%u, payloadlen=%u\n",
+ capturedbytes,
+ proto,
+ flags & DNSCAP_OUTPUT_ISFRAG ? "yes" : "no",
+ flags & DNSCAP_OUTPUT_ISDNS ? "yes" : "no",
+ olen,
+ payloadlen);
+ }
+ return;
+ }
+ }
+
+ msgcount++;
+ capturedbytes += olen;
+
+ if (dumptrace >= 3) {
+ fprintf(stderr, "output: capturedbytes=%zu, proto=%d, isfrag=%s, isdns=%s, olen=%u, payloadlen=%u\n",
+ capturedbytes,
+ proto,
+ flags & DNSCAP_OUTPUT_ISFRAG ? "yes" : "no",
+ flags & DNSCAP_OUTPUT_ISDNS ? "yes" : "no",
+ olen,
+ payloadlen);
+ }
+
+ /* Output stage. */
+ if (preso) {
+ fputs(descr, stderr);
+ if (flags & DNSCAP_OUTPUT_ISFRAG) {
+ fprintf(stderr, ";: [%s] ", ia_str(from));
+ fprintf(stderr, "-> [%s] (frag)\n", ia_str(to));
+ } else {
+ fprintf(stderr, "\t[%s].%u ", ia_str(from), sport);
+ fprintf(stderr, "[%s].%u ", ia_str(to), dport);
+ if ((flags & DNSCAP_OUTPUT_ISDNS) && payload)
+ dump_dns(payload, payloadlen, stderr, "\\\n\t");
+ }
+ putc('\n', stderr);
+ }
+ if (dump_type != nowhere) {
+ if (options.dump_format == pcap) {
+ struct pcap_pkthdr h;
+
+ memset(&h, 0, sizeof h);
+ h.ts = ts;
+ h.len = h.caplen = olen;
+ pcap_dump((u_char*)dumper, &h, pkt_copy);
+ if (flush)
+ pcap_dump_flush(dumper);
+ } else if (options.dump_format == cbor && (flags & DNSCAP_OUTPUT_ISDNS) && payload) {
+ int ret = output_cbor(from, to, proto, flags, sport, dport, ts, payload, payloadlen);
+
+ if (ret == DUMP_CBOR_FLUSH) {
+ if (dumper_close(ts)) {
+ fprintf(stderr, "%s: dumper_close() failed\n", ProgramName);
+ exit(1);
+ }
+ if (dumper_open(ts)) {
+ fprintf(stderr, "%s: dumper_open() failed\n", ProgramName);
+ exit(1);
+ }
+ } else if (ret != DUMP_CBOR_OK) {
+ fprintf(stderr, "%s: output to cbor failed [%u]\n", ProgramName, ret);
+ exit(1);
+ }
+ } else if (options.dump_format == cds) {
+ int ret = output_cds(from, to, proto, flags, sport, dport, ts, pkt_copy, olen, payload, payloadlen);
+
+ if (ret == DUMP_CDS_FLUSH) {
+ if (dumper_close(ts)) {
+ fprintf(stderr, "%s: dumper_close() failed\n", ProgramName);
+ exit(1);
+ }
+ if (dumper_open(ts)) {
+ fprintf(stderr, "%s: dumper_open() failed\n", ProgramName);
+ exit(1);
+ }
+ } else if (ret != DUMP_CDS_OK) {
+ fprintf(stderr, "%s: output to cds failed [%u]\n", ProgramName, ret);
+ exit(1);
+ }
+ }
+ }
+ for (p = HEAD(plugins); p != NULL; p = NEXT(p, link))
+ if (p->output)
+ (*p->output)(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, olen, payload, payloadlen);
+ return;
+}
+
+int dumper_open(my_bpftimeval ts)
+{
+ const char* t = NULL;
+ struct plugin* p;
+
+ assert(dump_state == dumper_closed);
+
+ while (ts.tv_usec >= MILLION) {
+ ts.tv_sec++;
+ ts.tv_usec -= MILLION;
+ }
+ if (limit_seconds != 0U)
+ next_interval = ts.tv_sec
+ - (ts.tv_sec % limit_seconds)
+ + limit_seconds;
+
+ if (dump_type == to_stdout) {
+ t = "-";
+ } else if (dump_type == to_file) {
+ char sbuf[64];
+ struct tm tm;
+
+ gmtime_r((time_t*)&ts.tv_sec, &tm);
+ strftime(sbuf, 64, "%Y%m%d.%H%M%S", &tm);
+ if (asprintf(&dumpname, "%s.%s.%06lu%s",
+ dump_base, sbuf,
+ (u_long)ts.tv_usec, dump_suffix ? dump_suffix : "")
+ < 0
+ || asprintf(&dumpnamepart, "%s.part", dumpname) < 0) {
+ logerr("asprintf: %s", strerror(errno));
+ return (TRUE);
+ }
+ t = dumpnamepart;
+ }
+ if (NULL != t) {
+ if (options.dump_format == pcap) {
+ dumper = dnscap_pcap_dump_open(pcap_dead, t);
+ if (dumper == NULL) {
+ logerr("pcap dump open: %s",
+ pcap_geterr(pcap_dead));
+ return (TRUE);
+ }
+ }
+ }
+ dumpstart = ts.tv_sec;
+ if (limit_seconds != 0U) {
+ struct timeval now;
+ u_int seconds;
+ time_t targ;
+
+ gettimeofday(&now, NULL);
+ while (now.tv_usec >= MILLION) {
+ now.tv_sec++;
+ now.tv_usec -= MILLION;
+ }
+ targ = (((now.tv_sec + (limit_seconds / 2))
+ / limit_seconds)
+ + 1)
+ * limit_seconds;
+ assert(targ > now.tv_sec);
+ seconds = targ - now.tv_sec;
+ if (next_interval == 0) {
+ alarm(seconds);
+ alarm_set = TRUE;
+ }
+ }
+ for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
+ int x;
+ if (!p->open)
+ continue;
+ x = (*p->open)(ts);
+ if (0 == x)
+ continue;
+ logerr("%s_open returned %d", p->name, x);
+ }
+ dump_state = dumper_opened;
+ return (FALSE);
+}
+
+int dumper_close(my_bpftimeval ts)
+{
+ int ret = FALSE;
+ struct plugin* p;
+
+ assert(dump_state == dumper_opened);
+
+ if (print_pcap_stats)
+ do_pcap_stats();
+
+ if (alarm_set) {
+ alarm(0);
+ alarm_set = FALSE;
+ }
+
+ if (options.dump_format == pcap) {
+ if (dumper) {
+ pcap_dump_close(dumper);
+ dumper = FALSE;
+ }
+ } else if (options.dump_format == cbor) {
+ int ret;
+
+ if (dump_type == to_stdout) {
+ ret = dump_cbor(stdout);
+
+ if (ret != DUMP_CBOR_OK) {
+ fprintf(stderr, "%s: output to cbor failed [%u]\n", ProgramName, ret);
+ exit(1);
+ }
+ } else if (dump_type == to_file) {
+ FILE* fp;
+
+ if (!(fp = fopen(dumpnamepart, "w"))) {
+ fprintf(stderr, "%s: fopen(%s) failed: %s\n", ProgramName, dumpnamepart, strerror(errno));
+ exit(1);
+ }
+ ret = dump_cbor(fp);
+ fclose(fp);
+ if (ret != DUMP_CBOR_OK) {
+ fprintf(stderr, "%s: output to cbor failed [%u]\n", ProgramName, ret);
+ exit(1);
+ }
+ }
+ } else if (options.dump_format == cds) {
+ int ret;
+
+ if (dump_type == to_stdout) {
+ ret = dump_cds(stdout);
+
+ if (ret != DUMP_CDS_OK) {
+ fprintf(stderr, "%s: output to cds failed [%u]\n", ProgramName, ret);
+ exit(1);
+ }
+ } else if (dump_type == to_file) {
+ FILE* fp;
+
+ if (!(fp = fopen(dumpnamepart, "w"))) {
+ fprintf(stderr, "%s: fopen(%s) failed: %s\n", ProgramName, dumpnamepart, strerror(errno));
+ exit(1);
+ }
+ ret = dump_cds(fp);
+ fclose(fp);
+ if (ret != DUMP_CDS_OK) {
+ fprintf(stderr, "%s: output to cds failed [%u]\n", ProgramName, ret);
+ exit(1);
+ }
+ }
+ }
+
+ if (dump_type == to_stdout) {
+ assert(dumpname == NULL);
+ assert(dumpnamepart == NULL);
+ if (dumptrace >= 1)
+ fprintf(stderr, "%s: breaking\n", ProgramName);
+ ret = TRUE;
+ } else if (dump_type == to_file) {
+ char* cmd = NULL;
+ ;
+
+ if (dumptrace >= 1)
+ fprintf(stderr, "%s: closing %s\n",
+ ProgramName, dumpname);
+ if (rename(dumpnamepart, dumpname)) {
+ logerr("rename: %s", strerror(errno));
+ return ret;
+ }
+ if (kick_cmd != NULL)
+ if (asprintf(&cmd, "%s %s &", kick_cmd, dumpname) < 0) {
+ logerr("asprintf: %s", strerror(errno));
+ cmd = NULL;
+ }
+ free(dumpnamepart);
+ dumpnamepart = NULL;
+ free(dumpname);
+ dumpname = NULL;
+ if (cmd != NULL) {
+ int x = system(cmd);
+ if (x)
+ logerr("system: \"%s\" returned %d", cmd, x);
+ free(cmd);
+ }
+ if (kick_cmd == NULL && options.dump_format != cbor && options.dump_format != cds)
+ ret = TRUE;
+ }
+ for (p = HEAD(plugins); p != NULL; p = NEXT(p, link)) {
+ int x;
+ if (!p->close)
+ continue;
+ x = (*p->close)(ts);
+ if (x)
+ logerr("%s_close returned %d", p->name, x);
+ }
+ dump_state = dumper_closed;
+ return (ret);
+}
+
+#if HAVE_ZLIB_H
+#if HAVE_FUNOPEN
+static int
+gzip_cookie_write(void* cookie, const char* buf, int size)
+{
+ return gzwrite((gzFile)cookie, (voidpc)buf, (unsigned)size);
+}
+#elif HAVE_FOPENCOOKIE
+static ssize_t
+gzip_cookie_write(void* cookie, const char* buf, size_t size)
+{
+ return gzwrite((gzFile)cookie, (voidpc)buf, (unsigned)size);
+}
+#endif
+
+static int
+gzip_cookie_close(void* cookie)
+{
+ return gzclose((gzFile)cookie);
+}
+#endif /* HAVE_ZLIB_H */
+
+pcap_dumper_t* dnscap_pcap_dump_open(pcap_t* pcap, const char* path)
+{
+#if HAVE_ZLIB_H
+#if HAVE_GZOPEN
+ if (wantgzip) {
+ FILE* fp = NULL;
+ gzFile z = gzopen(path, "w");
+ if (z == NULL) {
+ perror("gzopen");
+ return NULL;
+ }
+
+#if HAVE_FUNOPEN
+ fp = funopen(z, NULL, gzip_cookie_write, NULL, gzip_cookie_close);
+ if (fp == NULL) {
+ perror("funopen");
+ return NULL;
+ }
+#elif HAVE_FOPENCOOKIE
+ {
+ static cookie_io_functions_t cookiefuncs = {
+ NULL, gzip_cookie_write, NULL, gzip_cookie_close
+ };
+
+ fp = fopencookie(z, "w", cookiefuncs);
+ if (fp == NULL) {
+ perror("fopencookie");
+ return NULL;
+ }
+ }
+#endif
+ return pcap_dump_fopen(pcap, fp);
+ }
+#endif /* HAVE_GZOPEN */
+#endif /* HAVE_ZLIB_H */
+
+ return pcap_dump_open(pcap, path);
+}
diff --git a/src/dumper.h b/src/dumper.h
new file mode 100644
index 0000000..f447f5c
--- /dev/null
+++ b/src/dumper.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_dumper_h
+#define __dnscap_dumper_h
+
+void output(const char* descr, iaddr from, iaddr to, uint8_t proto, unsigned flags,
+ unsigned sport, unsigned dport, my_bpftimeval ts,
+ const u_char* pkt_copy, const unsigned olen,
+ const u_char* payload, const unsigned payloadlen);
+
+int dumper_open(my_bpftimeval ts);
+int dumper_close(my_bpftimeval ts);
+
+pcap_dumper_t* dnscap_pcap_dump_open(pcap_t* pcap, const char* path);
+
+#endif /* __dnscap_dumper_h */
diff --git a/src/endian_compat.h b/src/endian_compat.h
new file mode 100644
index 0000000..6c49625
--- /dev/null
+++ b/src/endian_compat.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __dnscap_endian_compat_h
+#define __dnscap_endian_compat_h
+
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#else
+#ifdef HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#else
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#endif
+#endif
+#endif
+
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#define htobe16(x) OSSwapHostToBigInt16(x)
+#define htole16(x) OSSwapHostToLittleInt16(x)
+#define be16toh(x) OSSwapBigToHostInt16(x)
+#define le16toh(x) OSSwapLittleToHostInt16(x)
+#define htobe32(x) OSSwapHostToBigInt32(x)
+#define htole32(x) OSSwapHostToLittleInt32(x)
+#define be32toh(x) OSSwapBigToHostInt32(x)
+#define le32toh(x) OSSwapLittleToHostInt32(x)
+#define htobe64(x) OSSwapHostToBigInt64(x)
+#define htole64(x) OSSwapHostToLittleInt64(x)
+#define be64toh(x) OSSwapBigToHostInt64(x)
+#define le64toh(x) OSSwapLittleToHostInt64(x)
+#define __BYTE_ORDER BYTE_ORDER
+#define __BIG_ENDIAN BIG_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#define __PDP_ENDIAN PDP_ENDIAN
+#endif
+
+#if defined(_WIN16) || defined(_WIN32) || defined(_WIN64) || defined(__WINDOWS__)
+#include <winsock2.h>
+#include <sys/param.h>
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define htobe16(x) htons(x)
+#define htole16(x) (x)
+#define be16toh(x) ntohs(x)
+#define le16toh(x) (x)
+#define htobe32(x) htonl(x)
+#define htole32(x) (x)
+#define be32toh(x) ntohl(x)
+#define le32toh(x) (x)
+#define htobe64(x) htonll(x)
+#define htole64(x) (x)
+#define be64toh(x) ntohll(x)
+#define le64toh(x) (x)
+#elif BYTE_ORDER == BIG_ENDIAN
+#define htobe16(x) (x)
+#define htole16(x) __builtin_bswap16(x)
+#define be16toh(x) (x)
+#define le16toh(x) __builtin_bswap16(x)
+#define htobe32(x) (x)
+#define htole32(x) __builtin_bswap32(x)
+#define be32toh(x) (x)
+#define le32toh(x) __builtin_bswap32(x)
+#define htobe64(x) (x)
+#define htole64(x) __builtin_bswap64(x)
+#define be64toh(x) (x)
+#define le64toh(x) __builtin_bswap64(x)
+#else
+#error "byte order not supported"
+#endif
+#define __BYTE_ORDER BYTE_ORDER
+#define __BIG_ENDIAN BIG_ENDIAN
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#define __PDP_ENDIAN PDP_ENDIAN
+#endif
+
+#endif
diff --git a/src/endpoint.c b/src/endpoint.c
new file mode 100644
index 0000000..da37fe3
--- /dev/null
+++ b/src/endpoint.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "endpoint.h"
+#include "args.h"
+#include "iaddr.h"
+
+void endpoint_arg(endpoint_list* list, const char* arg)
+{
+ struct addrinfo* ai;
+ iaddr ia;
+ void* p;
+
+ if (inet_pton(AF_INET6, arg, &ia.u.a6) > 0) {
+ ia.af = AF_INET6;
+ endpoint_add(list, ia);
+ } else if (inet_pton(AF_INET, arg, &ia.u.a4) > 0) {
+ ia.af = AF_INET;
+ endpoint_add(list, ia);
+ } else if (getaddrinfo(arg, NULL, NULL, &ai) == 0) {
+ struct addrinfo* a;
+
+ for (a = ai; a != NULL; a = a->ai_next) {
+ if (a->ai_socktype != SOCK_DGRAM)
+ continue;
+ switch (a->ai_family) {
+ case PF_INET:
+ ia.af = AF_INET;
+ p = &((struct sockaddr_in*)a->ai_addr)
+ ->sin_addr;
+ memcpy(&ia.u.a4, p, sizeof ia.u.a4);
+ break;
+ case PF_INET6:
+ ia.af = AF_INET6;
+ p = &((struct sockaddr_in6*)a->ai_addr)
+ ->sin6_addr;
+ memcpy(&ia.u.a6, p, sizeof ia.u.a6);
+ break;
+ default:
+ continue;
+ }
+ endpoint_add(list, ia);
+ }
+ freeaddrinfo(ai);
+ } else
+ usage("invalid host address");
+}
+
+void endpoint_add(endpoint_list* list, iaddr ia)
+{
+ endpoint_ptr ep;
+
+ ep = calloc(1, sizeof *ep);
+ assert(ep != NULL);
+ INIT_LINK(ep, link);
+ ep->ia = ia;
+ APPEND(*list, ep, link);
+}
+
+int ep_present(const endpoint_list* list, iaddr ia)
+{
+ endpoint_ptr ep;
+
+ for (ep = HEAD(*list);
+ ep != NULL;
+ ep = NEXT(ep, link))
+ if (ia_equal(ia, ep->ia))
+ return TRUE;
+ return (FALSE);
+}
diff --git a/src/endpoint.h b/src/endpoint.h
new file mode 100644
index 0000000..9136ca9
--- /dev/null
+++ b/src/endpoint.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_endpoint_h
+#define __dnscap_endpoint_h
+
+void endpoint_arg(endpoint_list* list, const char* arg);
+void endpoint_add(endpoint_list* list, iaddr ia);
+int ep_present(const endpoint_list* list, iaddr ia);
+
+#endif /* __dnscap_endpoint_h */
diff --git a/src/hashtbl.c b/src/hashtbl.c
new file mode 100644
index 0000000..62e1a9e
--- /dev/null
+++ b/src/hashtbl.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hashtbl.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+
+hashtbl* hash_create(unsigned int N, hashkey_func hasher, hashkeycmp_func cmp, hashfree_func datafree)
+{
+ hashtbl* new;
+
+ assert(N);
+ assert(hasher);
+ assert(cmp);
+
+ if ((new = calloc(1, sizeof(hashtbl)))) {
+ new->modulus = N;
+ new->hasher = hasher;
+ new->keycmp = cmp;
+ new->datafree = datafree;
+
+ if (!(new->items = calloc(N, sizeof(hashitem*)))) {
+ free(new);
+ return 0;
+ }
+ }
+
+ return new;
+}
+
+int hash_add(const void* key, void* data, hashtbl* tbl)
+{
+ hashitem* new, **I;
+ unsigned int slot;
+
+ if (!key || !tbl) {
+ return HASHTBL_EARGS;
+ }
+
+ new = calloc(1, sizeof(hashitem));
+ if (!new) {
+ return HASHTBL_ENOMEM;
+ }
+
+ new->key = key;
+ new->data = data;
+ slot = tbl->hasher(key) % tbl->modulus;
+
+ for (I = &tbl->items[slot]; *I; I = &(*I)->next)
+ ;
+ *I = new;
+
+ return 0;
+}
+
+void* hash_find(const void* key, hashtbl* tbl)
+{
+ unsigned int slot;
+ hashitem* i;
+
+ if (!key || !tbl) {
+ return NULL;
+ }
+
+ slot = tbl->hasher(key) % tbl->modulus;
+
+ for (i = tbl->items[slot]; i; i = i->next) {
+ if (!tbl->keycmp(key, i->key))
+ return i->data;
+ }
+
+ return NULL;
+}
+
+void hash_remove(const void* key, hashtbl* tbl)
+{
+ hashitem **I, *i;
+ int slot;
+
+ if (!key || !tbl) {
+ return;
+ }
+
+ slot = tbl->hasher(key) % tbl->modulus;
+
+ for (I = &tbl->items[slot]; *I; I = &(*I)->next) {
+ if (!tbl->keycmp(key, (*I)->key)) {
+ i = *I;
+ *I = (*I)->next;
+ if (tbl->datafree)
+ tbl->datafree(i->data);
+ free(i);
+ break;
+ }
+ }
+}
+
+void hash_free(hashtbl* tbl)
+{
+ hashitem *i, *next;
+ int slot;
+
+ if (!tbl) {
+ return;
+ }
+
+ for (slot = 0; slot < tbl->modulus; slot++) {
+ for (i = tbl->items[slot]; i;) {
+ next = i->next;
+ if (tbl->datafree)
+ tbl->datafree(i->data);
+ free(i);
+ i = next;
+ }
+ tbl->items[slot] = 0;
+ }
+}
+
+void hash_destroy(hashtbl* tbl)
+{
+ if (!tbl) {
+ return;
+ }
+
+ hash_free(tbl);
+ free(tbl->items);
+ free(tbl);
+}
diff --git a/src/hashtbl.h b/src/hashtbl.h
new file mode 100644
index 0000000..03eae65
--- /dev/null
+++ b/src/hashtbl.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __dnscap_hashtbl_h
+#define __dnscap_hashtbl_h
+
+#define HASHTBL_EARGS -1
+#define HASHTBL_ENOMEM -2
+
+typedef struct hashitem hashitem;
+
+struct hashitem {
+ const void* key;
+ void* data;
+ hashitem* next;
+};
+
+typedef unsigned int (*hashkey_func)(const void* key);
+typedef int (*hashkeycmp_func)(const void* a, const void* b);
+typedef void (*hashfree_func)(void* data);
+
+typedef struct hashtbl hashtbl;
+struct hashtbl {
+ unsigned int modulus;
+ hashitem** items;
+
+ hashkey_func hasher;
+ hashkeycmp_func keycmp;
+ hashfree_func datafree;
+};
+
+hashtbl* hash_create(unsigned int N, hashkey_func hasher, hashkeycmp_func cmp, hashfree_func datafree);
+int hash_add(const void* key, void* data, hashtbl* tbl);
+void* hash_find(const void* key, hashtbl* tbl);
+void hash_remove(const void* key, hashtbl* tbl);
+void hash_free(hashtbl* tbl);
+void hash_destroy(hashtbl* tbl);
+
+#endif // __dnscap_hashtbl_h
diff --git a/src/iaddr.c b/src/iaddr.c
new file mode 100644
index 0000000..2c5cbeb
--- /dev/null
+++ b/src/iaddr.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "iaddr.h"
+
+const char* ia_str(iaddr ia)
+{
+ static char inet[INET_ADDRSTRLEN], inet6[INET6_ADDRSTRLEN];
+
+ switch (ia.af) {
+ case AF_INET:
+ if (inet_ntop(ia.af, &ia.u, inet, sizeof(inet)))
+ return inet;
+ return "255.255.255.255";
+ case AF_INET6:
+ if (inet_ntop(ia.af, &ia.u, inet6, sizeof(inet6)))
+ return inet6;
+ return "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff";
+ }
+
+ return "UNKNOWN";
+}
+
+int ia_equal(iaddr x, iaddr y)
+{
+ if (x.af != y.af)
+ return FALSE;
+ switch (x.af) {
+ case AF_INET:
+ return (x.u.a4.s_addr == y.u.a4.s_addr);
+ case AF_INET6:
+ return (memcmp(&x.u.a6.s6_addr, &y.u.a6.s6_addr, sizeof(x.u.a6.s6_addr)) == 0);
+ }
+ return FALSE;
+}
diff --git a/src/iaddr.h b/src/iaddr.h
new file mode 100644
index 0000000..0c255bd
--- /dev/null
+++ b/src/iaddr.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_iaddr_h
+#define __dnscap_iaddr_h
+
+const char* ia_str(iaddr ia);
+int ia_equal(iaddr x, iaddr y);
+
+#endif /* __dnscap_iaddr_h */
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..a82d040
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "log.h"
+
+int logerr(const char* fmt, ...)
+{
+ va_list ap;
+ int x = 1;
+ va_start(ap, fmt);
+ if (background)
+ vsyslog(LOG_NOTICE, fmt, ap);
+ else {
+ x = vfprintf(stderr, fmt, ap);
+ fputc('\n', stderr);
+ }
+ va_end(ap);
+ return x;
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644
index 0000000..7bee5b1
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_log_h
+#define __dnscap_log_h
+
+int logerr(const char* fmt, ...);
+
+#endif /* __dnscap_log_h */
diff --git a/src/memzero.c b/src/memzero.c
new file mode 100644
index 0000000..98a3c0b
--- /dev/null
+++ b/src/memzero.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if defined(__FreeBSD__)
+#include <strings.h>
+#elif defined(__OpenBSD__)
+#include <string.h>
+#else
+#ifndef __STDC_WANT_LIB_EXT1__
+#define __STDC_WANT_LIB_EXT1__ 1
+#endif
+#include <string.h>
+#endif
+
+void dnscap_memzero(void* const pnt, const size_t len)
+{
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ explicit_bzero(pnt, len);
+#elif defined(__STDC_LIB_EXT1__)
+ memset_s(pnt, 0, len);
+#else
+ volatile unsigned char* volatile pnt_ = (volatile unsigned char* volatile)pnt;
+ size_t i = (size_t)0U;
+
+ while (i < len) {
+ pnt_[i++] = 0U;
+ }
+#endif
+}
diff --git a/src/memzero.h b/src/memzero.h
new file mode 100644
index 0000000..e25d81c
--- /dev/null
+++ b/src/memzero.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __dnscap_memzero_h
+#define __dnscap_memzero_h
+
+void dnscap_memzero(void* const pnt, const size_t len);
+
+#endif /* __dnscap_memzero_h */
diff --git a/src/network.c b/src/network.c
new file mode 100644
index 0000000..d0a4242
--- /dev/null
+++ b/src/network.c
@@ -0,0 +1,1834 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "network.h"
+#include "iaddr.h"
+#include "log.h"
+#include "pcaps.h"
+#include "dumper.h"
+#include "endpoint.h"
+#include "tcpstate.h"
+#include "tcpreasm.h"
+#include "endian_compat.h"
+
+#include <ldns/ldns.h>
+
+struct ip6_hdr* network_ipv6 = 0;
+struct ip* network_ip = 0;
+struct udphdr* network_udp = 0;
+
+extern tcpstate_ptr _curr_tcpstate; /* from tcpstate.c */
+
+static inline uint16_t _need16(const void* ptr)
+{
+ uint16_t v;
+ memcpy(&v, ptr, sizeof(v));
+ return be16toh(v);
+}
+
+static inline uint32_t _need32(const void* ptr)
+{
+ uint32_t v;
+ memcpy(&v, ptr, sizeof(v));
+ return be32toh(v);
+}
+
+static int skip_vlan(unsigned vlan)
+{
+ if (!EMPTY(vlans_excl)) {
+ vlan_ptr vl;
+
+ for (vl = HEAD(vlans_excl); vl != NULL; vl = NEXT(vl, link)) {
+ if (vl->vlan == vlan || vl->vlan == MAX_VLAN)
+ break;
+ }
+
+ /*
+ * If there is no VLAN matching the packet, skip it
+ */
+ if (vl == NULL)
+ return 1;
+ } else if (!EMPTY(vlans_incl)) {
+ vlan_ptr vl;
+
+ for (vl = HEAD(vlans_incl); vl != NULL; vl = NEXT(vl, link)) {
+ if (vl->vlan == vlan || vl->vlan == MAX_VLAN)
+ break;
+ }
+
+ /*
+ * If there is no VLAN matching the packet, and the packet is tagged, skip it
+ */
+ if (vl == NULL && vlan != MAX_VLAN)
+ return 1;
+ }
+
+ return 0;
+}
+
+void layer_pkt(u_char* user, const pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ mypcap_ptr mypcap = (mypcap_ptr)user;
+ size_t len;
+ unsigned vlan;
+ const pcap_thread_packet_t *prevpkt, *firstpkt = packet;
+ char descr[200];
+
+ if (!mypcap)
+ return;
+ if (!packet)
+ return;
+
+ while (firstpkt->have_prevpkt) {
+ if (firstpkt->have_pkthdr)
+ break;
+ firstpkt = firstpkt->prevpkt;
+ }
+ if (!firstpkt->have_pkthdr)
+ return;
+
+ if (only_offline_pcaps && start_time != 0 && firstpkt->pkthdr.ts.tv_sec < start_time)
+ return;
+
+ len = firstpkt->pkthdr.caplen;
+
+ last_ts = firstpkt->pkthdr.ts;
+ if (stop_time != 0 && firstpkt->pkthdr.ts.tv_sec >= stop_time) {
+ breakloop_pcaps();
+ main_exit = TRUE;
+ }
+
+ if (main_exit)
+ return;
+
+ /* If ever SNAPLEN wasn't big enough, we have no recourse. */
+ if (firstpkt->pkthdr.len != firstpkt->pkthdr.caplen)
+ return;
+
+ vlan = MAX_VLAN;
+ for (prevpkt = packet; prevpkt; prevpkt = prevpkt->prevpkt) {
+ if (prevpkt->have_ieee802hdr) {
+ /* TODO: Only match first found VLAN or all? */
+ vlan = prevpkt->ieee802hdr.vid;
+ len -= 4;
+ break;
+ }
+ if (!prevpkt->have_prevpkt)
+ break;
+ }
+ if (skip_vlan(vlan)) {
+ return;
+ }
+
+ descr[0] = 0;
+ if (preso) {
+ char when[100];
+ struct tm tm;
+ time_t t;
+
+ /*
+ * Reduce `len` to report same captured length as `dl_pkt`
+ */
+ for (prevpkt = packet; len && prevpkt; prevpkt = prevpkt->prevpkt) {
+ if (prevpkt->have_nullhdr) {
+ if (len > sizeof(prevpkt->nullhdr))
+ len -= sizeof(prevpkt->nullhdr);
+ else
+ len = 0;
+ }
+ if (prevpkt->have_loophdr) {
+ if (len > sizeof(prevpkt->loophdr))
+ len -= sizeof(prevpkt->loophdr);
+ else
+ len = 0;
+ }
+ if (prevpkt->have_ethhdr) {
+ if (len > sizeof(prevpkt->ethhdr))
+ len -= sizeof(prevpkt->ethhdr);
+ else
+ len = 0;
+ }
+ if (prevpkt->have_linux_sll) {
+ if (len > sizeof(prevpkt->linux_sll))
+ len -= sizeof(prevpkt->linux_sll);
+ else
+ len = 0;
+ }
+
+ if (!prevpkt->have_prevpkt)
+ break;
+ }
+
+ t = (time_t)firstpkt->pkthdr.ts.tv_sec;
+ gmtime_r(&t, &tm);
+ strftime(when, sizeof(when), "%Y-%m-%d %T", &tm);
+
+ if (vlan != MAX_VLAN) {
+ snprintf(descr, sizeof(descr), "[%lu] %s.%06lu [#%ld %s (vlan %u) %u] \\\n",
+ (u_long)len,
+ when,
+ (u_long)firstpkt->pkthdr.ts.tv_usec,
+ (long)msgcount,
+ mypcap->name ? mypcap->name : "\"some interface\"",
+ vlan,
+ vlan);
+ } else {
+ snprintf(descr, sizeof(descr), "[%lu] %s.%06lu [#%ld %s %u] \\\n",
+ (u_long)len,
+ when,
+ (u_long)firstpkt->pkthdr.ts.tv_usec,
+ (long)msgcount,
+ mypcap->name ? mypcap->name : "\"some interface\"",
+ vlan);
+ }
+ }
+
+ if (next_interval != 0 && firstpkt->pkthdr.ts.tv_sec >= next_interval) {
+ if (preso)
+ goto breakloop;
+ if (dumper_opened == dump_state)
+ dumper_close(firstpkt->pkthdr.ts);
+ if (dump_type == to_stdout)
+ goto breakloop;
+ }
+ if (dumper_closed == dump_state && dumper_open(firstpkt->pkthdr.ts))
+ goto breakloop;
+
+ network_pkt2(descr, firstpkt->pkthdr.ts, packet, payload, length);
+
+ if (limit_packets != 0U && msgcount == limit_packets) {
+ if (preso)
+ goto breakloop;
+ if (dumper_opened == dump_state && dumper_close(firstpkt->pkthdr.ts))
+ goto breakloop;
+ msgcount = 0;
+ }
+
+ if (limit_pcapfilesize != 0U && capturedbytes >= limit_pcapfilesize) {
+ if (preso) {
+ goto breakloop;
+ }
+ if (dumper_opened == dump_state && dumper_close(firstpkt->pkthdr.ts)) {
+ goto breakloop;
+ }
+ capturedbytes = 0;
+ }
+
+ return;
+breakloop:
+ breakloop_pcaps();
+ main_exit = TRUE;
+}
+
+void dl_pkt(u_char* user, const struct pcap_pkthdr* hdr, const u_char* pkt, const char* name, const int dlt)
+{
+ mypcap_ptr mypcap = (mypcap_ptr)user;
+ size_t len = hdr->caplen;
+ unsigned etype, vlan, pf;
+ char descr[512];
+
+ if (only_offline_pcaps && start_time != 0 && hdr->ts.tv_sec < start_time)
+ return;
+
+ last_ts = hdr->ts;
+ if (stop_time != 0 && hdr->ts.tv_sec >= stop_time) {
+ breakloop_pcaps();
+ main_exit = TRUE;
+ }
+
+ if (main_exit)
+ return;
+
+ /* If ever SNAPLEN wasn't big enough, we have no recourse. */
+ if (hdr->len != hdr->caplen)
+ return;
+
+ /* Data link. */
+ vlan = MAX_VLAN; /* MAX_VLAN (0xFFF) is reserved and shouldn't appear on the wire */
+ switch (dlt) {
+ case DLT_NULL: {
+ uint32_t x;
+
+ if (len < 4)
+ return;
+ x = _need32(pkt);
+ if (x == PF_INET)
+ etype = ETHERTYPE_IP;
+ else if (x == PF_INET6)
+ etype = ETHERTYPE_IPV6;
+ else
+ return;
+ pkt += 4;
+ len -= 4;
+ break;
+ }
+ case DLT_LOOP: {
+ uint32_t x;
+
+ if (len < 4)
+ return;
+ x = _need32(pkt);
+ if (x == PF_INET)
+ etype = ETHERTYPE_IP;
+ else if (x == PF_INET6)
+ etype = ETHERTYPE_IPV6;
+ else
+ return;
+ pkt += 4;
+ len -= 4;
+ break;
+ }
+ case DLT_RAW: {
+ if (len < 1)
+ return;
+ switch (*(const uint8_t*)pkt >> 4) {
+ case 4:
+ etype = ETHERTYPE_IP;
+ break;
+ case 6:
+ etype = ETHERTYPE_IPV6;
+ break;
+ default:
+ return;
+ }
+ break;
+ }
+ case DLT_EN10MB: {
+ const struct ether_header* ether;
+
+ if (len < ETHER_HDR_LEN)
+ return;
+ ether = (const struct ether_header*)pkt;
+ etype = ntohs(ether->ether_type);
+ pkt += ETHER_HDR_LEN;
+ len -= ETHER_HDR_LEN;
+ if (etype == ETHERTYPE_VLAN) {
+ if (len < 4)
+ return;
+ vlan = _need16(pkt) & 0xFFF;
+ pkt += 2;
+ len -= 2;
+ etype = _need16(pkt);
+ pkt += 2;
+ len -= 2;
+ }
+ break;
+ }
+#ifdef DLT_LINUX_SLL
+ case DLT_LINUX_SLL: {
+ if (len < 16)
+ return;
+ etype = _need16(&pkt[14]);
+ pkt += 16;
+ len -= 16;
+ break;
+ }
+#endif
+ default:
+ return;
+ }
+
+ if (!EMPTY(vlans_excl)) {
+ vlan_ptr vl;
+
+ for (vl = HEAD(vlans_excl);
+ vl != NULL;
+ vl = NEXT(vl, link))
+ if (vl->vlan == vlan || vl->vlan == MAX_VLAN)
+ break;
+ /*
+ * If there is no VLAN matching the packet, skip it
+ */
+ if (vl == NULL)
+ return;
+ } else if (!EMPTY(vlans_incl)) {
+ vlan_ptr vl;
+
+ for (vl = HEAD(vlans_incl);
+ vl != NULL;
+ vl = NEXT(vl, link))
+ if (vl->vlan == vlan || vl->vlan == MAX_VLAN)
+ break;
+ /*
+ * If there is no VLAN matching the packet, and the packet is tagged, skip it
+ */
+ if (vl == NULL && vlan != MAX_VLAN)
+ return;
+ }
+
+ switch (etype) {
+ case ETHERTYPE_IP:
+ pf = PF_INET;
+ break;
+ case ETHERTYPE_IPV6:
+ pf = PF_INET6;
+ break;
+ default:
+ return;
+ }
+
+ if (preso) {
+ char when[100], via[100];
+ const char* viap;
+ struct tm tm;
+ time_t t;
+
+ t = (time_t)hdr->ts.tv_sec;
+ gmtime_r(&t, &tm);
+ strftime(when, sizeof when, "%Y-%m-%d %T", &tm);
+ if (vlan != MAX_VLAN) {
+ snprintf(via, sizeof(via), "%s (vlan %u)", mypcap->name ? mypcap->name : "\"some interface\"", vlan);
+ viap = via;
+ } else if (mypcap->name) {
+ viap = mypcap->name;
+ } else {
+ viap = "\"some interface\"";
+ }
+ snprintf(descr, sizeof(descr), "[%lu] %s.%06lu [#%ld %s %u] \\\n",
+ (u_long)len, when, (u_long)hdr->ts.tv_usec, (long)msgcount, viap, vlan);
+ } else {
+ descr[0] = '\0';
+ }
+
+ if (next_interval != 0 && hdr->ts.tv_sec >= next_interval) {
+ if (preso)
+ goto breakloop;
+ if (dumper_opened == dump_state)
+ dumper_close(hdr->ts);
+ if (dump_type == to_stdout)
+ goto breakloop;
+ }
+ if (dumper_closed == dump_state && dumper_open(hdr->ts))
+ goto breakloop;
+
+ network_pkt(descr, hdr->ts, pf, pkt, len);
+
+ if (limit_packets != 0U && msgcount == limit_packets) {
+ if (preso)
+ goto breakloop;
+ if (dumper_opened == dump_state && dumper_close(hdr->ts))
+ goto breakloop;
+ msgcount = 0;
+ }
+
+ if (limit_pcapfilesize != 0U && capturedbytes >= limit_pcapfilesize) {
+ if (preso) {
+ goto breakloop;
+ }
+ if (dumper_opened == dump_state && dumper_close(hdr->ts)) {
+ goto breakloop;
+ }
+ capturedbytes = 0;
+ }
+
+ return;
+breakloop:
+ breakloop_pcaps();
+ main_exit = TRUE;
+}
+
+void network_pkt2(const char* descr, my_bpftimeval ts, const pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ u_char pkt_copy[SNAPLEN], *pkt = pkt_copy;
+ const u_char* dnspkt = 0;
+ unsigned proto, sport, dport;
+ iaddr from, to, initiator, responder;
+ int response, m;
+ unsigned flags = DNSCAP_OUTPUT_ISLAYER;
+ tcpstate_ptr tcpstate = NULL;
+ size_t len, dnslen = 0;
+ HEADER dns;
+ ldns_pkt* lpkt = 0;
+
+ /* Make a writable copy of the packet and use that copy from now on. */
+ if (length > SNAPLEN)
+ return;
+ memcpy(pkt, payload, len = length);
+
+ /* Network. */
+ sport = dport = 0;
+ if (packet->have_iphdr) {
+ if (dumptrace >= 4)
+ fprintf(stderr, "processing IPv4 packet: len=%zu\n", length);
+
+ memset(&from, 0, sizeof from);
+ from.af = AF_INET;
+ memcpy(&from.u.a4, &(packet->iphdr.ip_src), sizeof(struct in_addr));
+ memset(&to, 0, sizeof to);
+ to.af = AF_INET;
+ memcpy(&to.u.a4, &(packet->iphdr.ip_dst), sizeof(struct in_addr));
+ } else if (packet->have_ip6hdr) {
+ if (dumptrace >= 4)
+ fprintf(stderr, "processing IPv6 packet: len=%zu\n", length);
+
+ memset(&from, 0, sizeof from);
+ from.af = AF_INET6;
+ memcpy(&from.u.a6, &(packet->ip6hdr.ip6_src), sizeof(struct in6_addr));
+ memset(&to, 0, sizeof to);
+ to.af = AF_INET6;
+ memcpy(&to.u.a6, &(packet->ip6hdr.ip6_dst), sizeof(struct in6_addr));
+ } else {
+ if (dumptrace >= 4)
+ fprintf(stderr, "processing unknown packet: len=%zu\n", length);
+ from.af = AF_UNSPEC;
+ to.af = AF_UNSPEC;
+ }
+
+ /* Transport. */
+ if (packet->have_icmphdr) {
+ output(descr, from, to, IPPROTO_ICMP, flags, sport, dport, ts, pkt_copy, length, pkt, len);
+ return;
+ } else if (packet->have_icmpv6hdr) {
+ output(descr, from, to, IPPROTO_ICMPV6, flags, sport, dport, ts, pkt_copy, length, pkt, len);
+ return;
+ } else if (packet->have_udphdr) {
+ proto = IPPROTO_UDP;
+ sport = packet->udphdr.uh_sport;
+ dport = packet->udphdr.uh_dport;
+ dnspkt = payload;
+ dnslen = length;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ } else if (packet->have_tcphdr) {
+ uint32_t seq = packet->tcphdr.th_seq;
+
+ proto = IPPROTO_TCP;
+ sport = packet->tcphdr.th_sport;
+ dport = packet->tcphdr.th_dport;
+
+ /*
+ * TCP processing.
+ *
+ * We need to capture enough to allow a later analysis to
+ * reassemble the TCP stream, but we don't want to keep all
+ * the state required to do reassembly here.
+ * When we get a SYN, we don't yet know if the DNS message
+ * will pass the filters, so we always output it, and also
+ * generate a tcpstate to keep track of the stream. (An
+ * alternative would be to store the SYN packet on the
+ * tcpstate and not output it until a later packet passes the
+ * filter, but that would require more memory and would
+ * reorder packets in the pcap output.)
+ * When we get the _first_ DNS header on the stream, then we
+ * can apply the DNS header filters; if the packet passes, we
+ * output the packet and keep the tcpstate; if it fails, we
+ * discard the packet and the tcpstate.
+ * When we get any other packet with DNS payload, we output it
+ * only if there is a corresponding tcpstate indicating that
+ * the header passed the filters.
+ * Packets with no TCP payload (e.g., packets containing only
+ * an ACK) are discarded, since they carry no DNS information
+ * and are not needed for stream reassembly.
+ * FIN packets are always output to match the SYN, even if the
+ * DNS header failed the filter, to be friendly to later
+ * analysis programs that allocate state for each SYN.
+ * -- kkeys@caida.org
+ */
+
+ tcpstate = tcpstate_find(from, to, sport, dport, ts.tv_sec);
+ if (dumptrace >= 3) {
+ fprintf(stderr, "%s: tcp pkt: %lu.%06lu [%4lu] %15s -> ",
+ ProgramName,
+ (u_long)ts.tv_sec,
+ (u_long)ts.tv_usec,
+ (u_long)len,
+ ia_str(from));
+ fprintf(stderr, "%15s; ", ia_str(to));
+
+ if (tcpstate)
+ fprintf(stderr, "want=%08x; ", tcpstate->start);
+ else
+ fprintf(stderr, "no state; ");
+
+ fprintf(stderr, "seq=%08x; ", seq);
+ }
+ if (packet->tcphdr.th_flags & (TH_FIN | TH_RST)) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "FIN|RST\n");
+
+ /* Always output FIN and RST segments. */
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, length, NULL, 0);
+ _curr_tcpstate = 0;
+
+ /* End of stream; deallocate the tcpstate. */
+ if (tcpstate) {
+ UNLINK(tcpstates, tcpstate, link);
+ if (tcpstate->reasm) {
+ tcpreasm_free(tcpstate->reasm);
+ }
+ free(tcpstate);
+ tcpstate_count--;
+ }
+ return;
+ }
+ if (packet->tcphdr.th_flags & TH_SYN) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "SYN\n");
+
+ if (tcpstate) {
+ if (tcpstate->start == seq + 1) {
+ /* repeated SYN */
+ } else {
+ /* Assume existing state is stale and recycle it. */
+
+ /*
+ * Disabled because warning may scare user, and
+ * there's nothing else we can do anyway.
+ */
+
+ /*
+ if (ts.tv_sec - tcpstate->last_use < MAX_TCP_IDLE_TIME)
+ fprintf(stderr, "warning: recycling state for "
+ "duplicate tcp stream after only %ld "
+ "seconds idle\n",
+ (u_long)(ts.tv_sec - tcpstate->last_use));
+ */
+ }
+ } else {
+ /* create new tcpstate */
+ tcpstate = tcpstate_new(from, to, sport, dport);
+ }
+ tcpstate->last_use = ts.tv_sec;
+ tcpstate->start = seq + 1; /* add 1 for the SYN */
+ tcpstate->maxdiff = 1;
+ tcpstate->dnslen = 0;
+ tcpstate->lastdns = 0;
+
+ /* Always output SYN segments. */
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, length, NULL, 0);
+ _curr_tcpstate = 0;
+
+ return;
+ }
+ if (options.parse_ongoing_tcp && !tcpstate && len) {
+ tcpstate = tcpstate_new(from, to, sport, dport);
+ tcpstate->last_use = ts.tv_sec;
+ tcpstate->start = seq;
+ tcpstate->maxdiff = 0;
+ tcpstate->dnslen = 0;
+ tcpstate->lastdns = seq;
+ }
+ if (tcpstate && options.reassemble_tcp) {
+ if (!tcpstate->reasm) {
+ if (!(tcpstate->reasm = calloc(1, sizeof(tcpreasm_t)))) {
+ logerr("out of memory, TCP reassembly failed");
+ return;
+ }
+ tcpstate->reasm->seq_start = tcpstate->start;
+ tcpstate->reasm->seq_bfb = tcpstate->start;
+ }
+ if (options.allow_reset_tcpstate) {
+ if (tcpstate->reasm_faults > options.reassemble_tcp_faultreset) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "fault reset ");
+ tcpstate_reset(tcpstate, "too many reassembly faults");
+ tcpstate->reasm->seq_start = seq;
+ tcpstate->reasm->seq_bfb = seq;
+ tcpstate->reasm_faults = 0;
+ }
+ if (dumptrace >= 3)
+ fprintf(stderr, "reassemble\n");
+ if (pcap_handle_tcp_segment(pkt, len, seq, tcpstate)) {
+ tcpstate->reasm_faults++;
+ }
+ } else {
+ if (dumptrace >= 3)
+ fprintf(stderr, "reassemble\n");
+ (void)pcap_handle_tcp_segment(pkt, len, seq, tcpstate);
+ }
+ } else if (tcpstate) {
+ uint32_t seqdiff = seq - tcpstate->start;
+
+ tcpstate->currseq = seq;
+ tcpstate->currlen = len;
+
+ if (options.allow_reset_tcpstate && tcpstate->lastdns && seq > tcpstate->lastdns + 2) {
+ /*
+ * seq received is beyond where we expect next DNS message
+ * to be, reset tcpstate and continue
+ */
+ tcpstate->maxdiff = 0;
+ tcpstate->dnslen = 0;
+ tcpstate->lastdns = seq;
+ }
+
+ if (dumptrace >= 3)
+ fprintf(stderr, "diff=%08x; lastdns=%08x; ", seqdiff, tcpstate->lastdns);
+
+ if (tcpstate->lastdns && seq == tcpstate->lastdns && len > 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "+len+hdr\n");
+ dnslen = tcpstate->dnslen = (pkt[0] << 8) | (pkt[1] << 0);
+ dnspkt = pkt + 2;
+ if (dnslen > len - 2)
+ dnslen = len - 2;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ tcpstate->maxdiff = (uint32_t)len;
+ tcpstate->lastdns = seq + 2 + tcpstate->dnslen;
+ } else if (tcpstate->lastdns && seq == tcpstate->lastdns && len == 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "+len\n");
+ tcpstate->dnslen = (pkt[0] << 8) | (pkt[1] << 0);
+ tcpstate->maxdiff = (uint32_t)len;
+
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, length, NULL, 0);
+ _curr_tcpstate = 0;
+ return;
+ } else if (tcpstate->lastdns && ((seq == tcpstate->lastdns && len == 1) || seqdiff == 1)) {
+ tcpstate_discard(tcpstate, NULL);
+ return;
+ } else if (tcpstate->lastdns && seq == tcpstate->lastdns + 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "+hdr\n");
+ tcpstate->maxdiff = seqdiff + (uint32_t)len;
+ dnslen = tcpstate->dnslen;
+ dnspkt = pkt;
+ if (dnslen == 0) /* we never received it */
+ dnslen = len;
+ if (dnslen > len)
+ dnslen = len;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ tcpstate->lastdns = seq + tcpstate->dnslen;
+ } else if (seqdiff == 0 && len > 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "len+hdr\n");
+
+ /*
+ * This is the first segment of the stream, and
+ * contains the dnslen and dns header, so we can
+ * filter on it.
+ */
+ dnslen = tcpstate->dnslen = (pkt[0] << 8) | (pkt[1] << 0);
+ dnspkt = pkt + 2;
+ if (dnslen > len - 2)
+ dnslen = len - 2;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ tcpstate->maxdiff = (uint32_t)len;
+ tcpstate->lastdns = seq + 2 + tcpstate->dnslen;
+ } else if (seqdiff == 0 && len == 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "len\n");
+
+ /*
+ * This is the first segment of the stream, but only
+ * contains the dnslen.
+ */
+ tcpstate->dnslen = (pkt[0] << 8) | (pkt[1] << 0);
+ tcpstate->maxdiff = (uint32_t)len;
+
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, length, NULL, 0);
+ _curr_tcpstate = 0;
+ return;
+ } else if ((seqdiff == 0 && len == 1) || seqdiff == 1) {
+ /* shouldn't happen */
+ tcpstate_discard(tcpstate, NULL);
+ return;
+ } else if (seqdiff == 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "hdr\n");
+
+ /*
+ * This is not the first segment, but it does contain
+ * the first dns header, so we can filter on it.
+ */
+ tcpstate->maxdiff = seqdiff + (uint32_t)len;
+ dnslen = tcpstate->dnslen;
+ dnspkt = pkt;
+ if (dnslen == 0) /* we never received it */
+ dnslen = len;
+ if (dnslen > len)
+ dnslen = len;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ tcpstate->lastdns = seq + tcpstate->dnslen;
+ } else if (seqdiff > tcpstate->maxdiff + MAX_TCP_WINDOW) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "out of window\n");
+
+ /* This segment is outside the window. */
+ return;
+ } else if (len == 0) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "empty\n");
+
+ /* No payload (e.g., an ACK) */
+ return;
+ } else {
+ if (dumptrace >= 3)
+ fprintf(stderr, "keep\n");
+
+ /* non-first */
+ if (tcpstate->maxdiff < seqdiff + (uint32_t)len)
+ tcpstate->maxdiff = seqdiff + (uint32_t)len;
+
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, length, NULL, 0);
+ _curr_tcpstate = 0;
+ return;
+ }
+ } else {
+ if (dumptrace >= 3)
+ fprintf(stderr, "no state\n");
+
+ /*
+ * There is no state for this stream. Either we never saw
+ * a SYN for this stream, or we have already decided to
+ * discard this stream.
+ */
+ return;
+ }
+ } else {
+ return;
+ }
+
+ for (m = 0; m < MAX_TCP_DNS_MSG; m++) {
+ if (tcpstate && tcpstate->reasm) {
+ if (!tcpstate->reasm->dnsmsg[m])
+ continue;
+ dnslen = tcpstate->reasm->dnsmsg[m]->dnslen;
+ dnspkt = tcpstate->reasm->dnsmsg[m]->dnspkt;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ if (tcpstate->reasm->dnsmsg[m]->segments_seen > 1) {
+ /* emulate dnslen in own packet */
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, length, NULL, 0);
+ _curr_tcpstate = 0;
+ }
+ }
+
+ /* Application. */
+ if (!dnspkt) {
+ tcpstate_discard(tcpstate, "no dns");
+ return;
+ }
+ if (dnslen < sizeof dns) {
+ tcpstate_discard(tcpstate, "too small");
+ return;
+ }
+ memcpy(&dns, dnspkt, sizeof dns);
+
+ /* Policy filtering. */
+ if (dns.qr == 0 && dport == dns_port) {
+ if ((dir_wanted & DIR_INITIATE) == 0) {
+ tcpstate_discard(tcpstate, "unwanted dir=i");
+ return;
+ }
+ initiator = from;
+ responder = to;
+ response = FALSE;
+ } else if (dns.qr != 0 && sport == dns_port) {
+ if ((dir_wanted & DIR_RESPONSE) == 0) {
+ tcpstate_discard(tcpstate, "unwanted dir=r");
+ return;
+ }
+ initiator = to;
+ responder = from;
+ response = TRUE;
+ } else {
+ tcpstate_discard(tcpstate, "unwanted direction/port");
+ return;
+ }
+ if ((!EMPTY(initiators) && !ep_present(&initiators, initiator)) || (!EMPTY(responders) && !ep_present(&responders, responder))) {
+ tcpstate_discard(tcpstate, "unwanted host");
+ return;
+ }
+ if ((!EMPTY(not_initiators) && ep_present(&not_initiators, initiator)) || (!EMPTY(not_responders) && ep_present(&not_responders, responder))) {
+ tcpstate_discard(tcpstate, "missing required host");
+ return;
+ }
+ if (!(((msg_wanted & MSG_QUERY) != 0 && dns.opcode == LDNS_PACKET_QUERY) || ((msg_wanted & MSG_UPDATE) != 0 && dns.opcode == LDNS_PACKET_UPDATE) || ((msg_wanted & MSG_NOTIFY) != 0 && dns.opcode == LDNS_PACKET_NOTIFY))) {
+ tcpstate_discard(tcpstate, "unwanted opcode");
+ return;
+ }
+ if (response) {
+ int match_tc = (dns.tc != 0 && err_wanted & ERR_TRUNC);
+ int match_rcode = err_wanted & (ERR_RCODE_BASE << dns.rcode);
+
+ if (!match_tc && !match_rcode) {
+ tcpstate_discard(tcpstate, "unwanted error code");
+ return;
+ }
+ if (!EMPTY(drop_responders) && ep_present(&drop_responders, responder)) {
+ tcpstate_discard(tcpstate, "dropped response due to -Y");
+ return;
+ }
+ }
+ if (!EMPTY(myregexes) || match_qtype || nmatch_qtype) {
+ if (ldns_wire2pkt(&lpkt, dnspkt, dnslen) != LDNS_STATUS_OK) {
+ /* DNS message may have padding, try get actual size */
+ size_t dnslen2 = calcdnslen(dnspkt, dnslen);
+ if (dnslen2 > 0 && dnslen2 < dnslen) {
+ if (ldns_wire2pkt(&lpkt, dnspkt, dnslen2) != LDNS_STATUS_OK) {
+ tcpstate_discard(tcpstate, "failed parse");
+ return;
+ }
+ } else {
+ tcpstate_discard(tcpstate, "failed parse");
+ return;
+ }
+ }
+ }
+ if (match_qtype || nmatch_qtype) {
+ ldns_rr_list* rrs = ldns_pkt_question(lpkt);
+ if (!rrs) {
+ ldns_pkt_free(lpkt);
+ tcpstate_discard(tcpstate, "failed to get list of questions");
+ return;
+ }
+ /* Look at each RR in the section (or each QNAME in
+ the question section). */
+ size_t i, n;
+ for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) {
+ ldns_rr* rr = ldns_rr_list_rr(rrs, i);
+ if (!rr) {
+ ldns_pkt_free(lpkt);
+ tcpstate_discard(tcpstate, "failed to get question");
+ return;
+ }
+
+ if (match_qtype && ldns_rr_get_type(rr) != match_qtype) {
+ ldns_pkt_free(lpkt);
+ tcpstate_discard(tcpstate, "qtype not match");
+ return;
+ } else if (nmatch_qtype && ldns_rr_get_type(rr) == nmatch_qtype) {
+ ldns_pkt_free(lpkt);
+ tcpstate_discard(tcpstate, "!qtype match");
+ return;
+ }
+ }
+ }
+ if (!EMPTY(myregexes)) {
+ int match, negmatch;
+ ldns_buffer* buf = ldns_buffer_new(512);
+
+ if (!buf) {
+ fprintf(stderr, "%s: out of memory", ProgramName);
+ exit(1);
+ }
+
+ match = -1;
+ negmatch = -1;
+ /* Look at each section of the message:
+ question, answer, authority, additional */
+ ldns_rr_list* rrs = ldns_pkt_all(lpkt);
+ if (!rrs) {
+ ldns_pkt_free(lpkt);
+ ldns_buffer_free(buf);
+ tcpstate_discard(tcpstate, "failed to get list of RRs");
+ return;
+ }
+ /* Look at each RR in the section (or each QNAME in
+ the question section). */
+ size_t i, n;
+ for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) {
+ ldns_rr* rr = ldns_rr_list_rr(rrs, i);
+ if (!rr) {
+ ldns_rr_list_free(rrs);
+ ldns_pkt_free(lpkt);
+ ldns_buffer_free(buf);
+ tcpstate_discard(tcpstate, "failed to get RR");
+ return;
+ }
+
+ ldns_buffer_clear(buf);
+ if (ldns_rdf2buffer_str(buf, ldns_rr_owner(rr)) != LDNS_STATUS_OK) {
+ ldns_rr_list_free(rrs);
+ ldns_pkt_free(lpkt);
+ ldns_buffer_free(buf);
+ tcpstate_discard(tcpstate, "failed to get RR");
+ return;
+ }
+
+ myregex_ptr myregex;
+ for (myregex = HEAD(myregexes);
+ myregex != NULL;
+ myregex = NEXT(myregex, link)) {
+ if (myregex->not ) {
+ if (negmatch < 0)
+ negmatch = 0;
+ } else {
+ if (match < 0)
+ match = 0;
+ }
+
+ if (regexec(&myregex->reg, (char*)ldns_buffer_begin(buf), 0, NULL, 0) == 0) {
+ if (myregex->not )
+ negmatch++;
+ else
+ match++;
+
+ if (dumptrace >= 2)
+ fprintf(stderr,
+ "; \"%s\" %s~ /%s/ %d %d\n",
+ (char*)ldns_buffer_begin(buf),
+ myregex->not ? "!" : "",
+ myregex->str,
+ match,
+ negmatch);
+ }
+ }
+ }
+ ldns_rr_list_free(rrs);
+ ldns_buffer_free(buf);
+
+ /*
+ * Fail if any negative matching or if no match, match can be -1 which
+ * indicates that there are only negative matching
+ */
+ if (negmatch > 0 || match == 0) {
+ ldns_pkt_free(lpkt);
+ tcpstate_discard(tcpstate, "failed regex match");
+ return;
+ }
+ }
+ if (lpkt) {
+ ldns_pkt_free(lpkt);
+ }
+
+ /*
+ * TODO: Policy hiding.
+ */
+
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, length, dnspkt, dnslen);
+ _curr_tcpstate = 0;
+
+ if (tcpstate && tcpstate->reasm) {
+ free(tcpstate->reasm->dnsmsg[m]);
+ tcpstate->reasm->dnsmsg[m] = 0;
+ tcpstate->reasm->dnsmsgs--;
+ } else
+ break;
+ }
+}
+
+void network_pkt(const char* descr, my_bpftimeval ts, unsigned pf,
+ const u_char* opkt, size_t olen)
+{
+ u_char pkt_copy[SNAPLEN], *pkt = pkt_copy;
+ const u_char* dnspkt = 0;
+ unsigned proto, sport, dport;
+ iaddr from, to, initiator, responder;
+ struct ip6_hdr* ipv6;
+ int response, m;
+ unsigned flags = 0;
+ struct udphdr* udp = NULL;
+ struct tcphdr* tcp = NULL;
+ tcpstate_ptr tcpstate = NULL;
+ struct ip* ip;
+ size_t len, dnslen = 0;
+ HEADER dns;
+ ldns_pkt* lpkt = 0;
+
+ if (dumptrace >= 4)
+ fprintf(stderr, "processing %s packet: len=%zu\n", (pf == PF_INET ? "IPv4" : (pf == PF_INET6 ? "IPv6" : "unknown")), olen);
+
+ /* Make a writable copy of the packet and use that copy from now on. */
+ memcpy(pkt, opkt, len = olen);
+
+ /* Network. */
+ ip = NULL;
+ ipv6 = NULL;
+ sport = dport = 0;
+ switch (pf) {
+ case PF_INET: {
+ unsigned offset;
+
+ if (len < sizeof *ip)
+ return;
+ network_ip = ip = (void*)pkt;
+ network_ipv6 = 0;
+ if (ip->ip_v != IPVERSION)
+ goto network_pkt_end;
+ proto = ip->ip_p;
+ memset(&from, 0, sizeof from);
+ from.af = AF_INET;
+ memcpy(&from.u.a4, &ip->ip_src, sizeof(struct in_addr));
+ memset(&to, 0, sizeof to);
+ to.af = AF_INET;
+ memcpy(&to.u.a4, &ip->ip_dst, sizeof(struct in_addr));
+ offset = ip->ip_hl << 2;
+ if (len > ntohs(ip->ip_len)) /* small IP packets have L2 padding */
+ len = ntohs(ip->ip_len);
+ if (len <= (size_t)offset)
+ goto network_pkt_end;
+ pkt += offset;
+ len -= offset;
+ offset = ntohs(ip->ip_off);
+ if ((offset & IP_MF) != 0 || (offset & IP_OFFMASK) != 0) {
+ if (wantfrags) {
+ flags |= DNSCAP_OUTPUT_ISFRAG;
+ output(descr, from, to, ip->ip_p, flags, sport, dport, ts, pkt_copy, olen, NULL, 0);
+ goto network_pkt_end;
+ }
+ goto network_pkt_end;
+ }
+ break;
+ }
+ case PF_INET6: {
+ uint16_t payload_len;
+ uint8_t nexthdr;
+ unsigned offset;
+
+ if (len < sizeof *ipv6)
+ return;
+ network_ipv6 = ipv6 = (void*)pkt;
+ network_ip = 0;
+ if ((ipv6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION)
+ goto network_pkt_end;
+
+ nexthdr = ipv6->ip6_nxt;
+ offset = sizeof(struct ip6_hdr);
+ payload_len = ntohs(ipv6->ip6_plen);
+
+ memset(&from, 0, sizeof from);
+ from.af = AF_INET6;
+ memcpy(&from.u.a6, &ipv6->ip6_src, sizeof(struct in6_addr));
+ memset(&to, 0, sizeof to);
+ to.af = AF_INET6;
+ memcpy(&to.u.a6, &ipv6->ip6_dst, sizeof(struct in6_addr));
+
+ while (nexthdr == IPPROTO_ROUTING || /* routing header */
+ nexthdr == IPPROTO_HOPOPTS || /* Hop-by-Hop opts */
+ nexthdr == IPPROTO_FRAGMENT || /* fragmentation hdr */
+ nexthdr == IPPROTO_DSTOPTS || /* destination opts */
+ nexthdr == IPPROTO_AH || /* destination opts */
+ nexthdr == IPPROTO_ESP) /* encap sec payload */
+ {
+ struct {
+ uint8_t nexthdr;
+ uint8_t length;
+ } ext_hdr;
+ uint16_t ext_hdr_len;
+
+ /* Catch broken packets */
+ if ((offset + sizeof ext_hdr) > len)
+ goto network_pkt_end;
+
+ /* Cannot handle fragments. */
+ if (nexthdr == IPPROTO_FRAGMENT) {
+ if (wantfrags) {
+ flags |= DNSCAP_OUTPUT_ISFRAG;
+ output(descr, from, to, IPPROTO_FRAGMENT, flags, sport, dport, ts, pkt_copy, olen, NULL, 0);
+ goto network_pkt_end;
+ }
+ goto network_pkt_end;
+ }
+
+ memcpy(&ext_hdr, (u_char*)ipv6 + offset,
+ sizeof ext_hdr);
+ nexthdr = ext_hdr.nexthdr;
+ ext_hdr_len = (8 * (ntohs(ext_hdr.length) + 1));
+
+ if (ext_hdr_len > payload_len)
+ goto network_pkt_end;
+
+ offset += ext_hdr_len;
+ payload_len -= ext_hdr_len;
+ }
+
+ if ((offset + payload_len) > len || payload_len == 0)
+ goto network_pkt_end;
+
+ proto = nexthdr;
+ pkt += offset;
+ len -= offset;
+ break;
+ }
+ default:
+ goto network_pkt_end;
+ }
+
+ /* Transport. */
+ switch (proto) {
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ network_udp = 0;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, olen, pkt, len);
+ goto network_pkt_end;
+ case IPPROTO_UDP: {
+ if (len < sizeof *udp)
+ goto network_pkt_end;
+ network_udp = udp = (void*)pkt;
+ switch (from.af) {
+ case AF_INET:
+ case AF_INET6:
+ sport = ntohs(udp->uh_sport);
+ dport = ntohs(udp->uh_dport);
+ break;
+ default:
+ abort();
+ }
+ pkt += sizeof *udp;
+ len -= sizeof *udp;
+ dnspkt = pkt;
+ dnslen = len;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ break;
+ }
+ case IPPROTO_TCP: {
+ network_udp = 0;
+
+ /* TCP processing.
+ * We need to capture enough to allow a later analysis to
+ * reassemble the TCP stream, but we don't want to keep all
+ * the state required to do reassembly here.
+ * When we get a SYN, we don't yet know if the DNS message
+ * will pass the filters, so we always output it, and also
+ * generate a tcpstate to keep track of the stream. (An
+ * alternative would be to store the SYN packet on the
+ * tcpstate and not output it until a later packet passes the
+ * filter, but that would require more memory and would
+ * reorder packets in the pcap output.)
+ * When we get the _first_ DNS header on the stream, then we
+ * can apply the DNS header filters; if the packet passes, we
+ * output the packet and keep the tcpstate; if it fails, we
+ * discard the packet and the tcpstate.
+ * When we get any other packet with DNS payload, we output it
+ * only if there is a corresponding tcpstate indicating that
+ * the header passed the filters.
+ * Packets with no TCP payload (e.g., packets containing only
+ * an ACK) are discarded, since they carry no DNS information
+ * and are not needed for stream reassembly.
+ * FIN packets are always output to match the SYN, even if the
+ * DNS header failed the filter, to be friendly to later
+ * analysis programs that allocate state for each SYN.
+ * -- kkeys@caida.org
+ */
+ unsigned offset;
+ uint32_t seq;
+ if (!wanttcp)
+ goto network_pkt_end;
+ if (len < sizeof *tcp)
+ goto network_pkt_end;
+ tcp = (void*)pkt;
+ switch (from.af) {
+ case AF_INET:
+ case AF_INET6:
+ sport = ntohs(tcp->th_sport);
+ dport = ntohs(tcp->th_dport);
+ seq = ntohl(tcp->th_seq);
+ break;
+ default:
+ abort();
+ }
+ offset = tcp->th_off * 4;
+ pkt += offset;
+ len -= offset;
+
+ tcpstate = tcpstate_find(from, to, sport, dport, ts.tv_sec);
+ if (dumptrace >= 3) {
+ fprintf(stderr, "%s: tcp pkt: %lu.%06lu [%4lu] ", ProgramName,
+ (u_long)ts.tv_sec, (u_long)ts.tv_usec, (u_long)len);
+ fprintf(stderr, "%15s -> ", ia_str(from));
+ fprintf(stderr, "%15s; ", ia_str(to));
+ if (tcpstate)
+ fprintf(stderr, "want=%08x; ", tcpstate->start);
+ else
+ fprintf(stderr, "no state; ");
+ fprintf(stderr, "seq=%08x; ", seq);
+ }
+ if (tcp->th_flags & (TH_FIN | TH_RST)) {
+ /* Always output FIN and RST segments. */
+ if (dumptrace >= 3)
+ fprintf(stderr, "FIN|RST\n");
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts,
+ pkt_copy, olen, NULL, 0);
+ _curr_tcpstate = 0;
+ /* End of stream; deallocate the tcpstate. */
+ if (tcpstate) {
+ UNLINK(tcpstates, tcpstate, link);
+ if (tcpstate->reasm) {
+ tcpreasm_free(tcpstate->reasm);
+ }
+ free(tcpstate);
+ tcpstate_count--;
+ }
+ goto network_pkt_end;
+ }
+ if (tcp->th_flags & TH_SYN) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "SYN\n");
+ if (tcpstate) {
+#if 0
+ /* Disabled because warning may scare user, and
+ * there's nothing else we can do anyway. */
+ if (tcpstate->start == seq + 1) {
+ /* repeated SYN */
+ } else {
+ /* Assume existing state is stale and recycle it. */
+ if (ts.tv_sec - tcpstate->last_use < MAX_TCP_IDLE_TIME)
+ fprintf(stderr, "warning: recycling state for "
+ "duplicate tcp stream after only %ld "
+ "seconds idle\n",
+ (u_long)(ts.tv_sec - tcpstate->last_use));
+ }
+#endif
+ } else {
+ /* create new tcpstate */
+ tcpstate = tcpstate_new(from, to, sport, dport);
+ }
+ tcpstate->last_use = ts.tv_sec;
+ tcpstate->start = seq + 1; /* add 1 for the SYN */
+ tcpstate->maxdiff = 1;
+ tcpstate->dnslen = 0;
+ tcpstate->lastdns = 0;
+
+ /* Always output SYN segments. */
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts, pkt_copy, olen, NULL, 0);
+ _curr_tcpstate = 0;
+
+ goto network_pkt_end;
+ }
+ if (options.parse_ongoing_tcp && !tcpstate && len) {
+ tcpstate = tcpstate_new(from, to, sport, dport);
+ tcpstate->last_use = ts.tv_sec;
+ tcpstate->start = seq;
+ tcpstate->maxdiff = 0;
+ tcpstate->dnslen = 0;
+ tcpstate->lastdns = seq;
+ }
+ if (tcpstate && options.reassemble_tcp) {
+ if (!tcpstate->reasm) {
+ if (!(tcpstate->reasm = calloc(1, sizeof(tcpreasm_t)))) {
+ logerr("out of memory, TCP reassembly failed");
+ goto network_pkt_end;
+ }
+ tcpstate->reasm->seq_start = tcpstate->start;
+ tcpstate->reasm->seq_bfb = tcpstate->start;
+ }
+ if (options.allow_reset_tcpstate) {
+ if (tcpstate->reasm_faults > options.reassemble_tcp_faultreset) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "fault reset ");
+ tcpstate_reset(tcpstate, "too many reassembly faults");
+ tcpstate->reasm->seq_start = seq;
+ tcpstate->reasm->seq_bfb = seq;
+ tcpstate->reasm_faults = 0;
+ }
+ if (dumptrace >= 3)
+ fprintf(stderr, "reassemble\n");
+ if (pcap_handle_tcp_segment(pkt, len, seq, tcpstate)) {
+ tcpstate->reasm_faults++;
+ }
+ } else {
+ if (dumptrace >= 3)
+ fprintf(stderr, "reassemble\n");
+ (void)pcap_handle_tcp_segment(pkt, len, seq, tcpstate);
+ }
+ } else if (tcpstate) {
+ uint32_t seqdiff = seq - tcpstate->start;
+ tcpstate->currseq = seq;
+ tcpstate->currlen = len;
+ if (options.allow_reset_tcpstate && tcpstate->lastdns && seq > tcpstate->lastdns + 2) {
+ /*
+ * seq received is beyond where we expect next DNS message
+ * to be, reset tcpstate and continue
+ */
+ tcpstate->maxdiff = 0;
+ tcpstate->dnslen = 0;
+ tcpstate->lastdns = seq;
+ }
+ if (dumptrace >= 3)
+ fprintf(stderr, "diff=%08x; lastdns=%08x; ", seqdiff, tcpstate->lastdns);
+ if (tcpstate->lastdns && seq == tcpstate->lastdns && len > 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "+len+hdr\n");
+ dnslen = tcpstate->dnslen = (pkt[0] << 8) | (pkt[1] << 0);
+ dnspkt = pkt + 2;
+ if (dnslen > len - 2)
+ dnslen = len - 2;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ tcpstate->maxdiff = (uint32_t)len;
+ tcpstate->lastdns = seq + 2 + tcpstate->dnslen;
+ } else if (tcpstate->lastdns && seq == tcpstate->lastdns && len == 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "+len\n");
+ tcpstate->dnslen = (pkt[0] << 8) | (pkt[1] << 0);
+ tcpstate->maxdiff = (uint32_t)len;
+
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts,
+ pkt_copy, olen, NULL, 0);
+ _curr_tcpstate = 0;
+ goto network_pkt_end;
+ } else if (tcpstate->lastdns && ((seq == tcpstate->lastdns && len == 1) || seqdiff == 1)) {
+ tcpstate_discard(tcpstate, NULL);
+ goto network_pkt_end;
+ } else if (tcpstate->lastdns && seq == tcpstate->lastdns + 2) {
+ if (dumptrace >= 3)
+ fprintf(stderr, "+hdr\n");
+ tcpstate->maxdiff = seqdiff + (uint32_t)len;
+ dnslen = tcpstate->dnslen;
+ dnspkt = pkt;
+ if (dnslen == 0) /* we never received it */
+ dnslen = len;
+ if (dnslen > len)
+ dnslen = len;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ tcpstate->lastdns = seq + tcpstate->dnslen;
+ } else if (seqdiff == 0 && len > 2) {
+ /* This is the first segment of the stream, and
+ * contains the dnslen and dns header, so we can
+ * filter on it. */
+ if (dumptrace >= 3)
+ fprintf(stderr, "len+hdr\n");
+ dnslen = tcpstate->dnslen = (pkt[0] << 8) | (pkt[1] << 0);
+ dnspkt = pkt + 2;
+ if (dnslen > len - 2)
+ dnslen = len - 2;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ tcpstate->maxdiff = (uint32_t)len;
+ tcpstate->lastdns = seq + 2 + tcpstate->dnslen;
+ } else if (seqdiff == 0 && len == 2) {
+ /* This is the first segment of the stream, but only
+ * contains the dnslen. */
+ if (dumptrace >= 3)
+ fprintf(stderr, "len\n");
+ tcpstate->dnslen = (pkt[0] << 8) | (pkt[1] << 0);
+ tcpstate->maxdiff = (uint32_t)len;
+
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts,
+ pkt_copy, olen, NULL, 0);
+ _curr_tcpstate = 0;
+ goto network_pkt_end;
+ } else if ((seqdiff == 0 && len == 1) || seqdiff == 1) {
+ /* shouldn't happen */
+ tcpstate_discard(tcpstate, NULL);
+ goto network_pkt_end;
+ } else if (seqdiff == 2) {
+ /* This is not the first segment, but it does contain
+ * the first dns header, so we can filter on it. */
+ if (dumptrace >= 3)
+ fprintf(stderr, "hdr\n");
+ tcpstate->maxdiff = seqdiff + (uint32_t)len;
+ dnslen = tcpstate->dnslen;
+ dnspkt = pkt;
+ if (dnslen == 0) /* we never received it */
+ dnslen = len;
+ if (dnslen > len)
+ dnslen = len;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ tcpstate->lastdns = seq + tcpstate->dnslen;
+ } else if (seqdiff > tcpstate->maxdiff + MAX_TCP_WINDOW) {
+ /* This segment is outside the window. */
+ if (dumptrace >= 3)
+ fprintf(stderr, "out of window\n");
+ goto network_pkt_end;
+ } else if (len == 0) {
+ /* No payload (e.g., an ACK) */
+ if (dumptrace >= 3)
+ fprintf(stderr, "empty\n");
+ goto network_pkt_end;
+ } else {
+ /* non-first */
+ if (dumptrace >= 3)
+ fprintf(stderr, "keep\n");
+ if (tcpstate->maxdiff < seqdiff + (uint32_t)len)
+ tcpstate->maxdiff = seqdiff + (uint32_t)len;
+
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts,
+ pkt_copy, olen, NULL, 0);
+ _curr_tcpstate = 0;
+ goto network_pkt_end;
+ }
+ } else {
+ if (dumptrace >= 3)
+ fprintf(stderr, "no state\n");
+ /* There is no state for this stream. Either we never saw
+ * a SYN for this stream, or we have already decided to
+ * discard this stream. */
+ goto network_pkt_end;
+ }
+ break;
+ }
+ default:
+ goto network_pkt_end;
+ }
+
+ for (m = 0; m < MAX_TCP_DNS_MSG; m++) {
+ if (tcpstate && tcpstate->reasm) {
+ if (!tcpstate->reasm->dnsmsg[m])
+ continue;
+ dnslen = tcpstate->reasm->dnsmsg[m]->dnslen;
+ dnspkt = tcpstate->reasm->dnsmsg[m]->dnspkt;
+ flags |= DNSCAP_OUTPUT_ISDNS;
+ if (tcpstate->reasm->dnsmsg[m]->segments_seen > 1) {
+ /* emulate dnslen in own packet */
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts,
+ pkt_copy, olen, NULL, 0);
+ _curr_tcpstate = 0;
+ }
+ }
+
+ /* Application. */
+ if (!dnspkt) {
+ tcpstate_discard(tcpstate, "no dns");
+ goto network_pkt_end;
+ }
+ if (dnslen < sizeof dns) {
+ tcpstate_discard(tcpstate, "too small");
+ goto network_pkt_end;
+ }
+ memcpy(&dns, dnspkt, sizeof dns);
+
+ /* Policy filtering. */
+ if (dns.qr == 0 && dport == dns_port) {
+ if ((dir_wanted & DIR_INITIATE) == 0) {
+ tcpstate_discard(tcpstate, "unwanted dir=i");
+ goto network_pkt_end;
+ }
+ initiator = from;
+ responder = to;
+ response = FALSE;
+ } else if (dns.qr != 0 && sport == dns_port) {
+ if ((dir_wanted & DIR_RESPONSE) == 0) {
+ tcpstate_discard(tcpstate, "unwanted dir=r");
+ goto network_pkt_end;
+ }
+ initiator = to;
+ responder = from;
+ response = TRUE;
+ } else {
+ tcpstate_discard(tcpstate, "unwanted direction/port");
+ goto network_pkt_end;
+ }
+ if ((!EMPTY(initiators) && !ep_present(&initiators, initiator)) || (!EMPTY(responders) && !ep_present(&responders, responder))) {
+ tcpstate_discard(tcpstate, "unwanted host");
+ goto network_pkt_end;
+ }
+ if ((!EMPTY(not_initiators) && ep_present(&not_initiators, initiator)) || (!EMPTY(not_responders) && ep_present(&not_responders, responder))) {
+ tcpstate_discard(tcpstate, "missing required host");
+ goto network_pkt_end;
+ }
+ if (!(((msg_wanted & MSG_QUERY) != 0 && dns.opcode == LDNS_PACKET_QUERY) || ((msg_wanted & MSG_UPDATE) != 0 && dns.opcode == LDNS_PACKET_UPDATE) || ((msg_wanted & MSG_NOTIFY) != 0 && dns.opcode == LDNS_PACKET_NOTIFY))) {
+ tcpstate_discard(tcpstate, "unwanted opcode");
+ goto network_pkt_end;
+ }
+ if (response) {
+ int match_tc = (dns.tc != 0 && err_wanted & ERR_TRUNC);
+ int match_rcode = err_wanted & (ERR_RCODE_BASE << dns.rcode);
+
+ if (!match_tc && !match_rcode) {
+ tcpstate_discard(tcpstate, "unwanted error code");
+ goto network_pkt_end;
+ }
+ if (!EMPTY(drop_responders) && ep_present(&drop_responders, responder)) {
+ tcpstate_discard(tcpstate, "dropped response due to -Y");
+ goto network_pkt_end;
+ }
+ }
+ if (!EMPTY(myregexes) || match_qtype || nmatch_qtype) {
+ if (ldns_wire2pkt(&lpkt, dnspkt, dnslen) != LDNS_STATUS_OK) {
+ /* DNS message may have padding, try get actual size */
+ size_t dnslen2 = calcdnslen(dnspkt, dnslen);
+ if (dnslen2 > 0 && dnslen2 < dnslen) {
+ if (ldns_wire2pkt(&lpkt, dnspkt, dnslen2) != LDNS_STATUS_OK) {
+ tcpstate_discard(tcpstate, "failed parse");
+ goto network_pkt_end;
+ }
+ } else {
+ tcpstate_discard(tcpstate, "failed parse");
+ goto network_pkt_end;
+ }
+ }
+ }
+ if (match_qtype || nmatch_qtype) {
+ ldns_rr_list* rrs = ldns_pkt_question(lpkt);
+ if (!rrs) {
+ tcpstate_discard(tcpstate, "failed to get list of questions");
+ goto network_pkt_end;
+ }
+ /* Look at each RR in the section (or each QNAME in
+ the question section). */
+ size_t i, n;
+ for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) {
+ ldns_rr* rr = ldns_rr_list_rr(rrs, i);
+ if (!rr) {
+ tcpstate_discard(tcpstate, "failed to get question");
+ goto network_pkt_end;
+ }
+
+ if (match_qtype && ldns_rr_get_type(rr) != match_qtype) {
+ tcpstate_discard(tcpstate, "qtype not match");
+ goto network_pkt_end;
+ } else if (nmatch_qtype && ldns_rr_get_type(rr) == nmatch_qtype) {
+ tcpstate_discard(tcpstate, "!qtype match");
+ goto network_pkt_end;
+ }
+ }
+ }
+ if (!EMPTY(myregexes)) {
+ int match, negmatch;
+ ldns_buffer* buf = ldns_buffer_new(512);
+
+ if (!buf) {
+ fprintf(stderr, "%s: out of memory", ProgramName);
+ exit(1);
+ }
+
+ match = -1;
+ negmatch = -1;
+ /* Look at each section of the message:
+ question, answer, authority, additional */
+ ldns_rr_list* rrs = ldns_pkt_all(lpkt);
+ if (!rrs) {
+ ldns_buffer_free(buf);
+ tcpstate_discard(tcpstate, "failed to get list of RRs");
+ goto network_pkt_end;
+ }
+ /* Look at each RR in the section (or each QNAME in
+ the question section). */
+ size_t i, n;
+ for (i = 0, n = ldns_rr_list_rr_count(rrs); i < n; i++) {
+ ldns_rr* rr = ldns_rr_list_rr(rrs, i);
+ if (!rr) {
+ ldns_rr_list_free(rrs);
+ ldns_buffer_free(buf);
+ tcpstate_discard(tcpstate, "failed to get RR");
+ goto network_pkt_end;
+ }
+
+ ldns_buffer_clear(buf);
+ if (ldns_rdf2buffer_str(buf, ldns_rr_owner(rr)) != LDNS_STATUS_OK) {
+ ldns_rr_list_free(rrs);
+ ldns_buffer_free(buf);
+ tcpstate_discard(tcpstate, "failed to get RR");
+ goto network_pkt_end;
+ }
+
+ myregex_ptr myregex;
+ for (myregex = HEAD(myregexes);
+ myregex != NULL;
+ myregex = NEXT(myregex, link)) {
+ if (myregex->not ) {
+ if (negmatch < 0)
+ negmatch = 0;
+ } else {
+ if (match < 0)
+ match = 0;
+ }
+
+ if (regexec(&myregex->reg, (char*)ldns_buffer_begin(buf), 0, NULL, 0) == 0) {
+ if (myregex->not )
+ negmatch++;
+ else
+ match++;
+
+ if (dumptrace >= 2)
+ fprintf(stderr,
+ "; \"%s\" %s~ /%s/ %d %d\n",
+ (char*)ldns_buffer_begin(buf),
+ myregex->not ? "!" : "",
+ myregex->str,
+ match,
+ negmatch);
+ }
+ }
+ }
+ ldns_rr_list_free(rrs);
+ ldns_buffer_free(buf);
+
+ /*
+ * Fail if any negative matching or if no match, match can be -1 which
+ * indicates that there are only negative matching
+ */
+ if (negmatch > 0 || match == 0) {
+ tcpstate_discard(tcpstate, "failed regex match");
+ goto network_pkt_end;
+ }
+ }
+
+ /* Policy hiding. */
+ if (end_hide != 0) {
+ switch (from.af) {
+ case AF_INET: {
+ void * init_addr, *resp_addr;
+ uint16_t* init_port;
+
+ if (dns.qr == 0) {
+ init_addr = (void*)&ip->ip_src;
+ resp_addr = (void*)&ip->ip_dst;
+ init_port = tcp ? &tcp->th_sport : &udp->uh_sport;
+ } else {
+ init_addr = (void*)&ip->ip_dst;
+ resp_addr = (void*)&ip->ip_src;
+ init_port = tcp ? &tcp->th_dport : &udp->uh_dport;
+ }
+
+ if ((end_hide & END_INITIATOR) != 0) {
+ memcpy(init_addr, HIDE_INET, sizeof(struct in_addr));
+ *init_port = htons(HIDE_PORT);
+ }
+ if ((end_hide & END_RESPONDER) != 0)
+ memcpy(resp_addr, HIDE_INET, sizeof(struct in_addr));
+
+ ip->ip_sum = 0;
+ ip->ip_sum = ~in_checksum((u_char*)ip, sizeof *ip);
+ if (udp)
+ udp->uh_sum = 0U;
+ break;
+ }
+ case AF_INET6: {
+ void * init_addr, *resp_addr;
+ uint16_t* init_port;
+
+ if (dns.qr == 0) {
+ init_addr = (void*)&ipv6->ip6_src;
+ resp_addr = (void*)&ipv6->ip6_dst;
+ init_port = tcp ? &tcp->th_sport : &udp->uh_sport;
+ } else {
+ init_addr = (void*)&ipv6->ip6_dst;
+ resp_addr = (void*)&ipv6->ip6_src;
+ init_port = tcp ? &tcp->th_dport : &udp->uh_dport;
+ }
+
+ if ((end_hide & END_INITIATOR) != 0) {
+ memcpy(init_addr, HIDE_INET6, sizeof(struct in6_addr));
+ *init_port = htons(HIDE_PORT);
+ }
+ if ((end_hide & END_RESPONDER) != 0)
+ memcpy(resp_addr, HIDE_INET6, sizeof(struct in6_addr));
+
+ if (udp)
+ udp->uh_sum = 0U;
+ break;
+ }
+ default:
+ abort();
+ }
+ }
+ _curr_tcpstate = tcpstate;
+ output(descr, from, to, proto, flags, sport, dport, ts,
+ pkt_copy, olen, dnspkt, dnslen);
+ _curr_tcpstate = 0;
+
+ if (tcpstate && tcpstate->reasm) {
+ free(tcpstate->reasm->dnsmsg[m]);
+ tcpstate->reasm->dnsmsg[m] = 0;
+ tcpstate->reasm->dnsmsgs--;
+ } else
+ break;
+ }
+
+network_pkt_end:
+ network_ip = 0;
+ network_ipv6 = 0;
+ if (lpkt) {
+ ldns_pkt_free(lpkt);
+ }
+}
+
+uint16_t in_checksum(const u_char* ptr, size_t len)
+{
+ unsigned sum = 0, top;
+
+ /* Main body. */
+ while (len >= 2) {
+ sum += *(const uint16_t*)ptr;
+ ptr += 2;
+ len -= 2;
+ }
+
+ /* Leftover octet? */
+ if (len != 0)
+ sum += *ptr;
+
+ /* Leftover carries? */
+ while ((top = (sum >> 16)) != 0)
+ sum = ((uint16_t)sum) + top;
+
+ /* Caller should ~ this result. */
+ return ((uint16_t)sum);
+}
+
+static size_t calcrr(int q, const u_char* p, size_t l, size_t t)
+{
+ while (l < t) {
+ if ((p[l] & 0xc0) == 0xc0) {
+ l += 2;
+ } else if (p[l] & 0xc0) {
+ l += 1;
+ } else if (p[l]) {
+ l += p[l];
+ } else {
+ break;
+ }
+ }
+ l += 4; /* type + class */
+ if (q)
+ return l;
+ l += 6; /* ttl + rdlength */
+ if (l < t) {
+ l += (p[l - 2] << 8) + p[l - 1]; /* rdata */
+ }
+ return l;
+}
+
+size_t calcdnslen(const u_char* dnspkt, size_t dnslen)
+{
+ HEADER dns;
+ size_t n, len;
+
+ if (dnslen > 65535 || dnslen < sizeof(dns)) {
+ return 0;
+ }
+ memcpy(&dns, dnspkt, sizeof dns);
+ len = sizeof(dns);
+
+ for (n = 0; len < dnslen && n < dns.qdcount; n++) {
+ len = calcrr(1, dnspkt, len, dnslen);
+ }
+ for (n = 0; len < dnslen && n < dns.ancount; n++) {
+ len = calcrr(0, dnspkt, len, dnslen);
+ }
+ for (n = 0; len < dnslen && n < dns.nscount; n++) {
+ len = calcrr(0, dnspkt, len, dnslen);
+ }
+ for (n = 0; len < dnslen && n < dns.arcount; n++) {
+ len = calcrr(0, dnspkt, len, dnslen);
+ }
+ if (len < dnslen)
+ return len;
+ return dnslen;
+}
diff --git a/src/network.h b/src/network.h
new file mode 100644
index 0000000..9d5c7de
--- /dev/null
+++ b/src/network.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_network_h
+#define __dnscap_network_h
+
+tcpstate_ptr tcpstate_find(iaddr from, iaddr to, unsigned sport, unsigned dport, time_t t);
+tcpstate_ptr tcpstate_new(iaddr from, iaddr to, unsigned sport, unsigned dport);
+void dl_pkt(u_char* user, const struct pcap_pkthdr* hdr, const u_char* pkt, const char* name, const int dlt);
+void discard(tcpstate_ptr tcpstate, const char* msg);
+void network_pkt(const char* descr, my_bpftimeval ts, unsigned pf, const u_char* opkt, size_t olen);
+uint16_t in_checksum(const u_char* ptr, size_t len);
+
+void layer_pkt(u_char* user, const pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+void network_pkt2(const char* descr, my_bpftimeval ts, const pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+
+size_t calcdnslen(const u_char* dnspkt, size_t dnslen);
+
+#endif /* __dnscap_network_h */
diff --git a/src/options.c b/src/options.c
new file mode 100644
index 0000000..1eee2cf
--- /dev/null
+++ b/src/options.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "options.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <stdio.h>
+
+#define have(a) option_length == (sizeof(a) - 1) && !strncmp(option, a, (sizeof(a) - 1))
+
+int option_parse(options_t* options, const char* option)
+{
+ const char* argument;
+ int option_length;
+ char* p;
+ size_t s;
+
+ if (!options) {
+ return -1;
+ }
+ if (!option) {
+ return -1;
+ }
+
+ if (!(argument = strchr(option, '='))) {
+ return -2;
+ }
+ argument++;
+ if (!*argument) {
+ return -2;
+ }
+ option_length = argument - option - 1;
+ if (option_length < 1) {
+ return -2;
+ }
+
+ if (have("cbor_chunk_size")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->cbor_chunk_size = s;
+ return 0;
+ }
+ } else if (have("cds_cbor_size")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->cds_cbor_size = s;
+ return 0;
+ }
+ } else if (have("cds_message_size")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->cds_message_size = s;
+ return 0;
+ }
+ } else if (have("cds_max_rlabels")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->cds_max_rlabels = s;
+ return 0;
+ }
+ } else if (have("cds_min_rlabel_size")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->cds_min_rlabel_size = s;
+ return 0;
+ }
+ } else if (have("cds_use_rdata_index")) {
+ if (!strcmp(argument, "yes")) {
+ options->cds_use_rdata_index = 1;
+ return 0;
+ }
+ } else if (have("cds_rdata_index_min_size")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->cds_rdata_index_min_size = s;
+ return 0;
+ }
+ } else if (have("cds_use_rdata_rindex")) {
+ if (!strcmp(argument, "yes")) {
+ options->cds_use_rdata_rindex = 1;
+ return 0;
+ }
+ } else if (have("cds_rdata_rindex_size")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->cds_rdata_rindex_size = s;
+ return 0;
+ }
+ } else if (have("cds_rdata_rindex_min_size")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->cds_rdata_rindex_min_size = s;
+ return 0;
+ }
+ } else if (have("dump_format")) {
+ if (!strcmp(argument, "pcap")) {
+ options->dump_format = pcap;
+ return 0;
+ } else if (!strcmp(argument, "cbor")) {
+ options->dump_format = cbor;
+ return 0;
+ } else if (!strcmp(argument, "cds")) {
+ options->dump_format = cds;
+ return 0;
+ }
+ } else if (have("user")) {
+ if (options->user) {
+ free(options->user);
+ }
+ if ((options->user = strdup(argument))) {
+ return 0;
+ }
+ } else if (have("group")) {
+ if (options->group) {
+ free(options->group);
+ }
+ if ((options->group = strdup(argument))) {
+ return 0;
+ }
+ } else if (have("pcap_buffer_size")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->pcap_buffer_size = s;
+ return 0;
+ }
+ } else if (have("use_layers")) {
+ if (!strcmp(argument, "yes")) {
+ options->use_layers = 1;
+ return 0;
+ }
+ } else if (have("defrag_ipv4")) {
+ if (!strcmp(argument, "yes")) {
+ options->defrag_ipv4 = 1;
+ return 0;
+ }
+ } else if (have("max_ipv4_fragments")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->max_ipv4_fragments = s;
+ return 0;
+ }
+ } else if (have("max_ipv4_fragments_per_packet")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->max_ipv4_fragments_per_packet = s;
+ return 0;
+ }
+ } else if (have("defrag_ipv6")) {
+ if (!strcmp(argument, "yes")) {
+ options->defrag_ipv6 = 1;
+ return 0;
+ }
+ } else if (have("max_ipv6_fragments")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->max_ipv6_fragments = s;
+ return 0;
+ }
+ } else if (have("max_ipv6_fragments_per_packet")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->max_ipv6_fragments_per_packet = s;
+ return 0;
+ }
+ } else if (have("parse_ongoing_tcp")) {
+ if (!strcmp(argument, "yes")) {
+ options->parse_ongoing_tcp = 1;
+ return 0;
+ }
+ } else if (have("allow_reset_tcpstate")) {
+ if (!strcmp(argument, "yes")) {
+ options->allow_reset_tcpstate = 1;
+ return 0;
+ }
+ } else if (have("reassemble_tcp")) {
+ if (!strcmp(argument, "yes")) {
+ options->reassemble_tcp = 1;
+ return 0;
+ }
+ } else if (have("reassemble_tcp_faultreset")) {
+ s = strtoul(argument, &p, 0);
+ if (p && !*p && s > 0) {
+ options->reassemble_tcp_faultreset = s;
+ return 0;
+ }
+ } else if (have("reassemble_tcp_bfbparsedns")) {
+ if (!strcmp(argument, "yes")) {
+ options->reassemble_tcp_bfbparsedns = 1;
+ return 0;
+ }
+ } else if (have("bpf_hosts_apply_all")) {
+ if (!strcmp(argument, "yes")) {
+ options->bpf_hosts_apply_all = 1;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void options_free(options_t* options)
+{
+ if (options) {
+ if (options->user) {
+ free(options->user);
+ options->user = 0;
+ }
+ if (options->group) {
+ free(options->group);
+ options->group = 0;
+ }
+ }
+}
diff --git a/src/options.h b/src/options.h
new file mode 100644
index 0000000..e46dd06
--- /dev/null
+++ b/src/options.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include "dump_cds.h"
+
+#ifndef __dnscap_options_h
+#define __dnscap_options_h
+
+typedef enum dump_format dump_format_t;
+enum dump_format {
+ pcap,
+ cbor,
+ cds
+};
+
+/* clang-format off */
+
+#define OPTIONS_T_DEFAULTS { \
+ 1024 * 1024, \
+\
+ 1024 * 1024, \
+ 64 * 1024, \
+ CDS_DEFAULT_MAX_RLABELS, \
+ CDS_DEFAULT_MIN_RLABEL_SIZE, \
+ 0, \
+ CDS_DEFAULT_RDATA_INDEX_MIN_SIZE, \
+ 0, \
+ CDS_DEFAULT_RDATA_RINDEX_SIZE, \
+ CDS_DEFAULT_RDATA_RINDEX_MIN_SIZE, \
+\
+ pcap, \
+\
+ 0, \
+ 0, \
+\
+ 0, \
+\
+ 0, 0, 0, 0, 0, 0, 0, \
+\
+ 0, 0, 0, 0, 0, \
+\
+ 0 \
+}
+
+/* clang-format on */
+
+typedef struct options options_t;
+struct options {
+ size_t cbor_chunk_size;
+
+ size_t cds_cbor_size;
+ size_t cds_message_size;
+ size_t cds_max_rlabels;
+ size_t cds_min_rlabel_size;
+ int cds_use_rdata_index;
+ size_t cds_rdata_index_min_size;
+ int cds_use_rdata_rindex;
+ size_t cds_rdata_rindex_size;
+ size_t cds_rdata_rindex_min_size;
+
+ dump_format_t dump_format;
+
+ char* user;
+ char* group;
+
+ size_t pcap_buffer_size;
+
+ int use_layers;
+ int defrag_ipv4;
+ size_t max_ipv4_fragments;
+ size_t max_ipv4_fragments_per_packet;
+ int defrag_ipv6;
+ size_t max_ipv6_fragments;
+ size_t max_ipv6_fragments_per_packet;
+
+ int parse_ongoing_tcp;
+ int allow_reset_tcpstate;
+ int reassemble_tcp;
+ size_t reassemble_tcp_faultreset;
+ int reassemble_tcp_bfbparsedns;
+
+ int bpf_hosts_apply_all;
+};
+
+int option_parse(options_t* options, const char* option);
+void options_free(options_t* options);
+
+#endif /* __dnscap_options_h */
diff --git a/src/pcap-thread/m4/ax_pcap_thread.m4 b/src/pcap-thread/m4/ax_pcap_thread.m4
new file mode 100644
index 0000000..8831822
--- /dev/null
+++ b/src/pcap-thread/m4/ax_pcap_thread.m4
@@ -0,0 +1,15 @@
+AC_DEFUN([AX_PCAP_THREAD_PCAP], [
+ AC_HEADER_TIME
+ AC_CHECK_LIB([pcap], [pcap_open_live], [], AC_MSG_ERROR([libpcap not found]))
+ AC_CHECK_HEADER([pcap/pcap.h], [], [AC_MSG_ERROR([libpcap header not found])])
+ AC_CHECK_HEADERS([endian.h sys/endian.h machine/endian.h sys/time.h])
+ AC_CHECK_FUNCS([pcap_create pcap_set_tstamp_precision pcap_set_immediate_mode])
+ AC_CHECK_FUNCS([pcap_set_tstamp_type pcap_setdirection sched_yield])
+ AC_CHECK_FUNCS([pcap_open_offline_with_tstamp_precision pcap_activate])
+ AC_CHECK_TYPES([pcap_direction_t], [], [], [[#include <pcap/pcap.h>]])
+])
+
+AC_DEFUN([AX_PCAP_THREAD], [
+ AX_PTHREAD
+ AX_PCAP_THREAD_PCAP
+])
diff --git a/src/pcap-thread/m4/ax_pthread.m4 b/src/pcap-thread/m4/ax_pthread.m4
new file mode 100644
index 0000000..4c4051e
--- /dev/null
+++ b/src/pcap-thread/m4/ax_pthread.m4
@@ -0,0 +1,485 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+# This macro figures out how to build C programs using POSIX threads. It
+# sets the PTHREAD_LIBS output variable to the threads library and linker
+# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+# flags that are needed. (The user can also force certain compiler
+# flags/libs to be tested by setting these environment variables.)
+#
+# Also sets PTHREAD_CC to any special C compiler that is needed for
+# multi-threaded programs (defaults to the value of CC otherwise). (This
+# is necessary on AIX to use the special cc_r compiler alias.)
+#
+# NOTE: You are assumed to not only compile your program with these flags,
+# but also to link with them as well. For example, you might link with
+# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+# If you are only building threaded programs, you may wish to use these
+# variables in your default LIBS, CFLAGS, and CC:
+#
+# LIBS="$PTHREAD_LIBS $LIBS"
+# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+# CC="$PTHREAD_CC"
+#
+# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
+# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+# PTHREAD_CFLAGS.
+#
+# ACTION-IF-FOUND is a list of shell commands to run if a threads library
+# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+# is not found. If ACTION-IF-FOUND is not specified, the default action
+# will define HAVE_PTHREAD.
+#
+# Please let the authors know if this macro fails on any platform, or if
+# you have any other suggestions or comments. This macro was based on work
+# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+# Alejandro Forero Cuervo to the autoconf macro repository. We are also
+# grateful for the helpful feedback of numerous users.
+#
+# Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 23
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_PROG_SED])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on Tru64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+ ax_pthread_save_CC="$CC"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
+ AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
+ AC_MSG_RESULT([$ax_pthread_ok])
+ if test "x$ax_pthread_ok" = "xno"; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ CC="$ax_pthread_save_CC"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+# (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads and
+# -D_REENTRANT too), HP C (must be checked before -lpthread, which
+# is present but should not be used directly; and before -mthreads,
+# because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case $host_os in
+
+ freebsd*)
+
+ # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+ # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+ ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+ ;;
+
+ hpux*)
+
+ # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+ # multi-threading and also sets -lpthread."
+
+ ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+ ;;
+
+ openedition*)
+
+ # IBM z/OS requires a feature-test macro to be defined in order to
+ # enable POSIX threads at all, so give the user a hint if this is
+ # not set. (We don't define these ourselves, as they can affect
+ # other portions of the system API in unpredictable ways.)
+
+ AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
+ [
+# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+ AX_PTHREAD_ZOS_MISSING
+# endif
+ ],
+ [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
+ ;;
+
+ solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (N.B.: The stubs are missing
+ # pthread_cleanup_push, or rather a function called by this macro,
+ # so we could check for that, but who knows whether they'll stub
+ # that too in a future libc.) So we'll check first for the
+ # standard Solaris way of linking pthreads (-mt -lpthread).
+
+ ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
+ ;;
+esac
+
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+
+AS_IF([test "x$GCC" = "xyes"],
+ [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $host_os in
+ darwin* | hpux* | linux* | osf* | solaris*)
+ ax_pthread_check_macro="_REENTRANT"
+ ;;
+
+ aix*)
+ ax_pthread_check_macro="_THREAD_SAFE"
+ ;;
+
+ *)
+ ax_pthread_check_macro="--"
+ ;;
+esac
+AS_IF([test "x$ax_pthread_check_macro" = "x--"],
+ [ax_pthread_check_cond=0],
+ [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
+
+# Are we compiling with Clang?
+
+AC_CACHE_CHECK([whether $CC is Clang],
+ [ax_cv_PTHREAD_CLANG],
+ [ax_cv_PTHREAD_CLANG=no
+ # Note that Autoconf sets GCC=yes for Clang as well as GCC
+ if test "x$GCC" = "xyes"; then
+ AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
+ [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+# if defined(__clang__) && defined(__llvm__)
+ AX_PTHREAD_CC_IS_CLANG
+# endif
+ ],
+ [ax_cv_PTHREAD_CLANG=yes])
+ fi
+ ])
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+ax_pthread_clang_warning=no
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+ # Clang takes -pthread; it has never supported any other flag
+
+ # (Note 1: This will need to be revisited if a system that Clang
+ # supports has POSIX threads in a separate library. This tends not
+ # to be the way of modern systems, but it's conceivable.)
+
+ # (Note 2: On some systems, notably Darwin, -pthread is not needed
+ # to get POSIX threads support; the API is always present and
+ # active. We could reasonably leave PTHREAD_CFLAGS empty. But
+ # -pthread does define _REENTRANT, and while the Darwin headers
+ # ignore this macro, third-party headers might not.)
+
+ PTHREAD_CFLAGS="-pthread"
+ PTHREAD_LIBS=
+
+ ax_pthread_ok=yes
+
+ # However, older versions of Clang make a point of warning the user
+ # that, in an invocation where only linking and no compilation is
+ # taking place, the -pthread option has no effect ("argument unused
+ # during compilation"). They expect -pthread to be passed in only
+ # when source code is being compiled.
+ #
+ # Problem is, this is at odds with the way Automake and most other
+ # C build frameworks function, which is that the same flags used in
+ # compilation (CFLAGS) are also used in linking. Many systems
+ # supported by AX_PTHREAD require exactly this for POSIX threads
+ # support, and in fact it is often not straightforward to specify a
+ # flag that is used only in the compilation phase and not in
+ # linking. Such a scenario is extremely rare in practice.
+ #
+ # Even though use of the -pthread flag in linking would only print
+ # a warning, this can be a nuisance for well-run software projects
+ # that build with -Werror. So if the active version of Clang has
+ # this misfeature, we search for an option to squash it.
+
+ AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
+ [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
+ [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+ # Create an alternate version of $ac_link that compiles and
+ # links in two steps (.c -> .o, .o -> exe) instead of one
+ # (.c -> exe), because the warning occurs only in the second
+ # step
+ ax_pthread_save_ac_link="$ac_link"
+ ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+ ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+ ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+ AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
+ CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+ ac_link="$ax_pthread_save_ac_link"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+ [ac_link="$ax_pthread_2step_ac_link"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+ [break])
+ ])
+ done
+ ac_link="$ax_pthread_save_ac_link"
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
+ ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+ ])
+
+ case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+ no | unknown) ;;
+ *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+ esac
+
+fi # $ax_pthread_clang = yes
+
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+ case $ax_pthread_try_flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -mt,pthread)
+ AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
+ PTHREAD_CFLAGS="-mt"
+ PTHREAD_LIBS="-lpthread"
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
+ PTHREAD_CFLAGS="$ax_pthread_try_flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+ AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
+ PTHREAD_LIBS="-l$ax_pthread_try_flag"
+ ;;
+ esac
+
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+# if $ax_pthread_check_cond
+# error "$ax_pthread_check_macro must be defined"
+# endif
+ static void routine(void *a) { a = 0; }
+ static void *start_routine(void *a) { return a; }],
+ [pthread_t th; pthread_attr_t attr;
+ pthread_create(&th, 0, start_routine, 0);
+ pthread_join(th, 0);
+ pthread_attr_init(&attr);
+ pthread_cleanup_push(routine, 0);
+ pthread_cleanup_pop(0) /* ; */])],
+ [ax_pthread_ok=yes],
+ [])
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ AC_MSG_RESULT([$ax_pthread_ok])
+ AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = "xyes"; then
+ ax_pthread_save_CFLAGS="$CFLAGS"
+ ax_pthread_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_CACHE_CHECK([for joinable pthread attribute],
+ [ax_cv_PTHREAD_JOINABLE_ATTR],
+ [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+ for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+ [int attr = $ax_pthread_attr; return attr /* ; */])],
+ [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
+ [])
+ done
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+ test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+ test "x$ax_pthread_joinable_attr_defined" != "xyes"],
+ [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
+ [$ax_cv_PTHREAD_JOINABLE_ATTR],
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ ax_pthread_joinable_attr_defined=yes
+ ])
+
+ AC_CACHE_CHECK([whether more special flags are required for pthreads],
+ [ax_cv_PTHREAD_SPECIAL_FLAGS],
+ [ax_cv_PTHREAD_SPECIAL_FLAGS=no
+ case $host_os in
+ solaris*)
+ ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+ ;;
+ esac
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+ test "x$ax_pthread_special_flags_added" != "xyes"],
+ [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+ ax_pthread_special_flags_added=yes])
+
+ AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+ [ax_cv_PTHREAD_PRIO_INHERIT],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+ [[int i = PTHREAD_PRIO_INHERIT;]])],
+ [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+ [ax_cv_PTHREAD_PRIO_INHERIT=no])
+ ])
+ AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+ test "x$ax_pthread_prio_inherit_defined" != "xyes"],
+ [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
+ ax_pthread_prio_inherit_defined=yes
+ ])
+
+ CFLAGS="$ax_pthread_save_CFLAGS"
+ LIBS="$ax_pthread_save_LIBS"
+
+ # More AIX lossage: compile with *_r variant
+ if test "x$GCC" != "xyes"; then
+ case $host_os in
+ aix*)
+ AS_CASE(["x/$CC"],
+ [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+ [#handle absolute path differently from PATH based program lookup
+ AS_CASE(["x$CC"],
+ [x/*],
+ [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
+ [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
+ ;;
+ esac
+ fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test "x$ax_pthread_ok" = "xyes"; then
+ ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+ :
+else
+ ax_pthread_ok=no
+ $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD
diff --git a/src/pcap-thread/pcap_thread.c b/src/pcap-thread/pcap_thread.c
new file mode 100644
index 0000000..8acdcbe
--- /dev/null
+++ b/src/pcap-thread/pcap_thread.c
@@ -0,0 +1,3818 @@
+/*
+ * Author Jerry Lundström <jerry@dns-oarc.net>
+ * Copyright (c) 2016-2017, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "pcap_thread.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+
+#ifndef PCAP_THREAD_LAYER_TRACE
+#define PCAP_THREAD_LAYER_TRACE 0
+#endif
+
+/*
+ * Forward declares for layer callbacks
+ */
+
+static void pcap_thread_callback(u_char* user, const struct pcap_pkthdr* pkthdr, const u_char* pkt, const char* name, int dlt);
+static void pcap_thread_callback_linux_sll(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_ether(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_null(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_loop(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_ieee802(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_gre(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_ip(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_ipv4(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_ipv6(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_icmp(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_icmpv6(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_udp(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+static void pcap_thread_callback_tcp(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+
+/*
+ * Version
+ */
+
+static const char* _version = PCAP_THREAD_VERSION_STR;
+
+const char* pcap_thread_version_str(void)
+{
+ return _version;
+}
+
+int pcap_thread_version_major(void)
+{
+ return PCAP_THREAD_VERSION_MAJOR;
+}
+
+int pcap_thread_version_minor(void)
+{
+ return PCAP_THREAD_VERSION_MINOR;
+}
+
+int pcap_thread_version_patch(void)
+{
+ return PCAP_THREAD_VERSION_PATCH;
+}
+
+/*
+ * Create/Free
+ */
+
+static pcap_thread_t _pcap_thread_defaults = PCAP_THREAD_T_INIT;
+
+pcap_thread_t* pcap_thread_create(void)
+{
+ pcap_thread_t* pcap_thread = calloc(1, sizeof(pcap_thread_t));
+ if (pcap_thread) {
+ memcpy(pcap_thread, &_pcap_thread_defaults, sizeof(pcap_thread_t));
+ }
+
+ return pcap_thread;
+}
+
+void pcap_thread_free(pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return;
+ }
+
+ pcap_thread_close(pcap_thread);
+ if (pcap_thread->filter) {
+ free(pcap_thread->filter);
+ }
+ free(pcap_thread);
+}
+
+/*
+ * Get/Set
+ */
+
+int pcap_thread_use_threads(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->use_threads;
+}
+
+int pcap_thread_set_use_threads(pcap_thread_t* pcap_thread, const int use_threads)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->use_threads = use_threads;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_use_layers(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->use_layers;
+}
+
+int pcap_thread_set_use_layers(pcap_thread_t* pcap_thread, const int use_layers)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->use_layers = use_layers;
+
+ return PCAP_THREAD_OK;
+}
+
+pcap_thread_queue_mode_t pcap_thread_queue_mode(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->queue_mode;
+}
+
+int pcap_thread_set_queue_mode(pcap_thread_t* pcap_thread, const pcap_thread_queue_mode_t queue_mode)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ switch (queue_mode) {
+ case PCAP_THREAD_QUEUE_MODE_COND:
+ case PCAP_THREAD_QUEUE_MODE_DIRECT:
+ break;
+ case PCAP_THREAD_QUEUE_MODE_YIELD:
+ case PCAP_THREAD_QUEUE_MODE_WAIT:
+ case PCAP_THREAD_QUEUE_MODE_DROP:
+ return PCAP_THREAD_EOBSOLETE;
+ default:
+ return PCAP_THREAD_EINVAL;
+ }
+
+ pcap_thread->queue_mode = queue_mode;
+
+ return PCAP_THREAD_OK;
+}
+
+struct timeval pcap_thread_queue_wait(const pcap_thread_t* pcap_thread)
+{
+ static struct timeval tv = { 0, 0 };
+ return tv;
+}
+
+int pcap_thread_set_queue_wait(pcap_thread_t* pcap_thread, const struct timeval queue_wait)
+{
+ return PCAP_THREAD_EOBSOLETE;
+}
+
+pcap_thread_queue_mode_t pcap_thread_callback_queue_mode(const pcap_thread_t* pcap_thread)
+{
+ return PCAP_THREAD_EOBSOLETE;
+}
+
+int pcap_thread_set_callback_queue_mode(pcap_thread_t* pcap_thread, const pcap_thread_queue_mode_t callback_queue_mode)
+{
+ return PCAP_THREAD_EOBSOLETE;
+}
+
+struct timeval pcap_thread_callback_queue_wait(const pcap_thread_t* pcap_thread)
+{
+ static struct timeval tv = { 0, 0 };
+ return tv;
+}
+
+int pcap_thread_set_callback_queue_wait(pcap_thread_t* pcap_thread, const struct timeval callback_queue_wait)
+{
+ return PCAP_THREAD_EOBSOLETE;
+}
+
+int pcap_thread_snapshot(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->snapshot;
+}
+
+int pcap_thread_snaplen(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->snaplen;
+}
+
+int pcap_thread_set_snaplen(pcap_thread_t* pcap_thread, const int snaplen)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->snaplen = snaplen;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_promiscuous(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->promiscuous;
+}
+
+int pcap_thread_set_promiscuous(pcap_thread_t* pcap_thread, const int promiscuous)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->promiscuous = promiscuous;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_monitor(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->monitor;
+}
+
+int pcap_thread_set_monitor(pcap_thread_t* pcap_thread, const int monitor)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->monitor = monitor;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_timeout(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->timeout;
+}
+
+int pcap_thread_set_timeout(pcap_thread_t* pcap_thread, const int timeout)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->timeout = timeout;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_buffer_size(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->buffer_size;
+}
+
+int pcap_thread_set_buffer_size(pcap_thread_t* pcap_thread, const int buffer_size)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->buffer_size = buffer_size;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_timestamp_type(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->timestamp_type;
+}
+
+int pcap_thread_set_timestamp_type(pcap_thread_t* pcap_thread, const int timestamp_type)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->have_timestamp_type = 1;
+ pcap_thread->timestamp_type = timestamp_type;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_timestamp_precision(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->timestamp_precision;
+}
+
+int pcap_thread_set_timestamp_precision(pcap_thread_t* pcap_thread, const int timestamp_precision)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->have_timestamp_precision = 1;
+ pcap_thread->timestamp_precision = timestamp_precision;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_immediate_mode(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->immediate_mode;
+}
+
+int pcap_thread_set_immediate_mode(pcap_thread_t* pcap_thread, const int immediate_mode)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->immediate_mode = immediate_mode;
+
+ return PCAP_THREAD_OK;
+}
+
+pcap_direction_t pcap_thread_direction(const pcap_thread_t* pcap_thread)
+{
+#ifdef HAVE_PCAP_DIRECTION_T
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->direction;
+#else
+ return 0;
+#endif
+}
+
+int pcap_thread_set_direction(pcap_thread_t* pcap_thread, const pcap_direction_t direction)
+{
+#ifdef HAVE_PCAP_DIRECTION_T
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->have_direction = 1;
+ pcap_thread->direction = direction;
+
+ return PCAP_THREAD_OK;
+#else
+ return PCAP_THREAD_ENODIR;
+#endif
+}
+
+const char* pcap_thread_filter(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return 0;
+ }
+
+ return pcap_thread->filter;
+}
+
+int pcap_thread_set_filter(pcap_thread_t* pcap_thread, const char* filter, const size_t filter_len)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!filter) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!filter_len) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ if (pcap_thread->filter) {
+ free(pcap_thread->filter);
+ }
+ if (!(pcap_thread->filter = strndup(filter, filter_len))) {
+ return PCAP_THREAD_ENOMEM;
+ }
+ pcap_thread->filter_len = filter_len;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_clear_filter(pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ if (pcap_thread->filter) {
+ free(pcap_thread->filter);
+ pcap_thread->filter = 0;
+ pcap_thread->filter_len = 0;
+ }
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_filter_errno(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->filter_errno;
+}
+
+int pcap_thread_filter_optimize(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->filter_optimize;
+}
+
+int pcap_thread_set_filter_optimize(pcap_thread_t* pcap_thread, const int filter_optimize)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->filter_optimize = filter_optimize;
+
+ return PCAP_THREAD_OK;
+}
+
+bpf_u_int32 pcap_thread_filter_netmask(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->filter_netmask;
+}
+
+int pcap_thread_set_filter_netmask(pcap_thread_t* pcap_thread, const bpf_u_int32 filter_netmask)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->filter_netmask = filter_netmask;
+
+ return PCAP_THREAD_OK;
+}
+
+struct timeval pcap_thread_timedrun(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ static struct timeval tv = { 0, 0 };
+ return tv;
+ }
+
+ return pcap_thread->timedrun;
+}
+
+int pcap_thread_set_timedrun(pcap_thread_t* pcap_thread, const struct timeval timedrun)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->timedrun = timedrun;
+
+ return PCAP_THREAD_OK;
+}
+
+struct timeval pcap_thread_timedrun_to(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ static struct timeval tv = { 0, 0 };
+ return tv;
+ }
+
+ return pcap_thread->timedrun_to;
+}
+
+int pcap_thread_set_timedrun_to(pcap_thread_t* pcap_thread, const struct timeval timedrun_to)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->timedrun_to = timedrun_to;
+
+ return PCAP_THREAD_OK;
+}
+
+pcap_thread_activate_mode_t pcap_thread_activate_mode(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_DEFAULT_ACTIVATE_MODE;
+ }
+
+ return pcap_thread->activate_mode;
+}
+
+int pcap_thread_set_activate_mode(pcap_thread_t* pcap_thread, const pcap_thread_activate_mode_t activate_mode)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->activate_mode = activate_mode;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_was_stopped(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ return pcap_thread->was_stopped;
+}
+
+/*
+ * Queue
+ */
+
+size_t pcap_thread_queue_size(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return -1;
+ }
+
+ return pcap_thread->queue_size;
+}
+
+int pcap_thread_set_queue_size(pcap_thread_t* pcap_thread, const size_t queue_size)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!queue_size) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->queue_size = queue_size;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback(pcap_thread_t* pcap_thread, pcap_thread_callback_t callback)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback = callback;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_dropback(pcap_thread_t* pcap_thread, pcap_thread_callback_t dropback)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->dropback = dropback;
+
+ return PCAP_THREAD_OK;
+}
+
+/*
+ * Layers
+ */
+
+int pcap_thread_set_callback_linux_sll(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_linux_sll)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_linux_sll = callback_linux_sll;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_ether(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ether)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_ether = callback_ether;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_null(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_null)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_null = callback_null;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_loop(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_loop)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_loop = callback_loop;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_ieee802(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ieee802)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_ieee802 = callback_ieee802;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_gre(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_gre)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_gre = callback_gre;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_ip(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ip)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_ip = callback_ip;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_ipv4(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ipv4)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_ipv4 = callback_ipv4;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_ipv4_frag(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_frag_t callback_ipv4_frag)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!callback_ipv4_frag.new
+ || !callback_ipv4_frag.free
+ || !callback_ipv4_frag.reassemble
+ || !callback_ipv4_frag.release) {
+ if (callback_ipv4_frag.new
+ || callback_ipv4_frag.free
+ || callback_ipv4_frag.reassemble
+ || callback_ipv4_frag.release) {
+ return PCAP_THREAD_EINVAL;
+ }
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_ipv4_frag = callback_ipv4_frag;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_ipv6(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ipv6)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_ipv6 = callback_ipv6;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_ipv6_frag(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_frag_t callback_ipv6_frag)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!callback_ipv6_frag.new
+ || !callback_ipv6_frag.free
+ || !callback_ipv6_frag.reassemble
+ || !callback_ipv6_frag.release) {
+ if (callback_ipv6_frag.new
+ || callback_ipv6_frag.free
+ || callback_ipv6_frag.reassemble
+ || callback_ipv6_frag.release) {
+ return PCAP_THREAD_EINVAL;
+ }
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_ipv6_frag = callback_ipv6_frag;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_icmp(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_icmp)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_icmp = callback_icmp;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_icmpv6(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_icmpv6)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_icmpv6 = callback_icmpv6;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_udp(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_udp)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_udp = callback_udp;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_tcp(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_tcp)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6) {
+ return PCAP_THREAD_ELAYERCB;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_tcp = callback_tcp;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_set_callback_invalid(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_invalid)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ pcap_thread->callback_invalid = callback_invalid;
+
+ return PCAP_THREAD_OK;
+}
+
+#define need4x2(v1, v2, p, l) \
+ if (l < 1) { \
+ break; \
+ } \
+ v1 = (*p) >> 4; \
+ v2 = (*p) & 0xf; \
+ p += 1; \
+ l -= 1
+
+#define need8(v, p, l) \
+ if (l < 1) { \
+ break; \
+ } \
+ v = *p; \
+ p += 1; \
+ l -= 1
+
+#define need16(v, p, l) \
+ if (l < 2) { \
+ break; \
+ } \
+ v = (*p << 8) + *(p + 1); \
+ p += 2; \
+ l -= 2
+
+#define need32(v, p, l) \
+ if (l < 4) { \
+ break; \
+ } \
+ v = (*p << 24) + (*(p + 1) << 16) + (*(p + 2) << 8) + *(p + 3); \
+ p += 4; \
+ l -= 4
+
+#define needxb(b, x, p, l) \
+ if (l < x) { \
+ break; \
+ } \
+ memcpy(b, p, x); \
+ p += x; \
+ l -= x
+
+#define advancexb(x, p, l) \
+ if (l < x) { \
+ break; \
+ } \
+ p += x; \
+ l -= x
+
+#if PCAP_THREAD_LAYER_TRACE
+#define layer_trace(msg) printf("LT %s:%d: " msg "\n", __FILE__, __LINE__)
+#define layer_tracef(msg, args...) printf("LT %s:%d: " msg "\n", __FILE__, __LINE__, args)
+#else
+#define layer_trace(msg)
+#define layer_tracef(msg, args...)
+#endif
+
+static void pcap_thread_callback(u_char* user, const struct pcap_pkthdr* pkthdr, const u_char* pkt, const char* name, int dlt)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ size_t length;
+ pcap_thread_packet_t packet;
+ const u_char* orig = pkt;
+ size_t origlength;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!pkthdr) {
+ return;
+ }
+ if (!pkt) {
+ return;
+ }
+ if (!name) {
+ return;
+ }
+
+ memset(&packet, 0, sizeof(packet));
+ packet.name = name;
+ packet.dlt = dlt;
+ packet.pkthdr = *pkthdr;
+ packet.have_pkthdr = 1;
+ length = pkthdr->caplen;
+ origlength = length;
+
+ layer_tracef("packet, length %lu", length);
+
+ switch (dlt) {
+ case DLT_NULL:
+ layer_trace("dlt_null");
+ {
+ uint8_t hdr[4];
+
+ packet.state = PCAP_THREAD_PACKET_INVALID_NULL;
+ need8(hdr[0], pkt, length);
+ need8(hdr[1], pkt, length);
+ need8(hdr[2], pkt, length);
+ need8(hdr[3], pkt, length);
+ packet.state = PCAP_THREAD_PACKET_OK;
+
+ /*
+ * The header for null is in host byte order but may not be
+ * in the same endian as host if coming from a savefile
+ */
+
+ if (pcaplist->is_offline && pcap_is_swapped(pcaplist->pcap)) {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ packet.nullhdr.family = hdr[3] + (hdr[2] << 8) + (hdr[1] << 16) + (hdr[0] << 24);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ packet.nullhdr.family = hdr[0] + (hdr[1] << 8) + (hdr[2] << 16) + (hdr[3] << 24);
+#else
+#error "Please fix <endian.h>"
+#endif
+ } else {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ packet.nullhdr.family = hdr[0] + (hdr[1] << 8) + (hdr[2] << 16) + (hdr[3] << 24);
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ packet.nullhdr.family = hdr[3] + (hdr[2] << 8) + (hdr[1] << 16) + (hdr[0] << 24);
+#else
+#error "Please fix <endian.h>"
+#endif
+ }
+ packet.have_nullhdr = 1;
+
+ if (pcaplist->pcap_thread->callback_null)
+ pcaplist->pcap_thread->callback_null(pcaplist->user, &packet, pkt, length);
+ else
+ pcap_thread_callback_null((void*)pcaplist, &packet, pkt, length);
+ return;
+ }
+ break;
+
+ case DLT_EN10MB:
+ layer_trace("dlt_en10mb");
+ packet.state = PCAP_THREAD_PACKET_INVALID_ETHER;
+ needxb(packet.ethhdr.ether_dhost, sizeof(packet.ethhdr.ether_dhost), pkt, length);
+ needxb(packet.ethhdr.ether_shost, sizeof(packet.ethhdr.ether_shost), pkt, length);
+ need16(packet.ethhdr.ether_type, pkt, length);
+ packet.state = PCAP_THREAD_PACKET_OK;
+ packet.have_ethhdr = 1;
+
+ if (pcaplist->pcap_thread->callback_ether)
+ pcaplist->pcap_thread->callback_ether(pcaplist->user, &packet, pkt, length);
+ else
+ pcap_thread_callback_ether((void*)pcaplist, &packet, pkt, length);
+ return;
+
+ case DLT_LOOP:
+ layer_trace("dlt_loop");
+ packet.state = PCAP_THREAD_PACKET_INVALID_LOOP;
+ need32(packet.loophdr.family, pkt, length);
+ packet.state = PCAP_THREAD_PACKET_OK;
+ packet.have_loophdr = 1;
+
+ if (pcaplist->pcap_thread->callback_loop)
+ pcaplist->pcap_thread->callback_loop(pcaplist->user, &packet, pkt, length);
+ else
+ pcap_thread_callback_loop((void*)pcaplist, &packet, pkt, length);
+ return;
+
+ case DLT_RAW:
+#ifdef DLT_IPV4
+ case DLT_IPV4:
+#endif
+#ifdef DLT_IPV6
+ case DLT_IPV6:
+#endif
+ layer_trace("dlt_raw/ipv4/ipv6");
+ if (pcaplist->pcap_thread->callback_ip)
+ pcaplist->pcap_thread->callback_ip(pcaplist->user, &packet, pkt, length);
+ else
+ pcap_thread_callback_ip((void*)pcaplist, &packet, pkt, length);
+ return;
+
+ case DLT_LINUX_SLL:
+ layer_trace("dlt_linux_sll");
+ packet.state = PCAP_THREAD_PACKET_INVALID_LINUX_SLL;
+ need16(packet.linux_sll.packet_type, pkt, length);
+ need16(packet.linux_sll.arp_hardware, pkt, length);
+ need16(packet.linux_sll.link_layer_address_length, pkt, length);
+ needxb(packet.linux_sll.link_layer_address, 8, pkt, length);
+ need16(packet.linux_sll.ether_type, pkt, length);
+ packet.state = PCAP_THREAD_PACKET_OK;
+ packet.have_linux_sll = 1;
+
+ if (pcaplist->pcap_thread->callback_linux_sll)
+ pcaplist->pcap_thread->callback_linux_sll(pcaplist->user, &packet, pkt, length);
+ else
+ pcap_thread_callback_linux_sll((void*)pcaplist, &packet, pkt, length);
+ return;
+
+ /* TODO: These might be interesting to implement
+ case DLT_IPNET:
+ case DLT_PKTAP:
+ */
+
+ default:
+ packet.state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet.state == PCAP_THREAD_PACKET_OK)
+ packet.state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, &packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_linux_sll(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (packet->have_linux_sll) {
+ layer_trace("have_linux_sll");
+ switch (packet->linux_sll.ether_type) {
+ case 0x8100: /* 802.1q */
+ case 0x88a8: /* 802.1ad */
+ case 0x9100: /* 802.1 QinQ non-standard */
+ if (packet->have_ieee802hdr)
+ break;
+
+ {
+ uint16_t tci;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_IEEE802;
+ need16(tci, payload, length);
+ packet->ieee802hdr.pcp = (tci & 0xe000) >> 13;
+ packet->ieee802hdr.dei = (tci & 0x1000) >> 12;
+ packet->ieee802hdr.vid = tci & 0x0fff;
+ need16(packet->ieee802hdr.ether_type, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_ieee802hdr = 1;
+ }
+
+ if (pcaplist->pcap_thread->callback_ieee802)
+ pcaplist->pcap_thread->callback_ieee802(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ieee802((void*)pcaplist, packet, payload, length);
+ return;
+
+ case ETHERTYPE_IP:
+ case ETHERTYPE_IPV6:
+ if (pcaplist->pcap_thread->callback_ip)
+ pcaplist->pcap_thread->callback_ip(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ip((void*)pcaplist, packet, payload, length);
+ return;
+
+ default:
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_ether(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (packet->have_ethhdr) {
+ layer_trace("have_ethhdr");
+ switch (packet->ethhdr.ether_type) {
+ case 0x8100: /* 802.1q */
+ case 0x88a8: /* 802.1ad */
+ case 0x9100: /* 802.1 QinQ non-standard */
+ if (packet->have_ieee802hdr)
+ break;
+
+ {
+ uint16_t tci;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_IEEE802;
+ need16(tci, payload, length);
+ packet->ieee802hdr.pcp = (tci & 0xe000) >> 13;
+ packet->ieee802hdr.dei = (tci & 0x1000) >> 12;
+ packet->ieee802hdr.vid = tci & 0x0fff;
+ need16(packet->ieee802hdr.ether_type, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_ieee802hdr = 1;
+ }
+
+ if (pcaplist->pcap_thread->callback_ieee802)
+ pcaplist->pcap_thread->callback_ieee802(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ieee802((void*)pcaplist, packet, payload, length);
+ return;
+
+ case ETHERTYPE_IP:
+ case ETHERTYPE_IPV6:
+ if (pcaplist->pcap_thread->callback_ip)
+ pcaplist->pcap_thread->callback_ip(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ip((void*)pcaplist, packet, payload, length);
+ return;
+
+ default:
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_null(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (packet->have_nullhdr) {
+ layer_trace("have_nullhdr");
+
+ /* From libpcap link types documentation:
+ * containing a value of 2 for IPv4 packets, a value of either 24, 28,
+ * or 30 for IPv6 packets, a value of 7 for OSI packets, or a value of 23
+ * for IPX packets. All of the IPv6 values correspond to IPv6 packets;
+ * code reading files should check for all of them.
+ */
+
+ switch (packet->nullhdr.family) {
+ case 2:
+ case 24:
+ case 28:
+ case 30:
+ if (pcaplist->pcap_thread->callback_ip)
+ pcaplist->pcap_thread->callback_ip(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ip((void*)pcaplist, packet, payload, length);
+ return;
+
+ default:
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_loop(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (packet->have_loophdr) {
+ layer_trace("have_loophdr");
+
+ /* From libpcap link types documentation:
+ * containing a value of 2 for IPv4 packets, a value of either 24, 28,
+ * or 30 for IPv6 packets, a value of 7 for OSI packets, or a value of 23
+ * for IPX packets. All of the IPv6 values correspond to IPv6 packets;
+ * code reading files should check for all of them.
+ */
+
+ switch (packet->loophdr.family) {
+ case 2:
+ case 24:
+ case 28:
+ case 30:
+ if (pcaplist->pcap_thread->callback_ip)
+ pcaplist->pcap_thread->callback_ip(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ip((void*)pcaplist, packet, payload, length);
+ return;
+
+ default:
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_ieee802(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (packet->have_ieee802hdr) {
+ layer_trace("have_ieee802hdr");
+
+ switch (packet->ieee802hdr.ether_type) {
+ case 0x88a8: /* 802.1ad */
+ case 0x9100: /* 802.1 QinQ non-standard */
+ {
+ pcap_thread_packet_t ieee802pkt;
+ uint16_t tci;
+
+ memset(&ieee802pkt, 0, sizeof(ieee802pkt));
+ ieee802pkt.prevpkt = packet;
+ ieee802pkt.have_prevpkt = 1;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_IEEE802;
+ need16(tci, payload, length);
+ ieee802pkt.ieee802hdr.pcp = (tci & 0xe000) >> 13;
+ ieee802pkt.ieee802hdr.dei = (tci & 0x1000) >> 12;
+ ieee802pkt.ieee802hdr.vid = tci & 0x0fff;
+ need16(ieee802pkt.ieee802hdr.ether_type, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ ieee802pkt.have_ieee802hdr = 1;
+
+ if (pcaplist->pcap_thread->callback_ieee802)
+ pcaplist->pcap_thread->callback_ieee802(pcaplist->user, &ieee802pkt, payload, length);
+ else
+ pcap_thread_callback_ieee802((void*)pcaplist, &ieee802pkt, payload, length);
+ return;
+ }
+
+ case ETHERTYPE_IP:
+ case ETHERTYPE_IPV6:
+ if (pcaplist->pcap_thread->callback_ip)
+ pcaplist->pcap_thread->callback_ip(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ip((void*)pcaplist, packet, payload, length);
+ return;
+
+ default:
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_gre(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (packet->have_grehdr) {
+ pcap_thread_packet_t grepkt;
+
+ layer_trace("have_grehdr");
+
+ memset(&grepkt, 0, sizeof(grepkt));
+ grepkt.prevpkt = packet;
+ grepkt.have_prevpkt = 1;
+
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_INVALID_GRE;
+ if (packet->grehdr.gre_flags & 0x1) {
+ need16(packet->gre.checksum, payload, length);
+ }
+ if (packet->grehdr.gre_flags & 0x4) {
+ need16(packet->gre.key, payload, length);
+ }
+ if (packet->grehdr.gre_flags & 0x8) {
+ need16(packet->gre.sequence, payload, length);
+ }
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_gre = 1;
+
+ switch (packet->grehdr.ether_type) {
+ case ETHERTYPE_IP:
+ case ETHERTYPE_IPV6:
+ if (pcaplist->pcap_thread->callback_ip)
+ pcaplist->pcap_thread->callback_ip(pcaplist->user, &grepkt, payload, length);
+ else
+ pcap_thread_callback_ip((void*)pcaplist, &grepkt, payload, length);
+ return;
+
+ default:
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_ip(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (!packet->have_iphdr && !packet->have_ip6hdr) {
+ layer_trace("checking for ip");
+
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_INVALID_IP;
+ need4x2(packet->iphdr.ip_v, packet->iphdr.ip_hl, payload, length);
+ if (packet->iphdr.ip_v == 4) {
+ packet->state = PCAP_THREAD_PACKET_INVALID_IPV4;
+ need8(packet->iphdr.ip_tos, payload, length);
+ need16(packet->iphdr.ip_len, payload, length);
+ need16(packet->iphdr.ip_id, payload, length);
+ need16(packet->iphdr.ip_off, payload, length);
+ need8(packet->iphdr.ip_ttl, payload, length);
+ need8(packet->iphdr.ip_p, payload, length);
+ need16(packet->iphdr.ip_sum, payload, length);
+ needxb(&(packet->iphdr.ip_src.s_addr), 4, payload, length);
+ needxb(&(packet->iphdr.ip_dst.s_addr), 4, payload, length);
+
+ /* TODO: IPv4 options */
+
+ if (packet->iphdr.ip_hl < 5)
+ break;
+ if (packet->iphdr.ip_hl > 5) {
+ advancexb((packet->iphdr.ip_hl - 5) * 4, payload, length);
+ }
+
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_iphdr = 1;
+
+ if (pcaplist->pcap_thread->callback_ipv4)
+ pcaplist->pcap_thread->callback_ipv4(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ipv4((void*)pcaplist, packet, payload, length);
+ return;
+ } else if (packet->iphdr.ip_v == 6) {
+ /*
+ * Clear IPv4 headers and reverse reading one byte
+ */
+ packet->iphdr.ip_v = 0;
+ packet->iphdr.ip_hl = 0;
+ payload--;
+ length++;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_IPV6;
+ need32(packet->ip6hdr.ip6_flow, payload, length);
+ need16(packet->ip6hdr.ip6_plen, payload, length);
+ need8(packet->ip6hdr.ip6_nxt, payload, length);
+ need8(packet->ip6hdr.ip6_hlim, payload, length);
+ needxb(&(packet->ip6hdr.ip6_src), 16, payload, length);
+ needxb(&(packet->ip6hdr.ip6_dst), 16, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_ip6hdr = 1;
+
+ if (pcaplist->pcap_thread->callback_ipv6)
+ pcaplist->pcap_thread->callback_ipv6(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_ipv6((void*)pcaplist, packet, payload, length);
+ return;
+ }
+
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_ipv4(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+ int release_frag = 0;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (packet->have_iphdr) {
+ layer_trace("have_iphdr");
+
+ for (;;) {
+ /* Check reported length for missing payload or padding */
+ if (packet->iphdr.ip_len < (packet->iphdr.ip_hl * 4)) {
+ layer_trace("ip_len < ip header");
+ packet->state = PCAP_THREAD_PACKET_INVALID_IPV4;
+ break;
+ }
+ if (length < (packet->iphdr.ip_len - (packet->iphdr.ip_hl * 4))) {
+ layer_trace("length < (ip_len - ip header)");
+ packet->state = PCAP_THREAD_PACKET_INVALID_IPV4;
+ break;
+ }
+ if (length > (packet->iphdr.ip_len - (packet->iphdr.ip_hl * 4))) {
+ layer_trace("have_ippadding");
+ packet->ippadding = length - (packet->iphdr.ip_len - (packet->iphdr.ip_hl * 4));
+ packet->have_ippadding = 1;
+ length -= packet->ippadding;
+ }
+
+ /* Check if packet wants more fragments or has an offset */
+ if (packet->iphdr.ip_off & 0x2000 || packet->iphdr.ip_off & 0x1fff) {
+ layer_trace("is_v4_frag");
+
+ if (pcaplist->pcap_thread->callback_ipv4_frag.reassemble) {
+ pcap_thread_packet_t* whole_packet = 0;
+ const u_char* whole_payload = 0;
+ size_t whole_length = 0;
+
+ packet->state = pcaplist->pcap_thread->callback_ipv4_frag.reassemble(pcaplist->ipv4_frag_ctx, packet, payload, length, &whole_packet, &whole_payload, &whole_length);
+
+ /* Defragmentation failed some how, we return packet as invalid */
+ if (packet->state != PCAP_THREAD_PACKET_OK) {
+ break;
+ }
+
+ /* No whole/defragmented packet return, need more */
+ if (!whole_packet || !whole_payload || !whole_length) {
+ return;
+ }
+
+ layer_tracef("v4_reasm %p %p %lu", whole_packet, whole_payload, whole_length);
+
+ packet = whole_packet;
+ payload = whole_payload;
+ length = whole_length;
+ release_frag = 1;
+ } else {
+ /*
+ * Mark packet as fragment and send it to the next user
+ * layer (if any) or return it as invalid.
+ */
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+
+ switch (packet->iphdr.ip_p) {
+ case IPPROTO_GRE:
+ layer_trace("ipproto_gre frag");
+
+ if (!(packet->iphdr.ip_off & 0x1fff)) {
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_FRAGMENTED_GREHDR;
+ need16(packet->grehdr.gre_flags, payload, length);
+ need16(packet->grehdr.ether_type, payload, length);
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+ packet->have_grehdr = 1;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_gre) {
+ pcaplist->pcap_thread->callback_gre(pcaplist->user, packet, payload, length);
+ return;
+ }
+ break;
+
+ case IPPROTO_ICMP:
+ layer_trace("ipproto_icmp frag");
+
+ if (!(packet->iphdr.ip_off & 0x1fff)) {
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_FRAGMENTED_ICMPHDR;
+ need8(packet->icmphdr.type, payload, length);
+ need8(packet->icmphdr.code, payload, length);
+ need16(packet->icmphdr.checksum, payload, length);
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+ packet->have_icmphdr = 1;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_icmp) {
+ pcaplist->pcap_thread->callback_icmp(pcaplist->user, packet, payload, length);
+ return;
+ }
+ break;
+
+ case IPPROTO_UDP:
+ layer_trace("ipproto_udp frag");
+
+ if (!(packet->iphdr.ip_off & 0x1fff)) {
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_FRAGMENTED_UDPHDR;
+ need16(packet->udphdr.uh_sport, payload, length);
+ need16(packet->udphdr.uh_dport, payload, length);
+ need16(packet->udphdr.uh_ulen, payload, length);
+ need16(packet->udphdr.uh_sum, payload, length);
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+ packet->have_udphdr = 1;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_udp) {
+ pcaplist->pcap_thread->callback_udp(pcaplist->user, packet, payload, length);
+ return;
+ }
+ break;
+
+ case IPPROTO_TCP:
+ layer_trace("ipproto_tcp frag");
+
+ if (!(packet->iphdr.ip_off & 0x1fff)) {
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_FRAGMENTED_TCPHDR;
+ need16(packet->tcphdr.th_sport, payload, length);
+ need16(packet->tcphdr.th_dport, payload, length);
+ need32(packet->tcphdr.th_seq, payload, length);
+ need32(packet->tcphdr.th_ack, payload, length);
+ need4x2(packet->tcphdr.th_off, packet->tcphdr.th_x2, payload, length);
+ need8(packet->tcphdr.th_flags, payload, length);
+ need16(packet->tcphdr.th_win, payload, length);
+ need16(packet->tcphdr.th_sum, payload, length);
+ need16(packet->tcphdr.th_urp, payload, length);
+ if (packet->tcphdr.th_off > 5) {
+ packet->tcpopts_len = (packet->tcphdr.th_off - 5) * 4;
+ needxb(&(packet->tcpopts[0]), packet->tcpopts_len, payload, length);
+ packet->have_tcpopts = 1;
+ }
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+ packet->have_tcphdr = 1;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_tcp) {
+ pcaplist->pcap_thread->callback_tcp(pcaplist->user, packet, payload, length);
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ switch (packet->iphdr.ip_p) {
+ case IPPROTO_GRE:
+ layer_trace("ipproto_gre");
+
+ if (packet->have_grehdr)
+ break;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_GRE;
+ need16(packet->grehdr.gre_flags, payload, length);
+ need16(packet->grehdr.ether_type, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_grehdr = 1;
+
+ if (pcaplist->pcap_thread->callback_gre)
+ pcaplist->pcap_thread->callback_gre(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_gre((void*)pcaplist, packet, payload, length);
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv4_frag.release(pcaplist->ipv4_frag_ctx, packet, payload, length);
+ }
+ return;
+
+ case IPPROTO_ICMP:
+ layer_trace("ipproto_icmp");
+
+ if (packet->have_icmphdr)
+ break;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_ICMP;
+ need8(packet->icmphdr.type, payload, length);
+ need8(packet->icmphdr.code, payload, length);
+ need16(packet->icmphdr.checksum, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_icmphdr = 1;
+
+ if (pcaplist->pcap_thread->callback_icmp)
+ pcaplist->pcap_thread->callback_icmp(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_icmp((void*)pcaplist, packet, payload, length);
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv4_frag.release(pcaplist->ipv4_frag_ctx, packet, payload, length);
+ }
+ return;
+
+ case IPPROTO_UDP:
+ layer_trace("ipproto_udp");
+
+ if (packet->have_udphdr)
+ break;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_UDP;
+ need16(packet->udphdr.uh_sport, payload, length);
+ need16(packet->udphdr.uh_dport, payload, length);
+ need16(packet->udphdr.uh_ulen, payload, length);
+ need16(packet->udphdr.uh_sum, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_udphdr = 1;
+
+ if (pcaplist->pcap_thread->callback_udp)
+ pcaplist->pcap_thread->callback_udp(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_udp((void*)pcaplist, packet, payload, length);
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv4_frag.release(pcaplist->ipv4_frag_ctx, packet, payload, length);
+ }
+ return;
+
+ case IPPROTO_TCP:
+ layer_trace("ipproto_tcp");
+
+ if (packet->have_tcphdr)
+ break;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_TCP;
+ need16(packet->tcphdr.th_sport, payload, length);
+ need16(packet->tcphdr.th_dport, payload, length);
+ need32(packet->tcphdr.th_seq, payload, length);
+ need32(packet->tcphdr.th_ack, payload, length);
+ need4x2(packet->tcphdr.th_off, packet->tcphdr.th_x2, payload, length);
+ need8(packet->tcphdr.th_flags, payload, length);
+ need16(packet->tcphdr.th_win, payload, length);
+ need16(packet->tcphdr.th_sum, payload, length);
+ need16(packet->tcphdr.th_urp, payload, length);
+ if (packet->tcphdr.th_off > 5) {
+ packet->tcpopts_len = (packet->tcphdr.th_off - 5) * 4;
+ needxb(&(packet->tcpopts[0]), packet->tcpopts_len, payload, length);
+ packet->have_tcpopts = 1;
+ }
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_tcphdr = 1;
+
+ if (pcaplist->pcap_thread->callback_tcp)
+ pcaplist->pcap_thread->callback_tcp(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_tcp((void*)pcaplist, packet, payload, length);
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv4_frag.release(pcaplist->ipv4_frag_ctx, packet, payload, length);
+ }
+ return;
+
+ default:
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ if (release_frag)
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, payload, length);
+ else
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv4_frag.release(pcaplist->ipv4_frag_ctx, packet, payload, length);
+ }
+}
+
+static void pcap_thread_callback_ipv6(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+ int release_frag = 0;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ if (packet->have_ip6hdr) {
+ struct ip6_ext ext;
+ size_t already_advanced = 0;
+
+ layer_trace("have_ip6hdr");
+
+ /* Check reported length for missing payload or padding */
+ if (length < packet->ip6hdr.ip6_plen) {
+ layer_trace("length < ip6_plen");
+ packet->state = PCAP_THREAD_PACKET_INVALID_IPV6;
+ if (pcaplist->pcap_thread->callback_invalid) {
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+ return;
+ }
+ if (length > packet->ip6hdr.ip6_plen) {
+ layer_trace("have_ip6padding");
+ packet->ip6padding = length - packet->ip6hdr.ip6_plen;
+ packet->have_ip6padding = 1;
+ length -= packet->ip6padding;
+ }
+
+ ext.ip6e_nxt = packet->ip6hdr.ip6_nxt;
+ ext.ip6e_len = 0;
+ while (ext.ip6e_nxt != IPPROTO_NONE
+ && ext.ip6e_nxt != IPPROTO_GRE
+ && ext.ip6e_nxt != IPPROTO_ICMPV6
+ && ext.ip6e_nxt != IPPROTO_UDP
+ && ext.ip6e_nxt != IPPROTO_TCP) {
+ packet->state = PCAP_THREAD_PACKET_INVALID_IPV6HDR;
+
+ /*
+ * Advance to the start of next header, this may not be needed
+ * if it's the first header or if the header is supported.
+ */
+ if (ext.ip6e_len) {
+ if (ext.ip6e_len < already_advanced) {
+ /* Header length is invalid */
+ layer_trace("ip6hdr invalid");
+ break;
+ }
+ /* Advance if not already there */
+ else if (ext.ip6e_len > already_advanced) {
+ advancexb((ext.ip6e_len - already_advanced) * 8, payload, length);
+ }
+ already_advanced = 0;
+ } else if (already_advanced) {
+ /* Already advanced but header has no length */
+ layer_trace("ip6hdr already advanced");
+ break;
+ }
+
+ /* TODO: Store IPv6 headers? */
+
+ /* Handle supported headers */
+ if (ext.ip6e_nxt == IPPROTO_FRAGMENT) {
+ if (packet->have_ip6frag) {
+ layer_trace("dup ip6frag");
+ break;
+ }
+ layer_trace("ip6frag");
+ need8(ext.ip6e_nxt, payload, length);
+ need8(packet->ip6frag.ip6f_reserved, payload, length);
+ need16(packet->ip6frag.ip6f_offlg, payload, length);
+ need32(packet->ip6frag.ip6f_ident, payload, length);
+ packet->have_ip6frag = 1;
+ ext.ip6e_len = 1;
+ already_advanced = 1;
+ } else if (ext.ip6e_nxt == IPPROTO_ROUTING) {
+ struct ip6_rthdr rthdr;
+ struct in6_addr rt[255];
+
+ if (packet->have_ip6rtdst) {
+ layer_trace("dup ip6rtdst");
+ break;
+ }
+ need8(ext.ip6e_nxt, payload, length);
+ need8(ext.ip6e_len, payload, length);
+ need8(rthdr.ip6r_type, payload, length);
+ need8(rthdr.ip6r_segleft, payload, length);
+ if (!rthdr.ip6r_type) {
+ if (rthdr.ip6r_segleft > ext.ip6e_len)
+ break;
+ for (rthdr.ip6r_len = 0; rthdr.ip6r_len < ext.ip6e_len; rthdr.ip6r_len++, already_advanced += 2) {
+ needxb(&rt[rthdr.ip6r_len], 16, payload, length);
+ }
+ if (!rthdr.ip6r_len || rthdr.ip6r_len != ext.ip6e_len) {
+ break;
+ }
+ if (rthdr.ip6r_segleft) {
+ packet->ip6rtdst = rt[rthdr.ip6r_segleft];
+ packet->have_ip6rtdst = 1;
+ }
+ }
+ } else {
+ /* Nonsupported header */
+ layer_trace("ip6hdr?");
+ need8(ext.ip6e_nxt, payload, length);
+ need8(ext.ip6e_len, payload, length);
+ }
+
+ packet->state = PCAP_THREAD_PACKET_OK;
+
+ if (!ext.ip6e_len)
+ break;
+ }
+
+ for (; packet->state == PCAP_THREAD_PACKET_OK;) {
+ if (packet->have_ip6frag) {
+ packet->ip6frag_payload = ext.ip6e_nxt;
+
+ layer_trace("is_v6_frag");
+
+ if (pcaplist->pcap_thread->callback_ipv6_frag.reassemble) {
+ pcap_thread_packet_t* whole_packet = 0;
+ const u_char* whole_payload = 0;
+ size_t whole_length = 0;
+
+ packet->state = pcaplist->pcap_thread->callback_ipv6_frag.reassemble(pcaplist->ipv6_frag_ctx, packet, payload, length, &whole_packet, &whole_payload, &whole_length);
+
+ /* Defragmentation failed some how, we return packet as invalid */
+ if (packet->state != PCAP_THREAD_PACKET_OK) {
+ break;
+ }
+
+ /* No whole/defragmented packet return, need more */
+ if (!whole_packet || !whole_payload || !whole_length) {
+ return;
+ }
+
+ layer_tracef("v6_reasm %p %p %lu", whole_packet, whole_payload, whole_length);
+
+ packet = whole_packet;
+ payload = whole_payload;
+ length = whole_length;
+ release_frag = 1;
+ } else {
+ /*
+ * Mark packet as fragment and send it to the next user
+ * layer (if any) or return it as invalid.
+ */
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+
+ switch (ext.ip6e_nxt) {
+ case IPPROTO_GRE:
+ layer_trace("ipproto_gre frag");
+
+ if (!packet->ip6frag.ip6f_offlg) {
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_FRAGMENTED_GREHDR;
+ need16(packet->grehdr.gre_flags, payload, length);
+ need16(packet->grehdr.ether_type, payload, length);
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+ packet->have_grehdr = 1;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_gre) {
+ pcaplist->pcap_thread->callback_gre(pcaplist->user, packet, payload, length);
+ return;
+ }
+ break;
+
+ case IPPROTO_ICMPV6:
+ layer_trace("ipproto_icmpv6 frag");
+
+ if (!packet->ip6frag.ip6f_offlg) {
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_FRAGMENTED_ICMPV6HDR;
+ need8(packet->icmpv6hdr.icmp6_type, payload, length);
+ need8(packet->icmpv6hdr.icmp6_code, payload, length);
+ need16(packet->icmpv6hdr.icmp6_cksum, payload, length);
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+ packet->have_icmpv6hdr = 1;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_icmpv6) {
+ pcaplist->pcap_thread->callback_icmpv6(pcaplist->user, packet, payload, length);
+ return;
+ }
+ break;
+
+ case IPPROTO_UDP:
+ layer_trace("ipproto_udp frag");
+
+ if (!packet->ip6frag.ip6f_offlg) {
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_FRAGMENTED_UDPHDR;
+ need16(packet->udphdr.uh_sport, payload, length);
+ need16(packet->udphdr.uh_dport, payload, length);
+ need16(packet->udphdr.uh_ulen, payload, length);
+ need16(packet->udphdr.uh_sum, payload, length);
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+ packet->have_udphdr = 1;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_udp) {
+ pcaplist->pcap_thread->callback_udp(pcaplist->user, packet, payload, length);
+ return;
+ }
+ break;
+
+ case IPPROTO_TCP:
+ layer_trace("ipproto_tcp frag");
+
+ if (!packet->ip6frag.ip6f_offlg) {
+ for (;;) {
+ packet->state = PCAP_THREAD_PACKET_FRAGMENTED_TCPHDR;
+ need16(packet->tcphdr.th_sport, payload, length);
+ need16(packet->tcphdr.th_dport, payload, length);
+ need32(packet->tcphdr.th_seq, payload, length);
+ need32(packet->tcphdr.th_ack, payload, length);
+ need4x2(packet->tcphdr.th_off, packet->tcphdr.th_x2, payload, length);
+ need8(packet->tcphdr.th_flags, payload, length);
+ need16(packet->tcphdr.th_win, payload, length);
+ need16(packet->tcphdr.th_sum, payload, length);
+ need16(packet->tcphdr.th_urp, payload, length);
+ if (packet->tcphdr.th_off > 5) {
+ packet->tcpopts_len = (packet->tcphdr.th_off - 5) * 4;
+ needxb(&(packet->tcpopts[0]), packet->tcpopts_len, payload, length);
+ packet->have_tcpopts = 1;
+ }
+ packet->state = PCAP_THREAD_PACKET_IS_FRAGMENT;
+ packet->have_tcphdr = 1;
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_tcp) {
+ pcaplist->pcap_thread->callback_tcp(pcaplist->user, packet, payload, length);
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ switch (ext.ip6e_nxt) {
+ case IPPROTO_GRE:
+ if (packet->have_grehdr)
+ break;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_GRE;
+ need16(packet->grehdr.gre_flags, payload, length);
+ need16(packet->grehdr.ether_type, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_grehdr = 1;
+
+ if (pcaplist->pcap_thread->callback_gre)
+ pcaplist->pcap_thread->callback_gre(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_gre((void*)pcaplist, packet, payload, length);
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv6_frag.release(pcaplist->ipv6_frag_ctx, packet, payload, length);
+ }
+ return;
+
+ case IPPROTO_ICMPV6:
+ layer_trace("ipproto_icmpv6");
+
+ if (packet->have_icmpv6hdr)
+ break;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_ICMPV6;
+ need8(packet->icmpv6hdr.icmp6_type, payload, length);
+ need8(packet->icmpv6hdr.icmp6_code, payload, length);
+ need16(packet->icmpv6hdr.icmp6_cksum, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_icmpv6hdr = 1;
+
+ if (pcaplist->pcap_thread->callback_icmpv6)
+ pcaplist->pcap_thread->callback_icmpv6(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_icmpv6((void*)pcaplist, packet, payload, length);
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv6_frag.release(pcaplist->ipv6_frag_ctx, packet, payload, length);
+ }
+ return;
+
+ case IPPROTO_UDP:
+ if (packet->have_udphdr)
+ break;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_UDP;
+ need16(packet->udphdr.uh_sport, payload, length);
+ need16(packet->udphdr.uh_dport, payload, length);
+ need16(packet->udphdr.uh_ulen, payload, length);
+ need16(packet->udphdr.uh_sum, payload, length);
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_udphdr = 1;
+
+ if (pcaplist->pcap_thread->callback_udp)
+ pcaplist->pcap_thread->callback_udp(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_udp((void*)pcaplist, packet, payload, length);
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv6_frag.release(pcaplist->ipv6_frag_ctx, packet, payload, length);
+ }
+ return;
+
+ case IPPROTO_TCP:
+ if (packet->have_tcphdr)
+ break;
+
+ packet->state = PCAP_THREAD_PACKET_INVALID_TCP;
+ need16(packet->tcphdr.th_sport, payload, length);
+ need16(packet->tcphdr.th_dport, payload, length);
+ need32(packet->tcphdr.th_seq, payload, length);
+ need32(packet->tcphdr.th_ack, payload, length);
+ need4x2(packet->tcphdr.th_off, packet->tcphdr.th_x2, payload, length);
+ need8(packet->tcphdr.th_flags, payload, length);
+ need16(packet->tcphdr.th_win, payload, length);
+ need16(packet->tcphdr.th_sum, payload, length);
+ need16(packet->tcphdr.th_urp, payload, length);
+ if (packet->tcphdr.th_off > 5) {
+ packet->tcpopts_len = (packet->tcphdr.th_off - 5) * 4;
+ needxb(&(packet->tcpopts[0]), packet->tcpopts_len, payload, length);
+ packet->have_tcpopts = 1;
+ }
+ packet->state = PCAP_THREAD_PACKET_OK;
+ packet->have_tcphdr = 1;
+
+ if (pcaplist->pcap_thread->callback_tcp)
+ pcaplist->pcap_thread->callback_tcp(pcaplist->user, packet, payload, length);
+ else
+ pcap_thread_callback_tcp((void*)pcaplist, packet, payload, length);
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv6_frag.release(pcaplist->ipv6_frag_ctx, packet, payload, length);
+ }
+ return;
+
+ default:
+ packet->state = PCAP_THREAD_PACKET_UNSUPPORTED;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ if (release_frag)
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, payload, length);
+ else
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+
+ if (release_frag) {
+ pcaplist->pcap_thread->callback_ipv6_frag.release(pcaplist->ipv6_frag_ctx, packet, payload, length);
+ }
+}
+
+static void pcap_thread_callback_icmp(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ /* TODO: Higher layer support? */
+ packet->state = PCAP_THREAD_PACKET_UNPROCESSED;
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_icmpv6(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ /* TODO: Higher layer support? */
+ packet->state = PCAP_THREAD_PACKET_UNPROCESSED;
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_udp(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ /* TODO: Higher layer support? */
+ packet->state = PCAP_THREAD_PACKET_UNPROCESSED;
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+static void pcap_thread_callback_tcp(u_char* user, pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ pcap_thread_pcaplist_t* pcaplist = (pcap_thread_pcaplist_t*)user;
+ const u_char* orig = payload;
+ size_t origlength = length;
+
+ if (!pcaplist) {
+ return;
+ }
+ if (!pcaplist->pcap_thread) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (!payload) {
+ return;
+ }
+ if (!length) {
+ return;
+ }
+
+ /* TODO: Higher layer support? */
+ packet->state = PCAP_THREAD_PACKET_UNPROCESSED;
+
+ if (pcaplist->pcap_thread->callback_invalid) {
+ if (packet->state == PCAP_THREAD_PACKET_OK)
+ packet->state = PCAP_THREAD_PACKET_INVALID;
+ pcaplist->pcap_thread->callback_invalid(pcaplist->user, packet, orig, origlength);
+ }
+}
+
+/*
+ * Open/Close
+ */
+
+static pcap_thread_pcaplist_t _pcaplist_defaults = PCAP_THREAD_PCAPLIST_T_INIT;
+
+int pcap_thread_open(pcap_thread_t* pcap_thread, const char* device, void* user)
+{
+ pcap_t* pcap;
+ pcap_thread_pcaplist_t* pcaplist;
+ int snapshot;
+
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!device) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ if (pcap_thread->errbuf[0]) {
+ memset(pcap_thread->errbuf, 0, sizeof(pcap_thread->errbuf));
+ }
+ pcap_thread->status = 0;
+
+ if (!(pcaplist = malloc(sizeof(pcap_thread_pcaplist_t)))) {
+ return PCAP_THREAD_ENOMEM;
+ }
+ memcpy(pcaplist, &_pcaplist_defaults, sizeof(pcap_thread_pcaplist_t));
+ if (!(pcaplist->name = strdup(device))) {
+ free(pcaplist);
+ return PCAP_THREAD_ENOMEM;
+ }
+
+#ifdef HAVE_PCAP_CREATE
+ if (!(pcap = pcap_create(pcaplist->name, pcap_thread->errbuf))) {
+ free(pcaplist->name);
+ free(pcaplist);
+ return PCAP_THREAD_EPCAP;
+ }
+
+ if (pcap_thread->monitor) {
+ pcap_thread->status = pcap_can_set_rfmon(pcap);
+ if (pcap_thread->status == 0) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ return PCAP_THREAD_ENOMON;
+ }
+ if (pcap_thread->status != 1) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_can_set_rfmon()");
+ return PCAP_THREAD_EPCAP;
+ }
+ }
+
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+ if (pcap_thread->have_timestamp_precision && (pcap_thread->status = pcap_set_tstamp_precision(pcap, pcap_thread->timestamp_precision))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_set_tstamp_precision()");
+ return PCAP_THREAD_EPCAP;
+ }
+#endif
+#ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
+ if (pcap_thread->immediate_mode && (pcap_thread->status = pcap_set_immediate_mode(pcap, 1))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_set_immediate_mode()");
+ return PCAP_THREAD_EPCAP;
+ }
+#endif
+
+ if (pcap_thread->monitor && (pcap_thread->status = pcap_set_rfmon(pcap, 1))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_set_rfmon()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (pcap_thread->snaplen && (pcap_thread->status = pcap_set_snaplen(pcap, pcap_thread->snaplen))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_set_snaplen()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (pcap_thread->promiscuous && (pcap_thread->status = pcap_set_promisc(pcap, pcap_thread->promiscuous))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_set_promisc()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (pcap_thread->timeout && (pcap_thread->status = pcap_set_timeout(pcap, pcap_thread->timeout))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_set_timeout()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (pcap_thread->buffer_size && (pcap_thread->status = pcap_set_buffer_size(pcap, pcap_thread->buffer_size))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_set_buffer_size()");
+ return PCAP_THREAD_EPCAP;
+ }
+
+#ifdef HAVE_PCAP_SET_TSTAMP_TYPE
+ if (pcap_thread->have_timestamp_type && (pcap_thread->status = pcap_set_tstamp_type(pcap, pcap_thread->timestamp_type))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_set_tstamp_type()");
+ return PCAP_THREAD_EPCAP;
+ }
+#endif
+
+ if (pcap_thread->activate_mode == PCAP_THREAD_ACTIVATE_MODE_IMMEDIATE) {
+ if ((pcap_thread->status = pcap_activate(pcap))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_activate()");
+ return PCAP_THREAD_EPCAP;
+ }
+
+#ifdef HAVE_PCAP_SETDIRECTION
+#ifdef HAVE_PCAP_DIRECTION_T
+ if (pcap_thread->have_direction && (pcap_thread->status = pcap_setdirection(pcap, pcap_thread->direction))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_setdirection()");
+ return PCAP_THREAD_EPCAP;
+ }
+#endif
+#endif
+ }
+#else /* HAVE_PCAP_CREATE */
+ if (!(pcap = pcap_open_live(pcaplist->name, pcap_thread->snaplen, pcap_thread->promiscuous, pcap_thread->timeout, pcap_thread->errbuf))) {
+ free(pcaplist->name);
+ free(pcaplist);
+ return PCAP_THREAD_EPCAP;
+ }
+#endif
+
+ if (pcap_thread->activate_mode == PCAP_THREAD_ACTIVATE_MODE_IMMEDIATE) {
+ if (pcap_thread->filter) {
+ if ((pcap_thread->status = pcap_compile(pcap, &(pcaplist->bpf), pcap_thread->filter, pcap_thread->filter_optimize, pcap_thread->filter_netmask))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_compile()");
+ return PCAP_THREAD_EPCAP;
+ }
+ pcaplist->have_bpf = 1;
+ pcap_thread->filter_errno = 0;
+ errno = 0;
+ if ((pcap_thread->status = pcap_setfilter(pcap, &(pcaplist->bpf)))) {
+ pcap_freecode(&(pcaplist->bpf));
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_setfilter()");
+ return PCAP_THREAD_EPCAP;
+ }
+ pcap_thread->filter_errno = errno;
+ }
+
+ if ((snapshot = pcap_snapshot(pcap)) < 0) {
+ pcap_thread->status = snapshot;
+ if (pcaplist->have_bpf)
+ pcap_freecode(&(pcaplist->bpf));
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_snapshot()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (snapshot > pcap_thread->snapshot) {
+ pcap_thread->snapshot = snapshot;
+ }
+ }
+
+ pcaplist->pcap = pcap;
+ pcaplist->user = user;
+ if (pcap_thread->callback_ipv4_frag.new) {
+ pcaplist->ipv4_frag_ctx = pcap_thread->callback_ipv4_frag.new(pcap_thread->callback_ipv4_frag.conf, user);
+ pcaplist->have_ipv4_frag_ctx = 1;
+ }
+ if (pcap_thread->callback_ipv6_frag.new) {
+ pcaplist->ipv6_frag_ctx = pcap_thread->callback_ipv6_frag.new(pcap_thread->callback_ipv6_frag.conf, user);
+ pcaplist->have_ipv6_frag_ctx = 1;
+ }
+ if (pcap_thread->pcaplist) {
+ pcaplist->next = pcap_thread->pcaplist;
+ }
+ pcap_thread->pcaplist = pcaplist;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_open_offline(pcap_thread_t* pcap_thread, const char* file, void* user)
+{
+ pcap_t* pcap;
+ pcap_thread_pcaplist_t* pcaplist;
+ int snapshot;
+
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!file) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ if (pcap_thread->errbuf[0]) {
+ memset(pcap_thread->errbuf, 0, sizeof(pcap_thread->errbuf));
+ }
+ pcap_thread->status = 0;
+
+ if (!(pcaplist = malloc(sizeof(pcap_thread_pcaplist_t)))) {
+ return PCAP_THREAD_ENOMEM;
+ }
+ memcpy(pcaplist, &_pcaplist_defaults, sizeof(pcap_thread_pcaplist_t));
+ pcaplist->is_offline = 1;
+ if (!(pcaplist->name = strdup(file))) {
+ free(pcaplist);
+ return PCAP_THREAD_ENOMEM;
+ }
+
+#ifdef HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION
+ if (pcap_thread->have_timestamp_precision) {
+ if (!(pcap = pcap_open_offline_with_tstamp_precision(pcaplist->name, pcap_thread->timestamp_precision, pcap_thread->errbuf))) {
+ free(pcaplist->name);
+ free(pcaplist);
+ return PCAP_THREAD_EPCAP;
+ }
+ } else
+#endif
+ {
+ if (!(pcap = pcap_open_offline(pcaplist->name, pcap_thread->errbuf))) {
+ free(pcaplist->name);
+ free(pcaplist);
+ return PCAP_THREAD_EPCAP;
+ }
+ }
+
+ if (pcap_thread->filter) {
+ if ((pcap_thread->status = pcap_compile(pcap, &(pcaplist->bpf), pcap_thread->filter, pcap_thread->filter_optimize, pcap_thread->filter_netmask))) {
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_compile()");
+ return PCAP_THREAD_EPCAP;
+ }
+ pcaplist->have_bpf = 1;
+ pcap_thread->filter_errno = 0;
+ errno = 0;
+ if ((pcap_thread->status = pcap_setfilter(pcap, &(pcaplist->bpf)))) {
+ pcap_freecode(&(pcaplist->bpf));
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_setfilter()");
+ return PCAP_THREAD_EPCAP;
+ }
+ pcap_thread->filter_errno = errno;
+ }
+
+ if ((snapshot = pcap_snapshot(pcap)) < 0) {
+ pcap_thread->status = snapshot;
+ if (pcaplist->have_bpf)
+ pcap_freecode(&(pcaplist->bpf));
+ pcap_close(pcap);
+ free(pcaplist->name);
+ free(pcaplist);
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_snapshot()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (snapshot > pcap_thread->snapshot) {
+ pcap_thread->snapshot = snapshot;
+ }
+
+ pcaplist->pcap = pcap;
+ pcaplist->user = user;
+ if (pcap_thread->callback_ipv4_frag.new) {
+ pcaplist->ipv4_frag_ctx = pcap_thread->callback_ipv4_frag.new(pcap_thread->callback_ipv4_frag.conf, user);
+ pcaplist->have_ipv4_frag_ctx = 1;
+ }
+ if (pcap_thread->callback_ipv6_frag.new) {
+ pcaplist->ipv6_frag_ctx = pcap_thread->callback_ipv6_frag.new(pcap_thread->callback_ipv6_frag.conf, user);
+ pcaplist->have_ipv6_frag_ctx = 1;
+ }
+ if (pcap_thread->pcaplist) {
+ pcaplist->next = pcap_thread->pcaplist;
+ }
+ pcap_thread->pcaplist = pcaplist;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_add(pcap_thread_t* pcap_thread, const char* name, pcap_t* pcap, void* user)
+{
+ (void)pcap_thread;
+ (void)name;
+ (void)pcap;
+ (void)user;
+
+ if (pcap_thread->errbuf[0]) {
+ memset(pcap_thread->errbuf, 0, sizeof(pcap_thread->errbuf));
+ }
+ pcap_thread->status = 0;
+
+ return PCAP_THREAD_EOBSOLETE;
+}
+
+int pcap_thread_activate(pcap_thread_t* pcap_thread)
+{
+ pcap_thread_pcaplist_t* pcaplist;
+ int snapshot;
+
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ if (pcap_thread->errbuf[0]) {
+ memset(pcap_thread->errbuf, 0, sizeof(pcap_thread->errbuf));
+ }
+ pcap_thread->status = 0;
+
+ pcap_thread->filter_errno = 0;
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ if (pcaplist->is_offline) {
+ continue;
+ }
+
+#ifdef HAVE_PCAP_ACTIVATE
+ if ((pcap_thread->status = pcap_activate(pcaplist->pcap))) {
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_activate()");
+ return PCAP_THREAD_EPCAP;
+ }
+#endif
+
+#ifdef HAVE_PCAP_SETDIRECTION
+#ifdef HAVE_PCAP_DIRECTION_T
+ if (pcap_thread->have_direction && (pcap_thread->status = pcap_setdirection(pcaplist->pcap, pcap_thread->direction))) {
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_setdirection()");
+ return PCAP_THREAD_EPCAP;
+ }
+#endif
+#endif
+
+ if (pcap_thread->filter) {
+ if (pcaplist->have_bpf)
+ pcap_freecode(&(pcaplist->bpf));
+ if ((pcap_thread->status = pcap_compile(pcaplist->pcap, &(pcaplist->bpf), pcap_thread->filter, pcap_thread->filter_optimize, pcap_thread->filter_netmask))) {
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_compile()");
+ return PCAP_THREAD_EPCAP;
+ }
+ pcaplist->have_bpf = 1;
+ errno = 0;
+ if ((pcap_thread->status = pcap_setfilter(pcaplist->pcap, &(pcaplist->bpf)))) {
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_setfilter()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (errno && !pcap_thread->filter_errno)
+ pcap_thread->filter_errno = errno;
+ }
+
+ if ((snapshot = pcap_snapshot(pcaplist->pcap)) < 0) {
+ pcap_thread->status = snapshot;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_snapshot()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (snapshot > pcap_thread->snapshot) {
+ pcap_thread->snapshot = snapshot;
+ }
+ }
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_close(pcap_thread_t* pcap_thread)
+{
+ pcap_thread_pcaplist_t* pcaplist;
+
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ while (pcap_thread->pcaplist) {
+ pcaplist = pcap_thread->pcaplist;
+ pcap_thread->pcaplist = pcaplist->next;
+
+ if (pcap_thread->callback_ipv4_frag.free && pcaplist->have_ipv4_frag_ctx) {
+ pcap_thread->callback_ipv4_frag.free(pcaplist->ipv4_frag_ctx);
+ }
+ if (pcap_thread->callback_ipv6_frag.free && pcaplist->have_ipv6_frag_ctx) {
+ pcap_thread->callback_ipv6_frag.free(pcaplist->ipv6_frag_ctx);
+ }
+
+ if (pcaplist->pcap) {
+ pcap_close(pcaplist->pcap);
+ }
+ if (pcaplist->have_bpf) {
+ pcap_freecode(&(pcaplist->bpf));
+ }
+ if (pcaplist->name) {
+ free(pcaplist->name);
+ }
+ free(pcaplist);
+ }
+ pcap_thread->step = 0;
+
+#ifdef HAVE_PTHREAD
+ if (pcap_thread->pkthdr) {
+ free(pcap_thread->pkthdr);
+ pcap_thread->pkthdr = 0;
+ }
+ if (pcap_thread->pkt) {
+ free(pcap_thread->pkt);
+ pcap_thread->pkt = 0;
+ }
+ if (pcap_thread->pcaplist_pkt) {
+ free(pcap_thread->pcaplist_pkt);
+ pcap_thread->pcaplist_pkt = 0;
+ }
+#endif
+
+ return PCAP_THREAD_OK;
+}
+
+/*
+ * Engine
+ */
+
+#ifdef HAVE_PTHREAD
+static void _callback(u_char* user, const struct pcap_pkthdr* pkthdr, const u_char* pkt)
+{
+ pcap_thread_pcaplist_t* pcaplist;
+ pcap_thread_t* pcap_thread;
+
+ pthread_testcancel();
+
+ if (!user) {
+ return;
+ }
+ pcaplist = (pcap_thread_pcaplist_t*)user;
+
+ if (!pcaplist->pcap_thread) {
+ pcaplist->running = 0;
+ return;
+ }
+ pcap_thread = pcaplist->pcap_thread;
+
+ if (pkthdr->caplen > pcap_thread->snapshot) {
+ if (pcap_thread->dropback) {
+ pcap_thread->dropback(pcaplist->user, pkthdr, pkt, pcaplist->name, pcap_datalink(pcaplist->pcap));
+ }
+ return;
+ }
+
+ if (pcap_thread->queue_mode == PCAP_THREAD_QUEUE_MODE_DIRECT) {
+ if (pcap_thread->callback) {
+ pcap_thread->callback(pcaplist->user, pkthdr, pkt, pcaplist->name, pcap_datalink(pcaplist->pcap));
+ } else if (pcaplist->layer_callback) {
+ pcaplist->layer_callback((void*)pcaplist, pkthdr, pkt, pcaplist->name, pcap_datalink(pcaplist->pcap));
+ } else if (pcap_thread->dropback) {
+ pcap_thread->dropback(pcaplist->user, pkthdr, pkt, pcaplist->name, pcap_datalink(pcaplist->pcap));
+ }
+ return;
+ }
+
+ if (pthread_mutex_lock(&(pcap_thread->mutex))) {
+ if (pcap_thread->dropback) {
+ pcap_thread->dropback(pcaplist->user, pkthdr, pkt, pcaplist->name, pcap_datalink(pcaplist->pcap));
+ }
+ return;
+ }
+
+ while (pcaplist->running && pcap_thread->running) {
+ if (pcap_thread->pkts < pcap_thread->queue_size) {
+ pcap_thread->pcaplist_pkt[pcap_thread->write_pos] = pcaplist;
+ memcpy(&(pcap_thread->pkthdr[pcap_thread->write_pos]), pkthdr, sizeof(struct pcap_pkthdr));
+ memcpy(&(pcap_thread->pkt[pcap_thread->write_pos * pcap_thread->snapshot]), pkt, pkthdr->caplen);
+ pcap_thread->write_pos++;
+ if (pcap_thread->write_pos == pcap_thread->queue_size) {
+ pcap_thread->write_pos = 0;
+ }
+ pcap_thread->pkts++;
+
+ pthread_cond_signal(&(pcap_thread->have_packets));
+ break;
+ }
+
+ if (pthread_cond_wait(&(pcap_thread->can_write), &(pcap_thread->mutex))) {
+ pcaplist->running = 0;
+ pcap_breakloop(pcaplist->pcap);
+ return;
+ }
+ continue;
+ }
+
+ if (pthread_mutex_unlock(&(pcap_thread->mutex))) {
+ pcaplist->running = 0;
+ pcap_breakloop(pcaplist->pcap);
+ return;
+ }
+}
+
+static void* _thread(void* vp)
+{
+ pcap_thread_pcaplist_t* pcaplist;
+ int ret = 0;
+
+ /*pthread_detach(pthread_self());*/
+
+ if (!vp) {
+ return 0;
+ }
+ pcaplist = (pcap_thread_pcaplist_t*)vp;
+
+ if (!pcaplist->pcap_thread) {
+ pcaplist->running = 0;
+ return 0;
+ }
+
+ /*
+ * pcap_loop() might return -2 to indicate pcap_breakloop() was called
+ * but we do not need to act on that because either this thread has
+ * been cancelled or running has been cleared
+ */
+ while (pcaplist->running) {
+ pthread_testcancel();
+ ret = pcap_loop(pcaplist->pcap, -1, _callback, (u_char*)pcaplist);
+ if (ret == -1) {
+ /* TODO: Store pcap_loop() error */
+ break;
+ }
+ if (!ret)
+ break;
+ }
+
+ pcaplist->running = 0;
+
+ pthread_mutex_lock(&(pcaplist->pcap_thread->mutex));
+ pthread_cond_signal(&(pcaplist->pcap_thread->have_packets));
+ pthread_mutex_unlock(&(pcaplist->pcap_thread->mutex));
+
+ return 0;
+}
+#endif
+
+static void _callback2(u_char* user, const struct pcap_pkthdr* pkthdr, const u_char* pkt)
+{
+ pcap_thread_pcaplist_t* pcaplist;
+
+ if (!user) {
+ return;
+ }
+ pcaplist = (pcap_thread_pcaplist_t*)user;
+
+ if (!pcaplist->pcap_thread) {
+ pcaplist->running = 0;
+ return;
+ }
+ if (pcaplist->pcap_thread->callback) {
+ pcaplist->pcap_thread->callback(pcaplist->user, pkthdr, pkt, pcaplist->name, pcap_datalink(pcaplist->pcap));
+ } else if (pcaplist->layer_callback) {
+ pcaplist->layer_callback((void*)pcaplist, pkthdr, pkt, pcaplist->name, pcap_datalink(pcaplist->pcap));
+ } else {
+ pcaplist->running = 0;
+ }
+}
+
+int pcap_thread_run(pcap_thread_t* pcap_thread)
+{
+ pcap_thread_pcaplist_t* pcaplist;
+ int run = 1, timedrun = 0;
+ struct timeval start = { 0, 0 };
+ struct timespec end = { 0, 0 };
+
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!pcap_thread->pcaplist) {
+ return PCAP_THREAD_NOPCAPS;
+ }
+ if (!pcap_thread->callback && !pcap_thread->use_layers) {
+ return PCAP_THREAD_NOCALLBACK;
+ }
+ if (pcap_thread->use_layers
+ && !(pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp)) {
+ return PCAP_THREAD_NOCALLBACK;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ if (pcap_thread->errbuf[0]) {
+ memset(pcap_thread->errbuf, 0, sizeof(pcap_thread->errbuf));
+ }
+ pcap_thread->status = 0;
+
+ if (pcap_thread->timedrun.tv_sec || pcap_thread->timedrun.tv_usec) {
+ timedrun = 1;
+ if (gettimeofday(&start, 0)) {
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "gettimeofday()");
+ return PCAP_THREAD_ERRNO;
+ }
+
+ end.tv_sec = start.tv_sec + pcap_thread->timedrun.tv_sec
+ + ((start.tv_usec + pcap_thread->timedrun.tv_usec) / 1000000);
+ end.tv_nsec = ((start.tv_usec + pcap_thread->timedrun.tv_usec) % 1000000) * 1000;
+ } else if (pcap_thread->timedrun_to.tv_sec) {
+ timedrun = 1;
+
+ end.tv_sec = pcap_thread->timedrun_to.tv_sec;
+ end.tv_nsec = pcap_thread->timedrun_to.tv_usec * 1000;
+ }
+
+#ifdef HAVE_PTHREAD
+ if (pcap_thread->use_threads) {
+ int err, all_offline;
+
+ switch (pcap_thread->queue_mode) {
+ case PCAP_THREAD_QUEUE_MODE_COND:
+ case PCAP_THREAD_QUEUE_MODE_DIRECT:
+ if ((err = pthread_mutex_lock(&(pcap_thread->mutex)))) {
+ errno = err;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pthread_mutex_lock()");
+ return PCAP_THREAD_ERRNO;
+ }
+ break;
+ case PCAP_THREAD_QUEUE_MODE_WAIT:
+ case PCAP_THREAD_QUEUE_MODE_YIELD:
+ case PCAP_THREAD_QUEUE_MODE_DROP:
+ return PCAP_THREAD_EOBSOLETE;
+ default:
+ return PCAP_THREAD_EINVAL;
+ }
+
+ if (pcap_thread->running) {
+ pthread_mutex_unlock(&(pcap_thread->mutex));
+ return PCAP_THREAD_ERUNNING;
+ }
+
+ if (pcap_thread->pkthdr) {
+ free(pcap_thread->pkthdr);
+ }
+ if (!(pcap_thread->pkthdr = calloc(pcap_thread->queue_size, sizeof(struct pcap_pkthdr)))) {
+ pthread_mutex_unlock(&(pcap_thread->mutex));
+ return PCAP_THREAD_ENOMEM;
+ }
+
+ if (pcap_thread->pkt) {
+ free(pcap_thread->pkt);
+ }
+ if (!(pcap_thread->pkt = calloc(pcap_thread->queue_size, pcap_thread->snapshot))) {
+ pthread_mutex_unlock(&(pcap_thread->mutex));
+ return PCAP_THREAD_ENOMEM;
+ }
+
+ if (pcap_thread->pcaplist_pkt) {
+ free(pcap_thread->pcaplist_pkt);
+ }
+ if (!(pcap_thread->pcaplist_pkt = calloc(pcap_thread->queue_size, sizeof(pcap_thread_pcaplist_t*)))) {
+ pthread_mutex_unlock(&(pcap_thread->mutex));
+ return PCAP_THREAD_ENOMEM;
+ }
+
+ pcap_thread->read_pos = 0;
+ pcap_thread->write_pos = 0;
+ pcap_thread->pkts = 0;
+
+ all_offline = 1;
+ for (pcaplist = pcap_thread->pcaplist; all_offline && pcaplist; pcaplist = pcaplist->next) {
+ if (!pcaplist->is_offline) {
+ all_offline = 0;
+ break;
+ }
+ }
+
+ pcap_thread->running = 1;
+ pcap_thread->was_stopped = 0;
+ err = PCAP_THREAD_OK;
+
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ pcaplist->pcap_thread = pcap_thread;
+ if (pcap_thread->use_layers) {
+ pcaplist->layer_callback = &pcap_thread_callback;
+ }
+ if (pcap_thread->callback_ipv4_frag.new && !pcaplist->have_ipv4_frag_ctx) {
+ pcaplist->ipv4_frag_ctx = pcap_thread->callback_ipv4_frag.new(pcap_thread->callback_ipv4_frag.conf, pcaplist->user);
+ pcaplist->have_ipv4_frag_ctx = 1;
+ }
+ if (pcap_thread->callback_ipv6_frag.new && !pcaplist->have_ipv6_frag_ctx) {
+ pcaplist->ipv6_frag_ctx = pcap_thread->callback_ipv6_frag.new(pcap_thread->callback_ipv6_frag.conf, pcaplist->user);
+ pcaplist->have_ipv6_frag_ctx = 1;
+ }
+ pcaplist->running = 1;
+
+ if ((err = pthread_create(&(pcaplist->thread), 0, _thread, (void*)pcaplist))) {
+ errno = err;
+ err = PCAP_THREAD_ERRNO;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pthread_create()");
+ break;
+ }
+ }
+
+ while (err == PCAP_THREAD_OK && run && pcap_thread->running) {
+ while (pcap_thread->pkts) {
+ if (!pcap_thread->pcaplist_pkt[pcap_thread->read_pos]) {
+ err = PCAP_THREAD_ENOPCAPLIST;
+ break;
+ }
+
+ if (pcap_thread->callback) {
+ pcap_thread->callback(
+ pcap_thread->pcaplist_pkt[pcap_thread->read_pos]->user,
+ &(pcap_thread->pkthdr[pcap_thread->read_pos]),
+ &(pcap_thread->pkt[pcap_thread->read_pos * pcap_thread->snapshot]),
+ pcap_thread->pcaplist_pkt[pcap_thread->read_pos]->name,
+ pcap_datalink(pcap_thread->pcaplist_pkt[pcap_thread->read_pos]->pcap));
+ } else {
+ pcap_thread_callback(
+ (void*)pcap_thread->pcaplist_pkt[pcap_thread->read_pos],
+ &(pcap_thread->pkthdr[pcap_thread->read_pos]),
+ &(pcap_thread->pkt[pcap_thread->read_pos * pcap_thread->snapshot]),
+ pcap_thread->pcaplist_pkt[pcap_thread->read_pos]->name,
+ pcap_datalink(pcap_thread->pcaplist_pkt[pcap_thread->read_pos]->pcap));
+ }
+
+ pcap_thread->pcaplist_pkt[pcap_thread->read_pos] = 0;
+ pcap_thread->read_pos++;
+ if (pcap_thread->read_pos == pcap_thread->queue_size) {
+ pcap_thread->read_pos = 0;
+ }
+ pcap_thread->pkts--;
+ }
+
+ if (err != PCAP_THREAD_OK)
+ break;
+
+ if ((err = pthread_cond_broadcast(&(pcap_thread->can_write)))) {
+ errno = err;
+ err = PCAP_THREAD_ERRNO;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pthread_cond_broadcast()");
+ break;
+ }
+
+ run = 0;
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ if (pcaplist->running) {
+ run = 1;
+ }
+ }
+ if (!run)
+ break;
+
+ if (timedrun) {
+ struct timeval now;
+
+ if (gettimeofday(&now, 0)) {
+ err = PCAP_THREAD_ERRNO;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "gettimeofday()");
+ break;
+ }
+
+ if (now.tv_sec > end.tv_sec
+ || (now.tv_sec == end.tv_sec && (now.tv_usec * 1000) >= end.tv_nsec)) {
+ break;
+ }
+
+ err = pthread_cond_timedwait(&(pcap_thread->have_packets), &(pcap_thread->mutex), &end);
+ if (err == ETIMEDOUT) {
+ err = PCAP_THREAD_OK;
+ } else if (err) {
+ errno = err;
+ err = PCAP_THREAD_ERRNO;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pthread_cond_timedwait()");
+ break;
+ }
+ } else {
+ if ((err = pthread_cond_wait(&(pcap_thread->have_packets), &(pcap_thread->mutex)))) {
+ errno = err;
+ err = PCAP_THREAD_ERRNO;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pthread_cond_wait()");
+ break;
+ }
+ }
+ }
+
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ pcaplist->running = 0;
+ pcap_breakloop(pcaplist->pcap);
+ if (pcaplist->thread) {
+ pthread_cancel(pcaplist->thread);
+ }
+ }
+
+ pthread_mutex_unlock(&(pcap_thread->mutex));
+
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ if (pcaplist->thread) {
+ pthread_join(pcaplist->thread, 0);
+ pcaplist->thread = 0;
+ }
+ }
+
+ pcap_thread->running = 0;
+ return err;
+ } else
+#endif
+ {
+ fd_set fds, rfds;
+ int max_fd = 0;
+ struct timeval t1, t2;
+
+ pcap_thread->running = 1;
+ pcap_thread->was_stopped = 0;
+
+ FD_ZERO(&fds);
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ int fd = pcap_get_selectable_fd(pcaplist->pcap);
+
+ FD_SET(fd, &fds);
+ if (fd > max_fd)
+ max_fd = fd;
+
+ if (!pcaplist->is_offline && (pcap_thread->status = pcap_setnonblock(pcaplist->pcap, 1, pcap_thread->errbuf))) {
+ pcap_thread->running = 0;
+ return PCAP_THREAD_EPCAP;
+ }
+ pcaplist->pcap_thread = pcap_thread;
+ if (pcap_thread->use_layers) {
+ pcaplist->layer_callback = &pcap_thread_callback;
+ }
+ if (pcap_thread->callback_ipv4_frag.new && !pcaplist->have_ipv4_frag_ctx) {
+ pcaplist->ipv4_frag_ctx = pcap_thread->callback_ipv4_frag.new(pcap_thread->callback_ipv4_frag.conf, pcaplist->user);
+ pcaplist->have_ipv4_frag_ctx = 1;
+ }
+ if (pcap_thread->callback_ipv6_frag.new && !pcaplist->have_ipv6_frag_ctx) {
+ pcaplist->ipv6_frag_ctx = pcap_thread->callback_ipv6_frag.new(pcap_thread->callback_ipv6_frag.conf, pcaplist->user);
+ pcaplist->have_ipv6_frag_ctx = 1;
+ }
+ pcaplist->running = 1;
+ }
+
+ t1.tv_sec = pcap_thread->timeout / 1000;
+ t1.tv_usec = (pcap_thread->timeout % 1000) * 1000;
+ max_fd++;
+ while (run) {
+ rfds = fds;
+ t2 = t1;
+ if (timedrun) {
+ struct timeval now;
+ struct timeval diff;
+
+ if (gettimeofday(&now, 0)) {
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "gettimeofday()");
+ pcap_thread->running = 0;
+ return PCAP_THREAD_ERRNO;
+ }
+ if (now.tv_sec > end.tv_sec
+ || (now.tv_sec == end.tv_sec && (now.tv_usec * 1000) >= end.tv_nsec)) {
+ break;
+ }
+
+ if (end.tv_sec > now.tv_sec) {
+ diff.tv_sec = end.tv_sec - now.tv_sec - 1;
+ diff.tv_usec = 1000000 - now.tv_usec;
+ diff.tv_usec += end.tv_nsec / 1000;
+ if (diff.tv_usec > 1000000) {
+ diff.tv_sec += diff.tv_usec / 1000000;
+ diff.tv_usec %= 1000000;
+ }
+ } else {
+ diff.tv_sec = 0;
+ if (end.tv_sec == now.tv_sec && (end.tv_nsec / 1000) > now.tv_usec) {
+ diff.tv_usec = (end.tv_nsec / 1000) - now.tv_usec;
+ } else {
+ diff.tv_usec = 0;
+ }
+ }
+
+ if (diff.tv_sec < t1.tv_sec || (diff.tv_sec == t1.tv_sec && diff.tv_usec < t1.tv_usec)) {
+ t2 = diff;
+ }
+ }
+ if (select(max_fd, &rfds, 0, 0, &t2) == -1) {
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "select()");
+ pcap_thread->running = 0;
+ return PCAP_THREAD_ERRNO;
+ }
+
+ run = 0;
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ int packets;
+
+ if (!pcaplist->running) {
+ continue;
+ } else {
+ run = 1;
+ }
+
+ packets = pcap_dispatch(pcaplist->pcap, -1, _callback2, (u_char*)pcaplist);
+ if (packets == -1) {
+ pcap_thread->status = -1;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_dispatch()");
+ pcap_thread->running = 0;
+ return PCAP_THREAD_EPCAP;
+ } else if (packets == -2 || (pcaplist->is_offline && !packets)) {
+ pcaplist->running = 0;
+ }
+ }
+ }
+
+ pcap_thread->running = 0;
+ }
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_next(pcap_thread_t* pcap_thread)
+{
+ const u_char* pkt;
+ struct pcap_pkthdr pkthdr;
+
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!pcap_thread->callback && !pcap_thread->use_layers) {
+ return PCAP_THREAD_NOCALLBACK;
+ }
+ if (pcap_thread->use_layers
+ && !(pcap_thread->callback_linux_sll
+ || pcap_thread->callback_ether
+ || pcap_thread->callback_null
+ || pcap_thread->callback_loop
+ || pcap_thread->callback_ieee802
+ || pcap_thread->callback_gre
+ || pcap_thread->callback_ip
+ || pcap_thread->callback_ipv4
+ || pcap_thread->callback_ipv6
+ || pcap_thread->callback_icmp
+ || pcap_thread->callback_icmpv6
+ || pcap_thread->callback_udp
+ || pcap_thread->callback_tcp)) {
+ return PCAP_THREAD_NOCALLBACK;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+ if (!pcap_thread->pcaplist) {
+ return PCAP_THREAD_NOPCAPS;
+ }
+
+ if (pcap_thread->errbuf[0]) {
+ memset(pcap_thread->errbuf, 0, sizeof(pcap_thread->errbuf));
+ }
+ pcap_thread->status = 0;
+
+ if (!pcap_thread->step) {
+ pcap_thread->step = pcap_thread->pcaplist;
+ }
+ if (!pcap_thread->step) {
+ return PCAP_THREAD_OK;
+ }
+
+ pcap_thread->step->pcap_thread = pcap_thread;
+ if (pcap_thread->callback_ipv4_frag.new && !pcap_thread->step->have_ipv4_frag_ctx) {
+ pcap_thread->step->ipv4_frag_ctx = pcap_thread->callback_ipv4_frag.new(pcap_thread->callback_ipv4_frag.conf, pcap_thread->step->user);
+ pcap_thread->step->have_ipv4_frag_ctx = 1;
+ }
+ if (pcap_thread->callback_ipv6_frag.new && !pcap_thread->step->have_ipv6_frag_ctx) {
+ pcap_thread->step->ipv6_frag_ctx = pcap_thread->callback_ipv6_frag.new(pcap_thread->callback_ipv6_frag.conf, pcap_thread->step->user);
+ pcap_thread->step->have_ipv6_frag_ctx = 1;
+ }
+
+ if (!(pkt = pcap_next(pcap_thread->step->pcap, &pkthdr))) {
+ pcap_thread->status = -1;
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_next()");
+ return PCAP_THREAD_EPCAP;
+ }
+ if (pcap_thread->callback) {
+ pcap_thread->callback(pcap_thread->step->user, &pkthdr, pkt, pcap_thread->step->name, pcap_datalink(pcap_thread->step->pcap));
+ } else {
+ pcap_thread_callback((void*)pcap_thread->step, &pkthdr, pkt, pcap_thread->step->name, pcap_datalink(pcap_thread->step->pcap));
+ }
+ pcap_thread->step = pcap_thread->step->next;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_next_reset(pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (pcap_thread->running) {
+ return PCAP_THREAD_ERUNNING;
+ }
+ if (!pcap_thread->pcaplist) {
+ return PCAP_THREAD_NOPCAPS;
+ }
+
+ pcap_thread->step = 0;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_stop(pcap_thread_t* pcap_thread)
+{
+ pcap_thread_pcaplist_t* pcaplist;
+
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!pcap_thread->pcaplist) {
+ return PCAP_THREAD_NOPCAPS;
+ }
+
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ pcaplist->running = 0;
+ pcap_breakloop(pcaplist->pcap);
+ }
+ pcap_thread->running = 0;
+ pcap_thread->was_stopped = 1;
+
+#ifdef HAVE_PTHREAD
+ pthread_cond_broadcast(&(pcap_thread->have_packets));
+ pthread_cond_broadcast(&(pcap_thread->can_write));
+#endif
+
+ return PCAP_THREAD_OK;
+}
+
+/*
+ * Stats
+ */
+
+int pcap_thread_stats(pcap_thread_t* pcap_thread, pcap_thread_stats_callback_t callback, u_char* user)
+{
+ pcap_thread_pcaplist_t* pcaplist;
+ struct pcap_stat stats;
+
+ if (!pcap_thread) {
+ return PCAP_THREAD_EINVAL;
+ }
+ if (!callback) {
+ return PCAP_THREAD_NOCALLBACK;
+ }
+ if (!pcap_thread->pcaplist) {
+ return PCAP_THREAD_NOPCAPS;
+ }
+
+ if (pcap_thread->errbuf[0]) {
+ memset(pcap_thread->errbuf, 0, sizeof(pcap_thread->errbuf));
+ }
+ pcap_thread->status = 0;
+
+ for (pcaplist = pcap_thread->pcaplist; pcaplist; pcaplist = pcaplist->next) {
+ if (pcaplist->is_offline)
+ continue;
+ if ((pcap_thread->status = pcap_stats(pcaplist->pcap, &stats))) {
+ PCAP_THREAD_SET_ERRBUF(pcap_thread, "pcap_stats()");
+ return PCAP_THREAD_EPCAP;
+ }
+ callback(user, &stats, pcaplist->name, pcap_datalink(pcaplist->pcap));
+ }
+
+ return PCAP_THREAD_OK;
+}
+
+/*
+ * Error handling
+ */
+
+int pcap_thread_status(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return 0;
+ }
+
+ return pcap_thread->status;
+}
+
+const char* pcap_thread_errbuf(const pcap_thread_t* pcap_thread)
+{
+ if (!pcap_thread) {
+ return 0;
+ }
+
+ return pcap_thread->errbuf;
+}
+
+const char* pcap_thread_strerr(int error)
+{
+ switch (error) {
+ case PCAP_THREAD_OK:
+ return 0;
+ case PCAP_THREAD_EPCAP:
+ return PCAP_THREAD_EPCAP_STR;
+ case PCAP_THREAD_ENOMEM:
+ return PCAP_THREAD_ENOMEM_STR;
+ case PCAP_THREAD_ENOMON:
+ return PCAP_THREAD_ENOMON_STR;
+ case PCAP_THREAD_ENODIR:
+ return PCAP_THREAD_ENODIR_STR;
+ case PCAP_THREAD_EINVAL:
+ return PCAP_THREAD_EINVAL_STR;
+ case PCAP_THREAD_EWOULDBLOCK:
+ return PCAP_THREAD_EWOULDBLOCK_STR;
+ case PCAP_THREAD_NOPCAPS:
+ return PCAP_THREAD_NOPCAPS_STR;
+ case PCAP_THREAD_NOCALLBACK:
+ return PCAP_THREAD_NOCALLBACK_STR;
+ case PCAP_THREAD_ERRNO:
+ return PCAP_THREAD_ERRNO_STR;
+ case PCAP_THREAD_NOYIELD:
+ return PCAP_THREAD_NOYIELD_STR;
+ case PCAP_THREAD_EOBSOLETE:
+ return PCAP_THREAD_EOBSOLETE_STR;
+ case PCAP_THREAD_ERUNNING:
+ return PCAP_THREAD_ERUNNING_STR;
+ case PCAP_THREAD_ENOPCAPLIST:
+ return PCAP_THREAD_ENOPCAPLIST_STR;
+ case PCAP_THREAD_ELAYERCB:
+ return PCAP_THREAD_ELAYERCB_STR;
+ }
+ return "UNKNOWN";
+}
diff --git a/src/pcap-thread/pcap_thread.h b/src/pcap-thread/pcap_thread.h
new file mode 100644
index 0000000..ce43b5a
--- /dev/null
+++ b/src/pcap-thread/pcap_thread.h
@@ -0,0 +1,640 @@
+/*
+ * Author Jerry Lundström <jerry@dns-oarc.net>
+ * Copyright (c) 2016-2017, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __pcap_thread_h
+#define __pcap_thread_h
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+#include <pcap/pcap.h>
+#include <sys/socket.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <net/if_arp.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+#ifdef HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#endif
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#endif
+
+#ifndef __BYTE_ORDER
+#if defined(BYTE_ORDER)
+#define __BYTE_ORDER BYTE_ORDER
+#elif defined(_BYTE_ORDER)
+#define __BYTE_ORDER _BYTE_ORDER
+#else
+#error "No endian byte order define, please fix"
+#endif
+#endif
+#ifndef __LITTLE_ENDIAN
+#if defined(LITTLE_ENDIAN)
+#define __LITTLE_ENDIAN LITTLE_ENDIAN
+#elif defined(_LITTLE_ENDIAN)
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#else
+#error "No little endian define, please fix"
+#endif
+#endif
+#ifndef __BIG_ENDIAN
+#if defined(BIG_ENDIAN)
+#define __BIG_ENDIAN BIG_ENDIAN
+#elif defined(_BIG_ENDIAN)
+#define __BIG_ENDIAN _BIG_ENDIAN
+#else
+#error "No big endian define, please fix"
+#endif
+#endif
+
+#ifndef PCAP_NETMASK_UNKNOWN
+#define PCAP_NETMASK_UNKNOWN 0xffffffff
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clang-format off */
+
+#define PCAP_THREAD_VERSION_STR "4.0.0"
+#define PCAP_THREAD_VERSION_MAJOR 4
+#define PCAP_THREAD_VERSION_MINOR 0
+#define PCAP_THREAD_VERSION_PATCH 0
+
+#define PCAP_THREAD_DEFAULT_TIMEOUT 1000
+#define PCAP_THREAD_DEFAULT_QUEUE_SIZE 64
+#define PCAP_THREAD_DEFAULT_QUEUE_MODE PCAP_THREAD_QUEUE_MODE_COND
+#define PCAP_THREAD_DEFAULT_ACTIVATE_MODE PCAP_THREAD_ACTIVATE_MODE_IMMEDIATE
+
+#define PCAP_THREAD_OK 0
+#define PCAP_THREAD_EPCAP 1
+#define PCAP_THREAD_ENOMEM 2
+#define PCAP_THREAD_ENOMON 3
+#define PCAP_THREAD_ENODIR 4
+#define PCAP_THREAD_EINVAL 5
+#define PCAP_THREAD_EWOULDBLOCK 6
+#define PCAP_THREAD_NOPCAPS 7
+#define PCAP_THREAD_NOCALLBACK 8
+#define PCAP_THREAD_ERRNO 9
+#define PCAP_THREAD_NOYIELD 10
+#define PCAP_THREAD_EOBSOLETE 11
+#define PCAP_THREAD_ERUNNING 12
+#define PCAP_THREAD_ENOPCAPLIST 13
+#define PCAP_THREAD_ELAYERCB 14
+
+#define PCAP_THREAD_EPCAP_STR "libpcap error"
+#define PCAP_THREAD_ENOMEM_STR "out of memory"
+#define PCAP_THREAD_ENOMON_STR "monitor mode requested but not supported"
+#define PCAP_THREAD_ENODIR_STR "direction specified but not supported"
+#define PCAP_THREAD_EINVAL_STR "invalid argument"
+#define PCAP_THREAD_EWOULDBLOCK_STR "nonblocking pcap can not be added"
+#define PCAP_THREAD_NOPCAPS_STR "nothing to capture on"
+#define PCAP_THREAD_NOCALLBACK_STR "no callback set"
+#define PCAP_THREAD_ERRNO_STR "system error, check errno"
+#define PCAP_THREAD_NOYIELD_STR "queue more yield requested but not supported"
+#define PCAP_THREAD_EOBSOLETE_STR "obsolete function or feature"
+#define PCAP_THREAD_ERUNNING_STR "pcap thread are running, can not complete task"
+#define PCAP_THREAD_ENOPCAPLIST_STR "no internal reference to the pcap that captured the packet"
+#define PCAP_THREAD_ELAYERCB_STR "layer callback already set in lower or higher segment"
+
+/* clang-format on */
+
+struct pcap_thread_linux_sll {
+ uint16_t packet_type;
+ uint16_t arp_hardware;
+ uint16_t link_layer_address_length;
+ uint8_t link_layer_address[8];
+ uint16_t ether_type;
+};
+struct pcap_thread_null_hdr {
+ uint32_t family;
+};
+struct pcap_thread_loop_hdr {
+ uint32_t family;
+};
+struct pcap_thread_ieee802_hdr {
+ uint16_t tpid;
+ unsigned short pcp : 3;
+ unsigned short dei : 1;
+ unsigned short vid : 12;
+ uint16_t ether_type;
+};
+struct pcap_thread_gre_hdr {
+ uint16_t gre_flags;
+ uint16_t ether_type;
+};
+struct pcap_thread_gre {
+ uint16_t checksum;
+ uint16_t key;
+ uint16_t sequence;
+};
+typedef enum pcap_thread_packet_state pcap_thread_packet_state_t;
+enum pcap_thread_packet_state {
+ PCAP_THREAD_PACKET_OK = 0,
+ PCAP_THREAD_PACKET_INVALID,
+ PCAP_THREAD_PACKET_UNSUPPORTED,
+ PCAP_THREAD_PACKET_UNPROCESSED,
+ PCAP_THREAD_PACKET_INVALID_ETHER,
+ PCAP_THREAD_PACKET_INVALID_LINUX_SLL,
+ PCAP_THREAD_PACKET_INVALID_NULL,
+ PCAP_THREAD_PACKET_INVALID_LOOP,
+ PCAP_THREAD_PACKET_INVALID_IEEE802,
+ PCAP_THREAD_PACKET_INVALID_GRE,
+ PCAP_THREAD_PACKET_INVALID_IP,
+ PCAP_THREAD_PACKET_INVALID_IPV4,
+ PCAP_THREAD_PACKET_INVALID_IPV6,
+ PCAP_THREAD_PACKET_INVALID_IPV6HDR,
+ PCAP_THREAD_PACKET_INVALID_ICMP,
+ PCAP_THREAD_PACKET_INVALID_ICMPV6,
+ PCAP_THREAD_PACKET_INVALID_UDP,
+ PCAP_THREAD_PACKET_INVALID_TCP,
+ PCAP_THREAD_PACKET_IS_FRAGMENT,
+ PCAP_THREAD_PACKET_INVALID_FRAGMENT,
+ PCAP_THREAD_PACKET_ENOMEM,
+ PCAP_THREAD_PACKET_EMUTEX,
+ PCAP_THREAD_PACKET_FRAGMENTED_GREHDR,
+ PCAP_THREAD_PACKET_FRAGMENTED_ICMPHDR,
+ PCAP_THREAD_PACKET_FRAGMENTED_ICMPV6HDR,
+ PCAP_THREAD_PACKET_FRAGMENTED_UDPHDR,
+ PCAP_THREAD_PACKET_FRAGMENTED_TCPHDR
+};
+
+typedef struct pcap_thread_packet pcap_thread_packet_t;
+struct pcap_thread_packet {
+ unsigned short have_prevpkt : 1;
+ unsigned short have_pkthdr : 1;
+ unsigned short have_linux_sll : 1;
+ unsigned short have_ethhdr : 1;
+ unsigned short have_nullhdr : 1;
+ unsigned short have_loophdr : 1;
+ unsigned short have_ieee802hdr : 1;
+ unsigned short have_grehdr : 1;
+ unsigned short have_gre : 1;
+ unsigned short have_iphdr : 1;
+ unsigned short have_ip6hdr : 1;
+ unsigned short have_ip6frag : 1;
+ unsigned short have_ip6rtdst : 1;
+ unsigned short have_icmphdr : 1;
+ unsigned short have_icmpv6hdr : 1;
+ unsigned short have_udphdr : 1;
+ unsigned short have_tcphdr : 1;
+ unsigned short have_tcpopts : 1;
+ unsigned short have_ippadding : 1;
+ unsigned short have_ip6padding : 1;
+
+ const char* name;
+ int dlt;
+ pcap_thread_packet_t* prevpkt;
+ struct pcap_pkthdr pkthdr;
+ struct pcap_thread_linux_sll linux_sll;
+ struct ether_header ethhdr;
+ struct pcap_thread_null_hdr nullhdr;
+ struct pcap_thread_loop_hdr loophdr;
+ struct pcap_thread_ieee802_hdr ieee802hdr;
+ struct pcap_thread_gre_hdr grehdr;
+ struct pcap_thread_gre gre;
+ struct ip iphdr;
+ struct ip6_hdr ip6hdr;
+ struct ip6_frag ip6frag;
+ uint8_t ip6frag_payload;
+ struct in6_addr ip6rtdst;
+ struct {
+ u_int8_t type;
+ u_int8_t code;
+ u_int16_t checksum;
+ } icmphdr;
+ struct {
+ u_int8_t icmp6_type;
+ u_int8_t icmp6_code;
+ u_int16_t icmp6_cksum;
+ } icmpv6hdr;
+ struct {
+ union {
+ struct {
+ u_int16_t uh_sport;
+ u_int16_t uh_dport;
+ u_int16_t uh_ulen;
+ u_int16_t uh_sum;
+ };
+ struct {
+ u_int16_t source;
+ u_int16_t dest;
+ u_int16_t len;
+ u_int16_t check;
+ };
+ };
+ } udphdr;
+ struct {
+ union {
+ struct {
+ u_int16_t th_sport;
+ u_int16_t th_dport;
+ u_int32_t th_seq;
+ u_int32_t th_ack;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u_int8_t th_x2 : 4;
+ u_int8_t th_off : 4;
+#endif
+#if __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t th_off : 4;
+ u_int8_t th_x2 : 4;
+#endif
+ u_int8_t th_flags;
+ u_int16_t th_win;
+ u_int16_t th_sum;
+ u_int16_t th_urp;
+ };
+ struct {
+ u_int16_t source;
+ u_int16_t dest;
+ u_int32_t seq;
+ u_int32_t ack_seq;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u_int16_t res1 : 4;
+ u_int16_t doff : 4;
+ u_int16_t fin : 1;
+ u_int16_t syn : 1;
+ u_int16_t rst : 1;
+ u_int16_t psh : 1;
+ u_int16_t ack : 1;
+ u_int16_t urg : 1;
+ u_int16_t res2 : 2;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int16_t doff : 4;
+ u_int16_t res1 : 4;
+ u_int16_t res2 : 2;
+ u_int16_t urg : 1;
+ u_int16_t ack : 1;
+ u_int16_t psh : 1;
+ u_int16_t rst : 1;
+ u_int16_t syn : 1;
+ u_int16_t fin : 1;
+#endif
+ u_int16_t window;
+ u_int16_t check;
+ u_int16_t urg_ptr;
+ };
+ };
+ } tcphdr;
+ u_int8_t tcpopts[64];
+ size_t tcpopts_len;
+
+ size_t ippadding;
+ size_t ip6padding;
+
+ pcap_thread_packet_state_t state;
+};
+
+typedef enum pcap_thread_queue_mode pcap_thread_queue_mode_t;
+typedef struct pcap_thread pcap_thread_t;
+typedef void (*pcap_thread_callback_t)(u_char* user, const struct pcap_pkthdr* pkthdr, const u_char* pkt, const char* name, int dlt);
+typedef void (*pcap_thread_layer_callback_t)(u_char* user, const pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+typedef void (*pcap_thread_stats_callback_t)(u_char* user, const struct pcap_stat* stats, const char* name, int dlt);
+#ifndef HAVE_PCAP_DIRECTION_T
+typedef int pcap_direction_t;
+#endif
+typedef struct pcap_thread_pcaplist pcap_thread_pcaplist_t;
+typedef enum pcap_thread_activate_mode pcap_thread_activate_mode_t;
+
+enum pcap_thread_queue_mode {
+ PCAP_THREAD_QUEUE_MODE_COND,
+ PCAP_THREAD_QUEUE_MODE_WAIT,
+ PCAP_THREAD_QUEUE_MODE_YIELD,
+ PCAP_THREAD_QUEUE_MODE_DROP,
+ PCAP_THREAD_QUEUE_MODE_DIRECT
+};
+
+enum pcap_thread_activate_mode {
+ PCAP_THREAD_ACTIVATE_MODE_IMMEDIATE,
+ PCAP_THREAD_ACTIVATE_MODE_DELAYED
+};
+
+#ifdef HAVE_PCAP_DIRECTION_T
+#define PCAP_THREAD_T_INIT_DIRECTION_T 0,
+#else
+#define PCAP_THREAD_T_INIT_DIRECTION_T
+#endif
+
+#ifdef HAVE_PTHREAD
+#define PCAP_THREAD_T_INIT_QUEUE PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, \
+ 0, 0, 0, 0, 0, 0,
+#else
+#define PCAP_THREAD_T_INIT_QUEUE
+#endif
+
+#ifdef PCAP_TSTAMP_PRECISION_MICRO
+#define PCAP_THREAD_T_INIT_PRECISION PCAP_TSTAMP_PRECISION_MICRO
+#else
+#define PCAP_THREAD_T_INIT_PRECISION 0
+#endif
+
+typedef void* (*pcap_thread_layer_callback_frag_new_t)(void* conf, u_char* user);
+typedef void (*pcap_thread_layer_callback_frag_free_t)(void* ctx);
+typedef pcap_thread_packet_state_t (*pcap_thread_layer_callback_frag_reassemble_t)(void* ctx, const pcap_thread_packet_t* packet, const u_char* payload, size_t length, pcap_thread_packet_t** whole_packet, const u_char** whole_payload, size_t* whole_length);
+typedef void (*pcap_thread_layer_callback_frag_release_t)(void* ctx, const pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+
+/* clang-format off */
+#define PCAP_THREAD_LAYER_CALLBACK_FRAG_T_INIT { \
+ 0, 0, 0, 0, 0, \
+}
+/* clang-format on */
+
+typedef struct pcap_thread_layer_callback_frag pcap_thread_layer_callback_frag_t;
+struct pcap_thread_layer_callback_frag {
+ void* conf;
+ pcap_thread_layer_callback_frag_new_t new;
+ pcap_thread_layer_callback_frag_free_t free;
+ pcap_thread_layer_callback_frag_reassemble_t reassemble;
+ pcap_thread_layer_callback_frag_release_t release;
+};
+
+/* clang-format off */
+#define PCAP_THREAD_T_INIT { \
+ 0, 0, 0, 0, \
+ 0, 1, 0, PCAP_THREAD_DEFAULT_QUEUE_MODE, PCAP_THREAD_DEFAULT_QUEUE_SIZE, \
+ PCAP_THREAD_T_INIT_QUEUE \
+ 0, 0, 0, 0, PCAP_THREAD_DEFAULT_TIMEOUT, \
+ 0, 0, PCAP_THREAD_T_INIT_PRECISION, 0, \
+ PCAP_THREAD_T_INIT_DIRECTION_T \
+ 0, 0, 0, 1, PCAP_NETMASK_UNKNOWN, \
+ 0, 0, \
+ 0, "", 0, 0, \
+ { 0, 0 }, { 0, 0 }, \
+ PCAP_THREAD_DEFAULT_ACTIVATE_MODE, \
+ 0, 0, 0, 0, 0, 0, 0, 0, PCAP_THREAD_LAYER_CALLBACK_FRAG_T_INIT, 0, PCAP_THREAD_LAYER_CALLBACK_FRAG_T_INIT, 0, 0, 0, 0, \
+ 0 \
+}
+/* clang-format on */
+
+struct pcap_thread {
+ unsigned short have_timestamp_precision : 1;
+ unsigned short have_timestamp_type : 1;
+ unsigned short have_direction : 1;
+ unsigned short was_stopped : 1;
+
+ int running;
+ int use_threads;
+ int use_layers;
+ pcap_thread_queue_mode_t queue_mode;
+ size_t queue_size;
+
+#ifdef HAVE_PTHREAD
+ pthread_cond_t have_packets;
+ pthread_cond_t can_write;
+ pthread_mutex_t mutex;
+
+ struct pcap_pkthdr* pkthdr;
+ u_char* pkt;
+ pcap_thread_pcaplist_t** pcaplist_pkt;
+ size_t read_pos;
+ size_t write_pos;
+ size_t pkts;
+#endif
+
+ int snapshot;
+ int snaplen;
+ int promiscuous;
+ int monitor;
+ int timeout;
+
+ int buffer_size;
+ int timestamp_type;
+ int timestamp_precision;
+ int immediate_mode;
+
+#ifdef HAVE_PCAP_DIRECTION_T
+ pcap_direction_t direction;
+#endif
+
+ char* filter;
+ size_t filter_len;
+ int filter_errno;
+ int filter_optimize;
+ bpf_u_int32 filter_netmask;
+
+ pcap_thread_callback_t callback;
+ pcap_thread_callback_t dropback;
+
+ int status;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_thread_pcaplist_t* pcaplist;
+ pcap_thread_pcaplist_t* step;
+
+ struct timeval timedrun;
+ struct timeval timedrun_to;
+
+ pcap_thread_activate_mode_t activate_mode;
+
+ pcap_thread_layer_callback_t callback_linux_sll;
+ pcap_thread_layer_callback_t callback_ether;
+ pcap_thread_layer_callback_t callback_null;
+ pcap_thread_layer_callback_t callback_loop;
+ pcap_thread_layer_callback_t callback_ieee802;
+ pcap_thread_layer_callback_t callback_gre;
+ pcap_thread_layer_callback_t callback_ip;
+ pcap_thread_layer_callback_t callback_ipv4;
+ pcap_thread_layer_callback_frag_t callback_ipv4_frag;
+ pcap_thread_layer_callback_t callback_ipv6;
+ pcap_thread_layer_callback_frag_t callback_ipv6_frag;
+ pcap_thread_layer_callback_t callback_icmp;
+ pcap_thread_layer_callback_t callback_icmpv6;
+ pcap_thread_layer_callback_t callback_udp;
+ pcap_thread_layer_callback_t callback_tcp;
+
+ pcap_thread_layer_callback_t callback_invalid;
+};
+
+#define PCAP_THREAD_SET_ERRBUF(x, y) strncpy(x->errbuf, y, sizeof(x->errbuf) - 1)
+
+#ifdef HAVE_PTHREAD
+#define PCAP_THREAD_PCAPLIST_T_INIT_THREAD 0,
+#else
+#define PCAP_THREAD_PCAPLIST_T_INIT_THREAD
+#endif
+
+/* clang-format off */
+#define PCAP_THREAD_PCAPLIST_T_INIT { \
+ 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, \
+ PCAP_THREAD_PCAPLIST_T_INIT_THREAD \
+ { 0, 0 }, \
+ 0, \
+}
+/* clang-format on */
+
+struct pcap_thread_pcaplist {
+ unsigned short have_bpf : 1;
+ unsigned short have_ipv4_frag_ctx : 1;
+ unsigned short have_ipv6_frag_ctx : 1;
+
+ pcap_thread_pcaplist_t* next;
+ char* name;
+ pcap_t* pcap;
+ void* user;
+ int running;
+ int is_offline;
+ void* ipv4_frag_ctx;
+ void* ipv6_frag_ctx;
+
+ pcap_thread_t* pcap_thread;
+
+#ifdef HAVE_PTHREAD
+ pthread_t thread;
+#endif
+
+ struct bpf_program bpf;
+
+ pcap_thread_callback_t layer_callback;
+};
+
+const char* pcap_thread_version_str(void);
+
+int pcap_thread_version_major(void);
+int pcap_thread_version_minor(void);
+int pcap_thread_version_patch(void);
+
+pcap_thread_t* pcap_thread_create(void);
+void pcap_thread_free(pcap_thread_t* pcap_thread);
+
+int pcap_thread_use_threads(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_use_threads(pcap_thread_t* pcap_thread, const int use_threads);
+int pcap_thread_use_layers(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_use_layers(pcap_thread_t* pcap_thread, const int use_layers);
+pcap_thread_queue_mode_t pcap_thread_queue_mode(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_queue_mode(pcap_thread_t* pcap_thread, const pcap_thread_queue_mode_t queue_mode);
+struct timeval pcap_thread_queue_wait(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_queue_wait(pcap_thread_t* pcap_thread, const struct timeval queue_wait);
+pcap_thread_queue_mode_t pcap_thread_callback_queue_mode(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_callback_queue_mode(pcap_thread_t* pcap_thread, const pcap_thread_queue_mode_t callback_queue_mode);
+struct timeval pcap_thread_callback_queue_wait(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_callback_queue_wait(pcap_thread_t* pcap_thread, const struct timeval callback_queue_wait);
+int pcap_thread_snapshot(const pcap_thread_t* pcap_thread);
+int pcap_thread_snaplen(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_snaplen(pcap_thread_t* pcap_thread, const int snaplen);
+int pcap_thread_promiscuous(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_promiscuous(pcap_thread_t* pcap_thread, const int promiscuous);
+int pcap_thread_monitor(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_monitor(pcap_thread_t* pcap_thread, const int monitor);
+int pcap_thread_timeout(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_timeout(pcap_thread_t* pcap_thread, const int timeout);
+int pcap_thread_buffer_size(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_buffer_size(pcap_thread_t* pcap_thread, const int buffer_size);
+int pcap_thread_timestamp_type(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_timestamp_type(pcap_thread_t* pcap_thread, const int timestamp_type);
+int pcap_thread_timestamp_precision(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_timestamp_precision(pcap_thread_t* pcap_thread, const int timestamp_precision);
+int pcap_thread_immediate_mode(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_immediate_mode(pcap_thread_t* pcap_thread, const int immediate_mode);
+pcap_direction_t pcap_thread_direction(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_direction(pcap_thread_t* pcap_thread, const pcap_direction_t direction);
+const char* pcap_thread_filter(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_filter(pcap_thread_t* pcap_thread, const char* filter, const size_t filter_len);
+int pcap_thread_clear_filter(pcap_thread_t* pcap_thread);
+int pcap_thread_filter_errno(const pcap_thread_t* pcap_thread);
+int pcap_thread_filter_optimize(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_filter_optimize(pcap_thread_t* pcap_thread, const int filter_optimize);
+bpf_u_int32 pcap_thread_filter_netmask(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_filter_netmask(pcap_thread_t* pcap_thread, const bpf_u_int32 filter_netmask);
+struct timeval pcap_thread_timedrun(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_timedrun(pcap_thread_t* pcap_thread, const struct timeval timedrun);
+struct timeval pcap_thread_timedrun_to(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_timedrun_to(pcap_thread_t* pcap_thread, const struct timeval timedrun_to);
+pcap_thread_activate_mode_t pcap_thread_activate_mode(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_activate_mode(pcap_thread_t* pcap_thread, const pcap_thread_activate_mode_t activate_mode);
+int pcap_thread_was_stopped(const pcap_thread_t* pcap_thread);
+
+size_t pcap_thread_queue_size(const pcap_thread_t* pcap_thread);
+int pcap_thread_set_queue_size(pcap_thread_t* pcap_thread, const size_t queue_size);
+
+int pcap_thread_set_callback(pcap_thread_t* pcap_thread, pcap_thread_callback_t callback);
+int pcap_thread_set_dropback(pcap_thread_t* pcap_thread, pcap_thread_callback_t dropback);
+
+int pcap_thread_set_callback_linux_sll(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_linux_sll);
+int pcap_thread_set_callback_ether(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ether);
+int pcap_thread_set_callback_null(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_null);
+int pcap_thread_set_callback_loop(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_loop);
+int pcap_thread_set_callback_ieee802(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ieee802);
+int pcap_thread_set_callback_gre(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_gre);
+int pcap_thread_set_callback_ip(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ip);
+int pcap_thread_set_callback_ipv4(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ipv4);
+int pcap_thread_set_callback_ipv4_frag(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_frag_t callback_ipv4_frag);
+int pcap_thread_set_callback_ipv6(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_ipv6);
+int pcap_thread_set_callback_ipv6_frag(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_frag_t callback_ipv6_frag);
+int pcap_thread_set_callback_icmp(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_icmp);
+int pcap_thread_set_callback_icmpv6(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_icmpv6);
+int pcap_thread_set_callback_udp(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_udp);
+int pcap_thread_set_callback_tcp(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_tcp);
+int pcap_thread_set_callback_invalid(pcap_thread_t* pcap_thread, pcap_thread_layer_callback_t callback_tcp);
+
+int pcap_thread_open(pcap_thread_t* pcap_thread, const char* device, void* user);
+int pcap_thread_open_offline(pcap_thread_t* pcap_thread, const char* file, void* user);
+int pcap_thread_add(pcap_thread_t* pcap_thread, const char* name, pcap_t* pcap, void* user);
+int pcap_thread_activate(pcap_thread_t* pcap_thread);
+int pcap_thread_close(pcap_thread_t* pcap_thread);
+
+int pcap_thread_run(pcap_thread_t* pcap_thread);
+int pcap_thread_next(pcap_thread_t* pcap_thread);
+int pcap_thread_next_reset(pcap_thread_t* pcap_thread);
+int pcap_thread_stop(pcap_thread_t* pcap_thread);
+
+int pcap_thread_stats(pcap_thread_t* pcap_thread, pcap_thread_stats_callback_t callback, u_char* user);
+
+int pcap_thread_status(const pcap_thread_t* pcap_thread);
+const char* pcap_thread_errbuf(const pcap_thread_t* pcap_thread);
+const char* pcap_thread_strerr(int error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __pcap_thread_h */
diff --git a/src/pcap-thread/pcap_thread_ext_frag.c b/src/pcap-thread/pcap_thread_ext_frag.c
new file mode 100644
index 0000000..6593e92
--- /dev/null
+++ b/src/pcap-thread/pcap_thread_ext_frag.c
@@ -0,0 +1,1013 @@
+/*
+ * Author Jerry Lundström <jerry@dns-oarc.net>
+ * Copyright (c) 2016-2017, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "pcap_thread_ext_frag.h"
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+#ifndef PCAP_THREAD_EXT_FRAG_TRACE
+#define PCAP_THREAD_EXT_FRAG_TRACE 0
+#endif
+
+/*
+ * Forward declares for callbacks
+ */
+
+static void* pcap_thread_layer_callback_frag_new(void* conf, u_char* user);
+static void pcap_thread_layer_callback_frag_free(void* _ctx);
+static pcap_thread_packet_state_t pcap_thread_layer_callback_frag_reassemble(void* _ctx, const pcap_thread_packet_t* packet, const u_char* payload, size_t length, pcap_thread_packet_t** whole_packet, const u_char** whole_payload, size_t* whole_length);
+static void pcap_thread_layer_callback_frag_release(void* _ctx, const pcap_thread_packet_t* packet, const u_char* payload, size_t length);
+
+/*
+ * Create/Free
+ */
+
+static pcap_thread_ext_frag_conf_t _conf_defaults = PCAP_THREAD_EXT_FRAG_CONF_T_INIT;
+
+pcap_thread_ext_frag_conf_t* pcap_thread_ext_frag_conf_new(void)
+{
+ pcap_thread_ext_frag_conf_t* conf = calloc(1, sizeof(pcap_thread_ext_frag_conf_t));
+ if (conf) {
+ memcpy(conf, &_conf_defaults, sizeof(pcap_thread_ext_frag_conf_t));
+ }
+
+ return conf;
+}
+
+void pcap_thread_ext_frag_conf_free(pcap_thread_ext_frag_conf_t* conf)
+{
+ if (conf) {
+ free(conf);
+ }
+}
+
+/*
+ * Get/Set
+ */
+
+int pcap_thread_ext_frag_conf_reject_overlap(const pcap_thread_ext_frag_conf_t* conf)
+{
+ if (!conf) {
+ return 0;
+ }
+
+ return conf->reject_overlap;
+}
+
+int pcap_thread_ext_frag_conf_set_reject_overlap(pcap_thread_ext_frag_conf_t* conf, const int reject_overlap)
+{
+ if (!conf) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ conf->reject_overlap = reject_overlap ? 1 : 0;
+
+ return PCAP_THREAD_OK;
+}
+
+int pcap_thread_ext_frag_conf_check_timeout(const pcap_thread_ext_frag_conf_t* conf)
+{
+ if (!conf) {
+ return 0;
+ }
+
+ return conf->check_timeout;
+}
+
+int pcap_thread_ext_frag_conf_set_check_timeout(pcap_thread_ext_frag_conf_t* conf, const int check_timeout)
+{
+ if (!conf) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ conf->check_timeout = check_timeout ? 1 : 0;
+
+ return PCAP_THREAD_OK;
+}
+
+pcap_thread_ext_frag_reassemble_mode_t pcap_thread_ext_frag_conf_reassemble_mode(const pcap_thread_ext_frag_conf_t* conf)
+{
+ if (!conf) {
+ return PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC791;
+ }
+
+ return conf->reassemble_mode;
+}
+
+int pcap_thread_ext_frag_conf_set_reassemble_mode(pcap_thread_ext_frag_conf_t* conf, const pcap_thread_ext_frag_reassemble_mode_t reassemble_mode)
+{
+ if (!conf) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ switch (reassemble_mode) {
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC791:
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_BSD:
+ break;
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC815:
+ /* TODO: Implement */
+ default:
+ return PCAP_THREAD_EINVAL;
+ }
+
+ conf->reassemble_mode = reassemble_mode;
+
+ return PCAP_THREAD_OK;
+}
+
+size_t pcap_thread_ext_frag_conf_fragments(const pcap_thread_ext_frag_conf_t* conf)
+{
+ if (!conf) {
+ return -1;
+ }
+
+ return conf->fragments;
+}
+
+int pcap_thread_ext_frag_conf_set_fragments(pcap_thread_ext_frag_conf_t* conf, const size_t fragments)
+{
+ if (!conf) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ conf->fragments = fragments;
+
+ return PCAP_THREAD_OK;
+}
+
+size_t pcap_thread_ext_frag_conf_per_packet(const pcap_thread_ext_frag_conf_t* conf)
+{
+ if (!conf) {
+ return -1;
+ }
+
+ return conf->per_packet;
+}
+
+int pcap_thread_ext_frag_conf_set_per_packet(pcap_thread_ext_frag_conf_t* conf, const size_t per_packet)
+{
+ if (!conf) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ conf->per_packet = per_packet;
+
+ return PCAP_THREAD_OK;
+}
+
+struct timeval pcap_thread_ext_frag_conf_timeout(const pcap_thread_ext_frag_conf_t* conf)
+{
+ if (!conf) {
+ struct timeval ret = { 0, 0 };
+ return ret;
+ }
+
+ return conf->timeout;
+}
+
+int pcap_thread_ext_frag_conf_set_timeout(pcap_thread_ext_frag_conf_t* conf, const struct timeval timeout)
+{
+ if (!conf) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ conf->timeout = timeout;
+
+ return PCAP_THREAD_OK;
+}
+
+pcap_thread_ext_frag_callback_t pcap_thread_ext_frag_conf_overlap_callback(const pcap_thread_ext_frag_conf_t* conf)
+{
+ if (!conf) {
+ return 0;
+ }
+
+ return conf->overlap_callback;
+}
+
+int pcap_thread_ext_frag_conf_set_overlap_callback(pcap_thread_ext_frag_conf_t* conf, pcap_thread_ext_frag_callback_t overlap_callback)
+{
+ if (!conf) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ conf->overlap_callback = overlap_callback;
+
+ return PCAP_THREAD_OK;
+}
+
+pcap_thread_ext_frag_callback_t pcap_thread_ext_frag_conf_timeout_callback(const pcap_thread_ext_frag_conf_t* conf)
+{
+ if (!conf) {
+ return 0;
+ }
+
+ return conf->timeout_callback;
+}
+
+int pcap_thread_ext_frag_conf_set_timeout_callback(pcap_thread_ext_frag_conf_t* conf, pcap_thread_ext_frag_callback_t timeout_callback)
+{
+ if (!conf) {
+ return PCAP_THREAD_EINVAL;
+ }
+
+ conf->timeout_callback = timeout_callback;
+
+ return PCAP_THREAD_OK;
+}
+
+/*
+ * Init
+ */
+
+pcap_thread_layer_callback_frag_t pcap_thread_ext_frag_layer_callback(pcap_thread_ext_frag_conf_t* conf)
+{
+ pcap_thread_layer_callback_frag_t callback = PCAP_THREAD_LAYER_CALLBACK_FRAG_T_INIT;
+
+ if (conf) {
+ callback.conf = (void*)conf;
+ callback.new = pcap_thread_layer_callback_frag_new;
+ callback.free = pcap_thread_layer_callback_frag_free;
+ callback.reassemble = pcap_thread_layer_callback_frag_reassemble;
+ callback.release = pcap_thread_layer_callback_frag_release;
+ }
+
+ return callback;
+}
+
+/*
+ * Callbacks
+ */
+
+#if PCAP_THREAD_EXT_FRAG_TRACE
+#include <stdio.h>
+#define layer_trace(msg) printf("LT %s:%d: " msg "\n", __FILE__, __LINE__)
+#define layer_tracef(msg, args...) printf("LT %s:%d: " msg "\n", __FILE__, __LINE__, args)
+#else
+#define layer_trace(msg)
+#define layer_tracef(msg, args...)
+#endif
+
+/* TODO:
+typedef struct _hole _hole_t;
+struct _hole {
+ _hole_t* next;
+
+ size_t first, last;
+};
+*/
+
+#ifdef HAVE_PTHREAD
+#define PCAP_THREAD_EXT_FRAG_CTX_T_INIT_MUTEX PTHREAD_MUTEX_INITIALIZER,
+#else
+#define PCAP_THREAD_EXT_FRAG_CTX_T_INIT_MUTEX
+#endif
+
+/* clang-format off */
+#define PCAP_THREAD_EXT_FRAG_CTX_T_INIT { \
+ PCAP_THREAD_EXT_FRAG_CTX_T_INIT_MUTEX \
+ PCAP_THREAD_EXT_FRAG_CONF_T_INIT, 0, 0 \
+}
+/* clang-format on */
+
+typedef struct _ctx _ctx_t;
+struct _ctx {
+#ifdef HAVE_PTHREAD
+ pthread_mutex_t mutex;
+#endif
+ pcap_thread_ext_frag_conf_t conf;
+ pcap_thread_ext_frag_fragments_t* fragments;
+ size_t num_fragments;
+};
+
+static _ctx_t _ctx_defaults = PCAP_THREAD_EXT_FRAG_CTX_T_INIT;
+
+static void* pcap_thread_layer_callback_frag_new(void* conf, u_char* user)
+{
+ _ctx_t* ctx = calloc(1, sizeof(_ctx_t));
+ if (ctx) {
+ layer_tracef("new ctx %p", ctx);
+ memcpy(ctx, &_ctx_defaults, sizeof(_ctx_t));
+ if (conf) {
+ memcpy(&(ctx->conf), conf, sizeof(pcap_thread_ext_frag_conf_t));
+ }
+ }
+
+ return ctx;
+}
+
+static void pcap_thread_layer_callback_frag_free(void* _ctx)
+{
+ _ctx_t* ctx = (_ctx_t*)_ctx;
+ if (ctx) {
+ layer_tracef("free ctx %p", ctx);
+ while (ctx->fragments) {
+ pcap_thread_ext_frag_fragments_t* frags = ctx->fragments;
+ ctx->fragments = frags->next;
+
+ while (frags->fragments) {
+ pcap_thread_ext_frag_fragment_t* frag = frags->fragments;
+ frags->fragments = frag->next;
+
+ if (frag->payload) {
+ free(frag->payload);
+ }
+ free(frag);
+ }
+
+ if (frags->payload) {
+ free(frags->payload);
+ }
+ free(frags);
+ }
+ }
+}
+
+static pcap_thread_packet_state_t reassemble(_ctx_t* ctx, const pcap_thread_packet_t* packet, pcap_thread_packet_t** whole_packet, const u_char** whole_payload, size_t* whole_length, pcap_thread_ext_frag_fragments_t* frags, pcap_thread_ext_frag_fragment_t* frag)
+{
+ pcap_thread_ext_frag_fragment_t *f, *f_prev;
+ int missing_frag = 0;
+ /* TODO:
+ int rfc815_seen_no_more_frags = 0;
+ */
+
+ if ((frag->offset + frag->length) > frags->length) {
+ frags->length = frag->offset + frag->length;
+ }
+
+ layer_tracef("new frag len %lu off %lu mf %d (frags len %lu)", frag->length, frag->offset, frag->flag_more_fragments, frags->length);
+
+ /* Place the fragment in the fragments list */
+ switch (ctx->conf.reassemble_mode) {
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC791:
+ for (f_prev = 0, f = frags->fragments; f; f_prev = f, f = f->next) {
+ layer_tracef("checking frag %p len %lu off %lu mf %d next %p", f, f->length, f->offset, f->flag_more_fragments, f->next);
+
+ if (f->offset > frag->offset) {
+ if (f_prev) {
+ f_prev->next = frag;
+ } else {
+ frags->fragments = frag;
+ }
+ frag->next = f;
+ f = frag;
+ break;
+ }
+ if (f_prev && (f_prev->offset + f_prev->length) < f->offset) {
+ missing_frag = 1;
+ }
+ }
+ if (!f) {
+ if (f_prev) {
+ f_prev->next = frag;
+ if ((f_prev->offset + f_prev->length) < frag->offset) {
+ missing_frag = 1;
+ }
+ } else {
+ frags->fragments = frag;
+ }
+ /* New frag is now last frag */
+ f_prev = frag;
+ } else if (!missing_frag) {
+ for (; f; f_prev = f, f = f->next) {
+ layer_tracef("checking frag %p len %lu off %lu mf %d next %p", f, f->length, f->offset, f->flag_more_fragments, f->next);
+ if (f_prev && (f_prev->offset + f_prev->length) < f->offset) {
+ missing_frag = 1;
+ break;
+ }
+ }
+ }
+ /*
+ * If first is not offset zero or last have more fragments flag,
+ * we are missing fragments.
+ */
+ if (!missing_frag && (frags->fragments->offset || (f_prev && f_prev->flag_more_fragments))) {
+ missing_frag = 1;
+ }
+ break;
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC815:
+ /* TODO:
+ for (f_prev = 0, f = frags->fragments; f; f_prev = f, f = f->next) {
+ layer_tracef("checking frag %p len %lu off %lu mf %d next %p", f, f->length, f->offset, f->flag_more_fragments, f->next);
+
+ if (!f->flag_more_fragments) {
+ rfc815_seen_no_more_frags = 1;
+ }
+ }
+ */
+ free(frag->payload);
+ free(frag);
+ return PCAP_THREAD_EINVAL;
+ break;
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_BSD:
+ for (f_prev = 0, f = frags->fragments; f; f_prev = f, f = f->next) {
+ layer_tracef("checking frag %p len %lu off %lu mf %d next %p", f, f->length, f->offset, f->flag_more_fragments, f->next);
+
+ if (f->offset > frag->offset) {
+ if (f_prev) {
+ f_prev->next = frag;
+ } else {
+ frags->fragments = frag;
+ }
+ frag->next = f;
+ f = frag;
+ break;
+ }
+ if (f_prev && (f->offset + f->length) < f_prev->offset) {
+ missing_frag = 1;
+ }
+ }
+ if (!f) {
+ if (f_prev) {
+ f_prev->next = frag;
+ if ((frag->offset + frag->length) < f_prev->offset) {
+ missing_frag = 1;
+ }
+ } else {
+ frags->fragments = frag;
+ }
+ } else if (!missing_frag) {
+ for (; f; f_prev = f, f = f->next) {
+ layer_tracef("checking frag %p len %lu off %lu mf %d next %p", f, f->length, f->offset, f->flag_more_fragments, f->next);
+ if (f_prev && (f->offset + f->length) < f_prev->offset) {
+ missing_frag = 1;
+ break;
+ }
+ }
+ }
+ /*
+ * If first (last on list) is not offset zero or last (first on
+ * list) have more fragments flag, we are missing fragments.
+ */
+ if (!missing_frag && ((f_prev && f_prev->offset) || frags->fragments->flag_more_fragments)) {
+ missing_frag = 1;
+ }
+ break;
+ }
+ frags->num_fragments++;
+
+ if (missing_frag) {
+ layer_trace("need more frags");
+ return PCAP_THREAD_PACKET_OK;
+ }
+
+ if (!frags->length) {
+ layer_trace("frags complete but no size");
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+
+ if (ctx->conf.reject_overlap) {
+ switch (ctx->conf.reassemble_mode) {
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC791:
+ for (f_prev = 0, f = frags->fragments; f; f_prev = f, f = f->next) {
+ layer_tracef("checking frag %p len %lu off %lu mf %d next %p", f, f->length, f->offset, f->flag_more_fragments, f->next);
+ if (f_prev && (f_prev->offset + f_prev->length) > f->offset) {
+ layer_trace("overlapping fragment");
+ if (ctx->conf.overlap_callback)
+ ctx->conf.overlap_callback(packet, frag->payload, frag->length, frags);
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+ }
+ break;
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC815:
+ /* TODO:
+ */
+ break;
+ case PCAP_THREAD_EXT_FRAG_REASSEMBLE_BSD:
+ for (f_prev = 0, f = frags->fragments; f; f_prev = f, f = f->next) {
+ layer_tracef("checking frag %p len %lu off %lu mf %d next %p", f, f->length, f->offset, f->flag_more_fragments, f->next);
+ if (f_prev && (f->offset + f->length) > f_prev->offset) {
+ layer_trace("overlapping fragment");
+ if (ctx->conf.overlap_callback)
+ ctx->conf.overlap_callback(packet, frag->payload, frag->length, frags);
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+ }
+ break;
+ }
+ }
+
+ /*
+ * Reassemble packet
+ */
+ if (!(frags->payload = calloc(1, frags->length))) {
+ layer_trace("nomem frags payload");
+ return PCAP_THREAD_PACKET_ENOMEM;
+ }
+ for (f = frags->fragments; f; f = f->next) {
+ memcpy(frags->payload + f->offset, f->payload, f->length);
+ }
+
+ frags->packet.name = packet->name;
+ frags->packet.dlt = packet->dlt;
+ frags->packet.pkthdr = packet->pkthdr;
+ /*
+ * We add the total payload length minus current fragment, since it is
+ * already included, to the pkthdr lengths in order to return correct
+ * total packet length (header + payload).
+ */
+ frags->packet.pkthdr.len += frags->length - frag->length;
+ frags->packet.pkthdr.caplen += frags->length - frag->length;
+ frags->packet.have_pkthdr = packet->have_pkthdr;
+
+ *whole_packet = &(frags->packet);
+ *whole_payload = frags->payload;
+ *whole_length = frags->length;
+
+ return PCAP_THREAD_PACKET_OK;
+}
+
+static pcap_thread_packet_state_t reassemble_ipv4(_ctx_t* ctx, const pcap_thread_packet_t* packet, const u_char* payload, size_t length, pcap_thread_packet_t** whole_packet, const u_char** whole_payload, size_t* whole_length)
+{
+ pcap_thread_ext_frag_fragments_t *frags, *frags_prev;
+ pcap_thread_ext_frag_fragment_t* frag;
+
+ if (!packet->have_pkthdr) {
+ layer_trace("no pkthdr");
+ return PCAP_THREAD_PACKET_INVALID;
+ }
+
+ layer_tracef("ipv4 ctx %p", ctx);
+
+ /* Find packet fragments */
+ for (frags_prev = 0, frags = ctx->fragments; frags; frags_prev = frags, frags = frags->next) {
+ if (frags->packet.have_iphdr
+ && packet->iphdr.ip_id == frags->packet.iphdr.ip_id
+ && packet->iphdr.ip_p == frags->packet.iphdr.ip_p
+ && packet->iphdr.ip_src.s_addr == frags->packet.iphdr.ip_src.s_addr
+ && packet->iphdr.ip_dst.s_addr == frags->packet.iphdr.ip_dst.s_addr) {
+
+ layer_tracef("frags %d found", packet->iphdr.ip_id);
+
+ /* Found it, remove from list */
+ if (frags_prev) {
+ frags_prev->next = frags->next;
+ }
+ if (ctx->fragments == frags) {
+ ctx->fragments = frags->next;
+ }
+ frags->next = 0;
+ break;
+ }
+ }
+
+ /* Check if frags is timed out */
+ if (ctx->conf.check_timeout && frags) {
+ struct timeval ts;
+
+ ts = frags->packet.pkthdr.ts;
+ ts.tv_sec += ctx->conf.timeout.tv_sec;
+ ts.tv_usec += ctx->conf.timeout.tv_usec;
+ ts.tv_usec %= 1000000;
+ if (packet->pkthdr.ts.tv_sec > ts.tv_sec
+ || (packet->pkthdr.ts.tv_sec == ts.tv_sec
+ && packet->pkthdr.ts.tv_usec > ts.tv_usec)) {
+
+ pcap_thread_ext_frag_fragment_t* f;
+
+ layer_tracef("frags timed out (last: %lu.%lu, this: %lu.%lu)",
+ frags->packet.pkthdr.ts.tv_sec, frags->packet.pkthdr.ts.tv_usec,
+ packet->pkthdr.ts.tv_sec, packet->pkthdr.ts.tv_usec);
+
+ if (ctx->conf.timeout_callback)
+ ctx->conf.timeout_callback(packet, payload, length, frags);
+
+ for (f = frags->fragments; f;) {
+ frag = f;
+ f = f->next;
+ if (frag->payload) {
+ free(frag->payload);
+ }
+ free(frag);
+ }
+
+ if (frags->payload) {
+ free(frags->payload);
+ }
+ free(frags);
+ frags = 0;
+ } else {
+ frags->packet.pkthdr.ts = packet->pkthdr.ts;
+ }
+ }
+
+ /* No fragments found, create new */
+ if (!frags) {
+ if (ctx->num_fragments >= ctx->conf.fragments) {
+ layer_trace("too many frags");
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+
+ if (!(frags = calloc(1, sizeof(pcap_thread_ext_frag_fragments_t)))) {
+ layer_trace("nomem frags");
+ return PCAP_THREAD_PACKET_ENOMEM;
+ }
+
+ layer_tracef("new frags %d", packet->iphdr.ip_id);
+
+ // TODO: How to handle prevpkt
+ memcpy(&(frags->packet.iphdr), &(packet->iphdr), sizeof(struct ip));
+ frags->packet.have_iphdr = 1;
+ frags->packet.pkthdr.ts = packet->pkthdr.ts;
+
+ ctx->num_fragments++;
+ }
+ /* Put the fragments first on the list */
+ frags->next = ctx->fragments;
+ ctx->fragments = frags;
+
+ if (frags->payload) {
+ layer_trace("already reassembled");
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+
+ if (frags->num_fragments >= ctx->conf.per_packet) {
+ layer_trace("too many frags frag");
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+
+ /* Allocate for the new fragment */
+ if (!(frag = calloc(1, sizeof(pcap_thread_ext_frag_fragment_t)))) {
+ layer_trace("nomem frag");
+ return PCAP_THREAD_PACKET_ENOMEM;
+ }
+ if (!(frag->payload = calloc(1, length))) {
+ free(frag);
+ layer_trace("nomem frag");
+ return PCAP_THREAD_PACKET_ENOMEM;
+ }
+ memcpy(frag->payload, payload, length);
+ frag->length = length;
+ frag->offset = (packet->iphdr.ip_off & 0x1fff) * 8;
+ frag->flag_more_fragments = packet->iphdr.ip_off & 0x2000 ? 1 : 0;
+
+ return reassemble(ctx, packet, whole_packet, whole_payload, whole_length, frags, frag);
+}
+
+static pcap_thread_packet_state_t reassemble_ipv6(_ctx_t* ctx, const pcap_thread_packet_t* packet, const u_char* payload, size_t length, pcap_thread_packet_t** whole_packet, const u_char** whole_payload, size_t* whole_length)
+{
+ pcap_thread_ext_frag_fragments_t *frags, *frags_prev;
+ pcap_thread_ext_frag_fragment_t* frag;
+
+ layer_tracef("ipv6 ctx %p", ctx);
+
+ /* Find packet fragments */
+ for (frags_prev = 0, frags = ctx->fragments; frags; frags_prev = frags, frags = frags->next) {
+ if (frags->packet.have_ip6hdr
+ && packet->ip6frag.ip6f_ident == frags->packet.ip6frag.ip6f_ident
+ && !memcmp(&(packet->ip6hdr.ip6_src), &(frags->packet.ip6hdr.ip6_src), sizeof(struct in6_addr))
+ && ((!packet->have_ip6rtdst && !memcmp(&(packet->ip6hdr.ip6_dst), &(frags->packet.ip6hdr.ip6_dst), sizeof(struct in6_addr)))
+ || (packet->have_ip6rtdst && !memcmp(&(packet->ip6rtdst), &(frags->packet.ip6hdr.ip6_dst), sizeof(struct in6_addr))))) {
+
+ layer_tracef("frags %x found", packet->ip6frag.ip6f_ident);
+
+ /* Found it, remove from list */
+ if (frags_prev) {
+ frags_prev->next = frags->next;
+ }
+ if (ctx->fragments == frags) {
+ ctx->fragments = frags->next;
+ }
+ frags->next = 0;
+ break;
+ }
+ }
+
+ /* Check if frags is timed out */
+ if (ctx->conf.check_timeout && frags) {
+ struct timeval ts;
+
+ ts = frags->packet.pkthdr.ts;
+ ts.tv_sec += ctx->conf.timeout.tv_sec;
+ ts.tv_usec += ctx->conf.timeout.tv_usec;
+ ts.tv_usec %= 1000000;
+ if (packet->pkthdr.ts.tv_sec > ts.tv_sec
+ || (packet->pkthdr.ts.tv_sec == ts.tv_sec
+ && packet->pkthdr.ts.tv_usec > ts.tv_usec)) {
+
+ pcap_thread_ext_frag_fragment_t* f;
+
+ layer_tracef("frags timed out (last: %lu.%lu, this: %lu.%lu)",
+ frags->packet.pkthdr.ts.tv_sec, frags->packet.pkthdr.ts.tv_usec,
+ packet->pkthdr.ts.tv_sec, packet->pkthdr.ts.tv_usec);
+
+ if (ctx->conf.timeout_callback)
+ ctx->conf.timeout_callback(packet, payload, length, frags);
+
+ for (f = frags->fragments; f;) {
+ frag = f;
+ f = f->next;
+ if (frag->payload) {
+ free(frag->payload);
+ }
+ free(frag);
+ }
+
+ if (frags->payload) {
+ free(frags->payload);
+ }
+ free(frags);
+ frags = 0;
+ } else {
+ frags->packet.pkthdr.ts = packet->pkthdr.ts;
+ }
+ }
+
+ /* No fragments found, create new */
+ if (!frags) {
+ if (ctx->num_fragments >= ctx->conf.fragments) {
+ layer_trace("too many frags");
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+
+ if (!(frags = calloc(1, sizeof(pcap_thread_ext_frag_fragments_t)))) {
+ layer_trace("nomem frags");
+ return PCAP_THREAD_PACKET_ENOMEM;
+ }
+
+ layer_tracef("new frags %x", packet->ip6frag.ip6f_ident);
+
+ // TODO: How to handle prevpkt
+ memcpy(&(frags->packet.ip6hdr), &(packet->ip6hdr), sizeof(struct ip6_hdr));
+ frags->packet.have_ip6hdr = 1;
+ memcpy(&(frags->packet.ip6frag), &(packet->ip6frag), sizeof(struct ip6_frag));
+ frags->packet.have_ip6frag = 1;
+ frags->packet.ip6frag_payload = packet->ip6frag_payload;
+ if (packet->have_ip6rtdst) {
+ frags->packet.ip6hdr.ip6_dst = packet->ip6rtdst;
+ }
+ frags->packet.pkthdr.ts = packet->pkthdr.ts;
+
+ ctx->num_fragments++;
+ } else {
+ if (frags->packet.ip6frag_payload != packet->ip6frag_payload) {
+ layer_trace("wrong payload");
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+ }
+ /* Put the fragments first on the list */
+ frags->next = ctx->fragments;
+ ctx->fragments = frags;
+
+ if (frags->payload) {
+ layer_trace("already reassembled");
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+
+ if (frags->num_fragments >= ctx->conf.per_packet) {
+ layer_trace("too many frags frag");
+ return PCAP_THREAD_PACKET_INVALID_FRAGMENT;
+ }
+
+ /* Allocate for the new fragment */
+ if (!(frag = calloc(1, sizeof(pcap_thread_ext_frag_fragment_t)))) {
+ layer_trace("nomem frag");
+ return PCAP_THREAD_PACKET_ENOMEM;
+ }
+ if (!(frag->payload = calloc(1, length))) {
+ free(frag);
+ layer_trace("nomem frag");
+ return PCAP_THREAD_PACKET_ENOMEM;
+ }
+ memcpy(frag->payload, payload, length);
+ frag->length = length;
+ frag->offset = ((packet->ip6frag.ip6f_offlg & 0xfff8) >> 3) * 8;
+ frag->flag_more_fragments = packet->ip6frag.ip6f_offlg & 0x1 ? 1 : 0;
+
+ return reassemble(ctx, packet, whole_packet, whole_payload, whole_length, frags, frag);
+}
+
+#ifdef HAVE_PTHREAD /* _release() is only used when mutex functions fails */
+static void _release(_ctx_t* ctx, const pcap_thread_packet_t* packet)
+{
+ pcap_thread_ext_frag_fragments_t *frags, *frags_prev;
+
+ layer_tracef("release ctx %p", ctx);
+
+ /* Find packet fragments */
+ for (frags_prev = 0, frags = ctx->fragments; frags; frags_prev = frags, frags = frags->next) {
+ if (frags->packet.have_iphdr
+ && packet->iphdr.ip_id == frags->packet.iphdr.ip_id
+ && packet->iphdr.ip_p == frags->packet.iphdr.ip_p
+ && packet->iphdr.ip_src.s_addr == frags->packet.iphdr.ip_src.s_addr
+ && packet->iphdr.ip_dst.s_addr == frags->packet.iphdr.ip_dst.s_addr) {
+
+ layer_tracef("release frags %d", packet->iphdr.ip_id);
+ break;
+ } else if (frags->packet.have_ip6hdr
+ && packet->ip6frag.ip6f_ident == frags->packet.ip6frag.ip6f_ident
+ && !memcmp(&(packet->ip6hdr.ip6_src), &(frags->packet.ip6hdr.ip6_src), sizeof(struct in6_addr))
+ && ((!packet->have_ip6rtdst && !memcmp(&(packet->ip6hdr.ip6_dst), &(frags->packet.ip6hdr.ip6_dst), sizeof(struct in6_addr)))
+ || (packet->have_ip6rtdst && !memcmp(&(packet->ip6rtdst), &(frags->packet.ip6hdr.ip6_dst), sizeof(struct in6_addr))))) {
+
+ layer_tracef("release frags %x", packet->ip6frag.ip6f_ident);
+ break;
+ }
+ }
+
+ if (frags) {
+ pcap_thread_ext_frag_fragment_t *frag, *f;
+
+ /* Found it, remove from list */
+ if (frags_prev) {
+ frags_prev->next = frags->next;
+ }
+ if (ctx->fragments == frags) {
+ ctx->fragments = frags->next;
+ }
+ frags->next = 0;
+ ctx->num_fragments--;
+
+ for (f = frags->fragments; f;) {
+ frag = f;
+ f = f->next;
+ if (frag->payload) {
+ free(frag->payload);
+ }
+ free(frag);
+ }
+
+ if (frags->payload) {
+ free(frags->payload);
+ }
+ free(frags);
+ }
+}
+#endif
+
+static pcap_thread_packet_state_t pcap_thread_layer_callback_frag_reassemble(void* _ctx, const pcap_thread_packet_t* packet, const u_char* payload, size_t length, pcap_thread_packet_t** whole_packet, const u_char** whole_payload, size_t* whole_length)
+{
+ _ctx_t* ctx = (_ctx_t*)_ctx;
+ pcap_thread_packet_state_t state = PCAP_THREAD_PACKET_INVALID;
+
+ if (!ctx) {
+ return PCAP_THREAD_PACKET_INVALID;
+ }
+ if (!packet) {
+ return PCAP_THREAD_PACKET_INVALID;
+ }
+ if (!payload) {
+ return PCAP_THREAD_PACKET_INVALID;
+ }
+ if (!length) {
+ return PCAP_THREAD_PACKET_INVALID;
+ }
+ if (!whole_packet) {
+ return PCAP_THREAD_PACKET_INVALID;
+ }
+ if (!whole_payload) {
+ return PCAP_THREAD_PACKET_INVALID;
+ }
+ if (!whole_length) {
+ return PCAP_THREAD_PACKET_INVALID;
+ }
+
+ if (ctx && packet && payload && length
+ && whole_packet && whole_payload && whole_length) {
+ if (packet->have_iphdr) {
+#ifdef HAVE_PTHREAD
+ if (pthread_mutex_lock(&(ctx->mutex))) {
+ return PCAP_THREAD_PACKET_EMUTEX;
+ }
+#endif
+ state = reassemble_ipv4(ctx, packet, payload, length, whole_packet, whole_payload, whole_length);
+#ifdef HAVE_PTHREAD
+ if (pthread_mutex_unlock(&(ctx->mutex))) {
+ if (state == PCAP_THREAD_PACKET_OK && *whole_packet && *whole_payload && *whole_length) {
+ _release(ctx, *whole_packet);
+ }
+ return PCAP_THREAD_PACKET_EMUTEX;
+ }
+#endif
+ } else if (packet->have_ip6hdr && packet->have_ip6frag) {
+#ifdef HAVE_PTHREAD
+ if (pthread_mutex_lock(&(ctx->mutex))) {
+ return PCAP_THREAD_PACKET_EMUTEX;
+ }
+#endif
+ state = reassemble_ipv6(ctx, packet, payload, length, whole_packet, whole_payload, whole_length);
+#ifdef HAVE_PTHREAD
+ if (pthread_mutex_unlock(&(ctx->mutex))) {
+ if (state == PCAP_THREAD_PACKET_OK && *whole_packet && *whole_payload && *whole_length) {
+ _release(ctx, *whole_packet);
+ }
+ return PCAP_THREAD_PACKET_EMUTEX;
+ }
+#endif
+ }
+ }
+
+ return state;
+}
+
+static void pcap_thread_layer_callback_frag_release(void* _ctx, const pcap_thread_packet_t* packet, const u_char* payload, size_t length)
+{
+ _ctx_t* ctx = (_ctx_t*)_ctx;
+ pcap_thread_ext_frag_fragments_t *frags, *frags_prev;
+
+ if (!ctx) {
+ return;
+ }
+ if (!packet) {
+ return;
+ }
+ if (packet->have_ip6hdr) {
+ if (!packet->have_ip6frag) {
+ return;
+ }
+ } else if (!packet->have_iphdr) {
+ return;
+ }
+
+#ifdef HAVE_PTHREAD
+ if (pthread_mutex_lock(&(ctx->mutex))) {
+ return;
+ }
+#endif
+
+ /* Find packet fragments */
+ for (frags_prev = 0, frags = ctx->fragments; frags; frags_prev = frags, frags = frags->next) {
+ if ((frags->packet.have_iphdr
+ && packet->iphdr.ip_id == frags->packet.iphdr.ip_id
+ && packet->iphdr.ip_p == frags->packet.iphdr.ip_p
+ && packet->iphdr.ip_src.s_addr == frags->packet.iphdr.ip_src.s_addr
+ && packet->iphdr.ip_dst.s_addr == frags->packet.iphdr.ip_dst.s_addr)
+ || (frags->packet.have_ip6hdr
+ && packet->ip6frag.ip6f_ident == frags->packet.ip6frag.ip6f_ident
+ && !memcmp(&(packet->ip6hdr.ip6_src), &(frags->packet.ip6hdr.ip6_src), sizeof(struct in6_addr))
+ && ((!packet->have_ip6rtdst && !memcmp(&(packet->ip6hdr.ip6_dst), &(frags->packet.ip6hdr.ip6_dst), sizeof(struct in6_addr)))
+ || (packet->have_ip6rtdst && !memcmp(&(packet->ip6rtdst), &(frags->packet.ip6hdr.ip6_dst), sizeof(struct in6_addr)))))) {
+
+ /* Found it, remove from list */
+ if (frags_prev) {
+ frags_prev->next = frags->next;
+ }
+ if (ctx->fragments == frags) {
+ ctx->fragments = frags->next;
+ }
+ frags->next = 0;
+ ctx->num_fragments--;
+ break;
+ }
+ }
+
+#ifdef HAVE_PTHREAD
+ pthread_mutex_unlock(&(ctx->mutex));
+#endif
+
+ if (frags) {
+ pcap_thread_ext_frag_fragment_t *frag, *f;
+
+ for (f = frags->fragments; f;) {
+ frag = f;
+ f = f->next;
+ if (frag->payload) {
+ free(frag->payload);
+ }
+ free(frag);
+ }
+
+ if (frags->payload) {
+ free(frags->payload);
+ }
+ free(frags);
+ }
+}
diff --git a/src/pcap-thread/pcap_thread_ext_frag.h b/src/pcap-thread/pcap_thread_ext_frag.h
new file mode 100644
index 0000000..dfa151a
--- /dev/null
+++ b/src/pcap-thread/pcap_thread_ext_frag.h
@@ -0,0 +1,131 @@
+/*
+ * Author Jerry Lundström <jerry@dns-oarc.net>
+ * Copyright (c) 2016-2017, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pcap_thread.h"
+
+#ifndef __pcap_thread_ext_frag_h
+#define __pcap_thread_ext_frag_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * RFC791 - Handle fragments in an offset ascending order, allow fragments to overlap
+ * RFC815 - Handle fragments in a receiving order, allow fragments to overlap
+ * BSD - Handle fragments in an offset descending order, allow fragments to overlap
+ */
+typedef enum pcap_thread_ext_frag_reassemble_mode pcap_thread_ext_frag_reassemble_mode_t;
+enum pcap_thread_ext_frag_reassemble_mode {
+ PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC791 = 0,
+ PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC815,
+ PCAP_THREAD_EXT_FRAG_REASSEMBLE_BSD
+};
+
+typedef struct pcap_thread_ext_frag_fragment pcap_thread_ext_frag_fragment_t;
+struct pcap_thread_ext_frag_fragment {
+ pcap_thread_ext_frag_fragment_t* next;
+
+ unsigned short flag_more_fragments : 1;
+
+ u_char* payload;
+ size_t length;
+ size_t offset;
+};
+
+typedef struct pcap_thread_ext_frag_fragments pcap_thread_ext_frag_fragments_t;
+struct pcap_thread_ext_frag_fragments {
+ pcap_thread_ext_frag_fragments_t* next;
+
+ pcap_thread_packet_t packet;
+ pcap_thread_ext_frag_fragment_t* fragments;
+ size_t num_fragments;
+ u_char* payload;
+ size_t length;
+};
+
+typedef void (*pcap_thread_ext_frag_callback_t)(const pcap_thread_packet_t* packet, const u_char* payload, size_t length, const pcap_thread_ext_frag_fragments_t* fragments);
+
+/* clang-format off */
+#define PCAP_THREAD_EXT_FRAG_CONF_T_INIT { \
+ 0, 0, \
+ PCAP_THREAD_EXT_FRAG_REASSEMBLE_RFC791, \
+ 100, 10, { 30, 0 }, \
+ 0, 0 \
+}
+/* clang-format on */
+
+typedef struct pcap_thread_ext_frag_conf pcap_thread_ext_frag_conf_t;
+struct pcap_thread_ext_frag_conf {
+ unsigned short reject_overlap : 1;
+ unsigned short check_timeout : 1;
+
+ pcap_thread_ext_frag_reassemble_mode_t reassemble_mode;
+
+ size_t fragments;
+ size_t per_packet;
+ struct timeval timeout;
+
+ pcap_thread_ext_frag_callback_t overlap_callback;
+ pcap_thread_ext_frag_callback_t timeout_callback;
+};
+
+pcap_thread_ext_frag_conf_t* pcap_thread_ext_frag_conf_new(void);
+void pcap_thread_ext_frag_conf_free(pcap_thread_ext_frag_conf_t* conf);
+
+int pcap_thread_ext_frag_conf_reject_overlap(const pcap_thread_ext_frag_conf_t* conf);
+int pcap_thread_ext_frag_conf_set_reject_overlap(pcap_thread_ext_frag_conf_t* conf, const int reject_overlap);
+int pcap_thread_ext_frag_conf_check_timeout(const pcap_thread_ext_frag_conf_t* conf);
+int pcap_thread_ext_frag_conf_set_check_timeout(pcap_thread_ext_frag_conf_t* conf, const int check_timeout);
+pcap_thread_ext_frag_reassemble_mode_t pcap_thread_ext_frag_conf_reassemble_mode(const pcap_thread_ext_frag_conf_t* conf);
+int pcap_thread_ext_frag_conf_set_reassemble_mode(pcap_thread_ext_frag_conf_t* conf, const pcap_thread_ext_frag_reassemble_mode_t reassemble_mode);
+size_t pcap_thread_ext_frag_conf_fragments(const pcap_thread_ext_frag_conf_t* conf);
+int pcap_thread_ext_frag_conf_set_fragments(pcap_thread_ext_frag_conf_t* conf, const size_t fragments);
+size_t pcap_thread_ext_frag_conf_per_packet(const pcap_thread_ext_frag_conf_t* conf);
+int pcap_thread_ext_frag_conf_set_per_packet(pcap_thread_ext_frag_conf_t* conf, const size_t per_packet);
+struct timeval pcap_thread_ext_frag_conf_timeout(const pcap_thread_ext_frag_conf_t* conf);
+int pcap_thread_ext_frag_conf_set_timeout(pcap_thread_ext_frag_conf_t* conf, const struct timeval timeout);
+pcap_thread_ext_frag_callback_t pcap_thread_ext_frag_conf_overlap_callback(const pcap_thread_ext_frag_conf_t* conf);
+int pcap_thread_ext_frag_conf_set_overlap_callback(pcap_thread_ext_frag_conf_t* conf, pcap_thread_ext_frag_callback_t overlap_callback);
+pcap_thread_ext_frag_callback_t pcap_thread_ext_frag_conf_timeout_callback(const pcap_thread_ext_frag_conf_t* conf);
+int pcap_thread_ext_frag_conf_set_timeout_callback(pcap_thread_ext_frag_conf_t* conf, pcap_thread_ext_frag_callback_t timeout_callback);
+
+pcap_thread_layer_callback_frag_t pcap_thread_ext_frag_layer_callback(pcap_thread_ext_frag_conf_t* conf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __pcap_thread_ext_frag_h */
diff --git a/src/pcaps.c b/src/pcaps.c
new file mode 100644
index 0000000..9cb6b7b
--- /dev/null
+++ b/src/pcaps.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "pcaps.h"
+#include "log.h"
+#include "network.h"
+
+#include "pcap-thread/pcap_thread_ext_frag.h"
+
+static void
+drop_pkt(u_char* user, const struct pcap_pkthdr* hdr, const u_char* pkt, const char* name, const int dlt)
+{
+ mypcap_ptr mypcap = (mypcap_ptr)user;
+
+ pcap_drops++;
+ if (mypcap) {
+ mypcap->drops++;
+ }
+}
+
+void print_pcap_thread_error(const char* func, int err)
+{
+ if (err == PCAP_THREAD_EPCAP) {
+ fprintf(stderr, "%s: pcap_thread libpcap error [%d] %s: %s (%s)\n",
+ ProgramName,
+ pcap_thread_status(&pcap_thread),
+ func,
+ pcap_statustostr(pcap_thread_status(&pcap_thread)),
+ pcap_thread_errbuf(&pcap_thread));
+ } else if (err != PCAP_THREAD_OK) {
+ fprintf(stderr, "%s: pcap_thread error [%d] %s: %s\n",
+ ProgramName,
+ err,
+ func,
+ pcap_thread_strerr(err));
+ }
+}
+
+static pcap_thread_ext_frag_conf_t frag_conf_v4 = PCAP_THREAD_EXT_FRAG_CONF_T_INIT;
+static pcap_thread_ext_frag_conf_t frag_conf_v6 = PCAP_THREAD_EXT_FRAG_CONF_T_INIT;
+
+void open_pcaps(void)
+{
+ mypcap_ptr mypcap;
+ int err;
+
+ if ((err = pcap_thread_set_snaplen(&pcap_thread, SNAPLEN)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_snaplen()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_promiscuous(&pcap_thread, promisc)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_promiscuous()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_monitor(&pcap_thread, monitor_mode)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_monitor()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_immediate_mode(&pcap_thread, immediate_mode)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_immediate_mode()", err);
+ exit(1);
+ }
+ if (options.use_layers) {
+ if ((err = pcap_thread_set_callback_icmp(&pcap_thread, layer_pkt)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_callback_icmp()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_callback_icmpv6(&pcap_thread, layer_pkt)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_callback_icmpv6()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_callback_udp(&pcap_thread, layer_pkt)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_callback_udp()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_callback_tcp(&pcap_thread, layer_pkt)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_callback_tcp()", err);
+ exit(1);
+ }
+
+ if ((err = pcap_thread_set_use_layers(&pcap_thread, 1)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_use_layers()", err);
+ exit(1);
+ }
+
+ if (options.defrag_ipv4) {
+ if (options.max_ipv4_fragments > 0 && (err = pcap_thread_ext_frag_conf_set_fragments(&frag_conf_v4, options.max_ipv4_fragments)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_ext_frag_conf_set_fragments()", err);
+ exit(1);
+ }
+ if (options.max_ipv4_fragments_per_packet > 0 && (err = pcap_thread_ext_frag_conf_set_per_packet(&frag_conf_v4, options.max_ipv4_fragments_per_packet)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_ext_frag_conf_set_per_packet()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_callback_ipv4_frag(&pcap_thread, pcap_thread_ext_frag_layer_callback(&frag_conf_v4))) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_callback_ipv4_frag()", err);
+ exit(1);
+ }
+ }
+ if (options.defrag_ipv6) {
+ if (options.max_ipv6_fragments > 0 && (err = pcap_thread_ext_frag_conf_set_fragments(&frag_conf_v6, options.max_ipv6_fragments)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_ext_frag_conf_set_fragments()", err);
+ exit(1);
+ }
+ if (options.max_ipv6_fragments_per_packet > 0 && (err = pcap_thread_ext_frag_conf_set_per_packet(&frag_conf_v6, options.max_ipv6_fragments_per_packet)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_ext_frag_conf_set_per_packet()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_callback_ipv6_frag(&pcap_thread, pcap_thread_ext_frag_layer_callback(&frag_conf_v6))) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_callback_ipv6_frag()", err);
+ exit(1);
+ }
+ }
+ } else {
+ if ((err = pcap_thread_set_callback(&pcap_thread, dl_pkt)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_callback()", err);
+ exit(1);
+ }
+ }
+ if ((err = pcap_thread_set_dropback(&pcap_thread, drop_pkt)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_dropback()", err);
+ exit(1);
+ }
+ if ((err = pcap_thread_set_filter(&pcap_thread, bpft, strlen(bpft))) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_filter()", err);
+ exit(1);
+ }
+ if (options.pcap_buffer_size && (err = pcap_thread_set_buffer_size(&pcap_thread, options.pcap_buffer_size)) != PCAP_THREAD_OK) {
+ print_pcap_thread_error("pcap_thread_set_buffer_size()", err);
+ exit(1);
+ }
+
+ assert(!EMPTY(mypcaps));
+ for (mypcap = HEAD(mypcaps);
+ mypcap != NULL;
+ mypcap = NEXT(mypcap, link)) {
+ if (pcap_offline)
+ err = pcap_thread_open_offline(&pcap_thread, mypcap->name, (u_char*)mypcap);
+ else
+ err = pcap_thread_open(&pcap_thread, mypcap->name, (u_char*)mypcap);
+
+ if (err == PCAP_THREAD_EPCAP) {
+ fprintf(stderr, "%s: pcap_thread libpcap error [%d]: %s (%s)\n",
+ ProgramName,
+ pcap_thread_status(&pcap_thread),
+ pcap_statustostr(pcap_thread_status(&pcap_thread)),
+ pcap_thread_errbuf(&pcap_thread));
+ exit(1);
+ }
+ if (err) {
+ fprintf(stderr, "%s: pcap_thread error [%d]: %s\n",
+ ProgramName,
+ err,
+ pcap_thread_strerr(err));
+ exit(1);
+ }
+ }
+ pcap_dead = pcap_open_dead(DLT_RAW, SNAPLEN);
+}
+
+void poll_pcaps(void)
+{
+ pcap_thread_run(&pcap_thread);
+ main_exit = TRUE;
+}
+
+void breakloop_pcaps(void)
+{
+ pcap_thread_stop(&pcap_thread);
+}
+
+void close_pcaps(void)
+{
+ pcap_thread_close(&pcap_thread);
+}
+
+static void stat_callback(u_char* user, const struct pcap_stat* stats, const char* name, int dlt)
+{
+ mypcap_ptr mypcap;
+ for (mypcap = HEAD(mypcaps);
+ mypcap != NULL;
+ mypcap = NEXT(mypcap, link)) {
+ if (!strcmp(name, mypcap->name))
+ break;
+ }
+
+ if (mypcap) {
+ mypcap->ps0 = mypcap->ps1;
+ mypcap->ps1 = *stats;
+ logerr("%s: %u recv %u drop %u total ptdrop %lu",
+ mypcap->name,
+ mypcap->ps1.ps_recv - mypcap->ps0.ps_recv,
+ mypcap->ps1.ps_drop - mypcap->ps0.ps_drop,
+ mypcap->ps1.ps_recv + mypcap->ps1.ps_drop - mypcap->ps0.ps_recv - mypcap->ps0.ps_drop,
+ mypcap->drops);
+ }
+}
+
+void do_pcap_stats()
+{
+ logerr("total drops: %lu", pcap_drops);
+ pcap_thread_stats(&pcap_thread, stat_callback, 0);
+}
diff --git a/src/pcaps.h b/src/pcaps.h
new file mode 100644
index 0000000..6e1e075
--- /dev/null
+++ b/src/pcaps.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_pcaps_h
+#define __dnscap_pcaps_h
+
+void print_pcap_thread_error(const char* func, int err);
+void open_pcaps(void);
+void poll_pcaps(void);
+void breakloop_pcaps(void);
+void close_pcaps(void);
+void do_pcap_stats();
+
+#endif /* __dnscap_pcaps_h */
diff --git a/src/sig.c b/src/sig.c
new file mode 100644
index 0000000..7e7376e
--- /dev/null
+++ b/src/sig.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "sig.h"
+#include "log.h"
+#include "dumper.h"
+#include "pcaps.h"
+
+void setsig(int sig, int oneshot)
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ if (oneshot) {
+ sa.sa_handler = sigbreak;
+ sa.sa_flags = SA_RESETHAND;
+ } else {
+ sa.sa_handler = sigclose;
+ sa.sa_flags = SA_RESTART;
+ }
+ if (sigaction(sig, &sa, NULL) < 0) {
+ logerr("sigaction: %s", strerror(errno));
+ exit(1);
+ }
+}
+
+void sigclose(int signum)
+{
+ if (0 == last_ts.tv_sec)
+ gettimeofday(&last_ts, NULL);
+ if (signum == SIGALRM)
+ alarm_set = FALSE;
+ if (dumper_close(last_ts))
+ breakloop_pcaps();
+}
+
+void sigbreak(int signum __attribute__((unused)))
+{
+ logerr("%s: signalled break", ProgramName);
+ main_exit = TRUE;
+ breakloop_pcaps();
+}
+
+void* sigthread(void* arg)
+{
+#if HAVE_PTHREAD
+ sigset_t* set = (sigset_t*)arg;
+ int sig, err;
+
+ while (1) {
+ if ((err = sigwait(set, &sig))) {
+ logerr("sigwait: %s", strerror(err));
+ return 0;
+ }
+
+ switch (sig) {
+ case SIGALRM:
+ sigclose(sig);
+ break;
+
+ default:
+ sigbreak(sig);
+ break;
+ }
+ }
+#endif
+
+ return 0;
+}
diff --git a/src/sig.h b/src/sig.h
new file mode 100644
index 0000000..c7b1296
--- /dev/null
+++ b/src/sig.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_sig_h
+#define __dnscap_sig_h
+
+void setsig(int sig, int oneshot);
+void sigclose(int signum);
+void sigbreak(int signum __attribute__((unused)));
+void* sigthread(void* arg);
+
+#endif /* __dnscap_sig_h */
diff --git a/src/tcpreasm.c b/src/tcpreasm.c
new file mode 100644
index 0000000..ce37b10
--- /dev/null
+++ b/src/tcpreasm.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2018-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "tcpreasm.h"
+#include "log.h"
+#include "network.h"
+
+#include <stdlib.h>
+#include <ldns/ldns.h>
+
+#define dfprintf(a, b...) \
+ if (dumptrace >= 3) { \
+ fprintf(stderr, b); \
+ fprintf(stderr, "\n"); \
+ }
+#define dsyslogf(a, b...) logerr(b)
+#define nptohs(p) ((((uint8_t*)(p))[0] << 8) | ((uint8_t*)(p))[1])
+
+#define BFB_BUF_SIZE (0xffff + 0xffff + 2 + 2)
+
+/*
+ * Originally from DSC:
+ *
+ * TCP Reassembly.
+ *
+ * When we see a SYN, we allocate a new tcpstate for the connection, and
+ * establish the initial sequence number of the first dns message (seq_start)
+ * on the connection. We assume that no other segment can arrive before the
+ * SYN (if one does, it is discarded, and if is not repeated the message it
+ * belongs to can never be completely reassembled).
+ *
+ * Then, for each segment that arrives on the connection:
+ * - If it's the first segment of a message (containing the 2-byte message
+ * length), we allocate a msgbuf, and check for any held segments that might
+ * belong to it.
+ * - If the first byte of the segment belongs to any msgbuf, we fill
+ * in the holes of that message. If the message has no more holes, we
+ * handle the complete dns message. If the tail of the segment was longer
+ * than the hole, we recurse on the tail.
+ * - Otherwise, if the segment could be within the tcp window, we hold onto it
+ * pending the creation of a matching msgbuf.
+ *
+ * This algorithm handles segments that arrive out of order, duplicated or
+ * overlapping (including segments from different dns messages arriving out of
+ * order), and dns messages that do not necessarily start on segment
+ * boundaries.
+ *
+ */
+
+static int dns_protocol_handler(tcpreasm_t* t, u_char* segment, uint16_t dnslen, uint32_t seq)
+{
+ int m;
+
+ if (options.reassemble_tcp_bfbparsedns) {
+ int s;
+ ldns_pkt* pkt;
+ size_t at, len;
+
+ if (!t->bfb_buf && !(t->bfb_buf = malloc(BFB_BUF_SIZE))) {
+ dfprintf(1, "dns_protocol_handler: no memory for bfb_buf");
+ return 1;
+ }
+
+ /* if this is the first segment, add it to the processing buffer
+ and move up to next wanted segment */
+ if (seq == t->seq_bfb + 2) {
+ dfprintf(1, "dns_protocol_handler: first bfb_seg: seq = %u, len = %d", seq, dnslen);
+ if ((BFB_BUF_SIZE - t->bfb_at) < (dnslen + 2)) {
+ dfprintf(1, "dns_protocol_handler: out of space in bfb_buf");
+ return 1;
+ }
+
+ t->bfb_buf[t->bfb_at++] = dnslen >> 8;
+ t->bfb_buf[t->bfb_at++] = dnslen & 0xff; //NOSONAR
+ memcpy(&t->bfb_buf[t->bfb_at], segment, dnslen);
+ t->bfb_at += dnslen;
+ t->seq_bfb += 2 + dnslen;
+ } else {
+ /* add segment for later processing */
+ dfprintf(1, "dns_protocol_handler: add bfb_seg: seq = %u, len = %d", seq, dnslen);
+ for (s = 0; s < MAX_TCP_SEGS; s++) {
+ if (t->bfb_seg[s])
+ continue;
+ t->bfb_seg[s] = calloc(1, sizeof(tcp_segbuf_t) + dnslen);
+ t->bfb_seg[s]->seq = seq;
+ t->bfb_seg[s]->len = dnslen;
+ memcpy(t->bfb_seg[s]->buf, segment, dnslen);
+ dfprintf(1, "dns_protocol_handler: new bfbseg %d: seq = %u, len = %d",
+ s, t->bfb_seg[s]->seq, t->bfb_seg[s]->len);
+ break;
+ }
+ if (s >= MAX_TCP_SEGS) {
+ dfprintf(1, "dns_protocol_handler: out of bfbsegs");
+ return 1;
+ }
+ return 0;
+ }
+
+ for (;;) {
+ /* process the buffer, extract dnslen and try and parse */
+ at = 0;
+ len = t->bfb_at;
+ for (;;) {
+ dfprintf(1, "dns_protocol_handler: processing at = %zu, len = %zu", at, len);
+ if (len < 2) {
+ dfprintf(1, "dns_protocol_handler: bfb need more for dnslen");
+ break;
+ }
+ dnslen = nptohs(&t->bfb_buf[at]) & 0xffff;
+ if (dnslen > 11) {
+ /* 12 bytes minimum DNS header, other lengths should be invalid */
+ if (len < dnslen + 2) {
+ dfprintf(1, "dns_protocol_handler: bfb need %zu more", dnslen - len);
+ break;
+ }
+
+ if (ldns_wire2pkt(&pkt, &t->bfb_buf[at + 2], dnslen) == LDNS_STATUS_OK) {
+ ldns_pkt_free(pkt);
+ dfprintf(1, "dns_protocol_handler: dns at %zu len %u", at + 2, dnslen);
+
+ for (m = 0; t->dnsmsg[m];) {
+ if (++m >= MAX_TCP_DNS_MSG) {
+ dfprintf(1, "dns_protocol_handler: %s", "out of dnsmsgs");
+ return 1;
+ }
+ }
+ if (!(t->dnsmsg[m] = calloc(1, sizeof(tcpdnsmsg_t) + dnslen))) {
+ dsyslogf(LOG_ERR, "out of memory for dnsmsg (%d)", dnslen);
+ return 1;
+ }
+ t->dnsmsgs++;
+ t->dnsmsg[m]->dnslen = dnslen;
+ memcpy(t->dnsmsg[m]->dnspkt, &t->bfb_buf[at + 2], dnslen);
+ dfprintf(1, "dns_protocol_handler: new dnsmsg %d: dnslen = %d", m, dnslen);
+
+ at += 2 + dnslen;
+ len -= 2 + dnslen;
+ continue;
+ }
+ if (errno == EMSGSIZE) {
+ size_t l = calcdnslen(&t->bfb_buf[at + 2], dnslen);
+ if (l > 0 && l < dnslen && ldns_wire2pkt(&pkt, &t->bfb_buf[at + 2], l) == LDNS_STATUS_OK) {
+ ldns_pkt_free(pkt);
+ dfprintf(1, "dns_protocol_handler: dns at %zu len %u (real len %zu)", at + 2, dnslen, l);
+
+ for (m = 0; t->dnsmsg[m];) {
+ if (++m >= MAX_TCP_DNS_MSG) {
+ dfprintf(1, "dns_protocol_handler: %s", "out of dnsmsgs");
+ return 1;
+ }
+ }
+ if (!(t->dnsmsg[m] = calloc(1, sizeof(tcpdnsmsg_t) + dnslen))) {
+ dsyslogf(LOG_ERR, "out of memory for dnsmsg (%d)", dnslen);
+ return 1;
+ }
+ t->dnsmsgs++;
+ t->dnsmsg[m]->dnslen = dnslen;
+ memcpy(t->dnsmsg[m]->dnspkt, &t->bfb_buf[at + 2], dnslen);
+ dfprintf(1, "dns_protocol_handler: new dnsmsg %d: dnslen = %d", m, dnslen);
+
+ at += 2 + dnslen;
+ len -= 2 + dnslen;
+ continue;
+ }
+ }
+ }
+ dfprintf(1, "dns_protocol_handler: bfb dns parse failed at %zu", at);
+ at += 2;
+ len -= 2;
+ }
+
+ /* check for leftovers in the buffer */
+ if (!len) {
+ dfprintf(1, "dns_protocol_handler: bfb all buf parsed, reset at");
+ t->bfb_at = 0;
+ } else if (len && at) {
+ dfprintf(1, "dns_protocol_handler: bfb move %zu len %zu", at, len);
+ memmove(t->bfb_buf, &t->bfb_buf[at], len);
+ t->bfb_at = len;
+ }
+
+ dfprintf(1, "dns_protocol_handler: bfb fill at %zu", t->bfb_at);
+ /* see if we can fill the buffer */
+ for (s = 0; s < MAX_TCP_SEGS; s++) {
+ if (!t->bfb_seg[s])
+ continue;
+
+ if (t->bfb_seg[s]->seq == t->seq_bfb + 2) {
+ tcp_segbuf_t* seg = t->bfb_seg[s];
+ dfprintf(1, "dns_protocol_handler: next bfb_seg %d: seq = %u, len = %d", s, seg->seq, seg->len);
+ if ((BFB_BUF_SIZE - t->bfb_at) < (seg->len + 2)) {
+ dfprintf(1, "dns_protocol_handler: out of space in bfb_buf");
+ return 1;
+ }
+ t->bfb_seg[s] = 0;
+ t->bfb_buf[t->bfb_at++] = seg->len >> 8;
+ t->bfb_buf[t->bfb_at++] = seg->len & 0xff;
+ memcpy(&t->bfb_buf[t->bfb_at], seg->buf, seg->len);
+ t->bfb_at += seg->len;
+ t->seq_bfb += 2 + seg->len;
+ free(seg);
+ break;
+ }
+ }
+ if (s >= MAX_TCP_SEGS) {
+ dfprintf(1, "dns_protocol_handler: bfb need next seg");
+ return 0;
+ }
+ }
+ }
+
+ for (m = 0; t->dnsmsg[m];) {
+ if (++m >= MAX_TCP_DNS_MSG) {
+ dfprintf(1, "dns_protocol_handler: %s", "out of dnsmsgs");
+ return 1;
+ }
+ }
+ t->dnsmsg[m] = calloc(1, sizeof(tcpdnsmsg_t) + dnslen);
+ if (NULL == t->dnsmsg[m]) {
+ dsyslogf(LOG_ERR, "out of memory for dnsmsg (%d)", dnslen);
+ return 1;
+ }
+ t->dnsmsgs++;
+ t->dnsmsg[m]->segments_seen = t->segments_seen;
+ t->dnsmsg[m]->dnslen = dnslen;
+ memcpy(t->dnsmsg[m]->dnspkt, segment, dnslen);
+ dfprintf(1, "dns_protocol_handler: new dnsmsg %d: dnslen = %d", m, dnslen);
+ t->segments_seen = 0;
+ return 0;
+}
+
+int pcap_handle_tcp_segment(u_char* segment, int len, uint32_t seq, tcpstate_ptr _tcpstate)
+{
+ int i, m, s, ret;
+ uint16_t dnslen;
+ int segoff, seglen;
+ tcpreasm_t* tcpstate = _tcpstate->reasm;
+
+ dfprintf(1, "pcap_handle_tcp_segment: seq=%u, len=%d", seq, len);
+
+ if (len <= 0) /* there is no more payload */
+ return 0;
+
+ tcpstate->segments_seen++;
+
+ if (seq - tcpstate->seq_start < 2) {
+ /* this segment contains all or part of the 2-byte DNS length field */
+ uint32_t o = seq - tcpstate->seq_start;
+ int l = (len > 1 && o == 0) ? 2 : 1;
+ dfprintf(1, "pcap_handle_tcp_segment: copying %d bytes to dnslen_buf[%d]", l, o);
+ memcpy(&tcpstate->dnslen_buf[o], segment, l);
+ if (l == 2)
+ tcpstate->dnslen_bytes_seen_mask = 3;
+ else
+ tcpstate->dnslen_bytes_seen_mask |= (1 << o);
+ len -= l;
+ segment += l;
+ seq += l;
+ }
+
+ if (3 == tcpstate->dnslen_bytes_seen_mask) {
+ /* We have the dnslen stored now */
+ dnslen = nptohs(tcpstate->dnslen_buf) & 0xffff;
+ /*
+ * Next we poison the mask to indicate we are in to the message body.
+ * If one doesn't remember we're past the then,
+ * one loops forever getting more msgbufs rather than filling
+ * in the contents of THIS message.
+ *
+ * We need to later reset that mask when we process the message
+ * (method: tcpstate->dnslen_bytes_seen_mask = 0).
+ */
+ tcpstate->dnslen_bytes_seen_mask = 7;
+ tcpstate->seq_start += sizeof(uint16_t) + dnslen;
+ dfprintf(1, "pcap_handle_tcp_segment: first segment; dnslen = %d", dnslen);
+ if (len >= dnslen) {
+ /* this segment contains a complete message - avoid the reassembly
+ * buffer and just handle the message immediately */
+ ret = dns_protocol_handler(tcpstate, segment, dnslen, seq);
+
+ tcpstate->dnslen_bytes_seen_mask = 0; /* go back for another message in this tcp connection */
+ /* handle the trailing part of the segment? */
+ if (len > dnslen) {
+ dfprintf(1, "pcap_handle_tcp_segment: %s", "segment tail");
+ ret |= pcap_handle_tcp_segment(segment + dnslen, len - dnslen, seq + dnslen, _tcpstate);
+ }
+ return ret;
+ }
+ /*
+ * At this point we KNOW we have an incomplete message and need to do reassembly.
+ * i.e.: assert(len < dnslen);
+ */
+ dfprintf(2, "pcap_handle_tcp_segment: %s", "buffering segment");
+ /* allocate a msgbuf for reassembly */
+ for (m = 0; tcpstate->msgbuf[m];) {
+ if (++m >= MAX_TCP_MSGS) {
+ dfprintf(1, "pcap_handle_tcp_segment: %s", "out of msgbufs");
+ return 1;
+ }
+ }
+ tcpstate->msgbuf[m] = calloc(1, sizeof(tcp_msgbuf_t) + dnslen);
+ if (NULL == tcpstate->msgbuf[m]) {
+ dsyslogf(LOG_ERR, "out of memory for tcp_msgbuf (%d)", dnslen);
+ return 1;
+ }
+ tcpstate->msgbufs++;
+ tcpstate->msgbuf[m]->seq = seq;
+ tcpstate->msgbuf[m]->dnslen = dnslen;
+ tcpstate->msgbuf[m]->holes = 1;
+ tcpstate->msgbuf[m]->hole[0].start = len;
+ tcpstate->msgbuf[m]->hole[0].len = dnslen - len;
+ dfprintf(1,
+ "pcap_handle_tcp_segment: new msgbuf %d: seq = %u, dnslen = %d, hole start = %d, hole len = %d", m,
+ tcpstate->msgbuf[m]->seq, tcpstate->msgbuf[m]->dnslen, tcpstate->msgbuf[m]->hole[0].start,
+ tcpstate->msgbuf[m]->hole[0].len);
+ /* copy segment to appropriate location in reassembly buffer */
+ memcpy(tcpstate->msgbuf[m]->buf, segment, len);
+
+ /* Now that we know the length of this message, we must check any held
+ * segments to see if they belong to it. */
+ ret = 0;
+ for (s = 0; s < MAX_TCP_SEGS; s++) {
+ if (!tcpstate->segbuf[s])
+ continue;
+ /* TODO: seq >= 0 */
+ if (tcpstate->segbuf[s]->seq - seq > 0 && tcpstate->segbuf[s]->seq - seq < dnslen) {
+ tcp_segbuf_t* segbuf = tcpstate->segbuf[s];
+ tcpstate->segbuf[s] = NULL;
+ dfprintf(1, "pcap_handle_tcp_segment: %s", "message reassembled");
+ ret |= pcap_handle_tcp_segment(segbuf->buf, segbuf->len, segbuf->seq, _tcpstate);
+ /*
+ * Note that our recursion will also cover any tail messages (I hope).
+ * Thus we do not need to do so here and can return.
+ */
+ free(segbuf);
+ }
+ }
+ return ret;
+ }
+
+ /*
+ * Welcome to reassembly-land.
+ */
+ /* find the message to which the first byte of this segment belongs */
+ for (m = 0; m < MAX_TCP_MSGS; m++) {
+ if (!tcpstate->msgbuf[m])
+ continue;
+ segoff = seq - tcpstate->msgbuf[m]->seq;
+ if (segoff >= 0 && segoff < tcpstate->msgbuf[m]->dnslen) {
+ /* segment starts in this msgbuf */
+ dfprintf(1, "pcap_handle_tcp_segment: seg matches msg %d: seq = %u, dnslen = %d",
+ m, tcpstate->msgbuf[m]->seq, tcpstate->msgbuf[m]->dnslen);
+ if (segoff + len > tcpstate->msgbuf[m]->dnslen) {
+ /* segment would overflow msgbuf */
+ seglen = tcpstate->msgbuf[m]->dnslen - segoff;
+ dfprintf(1, "pcap_handle_tcp_segment: using partial segment %d", seglen);
+ } else {
+ seglen = len;
+ }
+ break;
+ }
+ }
+ if (m >= MAX_TCP_MSGS) {
+ /* seg does not match any msgbuf; just hold on to it. */
+ dfprintf(1, "pcap_handle_tcp_segment: %s", "seg does not match any msgbuf");
+
+ if (seq - tcpstate->seq_start > MAX_TCP_WINDOW_SIZE) {
+ dfprintf(1, "pcap_handle_tcp_segment: %s %u %u", "seg is outside window; discarding", seq, tcpstate->seq_start);
+ return 1;
+ }
+ for (s = 0; s < MAX_TCP_SEGS; s++) {
+ if (tcpstate->segbuf[s])
+ continue;
+ tcpstate->segbuf[s] = calloc(1, sizeof(tcp_segbuf_t) + len);
+ tcpstate->segbuf[s]->seq = seq;
+ tcpstate->segbuf[s]->len = len;
+ memcpy(tcpstate->segbuf[s]->buf, segment, len);
+ dfprintf(1, "pcap_handle_tcp_segment: new segbuf %d: seq = %u, len = %d",
+ s, tcpstate->segbuf[s]->seq, tcpstate->segbuf[s]->len);
+ return 0;
+ }
+ dfprintf(1, "pcap_handle_tcp_segment: %s", "out of segbufs");
+ return 1;
+ }
+
+ /* Reassembly algorithm adapted from RFC 815. */
+ for (i = 0; i < MAX_TCP_HOLES; i++) {
+ tcphole_t* newhole;
+ uint16_t hole_start, hole_len;
+ if (tcpstate->msgbuf[m]->hole[i].len == 0)
+ continue; /* hole descriptor is not in use */
+ hole_start = tcpstate->msgbuf[m]->hole[i].start;
+ hole_len = tcpstate->msgbuf[m]->hole[i].len;
+ if (segoff >= hole_start + hole_len)
+ continue; /* segment is totally after hole */
+ if (segoff + seglen <= hole_start)
+ continue; /* segment is totally before hole */
+ /* The segment overlaps this hole. Delete the hole. */
+ dfprintf(1, "pcap_handle_tcp_segment: overlaping hole %d: %d %d", i, hole_start, hole_len);
+ tcpstate->msgbuf[m]->hole[i].len = 0;
+ tcpstate->msgbuf[m]->holes--;
+ if (segoff + seglen < hole_start + hole_len) {
+ /* create a new hole after the segment (common case) */
+ newhole = &tcpstate->msgbuf[m]->hole[i]; /* hole[i] is guaranteed free */
+ newhole->start = segoff + seglen;
+ newhole->len = (hole_start + hole_len) - newhole->start;
+ tcpstate->msgbuf[m]->holes++;
+ dfprintf(1, "pcap_handle_tcp_segment: new post-hole %d: %d %d", i, newhole->start, newhole->len);
+ }
+ if (segoff > hole_start) {
+ /* create a new hole before the segment */
+ int j;
+ for (j = 0; j < MAX_TCP_HOLES; j++) {
+ if (tcpstate->msgbuf[m]->hole[j].len == 0) {
+ newhole = &tcpstate->msgbuf[m]->hole[j];
+ break;
+ }
+ }
+ if (j >= MAX_TCP_HOLES) {
+ dfprintf(1, "pcap_handle_tcp_segment: %s", "out of hole descriptors");
+ return 1;
+ }
+ tcpstate->msgbuf[m]->holes++;
+ newhole->start = hole_start;
+ newhole->len = segoff - hole_start;
+ dfprintf(1, "pcap_handle_tcp_segment: new pre-hole %d: %d %d", j, newhole->start, newhole->len);
+ }
+ if (segoff >= hole_start && (hole_len == 0 || segoff + seglen < hole_start + hole_len)) {
+ /* The segment does not extend past hole boundaries; there is
+ * no need to look for other matching holes. */
+ break;
+ }
+ }
+
+ /* copy payload to appropriate location in reassembly buffer */
+ memcpy(&tcpstate->msgbuf[m]->buf[segoff], segment, seglen);
+
+ dfprintf(1, "pcap_handle_tcp_segment: holes remaining: %d", tcpstate->msgbuf[m]->holes);
+
+ ret = 0;
+ if (tcpstate->msgbuf[m]->holes == 0) {
+ /* We now have a completely reassembled dns message */
+ dfprintf(2, "pcap_handle_tcp_segment: %s", "reassembly to dns_protocol_handler");
+ ret |= dns_protocol_handler(tcpstate, tcpstate->msgbuf[m]->buf, tcpstate->msgbuf[m]->dnslen, tcpstate->msgbuf[m]->seq);
+ tcpstate->dnslen_bytes_seen_mask = 0; /* go back for another message in this tcp connection */
+ free(tcpstate->msgbuf[m]);
+ tcpstate->msgbuf[m] = NULL;
+ tcpstate->msgbufs--;
+ }
+
+ if (seglen < len) {
+ dfprintf(1, "pcap_handle_tcp_segment: %s", "segment tail after reassembly");
+ ret |= pcap_handle_tcp_segment(segment + seglen, len - seglen, seq + seglen, _tcpstate);
+ } else {
+ dfprintf(1, "pcap_handle_tcp_segment: %s", "nothing more after reassembly");
+ }
+
+ return ret;
+}
+
+void tcpreasm_free(tcpreasm_t* tcpreasm)
+{
+ int i;
+
+ if (tcpreasm) {
+ for (i = 0; i < MAX_TCP_MSGS; i++) {
+ if (tcpreasm->msgbuf[i]) {
+ free(tcpreasm->msgbuf[i]);
+ }
+ }
+ for (i = 0; i < MAX_TCP_SEGS; i++) {
+ if (tcpreasm->segbuf[i]) {
+ free(tcpreasm->segbuf[i]);
+ }
+ if (tcpreasm->bfb_seg[i]) {
+ free(tcpreasm->bfb_seg[i]);
+ }
+ }
+ for (i = 0; i < MAX_TCP_DNS_MSG; i++) {
+ if (tcpreasm->dnsmsg[i]) {
+ free(tcpreasm->dnsmsg[i]);
+ }
+ }
+ free(tcpreasm->bfb_buf);
+ free(tcpreasm);
+ }
+}
+
+void tcpreasm_reset(tcpreasm_t* tcpreasm)
+{
+ int i;
+
+ if (tcpreasm) {
+ for (i = 0; i < MAX_TCP_MSGS; i++) {
+ if (tcpreasm->msgbuf[i]) {
+ free(tcpreasm->msgbuf[i]);
+ }
+ }
+ for (i = 0; i < MAX_TCP_SEGS; i++) {
+ if (tcpreasm->segbuf[i]) {
+ free(tcpreasm->segbuf[i]);
+ }
+ if (tcpreasm->bfb_seg[i]) {
+ free(tcpreasm->bfb_seg[i]);
+ }
+ }
+ for (i = 0; i < MAX_TCP_DNS_MSG; i++) {
+ if (tcpreasm->dnsmsg[i]) {
+ free(tcpreasm->dnsmsg[i]);
+ }
+ }
+ memset(tcpreasm, 0, sizeof(tcpreasm_t));
+ }
+}
diff --git a/src/tcpreasm.h b/src/tcpreasm.h
new file mode 100644
index 0000000..6418fb2
--- /dev/null
+++ b/src/tcpreasm.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_tcpreasm_h
+#define __dnscap_tcpreasm_h
+
+int pcap_handle_tcp_segment(u_char* segment, int len, uint32_t seq, tcpstate_ptr _tcpstate);
+void tcpreasm_free(tcpreasm_t* tcpreasm);
+void tcpreasm_reset(tcpreasm_t* tcpreasm);
+
+#endif /* __dnscap_tcpreasm_h */
diff --git a/src/tcpstate.c b/src/tcpstate.c
new file mode 100644
index 0000000..bfc5198
--- /dev/null
+++ b/src/tcpstate.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2018-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "tcpstate.h"
+#include "iaddr.h"
+#include "log.h"
+#include "tcpreasm.h"
+
+#define MAX_TCP_IDLE_TIME 600
+#define MAX_TCP_IDLE_COUNT 4096
+#define TCP_GC_TIME 60
+
+tcpstate_ptr tcpstate_find(iaddr from, iaddr to, unsigned sport, unsigned dport, time_t t)
+{
+ static time_t next_gc = 0;
+ tcpstate_ptr tcpstate;
+
+ for (tcpstate = HEAD(tcpstates);
+ tcpstate != NULL;
+ tcpstate = NEXT(tcpstate, link)) {
+ if (ia_equal(tcpstate->saddr, from) && ia_equal(tcpstate->daddr, to) && tcpstate->sport == sport && tcpstate->dport == dport)
+ break;
+ }
+ if (tcpstate != NULL) {
+ tcpstate->last_use = t;
+ if (tcpstate != HEAD(tcpstates)) {
+ /* move to beginning of list */
+ UNLINK(tcpstates, tcpstate, link);
+ PREPEND(tcpstates, tcpstate, link);
+ }
+ }
+
+ if (t >= next_gc || tcpstate_count > MAX_TCP_IDLE_COUNT) {
+ /* garbage collect stale states */
+ time_t min_last_use = t - MAX_TCP_IDLE_TIME;
+ while ((tcpstate = TAIL(tcpstates)) && tcpstate->last_use < min_last_use) {
+ UNLINK(tcpstates, tcpstate, link);
+ tcpstate_count--;
+ }
+ next_gc = t + TCP_GC_TIME;
+ }
+
+ return tcpstate;
+}
+
+tcpstate_ptr tcpstate_new(iaddr from, iaddr to, unsigned sport, unsigned dport)
+{
+
+ tcpstate_ptr tcpstate = calloc(1, sizeof *tcpstate);
+ if (tcpstate == NULL) {
+ /* Out of memory; recycle the least recently used */
+ logerr("warning: out of memory, "
+ "discarding some TCP state early");
+ tcpstate = TAIL(tcpstates);
+ assert(tcpstate != NULL);
+ } else {
+ tcpstate_count++;
+ }
+ tcpstate->saddr = from;
+ tcpstate->daddr = to;
+ tcpstate->sport = sport;
+ tcpstate->dport = dport;
+ INIT_LINK(tcpstate, link);
+ PREPEND(tcpstates, tcpstate, link);
+ return tcpstate;
+}
+
+/* Discard this packet. If it's part of TCP stream, all subsequent pkts on
+ * the same tcp stream will also be discarded. */
+void tcpstate_discard(tcpstate_ptr tcpstate, const char* msg)
+{
+ if (dumptrace >= 3 && msg)
+ fprintf(stderr, "discarding packet: %s\n", msg);
+ if (tcpstate) {
+ UNLINK(tcpstates, tcpstate, link);
+ if (tcpstate->reasm) {
+ tcpreasm_free(tcpstate->reasm);
+ }
+ free(tcpstate);
+ tcpstate_count--;
+ return;
+ }
+}
+
+tcpstate_ptr _curr_tcpstate = 0;
+
+tcpstate_ptr tcpstate_getcurr(void)
+{
+ return _curr_tcpstate;
+}
+
+void tcpstate_reset(tcpstate_ptr tcpstate, const char* msg)
+{
+ if (options.allow_reset_tcpstate && tcpstate) {
+ if (dumptrace >= 3 && msg)
+ fprintf(stderr, "resetting tcpstate: %s\n", msg);
+
+ tcpstate->start = tcpstate->currseq;
+ tcpstate->maxdiff = 0;
+ tcpstate->dnslen = 0;
+ tcpstate->lastdns = tcpstate->currseq + tcpstate->currlen;
+
+ if (tcpstate->reasm) {
+ tcpreasm_reset(tcpstate->reasm);
+ tcpstate->reasm->seq_start = tcpstate->start;
+ }
+ }
+}
diff --git a/src/tcpstate.h b/src/tcpstate.h
new file mode 100644
index 0000000..ac3dd56
--- /dev/null
+++ b/src/tcpstate.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018-2021, OARC, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dnscap.h"
+
+#ifndef __dnscap_tcpstate_h
+#define __dnscap_tcpstate_h
+
+tcpstate_ptr tcpstate_find(iaddr from, iaddr to, unsigned sport, unsigned dport, time_t t);
+tcpstate_ptr tcpstate_new(iaddr from, iaddr to, unsigned sport, unsigned dport);
+void tcpstate_discard(tcpstate_ptr tcpstate, const char* msg);
+tcpstate_ptr tcpstate_getcurr(void);
+void tcpstate_reset(tcpstate_ptr tcpstate, const char* msg);
+
+#endif /* __dnscap_tcpstate_h */
diff --git a/src/test/.gitignore b/src/test/.gitignore
new file mode 100644
index 0000000..7eaa8b0
--- /dev/null
+++ b/src/test/.gitignore
@@ -0,0 +1,4 @@
+dns.out
+dns.pcap.dist
+test*.log
+test*.trs
diff --git a/src/test/1qtcpnosyn.pcap b/src/test/1qtcpnosyn.pcap
new file mode 100644
index 0000000..d8de79b
--- /dev/null
+++ b/src/test/1qtcpnosyn.pcap
Binary files differ
diff --git a/src/test/1qtcppadd.pcap b/src/test/1qtcppadd.pcap
new file mode 100644
index 0000000..652234d
--- /dev/null
+++ b/src/test/1qtcppadd.pcap
Binary files differ
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
new file mode 100644
index 0000000..83d8621
--- /dev/null
+++ b/src/test/Makefile.am
@@ -0,0 +1,68 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+CLEANFILES = test*.log test*.trs \
+ *.pcap-dist \
+ dns.out \
+ no-layers.out layers.out \
+ frags.out \
+ padding-no-layers.out padding-layers.out \
+ vlan11.out \
+ dnspad.out \
+ test7.out test7.layer.out \
+ test8.out \
+ test9.out \
+ test10.out \
+ test11.out \
+ test12.out test12.20161020.152301.075993.gz \
+ test13.out \
+ test14.out
+
+TESTS = test1.sh test2.sh test3.sh test4.sh test5.sh test6.sh test7.sh \
+ test8.sh test9.sh test10.sh test11.sh test12.sh test13.sh test14.sh
+
+test1.sh: dns.pcap-dist
+
+test2.sh: dns.pcap-dist
+
+test3.sh: frags.pcap-dist
+
+test4.sh: 1qtcppadd.pcap-dist
+
+test5.sh: vlan11.pcap-dist
+
+test6.sh: dnspad.pcap-dist
+
+test7.sh: 1qtcpnosyn.pcap-dist dnso1tcp.pcap-dist \
+ do1t-nosyn-1nolen.pcap-dist dnso1tcp-midmiss.pcap-dist
+
+test8.sh: dnsotcp-many1pkt.pcap-dist dnsotcp-manyopkts.pcap-dist \
+ dnso1tcp-bighole.pcap-dist
+
+test9.sh: dns.pcap-dist
+
+test10.sh: dns6.pcap-dist
+
+test11.sh: dns.pcap-dist
+
+test12.sh: dns.pcap-dist
+
+test13.sh: dns.pcap-dist
+
+test14.sh: dns.pcap-dist
+
+.pcap.pcap-dist:
+ cp "$<" "$@"
+
+EXTRA_DIST = $(TESTS) \
+ dns.gold dns.pcap \
+ frags.pcap \
+ 1qtcppadd.pcap \
+ vlan11.gold vlan11.pcap \
+ dnspad.gold dnspad.pcap \
+ test7.gold 1qtcpnosyn.pcap dnso1tcp.pcap do1t-nosyn-1nolen.pcap \
+ dnso1tcp-midmiss.pcap \
+ test8.gold dnsotcp-many1pkt.pcap dnsotcp-manyopkts.pcap \
+ dnso1tcp-bighole.pcap \
+ test9.gold \
+ dns6.pcap test10.gold \
+ test14.gold
diff --git a/src/test/dns.gold b/src/test/dns.gold
new file mode 100644
index 0000000..b1cdd8f
--- /dev/null
+++ b/src/test/dns.gold
@@ -0,0 +1,714 @@
+[56] 2016-10-20 15:23:01.075993 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].53199 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.077982 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53199 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns4.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[73] 2016-10-20 15:23:01.082865 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].57822 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:01.084107 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].57822 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71608,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10 \
+ ns2.google.com.,IN,A,157880,216.239.34.10
+[56] 2016-10-20 15:23:01.087291 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].40043 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.088733 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40043 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:10.322117 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].37953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:10.323399 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37953 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,34,216.58.218.206 \
+ 4 google.com.,IN,NS,157870,ns4.google.com. \
+ google.com.,IN,NS,157870,ns1.google.com. \
+ google.com.,IN,NS,157870,ns2.google.com. \
+ google.com.,IN,NS,157870,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157870,216.239.34.10 \
+ ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10
+[73] 2016-10-20 15:23:10.328324 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].48658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18718,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:10.329572 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].48658 \
+ dns QUERY,NOERROR,18718,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71598,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10 \
+ ns2.google.com.,IN,A,157870,216.239.34.10
+[56] 2016-10-20 15:23:52.860937 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].40953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:52.863771 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40953 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,297,216.58.218.206 \
+ 4 google.com.,IN,NS,157828,ns2.google.com. \
+ google.com.,IN,NS,157828,ns4.google.com. \
+ google.com.,IN,NS,157828,ns1.google.com. \
+ google.com.,IN,NS,157828,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157828,216.239.34.10 \
+ ns1.google.com.,IN,A,331830,216.239.32.10 \
+ ns3.google.com.,IN,A,157828,216.239.36.10 \
+ ns4.google.com.,IN,A,157828,216.239.38.10
+[56] 2016-10-20 15:23:59.083869 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].45174 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:59.086104 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45174 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,291,216.58.218.206 \
+ 4 google.com.,IN,NS,157822,ns2.google.com. \
+ google.com.,IN,NS,157822,ns3.google.com. \
+ google.com.,IN,NS,157822,ns1.google.com. \
+ google.com.,IN,NS,157822,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157822,216.239.34.10 \
+ ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10
+[73] 2016-10-20 15:23:59.090911 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].33916 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:59.092204 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33916 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71550,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10 \
+ ns2.google.com.,IN,A,157822,216.239.34.10
+[56] 2016-10-20 15:24:04.323868 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].43559 [8.8.8.8].53 \
+ dns QUERY,NOERROR,49483,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:04.325597 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].43559 \
+ dns QUERY,NOERROR,49483,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,285,216.58.218.206 \
+ 4 google.com.,IN,NS,157816,ns4.google.com. \
+ google.com.,IN,NS,157816,ns3.google.com. \
+ google.com.,IN,NS,157816,ns1.google.com. \
+ google.com.,IN,NS,157816,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157816,216.239.34.10 \
+ ns1.google.com.,IN,A,331818,216.239.32.10 \
+ ns3.google.com.,IN,A,157816,216.239.36.10 \
+ ns4.google.com.,IN,A,157816,216.239.38.10
+[56] 2016-10-20 15:24:06.332239 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].54859 [8.8.8.8].53 \
+ dns QUERY,NOERROR,31669,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:06.333743 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].54859 \
+ dns QUERY,NOERROR,31669,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,283,216.58.218.206 \
+ 4 google.com.,IN,NS,157814,ns2.google.com. \
+ google.com.,IN,NS,157814,ns1.google.com. \
+ google.com.,IN,NS,157814,ns4.google.com. \
+ google.com.,IN,NS,157814,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157814,216.239.34.10 \
+ ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10
+[73] 2016-10-20 15:24:06.339145 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].58176 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:06.340820 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].58176 \
+ dns QUERY,NOERROR,25433,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71542,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10 \
+ ns2.google.com.,IN,A,157814,216.239.34.10
+[56] 2016-10-20 15:24:07.346429 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].41266 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:07.348160 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41266 \
+ dns QUERY,NOERROR,63798,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,282,216.58.218.206 \
+ 4 google.com.,IN,NS,157813,ns4.google.com. \
+ google.com.,IN,NS,157813,ns1.google.com. \
+ google.com.,IN,NS,157813,ns3.google.com. \
+ google.com.,IN,NS,157813,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157813,216.239.34.10 \
+ ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10
+[73] 2016-10-20 15:24:07.353123 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].34607 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:07.354682 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34607 \
+ dns QUERY,NOERROR,8470,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71541,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10 \
+ ns2.google.com.,IN,A,157813,216.239.34.10
+[56] 2016-10-20 15:24:08.360528 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].60437 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:08.362206 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60437 \
+ dns QUERY,NOERROR,60258,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,281,216.58.218.206 \
+ 4 google.com.,IN,NS,157812,ns3.google.com. \
+ google.com.,IN,NS,157812,ns2.google.com. \
+ google.com.,IN,NS,157812,ns4.google.com. \
+ google.com.,IN,NS,157812,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157812,216.239.34.10 \
+ ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10
+[73] 2016-10-20 15:24:08.368516 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].37149 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:08.370119 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37149 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71540,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10 \
+ ns2.google.com.,IN,A,157812,216.239.34.10
+[56] 2016-10-20 15:24:09.375942 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].53820 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:09.378425 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53820 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,280,216.58.218.206 \
+ 4 google.com.,IN,NS,157811,ns3.google.com. \
+ google.com.,IN,NS,157811,ns4.google.com. \
+ google.com.,IN,NS,157811,ns1.google.com. \
+ google.com.,IN,NS,157811,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157811,216.239.34.10 \
+ ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10
+[73] 2016-10-20 15:24:09.384057 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].52368 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:09.385463 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].52368 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71539,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10 \
+ ns2.google.com.,IN,A,157811,216.239.34.10
+[56] 2016-10-20 15:24:10.391358 [#34 dns.pcap-dist 4095] \
+ [172.17.0.10].47637 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:10.392886 [#35 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].47637 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,279,216.58.218.206 \
+ 4 google.com.,IN,NS,157810,ns1.google.com. \
+ google.com.,IN,NS,157810,ns2.google.com. \
+ google.com.,IN,NS,157810,ns4.google.com. \
+ google.com.,IN,NS,157810,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157810,216.239.34.10 \
+ ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10
+[73] 2016-10-20 15:24:10.398099 [#36 dns.pcap-dist 4095] \
+ [172.17.0.10].34426 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:10.400317 [#37 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34426 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71538,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10 \
+ ns2.google.com.,IN,A,157810,216.239.34.10
+[56] 2016-10-20 15:24:11.406297 [#38 dns.pcap-dist 4095] \
+ [172.17.0.10].41059 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:11.407460 [#39 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41059 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,278,216.58.218.206 \
+ 4 google.com.,IN,NS,157809,ns3.google.com. \
+ google.com.,IN,NS,157809,ns4.google.com. \
+ google.com.,IN,NS,157809,ns2.google.com. \
+ google.com.,IN,NS,157809,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157809,216.239.34.10 \
+ ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10
+[73] 2016-10-20 15:24:11.412133 [#40 dns.pcap-dist 4095] \
+ [172.17.0.10].51181 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:11.413370 [#41 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].51181 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71537,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10 \
+ ns2.google.com.,IN,A,157809,216.239.34.10
+[56] 2016-10-20 15:24:12.419936 [#42 dns.pcap-dist 4095] \
+ [172.17.0.10].32976 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:12.421228 [#43 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].32976 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,277,216.58.218.206 \
+ 4 google.com.,IN,NS,157808,ns2.google.com. \
+ google.com.,IN,NS,157808,ns3.google.com. \
+ google.com.,IN,NS,157808,ns1.google.com. \
+ google.com.,IN,NS,157808,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157808,216.239.34.10 \
+ ns1.google.com.,IN,A,331810,216.239.32.10 \
+ ns3.google.com.,IN,A,157808,216.239.36.10 \
+ ns4.google.com.,IN,A,157808,216.239.38.10
+[56] 2016-10-20 15:24:14.428524 [#44 dns.pcap-dist 4095] \
+ [172.17.0.10].53467 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:14.429863 [#45 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53467 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,275,216.58.218.206 \
+ 4 google.com.,IN,NS,157806,ns3.google.com. \
+ google.com.,IN,NS,157806,ns1.google.com. \
+ google.com.,IN,NS,157806,ns4.google.com. \
+ google.com.,IN,NS,157806,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157806,216.239.34.10 \
+ ns1.google.com.,IN,A,331808,216.239.32.10 \
+ ns3.google.com.,IN,A,157806,216.239.36.10 \
+ ns4.google.com.,IN,A,157806,216.239.38.10
+[56] 2016-10-20 15:24:16.435733 [#46 dns.pcap-dist 4095] \
+ [172.17.0.10].41532 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:16.437471 [#47 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41532 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,273,216.58.218.206 \
+ 4 google.com.,IN,NS,157804,ns1.google.com. \
+ google.com.,IN,NS,157804,ns3.google.com. \
+ google.com.,IN,NS,157804,ns2.google.com. \
+ google.com.,IN,NS,157804,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157804,216.239.34.10 \
+ ns1.google.com.,IN,A,331806,216.239.32.10 \
+ ns3.google.com.,IN,A,157804,216.239.36.10 \
+ ns4.google.com.,IN,A,157804,216.239.38.10
+[56] 2016-10-20 15:24:18.445519 [#48 dns.pcap-dist 4095] \
+ [172.17.0.10].44982 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:18.446775 [#49 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44982 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,271,216.58.218.206 \
+ 4 google.com.,IN,NS,157802,ns4.google.com. \
+ google.com.,IN,NS,157802,ns2.google.com. \
+ google.com.,IN,NS,157802,ns1.google.com. \
+ google.com.,IN,NS,157802,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157802,216.239.34.10 \
+ ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10
+[73] 2016-10-20 15:24:18.452451 [#50 dns.pcap-dist 4095] \
+ [172.17.0.10].40224 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:18.454030 [#51 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40224 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71530,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10 \
+ ns2.google.com.,IN,A,157802,216.239.34.10
+[56] 2016-10-20 15:24:19.460087 [#52 dns.pcap-dist 4095] \
+ [172.17.0.10].45658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:19.462224 [#53 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45658 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,270,216.58.218.206 \
+ 4 google.com.,IN,NS,157801,ns1.google.com. \
+ google.com.,IN,NS,157801,ns3.google.com. \
+ google.com.,IN,NS,157801,ns4.google.com. \
+ google.com.,IN,NS,157801,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157801,216.239.34.10 \
+ ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10
+[73] 2016-10-20 15:24:19.467324 [#54 dns.pcap-dist 4095] \
+ [172.17.0.10].60457 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:19.468895 [#55 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60457 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71529,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10 \
+ ns2.google.com.,IN,A,157801,216.239.34.10
+[56] 2016-10-20 15:24:20.475086 [#56 dns.pcap-dist 4095] \
+ [172.17.0.10].59762 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:20.476841 [#57 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].59762 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,269,216.58.218.206 \
+ 4 google.com.,IN,NS,157800,ns3.google.com. \
+ google.com.,IN,NS,157800,ns1.google.com. \
+ google.com.,IN,NS,157800,ns4.google.com. \
+ google.com.,IN,NS,157800,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157800,216.239.34.10 \
+ ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10
+[73] 2016-10-20 15:24:20.482188 [#58 dns.pcap-dist 4095] \
+ [172.17.0.10].56022 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:20.483927 [#59 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].56022 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71528,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10 \
+ ns2.google.com.,IN,A,157800,216.239.34.10
+[56] 2016-10-20 15:24:21.489468 [#60 dns.pcap-dist 4095] \
+ [172.17.0.10].37669 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:21.490573 [#61 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37669 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,268,216.58.218.206 \
+ 4 google.com.,IN,NS,157799,ns2.google.com. \
+ google.com.,IN,NS,157799,ns1.google.com. \
+ google.com.,IN,NS,157799,ns4.google.com. \
+ google.com.,IN,NS,157799,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157799,216.239.34.10 \
+ ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10
+[73] 2016-10-20 15:24:21.495324 [#62 dns.pcap-dist 4095] \
+ [172.17.0.10].42978 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:21.496815 [#63 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42978 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71527,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10 \
+ ns2.google.com.,IN,A,157799,216.239.34.10
+[56] 2016-10-20 15:24:22.502667 [#64 dns.pcap-dist 4095] \
+ [172.17.0.10].49829 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:22.504738 [#65 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].49829 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,267,216.58.218.206 \
+ 4 google.com.,IN,NS,157798,ns2.google.com. \
+ google.com.,IN,NS,157798,ns4.google.com. \
+ google.com.,IN,NS,157798,ns3.google.com. \
+ google.com.,IN,NS,157798,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157798,216.239.34.10 \
+ ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10
+[73] 2016-10-20 15:24:22.510176 [#66 dns.pcap-dist 4095] \
+ [172.17.0.10].50599 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:22.511746 [#67 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].50599 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71526,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10 \
+ ns2.google.com.,IN,A,157798,216.239.34.10
+[56] 2016-10-20 15:24:23.520203 [#68 dns.pcap-dist 4095] \
+ [172.17.0.10].44980 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:23.521976 [#69 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44980 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,266,216.58.218.206 \
+ 4 google.com.,IN,NS,157797,ns2.google.com. \
+ google.com.,IN,NS,157797,ns4.google.com. \
+ google.com.,IN,NS,157797,ns1.google.com. \
+ google.com.,IN,NS,157797,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157797,216.239.34.10 \
+ ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10
+[73] 2016-10-20 15:24:23.527449 [#70 dns.pcap-dist 4095] \
+ [172.17.0.10].60063 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:23.529385 [#71 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60063 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71525,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10 \
+ ns2.google.com.,IN,A,157797,216.239.34.10
+[56] 2016-10-20 15:24:24.537264 [#72 dns.pcap-dist 4095] \
+ [172.17.0.10].42042 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:24.539398 [#73 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42042 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,265,216.58.218.206 \
+ 4 google.com.,IN,NS,157796,ns3.google.com. \
+ google.com.,IN,NS,157796,ns4.google.com. \
+ google.com.,IN,NS,157796,ns1.google.com. \
+ google.com.,IN,NS,157796,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157796,216.239.34.10 \
+ ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10
+[73] 2016-10-20 15:24:24.544538 [#74 dns.pcap-dist 4095] \
+ [172.17.0.10].60469 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:24.546172 [#75 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60469 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71524,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10 \
+ ns2.google.com.,IN,A,157796,216.239.34.10
+[56] 2016-10-20 15:24:25.554744 [#76 dns.pcap-dist 4095] \
+ [172.17.0.10].45703 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:25.556513 [#77 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45703 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,264,216.58.218.206 \
+ 4 google.com.,IN,NS,157795,ns3.google.com. \
+ google.com.,IN,NS,157795,ns4.google.com. \
+ google.com.,IN,NS,157795,ns2.google.com. \
+ google.com.,IN,NS,157795,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157795,216.239.34.10 \
+ ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10
+[73] 2016-10-20 15:24:25.562608 [#78 dns.pcap-dist 4095] \
+ [172.17.0.10].33507 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:25.564509 [#79 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33507 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71523,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10 \
+ ns2.google.com.,IN,A,157795,216.239.34.10
+[56] 2016-10-20 15:24:26.572784 [#80 dns.pcap-dist 4095] \
+ [172.17.0.10].46798 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:26.574350 [#81 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].46798 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,263,216.58.218.206 \
+ 4 google.com.,IN,NS,157794,ns1.google.com. \
+ google.com.,IN,NS,157794,ns4.google.com. \
+ google.com.,IN,NS,157794,ns3.google.com. \
+ google.com.,IN,NS,157794,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157794,216.239.34.10 \
+ ns1.google.com.,IN,A,331796,216.239.32.10 \
+ ns3.google.com.,IN,A,157794,216.239.36.10 \
+ ns4.google.com.,IN,A,157794,216.239.38.10
diff --git a/src/test/dns.pcap b/src/test/dns.pcap
new file mode 100644
index 0000000..a0e585c
--- /dev/null
+++ b/src/test/dns.pcap
Binary files differ
diff --git a/src/test/dns6.pcap b/src/test/dns6.pcap
new file mode 100644
index 0000000..5fa3af8
--- /dev/null
+++ b/src/test/dns6.pcap
Binary files differ
diff --git a/src/test/dnso1tcp-bighole.pcap b/src/test/dnso1tcp-bighole.pcap
new file mode 100644
index 0000000..66bf30b
--- /dev/null
+++ b/src/test/dnso1tcp-bighole.pcap
Binary files differ
diff --git a/src/test/dnso1tcp-midmiss.pcap b/src/test/dnso1tcp-midmiss.pcap
new file mode 100644
index 0000000..c99b0fb
--- /dev/null
+++ b/src/test/dnso1tcp-midmiss.pcap
Binary files differ
diff --git a/src/test/dnso1tcp.pcap b/src/test/dnso1tcp.pcap
new file mode 100644
index 0000000..47dd663
--- /dev/null
+++ b/src/test/dnso1tcp.pcap
Binary files differ
diff --git a/src/test/dnsotcp-many1pkt.pcap b/src/test/dnsotcp-many1pkt.pcap
new file mode 100644
index 0000000..c43ce03
--- /dev/null
+++ b/src/test/dnsotcp-many1pkt.pcap
Binary files differ
diff --git a/src/test/dnsotcp-manyopkts.pcap b/src/test/dnsotcp-manyopkts.pcap
new file mode 100644
index 0000000..e232bac
--- /dev/null
+++ b/src/test/dnsotcp-manyopkts.pcap
Binary files differ
diff --git a/src/test/dnspad.gold b/src/test/dnspad.gold
new file mode 100644
index 0000000..8a5275a
--- /dev/null
+++ b/src/test/dnspad.gold
@@ -0,0 +1,8 @@
+[59] 2016-10-20 15:23:01.075993 [#0 dnspad.pcap-dist 4095] \
+ [172.17.0.10].53199 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[59] 2016-10-20 15:23:01.075993 [#0 dnspad.pcap-dist 4095] \
+ [172.17.0.10].53199 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
diff --git a/src/test/dnspad.pcap b/src/test/dnspad.pcap
new file mode 100644
index 0000000..df2b574
--- /dev/null
+++ b/src/test/dnspad.pcap
Binary files differ
diff --git a/src/test/do1t-nosyn-1nolen.pcap b/src/test/do1t-nosyn-1nolen.pcap
new file mode 100644
index 0000000..cd20a74
--- /dev/null
+++ b/src/test/do1t-nosyn-1nolen.pcap
Binary files differ
diff --git a/src/test/frags.pcap b/src/test/frags.pcap
new file mode 100644
index 0000000..5d44810
--- /dev/null
+++ b/src/test/frags.pcap
Binary files differ
diff --git a/src/test/test1.sh b/src/test/test1.sh
new file mode 100755
index 0000000..03142c9
--- /dev/null
+++ b/src/test/test1.sh
@@ -0,0 +1,9 @@
+#!/bin/sh -xe
+
+../dnscap -g -r dns.pcap-dist 2>dns.out
+
+mv dns.out dns.out.old
+grep -v "^libgcov profiling error:" dns.out.old > dns.out
+rm dns.out.old
+
+diff dns.out "$srcdir/dns.gold"
diff --git a/src/test/test10.gold b/src/test/test10.gold
new file mode 100644
index 0000000..69f51ef
--- /dev/null
+++ b/src/test/test10.gold
@@ -0,0 +1,22 @@
+[87] 2018-11-27 15:52:00.414188 [#0 dns6.pcap-dist 4095] \
+ [2a01:3f0:0:57::245].51972 [2001:4860:4860::8888].53 \
+ dns QUERY,NOERROR,51420,rd|ad \
+ 1 google.com.,IN,A 0 0 \
+ 1 .,4096,4096,0,edns0[len=0,UDP=4096,ver=0,rcode=0,DO=0,z=0]
+[103] 2018-11-27 15:52:00.428453 [#1 dns6.pcap-dist 4095] \
+ [2001:4860:4860::8888].53 [2a01:3f0:0:57::245].51972 \
+ dns QUERY,NOERROR,51420,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,299,172.217.20.46 0 \
+ 1 .,512,512,0,edns0[len=0,UDP=512,ver=0,rcode=0,DO=0,z=0]
+[87] 2018-11-27 15:52:00.414188 [#0 dns6.pcap-dist 4095] \
+ [2a01:3f0:0:57::245].51972 [2001:4860:4860::8888].53 \
+ dns QUERY,NOERROR,51420,rd|ad \
+ 1 google.com.,IN,A 0 0 \
+ 1 .,4096,4096,0,edns0[len=0,UDP=4096,ver=0,rcode=0,DO=0,z=0]
+[103] 2018-11-27 15:52:00.428453 [#1 dns6.pcap-dist 4095] \
+ [2001:4860:4860::8888].53 [2a01:3f0:0:57::245].51972 \
+ dns QUERY,NOERROR,51420,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,299,172.217.20.46 0 \
+ 1 .,512,512,0,edns0[len=0,UDP=512,ver=0,rcode=0,DO=0,z=0]
diff --git a/src/test/test10.sh b/src/test/test10.sh
new file mode 100755
index 0000000..2779cb0
--- /dev/null
+++ b/src/test/test10.sh
@@ -0,0 +1,6 @@
+#!/bin/sh -xe
+
+../dnscap -r dns6.pcap-dist -g 2>test10.out
+../dnscap -r dns6.pcap-dist -o use_layers=yes -g 2>>test10.out
+
+diff test10.out "$srcdir/test10.gold"
diff --git a/src/test/test11.sh b/src/test/test11.sh
new file mode 100755
index 0000000..7f58c89
--- /dev/null
+++ b/src/test/test11.sh
@@ -0,0 +1,79 @@
+#!/bin/sh -xe
+
+../dnscap -?
+! ../dnscap -j
+
+! ../dnscap -o testing
+! ../dnscap -o testing=
+! ../dnscap -o testing=a
+../dnscap -o user=user -o user=user -o group=group -o group=group \
+ -o dump_format=pcap -o dump_format=cbor -o dump_format=cds \
+ -F pcap -F cbor -F cds \
+ -?
+../dnscap -b -N -p -d -1 -I -i fake -m q -m u -m n -s i -s r -h i -h r \
+ -e n -e y -e t -e f -e s -e x -e i -e r -w - -W a -W a -t 1 -c 1 -C 1 \
+ -x '.*' -S -U fake -U fake -M -D -?
+../dnscap -w fake -k false -?
+! ../dnscap -m X
+! ../dnscap -s X
+! ../dnscap -h X
+! ../dnscap -e X
+! ../dnscap -k false
+! ../dnscap -F invalid
+! ../dnscap -t invalid
+! ../dnscap -c invalid
+! ../dnscap -C invalid
+! ../dnscap -x '('
+! ../dnscap -B invalid
+! ../dnscap -E invalid
+! ../dnscap -P invalid
+if ! ../dnscap -y -? 2>test11.out; then
+ grep -qF "seccomp-bpf not enabled" test11.out
+fi
+! ../dnscap -w fake -o use_layers=yes
+! ../dnscap -g -f -h i
+! ../dnscap -g -l 1 -L 1
+! ../dnscap -g -b -d -g
+! ../dnscap -g -b -g
+! ../dnscap -g -B "2020-01-01 00:00:00" -E "2019-01-01 00:00:00"
+! ../dnscap -g -o defrag_ipv4=yes
+! ../dnscap -g -o defrag_ipv6=yes
+! ../dnscap -g -o reassemble_tcp_bfbparsedns=yes
+
+../dnscap -V
+
+../dnscap -r dns.pcap-dist -g -ddddd
+../dnscap -r dns.pcap-dist -x '.*' -X '.*' -g -ddddd
+
+! ../dnscap -r dns.pcap-dist -i fake 2>test11.out
+cat test11.out
+grep -qF -- "-i makes no sense after -r" test11.out
+! ../dnscap -i fake -r dns.pcap-dist 2>test11.out
+cat test11.out
+grep -qF -- "-r makes no sense after -i" test11.out
+
+all_opts=
+for opt in cbor_chunk_size cds_cbor_size cds_message_size cds_max_rlabels \
+cds_min_rlabel_size cds_rdata_index_min_size cds_rdata_rindex_size \
+cds_rdata_rindex_min_size pcap_buffer_size max_ipv4_fragments \
+max_ipv6_fragments max_ipv6_fragments_per_packet reassemble_tcp_faultreset; \
+do
+ ! ../dnscap -o "$opt=0"
+ all_opts="$all_opts -o $opt=1"
+done
+
+../dnscap $all_opts -?
+
+all_opts=
+for opt in cds_use_rdata_rindex cds_use_rdata_index defrag_ipv6 \
+reassemble_tcp_bfbparsedns bpf_hosts_apply_all; \
+do
+ ! ../dnscap -o "$opt=f"
+ all_opts="$all_opts -o $opt=yes"
+done
+
+../dnscap $all_opts -?
+
+! ../dnscap -l 0 -l 4095 -l 4096
+! ../dnscap -L 0 -L 4095 -L 4096
+! ../dnscap -u 5353 -u 65536
diff --git a/src/test/test12.sh b/src/test/test12.sh
new file mode 100755
index 0000000..76b0e01
--- /dev/null
+++ b/src/test/test12.sh
@@ -0,0 +1,6 @@
+#!/bin/sh -xe
+
+if ! ../dnscap -g -r dns.pcap-dist -w test12 -W .gz 2>test12.out; then
+ grep -qF "gzip compression requested but not supported" test12.out && exit 0
+ exit 1
+fi
diff --git a/src/test/test13.sh b/src/test/test13.sh
new file mode 100755
index 0000000..4749a92
--- /dev/null
+++ b/src/test/test13.sh
@@ -0,0 +1,28 @@
+#!/bin/sh -xe
+
+test -f /etc/resolv.conf || exit 0
+
+! ../dnscap -a "fake_host-should+not/work" 2>test13.out
+cat test13.out
+grep -qF "invalid host address" test13.out
+
+if [ "`uname`" = "OpenBSD" ]; then
+ # IPv6 addresses in BPF seems to segfault on OpenBSD and doing host and
+ # not host throws generic pcap_compile error
+ ../dnscap -a 127.0.0.1 -r dns.pcap-dist -g -dddd
+ ../dnscap -z 127.0.0.1 -r dns.pcap-dist -g -dddd
+ ../dnscap -A 127.0.0.1 -r dns.pcap-dist -g -dddd
+ ../dnscap -Z 127.0.0.1 -r dns.pcap-dist -g -dddd
+ ../dnscap -Y 127.0.0.1 -r dns.pcap-dist -g -dddd
+else
+ ../dnscap -a 127.0.0.1 -a ::1 -r dns.pcap-dist -g -dddd
+ ../dnscap -z 127.0.0.1 -z ::1 -r dns.pcap-dist -g -dddd
+ ../dnscap -A 127.0.0.1 -A ::1 -r dns.pcap-dist -g -dddd
+ ../dnscap -Z 127.0.0.1 -Z ::1 -r dns.pcap-dist -g -dddd
+ ../dnscap -Y 127.0.0.1 -Y ::1 -r dns.pcap-dist -g -dddd
+fi
+if [ "$TEST_DNSCAP_WITH_NETWORK" = "1" ]; then
+ ../dnscap -a google.com -r dns.pcap-dist -g -dddd
+fi
+../dnscap -Y 127.0.0.1 -r dns.pcap-dist -g
+../dnscap -Y 8.8.8.8 -r dns.pcap-dist -g
diff --git a/src/test/test14.gold b/src/test/test14.gold
new file mode 100644
index 0000000..fb342e2
--- /dev/null
+++ b/src/test/test14.gold
@@ -0,0 +1,2864 @@
+-- only 1
+[56] 2016-10-20 15:23:01.075993 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].53199 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.077982 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53199 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns4.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:01.087291 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].40043 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.088733 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40043 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:10.322117 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].37953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:10.323399 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37953 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,34,216.58.218.206 \
+ 4 google.com.,IN,NS,157870,ns4.google.com. \
+ google.com.,IN,NS,157870,ns1.google.com. \
+ google.com.,IN,NS,157870,ns2.google.com. \
+ google.com.,IN,NS,157870,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157870,216.239.34.10 \
+ ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10
+[56] 2016-10-20 15:23:52.860937 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].40953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:52.863771 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40953 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,297,216.58.218.206 \
+ 4 google.com.,IN,NS,157828,ns2.google.com. \
+ google.com.,IN,NS,157828,ns4.google.com. \
+ google.com.,IN,NS,157828,ns1.google.com. \
+ google.com.,IN,NS,157828,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157828,216.239.34.10 \
+ ns1.google.com.,IN,A,331830,216.239.32.10 \
+ ns3.google.com.,IN,A,157828,216.239.36.10 \
+ ns4.google.com.,IN,A,157828,216.239.38.10
+[56] 2016-10-20 15:23:59.083869 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].45174 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:59.086104 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45174 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,291,216.58.218.206 \
+ 4 google.com.,IN,NS,157822,ns2.google.com. \
+ google.com.,IN,NS,157822,ns3.google.com. \
+ google.com.,IN,NS,157822,ns1.google.com. \
+ google.com.,IN,NS,157822,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157822,216.239.34.10 \
+ ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10
+[56] 2016-10-20 15:24:04.323868 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].43559 [8.8.8.8].53 \
+ dns QUERY,NOERROR,49483,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:04.325597 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].43559 \
+ dns QUERY,NOERROR,49483,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,285,216.58.218.206 \
+ 4 google.com.,IN,NS,157816,ns4.google.com. \
+ google.com.,IN,NS,157816,ns3.google.com. \
+ google.com.,IN,NS,157816,ns1.google.com. \
+ google.com.,IN,NS,157816,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157816,216.239.34.10 \
+ ns1.google.com.,IN,A,331818,216.239.32.10 \
+ ns3.google.com.,IN,A,157816,216.239.36.10 \
+ ns4.google.com.,IN,A,157816,216.239.38.10
+[56] 2016-10-20 15:24:06.332239 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].54859 [8.8.8.8].53 \
+ dns QUERY,NOERROR,31669,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:06.333743 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].54859 \
+ dns QUERY,NOERROR,31669,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,283,216.58.218.206 \
+ 4 google.com.,IN,NS,157814,ns2.google.com. \
+ google.com.,IN,NS,157814,ns1.google.com. \
+ google.com.,IN,NS,157814,ns4.google.com. \
+ google.com.,IN,NS,157814,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157814,216.239.34.10 \
+ ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10
+[56] 2016-10-20 15:24:07.346429 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].41266 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:07.348160 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41266 \
+ dns QUERY,NOERROR,63798,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,282,216.58.218.206 \
+ 4 google.com.,IN,NS,157813,ns4.google.com. \
+ google.com.,IN,NS,157813,ns1.google.com. \
+ google.com.,IN,NS,157813,ns3.google.com. \
+ google.com.,IN,NS,157813,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157813,216.239.34.10 \
+ ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10
+[56] 2016-10-20 15:24:08.360528 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].60437 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:08.362206 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60437 \
+ dns QUERY,NOERROR,60258,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,281,216.58.218.206 \
+ 4 google.com.,IN,NS,157812,ns3.google.com. \
+ google.com.,IN,NS,157812,ns2.google.com. \
+ google.com.,IN,NS,157812,ns4.google.com. \
+ google.com.,IN,NS,157812,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157812,216.239.34.10 \
+ ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10
+[56] 2016-10-20 15:24:09.375942 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].53820 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:09.378425 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53820 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,280,216.58.218.206 \
+ 4 google.com.,IN,NS,157811,ns3.google.com. \
+ google.com.,IN,NS,157811,ns4.google.com. \
+ google.com.,IN,NS,157811,ns1.google.com. \
+ google.com.,IN,NS,157811,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157811,216.239.34.10 \
+ ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10
+[56] 2016-10-20 15:24:10.391358 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].47637 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:10.392886 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].47637 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,279,216.58.218.206 \
+ 4 google.com.,IN,NS,157810,ns1.google.com. \
+ google.com.,IN,NS,157810,ns2.google.com. \
+ google.com.,IN,NS,157810,ns4.google.com. \
+ google.com.,IN,NS,157810,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157810,216.239.34.10 \
+ ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10
+[56] 2016-10-20 15:24:11.406297 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].41059 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:11.407460 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41059 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,278,216.58.218.206 \
+ 4 google.com.,IN,NS,157809,ns3.google.com. \
+ google.com.,IN,NS,157809,ns4.google.com. \
+ google.com.,IN,NS,157809,ns2.google.com. \
+ google.com.,IN,NS,157809,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157809,216.239.34.10 \
+ ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10
+[56] 2016-10-20 15:24:12.419936 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].32976 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:12.421228 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].32976 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,277,216.58.218.206 \
+ 4 google.com.,IN,NS,157808,ns2.google.com. \
+ google.com.,IN,NS,157808,ns3.google.com. \
+ google.com.,IN,NS,157808,ns1.google.com. \
+ google.com.,IN,NS,157808,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157808,216.239.34.10 \
+ ns1.google.com.,IN,A,331810,216.239.32.10 \
+ ns3.google.com.,IN,A,157808,216.239.36.10 \
+ ns4.google.com.,IN,A,157808,216.239.38.10
+[56] 2016-10-20 15:24:14.428524 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].53467 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:14.429863 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53467 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,275,216.58.218.206 \
+ 4 google.com.,IN,NS,157806,ns3.google.com. \
+ google.com.,IN,NS,157806,ns1.google.com. \
+ google.com.,IN,NS,157806,ns4.google.com. \
+ google.com.,IN,NS,157806,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157806,216.239.34.10 \
+ ns1.google.com.,IN,A,331808,216.239.32.10 \
+ ns3.google.com.,IN,A,157806,216.239.36.10 \
+ ns4.google.com.,IN,A,157806,216.239.38.10
+[56] 2016-10-20 15:24:16.435733 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].41532 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:16.437471 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41532 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,273,216.58.218.206 \
+ 4 google.com.,IN,NS,157804,ns1.google.com. \
+ google.com.,IN,NS,157804,ns3.google.com. \
+ google.com.,IN,NS,157804,ns2.google.com. \
+ google.com.,IN,NS,157804,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157804,216.239.34.10 \
+ ns1.google.com.,IN,A,331806,216.239.32.10 \
+ ns3.google.com.,IN,A,157804,216.239.36.10 \
+ ns4.google.com.,IN,A,157804,216.239.38.10
+[56] 2016-10-20 15:24:18.445519 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].44982 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:18.446775 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44982 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,271,216.58.218.206 \
+ 4 google.com.,IN,NS,157802,ns4.google.com. \
+ google.com.,IN,NS,157802,ns2.google.com. \
+ google.com.,IN,NS,157802,ns1.google.com. \
+ google.com.,IN,NS,157802,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157802,216.239.34.10 \
+ ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10
+[56] 2016-10-20 15:24:19.460087 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].45658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:19.462224 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45658 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,270,216.58.218.206 \
+ 4 google.com.,IN,NS,157801,ns1.google.com. \
+ google.com.,IN,NS,157801,ns3.google.com. \
+ google.com.,IN,NS,157801,ns4.google.com. \
+ google.com.,IN,NS,157801,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157801,216.239.34.10 \
+ ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10
+[56] 2016-10-20 15:24:20.475086 [#34 dns.pcap-dist 4095] \
+ [172.17.0.10].59762 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:20.476841 [#35 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].59762 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,269,216.58.218.206 \
+ 4 google.com.,IN,NS,157800,ns3.google.com. \
+ google.com.,IN,NS,157800,ns1.google.com. \
+ google.com.,IN,NS,157800,ns4.google.com. \
+ google.com.,IN,NS,157800,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157800,216.239.34.10 \
+ ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10
+[56] 2016-10-20 15:24:21.489468 [#36 dns.pcap-dist 4095] \
+ [172.17.0.10].37669 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:21.490573 [#37 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37669 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,268,216.58.218.206 \
+ 4 google.com.,IN,NS,157799,ns2.google.com. \
+ google.com.,IN,NS,157799,ns1.google.com. \
+ google.com.,IN,NS,157799,ns4.google.com. \
+ google.com.,IN,NS,157799,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157799,216.239.34.10 \
+ ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10
+[56] 2016-10-20 15:24:22.502667 [#38 dns.pcap-dist 4095] \
+ [172.17.0.10].49829 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:22.504738 [#39 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].49829 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,267,216.58.218.206 \
+ 4 google.com.,IN,NS,157798,ns2.google.com. \
+ google.com.,IN,NS,157798,ns4.google.com. \
+ google.com.,IN,NS,157798,ns3.google.com. \
+ google.com.,IN,NS,157798,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157798,216.239.34.10 \
+ ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10
+[56] 2016-10-20 15:24:23.520203 [#40 dns.pcap-dist 4095] \
+ [172.17.0.10].44980 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:23.521976 [#41 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44980 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,266,216.58.218.206 \
+ 4 google.com.,IN,NS,157797,ns2.google.com. \
+ google.com.,IN,NS,157797,ns4.google.com. \
+ google.com.,IN,NS,157797,ns1.google.com. \
+ google.com.,IN,NS,157797,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157797,216.239.34.10 \
+ ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10
+[56] 2016-10-20 15:24:24.537264 [#42 dns.pcap-dist 4095] \
+ [172.17.0.10].42042 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:24.539398 [#43 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42042 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,265,216.58.218.206 \
+ 4 google.com.,IN,NS,157796,ns3.google.com. \
+ google.com.,IN,NS,157796,ns4.google.com. \
+ google.com.,IN,NS,157796,ns1.google.com. \
+ google.com.,IN,NS,157796,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157796,216.239.34.10 \
+ ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10
+[56] 2016-10-20 15:24:25.554744 [#44 dns.pcap-dist 4095] \
+ [172.17.0.10].45703 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:25.556513 [#45 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45703 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,264,216.58.218.206 \
+ 4 google.com.,IN,NS,157795,ns3.google.com. \
+ google.com.,IN,NS,157795,ns4.google.com. \
+ google.com.,IN,NS,157795,ns2.google.com. \
+ google.com.,IN,NS,157795,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157795,216.239.34.10 \
+ ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10
+[56] 2016-10-20 15:24:26.572784 [#46 dns.pcap-dist 4095] \
+ [172.17.0.10].46798 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:26.574350 [#47 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].46798 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,263,216.58.218.206 \
+ 4 google.com.,IN,NS,157794,ns1.google.com. \
+ google.com.,IN,NS,157794,ns4.google.com. \
+ google.com.,IN,NS,157794,ns3.google.com. \
+ google.com.,IN,NS,157794,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157794,216.239.34.10 \
+ ns1.google.com.,IN,A,331796,216.239.32.10 \
+ ns3.google.com.,IN,A,157794,216.239.36.10 \
+ ns4.google.com.,IN,A,157794,216.239.38.10
+-- not 1
+[73] 2016-10-20 15:23:01.082865 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].57822 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:01.084107 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].57822 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71608,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10 \
+ ns2.google.com.,IN,A,157880,216.239.34.10
+[73] 2016-10-20 15:23:10.328324 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].48658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18718,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:10.329572 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].48658 \
+ dns QUERY,NOERROR,18718,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71598,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10 \
+ ns2.google.com.,IN,A,157870,216.239.34.10
+[73] 2016-10-20 15:23:59.090911 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].33916 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:59.092204 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33916 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71550,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10 \
+ ns2.google.com.,IN,A,157822,216.239.34.10
+[73] 2016-10-20 15:24:06.339145 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].58176 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:06.340820 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].58176 \
+ dns QUERY,NOERROR,25433,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71542,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10 \
+ ns2.google.com.,IN,A,157814,216.239.34.10
+[73] 2016-10-20 15:24:07.353123 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].34607 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:07.354682 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34607 \
+ dns QUERY,NOERROR,8470,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71541,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10 \
+ ns2.google.com.,IN,A,157813,216.239.34.10
+[73] 2016-10-20 15:24:08.368516 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].37149 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:08.370119 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37149 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71540,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10 \
+ ns2.google.com.,IN,A,157812,216.239.34.10
+[73] 2016-10-20 15:24:09.384057 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].52368 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:09.385463 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].52368 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71539,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10 \
+ ns2.google.com.,IN,A,157811,216.239.34.10
+[73] 2016-10-20 15:24:10.398099 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].34426 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:10.400317 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34426 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71538,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10 \
+ ns2.google.com.,IN,A,157810,216.239.34.10
+[73] 2016-10-20 15:24:11.412133 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].51181 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:11.413370 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].51181 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71537,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10 \
+ ns2.google.com.,IN,A,157809,216.239.34.10
+[73] 2016-10-20 15:24:18.452451 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].40224 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:18.454030 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40224 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71530,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10 \
+ ns2.google.com.,IN,A,157802,216.239.34.10
+[73] 2016-10-20 15:24:19.467324 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].60457 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:19.468895 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60457 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71529,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10 \
+ ns2.google.com.,IN,A,157801,216.239.34.10
+[73] 2016-10-20 15:24:20.482188 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].56022 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:20.483927 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].56022 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71528,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10 \
+ ns2.google.com.,IN,A,157800,216.239.34.10
+[73] 2016-10-20 15:24:21.495324 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].42978 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:21.496815 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42978 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71527,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10 \
+ ns2.google.com.,IN,A,157799,216.239.34.10
+[73] 2016-10-20 15:24:22.510176 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].50599 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:22.511746 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].50599 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71526,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10 \
+ ns2.google.com.,IN,A,157798,216.239.34.10
+[73] 2016-10-20 15:24:23.527449 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].60063 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:23.529385 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60063 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71525,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10 \
+ ns2.google.com.,IN,A,157797,216.239.34.10
+[73] 2016-10-20 15:24:24.544538 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].60469 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:24.546172 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60469 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71524,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10 \
+ ns2.google.com.,IN,A,157796,216.239.34.10
+[73] 2016-10-20 15:24:25.562608 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].33507 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:25.564509 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33507 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71523,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10 \
+ ns2.google.com.,IN,A,157795,216.239.34.10
+-- only PTR
+[73] 2016-10-20 15:23:01.082865 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].57822 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:01.084107 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].57822 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71608,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10 \
+ ns2.google.com.,IN,A,157880,216.239.34.10
+[73] 2016-10-20 15:23:10.328324 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].48658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18718,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:10.329572 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].48658 \
+ dns QUERY,NOERROR,18718,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71598,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10 \
+ ns2.google.com.,IN,A,157870,216.239.34.10
+[73] 2016-10-20 15:23:59.090911 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].33916 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:59.092204 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33916 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71550,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10 \
+ ns2.google.com.,IN,A,157822,216.239.34.10
+[73] 2016-10-20 15:24:06.339145 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].58176 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:06.340820 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].58176 \
+ dns QUERY,NOERROR,25433,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71542,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10 \
+ ns2.google.com.,IN,A,157814,216.239.34.10
+[73] 2016-10-20 15:24:07.353123 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].34607 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:07.354682 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34607 \
+ dns QUERY,NOERROR,8470,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71541,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10 \
+ ns2.google.com.,IN,A,157813,216.239.34.10
+[73] 2016-10-20 15:24:08.368516 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].37149 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:08.370119 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37149 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71540,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10 \
+ ns2.google.com.,IN,A,157812,216.239.34.10
+[73] 2016-10-20 15:24:09.384057 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].52368 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:09.385463 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].52368 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71539,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10 \
+ ns2.google.com.,IN,A,157811,216.239.34.10
+[73] 2016-10-20 15:24:10.398099 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].34426 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:10.400317 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34426 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71538,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10 \
+ ns2.google.com.,IN,A,157810,216.239.34.10
+[73] 2016-10-20 15:24:11.412133 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].51181 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:11.413370 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].51181 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71537,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10 \
+ ns2.google.com.,IN,A,157809,216.239.34.10
+[73] 2016-10-20 15:24:18.452451 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].40224 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:18.454030 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40224 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71530,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10 \
+ ns2.google.com.,IN,A,157802,216.239.34.10
+[73] 2016-10-20 15:24:19.467324 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].60457 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:19.468895 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60457 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71529,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10 \
+ ns2.google.com.,IN,A,157801,216.239.34.10
+[73] 2016-10-20 15:24:20.482188 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].56022 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:20.483927 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].56022 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71528,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10 \
+ ns2.google.com.,IN,A,157800,216.239.34.10
+[73] 2016-10-20 15:24:21.495324 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].42978 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:21.496815 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42978 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71527,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10 \
+ ns2.google.com.,IN,A,157799,216.239.34.10
+[73] 2016-10-20 15:24:22.510176 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].50599 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:22.511746 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].50599 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71526,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10 \
+ ns2.google.com.,IN,A,157798,216.239.34.10
+[73] 2016-10-20 15:24:23.527449 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].60063 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:23.529385 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60063 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71525,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10 \
+ ns2.google.com.,IN,A,157797,216.239.34.10
+[73] 2016-10-20 15:24:24.544538 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].60469 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:24.546172 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60469 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71524,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10 \
+ ns2.google.com.,IN,A,157796,216.239.34.10
+[73] 2016-10-20 15:24:25.562608 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].33507 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:25.564509 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33507 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71523,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10 \
+ ns2.google.com.,IN,A,157795,216.239.34.10
+-- not PTR
+[56] 2016-10-20 15:23:01.075993 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].53199 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.077982 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53199 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns4.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:01.087291 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].40043 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.088733 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40043 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:10.322117 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].37953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:10.323399 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37953 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,34,216.58.218.206 \
+ 4 google.com.,IN,NS,157870,ns4.google.com. \
+ google.com.,IN,NS,157870,ns1.google.com. \
+ google.com.,IN,NS,157870,ns2.google.com. \
+ google.com.,IN,NS,157870,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157870,216.239.34.10 \
+ ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10
+[56] 2016-10-20 15:23:52.860937 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].40953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:52.863771 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40953 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,297,216.58.218.206 \
+ 4 google.com.,IN,NS,157828,ns2.google.com. \
+ google.com.,IN,NS,157828,ns4.google.com. \
+ google.com.,IN,NS,157828,ns1.google.com. \
+ google.com.,IN,NS,157828,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157828,216.239.34.10 \
+ ns1.google.com.,IN,A,331830,216.239.32.10 \
+ ns3.google.com.,IN,A,157828,216.239.36.10 \
+ ns4.google.com.,IN,A,157828,216.239.38.10
+[56] 2016-10-20 15:23:59.083869 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].45174 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:59.086104 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45174 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,291,216.58.218.206 \
+ 4 google.com.,IN,NS,157822,ns2.google.com. \
+ google.com.,IN,NS,157822,ns3.google.com. \
+ google.com.,IN,NS,157822,ns1.google.com. \
+ google.com.,IN,NS,157822,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157822,216.239.34.10 \
+ ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10
+[56] 2016-10-20 15:24:04.323868 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].43559 [8.8.8.8].53 \
+ dns QUERY,NOERROR,49483,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:04.325597 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].43559 \
+ dns QUERY,NOERROR,49483,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,285,216.58.218.206 \
+ 4 google.com.,IN,NS,157816,ns4.google.com. \
+ google.com.,IN,NS,157816,ns3.google.com. \
+ google.com.,IN,NS,157816,ns1.google.com. \
+ google.com.,IN,NS,157816,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157816,216.239.34.10 \
+ ns1.google.com.,IN,A,331818,216.239.32.10 \
+ ns3.google.com.,IN,A,157816,216.239.36.10 \
+ ns4.google.com.,IN,A,157816,216.239.38.10
+[56] 2016-10-20 15:24:06.332239 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].54859 [8.8.8.8].53 \
+ dns QUERY,NOERROR,31669,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:06.333743 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].54859 \
+ dns QUERY,NOERROR,31669,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,283,216.58.218.206 \
+ 4 google.com.,IN,NS,157814,ns2.google.com. \
+ google.com.,IN,NS,157814,ns1.google.com. \
+ google.com.,IN,NS,157814,ns4.google.com. \
+ google.com.,IN,NS,157814,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157814,216.239.34.10 \
+ ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10
+[56] 2016-10-20 15:24:07.346429 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].41266 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:07.348160 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41266 \
+ dns QUERY,NOERROR,63798,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,282,216.58.218.206 \
+ 4 google.com.,IN,NS,157813,ns4.google.com. \
+ google.com.,IN,NS,157813,ns1.google.com. \
+ google.com.,IN,NS,157813,ns3.google.com. \
+ google.com.,IN,NS,157813,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157813,216.239.34.10 \
+ ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10
+[56] 2016-10-20 15:24:08.360528 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].60437 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:08.362206 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60437 \
+ dns QUERY,NOERROR,60258,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,281,216.58.218.206 \
+ 4 google.com.,IN,NS,157812,ns3.google.com. \
+ google.com.,IN,NS,157812,ns2.google.com. \
+ google.com.,IN,NS,157812,ns4.google.com. \
+ google.com.,IN,NS,157812,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157812,216.239.34.10 \
+ ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10
+[56] 2016-10-20 15:24:09.375942 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].53820 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:09.378425 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53820 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,280,216.58.218.206 \
+ 4 google.com.,IN,NS,157811,ns3.google.com. \
+ google.com.,IN,NS,157811,ns4.google.com. \
+ google.com.,IN,NS,157811,ns1.google.com. \
+ google.com.,IN,NS,157811,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157811,216.239.34.10 \
+ ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10
+[56] 2016-10-20 15:24:10.391358 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].47637 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:10.392886 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].47637 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,279,216.58.218.206 \
+ 4 google.com.,IN,NS,157810,ns1.google.com. \
+ google.com.,IN,NS,157810,ns2.google.com. \
+ google.com.,IN,NS,157810,ns4.google.com. \
+ google.com.,IN,NS,157810,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157810,216.239.34.10 \
+ ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10
+[56] 2016-10-20 15:24:11.406297 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].41059 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:11.407460 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41059 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,278,216.58.218.206 \
+ 4 google.com.,IN,NS,157809,ns3.google.com. \
+ google.com.,IN,NS,157809,ns4.google.com. \
+ google.com.,IN,NS,157809,ns2.google.com. \
+ google.com.,IN,NS,157809,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157809,216.239.34.10 \
+ ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10
+[56] 2016-10-20 15:24:12.419936 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].32976 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:12.421228 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].32976 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,277,216.58.218.206 \
+ 4 google.com.,IN,NS,157808,ns2.google.com. \
+ google.com.,IN,NS,157808,ns3.google.com. \
+ google.com.,IN,NS,157808,ns1.google.com. \
+ google.com.,IN,NS,157808,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157808,216.239.34.10 \
+ ns1.google.com.,IN,A,331810,216.239.32.10 \
+ ns3.google.com.,IN,A,157808,216.239.36.10 \
+ ns4.google.com.,IN,A,157808,216.239.38.10
+[56] 2016-10-20 15:24:14.428524 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].53467 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:14.429863 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53467 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,275,216.58.218.206 \
+ 4 google.com.,IN,NS,157806,ns3.google.com. \
+ google.com.,IN,NS,157806,ns1.google.com. \
+ google.com.,IN,NS,157806,ns4.google.com. \
+ google.com.,IN,NS,157806,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157806,216.239.34.10 \
+ ns1.google.com.,IN,A,331808,216.239.32.10 \
+ ns3.google.com.,IN,A,157806,216.239.36.10 \
+ ns4.google.com.,IN,A,157806,216.239.38.10
+[56] 2016-10-20 15:24:16.435733 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].41532 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:16.437471 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41532 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,273,216.58.218.206 \
+ 4 google.com.,IN,NS,157804,ns1.google.com. \
+ google.com.,IN,NS,157804,ns3.google.com. \
+ google.com.,IN,NS,157804,ns2.google.com. \
+ google.com.,IN,NS,157804,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157804,216.239.34.10 \
+ ns1.google.com.,IN,A,331806,216.239.32.10 \
+ ns3.google.com.,IN,A,157804,216.239.36.10 \
+ ns4.google.com.,IN,A,157804,216.239.38.10
+[56] 2016-10-20 15:24:18.445519 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].44982 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:18.446775 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44982 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,271,216.58.218.206 \
+ 4 google.com.,IN,NS,157802,ns4.google.com. \
+ google.com.,IN,NS,157802,ns2.google.com. \
+ google.com.,IN,NS,157802,ns1.google.com. \
+ google.com.,IN,NS,157802,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157802,216.239.34.10 \
+ ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10
+[56] 2016-10-20 15:24:19.460087 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].45658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:19.462224 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45658 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,270,216.58.218.206 \
+ 4 google.com.,IN,NS,157801,ns1.google.com. \
+ google.com.,IN,NS,157801,ns3.google.com. \
+ google.com.,IN,NS,157801,ns4.google.com. \
+ google.com.,IN,NS,157801,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157801,216.239.34.10 \
+ ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10
+[56] 2016-10-20 15:24:20.475086 [#34 dns.pcap-dist 4095] \
+ [172.17.0.10].59762 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:20.476841 [#35 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].59762 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,269,216.58.218.206 \
+ 4 google.com.,IN,NS,157800,ns3.google.com. \
+ google.com.,IN,NS,157800,ns1.google.com. \
+ google.com.,IN,NS,157800,ns4.google.com. \
+ google.com.,IN,NS,157800,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157800,216.239.34.10 \
+ ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10
+[56] 2016-10-20 15:24:21.489468 [#36 dns.pcap-dist 4095] \
+ [172.17.0.10].37669 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:21.490573 [#37 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37669 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,268,216.58.218.206 \
+ 4 google.com.,IN,NS,157799,ns2.google.com. \
+ google.com.,IN,NS,157799,ns1.google.com. \
+ google.com.,IN,NS,157799,ns4.google.com. \
+ google.com.,IN,NS,157799,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157799,216.239.34.10 \
+ ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10
+[56] 2016-10-20 15:24:22.502667 [#38 dns.pcap-dist 4095] \
+ [172.17.0.10].49829 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:22.504738 [#39 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].49829 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,267,216.58.218.206 \
+ 4 google.com.,IN,NS,157798,ns2.google.com. \
+ google.com.,IN,NS,157798,ns4.google.com. \
+ google.com.,IN,NS,157798,ns3.google.com. \
+ google.com.,IN,NS,157798,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157798,216.239.34.10 \
+ ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10
+[56] 2016-10-20 15:24:23.520203 [#40 dns.pcap-dist 4095] \
+ [172.17.0.10].44980 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:23.521976 [#41 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44980 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,266,216.58.218.206 \
+ 4 google.com.,IN,NS,157797,ns2.google.com. \
+ google.com.,IN,NS,157797,ns4.google.com. \
+ google.com.,IN,NS,157797,ns1.google.com. \
+ google.com.,IN,NS,157797,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157797,216.239.34.10 \
+ ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10
+[56] 2016-10-20 15:24:24.537264 [#42 dns.pcap-dist 4095] \
+ [172.17.0.10].42042 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:24.539398 [#43 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42042 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,265,216.58.218.206 \
+ 4 google.com.,IN,NS,157796,ns3.google.com. \
+ google.com.,IN,NS,157796,ns4.google.com. \
+ google.com.,IN,NS,157796,ns1.google.com. \
+ google.com.,IN,NS,157796,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157796,216.239.34.10 \
+ ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10
+[56] 2016-10-20 15:24:25.554744 [#44 dns.pcap-dist 4095] \
+ [172.17.0.10].45703 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:25.556513 [#45 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45703 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,264,216.58.218.206 \
+ 4 google.com.,IN,NS,157795,ns3.google.com. \
+ google.com.,IN,NS,157795,ns4.google.com. \
+ google.com.,IN,NS,157795,ns2.google.com. \
+ google.com.,IN,NS,157795,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157795,216.239.34.10 \
+ ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10
+[56] 2016-10-20 15:24:26.572784 [#46 dns.pcap-dist 4095] \
+ [172.17.0.10].46798 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:26.574350 [#47 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].46798 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,263,216.58.218.206 \
+ 4 google.com.,IN,NS,157794,ns1.google.com. \
+ google.com.,IN,NS,157794,ns4.google.com. \
+ google.com.,IN,NS,157794,ns3.google.com. \
+ google.com.,IN,NS,157794,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157794,216.239.34.10 \
+ ns1.google.com.,IN,A,331796,216.239.32.10 \
+ ns3.google.com.,IN,A,157794,216.239.36.10 \
+ ns4.google.com.,IN,A,157794,216.239.38.10
+-- only 1
+[56] 2016-10-20 15:23:01.075993 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].53199 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.077982 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53199 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns4.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:01.087291 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].40043 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.088733 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40043 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:10.322117 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].37953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:10.323399 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37953 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,34,216.58.218.206 \
+ 4 google.com.,IN,NS,157870,ns4.google.com. \
+ google.com.,IN,NS,157870,ns1.google.com. \
+ google.com.,IN,NS,157870,ns2.google.com. \
+ google.com.,IN,NS,157870,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157870,216.239.34.10 \
+ ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10
+[56] 2016-10-20 15:23:52.860937 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].40953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:52.863771 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40953 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,297,216.58.218.206 \
+ 4 google.com.,IN,NS,157828,ns2.google.com. \
+ google.com.,IN,NS,157828,ns4.google.com. \
+ google.com.,IN,NS,157828,ns1.google.com. \
+ google.com.,IN,NS,157828,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157828,216.239.34.10 \
+ ns1.google.com.,IN,A,331830,216.239.32.10 \
+ ns3.google.com.,IN,A,157828,216.239.36.10 \
+ ns4.google.com.,IN,A,157828,216.239.38.10
+[56] 2016-10-20 15:23:59.083869 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].45174 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:59.086104 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45174 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,291,216.58.218.206 \
+ 4 google.com.,IN,NS,157822,ns2.google.com. \
+ google.com.,IN,NS,157822,ns3.google.com. \
+ google.com.,IN,NS,157822,ns1.google.com. \
+ google.com.,IN,NS,157822,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157822,216.239.34.10 \
+ ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10
+[56] 2016-10-20 15:24:04.323868 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].43559 [8.8.8.8].53 \
+ dns QUERY,NOERROR,49483,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:04.325597 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].43559 \
+ dns QUERY,NOERROR,49483,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,285,216.58.218.206 \
+ 4 google.com.,IN,NS,157816,ns4.google.com. \
+ google.com.,IN,NS,157816,ns3.google.com. \
+ google.com.,IN,NS,157816,ns1.google.com. \
+ google.com.,IN,NS,157816,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157816,216.239.34.10 \
+ ns1.google.com.,IN,A,331818,216.239.32.10 \
+ ns3.google.com.,IN,A,157816,216.239.36.10 \
+ ns4.google.com.,IN,A,157816,216.239.38.10
+[56] 2016-10-20 15:24:06.332239 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].54859 [8.8.8.8].53 \
+ dns QUERY,NOERROR,31669,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:06.333743 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].54859 \
+ dns QUERY,NOERROR,31669,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,283,216.58.218.206 \
+ 4 google.com.,IN,NS,157814,ns2.google.com. \
+ google.com.,IN,NS,157814,ns1.google.com. \
+ google.com.,IN,NS,157814,ns4.google.com. \
+ google.com.,IN,NS,157814,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157814,216.239.34.10 \
+ ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10
+[56] 2016-10-20 15:24:07.346429 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].41266 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:07.348160 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41266 \
+ dns QUERY,NOERROR,63798,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,282,216.58.218.206 \
+ 4 google.com.,IN,NS,157813,ns4.google.com. \
+ google.com.,IN,NS,157813,ns1.google.com. \
+ google.com.,IN,NS,157813,ns3.google.com. \
+ google.com.,IN,NS,157813,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157813,216.239.34.10 \
+ ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10
+[56] 2016-10-20 15:24:08.360528 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].60437 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:08.362206 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60437 \
+ dns QUERY,NOERROR,60258,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,281,216.58.218.206 \
+ 4 google.com.,IN,NS,157812,ns3.google.com. \
+ google.com.,IN,NS,157812,ns2.google.com. \
+ google.com.,IN,NS,157812,ns4.google.com. \
+ google.com.,IN,NS,157812,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157812,216.239.34.10 \
+ ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10
+[56] 2016-10-20 15:24:09.375942 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].53820 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:09.378425 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53820 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,280,216.58.218.206 \
+ 4 google.com.,IN,NS,157811,ns3.google.com. \
+ google.com.,IN,NS,157811,ns4.google.com. \
+ google.com.,IN,NS,157811,ns1.google.com. \
+ google.com.,IN,NS,157811,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157811,216.239.34.10 \
+ ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10
+[56] 2016-10-20 15:24:10.391358 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].47637 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:10.392886 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].47637 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,279,216.58.218.206 \
+ 4 google.com.,IN,NS,157810,ns1.google.com. \
+ google.com.,IN,NS,157810,ns2.google.com. \
+ google.com.,IN,NS,157810,ns4.google.com. \
+ google.com.,IN,NS,157810,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157810,216.239.34.10 \
+ ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10
+[56] 2016-10-20 15:24:11.406297 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].41059 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:11.407460 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41059 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,278,216.58.218.206 \
+ 4 google.com.,IN,NS,157809,ns3.google.com. \
+ google.com.,IN,NS,157809,ns4.google.com. \
+ google.com.,IN,NS,157809,ns2.google.com. \
+ google.com.,IN,NS,157809,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157809,216.239.34.10 \
+ ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10
+[56] 2016-10-20 15:24:12.419936 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].32976 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:12.421228 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].32976 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,277,216.58.218.206 \
+ 4 google.com.,IN,NS,157808,ns2.google.com. \
+ google.com.,IN,NS,157808,ns3.google.com. \
+ google.com.,IN,NS,157808,ns1.google.com. \
+ google.com.,IN,NS,157808,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157808,216.239.34.10 \
+ ns1.google.com.,IN,A,331810,216.239.32.10 \
+ ns3.google.com.,IN,A,157808,216.239.36.10 \
+ ns4.google.com.,IN,A,157808,216.239.38.10
+[56] 2016-10-20 15:24:14.428524 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].53467 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:14.429863 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53467 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,275,216.58.218.206 \
+ 4 google.com.,IN,NS,157806,ns3.google.com. \
+ google.com.,IN,NS,157806,ns1.google.com. \
+ google.com.,IN,NS,157806,ns4.google.com. \
+ google.com.,IN,NS,157806,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157806,216.239.34.10 \
+ ns1.google.com.,IN,A,331808,216.239.32.10 \
+ ns3.google.com.,IN,A,157806,216.239.36.10 \
+ ns4.google.com.,IN,A,157806,216.239.38.10
+[56] 2016-10-20 15:24:16.435733 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].41532 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:16.437471 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41532 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,273,216.58.218.206 \
+ 4 google.com.,IN,NS,157804,ns1.google.com. \
+ google.com.,IN,NS,157804,ns3.google.com. \
+ google.com.,IN,NS,157804,ns2.google.com. \
+ google.com.,IN,NS,157804,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157804,216.239.34.10 \
+ ns1.google.com.,IN,A,331806,216.239.32.10 \
+ ns3.google.com.,IN,A,157804,216.239.36.10 \
+ ns4.google.com.,IN,A,157804,216.239.38.10
+[56] 2016-10-20 15:24:18.445519 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].44982 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:18.446775 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44982 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,271,216.58.218.206 \
+ 4 google.com.,IN,NS,157802,ns4.google.com. \
+ google.com.,IN,NS,157802,ns2.google.com. \
+ google.com.,IN,NS,157802,ns1.google.com. \
+ google.com.,IN,NS,157802,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157802,216.239.34.10 \
+ ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10
+[56] 2016-10-20 15:24:19.460087 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].45658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:19.462224 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45658 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,270,216.58.218.206 \
+ 4 google.com.,IN,NS,157801,ns1.google.com. \
+ google.com.,IN,NS,157801,ns3.google.com. \
+ google.com.,IN,NS,157801,ns4.google.com. \
+ google.com.,IN,NS,157801,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157801,216.239.34.10 \
+ ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10
+[56] 2016-10-20 15:24:20.475086 [#34 dns.pcap-dist 4095] \
+ [172.17.0.10].59762 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:20.476841 [#35 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].59762 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,269,216.58.218.206 \
+ 4 google.com.,IN,NS,157800,ns3.google.com. \
+ google.com.,IN,NS,157800,ns1.google.com. \
+ google.com.,IN,NS,157800,ns4.google.com. \
+ google.com.,IN,NS,157800,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157800,216.239.34.10 \
+ ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10
+[56] 2016-10-20 15:24:21.489468 [#36 dns.pcap-dist 4095] \
+ [172.17.0.10].37669 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:21.490573 [#37 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37669 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,268,216.58.218.206 \
+ 4 google.com.,IN,NS,157799,ns2.google.com. \
+ google.com.,IN,NS,157799,ns1.google.com. \
+ google.com.,IN,NS,157799,ns4.google.com. \
+ google.com.,IN,NS,157799,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157799,216.239.34.10 \
+ ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10
+[56] 2016-10-20 15:24:22.502667 [#38 dns.pcap-dist 4095] \
+ [172.17.0.10].49829 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:22.504738 [#39 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].49829 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,267,216.58.218.206 \
+ 4 google.com.,IN,NS,157798,ns2.google.com. \
+ google.com.,IN,NS,157798,ns4.google.com. \
+ google.com.,IN,NS,157798,ns3.google.com. \
+ google.com.,IN,NS,157798,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157798,216.239.34.10 \
+ ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10
+[56] 2016-10-20 15:24:23.520203 [#40 dns.pcap-dist 4095] \
+ [172.17.0.10].44980 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:23.521976 [#41 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44980 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,266,216.58.218.206 \
+ 4 google.com.,IN,NS,157797,ns2.google.com. \
+ google.com.,IN,NS,157797,ns4.google.com. \
+ google.com.,IN,NS,157797,ns1.google.com. \
+ google.com.,IN,NS,157797,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157797,216.239.34.10 \
+ ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10
+[56] 2016-10-20 15:24:24.537264 [#42 dns.pcap-dist 4095] \
+ [172.17.0.10].42042 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:24.539398 [#43 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42042 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,265,216.58.218.206 \
+ 4 google.com.,IN,NS,157796,ns3.google.com. \
+ google.com.,IN,NS,157796,ns4.google.com. \
+ google.com.,IN,NS,157796,ns1.google.com. \
+ google.com.,IN,NS,157796,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157796,216.239.34.10 \
+ ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10
+[56] 2016-10-20 15:24:25.554744 [#44 dns.pcap-dist 4095] \
+ [172.17.0.10].45703 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:25.556513 [#45 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45703 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,264,216.58.218.206 \
+ 4 google.com.,IN,NS,157795,ns3.google.com. \
+ google.com.,IN,NS,157795,ns4.google.com. \
+ google.com.,IN,NS,157795,ns2.google.com. \
+ google.com.,IN,NS,157795,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157795,216.239.34.10 \
+ ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10
+[56] 2016-10-20 15:24:26.572784 [#46 dns.pcap-dist 4095] \
+ [172.17.0.10].46798 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:26.574350 [#47 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].46798 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,263,216.58.218.206 \
+ 4 google.com.,IN,NS,157794,ns1.google.com. \
+ google.com.,IN,NS,157794,ns4.google.com. \
+ google.com.,IN,NS,157794,ns3.google.com. \
+ google.com.,IN,NS,157794,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157794,216.239.34.10 \
+ ns1.google.com.,IN,A,331796,216.239.32.10 \
+ ns3.google.com.,IN,A,157794,216.239.36.10 \
+ ns4.google.com.,IN,A,157794,216.239.38.10
+-- not 1
+[73] 2016-10-20 15:23:01.082865 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].57822 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:01.084107 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].57822 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71608,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10 \
+ ns2.google.com.,IN,A,157880,216.239.34.10
+[73] 2016-10-20 15:23:10.328324 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].48658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18718,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:10.329572 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].48658 \
+ dns QUERY,NOERROR,18718,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71598,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10 \
+ ns2.google.com.,IN,A,157870,216.239.34.10
+[73] 2016-10-20 15:23:59.090911 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].33916 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:59.092204 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33916 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71550,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10 \
+ ns2.google.com.,IN,A,157822,216.239.34.10
+[73] 2016-10-20 15:24:06.339145 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].58176 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:06.340820 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].58176 \
+ dns QUERY,NOERROR,25433,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71542,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10 \
+ ns2.google.com.,IN,A,157814,216.239.34.10
+[73] 2016-10-20 15:24:07.353123 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].34607 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:07.354682 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34607 \
+ dns QUERY,NOERROR,8470,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71541,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10 \
+ ns2.google.com.,IN,A,157813,216.239.34.10
+[73] 2016-10-20 15:24:08.368516 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].37149 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:08.370119 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37149 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71540,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10 \
+ ns2.google.com.,IN,A,157812,216.239.34.10
+[73] 2016-10-20 15:24:09.384057 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].52368 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:09.385463 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].52368 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71539,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10 \
+ ns2.google.com.,IN,A,157811,216.239.34.10
+[73] 2016-10-20 15:24:10.398099 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].34426 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:10.400317 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34426 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71538,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10 \
+ ns2.google.com.,IN,A,157810,216.239.34.10
+[73] 2016-10-20 15:24:11.412133 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].51181 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:11.413370 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].51181 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71537,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10 \
+ ns2.google.com.,IN,A,157809,216.239.34.10
+[73] 2016-10-20 15:24:18.452451 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].40224 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:18.454030 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40224 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71530,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10 \
+ ns2.google.com.,IN,A,157802,216.239.34.10
+[73] 2016-10-20 15:24:19.467324 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].60457 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:19.468895 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60457 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71529,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10 \
+ ns2.google.com.,IN,A,157801,216.239.34.10
+[73] 2016-10-20 15:24:20.482188 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].56022 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:20.483927 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].56022 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71528,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10 \
+ ns2.google.com.,IN,A,157800,216.239.34.10
+[73] 2016-10-20 15:24:21.495324 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].42978 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:21.496815 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42978 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71527,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10 \
+ ns2.google.com.,IN,A,157799,216.239.34.10
+[73] 2016-10-20 15:24:22.510176 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].50599 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:22.511746 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].50599 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71526,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10 \
+ ns2.google.com.,IN,A,157798,216.239.34.10
+[73] 2016-10-20 15:24:23.527449 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].60063 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:23.529385 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60063 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71525,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10 \
+ ns2.google.com.,IN,A,157797,216.239.34.10
+[73] 2016-10-20 15:24:24.544538 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].60469 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:24.546172 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60469 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71524,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10 \
+ ns2.google.com.,IN,A,157796,216.239.34.10
+[73] 2016-10-20 15:24:25.562608 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].33507 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:25.564509 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33507 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71523,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10 \
+ ns2.google.com.,IN,A,157795,216.239.34.10
+-- only PTR
+[73] 2016-10-20 15:23:01.082865 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].57822 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:01.084107 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].57822 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71608,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10 \
+ ns2.google.com.,IN,A,157880,216.239.34.10
+[73] 2016-10-20 15:23:10.328324 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].48658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18718,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:10.329572 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].48658 \
+ dns QUERY,NOERROR,18718,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71598,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10 \
+ ns2.google.com.,IN,A,157870,216.239.34.10
+[73] 2016-10-20 15:23:59.090911 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].33916 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:59.092204 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33916 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71550,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10 \
+ ns2.google.com.,IN,A,157822,216.239.34.10
+[73] 2016-10-20 15:24:06.339145 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].58176 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:06.340820 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].58176 \
+ dns QUERY,NOERROR,25433,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71542,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10 \
+ ns2.google.com.,IN,A,157814,216.239.34.10
+[73] 2016-10-20 15:24:07.353123 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].34607 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:07.354682 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34607 \
+ dns QUERY,NOERROR,8470,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71541,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10 \
+ ns2.google.com.,IN,A,157813,216.239.34.10
+[73] 2016-10-20 15:24:08.368516 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].37149 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:08.370119 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37149 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71540,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10 \
+ ns2.google.com.,IN,A,157812,216.239.34.10
+[73] 2016-10-20 15:24:09.384057 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].52368 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:09.385463 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].52368 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71539,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10 \
+ ns2.google.com.,IN,A,157811,216.239.34.10
+[73] 2016-10-20 15:24:10.398099 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].34426 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:10.400317 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].34426 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71538,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10 \
+ ns2.google.com.,IN,A,157810,216.239.34.10
+[73] 2016-10-20 15:24:11.412133 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].51181 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:11.413370 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].51181 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71537,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10 \
+ ns2.google.com.,IN,A,157809,216.239.34.10
+[73] 2016-10-20 15:24:18.452451 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].40224 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:18.454030 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40224 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71530,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10 \
+ ns2.google.com.,IN,A,157802,216.239.34.10
+[73] 2016-10-20 15:24:19.467324 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].60457 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:19.468895 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60457 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71529,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10 \
+ ns2.google.com.,IN,A,157801,216.239.34.10
+[73] 2016-10-20 15:24:20.482188 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].56022 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:20.483927 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].56022 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71528,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10 \
+ ns2.google.com.,IN,A,157800,216.239.34.10
+[73] 2016-10-20 15:24:21.495324 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].42978 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:21.496815 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42978 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71527,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10 \
+ ns2.google.com.,IN,A,157799,216.239.34.10
+[73] 2016-10-20 15:24:22.510176 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].50599 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:22.511746 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].50599 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71526,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10 \
+ ns2.google.com.,IN,A,157798,216.239.34.10
+[73] 2016-10-20 15:24:23.527449 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].60063 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:23.529385 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60063 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71525,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10 \
+ ns2.google.com.,IN,A,157797,216.239.34.10
+[73] 2016-10-20 15:24:24.544538 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].60469 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:24.546172 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60469 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71524,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10 \
+ ns2.google.com.,IN,A,157796,216.239.34.10
+[73] 2016-10-20 15:24:25.562608 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].33507 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:25.564509 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33507 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71523,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10 \
+ ns2.google.com.,IN,A,157795,216.239.34.10
+-- not PTR
+[56] 2016-10-20 15:23:01.075993 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].53199 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.077982 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53199 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns4.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:01.087291 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].40043 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.088733 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40043 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:10.322117 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].37953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:10.323399 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37953 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,34,216.58.218.206 \
+ 4 google.com.,IN,NS,157870,ns4.google.com. \
+ google.com.,IN,NS,157870,ns1.google.com. \
+ google.com.,IN,NS,157870,ns2.google.com. \
+ google.com.,IN,NS,157870,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157870,216.239.34.10 \
+ ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10
+[56] 2016-10-20 15:23:52.860937 [#6 dns.pcap-dist 4095] \
+ [172.17.0.10].40953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:52.863771 [#7 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40953 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,297,216.58.218.206 \
+ 4 google.com.,IN,NS,157828,ns2.google.com. \
+ google.com.,IN,NS,157828,ns4.google.com. \
+ google.com.,IN,NS,157828,ns1.google.com. \
+ google.com.,IN,NS,157828,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157828,216.239.34.10 \
+ ns1.google.com.,IN,A,331830,216.239.32.10 \
+ ns3.google.com.,IN,A,157828,216.239.36.10 \
+ ns4.google.com.,IN,A,157828,216.239.38.10
+[56] 2016-10-20 15:23:59.083869 [#8 dns.pcap-dist 4095] \
+ [172.17.0.10].45174 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:59.086104 [#9 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45174 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,291,216.58.218.206 \
+ 4 google.com.,IN,NS,157822,ns2.google.com. \
+ google.com.,IN,NS,157822,ns3.google.com. \
+ google.com.,IN,NS,157822,ns1.google.com. \
+ google.com.,IN,NS,157822,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157822,216.239.34.10 \
+ ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10
+[56] 2016-10-20 15:24:04.323868 [#10 dns.pcap-dist 4095] \
+ [172.17.0.10].43559 [8.8.8.8].53 \
+ dns QUERY,NOERROR,49483,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:04.325597 [#11 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].43559 \
+ dns QUERY,NOERROR,49483,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,285,216.58.218.206 \
+ 4 google.com.,IN,NS,157816,ns4.google.com. \
+ google.com.,IN,NS,157816,ns3.google.com. \
+ google.com.,IN,NS,157816,ns1.google.com. \
+ google.com.,IN,NS,157816,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157816,216.239.34.10 \
+ ns1.google.com.,IN,A,331818,216.239.32.10 \
+ ns3.google.com.,IN,A,157816,216.239.36.10 \
+ ns4.google.com.,IN,A,157816,216.239.38.10
+[56] 2016-10-20 15:24:06.332239 [#12 dns.pcap-dist 4095] \
+ [172.17.0.10].54859 [8.8.8.8].53 \
+ dns QUERY,NOERROR,31669,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:06.333743 [#13 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].54859 \
+ dns QUERY,NOERROR,31669,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,283,216.58.218.206 \
+ 4 google.com.,IN,NS,157814,ns2.google.com. \
+ google.com.,IN,NS,157814,ns1.google.com. \
+ google.com.,IN,NS,157814,ns4.google.com. \
+ google.com.,IN,NS,157814,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157814,216.239.34.10 \
+ ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10
+[56] 2016-10-20 15:24:07.346429 [#14 dns.pcap-dist 4095] \
+ [172.17.0.10].41266 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:07.348160 [#15 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41266 \
+ dns QUERY,NOERROR,63798,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,282,216.58.218.206 \
+ 4 google.com.,IN,NS,157813,ns4.google.com. \
+ google.com.,IN,NS,157813,ns1.google.com. \
+ google.com.,IN,NS,157813,ns3.google.com. \
+ google.com.,IN,NS,157813,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157813,216.239.34.10 \
+ ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10
+[56] 2016-10-20 15:24:08.360528 [#16 dns.pcap-dist 4095] \
+ [172.17.0.10].60437 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:08.362206 [#17 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].60437 \
+ dns QUERY,NOERROR,60258,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,281,216.58.218.206 \
+ 4 google.com.,IN,NS,157812,ns3.google.com. \
+ google.com.,IN,NS,157812,ns2.google.com. \
+ google.com.,IN,NS,157812,ns4.google.com. \
+ google.com.,IN,NS,157812,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157812,216.239.34.10 \
+ ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10
+[56] 2016-10-20 15:24:09.375942 [#18 dns.pcap-dist 4095] \
+ [172.17.0.10].53820 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:09.378425 [#19 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53820 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,280,216.58.218.206 \
+ 4 google.com.,IN,NS,157811,ns3.google.com. \
+ google.com.,IN,NS,157811,ns4.google.com. \
+ google.com.,IN,NS,157811,ns1.google.com. \
+ google.com.,IN,NS,157811,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157811,216.239.34.10 \
+ ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10
+[56] 2016-10-20 15:24:10.391358 [#20 dns.pcap-dist 4095] \
+ [172.17.0.10].47637 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:10.392886 [#21 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].47637 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,279,216.58.218.206 \
+ 4 google.com.,IN,NS,157810,ns1.google.com. \
+ google.com.,IN,NS,157810,ns2.google.com. \
+ google.com.,IN,NS,157810,ns4.google.com. \
+ google.com.,IN,NS,157810,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157810,216.239.34.10 \
+ ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10
+[56] 2016-10-20 15:24:11.406297 [#22 dns.pcap-dist 4095] \
+ [172.17.0.10].41059 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:11.407460 [#23 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41059 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,278,216.58.218.206 \
+ 4 google.com.,IN,NS,157809,ns3.google.com. \
+ google.com.,IN,NS,157809,ns4.google.com. \
+ google.com.,IN,NS,157809,ns2.google.com. \
+ google.com.,IN,NS,157809,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157809,216.239.34.10 \
+ ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10
+[56] 2016-10-20 15:24:12.419936 [#24 dns.pcap-dist 4095] \
+ [172.17.0.10].32976 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:12.421228 [#25 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].32976 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,277,216.58.218.206 \
+ 4 google.com.,IN,NS,157808,ns2.google.com. \
+ google.com.,IN,NS,157808,ns3.google.com. \
+ google.com.,IN,NS,157808,ns1.google.com. \
+ google.com.,IN,NS,157808,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157808,216.239.34.10 \
+ ns1.google.com.,IN,A,331810,216.239.32.10 \
+ ns3.google.com.,IN,A,157808,216.239.36.10 \
+ ns4.google.com.,IN,A,157808,216.239.38.10
+[56] 2016-10-20 15:24:14.428524 [#26 dns.pcap-dist 4095] \
+ [172.17.0.10].53467 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:14.429863 [#27 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].53467 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,275,216.58.218.206 \
+ 4 google.com.,IN,NS,157806,ns3.google.com. \
+ google.com.,IN,NS,157806,ns1.google.com. \
+ google.com.,IN,NS,157806,ns4.google.com. \
+ google.com.,IN,NS,157806,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157806,216.239.34.10 \
+ ns1.google.com.,IN,A,331808,216.239.32.10 \
+ ns3.google.com.,IN,A,157806,216.239.36.10 \
+ ns4.google.com.,IN,A,157806,216.239.38.10
+[56] 2016-10-20 15:24:16.435733 [#28 dns.pcap-dist 4095] \
+ [172.17.0.10].41532 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:16.437471 [#29 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].41532 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,273,216.58.218.206 \
+ 4 google.com.,IN,NS,157804,ns1.google.com. \
+ google.com.,IN,NS,157804,ns3.google.com. \
+ google.com.,IN,NS,157804,ns2.google.com. \
+ google.com.,IN,NS,157804,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157804,216.239.34.10 \
+ ns1.google.com.,IN,A,331806,216.239.32.10 \
+ ns3.google.com.,IN,A,157804,216.239.36.10 \
+ ns4.google.com.,IN,A,157804,216.239.38.10
+[56] 2016-10-20 15:24:18.445519 [#30 dns.pcap-dist 4095] \
+ [172.17.0.10].44982 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:18.446775 [#31 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44982 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,271,216.58.218.206 \
+ 4 google.com.,IN,NS,157802,ns4.google.com. \
+ google.com.,IN,NS,157802,ns2.google.com. \
+ google.com.,IN,NS,157802,ns1.google.com. \
+ google.com.,IN,NS,157802,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157802,216.239.34.10 \
+ ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10
+[56] 2016-10-20 15:24:19.460087 [#32 dns.pcap-dist 4095] \
+ [172.17.0.10].45658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:19.462224 [#33 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45658 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,270,216.58.218.206 \
+ 4 google.com.,IN,NS,157801,ns1.google.com. \
+ google.com.,IN,NS,157801,ns3.google.com. \
+ google.com.,IN,NS,157801,ns4.google.com. \
+ google.com.,IN,NS,157801,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157801,216.239.34.10 \
+ ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10
+[56] 2016-10-20 15:24:20.475086 [#34 dns.pcap-dist 4095] \
+ [172.17.0.10].59762 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:20.476841 [#35 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].59762 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,269,216.58.218.206 \
+ 4 google.com.,IN,NS,157800,ns3.google.com. \
+ google.com.,IN,NS,157800,ns1.google.com. \
+ google.com.,IN,NS,157800,ns4.google.com. \
+ google.com.,IN,NS,157800,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157800,216.239.34.10 \
+ ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10
+[56] 2016-10-20 15:24:21.489468 [#36 dns.pcap-dist 4095] \
+ [172.17.0.10].37669 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:21.490573 [#37 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].37669 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,268,216.58.218.206 \
+ 4 google.com.,IN,NS,157799,ns2.google.com. \
+ google.com.,IN,NS,157799,ns1.google.com. \
+ google.com.,IN,NS,157799,ns4.google.com. \
+ google.com.,IN,NS,157799,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157799,216.239.34.10 \
+ ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10
+[56] 2016-10-20 15:24:22.502667 [#38 dns.pcap-dist 4095] \
+ [172.17.0.10].49829 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:22.504738 [#39 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].49829 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,267,216.58.218.206 \
+ 4 google.com.,IN,NS,157798,ns2.google.com. \
+ google.com.,IN,NS,157798,ns4.google.com. \
+ google.com.,IN,NS,157798,ns3.google.com. \
+ google.com.,IN,NS,157798,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157798,216.239.34.10 \
+ ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10
+[56] 2016-10-20 15:24:23.520203 [#40 dns.pcap-dist 4095] \
+ [172.17.0.10].44980 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:23.521976 [#41 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].44980 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,266,216.58.218.206 \
+ 4 google.com.,IN,NS,157797,ns2.google.com. \
+ google.com.,IN,NS,157797,ns4.google.com. \
+ google.com.,IN,NS,157797,ns1.google.com. \
+ google.com.,IN,NS,157797,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157797,216.239.34.10 \
+ ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10
+[56] 2016-10-20 15:24:24.537264 [#42 dns.pcap-dist 4095] \
+ [172.17.0.10].42042 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:24.539398 [#43 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].42042 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,265,216.58.218.206 \
+ 4 google.com.,IN,NS,157796,ns3.google.com. \
+ google.com.,IN,NS,157796,ns4.google.com. \
+ google.com.,IN,NS,157796,ns1.google.com. \
+ google.com.,IN,NS,157796,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157796,216.239.34.10 \
+ ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10
+[56] 2016-10-20 15:24:25.554744 [#44 dns.pcap-dist 4095] \
+ [172.17.0.10].45703 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:25.556513 [#45 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45703 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,264,216.58.218.206 \
+ 4 google.com.,IN,NS,157795,ns3.google.com. \
+ google.com.,IN,NS,157795,ns4.google.com. \
+ google.com.,IN,NS,157795,ns2.google.com. \
+ google.com.,IN,NS,157795,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157795,216.239.34.10 \
+ ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10
+[56] 2016-10-20 15:24:26.572784 [#46 dns.pcap-dist 4095] \
+ [172.17.0.10].46798 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:26.574350 [#47 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].46798 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,263,216.58.218.206 \
+ 4 google.com.,IN,NS,157794,ns1.google.com. \
+ google.com.,IN,NS,157794,ns4.google.com. \
+ google.com.,IN,NS,157794,ns3.google.com. \
+ google.com.,IN,NS,157794,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157794,216.239.34.10 \
+ ns1.google.com.,IN,A,331796,216.239.32.10 \
+ ns3.google.com.,IN,A,157794,216.239.36.10 \
+ ns4.google.com.,IN,A,157794,216.239.38.10
diff --git a/src/test/test14.sh b/src/test/test14.sh
new file mode 100755
index 0000000..1788f10
--- /dev/null
+++ b/src/test/test14.sh
@@ -0,0 +1,25 @@
+#!/bin/sh -xe
+
+echo "-- only 1" >test14.out
+../dnscap -g -q 1 -r dns.pcap-dist 2>>test14.out
+echo "-- not 1" >>test14.out
+../dnscap -g -Q 1 -r dns.pcap-dist 2>>test14.out
+echo "-- only PTR" >>test14.out
+../dnscap -g -q PTR -r dns.pcap-dist 2>>test14.out
+echo "-- not PTR" >>test14.out
+../dnscap -g -Q PTR -r dns.pcap-dist 2>>test14.out
+
+echo "-- only 1" >>test14.out
+../dnscap -g -o use_layers=yes -q 1 -r dns.pcap-dist 2>>test14.out
+echo "-- not 1" >>test14.out
+../dnscap -g -o use_layers=yes -Q 1 -r dns.pcap-dist 2>>test14.out
+echo "-- only PTR" >>test14.out
+../dnscap -g -o use_layers=yes -q PTR -r dns.pcap-dist 2>>test14.out
+echo "-- not PTR" >>test14.out
+../dnscap -g -o use_layers=yes -Q PTR -r dns.pcap-dist 2>>test14.out
+
+mv test14.out test14.out.old
+grep -v "^libgcov profiling error:" test14.out.old > test14.out
+rm test14.out.old
+
+diff test14.out "$srcdir/test14.gold"
diff --git a/src/test/test2.sh b/src/test/test2.sh
new file mode 100755
index 0000000..83cc8c0
--- /dev/null
+++ b/src/test/test2.sh
@@ -0,0 +1,6 @@
+#!/bin/sh -xe
+
+../dnscap -g -r dns.pcap-dist 2>no-layers.out
+../dnscap -g -r dns.pcap-dist -o use_layers=yes 2>layers.out
+
+diff no-layers.out layers.out
diff --git a/src/test/test3.sh b/src/test/test3.sh
new file mode 100755
index 0000000..4b65121
--- /dev/null
+++ b/src/test/test3.sh
@@ -0,0 +1,13 @@
+#!/bin/sh -xe
+
+../dnscap -g -f -r frags.pcap-dist -o use_layers=yes -o defrag_ipv4=yes -o max_ipv4_fragments_per_packet=64 2>frags.out
+
+# remove timestamp
+sed -i -e 's%^\(\[[0-9]*\]\)[^\[]*\[%\1 [%g' frags.out
+
+# create gold file
+cp "$srcdir/dns.gold" frags.gold
+sed -i -e 's%^\(\[[0-9]*\]\)[^\[]*\[%\1 [%g' frags.gold
+sed -i -e 's%dns.pcap-dist%frags.pcap-dist%g' frags.gold
+
+diff frags.out frags.gold
diff --git a/src/test/test4.sh b/src/test/test4.sh
new file mode 100755
index 0000000..7cdf34e
--- /dev/null
+++ b/src/test/test4.sh
@@ -0,0 +1,6 @@
+#!/bin/sh -xe
+
+../dnscap -g -T -r 1qtcppadd.pcap-dist 2>padding-no-layers.out
+../dnscap -g -T -r 1qtcppadd.pcap-dist -o use_layers=yes 2>padding-layers.out
+
+diff padding-no-layers.out padding-layers.out
diff --git a/src/test/test5.sh b/src/test/test5.sh
new file mode 100755
index 0000000..a4789d7
--- /dev/null
+++ b/src/test/test5.sh
@@ -0,0 +1,20 @@
+#!/bin/sh -xe
+
+osrel=`uname -s`
+
+../dnscap -g -r vlan11.pcap-dist 2>vlan11.out
+test -f vlan11.out && ! test -s vlan11.out
+../dnscap -g -r vlan11.pcap-dist -L 10 2>vlan11.out
+test -f vlan11.out && ! test -s vlan11.out
+../dnscap -g -r vlan11.pcap-dist -L 4095 2>vlan11.out
+diff vlan11.out "$srcdir/vlan11.gold"
+../dnscap -g -r vlan11.pcap-dist -L 11 2>vlan11.out
+diff vlan11.out "$srcdir/vlan11.gold"
+../dnscap -g -r vlan11.pcap-dist -o use_layers=yes 2>vlan11.out
+test -f vlan11.out && ! test -s vlan11.out
+../dnscap -g -r vlan11.pcap-dist -o use_layers=yes -L 10 2>vlan11.out
+test -f vlan11.out && ! test -s vlan11.out
+../dnscap -g -r vlan11.pcap-dist -o use_layers=yes -L 4095 2>vlan11.out
+diff vlan11.out "$srcdir/vlan11.gold"
+../dnscap -g -r vlan11.pcap-dist -o use_layers=yes -L 11 2>vlan11.out
+diff vlan11.out "$srcdir/vlan11.gold"
diff --git a/src/test/test6.sh b/src/test/test6.sh
new file mode 100755
index 0000000..f05713b
--- /dev/null
+++ b/src/test/test6.sh
@@ -0,0 +1,6 @@
+#!/bin/sh -xe
+
+../dnscap -g -r dnspad.pcap-dist 2>dnspad.out
+../dnscap -o use_layers=yes -g -r dnspad.pcap-dist 2>>dnspad.out
+
+diff dnspad.out "$srcdir/dnspad.gold"
diff --git a/src/test/test7.gold b/src/test/test7.gold
new file mode 100644
index 0000000..c3bb683
--- /dev/null
+++ b/src/test/test7.gold
@@ -0,0 +1,1417 @@
+[60] 2018-01-10 11:22:41.543825 [#0 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[60] 2018-01-10 11:22:41.548834 [#1 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+[54] 2018-01-10 11:22:41.548947 [#2 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.552406 [#3 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.555912 [#4 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.556032 [#5 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.600183 [#6 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:41.616460 [#7 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:41.616663 [#8 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.659921 [#9 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.663576 [#10 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.663734 [#11 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.706183 [#12 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.709680 [#13 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.709779 [#14 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.754101 [#15 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18718,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:41.757876 [#16 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,18718,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:41.758191 [#17 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.804255 [#18 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.809483 [#19 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.809780 [#20 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.854113 [#21 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.857788 [#22 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.858002 [#23 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.902165 [#24 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:41.905802 [#25 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:41.905918 [#26 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.950164 [#27 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,49483,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.954138 [#28 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,49483,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.954452 [#29 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.999121 [#30 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,31669,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.002657 [#31 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,31669,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.002831 [#32 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.047148 [#33 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.052425 [#34 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25433,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.052901 [#35 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.097899 [#36 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.101443 [#37 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,63798,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.101553 [#38 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.145005 [#39 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.148639 [#40 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,8470,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.148770 [#41 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.192777 [#42 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.196256 [#43 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,60258,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.196471 [#44 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.240395 [#45 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.245103 [#46 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.245585 [#47 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.290257 [#48 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.293978 [#49 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.294300 [#50 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.337985 [#51 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.341559 [#52 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.341648 [#53 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.385009 [#54 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.389082 [#55 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.389343 [#56 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.433458 [#57 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.438748 [#58 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.439060 [#59 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.484005 [#60 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.487697 [#61 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.488035 [#62 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.532414 [#63 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.537574 [#64 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.537941 [#65 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.583021 [#66 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.586898 [#67 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.587050 [#68 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.630221 [#69 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.633808 [#70 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.634006 [#71 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.679168 [#72 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.682888 [#73 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.683273 [#74 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.727254 [#75 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.732703 [#76 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.733029 [#77 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.777184 [#78 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.781053 [#79 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.781416 [#80 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.824222 [#81 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.828050 [#82 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.828346 [#83 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.872186 [#84 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.875911 [#85 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.876226 [#86 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.920231 [#87 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.923917 [#88 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.924082 [#89 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.968961 [#90 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.972662 [#91 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.972972 [#92 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.017364 [#93 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.022591 [#94 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.022938 [#95 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.066765 [#96 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.070349 [#97 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.070484 [#98 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.114332 [#99 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.119538 [#100 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.119857 [#101 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.163857 [#102 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.167576 [#103 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.167733 [#104 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.211417 [#105 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.216686 [#106 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.217042 [#107 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.260995 [#108 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.265047 [#109 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.265399 [#110 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.310017 [#111 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.313596 [#112 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.313685 [#113 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.356802 [#114 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.360685 [#115 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.360864 [#116 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.406308 [#117 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.410191 [#118 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.410440 [#119 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.454193 [#120 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.458191 [#121 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.458511 [#122 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.503242 [#123 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.506884 [#124 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[52] 2018-01-10 11:22:43.507821 [#125 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[52] 2018-01-10 11:22:43.511351 [#126 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+1515583361.543825 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.548834 8.8.8.8 53 172.17.0.8 51388 6
+1515583361.548947 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.552406 172.17.0.8 51388 8.8.8.8 53 6 59311 0 0 |RD| IN A google.com.
+1515583361.555912 8.8.8.8 53 172.17.0.8 51388 6 59311 0 0 |QR|RD|RA| IN A google.com.
+1515583361.556032 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.600183 172.17.0.8 51388 8.8.8.8 53 6 35665 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.616460 8.8.8.8 53 172.17.0.8 51388 6 35665 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.616663 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.659921 172.17.0.8 51388 8.8.8.8 53 6 5337 0 0 |RD| IN A google.com.
+1515583361.663576 8.8.8.8 53 172.17.0.8 51388 6 5337 0 0 |QR|RD|RA| IN A google.com.
+1515583361.663734 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.706183 172.17.0.8 51388 8.8.8.8 53 6 22982 0 0 |RD| IN A google.com.
+1515583361.709680 8.8.8.8 53 172.17.0.8 51388 6 22982 0 0 |QR|RD|RA| IN A google.com.
+1515583361.709779 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.754101 172.17.0.8 51388 8.8.8.8 53 6 18718 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.757876 8.8.8.8 53 172.17.0.8 51388 6 18718 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.758191 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.804255 172.17.0.8 51388 8.8.8.8 53 6 22531 0 0 |RD| IN A google.com.
+1515583361.809483 8.8.8.8 53 172.17.0.8 51388 6 22531 0 0 |QR|RD|RA| IN A google.com.
+1515583361.809780 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.854113 172.17.0.8 51388 8.8.8.8 53 6 58510 0 0 |RD| IN A google.com.
+1515583361.857788 8.8.8.8 53 172.17.0.8 51388 6 58510 0 0 |QR|RD|RA| IN A google.com.
+1515583361.858002 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.902165 172.17.0.8 51388 8.8.8.8 53 6 45248 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.905802 8.8.8.8 53 172.17.0.8 51388 6 45248 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.905918 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.950164 172.17.0.8 51388 8.8.8.8 53 6 49483 0 0 |RD| IN A google.com.
+1515583361.954138 8.8.8.8 53 172.17.0.8 51388 6 49483 0 0 |QR|RD|RA| IN A google.com.
+1515583361.954452 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.999121 172.17.0.8 51388 8.8.8.8 53 6 31669 0 0 |RD| IN A google.com.
+1515583362.002657 8.8.8.8 53 172.17.0.8 51388 6 31669 0 0 |QR|RD|RA| IN A google.com.
+1515583362.002831 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.047148 172.17.0.8 51388 8.8.8.8 53 6 25433 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.052425 8.8.8.8 53 172.17.0.8 51388 6 25433 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.052901 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.097899 172.17.0.8 51388 8.8.8.8 53 6 63798 0 0 |RD| IN A google.com.
+1515583362.101443 8.8.8.8 53 172.17.0.8 51388 6 63798 0 0 |QR|RD|RA| IN A google.com.
+1515583362.101553 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.145005 172.17.0.8 51388 8.8.8.8 53 6 8470 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.148639 8.8.8.8 53 172.17.0.8 51388 6 8470 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.148770 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.192777 172.17.0.8 51388 8.8.8.8 53 6 60258 0 0 |RD| IN A google.com.
+1515583362.196256 8.8.8.8 53 172.17.0.8 51388 6 60258 0 0 |QR|RD|RA| IN A google.com.
+1515583362.196471 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.240395 172.17.0.8 51388 8.8.8.8 53 6 44985 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.245103 8.8.8.8 53 172.17.0.8 51388 6 44985 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.245585 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.290257 172.17.0.8 51388 8.8.8.8 53 6 45512 0 0 |RD| IN A google.com.
+1515583362.293978 8.8.8.8 53 172.17.0.8 51388 6 45512 0 0 |QR|RD|RA| IN A google.com.
+1515583362.294300 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.337985 172.17.0.8 51388 8.8.8.8 53 6 22980 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.341559 8.8.8.8 53 172.17.0.8 51388 6 22980 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.341648 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.385009 172.17.0.8 51388 8.8.8.8 53 6 1834 0 0 |RD| IN A google.com.
+1515583362.389082 8.8.8.8 53 172.17.0.8 51388 6 1834 0 0 |QR|RD|RA| IN A google.com.
+1515583362.389343 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.433458 172.17.0.8 51388 8.8.8.8 53 6 25431 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.438748 8.8.8.8 53 172.17.0.8 51388 6 25431 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.439060 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.484005 172.17.0.8 51388 8.8.8.8 53 6 48432 0 0 |RD| IN A google.com.
+1515583362.487697 8.8.8.8 53 172.17.0.8 51388 6 48432 0 0 |QR|RD|RA| IN A google.com.
+1515583362.488035 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.532414 172.17.0.8 51388 8.8.8.8 53 6 47411 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.537574 8.8.8.8 53 172.17.0.8 51388 6 47411 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.537941 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.583021 172.17.0.8 51388 8.8.8.8 53 6 12038 0 0 |RD| IN A google.com.
+1515583362.586898 8.8.8.8 53 172.17.0.8 51388 6 12038 0 0 |QR|RD|RA| IN A google.com.
+1515583362.587050 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.630221 172.17.0.8 51388 8.8.8.8 53 6 11614 0 0 |RD| IN A google.com.
+1515583362.633808 8.8.8.8 53 172.17.0.8 51388 6 11614 0 0 |QR|RD|RA| IN A google.com.
+1515583362.634006 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.679168 172.17.0.8 51388 8.8.8.8 53 6 59173 0 0 |RD| IN A google.com.
+1515583362.682888 8.8.8.8 53 172.17.0.8 51388 6 59173 0 0 |QR|RD|RA| IN A google.com.
+1515583362.683273 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.727254 172.17.0.8 51388 8.8.8.8 53 6 45535 0 0 |RD| IN A google.com.
+1515583362.732703 8.8.8.8 53 172.17.0.8 51388 6 45535 0 0 |QR|RD|RA| IN A google.com.
+1515583362.733029 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.777184 172.17.0.8 51388 8.8.8.8 53 6 60808 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.781053 8.8.8.8 53 172.17.0.8 51388 6 60808 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.781416 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.824222 172.17.0.8 51388 8.8.8.8 53 6 64325 0 0 |RD| IN A google.com.
+1515583362.828050 8.8.8.8 53 172.17.0.8 51388 6 64325 0 0 |QR|RD|RA| IN A google.com.
+1515583362.828346 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.872186 172.17.0.8 51388 8.8.8.8 53 6 25543 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.875911 8.8.8.8 53 172.17.0.8 51388 6 25543 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.876226 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.920231 172.17.0.8 51388 8.8.8.8 53 6 20736 0 0 |RD| IN A google.com.
+1515583362.923917 8.8.8.8 53 172.17.0.8 51388 6 20736 0 0 |QR|RD|RA| IN A google.com.
+1515583362.924082 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.968961 172.17.0.8 51388 8.8.8.8 53 6 25911 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.972662 8.8.8.8 53 172.17.0.8 51388 6 25911 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.972972 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.017364 172.17.0.8 51388 8.8.8.8 53 6 64358 0 0 |RD| IN A google.com.
+1515583363.022591 8.8.8.8 53 172.17.0.8 51388 6 64358 0 0 |QR|RD|RA| IN A google.com.
+1515583363.022938 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.066765 172.17.0.8 51388 8.8.8.8 53 6 37698 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.070349 8.8.8.8 53 172.17.0.8 51388 6 37698 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.070484 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.114332 172.17.0.8 51388 8.8.8.8 53 6 54706 0 0 |RD| IN A google.com.
+1515583363.119538 8.8.8.8 53 172.17.0.8 51388 6 54706 0 0 |QR|RD|RA| IN A google.com.
+1515583363.119857 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.163857 172.17.0.8 51388 8.8.8.8 53 6 32142 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.167576 8.8.8.8 53 172.17.0.8 51388 6 32142 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.167733 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.211417 172.17.0.8 51388 8.8.8.8 53 6 41808 0 0 |RD| IN A google.com.
+1515583363.216686 8.8.8.8 53 172.17.0.8 51388 6 41808 0 0 |QR|RD|RA| IN A google.com.
+1515583363.217042 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.260995 172.17.0.8 51388 8.8.8.8 53 6 18886 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.265047 8.8.8.8 53 172.17.0.8 51388 6 18886 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.265399 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.310017 172.17.0.8 51388 8.8.8.8 53 6 10624 0 0 |RD| IN A google.com.
+1515583363.313596 8.8.8.8 53 172.17.0.8 51388 6 10624 0 0 |QR|RD|RA| IN A google.com.
+1515583363.313685 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.356802 172.17.0.8 51388 8.8.8.8 53 6 33139 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.360685 8.8.8.8 53 172.17.0.8 51388 6 33139 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.360864 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.406308 172.17.0.8 51388 8.8.8.8 53 6 61415 0 0 |RD| IN A google.com.
+1515583363.410191 8.8.8.8 53 172.17.0.8 51388 6 61415 0 0 |QR|RD|RA| IN A google.com.
+1515583363.410440 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.454193 172.17.0.8 51388 8.8.8.8 53 6 59258 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.458191 8.8.8.8 53 172.17.0.8 51388 6 59258 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.458511 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.503242 172.17.0.8 51388 8.8.8.8 53 6 17700 0 0 |RD| IN A google.com.
+1515583363.506884 8.8.8.8 53 172.17.0.8 51388 6 17700 0 0 |QR|RD|RA| IN A google.com.
+1515583363.507821 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.511351 8.8.8.8 53 172.17.0.8 51388 6
+[52] 2017-12-11 13:59:04.957247 [#0 1qtcpnosyn.pcap-dist 4095] \
+ [172.17.0.9].48613 [8.8.8.8].53
+[52] 2017-12-11 13:59:04.960230 [#1 1qtcpnosyn.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.9].48613
+1513000744.957247 172.17.0.9 48613 8.8.8.8 53 6
+1513000744.960230 8.8.8.8 53 172.17.0.9 48613 6
+[60] 2018-01-10 11:22:41.543825 [#0 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[60] 2018-01-10 11:22:41.548834 [#1 dnso1tcp-midmiss.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+[54] 2018-01-10 11:22:41.548947 [#2 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.552406 [#3 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.555912 [#4 dnso1tcp-midmiss.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.556032 [#5 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.600183 [#6 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[98] 2018-01-10 11:22:41.663576 [#7 dnso1tcp-midmiss.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+[54] 2018-01-10 11:22:41.663734 [#8 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.706183 [#9 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[98] 2018-01-10 11:22:41.709680 [#10 dnso1tcp-midmiss.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+1515583361.543825 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.548834 8.8.8.8 53 172.17.0.8 51388 6
+1515583361.548947 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.552406 172.17.0.8 51388 8.8.8.8 53 6 59311 0 0 |RD| IN A google.com.
+1515583361.555912 8.8.8.8 53 172.17.0.8 51388 6 59311 0 0 |QR|RD|RA| IN A google.com.
+1515583361.556032 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.600183 172.17.0.8 51388 8.8.8.8 53 6 35665 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.663576 8.8.8.8 53 172.17.0.8 51388 6
+1515583361.663734 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.706183 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.709680 8.8.8.8 53 172.17.0.8 51388 6
+
+Enabling parse_ongoing_tcp and allow_reset_tcpstate
+
+[60] 2018-01-10 11:22:41.543825 [#0 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[60] 2018-01-10 11:22:41.548834 [#1 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+[54] 2018-01-10 11:22:41.548947 [#2 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.552406 [#3 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.555912 [#4 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.556032 [#5 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.600183 [#6 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:41.616460 [#7 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:41.616663 [#8 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.659921 [#9 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.663576 [#10 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.663734 [#11 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.706183 [#12 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.709680 [#13 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.709779 [#14 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.754101 [#15 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18718,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:41.757876 [#16 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,18718,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:41.758191 [#17 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.804255 [#18 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.809483 [#19 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.809780 [#20 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.854113 [#21 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.857788 [#22 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.858002 [#23 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.902165 [#24 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:41.905802 [#25 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:41.905918 [#26 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.950164 [#27 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,49483,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.954138 [#28 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,49483,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.954452 [#29 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.999121 [#30 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,31669,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.002657 [#31 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,31669,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.002831 [#32 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.047148 [#33 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.052425 [#34 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25433,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.052901 [#35 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.097899 [#36 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.101443 [#37 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,63798,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.101553 [#38 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.145005 [#39 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.148639 [#40 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,8470,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.148770 [#41 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.192777 [#42 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.196256 [#43 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,60258,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.196471 [#44 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.240395 [#45 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.245103 [#46 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.245585 [#47 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.290257 [#48 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.293978 [#49 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.294300 [#50 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.337985 [#51 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.341559 [#52 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.341648 [#53 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.385009 [#54 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.389082 [#55 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.389343 [#56 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.433458 [#57 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.438748 [#58 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.439060 [#59 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.484005 [#60 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.487697 [#61 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.488035 [#62 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.532414 [#63 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.537574 [#64 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.537941 [#65 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.583021 [#66 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.586898 [#67 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.587050 [#68 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.630221 [#69 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.633808 [#70 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.634006 [#71 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.679168 [#72 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.682888 [#73 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.683273 [#74 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.727254 [#75 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.732703 [#76 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.733029 [#77 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.777184 [#78 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.781053 [#79 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.781416 [#80 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.824222 [#81 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.828050 [#82 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.828346 [#83 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.872186 [#84 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.875911 [#85 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.876226 [#86 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.920231 [#87 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.923917 [#88 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[54] 2018-01-10 11:22:42.924082 [#89 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.968961 [#90 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.972662 [#91 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:42.972972 [#92 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.017364 [#93 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.022591 [#94 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.022938 [#95 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.066765 [#96 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.070349 [#97 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.070484 [#98 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.114332 [#99 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.119538 [#100 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.119857 [#101 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.163857 [#102 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.167576 [#103 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.167733 [#104 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.211417 [#105 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.216686 [#106 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.217042 [#107 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.260995 [#108 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.265047 [#109 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.265399 [#110 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.310017 [#111 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.313596 [#112 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.313685 [#113 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.356802 [#114 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.360685 [#115 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.360864 [#116 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.406308 [#117 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.410191 [#118 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[54] 2018-01-10 11:22:43.410440 [#119 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.454193 [#120 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.458191 [#121 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[54] 2018-01-10 11:22:43.458511 [#122 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.503242 [#123 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.506884 [#124 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[52] 2018-01-10 11:22:43.507821 [#125 dnso1tcp.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[52] 2018-01-10 11:22:43.511351 [#126 dnso1tcp.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+1515583361.543825 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.548834 8.8.8.8 53 172.17.0.8 51388 6
+1515583361.548947 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.552406 172.17.0.8 51388 8.8.8.8 53 6 59311 0 0 |RD| IN A google.com.
+1515583361.555912 8.8.8.8 53 172.17.0.8 51388 6 59311 0 0 |QR|RD|RA| IN A google.com.
+1515583361.556032 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.600183 172.17.0.8 51388 8.8.8.8 53 6 35665 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.616460 8.8.8.8 53 172.17.0.8 51388 6 35665 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.616663 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.659921 172.17.0.8 51388 8.8.8.8 53 6 5337 0 0 |RD| IN A google.com.
+1515583361.663576 8.8.8.8 53 172.17.0.8 51388 6 5337 0 0 |QR|RD|RA| IN A google.com.
+1515583361.663734 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.706183 172.17.0.8 51388 8.8.8.8 53 6 22982 0 0 |RD| IN A google.com.
+1515583361.709680 8.8.8.8 53 172.17.0.8 51388 6 22982 0 0 |QR|RD|RA| IN A google.com.
+1515583361.709779 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.754101 172.17.0.8 51388 8.8.8.8 53 6 18718 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.757876 8.8.8.8 53 172.17.0.8 51388 6 18718 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.758191 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.804255 172.17.0.8 51388 8.8.8.8 53 6 22531 0 0 |RD| IN A google.com.
+1515583361.809483 8.8.8.8 53 172.17.0.8 51388 6 22531 0 0 |QR|RD|RA| IN A google.com.
+1515583361.809780 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.854113 172.17.0.8 51388 8.8.8.8 53 6 58510 0 0 |RD| IN A google.com.
+1515583361.857788 8.8.8.8 53 172.17.0.8 51388 6 58510 0 0 |QR|RD|RA| IN A google.com.
+1515583361.858002 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.902165 172.17.0.8 51388 8.8.8.8 53 6 45248 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.905802 8.8.8.8 53 172.17.0.8 51388 6 45248 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.905918 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.950164 172.17.0.8 51388 8.8.8.8 53 6 49483 0 0 |RD| IN A google.com.
+1515583361.954138 8.8.8.8 53 172.17.0.8 51388 6 49483 0 0 |QR|RD|RA| IN A google.com.
+1515583361.954452 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.999121 172.17.0.8 51388 8.8.8.8 53 6 31669 0 0 |RD| IN A google.com.
+1515583362.002657 8.8.8.8 53 172.17.0.8 51388 6 31669 0 0 |QR|RD|RA| IN A google.com.
+1515583362.002831 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.047148 172.17.0.8 51388 8.8.8.8 53 6 25433 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.052425 8.8.8.8 53 172.17.0.8 51388 6 25433 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.052901 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.097899 172.17.0.8 51388 8.8.8.8 53 6 63798 0 0 |RD| IN A google.com.
+1515583362.101443 8.8.8.8 53 172.17.0.8 51388 6 63798 0 0 |QR|RD|RA| IN A google.com.
+1515583362.101553 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.145005 172.17.0.8 51388 8.8.8.8 53 6 8470 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.148639 8.8.8.8 53 172.17.0.8 51388 6 8470 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.148770 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.192777 172.17.0.8 51388 8.8.8.8 53 6 60258 0 0 |RD| IN A google.com.
+1515583362.196256 8.8.8.8 53 172.17.0.8 51388 6 60258 0 0 |QR|RD|RA| IN A google.com.
+1515583362.196471 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.240395 172.17.0.8 51388 8.8.8.8 53 6 44985 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.245103 8.8.8.8 53 172.17.0.8 51388 6 44985 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.245585 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.290257 172.17.0.8 51388 8.8.8.8 53 6 45512 0 0 |RD| IN A google.com.
+1515583362.293978 8.8.8.8 53 172.17.0.8 51388 6 45512 0 0 |QR|RD|RA| IN A google.com.
+1515583362.294300 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.337985 172.17.0.8 51388 8.8.8.8 53 6 22980 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.341559 8.8.8.8 53 172.17.0.8 51388 6 22980 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.341648 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.385009 172.17.0.8 51388 8.8.8.8 53 6 1834 0 0 |RD| IN A google.com.
+1515583362.389082 8.8.8.8 53 172.17.0.8 51388 6 1834 0 0 |QR|RD|RA| IN A google.com.
+1515583362.389343 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.433458 172.17.0.8 51388 8.8.8.8 53 6 25431 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.438748 8.8.8.8 53 172.17.0.8 51388 6 25431 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.439060 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.484005 172.17.0.8 51388 8.8.8.8 53 6 48432 0 0 |RD| IN A google.com.
+1515583362.487697 8.8.8.8 53 172.17.0.8 51388 6 48432 0 0 |QR|RD|RA| IN A google.com.
+1515583362.488035 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.532414 172.17.0.8 51388 8.8.8.8 53 6 47411 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.537574 8.8.8.8 53 172.17.0.8 51388 6 47411 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.537941 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.583021 172.17.0.8 51388 8.8.8.8 53 6 12038 0 0 |RD| IN A google.com.
+1515583362.586898 8.8.8.8 53 172.17.0.8 51388 6 12038 0 0 |QR|RD|RA| IN A google.com.
+1515583362.587050 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.630221 172.17.0.8 51388 8.8.8.8 53 6 11614 0 0 |RD| IN A google.com.
+1515583362.633808 8.8.8.8 53 172.17.0.8 51388 6 11614 0 0 |QR|RD|RA| IN A google.com.
+1515583362.634006 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.679168 172.17.0.8 51388 8.8.8.8 53 6 59173 0 0 |RD| IN A google.com.
+1515583362.682888 8.8.8.8 53 172.17.0.8 51388 6 59173 0 0 |QR|RD|RA| IN A google.com.
+1515583362.683273 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.727254 172.17.0.8 51388 8.8.8.8 53 6 45535 0 0 |RD| IN A google.com.
+1515583362.732703 8.8.8.8 53 172.17.0.8 51388 6 45535 0 0 |QR|RD|RA| IN A google.com.
+1515583362.733029 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.777184 172.17.0.8 51388 8.8.8.8 53 6 60808 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.781053 8.8.8.8 53 172.17.0.8 51388 6 60808 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.781416 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.824222 172.17.0.8 51388 8.8.8.8 53 6 64325 0 0 |RD| IN A google.com.
+1515583362.828050 8.8.8.8 53 172.17.0.8 51388 6 64325 0 0 |QR|RD|RA| IN A google.com.
+1515583362.828346 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.872186 172.17.0.8 51388 8.8.8.8 53 6 25543 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.875911 8.8.8.8 53 172.17.0.8 51388 6 25543 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.876226 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.920231 172.17.0.8 51388 8.8.8.8 53 6 20736 0 0 |RD| IN A google.com.
+1515583362.923917 8.8.8.8 53 172.17.0.8 51388 6 20736 0 0 |QR|RD|RA| IN A google.com.
+1515583362.924082 172.17.0.8 51388 8.8.8.8 53 6
+1515583362.968961 172.17.0.8 51388 8.8.8.8 53 6 25911 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.972662 8.8.8.8 53 172.17.0.8 51388 6 25911 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583362.972972 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.017364 172.17.0.8 51388 8.8.8.8 53 6 64358 0 0 |RD| IN A google.com.
+1515583363.022591 8.8.8.8 53 172.17.0.8 51388 6 64358 0 0 |QR|RD|RA| IN A google.com.
+1515583363.022938 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.066765 172.17.0.8 51388 8.8.8.8 53 6 37698 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.070349 8.8.8.8 53 172.17.0.8 51388 6 37698 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.070484 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.114332 172.17.0.8 51388 8.8.8.8 53 6 54706 0 0 |RD| IN A google.com.
+1515583363.119538 8.8.8.8 53 172.17.0.8 51388 6 54706 0 0 |QR|RD|RA| IN A google.com.
+1515583363.119857 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.163857 172.17.0.8 51388 8.8.8.8 53 6 32142 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.167576 8.8.8.8 53 172.17.0.8 51388 6 32142 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.167733 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.211417 172.17.0.8 51388 8.8.8.8 53 6 41808 0 0 |RD| IN A google.com.
+1515583363.216686 8.8.8.8 53 172.17.0.8 51388 6 41808 0 0 |QR|RD|RA| IN A google.com.
+1515583363.217042 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.260995 172.17.0.8 51388 8.8.8.8 53 6 18886 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.265047 8.8.8.8 53 172.17.0.8 51388 6 18886 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.265399 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.310017 172.17.0.8 51388 8.8.8.8 53 6 10624 0 0 |RD| IN A google.com.
+1515583363.313596 8.8.8.8 53 172.17.0.8 51388 6 10624 0 0 |QR|RD|RA| IN A google.com.
+1515583363.313685 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.356802 172.17.0.8 51388 8.8.8.8 53 6 33139 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.360685 8.8.8.8 53 172.17.0.8 51388 6 33139 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.360864 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.406308 172.17.0.8 51388 8.8.8.8 53 6 61415 0 0 |RD| IN A google.com.
+1515583363.410191 8.8.8.8 53 172.17.0.8 51388 6 61415 0 0 |QR|RD|RA| IN A google.com.
+1515583363.410440 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.454193 172.17.0.8 51388 8.8.8.8 53 6 59258 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.458191 8.8.8.8 53 172.17.0.8 51388 6 59258 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+1515583363.458511 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.503242 172.17.0.8 51388 8.8.8.8 53 6 17700 0 0 |RD| IN A google.com.
+1515583363.506884 8.8.8.8 53 172.17.0.8 51388 6 17700 0 0 |QR|RD|RA| IN A google.com.
+1515583363.507821 172.17.0.8 51388 8.8.8.8 53 6
+1515583363.511351 8.8.8.8 53 172.17.0.8 51388 6
+[93] 2017-12-11 13:59:04.953122 [#0 1qtcpnosyn.pcap-dist 4095] \
+ [172.17.0.9].48613 [8.8.8.8].53 \
+ dns QUERY,NOERROR,4815,rd|ad \
+ 1 google.com.,IN,A 0 0 \
+ 1 .,4096,4096,0,edns0[len=0,UDP=4096,ver=0,rcode=0,DO=0,z=0]
+[109] 2017-12-11 13:59:04.956698 [#1 1qtcpnosyn.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.9].48613 \
+ dns QUERY,NOERROR,4815,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,47,172.217.22.174 0 \
+ 1 .,512,512,0,edns0[len=0,UDP=512,ver=0,rcode=0,DO=0,z=0]
+[52] 2017-12-11 13:59:04.957247 [#2 1qtcpnosyn.pcap-dist 4095] \
+ [172.17.0.9].48613 [8.8.8.8].53
+[52] 2017-12-11 13:59:04.960230 [#3 1qtcpnosyn.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.9].48613
+1513000744.953122 172.17.0.9 48613 8.8.8.8 53 6 4815 0 0 |RD|AD| IN A google.com.
+1513000744.956698 8.8.8.8 53 172.17.0.9 48613 6 4815 0 0 |QR|RD|RA| IN A google.com.
+1513000744.957247 172.17.0.9 48613 8.8.8.8 53 6
+1513000744.960230 8.8.8.8 53 172.17.0.9 48613 6
+[80] 2018-01-10 11:22:41.552406 [#0 do1t-nosyn-1nolen.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns Label length overflow
+[98] 2018-01-10 11:22:41.555912 [#1 do1t-nosyn-1nolen.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.556032 [#2 do1t-nosyn-1nolen.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.600183 [#3 do1t-nosyn-1nolen.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:41.616460 [#4 do1t-nosyn-1nolen.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. 0 0
+1515583361.552406 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.555912 8.8.8.8 53 172.17.0.8 51388 6 59311 0 0 |QR|RD|RA| IN A google.com.
+1515583361.556032 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.600183 172.17.0.8 51388 8.8.8.8 53 6 35665 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.616460 8.8.8.8 53 172.17.0.8 51388 6 35665 0 0 |QR|RD|RA| IN PTR 206.218.58.216.in-addr.arpa.
+[60] 2018-01-10 11:22:41.543825 [#0 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[60] 2018-01-10 11:22:41.548834 [#1 dnso1tcp-midmiss.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+[54] 2018-01-10 11:22:41.548947 [#2 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.552406 [#3 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.555912 [#4 dnso1tcp-midmiss.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.556032 [#5 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.600183 [#6 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[98] 2018-01-10 11:22:41.663576 [#7 dnso1tcp-midmiss.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[54] 2018-01-10 11:22:41.663734 [#8 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.706183 [#9 dnso1tcp-midmiss.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.709680 [#10 dnso1tcp-midmiss.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+1515583361.543825 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.548834 8.8.8.8 53 172.17.0.8 51388 6
+1515583361.548947 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.552406 172.17.0.8 51388 8.8.8.8 53 6 59311 0 0 |RD| IN A google.com.
+1515583361.555912 8.8.8.8 53 172.17.0.8 51388 6 59311 0 0 |QR|RD|RA| IN A google.com.
+1515583361.556032 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.600183 172.17.0.8 51388 8.8.8.8 53 6 35665 0 0 |RD| IN PTR 206.218.58.216.in-addr.arpa.
+1515583361.663576 8.8.8.8 53 172.17.0.8 51388 6 5337 0 0 |QR|RD|RA| IN A google.com.
+1515583361.663734 172.17.0.8 51388 8.8.8.8 53 6
+1515583361.706183 172.17.0.8 51388 8.8.8.8 53 6 22982 0 0 |RD| IN A google.com.
+1515583361.709680 8.8.8.8 53 172.17.0.8 51388 6 22982 0 0 |QR|RD|RA| IN A google.com.
diff --git a/src/test/test7.sh b/src/test/test7.sh
new file mode 100755
index 0000000..6c9a4ec
--- /dev/null
+++ b/src/test/test7.sh
@@ -0,0 +1,33 @@
+#!/bin/sh -xe
+
+txtout="../../plugins/txtout/.libs/txtout.so"
+
+rm -f test7.out test7.layer.out
+
+for what in dnso1tcp.pcap-dist 1qtcpnosyn.pcap-dist do1t-nosyn-1nolen.pcap-dist dnso1tcp-midmiss.pcap-dist; do
+ ../dnscap -r "$what" -g -T 2>>test7.out
+ ../dnscap -r "$what" -g -T -o use_layers=yes 2>>test7.layer.out
+ if [ -f "$txtout" ]; then
+ ../dnscap -r "$what" -T -P "$txtout" >>test7.out
+ ../dnscap -r "$what" -T -o use_layers=yes -P "$txtout" >>test7.layer.out
+ fi
+done
+
+echo "" >>test7.out
+echo "Enabling parse_ongoing_tcp and allow_reset_tcpstate" >>test7.out
+echo "" >>test7.out
+echo "" >>test7.layer.out
+echo "Enabling parse_ongoing_tcp and allow_reset_tcpstate" >>test7.layer.out
+echo "" >>test7.layer.out
+
+for what in dnso1tcp.pcap-dist 1qtcpnosyn.pcap-dist do1t-nosyn-1nolen.pcap-dist dnso1tcp-midmiss.pcap-dist; do
+ ../dnscap -r "$what" -g -T -o parse_ongoing_tcp=yes -o allow_reset_tcpstate=yes 2>>test7.out
+ ../dnscap -r "$what" -g -T -o parse_ongoing_tcp=yes -o allow_reset_tcpstate=yes -o use_layers=yes 2>>test7.layer.out
+ if [ -f "$txtout" ]; then
+ ../dnscap -r "$what" -T -o parse_ongoing_tcp=yes -o allow_reset_tcpstate=yes -P "$txtout" >>test7.out
+ ../dnscap -r "$what" -T -o parse_ongoing_tcp=yes -o allow_reset_tcpstate=yes -o use_layers=yes -P "$txtout" >>test7.layer.out
+ fi
+done
+
+diff test7.out "$srcdir/test7.gold"
+diff test7.layer.out "$srcdir/test7.gold"
diff --git a/src/test/test8.gold b/src/test/test8.gold
new file mode 100644
index 0000000..a4196e4
--- /dev/null
+++ b/src/test/test8.gold
@@ -0,0 +1,440 @@
+[60] 2017-12-11 13:59:04.949707 [#0 dnsotcp-many1pkt.pcap-dist 4095] \
+ [172.17.0.9].48613 [8.8.8.8].53
+[60] 2017-12-11 13:59:04.953026 [#1 dnsotcp-many1pkt.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.9].48613
+[142] 2017-12-11 13:59:04.953122 [#2 dnsotcp-many1pkt.pcap-dist 4095] \
+ [172.17.0.9].48613 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[142] 2017-12-11 13:59:04.953122 [#2 dnsotcp-many1pkt.pcap-dist 4095] \
+ [172.17.0.9].48613 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[142] 2017-12-11 13:59:04.953122 [#2 dnsotcp-many1pkt.pcap-dist 4095] \
+ [172.17.0.9].48613 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[109] 2017-12-11 13:59:04.956698 [#5 dnsotcp-many1pkt.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.9].48613 \
+ dns QUERY,NOERROR,4815,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,47,172.217.22.174 0 \
+ 1 .,512,512,0,edns0[len=0,UDP=512,ver=0,rcode=0,DO=0,z=0]
+[52] 2017-12-11 13:59:04.957247 [#6 dnsotcp-many1pkt.pcap-dist 4095] \
+ [172.17.0.9].48613 [8.8.8.8].53
+[52] 2017-12-11 13:59:04.960230 [#7 dnsotcp-many1pkt.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.9].48613
+[60] 2018-01-10 11:22:41.543825 [#0 dnsotcp-manyopkts.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[60] 2018-01-10 11:22:41.548834 [#1 dnsotcp-manyopkts.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+[97] 2018-01-10 11:22:41.548947 [#2 dnsotcp-manyopkts.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[97] 2018-01-10 11:22:41.552406 [#3 dnsotcp-manyopkts.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.552406 [#3 dnsotcp-manyopkts.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[97] 2018-01-10 11:22:41.552406 [#3 dnsotcp-manyopkts.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[60] 2018-01-10 11:22:41.543825 [#0 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[60] 2018-01-10 11:22:41.548834 [#1 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
+[80] 2018-01-10 11:22:41.552406 [#2 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.552406 [#2 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:41.555912 [#4 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,58,216.58.211.142 0 0
+[97] 2018-01-10 11:22:41.600183 [#5 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:41.600183 [#5 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:41.616460 [#7 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21599,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:41.659921 [#8 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:41.659921 [#8 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[97] 2018-01-10 11:22:42.047148 [#10 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.047148 [#10 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[80] 2018-01-10 11:22:42.097899 [#12 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.097899 [#12 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[97] 2018-01-10 11:22:42.145005 [#14 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.145005 [#14 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[80] 2018-01-10 11:22:42.192777 [#16 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.192777 [#16 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[97] 2018-01-10 11:22:42.240395 [#18 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.240395 [#18 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.245103 [#20 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:42.290257 [#21 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.290257 [#21 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.293978 [#23 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[97] 2018-01-10 11:22:42.337985 [#24 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.337985 [#24 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.341559 [#26 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:42.385009 [#27 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.385009 [#27 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.389082 [#29 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[97] 2018-01-10 11:22:42.433458 [#30 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.433458 [#30 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.438748 [#32 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:42.484005 [#33 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.484005 [#33 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.487697 [#35 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[97] 2018-01-10 11:22:42.532414 [#36 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.532414 [#36 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.537574 [#38 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:42.583021 [#39 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.583021 [#39 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.586898 [#41 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[80] 2018-01-10 11:22:42.630221 [#42 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.630221 [#42 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.633808 [#44 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[80] 2018-01-10 11:22:42.679168 [#45 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.679168 [#45 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.682888 [#47 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[80] 2018-01-10 11:22:42.727254 [#48 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.727254 [#48 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.732703 [#50 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[97] 2018-01-10 11:22:42.777184 [#51 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.777184 [#51 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.781053 [#53 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:42.824222 [#54 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.824222 [#54 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.828050 [#56 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[97] 2018-01-10 11:22:42.872186 [#57 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.872186 [#57 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.875911 [#59 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21598,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:42.920231 [#60 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:42.920231 [#60 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:42.923917 [#62 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,57,216.58.211.142 0 0
+[97] 2018-01-10 11:22:42.968961 [#63 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:42.968961 [#63 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:42.972662 [#65 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:43.017364 [#66 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.017364 [#66 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.022591 [#68 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[97] 2018-01-10 11:22:43.066765 [#69 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.066765 [#69 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.070349 [#71 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:43.114332 [#72 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.114332 [#72 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.119538 [#74 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[97] 2018-01-10 11:22:43.163857 [#75 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.163857 [#75 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.167576 [#77 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:43.211417 [#78 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.211417 [#78 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.216686 [#80 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[97] 2018-01-10 11:22:43.260995 [#81 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.260995 [#81 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.265047 [#83 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:43.310017 [#84 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.310017 [#84 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.313596 [#86 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[97] 2018-01-10 11:22:43.356802 [#87 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.356802 [#87 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.360685 [#89 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:43.406308 [#90 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.406308 [#90 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.410191 [#92 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[97] 2018-01-10 11:22:43.454193 [#93 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[97] 2018-01-10 11:22:43.454193 [#93 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[197] 2018-01-10 11:22:43.458191 [#95 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 4 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,21597,dfw06s47-in-f14.1e100.net. 0 0
+[80] 2018-01-10 11:22:43.503242 [#96 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[80] 2018-01-10 11:22:43.503242 [#96 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[98] 2018-01-10 11:22:43.506884 [#98 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,56,216.58.211.142 0 0
+[52] 2018-01-10 11:22:43.507821 [#99 dnso1tcp-bighole.pcap-dist 4095] \
+ [172.17.0.8].51388 [8.8.8.8].53
+[52] 2018-01-10 11:22:43.511351 [#100 dnso1tcp-bighole.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.8].51388
diff --git a/src/test/test8.sh b/src/test/test8.sh
new file mode 100755
index 0000000..e091ff6
--- /dev/null
+++ b/src/test/test8.sh
@@ -0,0 +1,16 @@
+#!/bin/sh -xe
+
+rm -f test8.out test8.layer.out
+
+for what in dnsotcp-many1pkt.pcap-dist dnsotcp-manyopkts.pcap-dist; do
+ ../dnscap -r "$what" -g -T -o reassemble_tcp=yes 2>>test8.out
+ ../dnscap -r "$what" -g -T -o reassemble_tcp=yes -o use_layers=yes 2>>test8.layer.out
+done
+
+for what in dnso1tcp-bighole.pcap-dist; do
+ ../dnscap -r "$what" -g -T -o reassemble_tcp=yes -o allow_reset_tcpstate=yes 2>>test8.out
+ ../dnscap -r "$what" -g -T -o reassemble_tcp=yes -o allow_reset_tcpstate=yes -o use_layers=yes 2>>test8.layer.out
+done
+
+diff test8.out "$srcdir/test8.gold"
+diff test8.layer.out "$srcdir/test8.gold"
diff --git a/src/test/test9.gold b/src/test/test9.gold
new file mode 100644
index 0000000..1c50c70
--- /dev/null
+++ b/src/test/test9.gold
@@ -0,0 +1,104 @@
+[56] 2016-10-20 15:23:52.860937 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].40953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:52.863771 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40953 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,297,216.58.218.206 \
+ 4 google.com.,IN,NS,157828,ns2.google.com. \
+ google.com.,IN,NS,157828,ns4.google.com. \
+ google.com.,IN,NS,157828,ns1.google.com. \
+ google.com.,IN,NS,157828,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157828,216.239.34.10 \
+ ns1.google.com.,IN,A,331830,216.239.32.10 \
+ ns3.google.com.,IN,A,157828,216.239.36.10 \
+ ns4.google.com.,IN,A,157828,216.239.38.10
+[56] 2016-10-20 15:23:59.083869 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].45174 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:59.086104 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45174 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,291,216.58.218.206 \
+ 4 google.com.,IN,NS,157822,ns2.google.com. \
+ google.com.,IN,NS,157822,ns3.google.com. \
+ google.com.,IN,NS,157822,ns1.google.com. \
+ google.com.,IN,NS,157822,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157822,216.239.34.10 \
+ ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10
+[73] 2016-10-20 15:23:59.090911 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].33916 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:59.092204 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33916 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71550,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10 \
+ ns2.google.com.,IN,A,157822,216.239.34.10
+[56] 2016-10-20 15:23:52.860937 [#0 dns.pcap-dist 4095] \
+ [172.17.0.10].40953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:52.863771 [#1 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].40953 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,297,216.58.218.206 \
+ 4 google.com.,IN,NS,157828,ns2.google.com. \
+ google.com.,IN,NS,157828,ns4.google.com. \
+ google.com.,IN,NS,157828,ns1.google.com. \
+ google.com.,IN,NS,157828,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157828,216.239.34.10 \
+ ns1.google.com.,IN,A,331830,216.239.32.10 \
+ ns3.google.com.,IN,A,157828,216.239.36.10 \
+ ns4.google.com.,IN,A,157828,216.239.38.10
+[56] 2016-10-20 15:23:59.083869 [#2 dns.pcap-dist 4095] \
+ [172.17.0.10].45174 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:59.086104 [#3 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].45174 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,291,216.58.218.206 \
+ 4 google.com.,IN,NS,157822,ns2.google.com. \
+ google.com.,IN,NS,157822,ns3.google.com. \
+ google.com.,IN,NS,157822,ns1.google.com. \
+ google.com.,IN,NS,157822,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157822,216.239.34.10 \
+ ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10
+[73] 2016-10-20 15:23:59.090911 [#4 dns.pcap-dist 4095] \
+ [172.17.0.10].33916 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:59.092204 [#5 dns.pcap-dist 4095] \
+ [8.8.8.8].53 [172.17.0.10].33916 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71550,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10 \
+ ns2.google.com.,IN,A,157822,216.239.34.10
diff --git a/src/test/test9.sh b/src/test/test9.sh
new file mode 100755
index 0000000..aff7610
--- /dev/null
+++ b/src/test/test9.sh
@@ -0,0 +1,6 @@
+#!/bin/sh -xe
+
+../dnscap -r dns.pcap-dist -g -B '2016-10-20 15:23:30' -E '2016-10-20 15:24:00' 2>test9.out
+../dnscap -r dns.pcap-dist -o use_layers=yes -g -B '2016-10-20 15:23:30' -E '2016-10-20 15:24:00' 2>>test9.out
+
+diff test9.out "$srcdir/test9.gold"
diff --git a/src/test/vlan11.gold b/src/test/vlan11.gold
new file mode 100644
index 0000000..92f8d39
--- /dev/null
+++ b/src/test/vlan11.gold
@@ -0,0 +1,714 @@
+[56] 2016-10-20 15:23:01.075993 [#0 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].53199 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59311,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.077982 [#1 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].53199 \
+ dns QUERY,NOERROR,59311,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns4.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[73] 2016-10-20 15:23:01.082865 [#2 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].57822 [8.8.8.8].53 \
+ dns QUERY,NOERROR,35665,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:01.084107 [#3 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].57822 \
+ dns QUERY,NOERROR,35665,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72125,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71608,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71608,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10 \
+ ns2.google.com.,IN,A,157880,216.239.34.10
+[56] 2016-10-20 15:23:01.087291 [#4 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].40043 [8.8.8.8].53 \
+ dns QUERY,NOERROR,5337,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:01.088733 [#5 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].40043 \
+ dns QUERY,NOERROR,5337,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,44,216.58.218.206 \
+ 4 google.com.,IN,NS,157880,ns1.google.com. \
+ google.com.,IN,NS,157880,ns2.google.com. \
+ google.com.,IN,NS,157880,ns3.google.com. \
+ google.com.,IN,NS,157880,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157880,216.239.34.10 \
+ ns1.google.com.,IN,A,331882,216.239.32.10 \
+ ns3.google.com.,IN,A,157880,216.239.36.10 \
+ ns4.google.com.,IN,A,157880,216.239.38.10
+[56] 2016-10-20 15:23:10.322117 [#6 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].37953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22982,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:10.323399 [#7 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].37953 \
+ dns QUERY,NOERROR,22982,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,34,216.58.218.206 \
+ 4 google.com.,IN,NS,157870,ns4.google.com. \
+ google.com.,IN,NS,157870,ns1.google.com. \
+ google.com.,IN,NS,157870,ns2.google.com. \
+ google.com.,IN,NS,157870,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157870,216.239.34.10 \
+ ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10
+[73] 2016-10-20 15:23:10.328324 [#8 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].48658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18718,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:10.329572 [#9 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].48658 \
+ dns QUERY,NOERROR,18718,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72115,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71598,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71598,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331872,216.239.32.10 \
+ ns3.google.com.,IN,A,157870,216.239.36.10 \
+ ns4.google.com.,IN,A,157870,216.239.38.10 \
+ ns2.google.com.,IN,A,157870,216.239.34.10
+[56] 2016-10-20 15:23:52.860937 [#10 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].40953 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22531,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:52.863771 [#11 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].40953 \
+ dns QUERY,NOERROR,22531,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,297,216.58.218.206 \
+ 4 google.com.,IN,NS,157828,ns2.google.com. \
+ google.com.,IN,NS,157828,ns4.google.com. \
+ google.com.,IN,NS,157828,ns1.google.com. \
+ google.com.,IN,NS,157828,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157828,216.239.34.10 \
+ ns1.google.com.,IN,A,331830,216.239.32.10 \
+ ns3.google.com.,IN,A,157828,216.239.36.10 \
+ ns4.google.com.,IN,A,157828,216.239.38.10
+[56] 2016-10-20 15:23:59.083869 [#12 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].45174 [8.8.8.8].53 \
+ dns QUERY,NOERROR,58510,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:23:59.086104 [#13 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].45174 \
+ dns QUERY,NOERROR,58510,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,291,216.58.218.206 \
+ 4 google.com.,IN,NS,157822,ns2.google.com. \
+ google.com.,IN,NS,157822,ns3.google.com. \
+ google.com.,IN,NS,157822,ns1.google.com. \
+ google.com.,IN,NS,157822,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157822,216.239.34.10 \
+ ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10
+[73] 2016-10-20 15:23:59.090911 [#14 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].33916 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45248,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:23:59.092204 [#15 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].33916 \
+ dns QUERY,NOERROR,45248,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72067,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71550,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71550,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331824,216.239.32.10 \
+ ns3.google.com.,IN,A,157822,216.239.36.10 \
+ ns4.google.com.,IN,A,157822,216.239.38.10 \
+ ns2.google.com.,IN,A,157822,216.239.34.10
+[56] 2016-10-20 15:24:04.323868 [#16 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].43559 [8.8.8.8].53 \
+ dns QUERY,NOERROR,49483,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:04.325597 [#17 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].43559 \
+ dns QUERY,NOERROR,49483,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,285,216.58.218.206 \
+ 4 google.com.,IN,NS,157816,ns4.google.com. \
+ google.com.,IN,NS,157816,ns3.google.com. \
+ google.com.,IN,NS,157816,ns1.google.com. \
+ google.com.,IN,NS,157816,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157816,216.239.34.10 \
+ ns1.google.com.,IN,A,331818,216.239.32.10 \
+ ns3.google.com.,IN,A,157816,216.239.36.10 \
+ ns4.google.com.,IN,A,157816,216.239.38.10
+[56] 2016-10-20 15:24:06.332239 [#18 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].54859 [8.8.8.8].53 \
+ dns QUERY,NOERROR,31669,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:06.333743 [#19 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].54859 \
+ dns QUERY,NOERROR,31669,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,283,216.58.218.206 \
+ 4 google.com.,IN,NS,157814,ns2.google.com. \
+ google.com.,IN,NS,157814,ns1.google.com. \
+ google.com.,IN,NS,157814,ns4.google.com. \
+ google.com.,IN,NS,157814,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157814,216.239.34.10 \
+ ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10
+[73] 2016-10-20 15:24:06.339145 [#20 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].58176 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25433,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:06.340820 [#21 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].58176 \
+ dns QUERY,NOERROR,25433,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72059,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71542,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71542,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331816,216.239.32.10 \
+ ns3.google.com.,IN,A,157814,216.239.36.10 \
+ ns4.google.com.,IN,A,157814,216.239.38.10 \
+ ns2.google.com.,IN,A,157814,216.239.34.10
+[56] 2016-10-20 15:24:07.346429 [#22 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].41266 [8.8.8.8].53 \
+ dns QUERY,NOERROR,63798,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:07.348160 [#23 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].41266 \
+ dns QUERY,NOERROR,63798,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,282,216.58.218.206 \
+ 4 google.com.,IN,NS,157813,ns4.google.com. \
+ google.com.,IN,NS,157813,ns1.google.com. \
+ google.com.,IN,NS,157813,ns3.google.com. \
+ google.com.,IN,NS,157813,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157813,216.239.34.10 \
+ ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10
+[73] 2016-10-20 15:24:07.353123 [#24 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].34607 [8.8.8.8].53 \
+ dns QUERY,NOERROR,8470,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:07.354682 [#25 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].34607 \
+ dns QUERY,NOERROR,8470,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72058,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71541,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71541,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331815,216.239.32.10 \
+ ns3.google.com.,IN,A,157813,216.239.36.10 \
+ ns4.google.com.,IN,A,157813,216.239.38.10 \
+ ns2.google.com.,IN,A,157813,216.239.34.10
+[56] 2016-10-20 15:24:08.360528 [#26 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].60437 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60258,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:08.362206 [#27 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].60437 \
+ dns QUERY,NOERROR,60258,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,281,216.58.218.206 \
+ 4 google.com.,IN,NS,157812,ns3.google.com. \
+ google.com.,IN,NS,157812,ns2.google.com. \
+ google.com.,IN,NS,157812,ns4.google.com. \
+ google.com.,IN,NS,157812,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157812,216.239.34.10 \
+ ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10
+[73] 2016-10-20 15:24:08.368516 [#28 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].37149 [8.8.8.8].53 \
+ dns QUERY,NOERROR,44985,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:08.370119 [#29 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].37149 \
+ dns QUERY,NOERROR,44985,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72057,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71540,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71540,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331814,216.239.32.10 \
+ ns3.google.com.,IN,A,157812,216.239.36.10 \
+ ns4.google.com.,IN,A,157812,216.239.38.10 \
+ ns2.google.com.,IN,A,157812,216.239.34.10
+[56] 2016-10-20 15:24:09.375942 [#30 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].53820 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45512,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:09.378425 [#31 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].53820 \
+ dns QUERY,NOERROR,45512,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,280,216.58.218.206 \
+ 4 google.com.,IN,NS,157811,ns3.google.com. \
+ google.com.,IN,NS,157811,ns4.google.com. \
+ google.com.,IN,NS,157811,ns1.google.com. \
+ google.com.,IN,NS,157811,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157811,216.239.34.10 \
+ ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10
+[73] 2016-10-20 15:24:09.384057 [#32 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].52368 [8.8.8.8].53 \
+ dns QUERY,NOERROR,22980,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:09.385463 [#33 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].52368 \
+ dns QUERY,NOERROR,22980,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72056,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71539,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71539,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331813,216.239.32.10 \
+ ns3.google.com.,IN,A,157811,216.239.36.10 \
+ ns4.google.com.,IN,A,157811,216.239.38.10 \
+ ns2.google.com.,IN,A,157811,216.239.34.10
+[56] 2016-10-20 15:24:10.391358 [#34 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].47637 [8.8.8.8].53 \
+ dns QUERY,NOERROR,1834,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:10.392886 [#35 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].47637 \
+ dns QUERY,NOERROR,1834,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,279,216.58.218.206 \
+ 4 google.com.,IN,NS,157810,ns1.google.com. \
+ google.com.,IN,NS,157810,ns2.google.com. \
+ google.com.,IN,NS,157810,ns4.google.com. \
+ google.com.,IN,NS,157810,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157810,216.239.34.10 \
+ ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10
+[73] 2016-10-20 15:24:10.398099 [#36 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].34426 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25431,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:10.400317 [#37 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].34426 \
+ dns QUERY,NOERROR,25431,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72055,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71538,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71538,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331812,216.239.32.10 \
+ ns3.google.com.,IN,A,157810,216.239.36.10 \
+ ns4.google.com.,IN,A,157810,216.239.38.10 \
+ ns2.google.com.,IN,A,157810,216.239.34.10
+[56] 2016-10-20 15:24:11.406297 [#38 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].41059 [8.8.8.8].53 \
+ dns QUERY,NOERROR,48432,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:11.407460 [#39 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].41059 \
+ dns QUERY,NOERROR,48432,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,278,216.58.218.206 \
+ 4 google.com.,IN,NS,157809,ns3.google.com. \
+ google.com.,IN,NS,157809,ns4.google.com. \
+ google.com.,IN,NS,157809,ns2.google.com. \
+ google.com.,IN,NS,157809,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157809,216.239.34.10 \
+ ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10
+[73] 2016-10-20 15:24:11.412133 [#40 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].51181 [8.8.8.8].53 \
+ dns QUERY,NOERROR,47411,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:11.413370 [#41 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].51181 \
+ dns QUERY,NOERROR,47411,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72054,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71537,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71537,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331811,216.239.32.10 \
+ ns3.google.com.,IN,A,157809,216.239.36.10 \
+ ns4.google.com.,IN,A,157809,216.239.38.10 \
+ ns2.google.com.,IN,A,157809,216.239.34.10
+[56] 2016-10-20 15:24:12.419936 [#42 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].32976 [8.8.8.8].53 \
+ dns QUERY,NOERROR,12038,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:12.421228 [#43 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].32976 \
+ dns QUERY,NOERROR,12038,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,277,216.58.218.206 \
+ 4 google.com.,IN,NS,157808,ns2.google.com. \
+ google.com.,IN,NS,157808,ns3.google.com. \
+ google.com.,IN,NS,157808,ns1.google.com. \
+ google.com.,IN,NS,157808,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157808,216.239.34.10 \
+ ns1.google.com.,IN,A,331810,216.239.32.10 \
+ ns3.google.com.,IN,A,157808,216.239.36.10 \
+ ns4.google.com.,IN,A,157808,216.239.38.10
+[56] 2016-10-20 15:24:14.428524 [#44 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].53467 [8.8.8.8].53 \
+ dns QUERY,NOERROR,11614,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:14.429863 [#45 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].53467 \
+ dns QUERY,NOERROR,11614,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,275,216.58.218.206 \
+ 4 google.com.,IN,NS,157806,ns3.google.com. \
+ google.com.,IN,NS,157806,ns1.google.com. \
+ google.com.,IN,NS,157806,ns4.google.com. \
+ google.com.,IN,NS,157806,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157806,216.239.34.10 \
+ ns1.google.com.,IN,A,331808,216.239.32.10 \
+ ns3.google.com.,IN,A,157806,216.239.36.10 \
+ ns4.google.com.,IN,A,157806,216.239.38.10
+[56] 2016-10-20 15:24:16.435733 [#46 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].41532 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59173,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:16.437471 [#47 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].41532 \
+ dns QUERY,NOERROR,59173,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,273,216.58.218.206 \
+ 4 google.com.,IN,NS,157804,ns1.google.com. \
+ google.com.,IN,NS,157804,ns3.google.com. \
+ google.com.,IN,NS,157804,ns2.google.com. \
+ google.com.,IN,NS,157804,ns4.google.com. \
+ 4 ns2.google.com.,IN,A,157804,216.239.34.10 \
+ ns1.google.com.,IN,A,331806,216.239.32.10 \
+ ns3.google.com.,IN,A,157804,216.239.36.10 \
+ ns4.google.com.,IN,A,157804,216.239.38.10
+[56] 2016-10-20 15:24:18.445519 [#48 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].44982 [8.8.8.8].53 \
+ dns QUERY,NOERROR,45535,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:18.446775 [#49 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].44982 \
+ dns QUERY,NOERROR,45535,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,271,216.58.218.206 \
+ 4 google.com.,IN,NS,157802,ns4.google.com. \
+ google.com.,IN,NS,157802,ns2.google.com. \
+ google.com.,IN,NS,157802,ns1.google.com. \
+ google.com.,IN,NS,157802,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157802,216.239.34.10 \
+ ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10
+[73] 2016-10-20 15:24:18.452451 [#50 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].40224 [8.8.8.8].53 \
+ dns QUERY,NOERROR,60808,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:18.454030 [#51 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].40224 \
+ dns QUERY,NOERROR,60808,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72047,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71530,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71530,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331804,216.239.32.10 \
+ ns3.google.com.,IN,A,157802,216.239.36.10 \
+ ns4.google.com.,IN,A,157802,216.239.38.10 \
+ ns2.google.com.,IN,A,157802,216.239.34.10
+[56] 2016-10-20 15:24:19.460087 [#52 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].45658 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64325,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:19.462224 [#53 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].45658 \
+ dns QUERY,NOERROR,64325,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,270,216.58.218.206 \
+ 4 google.com.,IN,NS,157801,ns1.google.com. \
+ google.com.,IN,NS,157801,ns3.google.com. \
+ google.com.,IN,NS,157801,ns4.google.com. \
+ google.com.,IN,NS,157801,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157801,216.239.34.10 \
+ ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10
+[73] 2016-10-20 15:24:19.467324 [#54 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].60457 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25543,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:19.468895 [#55 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].60457 \
+ dns QUERY,NOERROR,25543,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72046,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71529,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71529,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331803,216.239.32.10 \
+ ns3.google.com.,IN,A,157801,216.239.36.10 \
+ ns4.google.com.,IN,A,157801,216.239.38.10 \
+ ns2.google.com.,IN,A,157801,216.239.34.10
+[56] 2016-10-20 15:24:20.475086 [#56 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].59762 [8.8.8.8].53 \
+ dns QUERY,NOERROR,20736,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:20.476841 [#57 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].59762 \
+ dns QUERY,NOERROR,20736,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,269,216.58.218.206 \
+ 4 google.com.,IN,NS,157800,ns3.google.com. \
+ google.com.,IN,NS,157800,ns1.google.com. \
+ google.com.,IN,NS,157800,ns4.google.com. \
+ google.com.,IN,NS,157800,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157800,216.239.34.10 \
+ ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10
+[73] 2016-10-20 15:24:20.482188 [#58 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].56022 [8.8.8.8].53 \
+ dns QUERY,NOERROR,25911,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:20.483927 [#59 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].56022 \
+ dns QUERY,NOERROR,25911,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72045,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71528,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71528,ns3.google.com. \
+ 4 ns1.google.com.,IN,A,331802,216.239.32.10 \
+ ns3.google.com.,IN,A,157800,216.239.36.10 \
+ ns4.google.com.,IN,A,157800,216.239.38.10 \
+ ns2.google.com.,IN,A,157800,216.239.34.10
+[56] 2016-10-20 15:24:21.489468 [#60 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].37669 [8.8.8.8].53 \
+ dns QUERY,NOERROR,64358,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:21.490573 [#61 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].37669 \
+ dns QUERY,NOERROR,64358,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,268,216.58.218.206 \
+ 4 google.com.,IN,NS,157799,ns2.google.com. \
+ google.com.,IN,NS,157799,ns1.google.com. \
+ google.com.,IN,NS,157799,ns4.google.com. \
+ google.com.,IN,NS,157799,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157799,216.239.34.10 \
+ ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10
+[73] 2016-10-20 15:24:21.495324 [#62 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].42978 [8.8.8.8].53 \
+ dns QUERY,NOERROR,37698,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:21.496815 [#63 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].42978 \
+ dns QUERY,NOERROR,37698,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72044,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71527,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71527,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331801,216.239.32.10 \
+ ns3.google.com.,IN,A,157799,216.239.36.10 \
+ ns4.google.com.,IN,A,157799,216.239.38.10 \
+ ns2.google.com.,IN,A,157799,216.239.34.10
+[56] 2016-10-20 15:24:22.502667 [#64 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].49829 [8.8.8.8].53 \
+ dns QUERY,NOERROR,54706,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:22.504738 [#65 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].49829 \
+ dns QUERY,NOERROR,54706,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,267,216.58.218.206 \
+ 4 google.com.,IN,NS,157798,ns2.google.com. \
+ google.com.,IN,NS,157798,ns4.google.com. \
+ google.com.,IN,NS,157798,ns3.google.com. \
+ google.com.,IN,NS,157798,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157798,216.239.34.10 \
+ ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10
+[73] 2016-10-20 15:24:22.510176 [#66 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].50599 [8.8.8.8].53 \
+ dns QUERY,NOERROR,32142,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:22.511746 [#67 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].50599 \
+ dns QUERY,NOERROR,32142,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72043,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71526,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71526,ns4.google.com. \
+ 4 ns1.google.com.,IN,A,331800,216.239.32.10 \
+ ns3.google.com.,IN,A,157798,216.239.36.10 \
+ ns4.google.com.,IN,A,157798,216.239.38.10 \
+ ns2.google.com.,IN,A,157798,216.239.34.10
+[56] 2016-10-20 15:24:23.520203 [#68 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].44980 [8.8.8.8].53 \
+ dns QUERY,NOERROR,41808,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:23.521976 [#69 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].44980 \
+ dns QUERY,NOERROR,41808,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,266,216.58.218.206 \
+ 4 google.com.,IN,NS,157797,ns2.google.com. \
+ google.com.,IN,NS,157797,ns4.google.com. \
+ google.com.,IN,NS,157797,ns1.google.com. \
+ google.com.,IN,NS,157797,ns3.google.com. \
+ 4 ns2.google.com.,IN,A,157797,216.239.34.10 \
+ ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10
+[73] 2016-10-20 15:24:23.527449 [#70 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].60063 [8.8.8.8].53 \
+ dns QUERY,NOERROR,18886,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:23.529385 [#71 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].60063 \
+ dns QUERY,NOERROR,18886,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72042,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71525,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71525,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331799,216.239.32.10 \
+ ns3.google.com.,IN,A,157797,216.239.36.10 \
+ ns4.google.com.,IN,A,157797,216.239.38.10 \
+ ns2.google.com.,IN,A,157797,216.239.34.10
+[56] 2016-10-20 15:24:24.537264 [#72 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].42042 [8.8.8.8].53 \
+ dns QUERY,NOERROR,10624,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:24.539398 [#73 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].42042 \
+ dns QUERY,NOERROR,10624,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,265,216.58.218.206 \
+ 4 google.com.,IN,NS,157796,ns3.google.com. \
+ google.com.,IN,NS,157796,ns4.google.com. \
+ google.com.,IN,NS,157796,ns1.google.com. \
+ google.com.,IN,NS,157796,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157796,216.239.34.10 \
+ ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10
+[73] 2016-10-20 15:24:24.544538 [#74 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].60469 [8.8.8.8].53 \
+ dns QUERY,NOERROR,33139,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:24.546172 [#75 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].60469 \
+ dns QUERY,NOERROR,33139,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f206.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72041,dfw06s47-in-f14.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71524,ns2.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71524,ns1.google.com. \
+ 4 ns1.google.com.,IN,A,331798,216.239.32.10 \
+ ns3.google.com.,IN,A,157796,216.239.36.10 \
+ ns4.google.com.,IN,A,157796,216.239.38.10 \
+ ns2.google.com.,IN,A,157796,216.239.34.10
+[56] 2016-10-20 15:24:25.554744 [#76 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].45703 [8.8.8.8].53 \
+ dns QUERY,NOERROR,61415,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:25.556513 [#77 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].45703 \
+ dns QUERY,NOERROR,61415,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,264,216.58.218.206 \
+ 4 google.com.,IN,NS,157795,ns3.google.com. \
+ google.com.,IN,NS,157795,ns4.google.com. \
+ google.com.,IN,NS,157795,ns2.google.com. \
+ google.com.,IN,NS,157795,ns1.google.com. \
+ 4 ns2.google.com.,IN,A,157795,216.239.34.10 \
+ ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10
+[73] 2016-10-20 15:24:25.562608 [#78 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].33507 [8.8.8.8].53 \
+ dns QUERY,NOERROR,59258,rd \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR 0 0 0
+[289] 2016-10-20 15:24:25.564509 [#79 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].33507 \
+ dns QUERY,NOERROR,59258,qr|rd|ra \
+ 1 206.218.58.216.in-addr.arpa.,IN,PTR \
+ 2 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f14.1e100.net. \
+ 206.218.58.216.in-addr.arpa.,IN,PTR,72040,dfw06s47-in-f206.1e100.net. \
+ 4 218.58.216.in-addr.arpa.,IN,NS,71523,ns1.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns4.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns3.google.com. \
+ 218.58.216.in-addr.arpa.,IN,NS,71523,ns2.google.com. \
+ 4 ns1.google.com.,IN,A,331797,216.239.32.10 \
+ ns3.google.com.,IN,A,157795,216.239.36.10 \
+ ns4.google.com.,IN,A,157795,216.239.38.10 \
+ ns2.google.com.,IN,A,157795,216.239.34.10
+[56] 2016-10-20 15:24:26.572784 [#80 vlan11.pcap-dist (vlan 11) 11] \
+ [172.17.0.10].46798 [8.8.8.8].53 \
+ dns QUERY,NOERROR,17700,rd \
+ 1 google.com.,IN,A 0 0 0
+[208] 2016-10-20 15:24:26.574350 [#81 vlan11.pcap-dist (vlan 11) 11] \
+ [8.8.8.8].53 [172.17.0.10].46798 \
+ dns QUERY,NOERROR,17700,qr|rd|ra \
+ 1 google.com.,IN,A \
+ 1 google.com.,IN,A,263,216.58.218.206 \
+ 4 google.com.,IN,NS,157794,ns1.google.com. \
+ google.com.,IN,NS,157794,ns4.google.com. \
+ google.com.,IN,NS,157794,ns3.google.com. \
+ google.com.,IN,NS,157794,ns2.google.com. \
+ 4 ns2.google.com.,IN,A,157794,216.239.34.10 \
+ ns1.google.com.,IN,A,331796,216.239.32.10 \
+ ns3.google.com.,IN,A,157794,216.239.36.10 \
+ ns4.google.com.,IN,A,157794,216.239.38.10
diff --git a/src/test/vlan11.pcap b/src/test/vlan11.pcap
new file mode 100644
index 0000000..9e1f5be
--- /dev/null
+++ b/src/test/vlan11.pcap
Binary files differ