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) {
150 fprintf(stderr, "Failed to connect to DNS server at %s "
152 server, -err, strerror(-err));
156 fcntl(sk, F_SETFL, O_NONBLOCK);
163 static int send_msg(int sk, unsigned char *msg, unsigned int len,
169 for (i = 0; i < len; i++) {
170 err = write(sk, &msg[i], 1);
173 LOG("write failed errno %d/%s", -err, strerror(-err));
176 g_assert_cmpint(err, >=, 0);
187 static int connect_udp_socket(char *server, struct sockaddr *sa,
193 struct addrinfo hints, *rp;
195 memset(&hints, 0, sizeof(hints));
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);
202 sk = create_udp_socket(rp->ai_family);
205 LOG("sk %d family %d", sk, rp->ai_family);
209 fprintf(stderr, "Failed to connect to DNS server at %s "
211 server, -err, strerror(-err));
213 memcpy(sa, rp->ai_addr, *sa_len);
214 *sa_len = rp->ai_addrlen;
222 static int sendto_msg(int sk, struct sockaddr *sa, socklen_t salen,
223 unsigned char *msg, unsigned int len)
227 err = sendto(sk, msg, len, MSG_NOSIGNAL, sa, salen);
230 LOG("sendto failed errno %d/%s", -err, strerror(-err));
233 g_assert_cmpint(err, >=, 0);
240 static unsigned short get_id()
245 static void change_msg(unsigned char *msg, unsigned int tranid,
246 unsigned int host_loc, unsigned char host_count)
248 unsigned short id = get_id();
250 msg[tranid] = id >> 8;
252 msg[host_loc] = host_count;
255 static void change_msg2(unsigned char *msg, unsigned char host_count)
257 change_msg(msg, 2, 20, host_count);
258 change_msg(msg, 32, 50, host_count+1);
261 static int receive_message(int sk, int timeout, int expected, int *server_closed)
263 int ret, received = 0;
264 unsigned char buf[512];
266 while (timeout > 0) {
267 ret = read(sk, buf, sizeof(buf));
269 LOG("received %d bytes from server %d", ret, sk);
271 if (received >= expected)
273 } else if (ret == 0) {
274 LOG("server %d closed socket", sk);
279 if (errno != EAGAIN && errno != EWOULDBLOCK)
290 static int receive_from_message(int sk, struct sockaddr *sa, socklen_t len,
291 int timeout, int expected)
293 int ret, received = 0;
294 unsigned char buf[512];
296 fcntl(sk, F_SETFL, O_NONBLOCK);
298 while (timeout > 0) {
299 ret = recvfrom(sk, buf, sizeof(buf), 0, sa, &len);
301 LOG("received %d bytes from server %d", ret, sk);
303 if (received >= expected)
305 } else if (ret < 0) {
306 if (errno != EAGAIN && errno != EWOULDBLOCK)
317 static void test_ipv4_udp_msg(void)
319 int sk, received = 0;
320 struct sockaddr_in sa;
321 socklen_t len = sizeof(sa);
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,
331 g_assert_cmpint(received, >=, sizeof(msg));
334 static void test_ipv6_udp_msg(void)
336 int sk, received = 0;
337 struct sockaddr_in6 sa;
338 socklen_t len = sizeof(sa);
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,
348 g_assert_cmpint(received, >=, sizeof(msg));
351 static void test_partial_ipv4_tcp_msg(void)
353 int sk, received = 0;
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);
362 g_assert_cmpint(received, >=, sizeof(msg));
365 static void test_partial_ipv6_tcp_msg(void)
367 int sk, received = 0;
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);
376 g_assert_cmpint(received, >=, sizeof(msg));
379 static void test_multiple_ipv4_tcp_msg(void)
381 int sk, received = 0, server_closed = 0;
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);
390 /* If the final DNS server refuses to serve us, then do not consider
391 * it an error. This happens very often with unbound.
393 if (server_closed == 0)
394 g_assert_cmpint(received, >=, sizeof(msg2));
397 static void test_multiple_ipv6_tcp_msg(void)
399 int sk, received = 0, server_closed = 0;
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);
408 if (server_closed == 0)
409 g_assert_cmpint(received, >=, sizeof(msg2));
412 static void test_failure_tcp_msg(void)
414 int sk, received = 0;
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);
422 g_assert_cmpint(received, ==, 0);
425 int main(int argc, char *argv[])
427 g_test_init(&argc, &argv, NULL);
429 g_test_add_func("/dnsproxy/ipv4 udp msg",
432 g_test_add_func("/dnsproxy/ipv6 udp msg",
435 g_test_add_func("/dnsproxy/failure tcp msg ",
436 test_failure_tcp_msg);
438 g_test_add_func("/dnsproxy/partial ipv4 tcp msg",
439 test_partial_ipv4_tcp_msg);
441 g_test_add_func("/dnsproxy/partial ipv6 tcp msg",
442 test_partial_ipv6_tcp_msg);
444 g_test_add_func("/dnsproxy/partial ipv4 tcp msg from cache",
445 test_partial_ipv4_tcp_msg);
447 g_test_add_func("/dnsproxy/partial ipv6 tcp msg from cache",
448 test_partial_ipv6_tcp_msg);
450 g_test_add_func("/dnsproxy/multiple ipv4 tcp msg",
451 test_multiple_ipv4_tcp_msg);
453 g_test_add_func("/dnsproxy/multiple ipv6 tcp msg",
454 test_multiple_ipv6_tcp_msg);
456 g_test_add_func("/dnsproxy/multiple ipv4 tcp msg from cache",
457 test_multiple_ipv4_tcp_msg);
459 g_test_add_func("/dnsproxy/multiple ipv6 tcp msg from cache",
460 test_multiple_ipv6_tcp_msg);