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
31 #include <arpa/inet.h>
32 #include <netinet/in.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
46 #define LOG(fmt, arg...) do { \
47 fprintf(stdout, "%s:%s() " fmt "\n", \
48 __FILE__, __func__ , ## arg); \
51 #define LOG(fmt, arg...)
54 static unsigned char msg[] = {
55 0x00, 0x1c, /* len 28 */
56 0x31, 0x82, /* tran id */
57 0x01, 0x00, /* flags (recursion required) */
58 0x00, 0x01, /* questions (1) */
59 0x00, 0x00, /* answer rr */
60 0x00, 0x00, /* authority rr */
61 0x00, 0x00, /* additional rr */
62 0x06, 0x6c, 0x6f, 0x6c, 0x67, 0x65, 0x30, /* lolge0, just some name */
63 0x03, 0x63, 0x6f, 0x6d, /* com */
64 0x00, /* null terminator */
65 0x00, 0x01, /* type A */
66 0x00, 0x01, /* class IN */
69 static unsigned char msg2[] = {
70 0x00, 0x1c, /* len 28 */
71 0x31, 0x83, /* tran id */
72 0x01, 0x00, /* flags (recursion required) */
73 0x00, 0x01, /* questions (1) */
74 0x00, 0x00, /* answer rr */
75 0x00, 0x00, /* authority rr */
76 0x00, 0x00, /* additional rr */
77 0x06, 0x6c, 0x6f, 0x67, 0x6c, 0x67, 0x65, /* loelge */
78 0x03, 0x63, 0x6f, 0x6d, /* com */
79 0x00, /* null terminator */
80 0x00, 0x01, /* type A */
81 0x00, 0x01, /* class IN */
83 0x00, 0x1c, /* len 28 */
84 0x31, 0x84, /* tran id */
85 0x01, 0x00, /* flags (recursion required) */
86 0x00, 0x01, /* questions (1) */
87 0x00, 0x00, /* answer rr */
88 0x00, 0x00, /* authority rr */
89 0x00, 0x00, /* additional rr */
90 0x06, 0x6c, 0x6f, 0x67, 0x6c, 0x67, 0x65, /* loelge */
91 0x03, 0x6e, 0x65, 0x74, /* net */
92 0x00, /* null terminator */
93 0x00, 0x01, /* type A */
94 0x00, 0x01, /* class IN */
97 static unsigned char msg_invalid[] = {
98 0x00, 0x1c, /* len 28 */
99 0x31, 0xC0, /* tran id */
102 static int create_tcp_socket(int family)
106 sk = socket(family, SOCK_STREAM, IPPROTO_TCP);
109 LOG("Failed to create TCP socket %d/%s", err, strerror(err));
116 static int create_udp_socket(int family)
120 sk = socket(family, SOCK_DGRAM, IPPROTO_UDP);
123 LOG("Failed to create UDP socket %d/%s", err, strerror(err));
130 static int connect_tcp_socket(char *server)
135 struct addrinfo hints, *rp;
137 memset(&hints, 0, sizeof(hints));
139 hints.ai_socktype = SOCK_STREAM;
140 hints.ai_family = AF_UNSPEC;
141 hints.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST;
142 getaddrinfo(server, "53", &hints, &rp);
144 sk = create_tcp_socket(rp->ai_family);
147 LOG("sk %d family %d", sk, rp->ai_family);
149 if (sk >= 0 && connect(sk, rp->ai_addr, rp->ai_addrlen) < 0) {
154 fprintf(stderr, "Failed to connect to DNS server at %s "
156 server, -err, strerror(-err));
160 fcntl(sk, F_SETFL, O_NONBLOCK);
167 static int send_msg(int sk, unsigned char *msg, unsigned int len,
173 for (i = 0; i < len; i++) {
174 err = write(sk, &msg[i], 1);
177 LOG("write failed errno %d/%s", -err, strerror(-err));
180 g_assert_cmpint(err, >=, 0);
191 static int connect_udp_socket(char *server, struct sockaddr *sa,
197 struct addrinfo hints, *rp;
199 memset(&hints, 0, sizeof(hints));
201 hints.ai_socktype = SOCK_DGRAM;
202 hints.ai_family = AF_UNSPEC;
203 hints.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST;
204 getaddrinfo(server, "53", &hints, &rp);
206 sk = create_udp_socket(rp->ai_family);
209 LOG("sk %d family %d", sk, rp->ai_family);
213 fprintf(stderr, "Failed to connect to DNS server at %s "
215 server, -err, strerror(-err));
217 memcpy(sa, rp->ai_addr, *sa_len);
218 *sa_len = rp->ai_addrlen;
226 static int sendto_msg(int sk, struct sockaddr *sa, socklen_t salen,
227 unsigned char *msg, unsigned int len)
231 err = sendto(sk, msg, len, MSG_NOSIGNAL, sa, salen);
234 LOG("sendto failed errno %d/%s", -err, strerror(-err));
237 g_assert_cmpint(err, >=, 0);
244 static unsigned short get_id(void)
249 static void change_msg(unsigned char *msg, unsigned int tranid,
250 unsigned int host_loc, unsigned char host_count)
252 unsigned short id = get_id();
254 msg[tranid] = id >> 8;
256 msg[host_loc] = host_count;
259 static void change_msg2(unsigned char *msg, unsigned char host_count)
261 change_msg(msg, 2, 20, host_count);
262 change_msg(msg, 32, 50, host_count+1);
265 static int receive_message(int sk, int timeout, int expected, int *server_closed)
267 int ret, received = 0;
268 unsigned char buf[512];
270 while (timeout > 0) {
271 ret = read(sk, buf, sizeof(buf));
273 LOG("received %d bytes from server %d", ret, sk);
275 if (received >= expected)
277 } else if (ret == 0) {
278 LOG("server %d closed socket", sk);
283 if (errno != EAGAIN && errno != EWOULDBLOCK)
294 static int receive_from_message(int sk, struct sockaddr *sa, socklen_t len,
295 int timeout, int expected)
297 int ret, received = 0;
298 unsigned char buf[512];
300 fcntl(sk, F_SETFL, O_NONBLOCK);
302 while (timeout > 0) {
303 ret = recvfrom(sk, buf, sizeof(buf), 0, sa, &len);
305 LOG("received %d bytes from server %d", ret, sk);
307 if (received >= expected)
309 } else if (ret < 0) {
310 if (errno != EAGAIN && errno != EWOULDBLOCK)
321 static void test_ipv4_udp_msg(void)
323 int sk, received = 0;
324 struct sockaddr_in sa;
325 socklen_t len = sizeof(sa);
327 sk = connect_udp_socket("127.0.0.1", (struct sockaddr *)&sa, &len);
328 g_assert_cmpint(sk, >=, 0);
329 change_msg(msg, 2, 20, '1');
330 sendto_msg(sk, (struct sockaddr *)&sa, len, msg, sizeof(msg));
331 received = receive_from_message(sk, (struct sockaddr *)&sa, len,
335 g_assert_cmpint(received, >=, sizeof(msg));
338 static void test_ipv6_udp_msg(void)
340 int sk, received = 0;
341 struct sockaddr_in6 sa;
342 socklen_t len = sizeof(sa);
344 sk = connect_udp_socket("::1", (struct sockaddr *)&sa, &len);
345 g_assert_cmpint(sk, >=, 0);
346 change_msg(msg, 2, 20, '1');
347 sendto_msg(sk, (struct sockaddr *)&sa, len, msg, sizeof(msg));
348 received = receive_from_message(sk, (struct sockaddr *)&sa, len,
352 g_assert_cmpint(received, >=, sizeof(msg));
355 static void test_partial_ipv4_tcp_msg(void)
357 int sk, received = 0;
359 sk = connect_tcp_socket("127.0.0.1");
360 g_assert_cmpint(sk, >=, 0);
361 change_msg(msg, 2, 20, '1');
362 send_msg(sk, msg, sizeof(msg), 1);
363 received = receive_message(sk, 10, sizeof(msg), NULL);
366 g_assert_cmpint(received, >=, sizeof(msg));
369 static void test_partial_ipv6_tcp_msg(void)
371 int sk, received = 0;
373 sk = connect_tcp_socket("::1");
374 g_assert_cmpint(sk, >=, 0);
375 change_msg(msg, 2, 20, '2');
376 send_msg(sk, msg, sizeof(msg), 1);
377 received = receive_message(sk, 10, sizeof(msg), NULL);
380 g_assert_cmpint(received, >=, sizeof(msg));
383 static void test_multiple_ipv4_tcp_msg(void)
385 int sk, received = 0, server_closed = 0;
387 sk = connect_tcp_socket("127.0.0.1");
388 g_assert_cmpint(sk, >=, 0);
389 change_msg2(msg2, '1');
390 send_msg(sk, msg2, sizeof(msg2), 0);
391 received = receive_message(sk, 35, sizeof(msg2), &server_closed);
394 /* If the final DNS server refuses to serve us, then do not consider
395 * it an error. This happens very often with unbound.
397 if (server_closed == 0)
398 g_assert_cmpint(received, >=, sizeof(msg2));
401 static void test_multiple_ipv6_tcp_msg(void)
403 int sk, received = 0, server_closed = 0;
405 sk = connect_tcp_socket("::1");
406 g_assert_cmpint(sk, >=, 0);
407 change_msg2(msg2, '2');
408 send_msg(sk, msg2, sizeof(msg2), 0);
409 received = receive_message(sk, 35, sizeof(msg2), &server_closed);
412 if (server_closed == 0)
413 g_assert_cmpint(received, >=, sizeof(msg2));
416 static void test_failure_tcp_msg(void)
418 int sk, received = 0;
420 sk = connect_tcp_socket("127.0.0.1");
421 g_assert_cmpint(sk, >=, 0);
422 send_msg(sk, msg_invalid, sizeof(msg_invalid), 0);
423 received = receive_message(sk, 10, 0, NULL);
426 g_assert_cmpint(received, ==, 0);
429 int main(int argc, char *argv[])
431 g_test_init(&argc, &argv, NULL);
433 g_test_add_func("/dnsproxy/ipv4 udp msg",
436 g_test_add_func("/dnsproxy/ipv6 udp msg",
439 g_test_add_func("/dnsproxy/failure tcp msg ",
440 test_failure_tcp_msg);
442 g_test_add_func("/dnsproxy/partial ipv4 tcp msg",
443 test_partial_ipv4_tcp_msg);
445 g_test_add_func("/dnsproxy/partial ipv6 tcp msg",
446 test_partial_ipv6_tcp_msg);
448 g_test_add_func("/dnsproxy/partial ipv4 tcp msg from cache",
449 test_partial_ipv4_tcp_msg);
451 g_test_add_func("/dnsproxy/partial ipv6 tcp msg from cache",
452 test_partial_ipv6_tcp_msg);
454 g_test_add_func("/dnsproxy/multiple ipv4 tcp msg",
455 test_multiple_ipv4_tcp_msg);
457 g_test_add_func("/dnsproxy/multiple ipv6 tcp msg",
458 test_multiple_ipv6_tcp_msg);
460 g_test_add_func("/dnsproxy/multiple ipv4 tcp msg from cache",
461 test_multiple_ipv4_tcp_msg);
463 g_test_add_func("/dnsproxy/multiple ipv6 tcp msg from cache",
464 test_multiple_ipv6_tcp_msg);