Adding upstream version 2.0.0+debian.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
65eb8bc08a
commit
1cf0d30d41
191 changed files with 48816 additions and 0 deletions
23
plugins/rzkeychange/Makefile.am
Normal file
23
plugins/rzkeychange/Makefile.am
Normal file
|
@ -0,0 +1,23 @@
|
|||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
CLEANFILES = *.gcda *.gcno *.gcov
|
||||
|
||||
AM_CFLAGS = -I$(srcdir) \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/isc \
|
||||
$(SECCOMPFLAGS) \
|
||||
$(libldns_CFLAGS)
|
||||
|
||||
pkglib_LTLIBRARIES = rzkeychange.la
|
||||
rzkeychange_la_SOURCES = rzkeychange.c
|
||||
rzkeychange_la_LDFLAGS = -module -avoid-version $(libldns_LIBS)
|
||||
|
||||
TESTS = test1.sh
|
||||
EXTRA_DIST = $(TESTS)
|
||||
CLEANFILES += *.pcap-dist
|
||||
|
||||
if ENABLE_GCOV
|
||||
gcov-local:
|
||||
for src in $(rzkeychange_la_SOURCES); do \
|
||||
gcov -o .libs -l -r -s "$(srcdir)" "$$src"; \
|
||||
done
|
||||
endif
|
470
plugins/rzkeychange/rzkeychange.c
Normal file
470
plugins/rzkeychange/rzkeychange.c
Normal file
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* Author Duane Wessels
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <memory.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <arpa/nameser.h>
|
||||
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
|
||||
#include <ldns/ldns.h>
|
||||
|
||||
#include "dnscap_common.h"
|
||||
|
||||
static logerr_t* logerr = 0;
|
||||
static my_bpftimeval open_ts = { 0, 0 };
|
||||
static my_bpftimeval clos_ts = { 0, 0 };
|
||||
static char* report_zone = 0;
|
||||
static char* report_server = 0;
|
||||
static char* report_node = 0;
|
||||
static char* keytag_zone = 0;
|
||||
static unsigned short resolver_port = 0;
|
||||
static unsigned int resolver_use_tcp = 0;
|
||||
static ldns_resolver* res;
|
||||
|
||||
static int dry_run = 0;
|
||||
|
||||
output_t rzkeychange_output;
|
||||
is_responder_t rzkeychange_is_responder = 0;
|
||||
ia_str_t rzkeychange_ia_str = 0;
|
||||
|
||||
#define MAX_KEY_TAG_SIGNALS 500
|
||||
static unsigned int num_key_tag_signals;
|
||||
struct {
|
||||
iaddr addr;
|
||||
uint8_t flags;
|
||||
const char* signal;
|
||||
} key_tag_signals[MAX_KEY_TAG_SIGNALS];
|
||||
|
||||
#define KEYTAG_FLAG_DO 1
|
||||
#define KEYTAG_FLAG_CD 2
|
||||
#define KEYTAG_FLAG_RD 4
|
||||
|
||||
struct {
|
||||
uint64_t dnskey;
|
||||
uint64_t tc_bit;
|
||||
uint64_t tcp;
|
||||
uint64_t icmp_unreach_frag;
|
||||
uint64_t icmp_timxceed_reass;
|
||||
uint64_t icmp_timxceed_intrans;
|
||||
uint64_t total;
|
||||
} counts;
|
||||
|
||||
#define MAX_NAMESERVERS 10
|
||||
static unsigned int num_ns_addrs = 0;
|
||||
static char* ns_addrs[MAX_NAMESERVERS];
|
||||
|
||||
void rzkeychange_usage()
|
||||
{
|
||||
fprintf(stderr,
|
||||
"\nrzkeychange.so options:\n"
|
||||
"\t-? print these instructions and exit\n"
|
||||
"\t-D dry run, just print queries\n"
|
||||
"\t-z <zone> Report counters to DNS zone <zone> (required)\n"
|
||||
"\t-s <server> Data is from server <server> (required)\n"
|
||||
"\t-n <node> Data is from site/node <node> (required)\n"
|
||||
"\t-k <zone> Report RFC 8145 key tag signals to <zone>\n"
|
||||
"\t-a <addr> Send DNS queries to this addr\n"
|
||||
"\t-p <port> Send DNS queries to this port\n"
|
||||
"\t-t Use TCP for DNS queries\n");
|
||||
}
|
||||
|
||||
void rzkeychange_extension(int ext, void* arg)
|
||||
{
|
||||
switch (ext) {
|
||||
case DNSCAP_EXT_IS_RESPONDER:
|
||||
rzkeychange_is_responder = (is_responder_t)arg;
|
||||
break;
|
||||
case DNSCAP_EXT_IA_STR:
|
||||
rzkeychange_ia_str = (ia_str_t)arg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void rzkeychange_getopt(int* argc, char** argv[])
|
||||
{
|
||||
int c;
|
||||
while ((c = getopt(*argc, *argv, "?a:k:n:p:s:tz:D")) != EOF) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
if (report_node)
|
||||
free(report_node);
|
||||
report_node = strdup(optarg);
|
||||
if (!report_node) {
|
||||
fprintf(stderr, "strdup() out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (report_server)
|
||||
free(report_server);
|
||||
report_server = strdup(optarg);
|
||||
if (!report_server) {
|
||||
fprintf(stderr, "strdup() out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'z':
|
||||
if (report_zone)
|
||||
free(report_zone);
|
||||
report_zone = strdup(optarg);
|
||||
if (!report_zone) {
|
||||
fprintf(stderr, "strdup() out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
if (keytag_zone)
|
||||
free(keytag_zone);
|
||||
keytag_zone = strdup(optarg);
|
||||
if (!keytag_zone) {
|
||||
fprintf(stderr, "strdup() out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
if (num_ns_addrs < MAX_NAMESERVERS) {
|
||||
ns_addrs[num_ns_addrs] = strdup(optarg);
|
||||
if (!ns_addrs[num_ns_addrs]) {
|
||||
fprintf(stderr, "strdup() out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
num_ns_addrs++;
|
||||
} else {
|
||||
fprintf(stderr, "too many nameservers\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
resolver_port = strtoul(optarg, 0, 10);
|
||||
break;
|
||||
case 't':
|
||||
resolver_use_tcp = 1;
|
||||
break;
|
||||
case 'D':
|
||||
dry_run = 1;
|
||||
break;
|
||||
case '?':
|
||||
rzkeychange_usage();
|
||||
if (!optopt || optopt == '?') {
|
||||
exit(0);
|
||||
}
|
||||
// fallthrough
|
||||
default:
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (!report_zone || !report_server || !report_node) {
|
||||
rzkeychange_usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
ldns_pkt*
|
||||
dns_query(const char* name, ldns_rr_type type)
|
||||
{
|
||||
fprintf(stderr, "%s\n", name);
|
||||
if (dry_run) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ldns_rdf* domain = ldns_dname_new_frm_str(name);
|
||||
if (0 == domain) {
|
||||
fprintf(stderr, "bad query name: '%s'\n", name);
|
||||
exit(1);
|
||||
}
|
||||
ldns_pkt* pkt = ldns_resolver_query(res,
|
||||
domain,
|
||||
type,
|
||||
LDNS_RR_CLASS_IN,
|
||||
LDNS_RD);
|
||||
ldns_rdf_deep_free(domain);
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void
|
||||
add_resolver_nameserver(const char* s)
|
||||
{
|
||||
ldns_rdf* nsaddr;
|
||||
fprintf(stderr, "adding nameserver '%s' to resolver config\n", s);
|
||||
if (strchr(s, ':'))
|
||||
nsaddr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA, s);
|
||||
else
|
||||
nsaddr = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A, s);
|
||||
if (!nsaddr) {
|
||||
logerr("rzkeychange.so: invalid IP address '%s'", s);
|
||||
exit(1);
|
||||
}
|
||||
assert(LDNS_STATUS_OK == ldns_resolver_push_nameserver(res, nsaddr));
|
||||
}
|
||||
|
||||
int rzkeychange_start(logerr_t* a_logerr)
|
||||
{
|
||||
ldns_pkt* pkt;
|
||||
struct timeval to;
|
||||
char qname[256];
|
||||
logerr = a_logerr;
|
||||
if (LDNS_STATUS_OK != ldns_resolver_new_frm_file(&res, NULL)) {
|
||||
fprintf(stderr, "Failed to initialize ldns resolver\n");
|
||||
exit(1);
|
||||
}
|
||||
if (num_ns_addrs) {
|
||||
unsigned int i;
|
||||
ldns_resolver_set_nameserver_count(res, 0);
|
||||
for (i = 0; i < num_ns_addrs; i++)
|
||||
add_resolver_nameserver(ns_addrs[i]);
|
||||
}
|
||||
if (0 == ldns_resolver_nameserver_count(res))
|
||||
add_resolver_nameserver("127.0.0.1");
|
||||
if (resolver_port)
|
||||
ldns_resolver_set_port(res, resolver_port);
|
||||
if (resolver_use_tcp)
|
||||
ldns_resolver_set_usevc(res, 1);
|
||||
|
||||
if (dry_run) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Testing reachability of zone '%s'\n", report_zone);
|
||||
pkt = dns_query(report_zone, LDNS_RR_TYPE_TXT);
|
||||
if (!pkt) {
|
||||
fprintf(stderr, "Test of zone '%s' failed\n", report_zone);
|
||||
exit(1);
|
||||
}
|
||||
if (0 != ldns_pkt_get_rcode(pkt)) {
|
||||
fprintf(stderr, "Query to zone '%s' returned rcode %d\n", report_zone, ldns_pkt_get_rcode(pkt));
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "Success.\n");
|
||||
if (pkt)
|
||||
ldns_pkt_free(pkt);
|
||||
/*
|
||||
* For all subsequent queries we don't actually care about the response
|
||||
* and don't wait to wait very long for it so the timeout is set really low.
|
||||
*/
|
||||
to.tv_sec = 0;
|
||||
to.tv_usec = 500000;
|
||||
ldns_resolver_set_timeout(res, to);
|
||||
snprintf(qname, sizeof(qname), "ts-elapsed-tot-dnskey-tcp-tc-unreachfrag-texcfrag-texcttl.%s.%s.%s", report_node, report_server, report_zone);
|
||||
pkt = dns_query(qname, LDNS_RR_TYPE_TXT);
|
||||
if (pkt)
|
||||
ldns_pkt_free(pkt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rzkeychange_stop()
|
||||
{
|
||||
}
|
||||
|
||||
int rzkeychange_open(my_bpftimeval ts)
|
||||
{
|
||||
open_ts = clos_ts.tv_sec ? clos_ts : ts;
|
||||
memset(&counts, 0, sizeof(counts));
|
||||
memset(&key_tag_signals, 0, sizeof(key_tag_signals));
|
||||
num_key_tag_signals = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rzkeychange_submit_counts(void)
|
||||
{
|
||||
char qname[256];
|
||||
ldns_pkt* pkt;
|
||||
double elapsed = (double)clos_ts.tv_sec - (double)open_ts.tv_sec + 0.000001 * clos_ts.tv_usec - 0.000001 * open_ts.tv_usec; //NOSONAR
|
||||
int k;
|
||||
|
||||
k = snprintf(qname, sizeof(qname), "%lu-%u-%" PRIu64 "-%" PRIu64 "-%" PRIu64 "-%" PRIu64 "-%" PRIu64 "-%" PRIu64 "-%" PRIu64 ".%s.%s.%s",
|
||||
(u_long)open_ts.tv_sec,
|
||||
(unsigned int)(elapsed + 0.5),
|
||||
counts.total,
|
||||
counts.dnskey,
|
||||
counts.tcp,
|
||||
counts.tc_bit,
|
||||
counts.icmp_unreach_frag,
|
||||
counts.icmp_timxceed_reass,
|
||||
counts.icmp_timxceed_intrans,
|
||||
report_node,
|
||||
report_server,
|
||||
report_zone);
|
||||
|
||||
if (k < sizeof(qname)) {
|
||||
pkt = dns_query(qname, LDNS_RR_TYPE_TXT);
|
||||
if (pkt)
|
||||
ldns_pkt_free(pkt);
|
||||
}
|
||||
|
||||
if (keytag_zone != 0) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_key_tag_signals; i++) {
|
||||
char* s = strdup(rzkeychange_ia_str(key_tag_signals[i].addr));
|
||||
char* t;
|
||||
|
||||
if (0 == s) {
|
||||
/*
|
||||
* Apparently out of memory. This function is called in
|
||||
* a child process which will exit right after this we
|
||||
* break from the loop and return from this function.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
for (t = s; *t; t++)
|
||||
if (*t == '.' || *t == ':')
|
||||
*t = '-';
|
||||
|
||||
k = snprintf(qname, sizeof(qname), "%lu.%s.%hhx.%s.%s.%s.%s",
|
||||
(u_long)open_ts.tv_sec,
|
||||
s,
|
||||
key_tag_signals[i].flags,
|
||||
key_tag_signals[i].signal,
|
||||
report_node,
|
||||
report_server,
|
||||
keytag_zone);
|
||||
free(s);
|
||||
|
||||
if (k >= sizeof(qname))
|
||||
continue; // qname was truncated in snprintf()
|
||||
|
||||
pkt = dns_query(qname, LDNS_RR_TYPE_TXT);
|
||||
if (pkt)
|
||||
ldns_pkt_free(pkt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fork a separate process so that we don't block the main dnscap. Use
|
||||
* double-fork to avoid zombies for the main dnscap process.
|
||||
*/
|
||||
int rzkeychange_close(my_bpftimeval ts)
|
||||
{
|
||||
pid_t pid;
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
logerr("rzkeychange.so: fork: %s", strerror(errno));
|
||||
return 1;
|
||||
} else if (pid) {
|
||||
/* parent */
|
||||
waitpid(pid, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
/* 1st gen child continues */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
logerr("rzkeychange.so: fork: %s", strerror(errno));
|
||||
return 1;
|
||||
} else if (pid) {
|
||||
/* 1st gen child exits */
|
||||
exit(0);
|
||||
}
|
||||
/* grandchild (2nd gen) continues */
|
||||
clos_ts = ts;
|
||||
rzkeychange_submit_counts();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void rzkeychange_keytagsignal(const ldns_pkt* pkt, const ldns_rr* question_rr, iaddr addr)
|
||||
{
|
||||
ldns_rdf* qn;
|
||||
char* qn_str = 0;
|
||||
if (LDNS_RR_TYPE_NULL != ldns_rr_get_type(question_rr))
|
||||
return;
|
||||
if (num_key_tag_signals == MAX_KEY_TAG_SIGNALS)
|
||||
return;
|
||||
qn = ldns_rr_owner(question_rr);
|
||||
if (qn == 0)
|
||||
return;
|
||||
qn_str = ldns_rdf2str(qn);
|
||||
if (qn_str == 0)
|
||||
return;
|
||||
if (0 != strncasecmp(qn_str, "_ta-", 4))
|
||||
goto keytagsignal_done;
|
||||
qn_str[strlen(qn_str) - 1] = 0; // ldns always adds terminating dot
|
||||
if (strchr(qn_str, '.')) // dont want non-root keytag signals
|
||||
goto keytagsignal_done;
|
||||
key_tag_signals[num_key_tag_signals].addr = addr;
|
||||
key_tag_signals[num_key_tag_signals].signal = strdup(qn_str);
|
||||
assert(key_tag_signals[num_key_tag_signals].signal);
|
||||
if (ldns_pkt_rd(pkt))
|
||||
key_tag_signals[num_key_tag_signals].flags |= KEYTAG_FLAG_RD;
|
||||
if (ldns_pkt_cd(pkt))
|
||||
key_tag_signals[num_key_tag_signals].flags |= KEYTAG_FLAG_CD;
|
||||
if (ldns_pkt_edns_do(pkt))
|
||||
key_tag_signals[num_key_tag_signals].flags |= KEYTAG_FLAG_DO;
|
||||
num_key_tag_signals++;
|
||||
keytagsignal_done:
|
||||
if (qn_str)
|
||||
free(qn_str);
|
||||
}
|
||||
|
||||
void rzkeychange_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)
|
||||
{
|
||||
ldns_pkt* pkt = 0;
|
||||
ldns_rr_list* question_rr_list = 0;
|
||||
ldns_rr* question_rr = 0;
|
||||
if (!(flags & DNSCAP_OUTPUT_ISDNS)) {
|
||||
if (IPPROTO_ICMP == proto && payloadlen >= 4) {
|
||||
struct icmp* icmp;
|
||||
if (rzkeychange_is_responder && !rzkeychange_is_responder(to))
|
||||
goto done;
|
||||
icmp = (void*)payload;
|
||||
if (ICMP_UNREACH == icmp->icmp_type) {
|
||||
if (ICMP_UNREACH_NEEDFRAG == icmp->icmp_code)
|
||||
counts.icmp_unreach_frag++;
|
||||
} else if (ICMP_TIMXCEED == icmp->icmp_type) {
|
||||
if (ICMP_TIMXCEED_INTRANS == icmp->icmp_code)
|
||||
counts.icmp_timxceed_intrans++;
|
||||
else if (ICMP_TIMXCEED_REASS == icmp->icmp_code)
|
||||
counts.icmp_timxceed_reass++;
|
||||
}
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
if (LDNS_STATUS_OK != ldns_wire2pkt(&pkt, payload, payloadlen))
|
||||
return;
|
||||
if (0 == ldns_pkt_qr(pkt))
|
||||
goto done;
|
||||
counts.total++;
|
||||
if (IPPROTO_UDP == proto) {
|
||||
if (0 != ldns_pkt_tc(pkt))
|
||||
counts.tc_bit++;
|
||||
} else if (IPPROTO_TCP == proto) {
|
||||
counts.tcp++;
|
||||
}
|
||||
if (LDNS_PACKET_QUERY != ldns_pkt_get_opcode(pkt))
|
||||
goto done;
|
||||
question_rr_list = ldns_pkt_question(pkt);
|
||||
if (0 == question_rr_list)
|
||||
goto done;
|
||||
question_rr = ldns_rr_list_rr(question_rr_list, 0);
|
||||
if (0 == question_rr)
|
||||
goto done;
|
||||
if (LDNS_RR_CLASS_IN == ldns_rr_get_class(question_rr))
|
||||
if (LDNS_RR_TYPE_DNSKEY == ldns_rr_get_type(question_rr))
|
||||
counts.dnskey++;
|
||||
if (keytag_zone != 0)
|
||||
rzkeychange_keytagsignal(pkt, question_rr, to); // 'to' here because plugin should be processing responses
|
||||
done:
|
||||
ldns_pkt_free(pkt);
|
||||
}
|
21
plugins/rzkeychange/test1.sh
Executable file
21
plugins/rzkeychange/test1.sh
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/bin/sh -xe
|
||||
|
||||
plugin=`find . -name 'rzkeychange.so' | head -n 1`
|
||||
if [ -z "$plugin" ]; then
|
||||
echo "Unable to find the rzkeychange plugin"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ln -fs "$srcdir/../../src/test/dns.pcap" dns.pcap-dist
|
||||
|
||||
../../src/dnscap -r dns.pcap-dist -g -P "$plugin" -?
|
||||
! ../../src/dnscap -r dns.pcap-dist -g -P "$plugin" -X
|
||||
! ../../src/dnscap -r dns.pcap-dist -g -P "$plugin" -n text -n text
|
||||
! ../../src/dnscap -r dns.pcap-dist -g -P "$plugin" -s text -s text
|
||||
! ../../src/dnscap -r dns.pcap-dist -g -P "$plugin" -z text -z text
|
||||
! ../../src/dnscap -r dns.pcap-dist -g -P "$plugin" -k text -k text
|
||||
! ../../src/dnscap -r dns.pcap-dist -g -P "$plugin" -a 1 -a 2 -a 3 -a 4 -a 5 -a 6 -a 7 -a 8 -a 9 -a 10 -a 11
|
||||
|
||||
# LDNS resolver needs /etc/resolv.conf
|
||||
test -f /etc/resolv.conf || exit 0
|
||||
../../src/dnscap -r dns.pcap-dist -g -P "$plugin" -D -t -p 5353 -a 127.0.0.1 -n n -s s -z example.com -k k
|
Loading…
Add table
Add a link
Reference in a new issue