higher.c revision 259065
1/*
2 * higher.c
3 *
4 * Specify some higher level functions that would
5 * be usefull to would be developers
6 *
7 * a Net::DNS like library for C
8 *
9 * (c) NLnet Labs, 2004-2006
10 *
11 * See the file LICENSE for the license
12 */
13
14#include <ldns/config.h>
15
16#include <ldns/ldns.h>
17
18#ifdef HAVE_SSL
19#include <openssl/ssl.h>
20#include <openssl/sha.h>
21#endif /* HAVE_SSL */
22
23ldns_rr_list *
24ldns_get_rr_list_addr_by_name(ldns_resolver *res, ldns_rdf *name, ldns_rr_class c,
25		uint16_t flags)
26{
27	ldns_pkt *pkt;
28	ldns_rr_list *aaaa;
29	ldns_rr_list *a;
30	ldns_rr_list *result = NULL;
31	ldns_rr_list *hostsfilenames;
32	size_t i;
33	uint8_t ip6;
34
35	a = NULL;
36	aaaa = NULL;
37	result = NULL;
38
39	if (!res) {
40		return NULL;
41	}
42	if (ldns_rdf_get_type(name) != LDNS_RDF_TYPE_DNAME) {
43		return NULL;
44	}
45
46	ip6 = ldns_resolver_ip6(res); /* we use INET_ANY here, save
47					 what was there */
48
49	ldns_resolver_set_ip6(res, LDNS_RESOLV_INETANY);
50
51	hostsfilenames = ldns_get_rr_list_hosts_frm_file(NULL);
52	for (i = 0; i < ldns_rr_list_rr_count(hostsfilenames); i++) {
53		if (ldns_rdf_compare(name,
54					ldns_rr_owner(ldns_rr_list_rr(hostsfilenames,
55							i))) == 0) {
56			if (!result) {
57				result = ldns_rr_list_new();
58			}
59			ldns_rr_list_push_rr(result,
60					ldns_rr_clone(ldns_rr_list_rr(hostsfilenames, i)));
61		}
62	}
63	ldns_rr_list_deep_free(hostsfilenames);
64
65	if (result) {
66		return result;
67	}
68
69	/* add the RD flags, because we want an answer */
70	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_AAAA, c, flags | LDNS_RD);
71	if (pkt) {
72		/* extract the data we need */
73		aaaa = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_AAAA,
74			LDNS_SECTION_ANSWER);
75		ldns_pkt_free(pkt);
76	}
77
78	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_A, c, flags | LDNS_RD);
79	if (pkt) {
80		/* extract the data we need */
81		a = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_A, LDNS_SECTION_ANSWER);
82		ldns_pkt_free(pkt);
83	}
84	ldns_resolver_set_ip6(res, ip6);
85
86	if (aaaa && a) {
87		result = ldns_rr_list_cat_clone(aaaa, a);
88		ldns_rr_list_deep_free(aaaa);
89		ldns_rr_list_deep_free(a);
90		return result;
91	}
92
93	if (aaaa) {
94		result = ldns_rr_list_clone(aaaa);
95	}
96
97	if (a) {
98		result = ldns_rr_list_clone(a);
99	}
100
101	ldns_rr_list_deep_free(aaaa);
102	ldns_rr_list_deep_free(a);
103	return result;
104}
105
106ldns_rr_list *
107ldns_get_rr_list_name_by_addr(ldns_resolver *res, ldns_rdf *addr, ldns_rr_class c,
108		uint16_t flags)
109{
110	ldns_pkt *pkt;
111	ldns_rr_list *names;
112	ldns_rdf *name;
113
114	names = NULL;
115
116	if (!res || !addr) {
117		return NULL;
118	}
119
120	if (ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_A &&
121			ldns_rdf_get_type(addr) != LDNS_RDF_TYPE_AAAA) {
122		return NULL;
123	}
124
125	name = ldns_rdf_address_reverse(addr);
126
127	/* add the RD flags, because we want an answer */
128	pkt = ldns_resolver_query(res, name, LDNS_RR_TYPE_PTR, c, flags | LDNS_RD);
129	ldns_rdf_deep_free(name);
130	if (pkt) {
131		/* extract the data we need */
132		names = ldns_pkt_rr_list_by_type(pkt,
133				LDNS_RR_TYPE_PTR, LDNS_SECTION_ANSWER);
134	}
135	return names;
136}
137
138/* read a line, put it in a buffer, parse the buffer */
139ldns_rr_list *
140ldns_get_rr_list_hosts_frm_fp(FILE *fp)
141{
142	return ldns_get_rr_list_hosts_frm_fp_l(fp, NULL);
143}
144
145ldns_rr_list *
146ldns_get_rr_list_hosts_frm_fp_l(FILE *fp, int *line_nr)
147{
148	ssize_t i, j;
149	size_t cnt;
150	char *line;
151	char *word;
152	char *addr;
153	char *rr_str;
154	ldns_buffer *linebuf;
155	ldns_rr *rr;
156	ldns_rr_list *list;
157	ldns_rdf *tmp;
158	bool ip6;
159	ldns_status parse_result;
160
161	line = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
162	word = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
163	addr = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
164	rr_str = LDNS_XMALLOC(char, LDNS_MAX_LINELEN + 1);
165	ip6 = false;
166	list = ldns_rr_list_new();
167	rr = NULL;
168	if(!line || !word || !addr || !rr_str || !list) {
169		LDNS_FREE(line);
170		LDNS_FREE(word);
171		LDNS_FREE(addr);
172		LDNS_FREE(rr_str);
173		ldns_rr_list_free(list);
174		return NULL;
175	}
176
177	for(i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr);
178			i > 0; i = ldns_fget_token_l(fp, line, "\n", LDNS_MAX_LINELEN, line_nr)) {
179		/* # is comment */
180		if (line[0] == '#') {
181			continue;
182		}
183		/* put it in a buffer for further processing */
184		linebuf = LDNS_MALLOC(ldns_buffer);
185		if(!linebuf) {
186			LDNS_FREE(line);
187			LDNS_FREE(word);
188			LDNS_FREE(addr);
189			LDNS_FREE(rr_str);
190			ldns_rr_list_deep_free(list);
191			return NULL;
192		}
193
194		ldns_buffer_new_frm_data(linebuf, line, (size_t) i);
195		for(cnt = 0, j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN);
196				j > 0;
197				j = ldns_bget_token(linebuf, word, LDNS_PARSE_NO_NL, LDNS_MAX_LINELEN), cnt++) {
198			if (cnt == 0) {
199				/* the address */
200				if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_AAAA,
201								word))) {
202					/* ip6 */
203					ldns_rdf_deep_free(tmp);
204					ip6 = true;
205				} else {
206					if ((tmp = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_A,
207									word))) {
208						/* ip4 */
209						ldns_rdf_deep_free(tmp);
210						ip6 = false;
211					} else {
212						/* kaput */
213						break;
214					}
215				}
216				(void)strlcpy(addr, word, LDNS_MAX_LINELEN+1);
217			} else {
218				/* la al la la */
219				if (ip6) {
220					snprintf(rr_str, LDNS_MAX_LINELEN,
221						"%s IN AAAA %s", word, addr);
222				} else {
223					snprintf(rr_str, LDNS_MAX_LINELEN,
224						"%s IN A %s", word, addr);
225				}
226				parse_result = ldns_rr_new_frm_str(&rr, rr_str, 0, NULL, NULL);
227				if (parse_result == LDNS_STATUS_OK && ldns_rr_owner(rr) && ldns_rr_rd_count(rr) > 0) {
228					ldns_rr_list_push_rr(list, ldns_rr_clone(rr));
229				}
230				ldns_rr_free(rr);
231			}
232		}
233		ldns_buffer_free(linebuf);
234	}
235	LDNS_FREE(line);
236	LDNS_FREE(word);
237	LDNS_FREE(addr);
238	LDNS_FREE(rr_str);
239	return list;
240}
241
242ldns_rr_list *
243ldns_get_rr_list_hosts_frm_file(char *filename)
244{
245	ldns_rr_list *names;
246	FILE *fp;
247
248	if (!filename) {
249                fp = fopen(LDNS_RESOLV_HOSTS, "r");
250
251        } else {
252                fp = fopen(filename, "r");
253        }
254        if (!fp) {
255                return NULL;
256        }
257
258	names = ldns_get_rr_list_hosts_frm_fp(fp);
259	fclose(fp);
260	return names;
261}
262
263uint16_t
264ldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c,
265		ldns_rr_list **ret)
266{
267	ldns_rdf_type t;
268	uint16_t names_found;
269	ldns_resolver *r;
270	ldns_status s;
271
272	t = ldns_rdf_get_type(node);
273	names_found = 0;
274	r = res;
275
276	if (res == NULL) {
277		/* prepare a new resolver, using /etc/resolv.conf as a guide  */
278		s = ldns_resolver_new_frm_file(&r, NULL);
279		if (s != LDNS_STATUS_OK) {
280			return 0;
281		}
282	}
283
284	if (t == LDNS_RDF_TYPE_DNAME) {
285		/* we're asked to query for a name */
286		*ret = ldns_get_rr_list_addr_by_name(r, node, c, 0);
287		names_found = ldns_rr_list_rr_count(*ret);
288	}
289
290	if (t == LDNS_RDF_TYPE_A || t == LDNS_RDF_TYPE_AAAA) {
291		/* an address */
292		*ret = ldns_get_rr_list_name_by_addr(r, node, c, 0);
293		names_found = ldns_rr_list_rr_count(*ret);
294	}
295
296	if (res == NULL) {
297		ldns_resolver_deep_free(r);
298	}
299
300	return names_found;
301}
302
303bool
304ldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t)
305{
306	/* does the nsec cover the t given? */
307	/* copied from host2str.c line 465: ldns_rdf2buffer_str_nsec */
308        uint8_t window_block_nr;
309        uint8_t bitmap_length;
310        uint16_t type;
311        uint16_t pos = 0;
312        uint16_t bit_pos;
313	ldns_rdf *nsec_type_list = ldns_rr_rdf(nsec, 1);
314	uint8_t *data;
315
316	if (nsec_type_list == NULL) {
317		return false;
318	}
319	data  = ldns_rdf_data(nsec_type_list);
320
321	while(pos < ldns_rdf_size(nsec_type_list)) {
322		window_block_nr = data[pos];
323		bitmap_length = data[pos + 1];
324		pos += 2;
325
326		for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) {
327			if (ldns_get_bit(&data[pos], bit_pos)) {
328				type = 256 * (uint16_t) window_block_nr + bit_pos;
329
330				if ((ldns_rr_type)type == t) {
331					/* we have a winner */
332					return true;
333				}
334			}
335		}
336		pos += (uint16_t) bitmap_length;
337	}
338	return false;
339}
340
341void
342ldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...)
343{
344	int16_t rdf;
345	ldns_rdf *rd;
346	va_list va_rdf;
347	va_start(va_rdf, rdfnum);
348
349	for (rdf = (int16_t)rdfnum; rdf != -1; rdf = (int16_t)va_arg(va_rdf, int))
350	{
351		rd = ldns_rr_rdf(r, rdf);
352		if (!rd) {
353			continue;
354		} else {
355			ldns_rdf_print(fp, rd);
356			fprintf(fp, " "); /* not sure if we want to do this */
357		}
358	}
359	va_end(va_rdf);
360}
361