Merge branch 'vendor/XZ'
[dragonfly.git] / contrib / ldns / higher.c
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 }