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 : rk_dns_string_to_type(const char *name)
83 0 : {
84 0 : struct stot *p = stot;
85 0 : for(p = stot; p->name; p++)
86 0 : if(strcasecmp(name, p->name) == 0)
87 0 : return p->type;
88 0 : return -1;
89 : }
90 :
91 : ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
92 : rk_dns_type_to_string(int type)
93 0 : {
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)
102 :
103 : static void
104 : dns_free_rr(struct rk_resource_record *rr)
105 0 : {
106 0 : if(rr->domain)
107 0 : free(rr->domain);
108 0 : if(rr->u.data)
109 0 : free(rr->u.data);
110 0 : free(rr);
111 0 : }
112 :
113 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
114 : rk_dns_free_data(struct rk_dns_reply *r)
115 0 : {
116 : struct rk_resource_record *rr;
117 0 : if(r->q.domain)
118 0 : free(r->q.domain);
119 0 : for(rr = r->head; rr;){
120 0 : struct rk_resource_record *tmp = rr;
121 0 : rr = rr->next;
122 0 : dns_free_rr(tmp);
123 : }
124 0 : free (r);
125 0 : }
126 :
127 : static int
128 : parse_record(const unsigned char *data, const unsigned char *end_data,
129 : const unsigned char **pp, struct rk_resource_record **ret_rr)
130 0 : {
131 : struct rk_resource_record *rr;
132 : int type, class, ttl;
133 : unsigned size;
134 : int status;
135 : char host[MAXDNAME];
136 0 : const unsigned char *p = *pp;
137 :
138 0 : *ret_rr = NULL;
139 :
140 0 : status = dn_expand(data, end_data, p, host, sizeof(host));
141 0 : if(status < 0)
142 0 : return -1;
143 0 : if (p + status + 10 > end_data)
144 0 : return -1;
145 :
146 0 : p += status;
147 0 : type = (p[0] << 8) | p[1];
148 0 : p += 2;
149 0 : class = (p[0] << 8) | p[1];
150 0 : p += 2;
151 0 : ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
152 0 : p += 4;
153 0 : size = (p[0] << 8) | p[1];
154 0 : p += 2;
155 :
156 0 : if (p + size > end_data)
157 0 : return -1;
158 :
159 0 : rr = calloc(1, sizeof(*rr));
160 0 : if(rr == NULL)
161 0 : return -1;
162 0 : rr->domain = strdup(host);
163 0 : if(rr->domain == NULL) {
164 0 : dns_free_rr(rr);
165 0 : return -1;
166 : }
167 0 : rr->type = type;
168 0 : rr->class = class;
169 0 : rr->ttl = ttl;
170 0 : rr->size = size;
171 0 : switch(type){
172 : case rk_ns_t_ns:
173 : case rk_ns_t_cname:
174 : case rk_ns_t_ptr:
175 0 : status = dn_expand(data, end_data, p, host, sizeof(host));
176 0 : if(status < 0) {
177 0 : dns_free_rr(rr);
178 0 : return -1;
179 : }
180 0 : rr->u.txt = strdup(host);
181 0 : if(rr->u.txt == NULL) {
182 0 : dns_free_rr(rr);
183 0 : return -1;
184 : }
185 0 : break;
186 : case rk_ns_t_mx:
187 : case rk_ns_t_afsdb:{
188 : size_t hostlen;
189 :
190 0 : status = dn_expand(data, end_data, p + 2, host, sizeof(host));
191 0 : if(status < 0){
192 0 : dns_free_rr(rr);
193 0 : return -1;
194 : }
195 0 : if (status + 2 > size) {
196 0 : dns_free_rr(rr);
197 0 : return -1;
198 : }
199 :
200 0 : hostlen = strlen(host);
201 0 : rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
202 : hostlen);
203 0 : if(rr->u.mx == NULL) {
204 0 : dns_free_rr(rr);
205 0 : return -1;
206 : }
207 0 : rr->u.mx->preference = (p[0] << 8) | p[1];
208 0 : strlcpy(rr->u.mx->domain, host, hostlen + 1);
209 0 : break;
210 : }
211 : case rk_ns_t_srv:{
212 : size_t hostlen;
213 0 : status = dn_expand(data, end_data, p + 6, host, sizeof(host));
214 0 : if(status < 0){
215 0 : dns_free_rr(rr);
216 0 : return -1;
217 : }
218 0 : if (status + 6 > size) {
219 0 : dns_free_rr(rr);
220 0 : return -1;
221 : }
222 :
223 0 : hostlen = strlen(host);
224 0 : rr->u.srv =
225 : (struct srv_record*)malloc(sizeof(struct srv_record) +
226 : hostlen);
227 0 : if(rr->u.srv == NULL) {
228 0 : dns_free_rr(rr);
229 0 : return -1;
230 : }
231 0 : rr->u.srv->priority = (p[0] << 8) | p[1];
232 0 : rr->u.srv->weight = (p[2] << 8) | p[3];
233 0 : rr->u.srv->port = (p[4] << 8) | p[5];
234 0 : strlcpy(rr->u.srv->target, host, hostlen + 1);
235 0 : break;
236 : }
237 : case rk_ns_t_txt:{
238 0 : if(size == 0 || size < *p + 1) {
239 0 : dns_free_rr(rr);
240 0 : return -1;
241 : }
242 0 : rr->u.txt = (char*)malloc(*p + 1);
243 0 : if(rr->u.txt == NULL) {
244 0 : dns_free_rr(rr);
245 0 : return -1;
246 : }
247 0 : strncpy(rr->u.txt, (const char*)(p + 1), *p);
248 0 : rr->u.txt[*p] = '\0';
249 0 : break;
250 : }
251 : case rk_ns_t_key : {
252 : size_t key_len;
253 :
254 0 : if (size < 4) {
255 0 : dns_free_rr(rr);
256 0 : return -1;
257 : }
258 :
259 0 : key_len = size - 4;
260 0 : rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
261 0 : if (rr->u.key == NULL) {
262 0 : dns_free_rr(rr);
263 0 : return -1;
264 : }
265 :
266 0 : rr->u.key->flags = (p[0] << 8) | p[1];
267 0 : rr->u.key->protocol = p[2];
268 0 : rr->u.key->algorithm = p[3];
269 0 : rr->u.key->key_len = key_len;
270 0 : memcpy (rr->u.key->key_data, p + 4, key_len);
271 0 : break;
272 : }
273 : case rk_ns_t_sig : {
274 : size_t sig_len, hostlen;
275 :
276 0 : if(size <= 18) {
277 0 : dns_free_rr(rr);
278 0 : return -1;
279 : }
280 0 : status = dn_expand (data, end_data, p + 18, host, sizeof(host));
281 0 : if (status < 0) {
282 0 : dns_free_rr(rr);
283 0 : return -1;
284 : }
285 0 : if (status + 18 > size) {
286 0 : dns_free_rr(rr);
287 0 : return -1;
288 : }
289 :
290 : /* the signer name is placed after the sig_data, to make it
291 : easy to free this structure; the size calculation below
292 : includes the zero-termination if the structure itself.
293 : don't you just love C?
294 : */
295 0 : sig_len = size - 18 - status;
296 0 : hostlen = strlen(host);
297 0 : rr->u.sig = malloc(sizeof(*rr->u.sig)
298 : + hostlen + sig_len);
299 0 : if (rr->u.sig == NULL) {
300 0 : dns_free_rr(rr);
301 0 : return -1;
302 : }
303 0 : rr->u.sig->type = (p[0] << 8) | p[1];
304 0 : rr->u.sig->algorithm = p[2];
305 0 : rr->u.sig->labels = p[3];
306 0 : rr->u.sig->orig_ttl = (p[4] << 24) | (p[5] << 16)
307 : | (p[6] << 8) | p[7];
308 0 : rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
309 : | (p[10] << 8) | p[11];
310 0 : rr->u.sig->sig_inception = (p[12] << 24) | (p[13] << 16)
311 : | (p[14] << 8) | p[15];
312 0 : rr->u.sig->key_tag = (p[16] << 8) | p[17];
313 0 : rr->u.sig->sig_len = sig_len;
314 0 : memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len);
315 0 : rr->u.sig->signer = &rr->u.sig->sig_data[sig_len];
316 0 : strlcpy(rr->u.sig->signer, host, hostlen + 1);
317 0 : break;
318 : }
319 :
320 : case rk_ns_t_cert : {
321 : size_t cert_len;
322 :
323 0 : if (size < 5) {
324 0 : dns_free_rr(rr);
325 0 : return -1;
326 : }
327 :
328 0 : cert_len = size - 5;
329 0 : rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1);
330 0 : if (rr->u.cert == NULL) {
331 0 : dns_free_rr(rr);
332 0 : return -1;
333 : }
334 :
335 0 : rr->u.cert->type = (p[0] << 8) | p[1];
336 0 : rr->u.cert->tag = (p[2] << 8) | p[3];
337 0 : rr->u.cert->algorithm = p[4];
338 0 : rr->u.cert->cert_len = cert_len;
339 0 : memcpy (rr->u.cert->cert_data, p + 5, cert_len);
340 0 : break;
341 : }
342 : case rk_ns_t_sshfp : {
343 : size_t sshfp_len;
344 :
345 0 : if (size < 2) {
346 0 : dns_free_rr(rr);
347 0 : return -1;
348 : }
349 :
350 0 : sshfp_len = size - 2;
351 :
352 0 : rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1);
353 0 : if (rr->u.sshfp == NULL) {
354 0 : dns_free_rr(rr);
355 0 : return -1;
356 : }
357 :
358 0 : rr->u.sshfp->algorithm = p[0];
359 0 : rr->u.sshfp->type = p[1];
360 0 : rr->u.sshfp->sshfp_len = sshfp_len;
361 0 : memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len);
362 0 : break;
363 : }
364 : case rk_ns_t_ds: {
365 : size_t digest_len;
366 :
367 0 : if (size < 4) {
368 0 : dns_free_rr(rr);
369 0 : return -1;
370 : }
371 :
372 0 : digest_len = size - 4;
373 :
374 0 : rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1);
375 0 : if (rr->u.ds == NULL) {
376 0 : dns_free_rr(rr);
377 0 : return -1;
378 : }
379 :
380 0 : rr->u.ds->key_tag = (p[0] << 8) | p[1];
381 0 : rr->u.ds->algorithm = p[2];
382 0 : rr->u.ds->digest_type = p[3];
383 0 : rr->u.ds->digest_len = digest_len;
384 0 : memcpy (rr->u.ds->digest_data, p + 4, digest_len);
385 0 : break;
386 : }
387 : default:
388 0 : rr->u.data = (unsigned char*)malloc(size);
389 0 : if(size != 0 && rr->u.data == NULL) {
390 0 : dns_free_rr(rr);
391 0 : return -1;
392 : }
393 0 : if (size)
394 0 : memcpy(rr->u.data, p, size);
395 : }
396 0 : *pp = p + size;
397 0 : *ret_rr = rr;
398 :
399 0 : return 0;
400 : }
401 :
402 : #ifndef TEST_RESOLVE
403 : static
404 : #endif
405 : struct rk_dns_reply*
406 : parse_reply(const unsigned char *data, size_t len)
407 0 : {
408 : const unsigned char *p;
409 : int status;
410 : int i;
411 : char host[MAXDNAME];
412 0 : const unsigned char *end_data = data + len;
413 : struct rk_dns_reply *r;
414 : struct rk_resource_record **rr;
415 :
416 0 : r = calloc(1, sizeof(*r));
417 0 : if (r == NULL)
418 0 : return NULL;
419 :
420 0 : p = data;
421 :
422 0 : r->h.id = (p[0] << 8) | p[1];
423 0 : r->h.flags = 0;
424 0 : if (p[2] & 0x01)
425 0 : r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
426 0 : r->h.opcode = (p[2] >> 1) & 0xf;
427 0 : if (p[2] & 0x20)
428 0 : r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
429 0 : if (p[2] & 0x40)
430 0 : r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
431 0 : if (p[2] & 0x80)
432 0 : r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
433 0 : if (p[3] & 0x01)
434 0 : r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
435 0 : if (p[3] & 0x04)
436 0 : r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
437 0 : if (p[3] & 0x08)
438 0 : r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
439 0 : r->h.response_code = (p[3] >> 4) & 0xf;
440 0 : r->h.qdcount = (p[4] << 8) | p[5];
441 0 : r->h.ancount = (p[6] << 8) | p[7];
442 0 : r->h.nscount = (p[8] << 8) | p[9];
443 0 : r->h.arcount = (p[10] << 8) | p[11];
444 :
445 0 : p += 12;
446 :
447 0 : if(r->h.qdcount != 1) {
448 0 : free(r);
449 0 : return NULL;
450 : }
451 0 : status = dn_expand(data, end_data, p, host, sizeof(host));
452 0 : if(status < 0){
453 0 : rk_dns_free_data(r);
454 0 : return NULL;
455 : }
456 0 : r->q.domain = strdup(host);
457 0 : if(r->q.domain == NULL) {
458 0 : rk_dns_free_data(r);
459 0 : return NULL;
460 : }
461 0 : if (p + status + 4 > end_data) {
462 0 : rk_dns_free_data(r);
463 0 : return NULL;
464 : }
465 0 : p += status;
466 0 : r->q.type = (p[0] << 8 | p[1]);
467 0 : p += 2;
468 0 : r->q.class = (p[0] << 8 | p[1]);
469 0 : p += 2;
470 :
471 0 : rr = &r->head;
472 0 : for(i = 0; i < r->h.ancount; i++) {
473 0 : if(parse_record(data, end_data, &p, rr) != 0) {
474 0 : rk_dns_free_data(r);
475 0 : return NULL;
476 : }
477 0 : rr = &(*rr)->next;
478 : }
479 0 : for(i = 0; i < r->h.nscount; i++) {
480 0 : if(parse_record(data, end_data, &p, rr) != 0) {
481 0 : rk_dns_free_data(r);
482 0 : return NULL;
483 : }
484 0 : rr = &(*rr)->next;
485 : }
486 0 : for(i = 0; i < r->h.arcount; i++) {
487 0 : if(parse_record(data, end_data, &p, rr) != 0) {
488 0 : rk_dns_free_data(r);
489 0 : return NULL;
490 : }
491 0 : rr = &(*rr)->next;
492 : }
493 0 : *rr = NULL;
494 0 : return r;
495 : }
496 :
497 : #ifdef HAVE_RES_NSEARCH
498 : #ifdef HAVE_RES_NDESTROY
499 : #define rk_res_free(x) res_ndestroy(x)
500 : #else
501 : #define rk_res_free(x) res_nclose(x)
502 : #endif
503 : #endif
504 :
505 : #if defined(HAVE_DNS_SEARCH)
506 : #define resolve_search(h,n,c,t,r,l) \
507 : ((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize))
508 : #define resolve_free_handle(h) dns_free(h)
509 : #elif defined(HAVE_RES_NSEARCH)
510 : #define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l)
511 : #define resolve_free_handle(h) rk_res_free(h);
512 : #else
513 : #define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l)
514 : #define handle 0
515 : #define resolve_free_handle(h)
516 : #endif
517 :
518 :
519 : static struct rk_dns_reply *
520 : dns_lookup_int(const char *domain, int rr_class, int rr_type)
521 0 : {
522 : struct rk_dns_reply *r;
523 0 : void *reply = NULL;
524 : int size, len;
525 : #if defined(HAVE_DNS_SEARCH)
526 : struct sockaddr_storage from;
527 : uint32_t fromsize = sizeof(from);
528 : dns_handle_t handle;
529 :
530 : handle = dns_open(NULL);
531 : if (handle == NULL)
532 : return NULL;
533 : #elif defined(HAVE_RES_NSEARCH)
534 : struct __res_state state;
535 0 : struct __res_state *handle = &state;
536 :
537 0 : memset(&state, 0, sizeof(state));
538 0 : if(res_ninit(handle))
539 0 : return NULL; /* is this the best we can do? */
540 : #endif
541 :
542 0 : len = 1500;
543 : while(1) {
544 0 : if (reply) {
545 0 : free(reply);
546 0 : reply = NULL;
547 : }
548 0 : if (_resolve_debug) {
549 : #if defined(HAVE_DNS_SEARCH)
550 : dns_set_debug(handle, 1);
551 : #elif defined(HAVE_RES_NSEARCH)
552 0 : state.options |= RES_DEBUG;
553 : #endif
554 0 : fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
555 : rr_class, rk_dns_type_to_string(rr_type), len);
556 : }
557 0 : reply = malloc(len);
558 0 : if (reply == NULL) {
559 0 : resolve_free_handle(handle);
560 0 : return NULL;
561 : }
562 :
563 0 : size = resolve_search(handle, domain, rr_class, rr_type, reply, len);
564 :
565 0 : if (_resolve_debug) {
566 0 : fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
567 : domain, rr_class, rk_dns_type_to_string(rr_type), size);
568 : }
569 0 : if (size > len) {
570 : /* resolver thinks it know better, go for it */
571 0 : len = size;
572 0 : } else if (size > 0) {
573 : /* got a good reply */
574 0 : break;
575 0 : } else if (size <= 0 && len < rk_DNS_MAX_PACKET_SIZE) {
576 0 : len *= 2;
577 0 : if (len > rk_DNS_MAX_PACKET_SIZE)
578 0 : len = rk_DNS_MAX_PACKET_SIZE;
579 : } else {
580 : /* the end, leave */
581 0 : resolve_free_handle(handle);
582 0 : free(reply);
583 0 : return NULL;
584 : }
585 0 : }
586 :
587 0 : len = min(len, size);
588 0 : r = parse_reply(reply, len);
589 0 : free(reply);
590 0 : return r;
591 : }
592 :
593 : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
594 : rk_dns_lookup(const char *domain, const char *type_name)
595 0 : {
596 : int type;
597 :
598 0 : type = rk_dns_string_to_type(type_name);
599 0 : if(type == -1) {
600 0 : if(_resolve_debug)
601 0 : fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
602 : type_name);
603 0 : return NULL;
604 : }
605 0 : return dns_lookup_int(domain, rk_ns_c_in, type);
606 : }
607 :
608 : static int
609 : compare_srv(const void *a, const void *b)
610 0 : {
611 0 : const struct rk_resource_record *const* aa = a, *const* bb = b;
612 :
613 0 : if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
614 0 : return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
615 0 : return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
616 : }
617 :
618 : #ifndef HAVE_RANDOM
619 : #define random() rand()
620 : #endif
621 :
622 : /* try to rearrange the srv-records by the algorithm in RFC2782 */
623 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
624 : rk_dns_srv_order(struct rk_dns_reply *r)
625 0 : {
626 : struct rk_resource_record **srvs, **ss, **headp;
627 : struct rk_resource_record *rr;
628 0 : int num_srv = 0;
629 :
630 : #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
631 : int state[256 / sizeof(int)];
632 : char *oldstate;
633 : #endif
634 :
635 0 : for(rr = r->head; rr; rr = rr->next)
636 0 : if(rr->type == rk_ns_t_srv)
637 0 : num_srv++;
638 :
639 0 : if(num_srv == 0)
640 0 : return;
641 :
642 0 : srvs = malloc(num_srv * sizeof(*srvs));
643 0 : if(srvs == NULL)
644 0 : return; /* XXX not much to do here */
645 :
646 : /* unlink all srv-records from the linked list and put them in
647 : a vector */
648 0 : for(ss = srvs, headp = &r->head; *headp; )
649 0 : if((*headp)->type == rk_ns_t_srv) {
650 0 : *ss = *headp;
651 0 : *headp = (*headp)->next;
652 0 : (*ss)->next = NULL;
653 0 : ss++;
654 : } else
655 0 : headp = &(*headp)->next;
656 :
657 : /* sort them by priority and weight */
658 0 : qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
659 :
660 : #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
661 : oldstate = initstate(time(NULL), (char*)state, sizeof(state));
662 : #endif
663 :
664 0 : headp = &r->head;
665 :
666 0 : for(ss = srvs; ss < srvs + num_srv; ) {
667 : int sum, rnd, count;
668 : struct rk_resource_record **ee, **tt;
669 : /* find the last record with the same priority and count the
670 : sum of all weights */
671 0 : for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
672 0 : assert(*tt != NULL);
673 0 : if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
674 0 : break;
675 0 : sum += (*tt)->u.srv->weight;
676 : }
677 0 : ee = tt;
678 : /* ss is now the first record of this priority and ee is the
679 : first of the next */
680 0 : while(ss < ee) {
681 0 : rnd = random() % (sum + 1);
682 0 : for(count = 0, tt = ss; ; tt++) {
683 0 : if(*tt == NULL)
684 0 : continue;
685 0 : count += (*tt)->u.srv->weight;
686 0 : if(count >= rnd)
687 0 : break;
688 0 : }
689 :
690 0 : assert(tt < ee);
691 :
692 : /* insert the selected record at the tail (of the head) of
693 : the list */
694 0 : (*tt)->next = *headp;
695 0 : *headp = *tt;
696 0 : headp = &(*tt)->next;
697 0 : sum -= (*tt)->u.srv->weight;
698 0 : *tt = NULL;
699 0 : while(ss < ee && *ss == NULL)
700 0 : ss++;
701 : }
702 : }
703 :
704 : #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
705 : setstate(oldstate);
706 : #endif
707 0 : free(srvs);
708 0 : return;
709 : }
710 :
711 : #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
712 :
713 : ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
714 : rk_dns_lookup(const char *domain, const char *type_name)
715 : {
716 : return NULL;
717 : }
718 :
719 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
720 : rk_dns_free_data(struct rk_dns_reply *r)
721 : {
722 : }
723 :
724 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
725 : rk_dns_srv_order(struct rk_dns_reply *r)
726 : {
727 : }
728 :
729 : #endif
|