1/*
2 * rdata.c
3 *
4 * rdata implementation
5 *
6 * a Net::DNS like library for C
7 *
8 * (c) NLnet Labs, 2004-2006
9 *
10 * See the file LICENSE for the license
11 */
12
13#include <ldns/config.h>
14
15#include <ldns/ldns.h>
16
17/*
18 * Access functions
19 * do this as functions to get type checking
20 */
21
22/* read */
23size_t
24ldns_rdf_size(const ldns_rdf *rd)
25{
26	assert(rd != NULL);
27	return rd->_size;
28}
29
30ldns_rdf_type
31ldns_rdf_get_type(const ldns_rdf *rd)
32{
33	assert(rd != NULL);
34	return rd->_type;
35}
36
37uint8_t *
38ldns_rdf_data(const ldns_rdf *rd)
39{
40	assert(rd != NULL);
41	return rd->_data;
42}
43
44/* write */
45void
46ldns_rdf_set_size(ldns_rdf *rd, size_t size)
47{
48	assert(rd != NULL);
49	rd->_size = size;
50}
51
52void
53ldns_rdf_set_type(ldns_rdf *rd, ldns_rdf_type type)
54{
55	assert(rd != NULL);
56	rd->_type = type;
57}
58
59void
60ldns_rdf_set_data(ldns_rdf *rd, void *data)
61{
62	/* only copy the pointer */
63	assert(rd != NULL);
64	rd->_data = data;
65}
66
67/* for types that allow it, return
68 * the native/host order type */
69uint8_t
70ldns_rdf2native_int8(const ldns_rdf *rd)
71{
72	uint8_t data;
73
74	/* only allow 8 bit rdfs */
75	if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_BYTE) {
76		return 0;
77	}
78
79	memcpy(&data, ldns_rdf_data(rd), sizeof(data));
80	return data;
81}
82
83uint16_t
84ldns_rdf2native_int16(const ldns_rdf *rd)
85{
86	uint16_t data;
87
88	/* only allow 16 bit rdfs */
89	if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_WORD) {
90		return 0;
91	}
92
93	memcpy(&data, ldns_rdf_data(rd), sizeof(data));
94	return ntohs(data);
95}
96
97uint32_t
98ldns_rdf2native_int32(const ldns_rdf *rd)
99{
100	uint32_t data;
101
102	/* only allow 32 bit rdfs */
103	if (ldns_rdf_size(rd) != LDNS_RDF_SIZE_DOUBLEWORD) {
104		return 0;
105	}
106
107	memcpy(&data, ldns_rdf_data(rd), sizeof(data));
108	return ntohl(data);
109}
110
111time_t
112ldns_rdf2native_time_t(const ldns_rdf *rd)
113{
114	uint32_t data;
115
116	switch(ldns_rdf_get_type(rd)) {
117		case LDNS_RDF_TYPE_TIME:
118			memcpy(&data, ldns_rdf_data(rd), sizeof(data));
119			return (time_t)ntohl(data);
120		default:
121			return 0;
122	}
123}
124
125ldns_rdf *
126ldns_native2rdf_int8(ldns_rdf_type type, uint8_t value)
127{
128	return ldns_rdf_new_frm_data(type, LDNS_RDF_SIZE_BYTE, &value);
129}
130
131ldns_rdf *
132ldns_native2rdf_int16(ldns_rdf_type type, uint16_t value)
133{
134	uint16_t *rdf_data = LDNS_XMALLOC(uint16_t, 1);
135        ldns_rdf* rdf;
136	if (!rdf_data) {
137		return NULL;
138	}
139	ldns_write_uint16(rdf_data, value);
140	rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_WORD, rdf_data);
141        if(!rdf)
142                LDNS_FREE(rdf_data);
143        return rdf;
144}
145
146ldns_rdf *
147ldns_native2rdf_int32(ldns_rdf_type type, uint32_t value)
148{
149	uint32_t *rdf_data = LDNS_XMALLOC(uint32_t, 1);
150        ldns_rdf* rdf;
151	if (!rdf_data) {
152		return NULL;
153	}
154	ldns_write_uint32(rdf_data, value);
155	rdf = ldns_rdf_new(type, LDNS_RDF_SIZE_DOUBLEWORD, rdf_data);
156        if(!rdf)
157                LDNS_FREE(rdf_data);
158        return rdf;
159}
160
161ldns_rdf *
162ldns_native2rdf_int16_data(size_t size, uint8_t *data)
163{
164	uint8_t *rdf_data = LDNS_XMALLOC(uint8_t, size + 2);
165        ldns_rdf* rdf;
166	if (!rdf_data) {
167		return NULL;
168	}
169	ldns_write_uint16(rdf_data, size);
170	memcpy(rdf_data + 2, data, size);
171	rdf = ldns_rdf_new(LDNS_RDF_TYPE_INT16_DATA, size + 2, rdf_data);
172        if(!rdf)
173                LDNS_FREE(rdf_data);
174        return rdf;
175}
176
177/* note: data must be allocated memory */
178ldns_rdf *
179ldns_rdf_new(ldns_rdf_type type, size_t size, void *data)
180{
181	ldns_rdf *rd;
182	rd = LDNS_MALLOC(ldns_rdf);
183	if (!rd) {
184		return NULL;
185	}
186	ldns_rdf_set_size(rd, size);
187	ldns_rdf_set_type(rd, type);
188	ldns_rdf_set_data(rd, data);
189	return rd;
190}
191
192ldns_rdf *
193ldns_rdf_new_frm_data(ldns_rdf_type type, size_t size, const void *data)
194{
195	ldns_rdf *rdf;
196
197	/* if the size is too big, fail */
198	if (size > LDNS_MAX_RDFLEN) {
199		return NULL;
200	}
201
202	/* allocate space */
203	rdf = LDNS_MALLOC(ldns_rdf);
204	if (!rdf) {
205		return NULL;
206	}
207	rdf->_data = LDNS_XMALLOC(uint8_t, size);
208	if (!rdf->_data) {
209		LDNS_FREE(rdf);
210		return NULL;
211	}
212
213	/* set the values */
214	ldns_rdf_set_type(rdf, type);
215	ldns_rdf_set_size(rdf, size);
216	memcpy(rdf->_data, data, size);
217
218	return rdf;
219}
220
221ldns_rdf *
222ldns_rdf_clone(const ldns_rdf *rd)
223{
224	assert(rd != NULL);
225	return (ldns_rdf_new_frm_data( ldns_rdf_get_type(rd),
226		ldns_rdf_size(rd), ldns_rdf_data(rd)));
227}
228
229void
230ldns_rdf_deep_free(ldns_rdf *rd)
231{
232	if (rd) {
233		if (rd->_data) {
234			LDNS_FREE(rd->_data);
235		}
236		LDNS_FREE(rd);
237	}
238}
239
240void
241ldns_rdf_free(ldns_rdf *rd)
242{
243	if (rd) {
244		LDNS_FREE(rd);
245	}
246}
247
248ldns_rdf *
249ldns_rdf_new_frm_str(ldns_rdf_type type, const char *str)
250{
251	ldns_rdf *rdf = NULL;
252	ldns_status status;
253
254	switch (type) {
255	case LDNS_RDF_TYPE_DNAME:
256		status = ldns_str2rdf_dname(&rdf, str);
257		break;
258	case LDNS_RDF_TYPE_INT8:
259		status = ldns_str2rdf_int8(&rdf, str);
260		break;
261	case LDNS_RDF_TYPE_INT16:
262		status = ldns_str2rdf_int16(&rdf, str);
263		break;
264	case LDNS_RDF_TYPE_INT32:
265		status = ldns_str2rdf_int32(&rdf, str);
266		break;
267	case LDNS_RDF_TYPE_A:
268		status = ldns_str2rdf_a(&rdf, str);
269		break;
270	case LDNS_RDF_TYPE_AAAA:
271		status = ldns_str2rdf_aaaa(&rdf, str);
272		break;
273	case LDNS_RDF_TYPE_STR:
274		status = ldns_str2rdf_str(&rdf, str);
275		break;
276	case LDNS_RDF_TYPE_APL:
277		status = ldns_str2rdf_apl(&rdf, str);
278		break;
279	case LDNS_RDF_TYPE_B64:
280		status = ldns_str2rdf_b64(&rdf, str);
281		break;
282	case LDNS_RDF_TYPE_B32_EXT:
283		status = ldns_str2rdf_b32_ext(&rdf, str);
284		break;
285	case LDNS_RDF_TYPE_HEX:
286		status = ldns_str2rdf_hex(&rdf, str);
287		break;
288	case LDNS_RDF_TYPE_NSEC:
289		status = ldns_str2rdf_nsec(&rdf, str);
290		break;
291	case LDNS_RDF_TYPE_TYPE:
292		status = ldns_str2rdf_type(&rdf, str);
293		break;
294	case LDNS_RDF_TYPE_CLASS:
295		status = ldns_str2rdf_class(&rdf, str);
296		break;
297	case LDNS_RDF_TYPE_CERT_ALG:
298		status = ldns_str2rdf_cert_alg(&rdf, str);
299		break;
300	case LDNS_RDF_TYPE_ALG:
301		status = ldns_str2rdf_alg(&rdf, str);
302		break;
303	case LDNS_RDF_TYPE_UNKNOWN:
304		status = ldns_str2rdf_unknown(&rdf, str);
305		break;
306	case LDNS_RDF_TYPE_TIME:
307		status = ldns_str2rdf_time(&rdf, str);
308		break;
309	case LDNS_RDF_TYPE_PERIOD:
310		status = ldns_str2rdf_period(&rdf, str);
311		break;
312	case LDNS_RDF_TYPE_TSIG:
313		status = ldns_str2rdf_tsig(&rdf, str);
314		break;
315	case LDNS_RDF_TYPE_SERVICE:
316		status = ldns_str2rdf_service(&rdf, str);
317		break;
318	case LDNS_RDF_TYPE_LOC:
319		status = ldns_str2rdf_loc(&rdf, str);
320		break;
321	case LDNS_RDF_TYPE_WKS:
322		status = ldns_str2rdf_wks(&rdf, str);
323		break;
324	case LDNS_RDF_TYPE_NSAP:
325		status = ldns_str2rdf_nsap(&rdf, str);
326		break;
327	case LDNS_RDF_TYPE_ATMA:
328		status = ldns_str2rdf_atma(&rdf, str);
329		break;
330	case LDNS_RDF_TYPE_IPSECKEY:
331		status = ldns_str2rdf_ipseckey(&rdf, str);
332		break;
333	case LDNS_RDF_TYPE_NSEC3_SALT:
334		status = ldns_str2rdf_nsec3_salt(&rdf, str);
335		break;
336	case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER:
337		status = ldns_str2rdf_b32_ext(&rdf, str);
338		break;
339	case LDNS_RDF_TYPE_NONE:
340	default:
341		/* default default ??? */
342		status = LDNS_STATUS_ERR;
343		break;
344	}
345	if (LDNS_STATUS_OK == status) {
346		ldns_rdf_set_type(rdf, type);
347		return rdf;
348	}
349	if (rdf) {
350		LDNS_FREE(rdf);
351	}
352	return NULL;
353}
354
355ldns_status
356ldns_rdf_new_frm_fp(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp)
357{
358	return ldns_rdf_new_frm_fp_l(rdf, type, fp, NULL);
359}
360
361ldns_status
362ldns_rdf_new_frm_fp_l(ldns_rdf **rdf, ldns_rdf_type type, FILE *fp, int *line_nr)
363{
364	char *line;
365	ldns_rdf *r;
366	ssize_t t;
367
368	line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
369	if (!line) {
370		return LDNS_STATUS_MEM_ERR;
371	}
372
373	/* read an entire line in from the file */
374	if ((t = ldns_fget_token_l(fp, line, LDNS_PARSE_SKIP_SPACE, 0, line_nr)) == -1 || t == 0) {
375		LDNS_FREE(line);
376		return LDNS_STATUS_SYNTAX_RDATA_ERR;
377	}
378	r =  ldns_rdf_new_frm_str(type, (const char*) line);
379	LDNS_FREE(line);
380	if (rdf) {
381		*rdf = r;
382		return LDNS_STATUS_OK;
383	} else {
384		return LDNS_STATUS_NULL;
385	}
386}
387
388ldns_rdf *
389ldns_rdf_address_reverse(ldns_rdf *rd)
390{
391	uint8_t buf_4[LDNS_IP4ADDRLEN];
392	uint8_t buf_6[LDNS_IP6ADDRLEN * 2];
393	ldns_rdf *rev;
394	ldns_rdf *in_addr;
395	ldns_rdf *ret_dname;
396	uint8_t octet;
397	uint8_t nnibble;
398	uint8_t nibble;
399	uint8_t i, j;
400
401	char *char_dname;
402	int nbit;
403
404	if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_A &&
405			ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_AAAA) {
406		return NULL;
407	}
408
409	in_addr = NULL;
410	ret_dname = NULL;
411
412	switch(ldns_rdf_get_type(rd)) {
413		case LDNS_RDF_TYPE_A:
414			/* the length of the buffer is 4 */
415			buf_4[3] = ldns_rdf_data(rd)[0];
416			buf_4[2] = ldns_rdf_data(rd)[1];
417			buf_4[1] = ldns_rdf_data(rd)[2];
418			buf_4[0] = ldns_rdf_data(rd)[3];
419			in_addr = ldns_dname_new_frm_str("in-addr.arpa.");
420			if (!in_addr) {
421				return NULL;
422			}
423			/* make a new rdf and convert that back  */
424			rev = ldns_rdf_new_frm_data( LDNS_RDF_TYPE_A,
425				LDNS_IP4ADDRLEN, (void*)&buf_4);
426			if (!rev) {
427				LDNS_FREE(in_addr);
428				return NULL;
429			}
430
431			/* convert rev to a string */
432			char_dname = ldns_rdf2str(rev);
433			if (!char_dname) {
434				LDNS_FREE(in_addr);
435				ldns_rdf_deep_free(rev);
436				return NULL;
437			}
438			/* transform back to rdf with type dname */
439			ret_dname = ldns_dname_new_frm_str(char_dname);
440			if (!ret_dname) {
441				LDNS_FREE(in_addr);
442				ldns_rdf_deep_free(rev);
443				LDNS_FREE(char_dname);
444				return NULL;
445			}
446			/* not needed anymore */
447			ldns_rdf_deep_free(rev);
448			LDNS_FREE(char_dname);
449			break;
450		case LDNS_RDF_TYPE_AAAA:
451			/* some foo magic to reverse the nibbles ... */
452
453			for (nbit = 127; nbit >= 0; nbit = nbit - 4) {
454				/* calculate octett (8 bit) */
455				octet = ( ((unsigned int) nbit) & 0x78) >> 3;
456				/* calculate nibble */
457				nnibble = ( ((unsigned int) nbit) & 0x04) >> 2;
458				/* extract nibble */
459				nibble = (ldns_rdf_data(rd)[octet] & ( 0xf << (4 * (1 -
460						 nnibble)) ) ) >> ( 4 * (1 -
461						nnibble));
462
463				buf_6[(LDNS_IP6ADDRLEN * 2 - 1) -
464					(octet * 2 + nnibble)] =
465						(uint8_t)ldns_int_to_hexdigit((int)nibble);
466			}
467
468			char_dname = LDNS_XMALLOC(char, (LDNS_IP6ADDRLEN * 4));
469			if (!char_dname) {
470				return NULL;
471			}
472			char_dname[LDNS_IP6ADDRLEN * 4 - 1] = '\0'; /* closure */
473
474			/* walk the string and add . 's */
475			for (i = 0, j = 0; i < LDNS_IP6ADDRLEN * 2; i++, j = j + 2) {
476				char_dname[j] = (char)buf_6[i];
477				if (i != LDNS_IP6ADDRLEN * 2 - 1) {
478					char_dname[j + 1] = '.';
479				}
480			}
481			in_addr = ldns_dname_new_frm_str("ip6.arpa.");
482			if (!in_addr) {
483				LDNS_FREE(char_dname);
484				return NULL;
485			}
486
487			/* convert rev to a string */
488			ret_dname = ldns_dname_new_frm_str(char_dname);
489			LDNS_FREE(char_dname);
490			if (!ret_dname) {
491				ldns_rdf_deep_free(in_addr);
492				return NULL;
493			}
494			break;
495		default:
496			break;
497	}
498	/* add the suffix */
499	rev = ldns_dname_cat_clone(ret_dname, in_addr);
500
501	ldns_rdf_deep_free(ret_dname);
502	ldns_rdf_deep_free(in_addr);
503	return rev;
504}
505
506ldns_status
507ldns_octet(char *word, size_t *length)
508{
509    char *s;
510    char *p;
511    *length = 0;
512
513    for (s = p = word; *s != '\0'; s++,p++) {
514        switch (*s) {
515            case '.':
516                if (s[1] == '.') {
517		    return LDNS_STATUS_EMPTY_LABEL;
518                }
519                *p = *s;
520                (*length)++;
521                break;
522            case '\\':
523                if ('0' <= s[1] && s[1] <= '9' &&
524                    '0' <= s[2] && s[2] <= '9' &&
525                    '0' <= s[3] && s[3] <= '9') {
526                    /* \DDD seen */
527                    int val = ((s[1] - '0') * 100 +
528                           (s[2] - '0') * 10 + (s[3] - '0'));
529
530                    if (0 <= val && val <= 255) {
531                        /* this also handles \0 */
532                        s += 3;
533                        *p = val;
534                        (*length)++;
535                    } else {
536                        return LDNS_STATUS_DDD_OVERFLOW;
537                    }
538                } else {
539                    /* an espaced character, like \<space> ?
540                    * remove the '\' keep the rest */
541                    *p = *++s;
542                    (*length)++;
543                }
544                break;
545            case '\"':
546                /* non quoted " Is either first or the last character in
547                 * the string */
548
549                *p = *++s; /* skip it */
550                (*length)++;
551		/* I'm not sure if this is needed in libdns... MG */
552                if ( *s == '\0' ) {
553                    /* ok, it was the last one */
554                    *p  = '\0';
555		    return LDNS_STATUS_OK;
556                }
557                break;
558            default:
559                *p = *s;
560                (*length)++;
561                break;
562        }
563    }
564    *p = '\0';
565    return LDNS_STATUS_OK;
566}
567
568int
569ldns_rdf_compare(const ldns_rdf *rd1, const ldns_rdf *rd2)
570{
571	uint16_t i1, i2, i;
572	uint8_t *d1, *d2;
573
574	/* only when both are not NULL we can say anything about them */
575	if (!rd1 && !rd2) {
576		return 0;
577	}
578	if (!rd1 || !rd2) {
579		return -1;
580	}
581	i1 = ldns_rdf_size(rd1);
582	i2 = ldns_rdf_size(rd2);
583
584	if (i1 < i2) {
585		return -1;
586	} else if (i1 > i2) {
587		return +1;
588	} else {
589		d1 = (uint8_t*)ldns_rdf_data(rd1);
590		d2 = (uint8_t*)ldns_rdf_data(rd2);
591		for(i = 0; i < i1; i++) {
592			if (d1[i] < d2[i]) {
593				return -1;
594			} else if (d1[i] > d2[i]) {
595				return +1;
596			}
597		}
598	}
599	return 0;
600}
601
602uint32_t
603ldns_str2period(const char *nptr, const char **endptr)
604{
605	int sign = 0;
606	uint32_t i = 0;
607	uint32_t seconds = 0;
608
609	for(*endptr = nptr; **endptr; (*endptr)++) {
610		switch (**endptr) {
611			case ' ':
612			case '\t':
613				break;
614			case '-':
615				if(sign == 0) {
616					sign = -1;
617				} else {
618					return seconds;
619				}
620				break;
621			case '+':
622				if(sign == 0) {
623					sign = 1;
624				} else {
625					return seconds;
626				}
627				break;
628			case 's':
629			case 'S':
630				seconds += i;
631				i = 0;
632				break;
633			case 'm':
634			case 'M':
635				seconds += i * 60;
636				i = 0;
637				break;
638			case 'h':
639			case 'H':
640				seconds += i * 60 * 60;
641				i = 0;
642				break;
643			case 'd':
644			case 'D':
645				seconds += i * 60 * 60 * 24;
646				i = 0;
647				break;
648			case 'w':
649			case 'W':
650				seconds += i * 60 * 60 * 24 * 7;
651				i = 0;
652				break;
653			case '0':
654			case '1':
655			case '2':
656			case '3':
657			case '4':
658			case '5':
659			case '6':
660			case '7':
661			case '8':
662			case '9':
663				i *= 10;
664				i += (**endptr - '0');
665				break;
666			default:
667				seconds += i;
668				/* disregard signedness */
669				return seconds;
670		}
671	}
672	seconds += i;
673	/* disregard signedness */
674	return seconds;
675}
676