xref: /illumos-gate/usr/src/test/os-tests/tests/libsocket/nametoindex.c (revision 2ea71e24ff718fdbfe2a79f10ce89db251e34645)
1*2ea71e24SRobert Mustacchi /*
2*2ea71e24SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*2ea71e24SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*2ea71e24SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*2ea71e24SRobert Mustacchi  * 1.0 of the CDDL.
6*2ea71e24SRobert Mustacchi  *
7*2ea71e24SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*2ea71e24SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*2ea71e24SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*2ea71e24SRobert Mustacchi  */
11*2ea71e24SRobert Mustacchi 
12*2ea71e24SRobert Mustacchi /*
13*2ea71e24SRobert Mustacchi  * Copyright 2026 Oxide Computer Company
14*2ea71e24SRobert Mustacchi  */
15*2ea71e24SRobert Mustacchi 
16*2ea71e24SRobert Mustacchi /*
17*2ea71e24SRobert Mustacchi  * Verify that a few sources all agree on socket index information:
18*2ea71e24SRobert Mustacchi  * getifaddrs(3SOCKET), if_nametoindex(3SOCKET), and manually walking
19*2ea71e24SRobert Mustacchi  * interfaces. if_nametoindex() doesn't always handle the fact that we can have
20*2ea71e24SRobert Mustacchi  * two interfaces (v4 and v6) with the same name. if_nametoindex() prefers v4
21*2ea71e24SRobert Mustacchi  * addresses over v6. So when both are up, we'll need to be careful.
22*2ea71e24SRobert Mustacchi  *
23*2ea71e24SRobert Mustacchi  * This test assumes the set of interfaces isn't changing durings its lifetime.
24*2ea71e24SRobert Mustacchi  */
25*2ea71e24SRobert Mustacchi 
26*2ea71e24SRobert Mustacchi #include <stdlib.h>
27*2ea71e24SRobert Mustacchi #include <err.h>
28*2ea71e24SRobert Mustacchi #include <sys/types.h>
29*2ea71e24SRobert Mustacchi #include <sys/socket.h>
30*2ea71e24SRobert Mustacchi #include <ifaddrs.h>
31*2ea71e24SRobert Mustacchi #include <net/if.h>
32*2ea71e24SRobert Mustacchi #include <sys/sockio.h>
33*2ea71e24SRobert Mustacchi #include <string.h>
34*2ea71e24SRobert Mustacchi #include <unistd.h>
35*2ea71e24SRobert Mustacchi #include <errno.h>
36*2ea71e24SRobert Mustacchi #include <sys/sysmacros.h>
37*2ea71e24SRobert Mustacchi 
38*2ea71e24SRobert Mustacchi int
main(void)39*2ea71e24SRobert Mustacchi main(void)
40*2ea71e24SRobert Mustacchi {
41*2ea71e24SRobert Mustacchi 	int ret = EXIT_SUCCESS;
42*2ea71e24SRobert Mustacchi 	int s4, s6;
43*2ea71e24SRobert Mustacchi 	struct ifaddrs *ifa;
44*2ea71e24SRobert Mustacchi 
45*2ea71e24SRobert Mustacchi 	if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
46*2ea71e24SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get IPv4 socket");
47*2ea71e24SRobert Mustacchi 	}
48*2ea71e24SRobert Mustacchi 
49*2ea71e24SRobert Mustacchi 	if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
50*2ea71e24SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get IPv6 socket");
51*2ea71e24SRobert Mustacchi 	}
52*2ea71e24SRobert Mustacchi 
53*2ea71e24SRobert Mustacchi 	if (getifaddrs(&ifa) != 0) {
54*2ea71e24SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get address information");
55*2ea71e24SRobert Mustacchi 	}
56*2ea71e24SRobert Mustacchi 
57*2ea71e24SRobert Mustacchi 	for (struct ifaddrs *i = ifa; i != NULL; i = i->ifa_next) {
58*2ea71e24SRobert Mustacchi 		struct lifreq lif;
59*2ea71e24SRobert Mustacchi 		char name[IF_NAMESIZE];
60*2ea71e24SRobert Mustacchi 		sa_family_t fam = i->ifa_addr->sa_family;
61*2ea71e24SRobert Mustacchi 
62*2ea71e24SRobert Mustacchi 		if (fam != AF_INET && fam != AF_INET6) {
63*2ea71e24SRobert Mustacchi 			continue;
64*2ea71e24SRobert Mustacchi 		}
65*2ea71e24SRobert Mustacchi 
66*2ea71e24SRobert Mustacchi 		/*
67*2ea71e24SRobert Mustacchi 		 * First ask the kernel our index.
68*2ea71e24SRobert Mustacchi 		 */
69*2ea71e24SRobert Mustacchi 		(void) memset(&lif, 0, sizeof (lif));
70*2ea71e24SRobert Mustacchi 		if (strlcpy(lif.lifr_name, i->ifa_name,
71*2ea71e24SRobert Mustacchi 		    sizeof (lif.lifr_name)) >= sizeof (lif.lifr_name)) {
72*2ea71e24SRobert Mustacchi 			errx(EXIT_FAILURE, "INTERNAL TEST FAILURE: encountered "
73*2ea71e24SRobert Mustacchi 			    "interface name %s that would overflow struct "
74*2ea71e24SRobert Mustacchi 			    "lifreq length!", i->ifa_name);
75*2ea71e24SRobert Mustacchi 		}
76*2ea71e24SRobert Mustacchi 
77*2ea71e24SRobert Mustacchi 		if (ioctl(fam == AF_INET ? s4 : s6, SIOCGLIFINDEX, &lif) != 0) {
78*2ea71e24SRobert Mustacchi 			warn("TEST FAILED: failed to ask kernel for index of "
79*2ea71e24SRobert Mustacchi 			    "interface %s (family 0x%x", i->ifa_name, fam);
80*2ea71e24SRobert Mustacchi 			ret = EXIT_FAILURE;
81*2ea71e24SRobert Mustacchi 			continue;
82*2ea71e24SRobert Mustacchi 		}
83*2ea71e24SRobert Mustacchi 
84*2ea71e24SRobert Mustacchi 		if (if_indextoname(lif.lifr_index, name) == NULL) {
85*2ea71e24SRobert Mustacchi 			warn("TEST FAILED: if_indextoname() failed to convert "
86*2ea71e24SRobert Mustacchi 			    "index 0x%x back to %s", lif.lifr_index,
87*2ea71e24SRobert Mustacchi 			    i->ifa_name);
88*2ea71e24SRobert Mustacchi 			ret = EXIT_FAILURE;
89*2ea71e24SRobert Mustacchi 			continue;
90*2ea71e24SRobert Mustacchi 		}
91*2ea71e24SRobert Mustacchi 
92*2ea71e24SRobert Mustacchi 		if (strcmp(name, i->ifa_name) != 0) {
93*2ea71e24SRobert Mustacchi 			warn("TEST FAILED: if_indextoname() returned name %s "
94*2ea71e24SRobert Mustacchi 			    "for index 0x%x, but expected %s", name,
95*2ea71e24SRobert Mustacchi 			    lif.lifr_index, i->ifa_name);
96*2ea71e24SRobert Mustacchi 			ret = EXIT_FAILURE;
97*2ea71e24SRobert Mustacchi 		} else {
98*2ea71e24SRobert Mustacchi 			(void) printf("TEST PASSED: Mapped %s (fam 0x%x) index "
99*2ea71e24SRobert Mustacchi 			    "back to expected name\n", i->ifa_name, fam);
100*2ea71e24SRobert Mustacchi 		}
101*2ea71e24SRobert Mustacchi 
102*2ea71e24SRobert Mustacchi 		/*
103*2ea71e24SRobert Mustacchi 		 * Now go from the name to the index. In general we expect the
104*2ea71e24SRobert Mustacchi 		 * IPv4 and IPv6 interfaces with the same name to share the same
105*2ea71e24SRobert Mustacchi 		 * index.
106*2ea71e24SRobert Mustacchi 		 */
107*2ea71e24SRobert Mustacchi 		uint_t idx = if_nametoindex(i->ifa_name);
108*2ea71e24SRobert Mustacchi 		if (idx == 0) {
109*2ea71e24SRobert Mustacchi 			warn("TEST FAILED: if_nametoindex() unexpected failed "
110*2ea71e24SRobert Mustacchi 			    "on %s (fam 0x%x)", i->ifa_name, fam);
111*2ea71e24SRobert Mustacchi 			ret = EXIT_FAILURE;
112*2ea71e24SRobert Mustacchi 		} else if (idx != lif.lifr_index) {
113*2ea71e24SRobert Mustacchi 			warnx("TEST FAILED: if_nametoindex() on %s (fam 0x%x) "
114*2ea71e24SRobert Mustacchi 			    "returned index 0x%x, but expected 0x%x from "
115*2ea71e24SRobert Mustacchi 			    "SIOCGLIFINDEX\n", i->ifa_name, fam, idx,
116*2ea71e24SRobert Mustacchi 			    lif.lifr_index);
117*2ea71e24SRobert Mustacchi 			ret = EXIT_FAILURE;
118*2ea71e24SRobert Mustacchi 		} else {
119*2ea71e24SRobert Mustacchi 			(void) printf("TEST PASSED: %s (fam 0x%x) name to "
120*2ea71e24SRobert Mustacchi 			    "index round tripped successfully\n", i->ifa_name,
121*2ea71e24SRobert Mustacchi 			    fam);
122*2ea71e24SRobert Mustacchi 		}
123*2ea71e24SRobert Mustacchi 	}
124*2ea71e24SRobert Mustacchi 
125*2ea71e24SRobert Mustacchi 	const char *bad_names[] = { "", "nonumber", "thisiswaytoolongforanif0",
126*2ea71e24SRobert Mustacchi 	    "bad/char23", "if1234567890123456" };
127*2ea71e24SRobert Mustacchi 	for (size_t i = 0; i < ARRAY_SIZE(bad_names); i++) {
128*2ea71e24SRobert Mustacchi 		uint_t idx = if_nametoindex(bad_names[i]);
129*2ea71e24SRobert Mustacchi 		if (idx != 0) {
130*2ea71e24SRobert Mustacchi 			warnx("TEST FAILED: if_nametoindex() returned idx 0x%x "
131*2ea71e24SRobert Mustacchi 			    "on invalid name '%s': expected failure", idx,
132*2ea71e24SRobert Mustacchi 			    bad_names[i]);
133*2ea71e24SRobert Mustacchi 			ret = EXIT_FAILURE;
134*2ea71e24SRobert Mustacchi 		} else if (errno != ENXIO) {
135*2ea71e24SRobert Mustacchi 			warnx("TEST FAILED: if_nametoindex() returned %s on "
136*2ea71e24SRobert Mustacchi 			    "invalid name '%s': expected ENXIO",
137*2ea71e24SRobert Mustacchi 			    strerrorname_np(errno), bad_names[i]);
138*2ea71e24SRobert Mustacchi 			ret = EXIT_FAILURE;
139*2ea71e24SRobert Mustacchi 		} else {
140*2ea71e24SRobert Mustacchi 			(void) printf("TEST PASSED: if_nametoindex() failed "
141*2ea71e24SRobert Mustacchi 			    "bad name '%s' with ENXIO\n", bad_names[i]);
142*2ea71e24SRobert Mustacchi 		}
143*2ea71e24SRobert Mustacchi 	}
144*2ea71e24SRobert Mustacchi 
145*2ea71e24SRobert Mustacchi 	freeifaddrs(ifa);
146*2ea71e24SRobert Mustacchi 	(void) close(s6);
147*2ea71e24SRobert Mustacchi 	(void) close(s4);
148*2ea71e24SRobert Mustacchi 	if (ret == EXIT_SUCCESS) {
149*2ea71e24SRobert Mustacchi 		(void) printf("All tests passed successfully\n");
150*2ea71e24SRobert Mustacchi 	}
151*2ea71e24SRobert Mustacchi 	return (ret);
152*2ea71e24SRobert Mustacchi }
153