xref: /dragonfly/contrib/ldns/higher.c (revision cfd1aba3)
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 
23 ldns_rr_list *
24 ldns_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 
106 ldns_rr_list *
107 ldns_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 */
139 ldns_rr_list *
140 ldns_get_rr_list_hosts_frm_fp(FILE *fp)
141 {
142 	return ldns_get_rr_list_hosts_frm_fp_l(fp, NULL);
143 }
144 
145 ldns_rr_list *
146 ldns_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 
242 ldns_rr_list *
243 ldns_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 
263 uint16_t
264 ldns_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 
303 bool
304 ldns_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 
341 void
342 ldns_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