xref: /onnv-gate/usr/src/lib/libsocket/inet/interface_id.c (revision 13021:0cbad7fa62eb)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58485SPeter.Memishian@Sun.COM  * Common Development and Distribution License (the "License").
68485SPeter.Memishian@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*13021SRenee.Sommerfeld@Oracle.COM 
220Sstevel@tonic-gate /*
23*13021SRenee.Sommerfeld@Oracle.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <ctype.h>
280Sstevel@tonic-gate #include <string.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/socket.h>
330Sstevel@tonic-gate #include <inet/common.h>
340Sstevel@tonic-gate #include <net/if.h>
350Sstevel@tonic-gate #include <netinet/in.h>
360Sstevel@tonic-gate #include <sys/sockio.h>
370Sstevel@tonic-gate #include <sys/ioctl.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <errno.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #define	IPIF_SEPARATOR_CHAR	":"
420Sstevel@tonic-gate 
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate  * Given an interface name, this function retrives the associated
450Sstevel@tonic-gate  * index value. Returns index value if successful, zero otherwise.
460Sstevel@tonic-gate  * The length of the supplied interface name must be at most
470Sstevel@tonic-gate  * IF_NAMESIZE-1 bytes
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate uint32_t
if_nametoindex(const char * ifname)500Sstevel@tonic-gate if_nametoindex(const char *ifname)
510Sstevel@tonic-gate {
520Sstevel@tonic-gate 	int		s;
530Sstevel@tonic-gate 	struct lifreq	lifr;
540Sstevel@tonic-gate 	int		save_err;
550Sstevel@tonic-gate 	size_t		size;
560Sstevel@tonic-gate 
570Sstevel@tonic-gate 
580Sstevel@tonic-gate 	/* Make sure the given name is not NULL */
590Sstevel@tonic-gate 	if ((ifname == NULL)||(*ifname == '\0')) {
600Sstevel@tonic-gate 		errno = ENXIO;
610Sstevel@tonic-gate 		return (0);
620Sstevel@tonic-gate 	}
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	/*
650Sstevel@tonic-gate 	 * Fill up the interface name in the ioctl
660Sstevel@tonic-gate 	 * request message. Make sure that the length of
670Sstevel@tonic-gate 	 * the given interface name <= (IF_NAMESIZE-1)
680Sstevel@tonic-gate 	 */
690Sstevel@tonic-gate 	size = strlen(ifname);
700Sstevel@tonic-gate 	if (size > (IF_NAMESIZE - 1)) {
710Sstevel@tonic-gate 		errno = EINVAL;
720Sstevel@tonic-gate 		return (0);
730Sstevel@tonic-gate 	}
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	strncpy(lifr.lifr_name, ifname, size +1);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	/* Check the v4 interfaces first */
780Sstevel@tonic-gate 	s = socket(AF_INET, SOCK_DGRAM, 0);
790Sstevel@tonic-gate 	if (s >= 0) {
800Sstevel@tonic-gate 		if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
810Sstevel@tonic-gate 			(void) close(s);
820Sstevel@tonic-gate 			return (lifr.lifr_index);
830Sstevel@tonic-gate 		}
840Sstevel@tonic-gate 		(void) close(s);
850Sstevel@tonic-gate 	}
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	/* Check the v6 interface list */
880Sstevel@tonic-gate 	s = socket(AF_INET6, SOCK_DGRAM, 0);
890Sstevel@tonic-gate 	if (s < 0)
900Sstevel@tonic-gate 		return (0);
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
930Sstevel@tonic-gate 		lifr.lifr_index = 0;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	save_err = errno;
960Sstevel@tonic-gate 	(void) close(s);
970Sstevel@tonic-gate 	errno = save_err;
980Sstevel@tonic-gate 	return (lifr.lifr_index);
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * Given an index, this function returns the associated interface
1030Sstevel@tonic-gate  * name in the supplied buffer ifname.
1040Sstevel@tonic-gate  * Returns physical interface name if successful, NULL otherwise.
1050Sstevel@tonic-gate  * The interface name returned will be at most IF_NAMESIZE-1 bytes.
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate char *
if_indextoname(uint32_t ifindex,char * ifname)1080Sstevel@tonic-gate if_indextoname(uint32_t ifindex, char *ifname)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	int		n;
1110Sstevel@tonic-gate 	int		s;
1120Sstevel@tonic-gate 	char		*buf;
1130Sstevel@tonic-gate 	uint32_t	index;
1140Sstevel@tonic-gate 	struct lifnum	lifn;
1150Sstevel@tonic-gate 	struct lifconf	lifc;
1160Sstevel@tonic-gate 	struct lifreq	*lifrp;
1170Sstevel@tonic-gate 	int		numifs;
1180Sstevel@tonic-gate 	size_t		bufsize;
1190Sstevel@tonic-gate 	boolean_t 	found;
1208485SPeter.Memishian@Sun.COM 	uint_t		flags;
1218485SPeter.Memishian@Sun.COM 
1228485SPeter.Memishian@Sun.COM 	flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	/* A interface index of 0 is invalid */
1250Sstevel@tonic-gate 	if (ifindex == 0) {
1260Sstevel@tonic-gate 		errno = ENXIO;
1270Sstevel@tonic-gate 		return (NULL);
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	s = socket(AF_INET6, SOCK_DGRAM, 0);
1310Sstevel@tonic-gate 	if (s < 0) {
1320Sstevel@tonic-gate 		s = socket(AF_INET, SOCK_DGRAM, 0);
1330Sstevel@tonic-gate 		if (s < 0) {
1340Sstevel@tonic-gate 			return (NULL);
1350Sstevel@tonic-gate 		}
1360Sstevel@tonic-gate 	}
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	/* Prepare to send a SIOCGLIFNUM request message */
1390Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
1408485SPeter.Memishian@Sun.COM 	lifn.lifn_flags = flags;
1410Sstevel@tonic-gate 	if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
1420Sstevel@tonic-gate 		int save_err = errno;
1430Sstevel@tonic-gate 		(void) close(s);
1440Sstevel@tonic-gate 		errno = save_err;
1450Sstevel@tonic-gate 		return (NULL);
1460Sstevel@tonic-gate 	}
1478485SPeter.Memishian@Sun.COM 
1488485SPeter.Memishian@Sun.COM 	/*
1498485SPeter.Memishian@Sun.COM 	 * NOTE: "+ 10" sleaze mitigates new IP interfaces showing up between
1508485SPeter.Memishian@Sun.COM 	 * the SIOCGLIFNUM and the SIOCGLIFCONF.
1518485SPeter.Memishian@Sun.COM 	 */
1528485SPeter.Memishian@Sun.COM 	numifs = lifn.lifn_count + 10;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	/*
1550Sstevel@tonic-gate 	 * Provide enough buffer to obtain the interface
1560Sstevel@tonic-gate 	 * list from the kernel as response to a SIOCGLIFCONF
1570Sstevel@tonic-gate 	 * request
1580Sstevel@tonic-gate 	 */
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct lifreq);
1610Sstevel@tonic-gate 	buf = malloc(bufsize);
1620Sstevel@tonic-gate 	if (buf == NULL) {
1630Sstevel@tonic-gate 		int save_err = errno;
1640Sstevel@tonic-gate 		(void) close(s);
1650Sstevel@tonic-gate 		errno = save_err;
1660Sstevel@tonic-gate 		return (NULL);
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 	lifc.lifc_family = AF_UNSPEC;
1698485SPeter.Memishian@Sun.COM 	lifc.lifc_flags = flags;
1700Sstevel@tonic-gate 	lifc.lifc_len = bufsize;
1710Sstevel@tonic-gate 	lifc.lifc_buf = buf;
1720Sstevel@tonic-gate 	if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
1730Sstevel@tonic-gate 		int save_err = errno;
1740Sstevel@tonic-gate 		(void) close(s);
1750Sstevel@tonic-gate 		errno = save_err;
1760Sstevel@tonic-gate 		free(buf);
1770Sstevel@tonic-gate 		return (NULL);
1780Sstevel@tonic-gate 	}
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	lifrp = lifc.lifc_req;
1810Sstevel@tonic-gate 	found = B_FALSE;
1820Sstevel@tonic-gate 	for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
1830Sstevel@tonic-gate 		/*
1840Sstevel@tonic-gate 		 * Obtain the index value of each interface, and
1850Sstevel@tonic-gate 		 * match to see if the retrived index value matches
1869593SAnders.Persson@Sun.COM 		 * the given one. If so we return the corresponding
1870Sstevel@tonic-gate 		 * device name of that interface.
1880Sstevel@tonic-gate 		 */
1890Sstevel@tonic-gate 		size_t	size;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 		index = if_nametoindex(lifrp->lifr_name);
1920Sstevel@tonic-gate 		if (index == 0)
1930Sstevel@tonic-gate 			/* Oops the interface just disappeared */
1940Sstevel@tonic-gate 			continue;
1950Sstevel@tonic-gate 		if (index == ifindex) {
1960Sstevel@tonic-gate 			size = strcspn(lifrp->lifr_name,
1970Sstevel@tonic-gate 			    (char *)IPIF_SEPARATOR_CHAR);
1980Sstevel@tonic-gate 			lifrp->lifr_name[size] = '\0';
1990Sstevel@tonic-gate 			found = B_TRUE;
2009593SAnders.Persson@Sun.COM 			(void) strncpy(ifname, lifrp->lifr_name, size + 1);
2010Sstevel@tonic-gate 			break;
2020Sstevel@tonic-gate 		}
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 	(void) close(s);
2050Sstevel@tonic-gate 	free(buf);
2060Sstevel@tonic-gate 	if (!found) {
2070Sstevel@tonic-gate 		errno = ENXIO;
2080Sstevel@tonic-gate 		return (NULL);
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	return (ifname);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  * This function returns all the interface names and indexes
2150Sstevel@tonic-gate  */
2160Sstevel@tonic-gate struct if_nameindex *
if_nameindex(void)2170Sstevel@tonic-gate if_nameindex(void)
2180Sstevel@tonic-gate {
2190Sstevel@tonic-gate 	int		n;
2200Sstevel@tonic-gate 	int		s;
2210Sstevel@tonic-gate 	boolean_t	found;
2220Sstevel@tonic-gate 	char		*buf;
2230Sstevel@tonic-gate 	struct lifnum	lifn;
2240Sstevel@tonic-gate 	struct lifconf	lifc;
2250Sstevel@tonic-gate 	struct lifreq	*lifrp;
2260Sstevel@tonic-gate 	int		numifs;
2270Sstevel@tonic-gate 	int		index;
2280Sstevel@tonic-gate 	int		i;
2290Sstevel@tonic-gate 	int 		physinterf_num;
2300Sstevel@tonic-gate 	size_t		bufsize;
2310Sstevel@tonic-gate 	struct if_nameindex	 *interface_list;
2320Sstevel@tonic-gate 	struct if_nameindex	 *interface_entry;
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	s = socket(AF_INET6, SOCK_DGRAM, 0);
2350Sstevel@tonic-gate 	if (s < 0) {
2360Sstevel@tonic-gate 		s = socket(AF_INET, SOCK_DGRAM, 0);
2370Sstevel@tonic-gate 		if (s < 0)
2380Sstevel@tonic-gate 			return (NULL);
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	lifn.lifn_family = AF_UNSPEC;
2420Sstevel@tonic-gate 	lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
2430Sstevel@tonic-gate 	if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
2440Sstevel@tonic-gate 		return (NULL);
2450Sstevel@tonic-gate 	numifs = lifn.lifn_count;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct lifreq);
2480Sstevel@tonic-gate 	buf = malloc(bufsize);
2490Sstevel@tonic-gate 	if (buf == NULL) {
2500Sstevel@tonic-gate 		int save_err = errno;
2510Sstevel@tonic-gate 		(void) close(s);
2520Sstevel@tonic-gate 		errno = save_err;
2530Sstevel@tonic-gate 		return (NULL);
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 	lifc.lifc_family = AF_UNSPEC;
2560Sstevel@tonic-gate 	lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
2570Sstevel@tonic-gate 	lifc.lifc_len = bufsize;
2580Sstevel@tonic-gate 	lifc.lifc_buf = buf;
2590Sstevel@tonic-gate 	if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
2600Sstevel@tonic-gate 		int save_err = errno;
2610Sstevel@tonic-gate 		(void) close(s);
2620Sstevel@tonic-gate 		errno = save_err;
2630Sstevel@tonic-gate 		free(buf);
2640Sstevel@tonic-gate 		return (NULL);
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	lifrp = lifc.lifc_req;
2680Sstevel@tonic-gate 	(void) close(s);
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	/* Allocate the array of if_nameindex structure */
2710Sstevel@tonic-gate 	interface_list = malloc((numifs + 1) * sizeof (struct if_nameindex));
2720Sstevel@tonic-gate 	if (!interface_list) {
2730Sstevel@tonic-gate 		int save_err = errno;
2740Sstevel@tonic-gate 		free(buf);
2750Sstevel@tonic-gate 		errno = save_err;
2760Sstevel@tonic-gate 		return (NULL);
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 	/*
2790Sstevel@tonic-gate 	 * Make sure that terminator structure automatically
2800Sstevel@tonic-gate 	 * happens to be all zeroes.
2810Sstevel@tonic-gate 	 */
2820Sstevel@tonic-gate 	bzero(interface_list, ((numifs + 1) * sizeof (struct if_nameindex)));
2830Sstevel@tonic-gate 	interface_entry = interface_list;
2840Sstevel@tonic-gate 	physinterf_num = 0;
2850Sstevel@tonic-gate 	for (n = numifs; n > 0; n--, lifrp++) {
2860Sstevel@tonic-gate 		size_t	size;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 		size = strcspn(lifrp->lifr_name, (char *)IPIF_SEPARATOR_CHAR);
2890Sstevel@tonic-gate 		found = B_FALSE;
2900Sstevel@tonic-gate 		/*
2910Sstevel@tonic-gate 		 * Search the current array to see if this interface
2929593SAnders.Persson@Sun.COM 		 * already exists. Only compare the physical name.
2930Sstevel@tonic-gate 		 */
2940Sstevel@tonic-gate 		for (i = 0; i < physinterf_num; i++) {
2959593SAnders.Persson@Sun.COM 			if (strncmp(interface_entry[i].if_name,
2969593SAnders.Persson@Sun.COM 			    lifrp->lifr_name, size) == 0) {
2970Sstevel@tonic-gate 				found = B_TRUE;
2980Sstevel@tonic-gate 				break;
2990Sstevel@tonic-gate 			}
3000Sstevel@tonic-gate 		}
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		/* New one. Allocate an array element and fill it */
3030Sstevel@tonic-gate 		if (!found) {
3049593SAnders.Persson@Sun.COM 			/*
3059593SAnders.Persson@Sun.COM 			 * Obtain the index value for the interface
3069593SAnders.Persson@Sun.COM 			 */
3079593SAnders.Persson@Sun.COM 			interface_entry[physinterf_num].if_index =
3089593SAnders.Persson@Sun.COM 			    if_nametoindex(lifrp->lifr_name);
3099593SAnders.Persson@Sun.COM 
3109593SAnders.Persson@Sun.COM 			if (interface_entry[physinterf_num].if_index == 0) {
3119593SAnders.Persson@Sun.COM 				/* The interface went away. Skip this entry. */
3129593SAnders.Persson@Sun.COM 				continue;
3139593SAnders.Persson@Sun.COM 			}
3149593SAnders.Persson@Sun.COM 
3159593SAnders.Persson@Sun.COM 			/*
3169593SAnders.Persson@Sun.COM 			 * Truncate the name to ensure that it represents
3179593SAnders.Persson@Sun.COM 			 * a physical interface.
3189593SAnders.Persson@Sun.COM 			 */
3199593SAnders.Persson@Sun.COM 			lifrp->lifr_name[size] = '\0';
3200Sstevel@tonic-gate 			if ((interface_entry[physinterf_num].if_name =
3210Sstevel@tonic-gate 			    strdup(lifrp->lifr_name)) == NULL) {
3220Sstevel@tonic-gate 				int save_err;
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 				if_freenameindex(interface_list);
3250Sstevel@tonic-gate 				save_err = errno;
3260Sstevel@tonic-gate 				free(buf);
3270Sstevel@tonic-gate 				errno = save_err;
3280Sstevel@tonic-gate 				return (NULL);
3290Sstevel@tonic-gate 			}
3300Sstevel@tonic-gate 
3319593SAnders.Persson@Sun.COM 			physinterf_num++;
3320Sstevel@tonic-gate 		}
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	/* Create the last one of the array */
3360Sstevel@tonic-gate 	interface_entry[physinterf_num].if_name = NULL;
3370Sstevel@tonic-gate 	interface_entry[physinterf_num].if_index = 0;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/* Free up the excess array space */
3400Sstevel@tonic-gate 	free(buf);
3410Sstevel@tonic-gate 	interface_list = realloc(interface_list, ((physinterf_num + 1) *
3420Sstevel@tonic-gate 	    sizeof (struct if_nameindex)));
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	return (interface_list);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate /*
3480Sstevel@tonic-gate  * This function frees the the array that is created while
3490Sstevel@tonic-gate  * the if_nameindex function.
3500Sstevel@tonic-gate  */
3510Sstevel@tonic-gate void
if_freenameindex(struct if_nameindex * ptr)3520Sstevel@tonic-gate if_freenameindex(struct if_nameindex *ptr)
3530Sstevel@tonic-gate {
354*13021SRenee.Sommerfeld@Oracle.COM 	struct if_nameindex *p;
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 	if (ptr == NULL)
3570Sstevel@tonic-gate 		return;
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/* First free the if_name member in each array element */
360*13021SRenee.Sommerfeld@Oracle.COM 	for (p = ptr; p->if_name != NULL; p++)
361*13021SRenee.Sommerfeld@Oracle.COM 		free(p->if_name);
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/* Now free up the array space */
3640Sstevel@tonic-gate 	free(ptr);
3650Sstevel@tonic-gate }
366