From 177ee2046a9718c8005a0c303e2af2bc873b78e4 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Sat, 14 Feb 2015 21:42:25 +0100 Subject: [PATCH] Wireformat rdata field iterator --- src/Makefile.in | 5 +- src/rr-iter.c | 189 ++++++++++++++++++++++++++++++++------------ src/rr-iter.h | 37 ++++++++- src/util-internal.c | 34 ++++++-- 4 files changed, 204 insertions(+), 61 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 4b78abf3..a7d7df4e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -247,7 +247,8 @@ rr-dict.lo rr-dict.o: $(srcdir)/rr-dict.c $(srcdir)/rr-dict.h getdns/getdns.h $( $(srcdir)/getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/context.h config.h \ $(srcdir)/extension/libmini_event.h config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ $(srcdir)/types-internal.h $(srcdir)/dict.h -rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h getdns/getdns.h $(srcdir)/gldns/pkthdr.h +rr-iter.lo rr-iter.o: $(srcdir)/rr-iter.c $(srcdir)/rr-iter.h getdns/getdns.h $(srcdir)/rr-dict.h config.h \ + $(srcdir)/gldns/pkthdr.h $(srcdir)/gldns/gbuffer.h stub.lo stub.o: $(srcdir)/stub.c config.h $(srcdir)/stub.h getdns/getdns.h $(srcdir)/types-internal.h \ $(srcdir)/getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h $(srcdir)/gldns/gbuffer.h \ $(srcdir)/gldns/pkthdr.h $(srcdir)/context.h $(srcdir)/extension/libmini_event.h config.h \ @@ -262,7 +263,7 @@ util-internal.lo util-internal.o: $(srcdir)/util-internal.c getdns/getdns.h $(sr $(srcdir)/util-internal.h $(srcdir)/context.h config.h $(srcdir)/extension/libmini_event.h config.h \ $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h $(srcdir)/types-internal.h $(srcdir)/rr-dict.h \ $(srcdir)/gldns/wire2str.h $(srcdir)/gldns/str2wire.h $(srcdir)/gldns/rrdef.h $(srcdir)/gldns/gbuffer.h \ - $(srcdir)/gldns/pkthdr.h + $(srcdir)/gldns/pkthdr.h $(srcdir)/rr-iter.h gbuffer.lo gbuffer.o: $(srcdir)/gldns/gbuffer.c config.h $(srcdir)/gldns/gbuffer.h keyraw.lo keyraw.o: $(srcdir)/gldns/keyraw.c config.h $(srcdir)/gldns/keyraw.h $(srcdir)/gldns/rrdef.h parse.lo parse.o: $(srcdir)/gldns/parse.c config.h $(srcdir)/gldns/parse.h $(srcdir)/gldns/parseutil.h \ diff --git a/src/rr-iter.c b/src/rr-iter.c index abbd274a..4e331f78 100644 --- a/src/rr-iter.c +++ b/src/rr-iter.c @@ -34,46 +34,51 @@ #include #include +static void +rr_iter_find_nxt(priv_getdns_rr_iter *i) +{ + assert(i); + assert(i->rr_type); + + i->nxt = i->n < GLDNS_QDCOUNT(i->pkt) + ? i->rr_type + 4 + : i->rr_type + 10 > i->pkt_end + ? i->pkt_end + : i->rr_type + 10 + gldns_read_uint16(i->rr_type + 8) > i->pkt_end + ? i->pkt_end + : i->rr_type + 10 + gldns_read_uint16(i->rr_type + 8); +} + static priv_getdns_rr_iter * find_rrtype(priv_getdns_rr_iter *i) { - size_t dlen; uint8_t *pos; + assert(i); + assert(i->pos); + /* Past the last RR in the pkt */ if (GLDNS_QDCOUNT(i->pkt) + GLDNS_ANCOUNT(i->pkt) + - GLDNS_NSCOUNT(i->pkt) + GLDNS_ARCOUNT(i->pkt) <= i->n) { + GLDNS_NSCOUNT(i->pkt) + GLDNS_ARCOUNT(i->pkt) <= i->n) + goto done; - i->pos = NULL; - return NULL; - } - - /* This iterator was already done */ - if (!i->pos) - return NULL; - - pos = i->pos; - dlen = i->pkt_len - (pos - i->pkt); - - while (dlen >= 5) { /* At least space for type and class */ - - if (*pos == 0) { + for (pos = i->pos; pos + 4 < i->pkt_end; pos += *pos + 1) + if (!*pos) { i->rr_type = pos + 1; + rr_iter_find_nxt(i); return i; - } - if ((*pos & 0xC0) == 0xC0) { + + } else if ((*pos & 0xC0) == 0xC0) { + if ( pos + 6 > i->pkt_end) + break; /* No space for class */ + i->rr_type = pos + 2; + rr_iter_find_nxt(i); return i; - } - if ((*pos & 0xC0) != 0) + + } else if (*pos & 0xC0) break; /* Unknown label type */ - - if (*pos > dlen) - break; /* Label size overflows packet size! */ - - dlen -= *pos + 1; - pos += *pos + 1; - } +done: i->pos = NULL; return NULL; } @@ -81,11 +86,14 @@ find_rrtype(priv_getdns_rr_iter *i) priv_getdns_rr_iter * priv_getdns_rr_iter_init(priv_getdns_rr_iter *i, uint8_t *pkt, size_t pkt_len) { - if (pkt_len < GLDNS_HEADER_SIZE + 5) - return NULL; + assert(i); + if (pkt_len < GLDNS_HEADER_SIZE + 5) { + i->pos = NULL; + return NULL; + } i->pkt = pkt; - i->pkt_len = pkt_len; + i->pkt_end = pkt + pkt_len; i->n = 0; i->pos = pkt + GLDNS_HEADER_SIZE; @@ -96,31 +104,114 @@ priv_getdns_rr_iter_init(priv_getdns_rr_iter *i, uint8_t *pkt, size_t pkt_len) priv_getdns_rr_iter * priv_getdns_rr_iter_next(priv_getdns_rr_iter *i) { - size_t dlen; + assert(i); /* Already done */ if (!i->pos) return NULL; - assert(i->rr_type); - - i->n += 1; - - if (i->n <= GLDNS_QDCOUNT(i->pkt)) { - i->pos = i->rr_type + 4; - return find_rrtype(i); - } - - dlen = i->pkt_len - (i->rr_type - i->pkt); - if (dlen < 10) - goto garbage; /* No space for type, class, ttl & rdlength */ - - if (gldns_read_uint16(i->rr_type + 8) > dlen - 10) - goto garbage; /* RData size overflos packet size */ - - i->pos = i->rr_type + 10 + gldns_read_uint16(i->rr_type + 8); + i->n += 1; + i->pos = i->nxt; return find_rrtype(i); -garbage: +} + +static priv_getdns_rdf_iter * +rdf_iter_find_nxt(priv_getdns_rdf_iter *i) +{ + uint8_t *pos; + + assert(i); + assert(i->pos); + assert(i->rdd_pos); + + if (!i->rdd_repeat && (i->rdd_pos->type & GETDNS_RDF_REPEAT)) { + if (i->rdd_pos->type == GETDNS_RDF_REPEAT && + ++i->rdd_pos == i->rdd_end) + goto done; + i->rdd_repeat = i->rdd_pos; + } + if (i->rdd_pos->type & GETDNS_RDF_FIXEDSZ) + i->nxt = i->pos + (i->rdd_pos->type & GETDNS_RDF_FIXEDSZ); + + else if ((i->rdd_pos->type & GETDNS_RDF_LEN_VAL) == 0x100) + i->nxt = i->pos < i->end ? i->pos + *i->pos + 1 : i->end; + + else if ((i->rdd_pos->type & GETDNS_RDF_LEN_VAL) == 0x200) + i->nxt = i->pos + 1 < i->end + ? i->pos + gldns_read_uint16(i->pos) + 2 : i->end; + + else if ((i->rdd_pos->type & GETDNS_RDF_DNAME) == GETDNS_RDF_DNAME) + + for (pos = i->pos; pos < i->end; pos += *pos + 1) { + if (!*pos) { + i->nxt = pos + 1; + break; + } else if ((*pos & 0xC0) == 0xC0) { + i->nxt = pos + 2; + break; + } else if (*pos & 0xC0) /* Uknown label type */ + goto done; + } + else + i->nxt = i->end; + + if (i->nxt <= i->end) + return i; +done: + i->pos = NULL; + return NULL; +} + +priv_getdns_rdf_iter * +priv_getdns_rdf_iter_init(priv_getdns_rdf_iter *i, priv_getdns_rr_iter *rr) +{ + const priv_getdns_rr_def *rr_def; + + assert(i); + assert(rr); + + /* rr_iter already done or in question section */ + if (!rr->pos || rr->n < GLDNS_QDCOUNT(rr->pkt)) + goto done; + + i->pkt = rr->pkt; + i->pkt_end = rr->pkt_end; + rr_def = priv_getdns_rr_def_lookup(gldns_read_uint16(rr->rr_type)); + i->rdd_pos = rr_def->rdata; + i->rdd_end = rr_def->rdata + rr_def->n_rdata_fields; + + /* No rdata */ + if (i->rdd_pos == i->rdd_end) + goto done; + + /* No space to read rdata len */ + if (rr->rr_type + 10 >= rr->nxt) + goto done; + + i->rdd_repeat = NULL; + i->pos = rr->rr_type + 10; + i->end = rr->nxt; + + return rdf_iter_find_nxt(i); +done: + i->pos = NULL; + return NULL; +} + +priv_getdns_rdf_iter * +priv_getdns_rdf_iter_next(priv_getdns_rdf_iter *i) +{ + if (!i->pos) + return NULL; + + i->rdd_pos += 1; + if ((i->pos = i->nxt) >= i->end) + goto done; /* Out of rdata */ + if (i->rdd_pos >= i->rdd_end && !(i->rdd_pos = i->rdd_repeat)) + goto done; /* Remaining rdata, but out of definitions! */ + + return rdf_iter_find_nxt(i); +done: i->pos = NULL; return NULL; } diff --git a/src/rr-iter.h b/src/rr-iter.h index a07dae3e..1a59eec4 100644 --- a/src/rr-iter.h +++ b/src/rr-iter.h @@ -33,13 +33,28 @@ #define RR_ITER_H_ #include "getdns/getdns.h" +#include "rr-dict.h" typedef struct priv_getdns_rr_iter { uint8_t *pkt; - size_t pkt_len; - size_t n; /* Which RR are we currently at */ + uint8_t *pkt_end; + + /* Which RR are we currently at */ + size_t n; + + /* pos points to start of the owner name the RR. + * Or is NULL when there are no RR's left. + */ uint8_t *pos; + + /* rr_type will point to the rr_type right after the RR's owner name. + * rr_type is guaranteed to have a value when pos has a value + */ uint8_t *rr_type; + + /* nxt point to the owner name of the next RR or to pkt_end */ + uint8_t *nxt; + } priv_getdns_rr_iter; priv_getdns_rr_iter *priv_getdns_rr_iter_init(priv_getdns_rr_iter *i, @@ -47,6 +62,20 @@ priv_getdns_rr_iter *priv_getdns_rr_iter_init(priv_getdns_rr_iter *i, priv_getdns_rr_iter *priv_getdns_rr_iter_next(priv_getdns_rr_iter *i); -#endif +typedef struct piv_getdns_rdf_iter { + uint8_t *pkt; + uint8_t *pkt_end; + const priv_getdns_rdata_def *rdd_pos; + const priv_getdns_rdata_def *rdd_end; + const priv_getdns_rdata_def *rdd_repeat; + uint8_t *pos; + uint8_t *end; + uint8_t *nxt; +} priv_getdns_rdf_iter; -/* rrs.h */ +priv_getdns_rdf_iter *priv_getdns_rdf_iter_init(priv_getdns_rdf_iter *i, + priv_getdns_rr_iter *rr); + +priv_getdns_rdf_iter *priv_getdns_rdf_iter_next(priv_getdns_rdf_iter *i); + +#endif diff --git a/src/util-internal.c b/src/util-internal.c index 05fe1383..16124126 100644 --- a/src/util-internal.c +++ b/src/util-internal.c @@ -504,8 +504,13 @@ create_getdns_response(getdns_dns_req *completed_request) /* info (bools) about dns_req */ int dnssec_return_status; + +#if defined(WIRE_DEBUG) && WIRE_DEBUG char *str_pkt; priv_getdns_rr_iter rr_iter_storage, *rr_iter; + priv_getdns_rdf_iter rdf_spc, *rdf_iter; + int i; +#endif for ( netreq_p = completed_request->netreqs ; ! r && (netreq = *netreq_p) @@ -529,12 +534,29 @@ create_getdns_response(getdns_dns_req *completed_request) ; rr_iter ; rr_iter = priv_getdns_rr_iter_next(rr_iter)) { - fprintf( stderr, "n: %d, dname: %p, rr_type: %p " - "-> type: %d, class: %d\n" - , (int)rr_iter->n,rr_iter->pos,rr_iter->rr_type - , (int)gldns_read_uint16(rr_iter->rr_type) - , (int)gldns_read_uint16(rr_iter->rr_type + 2) - ); + fprintf( stderr, "%d (%p): %s\n" + , (int)rr_iter->n, rr_iter->pos + , priv_getdns_rr_def_lookup( + (int)gldns_read_uint16(rr_iter->rr_type) + )->name); + + i = 0; + for ( rdf_iter = priv_getdns_rdf_iter_init(&rdf_spc + , rr_iter) + ; rdf_iter + ; rdf_iter = priv_getdns_rdf_iter_next(rdf_iter)) { + + fprintf( stderr, "\t%d (%p): " + "len: %3d, left: %3d, " + "name: %s\n" + , i++ + , rdf_iter->pos + , (int)(rdf_iter->nxt - rdf_iter->pos) + , (int)(rdf_iter->end - rdf_iter->nxt) + , rdf_iter->rdd_pos->name + ); + } + } if ((str_pkt = gldns_wire2str_pkt( netreq->response, netreq->response_len))) {