1 
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <unistd.h>
6 #include <sys/socket.h>
7 
8 #include "linkkit/wrappers/wrappers.h"
9 #include "dns.h"
10 
11 /* dns header field */
12 #define DNS_ID_FIELD               (0x6666)
13 #define DNS_CTRL_FIELD             (0x0100)
14 #define DNS_QUESTION_COUNT_FIELD   (0x0001)
15 #define DNS_ANSWER_COUNT_FIELD     (0x0000)
16 #define DNS_AUTHORITY_COUNT_FIELD  (0x0000)
17 #define DNS_ADDITIONAL_COUNT_FIELD (0x0000)
18 
19 /* dns record section */
20 #define DNS_QTYPE_FIELD            (0x0001)
21 #define DNS_QCLASS_FIELD           (0x0001)
22 
23 /* dns server and resolve result */
24 #define DNS_SERVER_COUNT           (3)
25 
26 static char g_dns_ip_list[DNS_RESULT_COUNT][16];
27 
28 static char *g_dns_server_list[DNS_SERVER_COUNT] = { "223.5.5.5", "223.6.6.6",
29                                                      "8.8.8.8" };
30 
dns_domain_check(char * domain)31 static int dns_domain_check(char *domain)
32 {
33     uint32_t idx = 0;
34 
35     for (idx = 0; idx < strlen(domain); idx++) {
36         if (domain[idx] == '.') {
37             continue;
38         }
39         if (domain[idx] < 0x30 || domain[idx] > 0x39) {
40             return 0;
41         }
42     }
43 
44     return -1;
45 }
46 
dns_uint2str(uint8_t * input,char * output)47 static void dns_uint2str(uint8_t *input, char *output)
48 {
49     uint8_t idx = 0, i = 0, j = 0;
50     uint8_t pos = 0;
51     char temp[10] = { 0 };
52 
53     memset(output, 0, 16);
54     for (idx = 0; idx < 4; idx++) {
55         i = 0;
56         j = 0;
57         pos = input[idx];
58         memset(temp, 0, 10);
59         do {
60             temp[i++] = pos % 10 + '0';
61         } while ((pos /= 10) > 0);
62 
63         do {
64             output[--i + strlen(output)] = temp[j++];
65         } while (i > 0);
66         if (idx < 3)
67             output[strlen(output)] = '.';
68     }
69 }
70 
dns_request_message(char * domain,uint8_t buffer[1024],uint32_t * index)71 void dns_request_message(char *domain, uint8_t buffer[1024], uint32_t *index)
72 {
73     uint32_t idx = 0;
74 
75     /* identification */
76     buffer[idx++] = (DNS_ID_FIELD >> 8) & 0x00FF;
77     buffer[idx++] = (DNS_ID_FIELD) & 0x00FF;
78 
79     /* control */
80     buffer[idx++] = (DNS_CTRL_FIELD >> 8) & 0x00FF;
81     buffer[idx++] = (DNS_CTRL_FIELD) & 0x00FF;
82 
83     /* question count */
84     buffer[idx++] = (DNS_QUESTION_COUNT_FIELD >> 8) & 0x00FF;
85     buffer[idx++] = (DNS_QUESTION_COUNT_FIELD) & 0x00FF;
86 
87     /* answer count */
88     buffer[idx++] = (DNS_ANSWER_COUNT_FIELD >> 8) & 0x00FF;
89     buffer[idx++] = (DNS_ANSWER_COUNT_FIELD) & 0x00FF;
90 
91     /* authority count */
92     buffer[idx++] = (DNS_AUTHORITY_COUNT_FIELD >> 8) & 0x00FF;
93     buffer[idx++] = (DNS_AUTHORITY_COUNT_FIELD) & 0x00FF;
94 
95     /* additional count */
96     buffer[idx++] = (DNS_ADDITIONAL_COUNT_FIELD >> 8) & 0x00FF;
97     buffer[idx++] = (DNS_ADDITIONAL_COUNT_FIELD) & 0x00FF;
98 
99     /* qname */
100     {
101         uint32_t section_start = 0, qname_idx = 0;
102         do {
103             if (domain[qname_idx] == '.' || qname_idx == strlen(domain)) {
104                 buffer[idx++] = (uint32_t)(qname_idx - section_start);
105                 memcpy(&buffer[idx], &domain[section_start],
106                        (qname_idx - section_start));
107                 idx += (qname_idx - section_start);
108                 section_start = qname_idx + 1;
109             }
110 
111             if (qname_idx == strlen(domain)) {
112                 break;
113             }
114 
115             qname_idx++;
116         } while (1);
117         buffer[idx++] = 0x00;
118     }
119 
120     /* qtype */
121     buffer[idx++] = (DNS_QTYPE_FIELD >> 8) & 0x00FF;
122     buffer[idx++] = (DNS_QTYPE_FIELD) & 0x00FF;
123 
124     /* qclass */
125     buffer[idx++] = (DNS_QCLASS_FIELD >> 8) & 0x00FF;
126     buffer[idx++] = (DNS_QCLASS_FIELD) & 0x00FF;
127 
128     *index = idx;
129 }
130 
dns_response_message(uint8_t buffer[1024],uint32_t buffer_len,char * ip[DNS_RESULT_COUNT])131 int dns_response_message(uint8_t buffer[1024], uint32_t buffer_len,
132                          char *ip[DNS_RESULT_COUNT])
133 {
134     int res = 0;
135     uint32_t idx = 0, rd_len = 0, dns_count = 0;
136 
137     /* skip dns header */
138     idx += 12;
139 
140     /* skip question qname section */
141     while (buffer[idx] != 0x00) {
142         idx += buffer[idx] + 1;
143     }
144 
145     if (idx >= buffer_len) {
146         return -1;
147     }
148 
149     /* skip 0x00, question qtype and qclass section */
150     idx += 1 + 4;
151 
152     memset(g_dns_ip_list, 0, DNS_RESULT_COUNT * 16);
153 
154     while (idx < buffer_len) {
155         /* name, type, class and TTL */
156         idx += 2 + 2 + 2 + 4;
157 
158         rd_len = (buffer[idx++] << 8);
159         rd_len |= buffer[idx++];
160 
161         if (idx >= buffer_len) {
162             return -1;
163         }
164 
165         if (rd_len == 4) {
166             if (dns_count < DNS_RESULT_COUNT) {
167                 dns_uint2str(&buffer[idx], g_dns_ip_list[dns_count]);
168                 ip[dns_count] = g_dns_ip_list[dns_count];
169                 dns_count++;
170             } else {
171                 break;
172             }
173         }
174 
175         idx += rd_len;
176     }
177 
178     if (dns_count == 0) {
179         return -1;
180     }
181 
182     return 0;
183 }
184 
dns_resolve(char dns[16],char * domain,char * ip[DNS_RESULT_COUNT])185 int dns_resolve(char dns[16], char *domain, char *ip[DNS_RESULT_COUNT])
186 {
187     int res = 0, sock_fd = 0;
188     struct sockaddr_in dest;
189     uint32_t dest_len = 0;
190     uint8_t send_message[1024] = { 0 }, recv_message[1024] = { 0 };
191     uint32_t idx = 0;
192     fd_set send_recv_sets;
193     struct timeval timeselect;
194 
195     res = dns_domain_check(domain);
196     if (res < 0) {
197         if (strlen(domain) >= 16) {
198             return -1;
199         }
200         memset(g_dns_ip_list, 0, DNS_RESULT_COUNT * 16);
201         memcpy(g_dns_ip_list[0], domain, strlen(domain));
202         ip[0] = g_dns_ip_list[0];
203         return 0;
204     }
205 
206     sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
207     if (sock_fd < 0) {
208         HAL_Printf("dns socket: \r\n");
209         return -1;
210     }
211 
212     dest.sin_family = AF_INET;
213     dest.sin_port = htons(53);
214     dest.sin_addr.s_addr = inet_addr(dns);
215 
216     /* set select timeout */
217     timeselect.tv_sec = 3;
218     timeselect.tv_usec = 0;
219 
220     /* dns request message */
221     dns_request_message(domain, send_message, &idx);
222 
223     /* send to dns server */
224     FD_ZERO(&send_recv_sets);
225     FD_SET(sock_fd, &send_recv_sets);
226     res = select(sock_fd + 1, NULL, &send_recv_sets, NULL, &timeselect);
227     if (res <= 0) {
228         close(sock_fd);
229         return -1;
230     }
231     if (FD_ISSET(sock_fd, &send_recv_sets)) {
232         res = sendto(sock_fd, (void *)send_message, (size_t)idx, 0,
233                           (struct sockaddr *)&dest, sizeof(dest));
234         if (res < 0) {
235             HAL_Printf("send dns request message failed.\r\n");
236             close(sock_fd);
237             return -1;
238         }
239 
240         if (res != idx) {
241             close(sock_fd);
242             return -1;
243         }
244     }
245 
246     /* recv from dns server */
247     FD_ZERO(&send_recv_sets);
248     FD_SET(sock_fd, &send_recv_sets);
249     res = select(sock_fd + 1, &send_recv_sets, NULL, NULL, &timeselect);
250     if (res <= 0) {
251         close(sock_fd);
252         return -1;
253     }
254     if (FD_ISSET(sock_fd, &send_recv_sets)) {
255         dest_len = sizeof(dest);
256         if ((res = recvfrom(sock_fd, (void *)recv_message, 1024, 0,
257                             (struct sockaddr *)&dest, &dest_len)) < 0) {
258             HAL_Printf("send dns request message failed;\r\n");
259             close(sock_fd);
260             return -1;
261         }
262     }
263 
264     close(sock_fd);
265 
266     return dns_response_message(recv_message, res, ip);
267 }
268 
dns_getaddrinfo(char * domain,char * ip[DNS_RESULT_COUNT])269 int dns_getaddrinfo(char *domain, char *ip[DNS_RESULT_COUNT])
270 {
271     int res = 0;
272     uint8_t idx = 0;
273 
274     memset(g_dns_ip_list, 0, DNS_RESULT_COUNT * 16);
275     for (idx = 0; idx < DNS_SERVER_COUNT; idx++) {
276         HAL_Printf("[prt] dns server: %s\n", g_dns_server_list[idx]);
277         res = dns_resolve(g_dns_server_list[idx], domain, ip);
278         if (res < 0) {
279             continue;
280         }
281         return 0;
282     }
283     return -1;
284 }
285