xref: /freebsd/crypto/heimdal/lib/roken/resolve.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
1 /*
2  * Copyright (c) 1995, 1996, 1997, 1998, 1999 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 
46 RCSID("$Id: resolve.c,v 1.22 1999/12/02 16:58:52 joda Exp $");
47 
48 #if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND)
49 
50 #define DECL(X) {#X, T_##X}
51 
52 static struct stot{
53     const char *name;
54     int type;
55 }stot[] = {
56     DECL(A),
57     DECL(NS),
58     DECL(CNAME),
59     DECL(PTR),
60     DECL(MX),
61     DECL(TXT),
62     DECL(AFSDB),
63     DECL(SRV),
64     {NULL, 	0}
65 };
66 
67 int _resolve_debug;
68 
69 static int
70 string_to_type(const char *name)
71 {
72     struct stot *p = stot;
73     for(p = stot; p->name; p++)
74 	if(strcasecmp(name, p->name) == 0)
75 	    return p->type;
76     return -1;
77 }
78 
79 static const char *
80 type_to_string(int type)
81 {
82     struct stot *p = stot;
83     for(p = stot; p->name; p++)
84 	if(type == p->type)
85 	    return p->name;
86     return NULL;
87 }
88 
89 void
90 dns_free_data(struct dns_reply *r)
91 {
92     struct resource_record *rr;
93     if(r->q.domain)
94 	free(r->q.domain);
95     for(rr = r->head; rr;){
96 	struct resource_record *tmp = rr;
97 	if(rr->domain)
98 	    free(rr->domain);
99 	if(rr->u.data)
100 	    free(rr->u.data);
101 	rr = rr->next;
102 	free(tmp);
103     }
104     free (r);
105 }
106 
107 static struct dns_reply*
108 parse_reply(unsigned char *data, int len)
109 {
110     unsigned char *p;
111     char host[128];
112     int status;
113 
114     struct dns_reply *r;
115     struct resource_record **rr;
116 
117     r = calloc(1, sizeof(*r));
118     if (r == NULL)
119 	return NULL;
120 
121     p = data;
122 #if 0
123     /* doesn't work on Crays */
124     memcpy(&r->h, p, sizeof(HEADER));
125     p += sizeof(HEADER);
126 #else
127     memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
128     p += 12;
129 #endif
130     status = dn_expand(data, data + len, p, host, sizeof(host));
131     if(status < 0){
132 	dns_free_data(r);
133 	return NULL;
134     }
135     r->q.domain = strdup(host);
136     if(r->q.domain == NULL) {
137 	dns_free_data(r);
138 	return NULL;
139     }
140     p += status;
141     r->q.type = (p[0] << 8 | p[1]);
142     p += 2;
143     r->q.class = (p[0] << 8 | p[1]);
144     p += 2;
145     rr = &r->head;
146     while(p < data + len){
147 	int type, class, ttl, size;
148 	status = dn_expand(data, data + len, p, host, sizeof(host));
149 	if(status < 0){
150 	    dns_free_data(r);
151 	    return NULL;
152 	}
153 	p += status;
154 	type = (p[0] << 8) | p[1];
155 	p += 2;
156 	class = (p[0] << 8) | p[1];
157 	p += 2;
158 	ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
159 	p += 4;
160 	size = (p[0] << 8) | p[1];
161 	p += 2;
162 	*rr = (struct resource_record*)calloc(1,
163 					      sizeof(struct resource_record));
164 	if(*rr == NULL) {
165 	    dns_free_data(r);
166 	    return NULL;
167 	}
168 	(*rr)->domain = strdup(host);
169 	if((*rr)->domain == NULL) {
170 	    dns_free_data(r);
171 	    return NULL;
172 	}
173 	(*rr)->type = type;
174 	(*rr)->class = class;
175 	(*rr)->ttl = ttl;
176 	(*rr)->size = size;
177 	switch(type){
178 	case T_NS:
179 	case T_CNAME:
180 	case T_PTR:
181 	    status = dn_expand(data, data + len, p, host, sizeof(host));
182 	    if(status < 0){
183 		dns_free_data(r);
184 		return NULL;
185 	    }
186 	    (*rr)->u.txt = strdup(host);
187 	    if((*rr)->u.txt == NULL) {
188 		dns_free_data(r);
189 		return NULL;
190 	    }
191 	    break;
192 	case T_MX:
193 	case T_AFSDB:{
194 	    status = dn_expand(data, data + len, p + 2, host, sizeof(host));
195 	    if(status < 0){
196 		dns_free_data(r);
197 		return NULL;
198 	    }
199 	    (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
200 						    strlen(host));
201 	    if((*rr)->u.mx == NULL) {
202 		dns_free_data(r);
203 		return NULL;
204 	    }
205 	    (*rr)->u.mx->preference = (p[0] << 8) | p[1];
206 	    strcpy((*rr)->u.mx->domain, host);
207 	    break;
208 	}
209 	case T_SRV:{
210 	    status = dn_expand(data, data + len, p + 6, host, sizeof(host));
211 	    if(status < 0){
212 		dns_free_data(r);
213 		return NULL;
214 	    }
215 	    (*rr)->u.srv =
216 		(struct srv_record*)malloc(sizeof(struct srv_record) +
217 					   strlen(host));
218 	    if((*rr)->u.srv == NULL) {
219 		dns_free_data(r);
220 		return NULL;
221 	    }
222 	    (*rr)->u.srv->priority = (p[0] << 8) | p[1];
223 	    (*rr)->u.srv->weight = (p[2] << 8) | p[3];
224 	    (*rr)->u.srv->port = (p[4] << 8) | p[5];
225 	    strcpy((*rr)->u.srv->target, host);
226 	    break;
227 	}
228 	case T_TXT:{
229 	    (*rr)->u.txt = (char*)malloc(size + 1);
230 	    if((*rr)->u.txt == NULL) {
231 		dns_free_data(r);
232 		return NULL;
233 	    }
234 	    strncpy((*rr)->u.txt, (char*)p + 1, *p);
235 	    (*rr)->u.txt[*p] = 0;
236 	    break;
237 	}
238 
239 	default:
240 	    (*rr)->u.data = (unsigned char*)malloc(size);
241 	    if(size != 0 && (*rr)->u.data == NULL) {
242 		dns_free_data(r);
243 		return NULL;
244 	    }
245 	    memcpy((*rr)->u.data, p, size);
246 	}
247 	p += size;
248 	rr = &(*rr)->next;
249     }
250     *rr = NULL;
251     return r;
252 }
253 
254 static struct dns_reply *
255 dns_lookup_int(const char *domain, int rr_class, int rr_type)
256 {
257     unsigned char reply[1024];
258     int len;
259     struct dns_reply *r = NULL;
260     u_long old_options = 0;
261 
262     if (_resolve_debug) {
263         old_options = _res.options;
264 	_res.options |= RES_DEBUG;
265 	fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain,
266 		rr_class, type_to_string(rr_type));
267     }
268     len = res_search(domain, rr_class, rr_type, reply, sizeof(reply));
269     if (_resolve_debug) {
270         _res.options = old_options;
271 	fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
272 		domain, rr_class, type_to_string(rr_type), len);
273     }
274     if (len >= 0)
275 	r = parse_reply(reply, len);
276     return r;
277 }
278 
279 struct dns_reply *
280 dns_lookup(const char *domain, const char *type_name)
281 {
282     int type;
283 
284     type = string_to_type(type_name);
285     if(type == -1) {
286 	if(_resolve_debug)
287 	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
288 		    type_name);
289 	return NULL;
290     }
291     return dns_lookup_int(domain, C_IN, type);
292 }
293 
294 #else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
295 
296 struct dns_reply *
297 dns_lookup(const char *domain, const char *type_name)
298 {
299     return NULL;
300 }
301 
302 void
303 dns_free_data(struct dns_reply *r)
304 {
305 }
306 
307 #endif
308 
309 #ifdef TEST
310 int
311 main(int argc, char **argv)
312 {
313     struct dns_reply *r;
314     struct resource_record *rr;
315     r = dns_lookup(argv[1], argv[2]);
316     if(r == NULL){
317 	printf("No reply.\n");
318 	return 1;
319     }
320     for(rr = r->head; rr;rr=rr->next){
321 	printf("%s %s %d ", rr->domain, type_to_string(rr->type), rr->ttl);
322 	switch(rr->type){
323 	case T_NS:
324 	    printf("%s\n", (char*)rr->u.data);
325 	    break;
326 	case T_A:
327 	    printf("%d.%d.%d.%d\n",
328 		   ((unsigned char*)rr->u.data)[0],
329 		   ((unsigned char*)rr->u.data)[1],
330 		   ((unsigned char*)rr->u.data)[2],
331 		   ((unsigned char*)rr->u.data)[3]);
332 	    break;
333 	case T_MX:
334 	case T_AFSDB:{
335 	    struct mx_record *mx = (struct mx_record*)rr->u.data;
336 	    printf("%d %s\n", mx->preference, mx->domain);
337 	    break;
338 	}
339 	case T_SRV:{
340 	    struct srv_record *srv = (struct srv_record*)rr->u.data;
341 	    printf("%d %d %d %s\n", srv->priority, srv->weight,
342 		   srv->port, srv->target);
343 	    break;
344 	}
345 	default:
346 	    printf("\n");
347 	    break;
348 	}
349     }
350 
351     return 0;
352 }
353 #endif
354