git: ae5c3dfd3e75 - main - netinet tests: Add error handling tests for UDP with v4-mapped sockets

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 17 Oct 2023 15:55:32 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=ae5c3dfd3e75bb287984947359d4f958aea505ec

commit ae5c3dfd3e75bb287984947359d4f958aea505ec
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2023-10-17 14:29:42 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-10-17 15:19:06 +0000

    netinet tests: Add error handling tests for UDP with v4-mapped sockets
    
    This provides a regression test for commit abca3ae7734f.
    
    Add it to the existing v4-mapped address test file, and rename
    accordingly.
    
    Reviewed by:    tuexen, karels, rrs
    MFC after:      1 week
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D39216
---
 ObsoleteFiles.inc                                  |  3 +
 tests/sys/netinet/Makefile                         |  2 +-
 ...p6_v4mapped_bind_test.c => ip6_v4mapped_test.c} | 81 +++++++++++++++++++---
 3 files changed, 76 insertions(+), 10 deletions(-)

diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index c3cc72351963..9e4be6b69312 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -51,6 +51,9 @@
 #   xargs -n1 | sort | uniq -d;
 # done
 
+# 20231006: rename tcp6_v4unmapped_bind_test
+OLD_FILES+=usr/tests/sys/netinet/tcp6_v4unmapped_bind_test
+
 # 20231005: Remove man page link for now gone net80211 function.
 OLD_FILES+=usr/share/man/man9/ieee80211_unref_node.9.gz
 
diff --git a/tests/sys/netinet/Makefile b/tests/sys/netinet/Makefile
index 144754acfbcc..44f76508bf5c 100644
--- a/tests/sys/netinet/Makefile
+++ b/tests/sys/netinet/Makefile
@@ -7,9 +7,9 @@ BINDIR=		${TESTSDIR}
 TESTS_SUBDIRS+=	libalias
 
 ATF_TESTS_C=	ip_reass_test \
+		ip6_v4mapped_test \
 		so_reuseport_lb_test \
 		socket_afinet \
-		tcp6_v4mapped_bind_test \
 		tcp_connect_port_test \
 		tcp_md5_getsockopt
 
diff --git a/tests/sys/netinet/tcp6_v4mapped_bind_test.c b/tests/sys/netinet/ip6_v4mapped_test.c
similarity index 81%
rename from tests/sys/netinet/tcp6_v4mapped_bind_test.c
rename to tests/sys/netinet/ip6_v4mapped_test.c
index c7fc682d7ae7..d4c4ed526ab5 100644
--- a/tests/sys/netinet/tcp6_v4mapped_bind_test.c
+++ b/tests/sys/netinet/ip6_v4mapped_test.c
@@ -194,17 +194,15 @@ restore_portrange(void)
 		    "failed while restoring value");
 }
 
-ATF_TC_WITH_CLEANUP(v4mapped);
-ATF_TC_HEAD(v4mapped, tc)
+ATF_TC_WITH_CLEANUP(tcp_v4mapped_bind);
+ATF_TC_HEAD(tcp_v4mapped_bind, tc)
 {
-
 	/* root is only required for sysctls (setup and cleanup). */
 	atf_tc_set_md_var(tc, "require.user", "root");
 	atf_tc_set_md_var(tc, "require.config", "allow_sysctl_side_effects");
 	atf_tc_set_md_var(tc, "descr",
 	    "Check local port assignment with bind and mapped V4 addresses");
 }
-
 /*
  * Create a listening IPv4 socket, then connect to it repeatedly using a
  * bound IPv6 socket using a v4 mapped address.  With a small port range,
@@ -213,7 +211,7 @@ ATF_TC_HEAD(v4mapped, tc)
  * and then the connect would fail with EADDRINUSE.  Make sure we get
  * the right error.
  */
