xref: /freebsd/crypto/heimdal/lib/roken/resolve.c (revision 5e9cd1ae3e10592ed70e7575551cba1bbab04d84)
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 
46 RCSID("$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 
52 static 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 
71 int _resolve_debug = 0;
72 
73 int
74 dns_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 
83 const char *
84 dns_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 
93 void
94 dns_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 
111 static struct dns_reply*
112 parse_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 
323 static struct dns_reply *
324 dns_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 
348 struct dns_reply *
349 dns_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 
365 struct dns_reply *
366 dns_lookup(const char *domain, const char *type_name)
367 {
368     return NULL;
369 }
370 
371 void
372 dns_free_data(struct dns_reply *r)
373 {
374 }
375 
376 #endif
377 
378 #ifdef TEST
379 int
380 main(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