• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/heimdal/lib/roken/
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
51RCSID("$Id: resolve.c,v 1.1.1.1 2011/06/10 09:34:42 andrew Exp $");
52
53#ifdef _AIX /* AIX have broken res_nsearch() in 5.1 (5.0 also ?) */
54#undef HAVE_RES_NSEARCH
55#endif
56
57#define DECL(X) {#X, rk_ns_t_##X}
58
59static struct stot{
60    const char *name;
61    int type;
62}stot[] = {
63    DECL(a),
64    DECL(aaaa),
65    DECL(ns),
66    DECL(cname),
67    DECL(soa),
68    DECL(ptr),
69    DECL(mx),
70    DECL(txt),
71    DECL(afsdb),
72    DECL(sig),
73    DECL(key),
74    DECL(srv),
75    DECL(naptr),
76    DECL(sshfp),
77    DECL(ds),
78    {NULL, 	0}
79};
80
81int _resolve_debug = 0;
82
83int ROKEN_LIB_FUNCTION
84rk_dns_string_to_type(const char *name)
85{
86    struct stot *p = stot;
87    for(p = stot; p->name; p++)
88	if(strcasecmp(name, p->name) == 0)
89	    return p->type;
90    return -1;
91}
92
93const char * ROKEN_LIB_FUNCTION
94rk_dns_type_to_string(int type)
95{
96    struct stot *p = stot;
97    for(p = stot; p->name; p++)
98	if(type == p->type)
99	    return p->name;
100    return NULL;
101}
102
103#if (defined(HAVE_RES_SEARCH) || defined(HAVE_RES_NSEARCH)) && defined(HAVE_DN_EXPAND)
104
105static void
106dns_free_rr(struct rk_resource_record *rr)
107{
108    if(rr->domain)
109	free(rr->domain);
110    if(rr->u.data)
111	free(rr->u.data);
112    free(rr);
113}
114
115void ROKEN_LIB_FUNCTION
116rk_dns_free_data(struct rk_dns_reply *r)
117{
118    struct rk_resource_record *rr;
119    if(r->q.domain)
120	free(r->q.domain);
121    for(rr = r->head; rr;){
122	struct rk_resource_record *tmp = rr;
123	rr = rr->next;
124	dns_free_rr(tmp);
125    }
126    free (r);
127}
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 (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 (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 < *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 (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    int 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;
527    int len;
528#if defined(HAVE_DNS_SEARCH)
529    struct sockaddr_storage from;
530    uint32_t fromsize = sizeof(from);
531    dns_handle_t handle;
532
533    handle = dns_open(NULL);
534    if (handle == NULL)
535	return NULL;
536#elif defined(HAVE_RES_NSEARCH)
537    struct __res_state state;
538    struct __res_state *handle = &state;
539
540    memset(&state, 0, sizeof(state));
541    if(res_ninit(handle))
542	return NULL; /* is this the best we can do? */
543#endif
544
545    size = 0;
546    len = 1000;
547    do {
548	if (reply) {
549	    free(reply);
550	    reply = NULL;
551	}
552	if (size <= len)
553	    size = len;
554	if (_resolve_debug) {
555#if defined(HAVE_DNS_SEARCH)
556	    dns_set_debug(handle, 1);
557#elif defined(HAVE_RES_NSEARCH)
558	    state.options |= RES_DEBUG;
559#endif
560	    fprintf(stderr, "dns_lookup(%s, %d, %s), buffer size %d\n", domain,
561		    rr_class, rk_dns_type_to_string(rr_type), size);
562	}
563	reply = malloc(size);
564	if (reply == NULL) {
565	    resolve_free_handle(handle);
566	    return NULL;
567	}
568
569	len = resolve_search(handle, domain, rr_class, rr_type, reply, size);
570
571	if (_resolve_debug) {
572	    fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
573		    domain, rr_class, rk_dns_type_to_string(rr_type), len);
574	}
575	if (len <= 0) {
576	    resolve_free_handle(handle);
577	    free(reply);
578	    return NULL;
579	}
580    } while (size < len && len < rk_DNS_MAX_PACKET_SIZE);
581    resolve_free_handle(handle);
582
583    len = min(len, size);
584    r = parse_reply(reply, len);
585    free(reply);
586    return r;
587}
588
589struct rk_dns_reply * ROKEN_LIB_FUNCTION
590rk_dns_lookup(const char *domain, const char *type_name)
591{
592    int type;
593
594    type = rk_dns_string_to_type(type_name);
595    if(type == -1) {
596	if(_resolve_debug)
597	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
598		    type_name);
599	return NULL;
600    }
601    return dns_lookup_int(domain, rk_ns_c_in, type);
602}
603
604static int
605compare_srv(const void *a, const void *b)
606{
607    const struct rk_resource_record *const* aa = a, *const* bb = b;
608
609    if((*aa)->u.srv->priority == (*bb)->u.srv->priority)
610	return ((*aa)->u.srv->weight - (*bb)->u.srv->weight);
611    return ((*aa)->u.srv->priority - (*bb)->u.srv->priority);
612}
613
614#ifndef HAVE_RANDOM
615#define random() rand()
616#endif
617
618/* try to rearrange the srv-records by the algorithm in RFC2782 */
619void ROKEN_LIB_FUNCTION
620rk_dns_srv_order(struct rk_dns_reply *r)
621{
622    struct rk_resource_record **srvs, **ss, **headp;
623    struct rk_resource_record *rr;
624    int num_srv = 0;
625
626#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
627    int state[256 / sizeof(int)];
628    char *oldstate;
629#endif
630
631    for(rr = r->head; rr; rr = rr->next)
632	if(rr->type == rk_ns_t_srv)
633	    num_srv++;
634
635    if(num_srv == 0)
636	return;
637
638    srvs = malloc(num_srv * sizeof(*srvs));
639    if(srvs == NULL)
640	return; /* XXX not much to do here */
641
642    /* unlink all srv-records from the linked list and put them in
643       a vector */
644    for(ss = srvs, headp = &r->head; *headp; )
645	if((*headp)->type == rk_ns_t_srv) {
646	    *ss = *headp;
647	    *headp = (*headp)->next;
648	    (*ss)->next = NULL;
649	    ss++;
650	} else
651	    headp = &(*headp)->next;
652
653    /* sort them by priority and weight */
654    qsort(srvs, num_srv, sizeof(*srvs), compare_srv);
655
656#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
657    oldstate = initstate(time(NULL), (char*)state, sizeof(state));
658#endif
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 = 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#if defined(HAVE_INITSTATE) && defined(HAVE_SETSTATE)
701    setstate(oldstate);
702#endif
703    free(srvs);
704    return;
705}
706
707#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
708
709struct rk_dns_reply * ROKEN_LIB_FUNCTION
710rk_dns_lookup(const char *domain, const char *type_name)
711{
712    return NULL;
713}
714
715void ROKEN_LIB_FUNCTION
716rk_dns_free_data(struct rk_dns_reply *r)
717{
718}
719
720void ROKEN_LIB_FUNCTION
721rk_dns_srv_order(struct rk_dns_reply *r)
722{
723}
724
725#endif
726