From b181782e0e9554c49e0f8031696e985f91954df7 Mon Sep 17 00:00:00 2001 From: Willem Toorop Date: Thu, 11 Aug 2022 11:30:34 +0200 Subject: [PATCH] Update gldns --- src/gldns/parse.c | 57 ++++++++++++++++++++++++++++++++++++------- src/gldns/parseutil.c | 40 ++++++++++++++++++++++++++---- src/gldns/parseutil.h | 4 ++- src/gldns/pkthdr.h | 4 +++ src/gldns/rrdef.c | 4 +-- src/gldns/rrdef.h | 32 ++++++++++++++++++++++++ src/gldns/str2wire.c | 40 ++++++++++++++++++++---------- src/gldns/wire2str.c | 3 ++- 8 files changed, 153 insertions(+), 31 deletions(-) diff --git a/src/gldns/parse.c b/src/gldns/parse.c index 6e0a4ec4..367fa80f 100644 --- a/src/gldns/parse.c +++ b/src/gldns/parse.c @@ -13,7 +13,7 @@ #include "gldns/gbuffer.h" #include -#include +#include gldns_lookup_table gldns_directive_types[] = { { GLDNS_DIR_TTL, "$TTL" }, @@ -34,7 +34,7 @@ gldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l { int c, prev_c; int p; /* 0 -> no parentheses seen, >0 nr of ( seen */ - int com, quoted; + int com, quoted, only_blank; char *t; size_t i; const char *d; @@ -53,6 +53,7 @@ gldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l com = 0; quoted = 0; prev_c = 0; + only_blank = 1; /* Assume we got only until now */ t = token; if (del[0] == '"') { quoted = 1; @@ -101,6 +102,22 @@ 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 (only_blank && i > 0) { + /* Got only so far. Reset and try + * again with the next line. + */ + i = 0; + t = token; + } + if (p == 0) { + /* If p != 0 then the next line is a continuation. So + * we assume that the next line starts with a blank only + * if it is actually a new line. + */ + only_blank = 1; /* Assume next line starts with + * . + */ + } if (p == 0 && i > 0) { goto tokenread; } else { @@ -131,12 +148,29 @@ gldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l /* check if we hit the delim */ for (d = del; *d; d++) { - if (c == *d && i > 0 && prev_c != '\\' && p == 0) { - if (c == '\n' && line_nr) { - *line_nr = *line_nr + 1; - } - goto tokenread; + if (c == *d) + break; + } + + if (c == *d && i > 0 && prev_c != '\\' && p == 0) { + if (c == '\n' && line_nr) { + *line_nr = *line_nr + 1; } + if (only_blank) { + /* Got only so far. Reset and + * try again with the next line. + */ + i = 0; + t = token; + only_blank = 1; + prev_c = c; + continue; + } + goto tokenread; + } + if (c != ' ' && c != '\t') { + /* Found something that is not */ + only_blank= 0; } if (c != '\0' && c != '\n') { i++; @@ -149,8 +183,13 @@ gldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l if (c != '\0' && c != '\n') { *t++ = c; } - if (c == '\n' && line_nr) { - *line_nr = *line_nr + 1; + if (c == '\n') { + if (line_nr) { + *line_nr = *line_nr + 1; + } + only_blank = 1; /* Assume next line starts with + * . + */ } if (c == '\\' && prev_c == '\\') prev_c = 0; diff --git a/src/gldns/parseutil.c b/src/gldns/parseutil.c index 4730057d..293496a9 100644 --- a/src/gldns/parseutil.c +++ b/src/gldns/parseutil.c @@ -14,12 +14,8 @@ #include "config.h" #include "gldns/parseutil.h" -#ifdef HAVE_SYS_TIME_H #include -#endif -#ifdef HAVE_TIME_H #include -#endif #include gldns_lookup_table * @@ -213,11 +209,13 @@ gldns_hexdigit_to_int(char ch) } uint32_t -gldns_str2period(const char *nptr, const char **endptr) +gldns_str2period(const char *nptr, const char **endptr, int* overflow) { int sign = 0; uint32_t i = 0; uint32_t seconds = 0; + const uint32_t maxint = 0xffffffff; + *overflow = 0; for(*endptr = nptr; **endptr; (*endptr)++) { switch (**endptr) { @@ -240,26 +238,46 @@ gldns_str2period(const char *nptr, const char **endptr) break; case 's': case 'S': + if(seconds > maxint-i) { + *overflow = 1; + return 0; + } seconds += i; i = 0; break; case 'm': case 'M': + if(i > maxint/60 || seconds > maxint-(i*60)) { + *overflow = 1; + return 0; + } seconds += i * 60; i = 0; break; case 'h': case 'H': + if(i > maxint/(60*60) || seconds > maxint-(i*60*60)) { + *overflow = 1; + return 0; + } seconds += i * 60 * 60; i = 0; break; case 'd': case 'D': + if(i > maxint/(60*60*24) || seconds > maxint-(i*60*60*24)) { + *overflow = 1; + return 0; + } seconds += i * 60 * 60 * 24; i = 0; break; case 'w': case 'W': + if(i > maxint/(60*60*24*7) || seconds > maxint-(i*60*60*24*7)) { + *overflow = 1; + return 0; + } seconds += i * 60 * 60 * 24 * 7; i = 0; break; @@ -273,15 +291,27 @@ gldns_str2period(const char *nptr, const char **endptr) case '7': case '8': case '9': + if(i > maxint/10 || i*10 > maxint - (**endptr - '0')) { + *overflow = 1; + return 0; + } i *= 10; i += (**endptr - '0'); break; default: + if(seconds > maxint-i) { + *overflow = 1; + return 0; + } seconds += i; /* disregard signedness */ return seconds; } } + if(seconds > maxint-i) { + *overflow = 1; + return 0; + } seconds += i; /* disregard signedness */ return seconds; diff --git a/src/gldns/parseutil.h b/src/gldns/parseutil.h index 8a23de00..0ce93d5a 100644 --- a/src/gldns/parseutil.h +++ b/src/gldns/parseutil.h @@ -74,9 +74,11 @@ struct tm * gldns_serial_arithmetics_gmtime_r(int32_t time, time_t now, struct t * converts a ttl value (like 5d2h) to a long. * \param[in] nptr the start of the string * \param[out] endptr points to the last char in case of error + * \param[out] overflow returns if the string causes integer overflow error, + * the number is too big, string of digits too long. * \return the convert duration value */ -uint32_t gldns_str2period(const char *nptr, const char **endptr); +uint32_t gldns_str2period(const char *nptr, const char **endptr, int* overflow); /** * Returns the int value of the given (hex) digit diff --git a/src/gldns/pkthdr.h b/src/gldns/pkthdr.h index d2572d12..a0b99717 100644 --- a/src/gldns/pkthdr.h +++ b/src/gldns/pkthdr.h @@ -97,18 +97,22 @@ extern "C" { #define QDCOUNT(wirebuf) (ntohs(*(uint16_t *)(wirebuf+QDCOUNT_OFF))) */ #define GLDNS_QDCOUNT(wirebuf) (gldns_read_uint16(wirebuf+GLDNS_QDCOUNT_OFF)) +#define GLDNS_QDCOUNT_SET(wirebuf, i) (gldns_write_uint16(wirebuf+GLDNS_QDCOUNT_OFF, i)) /* Counter of the answer section */ #define GLDNS_ANCOUNT_OFF 6 #define GLDNS_ANCOUNT(wirebuf) (gldns_read_uint16(wirebuf+GLDNS_ANCOUNT_OFF)) +#define GLDNS_ANCOUNT_SET(wirebuf, i) (gldns_write_uint16(wirebuf+GLDNS_ANCOUNT_OFF, i)) /* Counter of the authority section */ #define GLDNS_NSCOUNT_OFF 8 #define GLDNS_NSCOUNT(wirebuf) (gldns_read_uint16(wirebuf+GLDNS_NSCOUNT_OFF)) +#define GLDNS_NSCOUNT_SET(wirebuf, i) (gldns_write_uint16(wirebuf+GLDNS_NSCOUNT_OFF, i)) /* Counter of the additional section */ #define GLDNS_ARCOUNT_OFF 10 #define GLDNS_ARCOUNT(wirebuf) (gldns_read_uint16(wirebuf+GLDNS_ARCOUNT_OFF)) +#define GLDNS_ARCOUNT_SET(wirebuf, i) (gldns_write_uint16(wirebuf+GLDNS_ARCOUNT_OFF, i)) /** * The sections of a packet diff --git a/src/gldns/rrdef.c b/src/gldns/rrdef.c index 1b8c02fe..53a7f18f 100644 --- a/src/gldns/rrdef.c +++ b/src/gldns/rrdef.c @@ -392,9 +392,9 @@ static gldns_rr_descriptor rdata_field_descriptors[] = { /* 63 */ {GLDNS_RR_TYPE_ZONEMD, "ZONEMD", 4, 4, type_zonemd_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 }, /* 64 */ - {GLDNS_RR_TYPE_SVCB, "SVCB", 2, 2, type_svcb_wireformat, GLDNS_RDF_TYPE_SVCPARAM, GLDNS_RR_NO_COMPRESS, 0 }, + {GLDNS_RR_TYPE_SVCB, "SVCB", 2, 2, type_svcb_wireformat, GLDNS_RDF_TYPE_SVCPARAM, GLDNS_RR_NO_COMPRESS, 1 }, /* 65 */ - {GLDNS_RR_TYPE_HTTPS, "HTTPS", 2, 2, type_svcb_wireformat, GLDNS_RDF_TYPE_SVCPARAM, GLDNS_RR_NO_COMPRESS, 0 }, + {GLDNS_RR_TYPE_HTTPS, "HTTPS", 2, 2, type_svcb_wireformat, GLDNS_RDF_TYPE_SVCPARAM, GLDNS_RR_NO_COMPRESS, 1 }, {(enum gldns_enum_rr_type)0, "TYPE66", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 }, {(enum gldns_enum_rr_type)0, "TYPE67", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 }, {(enum gldns_enum_rr_type)0, "TYPE68", 1, 1, type_0_wireformat, GLDNS_RDF_TYPE_NONE, GLDNS_RR_NO_COMPRESS, 0 }, diff --git a/src/gldns/rrdef.h b/src/gldns/rrdef.h index 1ddf854d..fe9bf7bf 100644 --- a/src/gldns/rrdef.h +++ b/src/gldns/rrdef.h @@ -440,10 +440,42 @@ enum gldns_enum_edns_option GLDNS_EDNS_CLIENT_SUBNET = 8, /* RFC7871 */ GLDNS_EDNS_KEEPALIVE = 11, /* draft-ietf-dnsop-edns-tcp-keepalive*/ GLDNS_EDNS_PADDING = 12, /* RFC7830 */ + GLDNS_EDNS_EDE = 15, /* RFC8914 */ GLDNS_EDNS_CLIENT_TAG = 16 /* draft-bellis-dnsop-edns-tags-01 */ }; typedef enum gldns_enum_edns_option gldns_edns_option; +enum gldns_enum_ede_code +{ + GLDNS_EDE_NONE = -1, /* EDE undefined for internal use */ + GLDNS_EDE_OTHER = 0, + GLDNS_EDE_UNSUPPORTED_DNSKEY_ALG = 1, + GLDNS_EDE_UNSUPPORTED_DS_DIGEST = 2, + GLDNS_EDE_STALE_ANSWER = 3, + GLDNS_EDE_FORGED_ANSWER = 4, + GLDNS_EDE_DNSSEC_INDETERMINATE = 5, + GLDNS_EDE_DNSSEC_BOGUS = 6, + GLDNS_EDE_SIGNATURE_EXPIRED = 7, + GLDNS_EDE_SIGNATURE_NOT_YET_VALID = 8, + GLDNS_EDE_DNSKEY_MISSING = 9, + GLDNS_EDE_RRSIGS_MISSING = 10, + GLDNS_EDE_NO_ZONE_KEY_BIT_SET = 11, + GLDNS_EDE_NSEC_MISSING = 12, + GLDNS_EDE_CACHED_ERROR = 13, + GLDNS_EDE_NOT_READY = 14, + GLDNS_EDE_BLOCKED = 15, + GLDNS_EDE_CENSORED = 16, + GLDNS_EDE_FILTERED = 17, + GLDNS_EDE_PROHIBITED = 18, + GLDNS_EDE_STALE_NXDOMAIN_ANSWER = 19, + GLDNS_EDE_NOT_AUTHORITATIVE = 20, + GLDNS_EDE_NOT_SUPPORTED = 21, + GLDNS_EDE_NO_REACHABLE_AUTHORITY = 22, + GLDNS_EDE_NETWORK_ERROR = 23, + GLDNS_EDE_INVALID_DATA = 24, +}; +typedef enum gldns_enum_ede_code gldns_ede_code; + #define GLDNS_EDNS_MASK_DO_BIT 0x8000 /** TSIG and TKEY extended rcodes (16bit), 0-15 are the normal rcodes. */ diff --git a/src/gldns/str2wire.c b/src/gldns/str2wire.c index fa5f1344..9dd623e1 100644 --- a/src/gldns/str2wire.c +++ b/src/gldns/str2wire.c @@ -250,11 +250,16 @@ rrinternal_get_ttl(gldns_buffer* strbuf, char* token, size_t token_len, int* not_there, uint32_t* ttl, uint32_t default_ttl) { const char* endptr; + int overflow; if(gldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { return RET_ERR(GLDNS_WIREPARSE_ERR_SYNTAX_TTL, gldns_buffer_position(strbuf)); } - *ttl = (uint32_t) gldns_str2period(token, &endptr); + *ttl = (uint32_t) gldns_str2period(token, &endptr, &overflow); + if(overflow) { + return RET_ERR(GLDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW, + gldns_buffer_position(strbuf)); + } if (strlen(token) > 0 && !isdigit((unsigned char)token[0])) { *not_there = 1; @@ -374,7 +379,8 @@ rrinternal_get_quoted(gldns_buffer* strbuf, const char** delimiters, /* skip spaces */ while(gldns_buffer_remaining(strbuf) > 0 && - *(gldns_buffer_current(strbuf)) == ' ') { + (*(gldns_buffer_current(strbuf)) == ' ' || + *(gldns_buffer_current(strbuf)) == '\t')) { gldns_buffer_skip(strbuf, 1); } @@ -607,7 +613,7 @@ gldns_affix_token(gldns_buffer* strbuf, char* token, size_t* token_len, /* add space */ /* when addlen < 2, the token buffer is full considering the NULL byte * from strlen and will lead to buffer overflow with the second - * assignement below. */ + * assignment below. */ if(addlen < 2) return 0; token[*token_strlen] = ' '; token[++(*token_strlen)] = 0; @@ -671,10 +677,10 @@ static int gldns_str2wire_check_svcbparams(uint8_t* rdata, uint16_t rdata_len) ,gldns_str2wire_svcparam_key_cmp); - /* The code below revolves around sematic errors in the SVCParam set. + /* The code below revolves around semantic errors in the SVCParam set. * So long as we do not distinguish between running Unbound as a primary * or as a secondary, we default to secondary behavior and we ignore the - * sematic errors. */ + * semantic errors. */ #ifdef SVCB_SEMANTIC_ERRORS { @@ -776,7 +782,8 @@ rrinternal_parse_rdata(gldns_buffer* strbuf, char* token, size_t token_len, /* unknown RR data */ if(token_strlen>=2 && strncmp(token, "\\#", 2) == 0 && - !quoted && (token_strlen == 2 || token[2]==' ')) { + !quoted && (token_strlen == 2 || token[2]==' ' || + token[2]=='\t')) { was_unknown_rr_format = 1; if((status=rrinternal_parse_unknown(strbuf, token, token_len, rr, rr_len, &rr_cur_len, @@ -894,7 +901,7 @@ gldns_str2wire_rr_buf_internal(const char* str, uint8_t* rr, size_t* len, { int status; int not_there = 0; - char token[GLDNS_MAX_RDFLEN+1] = ""; + char token[GLDNS_MAX_RDFLEN+1]; uint32_t ttl = 0; uint16_t tp = 0, cl = 0; size_t ddlen = 0; @@ -1056,12 +1063,15 @@ int gldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len, return s; } else if(strncmp(line, "$TTL", 4) == 0 && isspace((unsigned char)line[4])) { const char* end = NULL; + int overflow = 0; strlcpy((char*)rr, line, *len); *len = 0; *dname_len = 0; if(!parse_state) return GLDNS_WIREPARSE_ERR_OK; parse_state->default_ttl = gldns_str2period( - gldns_strip_ws(line+5), &end); + gldns_strip_ws(line+5), &end, &overflow); + if(overflow) + return GLDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW; } else if (strncmp(line, "$INCLUDE", 8) == 0) { strlcpy((char*)rr, line, *len); *len = 0; @@ -1118,7 +1128,7 @@ gldns_str2wire_svcparam_key_lookup(const char *key, size_t key_len) if (!strncmp(key, "mandatory", sizeof("mandatory")-1)) return SVCB_KEY_MANDATORY; if (!strncmp(key, "echconfig", sizeof("echconfig")-1)) - return SVCB_KEY_ECH; /* allow "echconfig as well as "ech" */ + return SVCB_KEY_ECH; /* allow "echconfig" as well as "ech" */ break; case sizeof("alpn")-1: @@ -1357,7 +1367,7 @@ gldns_str2wire_svcbparam_mandatory(const char* val, uint8_t* rd, size_t* rd_len) */ qsort((void *)(rd + 4), count, sizeof(uint16_t), gldns_network_uint16_cmp); - /* The code below revolves around sematic errors in the SVCParam set. + /* The code below revolves around semantic errors in the SVCParam set. * So long as we do not distinguish between running Unbound as a primary * or as a secondary, we default to secondary behavior and we ignore the * semantic errors. */ @@ -1589,12 +1599,12 @@ static int gldns_str2wire_svcparam_buf(const char* str, uint8_t* rd, size_t* rd_ if (*val_in == '"') { val_in++; while (*val_in != '"' - && (unsigned)(val_out - unescaped_val + 1) < sizeof(unescaped_val) + && (size_t)(val_out - unescaped_val + 1) < sizeof(unescaped_val) && gldns_parse_char( (uint8_t*) val_out, &val_in)) { val_out++; } } else { - while ((unsigned)(val_out - unescaped_val + 1) < sizeof(unescaped_val) + while ((size_t)(val_out - unescaped_val + 1) < sizeof(unescaped_val) && gldns_parse_char( (uint8_t*) val_out, &val_in)) { val_out++; } @@ -2160,9 +2170,13 @@ int gldns_str2wire_tsigtime_buf(const char* str, uint8_t* rd, size_t* len) int gldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len) { const char* end; - uint32_t p = gldns_str2period(str, &end); + int overflow; + uint32_t p = gldns_str2period(str, &end, &overflow); if(*end != 0) return RET_ERR(GLDNS_WIREPARSE_ERR_SYNTAX_PERIOD, end-str); + if(overflow) + return RET_ERR(GLDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW, + end-str); if(*len < 4) return GLDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; gldns_write_uint32(rd, p); diff --git a/src/gldns/wire2str.c b/src/gldns/wire2str.c index 7b0a7095..bba13b42 100644 --- a/src/gldns/wire2str.c +++ b/src/gldns/wire2str.c @@ -196,6 +196,7 @@ static gldns_lookup_table gldns_edns_options_data[] = { { 8, "edns-client-subnet" }, { 11, "edns-tcp-keepalive"}, { 12, "Padding" }, + { 15, "EDE"}, { 0, NULL} }; gldns_lookup_table* gldns_edns_options = gldns_edns_options_data; @@ -1072,7 +1073,7 @@ static int gldns_wire2str_svcparam_mandatory2str(char** s, assert(data_len > 0); if (data_len % sizeof(uint16_t)) - return -1; // wireformat error, data_len must be multiple of shorts + return -1; /* wireformat error, data_len must be multiple of shorts */ w += gldns_str_print(s, slen, "="); w += gldns_print_svcparamkey(s, slen, gldns_read_uint16(data)); data += 2;