Line data Source code
1 : /*
2 : * Copyright (c) 1995 - 2006 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 :
35 : #include <config.h>
36 :
37 : #include "roken.h"
38 : #ifdef HAVE_ARPA_NAMESER_H
39 : #include <arpa/nameser.h>
40 : #endif
41 : #ifdef HAVE_RESOLV_H
42 : #include <resolv.h>
43 : #endif
44 : #ifdef HAVE_DNS_H
45 : #include <dns.h>
46 : #endif
47 : #include "resolve.h"
48 :
49 : #include <assert.h>
50 :
51 : #ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
52 : #undef HAVE_RES_NSEARCH
53 : #endif
54 :
55 : #define DECL(X) {#X, rk_ns_t_##X}
56 :
57 : static struct stot{
58 : const char *name;
59 : int type;
60 : }stot[] = {
61 : DECL(a),
62 : DECL(aaaa),
63 : DECL(ns),
64 : DECL(cname),
65 : DECL(soa),
66 : DECL(ptr),
67 : DECL(mx),
68 : DECL(txt),
69 : DECL(afsdb),
70 : DECL(sig),
71 : DECL(key),
72 : DECL(srv),
73 : DECL(naptr),
74 : DECL(sshfp),
75 : DECL(ds),
76 : {NULL, 0}
77 : };
78 :
79 : int _resolve_debug = 0;
80 :
81 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
82 153 : rk_dns_string_to_type(const char *name)
83 : {
84 153 : struct stot *p = stot;
85 1836 : for(p = stot; p->name; p++)
86 1836 : if(strcasecmp(name, p->name) == 0)
87 153 : return p->type;
88 0 : return -1;
89 : }
90 :
91 : ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
92 0 : rk_dns_type_to_string(int type)
93 : {
94 0 : struct stot *p = stot;
95 0 : for(p = stot; p->name; p++)
96 0 : if(type == p->type)
97 0 : return p->name;
98 0 : return NULL;
99 : }
100 :
101 : #if ((defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)) || defined(HAVE_WINDNS)
102 :
103 : static void
104 90 : dns_free_rr(struct rk_resource_record *rr)
105 : {
106 90 : if(rr->domain)
107 90 : free(rr->domain);
108 90 : if(rr->u.data)
109 90 : free(rr->u.data);
110 90 : free(rr);
111 90 : }
112 :
113 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
114 81 : rk_dns_free_data(struct rk_dns_reply *r)
115 : {
116 0 : struct rk_resource_record *rr;
117 81 : if(r->q.domain)
118 81 : free(r->q.domain);
119 171 : for(rr = r->head; rr;){
120 90 : struct rk_resource_record *tmp = rr;
121 90 : rr = rr->next;
122 90 : dns_free_rr(tmp);
123 : }
124 81 : free (r);
125 81 : }
126 :
127 : #ifndef HAVE_WINDNS
128 :
129 : static int
130 90 : parse_record(const unsigned char *data, const unsigned char *end_data,
131 : const unsigned char **pp, struct rk_resource_record **ret_rr)
132 : {
133 0 : struct rk_resource_record *rr;
134 0 : int type, class, ttl;
135 0 : unsigned size;
136 0 : int status;
137 0 : char host[MAXDNAME];
138 90 : const unsigned char *p = *pp;
139 :
140 90 : *ret_rr = NULL;
141 :
142 90 : status = dn_expand(data, end_data, p, host, sizeof(host));
143 90 : if(status < 0)
144 0 : return -1;
145 90 : if (p + status + 10 > end_data)
146 0 : return -1;
147 :
148 90 : p += status;
149 90 : type = (p[0] << 8) | p[1];
150 90 : p += 2;
151 90 : class = (p[0] << 8) | p[1];
152 90 : p += 2;
153 90 : ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
154 90 : p += 4;
155 90 : size = (p[0] << 8) | p[1];
156 90 : p += 2;
157 :
158 90 : if (p + size > end_data)
159 0 : return -1;
160 :
161 90 : rr = calloc(1, sizeof(*rr));
162 90 : if(rr == NULL)
163 0 : return -1;
164 90 : rr->domain = strdup(host);
165 90 : if(rr->domain == NULL) {
166 0 : dns_free_rr(rr);
167 0 : return -1;
168 : }
169 90 : rr->type = type;
170 90 : rr->class = class;
171 90 : rr->ttl = ttl;
172 90 : rr->size = size;
173 90 : switch(type){
174 0 : case rk_ns_t_ns:
175 : case rk_ns_t_cname:
176 : case rk_ns_t_ptr:
177 0 : status = dn_expand(data, end_data, p, host, sizeof(host));
178 0 : if(status < 0) {
179 0 : dns_free_rr(rr);
180 0 : return -1;
181 : }
182 0 : rr->u.txt = strdup(host);
183 0 : if(rr->u.txt == NULL) {
184 0 : dns_free_rr(rr);
185 0 : return -1;
186 : }
187 0 : break;
188 0 : case rk_ns_t_mx:
189 : case rk_ns_t_afsdb:{
190 0 : size_t hostlen;
191 :
192 0 : status = dn_expand(data, end_data, p + 2, host, sizeof(host));
193 0 : if(status < 0){
194 0 : dns_free_rr(rr);
195 0 : return -1;
196 : }
197 0 : if ((size_t)status + 2 > size) {
198 0 : dns_free_rr(rr);
199 0 : return -1;
200 : }
201 :
202 0 : hostlen = strlen(host);
203 0 : rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
204 : hostlen);
205 0 : if(rr->u.mx == NULL) {
206 0 : dns_free_rr(rr);
207 0 : return -1;
208 : }
209 0 : rr->u.mx->preference = (p[0] << 8) | p[1];
210 0 : strlcpy(rr->u.mx->domain, host, hostlen + 1);
211 0 : break;
212 : }
213 45 : case rk_ns_t_srv:{
214 0 : size_t hostlen;
215 45 : status = dn_expand(data, end_data, p + 6, host, sizeof(host));
216 45 : if(status < 0){
217 0 : dns_free_rr(rr);
218 0 : return -1;
219 : }
220 45 : if ((size_t)status + 6 > size) {
221 0 : dns_free_rr(rr);
222 0 : return -1;
223 : }
224 :
225 45 : hostlen = strlen(host);
226 45 : rr->u.srv =
227 45 : (struct srv_record*)malloc(sizeof(struct srv_record) +
228 : hostlen);
229 45 : if(rr->u.srv == NULL) {
230 0 : dns_free_rr(rr);
231 0 : return -1;
232 : }
233 45 : rr->u.srv->priority = (p[0] << 8) | p[1];
234 45 : rr->u.srv->weight = (p[2] << 8) | p[3];
235 45 : rr->u.srv->port = (p[4] << 8) | p[5];
236 45 : strlcpy(rr->u.srv->target, host, hostlen + 1);
237 45 : break;
238 : }
239 0 : case rk_ns_t_txt:{
240 0 : if(size == 0 || size < (unsigned)(*p + 1)) {
241 0 : dns_free_rr(rr);
242 0 : return -1;
243 : }
244 0 : rr->u.txt = (char*)malloc(*p + 1);
245 0 : if(rr->u.txt == NULL) {
246 0 : dns_free_rr(rr);
247 0 : return -1;
248 : }
249 0 : strncpy(rr->u.txt, (const char*)(p + 1), *p);
250 0 : rr->u.txt[*p] = '\0';
251 0 : break;
252 : }
253 0 : case rk_ns_t_key : {
254 0 : size_t key_len;
255 :
256 0 : if (size < 4) {
257 0 : dns_free_rr(rr);
258 0 : return -1;
259 : }
260 :
261 0 : key_len = size - 4;
262 0 : rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
263 0 : if (rr->u.key == NULL) {
264 0 : dns_free_rr(rr);
265 0 : return -1;
266 : }
267 :
268 0 : rr->u.key->flags = (p[0] << 8) | p[1];
269 0 : rr->u.key->protocol = p[2];
270 0 : rr->u.key->algorithm = p[3];
271 0 : rr->u.key->key_len = key_len;
272 0 : memcpy (rr->u.key->key_data, p + 4, key_len);
273 0 : break;
274 : }
275 0 : case rk_ns_t_sig : {
276 0 : size_t sig_len, hostlen;
277 :
278 0 : if(size <= 18) {
279 0 : dns_free_rr(rr);
280 0 : return -1;
281 : }
282 0 : status = dn_expand (data, end_data, p + 18, host, sizeof(host));
283 0 : if (status < 0) {
284 0 : dns_free_rr(rr);
285 0 : return -1;
286 : }
287 0 : if ((size_t)status + 18 > size) {
288 0 : dns_free_rr(rr);
289 0 : return -1;
290 : }
291 :
292 : /* the signer name is placed after the sig_data, to make it
293 : easy to free this structure; the size calculation below
294 : includes the zero-termination if the structure itself.
295 : don't you just love C?
296 : */
297 0 : sig_len = size - 18 - status;
298 0 : hostlen = strlen(host);
299 0 : rr->u.sig = malloc(sizeof(*rr->u.sig)
300 0 : + hostlen + sig_len);
301 0 : if (rr->u.sig == NULL) {
302 0 : dns_free_rr(rr);
303 0 : return -1;
304 : }
305 0 : rr->u.sig->type = (p[0] << 8) | p[1];
306 0 : rr->u.sig->algorithm = p[2];
307 0 : rr->u.sig->labels = p[3];
308 0 : rr->u.sig->orig_ttl = (p[4] << 24) | (p[5] << 16)
309 0 : | (p[6] << 8) | p[7];
310 0 : rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
311 0 : | (p[10] << 8) | p[11];
312 0 : rr->u.sig->sig_inception = (p[12] << 24) | (p[13] << 16)
313 0 : | (p[14] << 8) | p[15];
314 0 : rr->u.sig->key_tag = (p[16] << 8) | p[17];
315 0 : rr->u.sig->sig_len = sig_len;
316 0 : memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len);
317 0 : rr->u.sig->signer = &rr->u.sig->sig_data[sig_len];
318 0 : strlcpy(rr->u.sig->signer, host, hostlen + 1);
319 0 : break;
320 : }
321 :
322 0 : case rk_ns_t_cert : {
323 0 : size_t cert_len;
324 :
325 0 : if (size < 5) {
326 0 : dns_free_rr(rr);
327 0 : return -1;
328 : }
329 :
330 0 : cert_len = size - 5;
331 0 : rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1);
332 0 : if (rr->u.cert == NULL) {
333 0 : dns_free_rr(rr);
334 0 : return -1;
335 : }
336 :
337 0 : rr->u.cert->type = (p[0] << 8) | p[1];
338 0 : rr->u.cert->tag = (p[2] << 8) | p[3];
339 0 : rr->u.cert->algorithm = p[4];
340 0 : rr->u.cert->cert_len = cert_len;
341 0 : memcpy (rr->u.cert->cert_data, p + 5, cert_len);
342 0 : break;
343 : }
344 0 : case rk_ns_t_sshfp : {
345 0 : size_t sshfp_len;
346 :
347 0 : if (size < 2) {
348 0 : dns_free_rr(rr);
349 0 : return -1;
350 : }
351 :
352 0 : sshfp_len = size - 2;
353 :
354 0 : rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1);
355 0 : if (rr->u.sshfp == NULL) {
356 0 : dns_free_rr(rr);
357 0 : return -1;
358 : }
359 :
360 0 : rr->u.sshfp->algorithm = p[0];
361 0 : rr->u.sshfp->type = p[1];
362 0 : rr->u.sshfp->sshfp_len = sshfp_len;
363 0 : memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len);
364 0 : break;
365 : }
366 0 : case rk_ns_t_ds: {
367 0 : size_t digest_len;
368 :
369 0 : if (size < 4) {
370 0 : dns_free_rr(rr);
371 0 : return -1;
372 : }
373 :
374 0 : digest_len = size - 4;
375 :
376 0 : rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1);
377 0 : if (rr->u.ds == NULL) {
378 0 : dns_free_rr(rr);
379 0 : return -1;
380 : }
381 :
382 0 : rr->u.ds->key_tag = (p[0] << 8) | p[1];
383 0 : rr->u.ds->algorithm = p[2];
384 0 : rr->u.ds->digest_type = p[3];
385 0 : rr->u.ds->digest_len = digest_len;
386 0 : memcpy (rr->u.ds->digest_data, p + 4, digest_len);
387 0 : break;
388 : }
389 45 : default:
390 45 : rr->u.data = (unsigned char*)malloc(size);
391 45 : if(size != 0 && rr->u.data == NULL) {
392 0 : dns_free_rr(rr);
393 0 : return -1;
394 : }
395 45 : if (size)
396 45 : memcpy(rr->u.data, p, size);
397 : }
398 90 : *pp = p + size;
399 90 : *ret_rr = rr;
400 :
401 90 : return 0;
402 : }
403 :
404 : #ifndef TEST_RESOLVE
405 : static
406 : #endif
407 : struct rk_dns_reply*
408 81 : parse_reply(const unsigned char *data, size_t len)
409 : {
410 0 : const unsigned char *p;
411 0 : int status;
412 0 : size_t i;
413 0 : char host[MAXDNAME];
414 81 : const unsigned char *end_data = data + len;
415 0 : struct rk_dns_reply *r;
416 0 : struct rk_resource_record **rr;
417 :
418 81 : r = calloc(1, sizeof(*r));
419 81 : if (r == NULL)
420 0 : return NULL;
421 :
422 81 : p = data;
423 :
424 81 : r->h.id = (p[0] << 8) | p[1];
425 81 : r->h.flags = 0;
426 81 : if (p[2] & 0x01)
427 81 : r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
428 81 : r->h.opcode = (p[2] >> 1) & 0xf;
429 81 : if (p[2] & 0x20)
430 0 : r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
431 81 : if (p[2] & 0x40)
432 0 : r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
433 81 : if (p[2] & 0x80)
434 81 : r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
435 81 : if (p[3] & 0x01)
436 0 : r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
437 81 : if (p[3] & 0x04)
438 0 : r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
439 81 : if (p[3] & 0x08)
440 0 : r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
441 81 : r->h.response_code = (p[3] >> 4) & 0xf;
442 81 : r->h.qdcount = (p[4] << 8) | p[5];
443 81 : r->h.ancount = (p[6] << 8) | p[7];
444 81 : r->h.nscount = (p[8] << 8) | p[9];
445 81 : r->h.arcount = (p[10] << 8) | p[11];
446 :
447 81 : p += 12;
448 :
449 81 : if(r->h.qdcount != 1) {
450 0 : free(r);
451 0 : return NULL;
452 : }
453 81 : status = dn_expand(data, end_data, p, host, sizeof(host));
454 81 : if(status < 0){
455 0 : rk_dns_free_data(r);
456 0 : return NULL;
457 : }
458 81 : r->q.domain = strdup(host);
459 81 : if(r->q.domain == NULL) {
460 0 : rk_dns_free_data(r);
461 0 : return NULL;
462 : }
463 81 : if (p + status + 4 > end_data) {
464 0 : rk_dns_free_data(r);
465 0 : return NULL;
466 : }
467 81 : p += status;
468 81 : r->q.type = (p[0] << 8 | p[1]);
469 81 : p += 2;
470 81 : r->q.class = (p[0] << 8 | p[1]);
471 81 : p += 2;
472 :
473 81 : rr = &r->head;
474 126 : for(i = 0; i < r->h.ancount; i++) {
475 45 : if(parse_record(data, end_data, &p, rr) != 0) {
476 0 : rk_dns_free_data(r);
477 0 : return NULL;
478 : }
479 45 : rr = &(*rr)->next;
480 : }
481 81 : for(i = 0; i < r->h.nscount; i++) {
482 0 : if(parse_record(data, end_data, &p, rr) != 0) {
483 0 : rk_dns_free_data(r);
484 0 : return NULL;
485 : }
486 0 : rr = &(*rr)->next;
487 : }
488 126 : for(i = 0; i < r->h.arcount; i++) {
489 45 : if(parse_record(data, end_data, &p, rr) != 0) {
490 0 : rk_dns_free_data(r);
491 0 : return NULL;
492 : }
493 45 : rr = &(*rr)->next;
494 : }
495 81 : *rr = NULL;
496 81 : return r;
497 : }
498 :
499 : #ifdef HAVE_RES_NSEARCH
500 : #ifdef HAVE_RES_NDESTROY
501 : #define rk_res_free(x) res_ndestroy(x)
502 : #else
503 : #define rk_res_free(x) res_nclose(x)
504 : #endif
505 : #endif
506 :
507 : #if defined(HAVE_DNS_SEARCH)
508 : #define resolve_search(h,n,c,t,r,l) \
509 : ((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize))
510 : #define resolve_free_handle(h) dns_free(h)
511 : #elif defined(HAVE_RES_NSEARCH)
512 : #define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l)
513 : #define resolve_free_handle(h) rk_res_free(h);
514 : #else
515 : #define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l)
516 : #define handle 0
517 : #define resolve_free_handle(h)
518 : #endif
519 :
520 :
521 : static struct rk_dns_reply *
522 153 : dns_lookup_int(const char *domain, int rr_class, int rr_type)
523 : {
524 0 : struct rk_dns_reply *r;
525 153 : void *reply = NULL;
526 0 : int size, len;
527 : #if defined(HAVE_DNS_SEARCH)
528 : struct sockaddr_storage from;
529 : uint32_t fromsize = sizeof(from);
530 : dns_handle_t handle;
531 :
532 : handle = dns_open(NULL);
533 : if (handle == NULL)
534 : return NULL;
535 : #elif defined(HAVE_RES_NSEARCH)
536 0 : struct __res_state state;
537 153 : struct __res_state *handle = &state;
538 :
539 153 : memset(&state, 0, sizeof(state));
540 153 : if(res_ninit(handle))
541 0 : return NULL; /* is this the best we can do? */
542 : #endif
543 :
544 153 : len = 1500;
545 0 : while(1) {
546 585 : if (reply) {
547 432 : free(reply);
548 432 : reply = NULL;
549 : }
550 585 : if (_resolve_debug) {
551 : #if defined(HAVE_DNS_SEARCH)
552 : dns_set_debug(handle, 1);
553 : #elif defined(HAVE_RES_NSEARCH)
554 0 : state.options |= RES_DEBUG;
555 : #endif
556 0 : fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
557 : rr_class, rk_dns_type_to_string(rr_type), len);
558 : }
559 585 : reply = malloc(len);
560 585 : if (reply == NULL) {
561 0 : resolve_free_handle(handle);
562 0 : return NULL;
563 : }
564 :
565 585 : size = resolve_search(handle, domain, rr_class, rr_type, reply, len);
566 :
567 585 : if (_resolve_debug) {
568 0 : fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
569 : domain, rr_class, rk_dns_type_to_string(rr_type), size);
570 : }
571 585 : if (size > len) {
572 : /* resolver thinks it know better, go for it */
573 0 : len = size;
574 585 : } else if (size > 0) {
575 : /* got a good reply */
576 81 : break;
577 504 : } else if (size <= 0 && len < rk_DNS_MAX_PACKET_SIZE) {
578 432 : len *= 2;
579 432 : if (len > rk_DNS_MAX_PACKET_SIZE)
580 72 : len = rk_DNS_MAX_PACKET_SIZE;
581 : } else {
582 : /* the end, leave */
583 72 : resolve_free_handle(handle);
584 72 : free(reply);
585 72 : return NULL;
586 : }
587 : }
588 :
589 81 : len = min(len, size);
590 81 : r = parse_reply(reply, len);
591 81 : free(reply);
592 :
593 81 : resolve_free_handle(handle);
594 :
595 81 : return r;
596 : }
597 :
598 : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
599 153 : rk_dns_lookup(const char *domain, const char *type_name)
600 : {
601 0 : int type;
602 :
603 153 : type = rk_dns_string_to_type(type_name);
604 153 : if(type == -1) {
605 0 : if(_resolve_debug)
606 0 : fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
607 : type_name);
608 0 : return NULL;
609 : }
610 153 : return dns_lookup_int(domain, rk_ns_c_in, type);
611 : }
612 :
613 : #endif /* !HAVE_WINDNS */
614 :
615 : static int
616 0 : compare_srv(const void *a, const void *b)
617 : {
618 0 : const struct rk_resource_record *const* aa = a, *const* bb = b;
619 :
620 0 : if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
621 0 : return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
622 0 : return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
623 : }
624 :
625 : /* try to rearrange the srv-records by the algorithm in RFC2782 */
626 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
627 45 : rk_dns_srv_order(struct rk_dns_reply *r)
628 : {
629 0 : struct rk_resource_record **srvs, **ss, **headp;
630 0 : struct rk_resource_record *rr;
631 45 : int num_srv = 0;
632 45 : unsigned int srv_found = FALSE;
633 :
634 45 : rk_random_init();
635 :
636 135 : for(rr = r->head; rr; rr = rr->next)
637 90 : if(rr->type == rk_ns_t_srv) {
638 45 : num_srv++;
639 45 : srv_found = TRUE;
640 : }
641 :
642 45 : if(srv_found == FALSE)
643 0 : return;
644 :
645 45 : srvs = malloc(num_srv * sizeof(*srvs));
646 45 : if(srvs == NULL)
647 0 : return; /* XXX not much to do here */
648 :
649 : /* unlink all srv-records from the linked list and put them in
650 : a vector */
651 135 : for(ss = srvs, headp = &r->head; *headp; )
652 90 : if((*headp)->type == rk_ns_t_srv) {
653 45 : *ss = *headp;
654 45 : *headp = (*headp)->next;
655 45 : (*ss)->next = NULL;
656 45 : ss++;
657 : } else
658 45 : headp = &(*headp)->next;
659 :
660 : /* sort them by priority and weight */
661 45 : qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
662 :
663 45 : headp = &r->head;
664 :
665 90 : for (ss = srvs; ss < srvs + num_srv; ) {
666 : int sum, zeros, rnd, count; /* zeros -> weight scaling */
667 : struct rk_resource_record **ee, **tt;
668 :
669 : /*
670 : * find the last record with the same priority and count the sum of all
671 : * weights
672 : */
673 90 : for (sum = 0, zeros = 0, tt = ss; tt < srvs + num_srv; tt++) {
674 45 : assert(*tt != NULL);
675 45 : if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
676 0 : break;
677 45 : sum += (*tt)->u.srv->weight;
678 45 : if ((*tt)->u.srv->weight == 0)
679 0 : zeros++;
680 : }
681 : /* make sure scale (`zeros') is > 0 then scale out */
682 45 : sum += zeros ? 1 : zeros++;
683 45 : sum *= zeros;
684 45 : ee = tt;
685 :
686 : /*
687 : * ss is now the first record of this priority and ee is the first of
688 : * the next or the first past the end of srvs
689 : */
690 90 : while (ss < ee) {
691 45 : rnd = rk_random() % sum + 1;
692 45 : for (count = 0, tt = ss; tt < ee; tt++) {
693 45 : if (*tt == NULL)
694 0 : continue; /* this one's already been picked */
695 45 : if ((*tt)->u.srv->weight == 0)
696 0 : count++;
697 : else
698 45 : count += (*tt)->u.srv->weight * zeros;
699 45 : if (count >= rnd)
700 45 : break;
701 : }
702 45 : assert(tt < ee);
703 :
704 : /* push the selected record */
705 45 : (*tt)->next = *headp;
706 45 : *headp = *tt;
707 45 : headp = &(*tt)->next;
708 : /*
709 : * reduce the sum so the next iteration is sure to reach the random
710 : * total after examining all the remaining records.
711 : */
712 45 : if ((*tt)->u.srv->weight == 0)
713 0 : sum--;
714 : else
715 45 : sum -= (*tt)->u.srv->weight * zeros;
716 45 : *tt = NULL;
717 90 : while (ss < ee && *ss == NULL)
718 45 : ss++;
719 : }
720 : }
721 :
722 45 : free(srvs);
723 45 : return;
724 : }
725 :
726 : #ifdef HAVE_WINDNS
727 :
728 : #include <WinDNS.h>
729 :
730 : static struct rk_resource_record *
731 : parse_dns_record(PDNS_RECORD pRec)
732 : {
733 : struct rk_resource_record * rr;
734 :
735 : if (pRec == NULL)
736 : return NULL;
737 :
738 : rr = calloc(1, sizeof(*rr));
739 :
740 : rr->domain = strdup(pRec->pName);
741 : rr->type = pRec->wType;
742 : rr->class = 0;
743 : rr->ttl = pRec->dwTtl;
744 : rr->size = 0;
745 :
746 : switch (rr->type) {
747 : case rk_ns_t_ns:
748 : case rk_ns_t_cname:
749 : case rk_ns_t_ptr:
750 : rr->u.txt = strdup(pRec->Data.NS.pNameHost);
751 : if(rr->u.txt == NULL) {
752 : dns_free_rr(rr);
753 : return NULL;
754 : }
755 : break;
756 :
757 : case rk_ns_t_mx:
758 : case rk_ns_t_afsdb:{
759 : size_t hostlen = strnlen(pRec->Data.MX.pNameExchange, DNS_MAX_NAME_LENGTH);
760 :
761 : rr->u.mx = (struct mx_record *)malloc(sizeof(struct mx_record) +
762 : hostlen);
763 : if (rr->u.mx == NULL) {
764 : dns_free_rr(rr);
765 : return NULL;
766 : }
767 :
768 : strcpy_s(rr->u.mx->domain, hostlen + 1, pRec->Data.MX.pNameExchange);
769 : rr->u.mx->preference = pRec->Data.MX.wPreference;
770 : break;
771 : }
772 :
773 : case rk_ns_t_srv:{
774 : size_t hostlen = strnlen(pRec->Data.SRV.pNameTarget, DNS_MAX_NAME_LENGTH);
775 :
776 : rr->u.srv =
777 : (struct srv_record*)malloc(sizeof(struct srv_record) +
778 : hostlen);
779 : if(rr->u.srv == NULL) {
780 : dns_free_rr(rr);
781 : return NULL;
782 : }
783 :
784 : rr->u.srv->priority = pRec->Data.SRV.wPriority;
785 : rr->u.srv->weight = pRec->Data.SRV.wWeight;
786 : rr->u.srv->port = pRec->Data.SRV.wPort;
787 : strcpy_s(rr->u.srv->target, hostlen + 1, pRec->Data.SRV.pNameTarget);
788 :
789 : break;
790 : }
791 :
792 : case rk_ns_t_txt:{
793 : size_t len;
794 :
795 : if (pRec->Data.TXT.dwStringCount == 0) {
796 : rr->u.txt = strdup("");
797 : break;
798 : }
799 :
800 : len = strnlen(pRec->Data.TXT.pStringArray[0], DNS_MAX_TEXT_STRING_LENGTH);
801 :
802 : rr->u.txt = (char *)malloc(len + 1);
803 : strcpy_s(rr->u.txt, len + 1, pRec->Data.TXT.pStringArray[0]);
804 :
805 : break;
806 : }
807 :
808 : case rk_ns_t_key : {
809 : size_t key_len;
810 :
811 : if (pRec->wDataLength < 4) {
812 : dns_free_rr(rr);
813 : return NULL;
814 : }
815 :
816 : key_len = pRec->wDataLength - 4;
817 : rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
818 : if (rr->u.key == NULL) {
819 : dns_free_rr(rr);
820 : return NULL;
821 : }
822 :
823 : rr->u.key->flags = pRec->Data.KEY.wFlags;
824 : rr->u.key->protocol = pRec->Data.KEY.chProtocol;
825 : rr->u.key->algorithm = pRec->Data.KEY.chAlgorithm;
826 : rr->u.key->key_len = key_len;
827 : memcpy_s (rr->u.key->key_data, key_len,
828 : pRec->Data.KEY.Key, key_len);
829 : break;
830 : }
831 :
832 : case rk_ns_t_sig : {
833 : size_t sig_len, hostlen;
834 :
835 : if(pRec->wDataLength <= 18) {
836 : dns_free_rr(rr);
837 : return NULL;
838 : }
839 :
840 : sig_len = pRec->wDataLength;
841 :
842 : hostlen = strnlen(pRec->Data.SIG.pNameSigner, DNS_MAX_NAME_LENGTH);
843 :
844 : rr->u.sig = malloc(sizeof(*rr->u.sig)
845 : + hostlen + sig_len);
846 : if (rr->u.sig == NULL) {
847 : dns_free_rr(rr);
848 : return NULL;
849 : }
850 : rr->u.sig->type = pRec->Data.SIG.wTypeCovered;
851 : rr->u.sig->algorithm = pRec->Data.SIG.chAlgorithm;
852 : rr->u.sig->labels = pRec->Data.SIG.chLabelCount;
853 : rr->u.sig->orig_ttl = pRec->Data.SIG.dwOriginalTtl;
854 : rr->u.sig->sig_expiration = pRec->Data.SIG.dwExpiration;
855 : rr->u.sig->sig_inception = pRec->Data.SIG.dwTimeSigned;
856 : rr->u.sig->key_tag = pRec->Data.SIG.wKeyTag;
857 : rr->u.sig->sig_len = sig_len;
858 : memcpy_s (rr->u.sig->sig_data, sig_len,
859 : pRec->Data.SIG.Signature, sig_len);
860 : rr->u.sig->signer = &rr->u.sig->sig_data[sig_len];
861 : strcpy_s(rr->u.sig->signer, hostlen + 1, pRec->Data.SIG.pNameSigner);
862 : break;
863 : }
864 :
865 : #ifdef DNS_TYPE_DS
866 : case rk_ns_t_ds: {
867 : rr->u.ds = malloc (sizeof(*rr->u.ds) + pRec->Data.DS.wDigestLength - 1);
868 : if (rr->u.ds == NULL) {
869 : dns_free_rr(rr);
870 : return NULL;
871 : }
872 :
873 : rr->u.ds->key_tag = pRec->Data.DS.wKeyTag;
874 : rr->u.ds->algorithm = pRec->Data.DS.chAlgorithm;
875 : rr->u.ds->digest_type = pRec->Data.DS.chDigestType;
876 : rr->u.ds->digest_len = pRec->Data.DS.wDigestLength;
877 : memcpy_s (rr->u.ds->digest_data, pRec->Data.DS.wDigestLength,
878 : pRec->Data.DS.Digest, pRec->Data.DS.wDigestLength);
879 : break;
880 : }
881 : #endif
882 :
883 : default:
884 : dns_free_rr(rr);
885 : return NULL;
886 : }
887 :
888 : rr->next = parse_dns_record(pRec->pNext);
889 : return rr;
890 : }
891 :
892 : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
893 : rk_dns_lookup(const char *domain, const char *type_name)
894 : {
895 : DNS_STATUS status;
896 : int type;
897 : PDNS_RECORD pRec = NULL;
898 : struct rk_dns_reply * r = NULL;
899 :
900 : __try {
901 :
902 : type = rk_dns_string_to_type(type_name);
903 : if(type == -1) {
904 : if(_resolve_debug)
905 : fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
906 : type_name);
907 : return NULL;
908 : }
909 :
910 : status = DnsQuery_UTF8(domain, type, DNS_QUERY_STANDARD, NULL,
911 : &pRec, NULL);
912 : if (status != ERROR_SUCCESS)
913 : return NULL;
914 :
915 : r = calloc(1, sizeof(*r));
916 : r->q.domain = strdup(domain);
917 : r->q.type = type;
918 : r->q.class = 0;
919 :
920 : r->head = parse_dns_record(pRec);
921 :
922 : if (r->head == NULL) {
923 : rk_dns_free_data(r);
924 : return NULL;
925 : } else {
926 : return r;
927 : }
928 :
929 : } __finally {
930 :
931 : if (pRec)
932 : DnsRecordListFree(pRec, DnsFreeRecordList);
933 :
934 : }
935 : }
936 : #endif /* HAVE_WINDNS */
937 :
938 : #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
939 :
940 : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
941 : rk_dns_lookup(const char *domain, const char *type_name)
942 : {
943 : return NULL;
944 : }
945 :
946 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
947 : rk_dns_free_data(struct rk_dns_reply *r)
948 : {
949 : }
950 :
951 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
952 : rk_dns_srv_order(struct rk_dns_reply *r)
953 : {
954 : }
955 :
956 : #endif
|