diff --git a/tests/sys/netinet/fibs_test.sh b/tests/sys/netinet/fibs_test.sh index bf5a54b451a2..16213071baff 100755 --- a/tests/sys/netinet/fibs_test.sh +++ b/tests/sys/netinet/fibs_test.sh @@ -595,6 +595,61 @@ udp_dontroute_cleanup() cleanup_tap } +atf_test_case udp_dontroute6 cleanup +udp_dontroute6_head() +{ + atf_set "descr" "Source address selection for UDP IPv6 packets with SO_DONTROUTE on non-default FIBs works" + atf_set "require.user" "root" + atf_set "require.config" "fibs" +} + +udp_dontroute6_body() +{ + # Configure the TAP interface to use an RFC3849 nonrouteable address + # and a non-default fib + ADDR0="2001:db8::2" + ADDR1="2001:db8::3" + SUBNET="2001:db8::" + MASK="64" + # Use a different IP on the same subnet as the target + TARGET="2001:db8::100" + SRCDIR=`atf_get_srcdir` + + atf_expect_fail "PR196361 IPv6 network routes don't respect net.add_addr_allfibs=0" + + # Check system configuration + if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then + atf_skip "This test requires net.add_addr_allfibs=0" + fi + get_fibs 2 + + # Configure the TAP interfaces. Use no_dad so the addresses will be + # ready right away and won't be marked as tentative until DAD + # completes. + setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad + TARGET_TAP=${TAP} + setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad + + # Send a UDP packet with SO_DONTROUTE. In the failure case, it will + # return ENETUNREACH, or send the packet to the wrong tap + atf_check -o ignore setfib ${FIB0} \ + ${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP} + cleanup_tap + + # Repeat, but this time target the other tap + setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad + setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad + TARGET_TAP=${TAP} + + atf_check -o ignore setfib ${FIB1} \ + ${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP} +} + +udp_dontroute6_cleanup() +{ + cleanup_tap +} + atf_init_test_cases() { @@ -609,6 +664,7 @@ atf_init_test_cases() atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6 atf_add_test_case udp_dontroute + atf_add_test_case udp_dontroute6 } # Looks up one or more fibs from the configuration data and validates them. @@ -656,6 +712,7 @@ get_tap() # Protocol (inet or inet6) # IP address # Netmask in number of bits (eg 24 or 8) +# Extra flags # Return: the tap interface name as the env variable TAP setup_tap() { @@ -663,9 +720,10 @@ setup_tap() local PROTO=$2 local ADDR=$3 local MASK=$4 + local FLAGS=$5 get_tap - echo setfib ${FIB} ifconfig $TAP ${PROTO} ${ADDR}/${MASK} fib $FIB - setfib ${FIB} ifconfig $TAP ${PROTO} ${ADDR}/${MASK} fib $FIB + echo setfib ${FIB} ifconfig $TAP ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS + setfib ${FIB} ifconfig $TAP ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS } cleanup_tap() diff --git a/tests/sys/netinet/udp_dontroute.c b/tests/sys/netinet/udp_dontroute.c index 79421fd0b707..24e3fc4166aa 100644 --- a/tests/sys/netinet/udp_dontroute.c +++ b/tests/sys/netinet/udp_dontroute.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,7 @@ int main(int argc, char **argv) { - struct sockaddr_in dst; + struct sockaddr_storage dst; int s, t; int opt; int ret; @@ -60,17 +61,33 @@ main(int argc, char **argv) const char* sendbuf = "Hello, World!"; const size_t buflen = 80; char recvbuf[buflen]; + bool v6 = false; + const char *addr, *tapdev; + const uint16_t port = 46120; - if (argc != 3) { - fprintf(stderr, "Usage: %s ip_address tapdev\n", argv[0]); + bzero(&dst, sizeof(dst)); + if (argc < 3 || argc > 4) { + fprintf(stderr, "Usage: %s [-6] ip_address tapdev\n", argv[0]); exit(2); } - t = open(argv[2], O_RDWR | O_NONBLOCK); + if (strcmp("-6", argv[1]) == 0) { + v6 = true; + addr = argv[2]; + tapdev = argv[3]; + } else { + addr = argv[1]; + tapdev = argv[2]; + } + + t = open(tapdev, O_RDWR | O_NONBLOCK); if (t < 0) err(EXIT_FAILURE, "open"); - s = socket(PF_INET, SOCK_DGRAM, 0); + if (v6) + s = socket(PF_INET6, SOCK_DGRAM, 0); + else + s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) err(EXIT_FAILURE, "socket"); opt = 1; @@ -79,16 +96,26 @@ main(int argc, char **argv) if (ret == -1) err(EXIT_FAILURE, "setsockopt(SO_DONTROUTE)"); - dst.sin_len = sizeof(dst); - dst.sin_family = AF_INET; - dst.sin_port = htons(46120); - dst.sin_addr.s_addr = inet_addr(argv[1]); - if (dst.sin_addr.s_addr == htonl(INADDR_NONE)) { - fprintf(stderr, "Invalid address: %s\n", argv[1]); - exit(2); + if (v6) { + struct sockaddr_in6 *dst6 = ((struct sockaddr_in6*)&dst); + + dst.ss_len = sizeof(struct sockaddr_in6); + dst.ss_family = AF_INET6; + dst6->sin6_port = htons(port); + ret = inet_pton(AF_INET6, addr, &dst6->sin6_addr); + } else { + struct sockaddr_in *dst4 = ((struct sockaddr_in*)&dst); + + dst.ss_len = sizeof(struct sockaddr_in); + dst.ss_family = AF_INET; + dst4->sin_port = htons(port); + ret = inet_pton(AF_INET, addr, &dst4->sin_addr); } + if (ret != 1) + err(EXIT_FAILURE, "inet_pton returned %d", ret); + ret = sendto(s, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&dst, - dst.sin_len); + dst.ss_len); if (ret == -1) err(EXIT_FAILURE, "sendto");