diff --git a/src/gldns/gbuffer.h b/src/gldns/gbuffer.h index 1b1eb498..32b3f9d1 100644 --- a/src/gldns/gbuffer.h +++ b/src/gldns/gbuffer.h @@ -469,6 +469,30 @@ gldns_buffer_write_at(gldns_buffer *buffer, size_t at, const void *data, size_t memcpy(buffer->_data + at, data, count); } +/** + * set the given byte to the buffer at the specified position + * \param[in] buffer the buffer + * \param[in] at the position (in number of bytes) to write the data at + * \param[in] c the byte to set to the buffer + * \param[in] count the number of bytes of bytes to write + */ + +INLINE void +gldns_buffer_set_at(gldns_buffer *buffer, size_t at, int c, size_t count) +{ + if (!buffer->_vfixed) + assert(gldns_buffer_available_at(buffer, at, count)); + else if (gldns_buffer_remaining_at(buffer, at) == 0) + return; + else if (count > gldns_buffer_remaining_at(buffer, at)) { + memset(buffer->_data + at, c, + gldns_buffer_remaining_at(buffer, at)); + return; + } + memset(buffer->_data + at, c, count); +} + + /** * writes count bytes of data to the current position of the buffer * \param[in] buffer the buffer diff --git a/src/gldns/parse.c b/src/gldns/parse.c index e15b4780..d44c328e 100644 --- a/src/gldns/parse.c +++ b/src/gldns/parse.c @@ -120,6 +120,10 @@ gldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l if (line_nr) { *line_nr = *line_nr + 1; } + if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) { + *t = '\0'; + return -1; + } *t++ = ' '; prev_c = c; continue; diff --git a/src/gldns/rrdef.c b/src/gldns/rrdef.c index 8f84b48f..60b57c31 100644 --- a/src/gldns/rrdef.c +++ b/src/gldns/rrdef.c @@ -175,7 +175,7 @@ static const gldns_rdf_type type_tkey_wireformat[] = { GLDNS_RDF_TYPE_TIME, GLDNS_RDF_TYPE_TIME, GLDNS_RDF_TYPE_INT16, - GLDNS_RDF_TYPE_INT16, + GLDNS_RDF_TYPE_TSIGERROR, GLDNS_RDF_TYPE_INT16_DATA, GLDNS_RDF_TYPE_INT16_DATA, }; @@ -185,7 +185,7 @@ static const gldns_rdf_type type_tsig_wireformat[] = { GLDNS_RDF_TYPE_INT16, GLDNS_RDF_TYPE_INT16_DATA, GLDNS_RDF_TYPE_INT16, - GLDNS_RDF_TYPE_INT16, + GLDNS_RDF_TYPE_TSIGERROR, GLDNS_RDF_TYPE_INT16_DATA }; static const gldns_rdf_type type_tlsa_wireformat[] = { @@ -606,7 +606,7 @@ static gldns_rr_descriptor rdata_field_descriptors[] = { {GLDNS_RR_TYPE_CAA, "CAA", 3, 3, type_caa_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 }, #ifdef DRAFT_RRTYPES /* 258 */ - {GLDNS_RR_TYPE_AVC, "AVC", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 }, + {GLDNS_RR_TYPE_TXT, "AVC", 1, 0, NULL, GLDNS_RDF_TYPE_STR, GLDNS_RR_NO_COMPRESS, 0 }, #else {GLDNS_RR_TYPE_NULL, "TYPE258", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 }, #endif diff --git a/src/gldns/rrdef.h b/src/gldns/rrdef.h index 2bdd336e..b5975aa1 100644 --- a/src/gldns/rrdef.h +++ b/src/gldns/rrdef.h @@ -351,6 +351,9 @@ enum gldns_enum_rdf_type */ GLDNS_RDF_TYPE_LONG_STR, + /** TSIG extended 16bit error value */ + GLDNS_RDF_TYPE_TSIGERROR, + /* Aliases */ GLDNS_RDF_TYPE_BITMAP = GLDNS_RDF_TYPE_NSEC }; @@ -423,7 +426,7 @@ enum gldns_enum_edns_option GLDNS_EDNS_DAU = 5, /* RFC6975 */ GLDNS_EDNS_DHU = 6, /* RFC6975 */ GLDNS_EDNS_N3U = 7, /* RFC6975 */ - GLDNS_EDNS_CLIENT_SUBNET = 8, /* draft-vandergaast-edns-client-subnet */ + GLDNS_EDNS_CLIENT_SUBNET = 8, /* RFC7871 */ GLDNS_EDNS_KEEPALIVE = 11, /* draft-ietf-dnsop-edns-tcp-keepalive*/ GLDNS_EDNS_PADDING = 12 /* RFC7830 */ }; @@ -431,6 +434,15 @@ typedef enum gldns_enum_edns_option gldns_edns_option; #define GLDNS_EDNS_MASK_DO_BIT 0x8000 +/** TSIG and TKEY extended rcodes (16bit), 0-15 are the normal rcodes. */ +#define GLDNS_TSIG_ERROR_NOERROR 0 +#define GLDNS_TSIG_ERROR_BADSIG 16 +#define GLDNS_TSIG_ERROR_BADKEY 17 +#define GLDNS_TSIG_ERROR_BADTIME 18 +#define GLDNS_TSIG_ERROR_BADMODE 19 +#define GLDNS_TSIG_ERROR_BADNAME 20 +#define GLDNS_TSIG_ERROR_BADALG 21 + /** * Contains all information about resource record types. * diff --git a/src/gldns/str2wire.c b/src/gldns/str2wire.c index 08388658..57cbd4d1 100644 --- a/src/gldns/str2wire.c +++ b/src/gldns/str2wire.c @@ -664,6 +664,14 @@ rrinternal_parse_rdata(gldns_buffer* strbuf, char* token, size_t token_len, &pre_data_pos, delimiters, rdftype, &token_strlen)) break; + } else if(rdftype == GLDNS_RDF_TYPE_INT16_DATA && + strcmp(token, "0")!=0) { + /* affix len and b64 fields */ + if(!gldns_affix_token(strbuf, token, + &token_len, "ed, &parens, + &pre_data_pos, delimiters, + rdftype, &token_strlen)) + break; } /* normal RR */ @@ -940,6 +948,8 @@ int gldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len, return gldns_str2wire_time_buf(str, rd, len); case GLDNS_RDF_TYPE_PERIOD: return gldns_str2wire_period_buf(str, rd, len); + case GLDNS_RDF_TYPE_TSIGTIME: + return gldns_str2wire_tsigtime_buf(str, rd, len); case GLDNS_RDF_TYPE_LOC: return gldns_str2wire_loc_buf(str, rd, len); case GLDNS_RDF_TYPE_WKS: @@ -964,6 +974,8 @@ int gldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len, return gldns_str2wire_tag_buf(str, rd, len); case GLDNS_RDF_TYPE_LONG_STR: return gldns_str2wire_long_str_buf(str, rd, len); + case GLDNS_RDF_TYPE_TSIGERROR: + return gldns_str2wire_tsigerror_buf(str, rd, len); case GLDNS_RDF_TYPE_HIP: return gldns_str2wire_hip_buf(str, rd, len); case GLDNS_RDF_TYPE_INT16_DATA: @@ -1341,6 +1353,21 @@ int gldns_str2wire_alg_buf(const char* str, uint8_t* rd, size_t* len) return GLDNS_WIREPARSE_ERR_OK; } +int gldns_str2wire_tsigerror_buf(const char* str, uint8_t* rd, size_t* len) +{ + gldns_lookup_table *lt = gldns_lookup_by_name(gldns_tsig_errors, str); + if(*len < 2) + return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; + if(lt) { + gldns_write_uint16(rd, (uint16_t)lt->id); + *len = 2; + } else { + /* try as-is (a number) */ + return gldns_str2wire_int16_buf(str, rd, len); + } + return GLDNS_WIREPARSE_ERR_OK; +} + int gldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len) { /* convert a time YYYYDDMMHHMMSS to wireformat */ @@ -1383,6 +1410,24 @@ int gldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len) return GLDNS_WIREPARSE_ERR_OK; } +int gldns_str2wire_tsigtime_buf(const char* str, uint8_t* rd, size_t* len) +{ + char* end; + uint64_t t = (uint64_t)strtol((char*)str, &end, 10); + uint16_t high; + uint32_t low; + if(*end != 0) + return RET_ERR(GLDNS_WIREPARSE_ERR_SYNTAX_TIME, end-str); + if(*len < 6) + return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; + high = (uint16_t)(t>>32); + low = (uint32_t)(t); + gldns_write_uint16(rd, high); + gldns_write_uint32(rd+2, low); + *len = 6; + return GLDNS_WIREPARSE_ERR_OK; +} + int gldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len) { const char* end; @@ -2008,13 +2053,26 @@ int gldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len) int gldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len) { - size_t sz = gldns_b64_pton_calculate_size(strlen(str)); + char* s; int n; - if(*len < sz+2) + n = strtol(str, &s, 10); + if(*len < ((size_t)n)+2) return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; - if(sz > 65535) + if(n > 65535) return GLDNS_WIREPARSE_ERR_LABEL_OVERFLOW; - n = gldns_b64_pton(str, rd+2, (*len)-2); + + if(n == 0) { + gldns_write_uint16(rd, 0); + *len = 2; + return GLDNS_WIREPARSE_ERR_OK; + } + if(*s != ' ') + return RET_ERR(GLDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str); + s++; + while(*s == ' ') + s++; + + n = gldns_b64_pton(s, rd+2, (*len)-2); if(n < 0) return GLDNS_WIREPARSE_ERR_SYNTAX_B64; gldns_write_uint16(rd, (uint16_t)n); diff --git a/src/gldns/str2wire.h b/src/gldns/str2wire.h index e9360447..23094b6c 100644 --- a/src/gldns/str2wire.h +++ b/src/gldns/str2wire.h @@ -417,6 +417,24 @@ int gldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len); */ int gldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len); +/** + * Convert rdf of type GLDNS_RDF_TYPE_TSIGTIME 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 gldns_str2wire_tsigtime_buf(const char* str, uint8_t* rd, size_t* len); + +/** + * Convert rdf of type GLDNS_RDF_TYPE_TSIGERROR 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 gldns_str2wire_tsigerror_buf(const char* str, uint8_t* rd, size_t* len); + /** * Convert rdf of type GLDNS_RDF_TYPE_LOC from string to wireformat. * @param str: the text to convert for this rdata element. diff --git a/src/gldns/wire2str.c b/src/gldns/wire2str.c index b89f044a..29dcfe80 100644 --- a/src/gldns/wire2str.c +++ b/src/gldns/wire2str.c @@ -173,6 +173,28 @@ static gldns_lookup_table gldns_edns_options_data[] = { }; gldns_lookup_table* gldns_edns_options = gldns_edns_options_data; +static gldns_lookup_table gldns_tsig_errors_data[] = { + { GLDNS_TSIG_ERROR_NOERROR, "NOERROR" }, + { GLDNS_RCODE_FORMERR, "FORMERR" }, + { GLDNS_RCODE_SERVFAIL, "SERVFAIL" }, + { GLDNS_RCODE_NXDOMAIN, "NXDOMAIN" }, + { GLDNS_RCODE_NOTIMPL, "NOTIMPL" }, + { GLDNS_RCODE_REFUSED, "REFUSED" }, + { GLDNS_RCODE_YXDOMAIN, "YXDOMAIN" }, + { GLDNS_RCODE_YXRRSET, "YXRRSET" }, + { GLDNS_RCODE_NXRRSET, "NXRRSET" }, + { GLDNS_RCODE_NOTAUTH, "NOTAUTH" }, + { GLDNS_RCODE_NOTZONE, "NOTZONE" }, + { GLDNS_TSIG_ERROR_BADSIG, "BADSIG" }, + { GLDNS_TSIG_ERROR_BADKEY, "BADKEY" }, + { GLDNS_TSIG_ERROR_BADTIME, "BADTIME" }, + { GLDNS_TSIG_ERROR_BADMODE, "BADMODE" }, + { GLDNS_TSIG_ERROR_BADNAME, "BADNAME" }, + { GLDNS_TSIG_ERROR_BADALG, "BADALG" }, + { 0, NULL } +}; +gldns_lookup_table* gldns_tsig_errors = gldns_tsig_errors_data; + char* gldns_wire2str_pkt(uint8_t* data, size_t len) { size_t slen = (size_t)gldns_wire2str_pkt_buf(data, len, NULL, 0); @@ -285,6 +307,12 @@ int gldns_wire2str_rcode_buf(int rcode, char* s, size_t slen) return gldns_wire2str_rcode_print(&s, &slen, rcode); } +int gldns_wire2str_opcode_buf(int opcode, char* s, size_t slen) +{ + /* use arguments as temporary variables */ + return gldns_wire2str_opcode_print(&s, &slen, opcode); +} + int gldns_wire2str_dname_buf(uint8_t* d, size_t dlen, char* s, size_t slen) { /* use arguments as temporary variables */ @@ -982,6 +1010,8 @@ int gldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen, return gldns_wire2str_tag_scan(d, dlen, s, slen); case GLDNS_RDF_TYPE_LONG_STR: return gldns_wire2str_long_str_scan(d, dlen, s, slen); + case GLDNS_RDF_TYPE_TSIGERROR: + return gldns_wire2str_tsigerror_scan(d, dlen, s, slen); } /* unknown rdf type */ return -1; @@ -1580,6 +1610,7 @@ int gldns_wire2str_hip_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) int gldns_wire2str_int16_data_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) { + int w; uint16_t n; if(*dl < 2) return -1; @@ -1588,7 +1619,12 @@ int gldns_wire2str_int16_data_scan(uint8_t** d, size_t* dl, char** s, size_t* sl return -1; (*d)+=2; (*dl)-=2; - return gldns_wire2str_b64_scan_num(d, dl, s, sl, n); + if(n == 0) { + return gldns_str_print(s, sl, "0"); + } + w = gldns_str_print(s, sl, "%u ", (unsigned)n); + w += gldns_wire2str_b64_scan_num(d, dl, s, sl, n); + return w; } int gldns_wire2str_nsec3_next_owner_scan(uint8_t** d, size_t* dl, char** s, @@ -1645,10 +1681,10 @@ int gldns_wire2str_tag_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) if(*dl < 1+n) return -1; for(i=0; iname) + w = gldns_str_print(s, sl, "%s", lt->name); + else w = gldns_str_print(s, sl, "%d", data); + (*dl)-=2; + (*d)+=2; + return w; +} + int gldns_wire2str_edns_llq_print(char** s, size_t* sl, uint8_t* data, size_t len) { diff --git a/src/gldns/wire2str.h b/src/gldns/wire2str.h index a4409991..2007fd8e 100644 --- a/src/gldns/wire2str.h +++ b/src/gldns/wire2str.h @@ -38,6 +38,8 @@ extern struct gldns_struct_lookup_table* gldns_edns_flags; extern struct gldns_struct_lookup_table* gldns_edns_options; /** error string from wireparse */ extern struct gldns_struct_lookup_table* gldns_wireparse_errors; +/** tsig errors are the rcodes with extra (higher) values */ +extern struct gldns_struct_lookup_table* gldns_tsig_errors; /** * Convert wireformat packet to a string representation @@ -441,6 +443,17 @@ int gldns_wire2str_class_buf(uint16_t rrclass, char* str, size_t len); */ int gldns_wire2str_rcode_buf(int rcode, char* str, size_t len); +/** + * Convert host format opcode to a string. 'QUERY', 'NOTIFY', 'UPDATE'. + * With user buffer. + * @param opcode: opcode as integer in host order + * @param str: the string to write to. + * @param len: length of str. + * @return the number of characters for this element, excluding zerobyte. + * Is larger or equal than str_len if output was truncated. + */ +int gldns_wire2str_opcode_buf(int opcode, char* str, size_t len); + /** * Convert wire dname to a string, "example.com.". With user buffer. * @param dname: the dname in uncompressed wireformat. @@ -796,6 +809,19 @@ int gldns_wire2str_hip_scan(uint8_t** data, size_t* data_len, char** str, int gldns_wire2str_int16_data_scan(uint8_t** data, size_t* data_len, char** str, size_t* str_len); +/** + * Scan wireformat tsigerror field to string, with user buffers. + * It shifts the arguments to move along (see gldns_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 gldns_wire2str_tsigerror_scan(uint8_t** data, size_t* data_len, char** str, + size_t* str_len); + /** * Scan wireformat nsec3_next_owner field to string, with user buffers. * It shifts the arguments to move along (see gldns_wire2str_pkt_scan).