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