resolve.c revision 72445
1/*
2 * Copyright (c) 1995 - 2000 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#ifdef HAVE_CONFIG_H
35#include <config.h>
36#endif
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#include "resolve.h"
45
46RCSID("$Id: resolve.c,v 1.26 2000/06/27 01:15:53 assar Exp $");
47
48#if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND)
49
50#define DECL(X) {#X, T_##X}
51
52static struct stot{
53    const char *name;
54    int type;
55}stot[] = {
56    DECL(A),
57    DECL(NS),
58    DECL(CNAME),
59    DECL(SOA),
60    DECL(PTR),
61    DECL(MX),
62    DECL(TXT),
63    DECL(AFSDB),
64    DECL(SIG),
65    DECL(KEY),
66    DECL(SRV),
67    DECL(NAPTR),
68    {NULL, 	0}
69};
70
71int _resolve_debug = 0;
72
73int
74dns_string_to_type(const char *name)
75{
76    struct stot *p = stot;
77    for(p = stot; p->name; p++)
78	if(strcasecmp(name, p->name) == 0)
79	    return p->type;
80    return -1;
81}
82
83const char *
84dns_type_to_string(int type)
85{
86    struct stot *p = stot;
87    for(p = stot; p->name; p++)
88	if(type == p->type)
89	    return p->name;
90    return NULL;
91}
92
93void
94dns_free_data(struct dns_reply *r)
95{
96    struct resource_record *rr;
97    if(r->q.domain)
98	free(r->q.domain);
99    for(rr = r->head; rr;){
100	struct resource_record *tmp = rr;
101	if(rr->domain)
102	    free(rr->domain);
103	if(rr->u.data)
104	    free(rr->u.data);
105	rr = rr->next;
106	free(tmp);
107    }
108    free (r);
109}
110
111static struct dns_reply*
112parse_reply(unsigned char *data, int len)
113{
114    unsigned char *p;
115    char host[128];
116    int status;
117
118    struct dns_reply *r;
119    struct resource_record **rr;
120
121    r = calloc(1, sizeof(*r));
122    if (r == NULL)
123	return NULL;
124
125    p = data;
126#if 0
127    /* doesn't work on Crays */
128    memcpy(&r->h, p, sizeof(HEADER));
129    p += sizeof(HEADER);
130#else
131    memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
132    p += 12;
133#endif
134    status = dn_expand(data, data + len, p, host, sizeof(host));
135    if(status < 0){
136	dns_free_data(r);
137	return NULL;
138    }
139    r->q.domain = strdup(host);
140    if(r->q.domain == NULL) {
141	dns_free_data(r);
142	return NULL;
143    }
144    p += status;
145    r->q.type = (p[0] << 8 | p[1]);
146    p += 2;
147    r->q.class = (p[0] << 8 | p[1]);
148    p += 2;
149    rr = &r->head;
150    while(p < data + len){
151	int type, class, ttl, size;
152	status = dn_expand(data, data + len, p, host, sizeof(host));
153	if(status < 0){
154	    dns_free_data(r);
155	    return NULL;
156	}
157	p += status;
158	type = (p[0] << 8) | p[1];
159	p += 2;
160	class = (p[0] << 8) | p[1];
161	p += 2;
162	ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
163	p += 4;
164	size = (p[0] << 8) | p[1];
165	p += 2;
166	*rr = (struct resource_record*)calloc(1,
167					      sizeof(struct resource_record));
168	if(*rr == NULL) {
169	    dns_free_data(r);
170	    return NULL;
171	}
172	(*rr)->domain = strdup(host);
173	if((*rr)->domain == NULL) {
174	    dns_free_data(r);
175	    return NULL;
176	}
177	(*rr)->type = type;
178	(*rr)->class = class;
179	(*rr)->ttl = ttl;
180	(*rr)->size = size;
181	switch(type){
182	case T_NS:
183	case T_CNAME:
184	case T_PTR:
185	    status = dn_expand(data, data + len, p, host, sizeof(host));
186	    if(status < 0){
187		dns_free_data(r);
188		return NULL;
189	    }
190	    (*rr)->u.txt = strdup(host);
191	    if((*rr)->u.txt == NULL) {
192		dns_free_data(r);
193		return NULL;
194	    }
195	    break;
196	case T_MX:
197	case T_AFSDB:{
198	    status = dn_expand(data, data + len, p + 2, host, sizeof(host));
199	    if(status < 0){
200		dns_free_data(r);
201		return NULL;
202	    }
203	    (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
204						    strlen(host));
205	    if((*rr)->u.mx == NULL) {
206		dns_free_data(r);
207		return NULL;
208	    }
209	    (*rr)->u.mx->preference = (p[0] << 8) | p[1];
210	    strcpy((*rr)->u.mx->domain, host);
211	    break;
212	}
213	case T_SRV:{
214	    status = dn_expand(data, data + len, p + 6, host, sizeof(host));
215	    if(status < 0){
216		dns_free_data(r);
217		return NULL;
218	    }
219	    (*rr)->u.srv =
220		(struct srv_record*)malloc(sizeof(struct srv_record) +
221					   strlen(host));
222	    if((*rr)->u.srv == NULL) {
223		dns_free_data(r);
224		return NULL;
225	    }
226	    (*rr)->u.srv->priority = (p[0] << 8) | p[1];
227	    (*rr)->u.srv->weight = (p[2] << 8) | p[3];
228	    (*rr)->u.srv->port = (p[4] << 8) | p[5];
229	    strcpy((*rr)->u.srv->target, host);
230	    break;
231	}
232	case T_TXT:{
233	    (*rr)->u.txt = (char*)malloc(size + 1);
234	    if((*rr)->u.txt == NULL) {
235		dns_free_data(r);
236		return NULL;
237	    }
238	    strncpy((*rr)->u.txt, (char*)p + 1, *p);
239	    (*rr)->u.txt[*p] = 0;
240	    break;
241	}
242	case T_KEY : {
243	    size_t key_len;
244
245	    key_len = size - 4;
246	    (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
247	    if ((*rr)->u.key == NULL) {
248		dns_free_data (r);
249		return NULL;
250	    }
251
252	    (*rr)->u.key->flags     = (p[0] << 8) | p[1];
253	    (*rr)->u.key->protocol  = p[2];
254	    (*rr)->u.key->algorithm = p[3];
255	    (*rr)->u.key->key_len   = key_len;
256	    memcpy ((*rr)->u.key->key_data, p + 4, key_len);
257	    break;
258	}
259	case T_SIG : {
260	    size_t sig_len;
261
262	    status = dn_expand (data, data + len, p + 18, host, sizeof(host));
263	    if (status < 0) {
264		dns_free_data (r);
265		return NULL;
266	    }
267	    sig_len = len - 18 - status;
268	    (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
269				  + strlen(host) + sig_len);
270	    if ((*rr)->u.sig == NULL) {
271		dns_free_data (r);
272		return NULL;
273	    }
274	    (*rr)->u.sig->type           = (p[0] << 8) | p[1];
275	    (*rr)->u.sig->algorithm      = p[2];
276	    (*rr)->u.sig->labels         = p[3];
277	    (*rr)->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
278		| (p[6] << 8) | p[7];
279	    (*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
280		| (p[10] << 8) | p[11];
281	    (*rr)->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
282		| (p[14] << 8) | p[15];
283	    (*rr)->u.sig->key_tag        = (p[16] << 8) | p[17];
284	    (*rr)->u.sig->sig_len        = sig_len;
285	    memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len);
286	    (*rr)->u.sig->signer         = &(*rr)->u.sig->sig_data[sig_len];
287	    strcpy((*rr)->u.sig->signer, host);
288	    break;
289	}
290
291	case T_CERT : {
292	    size_t cert_len;
293
294	    cert_len = size - 5;
295	    (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
296	    if ((*rr)->u.cert == NULL) {
297		dns_free_data (r);
298		return NULL;
299	    }
300
301	    (*rr)->u.cert->type      = (p[0] << 8) | p[1];
302	    (*rr)->u.cert->tag       = (p[2] << 8) | p[3];
303	    (*rr)->u.cert->algorithm = p[4];
304	    (*rr)->u.cert->cert_len  = cert_len;
305	    memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len);
306	    break;
307	}
308	default:
309	    (*rr)->u.data = (unsigned char*)malloc(size);
310	    if(size != 0 && (*rr)->u.data == NULL) {
311		dns_free_data(r);
312		return NULL;
313	    }
314	    memcpy((*rr)->u.data, p, size);
315	}
316	p += size;
317	rr = &(*rr)->next;
318    }
319    *rr = NULL;
320    return r;
321}
322
323static struct dns_reply *
324dns_lookup_int(const char *domain, int rr_class, int rr_type)
325{
326    unsigned char reply[1024];
327    int len;
328    struct dns_reply *r = NULL;
329    u_long old_options = 0;
330
331    if (_resolve_debug) {
332        old_options = _res.options;
333	_res.options |= RES_DEBUG;
334	fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain,
335		rr_class, dns_type_to_string(rr_type));
336    }
337    len = res_search(domain, rr_class, rr_type, reply, sizeof(reply));
338    if (_resolve_debug) {
339        _res.options = old_options;
340	fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
341		domain, rr_class, dns_type_to_string(rr_type), len);
342    }
343    if (len >= 0)
344	r = parse_reply(reply, len);
345    return r;
346}
347
348struct dns_reply *
349dns_lookup(const char *domain, const char *type_name)
350{
351    int type;
352
353    type = dns_string_to_type(type_name);
354    if(type == -1) {
355	if(_resolve_debug)
356	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
357		    type_name);
358	return NULL;
359    }
360    return dns_lookup_int(domain, C_IN, type);
361}
362
363#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
364
365struct dns_reply *
366dns_lookup(const char *domain, const char *type_name)
367{
368    return NULL;
369}
370
371void
372dns_free_data(struct dns_reply *r)
373{
374}
375
376#endif
377
378#ifdef TEST
379int
380main(int argc, char **argv)
381{
382    struct dns_reply *r;
383    struct resource_record *rr;
384    r = dns_lookup(argv[1], argv[2]);
385    if(r == NULL){
386	printf("No reply.\n");
387	return 1;
388    }
389    for(rr = r->head; rr;rr=rr->next){
390	printf("%s %s %d ", rr->domain, dns_type_to_string(rr->type), rr->ttl);
391	switch(rr->type){
392	case T_NS:
393	case T_CNAME:
394	case T_PTR:
395	    printf("%s\n", (char*)rr->u.data);
396	    break;
397	case T_A:
398	    printf("%s\n", inet_ntoa(*rr->u.a));
399	    break;
400	case T_MX:
401	case T_AFSDB:{
402	    printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain);
403	    break;
404	}
405	case T_SRV:{
406	    struct srv_record *srv = rr->u.srv;
407	    printf("%d %d %d %s\n", srv->priority, srv->weight,
408		   srv->port, srv->target);
409	    break;
410	}
411	case T_TXT: {
412	    printf("%s\n", rr->u.txt);
413	    break;
414	}
415	case T_SIG : {
416	    struct sig_record *sig = rr->u.sig;
417	    const char *type_string = dns_type_to_string (sig->type);
418
419	    printf ("type %u (%s), algorithm %u, labels %u, orig_ttl %u, sig_expiration %u, sig_inception %u, key_tag %u, signer %s\n",
420		    sig->type, type_string ? type_string : "",
421		    sig->algorithm, sig->labels, sig->orig_ttl,
422		    sig->sig_expiration, sig->sig_inception, sig->key_tag,
423		    sig->signer);
424	    break;
425	}
426	case T_KEY : {
427	    struct key_record *key = rr->u.key;
428
429	    printf ("flags %u, protocol %u, algorithm %u\n",
430		    key->flags, key->protocol, key->algorithm);
431	    break;
432	}
433	default:
434	    printf("\n");
435	    break;
436	}
437    }
438
439    return 0;
440}
441#endif
442