resolve.c revision 103423
14Srgrimes/*
24Srgrimes * Copyright (c) 1995 - 2002 Kungliga Tekniska H�gskolan
34Srgrimes * (Royal Institute of Technology, Stockholm, Sweden).
44Srgrimes * All rights reserved.
54Srgrimes *
64Srgrimes * Redistribution and use in source and binary forms, with or without
74Srgrimes * modification, are permitted provided that the following conditions
85512Sjoerg * are met:
92838Sdg *
102838Sdg * 1. Redistributions of source code must retain the above copyright
112838Sdg *    notice, this list of conditions and the following disclaimer.
125512Sjoerg *
135512Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
142838Sdg *    notice, this list of conditions and the following disclaimer in the
155417Sjoerg *    documentation and/or other materials provided with the distribution.
162838Sdg *
174Srgrimes * 3. Neither the name of the Institute nor the names of its contributors
184Srgrimes *    may be used to endorse or promote products derived from this software
194Srgrimes *    without specific prior written permission.
204Srgrimes *
214Srgrimes * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
224Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
234Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
244Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
254Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
264Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
274Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
284Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
294Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
304Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
314Srgrimes * SUCH DAMAGE.
324Srgrimes */
334Srgrimes
344Srgrimes#ifdef HAVE_CONFIG_H
354Srgrimes#include <config.h>
364Srgrimes#endif
374Srgrimes#include "roken.h"
384Srgrimes#ifdef HAVE_ARPA_NAMESER_H
394Srgrimes#include <arpa/nameser.h>
404Srgrimes#endif
414Srgrimes#ifdef HAVE_RESOLV_H
424Srgrimes#include <resolv.h>
434Srgrimes#endif
444Srgrimes#include "resolve.h"
45471Srgrimes
468876Srgrimes#include <assert.h>
474Srgrimes
484SrgrimesRCSID("$Id: resolve.c,v 1.36 2002/09/09 21:39:19 joda Exp $");
494Srgrimes
501110Salm#undef HAVE_RES_NSEARCH
511110Salm#if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)
521110Salm
531110Salm#define DECL(X) {#X, T_##X}
544Srgrimes
554Srgrimesstatic struct stot{
561110Salm    const char *name;
571110Salm    int type;
581110Salm}stot[] = {
591110Salm    DECL(A),
601110Salm    DECL(NS),
611110Salm    DECL(CNAME),
621110Salm    DECL(SOA),
631110Salm    DECL(PTR),
646724Sbde    DECL(MX),
651110Salm    DECL(TXT),
661110Salm    DECL(AFSDB),
676724Sbde    DECL(SIG),
681110Salm    DECL(KEY),
691110Salm    DECL(SRV),
701110Salm    DECL(NAPTR),
712838Sdg    {NULL, 	0}
721110Salm};
733705Swollman
743705Swollmanint _resolve_debug = 0;
752056Swollman
762056Swollmanint
772056Swollmandns_string_to_type(const char *name)
782056Swollman{
792056Swollman    struct stot *p = stot;
805417Sjoerg    for(p = stot; p->name; p++)
813085Sphk	if(strcasecmp(name, p->name) == 0)
823085Sphk	    return p->type;
833085Sphk    return -1;
843085Sphk}
854Srgrimes
863705Swollmanconst char *
873705Swollmandns_type_to_string(int type)
885512Sjoerg{
895512Sjoerg    struct stot *p = stot;
903705Swollman    for(p = stot; p->name; p++)
914088Sjkh	if(type == p->type)
924088Sjkh	    return p->name;
934088Sjkh    return NULL;
944088Sjkh}
954088Sjkh
964088Sjkhvoid
974088Sjkhdns_free_data(struct dns_reply *r)
984088Sjkh{
994088Sjkh    struct resource_record *rr;
1005512Sjoerg    if(r->q.domain)
1017780Swollman	free(r->q.domain);
1027780Swollman    for(rr = r->head; rr;){
1034088Sjkh	struct resource_record *tmp = rr;
1044088Sjkh	if(rr->domain)
1054088Sjkh	    free(rr->domain);
1064088Sjkh	if(rr->u.data)
1074088Sjkh	    free(rr->u.data);
1084088Sjkh	rr = rr->next;
1094088Sjkh	free(tmp);
1104088Sjkh    }
1115512Sjoerg    free (r);
1127780Swollman}
1137780Swollman
1144088Sjkh#ifndef TEST_RESOLVE
1154088Sjkhstatic
1164088Sjkh#endif
1174088Sjkhstruct dns_reply*
1184088Sjkhparse_reply(const unsigned char *data, size_t len)
1194088Sjkh{
1204088Sjkh    const unsigned char *p;
1214088Sjkh    char host[128];
1224088Sjkh    int status;
1234088Sjkh    const unsigned char *end_data = data + len;
1244088Sjkh    struct dns_reply *r;
1254088Sjkh    struct resource_record **rr;
1264088Sjkh
1274088Sjkh    r = calloc(1, sizeof(*r));
1284088Sjkh    if (r == NULL)
1294088Sjkh	return NULL;
1304088Sjkh
1314088Sjkh    p = data;
1324088Sjkh#if 0
1334088Sjkh    /* doesn't work on Crays */
1344088Sjkh    memcpy(&r->h, p, sizeof(HEADER));
1354088Sjkh    p += sizeof(HEADER);
1364088Sjkh#else
1374088Sjkh    memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
1384088Sjkh    p += 12;
1394088Sjkh#endif
1404088Sjkh    status = dn_expand(data, end_data, p, host, sizeof(host));
1414088Sjkh    if(status < 0){
1424088Sjkh	dns_free_data(r);
1434088Sjkh	return NULL;
1444088Sjkh    }
1454088Sjkh    r->q.domain = strdup(host);
1464088Sjkh    if(r->q.domain == NULL) {
1474088Sjkh	dns_free_data(r);
1484088Sjkh	return NULL;
1494088Sjkh    }
1504088Sjkh    if (p + status + 4 > end_data) {
1514088Sjkh	dns_free_data(r);
1524088Sjkh	return NULL;
1534088Sjkh    }
1544088Sjkh    p += status;
1554088Sjkh    r->q.type = (p[0] << 8 | p[1]);
1564088Sjkh    p += 2;
1574088Sjkh    r->q.class = (p[0] << 8 | p[1]);
1584088Sjkh    p += 2;
1594088Sjkh    rr = &r->head;
1606724Sbde    while(p < end_data){
1614Srgrimes	int type, class, ttl, size;
162878Sache	status = dn_expand(data, end_data, p, host, sizeof(host));
163878Sache	if(status < 0){
1644Srgrimes	    dns_free_data(r);
1652838Sdg	    return NULL;
1662838Sdg	}
1672838Sdg	if (p + status + 10 > end_data) {
1682838Sdg	    dns_free_data(r);
1692838Sdg	    return NULL;
1702838Sdg	}
1715417Sjoerg	p += status;
1725417Sjoerg	type = (p[0] << 8) | p[1];
1735417Sjoerg	p += 2;
1745417Sjoerg	class = (p[0] << 8) | p[1];
1755417Sjoerg	p += 2;
176878Sache	ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
177878Sache	p += 4;
178863Sache	size = (p[0] << 8) | p[1];
1792838Sdg	p += 2;
1801110Salm
1811110Salm	if (p + size > end_data) {
1821110Salm	    dns_free_data(r);
1831110Salm	    return NULL;
1841110Salm	}
1851110Salm
1861110Salm	*rr = (struct resource_record*)calloc(1,
1871110Salm					      sizeof(struct resource_record));
1881110Salm	if(*rr == NULL) {
1891110Salm	    dns_free_data(r);
190863Sache	    return NULL;
1911110Salm	}
1921110Salm	(*rr)->domain = strdup(host);
1931110Salm	if((*rr)->domain == NULL) {
1941110Salm	    dns_free_data(r);
1951110Salm	    return NULL;
1961110Salm	}
197874Sache	(*rr)->type = type;
1981110Salm	(*rr)->class = class;
1994Srgrimes	(*rr)->ttl = ttl;
2004Srgrimes	(*rr)->size = size;
201890Sache	switch(type){
202890Sache	case T_NS:
203890Sache	case T_CNAME:
204890Sache	case T_PTR:
205890Sache	    status = dn_expand(data, end_data, p, host, sizeof(host));
206890Sache	    if(status < 0){
207890Sache		dns_free_data(r);
2081233Sache		return NULL;
209874Sache	    }
210890Sache	    (*rr)->u.txt = strdup(host);
211890Sache	    if((*rr)->u.txt == NULL) {
212890Sache		dns_free_data(r);
213890Sache		return NULL;
214890Sache	    }
215890Sache	    break;
2164Srgrimes	case T_MX:
2174Srgrimes	case T_AFSDB:{
2181110Salm	    status = dn_expand(data, end_data, p + 2, host, sizeof(host));
2195512Sjoerg	    if(status < 0){
2204Srgrimes		dns_free_data(r);
2214Srgrimes		return NULL;
2224Srgrimes	    }
2231110Salm	    if (status + 2 > size) {
2244Srgrimes		dns_free_data(r);
2254Srgrimes		return NULL;
2264Srgrimes	    }
2271110Salm
2284Srgrimes	    (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
2294Srgrimes						    strlen(host));
2301110Salm	    if((*rr)->u.mx == NULL) {
2314Srgrimes		dns_free_data(r);
2322838Sdg		return NULL;
2334Srgrimes	    }
2344Srgrimes	    (*rr)->u.mx->preference = (p[0] << 8) | p[1];
2354Srgrimes	    strcpy((*rr)->u.mx->domain, host);
2364Srgrimes	    break;
2374Srgrimes	}
2384Srgrimes	case T_SRV:{
2392838Sdg	    status = dn_expand(data, end_data, p + 6, host, sizeof(host));
2402838Sdg	    if(status < 0){
2415417Sjoerg		dns_free_data(r);
2422838Sdg		return NULL;
2432838Sdg	    }
2443705Swollman	    if (status + 6 > size) {
2454Srgrimes		dns_free_data(r);
2464Srgrimes		return NULL;
2474Srgrimes	    }
2484Srgrimes
2494Srgrimes	    (*rr)->u.srv =
2504Srgrimes		(struct srv_record*)malloc(sizeof(struct srv_record) +
2514Srgrimes					   strlen(host));
2524Srgrimes	    if((*rr)->u.srv == NULL) {
2534Srgrimes		dns_free_data(r);
2544Srgrimes		return NULL;
2554Srgrimes	    }
2562838Sdg	    (*rr)->u.srv->priority = (p[0] << 8) | p[1];
2572838Sdg	    (*rr)->u.srv->weight = (p[2] << 8) | p[3];
2582838Sdg	    (*rr)->u.srv->port = (p[4] << 8) | p[5];
2592838Sdg	    strcpy((*rr)->u.srv->target, host);
2602838Sdg	    break;
2612838Sdg	}
2622838Sdg	case T_TXT:{
2632838Sdg	    (*rr)->u.txt = (char*)malloc(size + 1);
2647643Srgrimes	    if((*rr)->u.txt == NULL) {
2652838Sdg		dns_free_data(r);
2661110Salm		return NULL;
2672838Sdg	    }
2682838Sdg	    strncpy((*rr)->u.txt, (char*)p + 1, *p);
2692838Sdg	    (*rr)->u.txt[*p] = 0;
2702838Sdg	    break;
2712838Sdg	}
2722838Sdg	case T_KEY : {
2732838Sdg	    size_t key_len;
2746724Sbde
2756724Sbde	    if (size < 4) {
2762838Sdg		dns_free_data (r);
2772838Sdg		return NULL;
2782838Sdg	    }
2792838Sdg
2802838Sdg	    key_len = size - 4;
2812838Sdg	    (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
2822838Sdg	    if ((*rr)->u.key == NULL) {
2832838Sdg		dns_free_data (r);
2842838Sdg		return NULL;
2852838Sdg	    }
2862838Sdg
2872838Sdg	    (*rr)->u.key->flags     = (p[0] << 8) | p[1];
2882838Sdg	    (*rr)->u.key->protocol  = p[2];
2892838Sdg	    (*rr)->u.key->algorithm = p[3];
2902838Sdg	    (*rr)->u.key->key_len   = key_len;
2917090Sbde	    memcpy ((*rr)->u.key->key_data, p + 4, key_len);
2922838Sdg	    break;
2932838Sdg	}
2942838Sdg	case T_SIG : {
2952838Sdg	    size_t sig_len;
296879Swollman
2972838Sdg	    status = dn_expand (data, end_data, p + 18, host, sizeof(host));
298879Swollman	    if (status < 0) {
2992838Sdg		dns_free_data (r);
3004Srgrimes		return NULL;
3014Srgrimes	    }
3024Srgrimes	    if (status + 18 > size) {
3034Srgrimes		dns_free_data(r);
3044Srgrimes		return NULL;
3054Srgrimes	    }
3064Srgrimes
3074Srgrimes	    sig_len = len - 18 - status;
3084Srgrimes	    (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
3094Srgrimes				  + strlen(host) + sig_len);
3104Srgrimes	    if ((*rr)->u.sig == NULL) {
3114Srgrimes		dns_free_data (r);
3124Srgrimes		return NULL;
3134Srgrimes	    }
3144Srgrimes	    (*rr)->u.sig->type           = (p[0] << 8) | p[1];
3154Srgrimes	    (*rr)->u.sig->algorithm      = p[2];
3164Srgrimes	    (*rr)->u.sig->labels         = p[3];
3174Srgrimes	    (*rr)->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
3184Srgrimes		| (p[6] << 8) | p[7];
3194Srgrimes	    (*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
3204Srgrimes		| (p[10] << 8) | p[11];
3214Srgrimes	    (*rr)->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
3224Srgrimes		| (p[14] << 8) | p[15];
3234Srgrimes	    (*rr)->u.sig->key_tag        = (p[16] << 8) | p[17];
3244Srgrimes	    (*rr)->u.sig->sig_len        = sig_len;
3254Srgrimes	    memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len);
3264Srgrimes	    (*rr)->u.sig->signer         = &(*rr)->u.sig->sig_data[sig_len];
3274Srgrimes	    strcpy((*rr)->u.sig->signer, host);
3284Srgrimes	    break;
3294Srgrimes	}
3302838Sdg
3312838Sdg	case T_CERT : {
3324Srgrimes	    size_t cert_len;
3332838Sdg
334798Swollman	    if (size < 5) {
3354Srgrimes		dns_free_data(r);
3362838Sdg		return NULL;
337798Swollman	    }
3384Srgrimes
3395512Sjoerg	    cert_len = size - 5;
3405512Sjoerg	    (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
3415512Sjoerg	    if ((*rr)->u.cert == NULL) {
3425512Sjoerg		dns_free_data (r);
3435512Sjoerg		return NULL;
3445512Sjoerg	    }
3453705Swollman
3463705Swollman	    (*rr)->u.cert->type      = (p[0] << 8) | p[1];
3473705Swollman	    (*rr)->u.cert->tag       = (p[2] << 8) | p[3];
3483705Swollman	    (*rr)->u.cert->algorithm = p[4];
3493705Swollman	    (*rr)->u.cert->cert_len  = cert_len;
3503705Swollman	    memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len);
3515512Sjoerg	    break;
3525512Sjoerg	}
3533705Swollman	default:
3543705Swollman	    (*rr)->u.data = (unsigned char*)malloc(size);
3553705Swollman	    if(size != 0 && (*rr)->u.data == NULL) {
3563705Swollman		dns_free_data(r);
3573705Swollman		return NULL;
3585512Sjoerg	    }
3595512Sjoerg	    memcpy((*rr)->u.data, p, size);
3603705Swollman	}
3613705Swollman	p += size;
3623705Swollman	rr = &(*rr)->next;
3633705Swollman    }
3645417Sjoerg    *rr = NULL;
3655417Sjoerg    return r;
3665417Sjoerg}
3675417Sjoerg
3685417Sjoergstatic struct dns_reply *
3697393Srgrimesdns_lookup_int(const char *domain, int rr_class, int rr_type)
3705417Sjoerg{
3715417Sjoerg    unsigned char reply[1024];
3725417Sjoerg    int len;
3738876Srgrimes#ifdef HAVE_RES_NSEARCH
3745417Sjoerg    struct __res_state stat;
3755417Sjoerg    memset(&stat, 0, sizeof(stat));
3765417Sjoerg    if(res_ninit(&stat))
3775417Sjoerg	return NULL; /* is this the best we can do? */
3785417Sjoerg#elif defined(HAVE__RES)
3795417Sjoerg    u_long old_options = 0;
3805417Sjoerg#endif
3818876Srgrimes
3825417Sjoerg    if (_resolve_debug) {
3835417Sjoerg#ifdef HAVE_RES_NSEARCH
3845417Sjoerg	stat.options |= RES_DEBUG;
3855417Sjoerg#elif defined(HAVE__RES)
3865417Sjoerg        old_options = _res.options;
3875417Sjoerg	_res.options |= RES_DEBUG;
3885417Sjoerg#endif
3895417Sjoerg	fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain,
3905417Sjoerg		rr_class, dns_type_to_string(rr_type));
3915417Sjoerg    }
3925417Sjoerg#ifdef HAVE_RES_NSEARCH
3935417Sjoerg    len = res_nsearch(&stat, domain, rr_class, rr_type, reply, sizeof(reply));
3945417Sjoerg#else
3955417Sjoerg    len = res_search(domain, rr_class, rr_type, reply, sizeof(reply));
3965417Sjoerg#endif
3975417Sjoerg    if (_resolve_debug) {
3985417Sjoerg#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
3995417Sjoerg        _res.options = old_options;
4005417Sjoerg#endif
4015417Sjoerg	fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
4025417Sjoerg		domain, rr_class, dns_type_to_string(rr_type), len);
4035417Sjoerg    }
4045417Sjoerg#ifdef HAVE_RES_NSEARCH
4055417Sjoerg    res_nclose(&stat);
4065417Sjoerg#endif
4075417Sjoerg    if(len < 0) {
4085417Sjoerg	return NULL;
4095417Sjoerg    } else {
4105417Sjoerg	len = min(len, sizeof(reply));
4115417Sjoerg	return parse_reply(reply, len);
4125417Sjoerg    }
4135417Sjoerg}
4145417Sjoerg
4155417Sjoergstruct dns_reply *
4165417Sjoergdns_lookup(const char *domain, const char *type_name)
4175417Sjoerg{
4185417Sjoerg    int type;
4195417Sjoerg
4205417Sjoerg    type = dns_string_to_type(type_name);
4215417Sjoerg    if(type == -1) {
4225417Sjoerg	if(_resolve_debug)
4235417Sjoerg	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
4245417Sjoerg		    type_name);
4255417Sjoerg	return NULL;
4265417Sjoerg    }
4275417Sjoerg    return dns_lookup_int(domain, C_IN, type);
4285417Sjoerg}
4295417Sjoerg
4305417Sjoergstatic int
4317393Srgrimescompare_srv(const void *a, const void *b)
4325417Sjoerg{
4335417Sjoerg    const struct resource_record *const* aa = a, *const* bb = b;
4345417Sjoerg
4355417Sjoerg    if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
4365417Sjoerg	return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
4375417Sjoerg    return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
4385417Sjoerg}
4395417Sjoerg
4405417Sjoerg#ifndef HAVE_RANDOM
4415417Sjoerg#define random() rand()
4425417Sjoerg#endif
4435417Sjoerg
4445417Sjoerg/* try to rearrange the srv-records by the algorithm in RFC2782 */
4455417Sjoergvoid
4465417Sjoergdns_srv_order(struct dns_reply *r)
4475417Sjoerg{
4485417Sjoerg    struct resource_record **srvs, **ss, **headp;
4495417Sjoerg    struct resource_record *rr;
4505417Sjoerg    int num_srv = 0;
4515417Sjoerg
4525417Sjoerg#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
4535417Sjoerg    int state[256 / sizeof(int)];
4545417Sjoerg    char *oldstate;
4555417Sjoerg#endif
4565417Sjoerg
4575417Sjoerg    for(rr = r->head; rr; rr = rr->next)
4585417Sjoerg	if(rr->type == T_SRV)
4595417Sjoerg	    num_srv++;
4605417Sjoerg
4615417Sjoerg    if(num_srv == 0)
4625417Sjoerg	return;
4635417Sjoerg
4645417Sjoerg    srvs = malloc(num_srv * sizeof(*srvs));
4655417Sjoerg    if(srvs == NULL)
4665417Sjoerg	return; /* XXX not much to do here */
4675417Sjoerg
4685417Sjoerg    /* unlink all srv-records from the linked list and put them in
4695417Sjoerg       a vector */
4705417Sjoerg    for(ss = srvs, headp = &r->head; *headp; )
4715417Sjoerg	if((*headp)->type == T_SRV) {
4725417Sjoerg	    *ss = *headp;
4735417Sjoerg	    *headp = (*headp)->next;
4745417Sjoerg	    (*ss)->next = NULL;
4755417Sjoerg	    ss++;
4765417Sjoerg	} else
4775417Sjoerg	    headp = &(*headp)->next;
4785417Sjoerg
4795417Sjoerg    /* sort them by priority and weight */
4807090Sbde    qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
4815417Sjoerg
4825417Sjoerg#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
4837090Sbde    oldstate = initstate(time(NULL), (char*)state, sizeof(state));
4847090Sbde#endif
4857090Sbde
4867090Sbde    headp = &r->head;
4877090Sbde
4887090Sbde    for(ss = srvs; ss < srvs + num_srv; ) {
4897090Sbde	int sum, rnd, count;
4907090Sbde	struct resource_record **ee, **tt;
4917090Sbde	/* find the last record with the same priority and count the
4927090Sbde           sum of all weights */
4935417Sjoerg	for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
4945417Sjoerg	    if(*tt == NULL)
4955417Sjoerg		continue;
4965417Sjoerg	    if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
4975417Sjoerg		break;
4985417Sjoerg	    sum += (*tt)->u.srv->weight;
4995417Sjoerg	}
5005417Sjoerg	ee = tt;
5015417Sjoerg	/* ss is now the first record of this priority and ee is the
5025417Sjoerg           first of the next */
5035417Sjoerg	while(ss < ee) {
5044Srgrimes	    rnd = random() % (sum + 1);
5054Srgrimes	    for(count = 0, tt = ss; ; tt++) {
5064Srgrimes		if(*tt == NULL)
5074Srgrimes		    continue;
5084Srgrimes		count += (*tt)->u.srv->weight;
5094Srgrimes		if(count >= rnd)
5104Srgrimes		    break;
5112838Sdg	    }
5125417Sjoerg
5134Srgrimes	    assert(tt < ee);
5144Srgrimes
5154Srgrimes	    /* insert the selected record at the tail (of the head) of
5164Srgrimes               the list */
5177393Srgrimes	    (*tt)->next = *headp;
5184Srgrimes	    *headp = *tt;
5194Srgrimes	    headp = &(*tt)->next;
5204Srgrimes	    sum -= (*tt)->u.srv->weight;
5213705Swollman	    *tt = NULL;
5224Srgrimes	    while(ss < ee && *ss == NULL)
5234Srgrimes		ss++;
5247780Swollman	}
5257780Swollman    }
5267780Swollman
5277780Swollman#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
528826Salm    setstate(oldstate);
5292838Sdg#endif
530826Salm    free(srvs);
5312838Sdg    return;
532826Salm}
5334Srgrimes
5345417Sjoerg#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
5355417Sjoerg
5365417Sjoergstruct dns_reply *
5374Srgrimesdns_lookup(const char *domain, const char *type_name)
5384Srgrimes{
5394Srgrimes    return NULL;
5405512Sjoerg}
5414Srgrimes
5424Srgrimesvoid
5434Srgrimesdns_free_data(struct dns_reply *r)
5444Srgrimes{
5454Srgrimes}
5464Srgrimes
5472838Sdgvoid
5485417Sjoergdns_srv_order(struct dns_reply *r)
5494Srgrimes{
5502838Sdg}
5514Srgrimes
5524Srgrimes#endif
5534Srgrimes
5544Srgrimes#ifdef TEST
5557643Srgrimesint
5561110Salmmain(int argc, char **argv)
5575417Sjoerg{
5587945Sjulian    struct dns_reply *r;
5597945Sjulian    struct resource_record *rr;
5607945Sjulian    r = dns_lookup(argv[1], argv[2]);
5617945Sjulian    if(r == NULL){
5624Srgrimes	printf("No reply.\n");
5634Srgrimes	return 1;
5644Srgrimes    }
5654Srgrimes    if(r->q.type == T_SRV)
5664Srgrimes	dns_srv_order(r);
5672838Sdg
5682838Sdg    for(rr = r->head; rr;rr=rr->next){
5694Srgrimes	printf("%s %s %d ", rr->domain, dns_type_to_string(rr->type), rr->ttl);
5704Srgrimes	switch(rr->type){
5711110Salm	case T_NS:
5721110Salm	case T_CNAME:
5731110Salm	case T_PTR:
5741110Salm	    printf("%s\n", (char*)rr->u.data);
5751110Salm	    break;
5761110Salm	case T_A:
5771110Salm	    printf("%s\n", inet_ntoa(*rr->u.a));
5781110Salm	    break;
5795417Sjoerg	case T_MX:
5801110Salm	case T_AFSDB:{
5811110Salm	    printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain);
5821110Salm	    break;
5831110Salm	}
5841110Salm	case T_SRV:{
5851110Salm	    struct srv_record *srv = rr->u.srv;
5861110Salm	    printf("%d %d %d %s\n", srv->priority, srv->weight,
5871110Salm		   srv->port, srv->target);
5884Srgrimes	    break;
5891110Salm	}
5901110Salm	case T_TXT: {
5915512Sjoerg	    printf("%s\n", rr->u.txt);
5921110Salm	    break;
5931110Salm	}
5941231Salm	case T_SIG : {
5951110Salm	    struct sig_record *sig = rr->u.sig;
5961110Salm	    const char *type_string = dns_type_to_string (sig->type);
5974874Sjkh
5984874Sjkh	    printf ("type %u (%s), algorithm %u, labels %u, orig_ttl %u, sig_expiration %u, sig_inception %u, key_tag %u, signer %s\n",
5997643Srgrimes		    sig->type, type_string ? type_string : "",
6007643Srgrimes		    sig->algorithm, sig->labels, sig->orig_ttl,
6017643Srgrimes		    sig->sig_expiration, sig->sig_inception, sig->key_tag,
6027643Srgrimes		    sig->signer);
6037643Srgrimes	    break;
6047643Srgrimes	}
6058310Sjoerg	case T_KEY : {
6061110Salm	    struct key_record *key = rr->u.key;
6078876Srgrimes
6081231Salm	    printf ("flags %u, protocol %u, algorithm %u\n",
6091110Salm		    key->flags, key->protocol, key->algorithm);
6104Srgrimes	    break;
611464Sjkh	}
6124Srgrimes	default:
6134Srgrimes	    printf("\n");
6142838Sdg	    break;
6152841Sjoerg	}
6165417Sjoerg    }
6175417Sjoerg
6185417Sjoerg    return 0;
6195417Sjoerg}
6207393Srgrimes#endif
6215417Sjoerg