From nobody Wed Mar 18 17:40:43 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fbbhW2lp8z6W66J for ; Wed, 18 Mar 2026 17:40:43 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fbbhW1VCQz4726 for ; Wed, 18 Mar 2026 17:40:43 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1773855643; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=eAEhGkDBMNzIvS/mQTmWmErSC6Dtr6zyqj0OMI9O89E=; b=OORDxwBkod3Fy7QJCL8NAiZ9oqaPXfYeyOb+HQjRaTYXo/ejsyPb0HXtWP/ZhCNyfx/BcY P/SZ5ROuLw/s23FVHeax/WJUC1HoNY+oZ/XI5V1H36klZekwQdVkx5ZHujo1TXBcwXEhKl 9gOxC+RpyOMFGrakqTfdsRbBdAQDDBfB8vc1CskZFkDkkTxCOBGcD3nACHOO3BSbyFaXE4 uLsreP/p+poXre12+nphdOWku2NWjx9CAaGQsW4NIDlBvyi6nR0daRXKD5Uw5TABrBnaVl dtZQ4k/xyS9nT96YZD8kDmhIZC0PmruWBIoeUUwf4ItdgpYN6H9ITnAmtR/UBg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1773855643; a=rsa-sha256; cv=none; b=wIMTgslBQCiaNxWfy6nzhwasvwBxnOrlTncJFeewcpW9FQHggW2RzsCktg6GPYThMTekqf 8MGsIXL82u58a+ndV63pUNXJLhQkARpSrlhLsV+/GyKyomfwVdKnJrMWyPhcss7sCzQksW 2PVDht0WcaJcq7iGjCtGlsD9A2S9TKBIzu2ko+1J/c36DPrqTdWDtUXRz66fuRKhzMQY1L wutxa6Yi4yo9hlccvTiPLqNQKtH/ELmoaMDA5ZxDq8RVWP0BhJ9g3wVS3QcSB6Sn6uPou3 sSvuo5urRldFEIrXbm5vcYQf/xzakFdS4u/NgrwwEMaBXdpnNKb8hNmWmaB+MA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1773855643; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=eAEhGkDBMNzIvS/mQTmWmErSC6Dtr6zyqj0OMI9O89E=; b=eGmv/ebhHZLeNUSRTzNXqY1ITH/clCPUXcCqfHH8cC+1BBMl9Ij1jG5ClmG6xSOhwRFy3F yKEbu7nrlUfwDhx5wlNd4L3rGvtUmecaylitGgGFfCjSRb3cBypW9ceASD5GrC+lAEDGPH q2CJ2OZ+x+Atcz3459DYH6Yi0yiAQpOUhlcxSJtS/6TFN31lPA9TbnUOy9GUBGFLNRomPg LBczeb4SmZpWIJmYMp0ejKsrYNhgqQgU2JWVOLJi5gjUt5AGqDJFv2J3c8usbDbYj+5AnB qrC1NXfsKiDE/dOMQMe4ePPcn3B3uvFFLWiLyq7qAE+macZaftqx7sXK7oKlww== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fbbhW0zVTz3GZ for ; Wed, 18 Mar 2026 17:40:43 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 243c0 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 18 Mar 2026 17:40:43 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Gleb Smirnoff Subject: git: c1481c9f4a42 - main - tests/netinet: provide test for raw_ip.c:rip_input() List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: glebius X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: c1481c9f4a425db7295332be87f837bfb7d127df Auto-Submitted: auto-generated Date: Wed, 18 Mar 2026 17:40:43 +0000 Message-Id: <69bae39b.243c0.182a86ab@gitrepo.freebsd.org> The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=c1481c9f4a425db7295332be87f837bfb7d127df commit c1481c9f4a425db7295332be87f837bfb7d127df Author: Gleb Smirnoff AuthorDate: 2026-03-17 22:15:43 +0000 Commit: Gleb Smirnoff CommitDate: 2026-03-18 17:38:42 +0000 tests/netinet: provide test for raw_ip.c:rip_input() The test creates differently bound SOCK_RAW sockets and sends different probe packets. There is expected results matrix that every probe is checked against. --- tests/sys/netinet/Makefile | 3 + tests/sys/netinet/raw.c | 219 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) diff --git a/tests/sys/netinet/Makefile b/tests/sys/netinet/Makefile index b3d76d1da125..564eabae3313 100644 --- a/tests/sys/netinet/Makefile +++ b/tests/sys/netinet/Makefile @@ -9,6 +9,7 @@ ATF_TESTS_C= broadcast \ fibs_multibind_test \ ip_reass_test \ ip6_v4mapped_test \ + raw \ so_reuseport_lb_test \ socket_afinet \ tcp_connect_port_test \ @@ -49,6 +50,8 @@ TEST_METADATA.forward+= required_programs="python" \ TEST_METADATA.multicast+= execenv="jail" \ execenv_jail_params="vnet" TEST_METADATA.output+= required_programs="python" +TEST_METADATA.raw+= execenv="jail" \ + execenv_jail_params="vnet allow.raw_sockets" TEST_METADATA.redirect+= required_programs="python" PROGS= udp_dontroute tcp_user_cookie multicast-send multicast-receive diff --git a/tests/sys/netinet/raw.c b/tests/sys/netinet/raw.c new file mode 100644 index 000000000000..1cae39b01c9b --- /dev/null +++ b/tests/sys/netinet/raw.c @@ -0,0 +1,219 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026 Gleb Smirnoff + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * The 'input' test exercises logic of rip_input(). The best documentation + * for raw socket input behavior is collected in Stevens's UNIX Network + * Programming, Section 28.4. We create several sockets, with different + * remote and local bindings, as well as a socket with multicast membership + * and then we send different packets and see which sockets received their + * copy. + * The table tests[] describes our expectations. + */ +ATF_TC_WITHOUT_HEAD(input); +#define PROT1 253 /* RFC3692 */ +#define PROT2 254 /* RFC3692 */ +static const struct rcvr { + struct in_addr laddr, faddr, maddr; + uint8_t proto; +} rcvrs[] = { +#define WILD { htonl(INADDR_ANY) } +#define LOOP(x) { htonl(INADDR_LOOPBACK + (x)) } +#define MULT(x) { htonl(INADDR_UNSPEC_GROUP + (x)) } + { WILD, WILD, WILD, 0 }, + { WILD, WILD, WILD, PROT1 }, + { LOOP(0), WILD, WILD, 0 }, + { LOOP(0), WILD, WILD, PROT1 }, + { LOOP(1), WILD, WILD, 0 }, + { LOOP(1), WILD, WILD, PROT1 }, + { LOOP(0), LOOP(2), WILD, 0 }, + { LOOP(0), LOOP(2), WILD, PROT1 }, + { LOOP(0), LOOP(3), WILD, 0 }, + { LOOP(0), LOOP(3), WILD, PROT1 }, + { LOOP(1), LOOP(3), WILD, 0 }, + { LOOP(1), LOOP(3), WILD, PROT1 }, + { WILD, WILD, MULT(1), 0 }, +}; +static const struct test { + struct in_addr src, dst; + uint8_t proto; + bool results[nitems(rcvrs)]; +} tests[] = { +#define x true +#define o false + { LOOP(2), LOOP(0), PROT1, + { x, x, x, x, o, o, x, x, o, o, o, o, x } }, + { LOOP(2), LOOP(0), PROT2, + { x, o, x, o, o, o, x, o, o, o, o, o, x } }, + { LOOP(3), LOOP(0), PROT1, + { x, x, x, x, o, o, o, o, x, x, o, o, x } }, + { LOOP(3), LOOP(0), PROT2, + { x, o, x, o, o, o, o, o, x, o, o, o, x } }, + { LOOP(2), LOOP(1), PROT1, + { x, x, o, o, x, x, o, o, o, o, o, o, x } }, + { LOOP(2), LOOP(1), PROT2, + { x, o, o, o, x, o, o, o, o, o, o, o, x } }, + { LOOP(3), LOOP(1), PROT1, + { x, x, o, o, x, x, o, o, o, o, x, x, x } }, + { LOOP(3), LOOP(1), PROT2, + { x, o, o, o, x, o, o, o, o, o, x, o, x } }, + { LOOP(3), MULT(1), PROT1, + { x, x, o, o, o, o, o, o, o, o, o, o, x } }, + { LOOP(3), MULT(2), PROT1, + { x, x, o, o, o, o, o, o, o, o, o, o, o } }, +#undef WILD +#undef LOOP +#undef MULT +#undef x +#undef o +}; + +ATF_TC_BODY(input, tc) +{ + struct pkt { + struct ip ip; + char payload[100]; + } __packed pkt = { + .ip.ip_v = IPVERSION, + .ip.ip_hl = sizeof(struct ip) >> 2, + .ip.ip_len = htons(sizeof(struct pkt)), + .ip.ip_ttl = 16, + }; + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_len = sizeof(sin), + }; + struct ip_mreqn mreqn = { + .imr_ifindex = if_nametoindex("lo0"), + }; + int r[nitems(rcvrs)]; + int s; + + /* + * This XXX to be removed when kyua provides generic framework for + * constructing test jail environments. + */ + system("/sbin/ifconfig lo0 127.0.0.1/32"); + system("/sbin/ifconfig lo0 127.0.0.2/32 alias"); + + for (u_int i = 0; i < nitems(rcvrs); i++) { + /* + * To avoid a race between send(2) and packet queueing in + * netisr(9) and our recv(2), set the very first receiver + * socket to blocking mode. Note in the above table that first + * receiver is supposed to receive something in every test. + */ + ATF_REQUIRE((r[i] = socket(PF_INET, SOCK_RAW | + (i != 0 ? SOCK_NONBLOCK : 0), + rcvrs[i].proto)) != -1); + if (rcvrs[i].laddr.s_addr != htonl(INADDR_ANY)) { + sin.sin_addr = rcvrs[i].laddr; + ATF_REQUIRE(bind(r[i], (struct sockaddr *)&sin, + sizeof(sin)) == 0); + } + if (rcvrs[i].faddr.s_addr != htonl(INADDR_ANY)) { + sin.sin_addr = rcvrs[i].faddr; + ATF_REQUIRE(connect(r[i], (struct sockaddr *)&sin, + sizeof(sin)) == 0); + } + if (rcvrs[i].maddr.s_addr != htonl(INADDR_ANY)) { + mreqn.imr_multiaddr = rcvrs[i].maddr; + ATF_REQUIRE(setsockopt(r[i], IPPROTO_IP, + IP_ADD_MEMBERSHIP, &mreqn, sizeof(mreqn)) == 0); + } + } + + ATF_REQUIRE((s = socket(PF_INET, SOCK_RAW, 0)) != -1); + ATF_REQUIRE(setsockopt(s, IPPROTO_IP, IP_HDRINCL, &(int){1}, + sizeof(int)) == 0); + /* + * Make sending socket connected. The socket API requires connected + * status to use send(2), even with IP_HDRINCL. Another side effect + * is that the sending socket won't receive own datagrams, which we + * don't drain out in this program. + */ + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK + 100); + ATF_REQUIRE(connect(s, (struct sockaddr *)&sin, sizeof(sin)) == 0); + /* + * Force multicast interface for the sending socket to be able to + * send to MULT(x) destinations. + */ + mreqn.imr_multiaddr.s_addr = 0; + ATF_REQUIRE(setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, + sizeof(mreqn)) == 0); + + for (u_int i = 0; i < nitems(tests); i++) { + arc4random_buf(&pkt.payload, sizeof(pkt.payload)); + pkt.ip.ip_src = tests[i].src; + pkt.ip.ip_dst = tests[i].dst; + pkt.ip.ip_p = tests[i].proto; + ATF_REQUIRE(send(s, &pkt, sizeof(pkt), 0) == sizeof(pkt)); + for (u_int j = 0; j < nitems(rcvrs); j++) { + char buf[sizeof(pkt)]; + char p[4][INET_ADDRSTRLEN]; + ssize_t ss; + + ss = recv(r[j], buf, sizeof(buf), 0); + + ATF_REQUIRE_MSG((tests[i].results[j] == true && + ss == sizeof(buf) && memcmp(buf + sizeof(struct ip), + pkt.payload, sizeof(pkt.payload)) == 0) || + (tests[i].results[j] == false && + ss == -1 && errno == EAGAIN), + "test #%u %s->%s %u unexpected receive of %jd " + "bytes errno %d on socket #%u %s->%s %u", i, + inet_ntop(AF_INET, &tests[i].src, p[0], + INET_ADDRSTRLEN), + inet_ntop(AF_INET, &tests[i].dst, p[1], + INET_ADDRSTRLEN), + tests[i].proto, ss, errno, j, + inet_ntop(AF_INET, &rcvrs[j].faddr, p[2], + INET_ADDRSTRLEN), + inet_ntop(AF_INET, &rcvrs[j].laddr, p[3], + INET_ADDRSTRLEN), + rcvrs[j].proto); + } + } +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, input); + + return (atf_no_error()); +}