#include <stdlib.h>
#include <err.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <sys/sockio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/sysmacros.h>
int
main(void)
{
int ret = EXIT_SUCCESS;
int s4, s6;
struct ifaddrs *ifa;
if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
err(EXIT_FAILURE, "failed to get IPv4 socket");
}
if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
err(EXIT_FAILURE, "failed to get IPv6 socket");
}
if (getifaddrs(&ifa) != 0) {
err(EXIT_FAILURE, "failed to get address information");
}
for (struct ifaddrs *i = ifa; i != NULL; i = i->ifa_next) {
struct lifreq lif;
char name[IF_NAMESIZE];
sa_family_t fam = i->ifa_addr->sa_family;
if (fam != AF_INET && fam != AF_INET6) {
continue;
}
(void) memset(&lif, 0, sizeof (lif));
if (strlcpy(lif.lifr_name, i->ifa_name,
sizeof (lif.lifr_name)) >= sizeof (lif.lifr_name)) {
errx(EXIT_FAILURE, "INTERNAL TEST FAILURE: encountered "
"interface name %s that would overflow struct "
"lifreq length!", i->ifa_name);
}
if (ioctl(fam == AF_INET ? s4 : s6, SIOCGLIFINDEX, &lif) != 0) {
warn("TEST FAILED: failed to ask kernel for index of "
"interface %s (family 0x%x", i->ifa_name, fam);
ret = EXIT_FAILURE;
continue;
}
if (if_indextoname(lif.lifr_index, name) == NULL) {
warn("TEST FAILED: if_indextoname() failed to convert "
"index 0x%x back to %s", lif.lifr_index,
i->ifa_name);
ret = EXIT_FAILURE;
continue;
}
if (strcmp(name, i->ifa_name) != 0) {
warn("TEST FAILED: if_indextoname() returned name %s "
"for index 0x%x, but expected %s", name,
lif.lifr_index, i->ifa_name);
ret = EXIT_FAILURE;
} else {
(void) printf("TEST PASSED: Mapped %s (fam 0x%x) index "
"back to expected name\n", i->ifa_name, fam);
}
uint_t idx = if_nametoindex(i->ifa_name);
if (idx == 0) {
warn("TEST FAILED: if_nametoindex() unexpected failed "
"on %s (fam 0x%x)", i->ifa_name, fam);
ret = EXIT_FAILURE;
} else if (idx != lif.lifr_index) {
warnx("TEST FAILED: if_nametoindex() on %s (fam 0x%x) "
"returned index 0x%x, but expected 0x%x from "
"SIOCGLIFINDEX\n", i->ifa_name, fam, idx,
lif.lifr_index);
ret = EXIT_FAILURE;
} else {
(void) printf("TEST PASSED: %s (fam 0x%x) name to "
"index round tripped successfully\n", i->ifa_name,
fam);
}
}
const char *bad_names[] = { "", "nonumber", "thisiswaytoolongforanif0",
"bad/char23", "if1234567890123456" };
for (size_t i = 0; i < ARRAY_SIZE(bad_names); i++) {
uint_t idx = if_nametoindex(bad_names[i]);
if (idx != 0) {
warnx("TEST FAILED: if_nametoindex() returned idx 0x%x "
"on invalid name '%s': expected failure", idx,
bad_names[i]);
ret = EXIT_FAILURE;
} else if (errno != ENXIO) {
warnx("TEST FAILED: if_nametoindex() returned %s on "
"invalid name '%s': expected ENXIO",
strerrorname_np(errno), bad_names[i]);
ret = EXIT_FAILURE;
} else {
(void) printf("TEST PASSED: if_nametoindex() failed "
"bad name '%s' with ENXIO\n", bad_names[i]);
}
}
freeifaddrs(ifa);
(void) close(s6);
(void) close(s4);
if (ret == EXIT_SUCCESS) {
(void) printf("All tests passed successfully\n");
}
return (ret);
}