551cae9147f52e5cc458924e80231dee9119f64a
[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                 close(sk);
151                 sk = -1;
152
153                 fprintf(stderr, "Failed to connect to DNS server at %s "
154                                 "errno %d/%s\n",
155                         server, -err, strerror(-err));
156         }
157
158         if (sk >= 0)
159                 fcntl(sk, F_SETFL, O_NONBLOCK);
160
161         freeaddrinfo(rp);
162
163         return err;
164 }
165
166 static int send_msg(int sk, unsigned char *msg, unsigned int len,
167                 int sleep_between)
168 {
169         unsigned int i;
170         int err;
171
172         for (i = 0; i < len; i++) {
173                 err = write(sk, &msg[i], 1);
174                 if (err < 0) {
175                         err = -errno;
176                         LOG("write failed errno %d/%s", -err, strerror(-err));
177                 }
178
179                 g_assert_cmpint(err, >=, 0);
180                 if (err < 0)
181                         return err;
182
183                 if (sleep_between)
184                         usleep(1000);
185         }
186
187         return 0;
188 }
189
190 static int connect_udp_socket(char *server, struct sockaddr *sa,
191                                                         socklen_t *sa_len)
192 {
193         int sk;
194         int err = 0;
195
196         struct addrinfo hints, *rp;
197
198         memset(&hints, 0, sizeof(hints));
199
200         hints.ai_socktype = SOCK_DGRAM;
201         hints.ai_family = AF_UNSPEC;
202         hints.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST;
203         getaddrinfo(server, "53", &hints, &rp);
204
205         sk = create_udp_socket(rp->ai_family);
206         err = sk;
207
208         LOG("sk %d family %d", sk, rp->ai_family);
209
210         if (sk < 0) {
211                 err = -errno;
212                 fprintf(stderr, "Failed to connect to DNS server at %s "
213                                 "errno %d/%s\n",
214                         server, -err, strerror(-err));
215         } else {
216                 memcpy(sa, rp->ai_addr, *sa_len);
217                 *sa_len = rp->ai_addrlen;
218         }
219
220         freeaddrinfo(rp);
221
222         return err;
223 }
224
225 static int sendto_msg(int sk, struct sockaddr *sa, socklen_t salen,
226                 unsigned char *msg, unsigned int len)
227 {
228         int err;
229
230         err = sendto(sk, msg, len, MSG_NOSIGNAL, sa, salen);
231         if (err < 0) {
232                 err = -errno;
233                 LOG("sendto failed errno %d/%s", -err, strerror(-err));
234         }
235
236         g_assert_cmpint(err, >=, 0);
237         if (err < 0)
238                 return err;
239
240         return 0;
241 }
242
243 static unsigned short get_id(void)
244 {
245         return random();
246 }
247
248 static void change_msg(unsigned char *msg, unsigned int tranid,
249                 unsigned int host_loc, unsigned char host_count)
250 {
251         unsigned short id = get_id();
252
253         msg[tranid] = id >> 8;
254         msg[tranid+1] = id;
255         msg[host_loc] = host_count;
256 }
257
258 static void change_msg2(unsigned char *msg, unsigned char host_count)
259 {
260         change_msg(msg, 2, 20, host_count);
261         change_msg(msg, 32, 50, host_count+1);
262 }
263
264 static int receive_message(int sk, int timeout, int expected, int *server_closed)
265 {
266         int ret, received = 0;
267         unsigned char buf[512];
268
269         while (timeout > 0) {
270                 ret = read(sk, buf, sizeof(buf));
271                 if (ret > 0) {
272                         LOG("received %d bytes from server %d", ret, sk);
273                         received += ret;
274                         if (received >= expected)
275                                 break;
276                 } else if (ret == 0) {
277                         LOG("server %d closed socket", sk);
278                         if (server_closed)
279                                 *server_closed = 1;
280                         break;
281                 } else {
282                         if (errno != EAGAIN && errno != EWOULDBLOCK)
283                                 break;
284                 }
285
286                 sleep(1);
287                 timeout--;
288         }
289
290         return received;
291 }
292
293 static int receive_from_message(int sk, struct sockaddr *sa, socklen_t len,
294                                 int timeout, int expected)
295 {
296         int ret, received = 0;
297         unsigned char buf[512];
298
299         fcntl(sk, F_SETFL, O_NONBLOCK);
300
301         while (timeout > 0) {
302                 ret = recvfrom(sk, buf, sizeof(buf), 0, sa, &len);
303                 if (ret > 0) {
304                         LOG("received %d bytes from server %d", ret, sk);
305                         received += ret;
306                         if (received >= expected)
307                                 break;
308                 } else if (ret < 0) {
309                         if (errno != EAGAIN && errno != EWOULDBLOCK)
310                                 break;
311                 }
312
313                 sleep(1);
314                 timeout--;
315         }
316
317         return received;
318 }
319
320 static void test_ipv4_udp_msg(void)
321 {
322         int sk, received = 0;
323         struct sockaddr_in sa;
324         socklen_t len = sizeof(sa);
325
326         sk = connect_udp_socket("127.0.0.1", (struct sockaddr *)&sa, &len);
327         g_assert_cmpint(sk, >=, 0);
328         change_msg(msg, 2, 20, '1');
329         sendto_msg(sk, (struct sockaddr *)&sa, len, msg, sizeof(msg));
330         received = receive_from_message(sk, (struct sockaddr *)&sa, len,
331                                         10, sizeof(msg));
332         close(sk);
333
334         g_assert_cmpint(received, >=, sizeof(msg));
335 }
336
337 static void test_ipv6_udp_msg(void)
338 {
339         int sk, received = 0;
340         struct sockaddr_in6 sa;
341         socklen_t len = sizeof(sa);
342
343         sk = connect_udp_socket("::1", (struct sockaddr *)&sa, &len);
344         g_assert_cmpint(sk, >=, 0);
345         change_msg(msg, 2, 20, '1');
346         sendto_msg(sk, (struct sockaddr *)&sa, len, msg, sizeof(msg));
347         received = receive_from_message(sk, (struct sockaddr *)&sa, len,
348                                         10, sizeof(msg));
349         close(sk);
350
351         g_assert_cmpint(received, >=, sizeof(msg));
352 }
353
354 static void test_partial_ipv4_tcp_msg(void)
355 {
356         int sk, received = 0;
357
358         sk = connect_tcp_socket("127.0.0.1");
359         g_assert_cmpint(sk, >=, 0);
360         change_msg(msg, 2, 20, '1');
361         send_msg(sk, msg, sizeof(msg), 1);
362         received = receive_message(sk, 10, sizeof(msg), NULL);
363         close(sk);
364
365         g_assert_cmpint(received, >=, sizeof(msg));
366 }
367
368 static void test_partial_ipv6_tcp_msg(void)
369 {
370         int sk, received = 0;
371
372         sk = connect_tcp_socket("::1");
373         g_assert_cmpint(sk, >=, 0);
374         change_msg(msg, 2, 20, '2');
375         send_msg(sk, msg, sizeof(msg), 1);
376         received = receive_message(sk, 10, sizeof(msg), NULL);
377         close(sk);
378
379         g_assert_cmpint(received, >=, sizeof(msg));
380 }
381
382 static void test_multiple_ipv4_tcp_msg(void)
383 {
384         int sk, received = 0, server_closed = 0;
385
386         sk = connect_tcp_socket("127.0.0.1");
387         g_assert_cmpint(sk, >=, 0);
388         change_msg2(msg2, '1');
389         send_msg(sk, msg2, sizeof(msg2), 0);
390         received = receive_message(sk, 35, sizeof(msg2), &server_closed);
391         close(sk);
392
393         /* If the final DNS server refuses to serve us, then do not consider
394          * it an error. This happens very often with unbound.
395          */
396         if (server_closed == 0)
397                 g_assert_cmpint(received, >=, sizeof(msg2));
398 }
399
400 static void test_multiple_ipv6_tcp_msg(void)
401 {
402         int sk, received = 0, server_closed = 0;
403
404         sk = connect_tcp_socket("::1");
405         g_assert_cmpint(sk, >=, 0);
406         change_msg2(msg2, '2');
407         send_msg(sk, msg2, sizeof(msg2), 0);
408         received = receive_message(sk, 35, sizeof(msg2), &server_closed);
409         close(sk);
410
411         if (server_closed == 0)
412                 g_assert_cmpint(received, >=, sizeof(msg2));
413 }
414
415 static void test_failure_tcp_msg(void)
416 {
417         int sk, received = 0;
418
419         sk = connect_tcp_socket("127.0.0.1");
420         g_assert_cmpint(sk, >=, 0);
421         send_msg(sk, msg_invalid, sizeof(msg_invalid), 0);
422         received = receive_message(sk, 10, 0, NULL);
423         close(sk);
424
425         g_assert_cmpint(received, ==, 0);
426 }
427
428 int main(int argc, char *argv[])
429 {
430         g_test_init(&argc, &argv, NULL);
431
432         g_test_add_func("/dnsproxy/ipv4 udp msg",
433                         test_ipv4_udp_msg);
434
435         g_test_add_func("/dnsproxy/ipv6 udp msg",
436                         test_ipv6_udp_msg);
437
438         g_test_add_func("/dnsproxy/failure tcp msg ",
439                         test_failure_tcp_msg);
440
441         g_test_add_func("/dnsproxy/partial ipv4 tcp msg",
442                         test_partial_ipv4_tcp_msg);
443
444         g_test_add_func("/dnsproxy/partial ipv6 tcp msg",
445                         test_partial_ipv6_tcp_msg);
446
447         g_test_add_func("/dnsproxy/partial ipv4 tcp msg from cache",
448                         test_partial_ipv4_tcp_msg);
449
450         g_test_add_func("/dnsproxy/partial ipv6 tcp msg from cache",
451                         test_partial_ipv6_tcp_msg);
452
453         g_test_add_func("/dnsproxy/multiple ipv4 tcp msg",
454                         test_multiple_ipv4_tcp_msg);
455
456         g_test_add_func("/dnsproxy/multiple ipv6 tcp msg",
457                         test_multiple_ipv6_tcp_msg);
458
459         g_test_add_func("/dnsproxy/multiple ipv4 tcp msg from cache",
460                         test_multiple_ipv4_tcp_msg);
461
462         g_test_add_func("/dnsproxy/multiple ipv6 tcp msg from cache",
463                         test_multiple_ipv6_tcp_msg);
464
465         return g_test_run();
466 }