diff options
Diffstat (limited to 'contrib/ldns/str2host.c')
-rw-r--r-- | contrib/ldns/str2host.c | 382 |
1 files changed, 316 insertions, 66 deletions
diff --git a/contrib/ldns/str2host.c b/contrib/ldns/str2host.c index 51357cc..26cef3d 100644 --- a/contrib/ldns/str2host.c +++ b/contrib/ldns/str2host.c @@ -257,33 +257,48 @@ ldns_str2rdf_int8(ldns_rdf **rd, const char *bytestr) * Returns the number of bytes read from the escaped string, or * 0 on error */ -static int -parse_escape(uint8_t *s, uint8_t *q) { +INLINE bool +parse_escape(uint8_t *ch_p, const char** str_p) +{ uint16_t val; - if (strlen((char *)s) > 3 && - isdigit((int) s[1]) && - isdigit((int) s[2]) && - isdigit((int) s[3])) { - /* cast this so it fits */ - val = (uint16_t) ldns_hexdigit_to_int((char) s[1]) * 100 + - ldns_hexdigit_to_int((char) s[2]) * 10 + - ldns_hexdigit_to_int((char) s[3]); + + if ((*str_p)[0] && isdigit((*str_p)[0]) && + (*str_p)[1] && isdigit((*str_p)[1]) && + (*str_p)[2] && isdigit((*str_p)[2])) { + + val = (uint16_t)(((*str_p)[0] - '0') * 100 + + ((*str_p)[1] - '0') * 10 + + ((*str_p)[2] - '0')); + if (val > 255) { - /* outside range */ - return 0; - } - *q = (uint8_t) val; - return 3; - } else { - s++; - if (*s == '\0' || isdigit((int) *s)) { - /* apparently the string terminator - * or a digit has been escaped... - */ - return 0; + goto error; } - *q = *s; - return 1; + *ch_p = (uint8_t)val; + *str_p += 3; + return true; + + } else if ((*str_p)[0] && !isdigit((*str_p)[0])) { + + *ch_p = (uint8_t)*(*str_p)++; + return true; + } +error: + *str_p = NULL; + return false; /* LDNS_STATUS_SYNTAX_BAD_ESCAPE */ +} + +INLINE bool +parse_char(uint8_t *ch_p, const char** str_p) +{ + switch (**str_p) { + + case '\0': return false; + + case '\\': *str_p += 1; + return parse_escape(ch_p, str_p); + + default: *ch_p = (uint8_t)*(*str_p)++; + return true; } } @@ -297,8 +312,8 @@ ldns_str2rdf_dname(ldns_rdf **d, const char *str) { size_t len; - int esc; - uint8_t *s, *q, *pq, label_len; + const char *s; + uint8_t *q, *pq, label_len; uint8_t buf[LDNS_MAX_DOMAINLEN + 1]; *d = NULL; @@ -328,7 +343,7 @@ ldns_str2rdf_dname(ldns_rdf **d, const char *str) q = buf+1; pq = buf; label_len = 0; - for (s = (uint8_t *)str; *s; s++, q++) { + for (s = str; *s; s++, q++) { if (q > buf + LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } @@ -348,16 +363,15 @@ ldns_str2rdf_dname(ldns_rdf **d, const char *str) break; case '\\': /* octet value or literal char */ - esc = parse_escape(s, q); - if (esc > 0) { - s += esc; - label_len++; - } else { + s += 1; + if (! parse_escape(q, &s)) { return LDNS_STATUS_SYNTAX_BAD_ESCAPE; } + s -= 1; + label_len++; break; default: - *q = *s; + *q = (uint8_t)*s; label_len++; } } @@ -413,36 +427,44 @@ ldns_str2rdf_aaaa(ldns_rdf **rd, const char *str) ldns_status ldns_str2rdf_str(ldns_rdf **rd, const char *str) { - uint8_t *data; - size_t i, str_i, esc_i; + uint8_t *data, *dp, ch = 0; + size_t length; - if (strlen(str) > 255) { - return LDNS_STATUS_INVALID_STR; + /* Worst case space requirement. We'll realloc to actual size later. */ + dp = data = LDNS_XMALLOC(uint8_t, strlen(str) > 255 ? 256 : (strlen(str) + 1)); + if (! data) { + return LDNS_STATUS_MEM_ERR; } - data = LDNS_XMALLOC(uint8_t, strlen(str) + 1); - if(!data) return LDNS_STATUS_MEM_ERR; - i = 1; - - for (str_i = 0; str_i < strlen(str); str_i++) { - if (str[str_i] == '\\') { - /* octet value or literal char */ - esc_i = (size_t) parse_escape((uint8_t*) &str[str_i], (uint8_t*) &data[i]); - if (esc_i == 0) { - LDNS_FREE(data); - return LDNS_STATUS_SYNTAX_BAD_ESCAPE; - } - str_i += esc_i; - } else { - data[i] = (uint8_t) str[str_i]; + /* Fill data (up to 255 characters) */ + while (parse_char(&ch, &str)) { + if (dp - data >= 255) { + LDNS_FREE(data); + return LDNS_STATUS_INVALID_STR; } - i++; + *++dp = ch; + } + if (! str) { + return LDNS_STATUS_SYNTAX_BAD_ESCAPE; } - data[0] = i - 1; - *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_STR, i, data); + length = (size_t)(dp - data); + /* Fix last length byte */ + data[0] = (uint8_t)length; - LDNS_FREE(data); - return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR; + /* Lose the overmeasure */ + data = LDNS_XREALLOC(dp = data, uint8_t, length + 1); + if (! data) { + LDNS_FREE(dp); + return LDNS_STATUS_MEM_ERR; + } + + /* Create rdf */ + *rd = ldns_rdf_new(LDNS_RDF_TYPE_STR, length + 1, data); + if (! *rd) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; } ldns_status @@ -791,15 +813,6 @@ ldns_str2rdf_unknown( ATTR_UNUSED(ldns_rdf **rd) } ldns_status -ldns_str2rdf_tsig( ATTR_UNUSED(ldns_rdf **rd) - , ATTR_UNUSED(const char *str) - ) -{ - /* there is no string representation for TSIG rrs */ - return LDNS_STATUS_NOT_IMPL; -} - -ldns_status ldns_str2rdf_service( ATTR_UNUSED(ldns_rdf **rd) , ATTR_UNUSED(const char *str) ) @@ -1317,3 +1330,240 @@ ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str) if(!*rd) return LDNS_STATUS_MEM_ERR; return LDNS_STATUS_OK; } + +ldns_status +ldns_str2rdf_ilnp64(ldns_rdf **rd, const char *str) +{ + unsigned int a, b, c, d; + uint16_t shorts[4]; + int l; + + if (sscanf(str, "%4x:%4x:%4x:%4x%n", &a, &b, &c, &d, &l) != 4 || + l != (int)strlen(str) || /* more data to read */ + strpbrk(str, "+-") /* signed hexes */ + ) { + return LDNS_STATUS_INVALID_ILNP64; + } else { + shorts[0] = htons(a); + shorts[1] = htons(b); + shorts[2] = htons(c); + shorts[3] = htons(d); + *rd = ldns_rdf_new_frm_data( + LDNS_RDF_TYPE_ILNP64, 4 * sizeof(uint16_t), &shorts); + } + return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; +} + +ldns_status +ldns_str2rdf_eui48(ldns_rdf **rd, const char *str) +{ + unsigned int a, b, c, d, e, f; + uint8_t bytes[6]; + int l; + + if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%n", + &a, &b, &c, &d, &e, &f, &l) != 6 || + l != (int)strlen(str) || /* more data to read */ + strpbrk(str, "+-") /* signed hexes */ + ) { + return LDNS_STATUS_INVALID_EUI48; + } else { + bytes[0] = a; + bytes[1] = b; + bytes[2] = c; + bytes[3] = d; + bytes[4] = e; + bytes[5] = f; + *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_EUI48, 6, &bytes); + } + return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; +} + +ldns_status +ldns_str2rdf_eui64(ldns_rdf **rd, const char *str) +{ + unsigned int a, b, c, d, e, f, g, h; + uint8_t bytes[8]; + int l; + + if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n", + &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 || + l != (int)strlen(str) || /* more data to read */ + strpbrk(str, "+-") /* signed hexes */ + ) { + return LDNS_STATUS_INVALID_EUI64; + } else { + bytes[0] = a; + bytes[1] = b; + bytes[2] = c; + bytes[3] = d; + bytes[4] = e; + bytes[5] = f; + bytes[6] = g; + bytes[7] = h; + *rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_EUI64, 8, &bytes); + } + return *rd ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; +} + +ldns_status +ldns_str2rdf_tag(ldns_rdf **rd, const char *str) +{ + uint8_t *data; + const char* ptr; + + if (strlen(str) > 255) { + return LDNS_STATUS_INVALID_TAG; + } + for (ptr = str; *ptr; ptr++) { + if (! isalnum(*ptr)) { + return LDNS_STATUS_INVALID_TAG; + } + } + data = LDNS_XMALLOC(uint8_t, strlen(str) + 1); + if (!data) { + return LDNS_STATUS_MEM_ERR; + } + data[0] = strlen(str); + memcpy(data + 1, str, strlen(str)); + + *rd = ldns_rdf_new(LDNS_RDF_TYPE_TAG, strlen(str) + 1, data); + if (!*rd) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} + +ldns_status +ldns_str2rdf_long_str(ldns_rdf **rd, const char *str) +{ + uint8_t *data, *dp, ch = 0; + size_t length; + + /* Worst case space requirement. We'll realloc to actual size later. */ + dp = data = LDNS_XMALLOC(uint8_t, strlen(str)); + if (! data) { + return LDNS_STATUS_MEM_ERR; + } + + /* Fill data with parsed bytes */ + while (parse_char(&ch, &str)) { + *dp++ = ch; + if (dp - data > LDNS_MAX_RDFLEN) { + LDNS_FREE(data); + return LDNS_STATUS_INVALID_STR; + } + } + if (! str) { + return LDNS_STATUS_SYNTAX_BAD_ESCAPE; + } + length = (size_t)(dp - data); + + /* Lose the overmeasure */ + data = LDNS_XREALLOC(dp = data, uint8_t, length); + if (! data) { + LDNS_FREE(dp); + return LDNS_STATUS_MEM_ERR; + } + + /* Create rdf */ + *rd = ldns_rdf_new(LDNS_RDF_TYPE_LONG_STR, length, data); + if (! *rd) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} + +ldns_status +ldns_str2rdf_hip(ldns_rdf **rd, const char *str) +{ + const char *hit = strchr(str, ' ') + 1; + const char *pk = hit == NULL ? NULL : strchr(hit, ' ') + 1; + size_t hit_size = hit == NULL ? 0 + : pk == NULL ? strlen(hit) : (size_t) (pk - hit) - 1; + size_t pk_size = pk == NULL ? 0 : strlen(pk); + size_t hit_wire_size = (hit_size + 1) / 2; + size_t pk_wire_size = ldns_b64_pton_calculate_size(pk_size); + size_t rdf_size = 4 + hit_wire_size + pk_wire_size; + + char *endptr; /* utility var for strtol usage */ + int algorithm = strtol(str, &endptr, 10); + + uint8_t *data, *dp; + int hi, lo, written; + + if (hit_size == 0 || pk_size == 0 || (hit_size + 1) / 2 > 255 + || rdf_size > LDNS_MAX_RDFLEN + || algorithm < 0 || algorithm > 255 + || (errno != 0 && algorithm == 0) /* out of range */ + || endptr == str /* no digits */) { + + return LDNS_STATUS_SYNTAX_ERR; + } + if ((data = LDNS_XMALLOC(uint8_t, rdf_size)) == NULL) { + + return LDNS_STATUS_MEM_ERR; + } + /* From RFC 5205 section 5. HIP RR Storage Format: + ************************************************* + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | HIT length | PK algorithm | PK length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + ~ HIT ~ + | | + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + +-+-+-+-+-+-+-+-+-+-+-+ + + | Public Key | + ~ ~ + | | + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + | | + ~ Rendezvous Servers ~ + | | + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + +-+-+-+-+-+-+-+ */ + + data[0] = (uint8_t) hit_wire_size; + data[1] = (uint8_t) algorithm; + + for (dp = data + 4; *hit && *hit != ' '; dp++) { + + if ((hi = ldns_hexdigit_to_int(*hit++)) == -1 || + (lo = ldns_hexdigit_to_int(*hit++)) == -1) { + + LDNS_FREE(data); + return LDNS_STATUS_INVALID_HEX; + } + *dp = (uint8_t) hi << 4 | lo; + } + if ((written = ldns_b64_pton(pk, dp, pk_wire_size)) <= 0) { + + LDNS_FREE(data); + return LDNS_STATUS_INVALID_B64; + } + + /* Because ldns_b64_pton_calculate_size isn't always correct: + * (we have to fix it at some point) + */ + pk_wire_size = (uint16_t) written; + ldns_write_uint16(data + 2, pk_wire_size); + rdf_size = 4 + hit_wire_size + pk_wire_size; + + /* Create rdf */ + if (! (*rd = ldns_rdf_new(LDNS_RDF_TYPE_HIP, rdf_size, data))) { + + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} |