higher.c revision 269257
1117395Skan/*
2169689Skan * higher.c
3169689Skan *
4117395Skan * Specify some higher level functions that would
5117395Skan * be usefull to would be developers
6117395Skan *
7132718Skan * a Net::DNS like library for C
8132718Skan *
9132718Skan * (c) NLnet Labs, 2004-2006
10117395Skan *
11117395Skan * See the file LICENSE for the license
12117395Skan */
13117395Skan
14132718Skan#include <ldns/config.h>
15117395Skan
16117395Skan#include <ldns/ldns.h>
17117395Skan
18117395Skan#ifdef HAVE_SSL
19117395Skan#include <openssl/ssl.h>
20132718Skan#include <openssl/sha.h>
21169689Skan#endif /* HAVE_SSL */
22169689Skan
23117395Skanldns_rr_list *
24117395Skanldns_get_rr_list_addr_by_name(ldns_resolver *res, ldns_rdf *name, ldns_rr_class c,
25132718Skan		uint16_t flags)
26117395Skan{
27117395Skan	ldns_pkt *pkt;
28117395Skan	ldns_rr_list *aaaa;
29117395Skan	ldns_rr_list *a;
30117395Skan	ldns_rr_list *result = NULL;
31117395Skan	ldns_rr_list *hostsfilenames;
32117395Skan	size_t i;
33117395Skan	uint8_t ip6;
34117395Skan
35117395Skan	a = NULL;
36117395Skan	aaaa = NULL;
37117395Skan	result = NULL;
38117395Skan
39117395Skan	if (!res) {
40117395Skan		return NULL;
41117395Skan	}
42117395Skan	if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) {
43132718Skan		return NULL;
44132718Skan	}
45117395Skan
46117395Skan	ip6 = ldns_resolver_ip6(res); /* we use INET_ANY here, save
47117395Skan					 what was there */
48117395Skan
49117395Skan	ldns_resolver_set_ip6(res, LDNS_RESOLV_INETANY);
50117395Skan
51117395Skan	hostsfilenames = ldns_get_rr_list_hosts_frm_file(NULL);
52132718Skan	for (i = 0; i < ldns_rr_list_rr_count(hostsfilenames); i++) {
53132718Skan		if (ldns_rdf_compare(name,
54117395Skan					ldns_rr_owner(ldns_rr_list_rr(hostsfilenames,
55117395Skan							i))) == 0) {
56117395Skan			if (!result) {
57117395Skan				result = ldns_rr_list_new();
58117395Skan			}
59117395Skan			ldns_rr_list_push_rr(result,
60117395Skan					ldns_rr_clone(ldns_rr_list_rr(hostsfilenames, i)));
61117395Skan		}
62132718Skan	}
63117395Skan	ldns_rr_list_deep_free(hostsfilenames);
64117395Skan
65117395Skan	if (result) {
66117395Skan		return result;
67117395Skan	}
68117395Skan
69117395Skan	/* add the RD flags, because we want an answer */
70117395Skan	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_AAAA, c, flags | LDNS_RD);
71132718Skan	if (pkt) {
72132718Skan		/* extract the data we need */
73117395Skan		aaaa = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_AAAA,
74117395Skan			LDNS_SECTION_ANSWER);
75117395Skan		ldns_pkt_free(pkt);
76117395Skan	}
77132718Skan
78117395Skan	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_A, c, flags | LDNS_RD);
79117395Skan	if (pkt) {
80117395Skan		/* extract the data we need */
81117395Skan		a = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_A, LDNS_SECTION_ANSWER);
82117395Skan		ldns_pkt_free(pkt);
83117395Skan	}
84117395Skan	ldns_resolver_set_ip6(res, ip6);
85117395Skan
86117395Skan	if (aaaa && a) {
87117395Skan		result = ldns_rr_list_cat_clone(aaaa, a);
88117395Skan		ldns_rr_list_deep_free(aaaa);
89117395Skan		ldns_rr_list_deep_free(a);
90132718Skan		return result;
91117395Skan	}
92117395Skan
93117395Skan	if (aaaa) {
94117395Skan		result = ldns_rr_list_clone(aaaa);
95117395Skan	}
96117395Skan
97117395Skan	if (a) {
98117395Skan		result = ldns_rr_list_clone(a);
99117395Skan	}
100117395Skan
101117395Skan	ldns_rr_list_deep_free(aaaa);
102117395Skan	ldns_rr_list_deep_free(a);
103117395Skan	return result;
104117395Skan}
105132718Skan
106117395Skanldns_rr_list *
107132718Skanldns_get_rr_list_name_by_addr(ldns_resolver *res, ldns_rdf *addr, ldns_rr_class c,
108132718Skan		uint16_t flags)
109117395Skan{
110117395Skan	ldns_pkt *pkt;
111117395Skan	ldns_rr_list *names;
112169689Skan	ldns_rdf *name;
113117395Skan
114117395Skan	names = NULL;
115117395Skan
116169689Skan	if (!res || !addr) {
117117395Skan		return NULL;
118117395Skan	}
119117395Skan
120117395Skan	if (ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_A &&
121117395Skan			ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_AAAA) {
122117395Skan		return NULL;
123117395Skan	}
124117395Skan
125117395Skan	name = ldns_rdf_address_reverse(addr);
126117395Skan
127117395Skan	/* add the RD flags, because we want an answer */
128117395Skan	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_PTR, c, flags | LDNS_RD);
129117395Skan	ldns_rdf_deep_free(name);
130117395Skan	if (pkt) {
131117395Skan		/* extract the data we need */
132117395Skan		names = ldns_pkt_rr_list_by_type(pkt,
133117395Skan				LDNS_RR_TYPE_PTR, LDNS_SECTION_ANSWER);
134117395Skan		ldns_pkt_free(pkt);
135117395Skan	}
136117395Skan	return names;
137117395Skan}
138117395Skan
139117395Skan/* read a line, put it in a buffer, parse the buffer */
140117395Skanldns_rr_list *
141117395Skanldns_get_rr_list_hosts_frm_fp(FILE *fp)
142117395Skan{
143117395Skan	return ldns_get_rr_list_hosts_frm_fp_l(fp, NULL);
144117395Skan}
145117395Skan
146117395Skanldns_rr_list *
147117395Skanldns_get_rr_list_hosts_frm_fp_l(FILE *fp, int *line_nr)
148117395Skan{
149117395Skan	ssize_t i, j;
150117395Skan	size_t cnt;
151117395Skan	char *line;
152117395Skan	char *word;
153117395Skan	char *addr;
154117395Skan	char *rr_str;
155117395Skan	ldns_buffer *linebuf;
156117395Skan	ldns_rr *rr;
157117395Skan	ldns_rr_list *list;
158117395Skan	ldns_rdf *tmp;
159132718Skan	bool ip6;
160117395Skan	ldns_status parse_result;
161117395Skan
162117395Skan	line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
163117395Skan	word = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
164117395Skan	addr = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
165117395Skan	rr_str = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
166117395Skan	ip6 = false;
167117395Skan	list = ldns_rr_list_new();
168117395Skan	rr = NULL;
169117395Skan	if(!line || !word || !addr || !rr_str || !list) {
170117395Skan		LDNS_FREE(line);
171117395Skan		LDNS_FREE(word);
172117395Skan		LDNS_FREE(addr);
173117395Skan		LDNS_FREE(rr_str);
174132718Skan		ldns_rr_list_free(list);
175132718Skan		return NULL;
176117395Skan	}
177117395Skan
178117395Skan	for(i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr);
179117395Skan			i > 0; i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr)) {
180117395Skan		/* # is comment */
181117395Skan		if (line[0] == '#') {
182117395Skan			continue;
183117395Skan		}
184117395Skan		/* put it in a buffer for further processing */
185117395Skan		linebuf = LDNS_MALLOC(ldns_buffer);
186117395Skan		if(!linebuf) {
187117395Skan			LDNS_FREE(line);
188132718Skan			LDNS_FREE(word);
189132718Skan			LDNS_FREE(addr);
190117395Skan			LDNS_FREE(rr_str);
191117395Skan			ldns_rr_list_deep_free(list);
192117395Skan			return NULL;
193117395Skan		}
194117395Skan
195117395Skan		ldns_buffer_new_frm_data(linebuf, line, (size_t) i);
196117395Skan		for(cnt = 0, j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN);
197117395Skan				j > 0;
198117395Skan				j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN), cnt++) {
199117395Skan			if (cnt == 0) {
200117395Skan				/* the address */
201117395Skan				if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA,
202117395Skan								word))) {
203117395Skan					/* ip6 */
204117395Skan					ldns_rdf_deep_free(tmp);
205169689Skan					ip6 = true;
206117395Skan				} else {
207169689Skan					if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A,
208169689Skan									word))) {
209169689Skan						/* ip4 */
210169689Skan						ldns_rdf_deep_free(tmp);
211169689Skan						ip6 = false;
212169689Skan					} else {
213169689Skan						/* kaput */
214169689Skan						break;
215169689Skan					}
216169689Skan				}
217117395Skan				(void)strlcpy(addr, word, LDNS_MAX_LINELEN+1);
218169689Skan			} else {
219169689Skan				/* la al la la */
220169689Skan				if (ip6) {
221169689Skan					snprintf(rr_str, LDNS_MAX_LINELEN,
222169689Skan						"%s IN AAAA %s", word, addr);
223169689Skan				} else {
224169689Skan					snprintf(rr_str, LDNS_MAX_LINELEN,
225169689Skan						"%s IN A %s", word, addr);
226169689Skan				}
227169689Skan				parse_result = ldns_rr_new_frm_str(&rr, rr_str, 0, NULL, NULL);
228169689Skan				if (parse_result == LDNS_STATUS_OK && ldns_rr_owner(rr) && ldns_rr_rd_count(rr) > 0) {
229169689Skan					ldns_rr_list_push_rr(list, ldns_rr_clone(rr));
230169689Skan				}
231169689Skan				ldns_rr_free(rr);
232169689Skan			}
233117395Skan		}
234117395Skan		ldns_buffer_free(linebuf);
235117395Skan	}
236117395Skan	LDNS_FREE(line);
237117395Skan	LDNS_FREE(word);
238117395Skan	LDNS_FREE(addr);
239117395Skan	LDNS_FREE(rr_str);
240117395Skan	return list;
241117395Skan}
242117395Skan
243117395Skanldns_rr_list *
244117395Skanldns_get_rr_list_hosts_frm_file(char *filename)
245117395Skan{
246117395Skan	ldns_rr_list *names;
247117395Skan	FILE *fp;
248117395Skan
249117395Skan	if (!filename) {
250132718Skan                fp = fopen(LDNS_RESOLV_HOSTS, "r");
251132718Skan
252117395Skan        } else {
253117395Skan                fp = fopen(filename, "r");
254117395Skan        }
255117395Skan        if (!fp) {
256117395Skan                return NULL;
257117395Skan        }
258117395Skan
259117395Skan	names = ldns_get_rr_list_hosts_frm_fp(fp);
260117395Skan	fclose(fp);
261117395Skan	return names;
262117395Skan}
263117395Skan
264117395Skanuint16_t
265117395Skanldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c,
266117395Skan		ldns_rr_list **ret)
267117395Skan{
268117395Skan	ldns_rdf_type t;
269117395Skan	uint16_t names_found;
270117395Skan	ldns_resolver *r;
271117395Skan	ldns_status s;
272117395Skan
273117395Skan	t = ldns_rdf_get_type(node);
274132718Skan	names_found = 0;
275132718Skan	r = res;
276132718Skan
277132718Skan	if (res == NULL) {
278117395Skan		/* prepare a new resolver, using /etc/resolv.conf as a guide  */
279117395Skan		s = ldns_resolver_new_frm_file(&r, NULL);
280117395Skan		if (s != LDNS_STATUS_OK) {
281117395Skan			return 0;
282117395Skan		}
283117395Skan	}
284117395Skan
285117395Skan	if (t == LDNS_RDF_TYPE_DNAME) {
286117395Skan		/* we're asked to query for a name */
287117395Skan		*ret = ldns_get_rr_list_addr_by_name(r, node, c, 0);
288117395Skan		names_found = ldns_rr_list_rr_count(*ret);
289117395Skan	}
290117395Skan
291117395Skan	if (t == LDNS_RDF_TYPE_A || t == LDNS_RDF_TYPE_AAAA) {
292117395Skan		/* an address */
293117395Skan		*ret = ldns_get_rr_list_name_by_addr(r, node, c, 0);
294117395Skan		names_found = ldns_rr_list_rr_count(*ret);
295117395Skan	}
296117395Skan
297117395Skan	if (res == NULL) {
298117395Skan		ldns_resolver_deep_free(r);
299117395Skan	}
300117395Skan
301117395Skan	return names_found;
302117395Skan}
303117395Skan
304117395Skanbool
305117395Skanldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t)
306117395Skan{
307117395Skan	switch (ldns_rr_get_type(nsec)) {
308117395Skan	case LDNS_RR_TYPE_NSEC	: if (ldns_rr_rd_count(nsec) < 2) {
309117395Skan					  return false;
310117395Skan				  }
311117395Skan				  return ldns_nsec_bitmap_covers_type(
312117395Skan						  ldns_rr_rdf(nsec, 1), t);
313117395Skan
314117395Skan	case LDNS_RR_TYPE_NSEC3	: if (ldns_rr_rd_count(nsec) < 6) {
315117395Skan					  return false;
316117395Skan				  }
317117395Skan				  return ldns_nsec_bitmap_covers_type(
318169689Skan						  ldns_rr_rdf(nsec, 5), t);
319117395Skan
320169689Skan	default			: return false;
321117395Skan	}
322117395Skan}
323117395Skan
324117395Skanvoid
325117395Skanldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...)
326117395Skan{
327117395Skan	int16_t rdf;
328117395Skan	ldns_rdf *rd;
329117395Skan	va_list va_rdf;
330117395Skan	va_start(va_rdf, rdfnum);
331117395Skan
332117395Skan	for (rdf = (int16_t)rdfnum; rdf != -1; rdf = (int16_t)va_arg(va_rdf, int))
333117395Skan	{
334117395Skan		rd = ldns_rr_rdf(r, rdf);
335117395Skan		if (!rd) {
336117395Skan			continue;
337117395Skan		} else {
338117395Skan			ldns_rdf_print(fp, rd);
339117395Skan			fprintf(fp, " "); /* not sure if we want to do this */
340117395Skan		}
341117395Skan	}
342132718Skan	va_end(va_rdf);
343132718Skan}
344132718Skan
345132718Skan