tests: add advanced TCP/IP tests (test91-94)

Change-Id: I052102f6122f82b3307595990bf91f64e97a45a8
This commit is contained in:
David van Moolenbroek 2016-09-29 23:16:22 +00:00
parent 1dee92ebe9
commit 3ba6090f82
10 changed files with 13248 additions and 3 deletions

View File

@ -1106,6 +1106,10 @@
./usr/libdata/debug/usr/tests/minix-posix/test89.debug minix-debug debug
./usr/libdata/debug/usr/tests/minix-posix/test9.debug minix-debug debug
./usr/libdata/debug/usr/tests/minix-posix/test90.debug minix-debug debug
./usr/libdata/debug/usr/tests/minix-posix/test91.debug minix-debug debug
./usr/libdata/debug/usr/tests/minix-posix/test92.debug minix-debug debug
./usr/libdata/debug/usr/tests/minix-posix/test93.debug minix-debug debug
./usr/libdata/debug/usr/tests/minix-posix/test94.debug minix-debug debug
./usr/libdata/debug/usr/tests/minix-posix/testvm.debug minix-debug debug
./usr/libdata/debug/usr/tests/minix-posix/tvnd.debug minix-debug debug
./usr/libdata/debug/usr/tests/usr.bin/id/h_id.debug minix-debug debug

View File

@ -194,6 +194,10 @@
./usr/tests/minix-posix/test89 minix-tests
./usr/tests/minix-posix/test9 minix-tests
./usr/tests/minix-posix/test90 minix-tests
./usr/tests/minix-posix/test91 minix-tests
./usr/tests/minix-posix/test92 minix-tests
./usr/tests/minix-posix/test93 minix-tests
./usr/tests/minix-posix/test94 minix-tests
./usr/tests/minix-posix/testinterp minix-tests
./usr/tests/minix-posix/testisofs minix-tests
./usr/tests/minix-posix/testkyua minix-tests

View File

@ -56,9 +56,21 @@ FILES += testvm.conf
# Network stack testing programs
OBJS.test90+= socklib.o
OBJS.test91+= socklib.o
OBJS.test92+= socklib.o
OBJS.test93+= socklib.o
# Uncomment the following lines to use SOCKLIB_SWEEP_GENERATE=1/2 in socklib.c
#.PATH: ${NETBSDSRCDIR}/minix/usr.bin/trace
#OBJS.test90+= error.o
#OBJS.test91+= error.o
#OBJS.test92+= error.o
#OBJS.test93+= error.o
.if ${USE_INET6} == "no"
# Tests 91-94 will fail without IPv6 support, but they should at least compile.
CPPFLAGS.socklib.c += -DNO_INET6
CPPFLAGS.test94.c += -DNO_INET6
.endif # ${USE_INET6} == "no"
# Tests to compile, For every architecture
MINIX_TESTS= \
@ -66,7 +78,7 @@ MINIX_TESTS= \
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
81 82 83 84 85 86 87 88 89 90
81 82 83 84 85 86 87 88 89 90 91 92 93 94
FILES += t84_h_nonexec.sh

View File

