resolve.c revision 107207
155682Smarkm/*
2102644Snectar * Copyright (c) 1995 - 2002 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
48107207SnectarRCSID("$Id: resolve.c,v 1.36.4.1 2002/10/21 14:48:15 joda 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:{
169107207Snectar	status = dn_expand(data, end_data, p + 2, host, sizeof(host));
170107207Snectar	if(status < 0){
171107207Snectar	    free(*rr);
172107207Snectar	    return -1;
173107207Snectar	}
174107207Snectar	if (status + 2 > size) {
175107207Snectar	    free(*rr);
176107207Snectar	    return -1;
177107207Snectar	}
178107207Snectar
179107207Snectar	(*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
180107207Snectar						strlen(host));
181107207Snectar	if((*rr)->u.mx == NULL) {
182107207Snectar	    free(*rr);
183107207Snectar	    return -1;
184107207Snectar	}
185107207Snectar	(*rr)->u.mx->preference = (p[0] << 8) | p[1];
186107207Snectar	strcpy((*rr)->u.mx->domain, host);
187107207Snectar	break;
188107207Snectar    }
189107207Snectar    case T_SRV:{
190107207Snectar	status = dn_expand(data, end_data, p + 6, host, sizeof(host));
191107207Snectar	if(status < 0){
192107207Snectar	    free(*rr);
193107207Snectar	    return -1;
194107207Snectar	}
195107207Snectar	if (status + 6 > size) {
196107207Snectar	    free(*rr);
197107207Snectar	    return -1;
198107207Snectar	}
199107207Snectar
200107207Snectar	(*rr)->u.srv =
201107207Snectar	    (struct srv_record*)malloc(sizeof(struct srv_record) +
202107207Snectar				       strlen(host));
203107207Snectar	if((*rr)->u.srv == NULL) {
204107207Snectar	    free(*rr);
205107207Snectar	    return -1;
206107207Snectar	}
207107207Snectar	(*rr)->u.srv->priority = (p[0] << 8) | p[1];
208107207Snectar	(*rr)->u.srv->weight = (p[2] << 8) | p[3];
209107207Snectar	(*rr)->u.srv->port = (p[4] << 8) | p[5];
210107207Snectar	strcpy((*rr)->u.srv->target, host);
211107207Snectar	break;
212107207Snectar    }
213107207Snectar    case T_TXT:{
214107207Snectar	if(size == 0 || size < *p + 1) {
215107207Snectar	    free(*rr);
216107207Snectar	    return -1;
217107207Snectar	}
218107207Snectar	(*rr)->u.txt = (char*)malloc(*p + 1);
219107207Snectar	if((*rr)->u.txt == NULL) {
220107207Snectar	    free(*rr);
221107207Snectar	    return -1;
222107207Snectar	}
223107207Snectar	strncpy((*rr)->u.txt, (char*)p + 1, *p);
224107207Snectar	(*rr)->u.txt[*p] = '\0';
225107207Snectar	break;
226107207Snectar    }
227107207Snectar    case T_KEY : {
228107207Snectar	size_t key_len;
229107207Snectar
230107207Snectar	if (size < 4) {
231107207Snectar	    free(*rr);
232107207Snectar	    return -1;
233107207Snectar	}
234107207Snectar
235107207Snectar	key_len = size - 4;
236107207Snectar	(*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
237107207Snectar	if ((*rr)->u.key == NULL) {
238107207Snectar	    free(*rr);
239107207Snectar	    return -1;
240107207Snectar	}
241107207Snectar
242107207Snectar	(*rr)->u.key->flags     = (p[0] << 8) | p[1];
243107207Snectar	(*rr)->u.key->protocol  = p[2];
244107207Snectar	(*rr)->u.key->algorithm = p[3];
245107207Snectar	(*rr)->u.key->key_len   = key_len;
246107207Snectar	memcpy ((*rr)->u.key->key_data, p + 4, key_len);
247107207Snectar	break;
248107207Snectar    }
249107207Snectar    case T_SIG : {
250107207Snectar	size_t sig_len;
251107207Snectar
252107207Snectar	if(size <= 18) {
253107207Snectar	    free(*rr);
254107207Snectar	    return -1;
255107207Snectar	}
256107207Snectar	status = dn_expand (data, end_data, p + 18, host, sizeof(host));
257107207Snectar	if (status < 0) {
258107207Snectar	    free(*rr);
259107207Snectar	    return -1;
260107207Snectar	}
261107207Snectar	if (status + 18 > size) {
262107207Snectar	    free(*rr);
263107207Snectar	    return -1;
264107207Snectar	}
265107207Snectar
266107207Snectar	/* the signer name is placed after the sig_data, to make it
267107207Snectar           easy to free this struture; the size calculation below
268107207Snectar           includes the zero-termination if the structure itself.
269107207Snectar	   don't you just love C?
270107207Snectar	*/
271107207Snectar	sig_len = size - 18 - status;
272107207Snectar	(*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
273107207Snectar			      + strlen(host) + sig_len);
274107207Snectar	if ((*rr)->u.sig == NULL) {
275107207Snectar	    free(*rr);
276107207Snectar	    return -1;
277107207Snectar	}
278107207Snectar	(*rr)->u.sig->type           = (p[0] << 8) | p[1];
279107207Snectar	(*rr)->u.sig->algorithm      = p[2];
280107207Snectar	(*rr)->u.sig->labels         = p[3];
281107207Snectar	(*rr)->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
282107207Snectar	    | (p[6] << 8) | p[7];
283107207Snectar	(*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
284107207Snectar	    | (p[10] << 8) | p[11];
285107207Snectar	(*rr)->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
286107207Snectar	    | (p[14] << 8) | p[15];
287107207Snectar	(*rr)->u.sig->key_tag        = (p[16] << 8) | p[17];
288107207Snectar	(*rr)->u.sig->sig_len        = sig_len;
289107207Snectar	memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len);
290107207Snectar	(*rr)->u.sig->signer         = &(*rr)->u.sig->sig_data[sig_len];
291107207Snectar	strcpy((*rr)->u.sig->signer, host);
292107207Snectar	break;
293107207Snectar    }
294107207Snectar
295107207Snectar    case T_CERT : {
296107207Snectar	size_t cert_len;
297107207Snectar
298107207Snectar	if (size < 5) {
299107207Snectar	    free(*rr);
300107207Snectar	    return -1;
301107207Snectar	}
302107207Snectar
303107207Snectar	cert_len = size - 5;
304107207Snectar	(*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
305107207Snectar	if ((*rr)->u.cert == NULL) {
306107207Snectar	    free(*rr);
307107207Snectar	    return -1;
308107207Snectar	}
309107207Snectar
310107207Snectar	(*rr)->u.cert->type      = (p[0] << 8) | p[1];
311107207Snectar	(*rr)->u.cert->tag       = (p[2] << 8) | p[3];
312107207Snectar	(*rr)->u.cert->algorithm = p[4];
313107207Snectar	(*rr)->u.cert->cert_len  = cert_len;
314107207Snectar	memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len);
315107207Snectar	break;
316107207Snectar    }
317107207Snectar    default:
318107207Snectar	(*rr)->u.data = (unsigned char*)malloc(size);
319107207Snectar	if(size != 0 && (*rr)->u.data == NULL) {
320107207Snectar	    free(*rr);
321107207Snectar	    return -1;
322107207Snectar	}
323107207Snectar	memcpy((*rr)->u.data, p, size);
324107207Snectar    }
325107207Snectar    *pp = p + size;
326107207Snectar    return 0;
327107207Snectar}
328107207Snectar
329103423Snectar#ifndef TEST_RESOLVE
330103423Snectarstatic
331103423Snectar#endif
332103423Snectarstruct dns_reply*
333103423Snectarparse_reply(const unsigned char *data, size_t len)
33455682Smarkm{
335102644Snectar    const unsigned char *p;
33655682Smarkm    int status;
337107207Snectar    int i;
338107207Snectar    char host[MAXDNAME];
339102644Snectar    const unsigned char *end_data = data + len;
34055682Smarkm    struct dns_reply *r;
34155682Smarkm    struct resource_record **rr;
34255682Smarkm
34355682Smarkm    r = calloc(1, sizeof(*r));
34455682Smarkm    if (r == NULL)
34555682Smarkm	return NULL;
34655682Smarkm
34755682Smarkm    p = data;
34855682Smarkm#if 0
34955682Smarkm    /* doesn't work on Crays */
35055682Smarkm    memcpy(&r->h, p, sizeof(HEADER));
35155682Smarkm    p += sizeof(HEADER);
35255682Smarkm#else
35355682Smarkm    memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
35455682Smarkm    p += 12;
35555682Smarkm#endif
356107207Snectar    if(ntohs(r->h.qdcount) != 1) {
357107207Snectar	free(r);
358107207Snectar	return NULL;
359107207Snectar    }
360102644Snectar    status = dn_expand(data, end_data, p, host, sizeof(host));
36155682Smarkm    if(status < 0){
36255682Smarkm	dns_free_data(r);
36355682Smarkm	return NULL;
36455682Smarkm    }
36555682Smarkm    r->q.domain = strdup(host);
36655682Smarkm    if(r->q.domain == NULL) {
36755682Smarkm	dns_free_data(r);
36855682Smarkm	return NULL;
36955682Smarkm    }
370102644Snectar    if (p + status + 4 > end_data) {
371102644Snectar	dns_free_data(r);
372102644Snectar	return NULL;
373102644Snectar    }
37455682Smarkm    p += status;
37555682Smarkm    r->q.type = (p[0] << 8 | p[1]);
37655682Smarkm    p += 2;
37755682Smarkm    r->q.class = (p[0] << 8 | p[1]);
37855682Smarkm    p += 2;
379107207Snectar
38055682Smarkm    rr = &r->head;
381107207Snectar    for(i = 0; i < ntohs(r->h.ancount); i++) {
382107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
38355682Smarkm	    dns_free_data(r);
38455682Smarkm	    return NULL;
38555682Smarkm	}
386107207Snectar	rr = &(*rr)->next;
387107207Snectar    }
388107207Snectar    for(i = 0; i < ntohs(r->h.nscount); i++) {
389107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
390102644Snectar	    dns_free_data(r);
391102644Snectar	    return NULL;
392102644Snectar	}
393107207Snectar	rr = &(*rr)->next;
394107207Snectar    }
395107207Snectar    for(i = 0; i < ntohs(r->h.arcount); i++) {
396107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
397102644Snectar	    dns_free_data(r);
398102644Snectar	    return NULL;
399102644Snectar	}
40055682Smarkm	rr = &(*rr)->next;
40155682Smarkm    }
40255682Smarkm    *rr = NULL;
40355682Smarkm    return r;
40455682Smarkm}
40555682Smarkm
40655682Smarkmstatic struct dns_reply *
40755682Smarkmdns_lookup_int(const char *domain, int rr_class, int rr_type)
40855682Smarkm{
40955682Smarkm    unsigned char reply[1024];
41055682Smarkm    int len;
411103423Snectar#ifdef HAVE_RES_NSEARCH
412103423Snectar    struct __res_state stat;
413103423Snectar    memset(&stat, 0, sizeof(stat));
414103423Snectar    if(res_ninit(&stat))
415103423Snectar	return NULL; /* is this the best we can do? */
416103423Snectar#elif defined(HAVE__RES)
41755682Smarkm    u_long old_options = 0;
418102644Snectar#endif
41955682Smarkm
42055682Smarkm    if (_resolve_debug) {
421103423Snectar#ifdef HAVE_RES_NSEARCH
422103423Snectar	stat.options |= RES_DEBUG;
423103423Snectar#elif defined(HAVE__RES)
42455682Smarkm        old_options = _res.options;
42555682Smarkm	_res.options |= RES_DEBUG;
426102644Snectar#endif
42755682Smarkm	fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain,
42872445Sassar		rr_class, dns_type_to_string(rr_type));
42955682Smarkm    }
430103423Snectar#ifdef HAVE_RES_NSEARCH
431103423Snectar    len = res_nsearch(&stat, domain, rr_class, rr_type, reply, sizeof(reply));
432103423Snectar#else
43355682Smarkm    len = res_search(domain, rr_class, rr_type, reply, sizeof(reply));
434103423Snectar#endif
43555682Smarkm    if (_resolve_debug) {
436103423Snectar#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
43755682Smarkm        _res.options = old_options;
438102644Snectar#endif
43955682Smarkm	fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
44072445Sassar		domain, rr_class, dns_type_to_string(rr_type), len);
44155682Smarkm    }
442103423Snectar#ifdef HAVE_RES_NSEARCH
443103423Snectar    res_nclose(&stat);
444103423Snectar#endif
445102644Snectar    if(len < 0) {
446102644Snectar	return NULL;
447102644Snectar    } else {
448102644Snectar	len = min(len, sizeof(reply));
449102644Snectar	return parse_reply(reply, len);
450102644Snectar    }
45155682Smarkm}
45255682Smarkm
45355682Smarkmstruct dns_reply *
45455682Smarkmdns_lookup(const char *domain, const char *type_name)
45555682Smarkm{
45655682Smarkm    int type;
45755682Smarkm
45872445Sassar    type = dns_string_to_type(type_name);
45955682Smarkm    if(type == -1) {
46055682Smarkm	if(_resolve_debug)
46155682Smarkm	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
46255682Smarkm		    type_name);
46355682Smarkm	return NULL;
46455682Smarkm    }
46555682Smarkm    return dns_lookup_int(domain, C_IN, type);
46655682Smarkm}
46755682Smarkm
46890926Snectarstatic int
46990926Snectarcompare_srv(const void *a, const void *b)
47090926Snectar{
47190926Snectar    const struct resource_record *const* aa = a, *const* bb = b;
47290926Snectar
47390926Snectar    if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
47490926Snectar	return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
47590926Snectar    return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
47690926Snectar}
47790926Snectar
47890926Snectar#ifndef HAVE_RANDOM
47990926Snectar#define random() rand()
48090926Snectar#endif
48190926Snectar
48290926Snectar/* try to rearrange the srv-records by the algorithm in RFC2782 */
48390926Snectarvoid
48490926Snectardns_srv_order(struct dns_reply *r)
48590926Snectar{
48690926Snectar    struct resource_record **srvs, **ss, **headp;
48790926Snectar    struct resource_record *rr;
48890926Snectar    int num_srv = 0;
48990926Snectar
49090926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
491102644Snectar    int state[256 / sizeof(int)];
492102644Snectar    char *oldstate;
49390926Snectar#endif
49490926Snectar
49590926Snectar    for(rr = r->head; rr; rr = rr->next)
49690926Snectar	if(rr->type == T_SRV)
49790926Snectar	    num_srv++;
49890926Snectar
49990926Snectar    if(num_srv == 0)
50090926Snectar	return;
50190926Snectar
50290926Snectar    srvs = malloc(num_srv * sizeof(*srvs));
50390926Snectar    if(srvs == NULL)
50490926Snectar	return; /* XXX not much to do here */
50590926Snectar
50690926Snectar    /* unlink all srv-records from the linked list and put them in
50790926Snectar       a vector */
50890926Snectar    for(ss = srvs, headp = &r->head; *headp; )
50990926Snectar	if((*headp)->type == T_SRV) {
51090926Snectar	    *ss = *headp;
51190926Snectar	    *headp = (*headp)->next;
51290926Snectar	    (*ss)->next = NULL;
51390926Snectar	    ss++;
51490926Snectar	} else
51590926Snectar	    headp = &(*headp)->next;
51690926Snectar
51790926Snectar    /* sort them by priority and weight */
51890926Snectar    qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
51990926Snectar
52090926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
521102644Snectar    oldstate = initstate(time(NULL), (char*)state, sizeof(state));
52290926Snectar#endif
52390926Snectar
52490926Snectar    headp = &r->head;
52590926Snectar
52690926Snectar    for(ss = srvs; ss < srvs + num_srv; ) {
52790926Snectar	int sum, rnd, count;
52890926Snectar	struct resource_record **ee, **tt;
52990926Snectar	/* find the last record with the same priority and count the
53090926Snectar           sum of all weights */
53190926Snectar	for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
53290926Snectar	    if(*tt == NULL)
53390926Snectar		continue;
53490926Snectar	    if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
53590926Snectar		break;
53690926Snectar	    sum += (*tt)->u.srv->weight;
53790926Snectar	}
53890926Snectar	ee = tt;
53990926Snectar	/* ss is now the first record of this priority and ee is the
54090926Snectar           first of the next */
54190926Snectar	while(ss < ee) {
54290926Snectar	    rnd = random() % (sum + 1);
54390926Snectar	    for(count = 0, tt = ss; ; tt++) {
54490926Snectar		if(*tt == NULL)
54590926Snectar		    continue;
54690926Snectar		count += (*tt)->u.srv->weight;
54790926Snectar		if(count >= rnd)
54890926Snectar		    break;
54990926Snectar	    }
55090926Snectar
55190926Snectar	    assert(tt < ee);
55290926Snectar
55390926Snectar	    /* insert the selected record at the tail (of the head) of
55490926Snectar               the list */
55590926Snectar	    (*tt)->next = *headp;
55690926Snectar	    *headp = *tt;
55790926Snectar	    headp = &(*tt)->next;
55890926Snectar	    sum -= (*tt)->u.srv->weight;
55990926Snectar	    *tt = NULL;
56090926Snectar	    while(ss < ee && *ss == NULL)
56190926Snectar		ss++;
56290926Snectar	}
56390926Snectar    }
56490926Snectar
56590926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
56690926Snectar    setstate(oldstate);
56790926Snectar#endif
56890926Snectar    free(srvs);
56990926Snectar    return;
57090926Snectar}
57190926Snectar
57255682Smarkm#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
57355682Smarkm
57455682Smarkmstruct dns_reply *
57555682Smarkmdns_lookup(const char *domain, const char *type_name)
57655682Smarkm{
57755682Smarkm    return NULL;
57855682Smarkm}
57955682Smarkm
58055682Smarkmvoid
58155682Smarkmdns_free_data(struct dns_reply *r)
58255682Smarkm{
58355682Smarkm}
58455682Smarkm
58590926Snectarvoid
58690926Snectardns_srv_order(struct dns_reply *r)
58790926Snectar{
58890926Snectar}
58990926Snectar
59055682Smarkm#endif
59155682Smarkm
59255682Smarkm#ifdef TEST
59355682Smarkmint
59455682Smarkmmain(int argc, char **argv)
59555682Smarkm{
59655682Smarkm    struct dns_reply *r;
59755682Smarkm    struct resource_record *rr;
59855682Smarkm    r = dns_lookup(argv[1], argv[2]);
59955682Smarkm    if(r == NULL){
60055682Smarkm	printf("No reply.\n");
60155682Smarkm	return 1;
60255682Smarkm    }
60390926Snectar    if(r->q.type == T_SRV)
60490926Snectar	dns_srv_order(r);
60590926Snectar
60655682Smarkm    for(rr = r->head; rr;rr=rr->next){
607107207Snectar	printf("%-30s %-5s %-6d ", rr->domain, dns_type_to_string(rr->type), rr->ttl);
60855682Smarkm	switch(rr->type){
60955682Smarkm	case T_NS:
61072445Sassar	case T_CNAME:
61172445Sassar	case T_PTR:
61255682Smarkm	    printf("%s\n", (char*)rr->u.data);
61355682Smarkm	    break;
61455682Smarkm	case T_A:
61572445Sassar	    printf("%s\n", inet_ntoa(*rr->u.a));
61655682Smarkm	    break;
61755682Smarkm	case T_MX:
61855682Smarkm	case T_AFSDB:{
61972445Sassar	    printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain);
62055682Smarkm	    break;
62155682Smarkm	}
62255682Smarkm	case T_SRV:{
62372445Sassar	    struct srv_record *srv = rr->u.srv;
62455682Smarkm	    printf("%d %d %d %s\n", srv->priority, srv->weight,
62555682Smarkm		   srv->port, srv->target);
62655682Smarkm	    break;
62755682Smarkm	}
62872445Sassar	case T_TXT: {
62972445Sassar	    printf("%s\n", rr->u.txt);
63072445Sassar	    break;
63172445Sassar	}
63272445Sassar	case T_SIG : {
63372445Sassar	    struct sig_record *sig = rr->u.sig;
63472445Sassar	    const char *type_string = dns_type_to_string (sig->type);
63572445Sassar
63672445Sassar	    printf ("type %u (%s), algorithm %u, labels %u, orig_ttl %u, sig_expiration %u, sig_inception %u, key_tag %u, signer %s\n",
63772445Sassar		    sig->type, type_string ? type_string : "",
63872445Sassar		    sig->algorithm, sig->labels, sig->orig_ttl,
63972445Sassar		    sig->sig_expiration, sig->sig_inception, sig->key_tag,
64072445Sassar		    sig->signer);
64172445Sassar	    break;
64272445Sassar	}
64372445Sassar	case T_KEY : {
64472445Sassar	    struct key_record *key = rr->u.key;
64572445Sassar
64672445Sassar	    printf ("flags %u, protocol %u, algorithm %u\n",
64772445Sassar		    key->flags, key->protocol, key->algorithm);
64872445Sassar	    break;
64972445Sassar	}
65055682Smarkm	default:
65155682Smarkm	    printf("\n");
65255682Smarkm	    break;
65355682Smarkm	}
65455682Smarkm    }
65555682Smarkm
65655682Smarkm    return 0;
65755682Smarkm}
65855682Smarkm#endif
659