summaryrefslogtreecommitdiffstats
path: root/src/dump_cds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dump_cds.c')
-rw-r--r--src/dump_cds.c1962
1 files changed, 1962 insertions, 0 deletions
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