1238104Sdes/*
2238104Sdes * rr_function.c
3238104Sdes *
4238104Sdes * function that operate on specific rr types
5238104Sdes *
6238104Sdes * (c) NLnet Labs, 2004-2006
7238104Sdes * See the file LICENSE for the license
8238104Sdes */
9238104Sdes
10238104Sdes/*
11238104Sdes * These come strait from perldoc Net::DNS::RR::xxx
12238104Sdes * first the read variant, then the write. This is
13238104Sdes * not complete.
14238104Sdes */
15238104Sdes
16238104Sdes#include <ldns/config.h>
17238104Sdes
18238104Sdes#include <ldns/ldns.h>
19238104Sdes
20238104Sdes#include <limits.h>
21238104Sdes#include <strings.h>
22238104Sdes
23238104Sdes/**
24238104Sdes * return a specific rdf
25238104Sdes * \param[in] type type of RR
26238104Sdes * \param[in] rr   the rr itself
27238104Sdes * \param[in] pos  at which postion to get it
28238104Sdes * \return the rdf sought
29238104Sdes */
30238104Sdesstatic ldns_rdf *
31238104Sdesldns_rr_function(ldns_rr_type type, const ldns_rr *rr, size_t pos)
32238104Sdes{
33238104Sdes        if (!rr || ldns_rr_get_type(rr) != type) {
34238104Sdes                return NULL;
35238104Sdes        }
36238104Sdes        return ldns_rr_rdf(rr, pos);
37238104Sdes}
38238104Sdes
39238104Sdes/**
40238104Sdes * set a specific rdf
41238104Sdes * \param[in] type type of RR
42238104Sdes * \param[in] rr   the rr itself
43238104Sdes * \param[in] rdf  the rdf to set
44238104Sdes * \param[in] pos  at which postion to set it
45238104Sdes * \return true or false
46238104Sdes */
47238104Sdesstatic bool
48238104Sdesldns_rr_set_function(ldns_rr_type type, ldns_rr *rr, ldns_rdf *rdf, size_t pos)
49238104Sdes{
50238104Sdes        ldns_rdf *pop;
51238104Sdes        if (!rr || ldns_rr_get_type(rr) != type) {
52238104Sdes                return false;
53238104Sdes        }
54238104Sdes        pop = ldns_rr_set_rdf(rr, rdf, pos);
55238104Sdes 	ldns_rdf_deep_free(pop);
56238104Sdes        return true;
57238104Sdes}
58238104Sdes
59238104Sdes/* A/AAAA records */
60238104Sdesldns_rdf *
61238104Sdesldns_rr_a_address(const ldns_rr *r)
62238104Sdes{
63238104Sdes	/* 2 types to check, cannot use the macro */
64238104Sdes	if (!r || (ldns_rr_get_type(r) != LDNS_RR_TYPE_A &&
65238104Sdes			ldns_rr_get_type(r) != LDNS_RR_TYPE_AAAA)) {
66238104Sdes		return NULL;
67238104Sdes	}
68238104Sdes	return ldns_rr_rdf(r, 0);
69238104Sdes}
70238104Sdes
71238104Sdesbool
72238104Sdesldns_rr_a_set_address(ldns_rr *r, ldns_rdf *f)
73238104Sdes{
74238104Sdes	/* 2 types to check, cannot use the macro... */
75238104Sdes	ldns_rdf *pop;
76238104Sdes	if (!r || (ldns_rr_get_type(r) != LDNS_RR_TYPE_A &&
77238104Sdes			ldns_rr_get_type(r) != LDNS_RR_TYPE_AAAA)) {
78238104Sdes		return false;
79238104Sdes	}
80238104Sdes	pop = ldns_rr_set_rdf(r, f, 0);
81238104Sdes	if (pop) {
82238104Sdes		LDNS_FREE(pop);
83238104Sdes		return true;
84238104Sdes	} else {
85238104Sdes		return false;
86238104Sdes	}
87238104Sdes}
88238104Sdes
89238104Sdes/* NS record */
90238104Sdesldns_rdf *
91238104Sdesldns_rr_ns_nsdname(const ldns_rr *r)
92238104Sdes{
93238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_NS, r, 0);
94238104Sdes}
95238104Sdes
96238104Sdes/* MX record */
97238104Sdesldns_rdf *
98238104Sdesldns_rr_mx_preference(const ldns_rr *r)
99238104Sdes{
100238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_MX, r, 0);
101238104Sdes}
102238104Sdes
103238104Sdesldns_rdf *
104238104Sdesldns_rr_mx_exchange(const ldns_rr *r)
105238104Sdes{
106238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_MX, r, 1);
107238104Sdes}
108238104Sdes
109238104Sdes/* RRSIG record */
110238104Sdesldns_rdf *
111238104Sdesldns_rr_rrsig_typecovered(const ldns_rr *r)
112238104Sdes{
113238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 0);
114238104Sdes}
115238104Sdes
116238104Sdesbool
117238104Sdesldns_rr_rrsig_set_typecovered(ldns_rr *r, ldns_rdf *f)
118238104Sdes{
119238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 0);
120238104Sdes}
121238104Sdes
122238104Sdesldns_rdf *
123238104Sdesldns_rr_rrsig_algorithm(const ldns_rr *r)
124238104Sdes{
125238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 1);
126238104Sdes}
127238104Sdes
128238104Sdesbool
129238104Sdesldns_rr_rrsig_set_algorithm(ldns_rr *r, ldns_rdf *f)
130238104Sdes{
131238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 1);
132238104Sdes}
133238104Sdes
134238104Sdesldns_rdf *
135238104Sdesldns_rr_rrsig_labels(const ldns_rr *r)
136238104Sdes{
137238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 2);
138238104Sdes}
139238104Sdes
140238104Sdesbool
141238104Sdesldns_rr_rrsig_set_labels(ldns_rr *r, ldns_rdf *f)
142238104Sdes{
143238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 2);
144238104Sdes}
145238104Sdes
146238104Sdesldns_rdf *
147238104Sdesldns_rr_rrsig_origttl(const ldns_rr *r)
148238104Sdes{
149238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 3);
150238104Sdes}
151238104Sdes
152238104Sdesbool
153238104Sdesldns_rr_rrsig_set_origttl(ldns_rr *r, ldns_rdf *f)
154238104Sdes{
155238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 3);
156238104Sdes}
157238104Sdes
158238104Sdesldns_rdf *
159238104Sdesldns_rr_rrsig_expiration(const ldns_rr *r)
160238104Sdes{
161238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 4);
162238104Sdes}
163238104Sdes
164238104Sdesbool
165238104Sdesldns_rr_rrsig_set_expiration(ldns_rr *r, ldns_rdf *f)
166238104Sdes{
167238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 4);
168238104Sdes}
169238104Sdes
170238104Sdesldns_rdf *
171238104Sdesldns_rr_rrsig_inception(const ldns_rr *r)
172238104Sdes{
173238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 5);
174238104Sdes}
175238104Sdes
176238104Sdesbool
177238104Sdesldns_rr_rrsig_set_inception(ldns_rr *r, ldns_rdf *f)
178238104Sdes{
179238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 5);
180238104Sdes}
181238104Sdes
182238104Sdesldns_rdf *
183238104Sdesldns_rr_rrsig_keytag(const ldns_rr *r)
184238104Sdes{
185238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 6);
186238104Sdes}
187238104Sdes
188238104Sdesbool
189238104Sdesldns_rr_rrsig_set_keytag(ldns_rr *r, ldns_rdf *f)
190238104Sdes{
191238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 6);
192238104Sdes}
193238104Sdes
194238104Sdesldns_rdf *
195238104Sdesldns_rr_rrsig_signame(const ldns_rr *r)
196238104Sdes{
197238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 7);
198238104Sdes}
199238104Sdes
200238104Sdesbool
201238104Sdesldns_rr_rrsig_set_signame(ldns_rr *r, ldns_rdf *f)
202238104Sdes{
203238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 7);
204238104Sdes}
205238104Sdes
206238104Sdesldns_rdf *
207238104Sdesldns_rr_rrsig_sig(const ldns_rr *r)
208238104Sdes{
209238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_RRSIG, r, 8);
210238104Sdes}
211238104Sdes
212238104Sdesbool
213238104Sdesldns_rr_rrsig_set_sig(ldns_rr *r, ldns_rdf *f)
214238104Sdes{
215238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_RRSIG, r, f, 8);
216238104Sdes}
217238104Sdes
218238104Sdes/* DNSKEY record */
219238104Sdesldns_rdf *
220238104Sdesldns_rr_dnskey_flags(const ldns_rr *r)
221238104Sdes{
222238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 0);
223238104Sdes}
224238104Sdes
225238104Sdesbool
226238104Sdesldns_rr_dnskey_set_flags(ldns_rr *r, ldns_rdf *f)
227238104Sdes{
228238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 0);
229238104Sdes}
230238104Sdes
231238104Sdesldns_rdf *
232238104Sdesldns_rr_dnskey_protocol(const ldns_rr *r)
233238104Sdes{
234238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 1);
235238104Sdes}
236238104Sdes
237238104Sdesbool
238238104Sdesldns_rr_dnskey_set_protocol(ldns_rr *r, ldns_rdf *f)
239238104Sdes{
240238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 1);
241238104Sdes}
242238104Sdes
243238104Sdesldns_rdf *
244238104Sdesldns_rr_dnskey_algorithm(const ldns_rr *r)
245238104Sdes{
246238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 2);
247238104Sdes}
248238104Sdes
249238104Sdesbool
250238104Sdesldns_rr_dnskey_set_algorithm(ldns_rr *r, ldns_rdf *f)
251238104Sdes{
252238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 2);
253238104Sdes}
254238104Sdes
255238104Sdesldns_rdf *
256238104Sdesldns_rr_dnskey_key(const ldns_rr *r)
257238104Sdes{
258238104Sdes	return ldns_rr_function(LDNS_RR_TYPE_DNSKEY, r, 3);
259238104Sdes}
260238104Sdes
261238104Sdesbool
262238104Sdesldns_rr_dnskey_set_key(ldns_rr *r, ldns_rdf *f)
263238104Sdes{
264238104Sdes	return ldns_rr_set_function(LDNS_RR_TYPE_DNSKEY, r, f, 3);
265238104Sdes}
266238104Sdes
267238104Sdessize_t
268238104Sdesldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
269238104Sdes                            const size_t len,
270238104Sdes                            const ldns_algorithm alg)
271238104Sdes{
272238104Sdes	/* for DSA keys */
273238104Sdes	uint8_t t;
274238104Sdes
275238104Sdes	/* for RSA keys */
276238104Sdes	uint16_t exp;
277238104Sdes	uint16_t int16;
278238104Sdes
279238104Sdes	switch ((ldns_signing_algorithm)alg) {
280238104Sdes	case LDNS_SIGN_DSA:
281238104Sdes	case LDNS_SIGN_DSA_NSEC3:
282238104Sdes		if (len > 0) {
283238104Sdes			t = keydata[0];
284238104Sdes			return (64 + t*8)*8;
285238104Sdes		} else {
286238104Sdes			return 0;
287238104Sdes		}
288238104Sdes		break;
289238104Sdes	case LDNS_SIGN_RSAMD5:
290238104Sdes	case LDNS_SIGN_RSASHA1:
291238104Sdes	case LDNS_SIGN_RSASHA1_NSEC3:
292238104Sdes#ifdef USE_SHA2
293238104Sdes	case LDNS_SIGN_RSASHA256:
294238104Sdes	case LDNS_SIGN_RSASHA512:
295238104Sdes#endif
296238104Sdes		if (len > 0) {
297238104Sdes			if (keydata[0] == 0) {
298238104Sdes				/* big exponent */
299238104Sdes				if (len > 3) {
300238104Sdes					memmove(&int16, keydata + 1, 2);
301238104Sdes					exp = ntohs(int16);
302238104Sdes					return (len - exp - 3)*8;
303238104Sdes				} else {
304238104Sdes					return 0;
305238104Sdes				}
306238104Sdes			} else {
307238104Sdes				exp = keydata[0];
308238104Sdes				return (len-exp-1)*8;
309238104Sdes			}
310238104Sdes		} else {
311238104Sdes			return 0;
312238104Sdes		}
313238104Sdes		break;
314238104Sdes#ifdef USE_GOST
315238104Sdes	case LDNS_SIGN_ECC_GOST:
316238104Sdes		return 512;
317238104Sdes#endif
318238104Sdes#ifdef USE_ECDSA
319238104Sdes        case LDNS_SIGN_ECDSAP256SHA256:
320238104Sdes                return 256;
321238104Sdes        case LDNS_SIGN_ECDSAP384SHA384:
322238104Sdes                return 384;
323238104Sdes#endif
324238104Sdes	case LDNS_SIGN_HMACMD5:
325238104Sdes		return len;
326238104Sdes	default:
327238104Sdes		return 0;
328238104Sdes	}
329238104Sdes}
330238104Sdes
331238104Sdessize_t
332238104Sdesldns_rr_dnskey_key_size(const ldns_rr *key)
333238104Sdes{
334238104Sdes	if (!key || !ldns_rr_dnskey_key(key)
335238104Sdes			|| !ldns_rr_dnskey_algorithm(key)) {
336238104Sdes		return 0;
337238104Sdes	}
338238104Sdes	return ldns_rr_dnskey_key_size_raw((unsigned char*)ldns_rdf_data(ldns_rr_dnskey_key(key)),
339238104Sdes	                                   ldns_rdf_size(ldns_rr_dnskey_key(key)),
340238104Sdes	                                   ldns_rdf2native_int8(ldns_rr_dnskey_algorithm(key))
341238104Sdes	                                  );
342238104Sdes}
343238104Sdes
344238104Sdesuint32_t ldns_soa_serial_identity(uint32_t ATTR_UNUSED(unused), void *data)
345238104Sdes{
346238104Sdes	return (uint32_t) (intptr_t) data;
347238104Sdes}
348238104Sdes
349238104Sdesuint32_t ldns_soa_serial_increment(uint32_t s, void *ATTR_UNUSED(unused))
350238104Sdes{
351238104Sdes	return ldns_soa_serial_increment_by(s, (void *)1);
352238104Sdes}
353238104Sdes
354238104Sdesuint32_t ldns_soa_serial_increment_by(uint32_t s, void *data)
355238104Sdes{
356238104Sdes	return s + (intptr_t) data;
357238104Sdes}
358238104Sdes
359238104Sdesuint32_t ldns_soa_serial_datecounter(uint32_t s, void *data)
360238104Sdes{
361238104Sdes	struct tm tm;
362238104Sdes	char s_str[11];
363238104Sdes	int32_t new_s;
364238104Sdes	time_t t = data ? (time_t) (intptr_t) data : ldns_time(NULL);
365238104Sdes
366238104Sdes	(void) strftime(s_str, 11, "%Y%m%d00", localtime_r(&t, &tm));
367238104Sdes	new_s = (int32_t) atoi(s_str);
368238104Sdes	return new_s - ((int32_t) s) <= 0 ? s+1 : ((uint32_t) new_s);
369238104Sdes}
370238104Sdes
371238104Sdesuint32_t ldns_soa_serial_unixtime(uint32_t s, void *data)
372238104Sdes{
373238104Sdes	int32_t new_s = data ? (int32_t) (intptr_t) data
374238104Sdes			     : (int32_t) ldns_time(NULL);
375238104Sdes	return new_s - ((int32_t) s) <= 0 ? s+1 : ((uint32_t) new_s);
376238104Sdes}
377238104Sdes
378238104Sdesvoid
379238104Sdesldns_rr_soa_increment(ldns_rr *soa)
380238104Sdes{
381238104Sdes	ldns_rr_soa_increment_func_data(soa, ldns_soa_serial_increment, NULL);
382238104Sdes}
383238104Sdes
384238104Sdesvoid
385238104Sdesldns_rr_soa_increment_func(ldns_rr *soa, ldns_soa_serial_increment_func_t f)
386238104Sdes{
387238104Sdes	ldns_rr_soa_increment_func_data(soa, f, NULL);
388238104Sdes}
389238104Sdes
390238104Sdesvoid
391238104Sdesldns_rr_soa_increment_func_data(ldns_rr *soa,
392238104Sdes		ldns_soa_serial_increment_func_t f, void *data)
393238104Sdes{
394238104Sdes	ldns_rdf *prev_soa_serial_rdf;
395238104Sdes	if ( !soa || !f || ldns_rr_get_type(soa) != LDNS_RR_TYPE_SOA
396238104Sdes			|| !ldns_rr_rdf(soa, 2)) {
397238104Sdes		return;
398238104Sdes	}
399238104Sdes	prev_soa_serial_rdf = ldns_rr_set_rdf(
400238104Sdes		  soa
401238104Sdes		, ldns_native2rdf_int32(
402238104Sdes			  LDNS_RDF_TYPE_INT32
403238104Sdes			, (*f)( ldns_rdf2native_int32(
404238104Sdes					ldns_rr_rdf(soa, 2))
405238104Sdes			      , data
406238104Sdes			)
407238104Sdes		)
408238104Sdes		, 2
409238104Sdes	);
410238104Sdes	LDNS_FREE(prev_soa_serial_rdf);
411238104Sdes}
412238104Sdes
413238104Sdesvoid
414238104Sdesldns_rr_soa_increment_func_int(ldns_rr *soa,
415238104Sdes		ldns_soa_serial_increment_func_t f, int data)
416238104Sdes{
417238104Sdes	ldns_rr_soa_increment_func_data(soa, f, (void *) (intptr_t) data);
418238104Sdes}
419238104Sdes
420