1 /*
2 * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hvgskolan
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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the Kungliga Tekniska
20 * Hvgskolan and its contributors.
21 *
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include "config.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <sys/types.h>
44 #include <netinet/in.h>
45 #include <arpa/nameser.h>
46 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
47 #include <arpa/nameser_compat.h>
48 #endif
49 #include <string.h>
50 #ifdef HAVE_STRINGS_H
51 #include <strings.h>
52 #endif
53
54 #include <resolv.h>
55
56 #include "resolve.h"
57
58 static char rcsId[] = "$Id: resolve.c,v 2.11 2009/05/26 07:25:12 lukeh Exp $";
59
60 #if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND)
61
62 #define DECL(X) {#X, T_##X}
63
64 static struct stot
65 {
66 char *name;
67 int type;
68 }
69 stot[] =
70 {
71 DECL (A),
72 DECL (NS),
73 DECL (CNAME), DECL (PTR), DECL (MX), DECL (TXT), DECL (AFSDB), DECL (SRV),
74 {
75 NULL, 0}
76 };
77
78 static int
string_to_type(const char * name)79 string_to_type (const char *name)
80 {
81 struct stot *p = stot;
82 for (p = stot; p->name; p++)
83 if (strcasecmp (name, p->name) == 0)
84 return p->type;
85 return -1;
86 }
87
88 #if 0
89 static char *
90 type_to_string (int type)
91 {
92 struct stot *p = stot;
93 for (p = stot; p->name; p++)
94 if (type == p->type)
95 return p->name;
96 return NULL;
97 }
98 #endif
99
100 void
dns_free_data(struct dns_reply * r)101 dns_free_data (struct dns_reply *r)
102 {
103 struct resource_record *rr;
104 if (r->q.domain)
105 free (r->q.domain);
106 for (rr = r->head; rr;)
107 {
108 struct resource_record *tmp = rr;
109 if (rr->domain)
110 free (rr->domain);
111 if (rr->u.data)
112 free (rr->u.data);
113 rr = rr->next;
114 free (tmp);
115 }
116 free (r);
117 }
118
119 static struct dns_reply *
parse_reply(unsigned char * data,int len)120 parse_reply (unsigned char *data, int len)
121 {
122 unsigned char *p;
123 char host[128];
124 int status;
125 int query, response;
126
127 struct dns_reply *r;
128 struct resource_record **rr;
129
130 r = (struct dns_reply *) malloc (sizeof (struct dns_reply));
131 memset (r, 0, sizeof (struct dns_reply));
132 r->q.domain = NULL;
133
134 p = data;
135 memcpy (&r->h, p, sizeof (HEADER));
136 p += sizeof (HEADER);
137 for (query = 0; query < ntohs(r->h.qdcount); query++)
138 {
139 status = dn_expand (data, data + len, p, host, sizeof (host));
140 if (status < 0)
141 {
142 dns_free_data (r);
143 return NULL;
144 }
145 p += status;
146 if (p + 4 > data + len)
147 {
148 dns_free_data (r);
149 return NULL;
150 }
151 if (r->q.domain == NULL)
152 {
153 r->q.domain = strdup (host);
154 r->q.type = (p[0] << 8 | p[1]);
155 r->q.class = (p[2] << 8 | p[3]);
156 }
157 p += 4;
158 }
159 rr = &r->head;
160 for (response = 0; (response < ntohs(r->h.ancount)) && (p < data + len); response++)
161 {
162 unsigned int type, class, ttl, size;
163 status = dn_expand (data, data + len, p, host, sizeof (host));
164 if (status < 0)
165 {
166 dns_free_data (r);
167 return NULL;
168 }
169 p += status;
170 if (p + 10 > data + len)
171 {
172 dns_free_data (r);
173 return NULL;
174 }
175 type = (p[0] << 8) | p[1];
176 p += 2;
177 class = (p[0] << 8) | p[1];
178 p += 2;
179 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
180 p += 4;
181 size = (p[0] << 8) | p[1];
182 p += 2;
183 if (p + size > data + len)
184 {
185 dns_free_data (r);
186 return NULL;
187 }
188 *rr = (struct resource_record *) calloc (1,
189 sizeof (struct
190 resource_record));
191 (*rr)->domain = strdup (host);
192 (*rr)->type = type;
193 (*rr)->class = class;
194 (*rr)->ttl = ttl;
195 (*rr)->size = size;
196 switch (type)
197 {
198 case T_NS:
199 case T_CNAME:
200 case T_PTR:
201 status = dn_expand (data, data + len, p, host, sizeof (host));
202 if (status < 0)
203 {
204 dns_free_data (r);
205 return NULL;
206 }
207 (*rr)->u.txt = strdup (host);
208 break;
209 case T_MX:
210 case T_AFSDB:
211 {
212 if (p + 2 > data + len)
213 {
214 dns_free_data (r);
215 return NULL;
216 }
217 status = dn_expand (data, data + len, p + 2, host, sizeof (host));
218 if (status < 0)
219 {
220 dns_free_data (r);
221 return NULL;
222 }
223
224 (*rr)->u.mx =
225 (struct mx_record *) malloc (sizeof (struct mx_record) +
226 strlen (host));
227 (*rr)->u.mx->preference = (p[0] << 8) | p[1];
228 strcpy ((*rr)->u.mx->domain, host);
229 break;
230 }
231 case T_SRV:
232 {
233 if (p + 6 > data + len)
234 {
235 dns_free_data (r);
236 return NULL;
237 }
238 status = dn_expand (data, data + len, p + 6, host, sizeof (host));
239 if (status < 0)
240 {
241 dns_free_data (r);
242 return NULL;
243 }
244 (*rr)->u.srv =
245 (struct srv_record *) malloc (sizeof (struct srv_record) +
246 strlen (host));
247 (*rr)->u.srv->priority = (p[0] << 8) | p[1];
248 (*rr)->u.srv->weight = (p[2] << 8) | p[3];
249 (*rr)->u.srv->port = (p[4] << 8) | p[5];
250 strcpy ((*rr)->u.srv->target, host);
251 break;
252 }
253 case T_TXT:
254 {
255 if (p + *p > data + len)
256 {
257 dns_free_data (r);
258 return NULL;
259 }
260 (*rr)->u.txt = (char *) malloc (size + 1);
261 strncpy ((*rr)->u.txt, (char *) p + 1, *p);
262 (*rr)->u.txt[*p] = 0;
263 break;
264 }
265
266 default:
267 (*rr)->u.data = (unsigned char *) malloc (size);
268 memcpy ((*rr)->u.data, p, size);
269 }
270 p += size;
271 rr = &(*rr)->next;
272 }
273 *rr = NULL;
274 return r;
275 }
276
277
278
279 struct dns_reply *
dns_lookup(const char * domain,const char * type_name)280 dns_lookup (const char *domain, const char *type_name)
281 {
282 unsigned char *reply = NULL;
283 int len, rlen;
284 int type;
285 struct dns_reply *r = NULL;
286
287 type = string_to_type (type_name);
288 rlen = 1024;
289 reply = malloc(rlen);
290 do
291 {
292 len = res_search (domain, C_IN, type, reply, rlen);
293 if ((len == -1) || (len < rlen))
294 {
295 break;
296 }
297 reply = realloc (reply, len + 1024);
298 rlen = len + 1024;
299 }
300 while (1);
301 if (len >= 0)
302 r = parse_reply (reply, len);
303 free(reply);
304 return r;
305 }
306
307 #else /* defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
308
309 struct dns_reply *
dns_lookup(const char * domain,const char * type_name)310 dns_lookup (const char *domain, const char *type_name)
311 {
312 return NULL;
313 }
314
315 void
dns_free_data(struct dns_reply * r)316 dns_free_data (struct dns_reply *r)
317 {
318 }
319
320 #endif
321
322 #ifdef TEST
323
324 int
main(int argc,char ** argv)325 main (int argc, char **argv)
326 {
327 struct dns_reply *r;
328 struct resource_record *rr;
329 r = dns_lookup (argv[1], argv[2]);
330 if (r == NULL)
331 {
332 printf ("No reply.\n");
333 return 1;
334 }
335 for (rr = r->head; rr; rr = rr->next)
336 {
337 printf ("%s %s %d ", rr->domain, type_to_string (rr->type), rr->ttl);
338 switch (rr->type)
339 {
340 case T_NS:
341 printf ("%s\n", (char *) rr->data);
342 break;
343 case T_A:
344 printf ("%d.%d.%d.%d\n",
345 ((unsigned char *) rr->data)[0],
346 ((unsigned char *) rr->data)[1],
347 ((unsigned char *) rr->data)[2],
348 ((unsigned char *) rr->data)[3]);
349 break;
350 case T_MX:
351 case T_AFSDB:
352 {
353 struct mx_record *mx = (struct mx_record *) rr->data;
354 printf ("%d %s\n", mx->preference, mx->domain);
355 break;
356 }
357 case T_SRV:
358 {
359 struct srv_record *srv = (struct srv_record *) rr->data;
360 printf ("%d %d %d %s\n", srv->priority, srv->weight,
361 srv->port, srv->target);
362 break;
363 }
364 default:
365 printf ("\n");
366 break;
367 }
368 }
369
370 return 0;
371 }
372 #endif
373