diff options
Diffstat (limited to 'rdata.c')
-rw-r--r-- | rdata.c | 675 |
1 files changed, 675 insertions, 0 deletions
diff --git a/rdata.c b/rdata.c new file mode 100644 index 000000000000..8af16a13a1c2 --- /dev/null +++ b/rdata.c @@ -0,0 +1,675 @@ +/* + * rdata.c + * + * rdata implementation + * + * a Net::DNS like library for C + * + * (c) NLnet Labs, 2004-2006 + * + * See the file LICENSE for the license + */ + +#include <ldns/config.h> + +#include <ldns/ldns.h> + +/* + * Access functions + * do this as functions to get type checking + */ + +/* read */ +size_t +ldns_rdf_size(const ldns_rdf *rd) +{ + assert(rd != NULL); + return rd->_size; +} + +ldns_rdf_type +ldns_rdf_get_type(const ldns_rdf *rd) +{ + assert(rd != NULL); + return rd->_type; +} + +uint8_t * +ldns_rdf_data(const ldns_rdf *rd) +{ + assert(rd != NULL); + return rd->_data; +} + +/* write */ +void +ldns_rdf_set_size(ldns_rdf *rd, size_t size) +{ + assert(rd != NULL); + rd->_size = size; +} + +void +ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type) +{ + assert(rd != NULL); + rd->_type = type; +} + +void +ldns_rdf_set_data(ldns_rdf *rd, void *data) +{ + /* only copy the pointer */ + assert(rd != NULL); + rd->_data = data; +} + +/* for types that allow it, return + * the native/host order type */ +uint8_t +ldns_rdf2native_int8(const ldns_rdf *rd) +{ + uint8_t data; + + /* only allow 8 bit rdfs */ + if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_BYTE) { + return 0; + } + + memcpy(&data, ldns_rdf_data(rd), sizeof(data)); + return data; +} + +uint16_t +ldns_rdf2native_int16(const ldns_rdf *rd) +{ + uint16_t data; + + /* only allow 16 bit rdfs */ + if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_WORD) { + return 0; + } + + memcpy(&data, ldns_rdf_data(rd), sizeof(data)); + return ntohs(data); +} + +uint32_t +ldns_rdf2native_int32(const ldns_rdf *rd) +{ + uint32_t data; + + /* only allow 32 bit rdfs */ + if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD) { + return 0; + } + + memcpy(&data, ldns_rdf_data(rd), sizeof(data)); + return ntohl(data); +} + +time_t +ldns_rdf2native_time_t(const ldns_rdf *rd) +{ + uint32_t data; + + switch(ldns_rdf_get_type(rd)) { + case LDNS_RDF_TYPE_TIME: + memcpy(&data, ldns_rdf_data(rd), sizeof(data)); + return (time_t)ntohl(data); + default: + return 0; + } +} + +ldns_rdf * +ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value) +{ + return ldns_rdf_new_frm_data(type, LDNS_RDF_SIZE_BYTE, &value); +} + +ldns_rdf * +ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value) +{ + uint16_t *rdf_data = LDNS_XMALLOC(uint16_t, 1); + ldns_rdf* rdf; + if (!rdf_data) { + return NULL; + } + ldns_write_uint16(rdf_data, value); + rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_WORD, rdf_data); + if(!rdf) + LDNS_FREE(rdf_data); + return rdf; +} + +ldns_rdf * +ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value) +{ + uint32_t *rdf_data = LDNS_XMALLOC(uint32_t, 1); + ldns_rdf* rdf; + if (!rdf_data) { + return NULL; + } + ldns_write_uint32(rdf_data, value); + rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_DOUBLEWORD, rdf_data); + if(!rdf) + LDNS_FREE(rdf_data); + return rdf; +} + +ldns_rdf * +ldns_native2rdf_int16_data(size_t size, uint8_t *data) +{ + uint8_t *rdf_data = LDNS_XMALLOC(uint8_t, size + 2); + ldns_rdf* rdf; + if (!rdf_data) { + return NULL; + } + ldns_write_uint16(rdf_data, size); + memcpy(rdf_data + 2, data, size); + rdf = ldns_rdf_new(LDNS_RDF_TYPE_INT16_DATA, size + 2, rdf_data); + if(!rdf) + LDNS_FREE(rdf_data); + return rdf; +} + +/* note: data must be allocated memory */ +ldns_rdf * +ldns_rdf_new(ldns_rdf_type type, size_t size, void *data) +{ + ldns_rdf *rd; + rd = LDNS_MALLOC(ldns_rdf); + if (!rd) { + return NULL; + } + ldns_rdf_set_size(rd, size); + ldns_rdf_set_type(rd, type); + ldns_rdf_set_data(rd, data); + return rd; +} + +ldns_rdf * +ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data) +{ + ldns_rdf *rdf; + + /* if the size is too big, fail */ + if (size > LDNS_MAX_RDFLEN) { + return NULL; + } + + /* allocate space */ + rdf = LDNS_MALLOC(ldns_rdf); + if (!rdf) { + return NULL; + } + rdf->_data = LDNS_XMALLOC(uint8_t, size); + if (!rdf->_data) { + LDNS_FREE(rdf); + return NULL; + } + + /* set the values */ + ldns_rdf_set_type(rdf, type); + ldns_rdf_set_size(rdf, size); + memcpy(rdf->_data, data, size); + + return rdf; +} + +ldns_rdf * +ldns_rdf_clone(const ldns_rdf *rd) +{ + assert(rd != NULL); + return (ldns_rdf_new_frm_data( ldns_rdf_get_type(rd), + ldns_rdf_size(rd), ldns_rdf_data(rd))); +} + +void +ldns_rdf_deep_free(ldns_rdf *rd) +{ + if (rd) { + if (rd->_data) { + LDNS_FREE(rd->_data); + } + LDNS_FREE(rd); + } +} + +void +ldns_rdf_free(ldns_rdf *rd) +{ + if (rd) { + LDNS_FREE(rd); + } +} + +ldns_rdf * +ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str) +{ + ldns_rdf *rdf = NULL; + ldns_status status; + + switch (type) { + case LDNS_RDF_TYPE_DNAME: + status = ldns_str2rdf_dname(&rdf, str); + break; + case LDNS_RDF_TYPE_INT8: + status = ldns_str2rdf_int8(&rdf, str); + break; + case LDNS_RDF_TYPE_INT16: + status = ldns_str2rdf_int16(&rdf, str); + break; + case LDNS_RDF_TYPE_INT32: + status = ldns_str2rdf_int32(&rdf, str); + break; + case LDNS_RDF_TYPE_A: + status = ldns_str2rdf_a(&rdf, str); + break; + case LDNS_RDF_TYPE_AAAA: + status = ldns_str2rdf_aaaa(&rdf, str); + break; + case LDNS_RDF_TYPE_STR: + status = ldns_str2rdf_str(&rdf, str); + break; + case LDNS_RDF_TYPE_APL: + status = ldns_str2rdf_apl(&rdf, str); + break; + case LDNS_RDF_TYPE_B64: + status = ldns_str2rdf_b64(&rdf, str); + break; + case LDNS_RDF_TYPE_B32_EXT: + status = ldns_str2rdf_b32_ext(&rdf, str); + break; + case LDNS_RDF_TYPE_HEX: + status = ldns_str2rdf_hex(&rdf, str); + break; + case LDNS_RDF_TYPE_NSEC: + status = ldns_str2rdf_nsec(&rdf, str); + break; + case LDNS_RDF_TYPE_TYPE: + status = ldns_str2rdf_type(&rdf, str); + break; + case LDNS_RDF_TYPE_CLASS: + status = ldns_str2rdf_class(&rdf, str); + break; + case LDNS_RDF_TYPE_CERT_ALG: + status = ldns_str2rdf_cert_alg(&rdf, str); + break; + case LDNS_RDF_TYPE_ALG: + status = ldns_str2rdf_alg(&rdf, str); + break; + case LDNS_RDF_TYPE_UNKNOWN: + status = ldns_str2rdf_unknown(&rdf, str); + break; + case LDNS_RDF_TYPE_TIME: + status = ldns_str2rdf_time(&rdf, str); + break; + case LDNS_RDF_TYPE_PERIOD: + status = ldns_str2rdf_period(&rdf, str); + break; + case LDNS_RDF_TYPE_TSIG: + status = ldns_str2rdf_tsig(&rdf, str); + break; + case LDNS_RDF_TYPE_SERVICE: + status = ldns_str2rdf_service(&rdf, str); + break; + case LDNS_RDF_TYPE_LOC: + status = ldns_str2rdf_loc(&rdf, str); + break; + case LDNS_RDF_TYPE_WKS: + status = ldns_str2rdf_wks(&rdf, str); + break; + case LDNS_RDF_TYPE_NSAP: + status = ldns_str2rdf_nsap(&rdf, str); + break; + case LDNS_RDF_TYPE_ATMA: + status = ldns_str2rdf_atma(&rdf, str); + break; + case LDNS_RDF_TYPE_IPSECKEY: + status = ldns_str2rdf_ipseckey(&rdf, str); + break; + case LDNS_RDF_TYPE_NSEC3_SALT: + status = ldns_str2rdf_nsec3_salt(&rdf, str); + break; + case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: + status = ldns_str2rdf_b32_ext(&rdf, str); + break; + case LDNS_RDF_TYPE_NONE: + default: + /* default default ??? */ + status = LDNS_STATUS_ERR; + break; + } + if (LDNS_STATUS_OK == status) { + ldns_rdf_set_type(rdf, type); + return rdf; + } + if (rdf) { + LDNS_FREE(rdf); + } + return NULL; +} + +ldns_status +ldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp) +{ + return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL); +} + +ldns_status +ldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr) +{ + char *line; + ldns_rdf *r; + ssize_t t; + + line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1); + if (!line) { + return LDNS_STATUS_MEM_ERR; + } + + /* read an entire line in from the file */ + if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1 || t == 0) { + LDNS_FREE(line); + return LDNS_STATUS_SYNTAX_RDATA_ERR; + } + r = ldns_rdf_new_frm_str(type, (const char*) line); + LDNS_FREE(line); + if (rdf) { + *rdf = r; + return LDNS_STATUS_OK; + } else { + return LDNS_STATUS_NULL; + } +} + +ldns_rdf * +ldns_rdf_address_reverse(ldns_rdf *rd) +{ + uint8_t buf_4[LDNS_IP4ADDRLEN]; + uint8_t buf_6[LDNS_IP6ADDRLEN * 2]; + ldns_rdf *rev; + ldns_rdf *in_addr; + ldns_rdf *ret_dname; + uint8_t octet; + uint8_t nnibble; + uint8_t nibble; + uint8_t i, j; + + char *char_dname; + int nbit; + + if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A && + ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) { + return NULL; + } + + in_addr = NULL; + ret_dname = NULL; + + switch(ldns_rdf_get_type(rd)) { + case LDNS_RDF_TYPE_A: + /* the length of the buffer is 4 */ + buf_4[3] = ldns_rdf_data(rd)[0]; + buf_4[2] = ldns_rdf_data(rd)[1]; + buf_4[1] = ldns_rdf_data(rd)[2]; + buf_4[0] = ldns_rdf_data(rd)[3]; + in_addr = ldns_dname_new_frm_str("in-addr.arpa."); + if (!in_addr) { + return NULL; + } + /* make a new rdf and convert that back */ + rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A, + LDNS_IP4ADDRLEN, (void*)&buf_4); + if (!rev) { + LDNS_FREE(in_addr); + return NULL; + } + + /* convert rev to a string */ + char_dname = ldns_rdf2str(rev); + if (!char_dname) { + LDNS_FREE(in_addr); + ldns_rdf_deep_free(rev); + return NULL; + } + /* transform back to rdf with type dname */ + ret_dname = ldns_dname_new_frm_str(char_dname); + if (!ret_dname) { + LDNS_FREE(in_addr); + ldns_rdf_deep_free(rev); + LDNS_FREE(char_dname); + return NULL; + } + /* not needed anymore */ + ldns_rdf_deep_free(rev); + LDNS_FREE(char_dname); + break; + case LDNS_RDF_TYPE_AAAA: + /* some foo magic to reverse the nibbles ... */ + + for (nbit = 127; nbit >= 0; nbit = nbit - 4) { + /* calculate octett (8 bit) */ + octet = ( ((unsigned int) nbit) & 0x78) >> 3; + /* calculate nibble */ + nnibble = ( ((unsigned int) nbit) & 0x04) >> 2; + /* extract nibble */ + nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 - + nnibble)) ) ) >> ( 4 * (1 - + nnibble)); + + buf_6[(LDNS_IP6ADDRLEN * 2 - 1) - + (octet * 2 + nnibble)] = + (uint8_t)ldns_int_to_hexdigit((int)nibble); + } + + char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4)); + if (!char_dname) { + return NULL; + } + char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */ + + /* walk the string and add . 's */ + for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) { + char_dname[j] = (char)buf_6[i]; + if (i != LDNS_IP6ADDRLEN * 2 - 1) { + char_dname[j + 1] = '.'; + } + } + in_addr = ldns_dname_new_frm_str("ip6.arpa."); + if (!in_addr) { + LDNS_FREE(char_dname); + return NULL; + } + + /* convert rev to a string */ + ret_dname = ldns_dname_new_frm_str(char_dname); + LDNS_FREE(char_dname); + if (!ret_dname) { + ldns_rdf_deep_free(in_addr); + return NULL; + } + break; + default: + break; + } + /* add the suffix */ + rev = ldns_dname_cat_clone(ret_dname, in_addr); + + ldns_rdf_deep_free(ret_dname); + ldns_rdf_deep_free(in_addr); + return rev; +} + +ldns_status +ldns_octet(char *word, size_t *length) +{ + char *s; + char *p; + *length = 0; + + for (s = p = word; *s != '\0'; s++,p++) { + switch (*s) { + case '.': + if (s[1] == '.') { + return LDNS_STATUS_EMPTY_LABEL; + } + *p = *s; + (*length)++; + break; + case '\\': + if ('0' <= s[1] && s[1] <= '9' && + '0' <= s[2] && s[2] <= '9' && + '0' <= s[3] && s[3] <= '9') { + /* \DDD seen */ + int val = ((s[1] - '0') * 100 + + (s[2] - '0') * 10 + (s[3] - '0')); + + if (0 <= val && val <= 255) { + /* this also handles \0 */ + s += 3; + *p = val; + (*length)++; + } else { + return LDNS_STATUS_DDD_OVERFLOW; + } + } else { + /* an espaced character, like \<space> ? + * remove the '\' keep the rest */ + *p = *++s; + (*length)++; + } + break; + case '\"': + /* non quoted " Is either first or the last character in + * the string */ + + *p = *++s; /* skip it */ + (*length)++; + /* I'm not sure if this is needed in libdns... MG */ + if ( *s == '\0' ) { + /* ok, it was the last one */ + *p = '\0'; + return LDNS_STATUS_OK; + } + break; + default: + *p = *s; + (*length)++; + break; + } + } + *p = '\0'; + return LDNS_STATUS_OK; +} + +int +ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2) +{ + uint16_t i1, i2, i; + uint8_t *d1, *d2; + + /* only when both are not NULL we can say anything about them */ + if (!rd1 && !rd2) { + return 0; + } + if (!rd1 || !rd2) { + return -1; + } + i1 = ldns_rdf_size(rd1); + i2 = ldns_rdf_size(rd2); + + if (i1 < i2) { + return -1; + } else if (i1 > i2) { + return +1; + } else { + d1 = (uint8_t*)ldns_rdf_data(rd1); + d2 = (uint8_t*)ldns_rdf_data(rd2); + for(i = 0; i < i1; i++) { + if (d1[i] < d2[i]) { + return -1; + } else if (d1[i] > d2[i]) { + return +1; + } + } + } + return 0; +} + +uint32_t +ldns_str2period(const char *nptr, const char **endptr) +{ + int sign = 0; + uint32_t i = 0; + uint32_t seconds = 0; + + for(*endptr = nptr; **endptr; (*endptr)++) { + switch (**endptr) { + case ' ': + case '\t': + break; + case '-': + if(sign == 0) { + sign = -1; + } else { + return seconds; + } + break; + case '+': + if(sign == 0) { + sign = 1; + } else { + return seconds; + } + break; + case 's': + case 'S': + seconds += i; + i = 0; + break; + case 'm': + case 'M': + seconds += i * 60; + i = 0; + break; + case 'h': + case 'H': + seconds += i * 60 * 60; + i = 0; + break; + case 'd': + case 'D': + seconds += i * 60 * 60 * 24; + i = 0; + break; + case 'w': + case 'W': + seconds += i * 60 * 60 * 24 * 7; + i = 0; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + i *= 10; + i += (**endptr - '0'); + break; + default: + seconds += i; + /* disregard signedness */ + return seconds; + } + } + seconds += i; + /* disregard signedness */ + return seconds; +} |