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.


Release 1.0
[palacios.git] / geekos / 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.2 2008/08/13 20:12:50 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 int appcall(void){ //for UIP_APPCALL, referred in uip-conf.h
137
138         return 0;
139 }
140
141 void uip_log(char *msg)  //you should replace this by your own log function
142 {
143     //PrintDebug("\nuIP log:");
144     //PrintDebug(msg);
145 }
146
147
148 /**
149  * Callback function which is called when a hostname is found.
150  *
151  * This function must be implemented by the module that uses the DNS
152  * resolver. It is called when a hostname is found, or when a hostname
153  * was not found.
154  *
155  * \param name A pointer to the name that was looked up.  \param
156  * ipaddr A pointer to a 4-byte array containing the IP address of the
157  * hostname, or NULL if the hostname could not be found.
158  */
159 void resolv_found(char *name, u16_t *ipaddr){
160
161 }
162
163 /*---------------------------------------------------------------------------*/
164 /** \internal
165  * Walk through a compact encoded DNS name and return the end of it.
166  *
167  * \return The end of the name.
168  */
169 /*---------------------------------------------------------------------------*/
170 static unsigned char *
171 parse_name(unsigned char *query)
172 {
173   unsigned char n;
174
175   do {
176     n = *query++;
177     
178     while(n > 0) {
179       /*      printf("%c", *query);*/
180       ++query;
181       --n;
182     };
183     /*    printf(".");*/
184   } while(*query != 0);
185   /*  printf("\n");*/
186   return query + 1;
187 }
188 /*---------------------------------------------------------------------------*/
189 /** \internal
190  * Runs through the list of names to see if there are any that have
191  * not yet been queried and, if so, sends out a query.
192  */
193 /*---------------------------------------------------------------------------*/
194 static void
195 check_entries(void)
196 {
197   register struct dns_hdr *hdr;
198   char *query, *nptr, *nameptr;
199   static u8_t i;
200   static u8_t n;
201   register struct namemap *namemapptr;
202   
203   for(i = 0; i < RESOLV_ENTRIES; ++i) {
204     namemapptr = &names[i];
205     if(namemapptr->state == STATE_NEW ||
206        namemapptr->state == STATE_ASKING) {
207       if(namemapptr->state == STATE_ASKING) {
208         if(--namemapptr->tmr == 0) {
209           if(++namemapptr->retries == MAX_RETRIES) {
210             namemapptr->state = STATE_ERROR;
211             resolv_found(namemapptr->name, NULL);
212             continue;
213           }
214           namemapptr->tmr = namemapptr->retries;
215         } else {
216           /*      printf("Timer %d\n", namemapptr->tmr);*/
217           /* Its timer has not run out, so we move on to next
218              entry. */
219           continue;
220         }
221       } else {
222         namemapptr->state = STATE_ASKING;
223         namemapptr->tmr = 1;
224         namemapptr->retries = 0;
225       }
226       hdr = (struct dns_hdr *)uip_appdata;
227       memset(hdr, 0, sizeof(struct dns_hdr));
228       hdr->id = htons(i);
229       hdr->flags1 = DNS_FLAG1_RD;
230       hdr->numquestions = HTONS(1);
231       query = (char *)uip_appdata + 12;
232       nameptr = namemapptr->name;
233       --nameptr;
234       /* Convert hostname into suitable query format. */
235       do {
236         ++nameptr;
237         nptr = query;
238         ++query;
239         for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) {
240           *query = *nameptr;
241           ++query;
242           ++n;
243         }
244         *nptr = n;
245       } while(*nameptr != 0);
246       {
247         static unsigned char endquery[] =
248           {0,0,1,0,1};
249         memcpy(query, endquery, 5);
250       }
251       uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata));
252       break;
253     }
254   }
255 }
256 /*---------------------------------------------------------------------------*/
257 /** \internal
258  * Called when new UDP data arrives.
259  */
260 /*---------------------------------------------------------------------------*/
261 static void
262 newdata(void)
263 {
264   char *nameptr;
265   struct dns_answer *ans;
266   struct dns_hdr *hdr;
267   static u8_t nquestions, nanswers;
268   static u8_t i;
269   register struct namemap *namemapptr;
270   
271   hdr = (struct dns_hdr *)uip_appdata;
272   /*  printf("ID %d\n", htons(hdr->id));
273       printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE);
274       printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK);
275       printf("Num questions %d, answers %d, authrr %d, extrarr %d\n",
276       htons(hdr->numquestions),
277       htons(hdr->numanswers),
278       htons(hdr->numauthrr),
279       htons(hdr->numextrarr));
280   */
281
282   /* The ID in the DNS header should be our entry into the name
283      table. */
284   i = htons(hdr->id);
285   namemapptr = &names[i];
286   if(i < RESOLV_ENTRIES &&
287      namemapptr->state == STATE_ASKING) {
288
289     /* This entry is now finished. */
290     namemapptr->state = STATE_DONE;
291     namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
292
293     /* Check for error. If so, call callback to inform. */
294     if(namemapptr->err != 0) {
295       namemapptr->state = STATE_ERROR;
296       resolv_found(namemapptr->name, NULL);
297       return;
298     }
299
300     /* We only care about the question(s) and the answers. The authrr
301        and the extrarr are simply discarded. */
302     nquestions = htons(hdr->numquestions);
303     nanswers = htons(hdr->numanswers);
304
305     /* Skip the name in the question. XXX: This should really be
306        checked agains the name in the question, to be sure that they
307        match. */
308     nameptr = parse_name((char *)uip_appdata + 12) + 4;
309
310     while(nanswers > 0) {
311       /* The first byte in the answer resource record determines if it
312          is a compressed record or a normal one. */
313       if(*nameptr & 0xc0) {
314         /* Compressed name. */
315         nameptr +=2;
316         /*      printf("Compressed anwser\n");*/
317       } else {
318         /* Not compressed name. */
319         nameptr = parse_name((char *)nameptr);
320       }
321
322       ans = (struct dns_answer *)nameptr;
323       /*      printf("Answer: type %x, class %x, ttl %x, length %x\n",
324              htons(ans->type), htons(ans->class), (htons(ans->ttl[0])
325              << 16) | htons(ans->ttl[1]), htons(ans->len));*/
326
327       /* Check for IP address type and Internet class. Others are
328          discarded. */
329       if(ans->type == HTONS(1) &&
330          ans->class == HTONS(1) &&
331          ans->len == HTONS(4)) {
332         /*      printf("IP address %d.%d.%d.%d\n",
333                htons(ans->ipaddr[0]) >> 8,
334                htons(ans->ipaddr[0]) & 0xff,
335                htons(ans->ipaddr[1]) >> 8,
336                htons(ans->ipaddr[1]) & 0xff);*/
337         /* XXX: we should really check that this IP address is the one
338            we want. */
339         namemapptr->ipaddr[0] = ans->ipaddr[0];
340         namemapptr->ipaddr[1] = ans->ipaddr[1];
341         
342         resolv_found(namemapptr->name, namemapptr->ipaddr);
343         return;
344       } else {
345         nameptr = nameptr + 10 + htons(ans->len);
346       }
347       --nanswers;
348     }
349   }
350
351 }
352 /*---------------------------------------------------------------------------*/
353 /** \internal
354  * The main UDP function.
355  */
356 /*---------------------------------------------------------------------------*/
357 void
358 resolv_appcall(void)
359 {
360   if(uip_udp_conn->rport == HTONS(53)) {
361     if(uip_poll()) {
362       check_entries();
363     }
364     if(uip_newdata()) {
365       newdata();
366     }
367   }
368 }
369 /*---------------------------------------------------------------------------*/
370 /**
371  * Queues a name so that a question for the name will be sent out.
372  *
373  * \param name The hostname that is to be queried.
374  */
375 /*---------------------------------------------------------------------------*/
376 void
377 resolv_query(char *name)
378 {
379   static u8_t i;
380   static u8_t lseq, lseqi;
381   register struct namemap *nameptr;
382       
383   lseq = lseqi = 0;
384   
385   for(i = 0; i < RESOLV_ENTRIES; ++i) {
386     nameptr = &names[i];
387     if(nameptr->state == STATE_UNUSED) {
388       break;
389     }
390     if(seqno - nameptr->seqno > lseq) {
391       lseq = seqno - nameptr->seqno;
392       lseqi = i;
393     }
394   }
395
396   if(i == RESOLV_ENTRIES) {
397     i = lseqi;
398     nameptr = &names[i];
399   }
400
401   /*  printf("Using entry %d\n", i);*/
402
403   strcpy(nameptr->name, name);
404   nameptr->state = STATE_NEW;
405   nameptr->seqno = seqno;
406   ++seqno;
407 }
408 /*---------------------------------------------------------------------------*/
409 /**
410  * Look up a hostname in the array of known hostnames.
411  *
412  * \note This function only looks in the internal array of known
413  * hostnames, it does not send out a query for the hostname if none
414  * was found. The function resolv_query() can be used to send a query
415  * for a hostname.
416  *
417  * \return A pointer to a 4-byte representation of the hostname's IP
418  * address, or NULL if the hostname was not found in the array of
419  * hostnames.
420  */
421 /*---------------------------------------------------------------------------*/
422 u16_t *
423 resolv_lookup(char *name)
424 {
425   static u8_t i;
426   struct namemap *nameptr;
427   
428   /* Walk through the list to see if the name is in there. If it is
429      not, we return NULL. */
430   for(i = 0; i < RESOLV_ENTRIES; ++i) {
431     nameptr = &names[i];
432     if(nameptr->state == STATE_DONE &&
433        strcmp(name, nameptr->name) == 0) {
434       return nameptr->ipaddr;
435     }
436   }
437   return NULL;
438 }
439 /*---------------------------------------------------------------------------*/
440 /**
441  * Obtain the currently configured DNS server.
442  *
443  * \return A pointer to a 4-byte representation of the IP address of
444  * the currently configured DNS server or NULL if no DNS server has
445  * been configured.
446  */
447 /*---------------------------------------------------------------------------*/
448 u16_t *
449 resolv_getserver(void)
450 {
451   if(resolv_conn == NULL) {
452     return NULL;
453   }
454   return resolv_conn->ripaddr;
455 }
456 /*---------------------------------------------------------------------------*/
457 /**
458  * Configure which DNS server to use for queries.
459  *
460  * \param dnsserver A pointer to a 4-byte representation of the IP
461  * address of the DNS server to be configured.
462  */
463 /*---------------------------------------------------------------------------*/
464 void
465 resolv_conf(u16_t *dnsserver)
466 {
467   if(resolv_conn != NULL) {
468     uip_udp_remove(resolv_conn);
469   }
470   
471   resolv_conn = uip_udp_new((uip_ipaddr_t *)dnsserver, HTONS(53));
472 }
473 /*---------------------------------------------------------------------------*/
474 /**
475  * Initalize the resolver.
476  */
477 /*---------------------------------------------------------------------------*/
478 void
479 resolv_init(void)
480 {
481   static u8_t i;
482   
483   for(i = 0; i < RESOLV_ENTRIES; ++i) {
484     names[i].state = STATE_DONE;
485   }
486
487 }
488 /*---------------------------------------------------------------------------*/
489
490 /** @} */
491 /** @} */