From: Tom Carpay Date: Thu, 20 May 2021 11:28:34 +0000 (+0200) Subject: happyflow for all signle svcparams X-Git-Tag: release-1.13.2rc1~42^2~34 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1a28a276376158f07e90f89b50965960bfe3e48a;p=thirdparty%2Funbound.git happyflow for all signle svcparams --- diff --git a/sldns/str2wire.c b/sldns/str2wire.c index 5a9c5eed8..665c6da1d 100644 --- a/sldns/str2wire.c +++ b/sldns/str2wire.c @@ -1011,13 +1011,14 @@ sldns_str2wire_svcparam_port(const char* val, uint8_t* rd, size_t* rd_len) && *endptr == 0 /* no non-digit chars after digits */ && port <= 65535) { /* no overflow */ - sldns_write_uint16(rd, htons(SVCB_KEY_PORT)); - sldns_write_uint16(rd + 2, htons(sizeof(uint16_t))); - sldns_write_uint16(rd + 4, htons(port)); + sldns_write_uint16(rd, SVCB_KEY_PORT); + sldns_write_uint16(rd + 2, sizeof(uint16_t)); + sldns_write_uint16(rd + 4, port); *rd_len = 6; return LDNS_WIREPARSE_ERR_OK; } + // ERROR: "Could not parse port SvcParamValue" return -1; } @@ -1047,8 +1048,8 @@ sldns_str2wire_svcbparam_ipv4hint(const char* val, uint8_t* rd, size_t* rd_len) /* count is number of comma's in val + 1; so the actual number of IPv4 * addresses in val */ - sldns_write_uint16(rd, htons(SVCB_KEY_IPV4HINT)); - sldns_write_uint16(rd + 2, htons(LDNS_IP4ADDRLEN * count)); + sldns_write_uint16(rd, SVCB_KEY_IPV4HINT); + sldns_write_uint16(rd + 2, LDNS_IP4ADDRLEN * count); *rd_len = 4; while (count) { @@ -1106,8 +1107,8 @@ sldns_str2wire_svcbparam_ipv6hint(const char* val, uint8_t* rd, size_t* rd_len) /* count is number of comma's in val + 1; so the actual number of IPv6 * addresses in val */ - sldns_write_uint16(rd, htons(SVCB_KEY_IPV6HINT)); - sldns_write_uint16(rd + 2, htons(LDNS_IP6ADDRLEN * count)); + sldns_write_uint16(rd, SVCB_KEY_IPV6HINT); + sldns_write_uint16(rd + 2, LDNS_IP6ADDRLEN * count); *rd_len = 4; while (count) { @@ -1169,19 +1170,19 @@ sldns_str2wire_svcbparam_mandatory(const char* val, uint8_t* rd, size_t* rd_len) // @TODO check if we have space to write in rd_len; look for the best spot - sldns_write_uint16(rd, htons(SVCB_KEY_MANDATORY)); - sldns_write_uint16(rd + 2, htons(sizeof(uint16_t) * count)); + sldns_write_uint16(rd, SVCB_KEY_MANDATORY); + sldns_write_uint16(rd + 2, sizeof(uint16_t) * count); *rd_len = 4; - for(;;) { + while (1) { if (!(next_key = strchr(val, ','))) { sldns_write_uint16(rd + *rd_len, - htons(sldns_str2wire_svcparam_key_lookup(val, val_len))); + sldns_str2wire_svcparam_key_lookup(val, val_len)); *rd_len += LDNS_IP6ADDRLEN; break; } else { sldns_write_uint16(rd + *rd_len, - htons(sldns_str2wire_svcparam_key_lookup(val, next_key - val))); + sldns_str2wire_svcparam_key_lookup(val, next_key - val)); *rd_len += LDNS_IP6ADDRLEN; } @@ -1228,7 +1229,7 @@ sldns_str2wire_svcbparam_ech_value(const char* val, uint8_t* rd, size_t* rd_len) if (wire_len == -1) { // zc_error_prev_line("invalid base64 data in ech"); - return LDNS_WIREPARSE_ERR_INVALID_STR; + return LDNS_WIREPARSE_ERR_SYNTAX_B64; } else if (wire_len + 4 > *rd_len) { return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; } else { @@ -1236,16 +1237,104 @@ sldns_str2wire_svcbparam_ech_value(const char* val, uint8_t* rd, size_t* rd_len) sldns_write_uint16(rd + 2, wire_len); memcpy(rd + 4, buffer, wire_len); *rd_len = 4 + wire_len; + return LDNS_WIREPARSE_ERR_OK; } } +static const char* +sldns_str2wire_svcbparam_parse_alpn_next_unescaped_comma(const char *val) +{ + while (*val) { + /* Only return when the comma is not escaped*/ + if (*val == '\\'){ + ++val; + if (!*val) + break; + } else if (*val == ',') + return val; + + val++; + } + return NULL; +} + +static size_t +sldns_str2wire_svcbparam_parse_alpn_copy_unescaped(uint8_t *dst, + const char *src, size_t len) +{ + uint8_t *orig_dst = dst; + + while (len) { + if (*src == '\\') { + src++; + len--; + if (!len) + break; + } + *dst++ = *src++; + len--; + } + return (size_t)(dst - orig_dst); +} + +int sldns_str2wire_svcbparam_alpn_value(const char* val, + uint8_t* rd, size_t* rd_len) +{ + uint8_t unescaped_dst[65536]; + uint8_t *dst = unescaped_dst; + const char *next_str; + size_t str_len; + size_t dst_len; + size_t val_len; + int wire_len; + + val_len = strlen(val); + + if (val_len > sizeof(unescaped_dst)) { + return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW; + } + while (val_len) { + size_t dst_len; + + str_len = (next_str = sldns_str2wire_svcbparam_parse_alpn_next_unescaped_comma(val)) + ? (size_t)(next_str - val) : val_len; + + if (str_len > 255) { + // ERROR "alpn strings need to be smaller than 255 chars" + return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW; + } + dst_len = sldns_str2wire_svcbparam_parse_alpn_copy_unescaped(dst + 1, val, str_len); + *dst++ = dst_len; + dst += dst_len; + + if (!next_str) + break; + + /* skip the comma for the next iteration */ + val_len -= next_str - val + 1; + val = next_str + 1; + } + dst_len = dst - unescaped_dst; + + sldns_write_uint16(rd, SVCB_KEY_ALPN); + sldns_write_uint16(rd + 2, dst_len); + memcpy(rd + 4, unescaped_dst, dst_len); + *rd_len = 4 + dst_len; + + return LDNS_WIREPARSE_ERR_OK; +} + static int sldns_str2wire_svcparam_key_value(const char *key, size_t key_len, const char *val, uint8_t* rd, size_t* rd_len) { uint16_t svcparamkey = sldns_str2wire_svcparam_key_lookup(key, key_len); + + fprintf(stderr, "key: %s\n", key); + fprintf(stderr, "val: %s\n", val); + switch (svcparamkey) { case SVCB_KEY_PORT: return sldns_str2wire_svcparam_port(val, rd, rd_len); @@ -1265,7 +1354,7 @@ sldns_str2wire_svcparam_key_value(const char *key, size_t key_len, case SVCB_KEY_ECH: return sldns_str2wire_svcbparam_ech_value(val, rd, rd_len); case SVCB_KEY_ALPN: - // return sldns_str2wire_svcbparam_alpn_value(val, rd, rd_len); + return sldns_str2wire_svcbparam_alpn_value(val, rd, rd_len); default: break; } diff --git a/sldns/wire2str.c b/sldns/wire2str.c index 3fea10fcd..21f6195ce 100644 --- a/sldns/wire2str.c +++ b/sldns/wire2str.c @@ -950,7 +950,6 @@ static int sldns_print_svcparamkey(char** s, size_t* slen, uint16_t svcparamkey) { if (svcparamkey < SVCPARAMKEY_COUNT) { - // fprintf(stderr, "HERE\n"); return sldns_str_print(s, slen, "%s", svcparamkey_strs[svcparamkey]); } else { @@ -959,106 +958,175 @@ sldns_print_svcparamkey(char** s, size_t* slen, uint16_t svcparamkey) } int sldns_wire2str_svcparam_port2str(char** s, - size_t* slen, uint16_t val_len, uint16_t val) + size_t* slen, uint16_t data_len, uint16_t data) { int w = 0; - if (val_len != 2) + if (data_len != 2) return -1; /* wireformat error, a short is 2 bytes */ - w = sldns_str_print(s, slen, "=%d", (int)ntohs(val)); + w = sldns_str_print(s, slen, "=%d", (int)data); return w; } static int sldns_wire2str_svcparam_ipv4hint2str(char** s, - size_t* slen, uint16_t val_len, uint8_t* data) + size_t* slen, uint16_t data_len, uint8_t* data) { char ip_str[INET_ADDRSTRLEN + 1]; // @TODO actually incorporate this int w = 0; - assert(val_len > 0); + assert(data_len > 0); - if ((val_len % LDNS_IP4ADDRLEN) == 0) { + if ((data_len % LDNS_IP4ADDRLEN) == 0) { if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL) return 0; /* wireformat error, incorrect size or inet family */ - sldns_str_print(s, slen, "=%s", ip_str); + w += sldns_str_print(s, slen, "=%s", ip_str); data += LDNS_IP4ADDRLEN / sizeof(uint16_t); - while ((val_len -= LDNS_IP4ADDRLEN) > 0) { + while ((data_len -= LDNS_IP4ADDRLEN) > 0) { if (inet_ntop(AF_INET, data, ip_str, sizeof(ip_str)) == NULL) return 0; /* wireformat error, incorrect size or inet family */ - sldns_str_print(s, slen, ",%s", ip_str); + w += sldns_str_print(s, slen, ",%s", ip_str); data += LDNS_IP4ADDRLEN / sizeof(uint16_t); } - return 1; - } else - return 0; + } + + return w; } int sldns_wire2str_svcparam_ipv6hint2str(char** s, - size_t* slen, uint16_t val_len, uint8_t* data) + size_t* slen, uint16_t data_len, uint8_t* data) { char ip_str[INET6_ADDRSTRLEN + 1]; - // @TODO actually incorporate this + // @TODO actually incorporate this -> is this correct now? int w = 0; - assert(val_len > 0); + assert(data_len > 0); - if ((val_len % LDNS_IP6ADDRLEN) == 0) { + // @TODO fix ntohs -> see output + + if ((data_len % LDNS_IP6ADDRLEN) == 0) { if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL) return 0; /* wireformat error, incorrect size or inet family */ - sldns_str_print(s, slen, "=%s", ip_str); + w += sldns_str_print(s, slen, "=%s", ip_str); data += LDNS_IP6ADDRLEN / sizeof(uint16_t); - while ((val_len -= LDNS_IP6ADDRLEN) > 0) { + while ((data_len -= LDNS_IP6ADDRLEN) > 0) { if (inet_ntop(AF_INET6, data, ip_str, sizeof(ip_str)) == NULL) return 0; /* wireformat error, incorrect size or inet family */ - sldns_str_print(s, slen, ",%s", ip_str); + w += sldns_str_print(s, slen, ",%s", ip_str); data += LDNS_IP6ADDRLEN / sizeof(uint16_t); } - return 1; - } else - return 0; + } + + return w; } int sldns_wire2str_svcparam_mandatory2str(char** s, - size_t* slen, uint16_t val_len, uint8_t* data) + size_t* slen, uint16_t data_len, uint8_t* data) { int w = 0; - assert(val_len > 0); + assert(data_len > 0); - // if (val_len % sizeof(uint16_t)) - // return 0; // wireformat error, val_len must be multiple of shorts + // if (data_len % sizeof(uint16_t)) + // return 0; // wireformat error, data_len must be multiple of shorts w += sldns_str_print(s, slen, "="); - w += sldns_print_svcparamkey(s, slen, ntohs(sldns_read_uint16(data))); + w += sldns_print_svcparamkey(s, slen, sldns_read_uint16(data)); data += 2; - while ((val_len -= sizeof(uint16_t))) { + while ((data_len -= sizeof(uint16_t))) { w += sldns_str_print(s, slen, ","); - w += sldns_print_svcparamkey(s, slen, ntohs(sldns_read_uint16(data))); + w += sldns_print_svcparamkey(s, slen, sldns_read_uint16(data)); data += 2; } return w; } +int sldns_wire2str_svcparam_alpn2str(char** s, + size_t* slen, uint16_t data_len, uint8_t* data) +{ + uint8_t *dp = (void *)data; + int w = 0; + + assert(data_len > 0); /* Guaranteed by rdata_svcparam_to_string */ + + w += sldns_str_print(s, slen, "=\""); + while (data_len) { + uint8_t i, str_len = *dp++; + + if (str_len > --data_len) + return 0; + + for (i = 0; i < str_len; i++) { + if (dp[i] == '"' || dp[i] == '\\') + w += sldns_str_print(s, slen, "\\\\\\%c", dp[i]); + + else if (dp[i] == ',') + w += sldns_str_print(s, slen, "\\\\%c", dp[i]); + + else if (!isprint(dp[i])) + w += sldns_str_print(s, slen, "\\%03u", (unsigned) dp[i]); + + else + w += sldns_str_print(s, slen, "%c", dp[i]); + } + dp += str_len; + if ((data_len -= str_len)) + w += sldns_str_print(s, slen, "%s", ","); + } + w += sldns_str_print(s, slen, "\""); + + return w; +} + +int sldns_wire2str_svcparam_ech2str(char** s, + size_t* slen, uint16_t data_len, uint8_t* data) +{ + int size; + int w; + + assert(data_len > 0); /* Guaranteed by rdata_svcparam_to_string */ + + w += sldns_str_print(s, slen, "=\""); + + /* b64_ntop_calculate size includes null at the end */ + size = sldns_b64_ntop_calculate_size(data_len); + + fprintf(stderr, "size %d\n", size); + + // @TODO store return value? + sldns_b64_ntop(data, data_len, *s, *slen); + (*s) += size; + (*slen) -= size; + + w += sldns_str_print(s, slen, "\""); + + // @TODO fix check + // if(size > *slen) { + // buffer_skip(output, size); + // } + + return w + size; +} + int sldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen) { - uint16_t svcparamkey, val_len; + uint16_t svcparamkey, data_len; uint8_t* data = *d; int written_chars = 0; if(*dlen == 0) return 0; /* verify that we actualy have data */ - svcparamkey = ntohs(sldns_read_uint16(data)); + svcparamkey = sldns_read_uint16(data); written_chars += sldns_print_svcparamkey(s, slen, svcparamkey); @@ -1066,15 +1134,15 @@ int sldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* sl // @TODO fix this to be dynamic and correct // fprintf(stderr, "*dlen2: %zu\n", *dlen); - // fprintf(stderr, "val_len %zu\n", val_len); + // fprintf(stderr, "data_len %zu\n", data_len); (*dlen) = 0; - val_len = ntohs(sldns_read_uint16(data+2)); + data_len = sldns_read_uint16(data+2); // if (size != val_len + 4) // return 0; wireformat error - // if (!val_len) { + // if (!data_len) { // /* Some SvcParams MUST have values */ // switch (svcparamkey) { // case SVCB_KEY_ALPN: @@ -1087,34 +1155,35 @@ int sldns_wire2str_svcparam_scan(uint8_t** d, size_t* dlen, char** s, size_t* sl // return 1; // } // } + switch (svcparamkey) { case SVCB_KEY_PORT: - written_chars += sldns_wire2str_svcparam_port2str(s, slen, val_len, sldns_read_uint16(data+4)); + written_chars += sldns_wire2str_svcparam_port2str(s, slen, data_len, sldns_read_uint16(data+4)); break; case SVCB_KEY_IPV4HINT: - written_chars += sldns_wire2str_svcparam_ipv4hint2str(s, slen, val_len, data+4); + written_chars += sldns_wire2str_svcparam_ipv4hint2str(s, slen, data_len, data+4); break; case SVCB_KEY_IPV6HINT: - written_chars += sldns_wire2str_svcparam_ipv6hint2str(s, slen, val_len, data+4); + written_chars += sldns_wire2str_svcparam_ipv6hint2str(s, slen, data_len, data+4); break; case SVCB_KEY_MANDATORY: - written_chars += sldns_wire2str_svcparam_mandatory2str(s, slen, val_len, data+4); + written_chars += sldns_wire2str_svcparam_mandatory2str(s, slen, data_len, data+4); break; case SVCB_KEY_NO_DEFAULT_ALPN: return 0; /* wireformat error, should not have a value */ case SVCB_KEY_ALPN: - // written_chars += sldns_wire2str_svcparam_alpn2str(output, val_len, data+2); - // break; + written_chars += sldns_wire2str_svcparam_alpn2str(s, slen, data_len, data+4); + break; case SVCB_KEY_ECH: - // written_chars += sldns_wire2str_svcparam_ech2str(output, val_len, data+2); - // break; + written_chars += sldns_wire2str_svcparam_ech2str(s, slen, data_len, data+4); + break; default: break; } // @TODO set str_len to 0: "If the end of the // * output string is reached, *str_len is set to 0" - // *str_len = 0; + // *slen = 0; return written_chars; }