resolve.c revision 120945
155682Smarkm/*
2120945Snectar * Copyright (c) 1995 - 2003 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#ifdef HAVE_CONFIG_H
3555682Smarkm#include <config.h>
3655682Smarkm#endif
3755682Smarkm#include "roken.h"
3855682Smarkm#ifdef HAVE_ARPA_NAMESER_H
3955682Smarkm#include <arpa/nameser.h>
4055682Smarkm#endif
4155682Smarkm#ifdef HAVE_RESOLV_H
4255682Smarkm#include <resolv.h>
4355682Smarkm#endif
4455682Smarkm#include "resolve.h"
4555682Smarkm
4690926Snectar#include <assert.h>
4755682Smarkm
48120945SnectarRCSID("$Id: resolve.c,v 1.38.2.1 2003/04/22 15:02:47 lha Exp $");
4990926Snectar
50103423Snectar#undef HAVE_RES_NSEARCH
51103423Snectar#if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)
5255682Smarkm
5355682Smarkm#define DECL(X) {#X, T_##X}
5455682Smarkm
5555682Smarkmstatic struct stot{
5655682Smarkm    const char *name;
5755682Smarkm    int type;
5855682Smarkm}stot[] = {
5955682Smarkm    DECL(A),
6055682Smarkm    DECL(NS),
6155682Smarkm    DECL(CNAME),
6272445Sassar    DECL(SOA),
6355682Smarkm    DECL(PTR),
6455682Smarkm    DECL(MX),
6555682Smarkm    DECL(TXT),
6655682Smarkm    DECL(AFSDB),
6772445Sassar    DECL(SIG),
6872445Sassar    DECL(KEY),
6955682Smarkm    DECL(SRV),
7072445Sassar    DECL(NAPTR),
7155682Smarkm    {NULL, 	0}
7255682Smarkm};
7355682Smarkm
7472445Sassarint _resolve_debug = 0;
7555682Smarkm
7672445Sassarint
7772445Sassardns_string_to_type(const char *name)
7855682Smarkm{
7955682Smarkm    struct stot *p = stot;
8055682Smarkm    for(p = stot; p->name; p++)
8155682Smarkm	if(strcasecmp(name, p->name) == 0)
8255682Smarkm	    return p->type;
8355682Smarkm    return -1;
8455682Smarkm}
8555682Smarkm
8672445Sassarconst char *
8772445Sassardns_type_to_string(int type)
8855682Smarkm{
8955682Smarkm    struct stot *p = stot;
9055682Smarkm    for(p = stot; p->name; p++)
9155682Smarkm	if(type == p->type)
9255682Smarkm	    return p->name;
9355682Smarkm    return NULL;
9455682Smarkm}
9555682Smarkm
9655682Smarkmvoid
9755682Smarkmdns_free_data(struct dns_reply *r)
9855682Smarkm{
9955682Smarkm    struct resource_record *rr;
10055682Smarkm    if(r->q.domain)
10155682Smarkm	free(r->q.domain);
10255682Smarkm    for(rr = r->head; rr;){
10355682Smarkm	struct resource_record *tmp = rr;
10455682Smarkm	if(rr->domain)
10555682Smarkm	    free(rr->domain);
10655682Smarkm	if(rr->u.data)
10755682Smarkm	    free(rr->u.data);
10855682Smarkm	rr = rr->next;
10955682Smarkm	free(tmp);
11055682Smarkm    }
11155682Smarkm    free (r);
11255682Smarkm}
11355682Smarkm
114107207Snectarstatic int
115107207Snectarparse_record(const unsigned char *data, const unsigned char *end_data,
116107207Snectar	     const unsigned char **pp, struct resource_record **rr)
117107207Snectar{
118107207Snectar    int type, class, ttl, size;
119107207Snectar    int status;
120107207Snectar    char host[MAXDNAME];
121107207Snectar    const unsigned char *p = *pp;
122107207Snectar    status = dn_expand(data, end_data, p, host, sizeof(host));
123107207Snectar    if(status < 0)
124107207Snectar	return -1;
125107207Snectar    if (p + status + 10 > end_data)
126107207Snectar	return -1;
127107207Snectar    p += status;
128107207Snectar    type = (p[0] << 8) | p[1];
129107207Snectar    p += 2;
130107207Snectar    class = (p[0] << 8) | p[1];
131107207Snectar    p += 2;
132107207Snectar    ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
133107207Snectar    p += 4;
134107207Snectar    size = (p[0] << 8) | p[1];
135107207Snectar    p += 2;
136107207Snectar
137107207Snectar    if (p + size > end_data)
138107207Snectar	return -1;
139107207Snectar
140107207Snectar    *rr = calloc(1, sizeof(**rr));
141107207Snectar    if(*rr == NULL)
142107207Snectar	return -1;
143107207Snectar    (*rr)->domain = strdup(host);
144107207Snectar    if((*rr)->domain == NULL) {
145107207Snectar	free(*rr);
146107207Snectar	return -1;
147107207Snectar    }
148107207Snectar    (*rr)->type = type;
149107207Snectar    (*rr)->class = class;
150107207Snectar    (*rr)->ttl = ttl;
151107207Snectar    (*rr)->size = size;
152107207Snectar    switch(type){
153107207Snectar    case T_NS:
154107207Snectar    case T_CNAME:
155107207Snectar    case T_PTR:
156107207Snectar	status = dn_expand(data, end_data, p, host, sizeof(host));
157107207Snectar	if(status < 0) {
158107207Snectar	    free(*rr);
159107207Snectar	    return -1;
160107207Snectar	}
161107207Snectar	(*rr)->u.txt = strdup(host);
162107207Snectar	if((*rr)->u.txt == NULL) {
163107207Snectar	    free(*rr);
164107207Snectar	    return -1;
165107207Snectar	}
166107207Snectar	break;
167107207Snectar    case T_MX:
168107207Snectar    case T_AFSDB:{
169120945Snectar	size_t hostlen;
170120945Snectar
171107207Snectar	status = dn_expand(data, end_data, p + 2, host, sizeof(host));
172107207Snectar	if(status < 0){
173107207Snectar	    free(*rr);
174107207Snectar	    return -1;
175107207Snectar	}
176107207Snectar	if (status + 2 > size) {
177107207Snectar	    free(*rr);
178107207Snectar	    return -1;
179107207Snectar	}
180107207Snectar
181120945Snectar	hostlen = strlen(host);
182107207Snectar	(*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
183120945Snectar						hostlen);
184107207Snectar	if((*rr)->u.mx == NULL) {
185107207Snectar	    free(*rr);
186107207Snectar	    return -1;
187107207Snectar	}
188107207Snectar	(*rr)->u.mx->preference = (p[0] << 8) | p[1];
189120945Snectar	strlcpy((*rr)->u.mx->domain, host, hostlen + 1);
190107207Snectar	break;
191107207Snectar    }
192107207Snectar    case T_SRV:{
193120945Snectar	size_t hostlen;
194107207Snectar	status = dn_expand(data, end_data, p + 6, host, sizeof(host));
195107207Snectar	if(status < 0){
196107207Snectar	    free(*rr);
197107207Snectar	    return -1;
198107207Snectar	}
199107207Snectar	if (status + 6 > size) {
200107207Snectar	    free(*rr);
201107207Snectar	    return -1;
202107207Snectar	}
203107207Snectar
204120945Snectar	hostlen = strlen(host);
205107207Snectar	(*rr)->u.srv =
206107207Snectar	    (struct srv_record*)malloc(sizeof(struct srv_record) +
207120945Snectar				       hostlen);
208107207Snectar	if((*rr)->u.srv == NULL) {
209107207Snectar	    free(*rr);
210107207Snectar	    return -1;
211107207Snectar	}
212107207Snectar	(*rr)->u.srv->priority = (p[0] << 8) | p[1];
213107207Snectar	(*rr)->u.srv->weight = (p[2] << 8) | p[3];
214107207Snectar	(*rr)->u.srv->port = (p[4] << 8) | p[5];
215120945Snectar	strlcpy((*rr)->u.srv->target, host, hostlen + 1);
216107207Snectar	break;
217107207Snectar    }
218107207Snectar    case T_TXT:{
219107207Snectar	if(size == 0 || size < *p + 1) {
220107207Snectar	    free(*rr);
221107207Snectar	    return -1;
222107207Snectar	}
223107207Snectar	(*rr)->u.txt = (char*)malloc(*p + 1);
224107207Snectar	if((*rr)->u.txt == NULL) {
225107207Snectar	    free(*rr);
226107207Snectar	    return -1;
227107207Snectar	}
228107207Snectar	strncpy((*rr)->u.txt, (char*)p + 1, *p);
229107207Snectar	(*rr)->u.txt[*p] = '\0';
230107207Snectar	break;
231107207Snectar    }
232107207Snectar    case T_KEY : {
233107207Snectar	size_t key_len;
234107207Snectar
235107207Snectar	if (size < 4) {
236107207Snectar	    free(*rr);
237107207Snectar	    return -1;
238107207Snectar	}
239107207Snectar
240107207Snectar	key_len = size - 4;
241107207Snectar	(*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
242107207Snectar	if ((*rr)->u.key == NULL) {
243107207Snectar	    free(*rr);
244107207Snectar	    return -1;
245107207Snectar	}
246107207Snectar
247107207Snectar	(*rr)->u.key->flags     = (p[0] << 8) | p[1];
248107207Snectar	(*rr)->u.key->protocol  = p[2];
249107207Snectar	(*rr)->u.key->algorithm = p[3];
250107207Snectar	(*rr)->u.key->key_len   = key_len;
251107207Snectar	memcpy ((*rr)->u.key->key_data, p + 4, key_len);
252107207Snectar	break;
253107207Snectar    }
254107207Snectar    case T_SIG : {
255120945Snectar	size_t sig_len, hostlen;
256107207Snectar
257107207Snectar	if(size <= 18) {
258107207Snectar	    free(*rr);
259107207Snectar	    return -1;
260107207Snectar	}
261107207Snectar	status = dn_expand (data, end_data, p + 18, host, sizeof(host));
262107207Snectar	if (status < 0) {
263107207Snectar	    free(*rr);
264107207Snectar	    return -1;
265107207Snectar	}
266107207Snectar	if (status + 18 > size) {
267107207Snectar	    free(*rr);
268107207Snectar	    return -1;
269107207Snectar	}
270107207Snectar
271107207Snectar	/* the signer name is placed after the sig_data, to make it
272107207Snectar           easy to free this struture; the size calculation below
273107207Snectar           includes the zero-termination if the structure itself.
274107207Snectar	   don't you just love C?
275107207Snectar	*/
276107207Snectar	sig_len = size - 18 - status;
277120945Snectar	hostlen = strlen(host);
278107207Snectar	(*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
279120945Snectar			      + hostlen + sig_len);
280107207Snectar	if ((*rr)->u.sig == NULL) {
281107207Snectar	    free(*rr);
282107207Snectar	    return -1;
283107207Snectar	}
284107207Snectar	(*rr)->u.sig->type           = (p[0] << 8) | p[1];
285107207Snectar	(*rr)->u.sig->algorithm      = p[2];
286107207Snectar	(*rr)->u.sig->labels         = p[3];
287107207Snectar	(*rr)->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
288107207Snectar	    | (p[6] << 8) | p[7];
289107207Snectar	(*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
290107207Snectar	    | (p[10] << 8) | p[11];
291107207Snectar	(*rr)->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
292107207Snectar	    | (p[14] << 8) | p[15];
293107207Snectar	(*rr)->u.sig->key_tag        = (p[16] << 8) | p[17];
294107207Snectar	(*rr)->u.sig->sig_len        = sig_len;
295107207Snectar	memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len);
296107207Snectar	(*rr)->u.sig->signer         = &(*rr)->u.sig->sig_data[sig_len];
297120945Snectar	strlcpy((*rr)->u.sig->signer, host, hostlen + 1);
298107207Snectar	break;
299107207Snectar    }
300107207Snectar
301107207Snectar    case T_CERT : {
302107207Snectar	size_t cert_len;
303107207Snectar
304107207Snectar	if (size < 5) {
305107207Snectar	    free(*rr);
306107207Snectar	    return -1;
307107207Snectar	}
308107207Snectar
309107207Snectar	cert_len = size - 5;
310107207Snectar	(*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
311107207Snectar	if ((*rr)->u.cert == NULL) {
312107207Snectar	    free(*rr);
313107207Snectar	    return -1;
314107207Snectar	}
315107207Snectar
316107207Snectar	(*rr)->u.cert->type      = (p[0] << 8) | p[1];
317107207Snectar	(*rr)->u.cert->tag       = (p[2] << 8) | p[3];
318107207Snectar	(*rr)->u.cert->algorithm = p[4];
319107207Snectar	(*rr)->u.cert->cert_len  = cert_len;
320107207Snectar	memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len);
321107207Snectar	break;
322107207Snectar    }
323107207Snectar    default:
324107207Snectar	(*rr)->u.data = (unsigned char*)malloc(size);
325107207Snectar	if(size != 0 && (*rr)->u.data == NULL) {
326107207Snectar	    free(*rr);
327107207Snectar	    return -1;
328107207Snectar	}
329107207Snectar	memcpy((*rr)->u.data, p, size);
330107207Snectar    }
331107207Snectar    *pp = p + size;
332107207Snectar    return 0;
333107207Snectar}
334107207Snectar
335103423Snectar#ifndef TEST_RESOLVE
336103423Snectarstatic
337103423Snectar#endif
338103423Snectarstruct dns_reply*
339103423Snectarparse_reply(const unsigned char *data, size_t len)
34055682Smarkm{
341102644Snectar    const unsigned char *p;
34255682Smarkm    int status;
343107207Snectar    int i;
344107207Snectar    char host[MAXDNAME];
345102644Snectar    const unsigned char *end_data = data + len;
34655682Smarkm    struct dns_reply *r;
34755682Smarkm    struct resource_record **rr;
34855682Smarkm
34955682Smarkm    r = calloc(1, sizeof(*r));
35055682Smarkm    if (r == NULL)
35155682Smarkm	return NULL;
35255682Smarkm
35355682Smarkm    p = data;
35455682Smarkm#if 0
35555682Smarkm    /* doesn't work on Crays */
35655682Smarkm    memcpy(&r->h, p, sizeof(HEADER));
35755682Smarkm    p += sizeof(HEADER);
35855682Smarkm#else
35955682Smarkm    memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
36055682Smarkm    p += 12;
36155682Smarkm#endif
362107207Snectar    if(ntohs(r->h.qdcount) != 1) {
363107207Snectar	free(r);
364107207Snectar	return NULL;
365107207Snectar    }
366102644Snectar    status = dn_expand(data, end_data, p, host, sizeof(host));
36755682Smarkm    if(status < 0){
36855682Smarkm	dns_free_data(r);
36955682Smarkm	return NULL;
37055682Smarkm    }
37155682Smarkm    r->q.domain = strdup(host);
37255682Smarkm    if(r->q.domain == NULL) {
37355682Smarkm	dns_free_data(r);
37455682Smarkm	return NULL;
37555682Smarkm    }
376102644Snectar    if (p + status + 4 > end_data) {
377102644Snectar	dns_free_data(r);
378102644Snectar	return NULL;
379102644Snectar    }
38055682Smarkm    p += status;
38155682Smarkm    r->q.type = (p[0] << 8 | p[1]);
38255682Smarkm    p += 2;
38355682Smarkm    r->q.class = (p[0] << 8 | p[1]);
38455682Smarkm    p += 2;
385107207Snectar
38655682Smarkm    rr = &r->head;
387107207Snectar    for(i = 0; i < ntohs(r->h.ancount); i++) {
388107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
38955682Smarkm	    dns_free_data(r);
39055682Smarkm	    return NULL;
39155682Smarkm	}
392107207Snectar	rr = &(*rr)->next;
393107207Snectar    }
394107207Snectar    for(i = 0; i < ntohs(r->h.nscount); i++) {
395107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
396102644Snectar	    dns_free_data(r);
397102644Snectar	    return NULL;
398102644Snectar	}
399107207Snectar	rr = &(*rr)->next;
400107207Snectar    }
401107207Snectar    for(i = 0; i < ntohs(r->h.arcount); i++) {
402107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
403102644Snectar	    dns_free_data(r);
404102644Snectar	    return NULL;
405102644Snectar	}
40655682Smarkm	rr = &(*rr)->next;
40755682Smarkm    }
40855682Smarkm    *rr = NULL;
40955682Smarkm    return r;
41055682Smarkm}
41155682Smarkm
41255682Smarkmstatic struct dns_reply *
41355682Smarkmdns_lookup_int(const char *domain, int rr_class, int rr_type)
41455682Smarkm{
41555682Smarkm    unsigned char reply[1024];
41655682Smarkm    int len;
417103423Snectar#ifdef HAVE_RES_NSEARCH
418103423Snectar    struct __res_state stat;
419103423Snectar    memset(&stat, 0, sizeof(stat));
420103423Snectar    if(res_ninit(&stat))
421103423Snectar	return NULL; /* is this the best we can do? */
422103423Snectar#elif defined(HAVE__RES)
42355682Smarkm    u_long old_options = 0;
424102644Snectar#endif
42555682Smarkm
42655682Smarkm    if (_resolve_debug) {
427103423Snectar#ifdef HAVE_RES_NSEARCH
428103423Snectar	stat.options |= RES_DEBUG;
429103423Snectar#elif defined(HAVE__RES)
43055682Smarkm        old_options = _res.options;
43155682Smarkm	_res.options |= RES_DEBUG;
432102644Snectar#endif
43355682Smarkm	fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain,
43472445Sassar		rr_class, dns_type_to_string(rr_type));
43555682Smarkm    }
436103423Snectar#ifdef HAVE_RES_NSEARCH
437103423Snectar    len = res_nsearch(&stat, domain, rr_class, rr_type, reply, sizeof(reply));
438103423Snectar#else
43955682Smarkm    len = res_search(domain, rr_class, rr_type, reply, sizeof(reply));
440103423Snectar#endif
44155682Smarkm    if (_resolve_debug) {
442103423Snectar#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
44355682Smarkm        _res.options = old_options;
444102644Snectar#endif
44555682Smarkm	fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
44672445Sassar		domain, rr_class, dns_type_to_string(rr_type), len);
44755682Smarkm    }
448103423Snectar#ifdef HAVE_RES_NSEARCH
449103423Snectar    res_nclose(&stat);
450103423Snectar#endif
451102644Snectar    if(len < 0) {
452102644Snectar	return NULL;
453102644Snectar    } else {
454102644Snectar	len = min(len, sizeof(reply));
455102644Snectar	return parse_reply(reply, len);
456102644Snectar    }
45755682Smarkm}
45855682Smarkm
45955682Smarkmstruct dns_reply *
46055682Smarkmdns_lookup(const char *domain, const char *type_name)
46155682Smarkm{
46255682Smarkm    int type;
46355682Smarkm
46472445Sassar    type = dns_string_to_type(type_name);
46555682Smarkm    if(type == -1) {
46655682Smarkm	if(_resolve_debug)
46755682Smarkm	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
46855682Smarkm		    type_name);
46955682Smarkm	return NULL;
47055682Smarkm    }
47155682Smarkm    return dns_lookup_int(domain, C_IN, type);
47255682Smarkm}
47355682Smarkm
47490926Snectarstatic int
47590926Snectarcompare_srv(const void *a, const void *b)
47690926Snectar{
47790926Snectar    const struct resource_record *const* aa = a, *const* bb = b;
47890926Snectar
47990926Snectar    if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
48090926Snectar	return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
48190926Snectar    return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
48290926Snectar}
48390926Snectar
48490926Snectar#ifndef HAVE_RANDOM
48590926Snectar#define random() rand()
48690926Snectar#endif
48790926Snectar
48890926Snectar/* try to rearrange the srv-records by the algorithm in RFC2782 */
48990926Snectarvoid
49090926Snectardns_srv_order(struct dns_reply *r)
49190926Snectar{
49290926Snectar    struct resource_record **srvs, **ss, **headp;
49390926Snectar    struct resource_record *rr;
49490926Snectar    int num_srv = 0;
49590926Snectar
49690926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
497102644Snectar    int state[256 / sizeof(int)];
498102644Snectar    char *oldstate;
49990926Snectar#endif
50090926Snectar
50190926Snectar    for(rr = r->head; rr; rr = rr->next)
50290926Snectar	if(rr->type == T_SRV)
50390926Snectar	    num_srv++;
50490926Snectar
50590926Snectar    if(num_srv == 0)
50690926Snectar	return;
50790926Snectar
50890926Snectar    srvs = malloc(num_srv * sizeof(*srvs));
50990926Snectar    if(srvs == NULL)
51090926Snectar	return; /* XXX not much to do here */
51190926Snectar
51290926Snectar    /* unlink all srv-records from the linked list and put them in
51390926Snectar       a vector */
51490926Snectar    for(ss = srvs, headp = &r->head; *headp; )
51590926Snectar	if((*headp)->type == T_SRV) {
51690926Snectar	    *ss = *headp;
51790926Snectar	    *headp = (*headp)->next;
51890926Snectar	    (*ss)->next = NULL;
51990926Snectar	    ss++;
52090926Snectar	} else
52190926Snectar	    headp = &(*headp)->next;
52290926Snectar
52390926Snectar    /* sort them by priority and weight */
52490926Snectar    qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
52590926Snectar
52690926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
527102644Snectar    oldstate = initstate(time(NULL), (char*)state, sizeof(state));
52890926Snectar#endif
52990926Snectar
53090926Snectar    headp = &r->head;
53190926Snectar
53290926Snectar    for(ss = srvs; ss < srvs + num_srv; ) {
53390926Snectar	int sum, rnd, count;
53490926Snectar	struct resource_record **ee, **tt;
53590926Snectar	/* find the last record with the same priority and count the
53690926Snectar           sum of all weights */
53790926Snectar	for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
53890926Snectar	    if(*tt == NULL)
53990926Snectar		continue;
54090926Snectar	    if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
54190926Snectar		break;
54290926Snectar	    sum += (*tt)->u.srv->weight;
54390926Snectar	}
54490926Snectar	ee = tt;
54590926Snectar	/* ss is now the first record of this priority and ee is the
54690926Snectar           first of the next */
54790926Snectar	while(ss < ee) {
54890926Snectar	    rnd = random() % (sum + 1);
54990926Snectar	    for(count = 0, tt = ss; ; tt++) {
55090926Snectar		if(*tt == NULL)
55190926Snectar		    continue;
55290926Snectar		count += (*tt)->u.srv->weight;
55390926Snectar		if(count >= rnd)
55490926Snectar		    break;
55590926Snectar	    }
55690926Snectar
55790926Snectar	    assert(tt < ee);
55890926Snectar
55990926Snectar	    /* insert the selected record at the tail (of the head) of
56090926Snectar               the list */
56190926Snectar	    (*tt)->next = *headp;
56290926Snectar	    *headp = *tt;
56390926Snectar	    headp = &(*tt)->next;
56490926Snectar	    sum -= (*tt)->u.srv->weight;
56590926Snectar	    *tt = NULL;
56690926Snectar	    while(ss < ee && *ss == NULL)
56790926Snectar		ss++;
56890926Snectar	}
56990926Snectar    }
57090926Snectar
57190926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
57290926Snectar    setstate(oldstate);
57390926Snectar#endif
57490926Snectar    free(srvs);
57590926Snectar    return;
57690926Snectar}
57790926Snectar
57855682Smarkm#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
57955682Smarkm
58055682Smarkmstruct dns_reply *
58155682Smarkmdns_lookup(const char *domain, const char *type_name)
58255682Smarkm{
58355682Smarkm    return NULL;
58455682Smarkm}
58555682Smarkm
58655682Smarkmvoid
58755682Smarkmdns_free_data(struct dns_reply *r)
58855682Smarkm{
58955682Smarkm}
59055682Smarkm
59190926Snectarvoid
59290926Snectardns_srv_order(struct dns_reply *r)
59390926Snectar{
59490926Snectar}
59590926Snectar
59655682Smarkm#endif
59755682Smarkm
59855682Smarkm#ifdef TEST
59955682Smarkmint
60055682Smarkmmain(int argc, char **argv)
60155682Smarkm{
60255682Smarkm    struct dns_reply *r;
60355682Smarkm    struct resource_record *rr;
60455682Smarkm    r = dns_lookup(argv[1], argv[2]);
60555682Smarkm    if(r == NULL){
60655682Smarkm	printf("No reply.\n");
60755682Smarkm	return 1;
60855682Smarkm    }
60990926Snectar    if(r->q.type == T_SRV)
61090926Snectar	dns_srv_order(r);
61190926Snectar
61255682Smarkm    for(rr = r->head; rr;rr=rr->next){
613107207Snectar	printf("%-30s %-5s %-6d ", rr->domain, dns_type_to_string(rr->type), rr->ttl);
61455682Smarkm	switch(rr->type){
61555682Smarkm	case T_NS:
61672445Sassar	case T_CNAME:
61772445Sassar	case T_PTR:
61855682Smarkm	    printf("%s\n", (char*)rr->u.data);
61955682Smarkm	    break;
62055682Smarkm	case T_A:
62172445Sassar	    printf("%s\n", inet_ntoa(*rr->u.a));
62255682Smarkm	    break;
62355682Smarkm	case T_MX:
62455682Smarkm	case T_AFSDB:{
62572445Sassar	    printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain);
62655682Smarkm	    break;
62755682Smarkm	}
62855682Smarkm	case T_SRV:{
62972445Sassar	    struct srv_record *srv = rr->u.srv;
63055682Smarkm	    printf("%d %d %d %s\n", srv->priority, srv->weight,
63155682Smarkm		   srv->port, srv->target);
63255682Smarkm	    break;
63355682Smarkm	}
63472445Sassar	case T_TXT: {
63572445Sassar	    printf("%s\n", rr->u.txt);
63672445Sassar	    break;
63772445Sassar	}
63872445Sassar	case T_SIG : {
63972445Sassar	    struct sig_record *sig = rr->u.sig;
64072445Sassar	    const char *type_string = dns_type_to_string (sig->type);
64172445Sassar
64272445Sassar	    printf ("type %u (%s), algorithm %u, labels %u, orig_ttl %u, sig_expiration %u, sig_inception %u, key_tag %u, signer %s\n",
64372445Sassar		    sig->type, type_string ? type_string : "",
64472445Sassar		    sig->algorithm, sig->labels, sig->orig_ttl,
64572445Sassar		    sig->sig_expiration, sig->sig_inception, sig->key_tag,
64672445Sassar		    sig->signer);
64772445Sassar	    break;
64872445Sassar	}
64972445Sassar	case T_KEY : {
65072445Sassar	    struct key_record *key = rr->u.key;
65172445Sassar
65272445Sassar	    printf ("flags %u, protocol %u, algorithm %u\n",
65372445Sassar		    key->flags, key->protocol, key->algorithm);
65472445Sassar	    break;
65572445Sassar	}
65655682Smarkm	default:
65755682Smarkm	    printf("\n");
65855682Smarkm	    break;
65955682Smarkm	}
66055682Smarkm    }
66155682Smarkm
66255682Smarkm    return 0;
66355682Smarkm}
66455682Smarkm#endif
665