QuakeGod
2024-11-25 9aed5d7e7b3c7bf09da712e9c272ece401a7acc9
提交 | 用户 | age
9aed5d 1 //*****************************************************************************
Q 2 //
3 //! \file dns.c
4 //! \brief DNS APIs Implement file.
5 //! \details Send DNS query & Receive DNS reponse.  \n
6 //!          It depends on stdlib.h & string.h in ansi-c library
7 //! \version 1.1.0
8 //! \date 2013/11/18
9 //! \par  Revision history
10 //!       <2013/10/21> 1st Release
11 //!       <2013/12/20> V1.1.0
12 //!         1. Remove secondary DNS server in DNS_run
13 //!            If 1st DNS_run failed, call DNS_run with 2nd DNS again
14 //!         2. DNS_timerHandler -> DNS_time_handler
15 //!         3. Remove the unused define
16 //!         4. Integrated dns.h dns.c & dns_parse.h dns_parse.c into dns.h & dns.c
17 //!       <2013/12/20> V1.1.0
18 //!
19 //! \author Eric Jung & MidnightCow
20 //! \copyright
21 //!
22 //! Copyright (c)  2013, WIZnet Co., LTD.
23 //! All rights reserved.
24 //! 
25 //! Redistribution and use in source and binary forms, with or without 
26 //! modification, are permitted provided that the following conditions 
27 //! are met: 
28 //! 
29 //!     * Redistributions of source code must retain the above copyright 
30 //! notice, this list of conditions and the following disclaimer. 
31 //!     * Redistributions in binary form must reproduce the above copyright
32 //! notice, this list of conditions and the following disclaimer in the
33 //! documentation and/or other materials provided with the distribution. 
34 //!     * Neither the name of the <ORGANIZATION> nor the names of its 
35 //! contributors may be used to endorse or promote products derived 
36 //! from this software without specific prior written permission. 
37 //! 
38 //! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
39 //! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
40 //! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 //! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
42 //! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
43 //! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
44 //! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45 //! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
46 //! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
47 //! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
48 //! THE POSSIBILITY OF SUCH DAMAGE.
49 //
50 //*****************************************************************************
51
52 #include <string.h>
53 #include <stdlib.h>
54
55 #include "Ethernet/socket.h"
56 #include "Internet/DNS/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_ANY       255    /* Matches any type */
82
83 #define    CLASS_IN       1       /* The ARPA Internet */
84
85 /* Round trip timing parameters */
86 #define    AGAIN          8     /* Average RTT gain = 1/8 */
87 #define    LAGAIN      3     /* Log2(AGAIN) */
88 #define    DGAIN       4     /* Mean deviation gain = 1/4 */
89 #define    LDGAIN      2     /* log2(DGAIN) */
90
91 /* Header for all domain messages */
92 struct dhdr
93 {
94     uint16_t id;   /* Identification */
95     uint8_t    qr;      /* Query/Response */
96 #define    QUERY    0
97 #define    RESPONSE 1
98     uint8_t    opcode;
99 #define    IQUERY   1
100     uint8_t    aa;      /* Authoratative answer */
101     uint8_t    tc;      /* Truncation */
102     uint8_t    rd;      /* Recursion desired */
103     uint8_t    ra;      /* Recursion available */
104     uint8_t    rcode;   /* Response code */
105 #define    NO_ERROR       0
106 #define    FORMAT_ERROR   1
107 #define    SERVER_FAIL    2
108 #define    NAME_ERROR     3
109 #define    NOT_IMPL       4
110 #define    REFUSED        5
111     uint16_t qdcount;    /* Question count */
112     uint16_t ancount;    /* Answer count */
113     uint16_t nscount;    /* Authority (name server) count */
114     uint16_t arcount;    /* Additional record count */
115 };
116
117
118 uint8_t* pDNSMSG;       // DNS message buffer
119 uint8_t  DNS_SOCKET;    // SOCKET number for DNS
120 uint16_t DNS_MSGID;     // DNS message ID
121
122 uint32_t dns_1s_tick;   // for timout of DNS processing
123
124 /* converts uint16_t from network buffer to a host byte order integer. */
125 uint16_t get16(uint8_t * s)
126 {
127     uint16_t i;
128     i = *s++ << 8;
129     i = i + *s;
130     return i;
131 }
132
133 /* copies uint16_t to the network buffer with network byte order. */
134 uint8_t * put16(uint8_t * s, uint16_t i)
135 {
136     *s++ = i >> 8;
137     *s++ = i;
138     return s;
139 }
140
141
142 /*
143  *              CONVERT A DOMAIN NAME TO THE HUMAN-READABLE FORM
144  *
145  * Description : This function converts a compressed domain name to the human-readable form
146  * Arguments   : msg        - is a pointer to the reply message
147  *               compressed - is a pointer to the domain name in reply message.
148  *               buf        - is a pointer to the buffer for the human-readable form name.
149  *               len        - is the MAX. size of buffer.
150  * Returns     : the length of compressed message
151  */
152 int parse_name(uint8_t * msg, uint8_t * compressed, char * buf, int16_t len)
153 {
154     uint16_t slen;        /* Length of current segment */
155     uint8_t * cp;
156     int clen = 0;        /* Total length of compressed name */
157     int indirect = 0;    /* Set if indirection encountered */
158     int nseg = 0;        /* Total number of segments in name */
159
160     cp = compressed;
161
162     for (;;)
163     {
164         slen = *cp++;    /* Length of this segment */
165
166         if (!indirect) clen++;
167
168         if ((slen & 0xc0) == 0xc0)
169         {
170             if (!indirect)
171                 clen++;
172             indirect = 1;
173             /* Follow indirection */
174             cp = &msg[((slen & 0x3f)<<8) + *cp];
175             slen = *cp++;
176         }
177
178         if (slen == 0)    /* zero length == all done */
179             break;
180
181         len -= slen + 1;
182
183         if (len < 0) return -1;
184
185         if (!indirect) clen += slen;
186
187         while (slen-- != 0) *buf++ = (char)*cp++;
188         *buf++ = '.';
189         nseg++;
190     }
191
192     if (nseg == 0)
193     {
194         /* Root name; represent as single dot */
195         *buf++ = '.';
196         len--;
197     }
198
199     *buf++ = '\0';
200     len--;
201
202     return clen;    /* Length of compressed message */
203 }
204
205 /*
206  *              PARSE QUESTION SECTION
207  *
208  * Description : This function parses the qeustion record of the reply message.
209  * Arguments   : msg - is a pointer to the reply message
210  *               cp  - is a pointer to the qeustion record.
211  * Returns     : a pointer the to next record.
212  */
213 uint8_t * dns_question(uint8_t * msg, uint8_t * cp)
214 {
215     int len;
216     char name[MAXCNAME];
217
218     len = parse_name(msg, cp, name, MAXCNAME);
219
220
221     if (len == -1) return 0;
222
223     cp += len;
224     cp += 2;        /* type */
225     cp += 2;        /* class */
226
227     return cp;
228 }
229
230
231 /*
232  *              PARSE ANSER SECTION
233  *
234  * Description : This function parses the answer record of the reply message.
235  * Arguments   : msg - is a pointer to the reply message
236  *               cp  - is a pointer to the answer record.
237  * Returns     : a pointer the to next record.
238  */
239 uint8_t * dns_answer(uint8_t * msg, uint8_t * cp, uint8_t * ip_from_dns)
240 {
241     int len, type;
242     char name[MAXCNAME];
243
244     len = parse_name(msg, cp, name, MAXCNAME);
245
246     if (len == -1) return 0;
247
248     cp += len;
249     type = get16(cp);
250     cp += 2;        /* type */
251     cp += 2;        /* class */
252     cp += 4;        /* ttl */
253     cp += 2;        /* len */
254
255
256     switch (type)
257     {
258     case TYPE_A:
259         /* Just read the address directly into the structure */
260         ip_from_dns[0] = *cp++;
261         ip_from_dns[1] = *cp++;
262         ip_from_dns[2] = *cp++;
263         ip_from_dns[3] = *cp++;
264         break;
265     case TYPE_CNAME:
266     case TYPE_MB:
267     case TYPE_MG:
268     case TYPE_MR:
269     case TYPE_NS:
270     case TYPE_PTR:
271         /* These types all consist of a single domain name */
272         /* convert it to ascii format */
273         len = parse_name(msg, cp, name, MAXCNAME);
274         if (len == -1) return 0;
275
276         cp += len;
277         break;
278     case TYPE_HINFO:
279         len = *cp++;
280         cp += len;
281
282         len = *cp++;
283         cp += len;
284         break;
285     case TYPE_MX:
286         cp += 2;
287         /* Get domain name of exchanger */
288         len = parse_name(msg, cp, name, MAXCNAME);
289         if (len == -1) return 0;
290
291         cp += len;
292         break;
293     case TYPE_SOA:
294         /* Get domain name of name server */
295         len = parse_name(msg, cp, name, MAXCNAME);
296         if (len == -1) return 0;
297
298         cp += len;
299
300         /* Get domain name of responsible person */
301         len = parse_name(msg, cp, name, MAXCNAME);
302         if (len == -1) return 0;
303
304         cp += len;
305
306         cp += 4;
307         cp += 4;
308         cp += 4;
309         cp += 4;
310         cp += 4;
311         break;
312     case TYPE_TXT:
313         /* Just stash */
314         break;
315     default:
316         /* Ignore */
317         break;
318     }
319
320     return cp;
321 }
322
323 /*
324  *              PARSE THE DNS REPLY
325  *
326  * Description : This function parses the reply message from DNS server.
327  * Arguments   : dhdr - is a pointer to the header for DNS message
328  *               buf  - is a pointer to the reply message.
329  *               len  - is the size of reply message.
330  * Returns     : -1 - Domain name lenght is too big 
331  *                0 - Fail (Timout or parse error)
332  *                1 - Success, 
333  */
334 int8_t parseDNSMSG(struct dhdr * pdhdr, uint8_t * pbuf, uint8_t * ip_from_dns)
335 {
336     uint16_t tmp;
337     uint16_t i;
338     uint8_t * msg;
339     uint8_t * cp;
340
341     msg = pbuf;
342     memset(pdhdr, 0, sizeof(pdhdr));
343
344     pdhdr->id = get16(&msg[0]);
345     tmp = get16(&msg[2]);
346     if (tmp & 0x8000) pdhdr->qr = 1;
347
348     pdhdr->opcode = (tmp >> 11) & 0xf;
349
350     if (tmp & 0x0400) pdhdr->aa = 1;
351     if (tmp & 0x0200) pdhdr->tc = 1;
352     if (tmp & 0x0100) pdhdr->rd = 1;
353     if (tmp & 0x0080) pdhdr->ra = 1;
354
355     pdhdr->rcode = tmp & 0xf;
356     pdhdr->qdcount = get16(&msg[4]);
357     pdhdr->ancount = get16(&msg[6]);
358     pdhdr->nscount = get16(&msg[8]);
359     pdhdr->arcount = get16(&msg[10]);
360
361
362     /* Now parse the variable length sections */
363     cp = &msg[12];
364
365     /* Question section */
366     for (i = 0; i < pdhdr->qdcount; i++)
367     {
368         cp = dns_question(msg, cp);
369    #ifdef _DNS_DEUBG_
370       printf("MAX_DOMAIN_NAME is too small, it should be redfine in dns.h"
371    #endif
372         if(!cp) return -1;
373     }
374
375     /* Answer section */
376     for (i = 0; i < pdhdr->ancount; i++)
377     {
378         cp = dns_answer(msg, cp, ip_from_dns);
379    #ifdef _DNS_DEUBG_
380       printf("MAX_DOMAIN_NAME is too small, it should be redfine in dns.h"
381    #endif
382         if(!cp) return -1;
383     }
384
385     /* Name server (authority) section */
386     for (i = 0; i < pdhdr->nscount; i++)
387     {
388         ;
389     }
390
391     /* Additional section */
392     for (i = 0; i < pdhdr->arcount; i++)
393     {
394         ;
395     }
396
397     if(pdhdr->rcode == 0) return 1;        // No error
398     else return 0;
399 }
400
401
402 /*
403  *              MAKE DNS QUERY MESSAGE
404  *
405  * Description : This function makes DNS query message.
406  * Arguments   : op   - Recursion desired
407  *               name - is a pointer to the domain name.
408  *               buf  - is a pointer to the buffer for DNS message.
409  *               len  - is the MAX. size of buffer.
410  * Returns     : the pointer to the DNS message.
411  */
412 int16_t dns_makequery(uint16_t op, char * name, uint8_t * buf, uint16_t len)
413 {
414     uint8_t *cp;
415     char *cp1;
416     char sname[MAXCNAME];
417     char *dname;
418     uint16_t p;
419     uint16_t dlen;
420
421     cp = buf;
422
423     DNS_MSGID++;
424     cp = put16(cp, DNS_MSGID);
425     p = (op << 11) | 0x0100;            /* Recursion desired */
426     cp = put16(cp, p);
427     cp = put16(cp, 1);
428     cp = put16(cp, 0);
429     cp = put16(cp, 0);
430     cp = put16(cp, 0);
431
432     strcpy(sname, name);
433     dname = sname;
434     dlen = strlen(dname);
435     for (;;)
436     {
437         /* Look for next dot */
438         cp1 = strchr(dname, '.');
439
440         if (cp1 != NULL) len = cp1 - dname;    /* More to come */
441         else len = dlen;            /* Last component */
442
443         *cp++ = len;                /* Write length of component */
444         if (len == 0) break;
445
446         /* Copy component up to (but not including) dot */
447         strncpy((char *)cp, dname, len);
448         cp += len;
449         if (cp1 == NULL)
450         {
451             *cp++ = 0;            /* Last one; write null and finish */
452             break;
453         }
454         dname += len+1;
455         dlen -= len+1;
456     }
457
458     cp = put16(cp, 0x0001);                /* type */
459     cp = put16(cp, 0x0001);                /* class */
460
461     return ((int16_t)((uint32_t)(cp) - (uint32_t)(buf)));
462 }
463
464 /*
465  *              CHECK DNS TIMEOUT
466  *
467  * Description : This function check the DNS timeout
468  * Arguments   : None.
469  * Returns     : -1 - timeout occurred, 0 - timer over, but no timeout, 1 - no timer over, no timeout occur
470  * Note        : timeout : retry count and timer both over.
471  */
472
473 int8_t check_DNS_timeout(void)
474 {
475     static uint8_t retry_count;
476
477     if(dns_1s_tick >= DNS_WAIT_TIME)
478     {
479         dns_1s_tick = 0;
480         if(retry_count >= MAX_DNS_RETRY) {
481             retry_count = 0;
482             return -1; // timeout occurred
483         }
484         retry_count++;
485         return 0; // timer over, but no timeout
486     }
487
488     return 1; // no timer over, no timeout occur
489 }
490
491
492
493 /* DNS CLIENT INIT */
494 void DNS_init(uint8_t s, uint8_t * buf)
495 {
496     DNS_SOCKET = s; // SOCK_DNS
497     pDNSMSG = buf; // User's shared buffer
498     DNS_MSGID = DNS_MSG_ID;
499 }
500
501 /* DNS CLIENT RUN */
502 int8_t DNS_run(uint8_t * dns_ip, uint8_t * name, uint8_t * ip_from_dns)
503 {
504     int8_t ret;
505     struct dhdr dhp;
506     uint8_t ip[4];
507     uint16_t len, port;
508     int8_t ret_check_timeout;
509    
510    // Socket open
511    socket(DNS_SOCKET, Sn_MR_UDP, 0, 0);
512
513 #ifdef _DNS_DEBUG_
514     printf("> DNS Query to DNS Server : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
515 #endif
516    
517     len = dns_makequery(0, (char *)name, pDNSMSG, MAX_DNS_BUF_SIZE);
518     sendto(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN);
519
520     while (1)
521     {
522         if ((len = getSn_RX_RSR(DNS_SOCKET)) > 0)
523         {
524             if (len > MAX_DNS_BUF_SIZE) len = MAX_DNS_BUF_SIZE;
525             len = recvfrom(DNS_SOCKET, pDNSMSG, len, ip, &port);
526       #ifdef _DNS_DEBUG_
527           printf("> Receive DNS message from %d.%d.%d.%d(%d). len = %d\r\n", ip[0], ip[1], ip[2], ip[3],port,len);
528       #endif
529          ret = parseDNSMSG(&dhp, pDNSMSG, ip_from_dns);
530             break;
531         }
532         // Check Timeout
533         ret_check_timeout = check_DNS_timeout();
534         if (ret_check_timeout < 0) {
535
536 #ifdef _DNS_DEBUG_
537             printf("> DNS Server is not responding : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
538 #endif
539             return 0; // timeout occurred
540         }
541         else if (ret_check_timeout == 0) {
542
543 #ifdef _DNS_DEBUG_
544             printf("> DNS Timeout\r\n");
545 #endif
546             sendto(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN);
547         }
548     }
549     close(DNS_SOCKET);
550     // Return value
551     // 0 > :  failed / 1 - success
552     return ret;
553 }
554
555
556 /* DNS TIMER HANDLER */
557 void DNS_time_handler(void)
558 {
559     dns_1s_tick++;
560 }
561
562
563