diff --git a/src/rr-dict.c b/src/rr-dict.c index 4952a02a..cb252d98 100644 --- a/src/rr-dict.c +++ b/src/rr-dict.c @@ -487,7 +487,7 @@ static getdns_return_t hip_public_key_2wire( const getdns_bindata *value, uint8_t *rdata, uint8_t *rdf, size_t *rdf_len) { - if (rdata > rdf - 4 || rdata + rdata[1] != rdf) + if (rdata > rdf - 4 || rdata + 4 + rdata[0] != rdf) return GETDNS_RETURN_GENERIC_ERROR; if (value && value->size > 0xFFFF) return GETDNS_RETURN_INVALID_PARAMETER; @@ -1057,74 +1057,109 @@ write_bindata_rdata(gldns_buffer *buf, static getdns_return_t -write_rdata_field(gldns_buffer *buf, - _getdns_rdf_type type, const char *name, getdns_dict *rdata) +write_rdata_field(gldns_buffer *buf, uint8_t *rdata_start, + const _getdns_rdata_def *rd_def, getdns_dict *rdata) { getdns_return_t r; getdns_list *list; uint32_t value; getdns_bindata *bindata; - size_t i; + size_t i, rdf_len; - if (type & GETDNS_RDF_INTEGER) { - if (!(type & GETDNS_RDF_REPEAT)) { - if ((r = getdns_dict_get_int(rdata, name, &value))) + if (rd_def->type & GETDNS_RDF_INTEGER) { + if (!(rd_def->type & GETDNS_RDF_REPEAT)) { + if ((r = getdns_dict_get_int( + rdata, rd_def->name, &value))) return r; else - write_int_rdata(buf, type, value); + write_int_rdata(buf, rd_def->type, value); - } else if ((r = getdns_dict_get_list(rdata, name, &list))) - return r; + } else if ((r = getdns_dict_get_list( + rdata, rd_def->name, &list))) + + return r == GETDNS_RETURN_NO_SUCH_DICT_NAME + ? GETDNS_RETURN_GOOD : r; else for ( i = 0 ; GETDNS_RETURN_GOOD == (r = getdns_list_get_int(list, i, &value)) ; i++) - write_int_rdata(buf, type, value); + write_int_rdata(buf, rd_def->type, value); - if (r != GETDNS_RETURN_NO_SUCH_LIST_ITEM) - return r; - - } else if (type & GETDNS_RDF_BINDATA) { - if (!(type & GETDNS_RDF_REPEAT)) { - if ((r = getdns_dict_get_bindata(rdata,name,&bindata))) + + } else if (rd_def->type & GETDNS_RDF_BINDATA) { + + + if (!(rd_def->type & GETDNS_RDF_REPEAT)) { + if ((r = getdns_dict_get_bindata( + rdata, rd_def->name, &bindata))) return r; else - write_bindata_rdata(buf, type, bindata); + write_bindata_rdata(buf, rd_def->type, bindata); - } else if ((r = getdns_dict_get_list(rdata, name, &list))) - return r; + } else if ((r = getdns_dict_get_list( + rdata, rd_def->name, &list))) + + return r == GETDNS_RETURN_NO_SUCH_DICT_NAME + ? GETDNS_RETURN_GOOD : r; else for ( i = 0 ; GETDNS_RETURN_GOOD == (r = getdns_list_get_bindata(list, i, &bindata)) ; i++) - write_bindata_rdata(buf, type, bindata); + write_bindata_rdata(buf, rd_def->type, bindata); - if (r != GETDNS_RETURN_NO_SUCH_LIST_ITEM) - return r; - } else - /* TODO: Handle the special types */ + } else if (!(rd_def->type & GETDNS_RDF_SPECIAL)) { + /* Unknown rdata type */ return GETDNS_RETURN_GENERIC_ERROR; - return GETDNS_RETURN_GOOD; + } else if (!(rd_def->type & GETDNS_RDF_REPEAT)) { + + rdf_len = gldns_buffer_remaining(buf); + r = rd_def->special->dict2wire(rdata, rdata_start, + gldns_buffer_current(buf), &rdf_len); + if (r == GETDNS_RETURN_GOOD || + r == GETDNS_RETURN_NEED_MORE_SPACE) + gldns_buffer_skip(buf, rdf_len); + if (r) + return r; + + } else if ((r = getdns_dict_get_list(rdata, rd_def->name, &list))) { + + return r == GETDNS_RETURN_NO_SUCH_DICT_NAME + ? GETDNS_RETURN_GOOD : r; + + } else for ( i = 0; r == GETDNS_RETURN_GOOD; i++ ) { + + rdf_len = gldns_buffer_remaining(buf); + r = rd_def->special->list2wire(list, i, rdata_start, + gldns_buffer_current(buf), &rdf_len); + if (r == GETDNS_RETURN_GOOD || + r == GETDNS_RETURN_NEED_MORE_SPACE) + gldns_buffer_skip(buf, rdf_len); + } + + return r != GETDNS_RETURN_NO_SUCH_LIST_ITEM ? r : GETDNS_RETURN_GOOD; } getdns_return_t _getdns_rr_dict2wire(const getdns_dict *rr_dict, gldns_buffer *buf) { getdns_return_t r = GETDNS_RETURN_GOOD; - struct getdns_bindata *name; - struct getdns_bindata *rdata_raw; - struct getdns_dict *rdata; + getdns_bindata *name; + getdns_bindata *rdata_raw; + getdns_dict *rdata; uint32_t rr_type; uint32_t rr_class = GETDNS_RRCLASS_IN; uint32_t rr_ttl = 0; const _getdns_rr_def *rr_def; - const _getdns_rdata_def *rd_def; - int n_rdata_fields; + const _getdns_rdata_def *rd_def, *rep_rd_def; + int n_rdata_fields, rep_n_rdata_fields; size_t rdata_size_mark; + uint8_t *rdata_start; + getdns_list *list; + size_t i; assert(rr_dict); assert(buf); @@ -1166,20 +1201,47 @@ _getdns_rr_dict2wire(const getdns_dict *rr_dict, gldns_buffer *buf) } else if (n_rdata_fields || r == GETDNS_RETURN_NO_SUCH_DICT_NAME) { + r = GETDNS_RETURN_GOOD; rdata_size_mark = gldns_buffer_position(buf); gldns_buffer_skip(buf, 2); + rdata_start = gldns_buffer_current(buf); for ( rd_def = rr_def->rdata , n_rdata_fields = rr_def->n_rdata_fields ; n_rdata_fields ; n_rdata_fields-- , rd_def++ ) { + if (rd_def->type == GETDNS_RDF_REPEAT) + break; - if (rd_def->type != GETDNS_RDF_REPEAT) { - if ((r = write_rdata_field( - buf, rd_def->type, rd_def->name, rdata))) + if ((r = write_rdata_field(buf, + rdata_start, rd_def, rdata))) + break; + } + if (n_rdata_fields == 0 || r) { + /* pass */; + + } else if ((r = getdns_dict_get_list( + rdata, rd_def->name, &list))) { + /* pass */; + + } else for ( i = 0 + ; r == GETDNS_RETURN_GOOD + ; i++) { + + if ((r = getdns_list_get_dict(list, i, &rdata))) { + if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM) + r = GETDNS_RETURN_GOOD; break; } - /* TODO: Deal with repeat blocks */ + for ( rep_rd_def = rd_def + 1 + , rep_n_rdata_fields = n_rdata_fields - 1 + ; rep_n_rdata_fields + ; rep_n_rdata_fields--, rep_rd_def++ ) { + + if ((r = write_rdata_field(buf, + rdata_start, rep_rd_def, rdata))) + break; + } } gldns_buffer_write_u16_at(buf, rdata_size_mark, (uint16_t)(gldns_buffer_position(buf)-rdata_size_mark-2)); diff --git a/src/rr-dict.h b/src/rr-dict.h index 5faab57a..c605be32 100644 --- a/src/rr-dict.h +++ b/src/rr-dict.h @@ -132,15 +132,15 @@ typedef enum _getdns_rdf_wf_type { } _getdns_rdf_type; typedef struct _getdns_rdata_def { - const char *name; + const char *name; _getdns_rdf_type type; _getdns_rdf_special *special; } _getdns_rdata_def; typedef struct _getdns_rr_def { - const char *name; + const char *name; const _getdns_rdata_def *rdata; - int n_rdata_fields; + int n_rdata_fields; } _getdns_rr_def; const _getdns_rr_def *_getdns_rr_def_lookup(uint16_t rr_type); diff --git a/src/test/tpkg/260-conversion-functions.tpkg/260-conversion-functions.c b/src/test/tpkg/260-conversion-functions.tpkg/260-conversion-functions.c index f92541b6..f3f5a4b6 100644 --- a/src/test/tpkg/260-conversion-functions.tpkg/260-conversion-functions.c +++ b/src/test/tpkg/260-conversion-functions.tpkg/260-conversion-functions.c @@ -54,38 +54,91 @@ int main() getdns_dict *rr_dict; getdns_bindata *dns_name; getdns_bindata address = { 4, "\xb9\x31\x8d\x25" }; - getdns_bindata nothing = { 8, "\x07nothing" }; + getdns_bindata fourth = { 11, "last string" }; + size_t length; + getdns_list *list; char *str; uint8_t wire_buf[4096], *wire = wire_buf, *end_of_wire; - size_t wire_len = sizeof(wire_buf); + size_t wire_len; + + /* Convert string to rr_dict + */ if ((r = getdns_str2rr_dict( - "some.domain.tld. 60 CH TXT \"first string\" second \"and third\"", + "some.domain.tld. 60 IN TXT \"first string\" second \"and third\"", &rr_dict, NULL, 3600))) FAIL_r("getdns_str2rr_dict"); + + /* Add a fourth text element. + */ + if ((r = getdns_dict_set_bindata(rr_dict, "/rdata/txt_strings/-", &fourth))) + FAIL_r("getdns_list_set_bindata"); + print_dict(rr_dict); + + /* Convert to wireformat from rdata_raw. + * Added fourth list element should NOT show. + */ + wire_len = sizeof(wire_buf); if ((r = getdns_rr_dict2wire(rr_dict, wire, &wire_len))) FAIL_r("getdns_rr_dict2wire"); print_wire(wire, wire_len); + + /* Convert to wireformat from parsing rdata fields. + * Added fourth list element should show. + */ if ((r = getdns_dict_remove_name(rr_dict, "/rdata/rdata_raw"))) FAIL_r("getdns_dict_remove_name"); - print_dict(rr_dict); + printf("\nremoved \"/rdata/rdata_raw\":\n\n"); + wire_len = sizeof(wire_buf); if ((r = getdns_rr_dict2wire(rr_dict, wire, &wire_len))) FAIL_r("getdns_rr_dict2wire"); print_wire(wire, wire_len); + + /* Remove second and third string elements and show text format. + */ + if ((r = getdns_dict_remove_name(rr_dict, "/rdata/txt_strings/1"))) + FAIL_r("getdns_dict_remove_name"); + if ((r = getdns_dict_remove_name(rr_dict, "/rdata/txt_strings/1"))) + FAIL_r("getdns_dict_remove_name"); + + if ((r = getdns_rr_dict2str(rr_dict, &str))) + FAIL_r("getdns_rr_dict2str"); + + printf("\n%s", str); + free(str); + + + /* Remove all string elements and show text format. + */ + if ((r = getdns_dict_remove_name(rr_dict, "/rdata/txt_strings/0"))) + FAIL_r("getdns_dict_remove_name"); + if ((r = getdns_dict_remove_name(rr_dict, "/rdata/txt_strings/0"))) + FAIL_r("getdns_dict_remove_name"); + + if ((r = getdns_rr_dict2str(rr_dict, &str))) + FAIL_r("getdns_rr_dict2str"); + + printf("%s", str); + free(str); + getdns_dict_destroy(rr_dict); + /* Forward wireformat to test scanning from wireformat later on + */ wire += wire_len; wire_len = sizeof(wire_buf) - (wire - wire_buf); + /* Construct rr_dict and convert to string + */ if (!(rr_dict = getdns_dict_create())) FAIL("getdns_dict_create returned NULL"); @@ -108,6 +161,7 @@ int main() FAIL_r("getdns_rr_dict2str"); printf("\n%s\n", str); + free(str); if ((r = getdns_rr_dict2wire(rr_dict, wire, &wire_len))) FAIL_r("getdns_rr_dict2wire"); @@ -118,6 +172,73 @@ int main() wire += wire_len; wire_len = sizeof(wire_buf) - (wire - wire_buf); + + /* Convert RR with special rdata fields and repeating last element + * from string to rr_dict + */ + if ((r = getdns_str2rr_dict( + "hip2 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2.example.com.", + &rr_dict, "nlnetlabs.nl", 3600))) + FAIL_r("getdns_str2rr_dict"); + + if ((r = getdns_dict_remove_name(rr_dict, "/rdata/rdata_raw"))) + FAIL_r("getdns_dict_remove_name"); + + printf("\n"); + print_dict(rr_dict); + + /* Convert RR with special rdata fields and repeating last element + * back to string. + */ + if ((r = getdns_rr_dict2str(rr_dict, &str))) + FAIL_r("getdns_rr_dict2str"); + + printf("%s", str); + free(str); + + + /* Convert RR with special rdata fields without repeating last element + * to string. + */ + if ((r = getdns_dict_remove_name(rr_dict, "/rdata/rendezvous_servers"))) + FAIL_r("getdns_dict_remove_name"); + + if ((r = getdns_dict_get_bindata(rr_dict, "name", &dns_name))) + FAIL_r("getdns_dict_get_bindata"); + + dns_name->data[4] = '0'; + + if ((r = getdns_rr_dict2str(rr_dict, &str))) + FAIL_r("getdns_rr_dict2str"); + + printf("%s\n", str); + free(str); + getdns_dict_destroy(rr_dict); + + + /* Convert RR with repeat block from string to rr_dict + */ + if ((r = getdns_str2rr_dict( + "apl APL 1:192.168.42.0/26 1:192.168.42.64/26 !1:192.168.42.128/25 1:224.0.0.0/4 2:FF00:0:0:0:0:0:0:0/8", + &rr_dict, "net-dns.org", 3600))) + FAIL_r("getdns_str2rr_dict"); + + if ((r = getdns_dict_remove_name(rr_dict, "/rdata/rdata_raw"))) + FAIL_r("getdns_dict_remove_name"); + + print_dict(rr_dict); + + + /* Convert repeat block from rr_dict back to string. + */ + if ((r = getdns_rr_dict2str(rr_dict, &str))) + FAIL_r("getdns_rr_dict2str"); + + printf("%s", str); + free(str); + getdns_dict_destroy(rr_dict); + + /* Parse over wire data, convert to string via dict, and print */ end_of_wire = wire; wire = wire_buf; diff --git a/src/test/tpkg/260-conversion-functions.tpkg/260-conversion-functions.good b/src/test/tpkg/260-conversion-functions.tpkg/260-conversion-functions.good index 11d4500a..6742cb86 100644 --- a/src/test/tpkg/260-conversion-functions.tpkg/260-conversion-functions.good +++ b/src/test/tpkg/260-conversion-functions.tpkg/260-conversion-functions.good @@ -1,5 +1,5 @@ { - "class": GETDNS_RRCLASS_CH, + "class": GETDNS_RRCLASS_IN, "name": , "rdata": { @@ -8,38 +8,95 @@ [ , , - + , + ] }, "ttl": 60, "type": GETDNS_RRTYPE_TXT } 0000 04 73 6f 6d 65 06 64 6f 6d 61 69 6e 03 74 6c 64 .some.do main.tld -0010 00 00 10 00 03 00 00 00 3c 00 1e 0c 66 69 72 73 ........ <...firs +0010 00 00 10 00 01 00 00 00 3c 00 1e 0c 66 69 72 73 ........ <...firs 0020 74 20 73 74 72 69 6e 67 06 73 65 63 6f 6e 64 09 t string .second. 0030 61 6e 64 20 74 68 69 72 64 and thir d....... -{ - "class": GETDNS_RRCLASS_CH, - "name": , - "rdata": - { - "txt_strings": - [ - , - , - - ] - }, - "ttl": 60, - "type": GETDNS_RRTYPE_TXT -} + +removed "/rdata/rdata_raw": + 0000 04 73 6f 6d 65 06 64 6f 6d 61 69 6e 03 74 6c 64 .some.do main.tld -0010 00 00 10 00 03 00 00 00 3c 00 1e 0c 66 69 72 73 ........ <...firs +0010 00 00 10 00 01 00 00 00 3c 00 2a 0c 66 69 72 73 ........ <.*.firs 0020 74 20 73 74 72 69 6e 67 06 73 65 63 6f 6e 64 09 t string .second. -0030 61 6e 64 20 74 68 69 72 64 and thir d....... +0030 61 6e 64 20 74 68 69 72 64 0b 6c 61 73 74 20 73 and thir d.last s +0040 74 72 69 6e 67 tring... ........ + +some.domain.tld. 60 IN TXT "first string" "last string" +some.domain.tld. 60 IN TXT \# 0 www.getdnsapi.net. 0 IN A 185.49.141.37 0000 03 77 77 77 09 67 65 74 64 6e 73 61 70 69 03 6e .www.get dnsapi.n 0010 65 74 00 00 01 00 01 00 00 00 00 00 04 b9 31 8d et...... ......1. 0020 25 %....... ........ + +{ + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "hit": , + "pk_algorithm": 2, + "public_key": , + "rendezvous_servers": + [ + , + + ] + }, + "ttl": 3600, + "type": GETDNS_RRTYPE_HIP +} +hip2.nlnetlabs.nl. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2.example.com. +hip0.nlnetlabs.nl. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D + +{ + "class": GETDNS_RRCLASS_IN, + "name": , + "rdata": + { + "apitems": + [ + { + "address_family": 1, + "afdpart": , + "n": 0, + "prefix": 26 + }, + { + "address_family": 1, + "afdpart": , + "n": 0, + "prefix": 26 + }, + { + "address_family": 1, + "afdpart": , + "n": 1, + "prefix": 25 + }, + { + "address_family": 1, + "afdpart": , + "n": 0, + "prefix": 4 + }, + { + "address_family": 2, + "afdpart": , + "n": 0, + "prefix": 8 + } + ] + }, + "ttl": 3600, + "type": GETDNS_RRTYPE_APL +} +apl.net-dns.org. 3600 IN APL 1:192.168.42.0/26 1:192.168.42.64/26 !1:192.168.42.128/25 1:224.0.0.0/4 2:ff00:0000:0000:0000:0000:0000:0000:0000/8