]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
happyflow for all signle svcparams
authorTom Carpay <tom@nlnetlabs.nl>
Thu, 20 May 2021 11:28:34 +0000 (13:28 +0200)
committerTom Carpay <tom@nlnetlabs.nl>
Thu, 20 May 2021 11:28:34 +0000 (13:28 +0200)
sldns/str2wire.c
sldns/wire2str.c

index 5a9c5eed845f3be1c41949dc72865908044b4c87..665c6da1d27a3e7da324e379514fff9cfb729e5c 100644 (file)
@@ -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;
        }
index 3fea10fcd63651383510243a2a0ac520ae8c553d..21f6195ce20403941d66eaf4f2d6b4ae2dd34d69 100644 (file)
@@ -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;
 }