#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <inet/common.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/sockio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#define IPIF_SEPARATOR_CHAR ":"
uint32_t
if_nametoindex(const char *ifname)
{
int s;
struct lifreq lifr;
int save_err;
size_t size;
if ((ifname == NULL)||(*ifname == '\0')) {
errno = ENXIO;
return (0);
}
size = strlen(ifname);
if (size > (IF_NAMESIZE - 1)) {
errno = EINVAL;
return (0);
}
strncpy(lifr.lifr_name, ifname, size +1);
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s >= 0) {
if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
(void) close(s);
return (lifr.lifr_index);
}
(void) close(s);
}
s = socket(AF_INET6, SOCK_DGRAM, 0);
if (s < 0)
return (0);
if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
lifr.lifr_index = 0;
save_err = errno;
(void) close(s);
errno = save_err;
return (lifr.lifr_index);
}
char *
if_indextoname(uint32_t ifindex, char *ifname)
{
int n;
int s;
char *buf;
uint32_t index;
struct lifnum lifn;
struct lifconf lifc;
struct lifreq *lifrp;
int numifs;
size_t bufsize;
boolean_t found;
uint_t flags;
flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
if (ifindex == 0) {
errno = ENXIO;
return (NULL);
}
s = socket(AF_INET6, SOCK_DGRAM, 0);
if (s < 0) {
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
return (NULL);
}
}
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = flags;
if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
int save_err = errno;
(void) close(s);
errno = save_err;
return (NULL);
}
numifs = lifn.lifn_count + 10;
bufsize = numifs * sizeof (struct lifreq);
buf = malloc(bufsize);
if (buf == NULL) {
int save_err = errno;
(void) close(s);
errno = save_err;
return (NULL);
}
lifc.lifc_family = AF_UNSPEC;
lifc.lifc_flags = flags;
lifc.lifc_len = bufsize;
lifc.lifc_buf = buf;
if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
int save_err = errno;
(void) close(s);
errno = save_err;
free(buf);
return (NULL);
}
lifrp = lifc.lifc_req;
found = B_FALSE;
for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
size_t size;
index = if_nametoindex(lifrp->lifr_name);
if (index == 0)
continue;
if (index == ifindex) {
size = strcspn(lifrp->lifr_name,
(char *)IPIF_SEPARATOR_CHAR);
lifrp->lifr_name[size] = '\0';
found = B_TRUE;
(void) strncpy(ifname, lifrp->lifr_name, size + 1);
break;
}
}
(void) close(s);
free(buf);
if (!found) {
errno = ENXIO;
return (NULL);
}
return (ifname);
}
struct if_nameindex *
if_nameindex(void)
{
int n;
int s;
boolean_t found;
char *buf;
struct lifnum lifn;
struct lifconf lifc;
struct lifreq *lifrp;
int numifs;
int index;
int i;
int physinterf_num;
size_t bufsize;
struct if_nameindex *interface_list;
struct if_nameindex *interface_entry;
s = socket(AF_INET6, SOCK_DGRAM, 0);
if (s < 0) {
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0)
return (NULL);
}
lifn.lifn_family = AF_UNSPEC;
lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
return (NULL);
numifs = lifn.lifn_count;
bufsize = numifs * sizeof (struct lifreq);
buf = malloc(bufsize);
if (buf == NULL) {
int save_err = errno;
(void) close(s);
errno = save_err;
return (NULL);
}
lifc.lifc_family = AF_UNSPEC;
lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
lifc.lifc_len = bufsize;
lifc.lifc_buf = buf;
if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
int save_err = errno;
(void) close(s);
errno = save_err;
free(buf);
return (NULL);
}
lifrp = lifc.lifc_req;
(void) close(s);
interface_list = malloc((numifs + 1) * sizeof (struct if_nameindex));
if (!interface_list) {
int save_err = errno;
free(buf);
errno = save_err;
return (NULL);
}
bzero(interface_list, ((numifs + 1) * sizeof (struct if_nameindex)));
interface_entry = interface_list;
physinterf_num = 0;
for (n = numifs; n > 0; n--, lifrp++) {
size_t size;
size = strcspn(lifrp->lifr_name, (char *)IPIF_SEPARATOR_CHAR);
found = B_FALSE;
for (i = 0; i < physinterf_num; i++) {
if (strncmp(interface_entry[i].if_name,
lifrp->lifr_name, size) == 0) {
found = B_TRUE;
break;
}
}
if (!found) {
interface_entry[physinterf_num].if_index =
if_nametoindex(lifrp->lifr_name);
if (interface_entry[physinterf_num].if_index == 0) {
continue;
}
lifrp->lifr_name[size] = '\0';
if ((interface_entry[physinterf_num].if_name =
strdup(lifrp->lifr_name)) == NULL) {
int save_err;
if_freenameindex(interface_list);
save_err = errno;
free(buf);
errno = save_err;
return (NULL);
}
physinterf_num++;
}
}
interface_entry[physinterf_num].if_name = NULL;
interface_entry[physinterf_num].if_index = 0;
free(buf);
interface_list = realloc(interface_list, ((physinterf_num + 1) *
sizeof (struct if_nameindex)));
return (interface_list);
}
void
if_freenameindex(struct if_nameindex *ptr)
{
struct if_nameindex *p;
if (ptr == NULL)
return;
for (p = ptr; p->if_name != NULL; p++)
free(p->if_name);
free(ptr);
}