Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


51aacba4d369d5845ba534b2c0803720726fb82e
[palacios.git] / palacios / src / net / resolv.c
1 /**
2  * \addtogroup apps
3  * @{
4  */
5
6 /**
7  * \defgroup resolv DNS resolver
8  * @{
9  *
10  * The uIP DNS resolver functions are used to lookup a hostname and
11  * map it to a numerical IP address. It maintains a list of resolved
12  * hostnames that can be queried with the resolv_lookup()
13  * function. New hostnames can be resolved using the resolv_query()
14  * function.
15  *
16  * When a hostname has been resolved (or found to be non-existant),
17  * the resolver code calls a callback function called resolv_found()
18  * that must be implemented by the module that uses the resolver.
19  */
20
21 /**
22  * \file
23  * DNS host name to IP address resolver.
24  * \author Adam Dunkels <adam@dunkels.com>
25  *
26  * This file implements a DNS host name to IP address resolver.
27  */
28
29 /*
30  * Copyright (c) 2002-2003, Adam Dunkels.
31  * All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  * 3. The name of the author may not be used to endorse or promote
42  *    products derived from this software without specific prior
43  *    written permission.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
46  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
47  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
49  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
51  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56  *
57  * This file is part of the uIP TCP/IP stack.
58  *
59  * $Id: resolv.c,v 1.1 2008/08/06 23:21:19 andrewlxia Exp $
60  *
61  */
62
63 #include <uip/resolv.h>
64 #include <uip/uip.h>
65
66 #include <string.h>
67
68 #ifndef NULL
69 #define NULL (void *)0
70 #endif /* NULL */
71
72 /** \internal The maximum number of retries when asking for a name. */
73 #define MAX_RETRIES 8
74
75 /** \internal The DNS message header. */
76 struct dns_hdr {
77   u16_t id;
78   u8_t flags1, flags2;
79 #define DNS_FLAG1_RESPONSE        0x80
80 #define DNS_FLAG1_OPCODE_STATUS   0x10
81 #define DNS_FLAG1_OPCODE_INVERSE  0x08
82 #define DNS_FLAG1_OPCODE_STANDARD 0x00
83 #define DNS_FLAG1_AUTHORATIVE     0x04
84 #define DNS_FLAG1_TRUNC           0x02
85 #define DNS_FLAG1_RD              0x01
86 #define DNS_FLAG2_RA              0x80
87 #define DNS_FLAG2_ERR_MASK        0x0f
88 #define DNS_FLAG2_ERR_NONE        0x00
89 #define DNS_FLAG2_ERR_NAME        0x03
90   u16_t numquestions;
91   u16_t numanswers;
92   u16_t numauthrr;
93   u16_t numextrarr;
94 };
95
96 /** \internal The DNS answer message structure. */
97 struct dns_answer {
98   /* DNS answer record starts with either a domain name or a pointer
99      to a name already present somewhere in the packet. */
100   u16_t type;
101   u16_t class;
102   u16_t ttl[2];
103   u16_t len;
104   uip_ipaddr_t ipaddr;
105 };
106
107 struct namemap {
108 #define STATE_UNUSED 0
109 #define STATE_NEW    1
110 #define STATE_ASKING 2
111 #define STATE_DONE   3
112 #define STATE_ERROR  4
113   u8_t state;
114   u8_t tmr;
115   u8_t retries;
116   u8_t seqno;
117   u8_t err;
118   char name[32];
119   uip_ipaddr_t ipaddr;
120 };
121
122 #ifndef UIP_CONF_RESOLV_ENTRIES
123 #define RESOLV_ENTRIES 4
124 #else /* UIP_CONF_RESOLV_ENTRIES */
125 #define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES
126 #endif /* UIP_CONF_RESOLV_ENTRIES */
127
128
129 static struct namemap names[RESOLV_ENTRIES];
130
131 static u8_t seqno;
132
133 static struct uip_udp_conn *resolv_conn = NULL;
134
135
136 /*---------------------------------------------------------------------------*/
137 /** \internal
138  * Walk through a compact encoded DNS name and return the end of it.
139  *
140  * \return The end of the name.
141  */
142 /*---------------------------------------------------------------------------*/
143 static unsigned char *
144 parse_name(unsigned char *query)
145 {
146   unsigned char n;
147
148   do {
149     n = *query++;
150     
151     while(n > 0) {
152       /*      printf("%c", *query);*/
153       ++query;
154       --n;
155     };
156     /*    printf(".");*/
157   } while(*query != 0);
158   /*  printf("\n");*/
159   return query + 1;
160 }
161 /*---------------------------------------------------------------------------*/
162 /** \internal
163  * Runs through the list of names to see if there are any that have
164  * not yet been queried and, if so, sends out a query.
165  */
166 /*---------------------------------------------------------------------------*/
167 static void
168 check_entries(void)
169 {
170   register struct dns_hdr *hdr;
171   char *query, *nptr, *nameptr;
172   static u8_t i;
173   static u8_t n;
174   register struct namemap *namemapptr;
175   
176   for(i = 0; i < RESOLV_ENTRIES; ++i) {
177     namemapptr = &names[i];
178     if(namemapptr->state == STATE_NEW ||
179        namemapptr->state == STATE_ASKING) {
180       if(namemapptr->state == STATE_ASKING) {
181         if(--namemapptr->tmr == 0) {
182           if(++namemapptr->retries == MAX_RETRIES) {
183             namemapptr->state = STATE_ERROR;
184             resolv_found(namemapptr->name, NULL);
185             continue;
186           }
187           namemapptr->tmr = namemapptr->retries;
188         } else {
189           /*      printf("Timer %d\n", namemapptr->tmr);*/
190           /* Its timer has not run out, so we move on to next
191              entry. */
192           continue;
193         }
194       } else {
195         namemapptr->state = STATE_ASKING;
196         namemapptr->tmr = 1;
197         namemapptr->retries = 0;
198       }
199       hdr = (struct dns_hdr *)uip_appdata;
200       memset(hdr, 0, sizeof(struct dns_hdr));
201       hdr->id = htons(i);
202       hdr->flags1 = DNS_FLAG1_RD;
203       hdr->numquestions = HTONS(1);
204       query = (char *)uip_appdata + 12;
205       nameptr = namemapptr->name;
206       --nameptr;
207       /* Convert hostname into suitable query format. */
208       do {
209         ++nameptr;
210         nptr = query;
211         ++query;
212         for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) {
213           *query = *nameptr;
214           ++query;
215           ++n;
216         }
217         *nptr = n;
218       } while(*nameptr != 0);
219       {
220         static unsigned char endquery[] =
221           {0,0,1,0,1};
222         memcpy(query, endquery, 5);
223       }
224       uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata));
225       break;
226     }
227   }
228 }
229 /*---------------------------------------------------------------------------*/
230 /** \internal
231  * Called when new UDP data arrives.
232  */
233 /*---------------------------------------------------------------------------*/
234 static void
235 newdata(void)
236 {
237   char *nameptr;
238   struct dns_answer *ans;
239   struct dns_hdr *hdr;
240   static u8_t nquestions, nanswers;
241   static u8_t i;
242   register struct namemap *namemapptr;
243   
244   hdr = (struct dns_hdr *)uip_appdata;
245   /*  printf("ID %d\n", htons(hdr->id));
246       printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE);
247       printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK);
248       printf("Num questions %d, answers %d, authrr %d, extrarr %d\n",
249       htons(hdr->numquestions),
250       htons(hdr->numanswers),
251       htons(hdr->numauthrr),
252       htons(hdr->numextrarr));
253   */
254
255   /* The ID in the DNS header should be our entry into the name
256      table. */
257   i = htons(hdr->id);
258   namemapptr = &names[i];
259   if(i < RESOLV_ENTRIES &&
260      namemapptr->state == STATE_ASKING) {
261
262     /* This entry is now finished. */
263     namemapptr->state = STATE_DONE;
264     namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
265
266     /* Check for error. If so, call callback to inform. */
267     if(namemapptr->err != 0) {
268       namemapptr->state = STATE_ERROR;
269       resolv_found(namemapptr->name, NULL);
270       return;
271     }
272
273     /* We only care about the question(s) and the answers. The authrr
274        and the extrarr are simply discarded. */
275     nquestions = htons(hdr->numquestions);
276     nanswers = htons(hdr->numanswers);
277
278     /* Skip the name in the question. XXX: This should really be
279        checked agains the name in the question, to be sure that they
280        match. */
281     nameptr = parse_name((char *)uip_appdata + 12) + 4;
282
283     while(nanswers > 0) {
284       /* The first byte in the answer resource record determines if it
285          is a compressed record or a normal one. */
286       if(*nameptr & 0xc0) {
287         /* Compressed name. */
288         nameptr +=2;
289         /*      printf("Compressed anwser\n");*/
290       } else {
291         /* Not compressed name. */
292         nameptr = parse_name((char *)nameptr);
293       }
294
295       ans = (struct dns_answer *)nameptr;
296       /*      printf("Answer: type %x, class %x, ttl %x, length %x\n",
297              htons(ans->type), htons(ans->class), (htons(ans->ttl[0])
298              << 16) | htons(ans->ttl[1]), htons(ans->len));*/
299
300       /* Check for IP address type and Internet class. Others are
301          discarded. */
302       if(ans->type == HTONS(1) &&
303          ans->class == HTONS(1) &&
304          ans->len == HTONS(4)) {
305         /*      printf("IP address %d.%d.%d.%d\n",
306                htons(ans->ipaddr[0]) >> 8,
307                htons(ans->ipaddr[0]) & 0xff,
308                htons(ans->ipaddr[1]) >> 8,
309                htons(ans->ipaddr[1]) & 0xff);*/
310         /* XXX: we should really check that this IP address is the one
311            we want. */
312         namemapptr->ipaddr[0] = ans->ipaddr[0];
313         namemapptr->ipaddr[1] = ans->ipaddr[1];
314         
315         resolv_found(namemapptr->name, namemapptr->ipaddr);
316         return;
317       } else {
318         nameptr = nameptr + 10 + htons(ans->len);
319       }
320       --nanswers;
321     }
322   }
323
324 }
325 /*---------------------------------------------------------------------------*/
326 /** \internal
327  * The main UDP function.
328  */
329 /*---------------------------------------------------------------------------*/
330 void
331 resolv_appcall(void)
332 {
333   if(uip_udp_conn->rport == HTONS(53)) {
334     if(uip_poll()) {
335       check_entries();
336     }
337     if(uip_newdata()) {
338       newdata();
339     }
340   }
341 }
342 /*---------------------------------------------------------------------------*/
343 /**
344  * Queues a name so that a question for the name will be sent out.
345  *
346  * \param name The hostname that is to be queried.
347  */
348 /*---------------------------------------------------------------------------*/
349 void
350 resolv_query(char *name)
351 {
352   static u8_t i;
353   static u8_t lseq, lseqi;
354   register struct namemap *nameptr;
355       
356   lseq = lseqi = 0;
357   
358   for(i = 0; i < RESOLV_ENTRIES; ++i) {
359     nameptr = &names[i];
360     if(nameptr->state == STATE_UNUSED) {
361       break;
362     }
363     if(seqno - nameptr->seqno > lseq) {
364       lseq = seqno - nameptr->seqno;
365       lseqi = i;
366     }
367   }
368
369   if(i == RESOLV_ENTRIES) {
370     i = lseqi;
371     nameptr = &names[i];
372   }
373
374   /*  printf("Using entry %d\n", i);*/
375
376   strcpy(nameptr->name, name);
377   nameptr->state = STATE_NEW;
378   nameptr->seqno = seqno;
379   ++seqno;
380 }
381 /*---------------------------------------------------------------------------*/
382 /**
383  * Look up a hostname in the array of known hostnames.
384  *
385  * \note This function only looks in the internal array of known
386  * hostnames, it does not send out a query for the hostname if none
387  * was found. The function resolv_query() can be used to send a query
388  * for a hostname.
389  *
390  * \return A pointer to a 4-byte representation of the hostname's IP
391  * address, or NULL if the hostname was not found in the array of
392  * hostnames.
393  */
394 /*---------------------------------------------------------------------------*/
395 u16_t *
396 resolv_lookup(char *name)
397 {
398   static u8_t i;
399   struct namemap *nameptr;
400   
401   /* Walk through the list to see if the name is in there. If it is
402      not, we return NULL. */
403   for(i = 0; i < RESOLV_ENTRIES; ++i) {
404     nameptr = &names[i];
405     if(nameptr->state == STATE_DONE &&
406        strcmp(name, nameptr->name) == 0) {
407       return nameptr->ipaddr;
408     }
409   }
410   return NULL;
411 }
412 /*---------------------------------------------------------------------------*/
413 /**
414  * Obtain the currently configured DNS server.
415  *
416  * \return A pointer to a 4-byte representation of the IP address of
417  * the currently configured DNS server or NULL if no DNS server has
418  * been configured.
419  */
420 /*---------------------------------------------------------------------------*/
421 u16_t *
422 resolv_getserver(void)
423 {
424   if(resolv_conn == NULL) {
425     return NULL;
426   }
427   return resolv_conn->ripaddr;
428 }
429 /*---------------------------------------------------------------------------*/
430 /**
431  * Configure which DNS server to use for queries.
432  *
433  * \param dnsserver A pointer to a 4-byte representation of the IP
434  * address of the DNS server to be configured.
435  */
436 /*---------------------------------------------------------------------------*/
437 void
438 resolv_conf(u16_t *dnsserver)
439 {
440   if(resolv_conn != NULL) {
441     uip_udp_remove(resolv_conn);
442   }
443   
444   resolv_conn = uip_udp_new((uip_ipaddr_t *)dnsserver, HTONS(53));
445 }
446 /*---------------------------------------------------------------------------*/
447 /**
448  * Initalize the resolver.
449  */
450 /*---------------------------------------------------------------------------*/
451 void
452 resolv_init(void)
453 {
454   static u8_t i;
455   
456   for(i = 0; i < RESOLV_ENTRIES; ++i) {
457     names[i].state = STATE_DONE;
458   }
459
460 }
461 /*---------------------------------------------------------------------------*/
462
463 /** @} */
464 /** @} */