dns6.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /**
  2. * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include <stdint.h>
  41. #include <stdbool.h>
  42. #include <string.h>
  43. #include "sdk_errors.h"
  44. #include "sdk_os.h"
  45. #include "sdk_config.h"
  46. #include "iot_common.h"
  47. #include "iot_pbuffer.h"
  48. #include "mem_manager.h"
  49. #include "ipv6_api.h"
  50. #include "udp_api.h"
  51. #include "dns6_api.h"
  52. #if DNS6_CONFIG_LOG_ENABLED
  53. #define NRF_LOG_MODULE_NAME dns6
  54. #define NRF_LOG_LEVEL DNS6_CONFIG_LOG_LEVEL
  55. #define NRF_LOG_INFO_COLOR DNS6_CONFIG_INFO_COLOR
  56. #define NRF_LOG_DEBUG_COLOR DNS6_CONFIG_DEBUG_COLOR
  57. #include "nrf_log.h"
  58. NRF_LOG_MODULE_REGISTER();
  59. #define DNS6_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
  60. #define DNS6_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
  61. #define DNS6_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
  62. #define DNS6_ENTRY() DNS6_TRC(">> %s", __func__)
  63. #define DNS6_EXIT() DNS6_TRC("<< %s", __func__)
  64. #else // DNS6_CONFIG_LOG_ENABLED
  65. #define DNS6_TRC(...) /**< Disables traces. */
  66. #define DNS6_DUMP(...) /**< Disables dumping of octet streams. */
  67. #define DNS6_ERR(...) /**< Disables error logs. */
  68. #define DNS6_ENTRY(...)
  69. #define DNS6_EXIT(...)
  70. #endif // DNS6_CONFIG_LOG_ENABLED
  71. /**
  72. * @defgroup dns6_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
  73. *
  74. * @details Macros used to lock and unlock modules. Currently, SDK does not use mutexes but
  75. * framework is provided in case need arises to use an alternative architecture.
  76. * @{
  77. */
  78. #define DNS6_MUTEX_LOCK() SDK_MUTEX_LOCK(m_dns6_mutex) /**< Lock module using mutex */
  79. #define DNS6_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_dns6_mutex) /**< Unlock module using mutex */
  80. /** @} */
  81. /**
  82. * @defgroup api_param_check API Parameters check macros.
  83. *
  84. * @details Macros that verify parameters passed to the module in the APIs. These macros
  85. * could be mapped to nothing in final versions of code to save execution and size.
  86. * DNS6_DISABLE_API_PARAM_CHECK should be set to 0 to enable these checks.
  87. *
  88. * @{
  89. */
  90. #if (DNS6_DISABLE_API_PARAM_CHECK == 0)
  91. /**@brief Macro to check is module is initialized before requesting one of the module procedures. */
  92. #define VERIFY_MODULE_IS_INITIALIZED() \
  93. if (m_initialization_state == false) \
  94. { \
  95. return (SDK_ERR_MODULE_NOT_INITIALIZED | IOT_DNS6_ERR_BASE);\
  96. }
  97. /**@brief Verify NULL parameters are not passed to API by application. */
  98. #define NULL_PARAM_CHECK(PARAM) \
  99. if ((PARAM) == NULL) \
  100. { \
  101. return (NRF_ERROR_NULL | IOT_DNS6_ERR_BASE); \
  102. }
  103. /**@brief Verify that empty parameters are not passed to API by application. */
  104. #define EMPTY_PARAM_CHECK(PARAM) \
  105. if (*PARAM == 0) \
  106. { \
  107. return (NRF_ERROR_INVALID_DATA | IOT_DNS6_ERR_BASE); \
  108. }
  109. #else // DNS6_DISABLE_API_PARAM_CHECK
  110. #define VERIFY_MODULE_IS_INITIALIZED()
  111. #define NULL_PARAM_CHECK(PARAM)
  112. #define EMPTY_PARAM_CHECK(PARAM)
  113. #endif // DNS6_DISABLE_API_PARAM_CHECK
  114. /** @} */
  115. /**@brief RFC1035 - DNS Header Fields and Values. */
  116. #define DNS_HEADER_FLAG1_QR_QUERY 0x00 /**< Bit specifies that message is a query. */
  117. #define DNS_HEADER_FLAG1_QR_RESPONSE 0x80 /**< Bit specifies that message is a response. */
  118. #define DNS_HEADER_FLAG1_OPCODE_STANDARD 0x00 /**< A standard type of query. */
  119. #define DNS_HEADER_FLAG1_OPCODE_INVERSE 0x08 /**< An inverse type of query. */
  120. #define DNS_HEADER_FLAG1_OPCODE_STATUS 0x10 /**< A server status request. */
  121. #define DNS_HEADER_FLAG1_AA 0x04 /**< Bit specifies that the responding name server is an authority for the domain name in question section. */
  122. #define DNS_HEADER_FLAG1_TC 0x02 /**< Bit specifies that message is truncated. */
  123. #define DNS_HEADER_FLAG1_RD 0x01 /**< Bit specifies that recursion is desired. */
  124. #define DNS_HEADER_FLAG2_RA 0x80 /**< Bit specifies if recursive query support is available in the name server. */
  125. #define DNS_HEADER_FLAG2_RCODE_NONE 0x00 /**< No error condition. */
  126. #define DNS_HEADER_FLAG2_RCODE_FORMAT_ERROR 0x01 /**< Error indicates that dns server is unable o interpret the query. */
  127. #define DNS_HEADER_FLAG2_RCODE_SERVER_FAILURE 0x02 /**< Error indicates that dns server has internal problem. */
  128. #define DNS_HEADER_FLAG2_RCODE_NAME_ERROR 0x03 /**< Error indicates that domain name referenced in the query does not exist. */
  129. #define DNS_HEADER_FLAG2_RCODE_NOT_IMPLEMENTED 0x04 /**< Error indicates that dns server does not support previously sent query. */
  130. #define DNS_HEADER_FLAG2_RCODE_REFUSED 0x05 /**< Error indicates that dns server refuses to perform operation. */
  131. #define DNS_HEADER_FLAG2_RCODE_MASK 0x0F /**< Bit mask of RCODE field. */
  132. #define DNS_QTYPE_A 0x0001 /**< QTYPE indicates IPv4 address. */
  133. #define DNS_QTYPE_CNAME 0x0005 /**< QTYPE indicates CNAME record. */
  134. #define DNS_QTYPE_AAAA 0x001C /**< QTYPE indicates IPv6 address. */
  135. #define DNS_QCLASS_IN 0x0001 /**< QCLASS indicates Internet type. */
  136. /**@brief DNS6 client module's defines. */
  137. #define DNS_LABEL_SEPARATOR '.' /**< Separator of hostname string. */
  138. #define DNS_LABEL_OFFSET 0xc0 /**< Byte indicates that offset is used to determine hostname. */
  139. #define DNS_HEADER_SIZE 12 /**< Size of DNS Header. */
  140. #define DNS_QUESTION_FOOTER_SIZE 4 /**< Size of DNS Question footer. */
  141. #define DNS_RR_BODY_SIZE 10 /**< Size of DNS Resource Record Body. */
  142. #define MESSAGE_ID_UNUSED 0 /**< Value indicates that record is unused and no request was performed yet. */
  143. #define MESSAGE_ID_INITIAL 0x0001 /**< Initial value of message id counter. */
  144. /**@brief DNS Header Format. */
  145. typedef struct
  146. {
  147. uint16_t msg_id; /**< Query/Response message identifier. */
  148. uint8_t flags_1; /**< Flags ( QR | Opcode | AA | TC | RD ). */
  149. uint8_t flags_2; /**< Flags ( RA | Z | RCODE ). */
  150. uint16_t qdcount; /**< The number of entries in the question section. */
  151. uint16_t ancount; /**< The number of resource records in the answer section. */
  152. uint16_t nscount; /**< The number of name server resource records in the authority records section. */
  153. uint16_t arcount; /**< The number of resource records in the additional records section. */
  154. } dns_header_t;
  155. /**@brief DNS Question Footer Format. */
  156. typedef struct
  157. {
  158. uint16_t qtype; /**< Type of the query. */
  159. uint16_t qclass; /**< Class of the query. */
  160. } dns_question_footer_t;
  161. /**@brief DNS Resource AAAA Record Body Format. */
  162. typedef struct
  163. {
  164. uint16_t rtype; /**< Type of the response. */
  165. uint16_t rclass; /**< Class of the response. */
  166. uint32_t rttl; /**< Time to Life field of the response. */
  167. uint16_t rdlength; /**< Length of data in octets. */
  168. } dns_rr_body_t;
  169. /**@brief Structure holds pending query. */
  170. typedef struct
  171. {
  172. uint16_t message_id; /**< Message id for DNS Query. */
  173. uint8_t retries; /**< Number of already performed retries. */
  174. uint8_t * p_hostname; /**< Pointer to hostname string in memory menager.*/
  175. iot_timer_time_in_ms_t next_retransmission; /**< Time when next retransmission should be invoked. */
  176. dns6_evt_handler_t evt_handler; /**< User registered callback. */
  177. } pending_query_t;
  178. SDK_MUTEX_DEFINE(m_dns6_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
  179. static bool m_initialization_state = false; /**< Variable to maintain module initialization state. */
  180. static pending_query_t m_pending_queries[DNS6_MAX_PENDING_QUERIES]; /**< Queue contains pending queries. */
  181. static uint16_t m_message_id_counter; /**< Message ID counter, used to generate unique message IDs. */
  182. static udp6_socket_t m_socket; /**< Socket information provided by UDP. */
  183. /**@brief Function for freeing query entry in pending queue.
  184. *
  185. * @param[in] index Index of query.
  186. *
  187. * @retval None.
  188. */
  189. static void query_init(uint32_t index)
  190. {
  191. if (m_pending_queries[index].p_hostname)
  192. {
  193. UNUSED_VARIABLE(nrf_free(m_pending_queries[index].p_hostname));
  194. }
  195. m_pending_queries[index].message_id = MESSAGE_ID_UNUSED;
  196. m_pending_queries[index].retries = 0;
  197. m_pending_queries[index].p_hostname = NULL;
  198. m_pending_queries[index].evt_handler = NULL;
  199. m_pending_queries[index].next_retransmission = 0;
  200. }
  201. /**@brief Function for adding new query to pending queue.
  202. *
  203. * @param[in] p_hostname Pointer to hostname string.
  204. * @param[in] evt_handler User defined event to handle given query.
  205. *
  206. * @retval Index of element in pending queries' table or DNS6_MAX_PENDING_QUERIES if no memory.
  207. */
  208. static uint32_t query_add(uint8_t * p_hostname, dns6_evt_handler_t evt_handler)
  209. {
  210. uint32_t index;
  211. for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
  212. {
  213. if (m_pending_queries[index].message_id == MESSAGE_ID_UNUSED)
  214. {
  215. m_pending_queries[index].message_id = m_message_id_counter++;
  216. m_pending_queries[index].retries = 0;
  217. m_pending_queries[index].p_hostname = p_hostname;
  218. m_pending_queries[index].evt_handler = evt_handler;
  219. m_pending_queries[index].next_retransmission = 0;
  220. break;
  221. }
  222. }
  223. return index;
  224. }
  225. /**@brief Function for finding element in pending queue with specific message_id.
  226. *
  227. * @param[in] message_id Message identifier to find.
  228. *
  229. * @retval Index of element in pending queue or DNS6_MAX_PENDING_QUERIES if nothing found.
  230. */
  231. static uint32_t query_find(uint32_t message_id)
  232. {
  233. uint32_t index;
  234. for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
  235. {
  236. if (m_pending_queries[index].message_id == message_id)
  237. {
  238. break;
  239. }
  240. }
  241. return index;
  242. }
  243. /**@brief Function for checking if retransmission time of DNS query has been expired.
  244. *
  245. * @param[in] index Index of pending query.
  246. *
  247. * @retval True if timer has been expired, False otherwise.
  248. */
  249. static bool query_timer_is_expired(uint32_t index)
  250. {
  251. uint32_t err_code;
  252. iot_timer_time_in_ms_t wall_clock_value;
  253. // Get wall clock time.
  254. err_code = iot_timer_wall_clock_get(&wall_clock_value);
  255. if (err_code == NRF_SUCCESS)
  256. {
  257. if (wall_clock_value >= m_pending_queries[index].next_retransmission)
  258. {
  259. return true;
  260. }
  261. }
  262. return false;
  263. }
  264. /**@brief Function for setting retransmissions time of DNS query has been expired.
  265. *
  266. * @param[in] index Index of pending query.
  267. *
  268. * @retval None.
  269. */
  270. static void query_timer_set(uint32_t index)
  271. {
  272. uint32_t err_code;
  273. iot_timer_time_in_ms_t wall_clock_value;
  274. // Get wall clock time.
  275. err_code = iot_timer_wall_clock_get(&wall_clock_value);
  276. if (err_code == NRF_SUCCESS)
  277. {
  278. m_pending_queries[index].next_retransmission =
  279. wall_clock_value + (DNS6_RETRANSMISSION_INTERVAL * 1000);
  280. }
  281. }
  282. /**@brief Function for creating compressed hostname from string.
  283. *
  284. * @param[inout] p_dest Pointer to place where hostname will be compressed.
  285. * @param[in] p_hostname Pointer to hostname string.
  286. *
  287. * @retval Number of used bytes to compress a hostname.
  288. */
  289. static uint32_t compress_hostname(uint8_t * p_dest, const uint8_t * p_hostname)
  290. {
  291. uint32_t index = 0;
  292. uint32_t label_pos = 0;
  293. uint8_t * p_original = p_dest;
  294. // Elide first byte in destination buffer to put label.
  295. p_dest++;
  296. // Parse until string termination is found.
  297. for (index = 0; p_hostname[index] != 0; index++)
  298. {
  299. // Look for string separator.
  300. if (p_hostname[index] == DNS_LABEL_SEPARATOR)
  301. {
  302. // Put number of subsequent string to last label.
  303. p_original[label_pos] = index - label_pos;
  304. // Protection to stop compressing after getting incorrect sequence.
  305. if (index == label_pos)
  306. {
  307. return index + 1;
  308. }
  309. label_pos = index + 1;
  310. }
  311. else
  312. {
  313. // Copy character of hostname to destination buffer.
  314. *p_dest = p_hostname[index];
  315. }
  316. p_dest++;
  317. }
  318. // Set last label.
  319. p_original[label_pos] = index - label_pos;
  320. // Terminate compressed hostname with 0.
  321. *p_dest = 0;
  322. // Return length of compressed string.
  323. return index + 2;
  324. }
  325. /**@brief Function for finding end of compressed hostname.
  326. *
  327. * @param[in] p_hostname Pointer to compressed hostname string.
  328. *
  329. * @retval Pointer to the end of compressed hostname.
  330. */
  331. static uint8_t * skip_compressed_hostname(uint8_t * p_hostname)
  332. {
  333. while (*p_hostname != 0)
  334. {
  335. if ((*p_hostname & DNS_LABEL_OFFSET) == DNS_LABEL_OFFSET)
  336. {
  337. return p_hostname + 2;
  338. }
  339. else
  340. {
  341. p_hostname += *p_hostname + 1;
  342. }
  343. }
  344. return p_hostname + 1;
  345. }
  346. /**@brief Function for sending DNS query.
  347. *
  348. * @param[in] index Index of query.
  349. *
  350. * @retval NRF_SUCCESS on successful execution of procedure, else an error code indicating reason
  351. * for failure.
  352. */
  353. static uint32_t query_send(uint32_t index)
  354. {
  355. uint32_t length;
  356. uint32_t err_code;
  357. iot_pbuffer_t * p_buffer;
  358. iot_pbuffer_alloc_param_t buffer_param;
  359. buffer_param.type = UDP6_PACKET_TYPE;
  360. buffer_param.flags = PBUFFER_FLAG_DEFAULT;
  361. buffer_param.length = DNS_HEADER_SIZE + DNS_QUESTION_FOOTER_SIZE +
  362. strlen((const char *)m_pending_queries[index].p_hostname) + 2;
  363. // Allocate packet buffer.
  364. err_code = iot_pbuffer_allocate(&buffer_param, &p_buffer);
  365. if (err_code == NRF_SUCCESS)
  366. {
  367. const dns_question_footer_t question_footer =
  368. {
  369. .qtype = HTONS(DNS_QTYPE_AAAA),
  370. .qclass = HTONS(DNS_QCLASS_IN)
  371. };
  372. dns_header_t * p_dns_header = (dns_header_t *)p_buffer->p_payload;
  373. // Fill DNS header fields.
  374. p_dns_header->msg_id = HTONS(m_pending_queries[index].message_id);
  375. p_dns_header->flags_1 = DNS_HEADER_FLAG1_QR_QUERY | DNS_HEADER_FLAG1_RD;
  376. p_dns_header->flags_2 = DNS_HEADER_FLAG2_RCODE_NONE;
  377. // Send only one question.
  378. p_dns_header->qdcount = HTONS(1);
  379. p_dns_header->ancount = HTONS(0);
  380. p_dns_header->nscount = HTONS(0);
  381. p_dns_header->arcount = HTONS(0);
  382. // Start indexing from the end of the DNS header.
  383. length = DNS_HEADER_SIZE;
  384. // Compress and put hostname.
  385. length += compress_hostname(&p_buffer->p_payload[length],
  386. m_pending_queries[index].p_hostname);
  387. // Add question footer.
  388. memcpy(&p_buffer->p_payload[length], (uint8_t *)&question_footer, DNS_QUESTION_FOOTER_SIZE);
  389. length += DNS_QUESTION_FOOTER_SIZE;
  390. // Update packet buffer's data length.
  391. p_buffer->length = length;
  392. // Set retransmission timer.
  393. query_timer_set(index);
  394. // Send DNS query using UDP socket.
  395. err_code = udp6_socket_send(&m_socket, p_buffer);
  396. if (err_code != NRF_SUCCESS)
  397. {
  398. DNS6_ERR("Unable to send query on UDP socket. Reason %08lx.", err_code);
  399. // Free the allocated buffer as send procedure has failed.
  400. UNUSED_VARIABLE(iot_pbuffer_free(p_buffer, true));
  401. }
  402. }
  403. else
  404. {
  405. DNS6_ERR("No memory to allocate packet buffer.");
  406. }
  407. return err_code;
  408. }
  409. /**@brief Function for notifying application of the DNS6 query status.
  410. *
  411. * @param[in] index Index of query.
  412. * @param[in] process_result Variable indicates result of DNS query.
  413. * @param[in] p_addr Pointer to memory that holds IPv6 addresses.
  414. * @param[in] addr_count Number of found addresses.
  415. *
  416. * @retval None.
  417. */
  418. static void app_notify(uint32_t index,
  419. uint32_t process_result,
  420. ipv6_addr_t * p_addr,
  421. uint16_t addr_count)
  422. {
  423. if (m_pending_queries[index].evt_handler)
  424. {
  425. DNS6_MUTEX_UNLOCK();
  426. // Call handler of user request.
  427. m_pending_queries[index].evt_handler(process_result,
  428. (const char *)m_pending_queries[index].p_hostname,
  429. p_addr,
  430. addr_count);
  431. DNS6_MUTEX_LOCK();
  432. }
  433. }
  434. /**@brief Callback handler to receive data on the UDP port.
  435. *
  436. * @param[in] p_socket Socket identifier.
  437. * @param[in] p_ip_header IPv6 header containing source and destination addresses.
  438. * @param[in] p_udp_header UDP header identifying local and remote endpoints.
  439. * @param[in] process_result Result of data reception, there could be possible errors like
  440. * invalid checksum etc.
  441. * @param[in] p_rx_packet Packet buffer containing the received data packet.
  442. *
  443. * @retval NRF_SUCCESS Indicates received data was handled successfully, else an an
  444. * error code indicating reason for failure..
  445. */
  446. static uint32_t server_response(const udp6_socket_t * p_socket,
  447. const ipv6_header_t * p_ip_header,
  448. const udp6_header_t * p_udp_header,
  449. uint32_t process_result,
  450. iot_pbuffer_t * p_rx_packet)
  451. {
  452. uint32_t index;
  453. uint32_t rr_index;
  454. uint32_t err_code = NRF_SUCCESS;
  455. ipv6_addr_t * p_addresses = NULL;
  456. uint16_t addr_length = 0;
  457. DNS6_MUTEX_LOCK();
  458. DNS6_ENTRY();
  459. // Check UDP process result and data length.
  460. if ((process_result != NRF_SUCCESS) || p_rx_packet->length < DNS_HEADER_SIZE)
  461. {
  462. DNS6_ERR("Received erroneous response.");
  463. err_code = (NRF_ERROR_INVALID_DATA | IOT_DNS6_ERR_BASE);
  464. }
  465. else
  466. {
  467. dns_header_t * p_dns_header = (dns_header_t *)p_rx_packet->p_payload;
  468. uint8_t * p_data = &p_rx_packet->p_payload[DNS_HEADER_SIZE];
  469. uint16_t qdcount = NTOHS(p_dns_header->qdcount);
  470. uint16_t ancount = NTOHS(p_dns_header->ancount);
  471. // Try to find a proper query for this response, else discard.
  472. index = query_find(NTOHS(p_dns_header->msg_id));
  473. if (index != DNS6_MAX_PENDING_QUERIES)
  474. {
  475. DNS6_TRC("Received response for hostname %s with %d answers.",
  476. m_pending_queries[index].p_hostname, ancount);
  477. // Check truncation error.
  478. if (p_dns_header->flags_1 & DNS_HEADER_FLAG1_TC)
  479. {
  480. err_code = DNS6_RESPONSE_TRUNCATED;
  481. }
  482. else if (!(p_dns_header->flags_1 & DNS_HEADER_FLAG1_QR_RESPONSE))
  483. {
  484. err_code = (NRF_ERROR_INVALID_DATA | IOT_DNS6_ERR_BASE);
  485. }
  486. // Check response code.
  487. else if (p_dns_header->flags_2 & DNS_HEADER_FLAG2_RCODE_MASK)
  488. {
  489. switch (p_dns_header->flags_2 & DNS_HEADER_FLAG2_RCODE_MASK)
  490. {
  491. case DNS_HEADER_FLAG2_RCODE_FORMAT_ERROR:
  492. err_code = DNS6_FORMAT_ERROR;
  493. break;
  494. case DNS_HEADER_FLAG2_RCODE_SERVER_FAILURE:
  495. err_code = DNS6_SERVER_FAILURE;
  496. break;
  497. case DNS_HEADER_FLAG2_RCODE_NAME_ERROR:
  498. err_code = DNS6_HOSTNAME_NOT_FOUND;
  499. break;
  500. case DNS_HEADER_FLAG2_RCODE_NOT_IMPLEMENTED:
  501. err_code = DNS6_NOT_IMPLEMENTED;
  502. break;
  503. case DNS_HEADER_FLAG2_RCODE_REFUSED:
  504. err_code = DNS6_REFUSED_ERROR;
  505. break;
  506. default:
  507. err_code = (NRF_ERROR_INVALID_DATA | IOT_DNS6_ERR_BASE);
  508. break;
  509. }
  510. }
  511. else if (ancount == 0)
  512. {
  513. // No answer found.
  514. err_code = DNS6_HOSTNAME_NOT_FOUND;
  515. }
  516. else
  517. {
  518. dns_rr_body_t rr;
  519. // Skip questions section.
  520. for (rr_index = 0; rr_index < qdcount; rr_index++)
  521. {
  522. p_data = skip_compressed_hostname(p_data) + DNS_QUESTION_FOOTER_SIZE;
  523. }
  524. // Addresses are moved to beginning of the packet to ensure alignment is correct.
  525. p_addresses = (ipv6_addr_t *)p_rx_packet->p_payload;
  526. // Parse responses section.
  527. for (rr_index = 0; rr_index < ancount; rr_index++)
  528. {
  529. p_data = skip_compressed_hostname(p_data);
  530. // Fill resource record structure to fit alignment.
  531. memcpy((uint8_t *)&rr, p_data, DNS_RR_BODY_SIZE);
  532. if (NTOHS(rr.rtype) == DNS_QTYPE_AAAA && NTOHS(rr.rclass) == DNS_QCLASS_IN)
  533. {
  534. if (NTOHS(rr.rdlength) == IPV6_ADDR_SIZE)
  535. {
  536. DNS6_TRC("Found AAAA record with IPv6 address:");
  537. DNS6_DUMP(p_data + DNS_RR_BODY_SIZE, IPV6_ADDR_SIZE);
  538. // Move all addresses next to each other.
  539. memmove(p_addresses[addr_length].u8,
  540. p_data + DNS_RR_BODY_SIZE,
  541. IPV6_ADDR_SIZE);
  542. addr_length++;
  543. }
  544. }
  545. p_data += DNS_RR_BODY_SIZE + NTOHS(rr.rdlength);
  546. }
  547. if (addr_length == 0)
  548. {
  549. DNS6_ERR("No IPv6 addresses was found.");
  550. err_code = DNS6_HOSTNAME_NOT_FOUND;
  551. }
  552. }
  553. // Notify application.
  554. app_notify(index, err_code, p_addresses, addr_length);
  555. // Initialize query entry.
  556. query_init(index);
  557. }
  558. else
  559. {
  560. DNS6_ERR("Response with unknown message id.");
  561. err_code = (NRF_ERROR_NOT_FOUND | IOT_DNS6_ERR_BASE);
  562. }
  563. }
  564. DNS6_EXIT();
  565. DNS6_MUTEX_UNLOCK();
  566. return err_code;
  567. }
  568. uint32_t dns6_init(const dns6_init_t * p_dns_init)
  569. {
  570. NULL_PARAM_CHECK(p_dns_init);
  571. uint32_t index;
  572. uint32_t err_code;
  573. DNS6_ENTRY();
  574. SDK_MUTEX_INIT(m_dns6_mutex);
  575. DNS6_MUTEX_LOCK();
  576. for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
  577. {
  578. query_init(index);
  579. }
  580. // Request new socket creation.
  581. err_code = udp6_socket_allocate(&m_socket);
  582. if (err_code == NRF_SUCCESS)
  583. {
  584. // Bind the socket to the local port.
  585. err_code = udp6_socket_bind(&m_socket, IPV6_ADDR_ANY, p_dns_init->local_src_port);
  586. if (err_code == NRF_SUCCESS)
  587. {
  588. // Connect to DNS server.
  589. err_code = udp6_socket_connect(&m_socket,
  590. &p_dns_init->dns_server.addr,
  591. p_dns_init->dns_server.port);
  592. if (err_code == NRF_SUCCESS)
  593. {
  594. // Register data receive callback.
  595. err_code = udp6_socket_recv(&m_socket, server_response);
  596. }
  597. }
  598. if (err_code == NRF_SUCCESS)
  599. {
  600. DNS6_TRC("Module initialization is complete.");
  601. // Set initialization state flag if all procedures succeeded.
  602. m_initialization_state = true;
  603. m_message_id_counter = 0x0001;
  604. }
  605. else
  606. {
  607. DNS6_ERR("UDP socket initialization failed. Reason %08lx.", err_code);
  608. // Not all procedures succeeded with allocated socket, hence free it.
  609. UNUSED_VARIABLE(udp6_socket_free(&m_socket));
  610. }
  611. }
  612. DNS6_EXIT();
  613. DNS6_MUTEX_UNLOCK();
  614. return err_code;
  615. }
  616. uint32_t dns6_uninit(void)
  617. {
  618. VERIFY_MODULE_IS_INITIALIZED();
  619. uint32_t index;
  620. DNS6_ENTRY();
  621. DNS6_MUTEX_LOCK();
  622. for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
  623. {
  624. query_init(index);
  625. }
  626. // Free UDP socket.
  627. UNUSED_VARIABLE(udp6_socket_free(&m_socket));
  628. // Clear initialization state flag.
  629. m_initialization_state = false;
  630. DNS6_EXIT();
  631. DNS6_MUTEX_UNLOCK();
  632. return NRF_SUCCESS;
  633. }
  634. uint32_t dns6_query(const char * p_hostname, dns6_evt_handler_t evt_handler)
  635. {
  636. VERIFY_MODULE_IS_INITIALIZED();
  637. NULL_PARAM_CHECK(evt_handler);
  638. NULL_PARAM_CHECK(p_hostname);
  639. EMPTY_PARAM_CHECK(p_hostname);
  640. uint32_t index;
  641. uint32_t err_code;
  642. uint32_t hostname_length;
  643. uint8_t * p_hostname_buff = NULL;
  644. DNS6_ENTRY();
  645. DNS6_MUTEX_LOCK();
  646. // Calculate hostname length.
  647. hostname_length = strlen(p_hostname) + 1;
  648. // Allocate memory to make copy of hostname string.
  649. err_code = nrf_mem_reserve(&p_hostname_buff, &hostname_length);
  650. if (err_code == NRF_SUCCESS)
  651. {
  652. // Copy hostname to cache buffer.
  653. strcpy((char *)p_hostname_buff, p_hostname);
  654. // Add query to pending queue.
  655. index = query_add(p_hostname_buff, evt_handler);
  656. if (index != DNS6_MAX_PENDING_QUERIES)
  657. {
  658. // Create and send DNS Query.
  659. err_code = query_send(index);
  660. if (err_code != NRF_SUCCESS)
  661. {
  662. // Remove query from pending queue immediately.
  663. query_init(index);
  664. }
  665. }
  666. else
  667. {
  668. DNS6_ERR("No place in pending queue.");
  669. // No place in pending queue.
  670. err_code = (NRF_ERROR_NO_MEM | IOT_DNS6_ERR_BASE);
  671. }
  672. // Not all procedures succeeded with sending query, hence free buffer for hostname.
  673. if (err_code != NRF_SUCCESS)
  674. {
  675. UNUSED_VARIABLE(nrf_free(p_hostname_buff));
  676. }
  677. }
  678. else
  679. {
  680. DNS6_ERR("No memory to allocate buffer for hostname.");
  681. }
  682. DNS6_EXIT();
  683. DNS6_MUTEX_UNLOCK();
  684. return err_code;
  685. }
  686. void dns6_timeout_process(iot_timer_time_in_ms_t wall_clock_value)
  687. {
  688. uint32_t index;
  689. uint32_t err_code;
  690. UNUSED_PARAMETER(wall_clock_value);
  691. DNS6_ENTRY();
  692. DNS6_MUTEX_LOCK();
  693. for (index = 0; index < DNS6_MAX_PENDING_QUERIES; index++)
  694. {
  695. if (m_pending_queries[index].message_id != MESSAGE_ID_UNUSED)
  696. {
  697. if (query_timer_is_expired(index))
  698. {
  699. err_code = NRF_SUCCESS;
  700. if (m_pending_queries[index].retries < DNS6_MAX_RETRANSMISSION_COUNT)
  701. {
  702. DNS6_TRC("Query retransmission [%d] for hostname %s.",
  703. m_pending_queries[index].retries, m_pending_queries[index].p_hostname);
  704. // Increase retransmission number.
  705. m_pending_queries[index].retries++;
  706. // Send query again.
  707. err_code = query_send(index);
  708. }
  709. else
  710. {
  711. DNS6_ERR("DNS server did not response on query for hostname %s.",
  712. m_pending_queries[index].p_hostname);
  713. // No response from server.
  714. err_code = DNS6_SERVER_UNREACHABLE;
  715. }
  716. if (err_code != NRF_SUCCESS)
  717. {
  718. // Inform application that timeout occurs.
  719. app_notify(index, err_code, NULL, 0);
  720. // Remove query from pending queue.
  721. query_init(index);
  722. }
  723. }
  724. break;
  725. }
  726. }
  727. DNS6_EXIT();
  728. DNS6_MUTEX_UNLOCK();
  729. }