dns.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  1. /**
  2. * @file
  3. * DNS - host name to IP address resolver.
  4. *
  5. */
  6. /**
  7. * This file implements a DNS host name to IP address resolver.
  8. * Port to lwIP from uIP
  9. * by Jim Pettinato April 2007
  10. * uIP version Copyright (c) 2002-2003, Adam Dunkels.
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or without
  14. * modification, are permitted provided that the following conditions
  15. * are met:
  16. * 1. Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. * 2. Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in the
  20. * documentation and/or other materials provided with the distribution.
  21. * 3. The name of the author may not be used to endorse or promote
  22. * products derived from this software without specific prior
  23. * written permission.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  26. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  27. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  29. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  31. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  32. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  33. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  34. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  35. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. *
  38. * DNS.C
  39. *
  40. * The lwIP DNS resolver functions are used to lookup a host name and
  41. * map it to a numerical IP address. It maintains a list of resolved
  42. * hostnames that can be queried with the dns_lookup() function.
  43. * New hostnames can be resolved using the dns_query() function.
  44. *
  45. * The lwIP version of the resolver also adds a non-blocking version of
  46. * gethostbyname() that will work with a raw API application. This function
  47. * checks for an IP address string first and converts it if it is valid.
  48. * gethostbyname() then does a dns_lookup() to see if the name is
  49. * already in the table. If so, the IP is returned. If not, a query is
  50. * issued and the function returns with a ERR_INPROGRESS status. The app
  51. * using the dns client must then go into a waiting state.
  52. *
  53. * Once a hostname has been resolved (or found to be non-existent),
  54. * the resolver code calls a specified callback function (which
  55. * must be implemented by the module that uses the resolver).
  56. */
  57. /*-----------------------------------------------------------------------------
  58. * RFC 1035 - Domain names - implementation and specification
  59. * RFC 2181 - Clarifications to the DNS Specification
  60. *----------------------------------------------------------------------------*/
  61. /** @todo: define good default values (rfc compliance) */
  62. /** @todo: improve answer parsing, more checkings... */
  63. /** @todo: check RFC1035 - 7.3. Processing responses */
  64. /*-----------------------------------------------------------------------------
  65. * Includes
  66. *----------------------------------------------------------------------------*/
  67. #include "lwip/opt.h"
  68. #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
  69. #include "lwip/udp.h"
  70. #include "lwip/mem.h"
  71. #include "lwip/dns.h"
  72. #include <string.h>
  73. /** DNS server IP address */
  74. #ifndef DNS_SERVER_ADDRESS
  75. #define DNS_SERVER_ADDRESS inet_addr("208.67.222.222") /* resolver1.opendns.com */
  76. #endif
  77. /** DNS server port address */
  78. #ifndef DNS_SERVER_PORT
  79. #define DNS_SERVER_PORT 53
  80. #endif
  81. /** DNS maximum number of retries when asking for a name, before "timeout". */
  82. #ifndef DNS_MAX_RETRIES
  83. #define DNS_MAX_RETRIES 4
  84. #endif
  85. /** DNS resource record max. TTL (one week as default) */
  86. #ifndef DNS_MAX_TTL
  87. #define DNS_MAX_TTL 604800
  88. #endif
  89. /* DNS protocol flags */
  90. #define DNS_FLAG1_RESPONSE 0x80
  91. #define DNS_FLAG1_OPCODE_STATUS 0x10
  92. #define DNS_FLAG1_OPCODE_INVERSE 0x08
  93. #define DNS_FLAG1_OPCODE_STANDARD 0x00
  94. #define DNS_FLAG1_AUTHORATIVE 0x04
  95. #define DNS_FLAG1_TRUNC 0x02
  96. #define DNS_FLAG1_RD 0x01
  97. #define DNS_FLAG2_RA 0x80
  98. #define DNS_FLAG2_ERR_MASK 0x0f
  99. #define DNS_FLAG2_ERR_NONE 0x00
  100. #define DNS_FLAG2_ERR_NAME 0x03
  101. /* DNS protocol states */
  102. #define DNS_STATE_UNUSED 0
  103. #define DNS_STATE_NEW 1
  104. #define DNS_STATE_ASKING 2
  105. #define DNS_STATE_DONE 3
  106. #ifdef PACK_STRUCT_USE_INCLUDES
  107. # include "arch/bpstruct.h"
  108. #endif
  109. PACK_STRUCT_BEGIN
  110. /** DNS message header */
  111. struct dns_hdr {
  112. PACK_STRUCT_FIELD(u16_t id);
  113. PACK_STRUCT_FIELD(u8_t flags1);
  114. PACK_STRUCT_FIELD(u8_t flags2);
  115. PACK_STRUCT_FIELD(u16_t numquestions);
  116. PACK_STRUCT_FIELD(u16_t numanswers);
  117. PACK_STRUCT_FIELD(u16_t numauthrr);
  118. PACK_STRUCT_FIELD(u16_t numextrarr);
  119. } PACK_STRUCT_STRUCT;
  120. PACK_STRUCT_END
  121. #ifdef PACK_STRUCT_USE_INCLUDES
  122. # include "arch/epstruct.h"
  123. #endif
  124. #define SIZEOF_DNS_HDR 12
  125. #ifdef PACK_STRUCT_USE_INCLUDES
  126. # include "arch/bpstruct.h"
  127. #endif
  128. PACK_STRUCT_BEGIN
  129. /** DNS query message structure */
  130. struct dns_query {
  131. /* DNS query record starts with either a domain name or a pointer
  132. to a name already present somewhere in the packet. */
  133. PACK_STRUCT_FIELD(u16_t type);
  134. PACK_STRUCT_FIELD(u16_t class);
  135. } PACK_STRUCT_STRUCT;
  136. PACK_STRUCT_END
  137. #ifdef PACK_STRUCT_USE_INCLUDES
  138. # include "arch/epstruct.h"
  139. #endif
  140. #define SIZEOF_DNS_QUERY 4
  141. #ifdef PACK_STRUCT_USE_INCLUDES
  142. # include "arch/bpstruct.h"
  143. #endif
  144. PACK_STRUCT_BEGIN
  145. /** DNS answer message structure */
  146. struct dns_answer {
  147. /* DNS answer record starts with either a domain name or a pointer
  148. to a name already present somewhere in the packet. */
  149. PACK_STRUCT_FIELD(u16_t type);
  150. PACK_STRUCT_FIELD(u16_t class);
  151. PACK_STRUCT_FIELD(u32_t ttl);
  152. PACK_STRUCT_FIELD(u16_t len);
  153. } PACK_STRUCT_STRUCT;
  154. PACK_STRUCT_END
  155. #ifdef PACK_STRUCT_USE_INCLUDES
  156. # include "arch/epstruct.h"
  157. #endif
  158. #define SIZEOF_DNS_ANSWER 10
  159. /** DNS table entry */
  160. struct dns_table_entry {
  161. u8_t state;
  162. u8_t numdns;
  163. u8_t tmr;
  164. u8_t retries;
  165. u8_t seqno;
  166. u8_t err;
  167. u32_t ttl;
  168. char name[DNS_MAX_NAME_LENGTH];
  169. struct ip_addr ipaddr;
  170. /* pointer to callback on DNS query done */
  171. dns_found_callback found;
  172. void *arg;
  173. };
  174. #if DNS_LOCAL_HOSTLIST
  175. /** struct used for local host-list */
  176. struct local_hostlist_entry {
  177. /** static hostname */
  178. const char *name;
  179. /** static host address in network byteorder */
  180. u32_t addr;
  181. struct local_hostlist_entry *next;
  182. };
  183. #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
  184. /** Local host-list. For hostnames in this list, no
  185. * external name resolution is performed */
  186. static struct local_hostlist_entry *local_hostlist_dynamic;
  187. #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
  188. /** Defining this allows the local_hostlist_static to be placed in a different
  189. * linker section (e.g. FLASH) */
  190. #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
  191. #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
  192. #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
  193. /** Defining this allows the local_hostlist_static to be placed in a different
  194. * linker section (e.g. FLASH) */
  195. #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
  196. #define DNS_LOCAL_HOSTLIST_STORAGE_POST
  197. #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
  198. DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
  199. DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
  200. #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
  201. static void dns_init_local();
  202. #endif /* DNS_LOCAL_HOSTLIST */
  203. /* forward declarations */
  204. static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
  205. static void dns_check_entries(void);
  206. /*-----------------------------------------------------------------------------
  207. * Globales
  208. *----------------------------------------------------------------------------*/
  209. /* DNS variables */
  210. static struct udp_pcb *dns_pcb;
  211. static u8_t dns_seqno;
  212. static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
  213. static struct ip_addr dns_servers[DNS_MAX_SERVERS];
  214. #if (DNS_USES_STATIC_BUF == 1)
  215. static u8_t dns_payload[DNS_MSG_SIZE];
  216. #endif /* (DNS_USES_STATIC_BUF == 1) */
  217. /**
  218. * Initialize the resolver: set up the UDP pcb and configure the default server
  219. * (DNS_SERVER_ADDRESS).
  220. */
  221. void
  222. dns_init()
  223. {
  224. struct ip_addr dnsserver;
  225. /* initialize default DNS server address */
  226. dnsserver.addr = DNS_SERVER_ADDRESS;
  227. LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
  228. /* if dns client not yet initialized... */
  229. if (dns_pcb == NULL) {
  230. dns_pcb = udp_new();
  231. if (dns_pcb != NULL) {
  232. /* initialize DNS table not needed (initialized to zero since it is a
  233. * global variable) */
  234. LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
  235. DNS_STATE_UNUSED == 0);
  236. /* initialize DNS client */
  237. udp_bind(dns_pcb, IP_ADDR_ANY, 0);
  238. udp_recv(dns_pcb, dns_recv, NULL);
  239. /* initialize default DNS primary server */
  240. dns_setserver(0, &dnsserver);
  241. }
  242. }
  243. #if DNS_LOCAL_HOSTLIST
  244. dns_init_local();
  245. #endif
  246. }
  247. /**
  248. * Initialize one of the DNS servers.
  249. *
  250. * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
  251. * @param dnsserver IP address of the DNS server to set
  252. */
  253. void
  254. dns_setserver(u8_t numdns, struct ip_addr *dnsserver)
  255. {
  256. if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
  257. (dnsserver != NULL) && (dnsserver->addr !=0 )) {
  258. dns_servers[numdns] = (*dnsserver);
  259. }
  260. }
  261. /**
  262. * Obtain one of the currently configured DNS server.
  263. *
  264. * @param numdns the index of the DNS server
  265. * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
  266. * server has not been configured.
  267. */
  268. struct ip_addr
  269. dns_getserver(u8_t numdns)
  270. {
  271. if (numdns < DNS_MAX_SERVERS) {
  272. return dns_servers[numdns];
  273. } else {
  274. return *IP_ADDR_ANY;
  275. }
  276. }
  277. /**
  278. * The DNS resolver client timer - handle retries and timeouts and should
  279. * be called every DNS_TMR_INTERVAL milliseconds (every second by default).
  280. */
  281. void
  282. dns_tmr(void)
  283. {
  284. if (dns_pcb != NULL) {
  285. LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
  286. dns_check_entries();
  287. }
  288. }
  289. #if DNS_LOCAL_HOSTLIST
  290. static void
  291. dns_init_local()
  292. {
  293. #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
  294. int i;
  295. struct local_hostlist_entry *entry;
  296. /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
  297. struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
  298. for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
  299. entry = mem_malloc(sizeof(struct local_hostlist_entry));
  300. LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
  301. if (entry != NULL) {
  302. struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
  303. entry->name = init_entry->name;
  304. entry->addr = init_entry->addr;
  305. entry->next = local_hostlist_dynamic;
  306. local_hostlist_dynamic = entry;
  307. }
  308. }
  309. #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
  310. }
  311. /**
  312. * Scans the local host-list for a hostname.
  313. *
  314. * @param hostname Hostname to look for in the local host-list
  315. * @return The first IP address for the hostname in the local host-list or
  316. * INADDR_NONE if not found.
  317. */
  318. static u32_t
  319. dns_lookup_local(const char *hostname)
  320. {
  321. #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
  322. struct local_hostlist_entry *entry = local_hostlist_dynamic;
  323. while(entry != NULL) {
  324. if(strcmp(entry->name, hostname) == 0) {
  325. return entry->addr;
  326. }
  327. entry = entry->next;
  328. }
  329. #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
  330. int i;
  331. for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
  332. if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
  333. return local_hostlist_static[i].addr;
  334. }
  335. }
  336. #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
  337. return INADDR_NONE;
  338. }
  339. #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
  340. /** Remove all entries from the local host-list for a specific hostname
  341. * and/or IP addess
  342. *
  343. * @param hostname hostname for which entries shall be removed from the local
  344. * host-list
  345. * @param addr address for which entries shall be removed from the local host-list
  346. * @return the number of removed entries
  347. */
  348. int
  349. dns_local_removehost(const char *hostname, const struct ip_addr *addr)
  350. {
  351. int removed = 0;
  352. struct local_hostlist_entry *entry = local_hostlist_dynamic;
  353. struct local_hostlist_entry *last_entry = NULL;
  354. while (entry != NULL) {
  355. if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
  356. ((addr == NULL) || (entry->addr == addr->addr))) {
  357. struct local_hostlist_entry *free_entry;
  358. if (last_entry != NULL) {
  359. last_entry->next = entry->next;
  360. } else {
  361. local_hostlist_dynamic = entry->next;
  362. }
  363. free_entry = entry;
  364. entry = entry->next;
  365. mem_free(free_entry);
  366. removed++;
  367. } else {
  368. last_entry = entry;
  369. entry = entry->next;
  370. }
  371. }
  372. return removed;
  373. }
  374. /**
  375. * Add a hostname/IP address pair to the local host-list.
  376. * Duplicates are not checked.
  377. *
  378. * @param hostname hostname of the new entry
  379. * @param addr IP address of the new entry
  380. * @return ERR_OK if succeeded or ERR_MEM on memory error
  381. */
  382. err_t
  383. dns_local_addhost(const char *hostname, const struct ip_addr *addr)
  384. {
  385. struct local_hostlist_entry *entry;
  386. entry = mem_malloc(sizeof(struct local_hostlist_entry));
  387. if (entry == NULL) {
  388. return ERR_MEM;
  389. }
  390. entry->name = hostname;
  391. entry->addr = addr->addr;
  392. entry->next = local_hostlist_dynamic;
  393. local_hostlist_dynamic = entry;
  394. return ERR_OK;
  395. }
  396. #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
  397. #endif /* DNS_LOCAL_HOSTLIST */
  398. /**
  399. * Look up a hostname in the array of known hostnames.
  400. *
  401. * @note This function only looks in the internal array of known
  402. * hostnames, it does not send out a query for the hostname if none
  403. * was found. The function dns_enqueue() can be used to send a query
  404. * for a hostname.
  405. *
  406. * @param name the hostname to look up
  407. * @return the hostname's IP address, as u32_t (instead of struct ip_addr to
  408. * better check for failure: != INADDR_NONE) or INADDR_NONE if the hostname
  409. * was not found in the cached dns_table.
  410. */
  411. static u32_t
  412. dns_lookup(const char *name)
  413. {
  414. u8_t i;
  415. #if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
  416. u32_t addr;
  417. #endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
  418. #if DNS_LOCAL_HOSTLIST
  419. if ((addr = dns_lookup_local(name)) != INADDR_NONE) {
  420. return addr;
  421. }
  422. #endif /* DNS_LOCAL_HOSTLIST */
  423. #ifdef DNS_LOOKUP_LOCAL_EXTERN
  424. if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != INADDR_NONE) {
  425. return addr;
  426. }
  427. #endif /* DNS_LOOKUP_LOCAL_EXTERN */
  428. /* Walk through name list, return entry if found. If not, return NULL. */
  429. for (i = 0; i < DNS_TABLE_SIZE; ++i) {
  430. if ((dns_table[i].state == DNS_STATE_DONE) &&
  431. (strcmp(name, dns_table[i].name) == 0)) {
  432. LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
  433. ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
  434. LWIP_DEBUGF(DNS_DEBUG, ("\n"));
  435. return dns_table[i].ipaddr.addr;
  436. }
  437. }
  438. return INADDR_NONE;
  439. }
  440. #if DNS_DOES_NAME_CHECK
  441. /**
  442. * Compare the "dotted" name "query" with the encoded name "response"
  443. * to make sure an answer from the DNS server matches the current dns_table
  444. * entry (otherwise, answers might arrive late for hostname not on the list
  445. * any more).
  446. *
  447. * @param query hostname (not encoded) from the dns_table
  448. * @param response encoded hostname in the DNS response
  449. * @return 0: names equal; 1: names differ
  450. */
  451. static u8_t
  452. dns_compare_name(unsigned char *query, unsigned char *response)
  453. {
  454. unsigned char n;
  455. do {
  456. n = *response++;
  457. /** @see RFC 1035 - 4.1.4. Message compression */
  458. if ((n & 0xc0) == 0xc0) {
  459. /* Compressed name */
  460. break;
  461. } else {
  462. /* Not compressed name */
  463. while (n > 0) {
  464. if ((*query) != (*response)) {
  465. return 1;
  466. }
  467. ++response;
  468. ++query;
  469. --n;
  470. };
  471. ++query;
  472. }
  473. } while (*response != 0);
  474. return 0;
  475. }
  476. #endif /* DNS_DOES_NAME_CHECK */
  477. /**
  478. * Walk through a compact encoded DNS name and return the end of the name.
  479. *
  480. * @param query encoded DNS name in the DNS server response
  481. * @return end of the name
  482. */
  483. static unsigned char *
  484. dns_parse_name(unsigned char *query)
  485. {
  486. unsigned char n;
  487. do {
  488. n = *query++;
  489. /** @see RFC 1035 - 4.1.4. Message compression */
  490. if ((n & 0xc0) == 0xc0) {
  491. /* Compressed name */
  492. break;
  493. } else {
  494. /* Not compressed name */
  495. while (n > 0) {
  496. ++query;
  497. --n;
  498. };
  499. }
  500. } while (*query != 0);
  501. return query + 1;
  502. }
  503. /**
  504. * Send a DNS query packet.
  505. *
  506. * @param numdns index of the DNS server in the dns_servers table
  507. * @param name hostname to query
  508. * @param id index of the hostname in dns_table, used as transaction ID in the
  509. * DNS query packet
  510. * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
  511. */
  512. static err_t
  513. dns_send(u8_t numdns, const char* name, u8_t id)
  514. {
  515. err_t err;
  516. struct dns_hdr *hdr;
  517. struct dns_query qry;
  518. struct pbuf *p;
  519. char *query, *nptr;
  520. const char *pHostname;
  521. u8_t n;
  522. LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
  523. (u16_t)(numdns), name));
  524. LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
  525. LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0);
  526. /* if here, we have either a new query or a retry on a previous query to process */
  527. p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
  528. SIZEOF_DNS_QUERY, PBUF_RAM);
  529. if (p != NULL) {
  530. LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
  531. /* fill dns header */
  532. hdr = (struct dns_hdr*)p->payload;
  533. memset(hdr, 0, SIZEOF_DNS_HDR);
  534. hdr->id = htons(id);
  535. hdr->flags1 = DNS_FLAG1_RD;
  536. hdr->numquestions = htons(1);
  537. query = (char*)hdr + SIZEOF_DNS_HDR;
  538. pHostname = name;
  539. --pHostname;
  540. /* convert hostname into suitable query format. */
  541. do {
  542. ++pHostname;
  543. nptr = query;
  544. ++query;
  545. for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
  546. *query = *pHostname;
  547. ++query;
  548. ++n;
  549. }
  550. *nptr = n;
  551. } while(*pHostname != 0);
  552. *query++='\0';
  553. /* fill dns query */
  554. qry.type = htons(DNS_RRTYPE_A);
  555. qry.class = htons(DNS_RRCLASS_IN);
  556. MEMCPY( query, &qry, SIZEOF_DNS_QUERY);
  557. /* resize pbuf to the exact dns query */
  558. pbuf_realloc(p, (query + SIZEOF_DNS_QUERY) - ((char*)(p->payload)));
  559. /* connect to the server for faster receiving */
  560. udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
  561. /* send dns packet */
  562. err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
  563. /* free pbuf */
  564. pbuf_free(p);
  565. } else {
  566. err = ERR_MEM;
  567. }
  568. return err;
  569. }
  570. /**
  571. * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
  572. * Check an entry in the dns_table:
  573. * - send out query for new entries
  574. * - retry old pending entries on timeout (also with different servers)
  575. * - remove completed entries from the table if their TTL has expired
  576. *
  577. * @param i index of the dns_table entry to check
  578. */
  579. static void
  580. dns_check_entry(u8_t i)
  581. {
  582. struct dns_table_entry *pEntry = &dns_table[i];
  583. LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
  584. switch(pEntry->state) {
  585. case DNS_STATE_NEW: {
  586. /* initialize new entry */
  587. pEntry->state = DNS_STATE_ASKING;
  588. pEntry->numdns = 0;
  589. pEntry->tmr = 1;
  590. pEntry->retries = 0;
  591. /* send DNS packet for this entry */
  592. dns_send(pEntry->numdns, pEntry->name, i);
  593. break;
  594. }
  595. case DNS_STATE_ASKING: {
  596. if (--pEntry->tmr == 0) {
  597. if (++pEntry->retries == DNS_MAX_RETRIES) {
  598. if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) {
  599. /* change of server */
  600. pEntry->numdns++;
  601. pEntry->tmr = 1;
  602. pEntry->retries = 0;
  603. break;
  604. } else {
  605. LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
  606. /* call specified callback function if provided */
  607. if (pEntry->found)
  608. (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
  609. /* flush this entry */
  610. pEntry->state = DNS_STATE_UNUSED;
  611. pEntry->found = NULL;
  612. break;
  613. }
  614. }
  615. /* wait longer for the next retry */
  616. pEntry->tmr = pEntry->retries;
  617. /* send DNS packet for this entry */
  618. dns_send(pEntry->numdns, pEntry->name, i);
  619. }
  620. break;
  621. }
  622. case DNS_STATE_DONE: {
  623. /* if the time to live is nul */
  624. if (--pEntry->ttl == 0) {
  625. LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
  626. /* flush this entry */
  627. pEntry->state = DNS_STATE_UNUSED;
  628. pEntry->found = NULL;
  629. }
  630. break;
  631. }
  632. case DNS_STATE_UNUSED:
  633. /* nothing to do */
  634. break;
  635. default:
  636. LWIP_ASSERT("unknown dns_table entry state:", 0);
  637. break;
  638. }
  639. }
  640. /**
  641. * Call dns_check_entry for each entry in dns_table - check all entries.
  642. */
  643. static void
  644. dns_check_entries(void)
  645. {
  646. u8_t i;
  647. for (i = 0; i < DNS_TABLE_SIZE; ++i) {
  648. dns_check_entry(i);
  649. }
  650. }
  651. /**
  652. * Receive input function for DNS response packets arriving for the dns UDP pcb.
  653. *
  654. * @params see udp.h
  655. */
  656. static void
  657. dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
  658. {
  659. u8_t i;
  660. char *pHostname;
  661. struct dns_hdr *hdr;
  662. struct dns_answer ans;
  663. struct dns_table_entry *pEntry;
  664. u8_t nquestions, nanswers;
  665. #if (DNS_USES_STATIC_BUF == 0)
  666. u8_t dns_payload[DNS_MSG_SIZE];
  667. #endif /* (DNS_USES_STATIC_BUF == 0) */
  668. #if (DNS_USES_STATIC_BUF == 2)
  669. u8_t* dns_payload;
  670. #endif /* (DNS_USES_STATIC_BUF == 2) */
  671. LWIP_UNUSED_ARG(arg);
  672. LWIP_UNUSED_ARG(pcb);
  673. LWIP_UNUSED_ARG(addr);
  674. LWIP_UNUSED_ARG(port);
  675. /* is the dns message too big ? */
  676. if (p->tot_len > DNS_MSG_SIZE) {
  677. LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
  678. /* free pbuf and return */
  679. goto memerr1;
  680. }
  681. /* is the dns message big enough ? */
  682. if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
  683. LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
  684. /* free pbuf and return */
  685. goto memerr1;
  686. }
  687. #if (DNS_USES_STATIC_BUF == 2)
  688. dns_payload = mem_malloc(p->tot_len);
  689. if (dns_payload == NULL) {
  690. LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n"));
  691. /* free pbuf and return */
  692. goto memerr1;
  693. }
  694. #endif /* (DNS_USES_STATIC_BUF == 2) */
  695. /* copy dns payload inside static buffer for processing */
  696. if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
  697. /* The ID in the DNS header should be our entry into the name table. */
  698. hdr = (struct dns_hdr*)dns_payload;
  699. i = htons(hdr->id);
  700. if (i < DNS_TABLE_SIZE) {
  701. pEntry = &dns_table[i];
  702. if(pEntry->state == DNS_STATE_ASKING) {
  703. /* This entry is now completed. */
  704. pEntry->state = DNS_STATE_DONE;
  705. pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
  706. /* We only care about the question(s) and the answers. The authrr
  707. and the extrarr are simply discarded. */
  708. nquestions = htons(hdr->numquestions);
  709. nanswers = htons(hdr->numanswers);
  710. /* Check for error. If so, call callback to inform. */
  711. if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
  712. LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
  713. /* call callback to indicate error, clean up memory and return */
  714. goto responseerr;
  715. }
  716. #if DNS_DOES_NAME_CHECK
  717. /* Check if the name in the "question" part match with the name in the entry. */
  718. if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
  719. LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
  720. /* call callback to indicate error, clean up memory and return */
  721. goto responseerr;
  722. }
  723. #endif /* DNS_DOES_NAME_CHECK */
  724. /* Skip the name in the "question" part */
  725. pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
  726. while(nanswers > 0) {
  727. /* skip answer resource record's host name */
  728. pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
  729. /* Check for IP address type and Internet class. Others are discarded. */
  730. MEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
  731. if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) {
  732. /* read the answer resource record's TTL, and maximize it if needed */
  733. pEntry->ttl = ntohl(ans.ttl);
  734. if (pEntry->ttl > DNS_MAX_TTL) {
  735. pEntry->ttl = DNS_MAX_TTL;
  736. }
  737. /* read the IP address after answer resource record's header */
  738. MEMCPY( &(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(struct ip_addr));
  739. LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
  740. ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
  741. LWIP_DEBUGF(DNS_DEBUG, ("\n"));
  742. /* call specified callback function if provided */
  743. if (pEntry->found) {
  744. (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
  745. }
  746. /* deallocate memory and return */
  747. goto memerr2;
  748. } else {
  749. pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
  750. }
  751. --nanswers;
  752. }
  753. LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
  754. /* call callback to indicate error, clean up memory and return */
  755. goto responseerr;
  756. }
  757. }
  758. }
  759. /* deallocate memory and return */
  760. goto memerr2;
  761. responseerr:
  762. /* ERROR: call specified callback function with NULL as name to indicate an error */
  763. if (pEntry->found) {
  764. (*pEntry->found)(pEntry->name, NULL, pEntry->arg);
  765. }
  766. /* flush this entry */
  767. pEntry->state = DNS_STATE_UNUSED;
  768. pEntry->found = NULL;
  769. memerr2:
  770. #if (DNS_USES_STATIC_BUF == 2)
  771. /* free dns buffer */
  772. mem_free(dns_payload);
  773. #endif /* (DNS_USES_STATIC_BUF == 2) */
  774. memerr1:
  775. /* free pbuf */
  776. pbuf_free(p);
  777. return;
  778. }
  779. /**
  780. * Queues a new hostname to resolve and sends out a DNS query for that hostname
  781. *
  782. * @param name the hostname that is to be queried
  783. * @param found a callback founction to be called on success, failure or timeout
  784. * @param callback_arg argument to pass to the callback function
  785. * @return @return a err_t return code.
  786. */
  787. static err_t
  788. dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
  789. {
  790. u8_t i;
  791. u8_t lseq, lseqi;
  792. struct dns_table_entry *pEntry = NULL;
  793. /* search an unused entry, or the oldest one */
  794. lseq = lseqi = 0;
  795. for (i = 0; i < DNS_TABLE_SIZE; ++i) {
  796. pEntry = &dns_table[i];
  797. /* is it an unused entry ? */
  798. if (pEntry->state == DNS_STATE_UNUSED)
  799. break;
  800. /* check if this is the oldest completed entry */
  801. if (pEntry->state == DNS_STATE_DONE) {
  802. if ((dns_seqno - pEntry->seqno) > lseq) {
  803. lseq = dns_seqno - pEntry->seqno;
  804. lseqi = i;
  805. }
  806. }
  807. }
  808. /* if we don't have found an unused entry, use the oldest completed one */
  809. if (i == DNS_TABLE_SIZE) {
  810. if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
  811. /* no entry can't be used now, table is full */
  812. LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
  813. return ERR_MEM;
  814. } else {
  815. /* use the oldest completed one */
  816. i = lseqi;
  817. pEntry = &dns_table[i];
  818. }
  819. }
  820. /* use this entry */
  821. LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
  822. /* fill the entry */
  823. pEntry->state = DNS_STATE_NEW;
  824. pEntry->seqno = dns_seqno++;
  825. pEntry->found = found;
  826. pEntry->arg = callback_arg;
  827. strcpy(pEntry->name, name);
  828. /* force to send query without waiting timer */
  829. dns_check_entry(i);
  830. /* dns query is enqueued */
  831. return ERR_INPROGRESS;
  832. }
  833. /**
  834. * Resolve a hostname (string) into an IP address.
  835. * NON-BLOCKING callback version for use with raw API!!!
  836. *
  837. * Returns immediately with one of err_t return codes:
  838. * - ERR_OK if hostname is a valid IP address string or the host
  839. * name is already in the local names table.
  840. * - ERR_INPROGRESS enqueue a request to be sent to the DNS server
  841. * for resolution if no errors are present.
  842. *
  843. * @param hostname the hostname that is to be queried
  844. * @param addr pointer to a struct ip_addr where to store the address if it is already
  845. * cached in the dns_table (only valid if ERR_OK is returned!)
  846. * @param found a callback function to be called on success, failure or timeout (only if
  847. * ERR_INPROGRESS is returned!)
  848. * @param callback_arg argument to pass to the callback function
  849. * @return a err_t return code.
  850. */
  851. err_t
  852. dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found,
  853. void *callback_arg)
  854. {
  855. /* not initialized or no valid server yet, or invalid addr pointer
  856. * or invalid hostname or invalid hostname length */
  857. if ((dns_pcb == NULL) || (addr == NULL) ||
  858. (!hostname) || (!hostname[0]) ||
  859. (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
  860. return ERR_VAL;
  861. }
  862. #if LWIP_HAVE_LOOPIF
  863. if (strcmp(hostname,"localhost")==0) {
  864. addr->addr = htonl(INADDR_LOOPBACK);
  865. return ERR_OK;
  866. }
  867. #endif /* LWIP_HAVE_LOOPIF */
  868. /* host name already in octet notation? set ip addr and return ERR_OK
  869. * already have this address cached? */
  870. if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||
  871. ((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) {
  872. return ERR_OK;
  873. }
  874. /* queue query with specified callback */
  875. return dns_enqueue(hostname, found, callback_arg);
  876. }
  877. #endif /* LWIP_DNS */