ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dns.c
Go to the documentation of this file.
00001 
00062 /*-----------------------------------------------------------------------------
00063  * RFC 1035 - Domain names - implementation and specification
00064  * RFC 2181 - Clarifications to the DNS Specification
00065  *----------------------------------------------------------------------------*/
00066 
00071 /*-----------------------------------------------------------------------------
00072  * Includes
00073  *----------------------------------------------------------------------------*/
00074 
00075 #include "lwip/opt.h"
00076 
00077 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
00078 
00079 #include "lwip/udp.h"
00080 #include "lwip/mem.h"
00081 #include "lwip/memp.h"
00082 #include "lwip/dns.h"
00083 
00084 #include <string.h>
00085 
00087 #ifndef DNS_SERVER_ADDRESS
00088 #define DNS_SERVER_ADDRESS(ipaddr)        (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
00089 #endif
00090 
00092 #ifndef DNS_SERVER_PORT
00093 #define DNS_SERVER_PORT           53
00094 #endif
00095 
00097 #ifndef DNS_MAX_RETRIES
00098 #define DNS_MAX_RETRIES           4
00099 #endif
00100 
00102 #ifndef DNS_MAX_TTL
00103 #define DNS_MAX_TTL               604800
00104 #endif
00105 
00106 /* DNS protocol flags */
00107 #define DNS_FLAG1_RESPONSE        0x80
00108 #define DNS_FLAG1_OPCODE_STATUS   0x10
00109 #define DNS_FLAG1_OPCODE_INVERSE  0x08
00110 #define DNS_FLAG1_OPCODE_STANDARD 0x00
00111 #define DNS_FLAG1_AUTHORATIVE     0x04
00112 #define DNS_FLAG1_TRUNC           0x02
00113 #define DNS_FLAG1_RD              0x01
00114 #define DNS_FLAG2_RA              0x80
00115 #define DNS_FLAG2_ERR_MASK        0x0f
00116 #define DNS_FLAG2_ERR_NONE        0x00
00117 #define DNS_FLAG2_ERR_NAME        0x03
00118 
00119 /* DNS protocol states */
00120 #define DNS_STATE_UNUSED          0
00121 #define DNS_STATE_NEW             1
00122 #define DNS_STATE_ASKING          2
00123 #define DNS_STATE_DONE            3
00124 
00125 #ifdef PACK_STRUCT_USE_INCLUDES
00126 #  include "arch/bpstruct.h"
00127 #endif
00128 PACK_STRUCT_BEGIN
00130 struct dns_hdr {
00131   PACK_STRUCT_FIELD(u16_t id);
00132   PACK_STRUCT_FIELD(u8_t flags1);
00133   PACK_STRUCT_FIELD(u8_t flags2);
00134   PACK_STRUCT_FIELD(u16_t numquestions);
00135   PACK_STRUCT_FIELD(u16_t numanswers);
00136   PACK_STRUCT_FIELD(u16_t numauthrr);
00137   PACK_STRUCT_FIELD(u16_t numextrarr);
00138 } PACK_STRUCT_STRUCT;
00139 PACK_STRUCT_END
00140 #ifdef PACK_STRUCT_USE_INCLUDES
00141 #  include "arch/epstruct.h"
00142 #endif
00143 #define SIZEOF_DNS_HDR 12
00144 
00147 struct dns_query {
00148   /* DNS query record starts with either a domain name or a pointer
00149      to a name already present somewhere in the packet. */
00150   u16_t type;
00151   u16_t cls;
00152 };
00153 #define SIZEOF_DNS_QUERY 4
00154 
00157 struct dns_answer {
00158   /* DNS answer record starts with either a domain name or a pointer
00159      to a name already present somewhere in the packet. */
00160   u16_t type;
00161   u16_t cls;
00162   u32_t ttl;
00163   u16_t len;
00164 };
00165 #define SIZEOF_DNS_ANSWER 10
00166 
00168 struct dns_table_entry {
00169   u8_t  state;
00170   u8_t  numdns;
00171   u8_t  tmr;
00172   u8_t  retries;
00173   u8_t  seqno;
00174   u8_t  err;
00175   u32_t ttl;
00176   char name[DNS_MAX_NAME_LENGTH];
00177   ip_addr_t ipaddr;
00178   /* pointer to callback on DNS query done */
00179   dns_found_callback found;
00180   void *arg;
00181 };
00182 
00183 #if DNS_LOCAL_HOSTLIST
00184 
00185 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
00186 
00188 static struct local_hostlist_entry *local_hostlist_dynamic;
00189 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
00190 
00193 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
00194 #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
00195 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
00196 
00198 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
00199 #define DNS_LOCAL_HOSTLIST_STORAGE_POST
00200 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
00201 DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
00202   DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
00203 
00204 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
00205 
00206 static void dns_init_local();
00207 #endif /* DNS_LOCAL_HOSTLIST */
00208 
00209 
00210 /* forward declarations */
00211 static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
00212 static void dns_check_entries(void);
00213 
00214 /*-----------------------------------------------------------------------------
00215  * Globales
00216  *----------------------------------------------------------------------------*/
00217 
00218 /* DNS variables */
00219 static struct udp_pcb        *dns_pcb;
00220 static u8_t                   dns_seqno;
00221 static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
00222 static ip_addr_t              dns_servers[DNS_MAX_SERVERS];
00224 static u8_t                   dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
00225 static u8_t*                  dns_payload;
00226 
00231 void
00232 dns_init()
00233 {
00234   ip_addr_t dnsserver;
00235 
00236   dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
00237   
00238   /* initialize default DNS server address */
00239   DNS_SERVER_ADDRESS(&dnsserver);
00240 
00241   LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
00242 
00243   /* if dns client not yet initialized... */
00244   if (dns_pcb == NULL) {
00245     dns_pcb = udp_new();
00246 
00247     if (dns_pcb != NULL) {
00248       /* initialize DNS table not needed (initialized to zero since it is a
00249        * global variable) */
00250       LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
00251         DNS_STATE_UNUSED == 0);
00252 
00253       /* initialize DNS client */
00254       udp_bind(dns_pcb, IP_ADDR_ANY, 0);
00255       udp_recv(dns_pcb, dns_recv, NULL);
00256 
00257       /* initialize default DNS primary server */
00258       dns_setserver(0, &dnsserver);
00259     }
00260   }
00261 #if DNS_LOCAL_HOSTLIST
00262   dns_init_local();
00263 #endif
00264 }
00265 
00272 void
00273 dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
00274 {
00275   if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
00276       (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
00277     dns_servers[numdns] = (*dnsserver);
00278   }
00279 }
00280 
00288 ip_addr_t
00289 dns_getserver(u8_t numdns)
00290 {
00291   if (numdns < DNS_MAX_SERVERS) {
00292     return dns_servers[numdns];
00293   } else {
00294     return *IP_ADDR_ANY;
00295   }
00296 }
00297 
00302 void
00303 dns_tmr(void)
00304 {
00305   if (dns_pcb != NULL) {
00306     LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
00307     dns_check_entries();
00308   }
00309 }
00310 
00311 #if DNS_LOCAL_HOSTLIST
00312 static void
00313 dns_init_local()
00314 {
00315 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
00316   int i;
00317   struct local_hostlist_entry *entry;
00318   /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
00319   struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
00320   size_t namelen;
00321   for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
00322     struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
00323     LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
00324     namelen = strlen(init_entry->name);
00325     LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
00326     entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
00327     LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
00328     if (entry != NULL) {
00329       entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
00330       MEMCPY((char*)entry->name, init_entry->name, namelen);
00331       ((char*)entry->name)[namelen] = 0;
00332       entry->addr = init_entry->addr;
00333       entry->next = local_hostlist_dynamic;
00334       local_hostlist_dynamic = entry;
00335     }
00336   }
00337 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
00338 }
00339 
00347 static u32_t
00348 dns_lookup_local(const char *hostname)
00349 {
00350 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
00351   struct local_hostlist_entry *entry = local_hostlist_dynamic;
00352   while(entry != NULL) {
00353     if(strcmp(entry->name, hostname) == 0) {
00354       return ip4_addr_get_u32(&entry->addr);
00355     }
00356     entry = entry->next;
00357   }
00358 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
00359   int i;
00360   for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
00361     if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
00362       return ip4_addr_get_u32(&local_hostlist_static[i].addr);
00363     }
00364   }
00365 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
00366   return IPADDR_NONE;
00367 }
00368 
00369 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
00370 
00378 int
00379 dns_local_removehost(const char *hostname, const ip_addr_t *addr)
00380 {
00381   int removed = 0;
00382   struct local_hostlist_entry *entry = local_hostlist_dynamic;
00383   struct local_hostlist_entry *last_entry = NULL;
00384   while (entry != NULL) {
00385     if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
00386         ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
00387       struct local_hostlist_entry *free_entry;
00388       if (last_entry != NULL) {
00389         last_entry->next = entry->next;
00390       } else {
00391         local_hostlist_dynamic = entry->next;
00392       }
00393       free_entry = entry;
00394       entry = entry->next;
00395       memp_free(MEMP_LOCALHOSTLIST, free_entry);
00396       removed++;
00397     } else {
00398       last_entry = entry;
00399       entry = entry->next;
00400     }
00401   }
00402   return removed;
00403 }
00404 
00413 err_t
00414 dns_local_addhost(const char *hostname, const ip_addr_t *addr)
00415 {
00416   struct local_hostlist_entry *entry;
00417   size_t namelen;
00418   LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
00419   namelen = strlen(hostname);
00420   LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
00421   entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
00422   if (entry == NULL) {
00423     return ERR_MEM;
00424   }
00425   entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
00426   MEMCPY((char*)entry->name, hostname, namelen);
00427   ((char*)entry->name)[namelen] = 0;
00428   ip_addr_copy(entry->addr, *addr);
00429   entry->next = local_hostlist_dynamic;
00430   local_hostlist_dynamic = entry;
00431   return ERR_OK;
00432 }
00433 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
00434 #endif /* DNS_LOCAL_HOSTLIST */
00435 
00449 static u32_t
00450 dns_lookup(const char *name)
00451 {
00452   u8_t i;
00453 #if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
00454   u32_t addr;
00455 #endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
00456 #if DNS_LOCAL_HOSTLIST
00457   if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
00458     return addr;
00459   }
00460 #endif /* DNS_LOCAL_HOSTLIST */
00461 #ifdef DNS_LOOKUP_LOCAL_EXTERN
00462   if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
00463     return addr;
00464   }
00465 #endif /* DNS_LOOKUP_LOCAL_EXTERN */
00466 
00467   /* Walk through name list, return entry if found. If not, return NULL. */
00468   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
00469     if ((dns_table[i].state == DNS_STATE_DONE) &&
00470         (strcmp(name, dns_table[i].name) == 0)) {
00471       LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
00472       ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
00473       LWIP_DEBUGF(DNS_DEBUG, ("\n"));
00474       return ip4_addr_get_u32(&dns_table[i].ipaddr);
00475     }
00476   }
00477 
00478   return IPADDR_NONE;
00479 }
00480 
00481 #if DNS_DOES_NAME_CHECK
00482 
00492 static u8_t
00493 dns_compare_name(unsigned char *query, unsigned char *response)
00494 {
00495   unsigned char n;
00496 
00497   do {
00498     n = *response++;
00500     if ((n & 0xc0) == 0xc0) {
00501       /* Compressed name */
00502       break;
00503     } else {
00504       /* Not compressed name */
00505       while (n > 0) {
00506         if ((*query) != (*response)) {
00507           return 1;
00508         }
00509         ++response;
00510         ++query;
00511         --n;
00512       };
00513       ++query;
00514     }
00515   } while (*response != 0);
00516 
00517   return 0;
00518 }
00519 #endif /* DNS_DOES_NAME_CHECK */
00520 
00527 static unsigned char *
00528 dns_parse_name(unsigned char *query)
00529 {
00530   unsigned char n;
00531 
00532   do {
00533     n = *query++;
00535     if ((n & 0xc0) == 0xc0) {
00536       /* Compressed name */
00537       break;
00538     } else {
00539       /* Not compressed name */
00540       while (n > 0) {
00541         ++query;
00542         --n;
00543       };
00544     }
00545   } while (*query != 0);
00546 
00547   return query + 1;
00548 }
00549 
00559 static err_t
00560 dns_send(u8_t numdns, const char* name, u8_t id)
00561 {
00562   err_t err;
00563   struct dns_hdr *hdr;
00564   struct dns_query qry;
00565   struct pbuf *p;
00566   char *query, *nptr;
00567   const char *pHostname;
00568   u8_t n;
00569 
00570   LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
00571               (u16_t)(numdns), name));
00572   LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
00573   LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
00574 
00575   /* if here, we have either a new query or a retry on a previous query to process */
00576   p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
00577                  SIZEOF_DNS_QUERY, PBUF_RAM);
00578   if (p != NULL) {
00579     LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
00580     /* fill dns header */
00581     hdr = (struct dns_hdr*)p->payload;
00582     memset(hdr, 0, SIZEOF_DNS_HDR);
00583     hdr->id = htons(id);
00584     hdr->flags1 = DNS_FLAG1_RD;
00585     hdr->numquestions = PP_HTONS(1);
00586     query = (char*)hdr + SIZEOF_DNS_HDR;
00587     pHostname = name;
00588     --pHostname;
00589 
00590     /* convert hostname into suitable query format. */
00591     do {
00592       ++pHostname;
00593       nptr = query;
00594       ++query;
00595       for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
00596         *query = *pHostname;
00597         ++query;
00598         ++n;
00599       }
00600       *nptr = n;
00601     } while(*pHostname != 0);
00602     *query++='\0';
00603 
00604     /* fill dns query */
00605     qry.type = PP_HTONS(DNS_RRTYPE_A);
00606     qry.cls = PP_HTONS(DNS_RRCLASS_IN);
00607     SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
00608 
00609     /* resize pbuf to the exact dns query */
00610     pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
00611 
00612     /* connect to the server for faster receiving */
00613     udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
00614     /* send dns packet */
00615     err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
00616 
00617     /* free pbuf */
00618     pbuf_free(p);
00619   } else {
00620     err = ERR_MEM;
00621   }
00622 
00623   return err;
00624 }
00625 
00635 static void
00636 dns_check_entry(u8_t i)
00637 {
00638   err_t err;
00639   struct dns_table_entry *pEntry = &dns_table[i];
00640 
00641   LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
00642 
00643   switch(pEntry->state) {
00644 
00645     case DNS_STATE_NEW: {
00646       /* initialize new entry */
00647       pEntry->state   = DNS_STATE_ASKING;
00648       pEntry->numdns  = 0;
00649       pEntry->tmr     = 1;
00650       pEntry->retries = 0;
00651       
00652       /* send DNS packet for this entry */
00653       err = dns_send(pEntry->numdns, pEntry->name, i);
00654       if (err != ERR_OK) {
00655         LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
00656                     ("dns_send returned error: %s\n", lwip_strerr(err)));
00657       }
00658       break;
00659     }
00660 
00661     case DNS_STATE_ASKING: {
00662       if (--pEntry->tmr == 0) {
00663         if (++pEntry->retries == DNS_MAX_RETRIES) {
00664           if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
00665             /* change of server */
00666             pEntry->numdns++;
00667             pEntry->tmr     = 1;
00668             pEntry->retries = 0;
00669             break;
00670           } else {
00671             LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
00672             /* call specified callback function if provided */
00673             if (pEntry->found)
00674               (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
00675             /* flush this entry */
00676             pEntry->state   = DNS_STATE_UNUSED;
00677             pEntry->found   = NULL;
00678             break;
00679           }
00680         }
00681 
00682         /* wait longer for the next retry */
00683         pEntry->tmr = pEntry->retries;
00684 
00685         /* send DNS packet for this entry */
00686         err = dns_send(pEntry->numdns, pEntry->name, i);
00687         if (err != ERR_OK) {
00688           LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING,
00689                       ("dns_send returned error: %s\n", lwip_strerr(err)));
00690         }
00691       }
00692       break;
00693     }
00694 
00695     case DNS_STATE_DONE: {
00696       /* if the time to live is nul */
00697       if (--pEntry->ttl == 0) {
00698         LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
00699         /* flush this entry */
00700         pEntry->state = DNS_STATE_UNUSED;
00701         pEntry->found = NULL;
00702       }
00703       break;
00704     }
00705     case DNS_STATE_UNUSED:
00706       /* nothing to do */
00707       break;
00708     default:
00709       LWIP_ASSERT("unknown dns_table entry state:", 0);
00710       break;
00711   }
00712 }
00713 
00717 static void
00718 dns_check_entries(void)
00719 {
00720   u8_t i;
00721 
00722   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
00723     dns_check_entry(i);
00724   }
00725 }
00726 
00732 static void
00733 dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
00734 {
00735   u16_t i;
00736   char *pHostname;
00737   struct dns_hdr *hdr;
00738   struct dns_answer ans;
00739   struct dns_table_entry *pEntry;
00740   u16_t nquestions, nanswers;
00741 
00742   LWIP_UNUSED_ARG(arg);
00743   LWIP_UNUSED_ARG(pcb);
00744   LWIP_UNUSED_ARG(addr);
00745   LWIP_UNUSED_ARG(port);
00746 
00747   /* is the dns message too big ? */
00748   if (p->tot_len > DNS_MSG_SIZE) {
00749     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
00750     /* free pbuf and return */
00751     goto memerr;
00752   }
00753 
00754   /* is the dns message big enough ? */
00755   if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
00756     LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
00757     /* free pbuf and return */
00758     goto memerr;
00759   }
00760 
00761   /* copy dns payload inside static buffer for processing */ 
00762   if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
00763     /* The ID in the DNS header should be our entry into the name table. */
00764     hdr = (struct dns_hdr*)dns_payload;
00765     i = htons(hdr->id);
00766     if (i < DNS_TABLE_SIZE) {
00767       pEntry = &dns_table[i];
00768       if(pEntry->state == DNS_STATE_ASKING) {
00769         /* This entry is now completed. */
00770         pEntry->state = DNS_STATE_DONE;
00771         pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;
00772 
00773         /* We only care about the question(s) and the answers. The authrr
00774            and the extrarr are simply discarded. */
00775         nquestions = htons(hdr->numquestions);
00776         nanswers   = htons(hdr->numanswers);
00777 
00778         /* Check for error. If so, call callback to inform. */
00779         if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
00780           LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
00781           /* call callback to indicate error, clean up memory and return */
00782           goto responseerr;
00783         }
00784 
00785 #if DNS_DOES_NAME_CHECK
00786         /* Check if the name in the "question" part match with the name in the entry. */
00787         if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
00788           LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
00789           /* call callback to indicate error, clean up memory and return */
00790           goto responseerr;
00791         }
00792 #endif /* DNS_DOES_NAME_CHECK */
00793 
00794         /* Skip the name in the "question" part */
00795         pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
00796 
00797         while (nanswers > 0) {
00798           /* skip answer resource record's host name */
00799           pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
00800 
00801           /* Check for IP address type and Internet class. Others are discarded. */
00802           SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
00803           if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
00804              (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
00805             /* read the answer resource record's TTL, and maximize it if needed */
00806             pEntry->ttl = ntohl(ans.ttl);
00807             if (pEntry->ttl > DNS_MAX_TTL) {
00808               pEntry->ttl = DNS_MAX_TTL;
00809             }
00810             /* read the IP address after answer resource record's header */
00811             SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
00812             LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
00813             ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
00814             LWIP_DEBUGF(DNS_DEBUG, ("\n"));
00815             /* call specified callback function if provided */
00816             if (pEntry->found) {
00817               (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
00818             }
00819             /* deallocate memory and return */
00820             goto memerr;
00821           } else {
00822             pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
00823           }
00824           --nanswers;
00825         }
00826         LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
00827         /* call callback to indicate error, clean up memory and return */
00828         goto responseerr;
00829       }
00830     }
00831   }
00832 
00833   /* deallocate memory and return */
00834   goto memerr;
00835 
00836 responseerr:
00837   /* ERROR: call specified callback function with NULL as name to indicate an error */
00838   if (pEntry->found) {
00839     (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
00840   }
00841   /* flush this entry */
00842   pEntry->state = DNS_STATE_UNUSED;
00843   pEntry->found = NULL;
00844 
00845 memerr:
00846   /* free pbuf */
00847   pbuf_free(p);
00848   return;
00849 }
00850 
00859 static err_t
00860 dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
00861 {
00862   u8_t i;
00863   u8_t lseq, lseqi;
00864   struct dns_table_entry *pEntry = NULL;
00865   size_t namelen;
00866 
00867   /* search an unused entry, or the oldest one */
00868   lseq = lseqi = 0;
00869   for (i = 0; i < DNS_TABLE_SIZE; ++i) {
00870     pEntry = &dns_table[i];
00871     /* is it an unused entry ? */
00872     if (pEntry->state == DNS_STATE_UNUSED)
00873       break;
00874 
00875     /* check if this is the oldest completed entry */
00876     if (pEntry->state == DNS_STATE_DONE) {
00877       if ((dns_seqno - pEntry->seqno) > lseq) {
00878         lseq = dns_seqno - pEntry->seqno;
00879         lseqi = i;
00880       }
00881     }
00882   }
00883 
00884   /* if we don't have found an unused entry, use the oldest completed one */
00885   if (i == DNS_TABLE_SIZE) {
00886     if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
00887       /* no entry can't be used now, table is full */
00888       LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
00889       return ERR_MEM;
00890     } else {
00891       /* use the oldest completed one */
00892       i = lseqi;
00893       pEntry = &dns_table[i];
00894     }
00895   }
00896 
00897   /* use this entry */
00898   LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
00899 
00900   /* fill the entry */
00901   pEntry->state = DNS_STATE_NEW;
00902   pEntry->seqno = dns_seqno++;
00903   pEntry->found = found;
00904   pEntry->arg   = callback_arg;
00905   namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1);
00906   MEMCPY(pEntry->name, name, namelen);
00907   pEntry->name[namelen] = 0;
00908 
00909   /* force to send query without waiting timer */
00910   dns_check_entry(i);
00911 
00912   /* dns query is enqueued */
00913   return ERR_INPROGRESS;
00914 }
00915 
00935 err_t
00936 dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
00937                   void *callback_arg)
00938 {
00939   u32_t ipaddr;
00940   /* not initialized or no valid server yet, or invalid addr pointer
00941    * or invalid hostname or invalid hostname length */
00942   if ((dns_pcb == NULL) || (addr == NULL) ||
00943       (!hostname) || (!hostname[0]) ||
00944       (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
00945     return ERR_ARG;
00946   }
00947 
00948 #if LWIP_HAVE_LOOPIF
00949   if (strcmp(hostname, "localhost")==0) {
00950     ip_addr_set_loopback(addr);
00951     return ERR_OK;
00952   }
00953 #endif /* LWIP_HAVE_LOOPIF */
00954 
00955   /* host name already in octet notation? set ip addr and return ERR_OK */
00956   ipaddr = ipaddr_addr(hostname);
00957   if (ipaddr == IPADDR_NONE) {
00958     /* already have this address cached? */
00959     ipaddr = dns_lookup(hostname);
00960   }
00961   if (ipaddr != IPADDR_NONE) {
00962     ip4_addr_set_u32(addr, ipaddr);
00963     return ERR_OK;
00964   }
00965 
00966   /* queue query with specified callback */
00967   return dns_enqueue(hostname, found, callback_arg);
00968 }
00969 
00970 #endif /* LWIP_DNS */

Generated on Sat May 26 2012 04:34:56 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.