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