@ -22,7 +22,8 @@ export USENETWORK # set to "yes" for test48+82 to use the network
# Programs that require setuid
setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \
test69 test73 test74 test78 test83 test85 test87 test88 test89"
test69 test73 test74 test78 test83 test85 test87 test88 test89 \
test92 test93 test94"
# Scripts that require to be run as root
rootscripts="testisofs testvnd testrmib testrelpol"
@ -30,7 +31,7 @@ alltests="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
81 82 83 84 85 86 87 88 89 90 \
81 82 83 84 85 86 87 88 89 90 91 92 93 94 \
sh1 sh2 interp mfs isofs vnd rmib"
tests_no=`expr 0`

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,28 @@
#ifndef MINIX_TEST_SOCKLIB_H
#define MINIX_TEST_SOCKLIB_H
/* TCP/IP test values. */
#define TEST_PORT_A 12345 /* this port should be free and usable */
#define TEST_PORT_B 12346 /* this port should be free and usable */
#define LOOPBACK_IFNAME "lo0" /* loopback interface name */
#define LOOPBACK_IPV4 "127.0.0.1" /* IPv4 address */
#define LOOPBACK_LL_IPV6 "fe80::1" /* link-local IPv6 address */
/* These address should simply eat all packets. */
/*
* IMPORTANT: the ::2 address works only if there is a route for ::/64. This
* route is supposed to be added by /etc/rc.d/network, and is not present by
* default. As a result, the tests will pass only when regular system/network
* initialization is not skipped. We cannot add the route ourselves, since not
* all tests run as root.
*/
#define TEST_BLACKHOLE_IPV4 "127.255.0.254"
#define TEST_BLACKHOLE_IPV6 "::2"
#define TEST_BLACKHOLE_LL_IPV6 "fe80::ffff"
#define BAD_SCOPE_ID 255 /* guaranteed not to belong to an interface */
enum state {
S_NEW,
S_N_SHUT_R,
@ -81,9 +103,14 @@ void socklib_sweep(int domain, int type, int protocol,
int (* proc)(int domain, int type, int protocol, enum state,
enum call));
void socklib_multicast_tx_options(int type);
void socklib_large_transfers(int fd[2]);
void socklib_producer_consumer(int fd[2]);
void socklib_stream_recv(int (* socket_pair)(int, int, int, int *), int domain,
int type, int (* break_recv)(int, const char *, size_t));
int socklib_find_pcb(const char * path, int protocol, uint16_t local_port,
uint16_t remote_port, struct kinfo_pcb * ki);
void socklib_test_addrs(int type, int protocol);
void socklib_test_multicast(int type, int protocol);
#endif /* !MINIX_TEST_SOCKLIB_H */

5396
minix/tests/test91.c Normal file

File diff suppressed because it is too large Load Diff

1735
minix/tests/test92.c Normal file

File diff suppressed because it is too large Load Diff

839
minix/tests/test93.c Normal file
View File

@ -0,0 +1,839 @@
/* Tests for network interfaces and routing (LWIP) - by D.C. van Moolenbroek */
/* This test needs to be run as root: it manipulates network settings. */
/*
* TODO: due to time constraints, this test is currently absolutely minimal.
* It does not yet test by far most of the service code it is supposed to test,
* in particular interface management code, interface address assignment code,
* routing sockets code, and routing code. The second subtest (test93b) in this
* file serves as a reasonable example of how many of the future subtests
* should operate, though: by issuing interface IOCTLs and routing commands on
* a loopback interface created for the occasion.
*/
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet6/in6_var.h>
#include <arpa/inet.h>
#include "common.h"
#include "socklib.h"
#define TEST_IFNAME "lo93"
#define ITERATIONS 2
static const enum state rtlnk_states[] = {
S_NEW, S_N_SHUT_R, S_N_SHUT_W, S_N_SHUT_RW,
};
static const int rt_results[][__arraycount(rtlnk_states)] = {
[C_ACCEPT] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_BIND] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_CONNECT] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_GETPEERNAME] = {
0, 0, 0, 0,
},
[C_GETSOCKNAME] = {
0, 0, 0, 0,
},
[C_GETSOCKOPT_ERR] = {
0, 0, 0, 0,
},
[C_GETSOCKOPT_KA] = {
0, 0, 0, 0,
},
[C_GETSOCKOPT_RB] = {
0, 0, 0, 0,
},
[C_IOCTL_NREAD] = {
0, 0, 0, 0,
},
[C_LISTEN] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_RECV] = {
-EAGAIN, 0, -EAGAIN, 0,
},
[C_RECVFROM] = {
-EAGAIN, 0, -EAGAIN, 0,
},
[C_SEND] = {
-ENOBUFS, -ENOBUFS, -EPIPE, -EPIPE,
},
[C_SENDTO] = {
-EISCONN, -EISCONN, -EPIPE, -EPIPE,
},
[C_SELECT_R] = {
0, 1, 0, 1,
},
[C_SELECT_W] = {
1, 1, 1, 1,
},
[C_SELECT_X] = {
0, 0, 0, 0,
},
[C_SETSOCKOPT_BC] = {
0, 0, 0, 0,
},
[C_SETSOCKOPT_KA] = {
0, 0, 0, 0,
},
[C_SETSOCKOPT_L] = {
0, 0, 0, 0,
},
[C_SETSOCKOPT_RA] = {
0, 0, 0, 0,
},
[C_SHUTDOWN_R] = {
0, 0, 0, 0,
},
[C_SHUTDOWN_RW] = {
0, 0, 0, 0,
},
[C_SHUTDOWN_W] = {
0, 0, 0, 0,
},
};
static const int lnk_results[][__arraycount(rtlnk_states)] = {
[C_ACCEPT] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_BIND] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_CONNECT] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_GETPEERNAME] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_GETSOCKNAME] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_GETSOCKOPT_ERR] = {
0, 0, 0, 0,
},
[C_GETSOCKOPT_KA] = {
0, 0, 0, 0,
},
[C_GETSOCKOPT_RB] = {
-ENOPROTOOPT, -ENOPROTOOPT, -ENOPROTOOPT, -ENOPROTOOPT,
},
[C_IOCTL_NREAD] = {
0, 0, 0, 0,
},
[C_LISTEN] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP, -EOPNOTSUPP,
},
[C_RECV] = {
-EOPNOTSUPP, 0, -EOPNOTSUPP, 0,
},
[C_RECVFROM] = {
-EOPNOTSUPP, 0, -EOPNOTSUPP, 0,
},
[C_SEND] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EPIPE, -EPIPE,
},
[C_SENDTO] = {
-EOPNOTSUPP, -EOPNOTSUPP, -EPIPE, -EPIPE,
},
[C_SELECT_R] = {
1, 1, 1, 1,
},
[C_SELECT_W] = {
1, 1, 1, 1,
},
[C_SELECT_X] = {
0, 0, 0, 0,
},
[C_SETSOCKOPT_BC] = {
0, 0, 0, 0,
},
[C_SETSOCKOPT_KA] = {
0, 0, 0, 0,
},
[C_SETSOCKOPT_L] = {
0, 0, 0, 0,
},
[C_SETSOCKOPT_RA] = {
0, 0, 0, 0,
},
[C_SHUTDOWN_R] = {
0, 0, 0, 0,
},
[C_SHUTDOWN_RW] = {
0, 0, 0, 0,
},
[C_SHUTDOWN_W] = {
0, 0, 0, 0,
},
};
/*
* Set up a routing or link socket file descriptor in the requested state and
* pass it to socklib_sweep_call() along with local and remote addresses and
* their lengths.
*/
static int
rtlnk_sweep(int domain, int type, int protocol, enum state state,
enum call call)
{
struct sockaddr sa;
int r, fd;
memset(&sa, 0, sizeof(sa));
sa.sa_family = domain;
if ((fd = socket(domain, type | SOCK_NONBLOCK, protocol)) < 0) e(0);
switch (state) {
case S_NEW: break;
case S_N_SHUT_R: if (shutdown(fd, SHUT_RD)) e(0); break;
case S_N_SHUT_W: if (shutdown(fd, SHUT_WR)) e(0); break;
case S_N_SHUT_RW: if (shutdown(fd, SHUT_RDWR)) e(0); break;
default: e(0);
}
r = socklib_sweep_call(call, fd, &sa, &sa,
offsetof(struct sockaddr, sa_data));
if (close(fd) != 0) e(0);
return r;
}
/*
* Sweep test for socket calls versus socket states of routing and link
* sockets.
*/
static void
test93a(void)
{
subtest = 1;
socklib_sweep(AF_ROUTE, SOCK_RAW, 0, rtlnk_states,
__arraycount(rtlnk_states), (const int *)rt_results, rtlnk_sweep);
/*
* Our implementation of link sockets currently serves only one
* purpose, and that is to pass on ioctl() calls issued on the socket.
* As such, the results here are not too important. The test mostly
* ensures that all calls actually complete--for example, that there is
* no function pointer NULL check missing in libsockevent.
*/
socklib_sweep(AF_LINK, SOCK_DGRAM, 0, rtlnk_states,
__arraycount(rtlnk_states), (const int *)lnk_results, rtlnk_sweep);
}
/*
* Attempt to destroy the test loopback interface. Return 0 if destruction was
* successful, or -1 if no such interface existed.
*/
static int
test93_destroy_if(void)
{
struct ifreq ifr;
int r, fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, TEST_IFNAME, sizeof(ifr.ifr_name));
r = ioctl(fd, SIOCIFDESTROY, &ifr);
if (r != 0 && (r != -1 || errno != ENXIO)) e(0);
if (close(fd) != 0) e(0);
return r;
}
/*
* Destroy the test interface at exit. It is always safe to do so as its name
* is sufficiently unique, and we do not want to leave it around.
*/
static void
test93_destroy_if_atexit(void)
{
static int atexit_set = 0;
if (!atexit_set) {
(void)test93_destroy_if();
atexit_set = 1;
}
}
/*
* Attempt to create a test loopback interface. Return 0 if creation was
* successful, or -1 if no more interfaces could be created.
*/
static int
test93_create_if(void)
{
struct ifreq ifr;
int r, fd;
(void)test93_destroy_if();
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, TEST_IFNAME, sizeof(ifr.ifr_name));
r = ioctl(fd, SIOCIFCREATE, &ifr);
if (r != 0 && (r != -1 || errno != ENOBUFS)) e(0);
if (close(fd) != 0) e(0);
atexit(test93_destroy_if_atexit);
return r;
}
/*
* Set the interface-up value for an interface to the given boolean value.
*/
static void
test93_set_if_up(const char * ifname, int up)
{
struct ifreq ifr;
int fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) e(0);
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, TEST_IFNAME, sizeof(ifr.ifr_name));
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) e(0);
if (up)
ifr.ifr_flags |= IFF_UP;
else
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) e(0);
if (close(fd) != 0) e(0);
}
/*
* Construct an IPv6 network mask for a certain prefix length.
*/
static void
test93_make_netmask6(struct sockaddr_in6 * sin6, unsigned int prefix)
{
unsigned int byte, bit;
if (prefix > 128) e(0);
memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
byte = prefix / NBBY;
bit = prefix % NBBY;
if (byte > 0)
memset(sin6->sin6_addr.s6_addr, 0xff, byte);
if (bit != 0)
sin6->sin6_addr.s6_addr[byte] = 0xff << (NBBY - bit);
}
/*
* Issue a modifying routing command, which must be one of RTM_ADD, RTM_CHANGE,
* RTM_DELETE, or RTM_LOCK. The destination address (IPv4 or IPv6) and netmask
* prefix are required. The flags (RTF_), interface name, and gateway are
* optional depending on the command (and flags) being issued. Return 0 on
* success, and -1 with errno set on failure.
*/
static int
test93_route_cmd(int cmd, const struct sockaddr * dest, socklen_t dest_len,
unsigned int prefix, int flags, const char * ifname,
const struct sockaddr * gw, socklen_t gw_len)
{
static unsigned int seq = 0;
struct sockaddr_storage destss, maskss, ifpss, gwss;
struct sockaddr_in mask4;
struct sockaddr_in6 mask6;
struct sockaddr_dl ifp;
struct rt_msghdr rtm;
struct iovec iov[5];
struct msghdr msg;
unsigned int i, iovlen;
int r, fd, err;
memset(&rtm, 0, sizeof(rtm));
rtm.rtm_version = RTM_VERSION;
rtm.rtm_type = cmd;
rtm.rtm_flags = flags;
rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
rtm.rtm_seq = ++seq;
iovlen = 0;
iov[iovlen].iov_base = &rtm;
iov[iovlen++].iov_len = sizeof(rtm);
memset(&destss, 0, sizeof(destss));
memcpy(&destss, dest, dest_len);
destss.ss_len = dest_len;
iov[iovlen].iov_base = &destss;
iov[iovlen++].iov_len = RT_ROUNDUP(dest_len);
/* Do this in RTA order. */
memset(&gwss, 0, sizeof(gwss));
if (gw != NULL) {
memcpy(&gwss, gw, gw_len);
gwss.ss_len = gw_len;
rtm.rtm_addrs |= RTA_GATEWAY;
iov[iovlen].iov_base = &gwss;
iov[iovlen++].iov_len = RT_ROUNDUP(gwss.ss_len);
}
memset(&maskss, 0, sizeof(maskss));
switch (dest->sa_family) {
case AF_INET:
if (prefix > 32) e(0);
memset(&mask4, 0, sizeof(mask4));
mask4.sin_family = AF_INET;
if (prefix < 32)
mask4.sin_addr.s_addr = htonl(0xffffffffUL << prefix);
memcpy(&maskss, &mask4, sizeof(mask4));
maskss.ss_len = sizeof(mask4);
break;
case AF_INET6:
test93_make_netmask6(&mask6, prefix);
memcpy(&maskss, &mask6, sizeof(mask6));
maskss.ss_len = sizeof(mask6);
break;
default:
e(0);
}
iov[iovlen].iov_base = &maskss;
iov[iovlen++].iov_len = RT_ROUNDUP(maskss.ss_len);
if (ifname != NULL) {
memset(&ifp, 0, sizeof(ifp));
ifp.sdl_nlen = strlen(ifname);
ifp.sdl_len = offsetof(struct sockaddr_dl, sdl_data) +
ifp.sdl_nlen;
ifp.sdl_family = AF_LINK;
memset(&ifpss, 0, sizeof(ifpss));
memcpy(&ifpss, &ifp, ifp.sdl_len);
memcpy(&((struct sockaddr_dl *)&ifpss)->sdl_data, ifname,
ifp.sdl_nlen);
rtm.rtm_addrs |= RTA_IFP;
iov[iovlen].iov_base = &ifpss;
iov[iovlen++].iov_len = RT_ROUNDUP(ifpss.ss_len);
}
memset(&msg, 0, sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = iovlen;
if ((fd = socket(AF_ROUTE, SOCK_RAW, 0)) < 0) e(0);
for (i = 0; i < iovlen; i++)
rtm.rtm_msglen += iov[i].iov_len;
r = sendmsg(fd, &msg, 0);
if (r != rtm.rtm_msglen && r != -1) e(0);
err = errno;
/*
* We could just shut down the socket for reading, but this is just an
* extra test we can do basically for free.
*/
rtm.rtm_seq = 0;
do {
iov[0].iov_base = &rtm;
iov[0].iov_len = sizeof(rtm);
if (recvmsg(fd, &msg, 0) <= 0) e(0);
} while (rtm.rtm_pid != getpid() || rtm.rtm_seq != seq);
if (r == -1) {
if (rtm.rtm_errno != err) e(0);
if (rtm.rtm_flags & RTF_DONE) e(0);
} else {
if (rtm.rtm_errno != 0) e(0);
if (!(rtm.rtm_flags & RTF_DONE)) e(0);
}
if (close(fd) != 0) e(0);
errno = err;
return (r > 0) ? 0 : -1;
}
/*
* Add or delete an IPv6 address to or from an interface. The interface name,
* address, and prefix length must always be given. When adding, a set of
* flags (IN6_IFF) and lifetimes must be given as well.
*/
static void
test93_ipv6_addr(int add, const char * ifname,
const struct sockaddr_in6 * sin6, unsigned int prefix, int flags,
uint32_t valid_life, uint32_t pref_life)
{
struct in6_aliasreq ifra;
int fd;
memset(&ifra, 0, sizeof(ifra));
strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
memcpy(&ifra.ifra_addr, sin6, sizeof(ifra.ifra_addr));
/* leave ifra_dstaddr blank */
test93_make_netmask6(&ifra.ifra_prefixmask, prefix);
ifra.ifra_flags = flags;
ifra.ifra_lifetime.ia6t_vltime = valid_life;
ifra.ifra_lifetime.ia6t_pltime = pref_life;
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) e(0);
if (ioctl(fd, (add) ? SIOCAIFADDR_IN6 : SIOCDIFADDR_IN6, &ifra) != 0)
e(0);
if (close(fd) != 0) e(0);
}
static const struct {
int result; /* 0..2 = prefer srcN, -1 = no preference */
const char *dest_addr;
const char *src0_addr;
unsigned int src0_prefix;
int src0_flags;
const char *src1_addr;
unsigned int src1_prefix;
int src1_flags;
const char *src2_addr;
unsigned int src2_prefix;
int src2_flags;
} test93b_table[] = {
/*
* These are all the applicable tests from RFC 6724 Sec. 10.1, slightly
* changed not to use the default link-local address of lo0.
*/
/* Prefer appropriate scope: */
{ 0, "2001:db8:1::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
/* Prefer appropriate scope: */
{ 0, "ff05::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
/* Prefer same address: */
{ 0, "2001:db8:1::1", "2001:db8:1::1", 64, IN6_IFF_DEPRECATED,
"2001:db8:2::1", 64, 0 },
/* Prefer appropriate scope: */
{ 0, "fe80::93:1", "fe80::93:2", 64, IN6_IFF_DEPRECATED,
"2001:db8:2::1", 64, 0 },
/* Longest matching prefix: */
{ 0, "2001:db8:1::1", "2001:db8:1::2", 64, 0, "2001:db8:3::2", 64, 0 },
/* Prefer matching label: */
{ 0, "2002:c633:6401::1", "2002:c633:6401::d5e3:7953:13eb:22e8", 64,
IN6_IFF_TEMPORARY, "2001:db8:1::2", 64, 0 },
/* Prefer temporary address: */
{ 1, "2001:db8:1::d5e3:0:0:1", "2001:db8:1::2", 64, 0,
"2001:db8:1::d5e3:7953:13eb:22e8", 64, IN6_IFF_TEMPORARY },
/*
* Our own additional tests.
*/
/* Prefer same address: */
{ 1, "4000:93::1", "2001:db8:3::1", 64, 0, "4000:93::1", 64, 0 },
{ 2, "2001:db8:1::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0,
"2001:db8:1::1", 64, 0 },
/* Prefer appropriate scope: */
{ 1, "ff01::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
{ 1, "ff02::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
{ 0, "ff0e::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
{ 1, "fd00:93::1", "2001:db8:3::1", 64, 0, "fd00::93:2", 64, 0 },
{ 1, "fd00:93::1", "fe80::93:1", 64, 0, "fd00::93:2", 64, 0 },
{ 0, "fd00:93::1", "2001:db8:3::1", 64, 0, "fe80::93:1", 64, 0 },
{ 1, "2001:db8:1::1", "fe80::93:1", 64, 0, "fd00::93:2", 64, 0 },
{ 0, "2001:db8:1::1", "2001:db8:3::1", 64, 0, "4000:93::1", 64, 0 },
{ 0, "4000:93::2", "2001:db8:3::1", 64, 0, "4000:93::1", 64, 0 },
{ 2, "2001:db8:1::1", "fe80::93:1", 64, 0, "fd00::93:1", 64, 0,
"2001:db8:3::1", 64, 0 },
{ 2, "2001:db8:1::1", "fe80::93:1", 64, IN6_IFF_DEPRECATED,
"fe80::93:2", 64, 0, "2001:db8:3::1", 64, 0 },
/* Avoid deprecated address: */
{ 1, "2002:c633:6401::1", "2002:c633:6401::d5e3:7953:13eb:22e8", 64,
IN6_IFF_DEPRECATED, "2001:db8:1::2", 64, 0 },
{ 2, "2001:db8:1::1", "2001:db8:1::3", 64, IN6_IFF_DEPRECATED,
"2001:db8:2::1", 64, IN6_IFF_DEPRECATED, "2001:db8:3::1", 64, 0 },
{ 2, "2001:db8:1::1", "2002:db8:1::3", 64, IN6_IFF_DEPRECATED,
"2001:db8:2::1", 64, IN6_IFF_DEPRECATED, "2001:db8:3::1", 64, 0 },
/* Prefer matching label: */
{ 0, "2002:c633:6401::1", "2002:c633:6401::d5e3:7953:13eb:22e8", 64, 0,
"2001:db8:1::2", 64, IN6_IFF_TEMPORARY },
{ 2, "2002:c633:6401::1", "2001:db8:3::2", 64, 0, "2001:db8:1::2", 64,
IN6_IFF_TEMPORARY, "2002:c633:6401::d5e3:7953:13eb:22e8", 64, 0 },
{ 2, "2001:db8:1::1", "2003:db8::1", 64, 0, "3ffe:db8::1", 64, 0,
"2001:db8:3::1", 64, 0 },
/* Prefer temporary address: */
{ 0, "2001:db8:1::d5e3:0:0:1", "2001:db8:1::2", 96, IN6_IFF_TEMPORARY,
"2001:db8:1::d5e3:7953:13eb:22e8", 96, 0 },
{ 2, "2002:c633:6401::1", "2001:db8:3::2", 64, 0, "2002:c633:6401::2",
64, 0, "2002:c633:6401::d5e3:7953:13eb:22e8", 64,
IN6_IFF_TEMPORARY },
/* Longest matching prefix: */
{ 1, "2001:db8:1::d5e3:0:0:1", "2001:db8:1::2", 96, 0,
"2001:db8:1::d5e3:7953:13eb:22e8", 96, 0 },
{ 2, "2001:db8:1:1::1", "2001:db8:2:1::2", 64, 0, "2001:db8:1:2::2",
64, 0, "2001:db8:1:1::2", 64, 0 },
{ 0, "2001:db8:1::1", "2001:db8:1::2", 47, 0, "2001:db8:3::2", 47, 0 },
/* No preference (a tie): */
{ -1, "2001:db8:1::1", "2001:db8:1::2", 46, 0, "2001:db8:3::2", 46,
0 },
{ -1, "2001:db8::1:0:0:1", "2001:db8::1:0:0:2", 64, 0,
"2001:db8::2:0:0:2", 64, 0, "2001:db8::3:0:0:2", 64, 0 },
};
struct src_addr {
struct sockaddr_in6 addr;
unsigned int prefix;
int flags;
};
/*
* Test source address selection with a particular destination address and two
* or three source addresses.
*/
static void
sub93b(int result, const struct sockaddr_in6 * dest, unsigned int ifindex,
const struct src_addr * src0, const struct src_addr * src1,
const struct src_addr * src2)
{
struct sockaddr_in6 dest_copy, src;
socklen_t len;
int fd, rt_res;
/* Add the candidate source addresses. */
test93_ipv6_addr(1, TEST_IFNAME, &src0->addr, src0->prefix,
src0->flags, 0xffffffffUL, 0xffffffffUL);
test93_ipv6_addr(1, TEST_IFNAME, &src1->addr, src1->prefix,
src1->flags, 0xffffffffUL, 0xffffffffUL);
if (src2 != NULL)
test93_ipv6_addr(1, TEST_IFNAME, &src2->addr, src2->prefix,
src2->flags, 0xffffffffUL, 0xffffffffUL);
/*
* We need to make sure that packets to the destination are routed to
* our test interface at all, so create a route for it. Creating the
* route may fail if the destination address is equal to either of the
* source addresses, but that is fine. We use a blackhole route here,
* but this test should not generate any traffic anyway.
*/
rt_res = test93_route_cmd(RTM_ADD, (struct sockaddr *)dest,
sizeof(*dest), 128, RTF_UP | RTF_BLACKHOLE | RTF_STATIC,
TEST_IFNAME, NULL, 0);
if (rt_res != 0 && (rt_res != -1 || errno != EEXIST)) e(0);
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) e(0);
/* Set a scope ID if necessary. */
memcpy(&dest_copy, dest, sizeof(dest_copy));
dest_copy.sin6_port = 1; /* anything that is not zero */
if (IN6_IS_ADDR_LINKLOCAL(&dest_copy.sin6_addr) ||
IN6_IS_ADDR_MC_NODELOCAL(&dest_copy.sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&dest_copy.sin6_addr))
dest_copy.sin6_scope_id = ifindex;
/* Connecting also selects a source address. */
if (connect(fd, (struct sockaddr *)&dest_copy, sizeof(dest_copy)) != 0)
e(0);
/* Obtain the selected source address. */
len = sizeof(src);
if (getsockname(fd, (struct sockaddr *)&src, &len) != 0) e(0);
/*
* If the chosen destination address has a scope ID, it must be for our
* test interface.
*/
if (src.sin6_scope_id != 0 && src.sin6_scope_id != ifindex) e(0);
/* Is it the expected candidate source address? */
if (!memcmp(&src.sin6_addr, &src0->addr.sin6_addr,
sizeof(src.sin6_addr))) {
if (result != 0) e(0);
} else if (!memcmp(&src.sin6_addr, &src1->addr.sin6_addr,
sizeof(src.sin6_addr))) {
if (result != 1) e(0);
} else if (src2 != NULL && !memcmp(&src.sin6_addr,
&src2->addr.sin6_addr, sizeof(src.sin6_addr))) {
if (result != 2) e(0);
} else
e(0);
/* Clean up. */
if (close(fd) != 0) e(0);
if (rt_res == 0) {
if (test93_route_cmd(RTM_DELETE, (struct sockaddr *)dest,
sizeof(*dest), 128, 0, NULL, NULL, 0) != 0) e(0);
}
if (src2 != NULL)
test93_ipv6_addr(0, TEST_IFNAME, &src2->addr, src2->prefix, 0,
0, 0);
test93_ipv6_addr(0, TEST_IFNAME, &src1->addr, src1->prefix, 0, 0, 0);
test93_ipv6_addr(0, TEST_IFNAME, &src0->addr, src0->prefix, 0, 0, 0);
}
/*
* IPv6 source address selection algorithm test.
*/
static void
test93b(void)
{
static const int order[][3] = {
{ 0, 1, 2 },
{ 1, 0, 2 },
{ 0, 2, 1 },
{ 1, 2, 0 },
{ 2, 0, 1 },
{ 2, 1, 0 }
};
struct sockaddr_in6 dest;
struct src_addr src[3];
unsigned int i, j, k, count, ifindex;
int result;
subtest = 2;
if (test93_create_if() != 0)
return; /* skip this test */
if ((ifindex = if_nametoindex(TEST_IFNAME)) == 0) e(0);
test93_set_if_up(TEST_IFNAME, 1);
for (i = 0; i < __arraycount(test93b_table); i++) {
memset(&dest, 0, sizeof(dest));
dest.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, test93b_table[i].dest_addr,
&dest.sin6_addr) != 1) e(0);
memset(&src[0].addr, 0, sizeof(src[0].addr));
src[0].addr.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, test93b_table[i].src0_addr,
&src[0].addr.sin6_addr) != 1) e(0);
src[0].prefix = test93b_table[i].src0_prefix;
src[0].flags = test93b_table[i].src0_flags;
memset(&src[1].addr, 0, sizeof(src[1].addr));
src[1].addr.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, test93b_table[i].src1_addr,
&src[1].addr.sin6_addr) != 1) e(0);
src[1].prefix = test93b_table[i].src1_prefix;
src[1].flags = test93b_table[i].src1_flags;
if (test93b_table[i].src2_addr != NULL) {
memset(&src[2].addr, 0, sizeof(src[2].addr));
src[2].addr.sin6_family = AF_INET6;
if (inet_pton(AF_INET6, test93b_table[i].src2_addr,
&src[2].addr.sin6_addr) != 1) e(0);
src[2].prefix = test93b_table[i].src2_prefix;
src[2].flags = test93b_table[i].src2_flags;
count = 6;
} else
count = 2;
result = test93b_table[i].result;
/*
* Try all orders for the source addresses. The permutation
* part can be done much better, but it really does not matter.
*/
for (j = 0; j < count; j++) {
for (k = 0; k < count; k++)
if (result == -1 || order[j][k] == result)
break;
sub93b((result != -1) ? k : 0, &dest, ifindex,
&src[order[j][0]], &src[order[j][1]],
(count > 2) ? &src[order[j][2]] : NULL);
}
}
if (test93_destroy_if() != 0) e(0);
}
/*
* Interface index number wrapping test.
*/
static void
test93c(void)
{
unsigned int i;
subtest = 3;
/* There might not be an available loopback interface at all. */
if (test93_create_if() != 0)
return; /* skip this test */
if (test93_destroy_if() != 0) e(0);
/*
* During the development of the LWIP service, the lwIP library's
* interface index assignment was still in its infancy. This test aims
* to ensure that future changes in the library do not break our
* service.
*/
for (i = 0; i < UINT8_MAX + 1; i++) {
if (test93_create_if() != 0) e(0);
if (test93_destroy_if() != 0) e(0);
}
}
/*
* Test program for LWIP interface and routing management.
*/
int
main(int argc, char ** argv)
{
int i, m;
start(93);
if (argc == 2)
m = atoi(argv[1]);
else
m = 0xFF;
for (i = 0; i < ITERATIONS; i++) {
if (m & 0x01) test93a();
if (m & 0x02) test93b();
if (m & 0x04) test93c();
}
quit();
/* NOTREACHED */
}

2650
minix/tests/test94.c Normal file

File diff suppressed because it is too large Load Diff