1238104Sdes/*
2238104Sdes * rdata.c
3238104Sdes *
4238104Sdes * rdata implementation
5238104Sdes *
6238104Sdes * a Net::DNS like library for C
7238104Sdes *
8238104Sdes * (c) NLnet Labs, 2004-2006
9238104Sdes *
10238104Sdes * See the file LICENSE for the license
11238104Sdes */
12238104Sdes
13238104Sdes#include <ldns/config.h>
14238104Sdes
15238104Sdes#include <ldns/ldns.h>
16238104Sdes
17238104Sdes/*
18238104Sdes * Access functions
19238104Sdes * do this as functions to get type checking
20238104Sdes */
21238104Sdes
22238104Sdes/* read */
23238104Sdessize_t
24238104Sdesldns_rdf_size(const ldns_rdf *rd)
25238104Sdes{
26238104Sdes	assert(rd != NULL);
27238104Sdes	return rd->_size;
28238104Sdes}
29238104Sdes
30238104Sdesldns_rdf_type
31238104Sdesldns_rdf_get_type(const ldns_rdf *rd)
32238104Sdes{
33238104Sdes	assert(rd != NULL);
34238104Sdes	return rd->_type;
35238104Sdes}
36238104Sdes
37238104Sdesuint8_t *
38238104Sdesldns_rdf_data(const ldns_rdf *rd)
39238104Sdes{
40238104Sdes	assert(rd != NULL);
41238104Sdes	return rd->_data;
42238104Sdes}
43238104Sdes
44238104Sdes/* write */
45238104Sdesvoid
46238104Sdesldns_rdf_set_size(ldns_rdf *rd, size_t size)
47238104Sdes{
48238104Sdes	assert(rd != NULL);
49238104Sdes	rd->_size = size;
50238104Sdes}
51238104Sdes
52238104Sdesvoid
53238104Sdesldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type)
54238104Sdes{
55238104Sdes	assert(rd != NULL);
56238104Sdes	rd->_type = type;
57238104Sdes}
58238104Sdes
59238104Sdesvoid
60238104Sdesldns_rdf_set_data(ldns_rdf *rd, void *data)
61238104Sdes{
62238104Sdes	/* only copy the pointer */
63238104Sdes	assert(rd != NULL);
64238104Sdes	rd->_data = data;
65238104Sdes}
66238104Sdes
67238104Sdes/* for types that allow it, return
68238104Sdes * the native/host order type */
69238104Sdesuint8_t
70238104Sdesldns_rdf2native_int8(const ldns_rdf *rd)
71238104Sdes{
72238104Sdes	uint8_t data;
73238104Sdes
74238104Sdes	/* only allow 8 bit rdfs */
75238104Sdes	if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_BYTE) {
76238104Sdes		return 0;
77238104Sdes	}
78238104Sdes
79238104Sdes	memcpy(&data, ldns_rdf_data(rd), sizeof(data));
80238104Sdes	return data;
81238104Sdes}
82238104Sdes
83238104Sdesuint16_t
84238104Sdesldns_rdf2native_int16(const ldns_rdf *rd)
85238104Sdes{
86238104Sdes	uint16_t data;
87238104Sdes
88238104Sdes	/* only allow 16 bit rdfs */
89238104Sdes	if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_WORD) {
90238104Sdes		return 0;
91238104Sdes	}
92238104Sdes
93238104Sdes	memcpy(&data, ldns_rdf_data(rd), sizeof(data));
94238104Sdes	return ntohs(data);
95238104Sdes}
96238104Sdes
97238104Sdesuint32_t
98238104Sdesldns_rdf2native_int32(const ldns_rdf *rd)
99238104Sdes{
100238104Sdes	uint32_t data;
101238104Sdes
102238104Sdes	/* only allow 32 bit rdfs */
103238104Sdes	if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD) {
104238104Sdes		return 0;
105238104Sdes	}
106238104Sdes
107238104Sdes	memcpy(&data, ldns_rdf_data(rd), sizeof(data));
108238104Sdes	return ntohl(data);
109238104Sdes}
110238104Sdes
111238104Sdestime_t
112238104Sdesldns_rdf2native_time_t(const ldns_rdf *rd)
113238104Sdes{
114238104Sdes	uint32_t data;
115269257Sdes
116269257Sdes	/* only allow 32 bit rdfs */
117269257Sdes	if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD ||
118269257Sdes			ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_TIME) {
119269257Sdes		return 0;
120238104Sdes	}
121269257Sdes	memcpy(&data, ldns_rdf_data(rd), sizeof(data));
122269257Sdes	return (time_t)ntohl(data);
123238104Sdes}
124238104Sdes
125238104Sdesldns_rdf *
126238104Sdesldns_native2rdf_int8(ldns_rdf_type type, uint8_t value)
127238104Sdes{
128238104Sdes	return ldns_rdf_new_frm_data(type, LDNS_RDF_SIZE_BYTE, &value);
129238104Sdes}
130238104Sdes
131238104Sdesldns_rdf *
132238104Sdesldns_native2rdf_int16(ldns_rdf_type type, uint16_t value)
133238104Sdes{
134238104Sdes	uint16_t *rdf_data = LDNS_XMALLOC(uint16_t, 1);
135238104Sdes        ldns_rdf* rdf;
136238104Sdes	if (!rdf_data) {
137238104Sdes		return NULL;
138238104Sdes	}
139238104Sdes	ldns_write_uint16(rdf_data, value);
140238104Sdes	rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_WORD, rdf_data);
141238104Sdes        if(!rdf)
142238104Sdes                LDNS_FREE(rdf_data);
143238104Sdes        return rdf;
144238104Sdes}
145238104Sdes
146238104Sdesldns_rdf *
147238104Sdesldns_native2rdf_int32(ldns_rdf_type type, uint32_t value)
148238104Sdes{
149238104Sdes	uint32_t *rdf_data = LDNS_XMALLOC(uint32_t, 1);
150238104Sdes        ldns_rdf* rdf;
151238104Sdes	if (!rdf_data) {
152238104Sdes		return NULL;
153238104Sdes	}
154238104Sdes	ldns_write_uint32(rdf_data, value);
155238104Sdes	rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_DOUBLEWORD, rdf_data);
156238104Sdes        if(!rdf)
157238104Sdes                LDNS_FREE(rdf_data);
158238104Sdes        return rdf;
159238104Sdes}
160238104Sdes
161238104Sdesldns_rdf *
162238104Sdesldns_native2rdf_int16_data(size_t size, uint8_t *data)
163238104Sdes{
164238104Sdes	uint8_t *rdf_data = LDNS_XMALLOC(uint8_t, size + 2);
165238104Sdes        ldns_rdf* rdf;
166238104Sdes	if (!rdf_data) {
167238104Sdes		return NULL;
168238104Sdes	}
169238104Sdes	ldns_write_uint16(rdf_data, size);
170238104Sdes	memcpy(rdf_data + 2, data, size);
171238104Sdes	rdf = ldns_rdf_new(LDNS_RDF_TYPE_INT16_DATA, size + 2, rdf_data);
172238104Sdes        if(!rdf)
173238104Sdes                LDNS_FREE(rdf_data);
174238104Sdes        return rdf;
175238104Sdes}
176238104Sdes
177238104Sdes/* note: data must be allocated memory */
178238104Sdesldns_rdf *
179238104Sdesldns_rdf_new(ldns_rdf_type type, size_t size, void *data)
180238104Sdes{
181238104Sdes	ldns_rdf *rd;
182238104Sdes	rd = LDNS_MALLOC(ldns_rdf);
183238104Sdes	if (!rd) {
184238104Sdes		return NULL;
185238104Sdes	}
186238104Sdes	ldns_rdf_set_size(rd, size);
187238104Sdes	ldns_rdf_set_type(rd, type);
188238104Sdes	ldns_rdf_set_data(rd, data);
189238104Sdes	return rd;
190238104Sdes}
191238104Sdes
192238104Sdesldns_rdf *
193238104Sdesldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data)
194238104Sdes{
195238104Sdes	ldns_rdf *rdf;
196238104Sdes
197238104Sdes	/* if the size is too big, fail */
198238104Sdes	if (size > LDNS_MAX_RDFLEN) {
199238104Sdes		return NULL;
200238104Sdes	}
201238104Sdes
202238104Sdes	/* allocate space */
203238104Sdes	rdf = LDNS_MALLOC(ldns_rdf);
204238104Sdes	if (!rdf) {
205238104Sdes		return NULL;
206238104Sdes	}
207238104Sdes	rdf->_data = LDNS_XMALLOC(uint8_t, size);
208238104Sdes	if (!rdf->_data) {
209238104Sdes		LDNS_FREE(rdf);
210238104Sdes		return NULL;
211238104Sdes	}
212238104Sdes
213238104Sdes	/* set the values */
214238104Sdes	ldns_rdf_set_type(rdf, type);
215238104Sdes	ldns_rdf_set_size(rdf, size);
216238104Sdes	memcpy(rdf->_data, data, size);
217238104Sdes
218238104Sdes	return rdf;
219238104Sdes}
220238104Sdes
221238104Sdesldns_rdf *
222238104Sdesldns_rdf_clone(const ldns_rdf *rd)
223238104Sdes{
224238104Sdes	assert(rd != NULL);
225238104Sdes	return (ldns_rdf_new_frm_data( ldns_rdf_get_type(rd),
226238104Sdes		ldns_rdf_size(rd), ldns_rdf_data(rd)));
227238104Sdes}
228238104Sdes
229238104Sdesvoid
230238104Sdesldns_rdf_deep_free(ldns_rdf *rd)
231238104Sdes{
232238104Sdes	if (rd) {
233238104Sdes		if (rd->_data) {
234238104Sdes			LDNS_FREE(rd->_data);
235238104Sdes		}
236238104Sdes		LDNS_FREE(rd);
237238104Sdes	}
238238104Sdes}
239238104Sdes
240238104Sdesvoid
241238104Sdesldns_rdf_free(ldns_rdf *rd)
242238104Sdes{
243238104Sdes	if (rd) {
244238104Sdes		LDNS_FREE(rd);
245238104Sdes	}
246238104Sdes}
247238104Sdes
248238104Sdesldns_rdf *
249238104Sdesldns_rdf_new_frm_str(ldns_rdf_type type, const char *str)
250238104Sdes{
251238104Sdes	ldns_rdf *rdf = NULL;
252238104Sdes	ldns_status status;
253238104Sdes
254238104Sdes	switch (type) {
255238104Sdes	case LDNS_RDF_TYPE_DNAME:
256238104Sdes		status = ldns_str2rdf_dname(&rdf, str);
257238104Sdes		break;
258238104Sdes	case LDNS_RDF_TYPE_INT8:
259238104Sdes		status = ldns_str2rdf_int8(&rdf, str);
260238104Sdes		break;
261238104Sdes	case LDNS_RDF_TYPE_INT16:
262238104Sdes		status = ldns_str2rdf_int16(&rdf, str);
263238104Sdes		break;
264238104Sdes	case LDNS_RDF_TYPE_INT32:
265238104Sdes		status = ldns_str2rdf_int32(&rdf, str);
266238104Sdes		break;
267238104Sdes	case LDNS_RDF_TYPE_A:
268238104Sdes		status = ldns_str2rdf_a(&rdf, str);
269238104Sdes		break;
270238104Sdes	case LDNS_RDF_TYPE_AAAA:
271238104Sdes		status = ldns_str2rdf_aaaa(&rdf, str);
272238104Sdes		break;
273238104Sdes	case LDNS_RDF_TYPE_STR:
274238104Sdes		status = ldns_str2rdf_str(&rdf, str);
275238104Sdes		break;
276238104Sdes	case LDNS_RDF_TYPE_APL:
277238104Sdes		status = ldns_str2rdf_apl(&rdf, str);
278238104Sdes		break;
279238104Sdes	case LDNS_RDF_TYPE_B64:
280238104Sdes		status = ldns_str2rdf_b64(&rdf, str);
281238104Sdes		break;
282238104Sdes	case LDNS_RDF_TYPE_B32_EXT:
283238104Sdes		status = ldns_str2rdf_b32_ext(&rdf, str);
284238104Sdes		break;
285238104Sdes	case LDNS_RDF_TYPE_HEX:
286238104Sdes		status = ldns_str2rdf_hex(&rdf, str);
287238104Sdes		break;
288238104Sdes	case LDNS_RDF_TYPE_NSEC:
289238104Sdes		status = ldns_str2rdf_nsec(&rdf, str);
290238104Sdes		break;
291238104Sdes	case LDNS_RDF_TYPE_TYPE:
292238104Sdes		status = ldns_str2rdf_type(&rdf, str);
293238104Sdes		break;
294238104Sdes	case LDNS_RDF_TYPE_CLASS:
295238104Sdes		status = ldns_str2rdf_class(&rdf, str);
296238104Sdes		break;
297238104Sdes	case LDNS_RDF_TYPE_CERT_ALG:
298238104Sdes		status = ldns_str2rdf_cert_alg(&rdf, str);
299238104Sdes		break;
300238104Sdes	case LDNS_RDF_TYPE_ALG:
301238104Sdes		status = ldns_str2rdf_alg(&rdf, str);
302238104Sdes		break;
303238104Sdes	case LDNS_RDF_TYPE_UNKNOWN:
304238104Sdes		status = ldns_str2rdf_unknown(&rdf, str);
305238104Sdes		break;
306238104Sdes	case LDNS_RDF_TYPE_TIME:
307238104Sdes		status = ldns_str2rdf_time(&rdf, str);
308238104Sdes		break;
309238104Sdes	case LDNS_RDF_TYPE_PERIOD:
310238104Sdes		status = ldns_str2rdf_period(&rdf, str);
311238104Sdes		break;
312269257Sdes	case LDNS_RDF_TYPE_HIP:
313269257Sdes		status = ldns_str2rdf_hip(&rdf, str);
314238104Sdes		break;
315238104Sdes	case LDNS_RDF_TYPE_SERVICE:
316238104Sdes		status = ldns_str2rdf_service(&rdf, str);
317238104Sdes		break;
318238104Sdes	case LDNS_RDF_TYPE_LOC:
319238104Sdes		status = ldns_str2rdf_loc(&rdf, str);
320238104Sdes		break;
321238104Sdes	case LDNS_RDF_TYPE_WKS:
322238104Sdes		status = ldns_str2rdf_wks(&rdf, str);
323238104Sdes		break;
324238104Sdes	case LDNS_RDF_TYPE_NSAP:
325238104Sdes		status = ldns_str2rdf_nsap(&rdf, str);
326238104Sdes		break;
327238104Sdes	case LDNS_RDF_TYPE_ATMA:
328238104Sdes		status = ldns_str2rdf_atma(&rdf, str);
329238104Sdes		break;
330238104Sdes	case LDNS_RDF_TYPE_IPSECKEY:
331238104Sdes		status = ldns_str2rdf_ipseckey(&rdf, str);
332238104Sdes		break;
333238104Sdes	case LDNS_RDF_TYPE_NSEC3_SALT:
334238104Sdes		status = ldns_str2rdf_nsec3_salt(&rdf, str);
335238104Sdes		break;
336238104Sdes	case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
337238104Sdes		status = ldns_str2rdf_b32_ext(&rdf, str);
338238104Sdes		break;
339269257Sdes	case LDNS_RDF_TYPE_ILNP64:
340269257Sdes		status = ldns_str2rdf_ilnp64(&rdf, str);
341269257Sdes		break;
342269257Sdes	case LDNS_RDF_TYPE_EUI48:
343269257Sdes		status = ldns_str2rdf_eui48(&rdf, str);
344269257Sdes		break;
345269257Sdes	case LDNS_RDF_TYPE_EUI64:
346269257Sdes		status = ldns_str2rdf_eui64(&rdf, str);
347269257Sdes		break;
348269257Sdes	case LDNS_RDF_TYPE_TAG:
349269257Sdes		status = ldns_str2rdf_tag(&rdf, str);
350269257Sdes		break;
351269257Sdes	case LDNS_RDF_TYPE_LONG_STR:
352269257Sdes		status = ldns_str2rdf_long_str(&rdf, str);
353269257Sdes		break;
354238104Sdes	case LDNS_RDF_TYPE_NONE:
355238104Sdes	default:
356238104Sdes		/* default default ??? */
357238104Sdes		status = LDNS_STATUS_ERR;
358238104Sdes		break;
359238104Sdes	}
360238104Sdes	if (LDNS_STATUS_OK == status) {
361238104Sdes		ldns_rdf_set_type(rdf, type);
362238104Sdes		return rdf;
363238104Sdes	}
364238104Sdes	if (rdf) {
365238104Sdes		LDNS_FREE(rdf);
366238104Sdes	}
367238104Sdes	return NULL;
368238104Sdes}
369238104Sdes
370238104Sdesldns_status
371238104Sdesldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp)
372238104Sdes{
373238104Sdes	return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL);
374238104Sdes}
375238104Sdes
376238104Sdesldns_status
377238104Sdesldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr)
378238104Sdes{
379238104Sdes	char *line;
380238104Sdes	ldns_rdf *r;
381238104Sdes	ssize_t t;
382238104Sdes
383238104Sdes	line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
384238104Sdes	if (!line) {
385238104Sdes		return LDNS_STATUS_MEM_ERR;
386238104Sdes	}
387238104Sdes
388238104Sdes	/* read an entire line in from the file */
389238104Sdes	if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1 || t == 0) {
390238104Sdes		LDNS_FREE(line);
391238104Sdes		return LDNS_STATUS_SYNTAX_RDATA_ERR;
392238104Sdes	}
393238104Sdes	r =  ldns_rdf_new_frm_str(type, (const char*) line);
394238104Sdes	LDNS_FREE(line);
395238104Sdes	if (rdf) {
396238104Sdes		*rdf = r;
397238104Sdes		return LDNS_STATUS_OK;
398238104Sdes	} else {
399238104Sdes		return LDNS_STATUS_NULL;
400238104Sdes	}
401238104Sdes}
402238104Sdes
403238104Sdesldns_rdf *
404238104Sdesldns_rdf_address_reverse(ldns_rdf *rd)
405238104Sdes{
406238104Sdes	uint8_t buf_4[LDNS_IP4ADDRLEN];
407238104Sdes	uint8_t buf_6[LDNS_IP6ADDRLEN * 2];
408238104Sdes	ldns_rdf *rev;
409238104Sdes	ldns_rdf *in_addr;
410238104Sdes	ldns_rdf *ret_dname;
411238104Sdes	uint8_t octet;
412238104Sdes	uint8_t nnibble;
413238104Sdes	uint8_t nibble;
414238104Sdes	uint8_t i, j;
415238104Sdes
416238104Sdes	char *char_dname;
417238104Sdes	int nbit;
418238104Sdes
419238104Sdes	if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A &&
420238104Sdes			ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) {
421238104Sdes		return NULL;
422238104Sdes	}
423238104Sdes
424238104Sdes	in_addr = NULL;
425238104Sdes	ret_dname = NULL;
426238104Sdes
427238104Sdes	switch(ldns_rdf_get_type(rd)) {
428238104Sdes		case LDNS_RDF_TYPE_A:
429238104Sdes			/* the length of the buffer is 4 */
430238104Sdes			buf_4[3] = ldns_rdf_data(rd)[0];
431238104Sdes			buf_4[2] = ldns_rdf_data(rd)[1];
432238104Sdes			buf_4[1] = ldns_rdf_data(rd)[2];
433238104Sdes			buf_4[0] = ldns_rdf_data(rd)[3];
434238104Sdes			in_addr = ldns_dname_new_frm_str("in-addr.arpa.");
435238104Sdes			if (!in_addr) {
436238104Sdes				return NULL;
437238104Sdes			}
438238104Sdes			/* make a new rdf and convert that back  */
439238104Sdes			rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A,
440238104Sdes				LDNS_IP4ADDRLEN, (void*)&buf_4);
441238104Sdes			if (!rev) {
442238104Sdes				LDNS_FREE(in_addr);
443238104Sdes				return NULL;
444238104Sdes			}
445238104Sdes
446238104Sdes			/* convert rev to a string */
447238104Sdes			char_dname = ldns_rdf2str(rev);
448238104Sdes			if (!char_dname) {
449238104Sdes				LDNS_FREE(in_addr);
450238104Sdes				ldns_rdf_deep_free(rev);
451238104Sdes				return NULL;
452238104Sdes			}
453238104Sdes			/* transform back to rdf with type dname */
454238104Sdes			ret_dname = ldns_dname_new_frm_str(char_dname);
455238104Sdes			if (!ret_dname) {
456238104Sdes				LDNS_FREE(in_addr);
457238104Sdes				ldns_rdf_deep_free(rev);
458238104Sdes				LDNS_FREE(char_dname);
459238104Sdes				return NULL;
460238104Sdes			}
461238104Sdes			/* not needed anymore */
462238104Sdes			ldns_rdf_deep_free(rev);
463238104Sdes			LDNS_FREE(char_dname);
464238104Sdes			break;
465238104Sdes		case LDNS_RDF_TYPE_AAAA:
466238104Sdes			/* some foo magic to reverse the nibbles ... */
467238104Sdes
468238104Sdes			for (nbit = 127; nbit >= 0; nbit = nbit - 4) {
469238104Sdes				/* calculate octett (8 bit) */
470238104Sdes				octet = ( ((unsigned int) nbit) & 0x78) >> 3;
471238104Sdes				/* calculate nibble */
472238104Sdes				nnibble = ( ((unsigned int) nbit) & 0x04) >> 2;
473238104Sdes				/* extract nibble */
474238104Sdes				nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 -
475238104Sdes						 nnibble)) ) ) >> ( 4 * (1 -
476238104Sdes						nnibble));
477238104Sdes
478238104Sdes				buf_6[(LDNS_IP6ADDRLEN * 2 - 1) -
479238104Sdes					(octet * 2 + nnibble)] =
480238104Sdes						(uint8_t)ldns_int_to_hexdigit((int)nibble);
481238104Sdes			}
482238104Sdes
483238104Sdes			char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4));
484238104Sdes			if (!char_dname) {
485238104Sdes				return NULL;
486238104Sdes			}
487238104Sdes			char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */
488238104Sdes
489238104Sdes			/* walk the string and add . 's */
490238104Sdes			for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) {
491238104Sdes				char_dname[j] = (char)buf_6[i];
492238104Sdes				if (i != LDNS_IP6ADDRLEN * 2 - 1) {
493238104Sdes					char_dname[j + 1] = '.';
494238104Sdes				}
495238104Sdes			}
496238104Sdes			in_addr = ldns_dname_new_frm_str("ip6.arpa.");
497238104Sdes			if (!in_addr) {
498238104Sdes				LDNS_FREE(char_dname);
499238104Sdes				return NULL;
500238104Sdes			}
501238104Sdes
502238104Sdes			/* convert rev to a string */
503238104Sdes			ret_dname = ldns_dname_new_frm_str(char_dname);
504238104Sdes			LDNS_FREE(char_dname);
505238104Sdes			if (!ret_dname) {
506238104Sdes				ldns_rdf_deep_free(in_addr);
507238104Sdes				return NULL;
508238104Sdes			}
509238104Sdes			break;
510238104Sdes		default:
511238104Sdes			break;
512238104Sdes	}
513238104Sdes	/* add the suffix */
514238104Sdes	rev = ldns_dname_cat_clone(ret_dname, in_addr);
515238104Sdes
516238104Sdes	ldns_rdf_deep_free(ret_dname);
517238104Sdes	ldns_rdf_deep_free(in_addr);
518238104Sdes	return rev;
519238104Sdes}
520238104Sdes
521238104Sdesldns_status
522269257Sdesldns_rdf_hip_get_alg_hit_pk(ldns_rdf *rdf, uint8_t* alg,
523269257Sdes                            uint8_t *hit_size, uint8_t** hit,
524269257Sdes                            uint16_t *pk_size, uint8_t** pk)
525269257Sdes{
526269257Sdes	uint8_t *data;
527269257Sdes	size_t rdf_size;
528269257Sdes
529269257Sdes	if (! rdf || ! alg || ! hit || ! hit_size || ! pk || ! pk_size) {
530269257Sdes		return LDNS_STATUS_INVALID_POINTER;
531269257Sdes	} else if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_HIP) {
532269257Sdes		return LDNS_STATUS_INVALID_RDF_TYPE;
533269257Sdes	} else if ((rdf_size = ldns_rdf_size(rdf)) < 6) {
534269257Sdes		return LDNS_STATUS_WIRE_RDATA_ERR;
535269257Sdes	}
536269257Sdes	data = ldns_rdf_data(rdf);
537269257Sdes	*hit_size = data[0];
538269257Sdes	*alg      = data[1];
539269257Sdes	*pk_size  = ldns_read_uint16(data + 2);
540269257Sdes	*hit      = data + 4;
541269257Sdes	*pk       = data + 4 + *hit_size;
542269257Sdes	if (*hit_size == 0 || *pk_size == 0 ||
543269257Sdes			rdf_size < (size_t) *hit_size + *pk_size + 4) {
544269257Sdes		return LDNS_STATUS_WIRE_RDATA_ERR;
545269257Sdes	}
546269257Sdes	return LDNS_STATUS_OK;
547269257Sdes}
548269257Sdes
549269257Sdesldns_status
550269257Sdesldns_rdf_hip_new_frm_alg_hit_pk(ldns_rdf** rdf, uint8_t alg,
551269257Sdes                                uint8_t hit_size, uint8_t *hit,
552269257Sdes				uint16_t pk_size, uint8_t *pk)
553269257Sdes{
554269257Sdes	uint8_t *data;
555269257Sdes
556269257Sdes	if (! rdf) {
557269257Sdes		return LDNS_STATUS_INVALID_POINTER;
558269257Sdes	}
559269257Sdes	if (4 + hit_size + pk_size > LDNS_MAX_RDFLEN) {
560269257Sdes		return LDNS_STATUS_RDATA_OVERFLOW;
561269257Sdes	}
562269257Sdes	data = LDNS_XMALLOC(uint8_t, 4 + hit_size + pk_size);
563269257Sdes	if (data == NULL) {
564269257Sdes		return LDNS_STATUS_MEM_ERR;
565269257Sdes	}
566269257Sdes	data[0] = hit_size;
567269257Sdes	data[1] = alg;
568269257Sdes	ldns_write_uint16(data + 2, pk_size);
569269257Sdes	memcpy(data + 4, hit, hit_size);
570269257Sdes	memcpy(data + 4 + hit_size, pk, pk_size);
571269257Sdes	*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HIP, 4 + hit_size + pk_size, data);
572269257Sdes	if (! *rdf) {
573269257Sdes		LDNS_FREE(data);
574269257Sdes		return LDNS_STATUS_MEM_ERR;
575269257Sdes	}
576269257Sdes	return LDNS_STATUS_OK;
577269257Sdes}
578269257Sdes
579269257Sdesldns_status
580238104Sdesldns_octet(char *word, size_t *length)
581238104Sdes{
582238104Sdes    char *s;
583238104Sdes    char *p;
584238104Sdes    *length = 0;
585238104Sdes
586238104Sdes    for (s = p = word; *s != '\0'; s++,p++) {
587238104Sdes        switch (*s) {
588238104Sdes            case '.':
589238104Sdes                if (s[1] == '.') {
590238104Sdes		    return LDNS_STATUS_EMPTY_LABEL;
591238104Sdes                }
592238104Sdes                *p = *s;
593238104Sdes                (*length)++;
594238104Sdes                break;
595238104Sdes            case '\\':
596238104Sdes                if ('0' <= s[1] && s[1] <= '9' &&
597238104Sdes                    '0' <= s[2] && s[2] <= '9' &&
598238104Sdes                    '0' <= s[3] && s[3] <= '9') {
599238104Sdes                    /* \DDD seen */
600238104Sdes                    int val = ((s[1] - '0') * 100 +
601238104Sdes                           (s[2] - '0') * 10 + (s[3] - '0'));
602238104Sdes
603238104Sdes                    if (0 <= val && val <= 255) {
604238104Sdes                        /* this also handles \0 */
605238104Sdes                        s += 3;
606238104Sdes                        *p = val;
607238104Sdes                        (*length)++;
608238104Sdes                    } else {
609238104Sdes                        return LDNS_STATUS_DDD_OVERFLOW;
610238104Sdes                    }
611238104Sdes                } else {
612238104Sdes                    /* an espaced character, like \<space> ?
613238104Sdes                    * remove the '\' keep the rest */
614238104Sdes                    *p = *++s;
615238104Sdes                    (*length)++;
616238104Sdes                }
617238104Sdes                break;
618238104Sdes            case '\"':
619238104Sdes                /* non quoted " Is either first or the last character in
620238104Sdes                 * the string */
621238104Sdes
622238104Sdes                *p = *++s; /* skip it */
623238104Sdes                (*length)++;
624238104Sdes		/* I'm not sure if this is needed in libdns... MG */
625238104Sdes                if ( *s == '\0' ) {
626238104Sdes                    /* ok, it was the last one */
627238104Sdes                    *p  = '\0';
628238104Sdes		    return LDNS_STATUS_OK;
629238104Sdes                }
630238104Sdes                break;
631238104Sdes            default:
632238104Sdes                *p = *s;
633238104Sdes                (*length)++;
634238104Sdes                break;
635238104Sdes        }
636238104Sdes    }
637238104Sdes    *p = '\0';
638238104Sdes    return LDNS_STATUS_OK;
639238104Sdes}
640238104Sdes
641238104Sdesint
642238104Sdesldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2)
643238104Sdes{
644238104Sdes	uint16_t i1, i2, i;
645238104Sdes	uint8_t *d1, *d2;
646238104Sdes
647238104Sdes	/* only when both are not NULL we can say anything about them */
648238104Sdes	if (!rd1 && !rd2) {
649238104Sdes		return 0;
650238104Sdes	}
651238104Sdes	if (!rd1 || !rd2) {
652238104Sdes		return -1;
653238104Sdes	}
654238104Sdes	i1 = ldns_rdf_size(rd1);
655238104Sdes	i2 = ldns_rdf_size(rd2);
656238104Sdes
657238104Sdes	if (i1 < i2) {
658238104Sdes		return -1;
659238104Sdes	} else if (i1 > i2) {
660238104Sdes		return +1;
661238104Sdes	} else {
662238104Sdes		d1 = (uint8_t*)ldns_rdf_data(rd1);
663238104Sdes		d2 = (uint8_t*)ldns_rdf_data(rd2);
664238104Sdes		for(i = 0; i < i1; i++) {
665238104Sdes			if (d1[i] < d2[i]) {
666238104Sdes				return -1;
667238104Sdes			} else if (d1[i] > d2[i]) {
668238104Sdes				return +1;
669238104Sdes			}
670238104Sdes		}
671238104Sdes	}
672238104Sdes	return 0;
673238104Sdes}
674238104Sdes
675238104Sdesuint32_t
676238104Sdesldns_str2period(const char *nptr, const char **endptr)
677238104Sdes{
678238104Sdes	int sign = 0;
679238104Sdes	uint32_t i = 0;
680238104Sdes	uint32_t seconds = 0;
681238104Sdes
682238104Sdes	for(*endptr = nptr; **endptr; (*endptr)++) {
683238104Sdes		switch (**endptr) {
684238104Sdes			case ' ':
685238104Sdes			case '\t':
686238104Sdes				break;
687238104Sdes			case '-':
688238104Sdes				if(sign == 0) {
689238104Sdes					sign = -1;
690238104Sdes				} else {
691238104Sdes					return seconds;
692238104Sdes				}
693238104Sdes				break;
694238104Sdes			case '+':
695238104Sdes				if(sign == 0) {
696238104Sdes					sign = 1;
697238104Sdes				} else {
698238104Sdes					return seconds;
699238104Sdes				}
700238104Sdes				break;
701238104Sdes			case 's':
702238104Sdes			case 'S':
703238104Sdes				seconds += i;
704238104Sdes				i = 0;
705238104Sdes				break;
706238104Sdes			case 'm':
707238104Sdes			case 'M':
708238104Sdes				seconds += i * 60;
709238104Sdes				i = 0;
710238104Sdes				break;
711238104Sdes			case 'h':
712238104Sdes			case 'H':
713238104Sdes				seconds += i * 60 * 60;
714238104Sdes				i = 0;
715238104Sdes				break;
716238104Sdes			case 'd':
717238104Sdes			case 'D':
718238104Sdes				seconds += i * 60 * 60 * 24;
719238104Sdes				i = 0;
720238104Sdes				break;
721238104Sdes			case 'w':
722238104Sdes			case 'W':
723238104Sdes				seconds += i * 60 * 60 * 24 * 7;
724238104Sdes				i = 0;
725238104Sdes				break;
726238104Sdes			case '0':
727238104Sdes			case '1':
728238104Sdes			case '2':
729238104Sdes			case '3':
730238104Sdes			case '4':
731238104Sdes			case '5':
732238104Sdes			case '6':
733238104Sdes			case '7':
734238104Sdes			case '8':
735238104Sdes			case '9':
736238104Sdes				i *= 10;
737238104Sdes				i += (**endptr - '0');
738238104Sdes				break;
739238104Sdes			default:
740238104Sdes				seconds += i;
741238104Sdes				/* disregard signedness */
742238104Sdes				return seconds;
743238104Sdes		}
744238104Sdes	}
745238104Sdes	seconds += i;
746238104Sdes	/* disregard signedness */
747238104Sdes	return seconds;
748238104Sdes}
749