dns.c 30 KB

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