&& *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;
}
/* 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) {
/* 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) {
// @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;
}
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 {
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);
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;
}
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 {
}
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);
// @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:
// 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;
}