summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordu.net>2016-03-30 21:35:31 +0200
committerLinus Nordberg <linus@nordu.net>2016-04-07 16:06:12 +0200
commit781201c780419377005f358b20017ba9d6edc288 (patch)
treead2c29207e77873a5e15c8d54c3bd3ecf502af97
parent5cf67186d026fa5bf44ee296efe81052c4b9e487 (diff)
Add validatechain.c and move some code to common.c.
dns-net2wire.c is nothing but an ugly hack on top of getdns_query.c making it save answer, validation_chain and trust anchors to three separate files. Used for testing purposes. validatechain takes the above mentioned three files as input and performs DNSSEC validation.
-rw-r--r--tools/dnssec/Makefile16
-rw-r--r--tools/dnssec/common.c201
-rw-r--r--tools/dnssec/common.h5
-rw-r--r--tools/dnssec/dns-net2wire.c80
-rw-r--r--tools/dnssec/dns-wire2text.c62
-rw-r--r--tools/dnssec/net2wire.c105
-rw-r--r--tools/dnssec/validatechain.c110
7 files changed, 401 insertions, 178 deletions
diff --git a/tools/dnssec/Makefile b/tools/dnssec/Makefile
index 7009220..7c3f2fb 100644
--- a/tools/dnssec/Makefile
+++ b/tools/dnssec/Makefile
@@ -1,12 +1,14 @@
CFLAGS = -Wall -g -std=c99
CFLAGS_PEDANTIC = -pedantic -Werror -Wextra
-all: dns-net2wire dns-wire2text
+all: dns-net2wire dns-wire2text net2wire validatechain
-dns-net2wire: dns-net2wire.c
- $(CC) $(CFLAGS) -o $@ -lgetdns -lgetdns_ext_event -levent $<
-dns-wire2text: dns-wire2text.c
- $(CC) $(CFLAGS) $(CFLAGS_PEDANTIC) -o $@ -lgetdns -lgetdns_ext_event -levent $<
+dns-net2wire: dns-net2wire.c common.c
+ $(CC) $(CFLAGS) -o $@ -lgetdns -lgetdns_ext_event -levent $^
+dns-wire2text: dns-wire2text.c common.c
+ $(CC) $(CFLAGS) $(CFLAGS_PEDANTIC) -o $@ -lgetdns -lgetdns_ext_event -levent $^
+validatechain: validatechain.c common.c
+ $(CC) $(CFLAGS) -o $@ -lgetdns -lgetdns_ext_event -levent $^
-net2wire: net2wire.c
- $(CC) $(CFLAGS) -I ~/usr/include -L ~/usr/lib -o $@ -lgetdns -lgetdns_ext_event -levent $<
+net2wire: net2wire.c common.c
+ $(CC) $(CFLAGS) -I ~/usr/include -L ~/usr/lib -o $@ -lgetdns -lgetdns_ext_event -levent $^
diff --git a/tools/dnssec/common.c b/tools/dnssec/common.c
new file mode 100644
index 0000000..4382a1d
--- /dev/null
+++ b/tools/dnssec/common.c
@@ -0,0 +1,201 @@
+#include <string.h>
+#include <errno.h>
+#include <getdns/getdns.h>
+#include <getdns/getdns_ext_libevent.h>
+
+static int debug = 0;
+
+static getdns_return_t
+dump_reply(FILE *fp, getdns_dict *reply, const char *section_name)
+{
+ getdns_list *section = NULL;
+ size_t section_len = -1;
+ getdns_return_t r;
+ uint8_t *res = NULL;
+ size_t res_len;
+
+ r = getdns_dict_get_list(reply, section_name, &section);
+ if (r) {
+ fprintf(stderr,
+ "unable to get section \"%s\" from reply\n",
+ section_name);
+ return r;
+ }
+
+ r = getdns_list_get_length(section, &section_len);
+ if (r) {
+ fprintf(stderr, "unable to get length of section\n");
+ return r;
+ }
+
+ for (size_t j = 0; j < section_len; j++) {
+ getdns_dict *rr = NULL;
+
+ r = getdns_list_get_dict(section, j , &rr);
+ if (r) {
+ fprintf(stderr, "unable to get rr from entry "
+ "%d: %d\n", j, r);
+ return r;
+ }
+
+ r = getdns_rr_dict2wire(rr, &res, &res_len);
+ if (r) {
+ fprintf(stderr,
+ "unable to convert entry %d "
+ "to wire format: %d\n", j, r);
+ return r;
+ }
+
+ if (0 && debug) {
+ char *s = getdns_pretty_print_dict(rr);
+ puts(s);
+ free(s);
+ }
+
+ if (fwrite(res, 1, res_len, fp) != res_len) {
+ fprintf(stderr,
+ "unable to write buffer to file: %s\n",
+ strerror(errno));
+ return -errno;
+ }
+
+ free(res);
+ }
+
+ return 0;
+}
+
+int
+dump_tree(FILE *fp, const getdns_dict *response, const char *tree_name, const char *section_name)
+{
+ getdns_return_t r;
+ getdns_list *tree = NULL;
+ size_t n_replies = -1;
+
+ r = getdns_dict_get_list(response, tree_name, &tree);
+ if (r) {
+ fprintf(stderr, "unable to get tree %s\n", tree_name);
+ return r;
+ }
+
+ if (section_name == NULL) {
+ size_t tree_len = 0;
+ r = getdns_list_get_length(tree, &tree_len);
+ if (r) {
+ fprintf(stderr, "unable to get tree length\n");
+ return r;
+ }
+ for (size_t i = 0; i < tree_len; i++) {
+ getdns_dict *rr = NULL;
+ r = getdns_list_get_dict(tree, i , &rr);
+ if (r) {
+ fprintf(stderr, "unable to get rr from entry %d: %d\n", i, r);
+ return r;
+ }
+ uint8_t *res = NULL;
+ size_t res_len = 0;
+ r = getdns_rr_dict2wire(rr, &res, &res_len);
+ if (r) {
+ fprintf(stderr,
+ "unable to convert entry %d "
+ "to wire format: %d\n", i, r);
+ return r;
+ }
+ if (fwrite(res, 1, res_len, fp) != res_len) {
+ fprintf(stderr,
+ "unable to write buffer to file: %s\n",
+ strerror(errno));
+ return errno;
+ }
+ free(res);
+ }
+ } else {
+ r = getdns_list_get_length(tree, &n_replies);
+ if (r) {
+ fprintf(stderr, "unable to get number of replies\n");
+ return r;
+ }
+
+ for (size_t i = 0; i < n_replies; i++) {
+ getdns_dict *reply = NULL;
+
+ r = getdns_list_get_dict(tree, i, &reply);
+ if (r) {
+ fprintf(stderr, "unable to get reply %d from tree\n", i);
+ return r;
+ }
+
+ if (debug) {
+ char *s = getdns_pretty_print_dict(reply);
+ printf("Pretty-printing reply #%d:%s\n", i, s);
+ free(s);
+ }
+
+ dump_reply(fp, reply, section_name);
+ }
+ }
+
+ return 0;
+}
+
+#define CHUNKSIZE 4096
+
+size_t
+read_buffer(FILE *infp, uint8_t **bufp_out, size_t size_hint)
+{
+ size_t nread = 0;
+ uint8_t *wirebuf = NULL;
+ size_t chunksize = CHUNKSIZE;
+ int chunks = 1;
+
+ if (size_hint > 0)
+ chunksize = size_hint;
+ wirebuf = malloc(chunksize);
+
+ if (wirebuf == NULL)
+ goto out;
+
+ while (1)
+ {
+ size_t n = fread(wirebuf + nread, 1, chunksize, infp);
+ nread += n;
+ if (n < chunksize)
+ break; /* Done. */
+
+ wirebuf = realloc(wirebuf, ++chunks * chunksize);
+ if (wirebuf == NULL)
+ break;
+ }
+
+ out:
+ if (bufp_out != NULL)
+ *bufp_out = wirebuf;
+ return nread;
+}
+
+getdns_return_t
+wire_rrs2list(const uint8_t *buf, size_t buf_len, getdns_list **list_out)
+{
+ getdns_return_t r = GETDNS_RETURN_GOOD;
+ getdns_list *list = getdns_list_create();
+ getdns_dict *dict = NULL;
+ size_t rr_count = 0;
+
+ if (list == NULL)
+ return GETDNS_RETURN_MEMORY_ERROR;
+ while (buf_len > 0)
+ {
+ r = getdns_wire2rr_dict_scan(&buf, &buf_len, &dict);
+ if (r)
+ break;
+ r = getdns_list_set_dict(list, rr_count, dict);
+ getdns_dict_destroy(dict); /* The list has a copy. */
+ if (r)
+ break;
+ rr_count++;
+ }
+
+ if (list_out)
+ *list_out = list;
+ return r;
+}
diff --git a/tools/dnssec/common.h b/tools/dnssec/common.h
new file mode 100644
index 0000000..465379d
--- /dev/null
+++ b/tools/dnssec/common.h
@@ -0,0 +1,5 @@
+int dump_tree(FILE *fp, const getdns_dict *response, const char *tree_name, const char *section_name);
+size_t read_buffer(FILE *infp, uint8_t **bufp_out, size_t size_hint);
+getdns_return_t wire_rrs2list(const uint8_t *buf, size_t buf_len, getdns_list **list_out);
+
+
diff --git a/tools/dnssec/dns-net2wire.c b/tools/dnssec/dns-net2wire.c
index c193139..0e5003d 100644
--- a/tools/dnssec/dns-net2wire.c
+++ b/tools/dnssec/dns-net2wire.c
@@ -20,6 +20,7 @@
#include <arpa/inet.h>
#include <getdns/getdns.h>
#include <getdns/getdns_extra.h>
+#include "common.h"
#define DEBUG_SCHED(...)
@@ -1140,6 +1141,53 @@ next: ;
return r;
}
+static void
+dump_ta(FILE *fp)
+{
+ getdns_list *trust_anchors = NULL;
+ getdns_return_t r = 0;
+ if ((r = getdns_context_get_dnssec_trust_anchors(
+ context, &trust_anchors))
+ || trust_anchors == NULL) {
+ fprintf(stderr, "Unable to get trust anchors: %s\n",
+ getdns_get_errorstr_by_id(r));
+ return;
+ }
+
+ size_t list_len = 0;
+ r = getdns_list_get_length(trust_anchors, &list_len);
+ if (r) {
+ fprintf(stderr, "unable to get length of trust_anchors\n");
+ return;
+ }
+
+ for (size_t i = 0; i < list_len; i++) {
+ getdns_dict *rr = NULL;
+ uint8_t *res = NULL;
+ size_t res_len;
+ r = getdns_list_get_dict(trust_anchors, i , &rr);
+ if (r) {
+ fprintf(stderr, "unable to get rr from entry "
+ "%d: %d\n", i, r);
+ return;
+ }
+
+ r = getdns_rr_dict2wire(rr, &res, &res_len);
+ if (r) {
+ fprintf(stderr,
+ "unable to convert entry %d "
+ "to wire format: %d\n", i, r);
+ return;
+ }
+
+ if (fwrite(res, 1, res_len, fp) != res_len)
+ fprintf(stderr, "Could not write trust anchor to file\n");
+ }
+}
+
+
+FILE *support_out_fp = NULL;
+
getdns_return_t do_the_call(void)
{
getdns_return_t r;
@@ -1223,18 +1271,28 @@ getdns_return_t do_the_call(void)
, "Could not print response\n");
}
}
-#if 1
- FILE *support_out_fp = fopen("treeout_support", "w");
- assert(support_out_fp);
getdns_list *validation_chain = NULL;
if ((r = getdns_dict_get_list(
- response, "validation_chain", &validation_chain)))
- assert(!r && "get_list validation_chain");
- if (response && support_out_fp) {
- ; //fwrite(support_out_fp, fixme, fixme_len);
+ response, "validation_chain", &validation_chain))) {
+ fprintf(stderr, "get_list validation_chain: %d (%s)\n",
+ r, getdns_get_errorstr_by_id(r));
+ exit(1);
}
- fclose(support_out_fp);
-#endif
+
+ if (dump_tree(support_out_fp, response, "validation_chain", NULL))
+ fprintf(stderr, "Could not dump %s to file\n", "validation_chain");
+
+ FILE *tree_out_fp = fopen("treeout", "w");
+ assert(tree_out_fp);
+ if (dump_tree(tree_out_fp, response, "replies_tree", "answer"))
+ fprintf(stderr, "Could not dump %s to file\n", "replies_tree");
+ if (fclose(tree_out_fp)) assert(0);
+
+ FILE *tree_out_ta = fopen("treeout_ta", "w");
+ assert(tree_out_ta);
+ dump_ta(tree_out_ta);
+ if (fclose(tree_out_ta)) assert(0);
+
getdns_dict_get_int(response, "status", &status);
fprintf(stdout, "Response code was: GOOD. Status was: %s\n",
getdns_get_errorstr_by_id(status));
@@ -1327,6 +1385,9 @@ main(int argc, char **argv)
} else
fp = stdin;
+ support_out_fp = fopen("treeout_support", "w");
+ assert(support_out_fp);
+
/* Make the call */
if (interactive) {
getdns_eventloop_event read_line_ev = {
@@ -1346,6 +1407,7 @@ main(int argc, char **argv)
getdns_context_run(context);
/* Clean up */
+ fclose(support_out_fp);
getdns_dict_destroy(extensions);
done_destroy_context:
getdns_context_destroy(context);
diff --git a/tools/dnssec/dns-wire2text.c b/tools/dnssec/dns-wire2text.c
index 896fc6e..1443bc4 100644
--- a/tools/dnssec/dns-wire2text.c
+++ b/tools/dnssec/dns-wire2text.c
@@ -9,6 +9,7 @@
#include <errno.h>
#include <getdns/getdns.h>
#include <getdns/getdns_extra.h>
+#include "common.h"
#undef DEBUG
@@ -34,63 +35,6 @@ hd(const char *buf, size_t buf_len)
#define hd(a,b)
#endif
-#define CHUNKSIZE 4096
-
-static size_t
-read_inbuf(FILE *infp, uint8_t **bufp_out)
-{
- size_t nread = 0;
- uint8_t *wirebuf = malloc(CHUNKSIZE);
- int chunks = 1;
-
- if (wirebuf == NULL)
- goto out;
-
- while (1)
- {
- size_t n = fread(wirebuf + nread, 1, CHUNKSIZE, infp);
- nread += n;
- if (n < CHUNKSIZE)
- break; /* Done. */
-
- wirebuf = realloc(wirebuf, ++chunks * CHUNKSIZE);
- if (wirebuf == NULL)
- break;
- }
-
- out:
- if (bufp_out != NULL)
- *bufp_out = wirebuf;
- return nread;
-}
-
-static getdns_return_t
-wire_rrs2list(const uint8_t *buf, size_t buf_len, getdns_list **list_out)
-{
- getdns_return_t r = GETDNS_RETURN_GOOD;
- getdns_list *list = getdns_list_create();
- getdns_dict *dict = NULL;
- size_t rr_count = 0;
-
- if (list == NULL)
- return GETDNS_RETURN_MEMORY_ERROR;
- while (buf_len > 0)
- {
- r = getdns_wire2rr_dict_scan(&buf, &buf_len, &dict);
- if (r)
- break;
- r = getdns_list_set_dict(list, rr_count, dict);
- getdns_dict_destroy(dict); /* The list has a copy. */
- if (r)
- break;
- rr_count++;
- }
-
- if (list_out)
- *list_out = list;
- return r;
-}
-
int
main(int argc, char *argv[])
{
@@ -108,10 +52,10 @@ main(int argc, char *argv[])
/* Read RRs in wire format. */
uint8_t *inbuf = NULL;
- size_t inbuf_len = read_inbuf(infp, &inbuf);
+ size_t inbuf_len = read_buffer(infp, &inbuf, 0);
if (inbuf == NULL)
{
- perror("read_inbuf");
+ perror("read_buffer");
return errno;
}
if (infp != stdin)
diff --git a/tools/dnssec/net2wire.c b/tools/dnssec/net2wire.c
index f97483f..bbf1269 100644
--- a/tools/dnssec/net2wire.c
+++ b/tools/dnssec/net2wire.c
@@ -22,108 +22,7 @@
#include <getdns/getdns_ext_libevent.h>
#include <event2/event.h>
-static int debug = 1;
-
-static getdns_return_t
-dump_reply(FILE *fp, getdns_dict *reply, const char *section_name)
-{
- getdns_list *section = NULL;
- size_t section_len = -1;
- getdns_return_t r;
- uint8_t res_buf[4096], *res = NULL;
- size_t res_len = sizeof(res_buf);
-
- r = getdns_dict_get_list(reply, section_name, &section);
- if (r) {
- fprintf(stderr,
- "unable to get section \"%s\" from reply\n",
- section_name);
- return r;
- }
-
- r = getdns_list_get_length(section, &section_len);
- if (r) {
- fprintf(stderr, "unable to get length of section\n");
- return r;
- }
-
- for (size_t j = 0; j < section_len; j++) {
- getdns_dict *rr = NULL;
-
- r = getdns_list_get_dict(section, j , &rr);
- if (r) {
- fprintf(stderr, "unable to get rr from entry "
- "%d: %d\n", j, r);
- return r;
- }
-
- r = getdns_rr_dict2wire(rr, &res, &res_len);
- if (r) {
- fprintf(stderr,
- "unable to convert entry %d "
- "to wire format: %d\n", j, r);
- return r;
- }
-
- if (0 && debug) {
- char *s = getdns_pretty_print_dict(rr);
- puts(s);
- free(s);
- }
-
- if (fwrite(res, 1, res_len, fp) != res_len) {
- fprintf(stderr,
- "unable to write buffer to file: %s\n",
- strerror(errno));
- return -errno;
- }
-
- free(res);
- }
-
- return 0;
-}
-
-int
-dump_tree(FILE *fp, const getdns_dict *response, const char *tree_name)
-{
- getdns_return_t r;
- getdns_list *tree = NULL;
- size_t n_replies = -1;
-
- r = getdns_dict_get_list(response, tree_name, &tree);
- if (r) {
- fprintf(stderr, "unable to get tree %s\n", tree_name);
- return r;
- }
-
- r = getdns_list_get_length(tree, &n_replies);
- if (r) {
- fprintf(stderr, "unable to get number of replies\n");
- return r;
- }
-
- for (size_t i = 0; i < n_replies; i++) {
- getdns_dict *reply = NULL;
-
- r = getdns_list_get_dict(tree, i, &reply);
- if (r) {
- fprintf(stderr, "unable to get reply %d from tree\n", i);
- return r;
- }
-
- if (debug) {
- char *s = getdns_pretty_print_dict(reply);
- printf("Pretty-printing reply #%d:%s\n", i, s);
- free(s);
- }
-
- dump_reply(fp, reply, "answer");
- }
-
- return 0;
-}
-
+#include "common.h"
/* Set up the callback function, which will also do the processing of the results */
void callback(getdns_context *context,
@@ -171,7 +70,7 @@ void callback(getdns_context *context,
static char *TREES[] = {"replies_tree", "validation_chain"};
static const int TREES_LEN = 2;
for (int i = 0; i < TREES_LEN; i++) {
- if (dump_tree(treeoutfp, response, TREES[i]))
+ if (dump_tree(treeoutfp, response, TREES[i], "answer"))
fprintf(stderr, "Could not dump %s to file\n", TREES[i]);
else if ((r = getdns_dict_get_bindata(response, "/just_address_answers/0/address_data", &address_data)))
diff --git a/tools/dnssec/validatechain.c b/tools/dnssec/validatechain.c
new file mode 100644
index 0000000..1ecf5f7
--- /dev/null
+++ b/tools/dnssec/validatechain.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <time.h>
+#include <getdns/getdns.h>
+#include <getdns/getdns_extra.h>
+#include "common.h"
+
+static getdns_return_t
+validate(const uint8_t *records_buf, size_t records_len,
+ const uint8_t *support_buf, size_t support_len,
+ const uint8_t *trust_anchors_buf, size_t trust_anchors_len,
+ time_t validation_time, uint32_t skew)
+{
+ getdns_return_t r = GETDNS_DNSSEC_INDETERMINATE;
+
+ getdns_list *to_validate = NULL;
+ if ((r = wire_rrs2list(records_buf, records_len, &to_validate)))
+ goto out;
+
+ getdns_list *support_records = NULL;
+ if ((r = wire_rrs2list(support_buf, support_len, &support_records)))
+ goto out;
+
+ getdns_list *trust_anchors = NULL;
+ if ((r = wire_rrs2list(trust_anchors_buf, trust_anchors_len, &trust_anchors)))
+ goto out;
+
+ /*
+ to_validate: The DS and an RRSIG for that DS.
+
+ support_records: DS's and DNSKEY's with accompanying RRSIG's.
+
+ trust_anchors: DNSKEY's (or DS?).
+ */
+
+ r = getdns_validate_dnssec2(to_validate,
+ support_records,
+ trust_anchors,
+ validation_time,
+ skew);
+
+out:
+ if (to_validate)
+ getdns_list_destroy(to_validate);
+ if (support_records)
+ getdns_list_destroy(support_records);
+ if (trust_anchors)
+ getdns_list_destroy(trust_anchors);
+
+ return r;
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: dns-validatechain to-validate-file "
+ "support-records-file [trust-anchors-file]\n");
+}
+
+static int
+read_file(const char *filename, uint8_t **out, size_t *out_len)
+{
+ FILE *fp = fopen(filename, "r");
+
+ if (fp == NULL)
+ return errno;
+ *out_len = read_buffer(fp, out, *out_len);
+ if (fclose(fp)) assert(0);
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ if (argc < 4) {
+ usage();
+ exit(1);
+ }
+
+ uint8_t *tv = NULL;
+ size_t tv_len = 8 * 1024;
+ if (read_file(argv[1], &tv, &tv_len))
+ assert(0);
+
+ uint8_t *sup = NULL;
+ size_t sup_len = 64 * 1024;
+ if (read_file(argv[2], &sup, &sup_len))
+ assert(0);
+
+ uint8_t *ta = NULL;
+ size_t ta_len = 4 * 1024;
+ if (read_file(argv[3], &ta, &ta_len))
+ assert(0);
+
+ getdns_return_t r = 0;
+ if ((r = validate(tv, tv_len,
+ sup, sup_len,
+ ta, ta_len,
+ time(NULL), 5)) != GETDNS_DNSSEC_SECURE) {
+ fprintf(stderr, "validation failed: %d (%s)\n",
+ r, getdns_get_errorstr_by_id(r));
+ return r;
+ }
+
+ return 0;
+}