freebsd-dev/contrib/ldns/str2host.c
Dag-Erling Smørgrav 986ba33c7a Upgrade LDNS to 1.7.0.
I've been holding back on this because 1.7.0 requires OpenSSL 1.1.0 or
newer for full DANE support.  But we can't wait forever, and nothing in
base uses DANE anyway, so here we go.
2018-05-12 12:00:18 +00:00

1608 lines
38 KiB
C

/*
* str2host.c
*
* conversion routines from the presentation format
* to the host format
*
* 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>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <time.h>
#include <errno.h>
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#include <limits.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
ldns_status
ldns_str2rdf_int16(ldns_rdf **rd, const char *shortstr)
{
char *end = NULL;
uint16_t *r;
r = LDNS_MALLOC(uint16_t);
if(!r) return LDNS_STATUS_MEM_ERR;
*r = htons((uint16_t)strtol((char *)shortstr, &end, 10));
if(*end != 0) {
LDNS_FREE(r);
return LDNS_STATUS_INVALID_INT;
} else {
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_INT16, sizeof(uint16_t), r);
LDNS_FREE(r);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
}
ldns_status
ldns_str2rdf_time(ldns_rdf **rd, const char *time)
{
/* convert a time YYYYDDMMHHMMSS to wireformat */
uint16_t *r = NULL;
struct tm tm;
uint32_t l;
char *end;
/* Try to scan the time... */
r = (uint16_t*)LDNS_MALLOC(uint32_t);
if(!r) return LDNS_STATUS_MEM_ERR;
memset(&tm, 0, sizeof(tm));
if (strlen(time) == 14 &&
sscanf(time, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 6
) {
tm.tm_year -= 1900;
tm.tm_mon--;
/* Check values */
if (tm.tm_year < 70) {
goto bad_format;
}
if (tm.tm_mon < 0 || tm.tm_mon > 11) {
goto bad_format;
}
if (tm.tm_mday < 1 || tm.tm_mday > 31) {
goto bad_format;
}
if (tm.tm_hour < 0 || tm.tm_hour > 23) {
goto bad_format;
}
if (tm.tm_min < 0 || tm.tm_min > 59) {
goto bad_format;
}
if (tm.tm_sec < 0 || tm.tm_sec > 59) {
goto bad_format;
}
l = htonl(ldns_mktime_from_utc(&tm));
memcpy(r, &l, sizeof(uint32_t));
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_TIME, sizeof(uint32_t), r);
LDNS_FREE(r);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
} else {
/* handle it as 32 bits timestamp */
l = htonl((uint32_t)strtol((char*)time, &end, 10));
if(*end != 0) {
LDNS_FREE(r);
return LDNS_STATUS_ERR;
} else {
memcpy(r, &l, sizeof(uint32_t));
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_INT32, sizeof(uint32_t), r);
LDNS_FREE(r);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
}
bad_format:
LDNS_FREE(r);
return LDNS_STATUS_INVALID_TIME;
}
ldns_status
ldns_str2rdf_nsec3_salt(ldns_rdf **rd, const char *salt_str)
{
uint8_t salt_length;
int c;
int salt_length_str;
uint8_t *salt;
uint8_t *data;
if(rd == NULL) {
return LDNS_STATUS_NULL;
}
salt_length_str = (int)strlen(salt_str);
if (salt_length_str == 1 && salt_str[0] == '-') {
salt_length_str = 0;
} else if (salt_length_str % 2 != 0) {
return LDNS_STATUS_INVALID_HEX;
}
if (salt_length_str > 512) {
return LDNS_STATUS_INVALID_HEX;
}
salt = LDNS_XMALLOC(uint8_t, salt_length_str / 2);
if(!salt) {
return LDNS_STATUS_MEM_ERR;
}
for (c = 0; c < salt_length_str; c += 2) {
if (isxdigit((int) salt_str[c]) && isxdigit((int) salt_str[c+1])) {
salt[c/2] = (uint8_t) ldns_hexdigit_to_int(salt_str[c]) * 16 +
ldns_hexdigit_to_int(salt_str[c+1]);
} else {
LDNS_FREE(salt);
return LDNS_STATUS_INVALID_HEX;
}
}
salt_length = (uint8_t) (salt_length_str / 2);
data = LDNS_XMALLOC(uint8_t, 1 + salt_length);
if(!data) {
LDNS_FREE(salt);
return LDNS_STATUS_MEM_ERR;
}
data[0] = salt_length;
memcpy(&data[1], salt, salt_length);
*rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_NSEC3_SALT, 1 + salt_length, data);
LDNS_FREE(data);
LDNS_FREE(salt);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_period(ldns_rdf **rd,const char *period)
{
uint32_t p;
const char *end;
/* Allocate required space... */
p = ldns_str2period(period, &end);
if (*end != 0) {
return LDNS_STATUS_ERR;
} else {
p = (uint32_t) htonl(p);
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_PERIOD, sizeof(uint32_t), &p);
}
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_int32(ldns_rdf **rd, const char *longstr)
{
char *end;
uint16_t *r = NULL;
uint32_t l;
r = (uint16_t*)LDNS_MALLOC(uint32_t);
if(!r) return LDNS_STATUS_MEM_ERR;
errno = 0; /* must set to zero before call,
note race condition on errno */
if(*longstr == '-')
l = htonl((uint32_t)strtol((char*)longstr, &end, 10));
else l = htonl((uint32_t)strtoul((char*)longstr, &end, 10));
if(*end != 0) {
LDNS_FREE(r);
return LDNS_STATUS_ERR;
} else {
if (errno == ERANGE) {
LDNS_FREE(r);
return LDNS_STATUS_SYNTAX_INTEGER_OVERFLOW;
}
memcpy(r, &l, sizeof(uint32_t));
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_INT32, sizeof(uint32_t), r);
LDNS_FREE(r);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
}
ldns_status
ldns_str2rdf_int8(ldns_rdf **rd, const char *bytestr)
{
char *end;
uint8_t *r = NULL;
r = LDNS_MALLOC(uint8_t);
if(!r) return LDNS_STATUS_MEM_ERR;
*r = (uint8_t)strtol((char*)bytestr, &end, 10);
if(*end != 0) {
LDNS_FREE(r);
return LDNS_STATUS_ERR;
} else {
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_INT8, sizeof(uint8_t), r);
LDNS_FREE(r);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
}
/*
* Checks whether the escaped value at **s is an decimal value or
* a 'normally' escaped character (and not eos)
*
* The string pointer at *s is increased by either 0 (on error), 1 (on
* normal escapes), or 3 (on decimals)
*
* Returns the number of bytes read from the escaped string, or
* 0 on error
*/
INLINE bool
parse_escape(uint8_t *ch_p, const char** str_p)
{
uint16_t val;
if ((*str_p)[0] && isdigit((unsigned char)(*str_p)[0]) &&
(*str_p)[1] && isdigit((unsigned char)(*str_p)[1]) &&
(*str_p)[2] && isdigit((unsigned char)(*str_p)[2])) {
val = (uint16_t)(((*str_p)[0] - '0') * 100 +
((*str_p)[1] - '0') * 10 +
((*str_p)[2] - '0'));
if (val > 255) {
goto error;
}
*ch_p = (uint8_t)val;
*str_p += 3;
return true;
} else if ((*str_p)[0] && !isdigit((unsigned char)(*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;
}
}
/*
* No special care is taken, all dots are translated into
* label seperators.
* Could be made more efficient....we do 3 memcpy's in total...
*/
ldns_status
ldns_str2rdf_dname(ldns_rdf **d, const char *str)
{
size_t len;
const char *s;
uint8_t *q, *pq, label_len;
uint8_t buf[LDNS_MAX_DOMAINLEN + 1];
*d = NULL;
len = strlen((char*)str);
/* octet representation can make strings a lot longer than actual length */
if (len > LDNS_MAX_DOMAINLEN * 4) {
return LDNS_STATUS_DOMAINNAME_OVERFLOW;
}
if (0 == len) {
return LDNS_STATUS_DOMAINNAME_UNDERFLOW;
}
/* root label */
if (1 == len && *str == '.') {
*d = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 1, "\0");
return LDNS_STATUS_OK;
}
/* get on with the rest */
/* s is on the current character in the string
* pq points to where the labellength is going to go
* label_len keeps track of the current label's length
* q builds the dname inside the buf array
*/
len = 0;
q = buf+1;
pq = buf;
label_len = 0;
for (s = str; *s; s++, q++) {
if (q > buf + LDNS_MAX_DOMAINLEN) {
return LDNS_STATUS_DOMAINNAME_OVERFLOW;
}
*q = 0;
switch (*s) {
case '.':
if (label_len > LDNS_MAX_LABELLEN) {
return LDNS_STATUS_LABEL_OVERFLOW;
}
if (label_len == 0) {
return LDNS_STATUS_EMPTY_LABEL;
}
len += label_len + 1;
*pq = label_len;
label_len = 0;
pq = q;
break;
case '\\':
/* octet value or literal char */
s += 1;
if (! parse_escape(q, &s)) {
return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
}
s -= 1;
label_len++;
break;
default:
*q = (uint8_t)*s;
label_len++;
}
}
/* add root label if last char was not '.' */
if (!ldns_dname_str_absolute(str)) {
if (q > buf + LDNS_MAX_DOMAINLEN) {
return LDNS_STATUS_DOMAINNAME_OVERFLOW;
}
if (label_len > LDNS_MAX_LABELLEN) {
return LDNS_STATUS_LABEL_OVERFLOW;
}
if (label_len == 0) { /* label_len 0 but not . at end? */
return LDNS_STATUS_EMPTY_LABEL;
}
len += label_len + 1;
*pq = label_len;
*q = 0;
}
len++;
*d = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, len, buf);
return LDNS_STATUS_OK;
}
ldns_status
ldns_str2rdf_a(ldns_rdf **rd, const char *str)
{
in_addr_t address;
if (inet_pton(AF_INET, (char*)str, &address) != 1) {
return LDNS_STATUS_INVALID_IP4;
} else {
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_A, sizeof(address), &address);
}
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_aaaa(ldns_rdf **rd, const char *str)
{
uint8_t address[LDNS_IP6ADDRLEN + 1];
if (inet_pton(AF_INET6, (char*)str, address) != 1) {
return LDNS_STATUS_INVALID_IP6;
} else {
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_AAAA, sizeof(address) - 1, &address);
}
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_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) > 255 ? 256 : (strlen(str) + 1));
if (! data) {
return LDNS_STATUS_MEM_ERR;
}
/* Fill data (up to 255 characters) */
while (parse_char(&ch, &str)) {
if (dp - data >= 255) {
LDNS_FREE(data);
return LDNS_STATUS_INVALID_STR;
}
*++dp = ch;
}
if (! str) {
return LDNS_STATUS_SYNTAX_BAD_ESCAPE;
}
length = (size_t)(dp - data);
/* Fix last length byte */
data[0] = (uint8_t)length;
/* 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
ldns_str2rdf_apl(ldns_rdf **rd, const char *str)
{
const char *my_str = str;
char *my_ip_str;
size_t ip_str_len;
uint16_t family;
bool negation;
uint8_t afdlength = 0;
uint8_t *afdpart;
uint8_t prefix;
uint8_t *data;
size_t i = 0;
/* [!]afi:address/prefix */
if (strlen(my_str) < 2
|| strchr(my_str, ':') == NULL
|| strchr(my_str, '/') == NULL
|| strchr(my_str, ':') > strchr(my_str, '/')) {
return LDNS_STATUS_INVALID_STR;
}
if (my_str[0] == '!') {
negation = true;
my_str += 1;
} else {
negation = false;
}
family = (uint16_t) atoi(my_str);
my_str = strchr(my_str, ':') + 1;
/* need ip addr and only ip addr for inet_pton */
ip_str_len = (size_t) (strchr(my_str, '/') - my_str);
my_ip_str = LDNS_XMALLOC(char, ip_str_len + 1);
if(!my_ip_str) return LDNS_STATUS_MEM_ERR;
strncpy(my_ip_str, my_str, ip_str_len + 1);
my_ip_str[ip_str_len] = '\0';
if (family == 1) {
/* ipv4 */
afdpart = LDNS_XMALLOC(uint8_t, 4);
if(!afdpart) {
LDNS_FREE(my_ip_str);
return LDNS_STATUS_MEM_ERR;
}
if (inet_pton(AF_INET, my_ip_str, afdpart) == 0) {
LDNS_FREE(my_ip_str);
LDNS_FREE(afdpart);
return LDNS_STATUS_INVALID_STR;
}
for (i = 0; i < 4; i++) {
if (afdpart[i] != 0) {
afdlength = i + 1;
}
}
} else if (family == 2) {
/* ipv6 */
afdpart = LDNS_XMALLOC(uint8_t, 16);
if(!afdpart) {
LDNS_FREE(my_ip_str);
return LDNS_STATUS_MEM_ERR;
}
if (inet_pton(AF_INET6, my_ip_str, afdpart) == 0) {
LDNS_FREE(my_ip_str);
LDNS_FREE(afdpart);
return LDNS_STATUS_INVALID_STR;
}
for (i = 0; i < 16; i++) {
if (afdpart[i] != 0) {
afdlength = i + 1;
}
}
} else {
/* unknown family */
LDNS_FREE(my_ip_str);
return LDNS_STATUS_INVALID_STR;
}
my_str = strchr(my_str, '/') + 1;
prefix = (uint8_t) atoi(my_str);
data = LDNS_XMALLOC(uint8_t, 4 + afdlength);
if(!data) {
LDNS_FREE(afdpart);
LDNS_FREE(my_ip_str);
return LDNS_STATUS_INVALID_STR;
}
ldns_write_uint16(data, family);
data[2] = prefix;
data[3] = afdlength;
if (negation) {
/* set bit 1 of byte 3 */
data[3] = data[3] | 0x80;
}
memcpy(data + 4, afdpart, afdlength);
*rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_APL, afdlength + 4, data);
LDNS_FREE(afdpart);
LDNS_FREE(data);
LDNS_FREE(my_ip_str);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_b64(ldns_rdf **rd, const char *str)
{
uint8_t *buffer;
int16_t i;
buffer = LDNS_XMALLOC(uint8_t, ldns_b64_ntop_calculate_size(strlen(str)));
if(!buffer) {
return LDNS_STATUS_MEM_ERR;
}
i = (uint16_t)ldns_b64_pton((const char*)str, buffer,
ldns_b64_ntop_calculate_size(strlen(str)));
if (-1 == i) {
LDNS_FREE(buffer);
return LDNS_STATUS_INVALID_B64;
} else {
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_B64, (uint16_t) i, buffer);
}
LDNS_FREE(buffer);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_b32_ext(ldns_rdf **rd, const char *str)
{
uint8_t *buffer;
int i;
/* first byte contains length of actual b32 data */
uint8_t len = ldns_b32_pton_calculate_size(strlen(str));
buffer = LDNS_XMALLOC(uint8_t, len + 1);
if(!buffer) {
return LDNS_STATUS_MEM_ERR;
}
buffer[0] = len;
i = ldns_b32_pton_extended_hex((const char*)str, strlen(str), buffer + 1,
ldns_b32_ntop_calculate_size(strlen(str)));
if (i < 0) {
LDNS_FREE(buffer);
return LDNS_STATUS_INVALID_B32_EXT;
} else {
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_B32_EXT, (uint16_t) i + 1, buffer);
}
LDNS_FREE(buffer);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_hex(ldns_rdf **rd, const char *str)
{
uint8_t *t, *t_orig;
int i;
size_t len;
len = strlen(str);
if (len > LDNS_MAX_RDFLEN * 2) {
return LDNS_STATUS_LABEL_OVERFLOW;
} else {
t = LDNS_XMALLOC(uint8_t, (len / 2) + 1);
if(!t) {
return LDNS_STATUS_MEM_ERR;
}
t_orig = t;
/* Now process octet by octet... */
while (*str) {
*t = 0;
if (isspace((int) *str)) {
str++;
} else {
for (i = 16; i >= 1; i -= 15) {
while (*str && isspace((int) *str)) { str++; }
if (*str) {
if (isxdigit((int) *str)) {
*t += ldns_hexdigit_to_int(*str) * i;
} else {
LDNS_FREE(t_orig);
return LDNS_STATUS_ERR;
}
++str;
}
}
++t;
}
}
*rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_HEX,
(size_t) (t - t_orig),
t_orig);
LDNS_FREE(t_orig);
}
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_nsec(ldns_rdf **rd, const char *str)
{
const char *delimiters = "\n\t ";
char *token = LDNS_XMALLOC(char, LDNS_MAX_RDFLEN);
ldns_buffer *str_buf;
ssize_t c;
uint16_t cur_type;
size_t type_count = 0;
ldns_rr_type type_list[65536];
if(!token) return LDNS_STATUS_MEM_ERR;
if(rd == NULL) {
LDNS_FREE(token);
return LDNS_STATUS_NULL;
}
str_buf = LDNS_MALLOC(ldns_buffer);
if(!str_buf) {
LDNS_FREE(token);
return LDNS_STATUS_MEM_ERR;
}
ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str));
if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) {
LDNS_FREE(str_buf);
LDNS_FREE(token);
return LDNS_STATUS_MEM_ERR;
}
while ((c = ldns_bget_token(str_buf, token, delimiters, LDNS_MAX_RDFLEN)) != -1 && c != 0) {
if(type_count >= sizeof(type_list)) {
LDNS_FREE(str_buf);
LDNS_FREE(token);
return LDNS_STATUS_ERR;
}
cur_type = ldns_get_rr_type_by_name(token);
type_list[type_count] = cur_type;
type_count++;
}
*rd = ldns_dnssec_create_nsec_bitmap(type_list,
type_count,
LDNS_RR_TYPE_NSEC);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_type(ldns_rdf **rd, const char *str)
{
uint16_t type;
type = htons(ldns_get_rr_type_by_name(str));
/* ldns_rr_type is a 16 bit value */
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_TYPE, sizeof(uint16_t), &type);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_class(ldns_rdf **rd, const char *str)
{
uint16_t klass;
klass = htons(ldns_get_rr_class_by_name(str));
/* class is 16 bit */
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_CLASS, sizeof(uint16_t), &klass);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
/* An certificate alg field can either be specified as a 8 bits number
* or by its symbolic name. Handle both
*/
ldns_status
ldns_str2rdf_cert_alg(ldns_rdf **rd, const char *str)
{
ldns_lookup_table *lt;
ldns_status st;
uint8_t idd[2];
lt = ldns_lookup_by_name(ldns_cert_algorithms, str);
st = LDNS_STATUS_OK;
if (lt) {
ldns_write_uint16(idd, (uint16_t) lt->id);
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_INT16, sizeof(uint16_t), idd);
if (!*rd) {
st = LDNS_STATUS_ERR;
}
} else {
/* try as-is (a number) */
st = ldns_str2rdf_int16(rd, str);
if (st == LDNS_STATUS_OK &&
ldns_rdf2native_int16(*rd) == 0) {
st = LDNS_STATUS_CERT_BAD_ALGORITHM;
}
}
return st;
}
static ldns_lookup_table ldns_tlsa_certificate_usages[] = {
{ LDNS_TLSA_USAGE_PKIX_TA , "PKIX-TA" },
{ LDNS_TLSA_USAGE_PKIX_EE , "PKIX-EE" },
{ LDNS_TLSA_USAGE_DANE_TA , "DANE-TA" },
{ LDNS_TLSA_USAGE_DANE_EE , "DANE-EE" },
{ LDNS_TLSA_USAGE_PRIVCERT , "PrivCert" },
{ 0, NULL }
};
static ldns_lookup_table ldns_tlsa_selectors[] = {
{ LDNS_TLSA_SELECTOR_CERT , "Cert" },
{ LDNS_TLSA_SELECTOR_SPKI , "SPKI" },
{ LDNS_TLSA_SELECTOR_PRIVSEL , "PrivSel" },
{ 0, NULL }
};
static ldns_lookup_table ldns_tlsa_matching_types[] = {
{ LDNS_TLSA_MATCHING_TYPE_FULL , "Full" },
{ LDNS_TLSA_MATCHING_TYPE_SHA2_256 , "SHA2-256" },
{ LDNS_TLSA_MATCHING_TYPE_SHA2_512 , "SHA2-512" },
{ LDNS_TLSA_MATCHING_TYPE_PRIVMATCH , "PrivMatch" },
{ 0, NULL }
};
static ldns_status
ldns_str2rdf_mnemonic4int8(ldns_lookup_table *lt,
ldns_rdf **rd, const char *str)
{
if ((lt = ldns_lookup_by_name(lt, str))) {
/* it was given as a integer */
*rd = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t) lt->id);
if (!*rd)
return LDNS_STATUS_ERR;
else
return LDNS_STATUS_OK;
}
return ldns_str2rdf_int8(rd, str);
}
/* An alg field can either be specified as a 8 bits number
* or by its symbolic name. Handle both
*/
ldns_status
ldns_str2rdf_alg(ldns_rdf **rd, const char *str)
{
return ldns_str2rdf_mnemonic4int8(ldns_algorithms, rd, str);
}
ldns_status
ldns_str2rdf_certificate_usage(ldns_rdf **rd, const char *str)
{
return ldns_str2rdf_mnemonic4int8(
ldns_tlsa_certificate_usages, rd, str);
}
ldns_status
ldns_str2rdf_selector(ldns_rdf **rd, const char *str)
{
return ldns_str2rdf_mnemonic4int8(ldns_tlsa_selectors, rd, str);
}
ldns_status
ldns_str2rdf_matching_type(ldns_rdf **rd, const char *str)
{
return ldns_str2rdf_mnemonic4int8(ldns_tlsa_matching_types, rd, str);
}
ldns_status
ldns_str2rdf_unknown( ATTR_UNUSED(ldns_rdf **rd)
, ATTR_UNUSED(const char *str)
)
{
/* this should be caught in an earlier time (general str2host for
rr's */
return LDNS_STATUS_NOT_IMPL;
}
ldns_status
ldns_str2rdf_service( ATTR_UNUSED(ldns_rdf **rd)
, ATTR_UNUSED(const char *str)
)
{
/* is this used? is this actually WKS? or SRV? */
return LDNS_STATUS_NOT_IMPL;
}
static int
loc_parse_cm(char* my_str, char** endstr, uint8_t* m, uint8_t* e)
{
/* read <digits>[.<digits>][mM] */
/* into mantissa exponent format for LOC type */
uint32_t meters = 0, cm = 0, val;
while (isblank((unsigned char)*my_str)) {
my_str++;
}
meters = (uint32_t)strtol(my_str, &my_str, 10);
if (*my_str == '.') {
my_str++;
cm = (uint32_t)strtol(my_str, &my_str, 10);
}
if (meters >= 1) {
*e = 2;
val = meters;
} else {
*e = 0;
val = cm;
}
while(val >= 10) {
(*e)++;
val /= 10;
}
*m = (uint8_t)val;
if (*e > 9)
return 0;
if (*my_str == 'm' || *my_str == 'M') {
my_str++;
}
*endstr = my_str;
return 1;
}
ldns_status
ldns_str2rdf_loc(ldns_rdf **rd, const char *str)
{
uint32_t latitude = 0;
uint32_t longitude = 0;
uint32_t altitude = 0;
uint8_t *data;
uint32_t equator = (uint32_t) ldns_power(2, 31);
uint32_t h = 0;
uint32_t m = 0;
uint8_t size_b = 1, size_e = 2;
uint8_t horiz_pre_b = 1, horiz_pre_e = 6;
uint8_t vert_pre_b = 1, vert_pre_e = 3;
double s = 0.0;
bool northerness;
bool easterness;
char *my_str = (char *) str;
/* only support version 0 */
if (isdigit((int) *my_str)) {
h = (uint32_t) strtol(my_str, &my_str, 10);
} else {
return LDNS_STATUS_INVALID_STR;
}
while (isblank((int) *my_str)) {
my_str++;
}
if (isdigit((int) *my_str)) {
m = (uint32_t) strtol(my_str, &my_str, 10);
} else if (*my_str == 'N' || *my_str == 'S') {
goto north;
} else {
return LDNS_STATUS_INVALID_STR;
}
while (isblank((int) *my_str)) {
my_str++;
}
if (isdigit((int) *my_str)) {
s = strtod(my_str, &my_str);
}
north:
while (isblank((int) *my_str)) {
my_str++;
}
if (*my_str == 'N') {
northerness = true;
} else if (*my_str == 'S') {
northerness = false;
} else {
return LDNS_STATUS_INVALID_STR;
}
my_str++;
/* store number */
s = 1000.0 * s;
/* add a little to make floor in conversion a round */
s += 0.0005;
latitude = (uint32_t) s;
latitude += 1000 * 60 * m;
latitude += 1000 * 60 * 60 * h;
if (northerness) {
latitude = equator + latitude;
} else {
latitude = equator - latitude;
}
while (isblank((unsigned char)*my_str)) {
my_str++;
}
if (isdigit((int) *my_str)) {
h = (uint32_t) strtol(my_str, &my_str, 10);
} else {
return LDNS_STATUS_INVALID_STR;
}
while (isblank((int) *my_str)) {
my_str++;
}
if (isdigit((int) *my_str)) {
m = (uint32_t) strtol(my_str, &my_str, 10);
} else if (*my_str == 'E' || *my_str == 'W') {
goto east;
} else {
return LDNS_STATUS_INVALID_STR;
}
while (isblank((unsigned char)*my_str)) {
my_str++;
}
if (isdigit((int) *my_str)) {
s = strtod(my_str, &my_str);
}
east:
while (isblank((unsigned char)*my_str)) {
my_str++;
}
if (*my_str == 'E') {
easterness = true;
} else if (*my_str == 'W') {
easterness = false;
} else {
return LDNS_STATUS_INVALID_STR;
}
my_str++;
/* store number */
s *= 1000.0;
/* add a little to make floor in conversion a round */
s += 0.0005;
longitude = (uint32_t) s;
longitude += 1000 * 60 * m;
longitude += 1000 * 60 * 60 * h;
if (easterness) {
longitude += equator;
} else {
longitude = equator - longitude;
}
altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 +
10000000.0 + 0.5);
if (*my_str == 'm' || *my_str == 'M') {
my_str++;
}
if (strlen(my_str) > 0) {
if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e))
return LDNS_STATUS_INVALID_STR;
}
if (strlen(my_str) > 0) {
if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e))
return LDNS_STATUS_INVALID_STR;
}
if (strlen(my_str) > 0) {
if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e))
return LDNS_STATUS_INVALID_STR;
}
data = LDNS_XMALLOC(uint8_t, 16);
if(!data) {
return LDNS_STATUS_MEM_ERR;
}
data[0] = 0;
data[1] = 0;
data[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f);
data[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f);
data[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f);
ldns_write_uint32(data + 4, latitude);
ldns_write_uint32(data + 8, longitude);
ldns_write_uint32(data + 12, altitude);
*rd = ldns_rdf_new_frm_data(
LDNS_RDF_TYPE_LOC, 16, data);
LDNS_FREE(data);
return *rd?LDNS_STATUS_OK:LDNS_STATUS_MEM_ERR;
}
ldns_status
ldns_str2rdf_wks(ldns_rdf **rd, const char *str)
{
uint8_t *bitmap = NULL;
uint8_t *data;
int bm_len = 0;
struct protoent *proto = NULL;
struct servent *serv = NULL;
int serv_port;
ldns_buffer *str_buf;
char *proto_str = NULL;
char *token;
if(strlen(str) == 0)
token = LDNS_XMALLOC(char, 50);
else token = LDNS_XMALLOC(char, strlen(str)+2);
if(!token) return LDNS_STATUS_MEM_ERR;
str_buf = LDNS_MALLOC(ldns_buffer);
if(!str_buf) {LDNS_FREE(token); return LDNS_STATUS_MEM_ERR;}
ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str));
if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) {
LDNS_FREE(str_buf);
LDNS_FREE(token);
return LDNS_STATUS_MEM_ERR;
}
while(ldns_bget_token(str_buf, token, "\t\n ", strlen(str)) > 0) {
if (!proto_str) {
proto_str = strdup(token);
if (!proto_str) {
LDNS_FREE(bitmap);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
return LDNS_STATUS_INVALID_STR;
}
} else {
serv = getservbyname(token, proto_str);
if (serv) {
serv_port = (int) ntohs((uint16_t) serv->s_port);
} else {
serv_port = atoi(token);
}
if (serv_port / 8 >= bm_len) {
uint8_t *b2 = LDNS_XREALLOC(bitmap, uint8_t, (serv_port / 8) + 1);
if(!b2) {
LDNS_FREE(bitmap);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
free(proto_str);
return LDNS_STATUS_INVALID_STR;
}
bitmap = b2;
/* set to zero to be sure */
for (; bm_len <= serv_port / 8; bm_len++) {
bitmap[bm_len] = 0;
}
}
ldns_set_bit(bitmap + (serv_port / 8), 7 - (serv_port % 8), true);
}
}
if (!proto_str || !bitmap) {
LDNS_FREE(bitmap);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
free(proto_str);
return LDNS_STATUS_INVALID_STR;
}
data = LDNS_XMALLOC(uint8_t, bm_len + 1);
if(!data) {
LDNS_FREE(token);
ldns_buffer_free(str_buf);
LDNS_FREE(bitmap);
free(proto_str);
return LDNS_STATUS_INVALID_STR;
}
if (proto_str)
proto = getprotobyname(proto_str);
if (proto) {
data[0] = (uint8_t) proto->p_proto;
} else if (proto_str) {
data[0] = (uint8_t) atoi(proto_str);
}
memcpy(data + 1, bitmap, (size_t) bm_len);
*rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_WKS, (uint16_t) (bm_len + 1), data);
LDNS_FREE(data);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
LDNS_FREE(bitmap);
free(proto_str);
#ifdef HAVE_ENDSERVENT
endservent();
#endif
#ifdef HAVE_ENDPROTOENT
endprotoent();
#endif
if(!*rd) return LDNS_STATUS_MEM_ERR;
return LDNS_STATUS_OK;
}
ldns_status
ldns_str2rdf_nsap(ldns_rdf **rd, const char *str)
{
size_t len, i;
char* nsap_str = (char*) str;
/* just a hex string with optional dots? */
if (str[0] != '0' || str[1] != 'x') {
return LDNS_STATUS_INVALID_STR;
} else {
len = strlen(str);
for (i=0; i < len; i++) {
if (nsap_str[i] == '.')
nsap_str[i] = ' ';
}
return ldns_str2rdf_hex(rd, str+2);
}
}
ldns_status
ldns_str2rdf_atma(ldns_rdf **rd, const char *str)
{
size_t len, i;
char* atma_str = (char*) str;
ldns_status status;
/* just a hex string with optional dots? */
len = strlen(str);
for (i=0; i < len; i++) {
if (atma_str[i] == '.')
atma_str[i] = ' ';
}
status = ldns_str2rdf_hex(rd, str);
if (status != LDNS_STATUS_OK) {
; /* probably in e.164 format than */
}
return status;
}
ldns_status
ldns_str2rdf_ipseckey(ldns_rdf **rd, const char *str)
{
uint8_t precedence = 0;
uint8_t gateway_type = 0;
uint8_t algorithm = 0;
char* gateway = NULL;
char* publickey = NULL;
uint8_t *data;
ldns_buffer *str_buf;
char *token;
int token_count = 0;
int ipseckey_len = 0;
ldns_rdf* gateway_rdf = NULL;
ldns_rdf* publickey_rdf = NULL;
ldns_status status = LDNS_STATUS_OK;
if(strlen(str) == 0)
token = LDNS_XMALLOC(char, 256);
else token = LDNS_XMALLOC(char, strlen(str)+2);
if(!token) return LDNS_STATUS_MEM_ERR;
str_buf = LDNS_MALLOC(ldns_buffer);
if(!str_buf) {LDNS_FREE(token); return LDNS_STATUS_MEM_ERR;}
ldns_buffer_new_frm_data(str_buf, (char *)str, strlen(str));
if(ldns_buffer_status(str_buf) != LDNS_STATUS_OK) {
LDNS_FREE(str_buf);
LDNS_FREE(token);
return LDNS_STATUS_MEM_ERR;
}
while(ldns_bget_token(str_buf, token, "\t\n ", strlen(str)) > 0) {
switch (token_count) {
case 0:
precedence = (uint8_t)atoi(token);
break;
case 1:
gateway_type = (uint8_t)atoi(token);
break;
case 2:
algorithm = (uint8_t)atoi(token);
break;
case 3:
gateway = strdup(token);
if (!gateway || (gateway_type == 0 &&
(token[0] != '.' || token[1] != '\0'))) {
LDNS_FREE(gateway);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
return LDNS_STATUS_INVALID_STR;
}
break;
case 4:
publickey = strdup(token);
break;
default:
LDNS_FREE(token);
ldns_buffer_free(str_buf);
return LDNS_STATUS_INVALID_STR;
break;
}
token_count++;
}
if (!gateway || !publickey) {
if (gateway)
LDNS_FREE(gateway);
if (publickey)
LDNS_FREE(publickey);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
return LDNS_STATUS_INVALID_STR;
}
if (gateway_type == 1) {
status = ldns_str2rdf_a(&gateway_rdf, gateway);
} else if (gateway_type == 2) {
status = ldns_str2rdf_aaaa(&gateway_rdf, gateway);
} else if (gateway_type == 3) {
status = ldns_str2rdf_dname(&gateway_rdf, gateway);
}
if (status != LDNS_STATUS_OK) {
if (gateway)
LDNS_FREE(gateway);
if (publickey)
LDNS_FREE(publickey);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
return LDNS_STATUS_INVALID_STR;
}
status = ldns_str2rdf_b64(&publickey_rdf, publickey);
if (status != LDNS_STATUS_OK) {
if (gateway)
LDNS_FREE(gateway);
if (publickey)
LDNS_FREE(publickey);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
if (gateway_rdf) ldns_rdf_free(gateway_rdf);
return LDNS_STATUS_INVALID_STR;
}
/* now copy all into one ipseckey rdf */
if (gateway_type)
ipseckey_len = 3 + (int)ldns_rdf_size(gateway_rdf) + (int)ldns_rdf_size(publickey_rdf);
else
ipseckey_len = 3 + (int)ldns_rdf_size(publickey_rdf);
data = LDNS_XMALLOC(uint8_t, ipseckey_len);
if(!data) {
if (gateway)
LDNS_FREE(gateway);
if (publickey)
LDNS_FREE(publickey);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
if (gateway_rdf) ldns_rdf_free(gateway_rdf);
if (publickey_rdf) ldns_rdf_free(publickey_rdf);
return LDNS_STATUS_MEM_ERR;
}
data[0] = precedence;
data[1] = gateway_type;
data[2] = algorithm;
if (gateway_type) {
memcpy(data + 3,
ldns_rdf_data(gateway_rdf), ldns_rdf_size(gateway_rdf));
memcpy(data + 3 + ldns_rdf_size(gateway_rdf),
ldns_rdf_data(publickey_rdf), ldns_rdf_size(publickey_rdf));
} else {
memcpy(data + 3,
ldns_rdf_data(publickey_rdf), ldns_rdf_size(publickey_rdf));
}
*rd = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_IPSECKEY, (uint16_t) ipseckey_len, data);
if (gateway)
LDNS_FREE(gateway);
if (publickey)
LDNS_FREE(publickey);
LDNS_FREE(token);
ldns_buffer_free(str_buf);
ldns_rdf_free(gateway_rdf);
ldns_rdf_free(publickey_rdf);
LDNS_FREE(data);
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)) {
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)) {
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((unsigned char)*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;
}