From nobody Tue May 20 21:52:56 2025 X-Original-To: dev-commits-src-all@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 4b27Zx25qBz5w3PV; Tue, 20 May 2025 21:52:57 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4b27Zx1JwRz3X33; Tue, 20 May 2025 21:52:57 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1747777977; 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=Os1tiwZjVLo9s2DveUmuCzNmPkXiSmbirk8pYk2zWIY=; b=QNV6QeMQf/gVHzDqc6n8qi626Mcpub0OolAs61JrXOtxQF32FEtIlyNmIqO9cd07yVcBQz RFPDxIWzatuPp8YAl+IzEyUQFTtyyRq9Puren85KJGXJ9iFt5qhc11UOcujAB54u4oVrhY sIi0Niqgx/kr3O+X2RY898o1RngVJeNugC+ahNAaLm6XPiAqlFY+A3+eKZDu1x1O2dplgg F8Wz2/EY9v9llrbxG7ZDB8hPVSTssFZ6ttH6lgsOrnF3EKO5vf5SRdpkesa6gmiMhgdXT2 twsIzKfMctDUqJ2vvFWL3E2Lov6i+Qgp/JSzKRTFZwlcseMCP/4HcXYVJydJAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1747777977; 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=Os1tiwZjVLo9s2DveUmuCzNmPkXiSmbirk8pYk2zWIY=; b=p4DN17O2daQNVhK9oVNhCtQDR1/Lv8N1qZIme+W4uQpK4LnNOZ9/n7r2YkUyRUYeidrTBC a8WAH9XToml1SB2S1Mf0wfIIELYBVYqHzA/5BwYFx0MFVPNFktQtxou0emQjCowpqjCDBB 14mlFu6SxUKGLV18Rz4maAT5h7ynUDXZzTmcob1Wme67fibKyvk+CkwN5pSqYJg3/LdVfZ VKOKhslkPd7G7+qZN2mAdIc1sni4NS6XJzYynBLHO/mbcnSxrhfRT2dRUtf66K0vUMlaQr xvqSyg0EPOCnfvzTYoH44RyQtefD9pfMhFALWRFAJSQLLswU3uu9cJjuOBxjkw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1747777977; a=rsa-sha256; cv=none; b=N+b2R0kkuAEuGG7qC49Cvhu7wmoAW6Ok70Bqdrjh2pkYjSvFxxi25Ay7Fd52H0dBluWs3L RLbUK2scVABv/RUEaeTkhiTmo35hMJY2X6G1USBiXNKVtrdsklO5nPXaeWbpgvKVCXNlZZ W6IQLDo86gOGTLnwpsbZgg2pg1TfzS4iV3Sq6hDksYUzESMpe7teTyXitZhoirR+BFTam2 KHV7H7Mp8foDVjxQG/dUEYrFhkJ1tDLuTmvLZz4Al1FEuyIr16ZcNEhnhPEU4+nYlnjgQn au0/gLNieiGoaTdJgbP2/6HLJy7N/23DfKuAZqiNr+ITOfLxt97ydJT2nh7r6w== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (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 did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4b27Zx0gcRz16Rq; Tue, 20 May 2025 21:52:57 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 54KLqunq039709; Tue, 20 May 2025 21:52:56 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 54KLqulA039706; Tue, 20 May 2025 21:52:56 GMT (envelope-from git) Date: Tue, 20 May 2025 21:52:56 GMT Message-Id: <202505202152.54KLqulA039706@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Lexi Winter Subject: git: 2f8ba2e5b93e - stable/14 - libc tests: add tests for link_addr(3) and link_ntoa(3) List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: ivy X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 2f8ba2e5b93eec8b51e6bf18a8e480ee5e1769cf Auto-Submitted: auto-generated The branch stable/14 has been updated by ivy: URL: https://cgit.FreeBSD.org/src/commit/?id=2f8ba2e5b93eec8b51e6bf18a8e480ee5e1769cf commit 2f8ba2e5b93eec8b51e6bf18a8e480ee5e1769cf Author: Lexi Winter AuthorDate: 2025-05-05 17:25:03 +0000 Commit: Lexi Winter CommitDate: 2025-05-20 21:49:34 +0000 libc tests: add tests for link_addr(3) and link_ntoa(3) for now, since link_addr() has no way to indicate an error, these are only positive tests which check the outcome of valid inputs. Reviewed by: ngie, des, adrian Approved by: des (mentor) Differential Revision: https://reviews.freebsd.org/D50062 (cherry picked from commit 757e973fb2112ea442aa8990d991f406d407b6f7) link_addr_test: use , not is the correct header; this fixes the GCC build. while here, sort the headers. Fixes: 757e973fb211 ("libc tests: add tests for link_addr(3) and link_ntoa(3)") Reviewed by: des Approved by: des (mentor) Differential Revision: https://reviews.freebsd.org/D50189 (cherry picked from commit bbffdfef3bf04b2f89027cb20e2019fdc74c4b1b) --- lib/libc/tests/net/Makefile | 3 + lib/libc/tests/net/link_addr_test.cc | 271 +++++++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+) diff --git a/lib/libc/tests/net/Makefile b/lib/libc/tests/net/Makefile index 6e90f22b98f5..d939edeeb00d 100644 --- a/lib/libc/tests/net/Makefile +++ b/lib/libc/tests/net/Makefile @@ -4,6 +4,9 @@ PACKAGE= tests ATF_TESTS_C+= ether_test ATF_TESTS_C+= eui64_aton_test ATF_TESTS_C+= eui64_ntoa_test +ATF_TESTS_CXX+= link_addr_test + +CXXSTD.link_addr_test= c++20 CFLAGS+= -I${.CURDIR} diff --git a/lib/libc/tests/net/link_addr_test.cc b/lib/libc/tests/net/link_addr_test.cc new file mode 100644 index 000000000000..6b9f5a841ef7 --- /dev/null +++ b/lib/libc/tests/net/link_addr_test.cc @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2025 Lexi Winter + * + * SPDX-License-Identifier: ISC + */ + +/* + * Tests for link_addr() and link_ntoa(). + * + * link_addr converts a string representing an (optionally null) interface name + * followed by an Ethernet address into a sockaddr_dl. The expected format is + * "[ifname]:lladdr". This means if ifname is not specified, the leading colon + * is still required. + * + * link_ntoa does the inverse of link_addr, returning a string representation + * of the address. + * + * Note that the output format of link_ntoa is not valid input for link_addr + * since the leading colon may be omitted. This is by design. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace std::literals; + +/* + * Define operator== and operator<< for ether_addr so we can use them in + * ATF_EXPECT_EQ expressions. + */ + +bool +operator==(ether_addr a, ether_addr b) +{ + return (std::ranges::equal(a.octet, b.octet)); +} + +std::ostream & +operator<<(std::ostream &s, ether_addr a) +{ + for (unsigned i = 0; i < ETHER_ADDR_LEN; ++i) { + if (i > 0) + s << ":"; + + s << std::format("{:02x}", static_cast(a.octet[i])); + } + + return (s); +} + +/* + * Create a sockaddr_dl from a string using link_addr(), and ensure the + * returned struct looks valid. + */ +sockaddr_dl +make_linkaddr(const std::string &addr) +{ + auto sdl = sockaddr_dl{}; + + sdl.sdl_len = sizeof(sdl); + ::link_addr(addr.c_str(), &sdl); + + ATF_REQUIRE_EQ(AF_LINK, static_cast(sdl.sdl_family)); + ATF_REQUIRE_EQ(true, sdl.sdl_len > 0); + ATF_REQUIRE_EQ(true, sdl.sdl_nlen >= 0); + + return (sdl); +} + +/* + * Return the data stored in a sockaddr_dl as a span. + */ +std::span +data(const sockaddr_dl &sdl) +{ + // sdl_len is the entire structure, but we only want the length of the + // data area. + auto dlen = sdl.sdl_len - offsetof(sockaddr_dl, sdl_data); + return {&sdl.sdl_data[0], dlen}; +} + +/* + * Return the interface name stored in a sockaddr_dl as a string. + */ +std::string_view +ifname(const sockaddr_dl &sdl) +{ + auto name = data(sdl).subspan(0, sdl.sdl_nlen); + return {name.begin(), name.end()}; +} + +/* + * Return the Ethernet address stored in a sockaddr_dl as an ether_addr. + */ +ether_addr +addr(const sockaddr_dl &sdl) +{ + ether_addr ret{}; + ATF_REQUIRE_EQ(ETHER_ADDR_LEN, sdl.sdl_alen); + std::ranges::copy(data(sdl).subspan(sdl.sdl_nlen, ETHER_ADDR_LEN), + &ret.octet[0]); + return (ret); +} + +/* + * Return the link address stored in a sockaddr_dl as a span of octets. + */ +std::span +lladdr(const sockaddr_dl &sdl) +{ + auto data = reinterpret_cast(LLADDR(&sdl)); + return {data, data + sdl.sdl_alen}; +} + + +/* + * Some sample addresses we use for testing. Include at least one address for + * each format we want to support. + */ + +struct test_address { + std::string input; /* value passed to link_addr */ + std::string ntoa; /* expected return from link_ntoa */ + ether_addr addr{}; /* expected return from link_addr */ +}; + +std::vector test_addresses{ + // No delimiter + {"001122334455"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // Colon delimiter + {"00:11:22:33:44:55"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // Dash delimiter + {"00-11-22-33-44-55"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // Period delimiter (link_ntoa format) + {"00.11.22.33.44.55"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // Period delimiter (Cisco format) + {"0011.2233.4455"s, "0.11.22.33.44.55", + ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}}, + + // An addresses without leading zeroes. + {"0:1:02:30:4:55"s, "0.1.2.30.4.55", + ether_addr{0x00, 0x01, 0x02, 0x30, 0x04, 0x55}}, + + // An address with some uppercase letters. + {"AA:B:cC:Dd:e0:1f"s, "aa.b.cc.dd.e0.1f", + ether_addr{0xaa, 0x0b, 0xcc, 0xdd, 0xe0, 0x1f}}, + + // Addresses composed only of letters, to make sure they're not + // confused with an interface name. + + {"aabbccddeeff"s, "aa.bb.cc.dd.ee.ff", + ether_addr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}, + + {"aa:bb:cc:dd:ee:ff"s, "aa.bb.cc.dd.ee.ff", + ether_addr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}}, +}; + +/* + * Test without an interface name. + */ +ATF_TEST_CASE_WITHOUT_HEAD(basic) +ATF_TEST_CASE_BODY(basic) +{ + for (const auto &ta : test_addresses) { + // This does basic tests on the returned value. + auto sdl = make_linkaddr(":" + ta.input); + + // Check the ifname and address. + ATF_REQUIRE_EQ(""s, ifname(sdl)); + ATF_REQUIRE_EQ(ETHER_ADDR_LEN, static_cast(sdl.sdl_alen)); + ATF_REQUIRE_EQ(ta.addr, addr(sdl)); + + // Check link_ntoa returns the expected value. + auto ntoa = std::string(::link_ntoa(&sdl)); + ATF_REQUIRE_EQ(ta.ntoa, ntoa); + } + +} + +/* + * Test with an interface name. + */ +ATF_TEST_CASE_WITHOUT_HEAD(ifname) +ATF_TEST_CASE_BODY(ifname) +{ + for (const auto &ta : test_addresses) { + auto sdl = make_linkaddr("ix0:" + ta.input); + + ATF_REQUIRE_EQ("ix0", ifname(sdl)); + ATF_REQUIRE_EQ(ETHER_ADDR_LEN, static_cast(sdl.sdl_alen)); + ATF_REQUIRE_EQ(ta.addr, addr(sdl)); + + auto ntoa = std::string(::link_ntoa(&sdl)); + ATF_REQUIRE_EQ("ix0:" + ta.ntoa, ntoa); + } + +} + +/* + * Test some non-Ethernet addresses. + */ +ATF_TEST_CASE_WITHOUT_HEAD(nonether) +ATF_TEST_CASE_BODY(nonether) +{ + sockaddr_dl sdl; + + /* A short address */ + sdl = make_linkaddr(":1:23:cc"); + ATF_REQUIRE_EQ("", ifname(sdl)); + ATF_REQUIRE_EQ("1.23.cc"s, ::link_ntoa(&sdl)); + ATF_REQUIRE_EQ(3, sdl.sdl_alen); + ATF_REQUIRE_EQ(true, + std::ranges::equal(std::vector{0x01u, 0x23u, 0xccu}, lladdr(sdl))); + + /* A long address */ + sdl = make_linkaddr(":1:23:cc:a:b:c:d:e:f"); + ATF_REQUIRE_EQ("", ifname(sdl)); + ATF_REQUIRE_EQ("1.23.cc.a.b.c.d.e.f"s, ::link_ntoa(&sdl)); + ATF_REQUIRE_EQ(9, sdl.sdl_alen); + ATF_REQUIRE_EQ(true, std::ranges::equal( + std::vector{0x01u, 0x23u, 0xccu, 0xau, 0xbu, 0xcu, 0xdu, 0xeu, 0xfu}, + lladdr(sdl))); +} + +/* + * Test an extremely long address which would overflow link_ntoa's internal + * buffer. It should handle this by truncating the output. + * (Test for SA-16:37.libc / CVE-2016-6559.) + */ +ATF_TEST_CASE_WITHOUT_HEAD(overlong) +ATF_TEST_CASE_BODY(overlong) +{ + auto sdl = make_linkaddr( + ":01.02.03.04.05.06.07.08.09.0a.0b.0c.0d.0e.0f." + "11.12.13.14.15.16.17.18.19.1a.1b.1c.1d.1e.1f." + "22.22.23.24.25.26.27.28.29.2a.2b.2c.2d.2e.2f"); + + ATF_REQUIRE_EQ( + "1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.11.12.13.14.15.16.17.18.19.1a.1b."s, + ::link_ntoa(&sdl)); +} + +ATF_INIT_TEST_CASES(tcs) +{ + ATF_ADD_TEST_CASE(tcs, basic); + ATF_ADD_TEST_CASE(tcs, ifname); + ATF_ADD_TEST_CASE(tcs, nonether); + ATF_ADD_TEST_CASE(tcs, overlong); +}