5 * Copyright (C) 2013 Intel Corporation. All rights reserved.
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.
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.
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
30 #include <arpa/inet.h>
31 #include <netinet/in.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
45 #define LOG(fmt, arg...) do { \
46 fprintf(stdout, "%s:%s() " fmt "\n", \
47 __FILE__, __func__ , ## arg); \
50 #define LOG(fmt, arg...)
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 */
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 */
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 */
96 static unsigned char msg_invalid[] = {
97 0x00, 0x1c, /* len 28 */
98 0x31, 0xC0, /* tran id */
101 static int create_tcp_socket(int family)
105 sk = socket(family, SOCK_STREAM, IPPROTO_TCP);
108 LOG("Failed to create TCP socket %d/%s", err, strerror(err));
115 static int create_udp_socket(int family)
119 sk = socket(family, SOCK_DGRAM, IPPROTO_UDP);
122 LOG("Failed to create UDP socket %d/%s", err, strerror(err));
129 static int connect_tcp_socket(char *server)
134 struct addrinfo hints, *rp;
136 memset(&hints, 0, sizeof(hints));
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);
143 sk = create_tcp_socket(rp->ai_family);
146 LOG("sk %d family %d", sk, rp->ai_family);
148 if (sk >= 0 && connect(sk, rp->ai_addr, rp->ai_addrlen) < 0) {
153 fprintf(stderr, "Failed to connect to DNS server at %s "
155 server, -err, strerror(-err));
159 fcntl(sk, F_SETFL, O_NONBLOCK);
166 static int send_msg(int sk, unsigned char *msg, unsigned int len,
172 for (i = 0; i < len; i++) {
173 err = write(sk, &msg[i], 1);
176 LOG("write failed errno %d/%s", -err, strerror(-err));
179 g_assert_cmpint(err, >=, 0);
190 static int connect_udp_socket(char *server, struct sockaddr *sa,
196 struct addrinfo hints, *rp;
198 memset(&hints, 0, sizeof(hints));
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);
205 sk = create_udp_socket(rp->ai_family);
208 LOG("sk %d family %d", sk, rp->ai_family);
212 fprintf(stderr, "Failed to connect to DNS server at %s "
214 server, -err, strerror(-err));
216 memcpy(sa, rp->ai_addr, *sa_len);
217 *sa_len = rp->ai_addrlen;
225 static int sendto_msg(int sk, struct sockaddr *sa, socklen_t salen,
226 unsigned char *msg, unsigned int len)
230 err = sendto(sk, msg, len, MSG_NOSIGNAL, sa, salen);
233 LOG("sendto failed errno %d/%s", -err, strerror(-err));
236 g_assert_cmpint(err, >=, 0);
243 static unsigned short get_id(void)
248 static void change_msg(unsigned char *msg, unsigned int tranid,
249 unsigned int host_loc, unsigned char host_count)
251 unsigned short id = get_id();
253 msg[tranid] = id >> 8;
255 msg[host_loc] = host_count;
258 static void change_msg2(unsigned char *msg, unsigned char host_count)
260 change_msg(msg, 2, 20, host_count);
261 change_msg(msg, 32, 50, host_count+1);
264 static int receive_message(int sk, int timeout, int expected, int *server_closed)
266 int ret, received = 0;
267 unsigned char buf[512];
269 while (timeout > 0) {
270 ret = read(sk, buf, sizeof(buf));
272 LOG("received %d bytes from server %d", ret, sk);
274 if (received >= expected)
276 } else if (ret == 0) {
277 LOG("server %d closed socket", sk);
282 if (errno != EAGAIN && errno != EWOULDBLOCK)
293 static int receive_from_message(int sk, struct sockaddr *sa, socklen_t len,
294 int timeout, int expected)
296 int ret, received = 0;
297 unsigned char buf[512];
299 fcntl(sk, F_SETFL, O_NONBLOCK);
301 while (timeout > 0) {
302 ret = recvfrom(sk, buf, sizeof(buf), 0, sa, &len);
304 LOG("received %d bytes from server %d", ret, sk);
306 if (received >= expected)
308 } else if (ret < 0) {
309 if (errno != EAGAIN && errno != EWOULDBLOCK)
320 static void test_ipv4_udp_msg(void)
322 int sk, received = 0;
323 struct sockaddr_in sa;
324 socklen_t len = sizeof(sa);
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,
334 g_assert_cmpint(received, >=, sizeof(msg));
337 static void test_ipv6_udp_msg(void)
339 int sk, received = 0;
340 struct sockaddr_in6 sa;
341 socklen_t len = sizeof(sa);
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,
351 g_assert_cmpint(received, >=, sizeof(msg));
354 static void test_partial_ipv4_tcp_msg(void)
356 int sk, received = 0;
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);
365 g_assert_cmpint(received, >=, sizeof(msg));
368 static void test_partial_ipv6_tcp_msg(void)
370 int sk, received = 0;
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);
379 g_assert_cmpint(received, >=, sizeof(msg));
382 static void test_multiple_ipv4_tcp_msg(void)
384 int sk, received = 0, server_closed = 0;
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);
393 /* If the final DNS server refuses to serve us, then do not consider
394 * it an error. This happens very often with unbound.
396 if (server_closed == 0)
397 g_assert_cmpint(received, >=, sizeof(msg2));
400 static void test_multiple_ipv6_tcp_msg(void)
402 int sk, received = 0, server_closed = 0;
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);
411 if (server_closed == 0)
412 g_assert_cmpint(received, >=, sizeof(msg2));
415 static void test_failure_tcp_msg(void)
417 int sk, received = 0;
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);
425 g_assert_cmpint(received, ==, 0);
428 int main(int argc, char *argv[])
430 g_test_init(&argc, &argv, NULL);
432 g_test_add_func("/dnsproxy/ipv4 udp msg",
435 g_test_add_func("/dnsproxy/ipv6 udp msg",
438 g_test_add_func("/dnsproxy/failure tcp msg ",
439 test_failure_tcp_msg);
441 g_test_add_func("/dnsproxy/partial ipv4 tcp msg",
442 test_partial_ipv4_tcp_msg);
444 g_test_add_func("/dnsproxy/partial ipv6 tcp msg",
445 test_partial_ipv6_tcp_msg);
447 g_test_add_func("/dnsproxy/partial ipv4 tcp msg from cache",
448 test_partial_ipv4_tcp_msg);
450 g_test_add_func("/dnsproxy/partial ipv6 tcp msg from cache",
451 test_partial_ipv6_tcp_msg);
453 g_test_add_func("/dnsproxy/multiple ipv4 tcp msg",
454 test_multiple_ipv4_tcp_msg);
456 g_test_add_func("/dnsproxy/multiple ipv6 tcp msg",
457 test_multiple_ipv6_tcp_msg);
459 g_test_add_func("/dnsproxy/multiple ipv4 tcp msg from cache",
460 test_multiple_ipv4_tcp_msg);
462 g_test_add_func("/dnsproxy/multiple ipv6 tcp msg from cache",
463 test_multiple_ipv6_tcp_msg);