io6Library
WIZnet Dual Stack TCP/IP Ethernet Controller Driver
dns.c
Go to the documentation of this file.
1 //*****************************************************************************
2 //
49 //
50 //*****************************************************************************
51 
52 #include <string.h>
53 #include <stdlib.h>
54 
55 #include "socket.h"
56 #include "dns.h"
57 
58 #ifdef _DNS_DEBUG_
59  #include <stdio.h>
60 #endif
61 
62 #define INITRTT 2000L /* Initial smoothed response time */
63 #define MAXCNAME (MAX_DOMAIN_NAME + (MAX_DOMAIN_NAME>>1)) /* Maximum amount of cname recursion */
64 
65 #define TYPE_A 1 /* Host address */
66 #define TYPE_NS 2 /* Name server */
67 #define TYPE_MD 3 /* Mail destination (obsolete) */
68 #define TYPE_MF 4 /* Mail forwarder (obsolete) */
69 #define TYPE_CNAME 5 /* Canonical name */
70 #define TYPE_SOA 6 /* Start of Authority */
71 #define TYPE_MB 7 /* Mailbox name (experimental) */
72 #define TYPE_MG 8 /* Mail group member (experimental) */
73 #define TYPE_MR 9 /* Mail rename name (experimental) */
74 #define TYPE_NULL 10 /* Null (experimental) */
75 #define TYPE_WKS 11 /* Well-known sockets */
76 #define TYPE_PTR 12 /* Pointer record */
77 #define TYPE_HINFO 13 /* Host information */
78 #define TYPE_MINFO 14 /* Mailbox information (experimental)*/
79 #define TYPE_MX 15 /* Mail exchanger */
80 #define TYPE_TXT 16 /* Text strings */
81 #define TYPE_AAAA 28
82 #define TYPE_ANY 255 /* Matches any type */
83 
84 #define CLASS_IN 1 /* The ARPA Internet */
85 
86 /* Round trip timing parameters */
87 #define AGAIN 8 /* Average RTT gain = 1/8 */
88 #define LAGAIN 3 /* Log2(AGAIN) */
89 #define DGAIN 4 /* Mean deviation gain = 1/4 */
90 #define LDGAIN 2 /* log2(DGAIN) */
91 
92 /* Header for all domain messages */
93 struct dhdr
94 {
95  uint16_t id; /* Identification */
96  uint8_t qr; /* Query/Response */
97 #define QUERY 0
98 #define RESPONSE 1
99  uint8_t opcode;
100 #define IQUERY 1
101  uint8_t aa; /* Authoratative answer */
102  uint8_t tc; /* Truncation */
103  uint8_t rd; /* Recursion desired */
104  uint8_t ra; /* Recursion available */
105  uint8_t rcode; /* Response code */
106 #define NO_ERROR 0
107 #define FORMAT_ERROR 1
108 #define SERVER_FAIL 2
109 #define NAME_ERROR 3
110 #define NOT_IMPL 4
111 #define REFUSED 5
112  uint16_t qdcount; /* Question count */
113  uint16_t ancount; /* Answer count */
114  uint16_t nscount; /* Authority (name server) count */
115  uint16_t arcount; /* Additional record count */
116 };
117 
118 
119 uint8_t* pDNSMSG; // DNS message buffer
120 uint8_t DNS_SOCKET; // SOCKET number for DNS
121 uint16_t DNS_MSGID; // DNS message ID
122 
123 uint32_t dns_1s_tick; // for timout of DNS processing
124 static uint8_t retry_count;
125 
126 /* converts uint16_t from network buffer to a host byte order integer. */
127 uint16_t get16(uint8_t * s)
128 {
129  uint16_t i;
130  i = *s++ << 8;
131  i = i + *s;
132  return i;
133 }
134 
135 /* copies uint16_t to the network buffer with network byte order. */
136 uint8_t * put16(uint8_t * s, uint16_t i)
137 {
138  *s++ = i >> 8;
139  *s++ = i;
140  return s;
141 }
142 
143 
144 /*
145  * CONVERT A DOMAIN NAME TO THE HUMAN-READABLE FORM
146  *
147  * Description : This function converts a compressed domain name to the human-readable form
148  * Arguments : msg - is a pointer to the reply message
149  * compressed - is a pointer to the domain name in reply message.
150  * buf - is a pointer to the buffer for the human-readable form name.
151  * len - is the MAX. size of buffer.
152  * Returns : the length of compressed message
153  */
154 int parse_name(uint8_t * msg, uint8_t * compressed, char * buf, int16_t len)
155 {
156  uint16_t slen; /* Length of current segment */
157  uint8_t * cp;
158  int clen = 0; /* Total length of compressed name */
159  int indirect = 0; /* Set if indirection encountered */
160  int nseg = 0; /* Total number of segments in name */
161 
162  cp = compressed;
163 
164  for (;;)
165  {
166  slen = *cp++; /* Length of this segment */
167 
168  if (!indirect) clen++;
169 
170  if ((slen & 0xc0) == 0xc0)
171  {
172  if (!indirect)
173  clen++;
174  indirect = 1;
175  /* Follow indirection */
176  cp = &msg[((slen & 0x3f)<<8) + *cp];
177  slen = *cp++;
178  }
179 
180  if (slen == 0) /* zero length == all done */
181  break;
182 
183  len -= slen + 1;
184 
185  if (len < 0) return -1;
186 
187  if (!indirect) clen += slen;
188 
189  while (slen-- != 0) *buf++ = (char)*cp++;
190  *buf++ = '.';
191  nseg++;
192  }
193 
194  if (nseg == 0)
195  {
196  /* Root name; represent as single dot */
197  *buf++ = '.';
198  len--;
199  }
200 
201  *buf++ = '\0';
202  len--;
203 
204  return clen; /* Length of compressed message */
205 }
206 
207 /*
208  * PARSE QUESTION SECTION
209  *
210  * Description : This function parses the qeustion record of the reply message.
211  * Arguments : msg - is a pointer to the reply message
212  * cp - is a pointer to the qeustion record.
213  * Returns : a pointer the to next record.
214  */
215 uint8_t * dns_question(uint8_t * msg, uint8_t * cp)
216 {
217  int len;
218  char name[MAXCNAME];
219 
220  len = parse_name(msg, cp, name, MAXCNAME);
221 
222 
223  if (len == -1) return 0;
224 
225  cp += len;
226  cp += 2; /* type */
227  cp += 2; /* class */
228 
229  return cp;
230 }
231 
232 
233 /*
234  * PARSE ANSER SECTION
235  *
236  * Description : This function parses the answer record of the reply message.
237  * Arguments : msg - is a pointer to the reply message
238  * cp - is a pointer to the answer record.
239  * Returns : a pointer the to next record.
240  */
241 uint8_t * dns_answer(uint8_t * msg, uint8_t * cp, uint8_t * ip_from_dns)
242 {
243  int len, type;
244  char name[MAXCNAME];
245 
246  len = parse_name(msg, cp, name, MAXCNAME);
247 
248  if (len == -1) return 0;
249 
250  cp += len;
251  type = get16(cp);
252  cp += 2; /* type */
253  cp += 2; /* class */
254  cp += 4; /* ttl */
255  cp += 2; /* len */
256 
257 
258  switch (type)
259  {
260  case TYPE_A:
261  /* Just read the address directly into the structure */
262  ip_from_dns[0] = *cp++;
263  ip_from_dns[1] = *cp++;
264  ip_from_dns[2] = *cp++;
265  ip_from_dns[3] = *cp++;
266  break;
267  case TYPE_AAAA:
268  ip_from_dns[0] = *cp++;
269  ip_from_dns[1] = *cp++;
270  ip_from_dns[2] = *cp++;
271  ip_from_dns[3] = *cp++;
272  ip_from_dns[4] = *cp++;
273  ip_from_dns[5] = *cp++;
274  ip_from_dns[6] = *cp++;
275  ip_from_dns[7] = *cp++;
276  ip_from_dns[8] = *cp++;
277  ip_from_dns[9] = *cp++;
278  ip_from_dns[10] = *cp++;
279  ip_from_dns[11] = *cp++;
280  ip_from_dns[12] = *cp++;
281  ip_from_dns[13] = *cp++;
282  ip_from_dns[14] = *cp++;
283  ip_from_dns[15] = *cp++;
284  break;
285  case TYPE_CNAME:
286  case TYPE_MB:
287  case TYPE_MG:
288  case TYPE_MR:
289  case TYPE_NS:
290  case TYPE_PTR:
291  /* These types all consist of a single domain name */
292  /* convert it to ascii format */
293  len = parse_name(msg, cp, name, MAXCNAME);
294  if (len == -1) return 0;
295 
296  cp += len;
297  break;
298  case TYPE_HINFO:
299  len = *cp++;
300  cp += len;
301 
302  len = *cp++;
303  cp += len;
304  break;
305  case TYPE_MX:
306  cp += 2;
307  /* Get domain name of exchanger */
308  len = parse_name(msg, cp, name, MAXCNAME);
309  if (len == -1) return 0;
310 
311  cp += len;
312  break;
313  case TYPE_SOA:
314  /* Get domain name of name server */
315  len = parse_name(msg, cp, name, MAXCNAME);
316  if (len == -1) return 0;
317 
318  cp += len;
319 
320  /* Get domain name of responsible person */
321  len = parse_name(msg, cp, name, MAXCNAME);
322  if (len == -1) return 0;
323 
324  cp += len;
325 
326  cp += 4;
327  cp += 4;
328  cp += 4;
329  cp += 4;
330  cp += 4;
331  break;
332  case TYPE_TXT:
333  /* Just stash */
334  break;
335  default:
336  /* Ignore */
337  break;
338  }
339 
340  return cp;
341 }
342 
343 /*
344  * PARSE THE DNS REPLY
345  *
346  * Description : This function parses the reply message from DNS server.
347  * Arguments : dhdr - is a pointer to the header for DNS message
348  * buf - is a pointer to the reply message.
349  * len - is the size of reply message.
350  * Returns : -1 - Domain name lenght is too big
351  * 0 - Fail (Timout or parse error)
352  * 1 - Success,
353  */
354 extern uint8_t IP_TYPE;
355 int8_t parseDNSMSG(struct dhdr * pdhdr, uint8_t * pbuf, uint8_t * ip_from_dns)
356 {
357  uint16_t tmp;
358  uint16_t i;
359  uint8_t * msg;
360  uint8_t * cp;
361 
362  msg = pbuf;
363  memset(pdhdr, 0, sizeof(*pdhdr));
364 
365  pdhdr->id = get16(&msg[0]);
366  tmp = get16(&msg[2]);
367  if (tmp & 0x8000) pdhdr->qr = 1;
368 
369  pdhdr->opcode = (tmp >> 11) & 0xf;
370 
371  if (tmp & 0x0400) pdhdr->aa = 1;
372  if (tmp & 0x0200) pdhdr->tc = 1;
373  if (tmp & 0x0100) pdhdr->rd = 1;
374  if (tmp & 0x0080) pdhdr->ra = 1;
375 
376  pdhdr->rcode = tmp & 0xf;
377  pdhdr->qdcount = get16(&msg[4]);
378  pdhdr->ancount = get16(&msg[6]);
379  pdhdr->nscount = get16(&msg[8]);
380  pdhdr->arcount = get16(&msg[10]);
381 
382 
383  /* Now parse the variable length sections */
384  cp = &msg[12];
385 
386  /* Question section */
387  for (i = 0; i < pdhdr->qdcount; i++)
388  {
389  cp = dns_question(msg, cp);
390  #ifdef _DNS_DEUBG_
391  printf("MAX_DOMAIN_NAME is too small, it should be redfine in dns.h");
392  #endif
393  if(!cp) return -1;
394  }
395 
396  /* Answer section */
397  for (i = 0; i < pdhdr->ancount; i++)
398  {
399  cp = dns_answer(msg, cp, ip_from_dns);
400  #ifdef _DNS_DEUBG_
401  printf("MAX_DOMAIN_NAME is too small, it should be redfine in dns.h");
402  #endif
403  if(!cp) return -1;
404  }
405 
406  /* Name server (authority) section */
407  for (i = 0; i < pdhdr->nscount; i++)
408  {
409  ;
410  }
411 
412  /* Additional section */
413  for (i = 0; i < pdhdr->arcount; i++)
414  {
415  ;
416  }
417 
418  if(pdhdr->rcode == 0) return 1; // No error
419  else return 0;
420 }
421 
422 
423 /*
424  * MAKE DNS QUERY MESSAGE
425  *
426  * Description : This function makes DNS query message.
427  * Arguments : op - Recursion desired
428  * name - is a pointer to the domain name.
429  * buf - is a pointer to the buffer for DNS message.
430  * len - is the MAX. size of buffer.
431  * Returns : the pointer to the DNS message.
432  */
433 int16_t dns_makequery(uint16_t op, char * name, uint8_t * buf, uint16_t len,uint8_t type)
434 {
435  uint8_t *cp;
436  char *cp1;
437  char sname[MAXCNAME];
438  char *dname;
439  uint16_t p;
440  uint16_t dlen;
441 
442  cp = buf;
443 
444  DNS_MSGID++;
445  cp = put16(cp, DNS_MSGID);
446  p = (op << 11) | 0x0100; /* Recursion desired */
447  cp = put16(cp, p);
448  cp = put16(cp, 1);
449  cp = put16(cp, 0);
450  cp = put16(cp, 0);
451  cp = put16(cp, 0);
452 
453  strcpy(sname, name);
454  dname = sname;
455  dlen = strlen(dname);
456  for (;;)
457  {
458  /* Look for next dot */
459  cp1 = strchr(dname, '.');
460 
461  if (cp1 != NULL) len = cp1 - dname; /* More to come */
462  else len = dlen; /* Last component */
463 
464  *cp++ = len; /* Write length of component */
465  if (len == 0) break;
466 
467  /* Copy component up to (but not including) dot */
468  strncpy((char *)cp, dname, len);
469  cp += len;
470  if (cp1 == NULL)
471  {
472  *cp++ = 0; /* Last one; write null and finish */
473  break;
474  }
475  dname += len+1;
476  dlen -= len+1;
477  }
478 #if 1
479  cp = put16(cp,IP_TYPE); /* type */
480 #else
481  cp = put16(cp, type); /* type */
482 #endif
483  cp = put16(cp, 0x0001); /* class */
484 
485 
486  return ((int16_t)((uint32_t)(cp) - (uint32_t)(buf)));
487 }
488 
489 /*
490  * CHECK DNS TIMEOUT
491  *
492  * Description : This function check the DNS timeout
493  * Arguments : None.
494  * Returns : -1 - timeout occurred, 0 - timer over, but no timeout, 1 - no timer over, no timeout occur
495  * Note : timeout : retry count and timer both over.
496  */
497 
498 int8_t check_DNS_timeout(void)
499 {
500 
502  {
503  dns_1s_tick = 0;
504  if(retry_count >= MAX_DNS_RETRY) {
505  retry_count = 0;
506  return -1; // timeout occurred
507  }
508  retry_count++;
509  return 0; // timer over, but no timeout
510  }
511 
512  return 1; // no timer over, no timeout occur
513 }
514 
515 
516 
517 /* DNS CLIENT INIT */
518 void DNS_init( uint8_t * buf)
519 {
520  //DNS_SOCKET = s; // SOCK_DNS
521  pDNSMSG = buf; // User's shared buffer
523 }
524 
525 /* DNS CLIENT RUN */
526 int8_t DNS_run(uint8_t s,uint8_t * dns_ip, uint8_t * name, uint8_t * ip_from_dns,uint8_t mode)
527 {
528  int8_t ret;
529  struct dhdr dhp;
530  uint8_t ip[4];
531  uint8_t addr_len;
532  uint16_t len, port;
533  int8_t ret_check_timeout;
534 
535  retry_count = 0;
536  dns_1s_tick = 0;
537 
538  // Socket open
539 
540  if(mode == AS_IPV4 ){
541  socket(s, Sn_MR_UDP4, 0, 0);
542  addr_len = 4;
543  }
544  else if(mode == AS_IPV6){
545  socket(s, Sn_MR_UDP6, 0, 0);
546  addr_len = 16;
547  }
548 
549 #ifdef _DNS_DEBUG_
550  printf("> DNS Query to DNS Server : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
551 
552 #endif
553 
554  len = dns_makequery(0, (char *)name, pDNSMSG, MAX_DNS_BUF_SIZE,mode);
555  sendto(s, pDNSMSG, len, dns_ip, IPPORT_DOMAIN,addr_len);
556 
557  while (1)
558  {
559  if ((len = getSn_RX_RSR(s)) > 0)
560  {
561  if (len > MAX_DNS_BUF_SIZE) len = MAX_DNS_BUF_SIZE;
562  len = recvfrom(s, pDNSMSG, len, ip, &port,&addr_len);
563  #ifdef _DNS_DEBUG_
564  printf("> Receive DNS message from %d.%d.%d.%d(%d). len = %d\r\n", ip[0], ip[1], ip[2], ip[3],port,len);
565  #endif
566  ret = parseDNSMSG(&dhp, pDNSMSG, ip_from_dns);
567  break;
568  }
569  // Check Timeout
570  ret_check_timeout = check_DNS_timeout();
571  if (ret_check_timeout < 0) {
572 
573 #ifdef _DNS_DEBUG_
574  printf("> DNS Server is not responding : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
575 #endif
576  return 0; // timeout occurred
577  }
578  else if (ret_check_timeout == 0) {
579 
580 #ifdef _DNS_DEBUG_
581  printf("> DNS Timeout\r\n");
582 #endif
583  sendto(s, pDNSMSG, len, dns_ip, IPPORT_DOMAIN,addr_len);
584  }
585  }
586  close(s);
587  // Return value
588  // 0 > : failed / 1 - success
589  return ret;
590 }
591 
592 
593 /* DNS TIMER HANDLER */
595 {
596  dns_1s_tick++;
597 }
dhdr::nscount
uint16_t nscount
Definition: dns.c:114
sendto
datasize_t sendto(uint8_t sn, uint8_t *buf, datasize_t len, uint8_t *addr, uint16_t port, uint8_t addrlen)
Send datagram to the peer specifed by destination IP address and port number passed as parameter.
Definition: socket.c:372
put16
uint8_t * put16(uint8_t *s, uint16_t i)
Definition: dns.c:136
dhdr::tc
uint8_t tc
Definition: dns.c:102
socket
int8_t socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag)
Open a socket.
Definition: socket.c:101
TYPE_A
#define TYPE_A
Definition: dns.c:65
dhdr::id
uint16_t id
Definition: dns.c:95
TYPE_CNAME
#define TYPE_CNAME
Definition: dns.c:69
dns_1s_tick
uint32_t dns_1s_tick
Definition: dns.c:123
dhdr::aa
uint8_t aa
Definition: dns.c:101
TYPE_PTR
#define TYPE_PTR
Definition: dns.c:76
MAX_DNS_RETRY
#define MAX_DNS_RETRY
Requery Count.
Definition: dns.h:73
dhdr::arcount
uint16_t arcount
Definition: dns.c:115
TYPE_MG
#define TYPE_MG
Definition: dns.c:72
IP_TYPE
uint8_t IP_TYPE
check_DNS_timeout
int8_t check_DNS_timeout(void)
Definition: dns.c:498
getSn_RX_RSR
datasize_t getSn_RX_RSR(uint8_t s)
dns_answer
uint8_t * dns_answer(uint8_t *msg, uint8_t *cp, uint8_t *ip_from_dns)
Definition: dns.c:241
dhdr::ra
uint8_t ra
Definition: dns.c:104
TYPE_SOA
#define TYPE_SOA
Definition: dns.c:70
dhdr::rcode
uint8_t rcode
Definition: dns.c:105
DNS_WAIT_TIME
#define DNS_WAIT_TIME
Wait response time. unit 1s.
Definition: dns.h:74
get16
uint16_t get16(uint8_t *s)
Definition: dns.c:127
MAX_DNS_BUF_SIZE
#define MAX_DNS_BUF_SIZE
maximum size of DNS buffer. *‍/
Definition: dns.h:65
TYPE_MB
#define TYPE_MB
Definition: dns.c:71
TYPE_MR
#define TYPE_MR
Definition: dns.c:73
AS_IPV4
#define AS_IPV4
Definition: Application.h:15
TYPE_TXT
#define TYPE_TXT
Definition: dns.c:80
DNS_MSG_ID
#define DNS_MSG_ID
ID for DNS message. You can be modifyed it any number.
Definition: dns.h:78
dns_question
uint8_t * dns_question(uint8_t *msg, uint8_t *cp)
Definition: dns.c:215
parseDNSMSG
int8_t parseDNSMSG(struct dhdr *pdhdr, uint8_t *pbuf, uint8_t *ip_from_dns)
Definition: dns.c:355
dns_makequery
int16_t dns_makequery(uint16_t op, char *name, uint8_t *buf, uint16_t len, uint8_t type)
Definition: dns.c:433
TYPE_MX
#define TYPE_MX
Definition: dns.c:79
AS_IPV6
#define AS_IPV6
Definition: Application.h:16
parse_name
int parse_name(uint8_t *msg, uint8_t *compressed, char *buf, int16_t len)
Definition: dns.c:154
TYPE_NS
#define TYPE_NS
Definition: dns.c:66
dhdr::rd
uint8_t rd
Definition: dns.c:103
TYPE_AAAA
#define TYPE_AAAA
Definition: dns.c:81
close
int8_t close(uint8_t sn)
Close a SOCKET.
Definition: socket.c:186
dhdr::qdcount
uint16_t qdcount
Definition: dns.c:112
DNS_SOCKET
uint8_t DNS_SOCKET
Definition: dns.c:120
IPPORT_DOMAIN
#define IPPORT_DOMAIN
DNS server port number.
Definition: dns.h:76
dhdr::opcode
uint8_t opcode
Definition: dns.c:99
DNS_init
void DNS_init(uint8_t *buf)
Definition: dns.c:518
Sn_MR_UDP6
#define Sn_MR_UDP6
IPv6 UDP mode.
Definition: w6100.h:2450
socket.h
SOCKET APIs Header File.
dhdr
Definition: dns.c:93
MAXCNAME
#define MAXCNAME
Definition: dns.c:63
DNS_time_handler
void DNS_time_handler(void)
Definition: dns.c:594
dhdr::ancount
uint16_t ancount
Definition: dns.c:113
DNS_MSGID
uint16_t DNS_MSGID
Definition: dns.c:121
dhdr::qr
uint8_t qr
Definition: dns.c:96
Sn_MR_UDP4
#define Sn_MR_UDP4
Refer to Sn_MR_UDP.
Definition: w6100.h:2404
dns.h
DNS APIs Header file.
pDNSMSG
uint8_t * pDNSMSG
Definition: dns.c:119
DNS_run
int8_t DNS_run(uint8_t s, uint8_t *dns_ip, uint8_t *name, uint8_t *ip_from_dns, uint8_t mode)
Definition: dns.c:526
TYPE_HINFO
#define TYPE_HINFO
Definition: dns.c:77
recvfrom
datasize_t recvfrom(uint8_t sn, uint8_t *buf, datasize_t len, uint8_t *addr, uint16_t *port, uint8_t *addrlen)
Receive datagram from a peer.
Definition: socket.c:441