From: Wouter Wijngaards Date: Thu, 6 Feb 2014 10:57:42 +0000 (+0000) Subject: - sldns has type HIP. X-Git-Tag: release-1.4.22rc1~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=51be201adad2eaaff770e18b30db2a21e02436aa;p=thirdparty%2Funbound.git - sldns has type HIP. git-svn-id: file:///svn/unbound/trunk@3071 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 70cb0df13..262efbb93 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,6 @@ +6 February 2014: Wouter + - sldns has type HIP. + 5 February 2014: Wouter - Fix sldns parse tests on osx. diff --git a/ldns/rrdef.c b/ldns/rrdef.c index 12d1a6da6..8f7dd3036 100644 --- a/ldns/rrdef.c +++ b/ldns/rrdef.c @@ -188,37 +188,9 @@ static const sldns_rdf_type type_tlsa_wireformat[] = { LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_HEX }; - -/** - * With HIP, wire and presentation format are out of step. - * In presentation format, we have: - * - a PK algorithm presented as integer in range [0..255] - * - a variable length HIT field presented as hexstring - * - a variable length Public Key field presented as Base64 - * - * Unfortunately in the wireformat the lengths of the variable - * length HIT and Public Key fields do not directly preceed them. - * In stead we have: - * - 1 byte HIT length: h - * - 1 byte PK algorithm - * - 2 bytes Public Key length: p - * - h bytes HIT - * - p bytes Public Key - * - * In ldns those deviations from the conventions for rdata fields are best - * tackeled by letting the array refered to by the descriptor for HIP represent - * host format only. - * - * BEWARE! Unlike other RR types, actual HIP wire format does not directly - * follow the RDF types enumerated in the array pointed to by _wireformat in - * its descriptor record. - */ -static const sldns_rdf_type type_hip_hostformat[] = { - LDNS_RDF_TYPE_INT8, - LDNS_RDF_TYPE_HEX, - LDNS_RDF_TYPE_B64 +static const sldns_rdf_type type_hip_wireformat[] = { + LDNS_RDF_TYPE_HIP }; - static const sldns_rdf_type type_nid_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_ILNP64 @@ -368,17 +340,12 @@ static sldns_rr_descriptor rdata_field_descriptors[] = { {LDNS_RR_TYPE_NULL, "TYPE53", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, {LDNS_RR_TYPE_NULL, "TYPE54", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, - - /* 55 + /* 55 * Hip ends with 0 or more Rendezvous Servers represented as dname's. * Hence the LDNS_RDF_TYPE_DNAME _variable field and the _maximum field * set to 0. - * - * BEWARE! Unlike other RR types, actual HIP wire format does not - * directly follow the RDF types enumerated in the array pointed to - * by _wireformat. For more info see type_hip_hostformat declaration. */ - {LDNS_RR_TYPE_HIP, "HIP", 3, 3, type_hip_hostformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, + {LDNS_RR_TYPE_HIP, "HIP", 1, 1, type_hip_wireformat, LDNS_RDF_TYPE_DNAME, LDNS_RR_NO_COMPRESS, 0 }, #ifdef DRAFT_RRTYPES /* 56 */ diff --git a/ldns/rrdef.h b/ldns/rrdef.h index 508d6c62b..442eb26e0 100644 --- a/ldns/rrdef.h +++ b/ldns/rrdef.h @@ -302,10 +302,13 @@ enum sldns_enum_rdf_type LDNS_RDF_TYPE_PERIOD, /** tsig time 48 bits */ LDNS_RDF_TYPE_TSIGTIME, - /** skip 21 unused */ + /** Represents the Public Key Algorithm, HIT and Public Key fields + for the HIP RR types. A HIP specific rdf type is used because of + the unusual layout in wireformat (see RFC 5205 Section 5) */ + LDNS_RDF_TYPE_HIP, /** variable length any type rdata where the length is specified by the first 2 bytes */ - LDNS_RDF_TYPE_INT16_DATA = 22, + LDNS_RDF_TYPE_INT16_DATA, /** protocol and port bitmaps */ LDNS_RDF_TYPE_SERVICE, /** location data */ diff --git a/ldns/str2wire.c b/ldns/str2wire.c index 60b0b88c8..e1eb84fba 100644 --- a/ldns/str2wire.c +++ b/ldns/str2wire.c @@ -525,6 +525,67 @@ rrinternal_parse_rdf(sldns_buffer* strbuf, char* token, size_t token_len, return LDNS_WIREPARSE_ERR_OK; } +/** + * Parse one rdf token. Takes care of quotes and parenthesis. + */ +static int +sldns_parse_rdf_token(sldns_buffer* strbuf, char* token, size_t token_len, + int* quoted, int* parens, int* tokquote, size_t* pre_data_pos, + const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen) +{ + size_t slen; + + /* skip spaces */ + while(sldns_buffer_remaining(strbuf) > 0 && !*quoted && + *(sldns_buffer_current(strbuf)) == ' ') { + sldns_buffer_skip(strbuf, 1); + } + + *pre_data_pos = sldns_buffer_position(strbuf); + if(sldns_bget_token_par(strbuf, token, (*quoted)?"\"":delimiters, + token_len, parens, (*quoted)?NULL:" \t") == -1) { + return 0; + } + slen = strlen(token); + /* check if not quoted yet, and we have encountered quotes */ + if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) && + slen >= 2 && + (token[0] == '"' || token[0] == '\'') && + (token[slen-1] == '"' || token[slen-1] == '\'')) { + /* move token two smaller (quotes) with endnull */ + memmove(token, token+1, slen-2); + token[slen-2] = 0; + slen -= 2; + *quoted = 1; + *tokquote = 1; /* do not read endquotechar from buffer */ + } else if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) && + slen >= 2 && + (token[0] == '"' || token[0] == '\'')) { + /* got the start quote (remove it) but read remainder + * of quoted string as well into remainder of token */ + memmove(token, token+1, slen-1); + token[slen-1] = 0; + slen -= 1; + *quoted = 1; + *tokquote = 0; + /* rewind buffer over skipped whitespace */ + while(sldns_buffer_position(strbuf) > 0 && + (sldns_buffer_current(strbuf)[-1] == ' ' || + sldns_buffer_current(strbuf)[-1] == '\t')) { + sldns_buffer_skip(strbuf, -1); + } + if(sldns_bget_token_par(strbuf, token+slen, + "\"", token_len-slen, + parens, NULL) == -1) { + return 0; + } + slen = strlen(token); + } else *tokquote = 0; + *token_strlen = slen; + return 1; +} + + /** parse rdata from string into rr buffer(-remainder after dname). */ static int rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, @@ -553,52 +614,10 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, delimiters = rrinternal_get_delims(rdftype, r_cnt, r_max); quoted = rrinternal_get_quoted(strbuf, &delimiters, rdftype); - /* skip spaces */ - while(sldns_buffer_remaining(strbuf) > 0 && !quoted && - *(sldns_buffer_current(strbuf)) == ' ') { - sldns_buffer_skip(strbuf, 1); - } - - pre_data_pos = sldns_buffer_position(strbuf); - if(sldns_bget_token_par(strbuf, token, quoted?"\"":delimiters, - token_len, &parens, quoted?NULL:" \t") == -1) { + if(!sldns_parse_rdf_token(strbuf, token, token_len, "ed, + &parens, &tokquote, &pre_data_pos, delimiters, rdftype, + &token_strlen)) break; - } - token_strlen = strlen(token); - /* check if not quoted yet, and we have encountered quotes */ - if(!quoted && sldns_rdf_type_maybe_quoted(rdftype) && - token_strlen >= 2 && - (token[0] == '"' || token[0] == '\'') && - (token[token_strlen-1] == '"' || token[token_strlen-1] == '\'')) { - /* move token two smaller (quotes) with endnull */ - memmove(token, token+1, token_strlen-2); - token[token_strlen-2] = 0; - token_strlen -= 2; - quoted = 1; - tokquote = 1; /* do not read endquotechar from buffer */ - } else if(!quoted && sldns_rdf_type_maybe_quoted(rdftype) && - token_strlen >= 2 && - (token[0] == '"' || token[0] == '\'')) { - /* got the start quote (remove it) but read remainder - * of quoted string as well into remainder of token */ - memmove(token, token+1, token_strlen-1); - token[token_strlen-1] = 0; - token_strlen -= 1; - quoted = 1; - tokquote = 0; - /* rewind buffer over skipped whitespace */ - while(sldns_buffer_position(strbuf) > 0 && - (sldns_buffer_current(strbuf)[-1] == ' ' || - sldns_buffer_current(strbuf)[-1] == '\t')) { - sldns_buffer_skip(strbuf, -1); - } - if(sldns_bget_token_par(strbuf, token+token_strlen, - "\"", token_len-token_strlen, - &parens, NULL) == -1) { - break; - } - token_strlen = strlen(token); - } else tokquote = 0; /* rfc3597 specifies that any type can be represented * with \# method, which can contain spaces... @@ -613,6 +632,38 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, pre_data_pos)) != 0) return status; } else if(token_strlen > 0 || quoted) { + if(rdftype == LDNS_RDF_TYPE_HIP) { + /* affix the HIT and PK fields, with a space */ + size_t addlen = token_len - token_strlen; + size_t addstrlen = 0; + /* add space */ + if(addlen < 1) break; + token[token_strlen] = ' '; + token[++token_strlen] = 0; + /* read another token */ + addlen = token_len - token_strlen; + if(!sldns_parse_rdf_token(strbuf, + token+token_strlen, addlen, "ed, + &parens, &tokquote, &pre_data_pos, + delimiters, rdftype, &addstrlen)) + break; + token_strlen += addstrlen; + /* add space */ + addlen = token_len - token_strlen; + if(addlen < 1) break; + token[token_strlen] = ' '; + token[++token_strlen] = 0; + /* read another token */ + addlen = token_len - token_strlen; + addstrlen = 0; + if(!sldns_parse_rdf_token(strbuf, + token+token_strlen, addlen, "ed, + &parens, &tokquote, &pre_data_pos, + delimiters, rdftype, &addstrlen)) + break; + token_strlen += addstrlen; + } + /* normal RR */ if((status=rrinternal_parse_rdf(strbuf, token, token_len, rr, *rr_len, &rr_cur_len, rdftype, @@ -907,6 +958,8 @@ int sldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len, return sldns_str2wire_tag_buf(str, rd, len); case LDNS_RDF_TYPE_LONG_STR: return sldns_str2wire_long_str_buf(str, rd, len); + case LDNS_RDF_TYPE_HIP: + return sldns_str2wire_hip_buf(str, rd, len); case LDNS_RDF_TYPE_INT16_DATA: return sldns_str2wire_int16_data_buf(str, rd, len); case LDNS_RDF_TYPE_UNKNOWN: @@ -1863,6 +1916,56 @@ int sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len) return LDNS_WIREPARSE_ERR_OK; } +int sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len) +{ + char* s, *end; + int e; + size_t hitlen, pklen = 0; + /* presentation format: + * pk-algo HIThex pubkeybase64 + * wireformat: + * hitlen[1byte] pkalgo[1byte] pubkeylen[2byte] [hit] [pubkey] */ + if(*len < 4) + return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; + + /* read PK algorithm */ + rd[1] = (uint8_t)strtol((char*)str, &s, 10); + if(*s != ' ') + return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str); + s++; + while(*s == ' ') + s++; + + /* read HIT hex tag */ + /* zero terminate the tag (replace later) */ + end = strchr(s, ' '); + if(!end) return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, s-(char*)str); + *end = 0; + hitlen = *len - 4; + if((e = sldns_str2wire_hex_buf(s, rd+4, &hitlen)) != 0) { + *end = ' '; + return RET_ERR_SHIFT(e, s-(char*)str); + } + if(hitlen > 255) { + *end = ' '; + return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+255*2); + } + rd[0] = (uint8_t)hitlen; + *end = ' '; + s = end+1; + + /* read pubkey base64 sequence */ + pklen = *len - 4 - hitlen; + if((e = sldns_str2wire_b64_buf(s, rd+4+hitlen, &pklen)) != 0) + return RET_ERR_SHIFT(e, s-(char*)str); + if(pklen > 65535) + return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+65535); + sldns_write_uint16(rd+2, pklen); + + *len = 4 + hitlen + pklen; + return LDNS_WIREPARSE_ERR_OK; +} + int sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len) { size_t sz = sldns_b64_pton_calculate_size(strlen(str)); diff --git a/ldns/str2wire.h b/ldns/str2wire.h index 990c9fcbb..94c893389 100644 --- a/ldns/str2wire.h +++ b/ldns/str2wire.h @@ -516,6 +516,15 @@ int sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len); */ int sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len); +/** + * Convert rdf of type LDNS_RDF_TYPE_HIP from string to wireformat. + * @param str: the text to convert for this rdata element. + * @param rd: rdata buffer for the wireformat. + * @param len: length of rd buffer on input, used length on output. + * @return 0 on success, error on failure. + */ +int sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len); + /** * Convert rdf of type LDNS_RDF_TYPE_INT16_DATA from string to wireformat. * @param str: the text to convert for this rdata element. diff --git a/ldns/wire2str.c b/ldns/wire2str.c index 76920c17f..79cc96292 100644 --- a/ldns/wire2str.c +++ b/ldns/wire2str.c @@ -946,6 +946,8 @@ int sldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen, case LDNS_RDF_TYPE_IPSECKEY: return sldns_wire2str_ipseckey_scan(d, dlen, s, slen, pkt, pktlen); + case LDNS_RDF_TYPE_HIP: + return sldns_wire2str_hip_scan(d, dlen, s, slen); case LDNS_RDF_TYPE_INT16_DATA: return sldns_wire2str_int16_data_scan(d, dlen, s, slen); case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: @@ -1531,6 +1533,31 @@ int sldns_wire2str_ipseckey_scan(uint8_t** d, size_t* dl, char** s, size_t* sl, return w; } +int sldns_wire2str_hip_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) +{ + int w; + uint8_t algo, hitlen; + uint16_t pklen; + + /* read lengths */ + if(*dl < 4) + return -1; + hitlen = (*d)[0]; + algo = (*d)[1]; + pklen = sldns_read_uint16((*d)+2); + if(*dl < (size_t)4 + (size_t)hitlen + (size_t)pklen) + return -1; + + /* write: algo hit pubkey */ + w = sldns_str_print(s, sl, "%u ", (unsigned)algo); + w += print_hex_buf(s, sl, (*d)+4, hitlen); + w += sldns_str_print(s, sl, " "); + (*d)+=4+hitlen; + (*dl)-= (4+hitlen); + w += sldns_wire2str_b64_scan_num(d, dl, s, sl, pklen); + return w; +} + int sldns_wire2str_int16_data_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) { uint16_t n; diff --git a/ldns/wire2str.h b/ldns/wire2str.h index 072d01292..67f543566 100644 --- a/ldns/wire2str.h +++ b/ldns/wire2str.h @@ -770,6 +770,19 @@ int sldns_wire2str_atma_scan(uint8_t** data, size_t* data_len, char** str, int sldns_wire2str_ipseckey_scan(uint8_t** data, size_t* data_len, char** str, size_t* str_len, uint8_t* pkt, size_t pktlen); +/** + * Scan wireformat HIP (algo, HIT, pubkey) field to string, with user buffers. + * It shifts the arguments to move along (see sldns_wire2str_pkt_scan). + * @param data: wireformat data. + * @param data_len: length of data buffer. + * @param str: string buffer. + * @param str_len: length of string buffer. + * @return number of characters (except null) needed to print. + * Can return -1 on failure. + */ +int sldns_wire2str_hip_scan(uint8_t** data, size_t* data_len, char** str, + size_t* str_len); + /** * Scan wireformat int16_data field to string, with user buffers. * It shifts the arguments to move along (see sldns_wire2str_pkt_scan). diff --git a/testdata/test_ldnsrr.c4 b/testdata/test_ldnsrr.c4 index 2dc4a7ebd..78591fcbc 100644 --- a/testdata/test_ldnsrr.c4 +++ b/testdata/test_ldnsrr.c4 @@ -70,8 +70,8 @@ all.rr.org. 3600 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= ee19kl3631qol646kjjrh6lh96pduqii.all.rr.org. 3600 IN NSEC3 1 0 5 6467B16F6F36BA4D 13k9b8dv58kcn28us3fc0lqa60jeadp0 A RRSIG 03616C6C027272036F7267000033000100000E10000D01000005086467B16F6F36BA4D all.rr.org. 3600 IN NSEC3PARAM 1 0 5 6467B16F6F36BA4D -03616C6C027272036F7267000037000100000E10009E02200100107B1A74DF365639CC39F1D57803010001B771CA136E4AEB5CE44333C53B3D2C13C22243851FC708BCCE29F7E2EB5787B5F56CCAD34F8223ACC10904DDB56B2EC4A6D6232F3B50EA094F0914B3B941BBE529AF582C36BBADEFDAF2ADAF9B4911906F5B2522603C615272B880EC8FB930CC6EE39C444DAA75B1678F005A4B2499D1DA5433F805C7A5AD3237ACC5DD5C5E43AEFB1EC5A9A995E728 -all.rr.org. 3600 IN HIP \# 158 02200100107B1A74DF365639CC39F1D57803010001B771CA136E4AEB5CE44333C53B3D2C13C22243851FC708BCCE29F7E2EB5787B5F56CCAD34F8223ACC10904DDB56B2EC4A6D6232F3B50EA094F0914B3B941BBE529AF582C36BBADEFDAF2ADAF9B4911906F5B2522603C615272B880EC8FB930CC6EE39C444DAA75B1678F005A4B2499D1DA5433F805C7A5AD3237ACC5DD5C5E43AEFB1EC5A9A995E728 +03616C6C027272036F7267000037000100000E1000A910020084200100107B1A74DF365639CC39F1D57803010001B771CA136E4AEB5CE44333C53B3D2C13C22243851FC708BCCE29F7E2EB5787B5F56CCAD34F8223ACC10904DDB56B2EC4A6D6232F3B50EA094F0914B3B941BBE529AF582C36BBADEFDAF2ADAF9B4911906F5B2522603C615272B880EC8FB930CC6EE39C444DAA75B1678F005A4B2499D1DA5433F805C7A5AD3237ACC5DD5C5E4303727673076578616D706C6503636F6D00 +all.rr.org. 3600 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs.example.com. 03616C6C027272036F7267000063000100000E10002625763D73706631202B6D7820613A636F6C6F2E6578616D706C652E636F6D2F3238202D616C6C all.rr.org. 3600 IN SPF "v=spf1 +mx a:colo.example.com/28 -all" 03616C6C027272036F7267008001000100000E10001830390301123456789ABCDEF67890123456789ABCDEF67890