resolv.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. /*
  2. * Copyright (C) 2009 by egnite GmbH
  3. * Copyright (C) 2001-2003 by egnite Software GmbH
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*
  36. * $Id: resolv.c 4473 2012-08-20 15:12:45Z haraldkipp $
  37. */
  38. #include <cfg/os.h>
  39. #include <sys/device.h>
  40. #include <sys/timer.h>
  41. #include <sys/heap.h>
  42. #include <arpa/inet.h>
  43. #include <net/if_var.h>
  44. #include <sys/socket.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <memdebug.h>
  48. #include <netdb.h>
  49. #ifdef NUTDEBUG
  50. #include <stdio.h>
  51. #endif
  52. /*!
  53. * \addtogroup xgDNS
  54. */
  55. /*@{*/
  56. extern DNSCONFIG confdns;
  57. typedef struct {
  58. uint16_t doh_id;
  59. uint16_t doh_flags;
  60. uint16_t doh_quests;
  61. uint16_t doh_answers;
  62. uint16_t doh_authrr;
  63. uint16_t doh_addrr;
  64. } DNSHEADER;
  65. typedef struct {
  66. uint8_t *doq_name;
  67. uint16_t doq_type;
  68. uint16_t doq_class;
  69. } DNSQUESTION;
  70. typedef struct {
  71. uint8_t *dor_name;
  72. uint16_t dor_type;
  73. uint16_t dor_class;
  74. uint32_t dor_ttl;
  75. uint16_t dor_len;
  76. uint8_t *dor_data;
  77. } DNSRESOURCE;
  78. #ifdef NUTDEBUG
  79. void DumpDnsHeader(FILE * stream, DNSHEADER * doh)
  80. {
  81. fprintf(stream, "HEADER: id=%u flg=%04X #q=%u #an=%u #au=%u #ad=%u\r\n",
  82. doh->doh_id, doh->doh_flags, doh->doh_quests, doh->doh_answers,
  83. doh->doh_authrr, doh->doh_addrr);
  84. }
  85. void DumpDnsQuestion(FILE * stream, DNSQUESTION * doq)
  86. {
  87. fprintf(stream, "QUESTION: name='%s' type=%u class=%u\r\n",
  88. doq->doq_name, doq->doq_type, doq->doq_class);
  89. }
  90. void DumpDnsResource(FILE * stream, DNSRESOURCE * dor)
  91. {
  92. uint16_t i;
  93. fprintf(stream, "RESOURCE: name='%s' type=%u class=%u ttl=%lu len=%u ",
  94. dor->dor_name, dor->dor_type, dor->dor_class, dor->dor_ttl, dor->dor_len);
  95. for (i = 0; i < dor->dor_len; i++)
  96. fprintf(stream, "%02X ", dor->dor_data[i]);
  97. fputc('\n', stream);
  98. }
  99. #endif
  100. static uint16_t AddShort(uint8_t * cp, uint16_t val)
  101. {
  102. *cp++ = (uint8_t) (val >> 8);
  103. *cp++ = (uint8_t) val;
  104. return 2;
  105. }
  106. static uint16_t AddName(uint8_t * cp, const uint8_t * name)
  107. {
  108. uint8_t *lcp;
  109. uint16_t rc = strlen((char *) name) + 2;
  110. lcp = cp++;
  111. *lcp = 0;
  112. while (*name) {
  113. if (*name == '.') {
  114. lcp = cp++;
  115. *lcp = 0;
  116. name++;
  117. } else {
  118. *cp++ = *name++;
  119. (*lcp)++;
  120. }
  121. }
  122. *cp = 0;
  123. return rc;
  124. }
  125. static uint16_t ScanShort(uint8_t * cp, uint16_t * val)
  126. {
  127. *val = (uint16_t) (*cp++) << 8;
  128. *val |= *cp;
  129. return 2;
  130. }
  131. static uint16_t ScanLong(uint8_t * cp, uint32_t * val)
  132. {
  133. *val = *cp++;
  134. *val <<= 8;
  135. *val |= *cp++;
  136. *val <<= 8;
  137. *val |= *cp++;
  138. *val <<= 8;
  139. *val |= *cp;
  140. return 4;
  141. }
  142. static uint16_t ScanName(uint8_t * cp, uint8_t ** npp)
  143. {
  144. uint8_t len;
  145. uint16_t rc;
  146. uint8_t *np;
  147. if (*npp) {
  148. free(*npp);
  149. *npp = 0;
  150. }
  151. if ((*cp & 0xC0) == 0xC0)
  152. return 2;
  153. rc = strlen((char *) cp) + 1;
  154. np = *npp = malloc(rc);
  155. len = *cp++;
  156. while (len) {
  157. while (len--)
  158. *np++ = *cp++;
  159. if ((len = *cp++) != 0)
  160. *np++ = '.';
  161. }
  162. *np = 0;
  163. return rc;
  164. }
  165. static uint16_t ScanBinary(uint8_t * cp, uint8_t ** npp, uint16_t len)
  166. {
  167. if (*npp)
  168. free(*npp);
  169. *npp = malloc(len);
  170. memcpy(*npp, cp, len);
  171. return len;
  172. }
  173. static DNSHEADER *CreateDnsHeader(DNSHEADER * doh, uint16_t id)
  174. {
  175. if (doh == NULL)
  176. doh = calloc(1, sizeof(DNSHEADER));
  177. if (doh) {
  178. doh->doh_id = id;
  179. doh->doh_flags = 0x0100;
  180. doh->doh_quests = 1;
  181. }
  182. return doh;
  183. }
  184. static void ReleaseDnsHeader(DNSHEADER * doh)
  185. {
  186. if (doh)
  187. free(doh);
  188. }
  189. static uint16_t EncodeDnsHeader(uint8_t * buf, DNSHEADER * doh)
  190. {
  191. uint16_t rc;
  192. rc = AddShort(buf, doh->doh_id);
  193. rc += AddShort(buf + rc, doh->doh_flags);
  194. rc += AddShort(buf + rc, doh->doh_quests);
  195. rc += AddShort(buf + rc, doh->doh_answers);
  196. rc += AddShort(buf + rc, doh->doh_authrr);
  197. rc += AddShort(buf + rc, doh->doh_addrr);
  198. return rc;
  199. }
  200. static uint16_t DecodeDnsHeader(DNSHEADER * doh, uint8_t * buf)
  201. {
  202. uint16_t rc;
  203. rc = ScanShort(buf, &doh->doh_id);
  204. rc += ScanShort(buf + rc, &doh->doh_flags);
  205. rc += ScanShort(buf + rc, &doh->doh_quests);
  206. rc += ScanShort(buf + rc, &doh->doh_answers);
  207. rc += ScanShort(buf + rc, &doh->doh_authrr);
  208. rc += ScanShort(buf + rc, &doh->doh_addrr);
  209. return rc;
  210. }
  211. static DNSQUESTION *CreateDnsQuestion(DNSQUESTION * doq, const uint8_t * name, uint16_t type)
  212. {
  213. if (doq == NULL)
  214. doq = calloc(1, sizeof(DNSQUESTION));
  215. if (doq) {
  216. if (doq->doq_name)
  217. free(doq->doq_name);
  218. doq->doq_name = (uint8_t *) strdup((char *) name);
  219. doq->doq_type = type;
  220. doq->doq_class = 1;
  221. }
  222. return doq;
  223. }
  224. static void ReleaseDnsQuestion(DNSQUESTION * doq)
  225. {
  226. if (doq) {
  227. if (doq->doq_name)
  228. free(doq->doq_name);
  229. free(doq);
  230. }
  231. }
  232. static uint16_t EncodeDnsQuestion(uint8_t * buf, DNSQUESTION * doq)
  233. {
  234. uint16_t rc;
  235. rc = AddName(buf, doq->doq_name);
  236. rc += AddShort(buf + rc, doq->doq_type);
  237. rc += AddShort(buf + rc, doq->doq_class);
  238. return rc;
  239. }
  240. static uint16_t DecodeDnsQuestion(DNSQUESTION * doq, uint8_t * buf)
  241. {
  242. uint16_t rc;
  243. rc = ScanName(buf, &doq->doq_name);
  244. rc += ScanShort(buf + rc, &doq->doq_type);
  245. rc += ScanShort(buf + rc, &doq->doq_class);
  246. return rc;
  247. }
  248. static DNSRESOURCE *CreateDnsResource(DNSRESOURCE * dor)
  249. {
  250. if (dor == NULL)
  251. dor = calloc(1, sizeof(DNSRESOURCE));
  252. return dor;
  253. }
  254. static void ReleaseDnsResource(DNSRESOURCE * dor)
  255. {
  256. if (dor) {
  257. if (dor->dor_name)
  258. free(dor->dor_name);
  259. if (dor->dor_data)
  260. free(dor->dor_data);
  261. free(dor);
  262. }
  263. }
  264. static uint16_t DecodeDnsResource(DNSRESOURCE * dor, uint8_t * buf)
  265. {
  266. uint16_t rc;
  267. rc = ScanName(buf, &dor->dor_name);
  268. rc += ScanShort(buf + rc, &dor->dor_type);
  269. rc += ScanShort(buf + rc, &dor->dor_class);
  270. rc += ScanLong(buf + rc, &dor->dor_ttl);
  271. rc += ScanShort(buf + rc, &dor->dor_len);
  272. rc += ScanBinary(buf + rc, &dor->dor_data, dor->dor_len);
  273. return rc;
  274. }
  275. /*!
  276. * \brief Sets DNS configuration.
  277. *
  278. * \deprecated New applications should use NutDnsConfig2().
  279. *
  280. * \param hostname DNS name of the local host.
  281. * \param domain Name of the domain of the local host.
  282. * \param dnsip IP address of the DNS server.
  283. */
  284. void NutDnsConfig(const uint8_t * hostname, const uint8_t * domain, uint32_t dnsip)
  285. {
  286. NutDnsConfig2(hostname, domain, dnsip, 0);
  287. }
  288. void NutDnsGetConfig2(char **hostname, char **domain, uint32_t * pdnsip, uint32_t * sdnsip)
  289. {
  290. if (hostname) {
  291. *hostname = (char *) confdns.doc_hostname;
  292. }
  293. if (domain) {
  294. *domain = (char *) confdns.doc_domain;
  295. }
  296. if (pdnsip) {
  297. *pdnsip = confdns.doc_ip1;
  298. }
  299. if (sdnsip) {
  300. *sdnsip = confdns.doc_ip2;
  301. }
  302. }
  303. /*!
  304. * \brief Retrieves IP-address corresponding to a host name.
  305. *
  306. * This is a very simple implementation, which will not return
  307. * any other resource information than the IP address.
  308. *
  309. * \param hostname Fully qualified domain name of the host.
  310. * \param type Request type.
  311. *
  312. * \return IP address, which is zero, if the name could not
  313. * be resolved.
  314. */
  315. uint32_t NutDnsGetResource(const uint8_t * hostname, const uint16_t type);
  316. uint32_t NutDnsGetHostByName(const uint8_t * hostname)
  317. {
  318. return NutDnsGetResource(hostname, 1);
  319. }
  320. /*!
  321. * \brief Retrieves all IP-address corresponding to a host name.
  322. *
  323. * This is a very simple implementation, which will not return
  324. * any other resource information than the IP address.
  325. *
  326. * \param hostname Fully qualified domain name of the host.
  327. * \param type Request type.
  328. * \param ip_all Array of IP Addresses.
  329. *
  330. * \return Number of IP address, which is zero, if the name could not
  331. * be resolved.
  332. */
  333. uint8_t NutDnsGetResourceAll(const uint8_t * hostname, const uint16_t type, uint32_t * ip_all);
  334. uint8_t NutDnsGetHostsByName(const uint8_t * hostname, uint32_t * ip_all)
  335. {
  336. return NutDnsGetResourceAll(hostname, 1, ip_all);
  337. }
  338. uint32_t NutDnsGetMxByDomain(const uint8_t * hostname)
  339. {
  340. return NutDnsGetResource(hostname, 0x0F);
  341. }
  342. uint32_t NutDnsGetResource(const uint8_t * hostname, const uint16_t type)
  343. {
  344. uint32_t ip = 0;
  345. uint8_t *pkt;
  346. uint16_t len;
  347. uint16_t id = 0;
  348. UDPSOCKET *sock;
  349. DNSHEADER *doh = 0;
  350. DNSQUESTION *doq = 0;
  351. DNSRESOURCE *dor = 0;
  352. int n;
  353. int retries;
  354. uint32_t raddr;
  355. uint16_t rport;
  356. /*
  357. * We need a configured DNS address.
  358. */
  359. if (confdns.doc_ip1 == 0 && confdns.doc_ip2 == 0)
  360. return 0;
  361. /*
  362. * Create client socket and allocate
  363. * a buffer for the UDP packet.
  364. */
  365. if ((sock = NutUdpCreateSocket(0)) == 0)
  366. return 0;
  367. pkt = malloc(512);
  368. for (retries = 0; retries < 6; retries++) {
  369. /*
  370. * Create standard header info structures.
  371. */
  372. doh = CreateDnsHeader(doh, ++id);
  373. doq = CreateDnsQuestion(doq, hostname, type);
  374. #ifdef NUTDEBUG
  375. //DumpDnsHeader(doh);
  376. //DumpDnsQuestion(doq);
  377. #endif
  378. /*
  379. * Encode the header info into the packet buffer
  380. * and send it to the DNS server.
  381. */
  382. len = EncodeDnsHeader(pkt, doh);
  383. len += EncodeDnsQuestion(pkt + len, doq);
  384. if ((retries & 1) == 0 || confdns.doc_ip2 == 0) {
  385. if (NutUdpSendTo(sock, confdns.doc_ip1, 53, pkt, len) < 0)
  386. break;
  387. } else {
  388. if (NutUdpSendTo(sock, confdns.doc_ip2, 53, pkt, len) < 0)
  389. break;
  390. }
  391. /*
  392. * Loop until we receive a response with the
  393. * expected id or until timeout.
  394. */
  395. for (;;) {
  396. len = 0;
  397. n = NutUdpReceiveFrom(sock, &raddr, &rport, pkt, 512, 1000);
  398. if (n <= 0)
  399. break;
  400. if (n > 12) {
  401. len = DecodeDnsHeader(doh, pkt);
  402. #ifdef NUTDEBUG
  403. //DumpDnsHeader(doh);
  404. #endif
  405. if (doh->doh_id == id)
  406. break;
  407. }
  408. }
  409. /*
  410. * Decode the answer.
  411. */
  412. if (len && doh->doh_quests == 1) {
  413. len += DecodeDnsQuestion(doq, pkt + len);
  414. #ifdef NUTDEBUG
  415. //DumpDnsQuestion(doq);
  416. #endif
  417. if (doh->doh_answers < 1)
  418. break;
  419. else {
  420. for (n = 1; n <= (int) doh->doh_answers; n++) {
  421. dor = CreateDnsResource(dor);
  422. len += DecodeDnsResource(dor, pkt + len);
  423. #ifdef NUTDEBUG
  424. //DumpDnsResource(dor);
  425. #endif
  426. if (dor->dor_type == 1)
  427. break;
  428. }
  429. if (dor->dor_len == 4) {
  430. ip = *dor->dor_data;
  431. ip += (uint32_t) (*(dor->dor_data + 1)) << 8;
  432. ip += (uint32_t) (*(dor->dor_data + 2)) << 16;
  433. ip += (uint32_t) (*(dor->dor_data + 3)) << 24;
  434. break;
  435. }
  436. /* TBD: 18.3.2004 - for MX requests authoritative rrs should be skipped + additional rrs should be searched for IP address */
  437. }
  438. }
  439. }
  440. /*
  441. * Clean up.
  442. */
  443. ReleaseDnsHeader(doh);
  444. ReleaseDnsQuestion(doq);
  445. ReleaseDnsResource(dor);
  446. free(pkt);
  447. NutUdpDestroySocket(sock);
  448. return ip;
  449. }
  450. uint8_t NutDnsGetResourceAll(const uint8_t * hostname, const uint16_t type, uint32_t * ip_all)
  451. {
  452. uint8_t n_ip;
  453. uint8_t *pkt;
  454. uint16_t len;
  455. uint16_t id = 0;
  456. UDPSOCKET *sock;
  457. DNSHEADER *doh = 0;
  458. DNSQUESTION *doq = 0;
  459. DNSRESOURCE *dor = 0;
  460. int n;
  461. int retries;
  462. uint32_t raddr;
  463. uint16_t rport;
  464. for (n_ip = 0; n_ip < 8; n_ip++)
  465. ip_all[n_ip] = 0;
  466. /*
  467. * We need a configured DNS address.
  468. */
  469. if (confdns.doc_ip1 == 0 && confdns.doc_ip2 == 0)
  470. return 0;
  471. /*
  472. * Create client socket and allocate
  473. * a buffer for the UDP packet.
  474. */
  475. if ((sock = NutUdpCreateSocket(0)) == 0)
  476. return 0;
  477. pkt = NutHeapAlloc(512);
  478. for (retries = 0; retries < 6; retries++) {
  479. /*
  480. * Create standard header info structures.
  481. */
  482. doh = CreateDnsHeader(doh, ++id);
  483. doq = CreateDnsQuestion(doq, hostname, type);
  484. #ifdef NUTDEBUG
  485. //DumpDnsHeader(doh);
  486. //DumpDnsQuestion(doq);
  487. #endif
  488. /*
  489. * Encode the header info into the packet buffer
  490. * and send it to the DNS server.
  491. */
  492. len = EncodeDnsHeader(pkt, doh);
  493. len += EncodeDnsQuestion(pkt + len, doq);
  494. if ((retries & 1) == 0 || confdns.doc_ip2 == 0) {
  495. if (NutUdpSendTo(sock, confdns.doc_ip1, 53, pkt, len) < 0)
  496. break;
  497. } else {
  498. if (NutUdpSendTo(sock, confdns.doc_ip2, 53, pkt, len) < 0)
  499. break;
  500. }
  501. /*
  502. * Loop until we receive a response with the
  503. * expected id or until timeout.
  504. */
  505. for (;;) {
  506. len = 0;
  507. n = NutUdpReceiveFrom(sock, &raddr, &rport, pkt, 512, 1000);
  508. if (n <= 0)
  509. break;
  510. if (n > 12) {
  511. len = DecodeDnsHeader(doh, pkt);
  512. #ifdef NUTDEBUG
  513. //DumpDnsHeader(doh);
  514. #endif
  515. if (doh->doh_id == id)
  516. break;
  517. }
  518. }
  519. /*
  520. * Decode the answer.
  521. */
  522. if (len && doh->doh_quests == 1) {
  523. len += DecodeDnsQuestion(doq, pkt + len);
  524. #ifdef NUTDEBUG
  525. //DumpDnsQuestion(doq);
  526. #endif
  527. if (doh->doh_answers < 1)
  528. break;
  529. else {
  530. n_ip = 0;
  531. for (n = 1; n <= (int) doh->doh_answers; n++) {
  532. dor = CreateDnsResource(dor);
  533. len += DecodeDnsResource(dor, pkt + len);
  534. #ifdef NUTDEBUG
  535. //DumpDnsResource(dor);
  536. #endif
  537. if (dor->dor_type == 1) {
  538. if (dor->dor_len == 4) {
  539. ip_all[n_ip] = *dor->dor_data;
  540. ip_all[n_ip] += (uint32_t) (*(dor->dor_data + 1)) << 8;
  541. ip_all[n_ip] += (uint32_t) (*(dor->dor_data + 2)) << 16;
  542. ip_all[n_ip] += (uint32_t) (*(dor->dor_data + 3)) << 24;
  543. n_ip++;
  544. }
  545. }
  546. }
  547. }
  548. }
  549. }
  550. /*
  551. * Clean up.
  552. */
  553. ReleaseDnsHeader(doh);
  554. ReleaseDnsQuestion(doq);
  555. ReleaseDnsResource(dor);
  556. NutHeapFree(pkt);
  557. NutUdpDestroySocket(sock);
  558. return n_ip;
  559. }
  560. /*@}*/