resolv.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /**
  2. * \addtogroup apps
  3. * @{
  4. */
  5. /**
  6. * \defgroup resolv DNS resolver
  7. * @{
  8. *
  9. * The uIP DNS resolver functions are used to lookup a hostname and
  10. * map it to a numerical IP address. It maintains a list of resolved
  11. * hostnames that can be queried with the resolv_lookup()
  12. * function. New hostnames can be resolved using the resolv_query()
  13. * function.
  14. *
  15. * When a hostname has been resolved (or found to be non-existant),
  16. * the resolver code calls a callback function called resolv_found()
  17. * that must be implemented by the module that uses the resolver.
  18. */
  19. /**
  20. * \file
  21. * DNS host name to IP address resolver.
  22. * \author Adam Dunkels <adam@dunkels.com>
  23. *
  24. * This file implements a DNS host name to IP address resolver.
  25. */
  26. /*
  27. * Copyright (c) 2002-2003, Adam Dunkels.
  28. * All rights reserved.
  29. *
  30. * Redistribution and use in source and binary forms, with or without
  31. * modification, are permitted provided that the following conditions
  32. * are met:
  33. * 1. Redistributions of source code must retain the above copyright
  34. * notice, this list of conditions and the following disclaimer.
  35. * 2. Redistributions in binary form must reproduce the above copyright
  36. * notice, this list of conditions and the following disclaimer in the
  37. * documentation and/or other materials provided with the distribution.
  38. * 3. The name of the author may not be used to endorse or promote
  39. * products derived from this software without specific prior
  40. * written permission.
  41. *
  42. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  43. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  44. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  45. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  46. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  47. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  48. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  49. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  50. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  51. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  52. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  53. *
  54. * This file is part of the uIP TCP/IP stack.
  55. *
  56. * $Id: resolv.c,v 1.5 2006/06/11 21:46:37 adam Exp $
  57. *
  58. */
  59. #include "resolv.h"
  60. #include "uip.h"
  61. #include <string.h>
  62. #ifndef NULL
  63. #define NULL (void *)0
  64. #endif /* NULL */
  65. /** \internal The maximum number of retries when asking for a name. */
  66. #define MAX_RETRIES 8
  67. /** \internal The DNS message header. */
  68. struct dns_hdr {
  69. u16_t id;
  70. u8_t flags1, flags2;
  71. #define DNS_FLAG1_RESPONSE 0x80
  72. #define DNS_FLAG1_OPCODE_STATUS 0x10
  73. #define DNS_FLAG1_OPCODE_INVERSE 0x08
  74. #define DNS_FLAG1_OPCODE_STANDARD 0x00
  75. #define DNS_FLAG1_AUTHORATIVE 0x04
  76. #define DNS_FLAG1_TRUNC 0x02
  77. #define DNS_FLAG1_RD 0x01
  78. #define DNS_FLAG2_RA 0x80
  79. #define DNS_FLAG2_ERR_MASK 0x0f
  80. #define DNS_FLAG2_ERR_NONE 0x00
  81. #define DNS_FLAG2_ERR_NAME 0x03
  82. u16_t numquestions;
  83. u16_t numanswers;
  84. u16_t numauthrr;
  85. u16_t numextrarr;
  86. };
  87. /** \internal The DNS answer message structure. */
  88. struct dns_answer {
  89. /* DNS answer record starts with either a domain name or a pointer
  90. to a name already present somewhere in the packet. */
  91. u16_t type;
  92. u16_t class;
  93. u16_t ttl[2];
  94. u16_t len;
  95. uip_ipaddr_t ipaddr;
  96. };
  97. struct namemap {
  98. #define STATE_UNUSED 0
  99. #define STATE_NEW 1
  100. #define STATE_ASKING 2
  101. #define STATE_DONE 3
  102. #define STATE_ERROR 4
  103. u8_t state;
  104. u8_t tmr;
  105. u8_t retries;
  106. u8_t seqno;
  107. u8_t err;
  108. char name[32];
  109. uip_ipaddr_t ipaddr;
  110. };
  111. #ifndef UIP_CONF_RESOLV_ENTRIES
  112. #define RESOLV_ENTRIES 4
  113. #else /* UIP_CONF_RESOLV_ENTRIES */
  114. #define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES
  115. #endif /* UIP_CONF_RESOLV_ENTRIES */
  116. static struct namemap names[RESOLV_ENTRIES];
  117. static u8_t seqno;
  118. static struct uip_udp_conn *resolv_conn = NULL;
  119. /*---------------------------------------------------------------------------*/
  120. /** \internal
  121. * Walk through a compact encoded DNS name and return the end of it.
  122. *
  123. * \return The end of the name.
  124. */
  125. /*---------------------------------------------------------------------------*/
  126. static unsigned char *
  127. parse_name(unsigned char *query)
  128. {
  129. unsigned char n;
  130. do {
  131. n = *query++;
  132. while(n > 0) {
  133. /* printf("%c", *query);*/
  134. ++query;
  135. --n;
  136. };
  137. /* printf(".");*/
  138. } while(*query != 0);
  139. /* printf("\n");*/
  140. return query + 1;
  141. }
  142. /*---------------------------------------------------------------------------*/
  143. /** \internal
  144. * Runs through the list of names to see if there are any that have
  145. * not yet been queried and, if so, sends out a query.
  146. */
  147. /*---------------------------------------------------------------------------*/
  148. static void
  149. check_entries(void)
  150. {
  151. register struct dns_hdr *hdr;
  152. char *query, *nptr, *nameptr;
  153. static u8_t i;
  154. static u8_t n;
  155. register struct namemap *namemapptr;
  156. for(i = 0; i < RESOLV_ENTRIES; ++i) {
  157. namemapptr = &names[i];
  158. if(namemapptr->state == STATE_NEW ||
  159. namemapptr->state == STATE_ASKING) {
  160. if(namemapptr->state == STATE_ASKING) {
  161. if(--namemapptr->tmr == 0) {
  162. if(++namemapptr->retries == MAX_RETRIES) {
  163. namemapptr->state = STATE_ERROR;
  164. resolv_found(namemapptr->name, NULL);
  165. continue;
  166. }
  167. namemapptr->tmr = namemapptr->retries;
  168. } else {
  169. /* printf("Timer %d\n", namemapptr->tmr);*/
  170. /* Its timer has not run out, so we move on to next
  171. entry. */
  172. continue;
  173. }
  174. } else {
  175. namemapptr->state = STATE_ASKING;
  176. namemapptr->tmr = 1;
  177. namemapptr->retries = 0;
  178. }
  179. hdr = (struct dns_hdr *)uip_appdata;
  180. memset(hdr, 0, sizeof(struct dns_hdr));
  181. hdr->id = htons(i);
  182. hdr->flags1 = DNS_FLAG1_RD;
  183. hdr->numquestions = HTONS(1);
  184. query = (char *)uip_appdata + 12;
  185. nameptr = namemapptr->name;
  186. --nameptr;
  187. /* Convert hostname into suitable query format. */
  188. do {
  189. ++nameptr;
  190. nptr = query;
  191. ++query;
  192. for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) {
  193. *query = *nameptr;
  194. ++query;
  195. ++n;
  196. }
  197. *nptr = n;
  198. } while(*nameptr != 0);
  199. {
  200. static unsigned char endquery[] =
  201. {0,0,1,0,1};
  202. memcpy(query, endquery, 5);
  203. }
  204. uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata));
  205. break;
  206. }
  207. }
  208. }
  209. /*---------------------------------------------------------------------------*/
  210. /** \internal
  211. * Called when new UDP data arrives.
  212. */
  213. /*---------------------------------------------------------------------------*/
  214. static void
  215. newdata(void)
  216. {
  217. char *nameptr;
  218. struct dns_answer *ans;
  219. struct dns_hdr *hdr;
  220. static u8_t nquestions, nanswers;
  221. static u8_t i;
  222. register struct namemap *namemapptr;
  223. hdr = (struct dns_hdr *)uip_appdata;
  224. /* printf("ID %d\n", htons(hdr->id));
  225. printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE);
  226. printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK);
  227. printf("Num questions %d, answers %d, authrr %d, extrarr %d\n",
  228. htons(hdr->numquestions),
  229. htons(hdr->numanswers),
  230. htons(hdr->numauthrr),
  231. htons(hdr->numextrarr));
  232. */
  233. /* The ID in the DNS header should be our entry into the name
  234. table. */
  235. i = htons(hdr->id);
  236. namemapptr = &names[i];
  237. if(i < RESOLV_ENTRIES &&
  238. namemapptr->state == STATE_ASKING) {
  239. /* This entry is now finished. */
  240. namemapptr->state = STATE_DONE;
  241. namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
  242. /* Check for error. If so, call callback to inform. */
  243. if(namemapptr->err != 0) {
  244. namemapptr->state = STATE_ERROR;
  245. resolv_found(namemapptr->name, NULL);
  246. return;
  247. }
  248. /* We only care about the question(s) and the answers. The authrr
  249. and the extrarr are simply discarded. */
  250. nquestions = htons(hdr->numquestions);
  251. nanswers = htons(hdr->numanswers);
  252. /* Skip the name in the question. XXX: This should really be
  253. checked agains the name in the question, to be sure that they
  254. match. */
  255. nameptr = parse_name((char *)uip_appdata + 12) + 4;
  256. while(nanswers > 0) {
  257. /* The first byte in the answer resource record determines if it
  258. is a compressed record or a normal one. */
  259. if(*nameptr & 0xc0) {
  260. /* Compressed name. */
  261. nameptr +=2;
  262. /* printf("Compressed anwser\n");*/
  263. } else {
  264. /* Not compressed name. */
  265. nameptr = parse_name((char *)nameptr);
  266. }
  267. ans = (struct dns_answer *)nameptr;
  268. /* printf("Answer: type %x, class %x, ttl %x, length %x\n",
  269. htons(ans->type), htons(ans->class), (htons(ans->ttl[0])
  270. << 16) | htons(ans->ttl[1]), htons(ans->len));*/
  271. /* Check for IP address type and Internet class. Others are
  272. discarded. */
  273. if(ans->type == HTONS(1) &&
  274. ans->class == HTONS(1) &&
  275. ans->len == HTONS(4)) {
  276. /* printf("IP address %d.%d.%d.%d\n",
  277. htons(ans->ipaddr[0]) >> 8,
  278. htons(ans->ipaddr[0]) & 0xff,
  279. htons(ans->ipaddr[1]) >> 8,
  280. htons(ans->ipaddr[1]) & 0xff);*/
  281. /* XXX: we should really check that this IP address is the one
  282. we want. */
  283. namemapptr->ipaddr[0] = ans->ipaddr[0];
  284. namemapptr->ipaddr[1] = ans->ipaddr[1];
  285. resolv_found(namemapptr->name, namemapptr->ipaddr);
  286. return;
  287. } else {
  288. nameptr = nameptr + 10 + htons(ans->len);
  289. }
  290. --nanswers;
  291. }
  292. }
  293. }
  294. /*---------------------------------------------------------------------------*/
  295. /** \internal
  296. * The main UDP function.
  297. */
  298. /*---------------------------------------------------------------------------*/
  299. void
  300. resolv_appcall(void)
  301. {
  302. if(uip_udp_conn->rport == HTONS(53)) {
  303. if(uip_poll()) {
  304. check_entries();
  305. }
  306. if(uip_newdata()) {
  307. newdata();
  308. }
  309. }
  310. }
  311. /*---------------------------------------------------------------------------*/
  312. /**
  313. * Queues a name so that a question for the name will be sent out.
  314. *
  315. * \param name The hostname that is to be queried.
  316. */
  317. /*---------------------------------------------------------------------------*/
  318. void
  319. resolv_query(char *name)
  320. {
  321. static u8_t i;
  322. static u8_t lseq, lseqi;
  323. register struct namemap *nameptr;
  324. lseq = lseqi = 0;
  325. for(i = 0; i < RESOLV_ENTRIES; ++i) {
  326. nameptr = &names[i];
  327. if(nameptr->state == STATE_UNUSED) {
  328. break;
  329. }
  330. if(seqno - nameptr->seqno > lseq) {
  331. lseq = seqno - nameptr->seqno;
  332. lseqi = i;
  333. }
  334. }
  335. if(i == RESOLV_ENTRIES) {
  336. i = lseqi;
  337. nameptr = &names[i];
  338. }
  339. /* printf("Using entry %d\n", i);*/
  340. strcpy(nameptr->name, name);
  341. nameptr->state = STATE_NEW;
  342. nameptr->seqno = seqno;
  343. ++seqno;
  344. }
  345. /*---------------------------------------------------------------------------*/
  346. /**
  347. * Look up a hostname in the array of known hostnames.
  348. *
  349. * \note This function only looks in the internal array of known
  350. * hostnames, it does not send out a query for the hostname if none
  351. * was found. The function resolv_query() can be used to send a query
  352. * for a hostname.
  353. *
  354. * \return A pointer to a 4-byte representation of the hostname's IP
  355. * address, or NULL if the hostname was not found in the array of
  356. * hostnames.
  357. */
  358. /*---------------------------------------------------------------------------*/
  359. u16_t *
  360. resolv_lookup(char *name)
  361. {
  362. static u8_t i;
  363. struct namemap *nameptr;
  364. /* Walk through the list to see if the name is in there. If it is
  365. not, we return NULL. */
  366. for(i = 0; i < RESOLV_ENTRIES; ++i) {
  367. nameptr = &names[i];
  368. if(nameptr->state == STATE_DONE &&
  369. strcmp(name, nameptr->name) == 0) {
  370. return nameptr->ipaddr;
  371. }
  372. }
  373. return NULL;
  374. }
  375. /*---------------------------------------------------------------------------*/
  376. /**
  377. * Obtain the currently configured DNS server.
  378. *
  379. * \return A pointer to a 4-byte representation of the IP address of
  380. * the currently configured DNS server or NULL if no DNS server has
  381. * been configured.
  382. */
  383. /*---------------------------------------------------------------------------*/
  384. u16_t *
  385. resolv_getserver(void)
  386. {
  387. if(resolv_conn == NULL) {
  388. return NULL;
  389. }
  390. return resolv_conn->ripaddr;
  391. }
  392. /*---------------------------------------------------------------------------*/
  393. /**
  394. * Configure which DNS server to use for queries.
  395. *
  396. * \param dnsserver A pointer to a 4-byte representation of the IP
  397. * address of the DNS server to be configured.
  398. */
  399. /*---------------------------------------------------------------------------*/
  400. void
  401. resolv_conf(u16_t *dnsserver)
  402. {
  403. if(resolv_conn != NULL) {
  404. uip_udp_remove(resolv_conn);
  405. }
  406. resolv_conn = uip_udp_new(dnsserver, HTONS(53));
  407. }
  408. /*---------------------------------------------------------------------------*/
  409. /**
  410. * Initalize the resolver.
  411. */
  412. /*---------------------------------------------------------------------------*/
  413. void
  414. resolv_init(void)
  415. {
  416. static u8_t i;
  417. for(i = 0; i < RESOLV_ENTRIES; ++i) {
  418. names[i].state = STATE_DONE;
  419. }
  420. }
  421. /*---------------------------------------------------------------------------*/
  422. /** @} */
  423. /** @} */