resolve.c revision 178825
155682Smarkm/*
2178825Sdfr * Copyright (c) 1995 - 2006 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
48178825SdfrRCSID("$Id: resolve.c 19869 2007-01-12 16:03:14Z lha $");
4990926Snectar
50178825Sdfr#ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
51103423Snectar#undef HAVE_RES_NSEARCH
52178825Sdfr#endif
5355682Smarkm
54178825Sdfr#define DECL(X) {#X, rk_ns_t_##X}
5555682Smarkm
5655682Smarkmstatic struct stot{
5755682Smarkm    const char *name;
5855682Smarkm    int type;
5955682Smarkm}stot[] = {
60178825Sdfr    DECL(a),
61178825Sdfr    DECL(aaaa),
62178825Sdfr    DECL(ns),
63178825Sdfr    DECL(cname),
64178825Sdfr    DECL(soa),
65178825Sdfr    DECL(ptr),
66178825Sdfr    DECL(mx),
67178825Sdfr    DECL(txt),
68178825Sdfr    DECL(afsdb),
69178825Sdfr    DECL(sig),
70178825Sdfr    DECL(key),
71178825Sdfr    DECL(srv),
72178825Sdfr    DECL(naptr),
73178825Sdfr    DECL(sshfp),
74178825Sdfr    DECL(ds),
7555682Smarkm    {NULL, 	0}
7655682Smarkm};
7755682Smarkm
7872445Sassarint _resolve_debug = 0;
7955682Smarkm
80178825Sdfrint ROKEN_LIB_FUNCTION
8172445Sassardns_string_to_type(const char *name)
8255682Smarkm{
8355682Smarkm    struct stot *p = stot;
8455682Smarkm    for(p = stot; p->name; p++)
8555682Smarkm	if(strcasecmp(name, p->name) == 0)
8655682Smarkm	    return p->type;
8755682Smarkm    return -1;
8855682Smarkm}
8955682Smarkm
90178825Sdfrconst char * ROKEN_LIB_FUNCTION
9172445Sassardns_type_to_string(int type)
9255682Smarkm{
9355682Smarkm    struct stot *p = stot;
9455682Smarkm    for(p = stot; p->name; p++)
9555682Smarkm	if(type == p->type)
9655682Smarkm	    return p->name;
9755682Smarkm    return NULL;
9855682Smarkm}
9955682Smarkm
100178825Sdfr#if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)
101178825Sdfr
102178825Sdfrstatic void
103178825Sdfrdns_free_rr(struct resource_record *rr)
104178825Sdfr{
105178825Sdfr    if(rr->domain)
106178825Sdfr	free(rr->domain);
107178825Sdfr    if(rr->u.data)
108178825Sdfr	free(rr->u.data);
109178825Sdfr    free(rr);
110178825Sdfr}
111178825Sdfr
112178825Sdfrvoid ROKEN_LIB_FUNCTION
11355682Smarkmdns_free_data(struct dns_reply *r)
11455682Smarkm{
11555682Smarkm    struct resource_record *rr;
11655682Smarkm    if(r->q.domain)
11755682Smarkm	free(r->q.domain);
11855682Smarkm    for(rr = r->head; rr;){
11955682Smarkm	struct resource_record *tmp = rr;
12055682Smarkm	rr = rr->next;
121178825Sdfr	dns_free_rr(tmp);
12255682Smarkm    }
12355682Smarkm    free (r);
12455682Smarkm}
12555682Smarkm
126107207Snectarstatic int
127107207Snectarparse_record(const unsigned char *data, const unsigned char *end_data,
128178825Sdfr	     const unsigned char **pp, struct resource_record **ret_rr)
129107207Snectar{
130178825Sdfr    struct resource_record *rr;
131107207Snectar    int type, class, ttl, size;
132107207Snectar    int status;
133107207Snectar    char host[MAXDNAME];
134107207Snectar    const unsigned char *p = *pp;
135178825Sdfr
136178825Sdfr    *ret_rr = NULL;
137178825Sdfr
138107207Snectar    status = dn_expand(data, end_data, p, host, sizeof(host));
139107207Snectar    if(status < 0)
140107207Snectar	return -1;
141107207Snectar    if (p + status + 10 > end_data)
142107207Snectar	return -1;
143178825Sdfr
144107207Snectar    p += status;
145107207Snectar    type = (p[0] << 8) | p[1];
146107207Snectar    p += 2;
147107207Snectar    class = (p[0] << 8) | p[1];
148107207Snectar    p += 2;
149107207Snectar    ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
150107207Snectar    p += 4;
151107207Snectar    size = (p[0] << 8) | p[1];
152107207Snectar    p += 2;
153107207Snectar
154107207Snectar    if (p + size > end_data)
155107207Snectar	return -1;
156107207Snectar
157178825Sdfr    rr = calloc(1, sizeof(*rr));
158178825Sdfr    if(rr == NULL)
159107207Snectar	return -1;
160178825Sdfr    rr->domain = strdup(host);
161178825Sdfr    if(rr->domain == NULL) {
162178825Sdfr	dns_free_rr(rr);
163107207Snectar	return -1;
164107207Snectar    }
165178825Sdfr    rr->type = type;
166178825Sdfr    rr->class = class;
167178825Sdfr    rr->ttl = ttl;
168178825Sdfr    rr->size = size;
169107207Snectar    switch(type){
170178825Sdfr    case rk_ns_t_ns:
171178825Sdfr    case rk_ns_t_cname:
172178825Sdfr    case rk_ns_t_ptr:
173107207Snectar	status = dn_expand(data, end_data, p, host, sizeof(host));
174107207Snectar	if(status < 0) {
175178825Sdfr	    dns_free_rr(rr);
176107207Snectar	    return -1;
177107207Snectar	}
178178825Sdfr	rr->u.txt = strdup(host);
179178825Sdfr	if(rr->u.txt == NULL) {
180178825Sdfr	    dns_free_rr(rr);
181107207Snectar	    return -1;
182107207Snectar	}
183107207Snectar	break;
184178825Sdfr    case rk_ns_t_mx:
185178825Sdfr    case rk_ns_t_afsdb:{
186120945Snectar	size_t hostlen;
187120945Snectar
188107207Snectar	status = dn_expand(data, end_data, p + 2, host, sizeof(host));
189107207Snectar	if(status < 0){
190178825Sdfr	    dns_free_rr(rr);
191107207Snectar	    return -1;
192107207Snectar	}
193107207Snectar	if (status + 2 > size) {
194178825Sdfr	    dns_free_rr(rr);
195107207Snectar	    return -1;
196107207Snectar	}
197107207Snectar
198120945Snectar	hostlen = strlen(host);
199178825Sdfr	rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
200120945Snectar						hostlen);
201178825Sdfr	if(rr->u.mx == NULL) {
202178825Sdfr	    dns_free_rr(rr);
203107207Snectar	    return -1;
204107207Snectar	}
205178825Sdfr	rr->u.mx->preference = (p[0] << 8) | p[1];
206178825Sdfr	strlcpy(rr->u.mx->domain, host, hostlen + 1);
207107207Snectar	break;
208107207Snectar    }
209178825Sdfr    case rk_ns_t_srv:{
210120945Snectar	size_t hostlen;
211107207Snectar	status = dn_expand(data, end_data, p + 6, host, sizeof(host));
212107207Snectar	if(status < 0){
213178825Sdfr	    dns_free_rr(rr);
214107207Snectar	    return -1;
215107207Snectar	}
216107207Snectar	if (status + 6 > size) {
217178825Sdfr	    dns_free_rr(rr);
218107207Snectar	    return -1;
219107207Snectar	}
220107207Snectar
221120945Snectar	hostlen = strlen(host);
222178825Sdfr	rr->u.srv =
223107207Snectar	    (struct srv_record*)malloc(sizeof(struct srv_record) +
224120945Snectar				       hostlen);
225178825Sdfr	if(rr->u.srv == NULL) {
226178825Sdfr	    dns_free_rr(rr);
227107207Snectar	    return -1;
228107207Snectar	}
229178825Sdfr	rr->u.srv->priority = (p[0] << 8) | p[1];
230178825Sdfr	rr->u.srv->weight = (p[2] << 8) | p[3];
231178825Sdfr	rr->u.srv->port = (p[4] << 8) | p[5];
232178825Sdfr	strlcpy(rr->u.srv->target, host, hostlen + 1);
233107207Snectar	break;
234107207Snectar    }
235178825Sdfr    case rk_ns_t_txt:{
236107207Snectar	if(size == 0 || size < *p + 1) {
237178825Sdfr	    dns_free_rr(rr);
238107207Snectar	    return -1;
239107207Snectar	}
240178825Sdfr	rr->u.txt = (char*)malloc(*p + 1);
241178825Sdfr	if(rr->u.txt == NULL) {
242178825Sdfr	    dns_free_rr(rr);
243107207Snectar	    return -1;
244107207Snectar	}
245178825Sdfr	strncpy(rr->u.txt, (const char*)(p + 1), *p);
246178825Sdfr	rr->u.txt[*p] = '\0';
247107207Snectar	break;
248107207Snectar    }
249178825Sdfr    case rk_ns_t_key : {
250107207Snectar	size_t key_len;
251107207Snectar
252107207Snectar	if (size < 4) {
253178825Sdfr	    dns_free_rr(rr);
254107207Snectar	    return -1;
255107207Snectar	}
256107207Snectar
257107207Snectar	key_len = size - 4;
258178825Sdfr	rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
259178825Sdfr	if (rr->u.key == NULL) {
260178825Sdfr	    dns_free_rr(rr);
261107207Snectar	    return -1;
262107207Snectar	}
263107207Snectar
264178825Sdfr	rr->u.key->flags     = (p[0] << 8) | p[1];
265178825Sdfr	rr->u.key->protocol  = p[2];
266178825Sdfr	rr->u.key->algorithm = p[3];
267178825Sdfr	rr->u.key->key_len   = key_len;
268178825Sdfr	memcpy (rr->u.key->key_data, p + 4, key_len);
269107207Snectar	break;
270107207Snectar    }
271178825Sdfr    case rk_ns_t_sig : {
272120945Snectar	size_t sig_len, hostlen;
273107207Snectar
274107207Snectar	if(size <= 18) {
275178825Sdfr	    dns_free_rr(rr);
276107207Snectar	    return -1;
277107207Snectar	}
278107207Snectar	status = dn_expand (data, end_data, p + 18, host, sizeof(host));
279107207Snectar	if (status < 0) {
280178825Sdfr	    dns_free_rr(rr);
281107207Snectar	    return -1;
282107207Snectar	}
283107207Snectar	if (status + 18 > size) {
284178825Sdfr	    dns_free_rr(rr);
285107207Snectar	    return -1;
286107207Snectar	}
287107207Snectar
288107207Snectar	/* the signer name is placed after the sig_data, to make it
289178825Sdfr           easy to free this structure; the size calculation below
290107207Snectar           includes the zero-termination if the structure itself.
291107207Snectar	   don't you just love C?
292107207Snectar	*/
293107207Snectar	sig_len = size - 18 - status;
294120945Snectar	hostlen = strlen(host);
295178825Sdfr	rr->u.sig = malloc(sizeof(*rr->u.sig)
296120945Snectar			      + hostlen + sig_len);
297178825Sdfr	if (rr->u.sig == NULL) {
298178825Sdfr	    dns_free_rr(rr);
299107207Snectar	    return -1;
300107207Snectar	}
301178825Sdfr	rr->u.sig->type           = (p[0] << 8) | p[1];
302178825Sdfr	rr->u.sig->algorithm      = p[2];
303178825Sdfr	rr->u.sig->labels         = p[3];
304178825Sdfr	rr->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
305107207Snectar	    | (p[6] << 8) | p[7];
306178825Sdfr	rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
307107207Snectar	    | (p[10] << 8) | p[11];
308178825Sdfr	rr->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
309107207Snectar	    | (p[14] << 8) | p[15];
310178825Sdfr	rr->u.sig->key_tag        = (p[16] << 8) | p[17];
311178825Sdfr	rr->u.sig->sig_len        = sig_len;
312178825Sdfr	memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len);
313178825Sdfr	rr->u.sig->signer         = &rr->u.sig->sig_data[sig_len];
314178825Sdfr	strlcpy(rr->u.sig->signer, host, hostlen + 1);
315107207Snectar	break;
316107207Snectar    }
317107207Snectar
318178825Sdfr    case rk_ns_t_cert : {
319107207Snectar	size_t cert_len;
320107207Snectar
321107207Snectar	if (size < 5) {
322178825Sdfr	    dns_free_rr(rr);
323107207Snectar	    return -1;
324107207Snectar	}
325107207Snectar
326107207Snectar	cert_len = size - 5;
327178825Sdfr	rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1);
328178825Sdfr	if (rr->u.cert == NULL) {
329178825Sdfr	    dns_free_rr(rr);
330107207Snectar	    return -1;
331107207Snectar	}
332107207Snectar
333178825Sdfr	rr->u.cert->type      = (p[0] << 8) | p[1];
334178825Sdfr	rr->u.cert->tag       = (p[2] << 8) | p[3];
335178825Sdfr	rr->u.cert->algorithm = p[4];
336178825Sdfr	rr->u.cert->cert_len  = cert_len;
337178825Sdfr	memcpy (rr->u.cert->cert_data, p + 5, cert_len);
338107207Snectar	break;
339107207Snectar    }
340178825Sdfr    case rk_ns_t_sshfp : {
341178825Sdfr	size_t sshfp_len;
342178825Sdfr
343178825Sdfr	if (size < 2) {
344178825Sdfr	    dns_free_rr(rr);
345178825Sdfr	    return -1;
346178825Sdfr	}
347178825Sdfr
348178825Sdfr	sshfp_len = size - 2;
349178825Sdfr
350178825Sdfr	rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1);
351178825Sdfr	if (rr->u.sshfp == NULL) {
352178825Sdfr	    dns_free_rr(rr);
353178825Sdfr	    return -1;
354178825Sdfr	}
355178825Sdfr
356178825Sdfr	rr->u.sshfp->algorithm = p[0];
357178825Sdfr	rr->u.sshfp->type      = p[1];
358178825Sdfr	rr->u.sshfp->sshfp_len  = sshfp_len;
359178825Sdfr	memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len);
360178825Sdfr	break;
361178825Sdfr    }
362178825Sdfr    case rk_ns_t_ds: {
363178825Sdfr	size_t digest_len;
364178825Sdfr
365178825Sdfr	if (size < 4) {
366178825Sdfr	    dns_free_rr(rr);
367178825Sdfr	    return -1;
368178825Sdfr	}
369178825Sdfr
370178825Sdfr	digest_len = size - 4;
371178825Sdfr
372178825Sdfr	rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1);
373178825Sdfr	if (rr->u.ds == NULL) {
374178825Sdfr	    dns_free_rr(rr);
375178825Sdfr	    return -1;
376178825Sdfr	}
377178825Sdfr
378178825Sdfr	rr->u.ds->key_tag     = (p[0] << 8) | p[1];
379178825Sdfr	rr->u.ds->algorithm   = p[2];
380178825Sdfr	rr->u.ds->digest_type = p[3];
381178825Sdfr	rr->u.ds->digest_len  = digest_len;
382178825Sdfr	memcpy (rr->u.ds->digest_data, p + 4, digest_len);
383178825Sdfr	break;
384178825Sdfr    }
385107207Snectar    default:
386178825Sdfr	rr->u.data = (unsigned char*)malloc(size);
387178825Sdfr	if(size != 0 && rr->u.data == NULL) {
388178825Sdfr	    dns_free_rr(rr);
389107207Snectar	    return -1;
390107207Snectar	}
391178825Sdfr	if (size)
392178825Sdfr	    memcpy(rr->u.data, p, size);
393107207Snectar    }
394107207Snectar    *pp = p + size;
395178825Sdfr    *ret_rr = rr;
396178825Sdfr
397107207Snectar    return 0;
398107207Snectar}
399107207Snectar
400103423Snectar#ifndef TEST_RESOLVE
401103423Snectarstatic
402103423Snectar#endif
403103423Snectarstruct dns_reply*
404103423Snectarparse_reply(const unsigned char *data, size_t len)
40555682Smarkm{
406102644Snectar    const unsigned char *p;
40755682Smarkm    int status;
408107207Snectar    int i;
409107207Snectar    char host[MAXDNAME];
410102644Snectar    const unsigned char *end_data = data + len;
41155682Smarkm    struct dns_reply *r;
41255682Smarkm    struct resource_record **rr;
41355682Smarkm
41455682Smarkm    r = calloc(1, sizeof(*r));
41555682Smarkm    if (r == NULL)
41655682Smarkm	return NULL;
41755682Smarkm
41855682Smarkm    p = data;
419178825Sdfr
420178825Sdfr    r->h.id = (p[0] << 8) | p[1];
421178825Sdfr    r->h.flags = 0;
422178825Sdfr    if (p[2] & 0x01)
423178825Sdfr	r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
424178825Sdfr    r->h.opcode = (p[2] >> 1) & 0xf;
425178825Sdfr    if (p[2] & 0x20)
426178825Sdfr	r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
427178825Sdfr    if (p[2] & 0x40)
428178825Sdfr	r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
429178825Sdfr    if (p[2] & 0x80)
430178825Sdfr	r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
431178825Sdfr    if (p[3] & 0x01)
432178825Sdfr	r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
433178825Sdfr    if (p[3] & 0x04)
434178825Sdfr	r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
435178825Sdfr    if (p[3] & 0x08)
436178825Sdfr	r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
437178825Sdfr    r->h.response_code = (p[3] >> 4) & 0xf;
438178825Sdfr    r->h.qdcount = (p[4] << 8) | p[5];
439178825Sdfr    r->h.ancount = (p[6] << 8) | p[7];
440178825Sdfr    r->h.nscount = (p[8] << 8) | p[9];
441178825Sdfr    r->h.arcount = (p[10] << 8) | p[11];
442178825Sdfr
44355682Smarkm    p += 12;
444178825Sdfr
445178825Sdfr    if(r->h.qdcount != 1) {
446107207Snectar	free(r);
447107207Snectar	return NULL;
448107207Snectar    }
449102644Snectar    status = dn_expand(data, end_data, p, host, sizeof(host));
45055682Smarkm    if(status < 0){
45155682Smarkm	dns_free_data(r);
45255682Smarkm	return NULL;
45355682Smarkm    }
45455682Smarkm    r->q.domain = strdup(host);
45555682Smarkm    if(r->q.domain == NULL) {
45655682Smarkm	dns_free_data(r);
45755682Smarkm	return NULL;
45855682Smarkm    }
459102644Snectar    if (p + status + 4 > end_data) {
460102644Snectar	dns_free_data(r);
461102644Snectar	return NULL;
462102644Snectar    }
46355682Smarkm    p += status;
46455682Smarkm    r->q.type = (p[0] << 8 | p[1]);
46555682Smarkm    p += 2;
46655682Smarkm    r->q.class = (p[0] << 8 | p[1]);
46755682Smarkm    p += 2;
468107207Snectar
46955682Smarkm    rr = &r->head;
470178825Sdfr    for(i = 0; i < r->h.ancount; i++) {
471107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
47255682Smarkm	    dns_free_data(r);
47355682Smarkm	    return NULL;
47455682Smarkm	}
475107207Snectar	rr = &(*rr)->next;
476107207Snectar    }
477178825Sdfr    for(i = 0; i < r->h.nscount; i++) {
478107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
479102644Snectar	    dns_free_data(r);
480102644Snectar	    return NULL;
481102644Snectar	}
482107207Snectar	rr = &(*rr)->next;
483107207Snectar    }
484178825Sdfr    for(i = 0; i < r->h.arcount; i++) {
485107207Snectar	if(parse_record(data, end_data, &p, rr) != 0) {
486102644Snectar	    dns_free_data(r);
487102644Snectar	    return NULL;
488102644Snectar	}
48955682Smarkm	rr = &(*rr)->next;
49055682Smarkm    }
49155682Smarkm    *rr = NULL;
49255682Smarkm    return r;
49355682Smarkm}
49455682Smarkm
495178825Sdfr#ifdef HAVE_RES_NSEARCH
496178825Sdfr#ifdef HAVE_RES_NDESTROY
497178825Sdfr#define rk_res_free(x) res_ndestroy(x)
498178825Sdfr#else
499178825Sdfr#define rk_res_free(x) res_nclose(x)
500178825Sdfr#endif
501178825Sdfr#endif
502178825Sdfr
50355682Smarkmstatic struct dns_reply *
50455682Smarkmdns_lookup_int(const char *domain, int rr_class, int rr_type)
50555682Smarkm{
506178825Sdfr    struct dns_reply *r;
507178825Sdfr    unsigned char *reply = NULL;
508178825Sdfr    int size;
50955682Smarkm    int len;
510103423Snectar#ifdef HAVE_RES_NSEARCH
511178825Sdfr    struct __res_state state;
512178825Sdfr    memset(&state, 0, sizeof(state));
513178825Sdfr    if(res_ninit(&state))
514103423Snectar	return NULL; /* is this the best we can do? */
515103423Snectar#elif defined(HAVE__RES)
51655682Smarkm    u_long old_options = 0;
517102644Snectar#endif
51855682Smarkm
519178825Sdfr    size = 0;
520178825Sdfr    len = 1000;
521178825Sdfr    do {
522178825Sdfr	if (reply) {
523178825Sdfr	    free(reply);
524178825Sdfr	    reply = NULL;
525178825Sdfr	}
526178825Sdfr	if (size <= len)
527178825Sdfr	    size = len;
528178825Sdfr	if (_resolve_debug) {
529103423Snectar#ifdef HAVE_RES_NSEARCH
530178825Sdfr	    state.options |= RES_DEBUG;
531103423Snectar#elif defined(HAVE__RES)
532178825Sdfr	    old_options = _res.options;
533178825Sdfr	    _res.options |= RES_DEBUG;
534102644Snectar#endif
535178825Sdfr	    fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
536178825Sdfr		    rr_class, dns_type_to_string(rr_type), size);
537178825Sdfr	}
538178825Sdfr	reply = malloc(size);
539178825Sdfr	if (reply == NULL) {
540103423Snectar#ifdef HAVE_RES_NSEARCH
541178825Sdfr	    rk_res_free(&state);
542178825Sdfr#endif
543178825Sdfr	    return NULL;
544178825Sdfr	}
545178825Sdfr#ifdef HAVE_RES_NSEARCH
546178825Sdfr	len = res_nsearch(&state, domain, rr_class, rr_type, reply, size);
547103423Snectar#else
548178825Sdfr	len = res_search(domain, rr_class, rr_type, reply, size);
549103423Snectar#endif
550178825Sdfr	if (_resolve_debug) {
551103423Snectar#if defined(HAVE__RES) && !defined(HAVE_RES_NSEARCH)
552178825Sdfr	    _res.options = old_options;
553102644Snectar#endif
554178825Sdfr	    fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
555178825Sdfr		    domain, rr_class, dns_type_to_string(rr_type), len);
556178825Sdfr	}
557178825Sdfr	if (len < 0) {
558103423Snectar#ifdef HAVE_RES_NSEARCH
559178825Sdfr	    rk_res_free(&state);
560178825Sdfr#endif
561178825Sdfr	    free(reply);
562178825Sdfr	    return NULL;
563178825Sdfr	}
564178825Sdfr    } while (size < len && len < rk_DNS_MAX_PACKET_SIZE);
565178825Sdfr#ifdef HAVE_RES_NSEARCH
566178825Sdfr    rk_res_free(&state);
567178825Sdfr#endif
568178825Sdfr
569178825Sdfr    len = min(len, size);
570178825Sdfr    r = parse_reply(reply, len);
571178825Sdfr    free(reply);
572178825Sdfr    return r;
57355682Smarkm}
57455682Smarkm
575178825Sdfrstruct dns_reply * ROKEN_LIB_FUNCTION
57655682Smarkmdns_lookup(const char *domain, const char *type_name)
57755682Smarkm{
57855682Smarkm    int type;
57955682Smarkm
58072445Sassar    type = dns_string_to_type(type_name);
58155682Smarkm    if(type == -1) {
58255682Smarkm	if(_resolve_debug)
58355682Smarkm	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
58455682Smarkm		    type_name);
58555682Smarkm	return NULL;
58655682Smarkm    }
58755682Smarkm    return dns_lookup_int(domain, C_IN, type);
58855682Smarkm}
58955682Smarkm
59090926Snectarstatic int
59190926Snectarcompare_srv(const void *a, const void *b)
59290926Snectar{
59390926Snectar    const struct resource_record *const* aa = a, *const* bb = b;
59490926Snectar
59590926Snectar    if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
59690926Snectar	return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
59790926Snectar    return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
59890926Snectar}
59990926Snectar
60090926Snectar#ifndef HAVE_RANDOM
60190926Snectar#define random() rand()
60290926Snectar#endif
60390926Snectar
60490926Snectar/* try to rearrange the srv-records by the algorithm in RFC2782 */
605178825Sdfrvoid ROKEN_LIB_FUNCTION
60690926Snectardns_srv_order(struct dns_reply *r)
60790926Snectar{
60890926Snectar    struct resource_record **srvs, **ss, **headp;
60990926Snectar    struct resource_record *rr;
61090926Snectar    int num_srv = 0;
61190926Snectar
61290926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
613102644Snectar    int state[256 / sizeof(int)];
614102644Snectar    char *oldstate;
61590926Snectar#endif
61690926Snectar
61790926Snectar    for(rr = r->head; rr; rr = rr->next)
618178825Sdfr	if(rr->type == rk_ns_t_srv)
61990926Snectar	    num_srv++;
62090926Snectar
62190926Snectar    if(num_srv == 0)
62290926Snectar	return;
62390926Snectar
62490926Snectar    srvs = malloc(num_srv * sizeof(*srvs));
62590926Snectar    if(srvs == NULL)
62690926Snectar	return; /* XXX not much to do here */
62790926Snectar
62890926Snectar    /* unlink all srv-records from the linked list and put them in
62990926Snectar       a vector */
63090926Snectar    for(ss = srvs, headp = &r->head; *headp; )
631178825Sdfr	if((*headp)->type == rk_ns_t_srv) {
63290926Snectar	    *ss = *headp;
63390926Snectar	    *headp = (*headp)->next;
63490926Snectar	    (*ss)->next = NULL;
63590926Snectar	    ss++;
63690926Snectar	} else
63790926Snectar	    headp = &(*headp)->next;
63890926Snectar
63990926Snectar    /* sort them by priority and weight */
64090926Snectar    qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
64190926Snectar
64290926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
643102644Snectar    oldstate = initstate(time(NULL), (char*)state, sizeof(state));
64490926Snectar#endif
64590926Snectar
64690926Snectar    headp = &r->head;
64790926Snectar
64890926Snectar    for(ss = srvs; ss < srvs + num_srv; ) {
64990926Snectar	int sum, rnd, count;
65090926Snectar	struct resource_record **ee, **tt;
65190926Snectar	/* find the last record with the same priority and count the
65290926Snectar           sum of all weights */
65390926Snectar	for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
654178825Sdfr	    assert(*tt != NULL);
65590926Snectar	    if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
65690926Snectar		break;
65790926Snectar	    sum += (*tt)->u.srv->weight;
65890926Snectar	}
65990926Snectar	ee = tt;
66090926Snectar	/* ss is now the first record of this priority and ee is the
66190926Snectar           first of the next */
66290926Snectar	while(ss < ee) {
66390926Snectar	    rnd = random() % (sum + 1);
66490926Snectar	    for(count = 0, tt = ss; ; tt++) {
66590926Snectar		if(*tt == NULL)
66690926Snectar		    continue;
66790926Snectar		count += (*tt)->u.srv->weight;
66890926Snectar		if(count >= rnd)
66990926Snectar		    break;
67090926Snectar	    }
67190926Snectar
67290926Snectar	    assert(tt < ee);
67390926Snectar
67490926Snectar	    /* insert the selected record at the tail (of the head) of
67590926Snectar               the list */
67690926Snectar	    (*tt)->next = *headp;
67790926Snectar	    *headp = *tt;
67890926Snectar	    headp = &(*tt)->next;
67990926Snectar	    sum -= (*tt)->u.srv->weight;
68090926Snectar	    *tt = NULL;
68190926Snectar	    while(ss < ee && *ss == NULL)
68290926Snectar		ss++;
68390926Snectar	}
68490926Snectar    }
68590926Snectar
68690926Snectar#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
68790926Snectar    setstate(oldstate);
68890926Snectar#endif
68990926Snectar    free(srvs);
69090926Snectar    return;
69190926Snectar}
69290926Snectar
69355682Smarkm#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
69455682Smarkm
695178825Sdfrstruct dns_reply * ROKEN_LIB_FUNCTION
69655682Smarkmdns_lookup(const char *domain, const char *type_name)
69755682Smarkm{
69855682Smarkm    return NULL;
69955682Smarkm}
70055682Smarkm
701178825Sdfrvoid ROKEN_LIB_FUNCTION
70255682Smarkmdns_free_data(struct dns_reply *r)
70355682Smarkm{
70455682Smarkm}
70555682Smarkm
706178825Sdfrvoid ROKEN_LIB_FUNCTION
70790926Snectardns_srv_order(struct dns_reply *r)
70890926Snectar{
70990926Snectar}
71090926Snectar
71155682Smarkm#endif
712