xref: /minix3/crypto/external/bsd/heimdal/dist/lib/roken/resolve.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: resolve.c,v 1.4 2014/04/24 14:49:43 pettai Exp $	*/
2ebfedea0SLionel Sambuc 
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc  * Copyright (c) 1995 - 2006 Kungliga Tekniska Högskolan
5ebfedea0SLionel Sambuc  * (Royal Institute of Technology, Stockholm, Sweden).
6ebfedea0SLionel Sambuc  * All rights reserved.
7ebfedea0SLionel Sambuc  *
8ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
9ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
10ebfedea0SLionel Sambuc  * are met:
11ebfedea0SLionel Sambuc  *
12ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
13ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
14ebfedea0SLionel Sambuc  *
15ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18ebfedea0SLionel Sambuc  *
19ebfedea0SLionel Sambuc  * 3. Neither the name of the Institute nor the names of its contributors
20ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
21ebfedea0SLionel Sambuc  *    without specific prior written permission.
22ebfedea0SLionel Sambuc  *
23ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ebfedea0SLionel Sambuc  * SUCH DAMAGE.
34ebfedea0SLionel Sambuc  */
35ebfedea0SLionel Sambuc 
36ebfedea0SLionel Sambuc 
37ebfedea0SLionel Sambuc #include <config.h>
38ebfedea0SLionel Sambuc 
39ebfedea0SLionel Sambuc #include <krb5/roken.h>
40ebfedea0SLionel Sambuc #ifdef HAVE_ARPA_NAMESER_H
41ebfedea0SLionel Sambuc #include <arpa/nameser.h>
42ebfedea0SLionel Sambuc #endif
43ebfedea0SLionel Sambuc #ifdef HAVE_RESOLV_H
44ebfedea0SLionel Sambuc #include <resolv.h>
45ebfedea0SLionel Sambuc #endif
46ebfedea0SLionel Sambuc #ifdef HAVE_DNS_H
47ebfedea0SLionel Sambuc #include <dns.h>
48ebfedea0SLionel Sambuc #endif
49ebfedea0SLionel Sambuc #include <krb5/resolve.h>
50ebfedea0SLionel Sambuc 
51ebfedea0SLionel Sambuc #include <assert.h>
52ebfedea0SLionel Sambuc 
53ebfedea0SLionel Sambuc #ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
54ebfedea0SLionel Sambuc #undef HAVE_RES_NSEARCH
55ebfedea0SLionel Sambuc #endif
56ebfedea0SLionel Sambuc 
57ebfedea0SLionel Sambuc #define DECL(X) {#X, rk_ns_t_##X}
58ebfedea0SLionel Sambuc 
59ebfedea0SLionel Sambuc static struct stot{
60ebfedea0SLionel Sambuc     const char *name;
61ebfedea0SLionel Sambuc     int type;
62ebfedea0SLionel Sambuc }stot[] = {
63ebfedea0SLionel Sambuc     DECL(a),
64ebfedea0SLionel Sambuc     DECL(aaaa),
65ebfedea0SLionel Sambuc     DECL(ns),
66ebfedea0SLionel Sambuc     DECL(cname),
67ebfedea0SLionel Sambuc     DECL(soa),
68ebfedea0SLionel Sambuc     DECL(ptr),
69ebfedea0SLionel Sambuc     DECL(mx),
70ebfedea0SLionel Sambuc     DECL(txt),
71ebfedea0SLionel Sambuc     DECL(afsdb),
72ebfedea0SLionel Sambuc     DECL(sig),
73ebfedea0SLionel Sambuc     DECL(key),
74ebfedea0SLionel Sambuc     DECL(srv),
75ebfedea0SLionel Sambuc     DECL(naptr),
76ebfedea0SLionel Sambuc     DECL(sshfp),
77ebfedea0SLionel Sambuc     DECL(ds),
78ebfedea0SLionel Sambuc     {NULL, 	0}
79ebfedea0SLionel Sambuc };
80ebfedea0SLionel Sambuc 
81ebfedea0SLionel Sambuc int _resolve_debug = 0;
82ebfedea0SLionel Sambuc 
83ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_dns_string_to_type(const char * name)84ebfedea0SLionel Sambuc rk_dns_string_to_type(const char *name)
85ebfedea0SLionel Sambuc {
86ebfedea0SLionel Sambuc     struct stot *p = stot;
87ebfedea0SLionel Sambuc     for(p = stot; p->name; p++)
88ebfedea0SLionel Sambuc 	if(strcasecmp(name, p->name) == 0)
89ebfedea0SLionel Sambuc 	    return p->type;
90ebfedea0SLionel Sambuc     return -1;
91ebfedea0SLionel Sambuc }
92ebfedea0SLionel Sambuc 
93ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION const char * ROKEN_LIB_CALL
rk_dns_type_to_string(int type)94ebfedea0SLionel Sambuc rk_dns_type_to_string(int type)
95ebfedea0SLionel Sambuc {
96ebfedea0SLionel Sambuc     struct stot *p = stot;
97ebfedea0SLionel Sambuc     for(p = stot; p->name; p++)
98ebfedea0SLionel Sambuc 	if(type == p->type)
99ebfedea0SLionel Sambuc 	    return p->name;
100ebfedea0SLionel Sambuc     return NULL;
101ebfedea0SLionel Sambuc }
102ebfedea0SLionel Sambuc 
103ebfedea0SLionel Sambuc #if ((defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)) || defined(HAVE_WINDNS)
104ebfedea0SLionel Sambuc 
105ebfedea0SLionel Sambuc static void
dns_free_rr(struct rk_resource_record * rr)106ebfedea0SLionel Sambuc dns_free_rr(struct rk_resource_record *rr)
107ebfedea0SLionel Sambuc {
108ebfedea0SLionel Sambuc     if(rr->domain)
109ebfedea0SLionel Sambuc 	free(rr->domain);
110ebfedea0SLionel Sambuc     if(rr->u.data)
111ebfedea0SLionel Sambuc 	free(rr->u.data);
112ebfedea0SLionel Sambuc     free(rr);
113ebfedea0SLionel Sambuc }
114ebfedea0SLionel Sambuc 
115ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rk_dns_free_data(struct rk_dns_reply * r)116ebfedea0SLionel Sambuc rk_dns_free_data(struct rk_dns_reply *r)
117ebfedea0SLionel Sambuc {
118ebfedea0SLionel Sambuc     struct rk_resource_record *rr;
119ebfedea0SLionel Sambuc     if(r->q.domain)
120ebfedea0SLionel Sambuc 	free(r->q.domain);
121ebfedea0SLionel Sambuc     for(rr = r->head; rr;){
122ebfedea0SLionel Sambuc 	struct rk_resource_record *tmp = rr;
123ebfedea0SLionel Sambuc 	rr = rr->next;
124ebfedea0SLionel Sambuc 	dns_free_rr(tmp);
125ebfedea0SLionel Sambuc     }
126ebfedea0SLionel Sambuc     free (r);
127ebfedea0SLionel Sambuc }
128ebfedea0SLionel Sambuc 
129ebfedea0SLionel Sambuc #ifndef HAVE_WINDNS
130ebfedea0SLionel Sambuc 
131ebfedea0SLionel Sambuc static int
parse_record(const unsigned char * data,const unsigned char * end_data,const unsigned char ** pp,struct rk_resource_record ** ret_rr)132ebfedea0SLionel Sambuc parse_record(const unsigned char *data, const unsigned char *end_data,
133ebfedea0SLionel Sambuc 	     const unsigned char **pp, struct rk_resource_record **ret_rr)
134ebfedea0SLionel Sambuc {
135ebfedea0SLionel Sambuc     struct rk_resource_record *rr;
136ebfedea0SLionel Sambuc     int type, class, ttl;
137ebfedea0SLionel Sambuc     unsigned size;
138ebfedea0SLionel Sambuc     int status;
139ebfedea0SLionel Sambuc     char host[MAXDNAME];
140ebfedea0SLionel Sambuc     const unsigned char *p = *pp;
141ebfedea0SLionel Sambuc 
142ebfedea0SLionel Sambuc     *ret_rr = NULL;
143ebfedea0SLionel Sambuc 
144ebfedea0SLionel Sambuc     status = dn_expand(data, end_data, p, host, sizeof(host));
145ebfedea0SLionel Sambuc     if(status < 0)
146ebfedea0SLionel Sambuc 	return -1;
147ebfedea0SLionel Sambuc     if (p + status + 10 > end_data)
148ebfedea0SLionel Sambuc 	return -1;
149ebfedea0SLionel Sambuc 
150ebfedea0SLionel Sambuc     p += status;
151ebfedea0SLionel Sambuc     type = (p[0] << 8) | p[1];
152ebfedea0SLionel Sambuc     p += 2;
153ebfedea0SLionel Sambuc     class = (p[0] << 8) | p[1];
154ebfedea0SLionel Sambuc     p += 2;
155ebfedea0SLionel Sambuc     ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
156ebfedea0SLionel Sambuc     p += 4;
157ebfedea0SLionel Sambuc     size = (p[0] << 8) | p[1];
158ebfedea0SLionel Sambuc     p += 2;
159ebfedea0SLionel Sambuc 
160ebfedea0SLionel Sambuc     if (p + size > end_data)
161ebfedea0SLionel Sambuc 	return -1;
162ebfedea0SLionel Sambuc 
163ebfedea0SLionel Sambuc     rr = calloc(1, sizeof(*rr));
164ebfedea0SLionel Sambuc     if(rr == NULL)
165ebfedea0SLionel Sambuc 	return -1;
166ebfedea0SLionel Sambuc     rr->domain = strdup(host);
167ebfedea0SLionel Sambuc     if(rr->domain == NULL) {
168ebfedea0SLionel Sambuc 	dns_free_rr(rr);
169ebfedea0SLionel Sambuc 	return -1;
170ebfedea0SLionel Sambuc     }
171ebfedea0SLionel Sambuc     rr->type = type;
172ebfedea0SLionel Sambuc     rr->class = class;
173ebfedea0SLionel Sambuc     rr->ttl = ttl;
174ebfedea0SLionel Sambuc     rr->size = size;
175ebfedea0SLionel Sambuc     switch(type){
176ebfedea0SLionel Sambuc     case rk_ns_t_ns:
177ebfedea0SLionel Sambuc     case rk_ns_t_cname:
178ebfedea0SLionel Sambuc     case rk_ns_t_ptr:
179ebfedea0SLionel Sambuc 	status = dn_expand(data, end_data, p, host, sizeof(host));
180ebfedea0SLionel Sambuc 	if(status < 0) {
181ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
182ebfedea0SLionel Sambuc 	    return -1;
183ebfedea0SLionel Sambuc 	}
184ebfedea0SLionel Sambuc 	rr->u.txt = strdup(host);
185ebfedea0SLionel Sambuc 	if(rr->u.txt == NULL) {
186ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
187ebfedea0SLionel Sambuc 	    return -1;
188ebfedea0SLionel Sambuc 	}
189ebfedea0SLionel Sambuc 	break;
190ebfedea0SLionel Sambuc     case rk_ns_t_mx:
191ebfedea0SLionel Sambuc     case rk_ns_t_afsdb:{
192ebfedea0SLionel Sambuc 	size_t hostlen;
193ebfedea0SLionel Sambuc 
194ebfedea0SLionel Sambuc 	status = dn_expand(data, end_data, p + 2, host, sizeof(host));
195ebfedea0SLionel Sambuc 	if(status < 0){
196ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
197ebfedea0SLionel Sambuc 	    return -1;
198ebfedea0SLionel Sambuc 	}
199*0a6a1f1dSLionel Sambuc 	if ((size_t)status + 2 > size) {
200ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
201ebfedea0SLionel Sambuc 	    return -1;
202ebfedea0SLionel Sambuc 	}
203ebfedea0SLionel Sambuc 
204ebfedea0SLionel Sambuc 	hostlen = strlen(host);
205ebfedea0SLionel Sambuc 	rr->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
206ebfedea0SLionel Sambuc 						hostlen);
207ebfedea0SLionel Sambuc 	if(rr->u.mx == NULL) {
208ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
209ebfedea0SLionel Sambuc 	    return -1;
210ebfedea0SLionel Sambuc 	}
211ebfedea0SLionel Sambuc 	rr->u.mx->preference = (p[0] << 8) | p[1];
212ebfedea0SLionel Sambuc 	strlcpy(rr->u.mx->domain, host, hostlen + 1);
213ebfedea0SLionel Sambuc 	break;
214ebfedea0SLionel Sambuc     }
215ebfedea0SLionel Sambuc     case rk_ns_t_srv:{
216ebfedea0SLionel Sambuc 	size_t hostlen;
217ebfedea0SLionel Sambuc 	status = dn_expand(data, end_data, p + 6, host, sizeof(host));
218ebfedea0SLionel Sambuc 	if(status < 0){
219ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
220ebfedea0SLionel Sambuc 	    return -1;
221ebfedea0SLionel Sambuc 	}
222*0a6a1f1dSLionel Sambuc 	if ((size_t)status + 6 > size) {
223ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
224ebfedea0SLionel Sambuc 	    return -1;
225ebfedea0SLionel Sambuc 	}
226ebfedea0SLionel Sambuc 
227ebfedea0SLionel Sambuc 	hostlen = strlen(host);
228ebfedea0SLionel Sambuc 	rr->u.srv =
229ebfedea0SLionel Sambuc 	    (struct srv_record*)malloc(sizeof(struct srv_record) +
230ebfedea0SLionel Sambuc 				       hostlen);
231ebfedea0SLionel Sambuc 	if(rr->u.srv == NULL) {
232ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
233ebfedea0SLionel Sambuc 	    return -1;
234ebfedea0SLionel Sambuc 	}
235ebfedea0SLionel Sambuc 	rr->u.srv->priority = (p[0] << 8) | p[1];
236ebfedea0SLionel Sambuc 	rr->u.srv->weight = (p[2] << 8) | p[3];
237ebfedea0SLionel Sambuc 	rr->u.srv->port = (p[4] << 8) | p[5];
238ebfedea0SLionel Sambuc 	strlcpy(rr->u.srv->target, host, hostlen + 1);
239ebfedea0SLionel Sambuc 	break;
240ebfedea0SLionel Sambuc     }
241ebfedea0SLionel Sambuc     case rk_ns_t_txt:{
242*0a6a1f1dSLionel Sambuc 	if(size == 0 || size < (unsigned)(*p + 1)) {
243ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
244ebfedea0SLionel Sambuc 	    return -1;
245ebfedea0SLionel Sambuc 	}
246ebfedea0SLionel Sambuc 	rr->u.txt = (char*)malloc(*p + 1);
247ebfedea0SLionel Sambuc 	if(rr->u.txt == NULL) {
248ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
249ebfedea0SLionel Sambuc 	    return -1;
250ebfedea0SLionel Sambuc 	}
251ebfedea0SLionel Sambuc 	strncpy(rr->u.txt, (const char*)(p + 1), *p);
252ebfedea0SLionel Sambuc 	rr->u.txt[*p] = '\0';
253ebfedea0SLionel Sambuc 	break;
254ebfedea0SLionel Sambuc     }
255ebfedea0SLionel Sambuc     case rk_ns_t_key : {
256ebfedea0SLionel Sambuc 	size_t key_len;
257ebfedea0SLionel Sambuc 
258ebfedea0SLionel Sambuc 	if (size < 4) {
259ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
260ebfedea0SLionel Sambuc 	    return -1;
261ebfedea0SLionel Sambuc 	}
262ebfedea0SLionel Sambuc 
263ebfedea0SLionel Sambuc 	key_len = size - 4;
264ebfedea0SLionel Sambuc 	rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
265ebfedea0SLionel Sambuc 	if (rr->u.key == NULL) {
266ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
267ebfedea0SLionel Sambuc 	    return -1;
268ebfedea0SLionel Sambuc 	}
269ebfedea0SLionel Sambuc 
270ebfedea0SLionel Sambuc 	rr->u.key->flags     = (p[0] << 8) | p[1];
271ebfedea0SLionel Sambuc 	rr->u.key->protocol  = p[2];
272ebfedea0SLionel Sambuc 	rr->u.key->algorithm = p[3];
273ebfedea0SLionel Sambuc 	rr->u.key->key_len   = key_len;
274ebfedea0SLionel Sambuc 	memcpy (rr->u.key->key_data, p + 4, key_len);
275ebfedea0SLionel Sambuc 	break;
276ebfedea0SLionel Sambuc     }
277ebfedea0SLionel Sambuc     case rk_ns_t_sig : {
278ebfedea0SLionel Sambuc 	size_t sig_len, hostlen;
279ebfedea0SLionel Sambuc 
280ebfedea0SLionel Sambuc 	if(size <= 18) {
281ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
282ebfedea0SLionel Sambuc 	    return -1;
283ebfedea0SLionel Sambuc 	}
284ebfedea0SLionel Sambuc 	status = dn_expand (data, end_data, p + 18, host, sizeof(host));
285ebfedea0SLionel Sambuc 	if (status < 0) {
286ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
287ebfedea0SLionel Sambuc 	    return -1;
288ebfedea0SLionel Sambuc 	}
289*0a6a1f1dSLionel Sambuc 	if ((size_t)status + 18 > size) {
290ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
291ebfedea0SLionel Sambuc 	    return -1;
292ebfedea0SLionel Sambuc 	}
293ebfedea0SLionel Sambuc 
294ebfedea0SLionel Sambuc 	/* the signer name is placed after the sig_data, to make it
295ebfedea0SLionel Sambuc            easy to free this structure; the size calculation below
296ebfedea0SLionel Sambuc            includes the zero-termination if the structure itself.
297ebfedea0SLionel Sambuc 	   don't you just love C?
298ebfedea0SLionel Sambuc 	*/
299ebfedea0SLionel Sambuc 	sig_len = size - 18 - status;
300ebfedea0SLionel Sambuc 	hostlen = strlen(host);
301ebfedea0SLionel Sambuc 	rr->u.sig = malloc(sizeof(*rr->u.sig)
302ebfedea0SLionel Sambuc 			      + hostlen + sig_len);
303ebfedea0SLionel Sambuc 	if (rr->u.sig == NULL) {
304ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
305ebfedea0SLionel Sambuc 	    return -1;
306ebfedea0SLionel Sambuc 	}
307ebfedea0SLionel Sambuc 	rr->u.sig->type           = (p[0] << 8) | p[1];
308ebfedea0SLionel Sambuc 	rr->u.sig->algorithm      = p[2];
309ebfedea0SLionel Sambuc 	rr->u.sig->labels         = p[3];
310ebfedea0SLionel Sambuc 	rr->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
311ebfedea0SLionel Sambuc 	    | (p[6] << 8) | p[7];
312ebfedea0SLionel Sambuc 	rr->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
313ebfedea0SLionel Sambuc 	    | (p[10] << 8) | p[11];
314ebfedea0SLionel Sambuc 	rr->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
315ebfedea0SLionel Sambuc 	    | (p[14] << 8) | p[15];
316ebfedea0SLionel Sambuc 	rr->u.sig->key_tag        = (p[16] << 8) | p[17];
317ebfedea0SLionel Sambuc 	rr->u.sig->sig_len        = sig_len;
318ebfedea0SLionel Sambuc 	memcpy (rr->u.sig->sig_data, p + 18 + status, sig_len);
319ebfedea0SLionel Sambuc 	rr->u.sig->signer         = &rr->u.sig->sig_data[sig_len];
320ebfedea0SLionel Sambuc 	strlcpy(rr->u.sig->signer, host, hostlen + 1);
321ebfedea0SLionel Sambuc 	break;
322ebfedea0SLionel Sambuc     }
323ebfedea0SLionel Sambuc 
324ebfedea0SLionel Sambuc     case rk_ns_t_cert : {
325ebfedea0SLionel Sambuc 	size_t cert_len;
326ebfedea0SLionel Sambuc 
327ebfedea0SLionel Sambuc 	if (size < 5) {
328ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
329ebfedea0SLionel Sambuc 	    return -1;
330ebfedea0SLionel Sambuc 	}
331ebfedea0SLionel Sambuc 
332ebfedea0SLionel Sambuc 	cert_len = size - 5;
333ebfedea0SLionel Sambuc 	rr->u.cert = malloc (sizeof(*rr->u.cert) + cert_len - 1);
334ebfedea0SLionel Sambuc 	if (rr->u.cert == NULL) {
335ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
336ebfedea0SLionel Sambuc 	    return -1;
337ebfedea0SLionel Sambuc 	}
338ebfedea0SLionel Sambuc 
339ebfedea0SLionel Sambuc 	rr->u.cert->type      = (p[0] << 8) | p[1];
340ebfedea0SLionel Sambuc 	rr->u.cert->tag       = (p[2] << 8) | p[3];
341ebfedea0SLionel Sambuc 	rr->u.cert->algorithm = p[4];
342ebfedea0SLionel Sambuc 	rr->u.cert->cert_len  = cert_len;
343ebfedea0SLionel Sambuc 	memcpy (rr->u.cert->cert_data, p + 5, cert_len);
344ebfedea0SLionel Sambuc 	break;
345ebfedea0SLionel Sambuc     }
346ebfedea0SLionel Sambuc     case rk_ns_t_sshfp : {
347ebfedea0SLionel Sambuc 	size_t sshfp_len;
348ebfedea0SLionel Sambuc 
349ebfedea0SLionel Sambuc 	if (size < 2) {
350ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
351ebfedea0SLionel Sambuc 	    return -1;
352ebfedea0SLionel Sambuc 	}
353ebfedea0SLionel Sambuc 
354ebfedea0SLionel Sambuc 	sshfp_len = size - 2;
355ebfedea0SLionel Sambuc 
356ebfedea0SLionel Sambuc 	rr->u.sshfp = malloc (sizeof(*rr->u.sshfp) + sshfp_len - 1);
357ebfedea0SLionel Sambuc 	if (rr->u.sshfp == NULL) {
358ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
359ebfedea0SLionel Sambuc 	    return -1;
360ebfedea0SLionel Sambuc 	}
361ebfedea0SLionel Sambuc 
362ebfedea0SLionel Sambuc 	rr->u.sshfp->algorithm = p[0];
363ebfedea0SLionel Sambuc 	rr->u.sshfp->type      = p[1];
364ebfedea0SLionel Sambuc 	rr->u.sshfp->sshfp_len  = sshfp_len;
365ebfedea0SLionel Sambuc 	memcpy (rr->u.sshfp->sshfp_data, p + 2, sshfp_len);
366ebfedea0SLionel Sambuc 	break;
367ebfedea0SLionel Sambuc     }
368ebfedea0SLionel Sambuc     case rk_ns_t_ds: {
369ebfedea0SLionel Sambuc 	size_t digest_len;
370ebfedea0SLionel Sambuc 
371ebfedea0SLionel Sambuc 	if (size < 4) {
372ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
373ebfedea0SLionel Sambuc 	    return -1;
374ebfedea0SLionel Sambuc 	}
375ebfedea0SLionel Sambuc 
376ebfedea0SLionel Sambuc 	digest_len = size - 4;
377ebfedea0SLionel Sambuc 
378ebfedea0SLionel Sambuc 	rr->u.ds = malloc (sizeof(*rr->u.ds) + digest_len - 1);
379ebfedea0SLionel Sambuc 	if (rr->u.ds == NULL) {
380ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
381ebfedea0SLionel Sambuc 	    return -1;
382ebfedea0SLionel Sambuc 	}
383ebfedea0SLionel Sambuc 
384ebfedea0SLionel Sambuc 	rr->u.ds->key_tag     = (p[0] << 8) | p[1];
385ebfedea0SLionel Sambuc 	rr->u.ds->algorithm   = p[2];
386ebfedea0SLionel Sambuc 	rr->u.ds->digest_type = p[3];
387ebfedea0SLionel Sambuc 	rr->u.ds->digest_len  = digest_len;
388ebfedea0SLionel Sambuc 	memcpy (rr->u.ds->digest_data, p + 4, digest_len);
389ebfedea0SLionel Sambuc 	break;
390ebfedea0SLionel Sambuc     }
391ebfedea0SLionel Sambuc     default:
392ebfedea0SLionel Sambuc 	rr->u.data = (unsigned char*)malloc(size);
393ebfedea0SLionel Sambuc 	if(size != 0 && rr->u.data == NULL) {
394ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
395ebfedea0SLionel Sambuc 	    return -1;
396ebfedea0SLionel Sambuc 	}
397ebfedea0SLionel Sambuc 	if (size)
398ebfedea0SLionel Sambuc 	    memcpy(rr->u.data, p, size);
399ebfedea0SLionel Sambuc     }
400ebfedea0SLionel Sambuc     *pp = p + size;
401ebfedea0SLionel Sambuc     *ret_rr = rr;
402ebfedea0SLionel Sambuc 
403ebfedea0SLionel Sambuc     return 0;
404ebfedea0SLionel Sambuc }
405ebfedea0SLionel Sambuc 
406ebfedea0SLionel Sambuc #ifndef TEST_RESOLVE
407ebfedea0SLionel Sambuc static
408ebfedea0SLionel Sambuc #endif
409ebfedea0SLionel Sambuc struct rk_dns_reply*
parse_reply(const unsigned char * data,size_t len)410ebfedea0SLionel Sambuc parse_reply(const unsigned char *data, size_t len)
411ebfedea0SLionel Sambuc {
412ebfedea0SLionel Sambuc     const unsigned char *p;
413ebfedea0SLionel Sambuc     int status;
414*0a6a1f1dSLionel Sambuc     size_t i;
415ebfedea0SLionel Sambuc     char host[MAXDNAME];
416ebfedea0SLionel Sambuc     const unsigned char *end_data = data + len;
417ebfedea0SLionel Sambuc     struct rk_dns_reply *r;
418ebfedea0SLionel Sambuc     struct rk_resource_record **rr;
419ebfedea0SLionel Sambuc 
420ebfedea0SLionel Sambuc     r = calloc(1, sizeof(*r));
421ebfedea0SLionel Sambuc     if (r == NULL)
422ebfedea0SLionel Sambuc 	return NULL;
423ebfedea0SLionel Sambuc 
424ebfedea0SLionel Sambuc     p = data;
425ebfedea0SLionel Sambuc 
426ebfedea0SLionel Sambuc     r->h.id = (p[0] << 8) | p[1];
427ebfedea0SLionel Sambuc     r->h.flags = 0;
428ebfedea0SLionel Sambuc     if (p[2] & 0x01)
429ebfedea0SLionel Sambuc 	r->h.flags |= rk_DNS_HEADER_RESPONSE_FLAG;
430ebfedea0SLionel Sambuc     r->h.opcode = (p[2] >> 1) & 0xf;
431ebfedea0SLionel Sambuc     if (p[2] & 0x20)
432ebfedea0SLionel Sambuc 	r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
433ebfedea0SLionel Sambuc     if (p[2] & 0x40)
434ebfedea0SLionel Sambuc 	r->h.flags |= rk_DNS_HEADER_TRUNCATED_MESSAGE;
435ebfedea0SLionel Sambuc     if (p[2] & 0x80)
436ebfedea0SLionel Sambuc 	r->h.flags |= rk_DNS_HEADER_RECURSION_DESIRED;
437ebfedea0SLionel Sambuc     if (p[3] & 0x01)
438ebfedea0SLionel Sambuc 	r->h.flags |= rk_DNS_HEADER_RECURSION_AVAILABLE;
439ebfedea0SLionel Sambuc     if (p[3] & 0x04)
440ebfedea0SLionel Sambuc 	r->h.flags |= rk_DNS_HEADER_AUTHORITIVE_ANSWER;
441ebfedea0SLionel Sambuc     if (p[3] & 0x08)
442ebfedea0SLionel Sambuc 	r->h.flags |= rk_DNS_HEADER_CHECKING_DISABLED;
443ebfedea0SLionel Sambuc     r->h.response_code = (p[3] >> 4) & 0xf;
444ebfedea0SLionel Sambuc     r->h.qdcount = (p[4] << 8) | p[5];
445ebfedea0SLionel Sambuc     r->h.ancount = (p[6] << 8) | p[7];
446ebfedea0SLionel Sambuc     r->h.nscount = (p[8] << 8) | p[9];
447ebfedea0SLionel Sambuc     r->h.arcount = (p[10] << 8) | p[11];
448ebfedea0SLionel Sambuc 
449ebfedea0SLionel Sambuc     p += 12;
450ebfedea0SLionel Sambuc 
451ebfedea0SLionel Sambuc     if(r->h.qdcount != 1) {
452ebfedea0SLionel Sambuc 	free(r);
453ebfedea0SLionel Sambuc 	return NULL;
454ebfedea0SLionel Sambuc     }
455ebfedea0SLionel Sambuc     status = dn_expand(data, end_data, p, host, sizeof(host));
456ebfedea0SLionel Sambuc     if(status < 0){
457ebfedea0SLionel Sambuc 	rk_dns_free_data(r);
458ebfedea0SLionel Sambuc 	return NULL;
459ebfedea0SLionel Sambuc     }
460ebfedea0SLionel Sambuc     r->q.domain = strdup(host);
461ebfedea0SLionel Sambuc     if(r->q.domain == NULL) {
462ebfedea0SLionel Sambuc 	rk_dns_free_data(r);
463ebfedea0SLionel Sambuc 	return NULL;
464ebfedea0SLionel Sambuc     }
465ebfedea0SLionel Sambuc     if (p + status + 4 > end_data) {
466ebfedea0SLionel Sambuc 	rk_dns_free_data(r);
467ebfedea0SLionel Sambuc 	return NULL;
468ebfedea0SLionel Sambuc     }
469ebfedea0SLionel Sambuc     p += status;
470ebfedea0SLionel Sambuc     r->q.type = (p[0] << 8 | p[1]);
471ebfedea0SLionel Sambuc     p += 2;
472ebfedea0SLionel Sambuc     r->q.class = (p[0] << 8 | p[1]);
473ebfedea0SLionel Sambuc     p += 2;
474ebfedea0SLionel Sambuc 
475ebfedea0SLionel Sambuc     rr = &r->head;
476ebfedea0SLionel Sambuc     for(i = 0; i < r->h.ancount; i++) {
477ebfedea0SLionel Sambuc 	if(parse_record(data, end_data, &p, rr) != 0) {
478ebfedea0SLionel Sambuc 	    rk_dns_free_data(r);
479ebfedea0SLionel Sambuc 	    return NULL;
480ebfedea0SLionel Sambuc 	}
481ebfedea0SLionel Sambuc 	rr = &(*rr)->next;
482ebfedea0SLionel Sambuc     }
483ebfedea0SLionel Sambuc     for(i = 0; i < r->h.nscount; i++) {
484ebfedea0SLionel Sambuc 	if(parse_record(data, end_data, &p, rr) != 0) {
485ebfedea0SLionel Sambuc 	    rk_dns_free_data(r);
486ebfedea0SLionel Sambuc 	    return NULL;
487ebfedea0SLionel Sambuc 	}
488ebfedea0SLionel Sambuc 	rr = &(*rr)->next;
489ebfedea0SLionel Sambuc     }
490ebfedea0SLionel Sambuc     for(i = 0; i < r->h.arcount; i++) {
491ebfedea0SLionel Sambuc 	if(parse_record(data, end_data, &p, rr) != 0) {
492ebfedea0SLionel Sambuc 	    rk_dns_free_data(r);
493ebfedea0SLionel Sambuc 	    return NULL;
494ebfedea0SLionel Sambuc 	}
495ebfedea0SLionel Sambuc 	rr = &(*rr)->next;
496ebfedea0SLionel Sambuc     }
497ebfedea0SLionel Sambuc     *rr = NULL;
498ebfedea0SLionel Sambuc     return r;
499ebfedea0SLionel Sambuc }
500ebfedea0SLionel Sambuc 
501ebfedea0SLionel Sambuc #ifdef HAVE_RES_NSEARCH
502ebfedea0SLionel Sambuc #ifdef HAVE_RES_NDESTROY
503ebfedea0SLionel Sambuc #define rk_res_free(x) res_ndestroy(x)
504ebfedea0SLionel Sambuc #else
505ebfedea0SLionel Sambuc #define rk_res_free(x) res_nclose(x)
506ebfedea0SLionel Sambuc #endif
507ebfedea0SLionel Sambuc #endif
508ebfedea0SLionel Sambuc 
509ebfedea0SLionel Sambuc #if defined(HAVE_DNS_SEARCH)
510ebfedea0SLionel Sambuc #define resolve_search(h,n,c,t,r,l) \
511ebfedea0SLionel Sambuc     	((int)dns_search(h,n,c,t,r,l,(struct sockaddr *)&from,&fromsize))
512ebfedea0SLionel Sambuc #define resolve_free_handle(h) dns_free(h)
513ebfedea0SLionel Sambuc #elif defined(HAVE_RES_NSEARCH)
514ebfedea0SLionel Sambuc #define resolve_search(h,n,c,t,r,l) res_nsearch(h,n,c,t,r,l)
515ebfedea0SLionel Sambuc #define resolve_free_handle(h) rk_res_free(h);
516ebfedea0SLionel Sambuc #else
517ebfedea0SLionel Sambuc #define resolve_search(h,n,c,t,r,l) res_search(n,c,t,r,l)
518ebfedea0SLionel Sambuc #define handle 0
519ebfedea0SLionel Sambuc #define resolve_free_handle(h)
520ebfedea0SLionel Sambuc #endif
521ebfedea0SLionel Sambuc 
522ebfedea0SLionel Sambuc 
523ebfedea0SLionel Sambuc static struct rk_dns_reply *
dns_lookup_int(const char * domain,int rr_class,int rr_type)524ebfedea0SLionel Sambuc dns_lookup_int(const char *domain, int rr_class, int rr_type)
525ebfedea0SLionel Sambuc {
526ebfedea0SLionel Sambuc     struct rk_dns_reply *r;
527ebfedea0SLionel Sambuc     void *reply = NULL;
528ebfedea0SLionel Sambuc     int size, len;
529ebfedea0SLionel Sambuc #if defined(HAVE_DNS_SEARCH)
530ebfedea0SLionel Sambuc     struct sockaddr_storage from;
531ebfedea0SLionel Sambuc     uint32_t fromsize = sizeof(from);
532ebfedea0SLionel Sambuc     dns_handle_t handle;
533ebfedea0SLionel Sambuc 
534ebfedea0SLionel Sambuc     handle = dns_open(NULL);
535ebfedea0SLionel Sambuc     if (handle == NULL)
536ebfedea0SLionel Sambuc 	return NULL;
537ebfedea0SLionel Sambuc #elif defined(HAVE_RES_NSEARCH)
538ebfedea0SLionel Sambuc     struct __res_state state;
539ebfedea0SLionel Sambuc     struct __res_state *handle = &state;
540ebfedea0SLionel Sambuc 
541ebfedea0SLionel Sambuc     memset(&state, 0, sizeof(state));
542ebfedea0SLionel Sambuc     if(res_ninit(handle))
543ebfedea0SLionel Sambuc 	return NULL; /* is this the best we can do? */
544ebfedea0SLionel Sambuc #endif
545ebfedea0SLionel Sambuc 
546ebfedea0SLionel Sambuc     len = 1500;
547ebfedea0SLionel Sambuc     while(1) {
548ebfedea0SLionel Sambuc 	if (reply) {
549ebfedea0SLionel Sambuc 	    free(reply);
550ebfedea0SLionel Sambuc 	    reply = NULL;
551ebfedea0SLionel Sambuc 	}
552ebfedea0SLionel Sambuc 	if (_resolve_debug) {
553ebfedea0SLionel Sambuc #if defined(HAVE_DNS_SEARCH)
554ebfedea0SLionel Sambuc 	    dns_set_debug(handle, 1);
555ebfedea0SLionel Sambuc #elif defined(HAVE_RES_NSEARCH)
556ebfedea0SLionel Sambuc 	    state.options |= RES_DEBUG;
557ebfedea0SLionel Sambuc #endif
558ebfedea0SLionel Sambuc 	    fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
559ebfedea0SLionel Sambuc 		    rr_class, rk_dns_type_to_string(rr_type), len);
560ebfedea0SLionel Sambuc 	}
561ebfedea0SLionel Sambuc 	reply = malloc(len);
562ebfedea0SLionel Sambuc 	if (reply == NULL) {
563ebfedea0SLionel Sambuc 	    resolve_free_handle(handle);
564ebfedea0SLionel Sambuc 	    return NULL;
565ebfedea0SLionel Sambuc 	}
566ebfedea0SLionel Sambuc 
567ebfedea0SLionel Sambuc 	size = resolve_search(handle, domain, rr_class, rr_type, reply, len);
568ebfedea0SLionel Sambuc 
569ebfedea0SLionel Sambuc 	if (_resolve_debug) {
570ebfedea0SLionel Sambuc 	    fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
571ebfedea0SLionel Sambuc 		    domain, rr_class, rk_dns_type_to_string(rr_type), size);
572ebfedea0SLionel Sambuc 	}
573ebfedea0SLionel Sambuc 	if (size > len) {
574ebfedea0SLionel Sambuc 	    /* resolver thinks it know better, go for it */
575ebfedea0SLionel Sambuc 	    len = size;
576ebfedea0SLionel Sambuc 	} else if (size > 0) {
577ebfedea0SLionel Sambuc 	    /* got a good reply */
578ebfedea0SLionel Sambuc 	    break;
579ebfedea0SLionel Sambuc 	} else if (size <= 0 && len < rk_DNS_MAX_PACKET_SIZE) {
580ebfedea0SLionel Sambuc 	    len *= 2;
581ebfedea0SLionel Sambuc 	    if (len > rk_DNS_MAX_PACKET_SIZE)
582ebfedea0SLionel Sambuc 		len = rk_DNS_MAX_PACKET_SIZE;
583ebfedea0SLionel Sambuc 	} else {
584ebfedea0SLionel Sambuc 	    /* the end, leave */
585ebfedea0SLionel Sambuc 	    resolve_free_handle(handle);
586ebfedea0SLionel Sambuc 	    free(reply);
587ebfedea0SLionel Sambuc 	    return NULL;
588ebfedea0SLionel Sambuc 	}
589ebfedea0SLionel Sambuc     }
590ebfedea0SLionel Sambuc 
591ebfedea0SLionel Sambuc     len = min(len, size);
592ebfedea0SLionel Sambuc     r = parse_reply(reply, len);
593ebfedea0SLionel Sambuc     free(reply);
594*0a6a1f1dSLionel Sambuc 
595*0a6a1f1dSLionel Sambuc     resolve_free_handle(handle);
596*0a6a1f1dSLionel Sambuc 
597ebfedea0SLionel Sambuc     return r;
598ebfedea0SLionel Sambuc }
599ebfedea0SLionel Sambuc 
600ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
rk_dns_lookup(const char * domain,const char * type_name)601ebfedea0SLionel Sambuc rk_dns_lookup(const char *domain, const char *type_name)
602ebfedea0SLionel Sambuc {
603ebfedea0SLionel Sambuc     int type;
604ebfedea0SLionel Sambuc 
605ebfedea0SLionel Sambuc     type = rk_dns_string_to_type(type_name);
606ebfedea0SLionel Sambuc     if(type == -1) {
607ebfedea0SLionel Sambuc 	if(_resolve_debug)
608ebfedea0SLionel Sambuc 	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
609ebfedea0SLionel Sambuc 		    type_name);
610ebfedea0SLionel Sambuc 	return NULL;
611ebfedea0SLionel Sambuc     }
612ebfedea0SLionel Sambuc     return dns_lookup_int(domain, rk_ns_c_in, type);
613ebfedea0SLionel Sambuc }
614ebfedea0SLionel Sambuc 
615ebfedea0SLionel Sambuc #endif	/* !HAVE_WINDNS */
616ebfedea0SLionel Sambuc 
617ebfedea0SLionel Sambuc static int
compare_srv(const void * a,const void * b)618ebfedea0SLionel Sambuc compare_srv(const void *a, const void *b)
619ebfedea0SLionel Sambuc {
620ebfedea0SLionel Sambuc     const struct rk_resource_record *const* aa = a, *const* bb = b;
621ebfedea0SLionel Sambuc 
622ebfedea0SLionel Sambuc     if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
623ebfedea0SLionel Sambuc 	return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
624ebfedea0SLionel Sambuc     return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
625ebfedea0SLionel Sambuc }
626ebfedea0SLionel Sambuc 
627ebfedea0SLionel Sambuc /* try to rearrange the srv-records by the algorithm in RFC2782 */
628ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rk_dns_srv_order(struct rk_dns_reply * r)629ebfedea0SLionel Sambuc rk_dns_srv_order(struct rk_dns_reply *r)
630ebfedea0SLionel Sambuc {
631ebfedea0SLionel Sambuc     struct rk_resource_record **srvs, **ss, **headp;
632ebfedea0SLionel Sambuc     struct rk_resource_record *rr;
633ebfedea0SLionel Sambuc     int num_srv = 0;
634ebfedea0SLionel Sambuc 
635ebfedea0SLionel Sambuc     rk_random_init();
636ebfedea0SLionel Sambuc 
637ebfedea0SLionel Sambuc     for(rr = r->head; rr; rr = rr->next)
638ebfedea0SLionel Sambuc 	if(rr->type == rk_ns_t_srv)
639ebfedea0SLionel Sambuc 	    num_srv++;
640ebfedea0SLionel Sambuc 
641ebfedea0SLionel Sambuc     if(num_srv == 0)
642ebfedea0SLionel Sambuc 	return;
643ebfedea0SLionel Sambuc 
644ebfedea0SLionel Sambuc     srvs = malloc(num_srv * sizeof(*srvs));
645ebfedea0SLionel Sambuc     if(srvs == NULL)
646ebfedea0SLionel Sambuc 	return; /* XXX not much to do here */
647ebfedea0SLionel Sambuc 
648ebfedea0SLionel Sambuc     /* unlink all srv-records from the linked list and put them in
649ebfedea0SLionel Sambuc        a vector */
650ebfedea0SLionel Sambuc     for(ss = srvs, headp = &r->head; *headp; )
651ebfedea0SLionel Sambuc 	if((*headp)->type == rk_ns_t_srv) {
652ebfedea0SLionel Sambuc 	    *ss = *headp;
653ebfedea0SLionel Sambuc 	    *headp = (*headp)->next;
654ebfedea0SLionel Sambuc 	    (*ss)->next = NULL;
655ebfedea0SLionel Sambuc 	    ss++;
656ebfedea0SLionel Sambuc 	} else
657ebfedea0SLionel Sambuc 	    headp = &(*headp)->next;
658ebfedea0SLionel Sambuc 
659ebfedea0SLionel Sambuc     /* sort them by priority and weight */
660ebfedea0SLionel Sambuc     qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
661ebfedea0SLionel Sambuc 
662ebfedea0SLionel Sambuc     headp = &r->head;
663ebfedea0SLionel Sambuc 
664ebfedea0SLionel Sambuc     for(ss = srvs; ss < srvs + num_srv; ) {
665ebfedea0SLionel Sambuc 	int sum, rnd, count;
666ebfedea0SLionel Sambuc 	struct rk_resource_record **ee, **tt;
667ebfedea0SLionel Sambuc 	/* find the last record with the same priority and count the
668ebfedea0SLionel Sambuc            sum of all weights */
669ebfedea0SLionel Sambuc 	for(sum = 0, tt = ss; tt < srvs + num_srv; tt++) {
670ebfedea0SLionel Sambuc 	    assert(*tt != NULL);
671ebfedea0SLionel Sambuc 	    if((*tt)->u.srv->priority != (*ss)->u.srv->priority)
672ebfedea0SLionel Sambuc 		break;
673ebfedea0SLionel Sambuc 	    sum += (*tt)->u.srv->weight;
674ebfedea0SLionel Sambuc 	}
675ebfedea0SLionel Sambuc 	ee = tt;
676ebfedea0SLionel Sambuc 	/* ss is now the first record of this priority and ee is the
677ebfedea0SLionel Sambuc            first of the next */
678ebfedea0SLionel Sambuc 	while(ss < ee) {
679ebfedea0SLionel Sambuc 	    rnd = rk_random() % (sum + 1);
680ebfedea0SLionel Sambuc 	    for(count = 0, tt = ss; ; tt++) {
681ebfedea0SLionel Sambuc 		if(*tt == NULL)
682ebfedea0SLionel Sambuc 		    continue;
683ebfedea0SLionel Sambuc 		count += (*tt)->u.srv->weight;
684ebfedea0SLionel Sambuc 		if(count >= rnd)
685ebfedea0SLionel Sambuc 		    break;
686ebfedea0SLionel Sambuc 	    }
687ebfedea0SLionel Sambuc 
688ebfedea0SLionel Sambuc 	    assert(tt < ee);
689ebfedea0SLionel Sambuc 
690ebfedea0SLionel Sambuc 	    /* insert the selected record at the tail (of the head) of
691ebfedea0SLionel Sambuc                the list */
692ebfedea0SLionel Sambuc 	    (*tt)->next = *headp;
693ebfedea0SLionel Sambuc 	    *headp = *tt;
694ebfedea0SLionel Sambuc 	    headp = &(*tt)->next;
695ebfedea0SLionel Sambuc 	    sum -= (*tt)->u.srv->weight;
696ebfedea0SLionel Sambuc 	    *tt = NULL;
697ebfedea0SLionel Sambuc 	    while(ss < ee && *ss == NULL)
698ebfedea0SLionel Sambuc 		ss++;
699ebfedea0SLionel Sambuc 	}
700ebfedea0SLionel Sambuc     }
701ebfedea0SLionel Sambuc 
702ebfedea0SLionel Sambuc     free(srvs);
703ebfedea0SLionel Sambuc     return;
704ebfedea0SLionel Sambuc }
705ebfedea0SLionel Sambuc 
706ebfedea0SLionel Sambuc #ifdef HAVE_WINDNS
707ebfedea0SLionel Sambuc 
708ebfedea0SLionel Sambuc #include <WinDNS.h>
709ebfedea0SLionel Sambuc 
710ebfedea0SLionel Sambuc static struct rk_resource_record *
parse_dns_record(PDNS_RECORD pRec)711ebfedea0SLionel Sambuc parse_dns_record(PDNS_RECORD pRec)
712ebfedea0SLionel Sambuc {
713ebfedea0SLionel Sambuc     struct rk_resource_record * rr;
714ebfedea0SLionel Sambuc 
715ebfedea0SLionel Sambuc     if (pRec == NULL)
716ebfedea0SLionel Sambuc 	return NULL;
717ebfedea0SLionel Sambuc 
718ebfedea0SLionel Sambuc     rr = calloc(1, sizeof(*rr));
719ebfedea0SLionel Sambuc 
720ebfedea0SLionel Sambuc     rr->domain = strdup(pRec->pName);
721ebfedea0SLionel Sambuc     rr->type = pRec->wType;
722ebfedea0SLionel Sambuc     rr->class = 0;
723ebfedea0SLionel Sambuc     rr->ttl = pRec->dwTtl;
724ebfedea0SLionel Sambuc     rr->size = 0;
725ebfedea0SLionel Sambuc 
726ebfedea0SLionel Sambuc     switch (rr->type) {
727ebfedea0SLionel Sambuc     case rk_ns_t_ns:
728ebfedea0SLionel Sambuc     case rk_ns_t_cname:
729ebfedea0SLionel Sambuc     case rk_ns_t_ptr:
730ebfedea0SLionel Sambuc 	rr->u.txt = strdup(pRec->Data.NS.pNameHost);
731ebfedea0SLionel Sambuc 	if(rr->u.txt == NULL) {
732ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
733ebfedea0SLionel Sambuc 	    return NULL;
734ebfedea0SLionel Sambuc 	}
735ebfedea0SLionel Sambuc 	break;
736ebfedea0SLionel Sambuc 
737ebfedea0SLionel Sambuc     case rk_ns_t_mx:
738ebfedea0SLionel Sambuc     case rk_ns_t_afsdb:{
739ebfedea0SLionel Sambuc 	size_t hostlen = strnlen(pRec->Data.MX.pNameExchange, DNS_MAX_NAME_LENGTH);
740ebfedea0SLionel Sambuc 
741ebfedea0SLionel Sambuc 	rr->u.mx = (struct mx_record *)malloc(sizeof(struct mx_record) +
742ebfedea0SLionel Sambuc 					      hostlen);
743ebfedea0SLionel Sambuc 	if (rr->u.mx == NULL) {
744ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
745ebfedea0SLionel Sambuc 	    return NULL;
746ebfedea0SLionel Sambuc 	}
747ebfedea0SLionel Sambuc 
748ebfedea0SLionel Sambuc 	strcpy_s(rr->u.mx->domain, hostlen + 1, pRec->Data.MX.pNameExchange);
749ebfedea0SLionel Sambuc 	rr->u.mx->preference = pRec->Data.MX.wPreference;
750ebfedea0SLionel Sambuc 	break;
751ebfedea0SLionel Sambuc     }
752ebfedea0SLionel Sambuc 
753ebfedea0SLionel Sambuc     case rk_ns_t_srv:{
754ebfedea0SLionel Sambuc 	size_t hostlen = strnlen(pRec->Data.SRV.pNameTarget, DNS_MAX_NAME_LENGTH);
755ebfedea0SLionel Sambuc 
756ebfedea0SLionel Sambuc 	rr->u.srv =
757ebfedea0SLionel Sambuc 	    (struct srv_record*)malloc(sizeof(struct srv_record) +
758ebfedea0SLionel Sambuc 				       hostlen);
759ebfedea0SLionel Sambuc 	if(rr->u.srv == NULL) {
760ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
761ebfedea0SLionel Sambuc 	    return NULL;
762ebfedea0SLionel Sambuc 	}
763ebfedea0SLionel Sambuc 
764ebfedea0SLionel Sambuc 	rr->u.srv->priority = pRec->Data.SRV.wPriority;
765ebfedea0SLionel Sambuc 	rr->u.srv->weight = pRec->Data.SRV.wWeight;
766ebfedea0SLionel Sambuc 	rr->u.srv->port = pRec->Data.SRV.wPort;
767ebfedea0SLionel Sambuc 	strcpy_s(rr->u.srv->target, hostlen + 1, pRec->Data.SRV.pNameTarget);
768ebfedea0SLionel Sambuc 
769ebfedea0SLionel Sambuc 	break;
770ebfedea0SLionel Sambuc     }
771ebfedea0SLionel Sambuc 
772ebfedea0SLionel Sambuc     case rk_ns_t_txt:{
773ebfedea0SLionel Sambuc 	size_t len;
774ebfedea0SLionel Sambuc 
775ebfedea0SLionel Sambuc 	if (pRec->Data.TXT.dwStringCount == 0) {
776ebfedea0SLionel Sambuc 	    rr->u.txt = strdup("");
777ebfedea0SLionel Sambuc 	    break;
778ebfedea0SLionel Sambuc 	}
779ebfedea0SLionel Sambuc 
780ebfedea0SLionel Sambuc 	len = strnlen(pRec->Data.TXT.pStringArray[0], DNS_MAX_TEXT_STRING_LENGTH);
781ebfedea0SLionel Sambuc 
782ebfedea0SLionel Sambuc 	rr->u.txt = (char *)malloc(len + 1);
783ebfedea0SLionel Sambuc 	strcpy_s(rr->u.txt, len + 1, pRec->Data.TXT.pStringArray[0]);
784ebfedea0SLionel Sambuc 
785ebfedea0SLionel Sambuc 	break;
786ebfedea0SLionel Sambuc     }
787ebfedea0SLionel Sambuc 
788ebfedea0SLionel Sambuc     case rk_ns_t_key : {
789ebfedea0SLionel Sambuc 	size_t key_len;
790ebfedea0SLionel Sambuc 
791ebfedea0SLionel Sambuc 	if (pRec->wDataLength < 4) {
792ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
793ebfedea0SLionel Sambuc 	    return NULL;
794ebfedea0SLionel Sambuc 	}
795ebfedea0SLionel Sambuc 
796ebfedea0SLionel Sambuc 	key_len = pRec->wDataLength - 4;
797ebfedea0SLionel Sambuc 	rr->u.key = malloc (sizeof(*rr->u.key) + key_len - 1);
798ebfedea0SLionel Sambuc 	if (rr->u.key == NULL) {
799ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
800ebfedea0SLionel Sambuc 	    return NULL;
801ebfedea0SLionel Sambuc 	}
802ebfedea0SLionel Sambuc 
803ebfedea0SLionel Sambuc 	rr->u.key->flags     = pRec->Data.KEY.wFlags;
804ebfedea0SLionel Sambuc 	rr->u.key->protocol  = pRec->Data.KEY.chProtocol;
805ebfedea0SLionel Sambuc 	rr->u.key->algorithm = pRec->Data.KEY.chAlgorithm;
806ebfedea0SLionel Sambuc 	rr->u.key->key_len   = key_len;
807ebfedea0SLionel Sambuc 	memcpy_s (rr->u.key->key_data, key_len,
808ebfedea0SLionel Sambuc 		  pRec->Data.KEY.Key, key_len);
809ebfedea0SLionel Sambuc 	break;
810ebfedea0SLionel Sambuc     }
811ebfedea0SLionel Sambuc 
812ebfedea0SLionel Sambuc     case rk_ns_t_sig : {
813ebfedea0SLionel Sambuc 	size_t sig_len, hostlen;
814ebfedea0SLionel Sambuc 
815ebfedea0SLionel Sambuc 	if(pRec->wDataLength <= 18) {
816ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
817ebfedea0SLionel Sambuc 	    return NULL;
818ebfedea0SLionel Sambuc 	}
819ebfedea0SLionel Sambuc 
820ebfedea0SLionel Sambuc 	sig_len = pRec->wDataLength;
821ebfedea0SLionel Sambuc 
822ebfedea0SLionel Sambuc 	hostlen = strnlen(pRec->Data.SIG.pNameSigner, DNS_MAX_NAME_LENGTH);
823ebfedea0SLionel Sambuc 
824ebfedea0SLionel Sambuc 	rr->u.sig = malloc(sizeof(*rr->u.sig)
825ebfedea0SLionel Sambuc 			      + hostlen + sig_len);
826ebfedea0SLionel Sambuc 	if (rr->u.sig == NULL) {
827ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
828ebfedea0SLionel Sambuc 	    return NULL;
829ebfedea0SLionel Sambuc 	}
830ebfedea0SLionel Sambuc 	rr->u.sig->type           = pRec->Data.SIG.wTypeCovered;
831ebfedea0SLionel Sambuc 	rr->u.sig->algorithm      = pRec->Data.SIG.chAlgorithm;
832ebfedea0SLionel Sambuc 	rr->u.sig->labels         = pRec->Data.SIG.chLabelCount;
833ebfedea0SLionel Sambuc 	rr->u.sig->orig_ttl       = pRec->Data.SIG.dwOriginalTtl;
834ebfedea0SLionel Sambuc 	rr->u.sig->sig_expiration = pRec->Data.SIG.dwExpiration;
835ebfedea0SLionel Sambuc 	rr->u.sig->sig_inception  = pRec->Data.SIG.dwTimeSigned;
836ebfedea0SLionel Sambuc 	rr->u.sig->key_tag        = pRec->Data.SIG.wKeyTag;
837ebfedea0SLionel Sambuc 	rr->u.sig->sig_len        = sig_len;
838ebfedea0SLionel Sambuc 	memcpy_s (rr->u.sig->sig_data, sig_len,
839ebfedea0SLionel Sambuc 		  pRec->Data.SIG.Signature, sig_len);
840ebfedea0SLionel Sambuc 	rr->u.sig->signer         = &rr->u.sig->sig_data[sig_len];
841ebfedea0SLionel Sambuc 	strcpy_s(rr->u.sig->signer, hostlen + 1, pRec->Data.SIG.pNameSigner);
842ebfedea0SLionel Sambuc 	break;
843ebfedea0SLionel Sambuc     }
844ebfedea0SLionel Sambuc 
845ebfedea0SLionel Sambuc #ifdef DNS_TYPE_DS
846ebfedea0SLionel Sambuc     case rk_ns_t_ds: {
847ebfedea0SLionel Sambuc 	rr->u.ds = malloc (sizeof(*rr->u.ds) + pRec->Data.DS.wDigestLength - 1);
848ebfedea0SLionel Sambuc 	if (rr->u.ds == NULL) {
849ebfedea0SLionel Sambuc 	    dns_free_rr(rr);
850ebfedea0SLionel Sambuc 	    return NULL;
851ebfedea0SLionel Sambuc 	}
852ebfedea0SLionel Sambuc 
853ebfedea0SLionel Sambuc 	rr->u.ds->key_tag     = pRec->Data.DS.wKeyTag;
854ebfedea0SLionel Sambuc 	rr->u.ds->algorithm   = pRec->Data.DS.chAlgorithm;
855ebfedea0SLionel Sambuc 	rr->u.ds->digest_type = pRec->Data.DS.chDigestType;
856ebfedea0SLionel Sambuc 	rr->u.ds->digest_len  = pRec->Data.DS.wDigestLength;
857ebfedea0SLionel Sambuc 	memcpy_s (rr->u.ds->digest_data, pRec->Data.DS.wDigestLength,
858ebfedea0SLionel Sambuc 		  pRec->Data.DS.Digest, pRec->Data.DS.wDigestLength);
859ebfedea0SLionel Sambuc 	break;
860ebfedea0SLionel Sambuc     }
861ebfedea0SLionel Sambuc #endif
862ebfedea0SLionel Sambuc 
863ebfedea0SLionel Sambuc     default:
864ebfedea0SLionel Sambuc 	dns_free_rr(rr);
865ebfedea0SLionel Sambuc 	return NULL;
866ebfedea0SLionel Sambuc     }
867ebfedea0SLionel Sambuc 
868ebfedea0SLionel Sambuc     rr->next = parse_dns_record(pRec->pNext);
869ebfedea0SLionel Sambuc     return rr;
870ebfedea0SLionel Sambuc }
871ebfedea0SLionel Sambuc 
872ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
rk_dns_lookup(const char * domain,const char * type_name)873ebfedea0SLionel Sambuc rk_dns_lookup(const char *domain, const char *type_name)
874ebfedea0SLionel Sambuc {
875ebfedea0SLionel Sambuc     DNS_STATUS status;
876ebfedea0SLionel Sambuc     int type;
877ebfedea0SLionel Sambuc     PDNS_RECORD pRec = NULL;
878ebfedea0SLionel Sambuc     struct rk_dns_reply * r = NULL;
879ebfedea0SLionel Sambuc 
880ebfedea0SLionel Sambuc     __try {
881ebfedea0SLionel Sambuc 
882ebfedea0SLionel Sambuc 	type = rk_dns_string_to_type(type_name);
883ebfedea0SLionel Sambuc 	if(type == -1) {
884ebfedea0SLionel Sambuc 	    if(_resolve_debug)
885ebfedea0SLionel Sambuc 		fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
886ebfedea0SLionel Sambuc 			type_name);
887ebfedea0SLionel Sambuc 	    return NULL;
888ebfedea0SLionel Sambuc 	}
889ebfedea0SLionel Sambuc 
890ebfedea0SLionel Sambuc 	status = DnsQuery_UTF8(domain, type, DNS_QUERY_STANDARD, NULL,
891ebfedea0SLionel Sambuc 			       &pRec, NULL);
892ebfedea0SLionel Sambuc 	if (status != ERROR_SUCCESS)
893ebfedea0SLionel Sambuc 	    return NULL;
894ebfedea0SLionel Sambuc 
895ebfedea0SLionel Sambuc 	r = calloc(1, sizeof(*r));
896ebfedea0SLionel Sambuc 	r->q.domain = strdup(domain);
897ebfedea0SLionel Sambuc 	r->q.type = type;
898ebfedea0SLionel Sambuc 	r->q.class = 0;
899ebfedea0SLionel Sambuc 
900ebfedea0SLionel Sambuc 	r->head = parse_dns_record(pRec);
901ebfedea0SLionel Sambuc 
902ebfedea0SLionel Sambuc 	if (r->head == NULL) {
903ebfedea0SLionel Sambuc 	    rk_dns_free_data(r);
904ebfedea0SLionel Sambuc 	    return NULL;
905ebfedea0SLionel Sambuc 	} else {
906ebfedea0SLionel Sambuc 	    return r;
907ebfedea0SLionel Sambuc 	}
908ebfedea0SLionel Sambuc 
909ebfedea0SLionel Sambuc     } __finally {
910ebfedea0SLionel Sambuc 
911ebfedea0SLionel Sambuc 	if (pRec)
912ebfedea0SLionel Sambuc 	    DnsRecordListFree(pRec, DnsFreeRecordList);
913ebfedea0SLionel Sambuc 
914ebfedea0SLionel Sambuc     }
915ebfedea0SLionel Sambuc }
916ebfedea0SLionel Sambuc #endif	/* HAVE_WINDNS */
917ebfedea0SLionel Sambuc 
918ebfedea0SLionel Sambuc #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
919ebfedea0SLionel Sambuc 
920ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION struct rk_dns_reply * ROKEN_LIB_CALL
rk_dns_lookup(const char * domain,const char * type_name)921ebfedea0SLionel Sambuc rk_dns_lookup(const char *domain, const char *type_name)
922ebfedea0SLionel Sambuc {
923ebfedea0SLionel Sambuc     return NULL;
924ebfedea0SLionel Sambuc }
925ebfedea0SLionel Sambuc 
926ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rk_dns_free_data(struct rk_dns_reply * r)927ebfedea0SLionel Sambuc rk_dns_free_data(struct rk_dns_reply *r)
928ebfedea0SLionel Sambuc {
929ebfedea0SLionel Sambuc }
930ebfedea0SLionel Sambuc 
931ebfedea0SLionel Sambuc ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rk_dns_srv_order(struct rk_dns_reply * r)932ebfedea0SLionel Sambuc rk_dns_srv_order(struct rk_dns_reply *r)
933ebfedea0SLionel Sambuc {
934ebfedea0SLionel Sambuc }
935ebfedea0SLionel Sambuc 
936ebfedea0SLionel Sambuc #endif
937