diff options
Diffstat (limited to 'tests/sys/netinet')
-rw-r--r-- | tests/sys/netinet/Makefile | 1 | ||||
-rwxr-xr-x | tests/sys/netinet/carp.sh | 3 | ||||
-rw-r--r-- | tests/sys/netinet/multicast-receive.c | 16 | ||||
-rwxr-xr-x | tests/sys/netinet/multicast.sh | 76 | ||||
-rw-r--r-- | tests/sys/netinet/so_reuseport_lb_test.c | 148 | ||||
-rw-r--r-- | tests/sys/netinet/tcp_hpts_test.py | 4 |
6 files changed, 229 insertions, 19 deletions
diff --git a/tests/sys/netinet/Makefile b/tests/sys/netinet/Makefile index b742342beecb..9739221676ce 100644 --- a/tests/sys/netinet/Makefile +++ b/tests/sys/netinet/Makefile @@ -30,6 +30,7 @@ ATF_TESTS_SH= arp \ ATF_TESTS_PYTEST+= carp.py ATF_TESTS_PYTEST+= igmp.py +ATF_TESTS_PYTEST+= tcp_hpts_test.py LIBADD.so_reuseport_lb_test= pthread LIBADD.udp_bindings= pthread diff --git a/tests/sys/netinet/carp.sh b/tests/sys/netinet/carp.sh index 2aae2854826e..568d2beaf914 100755 --- a/tests/sys/netinet/carp.sh +++ b/tests/sys/netinet/carp.sh @@ -215,6 +215,9 @@ unicast_v4_body() unicast_v4_cleanup() { + jexec carp_uni_v4_one killall routed + jexec carp_uni_v4_two killall routed + jexec carp_uni_v4_three killall routed vnet_cleanup } diff --git a/tests/sys/netinet/multicast-receive.c b/tests/sys/netinet/multicast-receive.c index 81d0f10f5cfe..62fc68200dd6 100644 --- a/tests/sys/netinet/multicast-receive.c +++ b/tests/sys/netinet/multicast-receive.c @@ -36,6 +36,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sysexits.h> #include <limits.h> #include <err.h> @@ -93,8 +94,9 @@ usage: .imr_multiaddr = maddr, .imr_interface = ifaddr, }; - assert(setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)) == 0); + if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) != 0) + err(EX_OSERR, "setsockopt"); } else if (strcmp(argv[1], "ip_mreqn") == 0) { /* * ip_mreqn shall be used with index, but for testing @@ -105,8 +107,9 @@ usage: .imr_address = index ? (struct in_addr){ 0 } : ifaddr, .imr_ifindex = index ? ifindex : 0, }; - assert(setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqn, - sizeof(mreqn)) == 0); + if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqn, + sizeof(mreqn)) != 0) + err(EX_OSERR, "setsockopt"); } else if (strcmp(argv[1], "group_req") == 0) { if (!index) errx(1, "group_req expects index"); @@ -116,8 +119,9 @@ usage: gsa->sin_family = AF_INET; gsa->sin_len = sizeof(struct sockaddr_in); gsa->sin_addr = maddr; - assert(setsockopt(s, IPPROTO_IP, MCAST_JOIN_GROUP, &greq, - sizeof(greq)) == 0); + if (setsockopt(s, IPPROTO_IP, MCAST_JOIN_GROUP, &greq, + sizeof(greq)) != 0) + err(EX_OSERR, "setsockopt"); } else goto usage; diff --git a/tests/sys/netinet/multicast.sh b/tests/sys/netinet/multicast.sh index a3854fd2fd20..34094ff08705 100755 --- a/tests/sys/netinet/multicast.sh +++ b/tests/sys/netinet/multicast.sh @@ -45,6 +45,15 @@ multicast_vnet_init() jexec mjail2 ifconfig ${epair2}b 192.0.3.2/24 } +multicast_join() +{ + jexec mjail2 $(atf_get_srcdir)/multicast-receive \ + $1 233.252.0.1 6676 $2 > out & pid=$! + while ! jexec mjail2 ifmcstat | grep -q 233\.252\.0\.1; do + sleep 0.01 + done +} + atf_test_case "IP_ADD_MEMBERSHIP_ip_mreq" "cleanup" IP_ADD_MEMBERSHIP_ip_mreq_head() { @@ -56,8 +65,7 @@ IP_ADD_MEMBERSHIP_ip_mreq_body() multicast_vnet_init # join group on interface with IP address 192.0.2.2 - jexec mjail2 $(atf_get_srcdir)/multicast-receive \ - ip_mreq 233.252.0.1 6676 192.0.2.2 > out & pid=$! + multicast_join ip_mreq 192.0.2.2 atf_check -s exit:0 -o empty \ jexec mjail1 $(atf_get_srcdir)/multicast-send \ 0.0.0.0 6676 233.252.0.1 6676 192.0.2.1 hello @@ -65,8 +73,28 @@ IP_ADD_MEMBERSHIP_ip_mreq_body() atf_check -s exit:0 -o inline:"192.0.2.1:6676 hello\n" cat out # join group on interface with IP address 192.0.3.2 - jexec mjail2 $(atf_get_srcdir)/multicast-receive \ - ip_mreq 233.252.0.1 6676 192.0.3.2 > out & pid=$! + multicast_join ip_mreq 192.0.3.2 + atf_check -s exit:0 -o empty \ + jexec mjail1 $(atf_get_srcdir)/multicast-send \ + 0.0.0.0 6676 233.252.0.1 6676 192.0.3.1 hello + atf_check -s exit:0 sh -c "wait $pid; exit $?" + atf_check -s exit:0 -o inline:"192.0.3.1:6676 hello\n" cat out + + # join group on the first multicast capable interface (epair1a) + multicast_join ip_mreq 0.0.0.0 + atf_check -s exit:0 -o empty \ + jexec mjail1 $(atf_get_srcdir)/multicast-send \ + 0.0.0.0 6676 233.252.0.1 6676 192.0.2.1 hello + atf_check -s exit:0 sh -c "wait $pid; exit $?" + atf_check -s exit:0 -o inline:"192.0.2.1:6676 hello\n" cat out + + # Set up the receiving jail so that first multicast capable interface + # is epair1a and default route points into epair2a. This will allow us + # to exercise both branches of inp_lookup_mcast_ifp(). + jexec mjail2 route add default 192.0.3.254 + + # join group on the interface determined by the route lookup + multicast_join ip_mreq 0.0.0.0 atf_check -s exit:0 -o empty \ jexec mjail1 $(atf_get_srcdir)/multicast-send \ 0.0.0.0 6676 233.252.0.1 6676 192.0.3.1 hello @@ -90,8 +118,7 @@ IP_ADD_MEMBERSHIP_ip_mreqn_body() multicast_vnet_init # join group on interface epair2 - jexec mjail2 $(atf_get_srcdir)/multicast-receive \ - ip_mreqn 233.252.0.1 6676 ${epair1}b > out & pid=$! + multicast_join ip_mreqn ${epair1}b atf_check -s exit:0 -o empty \ jexec mjail1 $(atf_get_srcdir)/multicast-send \ 0.0.0.0 6676 233.252.0.1 6676 ${epair1}a hello @@ -99,13 +126,25 @@ IP_ADD_MEMBERSHIP_ip_mreqn_body() atf_check -s exit:0 -o inline:"192.0.2.1:6676 hello\n" cat out # join group on interface epair2 - jexec mjail2 $(atf_get_srcdir)/multicast-receive \ - ip_mreqn 233.252.0.1 6676 ${epair2}b > out & pid=$! + multicast_join ip_mreqn ${epair2}b atf_check -s exit:0 -o empty \ jexec mjail1 $(atf_get_srcdir)/multicast-send \ 0.0.0.0 6676 233.252.0.1 6676 ${epair2}a hello atf_check -s exit:0 sh -c "wait $pid; exit $?" atf_check -s exit:0 -o inline:"192.0.3.1:6676 hello\n" cat out + + # try to join group on the interface determined by the route lookup + atf_check -s exit:71 -e inline:"multicast-receive: setsockopt: Can't assign requested address\n" \ + jexec mjail2 $(atf_get_srcdir)/multicast-receive \ + ip_mreqn 233.252.0.1 6676 0 + # add route and try again + jexec mjail2 route add default 192.0.3.254 + multicast_join ip_mreqn 0 + atf_check -s exit:0 -o empty \ + jexec mjail1 $(atf_get_srcdir)/multicast-send \ + 0.0.0.0 6676 233.252.0.1 6676 192.0.3.1 hello + atf_check -s exit:0 sh -c "wait $pid; exit $?" + atf_check -s exit:0 -o inline:"192.0.3.1:6676 hello\n" cat out } IP_ADD_MEMBERSHIP_ip_mreqn_cleanup() { @@ -123,9 +162,8 @@ MCAST_JOIN_GROUP_body() { multicast_vnet_init - # join group on interface epair2 - jexec mjail2 $(atf_get_srcdir)/multicast-receive \ - group_req 233.252.0.1 6676 ${epair1}b > out & pid=$! + # join group on interface epair1 + multicast_join group_req ${epair1}b atf_check -s exit:0 -o empty \ jexec mjail1 $(atf_get_srcdir)/multicast-send \ 0.0.0.0 6676 233.252.0.1 6676 ${epair1}a hello @@ -133,13 +171,25 @@ MCAST_JOIN_GROUP_body() atf_check -s exit:0 -o inline:"192.0.2.1:6676 hello\n" cat out # join group on interface epair2 - jexec mjail2 $(atf_get_srcdir)/multicast-receive \ - group_req 233.252.0.1 6676 ${epair2}b > out & pid=$! + multicast_join group_req ${epair2}b atf_check -s exit:0 -o empty \ jexec mjail1 $(atf_get_srcdir)/multicast-send \ 0.0.0.0 6676 233.252.0.1 6676 ${epair2}a hello atf_check -s exit:0 sh -c "wait $pid; exit $?" atf_check -s exit:0 -o inline:"192.0.3.1:6676 hello\n" cat out + + # try to join group on the interface determined by the route lookup + atf_check -s exit:71 -e inline:"multicast-receive: setsockopt: Can't assign requested address\n" \ + jexec mjail2 $(atf_get_srcdir)/multicast-receive \ + group_req 233.252.0.1 6676 0 + # add route and try again + jexec mjail2 route add default 192.0.3.254 + multicast_join group_req 0 + atf_check -s exit:0 -o empty \ + jexec mjail1 $(atf_get_srcdir)/multicast-send \ + 0.0.0.0 6676 233.252.0.1 6676 192.0.3.1 hello + atf_check -s exit:0 sh -c "wait $pid; exit $?" + atf_check -s exit:0 -o inline:"192.0.3.1:6676 hello\n" cat out } MCAST_JOIN_GROUP_cleanup() { diff --git a/tests/sys/netinet/so_reuseport_lb_test.c b/tests/sys/netinet/so_reuseport_lb_test.c index 0479bd070ca6..393a626af5a4 100644 --- a/tests/sys/netinet/so_reuseport_lb_test.c +++ b/tests/sys/netinet/so_reuseport_lb_test.c @@ -29,6 +29,8 @@ #include <sys/param.h> #include <sys/event.h> +#include <sys/filio.h> +#include <sys/ioccom.h> #include <sys/socket.h> #include <netinet/in.h> @@ -556,6 +558,150 @@ ATF_TC_BODY(connect_bound, tc) close(s); } +/* + * The kernel erroneously permits calling connect() on a UDP socket with + * SO_REUSEPORT_LB set. Verify that packets sent to the bound address are + * dropped unless they come from the connected address. + */ +ATF_TC_WITHOUT_HEAD(connect_udp); +ATF_TC_BODY(connect_udp, tc) +{ + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_len = sizeof(sin), + .sin_addr = { htonl(INADDR_LOOPBACK) }, + }; + ssize_t n; + int error, len, s1, s2, s3; + char ch; + + s1 = socket(PF_INET, SOCK_DGRAM, 0); + ATF_REQUIRE(s1 >= 0); + s2 = socket(PF_INET, SOCK_DGRAM, 0); + ATF_REQUIRE(s2 >= 0); + s3 = socket(PF_INET, SOCK_DGRAM, 0); + ATF_REQUIRE(s3 >= 0); + + error = setsockopt(s1, SOL_SOCKET, SO_REUSEPORT_LB, (int[]){1}, + sizeof(int)); + ATF_REQUIRE_MSG(error == 0, + "setsockopt(SO_REUSEPORT_LB) failed: %s", strerror(errno)); + error = bind(s1, (struct sockaddr *)&sin, sizeof(sin)); + ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); + + error = bind(s2, (struct sockaddr *)&sin, sizeof(sin)); + ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); + + error = bind(s3, (struct sockaddr *)&sin, sizeof(sin)); + ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); + + /* Connect to an address not owned by s2. */ + error = getsockname(s3, (struct sockaddr *)&sin, + (socklen_t[]){sizeof(sin)}); + ATF_REQUIRE(error == 0); + error = connect(s1, (struct sockaddr *)&sin, sizeof(sin)); + ATF_REQUIRE_MSG(error == 0, "connect() failed: %s", strerror(errno)); + + /* Try to send a packet to s1 from s2. */ + error = getsockname(s1, (struct sockaddr *)&sin, + (socklen_t[]){sizeof(sin)}); + ATF_REQUIRE(error == 0); + + ch = 42; + n = sendto(s2, &ch, sizeof(ch), 0, (struct sockaddr *)&sin, + sizeof(sin)); + ATF_REQUIRE(n == 1); + + /* Give the packet some time to arrive. */ + usleep(100000); + + /* s1 is connected to s3 and shouldn't receive from s2. */ + error = ioctl(s1, FIONREAD, &len); + ATF_REQUIRE(error == 0); + ATF_REQUIRE_MSG(len == 0, "unexpected data available"); + + /* ... but s3 can of course send to s1. */ + n = sendto(s3, &ch, sizeof(ch), 0, (struct sockaddr *)&sin, + sizeof(sin)); + ATF_REQUIRE(n == 1); + usleep(100000); + error = ioctl(s1, FIONREAD, &len); + ATF_REQUIRE(error == 0); + ATF_REQUIRE_MSG(len == 1, "expected data available"); +} + +/* + * The kernel erroneously permits calling connect() on a UDP socket with + * SO_REUSEPORT_LB set. Verify that packets sent to the bound address are + * dropped unless they come from the connected address. + */ +ATF_TC_WITHOUT_HEAD(connect_udp6); +ATF_TC_BODY(connect_udp6, tc) +{ + struct sockaddr_in6 sin6 = { + .sin6_family = AF_INET6, + .sin6_len = sizeof(sin6), + .sin6_addr = IN6ADDR_LOOPBACK_INIT, + }; + ssize_t n; + int error, len, s1, s2, s3; + char ch; + + s1 = socket(PF_INET6, SOCK_DGRAM, 0); + ATF_REQUIRE(s1 >= 0); + s2 = socket(PF_INET6, SOCK_DGRAM, 0); + ATF_REQUIRE(s2 >= 0); + s3 = socket(PF_INET6, SOCK_DGRAM, 0); + ATF_REQUIRE(s3 >= 0); + + error = setsockopt(s1, SOL_SOCKET, SO_REUSEPORT_LB, (int[]){1}, + sizeof(int)); + ATF_REQUIRE_MSG(error == 0, + "setsockopt(SO_REUSEPORT_LB) failed: %s", strerror(errno)); + error = bind(s1, (struct sockaddr *)&sin6, sizeof(sin6)); + ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); + + error = bind(s2, (struct sockaddr *)&sin6, sizeof(sin6)); + ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); + + error = bind(s3, (struct sockaddr *)&sin6, sizeof(sin6)); + ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); + + /* Connect to an address not owned by s2. */ + error = getsockname(s3, (struct sockaddr *)&sin6, + (socklen_t[]){sizeof(sin6)}); + ATF_REQUIRE(error == 0); + error = connect(s1, (struct sockaddr *)&sin6, sizeof(sin6)); + ATF_REQUIRE_MSG(error == 0, "connect() failed: %s", strerror(errno)); + + /* Try to send a packet to s1 from s2. */ + error = getsockname(s1, (struct sockaddr *)&sin6, + (socklen_t[]){sizeof(sin6)}); + ATF_REQUIRE(error == 0); + + ch = 42; + n = sendto(s2, &ch, sizeof(ch), 0, (struct sockaddr *)&sin6, + sizeof(sin6)); + ATF_REQUIRE(n == 1); + + /* Give the packet some time to arrive. */ + usleep(100000); + + /* s1 is connected to s3 and shouldn't receive from s2. */ + error = ioctl(s1, FIONREAD, &len); + ATF_REQUIRE(error == 0); + ATF_REQUIRE_MSG(len == 0, "unexpected data available"); + + /* ... but s3 can of course send to s1. */ + n = sendto(s3, &ch, sizeof(ch), 0, (struct sockaddr *)&sin6, + sizeof(sin6)); + ATF_REQUIRE(n == 1); + usleep(100000); + error = ioctl(s1, FIONREAD, &len); + ATF_REQUIRE(error == 0); + ATF_REQUIRE_MSG(len == 1, "expected data available"); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, basic_ipv4); @@ -566,6 +712,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, bind_without_listen); ATF_TP_ADD_TC(tp, connect_not_bound); ATF_TP_ADD_TC(tp, connect_bound); + ATF_TP_ADD_TC(tp, connect_udp); + ATF_TP_ADD_TC(tp, connect_udp6); return (atf_no_error()); } diff --git a/tests/sys/netinet/tcp_hpts_test.py b/tests/sys/netinet/tcp_hpts_test.py new file mode 100644 index 000000000000..c56383fb310f --- /dev/null +++ b/tests/sys/netinet/tcp_hpts_test.py @@ -0,0 +1,4 @@ +from atf_python.ktest import BaseKernelTest + +class TestTcpHpts(BaseKernelTest): + KTEST_MODULE_NAME = "ktest_tcphpts" |