7 * \defgroup resolv DNS resolver
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()
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.
23 * DNS host name to IP address resolver.
24 * \author Adam Dunkels <adam@dunkels.com>
26 * This file implements a DNS host name to IP address resolver.
30 * Copyright (c) 2002-2003, Adam Dunkels.
31 * All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
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
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.
57 * This file is part of the uIP TCP/IP stack.
59 * $Id: resolv.c,v 1.2 2008/08/13 20:12:50 andrewlxia Exp $
63 #include <uip/resolv.h>
69 #define NULL (void *)0
72 /** \internal The maximum number of retries when asking for a name. */
75 /** \internal The DNS message header. */
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
96 /** \internal The DNS answer message structure. */
98 /* DNS answer record starts with either a domain name or a pointer
99 to a name already present somewhere in the packet. */
108 #define STATE_UNUSED 0
110 #define STATE_ASKING 2
112 #define STATE_ERROR 4
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 */
129 static struct namemap names[RESOLV_ENTRIES];
133 static struct uip_udp_conn *resolv_conn = NULL;
136 int appcall(void){ //for UIP_APPCALL, referred in uip-conf.h
141 void uip_log(char *msg) //you should replace this by your own log function
143 //PrintDebug("\nuIP log:");
149 * Callback function which is called when a hostname is found.
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
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.
159 void resolv_found(char *name, u16_t *ipaddr){
163 /*---------------------------------------------------------------------------*/
165 * Walk through a compact encoded DNS name and return the end of it.
167 * \return The end of the name.
169 /*---------------------------------------------------------------------------*/
170 static unsigned char *
171 parse_name(unsigned char *query)
179 /* printf("%c", *query);*/
184 } while(*query != 0);
188 /*---------------------------------------------------------------------------*/
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.
193 /*---------------------------------------------------------------------------*/
197 register struct dns_hdr *hdr;
198 char *query, *nptr, *nameptr;
201 register struct namemap *namemapptr;
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);
214 namemapptr->tmr = namemapptr->retries;
216 /* printf("Timer %d\n", namemapptr->tmr);*/
217 /* Its timer has not run out, so we move on to next
222 namemapptr->state = STATE_ASKING;
224 namemapptr->retries = 0;
226 hdr = (struct dns_hdr *)uip_appdata;
227 memset(hdr, 0, sizeof(struct dns_hdr));
229 hdr->flags1 = DNS_FLAG1_RD;
230 hdr->numquestions = HTONS(1);
231 query = (char *)uip_appdata + 12;
232 nameptr = namemapptr->name;
234 /* Convert hostname into suitable query format. */
239 for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) {
245 } while(*nameptr != 0);
247 static unsigned char endquery[] =
249 memcpy(query, endquery, 5);
251 uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata));
256 /*---------------------------------------------------------------------------*/
258 * Called when new UDP data arrives.
260 /*---------------------------------------------------------------------------*/
265 struct dns_answer *ans;
267 static u8_t nquestions, nanswers;
269 register struct namemap *namemapptr;
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));
282 /* The ID in the DNS header should be our entry into the name
285 namemapptr = &names[i];
286 if(i < RESOLV_ENTRIES &&
287 namemapptr->state == STATE_ASKING) {
289 /* This entry is now finished. */
290 namemapptr->state = STATE_DONE;
291 namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
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);
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);
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
308 nameptr = parse_name((char *)uip_appdata + 12) + 4;
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. */
316 /* printf("Compressed anwser\n");*/
318 /* Not compressed name. */
319 nameptr = parse_name((char *)nameptr);
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));*/
327 /* Check for IP address type and Internet class. Others are
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
339 namemapptr->ipaddr[0] = ans->ipaddr[0];
340 namemapptr->ipaddr[1] = ans->ipaddr[1];
342 resolv_found(namemapptr->name, namemapptr->ipaddr);
345 nameptr = nameptr + 10 + htons(ans->len);
352 /*---------------------------------------------------------------------------*/
354 * The main UDP function.
356 /*---------------------------------------------------------------------------*/
360 if(uip_udp_conn->rport == HTONS(53)) {
369 /*---------------------------------------------------------------------------*/
371 * Queues a name so that a question for the name will be sent out.
373 * \param name The hostname that is to be queried.
375 /*---------------------------------------------------------------------------*/
377 resolv_query(char *name)
380 static u8_t lseq, lseqi;
381 register struct namemap *nameptr;
385 for(i = 0; i < RESOLV_ENTRIES; ++i) {
387 if(nameptr->state == STATE_UNUSED) {
390 if(seqno - nameptr->seqno > lseq) {
391 lseq = seqno - nameptr->seqno;
396 if(i == RESOLV_ENTRIES) {
401 /* printf("Using entry %d\n", i);*/
403 strcpy(nameptr->name, name);
404 nameptr->state = STATE_NEW;
405 nameptr->seqno = seqno;
408 /*---------------------------------------------------------------------------*/
410 * Look up a hostname in the array of known hostnames.
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
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
421 /*---------------------------------------------------------------------------*/
423 resolv_lookup(char *name)
426 struct namemap *nameptr;
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) {
432 if(nameptr->state == STATE_DONE &&
433 strcmp(name, nameptr->name) == 0) {
434 return nameptr->ipaddr;
439 /*---------------------------------------------------------------------------*/
441 * Obtain the currently configured DNS server.
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
447 /*---------------------------------------------------------------------------*/
449 resolv_getserver(void)
451 if(resolv_conn == NULL) {
454 return resolv_conn->ripaddr;
456 /*---------------------------------------------------------------------------*/
458 * Configure which DNS server to use for queries.
460 * \param dnsserver A pointer to a 4-byte representation of the IP
461 * address of the DNS server to be configured.
463 /*---------------------------------------------------------------------------*/
465 resolv_conf(u16_t *dnsserver)
467 if(resolv_conn != NULL) {
468 uip_udp_remove(resolv_conn);
471 resolv_conn = uip_udp_new((uip_ipaddr_t *)dnsserver, HTONS(53));
473 /*---------------------------------------------------------------------------*/
475 * Initalize the resolver.
477 /*---------------------------------------------------------------------------*/
483 for(i = 0; i < RESOLV_ENTRIES; ++i) {
484 names[i].state = STATE_DONE;
488 /*---------------------------------------------------------------------------*/