ReactOS  0.4.15-dev-1397-g19779b3
dns.c
Go to the documentation of this file.
1 
62 /*-----------------------------------------------------------------------------
63  * RFC 1035 - Domain names - implementation and specification
64  * RFC 2181 - Clarifications to the DNS Specification
65  *----------------------------------------------------------------------------*/
66 
71 /*-----------------------------------------------------------------------------
72  * Includes
73  *----------------------------------------------------------------------------*/
74 
75 #include "lwip/opt.h"
76 
77 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
78 
79 #include "lwip/udp.h"
80 #include "lwip/mem.h"
81 #include "lwip/memp.h"
82 #include "lwip/dns.h"
83 
84 #include <string.h>
85 
87 #ifndef DNS_SERVER_ADDRESS
88 #define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */
89 #endif
90 
92 #ifndef DNS_SERVER_PORT
93 #define DNS_SERVER_PORT 53
94 #endif
95 
97 #ifndef DNS_MAX_RETRIES
98 #define DNS_MAX_RETRIES 4
99 #endif
100 
102 #ifndef DNS_MAX_TTL
103 #define DNS_MAX_TTL 604800
104 #endif
105 
106 /* DNS protocol flags */
107 #define DNS_FLAG1_RESPONSE 0x80
108 #define DNS_FLAG1_OPCODE_STATUS 0x10
109 #define DNS_FLAG1_OPCODE_INVERSE 0x08
110 #define DNS_FLAG1_OPCODE_STANDARD 0x00
111 #define DNS_FLAG1_AUTHORATIVE 0x04
112 #define DNS_FLAG1_TRUNC 0x02
113 #define DNS_FLAG1_RD 0x01
114 #define DNS_FLAG2_RA 0x80
115 #define DNS_FLAG2_ERR_MASK 0x0f
116 #define DNS_FLAG2_ERR_NONE 0x00
117 #define DNS_FLAG2_ERR_NAME 0x03
118 
119 /* DNS protocol states */
120 #define DNS_STATE_UNUSED 0
121 #define DNS_STATE_NEW 1
122 #define DNS_STATE_ASKING 2
123 #define DNS_STATE_DONE 3
124 
125 #ifdef PACK_STRUCT_USE_INCLUDES
126 # include "arch/bpstruct.h"
127 #endif
130 struct dns_hdr {
132  PACK_STRUCT_FIELD(u8_t flags1);
133  PACK_STRUCT_FIELD(u8_t flags2);
134  PACK_STRUCT_FIELD(u16_t numquestions);
135  PACK_STRUCT_FIELD(u16_t numanswers);
136  PACK_STRUCT_FIELD(u16_t numauthrr);
137  PACK_STRUCT_FIELD(u16_t numextrarr);
140 #ifdef PACK_STRUCT_USE_INCLUDES
141 # include "arch/epstruct.h"
142 #endif
143 #define SIZEOF_DNS_HDR 12
144 
147 struct dns_query {
148  /* DNS query record starts with either a domain name or a pointer
149  to a name already present somewhere in the packet. */
150  u16_t type;
151  u16_t cls;
152 };
153 #define SIZEOF_DNS_QUERY 4
154 
157 struct dns_answer {
158  /* DNS answer record starts with either a domain name or a pointer
159  to a name already present somewhere in the packet. */
160  u16_t type;
161  u16_t cls;
162  u32_t ttl;
163  u16_t len;
164 };
165 #define SIZEOF_DNS_ANSWER 10
166 
168 struct dns_table_entry {
169  u8_t state;
170  u8_t numdns;
171  u8_t tmr;
172  u8_t retries;
173  u8_t seqno;
174  u8_t err;
175  u32_t ttl;
177  ip_addr_t ipaddr;
178  /* pointer to callback on DNS query done */
179  dns_found_callback found;
180  void *arg;
181 };
182 
183 #if DNS_LOCAL_HOSTLIST
184 
185 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
186 
188 static struct local_hostlist_entry *local_hostlist_dynamic;
189 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
190 
193 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
194 #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
195 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
196 
198 #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
199 #define DNS_LOCAL_HOSTLIST_STORAGE_POST
200 #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
201 DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
202  DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
203 
204 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
205 
206 static void dns_init_local();
207 #endif /* DNS_LOCAL_HOSTLIST */
208 
209 
210 /* forward declarations */
211 static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
212 static void dns_check_entries(void);
213 
214 /*-----------------------------------------------------------------------------
215  * Globales
216  *----------------------------------------------------------------------------*/
217 
218 /* DNS variables */
219 static struct udp_pcb *dns_pcb;
220 static u8_t dns_seqno;
221 static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
222 static ip_addr_t dns_servers[DNS_MAX_SERVERS];
224 static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)];
225 static u8_t* dns_payload;
226 
231 void
232 dns_init()
233 {
234  ip_addr_t dnsserver;
235 
236  dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer);
237 
238  /* initialize default DNS server address */
239  DNS_SERVER_ADDRESS(&dnsserver);
240 
241  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
242 
243  /* if dns client not yet initialized... */
244  if (dns_pcb == NULL) {
245  dns_pcb = udp_new();
246 
247  if (dns_pcb != NULL) {
248  /* initialize DNS table not needed (initialized to zero since it is a
249  * global variable) */
250  LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
251  DNS_STATE_UNUSED == 0);
252 
253  /* initialize DNS client */
254  udp_bind(dns_pcb, IP_ADDR_ANY, 0);
255  udp_recv(dns_pcb, dns_recv, NULL);
256 
257  /* initialize default DNS primary server */
258  dns_setserver(0, &dnsserver);
259  }
260  }
261 #if DNS_LOCAL_HOSTLIST
262  dns_init_local();
263 #endif
264 }
265 
272 void
273 dns_setserver(u8_t numdns, ip_addr_t *dnsserver)
274 {
275  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
276  (dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
277  dns_servers[numdns] = (*dnsserver);
278  }
279 }
280 
288 ip_addr_t
289 dns_getserver(u8_t numdns)
290 {
291  if (numdns < DNS_MAX_SERVERS) {
292  return dns_servers[numdns];
293  } else {
294  return *IP_ADDR_ANY;
295  }
296 }
297 
302 void
303 dns_tmr(void)
304 {
305  if (dns_pcb != NULL) {
306  LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
307  dns_check_entries();
308  }
309 }
310 
311 #if DNS_LOCAL_HOSTLIST
312 static void
313 dns_init_local()
314 {
315 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
316  int i;
317  struct local_hostlist_entry *entry;
318  /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
319  struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
320  size_t namelen;
321  for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
322  struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
323  LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL);
324  namelen = strlen(init_entry->name);
325  LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
326  entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
327  LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
328  if (entry != NULL) {
329  entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
330  MEMCPY((char*)entry->name, init_entry->name, namelen);
331  ((char*)entry->name)[namelen] = 0;
332  entry->addr = init_entry->addr;
333  entry->next = local_hostlist_dynamic;
334  local_hostlist_dynamic = entry;
335  }
336  }
337 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
338 }
339 
347 static u32_t
348 dns_lookup_local(const char *hostname)
349 {
350 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
351  struct local_hostlist_entry *entry = local_hostlist_dynamic;
352  while(entry != NULL) {
353  if(strcmp(entry->name, hostname) == 0) {
354  return ip4_addr_get_u32(&entry->addr);
355  }
356  entry = entry->next;
357  }
358 #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
359  int i;
360  for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
361  if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
362  return ip4_addr_get_u32(&local_hostlist_static[i].addr);
363  }
364  }
365 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
366  return IPADDR_NONE;
367 }
368 
369 #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
370 
378 int
379 dns_local_removehost(const char *hostname, const ip_addr_t *addr)
380 {
381  int removed = 0;
382  struct local_hostlist_entry *entry = local_hostlist_dynamic;
383  struct local_hostlist_entry *last_entry = NULL;
384  while (entry != NULL) {
385  if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
386  ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) {
387  struct local_hostlist_entry *free_entry;
388  if (last_entry != NULL) {
389  last_entry->next = entry->next;
390  } else {
391  local_hostlist_dynamic = entry->next;
392  }
393  free_entry = entry;
394  entry = entry->next;
395  memp_free(MEMP_LOCALHOSTLIST, free_entry);
396  removed++;
397  } else {
398  last_entry = entry;
399  entry = entry->next;
400  }
401  }
402  return removed;
403 }
404 
413 err_t
414 dns_local_addhost(const char *hostname, const ip_addr_t *addr)
415 {
416  struct local_hostlist_entry *entry;
417  size_t namelen;
418  LWIP_ASSERT("invalid host name (NULL)", hostname != NULL);
420  LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN);
421  entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST);
422  if (entry == NULL) {
423  return ERR_MEM;
424  }
425  entry->name = (char*)entry + sizeof(struct local_hostlist_entry);
426  MEMCPY((char*)entry->name, hostname, namelen);
427  ((char*)entry->name)[namelen] = 0;
428  ip_addr_copy(entry->addr, *addr);
429  entry->next = local_hostlist_dynamic;
430  local_hostlist_dynamic = entry;
431  return ERR_OK;
432 }
433 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
434 #endif /* DNS_LOCAL_HOSTLIST */
435 
449 static u32_t
450 dns_lookup(const char *name)
451 {
452  u8_t i;
453 #if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
454  u32_t addr;
455 #endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
456 #if DNS_LOCAL_HOSTLIST
457  if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
458  return addr;
459  }
460 #endif /* DNS_LOCAL_HOSTLIST */
461 #ifdef DNS_LOOKUP_LOCAL_EXTERN
462  if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
463  return addr;
464  }
465 #endif /* DNS_LOOKUP_LOCAL_EXTERN */
466 
467  /* Walk through name list, return entry if found. If not, return NULL. */
468  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
469  if ((dns_table[i].state == DNS_STATE_DONE) &&
470  (strcmp(name, dns_table[i].name) == 0)) {
471  LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
472  ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
473  LWIP_DEBUGF(DNS_DEBUG, ("\n"));
474  return ip4_addr_get_u32(&dns_table[i].ipaddr);
475  }
476  }
477 
478  return IPADDR_NONE;
479 }
480 
481 #if DNS_DOES_NAME_CHECK
482 
492 static u8_t
493 dns_compare_name(unsigned char *query, unsigned char *response)
494 {
495  unsigned char n;
496 
497  do {
498  n = *response++;
500  if ((n & 0xc0) == 0xc0) {
501  /* Compressed name */
502  break;
503  } else {
504  /* Not compressed name */
505  while (n > 0) {
506  if ((*query) != (*response)) {
507  return 1;
508  }
509  ++response;
510  ++query;
511  --n;
512  };
513  ++query;
514  }
515  } while (*response != 0);
516 
517  return 0;
518 }
519 #endif /* DNS_DOES_NAME_CHECK */
520 
527 static unsigned char *
528 dns_parse_name(unsigned char *query)
529 {
530  unsigned char n;
531 
532  do {
533  n = *query++;
535  if ((n & 0xc0) == 0xc0) {
536  /* Compressed name */
537  break;
538  } else {
539  /* Not compressed name */
540  while (n > 0) {
541  ++query;
542  --n;
543  };
544  }
545  } while (*query != 0);
546 
547  return query + 1;
548 }
549 
559 static err_t
560 dns_send(u8_t numdns, const char* name, u8_t id)
561 {
562  err_t err;
563  struct dns_hdr *hdr;
564  struct dns_query qry;
565  struct pbuf *p;
566  char *query, *nptr;
567  const char *pHostname;
568  u8_t n;
569 
570  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
571  (u16_t)(numdns), name));
572  LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
573  LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns]));
574 
575  /* if here, we have either a new query or a retry on a previous query to process */
576  p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
577  SIZEOF_DNS_QUERY, PBUF_RAM);
578  if (p != NULL) {
579  LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
580  /* fill dns header */
581  hdr = (struct dns_hdr*)p->payload;
582  memset(hdr, 0, SIZEOF_DNS_HDR);
583  hdr->id = htons(id);
584  hdr->flags1 = DNS_FLAG1_RD;
585  hdr->numquestions = PP_HTONS(1);
586  query = (char*)hdr + SIZEOF_DNS_HDR;
587  pHostname = name;
588  --pHostname;
589 
590  /* convert hostname into suitable query format. */
591  do {
592  ++pHostname;
593  nptr = query;
594  ++query;
595  for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
596  *query = *pHostname;
597  ++query;
598  ++n;
599  }
600  *nptr = n;
601  } while(*pHostname != 0);
602  *query++='\0';
603 
604  /* fill dns query */
605  qry.type = PP_HTONS(DNS_RRTYPE_A);
606  qry.cls = PP_HTONS(DNS_RRCLASS_IN);
607  SMEMCPY(query, &qry, SIZEOF_DNS_QUERY);
608 
609  /* resize pbuf to the exact dns query */
610  pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))));
611 
612  /* connect to the server for faster receiving */
613  udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
614  /* send dns packet */
615  err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
616 
617  /* free pbuf */
618  pbuf_free(p);
619  } else {
620  err = ERR_MEM;
621  }
622 
623  return err;
624 }
625 
635 static void
636 dns_check_entry(u8_t i)
637 {
638  err_t err;
639  struct dns_table_entry *pEntry = &dns_table[i];
640 
641  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
642 
643  switch(pEntry->state) {
644 
645  case DNS_STATE_NEW: {
646  /* initialize new entry */
647  pEntry->state = DNS_STATE_ASKING;
648  pEntry->numdns = 0;
649  pEntry->tmr = 1;
650  pEntry->retries = 0;
651 
652  /* send DNS packet for this entry */
653  err = dns_send(pEntry->numdns, pEntry->name, i);
654  if (err != ERR_OK) {
656  ("dns_send returned error: %s\n", lwip_strerr(err)));
657  }
658  break;
659  }
660 
661  case DNS_STATE_ASKING: {
662  if (--pEntry->tmr == 0) {
663  if (++pEntry->retries == DNS_MAX_RETRIES) {
664  if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) {
665  /* change of server */
666  pEntry->numdns++;
667  pEntry->tmr = 1;
668  pEntry->retries = 0;
669  break;
670  } else {
671  LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
672  /* call specified callback function if provided */
673  if (pEntry->found)
674  (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
675  /* flush this entry */
676  pEntry->state = DNS_STATE_UNUSED;
677  pEntry->found = NULL;
678  break;
679  }
680  }
681 
682  /* wait longer for the next retry */
683  pEntry->tmr = pEntry->retries;
684 
685  /* send DNS packet for this entry */
686  err = dns_send(pEntry->numdns, pEntry->name, i);
687  if (err != ERR_OK) {
689  ("dns_send returned error: %s\n", lwip_strerr(err)));
690  }
691  }
692  break;
693  }
694 
695  case DNS_STATE_DONE: {
696  /* if the time to live is nul */
697  if (--pEntry->ttl == 0) {
698  LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
699  /* flush this entry */
700  pEntry->state = DNS_STATE_UNUSED;
701  pEntry->found = NULL;
702  }
703  break;
704  }
705  case DNS_STATE_UNUSED:
706  /* nothing to do */
707  break;
708  default:
709  LWIP_ASSERT("unknown dns_table entry state:", 0);
710  break;
711  }
712 }
713 
717 static void
718 dns_check_entries(void)
719 {
720  u8_t i;
721 
722  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
723  dns_check_entry(i);
724  }
725 }
726 
732 static void
733 dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
734 {
735  u16_t i;
736  char *pHostname;
737  struct dns_hdr *hdr;
738  struct dns_answer ans;
739  struct dns_table_entry *pEntry;
740  u16_t nquestions, nanswers;
741 
743  LWIP_UNUSED_ARG(pcb);
746 
747  /* is the dns message too big ? */
748  if (p->tot_len > DNS_MSG_SIZE) {
749  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
750  /* free pbuf and return */
751  goto memerr;
752  }
753 
754  /* is the dns message big enough ? */
755  if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
756  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
757  /* free pbuf and return */
758  goto memerr;
759  }
760 
761  /* copy dns payload inside static buffer for processing */
762  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
763  /* The ID in the DNS header should be our entry into the name table. */
764  hdr = (struct dns_hdr*)dns_payload;
765  i = htons(hdr->id);
766  if (i < DNS_TABLE_SIZE) {
767  pEntry = &dns_table[i];
768  if(pEntry->state == DNS_STATE_ASKING) {
769  /* This entry is now completed. */
770  pEntry->state = DNS_STATE_DONE;
771  pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
772 
773  /* We only care about the question(s) and the answers. The authrr
774  and the extrarr are simply discarded. */
775  nquestions = htons(hdr->numquestions);
776  nanswers = htons(hdr->numanswers);
777 
778  /* Check for error. If so, call callback to inform. */
779  if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
780  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
781  /* call callback to indicate error, clean up memory and return */
782  goto responseerr;
783  }
784 
785 #if DNS_DOES_NAME_CHECK
786  /* Check if the name in the "question" part match with the name in the entry. */
787  if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
788  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
789  /* call callback to indicate error, clean up memory and return */
790  goto responseerr;
791  }
792 #endif /* DNS_DOES_NAME_CHECK */
793 
794  /* Skip the name in the "question" part */
795  pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
796 
797  while (nanswers > 0) {
798  /* skip answer resource record's host name */
799  pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
800 
801  /* Check for IP address type and Internet class. Others are discarded. */
802  SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
803  if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) &&
804  (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) {
805  /* read the answer resource record's TTL, and maximize it if needed */
806  pEntry->ttl = ntohl(ans.ttl);
807  if (pEntry->ttl > DNS_MAX_TTL) {
808  pEntry->ttl = DNS_MAX_TTL;
809  }
810  /* read the IP address after answer resource record's header */
811  SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t));
812  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
813  ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
814  LWIP_DEBUGF(DNS_DEBUG, ("\n"));
815  /* call specified callback function if provided */
816  if (pEntry->found) {
817  (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
818  }
819  /* deallocate memory and return */
820  goto memerr;
821  } else {
822  pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
823  }
824  --nanswers;
825  }
826  LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
827  /* call callback to indicate error, clean up memory and return */
828  goto responseerr;
829  }
830  }
831  }
832 
833  /* deallocate memory and return */
834  goto memerr;
835 
836 responseerr:
837  /* ERROR: call specified callback function with NULL as name to indicate an error */
838  if (pEntry->found) {
839  (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
840  }
841  /* flush this entry */
842  pEntry->state = DNS_STATE_UNUSED;
843  pEntry->found = NULL;
844 
845 memerr:
846  /* free pbuf */
847  pbuf_free(p);
848  return;
849 }
850 
859 static err_t
860 dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
861 {
862  u8_t i;
863  u8_t lseq, lseqi;
864  struct dns_table_entry *pEntry = NULL;
865  size_t namelen;
866 
867  /* search an unused entry, or the oldest one */
868  lseq = lseqi = 0;
869  for (i = 0; i < DNS_TABLE_SIZE; ++i) {
870  pEntry = &dns_table[i];
871  /* is it an unused entry ? */
872  if (pEntry->state == DNS_STATE_UNUSED)
873  break;
874 
875  /* check if this is the oldest completed entry */
876  if (pEntry->state == DNS_STATE_DONE) {
877  if ((dns_seqno - pEntry->seqno) > lseq) {
878  lseq = dns_seqno - pEntry->seqno;
879  lseqi = i;
880  }
881  }
882  }
883 
884  /* if we don't have found an unused entry, use the oldest completed one */
885  if (i == DNS_TABLE_SIZE) {
886  if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
887  /* no entry can't be used now, table is full */
888  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
889  return ERR_MEM;
890  } else {
891  /* use the oldest completed one */
892  i = lseqi;
893  pEntry = &dns_table[i];
894  }
895  }
896 
897  /* use this entry */
898  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
899 
900  /* fill the entry */
901  pEntry->state = DNS_STATE_NEW;
902  pEntry->seqno = dns_seqno++;
903  pEntry->found = found;
904  pEntry->arg = callback_arg;
906  MEMCPY(pEntry->name, name, namelen);
907  pEntry->name[namelen] = 0;
908 
909  /* force to send query without waiting timer */
910  dns_check_entry(i);
911 
912  /* dns query is enqueued */
913  return ERR_INPROGRESS;
914 }
915 
935 err_t
936 dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found,
937  void *callback_arg)
938 {
939  u32_t ipaddr;
940  /* not initialized or no valid server yet, or invalid addr pointer
941  * or invalid hostname or invalid hostname length */
942  if ((dns_pcb == NULL) || (addr == NULL) ||
943  (!hostname) || (!hostname[0]) ||
945  return ERR_ARG;
946  }
947 
948 #if LWIP_HAVE_LOOPIF
949  if (strcmp(hostname, "localhost")==0) {
951  return ERR_OK;
952  }
953 #endif /* LWIP_HAVE_LOOPIF */
954 
955  /* host name already in octet notation? set ip addr and return ERR_OK */
956  ipaddr = ipaddr_addr(hostname);
957  if (ipaddr == IPADDR_NONE) {
958  /* already have this address cached? */
959  ipaddr = dns_lookup(hostname);
960  }
961  if (ipaddr != IPADDR_NONE) {
962  ip4_addr_set_u32(addr, ipaddr);
963  return ERR_OK;
964  }
965 
966  /* queue query with specified callback */
967  return dns_enqueue(hostname, found, callback_arg);
968 }
969 
970 #endif /* LWIP_DNS */
#define DNS_TABLE_SIZE
Definition: opt.h:823
#define DNS_MAX_NAME_LENGTH
Definition: opt.h:828
#define DNS_MSG_SIZE
Definition: opt.h:843
#define ERR_ARG
Definition: err.h:70
#define ip_addr_copy(dest, src)
Definition: ip_addr.h:162
char hdr[14]
Definition: iptest.cpp:33
#define SMEMCPY(dst, src, len)
Definition: opt.h:92
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
GLdouble n
Definition: glext.h:7729
void pbuf_realloc(struct pbuf *p, u16_t new_len)
Definition: pbuf.c:430
typedefPACK_STRUCT_END struct ip_addr ip_addr_t
Definition: ip_addr.h:64
void * arg
Definition: msvc.h:10
GLint namelen
Definition: glext.h:7232
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:66
#define PACK_STRUCT_FIELD(x)
Definition: arch.h:68
#define ip_addr_set_loopback(ipaddr)
Definition: ip_addr.h:172
void memp_free(memp_t type, void *mem)
Definition: memp.c:435
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:207
char * hostname
Definition: ftp.c:88
Definition: pbuf.h:58
#define DNS_DEBUG
Definition: opt.h:2130
#define LWIP_MIN(x, y)
Definition: def.h:44
#define PACK_STRUCT_STRUCT
Definition: cc.h:59
#define DNS_MAX_SERVERS
Definition: opt.h:833
#define lwip_strerr(x)
Definition: err.h:78
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:618
s8_t err_t
Definition: err.h:47
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:95
#define PP_HTONS(x)
Definition: def.h:88
#define U16_F
Definition: cc.h:36
#define ERR_OK
Definition: err.h:52
Definition: pbuf.h:79
static void free_entry(Entry *entry)
Definition: winefile.c:304
unsigned long u32_t
Definition: cc.h:25
#define MEMCPY(DST, SRC, BYTES)
Definition: macros.h:231
#define IP_ADDR_ANY
Definition: ip_addr.h:92
#define ip_addr_debug_print(debug, ipaddr)
Definition: ip_addr.h:212
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:46
GLenum const GLvoid * addr
Definition: glext.h:9621
u32_t ipaddr_addr(const char *cp)
Definition: ip_addr.c:130
#define PACK_STRUCT_BEGIN
Definition: arch.h:60
static int state
Definition: maze.c:121
uint32_t entry
Definition: isohybrid.c:63
GLenum GLsizei len
Definition: glext.h:6722
GLdouble s
Definition: gl.h:2039
#define err(...)
#define LWIP_MEM_ALIGN_BUFFER(size)
Definition: mem.h:109
u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition: pbuf.c:918
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define ip4_addr_set_u32(dest_ipaddr, src_u32)
Definition: ip_addr.h:179
#define ip_addr_isany(addr1)
Definition: ip_addr.h:200
#define ip_addr_cmp(addr1, addr2)
Definition: ip_addr.h:198
#define ERR_MEM
Definition: fontsub.h:52
unsigned char u8_t
Definition: cc.h:23
#define NULL
Definition: types.h:112
#define PACK_STRUCT_END
Definition: arch.h:64
#define LWIP_MEM_ALIGN(addr)
Definition: mem.h:116
#define ERR_INPROGRESS
Definition: err.h:57
Definition: name.c:38
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
unsigned short u16_t
Definition: cc.h:24
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
void * memp_malloc(memp_t type)
Definition: memp.c:390
GLfloat GLfloat p
Definition: glext.h:8902
#define htons(x)
Definition: module.h:213
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
USHORT port
Definition: uri.c:228
#define memset(x, y, z)
Definition: compat.h:39
#define IPADDR_NONE
Definition: ip_addr.h:96
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:73
GLenum query
Definition: glext.h:7781
#define ip4_addr_get_u32(src_ipaddr)
Definition: ip_addr.h:181
#define ntohl(x)
Definition: module.h:203
GLuint const GLchar * name
Definition: glext.h:6031