From: TCY16 Date: Wed, 30 Mar 2022 11:05:33 +0000 (+0200) Subject: add edns file and functionality in wire2host X-Git-Tag: 1.8.2-rc.1~3^2~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0732aaec47e3a430622ace04ceaf46d73b946025;p=thirdparty%2Fldns.git add edns file and functionality in wire2host --- diff --git a/.gitignore b/.gitignore index 906e2876..4e0296ba 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,8 @@ /duration.o /error.lo /error.o +/edns.lo +/edns.o /examples/.libs/ /examples/ldns-chaos /examples/ldns-chaos.lo diff --git a/Makefile.in b/Makefile.in index 574098c6..4cd4c906 100644 --- a/Makefile.in +++ b/Makefile.in @@ -89,12 +89,12 @@ DEPFLAG = @DEPFLAG@ INSTALL = $(srcdir)/install-sh LIBLOBJS = $(LIBOBJS:.o=.lo) -LDNS_LOBJS = buffer.lo dane.lo dname.lo dnssec.lo dnssec_sign.lo dnssec_verify.lo dnssec_zone.lo duration.lo error.lo higher.lo host2str.lo host2wire.lo keys.lo net.lo packet.lo parse.lo radix.lo rbtree.lo rdata.lo resolver.lo rr.lo rr_functions.lo sha1.lo sha2.lo str2host.lo tsig.lo update.lo util.lo wire2host.lo zone.lo +LDNS_LOBJS = buffer.lo dane.lo dname.lo dnssec.lo dnssec_sign.lo dnssec_verify.lo dnssec_zone.lo duration.lo error.lo higher.lo host2str.lo host2wire.lo keys.lo net.lo packet.lo parse.lo radix.lo rbtree.lo rdata.lo resolver.lo rr.lo rr_functions.lo sha1.lo sha2.lo str2host.lo tsig.lo update.lo util.lo wire2host.lo zone.lo edns.lo LDNS_LOBJS_EX = ^linktest\.c$$ LDNS_ALL_LOBJS = $(LDNS_LOBJS) $(LIBLOBJS) LIB = libldns.la -LDNS_HEADERS = buffer.h dane.h dname.h dnssec.h dnssec_sign.h dnssec_verify.h dnssec_zone.h duration.h error.h higher.h host2str.h host2wire.h keys.h ldns.h packet.h parse.h radix.h rbtree.h rdata.h resolver.h rr_functions.h rr.h sha1.h sha2.h str2host.h tsig.h update.h wire2host.h zone.h +LDNS_HEADERS = buffer.h dane.h dname.h dnssec.h dnssec_sign.h dnssec_verify.h dnssec_zone.h duration.h error.h higher.h host2str.h host2wire.h keys.h ldns.h packet.h parse.h radix.h rbtree.h rdata.h resolver.h rr_functions.h rr.h sha1.h sha2.h str2host.h tsig.h update.h wire2host.h zone.h edns.h LDNS_HEADERS_EX = ^config\.h|common\.h|util\.h|net\.h$$ LDNS_HEADERS_GEN= common.h util.h net.h @@ -799,6 +799,7 @@ zone.lo zone.o: $(srcdir)/zone.c ldns/config.h $(srcdir)/ldns/ldns.h ldns/util.h $(srcdir)/ldns/higher.h $(srcdir)/ldns/host2wire.h ldns/net.h $(srcdir)/ldns/str2host.h $(srcdir)/ldns/update.h \ $(srcdir)/ldns/wire2host.h $(srcdir)/ldns/rr_functions.h $(srcdir)/ldns/parse.h $(srcdir)/ldns/radix.h \ $(srcdir)/ldns/sha1.h $(srcdir)/ldns/sha2.h +edns.lo edns.o: $(srcdir)/edns.c ldns/config.h $(srcdir)/ldns/edns.h compat/b64_ntop.lo compat/b64_ntop.o: $(srcdir)/compat/b64_ntop.c ldns/config.h compat/b64_pton.lo compat/b64_pton.o: $(srcdir)/compat/b64_pton.c ldns/config.h compat/calloc.lo compat/calloc.o: $(srcdir)/compat/calloc.c ldns/config.h diff --git a/drill/drill.c b/drill/drill.c index 13afb84f..07695f60 100644 --- a/drill/drill.c +++ b/drill/drill.c @@ -699,6 +699,8 @@ main(int argc, char *argv[]) ldns_resolver_set_tsig_algorithm(res, tsig_algorithm); } + printf("HERE: drill:main() PURPOSE: %d\n", PURPOSE); + /* main switching part of drill */ switch(PURPOSE) { case DRILL_TRACE: diff --git a/edns.c b/edns.c new file mode 100644 index 00000000..2f6d8098 --- /dev/null +++ b/edns.c @@ -0,0 +1,98 @@ +/* + * edns.c + * + * edns implementation + * + * a Net::DNS like library for C + * + * (c) NLnet Labs, 2004-2022 + * + * See the file LICENSE for the license + */ + +#include + +/* + * Access functions + * functions to get and set type checking + */ + +/* read */ +size_t +ldns_edns_get_size(const ldns_edns_option *edns) +{ + assert(edns != NULL); + return edns->_size; +} + +ldns_edns_option_code +ldns_edns_get_code(const ldns_edns_option *edns) +{ + assert(edns != NULL); + return edns->_code; +} + +uint8_t * +ldns_edns_get_data(const ldns_edns_option *edns) +{ + assert(edns != NULL); + return edns->_data; +} + + +/* write */ +void +ldns_edns_set_size(ldns_edns_option *edns, size_t size) +{ + assert(edns != NULL); + edns->_size = size; +} + +void +ldns_edns_set_code(ldns_edns_option *edns, ldns_edns_option_code code) +{ + assert(edns != NULL); + edns->_code = code; +} + +void +ldns_edns_set_data(ldns_edns_option *edns, void *data) +{ + /* only copy the pointer */ + assert(edns != NULL); + edns->_data = data; +} + +/* note: data must be allocated memory */ +ldns_edns_option * +ldns_edns_new(ldns_edns_option_code code, size_t size, void *data) +{ + ldns_edns_option *edns; + edns = LDNS_MALLOC(ldns_edns_option); + if (!edns) { + return NULL; + } + ldns_edns_set_size(edns, size); + ldns_edns_set_code(edns, code); + ldns_edns_set_data(edns, data); + return edns; +} + +void +ldns_edns_deep_free(ldns_edns_option *edns) +{ + if (edns) { + if (edns->_data) { + LDNS_FREE(edns->_data); + } + LDNS_FREE(edns); + } +} + +void +ldns_edns_free(ldns_edns_option *edns) +{ + if (edns) { + LDNS_FREE(edns); + } +} diff --git a/host2str.c b/host2str.c index a207a913..91fbc753 100644 --- a/host2str.c +++ b/host2str.c @@ -2205,6 +2205,10 @@ ldns_pkt2buffer_str_fmt(ldns_buffer *output, if (ldns_pkt_edns_data(pkt)) { ldns_buffer_printf(output, ";; Data: "); + + // @TODO loop through options on the newly created ldns_edns_opt + // struct and create + (void)ldns_rdf2buffer_str(output, ldns_pkt_edns_data(pkt)); ldns_buffer_printf(output, "\n"); diff --git a/ldns/edns.h b/ldns/edns.h new file mode 100644 index 00000000..e7100509 --- /dev/null +++ b/ldns/edns.h @@ -0,0 +1,122 @@ +/* + * edns.h + * + * + * a Net::DNS like library for C + * + * (c) NLnet Labs, 2004-2022 + * + * See the file LICENSE for the license + */ + +#ifndef LDNS_EDNS_H +#define LDNS_EDNS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +/** + * EDNS option codes + */ +enum ldns_enum_edns_option +{ + LDNS_EDNS_LLQ = 1, /* http://files.dns-sd.org/draft-sekar-dns-llq.txt */ + LDNS_EDNS_UL = 2, /* http://files.dns-sd.org/draft-sekar-dns-ul.txt */ + LDNS_EDNS_NSID = 3, /* RFC5001 */ + /* 4 draft-cheshire-edns0-owner-option */ + LDNS_EDNS_DAU = 5, /* RFC6975 */ + LDNS_EDNS_DHU = 6, /* RFC6975 */ + LDNS_EDNS_N3U = 7, /* RFC6975 */ + LDNS_EDNS_CLIENT_SUBNET = 8, /* RFC7871 */ + LDNS_EDNS_KEEPALIVE = 11, /* draft-ietf-dnsop-edns-tcp-keepalive*/ + LDNS_EDNS_PADDING = 12, /* RFC7830 */ + LDNS_EDNS_EDE = 15, /* RFC8914 */ + LDNS_EDNS_CLIENT_TAG = 16 /* draft-bellis-dnsop-edns-tags-01 */ +}; +typedef enum ldns_enum_edns_option ldns_edns_option_code; + +/** + * + * An EDNS option is structed as follows: + +0 (MSB) +1 (LSB) + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + 0: | OPTION-CODE | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + 2: | OPTION-LENGTH | + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + 4: | | + / OPTION-DATA / + / / + +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * + * + * @TODO write this + */ +struct ldns_struct_edns_option { + ldns_edns_option_code _code; + size_t _size; + void *_data; +}; +typedef struct ldns_struct_edns_option ldns_edns_option; + + +/* + * + * @TODO write this + */ +struct ldns_struct_edns_option_list +{ + size_t _option_count; + size_t _rr_capacity; // ??? + ldns_rr **_options; +}; +typedef struct ldns_struct_edns_option_list edns_option_list; + +/* + * Access functions + * do this as functions to get type checking + */ + +/** + * returns the size of the EDNS data. + * \param[in] *edns the EDNS struct to read from + * \return uint16_t with the size + */ +size_t ldns_edns_get_size(const ldns_edns_option *edns); + +/** + * returns the size of the EDNS data. + * \param[in] *edns the EDNS struct to read from + * \return uint16_t with the size + */ +ldns_edns_option_code ldns_edns_get_code(const ldns_edns_option *edns); + +/** + * returns the EDNS option data. + * \param[in] *edns the rdf to read from + * \return uint8_t* pointer to the rdf's data + */ +uint8_t *ldns_edns_get_data(const ldns_edns_option *edns); + + +/** + * allocates a new EDNS structure and fills it. + * This function DOES NOT copy the contents from + * the buffer, unlike ldns_rdf_new_frm_data() + * \param[in] type type of the rdf + * \param[in] size size of the buffer + * \param[in] data pointer to the buffer to be copied + * \return the new rdf structure or NULL on failure + */ +ldns_edns_option *ldns_edns_new(ldns_edns_option_code code, size_t size, void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* LDNS_EDNS_H */ \ No newline at end of file diff --git a/ldns/ldns.h b/ldns/ldns.h index 60663ef9..74713a21 100644 --- a/ldns/ldns.h +++ b/ldns/ldns.h @@ -123,6 +123,7 @@ Or you can just use the menu above to browse through the API docs. #include #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/ldns/packet.h b/ldns/packet.h index c0ed0c79..73d04b09 100644 --- a/ldns/packet.h +++ b/ldns/packet.h @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -257,6 +258,10 @@ struct ldns_struct_pkt uint16_t _edns_z; /** Arbitrary EDNS rdata */ ldns_rdf *_edns_data; + + /** Structured ENDS options */ + ldns_edns_option *_edns_options; // @TODO rewrite into "edns_option_list" struct + /** Question section */ ldns_rr_list *_question; /** Answer section */ @@ -719,7 +724,7 @@ uint16_t ldns_pkt_edns_unassigned(const ldns_pkt *packet); void ldns_pkt_set_edns_unassigned(ldns_pkt *packet, uint16_t value); /** - * returns true if this packet needs and EDNS rr to be sent. + * returns true if this packet needs an EDNS rr to be sent. * At the moment the only reason is an expected packet * size larger than 512 bytes, but for instance dnssec would * be a good reason too. @@ -760,6 +765,18 @@ void ldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z); */ void ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data); + +// * +// * Set the packet's edns data +// * \param[in] packet the packet +// * \param[in] data the data +// * \return 0 is there is no next EDNS option in the + +// uint16_t ldns_pkt_get_next_edns_option(ldns_pkt *packet, ); + + + + /** * allocates and initializes a ldns_pkt structure. * \return pointer to the new packet diff --git a/ldns/rr.h b/ldns/rr.h index 2b03a60e..44d54121 100644 --- a/ldns/rr.h +++ b/ldns/rr.h @@ -156,7 +156,7 @@ enum ldns_enum_rr_type LDNS_RR_TYPE_DNAME = 39, /** dnsind-kitchen-sink-02.txt */ LDNS_RR_TYPE_SINK = 40, - /** Pseudo OPT record... */ + /** OPT record RFC 6891 */ LDNS_RR_TYPE_OPT = 41, /** RFC3123 */ LDNS_RR_TYPE_APL = 42, diff --git a/packet.c b/packet.c index a57e1901..0cee38f1 100644 --- a/packet.c +++ b/packet.c @@ -798,6 +798,8 @@ ldns_pkt_new(void) ldns_pkt_set_edns_data(packet, NULL); packet->_edns_present = false; + packet->_edns_options = NULL; //@TODO change this to set_function/list function + ldns_pkt_set_tsig(packet, NULL); return packet; diff --git a/wire2host.c b/wire2host.c index ee70fbde..ab5fdd1b 100644 --- a/wire2host.c +++ b/wire2host.c @@ -185,7 +185,7 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) end = *pos + (size_t) rd_length; rdf_index = 0; - while (*pos < end && + while (*pos < end && rdf_index < ldns_rr_descriptor_maximum(descriptor)) { cur_rdf_length = 0; @@ -312,6 +312,104 @@ ldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) } + +/* Parse the additional section like wire2rr with a case for EDNS options */ +// @TODO remove static? +static ldns_status +ldns_wire2rr_additional(ldns_pkt* packet, ldns_rr **rr_p, const uint8_t *wire, + size_t max, size_t *pos) +{ + size_t end; + ldns_rdf *owner = NULL; + ldns_rr *rr = ldns_rr_new(); + ldns_status status; + ldns_rr_type rr_type; + uint16_t rd_length; + + status = ldns_wire2dname(&owner, wire, max, pos); + LDNS_STATUS_CHECK_GOTO(status, status_error); + + ldns_rr_set_owner(rr, owner); + + if (*pos + 4 > max) { + status = LDNS_STATUS_PACKET_OVERFLOW; + goto status_error; + } + + rr_type = ldns_read_uint16(&wire[*pos]); + ldns_rr_set_type(rr, rr_type); + *pos = *pos + 2; + + ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos])); + *pos = *pos + 2; + + if (*pos + 4 > max) { + status = LDNS_STATUS_PACKET_OVERFLOW; + goto status_error; + } + ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos])); + + *pos = *pos + 4; + + if (rr_type != LDNS_RR_TYPE_OPT) + status = ldns_wire2rdf(rr, wire, max, pos); + else { + ldns_edns_option* edns; + ldns_edns_option_code option_code; + uint16_t option_size; + uint8_t *option_data; + + if (*pos + 2 > max) { + status = LDNS_STATUS_PACKET_OVERFLOW; + goto status_error; + } + + rd_length = ldns_read_uint16(&wire[*pos]); + *pos = *pos + 2; + + if (*pos + rd_length > max) { + status = LDNS_STATUS_PACKET_OVERFLOW; + goto status_error; + } + + end = *pos + (size_t) rd_length; + + while (*pos < end) { // @TODO fix for multiple EDNS opts? + option_code = ldns_read_uint16(&wire[*pos]); + option_size = ldns_read_uint16(&wire[*pos + 2]); + *pos = *pos + 4; + + option_data = LDNS_XMALLOC(uint8_t, option_size); + if (!option_data) { + status = LDNS_STATUS_MEM_ERR; + goto status_error; + } + memcpy(option_data, &wire[*pos], option_size); + + printf("HERE: ldns_wire2rr_additional():option code: %d\n", option_code); + printf("HERE: ldns_wire2rr_additional():option size: %d\n", option_size); + + edns = ldns_edns_new(option_code, option_size, option_data); + + // @TODO push edns to packet/rr list (1) with function (2) + packet->_edns_options = edns; + + *pos = *pos + option_size; + } + + } + + LDNS_STATUS_CHECK_GOTO(status, status_error); + ldns_rr_set_question(rr, false); + + *rr_p = rr; + return LDNS_STATUS_OK; + +status_error: + ldns_rr_free(rr); + return status; +} + /* TODO: can *pos be incremented at READ_INT? or maybe use something like RR_CLASS(wire)? @@ -411,6 +509,8 @@ ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max) ldns_pkt *packet = ldns_pkt_new(); ldns_status status = LDNS_STATUS_OK; uint8_t have_edns = 0; + // ldns_rdf *edns; + ldns_edns_option *edns; uint8_t data[4]; @@ -418,6 +518,8 @@ ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max) return LDNS_STATUS_MEM_ERR; } + printf("HERE: ldns_wire2pkt()\n"); + status = ldns_wire2pkt_hdr(packet, wire, max, &pos); LDNS_STATUS_CHECK_GOTO(status, status_error); @@ -456,7 +558,10 @@ ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max) } } for (i = 0; i < ldns_pkt_arcount(packet); i++) { - status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL); + + status = ldns_wire2rr_additional(packet ,&rr, wire, max, &pos); + + // status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL); if (status == LDNS_STATUS_PACKET_OVERFLOW) { status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL; } @@ -468,10 +573,16 @@ ldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max) ldns_pkt_set_edns_extended_rcode(packet, data[0]); ldns_pkt_set_edns_version(packet, data[1]); ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2])); - /* edns might not have rdfs */ - if (ldns_rr_rdf(rr, 0)) { - ldns_rdf_deep_free(ldns_pkt_edns_data(packet)); - ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0))); + /* edns is already parsed here in ldns_wire2rr_additional() */ + + if (packet->_edns_options != NULL) { + edns = packet->_edns_options; // @TODO loop-ify + + + printf("HERE: edns code: %d\n", ldns_edns_get_code(edns)); + + // ldns_rdf_deep_free(ldns_pkt_edns_data(packet)); + // ldns_pkt_set_edns_data(packet, ldns_edns_get_data(edns)); } ldns_rr_free(rr); have_edns += 1;