PageRenderTime 53ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/platform/FNET/fnet_stack/services/dns/fnet_dns.c

https://gitlab.com/fuggles/ucos
C | 448 lines | 233 code | 68 blank | 147 comment | 47 complexity | 267451c2b281c22e0a93e38a362421e9 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
  1. /**************************************************************************
  2. *
  3. * Copyright 2011-2015 by Andrey Butok. FNET Community.
  4. *
  5. ***************************************************************************
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License Version 3
  8. * or later (the "LGPL").
  9. *
  10. * As a special exception, the copyright holders of the FNET project give you
  11. * permission to link the FNET sources with independent modules to produce an
  12. * executable, regardless of the license terms of these independent modules,
  13. * and to copy and distribute the resulting executable under terms of your
  14. * choice, provided that you also meet, for each linked independent module,
  15. * the terms and conditions of the license of that module.
  16. * An independent module is a module which is not derived from or based
  17. * on this library.
  18. * If you modify the FNET sources, you may extend this exception
  19. * to your version of the FNET sources, but you are not obligated
  20. * to do so. If you do not wish to do so, delete this
  21. * exception statement from your version.
  22. *
  23. * This program is distributed in the hope that it will be useful,
  24. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * and the GNU Lesser General Public License along with this program.
  29. * If not, see <http://www.gnu.org/licenses/>.
  30. *
  31. **********************************************************************/ /*!
  32. *
  33. * @file fnet_dns.c
  34. *
  35. * @author Andrey Butok
  36. *
  37. * @brief DNS Resolver implementation.
  38. *
  39. ***************************************************************************/
  40. #include "fnet_config.h"
  41. #if FNET_CFG_DNS_RESOLVER
  42. #include "fnet_dns.h"
  43. #include "fnet_dns_prv.h"
  44. #if FNET_CFG_DEBUG_DNS
  45. #define FNET_DEBUG_DNS FNET_DEBUG
  46. #else
  47. #define FNET_DEBUG_DNS(...)
  48. #endif
  49. /************************************************************************
  50. * Definitions
  51. *************************************************************************/
  52. #define FNET_DNS_ERR_PARAMS "ERROR: Wrong input parameters."
  53. #define FNET_DNS_ERR_SOCKET_CREATION "ERROR: Socket creation error."
  54. #define FNET_DNS_ERR_SOCKET_CONNECT "ERROR: Socket Error during connect."
  55. #define FNET_DNS_ERR_SERVICE "ERROR: Service registration is failed."
  56. #define FNET_DNS_ERR_IS_INITIALIZED "ERROR: DNS is already initialized."
  57. static void fnet_dns_state_machine(void *);
  58. static unsigned int fnet_dns_add_question( char *message, unsigned short type, char *host_name);
  59. /************************************************************************
  60. * DNS-client interface structure.
  61. *************************************************************************/
  62. typedef struct
  63. {
  64. SOCKET socket_cln;
  65. fnet_poll_desc_t service_descriptor;
  66. fnet_dns_state_t state; /* Current state. */
  67. fnet_dns_handler_resolved_t handler; /* Callback function. */
  68. long handler_cookie; /* Callback-handler specific parameter. */
  69. unsigned long last_time; /* Last receive time, used for timeout detection. */
  70. unsigned int iteration; /* Current iteration number.*/
  71. /* Internal buffer used for Message buffer and Resolved addresses.*/
  72. union{
  73. char message[FNET_DNS_MESSAGE_SIZE]; /* Message buffer and Resolved addresses.*/
  74. fnet_ip4_addr_t resolved_ip4_addr[FNET_DNS_MESSAGE_SIZE/sizeof(fnet_ip4_addr_t)]; /* Resolved IPv4 addresses.*/
  75. fnet_ip6_addr_t resolved_ip6_addr[FNET_DNS_MESSAGE_SIZE/sizeof(fnet_ip6_addr_t)]; /* Resolved IPv6 addresses.*/
  76. };
  77. int addr_number;
  78. unsigned long message_size; /* Size of the message.*/
  79. unsigned short id;
  80. unsigned short dns_type; /* DNS Resource Record type that is queried.*/
  81. fnet_address_family_t addr_family;
  82. }
  83. fnet_dns_if_t;
  84. /* DNS-client interface */
  85. static fnet_dns_if_t fnet_dns_if;
  86. /************************************************************************
  87. * NAME: fnet_dns_init
  88. *
  89. * DESCRIPTION: Initializes DNS client service and starts the host
  90. * name reolving.
  91. ************************************************************************/
  92. static unsigned int fnet_dns_add_question( char *message, unsigned short type, char *host_name)
  93. {
  94. unsigned int total_length = 0U;
  95. unsigned int label_length;
  96. fnet_dns_q_tail_t *q_tail;
  97. char *strtok_pos = FNET_NULL;
  98. /* Set Question section :
  99. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  100. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  101. | |
  102. / QNAME /
  103. / /
  104. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  105. | QTYPE |
  106. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  107. | QCLASS |
  108. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  109. */
  110. /* QNAME */
  111. /* a domain name represented as a sequence of labels, where
  112. * each label consists of a length octet followed by that
  113. * number of octets. The domain name terminates with the
  114. * zero length octet for the null label of the root. Note
  115. * that this field may be an odd number of octets; no
  116. * padding is used.
  117. */
  118. /* Copy host_name string.*/
  119. fnet_strcpy(&message[1], host_name);
  120. /* TBD PFI, use strtok_pos as pointer.*/
  121. /* Replace '.' by zero.*/
  122. fnet_strtok_r(&message[1], ".", &strtok_pos);
  123. while((label_length = fnet_strlen(&message[total_length]+1U)) > 0U)
  124. {
  125. message[total_length] = (char)label_length; /* Set length before (previous) label.*/
  126. total_length += label_length + 1U;
  127. fnet_strtok_r(FNET_NULL,".", &strtok_pos);
  128. }
  129. q_tail = (fnet_dns_q_tail_t *)&message[total_length];
  130. /* Skip 1 byte (zero). End of string. */
  131. /* QTYPE */
  132. q_tail->qtype = type;
  133. /* QCLASS */
  134. q_tail->qclass = FNET_HTONS(FNET_DNS_HEADER_CLASS_IN);
  135. return (total_length+ sizeof(fnet_dns_q_tail_t));
  136. }
  137. /************************************************************************
  138. * NAME: fnet_dns_init
  139. *
  140. * DESCRIPTION: Initializes DNS client service and starts the host
  141. * name resolving.
  142. ************************************************************************/
  143. int fnet_dns_init( struct fnet_dns_params *params )
  144. {
  145. const unsigned long bufsize_option = FNET_DNS_MESSAGE_SIZE;
  146. unsigned int total_length;
  147. unsigned long host_name_length;
  148. struct sockaddr remote_addr;
  149. fnet_dns_header_t *header;
  150. /* Check input parameters. */
  151. if((params == 0)
  152. || (params->dns_server_addr.sa_family == AF_UNSPEC)
  153. || fnet_socket_addr_is_unspecified(&params->dns_server_addr)
  154. || (params->handler == 0)
  155. /* Check length of host_name.*/
  156. || ((host_name_length = fnet_strlen(params->host_name)) == 0U) || (host_name_length >= FNET_DNS_MAME_SIZE))
  157. {
  158. FNET_DEBUG_DNS(FNET_DNS_ERR_PARAMS);
  159. goto ERROR;
  160. }
  161. /* Check if DNS service is free.*/
  162. if(fnet_dns_if.state != FNET_DNS_STATE_DISABLED)
  163. {
  164. FNET_DEBUG_DNS(FNET_DNS_ERR_IS_INITIALIZED);
  165. goto ERROR;
  166. }
  167. /* Save input parmeters.*/
  168. fnet_dns_if.handler = params->handler;
  169. fnet_dns_if.handler_cookie = params->cookie;
  170. fnet_dns_if.addr_family = params->addr_family;
  171. fnet_dns_if.addr_number = 0;
  172. if(params->addr_family == AF_INET)
  173. {
  174. fnet_dns_if.dns_type = FNET_HTONS(FNET_DNS_TYPE_A);
  175. }
  176. else
  177. if(params->addr_family == AF_INET6)
  178. {
  179. fnet_dns_if.dns_type = FNET_HTONS(FNET_DNS_TYPE_AAAA);
  180. }
  181. else
  182. {
  183. FNET_DEBUG_DNS(FNET_DNS_ERR_PARAMS);
  184. goto ERROR;
  185. }
  186. fnet_dns_if.iteration = 0U; /* Reset iteration counter.*/
  187. fnet_dns_if.id++; /* Change query ID.*/
  188. /* Create socket */
  189. if((fnet_dns_if.socket_cln = socket(params->dns_server_addr.sa_family, SOCK_DGRAM, 0)) == SOCKET_INVALID)
  190. {
  191. FNET_DEBUG_DNS(FNET_DNS_ERR_SOCKET_CREATION);
  192. goto ERROR;
  193. }
  194. /* Set socket options */
  195. setsockopt(fnet_dns_if.socket_cln, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize_option, sizeof(bufsize_option));
  196. setsockopt(fnet_dns_if.socket_cln, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize_option, sizeof(bufsize_option));
  197. /* Bind/connect to the server.*/
  198. FNET_DEBUG_DNS("Connecting to DNS Server.");
  199. fnet_memset_zero(&remote_addr, sizeof(remote_addr));
  200. remote_addr = params->dns_server_addr;
  201. if(remote_addr.sa_port == 0U)
  202. {
  203. remote_addr.sa_port = FNET_CFG_DNS_PORT;
  204. }
  205. if(connect(fnet_dns_if.socket_cln, &remote_addr, sizeof(remote_addr))== FNET_ERR)
  206. {
  207. FNET_DEBUG_DNS(FNET_DNS_ERR_SOCKET_CONNECT);
  208. goto ERROR_1;
  209. }
  210. /* ==== Build message. ==== */
  211. fnet_memset_zero(fnet_dns_if.message, sizeof(fnet_dns_if.message)); /* Clear buffer.*/
  212. /* Set header fields:
  213. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  214. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  215. | ID |
  216. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  217. |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
  218. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  219. | QDCOUNT |
  220. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  221. | ANCOUNT |
  222. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  223. | NSCOUNT |
  224. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  225. | ARCOUNT |
  226. +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  227. */
  228. header = (fnet_dns_header_t *)fnet_dns_if.message;
  229. header->id = fnet_dns_if.id; /* Set ID. */
  230. header->flags = FNET_HTONS(FNET_DNS_HEADER_FLAGS_RD); /* Recursion Desired.*/
  231. header->qdcount = FNET_HTONS(1U); /* One Question. */
  232. /* No Answer (ANCOUNT).*/ /* No Authority (NSCOUNT). */ /* No Additional (ARCOUNT). */
  233. total_length = sizeof(fnet_dns_header_t);
  234. total_length += fnet_dns_add_question( &fnet_dns_if.message[total_length], fnet_dns_if.dns_type, params->host_name);
  235. fnet_dns_if.message_size = (unsigned long)(total_length);
  236. /* Register DNS service. */
  237. fnet_dns_if.service_descriptor = fnet_poll_service_register(fnet_dns_state_machine, (void *) &fnet_dns_if);
  238. if(fnet_dns_if.service_descriptor == (fnet_poll_desc_t)FNET_ERR)
  239. {
  240. FNET_DEBUG_DNS(FNET_DNS_ERR_SERVICE);
  241. goto ERROR_1;
  242. }
  243. fnet_dns_if.state = FNET_DNS_STATE_TX; /* => Send request. */
  244. return FNET_OK;
  245. ERROR_1:
  246. closesocket(fnet_dns_if.socket_cln);
  247. ERROR:
  248. return FNET_ERR;
  249. }
  250. /************************************************************************
  251. * NAME: fnet_dns_state_machine
  252. *
  253. * DESCRIPTION: DNS-client state machine.
  254. ************************************************************************/
  255. static void fnet_dns_state_machine( void *fnet_dns_if_p )
  256. {
  257. int sent_size;
  258. int received;
  259. unsigned int i;
  260. fnet_dns_header_t *header;
  261. fnet_dns_rr_header_t *rr_header;
  262. fnet_dns_if_t *dns_if = (fnet_dns_if_t *)fnet_dns_if_p;
  263. switch(dns_if->state)
  264. {
  265. /*---- TX --------------------------------------------*/
  266. case FNET_DNS_STATE_TX:
  267. FNET_DEBUG_DNS("Sending query...");
  268. sent_size = send(dns_if->socket_cln, dns_if->message, dns_if->message_size, 0U);
  269. if (sent_size != (int)dns_if->message_size)
  270. {
  271. dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */
  272. }
  273. else
  274. {
  275. dns_if->last_time = fnet_timer_ticks();
  276. dns_if->state = FNET_DNS_STATE_RX;
  277. }
  278. break;
  279. /*---- RX -----------------------------------------------*/
  280. case FNET_DNS_STATE_RX:
  281. /* Receive data */
  282. received = recv(dns_if->socket_cln, dns_if->message, sizeof(dns_if->message), 0U);
  283. if(received > 0 )
  284. {
  285. header = (fnet_dns_header_t *)fnet_dns_if.message;
  286. if((header->id == dns_if->id) && /* Check the ID.*/
  287. (header->flags & FNET_DNS_HEADER_FLAGS_QR)) /* Is response.*/
  288. {
  289. for (i=(sizeof(fnet_dns_header_t)-1U); i < (unsigned int)received; i++)
  290. {
  291. /* [RFC1035 4.1.4.] In order to reduce the size of messages, the domain system utilizes a
  292. * compression scheme which eliminates the repetition of domain names in a
  293. * message. In this scheme, an entire domain name or a list of labels at
  294. * the end of a domain name is replaced with a pointer to a prior occurance
  295. * of the same name.
  296. * The pointer takes the form of a two octet sequence:
  297. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  298. * | 1 1| OFFSET |
  299. * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  300. */
  301. /* => Check for 0xC0. */
  302. if ((unsigned char)dns_if->message[i] == FNET_DNS_NAME_COMPRESSED_MASK) /* look for the beginnig of the response (Question Name == 192 (label compression))*/
  303. {
  304. rr_header = (fnet_dns_rr_header_t *)&dns_if->message[i];
  305. /* Check Question Type, Class and Resource Data Length. */
  306. if ( (rr_header->type == dns_if->dns_type) &&
  307. (rr_header->rr_class == FNET_HTONS(FNET_DNS_HEADER_CLASS_IN)))
  308. {
  309. /* Resolved.*/
  310. if(rr_header->type == FNET_HTONS(FNET_DNS_TYPE_A))
  311. {
  312. dns_if->resolved_ip4_addr[dns_if->addr_number] = *((fnet_ip4_addr_t*)(&rr_header->rdata));
  313. }
  314. else /* AF_INET6 */
  315. {
  316. FNET_IP6_ADDR_COPY( (fnet_ip6_addr_t*)(&rr_header->rdata), &dns_if->resolved_ip6_addr[dns_if->addr_number] );
  317. }
  318. dns_if->addr_number++;
  319. }
  320. i+=(unsigned int)(sizeof(fnet_dns_rr_header_t)+fnet_ntohs(rr_header->rdlength)-4U-1U);
  321. }
  322. }
  323. }
  324. /* else = wrong message.*/
  325. dns_if->state = FNET_DNS_STATE_RELEASE;
  326. }
  327. else if(received == SOCKET_ERROR) /* Check error.*/
  328. {
  329. dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */
  330. }
  331. else /* No data. Check timeout */
  332. if(fnet_timer_get_interval(dns_if->last_time, fnet_timer_ticks()) > ((FNET_CFG_DNS_RETRANSMISSION_TIMEOUT*1000U)/FNET_TIMER_PERIOD_MS))
  333. {
  334. dns_if->iteration++;
  335. if(dns_if->iteration > FNET_CFG_DNS_RETRANSMISSION_MAX)
  336. {
  337. dns_if->state = FNET_DNS_STATE_RELEASE; /* ERROR */
  338. }
  339. else
  340. {
  341. dns_if->state = FNET_DNS_STATE_TX;
  342. }
  343. }
  344. break;
  345. /*---- RELEASE -------------------------------------------------*/
  346. case FNET_DNS_STATE_RELEASE:
  347. fnet_dns_release();
  348. dns_if->handler( dns_if->addr_family, dns_if->addr_number ? dns_if->message : FNET_NULL, dns_if->addr_number, dns_if->handler_cookie); /* User Callback.*/
  349. break;
  350. default:
  351. break;
  352. }
  353. }
  354. /************************************************************************
  355. * NAME: fnet_dns_release
  356. *
  357. * DESCRIPTION: This function aborts the resolving and releases
  358. * the DNS-client service.
  359. ************************************************************************/
  360. void fnet_dns_release( void )
  361. {
  362. if(fnet_dns_if.state != FNET_DNS_STATE_DISABLED)
  363. {
  364. /* Close socket. */
  365. closesocket(fnet_dns_if.socket_cln);
  366. /* Unregister the tftp service. */
  367. fnet_poll_service_unregister( fnet_dns_if.service_descriptor );
  368. fnet_dns_if.state = FNET_DNS_STATE_DISABLED;
  369. }
  370. }
  371. /************************************************************************
  372. * NAME: fnet_dns_state
  373. *
  374. * DESCRIPTION: This function returns a current state of the DNS client.
  375. ************************************************************************/
  376. fnet_dns_state_t fnet_dns_state( void )
  377. {
  378. return fnet_dns_if.state;
  379. }
  380. #endif /* FNET_CFG_DNS_RESOLVER */