1238104Sdes/*
2238104Sdes * higher.c
3238104Sdes *
4238104Sdes * Specify some higher level functions that would
5238104Sdes * be usefull to would be developers
6238104Sdes *
7238104Sdes * a Net::DNS like library for C
8238104Sdes *
9238104Sdes * (c) NLnet Labs, 2004-2006
10238104Sdes *
11238104Sdes * See the file LICENSE for the license
12238104Sdes */
13238104Sdes
14238104Sdes#include <ldns/config.h>
15238104Sdes
16238104Sdes#include <ldns/ldns.h>
17238104Sdes
18238104Sdes#ifdef HAVE_SSL
19238104Sdes#include <openssl/ssl.h>
20238104Sdes#include <openssl/sha.h>
21238104Sdes#endif /* HAVE_SSL */
22238104Sdes
23238104Sdesldns_rr_list *
24238104Sdesldns_get_rr_list_addr_by_name(ldns_resolver *res, ldns_rdf *name, ldns_rr_class c,
25238104Sdes		uint16_t flags)
26238104Sdes{
27238104Sdes	ldns_pkt *pkt;
28238104Sdes	ldns_rr_list *aaaa;
29238104Sdes	ldns_rr_list *a;
30238104Sdes	ldns_rr_list *result = NULL;
31238104Sdes	ldns_rr_list *hostsfilenames;
32238104Sdes	size_t i;
33238104Sdes	uint8_t ip6;
34238104Sdes
35238104Sdes	a = NULL;
36238104Sdes	aaaa = NULL;
37238104Sdes	result = NULL;
38238104Sdes
39238104Sdes	if (!res) {
40238104Sdes		return NULL;
41238104Sdes	}
42238104Sdes	if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) {
43238104Sdes		return NULL;
44238104Sdes	}
45238104Sdes
46238104Sdes	ip6 = ldns_resolver_ip6(res); /* we use INET_ANY here, save
47238104Sdes					 what was there */
48238104Sdes
49238104Sdes	ldns_resolver_set_ip6(res, LDNS_RESOLV_INETANY);
50238104Sdes
51238104Sdes	hostsfilenames = ldns_get_rr_list_hosts_frm_file(NULL);
52238104Sdes	for (i = 0; i < ldns_rr_list_rr_count(hostsfilenames); i++) {
53238104Sdes		if (ldns_rdf_compare(name,
54238104Sdes					ldns_rr_owner(ldns_rr_list_rr(hostsfilenames,
55238104Sdes							i))) == 0) {
56238104Sdes			if (!result) {
57238104Sdes				result = ldns_rr_list_new();
58238104Sdes			}
59238104Sdes			ldns_rr_list_push_rr(result,
60238104Sdes					ldns_rr_clone(ldns_rr_list_rr(hostsfilenames, i)));
61238104Sdes		}
62238104Sdes	}
63238104Sdes	ldns_rr_list_deep_free(hostsfilenames);
64238104Sdes
65238104Sdes	if (result) {
66238104Sdes		return result;
67238104Sdes	}
68238104Sdes
69238104Sdes	/* add the RD flags, because we want an answer */
70238104Sdes	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_AAAA, c, flags | LDNS_RD);
71238104Sdes	if (pkt) {
72238104Sdes		/* extract the data we need */
73238104Sdes		aaaa = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_AAAA,
74238104Sdes			LDNS_SECTION_ANSWER);
75238104Sdes		ldns_pkt_free(pkt);
76238104Sdes	}
77238104Sdes
78238104Sdes	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_A, c, flags | LDNS_RD);
79238104Sdes	if (pkt) {
80238104Sdes		/* extract the data we need */
81238104Sdes		a = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_A, LDNS_SECTION_ANSWER);
82238104Sdes		ldns_pkt_free(pkt);
83238104Sdes	}
84238104Sdes	ldns_resolver_set_ip6(res, ip6);
85238104Sdes
86238104Sdes	if (aaaa && a) {
87238104Sdes		result = ldns_rr_list_cat_clone(aaaa, a);
88238104Sdes		ldns_rr_list_deep_free(aaaa);
89238104Sdes		ldns_rr_list_deep_free(a);
90238104Sdes		return result;
91238104Sdes	}
92238104Sdes
93238104Sdes	if (aaaa) {
94238104Sdes		result = ldns_rr_list_clone(aaaa);
95238104Sdes	}
96238104Sdes
97238104Sdes	if (a) {
98238104Sdes		result = ldns_rr_list_clone(a);
99238104Sdes	}
100238104Sdes
101238104Sdes	ldns_rr_list_deep_free(aaaa);
102238104Sdes	ldns_rr_list_deep_free(a);
103238104Sdes	return result;
104238104Sdes}
105238104Sdes
106238104Sdesldns_rr_list *
107238104Sdesldns_get_rr_list_name_by_addr(ldns_resolver *res, ldns_rdf *addr, ldns_rr_class c,
108238104Sdes		uint16_t flags)
109238104Sdes{
110238104Sdes	ldns_pkt *pkt;
111238104Sdes	ldns_rr_list *names;
112238104Sdes	ldns_rdf *name;
113238104Sdes
114238104Sdes	names = NULL;
115238104Sdes
116238104Sdes	if (!res || !addr) {
117238104Sdes		return NULL;
118238104Sdes	}
119238104Sdes
120238104Sdes	if (ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_A &&
121238104Sdes			ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_AAAA) {
122238104Sdes		return NULL;
123238104Sdes	}
124238104Sdes
125238104Sdes	name = ldns_rdf_address_reverse(addr);
126238104Sdes
127238104Sdes	/* add the RD flags, because we want an answer */
128238104Sdes	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_PTR, c, flags | LDNS_RD);
129246854Sdes	ldns_rdf_deep_free(name);
130238104Sdes	if (pkt) {
131238104Sdes		/* extract the data we need */
132238104Sdes		names = ldns_pkt_rr_list_by_type(pkt,
133238104Sdes				LDNS_RR_TYPE_PTR, LDNS_SECTION_ANSWER);
134269257Sdes		ldns_pkt_free(pkt);
135238104Sdes	}
136238104Sdes	return names;
137238104Sdes}
138238104Sdes
139238104Sdes/* read a line, put it in a buffer, parse the buffer */
140238104Sdesldns_rr_list *
141238104Sdesldns_get_rr_list_hosts_frm_fp(FILE *fp)
142238104Sdes{
143238104Sdes	return ldns_get_rr_list_hosts_frm_fp_l(fp, NULL);
144238104Sdes}
145238104Sdes
146238104Sdesldns_rr_list *
147238104Sdesldns_get_rr_list_hosts_frm_fp_l(FILE *fp, int *line_nr)
148238104Sdes{
149238104Sdes	ssize_t i, j;
150238104Sdes	size_t cnt;
151238104Sdes	char *line;
152238104Sdes	char *word;
153238104Sdes	char *addr;
154238104Sdes	char *rr_str;
155238104Sdes	ldns_buffer *linebuf;
156238104Sdes	ldns_rr *rr;
157238104Sdes	ldns_rr_list *list;
158238104Sdes	ldns_rdf *tmp;
159238104Sdes	bool ip6;
160238104Sdes	ldns_status parse_result;
161238104Sdes
162238104Sdes	line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
163238104Sdes	word = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
164238104Sdes	addr = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
165238104Sdes	rr_str = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
166238104Sdes	ip6 = false;
167238104Sdes	list = ldns_rr_list_new();
168238104Sdes	rr = NULL;
169238104Sdes	if(!line || !word || !addr || !rr_str || !list) {
170238104Sdes		LDNS_FREE(line);
171238104Sdes		LDNS_FREE(word);
172238104Sdes		LDNS_FREE(addr);
173238104Sdes		LDNS_FREE(rr_str);
174238104Sdes		ldns_rr_list_free(list);
175238104Sdes		return NULL;
176238104Sdes	}
177238104Sdes
178238104Sdes	for(i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr);
179238104Sdes			i > 0; i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr)) {
180238104Sdes		/* # is comment */
181238104Sdes		if (line[0] == '#') {
182238104Sdes			continue;
183238104Sdes		}
184238104Sdes		/* put it in a buffer for further processing */
185238104Sdes		linebuf = LDNS_MALLOC(ldns_buffer);
186238104Sdes		if(!linebuf) {
187238104Sdes			LDNS_FREE(line);
188238104Sdes			LDNS_FREE(word);
189238104Sdes			LDNS_FREE(addr);
190238104Sdes			LDNS_FREE(rr_str);
191238104Sdes			ldns_rr_list_deep_free(list);
192238104Sdes			return NULL;
193238104Sdes		}
194238104Sdes
195238104Sdes		ldns_buffer_new_frm_data(linebuf, line, (size_t) i);
196238104Sdes		for(cnt = 0, j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN);
197238104Sdes				j > 0;
198238104Sdes				j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN), cnt++) {
199238104Sdes			if (cnt == 0) {
200238104Sdes				/* the address */
201238104Sdes				if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA,
202238104Sdes								word))) {
203238104Sdes					/* ip6 */
204238104Sdes					ldns_rdf_deep_free(tmp);
205238104Sdes					ip6 = true;
206238104Sdes				} else {
207238104Sdes					if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A,
208238104Sdes									word))) {
209238104Sdes						/* ip4 */
210238104Sdes						ldns_rdf_deep_free(tmp);
211238104Sdes						ip6 = false;
212238104Sdes					} else {
213238104Sdes						/* kaput */
214238104Sdes						break;
215238104Sdes					}
216238104Sdes				}
217238104Sdes				(void)strlcpy(addr, word, LDNS_MAX_LINELEN+1);
218238104Sdes			} else {
219238104Sdes				/* la al la la */
220238104Sdes				if (ip6) {
221238104Sdes					snprintf(rr_str, LDNS_MAX_LINELEN,
222238104Sdes						"%s IN AAAA %s", word, addr);
223238104Sdes				} else {
224238104Sdes					snprintf(rr_str, LDNS_MAX_LINELEN,
225238104Sdes						"%s IN A %s", word, addr);
226238104Sdes				}
227238104Sdes				parse_result = ldns_rr_new_frm_str(&rr, rr_str, 0, NULL, NULL);
228238104Sdes				if (parse_result == LDNS_STATUS_OK && ldns_rr_owner(rr) && ldns_rr_rd_count(rr) > 0) {
229238104Sdes					ldns_rr_list_push_rr(list, ldns_rr_clone(rr));
230238104Sdes				}
231238104Sdes				ldns_rr_free(rr);
232238104Sdes			}
233238104Sdes		}
234238104Sdes		ldns_buffer_free(linebuf);
235238104Sdes	}
236238104Sdes	LDNS_FREE(line);
237238104Sdes	LDNS_FREE(word);
238238104Sdes	LDNS_FREE(addr);
239238104Sdes	LDNS_FREE(rr_str);
240238104Sdes	return list;
241238104Sdes}
242238104Sdes
243238104Sdesldns_rr_list *
244238104Sdesldns_get_rr_list_hosts_frm_file(char *filename)
245238104Sdes{
246238104Sdes	ldns_rr_list *names;
247238104Sdes	FILE *fp;
248238104Sdes
249238104Sdes	if (!filename) {
250238104Sdes                fp = fopen(LDNS_RESOLV_HOSTS, "r");
251238104Sdes
252238104Sdes        } else {
253238104Sdes                fp = fopen(filename, "r");
254238104Sdes        }
255238104Sdes        if (!fp) {
256238104Sdes                return NULL;
257238104Sdes        }
258238104Sdes
259238104Sdes	names = ldns_get_rr_list_hosts_frm_fp(fp);
260238104Sdes	fclose(fp);
261238104Sdes	return names;
262238104Sdes}
263238104Sdes
264238104Sdesuint16_t
265238104Sdesldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c,
266238104Sdes		ldns_rr_list **ret)
267238104Sdes{
268238104Sdes	ldns_rdf_type t;
269238104Sdes	uint16_t names_found;
270238104Sdes	ldns_resolver *r;
271238104Sdes	ldns_status s;
272238104Sdes
273238104Sdes	t = ldns_rdf_get_type(node);
274238104Sdes	names_found = 0;
275238104Sdes	r = res;
276238104Sdes
277238104Sdes	if (res == NULL) {
278238104Sdes		/* prepare a new resolver, using /etc/resolv.conf as a guide  */
279238104Sdes		s = ldns_resolver_new_frm_file(&r, NULL);
280238104Sdes		if (s != LDNS_STATUS_OK) {
281238104Sdes			return 0;
282238104Sdes		}
283238104Sdes	}
284238104Sdes
285238104Sdes	if (t == LDNS_RDF_TYPE_DNAME) {
286238104Sdes		/* we're asked to query for a name */
287238104Sdes		*ret = ldns_get_rr_list_addr_by_name(r, node, c, 0);
288238104Sdes		names_found = ldns_rr_list_rr_count(*ret);
289238104Sdes	}
290238104Sdes
291238104Sdes	if (t == LDNS_RDF_TYPE_A || t == LDNS_RDF_TYPE_AAAA) {
292238104Sdes		/* an address */
293238104Sdes		*ret = ldns_get_rr_list_name_by_addr(r, node, c, 0);
294238104Sdes		names_found = ldns_rr_list_rr_count(*ret);
295238104Sdes	}
296238104Sdes
297238104Sdes	if (res == NULL) {
298238104Sdes		ldns_resolver_deep_free(r);
299238104Sdes	}
300238104Sdes
301238104Sdes	return names_found;
302238104Sdes}
303238104Sdes
304238104Sdesbool
305238104Sdesldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t)
306238104Sdes{
307269257Sdes	switch (ldns_rr_get_type(nsec)) {
308269257Sdes	case LDNS_RR_TYPE_NSEC	: if (ldns_rr_rd_count(nsec) < 2) {
309269257Sdes					  return false;
310269257Sdes				  }
311269257Sdes				  return ldns_nsec_bitmap_covers_type(
312269257Sdes						  ldns_rr_rdf(nsec, 1), t);
313238104Sdes
314269257Sdes	case LDNS_RR_TYPE_NSEC3	: if (ldns_rr_rd_count(nsec) < 6) {
315269257Sdes					  return false;
316269257Sdes				  }
317269257Sdes				  return ldns_nsec_bitmap_covers_type(
318269257Sdes						  ldns_rr_rdf(nsec, 5), t);
319238104Sdes
320269257Sdes	default			: return false;
321238104Sdes	}
322238104Sdes}
323238104Sdes
324238104Sdesvoid
325238104Sdesldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...)
326238104Sdes{
327238104Sdes	int16_t rdf;
328238104Sdes	ldns_rdf *rd;
329238104Sdes	va_list va_rdf;
330238104Sdes	va_start(va_rdf, rdfnum);
331238104Sdes
332238104Sdes	for (rdf = (int16_t)rdfnum; rdf != -1; rdf = (int16_t)va_arg(va_rdf, int))
333238104Sdes	{
334238104Sdes		rd = ldns_rr_rdf(r, rdf);
335238104Sdes		if (!rd) {
336238104Sdes			continue;
337238104Sdes		} else {
338238104Sdes			ldns_rdf_print(fp, rd);
339238104Sdes			fprintf(fp, " "); /* not sure if we want to do this */
340238104Sdes		}
341238104Sdes	}
342238104Sdes	va_end(va_rdf);
343238104Sdes}
344269257Sdes
345