Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / kerberosIV / lib / roken / resolve.c
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