418767a83aee84a5efa23b7433d911378779d5f9
[platform/upstream/connman.git] / tools / dnsproxy-test.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2013  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <arpa/inet.h>
31 #include <netinet/in.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netdb.h>
35 #include <resolv.h>
36 #include <glib.h>
37 #include <fcntl.h>
38
39 #if 0
40 #define DEBUG
41 #endif
42 #ifdef DEBUG
43 #include <stdio.h>
44
45 #define LOG(fmt, arg...) do { \
46         fprintf(stdout, "%s:%s() " fmt "\n",   \
47                         __FILE__, __func__ , ## arg); \
48 } while (0)
49 #else
50 #define LOG(fmt, arg...)
51 #endif
52
53 static unsigned char msg[] = {
54         0x00, 0x1c, /* len 28 */
55         0x31, 0x82, /* tran id */
56         0x01, 0x00, /* flags (recursion required) */
57         0x00, 0x01, /* questions (1) */
58         0x00, 0x00, /* answer rr */
59         0x00, 0x00, /* authority rr */
60         0x00, 0x00, /* additional rr */
61         0x06, 0x6c, 0x6f, 0x6c, 0x67, 0x65, 0x30, /* lolge0, just some name */
62         0x03, 0x63, 0x6f, 0x6d, /* com */
63         0x00,       /* null terminator */
64         0x00, 0x01, /* type A */
65         0x00, 0x01, /* class IN */
66 };
67
68 static unsigned char msg2[] = {
69         0x00, 0x1c, /* len 28 */
70         0x31, 0x83, /* tran id */
71         0x01, 0x00, /* flags (recursion required) */
72         0x00, 0x01, /* questions (1) */
73         0x00, 0x00, /* answer rr */
74         0x00, 0x00, /* authority rr */
75         0x00, 0x00, /* additional rr */
76         0x06, 0x6c, 0x6f, 0x67, 0x6c, 0x67, 0x65, /* loelge */
77         0x03, 0x63, 0x6f, 0x6d, /* com */
78         0x00,       /* null terminator */
79         0x00, 0x01, /* type A */
80         0x00, 0x01, /* class IN */
81
82         0x00, 0x1c, /* len 28 */
83         0x31, 0x84, /* tran id */
84         0x01, 0x00, /* flags (recursion required) */
85         0x00, 0x01, /* questions (1) */
86         0x00, 0x00, /* answer rr */
87         0x00, 0x00, /* authority rr */
88         0x00, 0x00, /* additional rr */
89         0x06, 0x6c, 0x6f, 0x67, 0x6c, 0x67, 0x65, /* loelge */
90         0x03, 0x6e, 0x65, 0x74, /* net */
91         0x00,       /* null terminator */
92         0x00, 0x01, /* type A */
93         0x00, 0x01, /* class IN */
94 };
95
96 static unsigned char msg_invalid[] = {
97         0x00, 0x1c, /* len 28 */
98         0x31, 0xC0, /* tran id */
99 };
100
101 static int create_tcp_socket(int family)
102 {
103         int sk, err;
104
105         sk = socket(family, SOCK_STREAM, IPPROTO_TCP);
106         if (sk < 0) {
107                 err = errno;
108                 LOG("Failed to create TCP socket %d/%s", err, strerror(err));
109                 return -err;
110         }
111
112         return sk;
113 }
114
115 static int create_udp_socket(int family)
116 {
117         int sk, err;
118
119         sk = socket(family, SOCK_DGRAM, IPPROTO_UDP);
120         if (sk < 0) {
121                 err = errno;
122                 LOG("Failed to create UDP socket %d/%s", err, strerror(err));
123                 return -err;
124         }
125
126         return sk;
127 }
128
129 static int connect_tcp_socket(char *server)
130 {
131         int sk;
132         int err = 0;
133
134         struct addrinfo hints, *rp;
135
136         memset(&hints, 0, sizeof(hints));
137
138         hints.ai_socktype = SOCK_STREAM;
139         hints.ai_family = AF_UNSPEC;
140         hints.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST;
141         getaddrinfo(server, "53", &hints, &rp);
142
143         sk = create_tcp_socket(rp->ai_family);
144         err = sk;
145
146         LOG("sk %d family %d", sk, rp->ai_family);
147
148         if (sk >= 0 && connect(sk, rp->ai_addr, rp->ai_addrlen) < 0) {
149                 err = -errno;
150                 fprintf(stderr, "Failed to connect to DNS server at %s "
151                                 "errno %d/%s\n",
152                         server, -err, strerror(-err));
153         }
154
155         if (sk >= 0)
156                 fcntl(sk, F_SETFL, O_NONBLOCK);
157
158         freeaddrinfo(rp);
159
160         return err;
161 }
162
163 static int send_msg(int sk, unsigned char *msg, unsigned int len,
164                 int sleep_between)
165 {
166         unsigned int i;
167         int err;
168
169         for (i = 0; i < len; i++) {
170                 err = write(sk, &msg[i], 1);
171                 if (err < 0) {
172                         err = -errno;
173                         LOG("write failed errno %d/%s", -err, strerror(-err));
174                 }
175
176                 g_assert_cmpint(err, >=, 0);
177                 if (err < 0)
178                         return err;
179
180                 if (sleep_between)
181                         usleep(1000);
182         }
183
184         return 0;
185 }
186
187 static int connect_udp_socket(char *server, struct sockaddr *sa,
188                                                         socklen_t *sa_len)
189 {
190         int sk;
191         int err = 0;
192
193         struct addrinfo hints, *rp;
194
195         memset(&hints, 0, sizeof(hints));
196
197         hints.ai_socktype = SOCK_DGRAM;
198         hints.ai_family = AF_UNSPEC;
199         hints.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST;
200         getaddrinfo(server, "53", &hints, &rp);
201
202         sk = create_udp_socket(rp->ai_family);
203         err = sk;
204
205         LOG("sk %d family %d", sk, rp->ai_family);
206
207         if (sk < 0) {
208                 err = -errno;
209                 fprintf(stderr, "Failed to connect to DNS server at %s "
210                                 "errno %d/%s\n",
211                         server, -err, strerror(-err));
212         } else {
213                 memcpy(sa, rp->ai_addr, *sa_len);
214                 *sa_len = rp->ai_addrlen;
215         }
216
217         freeaddrinfo(rp);
218
219         return err;
220 }
221
222 static int sendto_msg(int sk, struct sockaddr *sa, socklen_t salen,
223                 unsigned char *msg, unsigned int len)
224 {
225         int err;
226
227         err = sendto(sk, msg, len, MSG_NOSIGNAL, sa, salen);
228         if (err < 0) {
229                 err = -errno;
230                 LOG("sendto failed errno %d/%s", -err, strerror(-err));
231         }
232
233         g_assert_cmpint(err, >=, 0);
234         if (err < 0)
235                 return err;
236
237         return 0;
238 }
239
240 static unsigned short get_id()
241 {
242         return random();
243 }
244
245 static void change_msg(unsigned char *msg, unsigned int tranid,
246                 unsigned int host_loc, unsigned char host_count)
247 {
248         unsigned short id = get_id();
249
250         msg[tranid] = id >> 8;
251         msg[tranid+1] = id;
252         msg[host_loc] = host_count;
253 }
254
255 static void change_msg2(unsigned char *msg, unsigned char host_count)
256 {
257         change_msg(msg, 2, 20, host_count);
258         change_msg(msg, 32, 50, host_count+1);
259 }
260
261 static int receive_message(int sk, int timeout, int expected, int *server_closed)
262 {
263         int ret, received = 0;
264         unsigned char buf[512];
265
266         while (timeout > 0) {
267                 ret = read(sk, buf, sizeof(buf));
268                 if (ret > 0) {
269                         LOG("received %d bytes from server %d", ret, sk);
270                         received += ret;
271                         if (received >= expected)
272                                 break;
273                 } else if (ret == 0) {
274                         LOG("server %d closed socket", sk);
275                         if (server_closed)
276                                 *server_closed = 1;
277                         break;
278                 } else {
279                         if (errno != EAGAIN && errno != EWOULDBLOCK)
280                                 break;
281                 }
282
283                 sleep(1);
284                 timeout--;
285         }
286
287         return received;
288 }
289
290 static int receive_from_message(int sk, struct sockaddr *sa, socklen_t len,
291                                 int timeout, int expected)
292 {
293         int ret, received = 0;
294         unsigned char buf[512];
295
296         fcntl(sk, F_SETFL, O_NONBLOCK);
297
298         while (timeout > 0) {
299                 ret = recvfrom(sk, buf, sizeof(buf), 0, sa, &len);
300                 if (ret > 0) {
301                         LOG("received %d bytes from server %d", ret, sk);
302                         received += ret;
303                         if (received >= expected)
304                                 break;
305                 } else if (ret < 0) {
306                         if (errno != EAGAIN && errno != EWOULDBLOCK)
307                                 break;
308                 }
309
310                 sleep(1);
311                 timeout--;
312         }
313
314         return received;
315 }
316
317 static void test_ipv4_udp_msg(void)
318 {
319         int sk, received = 0;
320         struct sockaddr_in sa;
321         socklen_t len = sizeof(sa);
322
323         sk = connect_udp_socket("127.0.0.1", (struct sockaddr *)&sa, &len);
324         g_assert_cmpint(sk, >=, 0);
325         change_msg(msg, 2, 20, '1');
326         sendto_msg(sk, (struct sockaddr *)&sa, len, msg, sizeof(msg));
327         received = receive_from_message(sk, (struct sockaddr *)&sa, len,
328                                         10, sizeof(msg));
329         close(sk);
330
331         g_assert_cmpint(received, >=, sizeof(msg));
332 }
333
334 static void test_ipv6_udp_msg(void)
335 {
336         int sk, received = 0;
337         struct sockaddr_in6 sa;
338         socklen_t len = sizeof(sa);
339
340         sk = connect_udp_socket("::1", (struct sockaddr *)&sa, &len);
341         g_assert_cmpint(sk, >=, 0);
342         change_msg(msg, 2, 20, '1');
343         sendto_msg(sk, (struct sockaddr *)&sa, len, msg, sizeof(msg));
344         received = receive_from_message(sk, (struct sockaddr *)&sa, len,
345                                         10, sizeof(msg));
346         close(sk);
347
348         g_assert_cmpint(received, >=, sizeof(msg));
349 }
350
351 static void test_partial_ipv4_tcp_msg(void)
352 {
353         int sk, received = 0;
354
355         sk = connect_tcp_socket("127.0.0.1");
356         g_assert_cmpint(sk, >=, 0);
357         change_msg(msg, 2, 20, '1');
358         send_msg(sk, msg, sizeof(msg), 1);
359         received = receive_message(sk, 10, sizeof(msg), NULL);
360         close(sk);
361
362         g_assert_cmpint(received, >=, sizeof(msg));
363 }
364
365 static void test_partial_ipv6_tcp_msg(void)
366 {
367         int sk, received = 0;
368
369         sk = connect_tcp_socket("::1");
370         g_assert_cmpint(sk, >=, 0);
371         change_msg(msg, 2, 20, '2');
372         send_msg(sk, msg, sizeof(msg), 1);
373         received = receive_message(sk, 10, sizeof(msg), NULL);
374         close(sk);
375
376         g_assert_cmpint(received, >=, sizeof(msg));
377 }
378
379 static void test_multiple_ipv4_tcp_msg(void)
380 {
381         int sk, received = 0, server_closed = 0;
382
383         sk = connect_tcp_socket("127.0.0.1");
384         g_assert_cmpint(sk, >=, 0);
385         change_msg2(msg2, '1');
386         send_msg(sk, msg2, sizeof(msg2), 0);
387         received = receive_message(sk, 35, sizeof(msg2), &server_closed);
388         close(sk);
389
390         /* If the final DNS server refuses to serve us, then do not consider
391          * it an error. This happens very often with unbound.
392          */
393         if (server_closed == 0)
394                 g_assert_cmpint(received, >=, sizeof(msg2));
395 }
396
397 static void test_multiple_ipv6_tcp_msg(void)
398 {
399         int sk, received = 0, server_closed = 0;
400
401         sk = connect_tcp_socket("::1");
402         g_assert_cmpint(sk, >=, 0);
403         change_msg2(msg2, '2');
404         send_msg(sk, msg2, sizeof(msg2), 0);
405         received = receive_message(sk, 35, sizeof(msg2), &server_closed);
406         close(sk);
407
408         if (server_closed == 0)
409                 g_assert_cmpint(received, >=, sizeof(msg2));
410 }
411
412 static void test_failure_tcp_msg(void)
413 {
414         int sk, received = 0;
415
416         sk = connect_tcp_socket("127.0.0.1");
417         g_assert_cmpint(sk, >=, 0);
418         send_msg(sk, msg_invalid, sizeof(msg_invalid), 0);
419         received = receive_message(sk, 10, 0, NULL);
420         close(sk);
421
422         g_assert_cmpint(received, ==, 0);
423 }
424
425 int main(int argc, char *argv[])
426 {
427         g_test_init(&argc, &argv, NULL);
428
429         g_test_add_func("/dnsproxy/ipv4 udp msg",
430                         test_ipv4_udp_msg);
431
432         g_test_add_func("/dnsproxy/ipv6 udp msg",
433                         test_ipv6_udp_msg);
434
435         g_test_add_func("/dnsproxy/failure tcp msg ",
436                         test_failure_tcp_msg);
437
438         g_test_add_func("/dnsproxy/partial ipv4 tcp msg",
439                         test_partial_ipv4_tcp_msg);
440
441         g_test_add_func("/dnsproxy/partial ipv6 tcp msg",
442                         test_partial_ipv6_tcp_msg);
443
444         g_test_add_func("/dnsproxy/partial ipv4 tcp msg from cache",
445                         test_partial_ipv4_tcp_msg);
446
447         g_test_add_func("/dnsproxy/partial ipv6 tcp msg from cache",
448                         test_partial_ipv6_tcp_msg);
449
450         g_test_add_func("/dnsproxy/multiple ipv4 tcp msg",
451                         test_multiple_ipv4_tcp_msg);
452
453         g_test_add_func("/dnsproxy/multiple ipv6 tcp msg",
454                         test_multiple_ipv6_tcp_msg);
455
456         g_test_add_func("/dnsproxy/multiple ipv4 tcp msg from cache",
457                         test_multiple_ipv4_tcp_msg);
458
459         g_test_add_func("/dnsproxy/multiple ipv6 tcp msg from cache",
460                         test_multiple_ipv6_tcp_msg);
461
462         return g_test_run();
463 }