xref: /freebsd/lib/libc/tests/net/link_addr_test.cc (revision a1215090416b8afb346fb2ff5b38f25ba0134a3a)
1757e973fSLexi Winter /*
2757e973fSLexi Winter  * Copyright (c) 2025 Lexi Winter
3757e973fSLexi Winter  *
4757e973fSLexi Winter  * SPDX-License-Identifier: ISC
5757e973fSLexi Winter  */
6757e973fSLexi Winter 
7757e973fSLexi Winter /*
8757e973fSLexi Winter  * Tests for link_addr() and link_ntoa().
9757e973fSLexi Winter  *
10757e973fSLexi Winter  * link_addr converts a string representing an (optionally null) interface name
11757e973fSLexi Winter  * followed by an Ethernet address into a sockaddr_dl.  The expected format is
12757e973fSLexi Winter  * "[ifname]:lladdr".  This means if ifname is not specified, the leading colon
13757e973fSLexi Winter  * is still required.
14757e973fSLexi Winter  *
15757e973fSLexi Winter  * link_ntoa does the inverse of link_addr, returning a string representation
16757e973fSLexi Winter  * of the address.
17757e973fSLexi Winter  *
18757e973fSLexi Winter  * Note that the output format of link_ntoa is not valid input for link_addr
19757e973fSLexi Winter  * since the leading colon may be omitted.  This is by design.
20757e973fSLexi Winter  */
21757e973fSLexi Winter 
22757e973fSLexi Winter #include <sys/types.h>
23757e973fSLexi Winter #include <sys/socket.h>
24bbffdfefSLexi Winter 
25757e973fSLexi Winter #include <net/ethernet.h>
26757e973fSLexi Winter #include <net/if_dl.h>
27757e973fSLexi Winter 
28757e973fSLexi Winter #include <format>
29da509c29SLexi Winter #include <iostream>
30757e973fSLexi Winter #include <ranges>
31bbffdfefSLexi Winter #include <span>
32bbffdfefSLexi Winter #include <utility>
33bbffdfefSLexi Winter #include <vector>
34bbffdfefSLexi Winter 
35bbffdfefSLexi Winter #include <cstddef>
36757e973fSLexi Winter #include <cstdint>
37757e973fSLexi Winter 
38757e973fSLexi Winter #include <atf-c++.hpp>
39757e973fSLexi Winter 
40757e973fSLexi Winter using namespace std::literals;
41757e973fSLexi Winter 
42757e973fSLexi Winter /*
43757e973fSLexi Winter  * Define operator== and operator<< for ether_addr so we can use them in
44757e973fSLexi Winter  * ATF_EXPECT_EQ expressions.
45757e973fSLexi Winter  */
46757e973fSLexi Winter 
47757e973fSLexi Winter bool
operator ==(ether_addr a,ether_addr b)48757e973fSLexi Winter operator==(ether_addr a, ether_addr b)
49757e973fSLexi Winter {
50757e973fSLexi Winter 	return (std::ranges::equal(a.octet, b.octet));
51757e973fSLexi Winter }
52757e973fSLexi Winter 
53757e973fSLexi Winter std::ostream &
operator <<(std::ostream & s,ether_addr a)54757e973fSLexi Winter operator<<(std::ostream &s, ether_addr a)
55757e973fSLexi Winter {
56757e973fSLexi Winter 	for (unsigned i = 0; i < ETHER_ADDR_LEN; ++i) {
57757e973fSLexi Winter 		if (i > 0)
58757e973fSLexi Winter 			s << ":";
59757e973fSLexi Winter 
60757e973fSLexi Winter 		s << std::format("{:02x}", static_cast<int>(a.octet[i]));
61757e973fSLexi Winter 	}
62757e973fSLexi Winter 
63757e973fSLexi Winter 	return (s);
64757e973fSLexi Winter }
65757e973fSLexi Winter 
66757e973fSLexi Winter /*
67757e973fSLexi Winter  * Create a sockaddr_dl from a string using link_addr(), and ensure the
68757e973fSLexi Winter  * returned struct looks valid.
69757e973fSLexi Winter  */
70757e973fSLexi Winter sockaddr_dl
make_linkaddr(const std::string & addr)71757e973fSLexi Winter make_linkaddr(const std::string &addr)
72757e973fSLexi Winter {
73757e973fSLexi Winter 	auto sdl = sockaddr_dl{};
74*a1215090SLexi Winter 	int ret;
75757e973fSLexi Winter 
76757e973fSLexi Winter 	sdl.sdl_len = sizeof(sdl);
77*a1215090SLexi Winter 	ret = ::link_addr(addr.c_str(), &sdl);
78757e973fSLexi Winter 
79*a1215090SLexi Winter 	ATF_REQUIRE_EQ(0, ret);
80757e973fSLexi Winter 	ATF_REQUIRE_EQ(AF_LINK, static_cast<int>(sdl.sdl_family));
81757e973fSLexi Winter 	ATF_REQUIRE_EQ(true, sdl.sdl_len > 0);
82757e973fSLexi Winter 	ATF_REQUIRE_EQ(true, sdl.sdl_nlen >= 0);
83757e973fSLexi Winter 
84757e973fSLexi Winter 	return (sdl);
85757e973fSLexi Winter }
86757e973fSLexi Winter 
87757e973fSLexi Winter /*
88757e973fSLexi Winter  * Return the data stored in a sockaddr_dl as a span.
89757e973fSLexi Winter  */
90757e973fSLexi Winter std::span<const char>
data(const sockaddr_dl & sdl)91757e973fSLexi Winter data(const sockaddr_dl &sdl)
92757e973fSLexi Winter {
93757e973fSLexi Winter 	// sdl_len is the entire structure, but we only want the length of the
94757e973fSLexi Winter 	// data area.
95757e973fSLexi Winter 	auto dlen = sdl.sdl_len - offsetof(sockaddr_dl, sdl_data);
96757e973fSLexi Winter 	return {&sdl.sdl_data[0], dlen};
97757e973fSLexi Winter }
98757e973fSLexi Winter 
99757e973fSLexi Winter /*
100757e973fSLexi Winter  * Return the interface name stored in a sockaddr_dl as a string.
101757e973fSLexi Winter  */
102757e973fSLexi Winter std::string_view
ifname(const sockaddr_dl & sdl)103757e973fSLexi Winter ifname(const sockaddr_dl &sdl)
104757e973fSLexi Winter {
105757e973fSLexi Winter 	auto name = data(sdl).subspan(0, sdl.sdl_nlen);
106757e973fSLexi Winter 	return {name.begin(), name.end()};
107757e973fSLexi Winter }
108757e973fSLexi Winter 
109757e973fSLexi Winter /*
110757e973fSLexi Winter  * Return the Ethernet address stored in a sockaddr_dl as an ether_addr.
111757e973fSLexi Winter  */
112757e973fSLexi Winter ether_addr
addr(const sockaddr_dl & sdl)113757e973fSLexi Winter addr(const sockaddr_dl &sdl)
114757e973fSLexi Winter {
115757e973fSLexi Winter 	ether_addr ret{};
116757e973fSLexi Winter 	ATF_REQUIRE_EQ(ETHER_ADDR_LEN, sdl.sdl_alen);
117757e973fSLexi Winter 	std::ranges::copy(data(sdl).subspan(sdl.sdl_nlen, ETHER_ADDR_LEN),
118757e973fSLexi Winter 			  &ret.octet[0]);
119757e973fSLexi Winter 	return (ret);
120757e973fSLexi Winter }
121757e973fSLexi Winter 
122757e973fSLexi Winter /*
123757e973fSLexi Winter  * Return the link address stored in a sockaddr_dl as a span of octets.
124757e973fSLexi Winter  */
125757e973fSLexi Winter std::span<const std::uint8_t>
lladdr(const sockaddr_dl & sdl)126757e973fSLexi Winter lladdr(const sockaddr_dl &sdl)
127757e973fSLexi Winter {
128757e973fSLexi Winter 	auto data = reinterpret_cast<const uint8_t *>(LLADDR(&sdl));
129757e973fSLexi Winter 	return {data, data + sdl.sdl_alen};
130757e973fSLexi Winter }
131757e973fSLexi Winter 
132757e973fSLexi Winter 
133757e973fSLexi Winter /*
134757e973fSLexi Winter  * Some sample addresses we use for testing.  Include at least one address for
135757e973fSLexi Winter  * each format we want to support.
136757e973fSLexi Winter  */
137757e973fSLexi Winter 
138757e973fSLexi Winter struct test_address {
139757e973fSLexi Winter 	std::string input;	/* value passed to link_addr */
140757e973fSLexi Winter 	std::string ntoa;	/* expected return from link_ntoa */
141757e973fSLexi Winter 	ether_addr addr{};	/* expected return from link_addr */
142757e973fSLexi Winter };
143757e973fSLexi Winter 
144757e973fSLexi Winter std::vector<test_address> test_addresses{
145757e973fSLexi Winter 	// No delimiter
146757e973fSLexi Winter 	{"001122334455"s, "0.11.22.33.44.55",
147757e973fSLexi Winter 	 ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
148757e973fSLexi Winter 
149757e973fSLexi Winter 	// Colon delimiter
150757e973fSLexi Winter 	{"00:11:22:33:44:55"s, "0.11.22.33.44.55",
151757e973fSLexi Winter 	 ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
152757e973fSLexi Winter 
153757e973fSLexi Winter 	// Dash delimiter
154757e973fSLexi Winter 	{"00-11-22-33-44-55"s, "0.11.22.33.44.55",
155757e973fSLexi Winter 	 ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
156757e973fSLexi Winter 
157757e973fSLexi Winter 	// Period delimiter (link_ntoa format)
158757e973fSLexi Winter 	{"00.11.22.33.44.55"s, "0.11.22.33.44.55",
159757e973fSLexi Winter 	 ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
160757e973fSLexi Winter 
161757e973fSLexi Winter 	// Period delimiter (Cisco format)
162757e973fSLexi Winter 	{"0011.2233.4455"s, "0.11.22.33.44.55",
163757e973fSLexi Winter 	 ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
164757e973fSLexi Winter 
165757e973fSLexi Winter 	// An addresses without leading zeroes.
166757e973fSLexi Winter 	{"0:1:02:30:4:55"s, "0.1.2.30.4.55",
167757e973fSLexi Winter 	 ether_addr{0x00, 0x01, 0x02, 0x30, 0x04, 0x55}},
168757e973fSLexi Winter 
169757e973fSLexi Winter 	// An address with some uppercase letters.
170757e973fSLexi Winter 	{"AA:B:cC:Dd:e0:1f"s, "aa.b.cc.dd.e0.1f",
171757e973fSLexi Winter 	 ether_addr{0xaa, 0x0b, 0xcc, 0xdd, 0xe0, 0x1f}},
172757e973fSLexi Winter 
173757e973fSLexi Winter 	// Addresses composed only of letters, to make sure they're not
174757e973fSLexi Winter 	// confused with an interface name.
175757e973fSLexi Winter 
176757e973fSLexi Winter 	{"aabbccddeeff"s, "aa.bb.cc.dd.ee.ff",
177757e973fSLexi Winter 	 ether_addr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}},
178757e973fSLexi Winter 
179757e973fSLexi Winter 	{"aa:bb:cc:dd:ee:ff"s, "aa.bb.cc.dd.ee.ff",
180757e973fSLexi Winter 	 ether_addr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}},
181*a1215090SLexi Winter 
182*a1215090SLexi Winter 	// Address with a blank octet; this is an old form of Ethernet address.
183*a1215090SLexi Winter 	{"00:11::33:44:55"s, "0.11.0.33.44.55",
184*a1215090SLexi Winter 	 ether_addr{0x00, 0x11, 0x00, 0x33, 0x44, 0x55}},
185757e973fSLexi Winter };
186757e973fSLexi Winter 
187757e973fSLexi Winter /*
188757e973fSLexi Winter  * Test without an interface name.
189757e973fSLexi Winter  */
190757e973fSLexi Winter ATF_TEST_CASE_WITHOUT_HEAD(basic)
ATF_TEST_CASE_BODY(basic)191757e973fSLexi Winter ATF_TEST_CASE_BODY(basic)
192757e973fSLexi Winter {
193757e973fSLexi Winter 	for (const auto &ta : test_addresses) {
194757e973fSLexi Winter 		// This does basic tests on the returned value.
195757e973fSLexi Winter 		auto sdl = make_linkaddr(":" + ta.input);
196757e973fSLexi Winter 
197757e973fSLexi Winter 		// Check the ifname and address.
198757e973fSLexi Winter 		ATF_REQUIRE_EQ(""s, ifname(sdl));
199757e973fSLexi Winter 		ATF_REQUIRE_EQ(ETHER_ADDR_LEN, static_cast<int>(sdl.sdl_alen));
200757e973fSLexi Winter 		ATF_REQUIRE_EQ(ta.addr, addr(sdl));
201757e973fSLexi Winter 
202757e973fSLexi Winter 		// Check link_ntoa returns the expected value.
203757e973fSLexi Winter 		auto ntoa = std::string(::link_ntoa(&sdl));
204757e973fSLexi Winter 		ATF_REQUIRE_EQ(ta.ntoa, ntoa);
205757e973fSLexi Winter 	}
206757e973fSLexi Winter 
207757e973fSLexi Winter }
208757e973fSLexi Winter 
209757e973fSLexi Winter /*
210757e973fSLexi Winter  * Test with an interface name.
211757e973fSLexi Winter  */
212757e973fSLexi Winter ATF_TEST_CASE_WITHOUT_HEAD(ifname)
ATF_TEST_CASE_BODY(ifname)213757e973fSLexi Winter ATF_TEST_CASE_BODY(ifname)
214757e973fSLexi Winter {
215757e973fSLexi Winter 	for (const auto &ta : test_addresses) {
216757e973fSLexi Winter 		auto sdl = make_linkaddr("ix0:" + ta.input);
217757e973fSLexi Winter 
218757e973fSLexi Winter 		ATF_REQUIRE_EQ("ix0", ifname(sdl));
219757e973fSLexi Winter 		ATF_REQUIRE_EQ(ETHER_ADDR_LEN, static_cast<int>(sdl.sdl_alen));
220757e973fSLexi Winter 		ATF_REQUIRE_EQ(ta.addr, addr(sdl));
221757e973fSLexi Winter 
222757e973fSLexi Winter 		auto ntoa = std::string(::link_ntoa(&sdl));
223757e973fSLexi Winter 		ATF_REQUIRE_EQ("ix0:" + ta.ntoa, ntoa);
224757e973fSLexi Winter 	}
225757e973fSLexi Winter 
226757e973fSLexi Winter }
227757e973fSLexi Winter 
228757e973fSLexi Winter /*
229*a1215090SLexi Winter  * Test with some invalid addresses.
230*a1215090SLexi Winter  */
231*a1215090SLexi Winter ATF_TEST_CASE_WITHOUT_HEAD(invalid)
ATF_TEST_CASE_BODY(invalid)232*a1215090SLexi Winter ATF_TEST_CASE_BODY(invalid)
233*a1215090SLexi Winter {
234*a1215090SLexi Winter 	auto const invalid_addresses = std::vector{
235*a1215090SLexi Winter 		// Invalid separator
236*a1215090SLexi Winter 		":1/2/3"s,
237*a1215090SLexi Winter 		"ix0:1/2/3"s,
238*a1215090SLexi Winter 
239*a1215090SLexi Winter 		// Multiple different separators
240*a1215090SLexi Winter 		":1.2-3"s,
241*a1215090SLexi Winter 		"ix0:1.2-3"s,
242*a1215090SLexi Winter 
243*a1215090SLexi Winter 		// An IP address
244*a1215090SLexi Winter 		":10.1.2.200/28"s,
245*a1215090SLexi Winter 		"ix0:10.1.2.200/28"s,
246*a1215090SLexi Winter 
247*a1215090SLexi Winter 		// Valid address followed by garbage
248*a1215090SLexi Winter 		":1.2.3xxx"s,
249*a1215090SLexi Winter 		":1.2.3.xxx"s,
250*a1215090SLexi Winter 		"ix0:1.2.3xxx"s,
251*a1215090SLexi Winter 		"ix0:1.2.3.xxx"s,
252*a1215090SLexi Winter 	};
253*a1215090SLexi Winter 
254*a1215090SLexi Winter 	for (auto const &addr : invalid_addresses) {
255*a1215090SLexi Winter 		int ret;
256*a1215090SLexi Winter 
257*a1215090SLexi Winter 		auto sdl = sockaddr_dl{};
258*a1215090SLexi Winter 		sdl.sdl_len = sizeof(sdl);
259*a1215090SLexi Winter 
260*a1215090SLexi Winter 		ret = link_addr(addr.c_str(), &sdl);
261*a1215090SLexi Winter 		ATF_REQUIRE_EQ(-1, ret);
262*a1215090SLexi Winter 	}
263*a1215090SLexi Winter }
264*a1215090SLexi Winter 
265*a1215090SLexi Winter /*
266757e973fSLexi Winter  * Test some non-Ethernet addresses.
267757e973fSLexi Winter  */
268757e973fSLexi Winter ATF_TEST_CASE_WITHOUT_HEAD(nonether)
ATF_TEST_CASE_BODY(nonether)269757e973fSLexi Winter ATF_TEST_CASE_BODY(nonether)
270757e973fSLexi Winter {
271757e973fSLexi Winter 	sockaddr_dl sdl;
272757e973fSLexi Winter 
273757e973fSLexi Winter 	/* A short address */
274757e973fSLexi Winter 	sdl = make_linkaddr(":1:23:cc");
275757e973fSLexi Winter 	ATF_REQUIRE_EQ("", ifname(sdl));
276757e973fSLexi Winter 	ATF_REQUIRE_EQ("1.23.cc"s, ::link_ntoa(&sdl));
277757e973fSLexi Winter 	ATF_REQUIRE_EQ(3, sdl.sdl_alen);
278757e973fSLexi Winter 	ATF_REQUIRE_EQ(true,
279757e973fSLexi Winter 	    std::ranges::equal(std::vector{0x01u, 0x23u, 0xccu}, lladdr(sdl)));
280757e973fSLexi Winter 
281757e973fSLexi Winter 	/* A long address */
282757e973fSLexi Winter 	sdl = make_linkaddr(":1:23:cc:a:b:c:d:e:f");
283757e973fSLexi Winter 	ATF_REQUIRE_EQ("", ifname(sdl));
284757e973fSLexi Winter 	ATF_REQUIRE_EQ("1.23.cc.a.b.c.d.e.f"s, ::link_ntoa(&sdl));
285757e973fSLexi Winter 	ATF_REQUIRE_EQ(9, sdl.sdl_alen);
286757e973fSLexi Winter 	ATF_REQUIRE_EQ(true, std::ranges::equal(
287757e973fSLexi Winter 	    std::vector{0x01u, 0x23u, 0xccu, 0xau, 0xbu, 0xcu, 0xdu, 0xeu, 0xfu},
288757e973fSLexi Winter 	    lladdr(sdl)));
289757e973fSLexi Winter }
290757e973fSLexi Winter 
291757e973fSLexi Winter /*
292*a1215090SLexi Winter  * Test link_addr behaviour with undersized buffers.
293*a1215090SLexi Winter  */
294*a1215090SLexi Winter ATF_TEST_CASE_WITHOUT_HEAD(smallbuf)
ATF_TEST_CASE_BODY(smallbuf)295*a1215090SLexi Winter ATF_TEST_CASE_BODY(smallbuf)
296*a1215090SLexi Winter {
297*a1215090SLexi Winter 	static constexpr auto garbage = std::byte{0xcc};
298*a1215090SLexi Winter 	auto buf = std::vector<std::byte>();
299*a1215090SLexi Winter 	sockaddr_dl *sdl;
300*a1215090SLexi Winter 	int ret;
301*a1215090SLexi Winter 
302*a1215090SLexi Winter 	/*
303*a1215090SLexi Winter 	 * Make an sdl with an sdl_data member of the appropriate size, and
304*a1215090SLexi Winter 	 * place it in buf.  Ensure it's followed by a trailing byte of garbage
305*a1215090SLexi Winter 	 * so we can test that link_addr doesn't write past the end.
306*a1215090SLexi Winter 	 */
307*a1215090SLexi Winter 	auto mksdl = [&buf](std::size_t datalen) -> sockaddr_dl * {
308*a1215090SLexi Winter 		auto actual_size = datalen + offsetof(sockaddr_dl, sdl_data);
309*a1215090SLexi Winter 
310*a1215090SLexi Winter 		buf.resize(actual_size + 1);
311*a1215090SLexi Winter 		std::ranges::fill(buf, garbage);
312*a1215090SLexi Winter 
313*a1215090SLexi Winter 		auto *sdl = new(reinterpret_cast<sockaddr_dl *>(&buf[0]))
314*a1215090SLexi Winter 		    sockaddr_dl;
315*a1215090SLexi Winter 		sdl->sdl_len = actual_size;
316*a1215090SLexi Winter 		return (sdl);
317*a1215090SLexi Winter 	};
318*a1215090SLexi Winter 
319*a1215090SLexi Winter 	/* An sdl large enough to store the interface name */
320*a1215090SLexi Winter 	sdl = mksdl(3);
321*a1215090SLexi Winter 	ret = link_addr("ix0:1.2.3", sdl);
322*a1215090SLexi Winter 	ATF_REQUIRE(*rbegin(buf) == garbage);
323*a1215090SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
324*a1215090SLexi Winter 	ATF_REQUIRE_EQ(ENOSPC, errno);
325*a1215090SLexi Winter 	ATF_REQUIRE_EQ(3, sdl->sdl_nlen);
326*a1215090SLexi Winter 	ATF_REQUIRE_EQ("ix0", ifname(*sdl));
327*a1215090SLexi Winter 	ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen));
328*a1215090SLexi Winter 
329*a1215090SLexi Winter 	/*
330*a1215090SLexi Winter 	 * For these tests, test both with and without an interface name, since
331*a1215090SLexi Winter 	 * that will overflow the buffer in different places.
332*a1215090SLexi Winter 	 */
333*a1215090SLexi Winter 
334*a1215090SLexi Winter 	/* An empty sdl.  Nothing may grow on this cursed ground. */
335*a1215090SLexi Winter 
336*a1215090SLexi Winter 	sdl = mksdl(0);
337*a1215090SLexi Winter 	ret = link_addr("ix0:1.2.3", sdl);
338*a1215090SLexi Winter 	ATF_REQUIRE(*rbegin(buf) == garbage);
339*a1215090SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
340*a1215090SLexi Winter 	ATF_REQUIRE_EQ(ENOSPC, errno);
341*a1215090SLexi Winter 	ATF_REQUIRE_EQ(0, sdl->sdl_nlen);
342*a1215090SLexi Winter 	ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen));
343*a1215090SLexi Winter 
344*a1215090SLexi Winter 	sdl = mksdl(0);
345*a1215090SLexi Winter 	ret = link_addr(":1.2.3", sdl);
346*a1215090SLexi Winter 	ATF_REQUIRE(*rbegin(buf) == garbage);
347*a1215090SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
348*a1215090SLexi Winter 	ATF_REQUIRE_EQ(ENOSPC, errno);
349*a1215090SLexi Winter 	ATF_REQUIRE_EQ(0, sdl->sdl_nlen);
350*a1215090SLexi Winter 	ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen));
351*a1215090SLexi Winter 
352*a1215090SLexi Winter 	/*
353*a1215090SLexi Winter 	 * An sdl large enough to store the interface name and two octets of the
354*a1215090SLexi Winter 	 * address.
355*a1215090SLexi Winter 	 */
356*a1215090SLexi Winter 
357*a1215090SLexi Winter 	sdl = mksdl(5);
358*a1215090SLexi Winter 	ret = link_addr("ix0:1.2.3", sdl);
359*a1215090SLexi Winter 	ATF_REQUIRE(*rbegin(buf) == garbage);
360*a1215090SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
361*a1215090SLexi Winter 	ATF_REQUIRE_EQ(ENOSPC, errno);
362*a1215090SLexi Winter 	ATF_REQUIRE_EQ("ix0", ifname(*sdl));
363*a1215090SLexi Winter 	ATF_REQUIRE(std::ranges::equal(
364*a1215090SLexi Winter 	    std::vector{ 0x01, 0x02 }, lladdr(*sdl)));
365*a1215090SLexi Winter 
366*a1215090SLexi Winter 	sdl = mksdl(2);
367*a1215090SLexi Winter 	ret = link_addr(":1.2.3", sdl);
368*a1215090SLexi Winter 	ATF_REQUIRE(*rbegin(buf) == garbage);
369*a1215090SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
370*a1215090SLexi Winter 	ATF_REQUIRE_EQ(ENOSPC, errno);
371*a1215090SLexi Winter 	ATF_REQUIRE_EQ("", ifname(*sdl));
372*a1215090SLexi Winter 	ATF_REQUIRE(std::ranges::equal(
373*a1215090SLexi Winter 	    std::vector{ 0x01, 0x02 }, lladdr(*sdl)));
374*a1215090SLexi Winter 
375*a1215090SLexi Winter 	/*
376*a1215090SLexi Winter 	 * An sdl large enough to store the entire address.
377*a1215090SLexi Winter 	 */
378*a1215090SLexi Winter 
379*a1215090SLexi Winter 	sdl = mksdl(6);
380*a1215090SLexi Winter 	ret = link_addr("ix0:1.2.3", sdl);
381*a1215090SLexi Winter 	ATF_REQUIRE(*rbegin(buf) == garbage);
382*a1215090SLexi Winter 	ATF_REQUIRE_EQ(0, ret);
383*a1215090SLexi Winter 	ATF_REQUIRE_EQ("ix0", ifname(*sdl));
384*a1215090SLexi Winter 	ATF_REQUIRE(std::ranges::equal(
385*a1215090SLexi Winter 	    std::vector{ 0x01, 0x02, 0x03 }, lladdr(*sdl)));
386*a1215090SLexi Winter 
387*a1215090SLexi Winter 	sdl = mksdl(3);
388*a1215090SLexi Winter 	ret = link_addr(":1.2.3", sdl);
389*a1215090SLexi Winter 	ATF_REQUIRE(*rbegin(buf) == garbage);
390*a1215090SLexi Winter 	ATF_REQUIRE_EQ(0, ret);
391*a1215090SLexi Winter 	ATF_REQUIRE_EQ("", ifname(*sdl));
392*a1215090SLexi Winter 	ATF_REQUIRE(std::ranges::equal(
393*a1215090SLexi Winter 	    std::vector{ 0x01, 0x02, 0x03 }, lladdr(*sdl)));
394*a1215090SLexi Winter }
395*a1215090SLexi Winter 
396*a1215090SLexi Winter /*
397757e973fSLexi Winter  * Test an extremely long address which would overflow link_ntoa's internal
398757e973fSLexi Winter  * buffer.  It should handle this by truncating the output.
399757e973fSLexi Winter  * (Test for SA-16:37.libc / CVE-2016-6559.)
400757e973fSLexi Winter  */
401757e973fSLexi Winter ATF_TEST_CASE_WITHOUT_HEAD(overlong)
ATF_TEST_CASE_BODY(overlong)402757e973fSLexi Winter ATF_TEST_CASE_BODY(overlong)
403757e973fSLexi Winter {
404757e973fSLexi Winter 	auto sdl = make_linkaddr(
405757e973fSLexi Winter 	    ":01.02.03.04.05.06.07.08.09.0a.0b.0c.0d.0e.0f."
406757e973fSLexi Winter 	    "11.12.13.14.15.16.17.18.19.1a.1b.1c.1d.1e.1f."
407757e973fSLexi Winter 	    "22.22.23.24.25.26.27.28.29.2a.2b.2c.2d.2e.2f");
408757e973fSLexi Winter 
409757e973fSLexi Winter 	ATF_REQUIRE_EQ(
410757e973fSLexi Winter 	    "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,
411757e973fSLexi Winter 	    ::link_ntoa(&sdl));
412757e973fSLexi Winter }
413757e973fSLexi Winter 
414da509c29SLexi Winter /*
415da509c29SLexi Winter  * Test link_ntoa_r, the re-entrant version of link_ntoa().
416da509c29SLexi Winter  */
417da509c29SLexi Winter ATF_TEST_CASE_WITHOUT_HEAD(link_ntoa_r)
ATF_TEST_CASE_BODY(link_ntoa_r)418da509c29SLexi Winter ATF_TEST_CASE_BODY(link_ntoa_r)
419da509c29SLexi Winter {
420da509c29SLexi Winter 	static constexpr char garbage = 0x41;
421da509c29SLexi Winter 	std::vector<char> buf;
422da509c29SLexi Winter 	sockaddr_dl sdl;
423da509c29SLexi Winter 	size_t len;
424da509c29SLexi Winter 	int ret;
425da509c29SLexi Winter 
426da509c29SLexi Winter 	// Return the contents of buf as a string, using the NUL terminator to
427da509c29SLexi Winter 	// determine length.  This is to ensure we're using the return value in
428da509c29SLexi Winter 	// the same way C code would, but we do a bit more verification to
429da509c29SLexi Winter 	// elicit a test failure rather than a SEGV if it's broken.
430da509c29SLexi Winter 	auto bufstr = [&buf]() -> std::string_view {
431da509c29SLexi Winter 		// Find the NUL.
432da509c29SLexi Winter 		auto end = std::ranges::find(buf, '\0');
433da509c29SLexi Winter 		ATF_REQUIRE(end != buf.end());
434da509c29SLexi Winter 
435da509c29SLexi Winter 		// Intentionally chopping the NUL off.
436da509c29SLexi Winter 		return {begin(buf), end};
437da509c29SLexi Winter 	};
438da509c29SLexi Winter 
439da509c29SLexi Winter 	// Resize the buffer and set the contents to a known garbage value, so
440da509c29SLexi Winter 	// we don't accidentally have a NUL in the right place when link_ntoa_r
441da509c29SLexi Winter 	// didn't put it there.
442da509c29SLexi Winter 	auto resetbuf = [&buf, &len](std::size_t size) {
443da509c29SLexi Winter 		len = size;
444da509c29SLexi Winter 		buf.resize(len);
445da509c29SLexi Winter 		std::ranges::fill(buf, garbage);
446da509c29SLexi Winter 	};
447da509c29SLexi Winter 
448da509c29SLexi Winter 	// Test a short address with a large buffer.
449da509c29SLexi Winter 	sdl = make_linkaddr("ix0:1.2.3");
450da509c29SLexi Winter 	resetbuf(64);
451da509c29SLexi Winter 	ret = ::link_ntoa_r(&sdl, &buf[0], &len);
452da509c29SLexi Winter 	ATF_REQUIRE_EQ(0, ret);
453da509c29SLexi Winter 	ATF_REQUIRE_EQ(10, len);
454da509c29SLexi Winter 	ATF_REQUIRE_EQ("ix0:1.2.3"s, bufstr());
455da509c29SLexi Winter 
456da509c29SLexi Winter 	// Test a buffer which is exactly the right size.
457da509c29SLexi Winter 	sdl = make_linkaddr("ix0:1.2.3");
458da509c29SLexi Winter 	resetbuf(10);
459da509c29SLexi Winter 	ret = ::link_ntoa_r(&sdl, &buf[0], &len);
460da509c29SLexi Winter 	ATF_REQUIRE_EQ(0, ret);
461da509c29SLexi Winter 	ATF_REQUIRE_EQ(10, len);
462da509c29SLexi Winter 	ATF_REQUIRE_EQ("ix0:1.2.3"sv, bufstr());
463da509c29SLexi Winter 
464da509c29SLexi Winter 	// Test various short buffers, using a table of buffer length and the
465da509c29SLexi Winter 	// output we expect.  All of these should produce valid but truncated
466da509c29SLexi Winter 	// strings, with a trailing NUL and with buflen set correctly.
467da509c29SLexi Winter 
468da509c29SLexi Winter 	auto buftests = std::vector<std::pair<std::size_t, std::string_view>>{
469da509c29SLexi Winter 		{1u, ""sv},
470da509c29SLexi Winter 		{2u, ""sv},
471da509c29SLexi Winter 		{3u, ""sv},
472da509c29SLexi Winter 		{4u, "ix0"sv},
473da509c29SLexi Winter 		{5u, "ix0:"sv},
474da509c29SLexi Winter 		{6u, "ix0:1"sv},
475da509c29SLexi Winter 		{7u, "ix0:1."sv},
476da509c29SLexi Winter 		{8u, "ix0:1.2"sv},
477da509c29SLexi Winter 		{9u, "ix0:1.2."sv},
478da509c29SLexi Winter 	};
479da509c29SLexi Winter 
480da509c29SLexi Winter 	for (auto const &[buflen, expected] : buftests) {
481da509c29SLexi Winter 		sdl = make_linkaddr("ix0:1.2.3");
482da509c29SLexi Winter 		resetbuf(buflen);
483da509c29SLexi Winter 		ret = ::link_ntoa_r(&sdl, &buf[0], &len);
484da509c29SLexi Winter 		ATF_REQUIRE_EQ(-1, ret);
485da509c29SLexi Winter 		ATF_REQUIRE_EQ(10, len);
486da509c29SLexi Winter 		ATF_REQUIRE_EQ(expected, bufstr());
487da509c29SLexi Winter 	}
488da509c29SLexi Winter 
489da509c29SLexi Winter 	// Test a NULL buffer, which should just set buflen.
490da509c29SLexi Winter 	sdl = make_linkaddr("ix0:1.2.3");
491da509c29SLexi Winter 	len = 0;
492da509c29SLexi Winter 	ret = ::link_ntoa_r(&sdl, NULL, &len);
493da509c29SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
494da509c29SLexi Winter 	ATF_REQUIRE_EQ(10, len);
495da509c29SLexi Winter 
496da509c29SLexi Winter 	// A NULL buffer with a non-zero length should also be accepted.
497da509c29SLexi Winter 	sdl = make_linkaddr("ix0:1.2.3");
498da509c29SLexi Winter 	len = 64;
499da509c29SLexi Winter 	ret = ::link_ntoa_r(&sdl, NULL, &len);
500da509c29SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
501da509c29SLexi Winter 	ATF_REQUIRE_EQ(10, len);
502da509c29SLexi Winter 
503da509c29SLexi Winter 	// Test a non-NULL buffer, but with a length of zero.
504da509c29SLexi Winter 	sdl = make_linkaddr("ix0:1.2.3");
505da509c29SLexi Winter 	resetbuf(1);
506da509c29SLexi Winter 	len = 0;
507da509c29SLexi Winter 	ret = ::link_ntoa_r(&sdl, &buf[0], &len);
508da509c29SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
509da509c29SLexi Winter 	ATF_REQUIRE_EQ(10, len);
510da509c29SLexi Winter 	// Check we really didn't write anything.
511da509c29SLexi Winter 	ATF_REQUIRE_EQ(garbage, buf[0]);
512da509c29SLexi Winter 
513da509c29SLexi Winter 	// Test a buffer which would be truncated in the middle of a two-digit
514da509c29SLexi Winter 	// hex octet, which should not write the truncated octet at all.
515da509c29SLexi Winter 	sdl = make_linkaddr("ix0:1.22.3");
516da509c29SLexi Winter 	resetbuf(8);
517da509c29SLexi Winter 	ret = ::link_ntoa_r(&sdl, &buf[0], &len);
518da509c29SLexi Winter 	ATF_REQUIRE_EQ(-1, ret);
519da509c29SLexi Winter 	ATF_REQUIRE_EQ(11, len);
520da509c29SLexi Winter 	ATF_REQUIRE_EQ("ix0:1."sv, bufstr());
521da509c29SLexi Winter }
522da509c29SLexi Winter 
ATF_INIT_TEST_CASES(tcs)523757e973fSLexi Winter ATF_INIT_TEST_CASES(tcs)
524757e973fSLexi Winter {
525757e973fSLexi Winter 	ATF_ADD_TEST_CASE(tcs, basic);
526757e973fSLexi Winter 	ATF_ADD_TEST_CASE(tcs, ifname);
527*a1215090SLexi Winter 	ATF_ADD_TEST_CASE(tcs, smallbuf);
528*a1215090SLexi Winter 	ATF_ADD_TEST_CASE(tcs, invalid);
529757e973fSLexi Winter 	ATF_ADD_TEST_CASE(tcs, nonether);
530757e973fSLexi Winter 	ATF_ADD_TEST_CASE(tcs, overlong);
531da509c29SLexi Winter 	ATF_ADD_TEST_CASE(tcs, link_ntoa_r);
532757e973fSLexi Winter }
533