~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/roken/resolve.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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