-ATF_TC_BODY(v4mapped, tc)
+ATF_TC_BODY(tcp_v4mapped_bind, tc)
 {
 	union {
 		struct sockaddr saddr;
@@ -315,17 +313,82 @@ ATF_TC_BODY(v4mapped, tc)
 	ATF_REQUIRE_MSG(i >= 1, "No successful connections");
 	ATF_REQUIRE_MSG(got_bind_error == true, "No expected bind error");
 }
+ATF_TC_CLEANUP(tcp_v4mapped_bind, tc)
+{
+	restore_portrange();
+}
 
-ATF_TC_CLEANUP(v4mapped, tc)
+ATF_TC(udp_v4mapped_sendto);
+ATF_TC_HEAD(udp_v4mapped_sendto, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Validate sendto() with a v4-mapped address and a v6-only socket");
+}
+ATF_TC_BODY(udp_v4mapped_sendto, tc)
 {
+	struct addrinfo ai_hint, *aip;
+	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
+	ssize_t n;
+	socklen_t salen;
+	int error, ls, s, zero;
+	short port;
+	char ch;
 
-	restore_portrange();
+	ls = socket(PF_INET, SOCK_DGRAM, 0);
+	ATF_REQUIRE(ls >= 0);
+
+	memset(&ai_hint, 0, sizeof(ai_hint));
+	ai_hint.ai_family = AF_INET;
+	ai_hint.ai_flags = AI_NUMERICHOST;
+	error = getaddrinfo("127.0.0.1", NULL, &ai_hint, &aip);
+	ATF_REQUIRE_MSG(error == 0, "getaddrinfo: %s", gai_strerror(error));
+	memcpy(&sin, aip->ai_addr, sizeof(sin));
+
+	error = bind(ls, (struct sockaddr *)&sin, sizeof(sin));
+	ATF_REQUIRE_MSG(error == 0, "bind: %s", strerror(errno));
+	salen = sizeof(sin);
+	error = getsockname(ls, (struct sockaddr *)&sin, &salen);
+	ATF_REQUIRE_MSG(error == 0,
+	    "getsockname() for listen socket failed: %s", strerror(errno));
+	ATF_REQUIRE_MSG(salen == sizeof(struct sockaddr_in),
+	    "unexpected sockaddr size");
+	port = sin.sin_port;
+
+	s = socket(PF_INET6, SOCK_DGRAM, 0);
+	ATF_REQUIRE(s >= 0);
+
+	memset(&ai_hint, 0, sizeof(ai_hint));
+	ai_hint.ai_family = AF_INET6;
+	ai_hint.ai_flags = AI_NUMERICHOST | AI_V4MAPPED;
+	error = getaddrinfo("127.0.0.1", NULL, &ai_hint, &aip);
+	ATF_REQUIRE_MSG(error == 0, "getaddrinfo: %s", gai_strerror(error));
+	memcpy(&sin6, aip->ai_addr, sizeof(sin6));
+	sin6.sin6_port = port;
+
+	ch = 0x42;
+	n = sendto(s, &ch, 1, 0, (struct sockaddr *)&sin6, sizeof(sin6));
+	ATF_REQUIRE_ERRNO(EINVAL, n == -1);
+
+	zero = 0;
+	error = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero));
+	ATF_REQUIRE_MSG(error == 0,
+	    "setsockopt(IPV6_V6ONLY) failed: %s", strerror(errno));
+
+	ch = 0x42;
+	n = sendto(s, &ch, 1, 0, (struct sockaddr *)&sin6, sizeof(sin6));
+	ATF_REQUIRE_MSG(n == 1, "sendto() failed: %s", strerror(errno));
+
+	ch = 0;
+	n = recv(ls, &ch, 1, 0);
+	ATF_REQUIRE_MSG(n == 1, "recv() failed: %s", strerror(errno));
+	ATF_REQUIRE(ch == 0x42);
 }
 
 ATF_TP_ADD_TCS(tp)
 {
-	ATF_TP_ADD_TC(tp, v4mapped);
+	ATF_TP_ADD_TC(tp, tcp_v4mapped_bind);
+	ATF_TP_ADD_TC(tp, udp_v4mapped_sendto);
 
 	return (atf_no_error());
 }
-