1 /*
2 * Test suite for network server functions.
3 *
4 * The canonical version of this file is maintained in the rra-c-util package,
5 * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
6 *
7 * Written by Russ Allbery <eagle@eyrie.org>
8 * Copyright 2005, 2013, 2016-2018, 2020 Russ Allbery <eagle@eyrie.org>
9 * Copyright 2009-2013
10 * The Board of Trustees of the Leland Stanford Junior University
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 *
30 * SPDX-License-Identifier: MIT
31 */
32
33 #define LIBTEST_NEW_FORMAT 1
34
35 #include "config.h"
36 #include "portable/socket.h"
37 #include "portable/system.h"
38
39 #include <errno.h>
40 #include <signal.h>
41 #include <sys/wait.h>
42
43 #include "inn/fdflag.h"
44 #include "inn/macros.h"
45 #include "inn/messages.h"
46 #include "inn/network.h"
47 #include "tap/basic.h"
48
49
50 /*
51 * Check whether IPv6 actually works. On some systems (such as Solaris 8
52 * without IPv6 configured), it's possible to create an IPv6 socket, but
53 * binding the socket will fail. We therefore attempt an IPv6 socket creation
54 * and, if it fails, check errno for several errors that indicate that IPv6
55 * is supported but doesn't work. This will also handle the case where IPv6
56 * support is not configured, since network_bind_ipv6 will return
57 * INVALID_SOCKET.
58 */
59 static bool
ipv6_works(void)60 ipv6_works(void)
61 {
62 socket_type fd, client, server;
63
64 /*
65 * Create the socket and then try to connect to it with a short timeout
66 * and accept it on the server side. If this works, IPv6 is supported.
67 */
68 fd = network_bind_ipv6(SOCK_STREAM, "::1", 11119);
69 if (fd != INVALID_SOCKET) {
70 fdflag_nonblocking(fd, true);
71 client = network_connect_host("::1", 11119, NULL, 1);
72 if (client == INVALID_SOCKET) {
73 close(fd);
74 if (socket_errno == ETIMEDOUT || socket_errno == ENETUNREACH)
75 return false;
76 } else {
77 server = accept(fd, NULL, NULL);
78 close(fd);
79 if (server == INVALID_SOCKET) {
80 close(client);
81
82 /*
83 * Written as two separate if statements because gcc with
84 * -Werror=logical-op warns about identical expressions, and
85 * EAGAIN and EWOULDBLOCK are the same number on Linux (but
86 * not on some other platforms).
87 */
88 if (socket_errno == EAGAIN)
89 return false;
90 if (socket_errno == EWOULDBLOCK)
91 return false;
92 } else {
93 close(server);
94 close(client);
95 return true;
96 }
97 }
98 }
99
100 /* IPv6 not recognized, indicating no support. */
101 if (socket_errno == EAFNOSUPPORT || socket_errno == EPROTONOSUPPORT)
102 return false;
103
104 /* IPv6 is recognized but we can't actually use it. */
105 if (socket_errno == EADDRNOTAVAIL)
106 return false;
107
108 /*
109 * Some other error. Assume it's not related to IPv6. We'll probably
110 * fail later.
111 */
112 return true;
113 }
114
115
116 /*
117 * A client writer used to generate data for a server test. Connect to the
118 * given host on port 11119 and send a constant string to a socket. Takes the
119 * source address as well to pass into network_connect_host. If the flag is
120 * true, expects to succeed in connecting; otherwise, fail the test (by
121 * exiting with a non-zero status) if the connection is successful.
122 *
123 * If the succeed argument is true, this is guarateed to never return.
124 */
125 static void
client_writer(const char * host,const char * source,bool succeed)126 client_writer(const char *host, const char *source, bool succeed)
127 {
128 socket_type fd;
129 FILE *out;
130
131 fd = network_connect_host(host, 11119, source, 0);
132 if (fd == INVALID_SOCKET) {
133 if (succeed)
134 _exit(1);
135 else
136 return;
137 }
138 out = fdopen(fd, "w");
139 if (out == NULL)
140 sysdie("fdopen failed");
141 fputs("socket test\r\n", out);
142 fclose(out);
143 _exit(succeed ? 0 : 1);
144 }
145
146
147 /*
148 * A client writer for testing UDP. Sends a UDP packet to port 11119 on
149 * localhost, from the given source address, containing a constant string.
150 * This also verifies that network_client_create works properly.
151 */
152 __attribute__((__noreturn__)) static void
client_ipv4_udp_writer(const char * source)153 client_ipv4_udp_writer(const char *source)
154 {
155 socket_type fd;
156 struct sockaddr_in sin;
157
158 /* Create and bind the socket. */
159 fd = network_client_create(AF_INET, SOCK_DGRAM, source);
160 if (fd == INVALID_SOCKET)
161 _exit(1);
162
163 /* Connect to localhost port 11119. */
164 memset(&sin, 0, sizeof(sin));
165 sin.sin_family = AF_INET;
166 sin.sin_port = htons(11119);
167 sin.sin_addr.s_addr = htonl(0x7f000001UL);
168 if (connect(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0)
169 _exit(1);
170
171 /* Send our fixed UDP packet. */
172 if (send(fd, "socket test\r\n", 13, 0) < 13)
173 _exit(1);
174 _exit(0);
175 }
176
177
178 /*
179 * The same as client_ipv4_udp_writer, but sents the packet via IPv6 instead.
180 * If somehow this was called without IPv6 being available (which should be
181 * impossible), do nothing and exit with a non-zero status.
182 */
183 __attribute__((__noreturn__)) static void
client_ipv6_udp_writer(const char * source)184 client_ipv6_udp_writer(const char *source)
185 {
186 #ifdef HAVE_INET6
187 socket_type fd;
188 struct sockaddr_in6 sin6;
189
190 /* Create and bind the socket. */
191 fd = network_client_create(AF_INET6, SOCK_DGRAM, source);
192 if (fd == INVALID_SOCKET)
193 _exit(1);
194
195 /* Connect to localhost port 11119. */
196 memset(&sin6, 0, sizeof(sin6));
197 sin6.sin6_family = AF_INET6;
198 sin6.sin6_port = htons(11119);
199 if (inet_pton(AF_INET6, "::1", &sin6.sin6_addr) < 1)
200 sysbail("cannot convert ::1 to an in6_addr");
201 if (connect(fd, (struct sockaddr *) &sin6, sizeof(sin6)) < 0)
202 _exit(1);
203
204 /* Send our fixed UDP packet. */
205 if (send(fd, "socket test\r\n", 13, 0) < 13)
206 _exit(1);
207 _exit(0);
208 #else
209 _exit(1);
210 #endif
211 }
212
213
214 /*
215 * When testing the bind (server) functions, we create listening sockets, fork
216 * a child process to connect to it, and accept the connection and read the
217 * data in the server. The test reporting is therefore done by the listener.
218 * There are two listeners, depending on whether we're listening to a single
219 * socket or an array of sockets, both of which invoke this handler when the
220 * connection is accepted.
221 *
222 * Check that the result of accept, read data from the client, and ensure we
223 * got the expected data, reporting all results through the normal test
224 * reporting mechanism.
225 */
226 static void
test_server_connection(socket_type client)227 test_server_connection(socket_type client)
228 {
229 FILE *out;
230 char buffer[512];
231
232 /* Verify that the result of accept is good. */
233 if (client == INVALID_SOCKET) {
234 sysdiag("cannot accept connection from socket");
235 ok_block(2, 0, "...socket read test");
236 return;
237 }
238 ok(1, "...socket accept");
239
240 /* Read data from the client and ensure it matches our expectations. */
241 out = fdopen(client, "r");
242 if (fgets(buffer, sizeof(buffer), out) == NULL) {
243 sysdiag("cannot read from socket");
244 ok(0, "...socket read");
245 }
246 is_string("socket test\r\n", buffer, "...socket read");
247 fclose(out);
248 }
249
250
251 /*
252 * Test a single listening socket. Accepts one connection and invokes
253 * test_server_connection. For skipping purposes, this produces two tests.
254 */
255 static void
test_server_accept(socket_type fd)256 test_server_accept(socket_type fd)
257 {
258 socket_type client;
259
260 /* If there are firewalls that block connections, we could hang here. */
261 alarm(5);
262
263 /* Accept the connection and writes from the client. */
264 client = accept(fd, NULL, NULL);
265 test_server_connection(client);
266 socket_close(fd);
267
268 /* Cancel the alarm. */
269 alarm(0);
270 }
271
272
273 /*
274 * A variant version of the server portion of the test. Takes an array of
275 * sockets and the size of the sockets and accepts a connection on any of
276 * those sockets. Ensures that the client address information is stored
277 * correctly by checking that it is an IPv4 or IPv6 address. For skipping
278 * purposes, this produces three tests.
279 *
280 * Normally, the client address should be 127.0.0.1, but hosts with odd local
281 * networking setups may rewrite client IP addresses so that they appear to
282 * come from other addresses. Hosts that only have IPv6 interfaces will see a
283 * client connection on ::1 instead. Avoid checking if the client IP is
284 * 127.0.0.1 for that reason. Hopefully this won't hide bugs.
285 *
286 * saddr is allocated from the heap instead of using a local struct
287 * sockaddr_storage to work around a misdiagnosis of strict aliasing
288 * violations from gcc 4.4 (fixed in later versions).
289 */
290 static void
test_server_accept_any(socket_type fds[],unsigned int count)291 test_server_accept_any(socket_type fds[], unsigned int count)
292 {
293 socket_type client;
294 unsigned int i;
295 struct sockaddr *saddr;
296 socklen_t slen;
297
298 /* If there are firewalls that block connections, we could hang here. */
299 alarm(5);
300
301 /* Accept the connection and writes from the client. */
302 slen = sizeof(struct sockaddr_storage);
303 saddr = bcalloc(1, slen);
304 client = network_accept_any(fds, count, saddr, &slen);
305 test_server_connection(client);
306 if (saddr->sa_family == AF_INET)
307 is_int(AF_INET, saddr->sa_family, "...address family is IPv4");
308 else
309 is_int(AF_INET6, saddr->sa_family, "...address family is IPv6");
310 free(saddr);
311 for (i = 0; i < count; i++)
312 socket_close(fds[i]);
313
314 /* Cancel the alarm. */
315 alarm(0);
316 }
317
318
319 /*
320 * Bring up a server on port 11119 on the loopback address and test connecting
321 * to it via IPv4. Takes an optional source address to use for client
322 * connections. For skipping purposes, this produces four tests.
323 */
324 static void
test_ipv4(const char * source)325 test_ipv4(const char *source)
326 {
327 socket_type fd;
328 pid_t child;
329 int status;
330
331 /* Set up the server socket. */
332 fd = network_bind_ipv4(SOCK_STREAM, "127.0.0.1", 11119);
333 if (fd == INVALID_SOCKET)
334 sysbail("cannot create or bind socket");
335 ok(fd != INVALID_SOCKET, "IPv4 server test");
336 if (listen(fd, 1) < 0)
337 sysbail("cannot listen to socket");
338
339 /* Fork off a child writer and test the server accept. */
340 child = fork();
341 if (child < 0)
342 sysbail("cannot fork");
343 else if (child == 0) {
344 socket_close(fd);
345 client_writer("127.0.0.1", source, true);
346 } else {
347 test_server_accept(fd);
348 waitpid(child, &status, 0);
349 is_int(0, status, "client made correct connections");
350 }
351 }
352
353
354 /*
355 * Bring up a server on port 11119 on the loopback address and test connecting
356 * to it via IPv6. Takes an optional source address to use for client
357 * connections. For skipping purposes, this produces four tests.
358 */
359 static void
test_ipv6(const char * source)360 test_ipv6(const char *source)
361 {
362 socket_type fd;
363 pid_t child;
364 int status;
365
366 /* Set up the server socket. */
367 fd = network_bind_ipv6(SOCK_STREAM, "::1", 11119);
368 if (fd == INVALID_SOCKET)
369 sysbail("cannot create socket");
370 ok(fd != INVALID_SOCKET, "IPv6 server test");
371 if (listen(fd, 1) < 0)
372 sysbail("cannot listen to socket");
373
374 /*
375 * Fork off a child writer and test the server accept. If IPV6_V6ONLY is
376 * supported, we can also check that connecting to 127.0.0.1 will fail.
377 */
378 child = fork();
379 if (child < 0)
380 sysbail("cannot fork");
381 else if (child == 0) {
382 socket_close(fd);
383 #ifdef IPV6_V6ONLY
384 client_writer("127.0.0.1", NULL, false);
385 #endif
386 client_writer("::1", source, true);
387 } else {
388 test_server_accept(fd);
389 waitpid(child, &status, 0);
390 is_int(0, status, "client made correct connections");
391 }
392 }
393
394
395 /*
396 * Returns the struct sockaddr * corresponding to a local socket. Handles the
397 * initial allocation being too small and dynamically increasing it. Caller
398 * is responsible for freeing the allocated sockaddr.
399 */
400 static struct sockaddr *
get_sockaddr(socket_type fd)401 get_sockaddr(socket_type fd)
402 {
403 struct sockaddr *saddr;
404 socklen_t size;
405
406 saddr = bmalloc(sizeof(struct sockaddr_storage));
407 size = sizeof(struct sockaddr_storage);
408 if (getsockname(fd, saddr, &size) < 0)
409 sysbail("cannot getsockname");
410 if (size > sizeof(struct sockaddr)) {
411 free(saddr);
412 saddr = bmalloc(size);
413 if (getsockname(fd, saddr, &size) < 0)
414 sysbail("cannot getsockname");
415 }
416 return saddr;
417 }
418
419
420 /*
421 * Bring up a server on port 11119 on all addresses and try connecting to it
422 * via all of the available protocols. Takes an optional source address to
423 * use for client connections. For skipping purposes, this produces eight
424 * tests.
425 */
426 static void
test_all(const char * source_ipv4,const char * source_ipv6 UNUSED)427 test_all(const char *source_ipv4, const char *source_ipv6 UNUSED)
428 {
429 socket_type *fds, fd;
430 unsigned int count, i;
431 pid_t child;
432 struct sockaddr *saddr;
433 int status, family;
434
435 /* Bind sockets for all available local addresses. */
436 if (!network_bind_all(SOCK_STREAM, 11119, &fds, &count))
437 sysbail("cannot create or bind socket");
438
439 /*
440 * There should be at most two, one for IPv4 and one for IPv6, but allow
441 * for possible future weirdness in networking.
442 */
443 if (count > 2) {
444 diag("got more than two sockets, using just the first two");
445 count = 2;
446 }
447
448 /* We'll test each socket in turn by listening and trying to connect. */
449 for (i = 0; i < count; i++) {
450 fd = fds[i];
451 if (listen(fd, 1) < 0)
452 sysbail("cannot listen to socket %d", fd);
453 ok(fd != INVALID_SOCKET, "all address server test (part %u)", i + 1);
454
455 /* Get the socket type to determine what type of client to run. */
456 saddr = get_sockaddr(fd);
457 family = saddr->sa_family;
458 free(saddr);
459
460 /*
461 * Fork off a child writer and test the server accept. If IPV6_V6ONLY
462 * is supported, we can also check that connecting to 127.0.0.1 will
463 * fail.
464 */
465 child = fork();
466 if (child < 0)
467 sysbail("cannot fork");
468 else if (child == 0) {
469 if (family == AF_INET) {
470 client_writer("::1", source_ipv6, false);
471 client_writer("127.0.0.1", source_ipv4, true);
472 #ifdef HAVE_INET6
473 } else if (family == AF_INET6) {
474 # ifdef IPV6_V6ONLY
475 client_writer("127.0.0.1", source_ipv4, false);
476 # endif
477 client_writer("::1", source_ipv6, true);
478 #endif
479 } else {
480 die("unknown socket family %d", family);
481 }
482 } else {
483 test_server_accept(fd);
484 waitpid(child, &status, 0);
485 is_int(0, status, "client made correct connections");
486 }
487 }
488 network_bind_all_free(fds);
489
490 /* If we only got one listening socket, skip for consistent test count. */
491 if (count == 1)
492 skip_block(4, "only one listening socket");
493 }
494
495
496 /*
497 * Bring up a server on port 11119 on all addresses and try connecting to it
498 * via 127.0.0.1, using network_accept_any underneath. For skipping purposes,
499 * this runs three tests.
500 */
501 static void
test_any(void)502 test_any(void)
503 {
504 socket_type *fds;
505 unsigned int count, i;
506 pid_t child;
507 int status, family;
508 struct sockaddr *saddr;
509
510 /* Bind our socket.
511 *
512 * If the host has no IPv4 addresses, we may have only an IPv6 socket and
513 * thus can't us an IPv4 client. Determine the address family of the
514 * first socket so that we can use an appropriate client.
515 */
516 if (!network_bind_all(SOCK_STREAM, 11119, &fds, &count))
517 sysbail("cannot create or bind socket");
518 saddr = get_sockaddr(fds[0]);
519 family = saddr->sa_family;
520 free(saddr);
521 ok(1, "network_accept_any test");
522
523 /* Listen on all bound sockets. */
524 for (i = 0; i < count; i++)
525 if (listen(fds[i], 1) < 0)
526 sysbail("cannot listen to socket %d", fds[i]);
527
528 /* Write a packet from a client and receive it on the server. */
529 child = fork();
530 if (child < 0)
531 sysbail("cannot fork");
532 else if (child == 0) {
533 if (family == AF_INET)
534 client_writer("127.0.0.1", NULL, true);
535 else
536 client_writer("::1", NULL, true);
537 } else {
538 test_server_accept_any(fds, count);
539 waitpid(child, &status, 0);
540 is_int(0, status, "client made correct connections");
541 }
542 network_bind_all_free(fds);
543 }
544
545
546 /*
547 * Bring up a UDP server on port 11119 on all addresses and try connecting to
548 * it via 127.0.0.1, using network_wait_any underneath. This tests the bind
549 * functions for UDP sockets, network_client_create for UDP addresses, and
550 * network_wait_any.
551 */
552 static void
test_any_udp(void)553 test_any_udp(void)
554 {
555 socket_type *fds, fd;
556 unsigned int count, i;
557 pid_t child;
558 char buffer[BUFSIZ];
559 ssize_t length;
560 int status, family;
561 struct sockaddr_storage addr;
562 struct sockaddr *saddr;
563 socklen_t addrlen;
564
565 /*
566 * Bind our UDP socket.
567 *
568 * If the host has no IPv4 addresses, we may have only an IPv6 socket and
569 * thus can't us an IPv4 client. Determine the address family of the
570 * first socket so that we can use an appropriate client.
571 */
572 if (!network_bind_all(SOCK_DGRAM, 11119, &fds, &count))
573 sysbail("cannot create or bind socket");
574 saddr = get_sockaddr(fds[0]);
575 family = saddr->sa_family;
576 free(saddr);
577
578 /* Create a child that writes a single UDP packet to the server. */
579 child = fork();
580 if (child < 0)
581 sysbail("cannot fork");
582 else if (child == 0) {
583 if (family == AF_INET)
584 client_ipv4_udp_writer("127.0.0.1");
585 else
586 client_ipv6_udp_writer("::1");
587 }
588
589 /* Set an alarm, since if the client malfunctions, nothing happens. */
590 alarm(5);
591
592 /* Wait for the UDP packet and then read and confirm it. */
593 fd = network_wait_any(fds, count);
594 ok(fd != INVALID_SOCKET, "network_wait_any found UDP message");
595 if (fd == INVALID_SOCKET)
596 ok_block(3, false, "could not accept client");
597 else {
598 saddr = (struct sockaddr *) &addr;
599 addrlen = sizeof(addr);
600 length = recvfrom(fd, buffer, sizeof(buffer), 0, saddr, &addrlen);
601 is_int(13, length, "...of correct length");
602 is_int(family, saddr->sa_family, "...from correct family");
603 buffer[13] = '\0';
604 is_string("socket test\r\n", buffer, "...and correct contents");
605 }
606
607 /* Wait for the child and be sure it exited successfully. */
608 waitpid(child, &status, 0);
609 is_int(0, status, "client made correct connections");
610
611 /* Clean up. */
612 for (i = 0; i < count; i++)
613 socket_close(fds[i]);
614 network_bind_all_free(fds);
615 }
616
617
618 int
main(void)619 main(void)
620 {
621 /* Set up the plan. */
622 plan(42);
623
624 /* Test network_bind functions. */
625 test_ipv4(NULL);
626 test_ipv4("127.0.0.1");
627
628 /*
629 * Optionally test IPv6 support. If IPv6 support appears to be available
630 * but doesn't work, we have to explicitly skip test_all, since it will
631 * create a socket that we then can't connect to.
632 */
633 if (ipv6_works()) {
634 test_ipv6(NULL);
635 test_ipv6("::1");
636 test_all(NULL, NULL);
637 test_all("127.0.0.1", "::1");
638 } else {
639 skip_block(24, "IPv6 not configured");
640 }
641
642 /* Test network_accept_any. */
643 test_any();
644
645 /* Test UDP socket handling and network_wait_any. */
646 test_any_udp();
647 return 0;
648 }
649