diff options
Diffstat (limited to 'tests/sys/netinet')
-rw-r--r-- | tests/sys/netinet/Makefile | 2 | ||||
-rwxr-xr-x | tests/sys/netinet/divert.sh | 11 | ||||
-rw-r--r-- | tests/sys/netinet/multicast-receive.c | 130 | ||||
-rw-r--r-- | tests/sys/netinet/multicast-send.c (renamed from tests/sys/netinet/sendto-IP_MULTICAST_IF.c) | 62 | ||||
-rwxr-xr-x[-rw-r--r--] | tests/sys/netinet/multicast.sh | 126 | ||||
-rw-r--r-- | tests/sys/netinet/tcp_md5_getsockopt.c | 5 |
6 files changed, 293 insertions, 43 deletions
diff --git a/tests/sys/netinet/Makefile b/tests/sys/netinet/Makefile index cc525bf24480..b742342beecb 100644 --- a/tests/sys/netinet/Makefile +++ b/tests/sys/netinet/Makefile @@ -48,7 +48,7 @@ TEST_METADATA.forward+= required_programs="python" \ TEST_METADATA.output+= required_programs="python" TEST_METADATA.redirect+= required_programs="python" -PROGS= udp_dontroute tcp_user_cookie sendto-IP_MULTICAST_IF +PROGS= udp_dontroute tcp_user_cookie multicast-send multicast-receive ${PACKAGE}FILES+= redirect.py diff --git a/tests/sys/netinet/divert.sh b/tests/sys/netinet/divert.sh index d50620d94a09..f521038ba687 100755 --- a/tests/sys/netinet/divert.sh +++ b/tests/sys/netinet/divert.sh @@ -29,19 +29,13 @@ . $(atf_get_srcdir)/../common/vnet.subr -load_divert_module() { - kldstat -q -m ipdivert - if [ $? -ne 0 ]; then - atf_skip "ipdivert module is not loaded" - fi -} - atf_test_case "ipdivert_ip_output_remote_success" "cleanup" ipdivert_ip_output_remote_success_head() { atf_set descr 'Test diverting IPv4 packet to remote destination' atf_set require.user root atf_set require.progs python3 scapy + atf_set require.kmods ipdivert } ipdivert_ip_output_remote_success_body() { @@ -62,7 +56,6 @@ ipdivert_ip_output_remote_success_body() { fi vnet_init - load_divert_module ip4a="192.0.2.5" ip4b="192.0.2.6" @@ -97,6 +90,7 @@ ipdivert_ip_input_local_success_head() { atf_set descr 'Test diverting IPv4 packet to remote destination' atf_set require.user root atf_set require.progs python3 scapy + atf_set require.kmods ipdivert } ipdivert_ip_input_local_success_body() { @@ -117,7 +111,6 @@ ipdivert_ip_input_local_success_body() { fi vnet_init - load_divert_module ip4a="192.0.2.5" ip4b="192.0.2.6" diff --git a/tests/sys/netinet/multicast-receive.c b/tests/sys/netinet/multicast-receive.c new file mode 100644 index 000000000000..81d0f10f5cfe --- /dev/null +++ b/tests/sys/netinet/multicast-receive.c @@ -0,0 +1,130 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <err.h> + +static in_port_t +atop(const char *c) +{ + unsigned long ul; + + errno = 0; + if ((ul = strtol(c, NULL, 10)) < 1 || ul > IPPORT_MAX || errno != 0) + err(1, "can't parse %s", c); + + return ((in_port_t)ul); +} + +int +main(int argc, char *argv[]) +{ + char buf[IP_MAXPACKET + 1]; + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_len = sizeof(struct sockaddr_in), + }; + socklen_t slen = sizeof(struct sockaddr_in); + struct in_addr maddr, ifaddr; + ssize_t len; + int s, ifindex; + bool index; + + if (argc < 4) +usage: + errx(1, "Usage: %s (ip_mreq|ip_mreqn|group_req) " + "IPv4-group port interface", argv[0]); + + if (inet_pton(AF_INET, argv[2], &maddr) != 1) + err(1, "inet_pton(%s) failed", argv[2]); + sin.sin_port = htons(atop(argv[3])); + if (inet_pton(AF_INET, argv[4], &ifaddr) == 1) + index = false; + else if ((ifindex = if_nametoindex(argv[4])) > 0) + index = true; + else if (strcmp(argv[4], "0") == 0) { + ifindex = 0; + index = true; + } else + err(1, "if_nametoindex(%s) failed", argv[4]); + + assert((s = socket(PF_INET, SOCK_DGRAM, 0)) > 0); + assert(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0); + + if (strcmp(argv[1], "ip_mreq") == 0) { + if (index) + errx(1, "ip_mreq doesn't accept index"); + struct ip_mreq mreq = { + .imr_multiaddr = maddr, + .imr_interface = ifaddr, + }; + assert(setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)) == 0); + } else if (strcmp(argv[1], "ip_mreqn") == 0) { + /* + * ip_mreqn shall be used with index, but for testing + * purposes accept address too. + */ + struct ip_mreqn mreqn = { + .imr_multiaddr = maddr, + .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); + } else if (strcmp(argv[1], "group_req") == 0) { + if (!index) + errx(1, "group_req expects index"); + struct group_req greq = { .gr_interface = ifindex }; + struct sockaddr_in *gsa = (struct sockaddr_in *)&greq.gr_group; + + 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); + } else + goto usage; + + assert((len = recvfrom(s, buf, sizeof(buf) - 1, 0, + (struct sockaddr *)&sin, &slen)) > 0); + buf[len] = '\0'; + printf("%s:%u %s\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), buf); + + return (0); +} diff --git a/tests/sys/netinet/sendto-IP_MULTICAST_IF.c b/tests/sys/netinet/multicast-send.c index d478e4da0b3b..f10b2b6338dd 100644 --- a/tests/sys/netinet/sendto-IP_MULTICAST_IF.c +++ b/tests/sys/netinet/multicast-send.c @@ -28,35 +28,69 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <net/if.h> #include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> #include <err.h> +static in_port_t +atop(const char *c) +{ + unsigned long ul; + + errno = 0; + if ((ul = strtol(c, NULL, 10)) < 1 || ul > IPPORT_MAX || errno != 0) + err(1, "can't parse %s", c); + + return ((in_port_t)ul); +} + int main(int argc, char *argv[]) { - struct sockaddr_in sin = { + struct sockaddr_in src = { + .sin_family = AF_INET, + .sin_len = sizeof(struct sockaddr_in), + }, dst = { .sin_family = AF_INET, .sin_len = sizeof(struct sockaddr_in), }; + struct ip_mreqn mreqn; struct in_addr in; - int s, rv; + int s; + bool index; - if (argc < 2) - errx(1, "Usage: %s IPv4-address", argv[0]); + if (argc < 7) + errx(1, "Usage: %s src-IPv4 src-port dst-IPv4 dst-port " + "interface payload", argv[0]); - if (inet_pton(AF_INET, argv[1], &in) != 1) + if (inet_pton(AF_INET, argv[1], &src.sin_addr) != 1) err(1, "inet_pton(%s) failed", argv[1]); + src.sin_port = htons(atop(argv[2])); + if (inet_pton(AF_INET, argv[3], &dst.sin_addr) != 1) + err(1, "inet_pton(%s) failed", argv[3]); + dst.sin_port = htons(atop(argv[4])); + if (inet_pton(AF_INET, argv[5], &in) == 1) + index = false; + else if ((mreqn.imr_ifindex = if_nametoindex(argv[5])) > 0) + index = true; + else + err(1, "if_nametoindex(%s) failed", argv[5]); assert((s = socket(PF_INET, SOCK_DGRAM, 0)) > 0); - assert(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0); - assert(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &in, sizeof(in)) - == 0); - /* RFC 6676 */ - assert(inet_pton(AF_INET, "233.252.0.1", &sin.sin_addr) == 1); - sin.sin_port = htons(6676); - rv = sendto(s, &sin, sizeof(sin), 0, - (struct sockaddr *)&sin, sizeof(sin)); - if (rv != sizeof(sin)) + assert(bind(s, (struct sockaddr *)&src, sizeof(src)) == 0); + if (index) + assert(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, + sizeof(mreqn)) == 0); + else + assert(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &in, + sizeof(in)) == 0); + if (sendto(s, argv[6], strlen(argv[6]) + 1, 0, (struct sockaddr *)&dst, + sizeof(dst)) != (ssize_t)strlen(argv[6]) + 1) err(1, "sendto failed"); return (0); diff --git a/tests/sys/netinet/multicast.sh b/tests/sys/netinet/multicast.sh index eb2b962dac70..a3854fd2fd20 100644..100755 --- a/tests/sys/netinet/multicast.sh +++ b/tests/sys/netinet/multicast.sh @@ -26,36 +26,130 @@ . $(atf_get_srcdir)/../common/vnet.subr -# See regression fixed in baad45c9c12028964acd0b58096f3aaa0fb22859 -atf_test_case "IP_MULTICAST_IF" "cleanup" -IP_MULTICAST_IF_head() +# Set up two jails, mjail1 and mjail2, connected with two interface pairs +multicast_vnet_init() { - atf_set descr \ - 'sendto() for IP_MULTICAST_IF socket does not do routing lookup' + + vnet_init + epair1=$(vnet_mkepair) + epair2=$(vnet_mkepair) + vnet_mkjail mjail1 ${epair1}a ${epair2}a + jexec mjail1 ifconfig ${epair1}a up + jexec mjail1 ifconfig ${epair1}a 192.0.2.1/24 + jexec mjail1 ifconfig ${epair2}a up + jexec mjail1 ifconfig ${epair2}a 192.0.3.1/24 + vnet_mkjail mjail2 ${epair1}b ${epair2}b + jexec mjail2 ifconfig ${epair1}b up + jexec mjail2 ifconfig ${epair1}b 192.0.2.2/24 + jexec mjail2 ifconfig ${epair2}b up + jexec mjail2 ifconfig ${epair2}b 192.0.3.2/24 +} + +atf_test_case "IP_ADD_MEMBERSHIP_ip_mreq" "cleanup" +IP_ADD_MEMBERSHIP_ip_mreq_head() +{ + atf_set descr 'IP_ADD_MEMBERSHIP / IP_MULTICAST_IF with ip_mreq' atf_set require.user root +} +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=$! + 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 + # 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=$! + 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_mreq_cleanup() +{ + rm out + vnet_cleanup } -IP_MULTICAST_IF_body() +atf_test_case "IP_ADD_MEMBERSHIP_ip_mreqn" "cleanup" +IP_ADD_MEMBERSHIP_ip_mreqn_head() +{ + atf_set descr 'IP_ADD_MEMBERSHIP / IP_MULTICAST_IF with ip_mreqn' + atf_set require.user root +} +IP_ADD_MEMBERSHIP_ip_mreqn_body() { - local epair mjail + multicast_vnet_init - vnet_init - # The test doesn't use our half of epair - epair=$(vnet_mkepair) - vnet_mkjail mjail ${epair}a - jexec mjail ifconfig ${epair}a up - jexec mjail ifconfig ${epair}a 192.0.2.1/24 + # join group on interface epair2 + jexec mjail2 $(atf_get_srcdir)/multicast-receive \ + ip_mreqn 233.252.0.1 6676 ${epair1}b > out & pid=$! + 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 + 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 + + # join group on interface epair2 + jexec mjail2 $(atf_get_srcdir)/multicast-receive \ + ip_mreqn 233.252.0.1 6676 ${epair2}b > out & pid=$! atf_check -s exit:0 -o empty \ - jexec mjail $(atf_get_srcdir)/sendto-IP_MULTICAST_IF 192.0.2.1 + 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 +} +IP_ADD_MEMBERSHIP_ip_mreqn_cleanup() +{ + rm out + vnet_cleanup } -IP_MULTICAST_IF_cleanup() +atf_test_case "MCAST_JOIN_GROUP" "cleanup" +MCAST_JOIN_GROUP_head() +{ + atf_set descr 'MCAST_JOIN_GROUP' + atf_set require.user root +} +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=$! + 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 + 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 + + # join group on interface epair2 + jexec mjail2 $(atf_get_srcdir)/multicast-receive \ + group_req 233.252.0.1 6676 ${epair2}b > out & pid=$! + 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 +} +MCAST_JOIN_GROUP_cleanup() { + rm out vnet_cleanup } atf_init_test_cases() { - atf_add_test_case "IP_MULTICAST_IF" + atf_add_test_case "IP_ADD_MEMBERSHIP_ip_mreq" + atf_add_test_case "IP_ADD_MEMBERSHIP_ip_mreqn" + atf_add_test_case "MCAST_JOIN_GROUP" } diff --git a/tests/sys/netinet/tcp_md5_getsockopt.c b/tests/sys/netinet/tcp_md5_getsockopt.c index deaa4170caea..e23cfa67185a 100644 --- a/tests/sys/netinet/tcp_md5_getsockopt.c +++ b/tests/sys/netinet/tcp_md5_getsockopt.c @@ -45,9 +45,6 @@ void test_tcp_md5_getsockopt(int); void test_tcp_md5_getsockopt(int v6) { - if (kldfind("tcpmd5.ko") == -1) - atf_tc_skip("Test requires the tcpmd5 kernel module to be loaded"); - struct sockaddr_in *s; struct sockaddr_in6 s6 = { 0 }; struct sockaddr_in s4 = { 0 }; @@ -108,6 +105,7 @@ ATF_TC(tcp_md5_getsockopt_v4); ATF_TC_HEAD(tcp_md5_getsockopt_v4, tc) { atf_tc_set_md_var(tc, "descr", "Test getsockopt for TCP MD5 SIG (IPv4)"); + atf_tc_set_md_var(tc, "require.kmods", "tcpmd5"); } ATF_TC_BODY(tcp_md5_getsockopt_v4, tc) @@ -119,6 +117,7 @@ ATF_TC(tcp_md5_getsockopt_v6); ATF_TC_HEAD(tcp_md5_getsockopt_v6, tc) { atf_tc_set_md_var(tc, "descr", "Test getsockopt for TCP MD5 SIG (IPv6)"); + atf_tc_set_md_var(tc, "require.kmods", "tcpmd5"); } ATF_TC_BODY(tcp_md5_getsockopt_v6, tc) |