xref: /freebsd-src/crypto/heimdal/lib/roken/resolve.c (revision 8373020d34ceb1ac55d8f43333c1ca3680185b39)
1b528cefcSMark Murray /*
2*8373020dSJacques Vidrine  * Copyright (c) 1995 - 2002 Kungliga Tekniska H�gskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #ifdef HAVE_CONFIG_H
35b528cefcSMark Murray #include <config.h>
36b528cefcSMark Murray #endif
37b528cefcSMark Murray #include "roken.h"
38b528cefcSMark Murray #ifdef HAVE_ARPA_NAMESER_H
39b528cefcSMark Murray #include <arpa/nameser.h>
40b528cefcSMark Murray #endif
41b528cefcSMark Murray #ifdef HAVE_RESOLV_H
42b528cefcSMark Murray #include <resolv.h>
43b528cefcSMark Murray #endif
44b528cefcSMark Murray #include "resolve.h"
45b528cefcSMark Murray 
464137ff4cSJacques Vidrine #include <assert.h>
474137ff4cSJacques Vidrine 
48*8373020dSJacques Vidrine RCSID("$Id: resolve.c,v 1.33 2002/08/28 20:07:24 joda Exp $");
49b528cefcSMark Murray 
50b528cefcSMark Murray #if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND)
51b528cefcSMark Murray 
52b528cefcSMark Murray #define DECL(X) {#X, T_##X}
53b528cefcSMark Murray 
54b528cefcSMark Murray static struct stot{
55b528cefcSMark Murray     const char *name;
56b528cefcSMark Murray     int type;
57b528cefcSMark Murray }stot[] = {
58b528cefcSMark Murray     DECL(A),
59b528cefcSMark Murray     DECL(NS),
60b528cefcSMark Murray     DECL(CNAME),
615e9cd1aeSAssar Westerlund     DECL(SOA),
62b528cefcSMark Murray     DECL(PTR),
63b528cefcSMark Murray     DECL(MX),
64b528cefcSMark Murray     DECL(TXT),
65b528cefcSMark Murray     DECL(AFSDB),
665e9cd1aeSAssar Westerlund     DECL(SIG),
675e9cd1aeSAssar Westerlund     DECL(KEY),
68b528cefcSMark Murray     DECL(SRV),
695e9cd1aeSAssar Westerlund     DECL(NAPTR),
70b528cefcSMark Murray     {NULL, 	0}
71b528cefcSMark Murray };
72b528cefcSMark Murray 
735e9cd1aeSAssar Westerlund int _resolve_debug = 0;
74b528cefcSMark Murray 
755e9cd1aeSAssar Westerlund int
765e9cd1aeSAssar Westerlund dns_string_to_type(const char *name)
77b528cefcSMark Murray {
78b528cefcSMark Murray     struct stot *p = stot;
79b528cefcSMark Murray     for(p = stot; p->name; p++)
80b528cefcSMark Murray 	if(strcasecmp(name, p->name) == 0)
81b528cefcSMark Murray 	    return p->type;
82b528cefcSMark Murray     return -1;
83b528cefcSMark Murray }
84b528cefcSMark Murray 
855e9cd1aeSAssar Westerlund const char *
865e9cd1aeSAssar Westerlund dns_type_to_string(int type)
87b528cefcSMark Murray {
88b528cefcSMark Murray     struct stot *p = stot;
89b528cefcSMark Murray     for(p = stot; p->name; p++)
90b528cefcSMark Murray 	if(type == p->type)
91b528cefcSMark Murray 	    return p->name;
92b528cefcSMark Murray     return NULL;
93b528cefcSMark Murray }
94b528cefcSMark Murray 
95b528cefcSMark Murray void
96b528cefcSMark Murray dns_free_data(struct dns_reply *r)
97b528cefcSMark Murray {
98b528cefcSMark Murray     struct resource_record *rr;
99b528cefcSMark Murray     if(r->q.domain)
100b528cefcSMark Murray 	free(r->q.domain);
101b528cefcSMark Murray     for(rr = r->head; rr;){
102b528cefcSMark Murray 	struct resource_record *tmp = rr;
103b528cefcSMark Murray 	if(rr->domain)
104b528cefcSMark Murray 	    free(rr->domain);
105b528cefcSMark Murray 	if(rr->u.data)
106b528cefcSMark Murray 	    free(rr->u.data);
107b528cefcSMark Murray 	rr = rr->next;
108b528cefcSMark Murray 	free(tmp);
109b528cefcSMark Murray     }
110b528cefcSMark Murray     free (r);
111b528cefcSMark Murray }
112b528cefcSMark Murray 
113b528cefcSMark Murray static struct dns_reply*
114b528cefcSMark Murray parse_reply(unsigned char *data, int len)
115b528cefcSMark Murray {
116*8373020dSJacques Vidrine     const unsigned char *p;
117b528cefcSMark Murray     char host[128];
118b528cefcSMark Murray     int status;
119*8373020dSJacques Vidrine     const unsigned char *end_data = data + len;
120b528cefcSMark Murray     struct dns_reply *r;
121b528cefcSMark Murray     struct resource_record **rr;
122b528cefcSMark Murray 
123b528cefcSMark Murray     r = calloc(1, sizeof(*r));
124b528cefcSMark Murray     if (r == NULL)
125b528cefcSMark Murray 	return NULL;
126b528cefcSMark Murray 
127b528cefcSMark Murray     p = data;
128b528cefcSMark Murray #if 0
129b528cefcSMark Murray     /* doesn't work on Crays */
130b528cefcSMark Murray     memcpy(&r->h, p, sizeof(HEADER));
131b528cefcSMark Murray     p += sizeof(HEADER);
132b528cefcSMark Murray #else
133b528cefcSMark Murray     memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
134b528cefcSMark Murray     p += 12;
135b528cefcSMark Murray #endif
136*8373020dSJacques Vidrine     status = dn_expand(data, end_data, p, host, sizeof(host));
137b528cefcSMark Murray     if(status < 0){
138b528cefcSMark Murray 	dns_free_data(r);
139b528cefcSMark Murray 	return NULL;
140b528cefcSMark Murray     }
141b528cefcSMark Murray     r->q.domain = strdup(host);
142b528cefcSMark Murray     if(r->q.domain == NULL) {
143b528cefcSMark Murray 	dns_free_data(r);
144b528cefcSMark Murray 	return NULL;
145b528cefcSMark Murray     }
146*8373020dSJacques Vidrine     if (p + status + 4 > end_data) {
147*8373020dSJacques Vidrine 	dns_free_data(r);
148*8373020dSJacques Vidrine 	return NULL;
149*8373020dSJacques Vidrine     }
150b528cefcSMark Murray     p += status;
151b528cefcSMark Murray     r->q.type = (p[0] << 8 | p[1]);
152b528cefcSMark Murray     p += 2;
153b528cefcSMark Murray     r->q.class = (p[0] << 8 | p[1]);
154b528cefcSMark Murray     p += 2;
155b528cefcSMark Murray     rr = &r->head;
156*8373020dSJacques Vidrine     while(p < end_data){
157b528cefcSMark Murray 	int type, class, ttl, size;
158*8373020dSJacques Vidrine 	status = dn_expand(data, end_data, p, host, sizeof(host));
159b528cefcSMark Murray 	if(status < 0){
160b528cefcSMark Murray 	    dns_free_data(r);
161b528cefcSMark Murray 	    return NULL;
162b528cefcSMark Murray 	}
163*8373020dSJacques Vidrine 	if (p + status + 10 > end_data) {
164*8373020dSJacques Vidrine 	    dns_free_data(r);
165*8373020dSJacques Vidrine 	    return NULL;
166*8373020dSJacques Vidrine 	}
167b528cefcSMark Murray 	p += status;
168b528cefcSMark Murray 	type = (p[0] << 8) | p[1];
169b528cefcSMark Murray 	p += 2;
170b528cefcSMark Murray 	class = (p[0] << 8) | p[1];
171b528cefcSMark Murray 	p += 2;
172b528cefcSMark Murray 	ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
173b528cefcSMark Murray 	p += 4;
174b528cefcSMark Murray 	size = (p[0] << 8) | p[1];
175b528cefcSMark Murray 	p += 2;
176*8373020dSJacques Vidrine 
177*8373020dSJacques Vidrine 	if (p + size > end_data) {
178*8373020dSJacques Vidrine 	    dns_free_data(r);
179*8373020dSJacques Vidrine 	    return NULL;
180*8373020dSJacques Vidrine 	}
181*8373020dSJacques Vidrine 
182b528cefcSMark Murray 	*rr = (struct resource_record*)calloc(1,
183b528cefcSMark Murray 					      sizeof(struct resource_record));
184b528cefcSMark Murray 	if(*rr == NULL) {
185b528cefcSMark Murray 	    dns_free_data(r);
186b528cefcSMark Murray 	    return NULL;
187b528cefcSMark Murray 	}
188b528cefcSMark Murray 	(*rr)->domain = strdup(host);
189b528cefcSMark Murray 	if((*rr)->domain == NULL) {
190b528cefcSMark Murray 	    dns_free_data(r);
191b528cefcSMark Murray 	    return NULL;
192b528cefcSMark Murray 	}
193b528cefcSMark Murray 	(*rr)->type = type;
194b528cefcSMark Murray 	(*rr)->class = class;
195b528cefcSMark Murray 	(*rr)->ttl = ttl;
196b528cefcSMark Murray 	(*rr)->size = size;
197b528cefcSMark Murray 	switch(type){
198b528cefcSMark Murray 	case T_NS:
199b528cefcSMark Murray 	case T_CNAME:
200b528cefcSMark Murray 	case T_PTR:
201*8373020dSJacques Vidrine 	    status = dn_expand(data, end_data, p, host, sizeof(host));
202b528cefcSMark Murray 	    if(status < 0){
203b528cefcSMark Murray 		dns_free_data(r);
204b528cefcSMark Murray 		return NULL;
205b528cefcSMark Murray 	    }
206b528cefcSMark Murray 	    (*rr)->u.txt = strdup(host);
207b528cefcSMark Murray 	    if((*rr)->u.txt == NULL) {
208b528cefcSMark Murray 		dns_free_data(r);
209b528cefcSMark Murray 		return NULL;
210b528cefcSMark Murray 	    }
211b528cefcSMark Murray 	    break;
212b528cefcSMark Murray 	case T_MX:
213b528cefcSMark Murray 	case T_AFSDB:{
214*8373020dSJacques Vidrine 	    status = dn_expand(data, end_data, p + 2, host, sizeof(host));
215b528cefcSMark Murray 	    if(status < 0){
216b528cefcSMark Murray 		dns_free_data(r);
217b528cefcSMark Murray 		return NULL;
218b528cefcSMark Murray 	    }
219*8373020dSJacques Vidrine 	    if (status + 2 > size) {
220*8373020dSJacques Vidrine 		dns_free_data(r);
221*8373020dSJacques Vidrine 		return NULL;
222*8373020dSJacques Vidrine 	    }
223*8373020dSJacques Vidrine 
224b528cefcSMark Murray 	    (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
225b528cefcSMark Murray 						    strlen(host));
226b528cefcSMark Murray 	    if((*rr)->u.mx == NULL) {
227b528cefcSMark Murray 		dns_free_data(r);
228b528cefcSMark Murray 		return NULL;
229b528cefcSMark Murray 	    }
230b528cefcSMark Murray 	    (*rr)->u.mx->preference = (p[0] << 8) | p[1];
231b528cefcSMark Murray 	    strcpy((*rr)->u.mx->domain, host);
232b528cefcSMark Murray 	    break;
233b528cefcSMark Murray 	}
234b528cefcSMark Murray 	case T_SRV:{
235*8373020dSJacques Vidrine 	    status = dn_expand(data, end_data, p + 6, host, sizeof(host));
236b528cefcSMark Murray 	    if(status < 0){
237b528cefcSMark Murray 		dns_free_data(r);
238b528cefcSMark Murray 		return NULL;
239b528cefcSMark Murray 	    }
240*8373020dSJacques Vidrine 	    if (status + 6 > size) {
241*8373020dSJacques Vidrine 		dns_free_data(r);
242*8373020dSJacques Vidrine 		return NULL;
243*8373020dSJacques Vidrine 	    }
244*8373020dSJacques Vidrine 
245b528cefcSMark Murray 	    (*rr)->u.srv =
246b528cefcSMark Murray 		(struct srv_record*)malloc(sizeof(struct srv_record) +
247b528cefcSMark Murray 					   strlen(host));
248b528cefcSMark Murray 	    if((*rr)->u.srv == NULL) {
249b528cefcSMark Murray 		dns_free_data(r);
250b528cefcSMark Murray 		return NULL;
251b528cefcSMark Murray 	    }
252b528cefcSMark Murray 	    (*rr)->u.srv->priority = (p[0] << 8) | p[1];
253b528cefcSMark Murray 	    (*rr)->u.srv->weight = (p[2] << 8) | p[3];
254b528cefcSMark Murray 	    (*rr)->u.srv->port = (p[4] << 8) | p[5];
255b528cefcSMark Murray 	    strcpy((*rr)->u.srv->target, host);
256b528cefcSMark Murray 	    break;
257b528cefcSMark Murray 	}
258b528cefcSMark Murray 	case T_TXT:{
259b528cefcSMark Murray 	    (*rr)->u.txt = (char*)malloc(size + 1);
260b528cefcSMark Murray 	    if((*rr)->u.txt == NULL) {
261b528cefcSMark Murray 		dns_free_data(r);
262b528cefcSMark Murray 		return NULL;
263b528cefcSMark Murray 	    }
264b528cefcSMark Murray 	    strncpy((*rr)->u.txt, (char*)p + 1, *p);
265b528cefcSMark Murray 	    (*rr)->u.txt[*p] = 0;
266b528cefcSMark Murray 	    break;
267b528cefcSMark Murray 	}
2685e9cd1aeSAssar Westerlund 	case T_KEY : {
2695e9cd1aeSAssar Westerlund 	    size_t key_len;
270b528cefcSMark Murray 
271*8373020dSJacques Vidrine 	    if (size < 4) {
272*8373020dSJacques Vidrine 		dns_free_data (r);
273*8373020dSJacques Vidrine 		return NULL;
274*8373020dSJacques Vidrine 	    }
275*8373020dSJacques Vidrine 
2765e9cd1aeSAssar Westerlund 	    key_len = size - 4;
2775e9cd1aeSAssar Westerlund 	    (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
2785e9cd1aeSAssar Westerlund 	    if ((*rr)->u.key == NULL) {
2795e9cd1aeSAssar Westerlund 		dns_free_data (r);
2805e9cd1aeSAssar Westerlund 		return NULL;
2815e9cd1aeSAssar Westerlund 	    }
2825e9cd1aeSAssar Westerlund 
2835e9cd1aeSAssar Westerlund 	    (*rr)->u.key->flags     = (p[0] << 8) | p[1];
2845e9cd1aeSAssar Westerlund 	    (*rr)->u.key->protocol  = p[2];
2855e9cd1aeSAssar Westerlund 	    (*rr)->u.key->algorithm = p[3];
2865e9cd1aeSAssar Westerlund 	    (*rr)->u.key->key_len   = key_len;
2875e9cd1aeSAssar Westerlund 	    memcpy ((*rr)->u.key->key_data, p + 4, key_len);
2885e9cd1aeSAssar Westerlund 	    break;
2895e9cd1aeSAssar Westerlund 	}
2905e9cd1aeSAssar Westerlund 	case T_SIG : {
2915e9cd1aeSAssar Westerlund 	    size_t sig_len;
2925e9cd1aeSAssar Westerlund 
293*8373020dSJacques Vidrine 	    status = dn_expand (data, end_data, p + 18, host, sizeof(host));
2945e9cd1aeSAssar Westerlund 	    if (status < 0) {
2955e9cd1aeSAssar Westerlund 		dns_free_data (r);
2965e9cd1aeSAssar Westerlund 		return NULL;
2975e9cd1aeSAssar Westerlund 	    }
298*8373020dSJacques Vidrine 	    if (status + 18 > size) {
299*8373020dSJacques Vidrine 		dns_free_data(r);
300*8373020dSJacques Vidrine 		return NULL;
301*8373020dSJacques Vidrine 	    }
302*8373020dSJacques Vidrine 
3035e9cd1aeSAssar Westerlund 	    sig_len = len - 18 - status;
3045e9cd1aeSAssar Westerlund 	    (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
3055e9cd1aeSAssar Westerlund 				  + strlen(host) + sig_len);
3065e9cd1aeSAssar Westerlund 	    if ((*rr)->u.sig == NULL) {
3075e9cd1aeSAssar Westerlund 		dns_free_data (r);
3085e9cd1aeSAssar Westerlund 		return NULL;
3095e9cd1aeSAssar Westerlund 	    }
3105e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->type           = (p[0] << 8) | p[1];
3115e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->algorithm      = p[2];
3125e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->labels         = p[3];
3135e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
3145e9cd1aeSAssar Westerlund 		| (p[6] << 8) | p[7];
3155e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
3165e9cd1aeSAssar Westerlund 		| (p[10] << 8) | p[11];
3175e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
3185e9cd1aeSAssar Westerlund 		| (p[14] << 8) | p[15];
3195e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->key_tag        = (p[16] << 8) | p[17];
3205e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->sig_len        = sig_len;
3215e9cd1aeSAssar Westerlund 	    memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len);
3225e9cd1aeSAssar Westerlund 	    (*rr)->u.sig->signer         = &(*rr)->u.sig->sig_data[sig_len];
3235e9cd1aeSAssar Westerlund 	    strcpy((*rr)->u.sig->signer, host);
3245e9cd1aeSAssar Westerlund 	    break;
3255e9cd1aeSAssar Westerlund 	}
3265e9cd1aeSAssar Westerlund 
3275e9cd1aeSAssar Westerlund 	case T_CERT : {
3285e9cd1aeSAssar Westerlund 	    size_t cert_len;
3295e9cd1aeSAssar Westerlund 
330*8373020dSJacques Vidrine 	    if (size < 5) {
331*8373020dSJacques Vidrine 		dns_free_data(r);
332*8373020dSJacques Vidrine 		return NULL;
333*8373020dSJacques Vidrine 	    }
334*8373020dSJacques Vidrine 
3355e9cd1aeSAssar Westerlund 	    cert_len = size - 5;
3365e9cd1aeSAssar Westerlund 	    (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
3375e9cd1aeSAssar Westerlund 	    if ((*rr)->u.cert == NULL) {
3385e9cd1aeSAssar Westerlund 		dns_free_data (r);
3395e9cd1aeSAssar Westerlund 		return NULL;
3405e9cd1aeSAssar Westerlund 	    }
3415e9cd1aeSAssar Westerlund 
3425e9cd1aeSAssar Westerlund 	    (*rr)->u.cert->type      = (p[0] << 8) | p[1];
3435e9cd1aeSAssar Westerlund 	    (*rr)->u.cert->tag       = (p[2] << 8) | p[3];
3445e9cd1aeSAssar Westerlund 	    (*rr)->u.cert->algorithm = p[4];
3455e9cd1aeSAssar Westerlund 	    (*rr)->u.cert->cert_len  = cert_len;
3465e9cd1aeSAssar Westerlund 	    memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len);
3475e9cd1aeSAssar Westerlund 	    break;
3485e9cd1aeSAssar Westerlund 	}
349b528cefcSMark Murray 	default:
350b528cefcSMark Murray 	    (*rr)->u.data = (unsigned char*)malloc(size);
351b528cefcSMark Murray 	    if(size != 0 && (*rr)->u.data == NULL) {
352b528cefcSMark Murray 		dns_free_data(r);
353b528cefcSMark Murray 		return NULL;
354b528cefcSMark Murray 	    }
355b528cefcSMark Murray 	    memcpy((*rr)->u.data, p, size);
356b528cefcSMark Murray 	}
357b528cefcSMark Murray 	p += size;
358b528cefcSMark Murray 	rr = &(*rr)->next;
359b528cefcSMark Murray     }
360b528cefcSMark Murray     *rr = NULL;
361b528cefcSMark Murray     return r;
362b528cefcSMark Murray }
363b528cefcSMark Murray 
364b528cefcSMark Murray static struct dns_reply *
365b528cefcSMark Murray dns_lookup_int(const char *domain, int rr_class, int rr_type)
366b528cefcSMark Murray {
367b528cefcSMark Murray     unsigned char reply[1024];
368b528cefcSMark Murray     int len;
369*8373020dSJacques Vidrine #ifdef HAVE__RES
370b528cefcSMark Murray     u_long old_options = 0;
371*8373020dSJacques Vidrine #endif
372b528cefcSMark Murray 
373b528cefcSMark Murray     if (_resolve_debug) {
374*8373020dSJacques Vidrine #ifdef HAVE__RES
375b528cefcSMark Murray         old_options = _res.options;
376b528cefcSMark Murray 	_res.options |= RES_DEBUG;
377*8373020dSJacques Vidrine #endif
378b528cefcSMark Murray 	fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain,
3795e9cd1aeSAssar Westerlund 		rr_class, dns_type_to_string(rr_type));
380b528cefcSMark Murray     }
381b528cefcSMark Murray     len = res_search(domain, rr_class, rr_type, reply, sizeof(reply));
382b528cefcSMark Murray     if (_resolve_debug) {
383*8373020dSJacques Vidrine #ifdef HAVE__RES
384b528cefcSMark Murray         _res.options = old_options;
385*8373020dSJacques Vidrine #endif
386b528cefcSMark Murray 	fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
3875e9cd1aeSAssar Westerlund 		domain, rr_class, dns_type_to_string(rr_type), len);
388b528cefcSMark Murray     }
389*8373020dSJacques Vidrine     if(len < 0) {
390*8373020dSJacques Vidrine 	return NULL;
391*8373020dSJacques Vidrine     } else {
392*8373020dSJacques Vidrine 	len = min(len, sizeof(reply));
393*8373020dSJacques Vidrine 	return parse_reply(reply, len);
394*8373020dSJacques Vidrine     }
395b528cefcSMark Murray }
396b528cefcSMark Murray 
397b528cefcSMark Murray struct dns_reply *
398b528cefcSMark Murray dns_lookup(const char *domain, const char *type_name)
399b528cefcSMark Murray {
400b528cefcSMark Murray     int type;
401b528cefcSMark Murray 
4025e9cd1aeSAssar Westerlund     type = dns_string_to_type(type_name);
403b528cefcSMark Murray     if(type == -1) {
404b528cefcSMark Murray 	if(_resolve_debug)
405b528cefcSMark Murray 	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
406b528cefcSMark Murray 		    type_name);
407b528cefcSMark Murray 	return NULL;
408b528cefcSMark Murray     }
409b528cefcSMark Murray     return dns_lookup_int(domain, C_IN, type);
410b528cefcSMark Murray }
411b528cefcSMark Murray 
4124137ff4cSJacques Vidrine static int
4134137ff4cSJacques Vidrine compare_srv(const void *a, const void *b)
4144137ff4cSJacques Vidrine {
4154137ff4cSJacques Vidrine     const struct resource_record *const* aa = a, *const* bb = b;
4164137ff4cSJacques Vidrine 
4174137ff4cSJacques Vidrine     if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
4184137ff4cSJacques Vidrine 	return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
4194137ff4cSJacques Vidrine     return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
4204137ff4cSJacques Vidrine }
4214137ff4cSJacques Vidrine 
4224137ff4cSJacques Vidrine #ifndef HAVE_RANDOM
4234137ff4cSJacques Vidrine #define random() rand()
4244137ff4cSJacques Vidrine #endif
4254137ff4cSJacques Vidrine 
4264137ff4cSJacques Vidrine /* try to rearrange the srv-records by the algorithm in RFC2782 */
4274137ff4cSJacques Vidrine void
4284137ff4cSJacques Vidrine dns_srv_order(struct dns_reply *r)
4294137ff4cSJacques Vidrine {
4304137ff4cSJacques Vidrine     struct resource_record **srvs, **ss, **headp;
4314137ff4cSJacques Vidrine     struct resource_record *rr;
4324137ff4cSJacques Vidrine     int num_srv = 0;
4334137ff4cSJacques Vidrine 
4344137ff4cSJacques Vidrine #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
435*8373020dSJacques Vidrine     int state[256 / sizeof(int)];
436*8373020dSJacques Vidrine     char *oldstate;
4374137ff4cSJacques Vidrine #endif
4384137ff4cSJacques Vidrine 
4394137ff4cSJacques Vidrine     for(rr = r->head; rr; rr = rr->next)
4404137ff4cSJacques Vidrine 	if(rr->type == T_SRV)
4414137ff4cSJacques Vidrine 	    num_srv++;
4424137ff4cSJacques Vidrine 
4434137ff4cSJacques Vidrine     if(num_srv == 0)
4444137ff4cSJacques Vidrine 	return;
4454137ff4cSJacques Vidrine 
4464137ff4cSJacques Vidrine     srvs = malloc(num_srv * sizeof(*srvs));
4474137ff4cSJacques Vidrine     if(srvs == NULL)
4484137ff4cSJacques Vidrine 	return; /* XXX not much to do here */
4494137ff4cSJacques Vidrine 
4504137ff4cSJacques Vidrine     /* unlink all srv-records from the linked list and put them in
4514137ff4cSJacques Vidrine        a vector */
4524137ff4cSJacques Vidrine     for(ss = srvs, headp = &r->head; *headp; )
4534137ff4cSJacques Vidrine 	if((*headp)->type == T_SRV) {
4544137ff4cSJacques Vidrine 	    *ss = *headp;
4554137ff4cSJacques Vidrine 	    *headp = (*headp)->next;
4564137ff4cSJacques Vidrine 	    (*ss)->next = NULL;
4574137ff4cSJacques Vidrine 	    ss++;
4584137ff4cSJacques Vidrine 	} else
4594137ff4cSJacques Vidrine 	    headp = &(*headp)->next;
4604137ff4cSJacques Vidrine 
4614137ff4cSJacques Vidrine     /* sort them by priority and weight */
4624137ff4cSJacques Vidrine     qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
4634137ff4cSJacques Vidrine 
4644137ff4cSJacques Vidrine #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
465*8373020dSJacques Vidrine     oldstate = initstate(time(NULL), (char*)state, sizeof(state));
4664137ff4cSJacques Vidrine #endif
4674137ff4cSJacques Vidrine 
4684137ff4cSJacques Vidrine     headp = &r->head;
4694137ff4cSJacques Vidrine 
4704137ff4cSJacques Vidrine     for(ss = srvs; ss < srvs + num_srv; ) {
4714137ff4cSJacques Vidrine 	int sum, rnd, count;
4724137ff4cSJacques Vidrine 	struct resource_record **ee, **tt;
4734137ff4cSJacques Vidrine 	/* find the last record with the same priority and count the
4744137ff4cSJacques Vidrine            sum of all weights */
4754137ff4cSJacques Vidrine 	for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
4764137ff4cSJacques Vidrine 	    if(*tt == NULL)
4774137ff4cSJacques Vidrine 		continue;
4784137ff4cSJacques Vidrine 	    if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
4794137ff4cSJacques Vidrine 		break;
4804137ff4cSJacques Vidrine 	    sum += (*tt)->u.srv->weight;
4814137ff4cSJacques Vidrine 	}
4824137ff4cSJacques Vidrine 	ee = tt;
4834137ff4cSJacques Vidrine 	/* ss is now the first record of this priority and ee is the
4844137ff4cSJacques Vidrine            first of the next */
4854137ff4cSJacques Vidrine 	while(ss < ee) {
4864137ff4cSJacques Vidrine 	    rnd = random() % (sum + 1);
4874137ff4cSJacques Vidrine 	    for(count = 0, tt = ss; ; tt++) {
4884137ff4cSJacques Vidrine 		if(*tt == NULL)
4894137ff4cSJacques Vidrine 		    continue;
4904137ff4cSJacques Vidrine 		count += (*tt)->u.srv->weight;
4914137ff4cSJacques Vidrine 		if(count >= rnd)
4924137ff4cSJacques Vidrine 		    break;
4934137ff4cSJacques Vidrine 	    }
4944137ff4cSJacques Vidrine 
4954137ff4cSJacques Vidrine 	    assert(tt < ee);
4964137ff4cSJacques Vidrine 
4974137ff4cSJacques Vidrine 	    /* insert the selected record at the tail (of the head) of
4984137ff4cSJacques Vidrine                the list */
4994137ff4cSJacques Vidrine 	    (*tt)->next = *headp;
5004137ff4cSJacques Vidrine 	    *headp = *tt;
5014137ff4cSJacques Vidrine 	    headp = &(*tt)->next;
5024137ff4cSJacques Vidrine 	    sum -= (*tt)->u.srv->weight;
5034137ff4cSJacques Vidrine 	    *tt = NULL;
5044137ff4cSJacques Vidrine 	    while(ss < ee && *ss == NULL)
5054137ff4cSJacques Vidrine 		ss++;
5064137ff4cSJacques Vidrine 	}
5074137ff4cSJacques Vidrine     }
5084137ff4cSJacques Vidrine 
5094137ff4cSJacques Vidrine #if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
5104137ff4cSJacques Vidrine     setstate(oldstate);
5114137ff4cSJacques Vidrine #endif
5124137ff4cSJacques Vidrine     free(srvs);
5134137ff4cSJacques Vidrine     return;
5144137ff4cSJacques Vidrine }
5154137ff4cSJacques Vidrine 
516b528cefcSMark Murray #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
517b528cefcSMark Murray 
518b528cefcSMark Murray struct dns_reply *
519b528cefcSMark Murray dns_lookup(const char *domain, const char *type_name)
520b528cefcSMark Murray {
521b528cefcSMark Murray     return NULL;
522b528cefcSMark Murray }
523b528cefcSMark Murray 
524b528cefcSMark Murray void
525b528cefcSMark Murray dns_free_data(struct dns_reply *r)
526b528cefcSMark Murray {
527b528cefcSMark Murray }
528b528cefcSMark Murray 
5294137ff4cSJacques Vidrine void
5304137ff4cSJacques Vidrine dns_srv_order(struct dns_reply *r)
5314137ff4cSJacques Vidrine {
5324137ff4cSJacques Vidrine }
5334137ff4cSJacques Vidrine 
534b528cefcSMark Murray #endif
535b528cefcSMark Murray 
536b528cefcSMark Murray #ifdef TEST
537b528cefcSMark Murray int
538b528cefcSMark Murray main(int argc, char **argv)
539b528cefcSMark Murray {
540b528cefcSMark Murray     struct dns_reply *r;
541b528cefcSMark Murray     struct resource_record *rr;
542b528cefcSMark Murray     r = dns_lookup(argv[1], argv[2]);
543b528cefcSMark Murray     if(r == NULL){
544b528cefcSMark Murray 	printf("No reply.\n");
545b528cefcSMark Murray 	return 1;
546b528cefcSMark Murray     }
5474137ff4cSJacques Vidrine     if(r->q.type == T_SRV)
5484137ff4cSJacques Vidrine 	dns_srv_order(r);
5494137ff4cSJacques Vidrine 
550b528cefcSMark Murray     for(rr = r->head; rr;rr=rr->next){
5515e9cd1aeSAssar Westerlund 	printf("%s %s %d ", rr->domain, dns_type_to_string(rr->type), rr->ttl);
552b528cefcSMark Murray 	switch(rr->type){
553b528cefcSMark Murray 	case T_NS:
5545e9cd1aeSAssar Westerlund 	case T_CNAME:
5555e9cd1aeSAssar Westerlund 	case T_PTR:
556b528cefcSMark Murray 	    printf("%s\n", (char*)rr->u.data);
557b528cefcSMark Murray 	    break;
558b528cefcSMark Murray 	case T_A:
5595e9cd1aeSAssar Westerlund 	    printf("%s\n", inet_ntoa(*rr->u.a));
560b528cefcSMark Murray 	    break;
561b528cefcSMark Murray 	case T_MX:
562b528cefcSMark Murray 	case T_AFSDB:{
5635e9cd1aeSAssar Westerlund 	    printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain);
564b528cefcSMark Murray 	    break;
565b528cefcSMark Murray 	}
566b528cefcSMark Murray 	case T_SRV:{
5675e9cd1aeSAssar Westerlund 	    struct srv_record *srv = rr->u.srv;
568b528cefcSMark Murray 	    printf("%d %d %d %s\n", srv->priority, srv->weight,
569b528cefcSMark Murray 		   srv->port, srv->target);
570b528cefcSMark Murray 	    break;
571b528cefcSMark Murray 	}
5725e9cd1aeSAssar Westerlund 	case T_TXT: {
5735e9cd1aeSAssar Westerlund 	    printf("%s\n", rr->u.txt);
5745e9cd1aeSAssar Westerlund 	    break;
5755e9cd1aeSAssar Westerlund 	}
5765e9cd1aeSAssar Westerlund 	case T_SIG : {
5775e9cd1aeSAssar Westerlund 	    struct sig_record *sig = rr->u.sig;
5785e9cd1aeSAssar Westerlund 	    const char *type_string = dns_type_to_string (sig->type);
5795e9cd1aeSAssar Westerlund 
5805e9cd1aeSAssar Westerlund 	    printf ("type %u (%s), algorithm %u, labels %u, orig_ttl %u, sig_expiration %u, sig_inception %u, key_tag %u, signer %s\n",
5815e9cd1aeSAssar Westerlund 		    sig->type, type_string ? type_string : "",
5825e9cd1aeSAssar Westerlund 		    sig->algorithm, sig->labels, sig->orig_ttl,
5835e9cd1aeSAssar Westerlund 		    sig->sig_expiration, sig->sig_inception, sig->key_tag,
5845e9cd1aeSAssar Westerlund 		    sig->signer);
5855e9cd1aeSAssar Westerlund 	    break;
5865e9cd1aeSAssar Westerlund 	}
5875e9cd1aeSAssar Westerlund 	case T_KEY : {
5885e9cd1aeSAssar Westerlund 	    struct key_record *key = rr->u.key;
5895e9cd1aeSAssar Westerlund 
5905e9cd1aeSAssar Westerlund 	    printf ("flags %u, protocol %u, algorithm %u\n",
5915e9cd1aeSAssar Westerlund 		    key->flags, key->protocol, key->algorithm);
5925e9cd1aeSAssar Westerlund 	    break;
5935e9cd1aeSAssar Westerlund 	}
594b528cefcSMark Murray 	default:
595b528cefcSMark Murray 	    printf("\n");
596b528cefcSMark Murray 	    break;
597b528cefcSMark Murray 	}
598b528cefcSMark Murray     }
599b528cefcSMark Murray 
600b528cefcSMark Murray     return 0;
601b528cefcSMark Murray }
602b528cefcSMark Murray #endif
603