Skip to content

Commit

Permalink
Merge pull request DNS-OARC#23 from jelu/various
Browse files Browse the repository at this point in the history
Various
  • Loading branch information
jelu authored Aug 31, 2016
2 parents d9dd3ff + 33576ef commit 4f120c2
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 18 deletions.
40 changes: 37 additions & 3 deletions src/dnscap.1.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
.Op Fl r Ar file ...
.Op Fl l Ar vlan ...
.Op Fl L Ar vlan ...
.Op Fl u Ar port
.Op Fl x Ar pat ...
.Op Fl X Ar pat ...
.Oo
Expand All @@ -26,8 +27,12 @@
.Op ir
.Oc
.Oo
.Fl h
.Op ir
.Oc
.Oo
.Fl e
.Op nytfsxir
.Op nytfsxirMD
.Oc
.Op Fl a Ar host ...
.Op Fl z Ar host ...
Expand All @@ -38,10 +43,16 @@
.Oo
.Fl w
.Ar base
.Op Fl W Ar suffix
.Op Fl k Ar cmd
.Oc
.Op Fl t Ar lim
.Op Fl c Ar lim
.Op Fl C Ar lim
.Op Fl B Ar datetime
.Op Fl E Ar datetime
.Op Fl P Ar plugin.so
.Op Fl U Ar str
.Sh DESCRIPTION
.Nm
is a network capture utility designed specifically for DNS traffic. It
Expand All @@ -59,6 +70,8 @@ is expected to be used for gathering continuous research or audit traces.
.Pp
The following options are available:
.Bl -tag -width 10n
.It Fl b
Run in background as daemon.
.It Fl 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
Expand Down Expand Up @@ -110,6 +123,8 @@ boundaries, will be captured if and only if the first DNS header passed all
filter options.
TCP packets will usually not be printable with
.Fl g .
.It Fl I
Select ICMP and ICMPv6 packets.
.It Fl i Ar 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
Expand Down Expand Up @@ -241,6 +256,8 @@ and
.Fl t
options affect the total duration of the capture, and not merely the size and
time limits of each individual dump file.
.It Fl W Ar suffix
The provided suffix is added to the dump file name, e. g.: ".pcap"
.It Fl k Ar cmd
After each dump file specified by
.Fl w
Expand Down Expand Up @@ -281,6 +298,17 @@ file,
.Nm
exits. This option is inclusive with
.Fl t .
.It Fl C Ar lim
By default,
.Nm
will close its packet dump file only when interrupted. A dump file size,
measured in bytes captured, can be specified with the
.Fl C
option. If the packet dump file is standard output, then after closing this
file,
.Nm
exits. This option is inclusive with
.Fl t .
.It Fl B Ar datetime
When using
.Fl w ,
Expand Down Expand Up @@ -312,13 +340,19 @@ Causes
.Nm
to print pcap_stats() counters on stderr when
.Fl t
or
,
.Fl c
or
.Fl C
limits are reached.
.It Fl M
Enable monitor mode on interfaces.
.It Fl C
.It Fl D
Enable immediate mode on interfaces.
.It Fl U Ar str
Append "and
.Ar str
" to the pcap filter.
.El
.Pp
If started with no options,
Expand Down
75 changes: 60 additions & 15 deletions src/dnscap.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,19 +342,22 @@ static myregex_list myregexes;
static mypcap_list mypcaps;
static mypcap_ptr pcap_offline = NULL;
static const char *dump_base = NULL;
static char *dump_suffix = NULL;
static char *extra_bpf = NULL;
static enum {nowhere, to_stdout, to_file} dump_type = nowhere;
static enum {dumper_opened, dumper_closed} dump_state = dumper_closed;
static const char *kick_cmd = NULL;
static unsigned limit_seconds = 0U;
static time_t next_interval = 0;
static unsigned limit_packets = 0U;
static size_t limit_pcapfilesize = 0U;
static fd_set mypcap_fdset;
static int pcap_maxfd;
static pcap_t *pcap_dead;
static pcap_dumper_t *dumper;
static time_t dumpstart;
static unsigned msgcount;
static size_t capturedbytes = 0;
static char *dumpname, *dumpnamepart;
static char *bpft;
static unsigned dns_port = DNS_PORT;
Expand Down Expand Up @@ -427,9 +430,10 @@ main(int argc, char *argv[]) {
daemonize();
while (!main_exit)
poll_pcaps();
close_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)();
Expand Down Expand Up @@ -683,13 +687,13 @@ help_1(void) {
fprintf(stderr, "%s: version %s\n\n", ProgramName, version());
fprintf(stderr,
"usage: %s\n"
"\t[-?bpd1g6fTISMC] [-i <if>]+ [-r <file>]+ [-l <vlan>]+ [-L <vlan>]+\n"
"\t[-?bpd1g6fTISMD] [-i <if>]+ [-r <file>]+ [-l <vlan>]+ [-L <vlan>]+\n"
"\t[-u <port>] [-m [qun]] [-e [nytfsxir]]\n"
"\t[-h [ir]] [-s [ir]]\n"
"\t[-a <host>]+ [-z <host>]+ [-A <host>]+ [-Z <host>]+\n"
"\t[-w <base> [-k <cmd>]] [-t <lim>] [-c <lim>]\n"
"\t[-a <host>]+ [-z <host>]+ [-A <host>]+ [-Z <host>]+ [-Y <host>]+\n"
"\t[-w <base> [-W <suffix>] [-k <cmd>]] [-t <lim>] [-c <lim>] [-C <lim>]\n"
"\t[-x <pat>]+ [-X <pat>]+\n"
"\t[-B <datetime>]+ [-E <datetime>]+\n"
"\t[-B <datetime>] [-E <datetime>]\n"
"\t[-P plugin.so] [-U <str>]\n",
ProgramName);
}
Expand All @@ -702,7 +706,7 @@ help_2(void) {
"\t-? or -\\? print these instructions and exit\n"
"\t-b run in background as daemon\n"
"\t-p do not put interface in promiscuous mode\n"
"\t-d dump verbose trace information to stderr\n"
"\t-d dump verbose trace information to stderr, specify multiple times to increase debugging\n"
"\t-1 flush output on every packet\n"
"\t-g dump packets dig-style on stderr\n"
"\t-6 compensate for PCAP/BPF IPv6 bug\n"
Expand Down Expand Up @@ -734,9 +738,11 @@ help_2(void) {
"\t-Z <host> want messages NOT to/from these responder(s)\n"
"\t-Y <host> drop responses from these responder(s)\n"
"\t-w <base> dump to <base>.<timesec>.<timeusec>\n"
"\t-W <suffix> add suffix to dump file name, e.g. '.pcap'\n"
"\t-k <cmd> kick off <cmd> when each dump closes\n"
"\t-t <lim> close dump or exit every/after <lim> secs\n"
"\t-c <lim> close dump or exit every/after <lim> pkts\n"
"\t-C <lim> close dump or exit every/after <lim> bytes captured\n"
"\t-x <pat> select messages matching regex <pat>\n"
"\t-X <pat> select messages not matching regex <pat>\n"
#ifdef USE_SECCOMP
Expand All @@ -748,7 +754,7 @@ help_2(void) {
"\t-B <datetime> begin collecting at this date and time\n"
"\t-E <datetime> end collecting at this date and time\n"
"\t-M set monitor mode on interfaces\n"
"\t-C set immediate mode on interfaces\n"
"\t-D set immediate mode on interfaces\n"
);
}

Expand Down Expand Up @@ -780,7 +786,7 @@ parse_args(int argc, char *argv[]) {
#ifdef USE_SECCOMP
"y"
#endif
"z:A:B:E:IL:P:STU:X:Y:Z:16?MC")
"z:A:B:C:DE:IL:MP:STU:W:X:Y:Z:16?")
) != EOF)
{
switch (ch) {
Expand Down Expand Up @@ -940,6 +946,11 @@ parse_args(int argc, char *argv[]) {
else
dump_type = to_file;
break;
case 'W':
if (dump_suffix)
free(dump_suffix);
dump_suffix = strdup(optarg);
break;
case 'k':
if (dump_type != to_file)
usage("-k depends on -w"
Expand All @@ -958,6 +969,12 @@ parse_args(int argc, char *argv[]) {
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':
Expand Down Expand Up @@ -1065,7 +1082,7 @@ parse_args(int argc, char *argv[]) {
case 'M':
monitor_mode = TRUE;
break;
case 'C':
case 'D':
immediate_mode = TRUE;
break;
default:
Expand All @@ -1089,7 +1106,7 @@ parse_args(int argc, char *argv[]) {

fprintf(stderr, "%s: version %s\n", ProgramName, 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\n",
"%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\n",
ProgramName,
(msg_wanted & MSG_QUERY) != 0 ? 'Q' : '.',
(msg_wanted & MSG_UPDATE) != 0 ? 'U' : '.',
Expand All @@ -1106,7 +1123,7 @@ parse_args(int argc, char *argv[]) {
(err_wanted & ERR_NXDOMAIN) != 0 ? 'x' : '.',
(err_wanted & ERR_NOTIMPL) != 0 ? 'i' : '.',
(err_wanted & ERR_REFUSED) != 0 ? 'r' : '.',
limit_seconds, limit_packets);
limit_seconds, limit_packets, limit_pcapfilesize);
sep = "\tinit";
for (ep = HEAD(initiators);
ep != NULL;
Expand Down Expand Up @@ -1761,6 +1778,17 @@ dl_pkt(u_char *user, const struct pcap_pkthdr *hdr, const u_char *pkt, const cha
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();
Expand All @@ -1773,7 +1801,7 @@ static void
discard(tcpstate_ptr tcpstate, const char *msg)
{
if (dumptrace >= 3 && msg)
fprintf(stderr, "%s\n", msg);
fprintf(stderr, "discarding packet: %s\n", msg);
if (tcpstate) {
UNLINK(tcpstates, tcpstate, link);
free(tcpstate);
Expand All @@ -1800,6 +1828,9 @@ network_pkt(const char *descr, my_bpftimeval ts, unsigned pf,
size_t len, dnslen;
HEADER dns;

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);

Expand Down Expand Up @@ -2308,7 +2339,6 @@ network_pkt(const char *descr, my_bpftimeval ts, unsigned pf,
abort();
}
}
msgcount++;
output(descr, from, to, proto, flags, sport, dport, ts,
pkt_copy, olen, dnspkt, dnslen);
}
Expand All @@ -2323,6 +2353,21 @@ output(const char *descr, iaddr from, iaddr to, uint8_t proto, unsigned flags,
const u_char *payload, const unsigned payloadlen)
{
struct plugin *p;

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);
Expand Down Expand Up @@ -2373,9 +2418,9 @@ dumper_open(my_bpftimeval ts) {
char sbuf[64];

strftime(sbuf, 64, "%Y%m%d.%H%M%S", gmtime((time_t *) &ts.tv_sec));
if (asprintf(&dumpname, "%s.%s.%06lu",
if (asprintf(&dumpname, "%s.%s.%06lu%s",
dump_base, sbuf,
(u_long) ts.tv_usec) < 0 ||
(u_long) ts.tv_usec, dump_suffix ? dump_suffix : "") < 0 ||
asprintf(&dumpnamepart, "%s.part", dumpname) < 0)
{
logerr("asprintf: %s", strerror(errno));
Expand Down

0 comments on commit 4f120c2

Please sign in to comment.