xref: /titanic_44/usr/src/cmd/cmd-inet/usr.sbin/ipaddrsel.c (revision 0c6f1683238ba0627fb13bb20513e4917993c79d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*0c6f1683Sdg199075  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <libintl.h>
307c478bd9Sstevel@tonic-gate #include <locale.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <errno.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <ctype.h>
377c478bd9Sstevel@tonic-gate #include <sys/param.h>
387c478bd9Sstevel@tonic-gate #include <sys/types.h>
397c478bd9Sstevel@tonic-gate #include <stropts.h>
407c478bd9Sstevel@tonic-gate #include <sys/conf.h>
417c478bd9Sstevel@tonic-gate #include <sys/socket.h>
427c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
437c478bd9Sstevel@tonic-gate #include <netinet/in.h>
447c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
457c478bd9Sstevel@tonic-gate #include <inet/ip.h>
467c478bd9Sstevel@tonic-gate #include <inet/ip6_asp.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * The size of the table we initially use to retrieve the kernel's policy
507c478bd9Sstevel@tonic-gate  * table.  If this value is too small, we use the value returned from the
517c478bd9Sstevel@tonic-gate  * SIOCGIP6ADDRPOLICY ioctl.
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate #define	KERN_POLICY_SIZE	32
547c478bd9Sstevel@tonic-gate #define	IPV6DAS_MAXLINELEN	1024
557c478bd9Sstevel@tonic-gate #define	IPV6DAS_MAXENTRIES	512
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate typedef enum {
587c478bd9Sstevel@tonic-gate 	IPV6DAS_PRINTPOLICY,
597c478bd9Sstevel@tonic-gate 	IPV6DAS_SETPOLICY,
607c478bd9Sstevel@tonic-gate 	IPV6DAS_SETDEFAULT
617c478bd9Sstevel@tonic-gate } ipv6das_cmd_t;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static char *myname;	/* Copied from argv[0] */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static int	parseconf(const char *, ip6_asp_t **);
667c478bd9Sstevel@tonic-gate static int	setpolicy(int, ip6_asp_t *, int);
677c478bd9Sstevel@tonic-gate static int	printpolicy(int);
687c478bd9Sstevel@tonic-gate static int	ip_mask_to_plen_v6(const in6_addr_t *);
697c478bd9Sstevel@tonic-gate static in6_addr_t *ip_plen_to_mask_v6(int, in6_addr_t *);
707c478bd9Sstevel@tonic-gate static int	strioctl(int, int, void *, int);
717c478bd9Sstevel@tonic-gate static void	usage(void);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)747c478bd9Sstevel@tonic-gate main(int argc, char **argv)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	int		opt, status, sock, count;
777c478bd9Sstevel@tonic-gate 	char		*conf_filename;
787c478bd9Sstevel@tonic-gate 	ipv6das_cmd_t	ipv6das_cmd = IPV6DAS_PRINTPOLICY;
797c478bd9Sstevel@tonic-gate 	ip6_asp_t	*policy_table;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	myname = *argv;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
867c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
877c478bd9Sstevel@tonic-gate #endif
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "df:")) != EOF)
927c478bd9Sstevel@tonic-gate 		switch (opt) {
937c478bd9Sstevel@tonic-gate 		case 'd':
947c478bd9Sstevel@tonic-gate 			ipv6das_cmd = IPV6DAS_SETDEFAULT;
957c478bd9Sstevel@tonic-gate 			break;
967c478bd9Sstevel@tonic-gate 		case 'f':
977c478bd9Sstevel@tonic-gate 			conf_filename = optarg;
987c478bd9Sstevel@tonic-gate 			ipv6das_cmd = IPV6DAS_SETPOLICY;
997c478bd9Sstevel@tonic-gate 			break;
1007c478bd9Sstevel@tonic-gate 		default:
1017c478bd9Sstevel@tonic-gate 			usage();
1027c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
1037c478bd9Sstevel@tonic-gate 		}
1047c478bd9Sstevel@tonic-gate 	if (argc > optind) {
1057c478bd9Sstevel@tonic-gate 		/* shouldn't be any extra args */
1067c478bd9Sstevel@tonic-gate 		usage();
1077c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	/* Open a socket that we can use to send ioctls down to IP. */
1117c478bd9Sstevel@tonic-gate 	if ((sock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) {
1127c478bd9Sstevel@tonic-gate 		perror("socket");
1137c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	switch (ipv6das_cmd) {
1177c478bd9Sstevel@tonic-gate 	case IPV6DAS_SETPOLICY:
1187c478bd9Sstevel@tonic-gate 		if ((count = parseconf(conf_filename, &policy_table)) <= 0)
1197c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
1207c478bd9Sstevel@tonic-gate 		status = setpolicy(sock, policy_table, count);
1217c478bd9Sstevel@tonic-gate 		free(policy_table);
1227c478bd9Sstevel@tonic-gate 		break;
1237c478bd9Sstevel@tonic-gate 	case IPV6DAS_SETDEFAULT:
1247c478bd9Sstevel@tonic-gate 		status = setpolicy(sock, NULL, 0);
1257c478bd9Sstevel@tonic-gate 		break;
1267c478bd9Sstevel@tonic-gate 	case IPV6DAS_PRINTPOLICY:
1277c478bd9Sstevel@tonic-gate 	default:
1287c478bd9Sstevel@tonic-gate 		status = printpolicy(sock);
1297c478bd9Sstevel@tonic-gate 		break;
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	(void) close(sock);
1337c478bd9Sstevel@tonic-gate 	return (status);
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate  * parseconf(filename, new_policy)
1387c478bd9Sstevel@tonic-gate  *
1397c478bd9Sstevel@tonic-gate  * Parses the file identified by filename, filling in new_policy
1407c478bd9Sstevel@tonic-gate  * with the address selection policy table specified in filename.
1417c478bd9Sstevel@tonic-gate  * Returns -1 on failure, or the number of table entries found
1427c478bd9Sstevel@tonic-gate  * on success.
1437c478bd9Sstevel@tonic-gate  */
1447c478bd9Sstevel@tonic-gate static int
parseconf(const char * filename,ip6_asp_t ** new_policy)1457c478bd9Sstevel@tonic-gate parseconf(const char *filename, ip6_asp_t **new_policy)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	FILE		*fp;
1487c478bd9Sstevel@tonic-gate 	char		line[IPV6DAS_MAXLINELEN];
1497c478bd9Sstevel@tonic-gate 	char		*cp, *end;
1507c478bd9Sstevel@tonic-gate 	char		*prefixstr;
1517c478bd9Sstevel@tonic-gate 	uint_t		lineno = 0, entryindex = 0;
1527c478bd9Sstevel@tonic-gate 	int		plen, precedence;
1537c478bd9Sstevel@tonic-gate 	char		*label;
1547c478bd9Sstevel@tonic-gate 	size_t		labellen;
1557c478bd9Sstevel@tonic-gate 	int		retval;
1567c478bd9Sstevel@tonic-gate 	ip6_asp_t	tmp_policy[IPV6DAS_MAXENTRIES];
1577c478bd9Sstevel@tonic-gate 	boolean_t	have_default = B_FALSE;
1587c478bd9Sstevel@tonic-gate 	in6_addr_t	prefix, mask;
1597c478bd9Sstevel@tonic-gate 	boolean_t	comment_found = B_FALSE, end_of_line = B_FALSE;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	if ((fp = fopen(filename, "r")) == NULL) {
1627c478bd9Sstevel@tonic-gate 		perror(filename);
1637c478bd9Sstevel@tonic-gate 		return (-1);
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	while (fgets(line, sizeof (line), fp) != NULL) {
1677c478bd9Sstevel@tonic-gate 		if (entryindex == IPV6DAS_MAXENTRIES) {
1687c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1697c478bd9Sstevel@tonic-gate 			    gettext("%s: too many entries\n"), filename);
1707c478bd9Sstevel@tonic-gate 			retval = -1;
1717c478bd9Sstevel@tonic-gate 			goto end_parse;
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		lineno++;
1757c478bd9Sstevel@tonic-gate 		cp = line;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		/* Skip leading whitespace */
1787c478bd9Sstevel@tonic-gate 		while (isspace(*cp))
1797c478bd9Sstevel@tonic-gate 			cp++;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 		/* Is this a comment or blank line? */
1827c478bd9Sstevel@tonic-gate 		if (*cp == '#' || *cp == '\0')
1837c478bd9Sstevel@tonic-gate 			continue;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 		/*
1867c478bd9Sstevel@tonic-gate 		 * Anything else must be of the form:
1877c478bd9Sstevel@tonic-gate 		 * <IPv6-addr>/<plen> <precedence> <label>
1887c478bd9Sstevel@tonic-gate 		 */
1897c478bd9Sstevel@tonic-gate 		prefixstr = cp;
1907c478bd9Sstevel@tonic-gate 		if ((cp = strchr(cp, '/')) == NULL) {
1917c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1927c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid prefix on line %d: %s\n"),
1937c478bd9Sstevel@tonic-gate 			    filename, lineno, prefixstr);
1947c478bd9Sstevel@tonic-gate 			continue;
1957c478bd9Sstevel@tonic-gate 		}
1967c478bd9Sstevel@tonic-gate 		*cp = '\0';
1977c478bd9Sstevel@tonic-gate 		if (inet_pton(AF_INET6, prefixstr, &prefix) != 1) {
1987c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1997c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid prefix on line %d: %s\n"),
2007c478bd9Sstevel@tonic-gate 			    filename, lineno, prefixstr);
2017c478bd9Sstevel@tonic-gate 			continue;
2027c478bd9Sstevel@tonic-gate 		}
2037c478bd9Sstevel@tonic-gate 		cp++;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 		errno = 0;
2067c478bd9Sstevel@tonic-gate 		plen = strtol(cp, &end, 10);
2077c478bd9Sstevel@tonic-gate 		if (cp == end || errno != 0) {
2087c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2097c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid prefix length on line %d\n"),
2107c478bd9Sstevel@tonic-gate 			    filename, lineno);
2117c478bd9Sstevel@tonic-gate 			continue;
2127c478bd9Sstevel@tonic-gate 		}
2137c478bd9Sstevel@tonic-gate 		if (ip_plen_to_mask_v6(plen, &mask) == NULL) {
2147c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2157c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid prefix length on line %d:"
2167c478bd9Sstevel@tonic-gate 			    " %d\n"), filename, lineno, plen);
2177c478bd9Sstevel@tonic-gate 			continue;
2187c478bd9Sstevel@tonic-gate 		}
2197c478bd9Sstevel@tonic-gate 		cp = end;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 		errno = 0;
2227c478bd9Sstevel@tonic-gate 		precedence = strtol(cp, &end, 10);
2237c478bd9Sstevel@tonic-gate 		if (cp == end || precedence < 0 || errno != 0) {
2247c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2257c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid precedence on line %d\n"),
2267c478bd9Sstevel@tonic-gate 			    filename, lineno);
2277c478bd9Sstevel@tonic-gate 			continue;
2287c478bd9Sstevel@tonic-gate 		}
2297c478bd9Sstevel@tonic-gate 		cp = end;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		while (isspace(*cp))
2327c478bd9Sstevel@tonic-gate 			cp++;
2337c478bd9Sstevel@tonic-gate 		label = cp;
2347c478bd9Sstevel@tonic-gate 		/*
2357c478bd9Sstevel@tonic-gate 		 * NULL terminate the label string.  The label string is
2367c478bd9Sstevel@tonic-gate 		 * composed of non-blank characters, and can optionally be
2377c478bd9Sstevel@tonic-gate 		 * followed by a comment.
2387c478bd9Sstevel@tonic-gate 		 */
2397c478bd9Sstevel@tonic-gate 		while (*cp != '\0' && !isspace(*cp) && *cp != '#')
2407c478bd9Sstevel@tonic-gate 			cp++;
2417c478bd9Sstevel@tonic-gate 		if (*cp == '#')
2427c478bd9Sstevel@tonic-gate 			comment_found = B_TRUE;
2437c478bd9Sstevel@tonic-gate 		else if (*cp == '\0' || *cp == '\n')
2447c478bd9Sstevel@tonic-gate 			end_of_line = B_TRUE;
2457c478bd9Sstevel@tonic-gate 		*cp = '\0';
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 		labellen = cp - label;
2487c478bd9Sstevel@tonic-gate 		if (labellen == 0) {
2497c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2507c478bd9Sstevel@tonic-gate 			    gettext("%s: missing label on line %d\n"),
2517c478bd9Sstevel@tonic-gate 			    filename, lineno);
2527c478bd9Sstevel@tonic-gate 			continue;
2537c478bd9Sstevel@tonic-gate 		}
2547c478bd9Sstevel@tonic-gate 		if (labellen >= IP6_ASP_MAXLABELSIZE) {
2557c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
2567c478bd9Sstevel@tonic-gate 			    gettext("%s: label too long on line %d, labels "
2577c478bd9Sstevel@tonic-gate 			    "have a %d character limit.\n"), filename, lineno,
2587c478bd9Sstevel@tonic-gate 			    IP6_ASP_MAXLABELSIZE - 1);
2597c478bd9Sstevel@tonic-gate 			continue;
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 		tmp_policy[entryindex].ip6_asp_prefix = prefix;
2637c478bd9Sstevel@tonic-gate 		tmp_policy[entryindex].ip6_asp_mask = mask;
2647c478bd9Sstevel@tonic-gate 		tmp_policy[entryindex].ip6_asp_precedence = precedence;
2657c478bd9Sstevel@tonic-gate 		/*
2667c478bd9Sstevel@tonic-gate 		 * We're specifically using strncpy() to copy the label
2677c478bd9Sstevel@tonic-gate 		 * to take advantage of the fact that strncpy will add
2687c478bd9Sstevel@tonic-gate 		 * NULL characters to the target string up to the given
2697c478bd9Sstevel@tonic-gate 		 * length, so don't change the call to strncpy() with
2707c478bd9Sstevel@tonic-gate 		 * out also taking into account this requirement.  The
2717c478bd9Sstevel@tonic-gate 		 * labels are stored in the kernel in that way in order
2727c478bd9Sstevel@tonic-gate 		 * to make comparisons more efficient: all 16 bytes of
2737c478bd9Sstevel@tonic-gate 		 * the labels are compared to each other; random bytes
2747c478bd9Sstevel@tonic-gate 		 * after the NULL terminator would yield incorrect
2757c478bd9Sstevel@tonic-gate 		 * comparisons.
2767c478bd9Sstevel@tonic-gate 		 */
2777c478bd9Sstevel@tonic-gate 		(void) strncpy(tmp_policy[entryindex].ip6_asp_label, label,
2787c478bd9Sstevel@tonic-gate 		    IP6_ASP_MAXLABELSIZE);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 		/*
2817c478bd9Sstevel@tonic-gate 		 * Anything else on the line should be a comment; print
2827c478bd9Sstevel@tonic-gate 		 * a warning if that's not the case.
2837c478bd9Sstevel@tonic-gate 		 */
2847c478bd9Sstevel@tonic-gate 		if (!comment_found && !end_of_line) {
2857c478bd9Sstevel@tonic-gate 			cp++;
2867c478bd9Sstevel@tonic-gate 			while (*cp != '\0' && isspace(*cp) && *cp != '#')
2877c478bd9Sstevel@tonic-gate 				cp++;
2887c478bd9Sstevel@tonic-gate 			if (*cp != '\0' && *cp != '#') {
2897c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2907c478bd9Sstevel@tonic-gate 				    gettext("%s: characters following label "
2917c478bd9Sstevel@tonic-gate 				    "on line %d will be ignored\n"),
2927c478bd9Sstevel@tonic-gate 				    filename, lineno);
2937c478bd9Sstevel@tonic-gate 			}
2947c478bd9Sstevel@tonic-gate 		}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&prefix) && plen == 0)
2977c478bd9Sstevel@tonic-gate 			have_default = B_TRUE;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 		comment_found = B_FALSE;
3007c478bd9Sstevel@tonic-gate 		end_of_line = B_FALSE;
3017c478bd9Sstevel@tonic-gate 		entryindex++;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if (!have_default) {
3057c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
3067c478bd9Sstevel@tonic-gate 		    gettext("%s: config doesn't contain a default entry.\n"),
3077c478bd9Sstevel@tonic-gate 		    filename);
3087c478bd9Sstevel@tonic-gate 		retval = -1;
3097c478bd9Sstevel@tonic-gate 		goto end_parse;
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/* Allocate the caller's array. */
3137c478bd9Sstevel@tonic-gate 	if ((*new_policy = malloc(entryindex * sizeof (ip6_asp_t))) == NULL) {
3147c478bd9Sstevel@tonic-gate 		perror("malloc");
3157c478bd9Sstevel@tonic-gate 		retval = -1;
3167c478bd9Sstevel@tonic-gate 		goto end_parse;
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	(void) memcpy(*new_policy, tmp_policy, entryindex * sizeof (ip6_asp_t));
3207c478bd9Sstevel@tonic-gate 	retval = entryindex;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate end_parse:
3237c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
3247c478bd9Sstevel@tonic-gate 	return (retval);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate  * setpolicy(sock, new_policy, count)
3297c478bd9Sstevel@tonic-gate  *
3307c478bd9Sstevel@tonic-gate  * Sends an SIOCSIP6ADDRPOLICY ioctl to the kernel to set the address
3317c478bd9Sstevel@tonic-gate  * selection policy table pointed to by new_policy.  count should be
3327c478bd9Sstevel@tonic-gate  * the number of entries in the table; sock should be an open INET6
3337c478bd9Sstevel@tonic-gate  * socket.  Returns EXIT_FAILURE or EXIT_SUCCESS.
3347c478bd9Sstevel@tonic-gate  */
3357c478bd9Sstevel@tonic-gate static int
setpolicy(int sock,ip6_asp_t * new_policy,int count)3367c478bd9Sstevel@tonic-gate setpolicy(int sock, ip6_asp_t *new_policy, int count)
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 	if (strioctl(sock, SIOCSIP6ADDRPOLICY, new_policy,
3397c478bd9Sstevel@tonic-gate 	    count * sizeof (ip6_asp_t)) < 0) {
3407c478bd9Sstevel@tonic-gate 		perror("SIOCSIP6ADDRPOLICY");
3417c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate /*
3477c478bd9Sstevel@tonic-gate  * printpolicy(sock)
3487c478bd9Sstevel@tonic-gate  *
3497c478bd9Sstevel@tonic-gate  * Queries the kernel for the current address selection policy using
3507c478bd9Sstevel@tonic-gate  * the open socket sock, and prints the result.  Returns EXIT_FAILURE
3517c478bd9Sstevel@tonic-gate  * if the table cannot be obtained, or EXIT_SUCCESS if the table is
3527c478bd9Sstevel@tonic-gate  * obtained and printed successfully.
3537c478bd9Sstevel@tonic-gate  */
3547c478bd9Sstevel@tonic-gate static int
printpolicy(int sock)3557c478bd9Sstevel@tonic-gate printpolicy(int sock)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	ip6_asp_t	policy[KERN_POLICY_SIZE];
3587c478bd9Sstevel@tonic-gate 	ip6_asp_t	*policy_ptr = policy;
3597c478bd9Sstevel@tonic-gate 	int		count, policy_index;
3607c478bd9Sstevel@tonic-gate 	char		prefixstr[INET6_ADDRSTRLEN + sizeof ("/128")];
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if ((count = strioctl(sock, SIOCGIP6ADDRPOLICY, policy_ptr,
3637c478bd9Sstevel@tonic-gate 	    KERN_POLICY_SIZE * sizeof (ip6_asp_t))) < 0) {
3647c478bd9Sstevel@tonic-gate 		perror("SIOCGIP6ADDRPOLICY");
3657c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 	if (count > KERN_POLICY_SIZE) {
3687c478bd9Sstevel@tonic-gate 		policy_ptr = malloc(count * sizeof (ip6_asp_t));
3697c478bd9Sstevel@tonic-gate 		if (policy_ptr == NULL) {
3707c478bd9Sstevel@tonic-gate 			perror("malloc");
3717c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
3727c478bd9Sstevel@tonic-gate 		}
3737c478bd9Sstevel@tonic-gate 		if ((count = strioctl(sock, SIOCGIP6ADDRPOLICY, policy_ptr,
3747c478bd9Sstevel@tonic-gate 		    count * sizeof (ip6_asp_t))) < 0) {
3757c478bd9Sstevel@tonic-gate 			perror("SIOCGIP6ADDRPOLICY");
3767c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
3777c478bd9Sstevel@tonic-gate 		}
3787c478bd9Sstevel@tonic-gate 	}
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	if (count == 0) {
3817c478bd9Sstevel@tonic-gate 		/*
3827c478bd9Sstevel@tonic-gate 		 * There should always at least be a default entry in the
3837c478bd9Sstevel@tonic-gate 		 * policy table, so the minimum acceptable value of
3847c478bd9Sstevel@tonic-gate 		 * policy_count is 1.
3857c478bd9Sstevel@tonic-gate 		 */
3867c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: ERROR: "
3877c478bd9Sstevel@tonic-gate 		    "IPv6 address selection policy is empty.\n"), myname);
3887c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/*
3927c478bd9Sstevel@tonic-gate 	 * The format printed here must also be parsable by parseconf(),
3937c478bd9Sstevel@tonic-gate 	 * since we expect users to be able to redirect this output to
3947c478bd9Sstevel@tonic-gate 	 * a usable configuration file if need be.
3957c478bd9Sstevel@tonic-gate 	 */
396*0c6f1683Sdg199075 	(void) printf("# Prefix                  "
397*0c6f1683Sdg199075 		"                    Precedence Label\n");
3987c478bd9Sstevel@tonic-gate 	for (policy_index = 0; policy_index < count; policy_index++) {
3997c478bd9Sstevel@tonic-gate 		(void) snprintf(prefixstr, sizeof (prefixstr), "%s/%d",
4007c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6,
4017c478bd9Sstevel@tonic-gate 			&policy_ptr[policy_index].ip6_asp_prefix, prefixstr,
4027c478bd9Sstevel@tonic-gate 			sizeof (prefixstr)),
4037c478bd9Sstevel@tonic-gate 		    ip_mask_to_plen_v6(&policy_ptr[policy_index].ip6_asp_mask));
404*0c6f1683Sdg199075 		(void) printf("%-45s %10d %s\n", prefixstr,
4057c478bd9Sstevel@tonic-gate 		    policy_ptr[policy_index].ip6_asp_precedence,
4067c478bd9Sstevel@tonic-gate 		    policy_ptr[policy_index].ip6_asp_label);
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	if (policy_ptr != policy)
4107c478bd9Sstevel@tonic-gate 		free(policy_ptr);
4117c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate  * ip_mask_to_plen_v6(v6mask)
4167c478bd9Sstevel@tonic-gate  *
4177c478bd9Sstevel@tonic-gate  * This function takes a mask and returns number of bits set in the
4187c478bd9Sstevel@tonic-gate  * mask (the represented prefix length).  Assumes a contigious mask.
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate int
ip_mask_to_plen_v6(const in6_addr_t * v6mask)4217c478bd9Sstevel@tonic-gate ip_mask_to_plen_v6(const in6_addr_t *v6mask)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	uint8_t		bits;
4247c478bd9Sstevel@tonic-gate 	uint32_t	mask;
4257c478bd9Sstevel@tonic-gate 	int		i;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (v6mask->_S6_un._S6_u32[3] == 0xffffffff) /* check for all ones */
4287c478bd9Sstevel@tonic-gate 		return (IPV6_ABITS);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/* Find number of words with 32 ones */
4317c478bd9Sstevel@tonic-gate 	bits = 0;
4327c478bd9Sstevel@tonic-gate 	for (i = 0; i < 4; i++) {
4337c478bd9Sstevel@tonic-gate 		if (v6mask->_S6_un._S6_u32[i] == 0xffffffff) {
4347c478bd9Sstevel@tonic-gate 			bits += 32;
4357c478bd9Sstevel@tonic-gate 			continue;
4367c478bd9Sstevel@tonic-gate 		}
4377c478bd9Sstevel@tonic-gate 		break;
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	/*
4417c478bd9Sstevel@tonic-gate 	 * Find number of bits in the last word by searching
4427c478bd9Sstevel@tonic-gate 	 * for the first one from the right
4437c478bd9Sstevel@tonic-gate 	 */
4447c478bd9Sstevel@tonic-gate 	mask = ntohl(v6mask->_S6_un._S6_u32[i]);
4457c478bd9Sstevel@tonic-gate 	if (mask == 0)
4467c478bd9Sstevel@tonic-gate 		return (bits);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	return (bits + 32 - (ffs(mask) - 1));
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate  * ip_plen_to_mask_v6(plen, bitmask)
4537c478bd9Sstevel@tonic-gate  *
4547c478bd9Sstevel@tonic-gate  * Convert a prefix length to the mask for that prefix.
4557c478bd9Sstevel@tonic-gate  * Returns the argument bitmask.
4567c478bd9Sstevel@tonic-gate  */
4577c478bd9Sstevel@tonic-gate in6_addr_t *
ip_plen_to_mask_v6(int plen,in6_addr_t * bitmask)4587c478bd9Sstevel@tonic-gate ip_plen_to_mask_v6(int plen, in6_addr_t *bitmask)
4597c478bd9Sstevel@tonic-gate {
4607c478bd9Sstevel@tonic-gate 	uint32_t *ptr;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if (plen > IPV6_ABITS || plen < 0)
4637c478bd9Sstevel@tonic-gate 		return (NULL);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	(void) memset(bitmask, 0, sizeof (in6_addr_t));
4667c478bd9Sstevel@tonic-gate 	if (plen == 0)
4677c478bd9Sstevel@tonic-gate 		return (bitmask);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	ptr = (uint32_t *)bitmask;
4707c478bd9Sstevel@tonic-gate 	while (plen > 32) {
4717c478bd9Sstevel@tonic-gate 		*ptr++ = 0xffffffffU;
4727c478bd9Sstevel@tonic-gate 		plen -= 32;
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 	*ptr = htonl(0xffffffffU << (32 - plen));
4757c478bd9Sstevel@tonic-gate 	return (bitmask);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate  * strioctl(fd, cmd, ptr, ilen)
4807c478bd9Sstevel@tonic-gate  *
4817c478bd9Sstevel@tonic-gate  * Passes an I_STR ioctl to fd.  The ioctl type is specified by cmd, and
4827c478bd9Sstevel@tonic-gate  * any date to be sent down is specified by a pointer to the buffer (ptr)
4837c478bd9Sstevel@tonic-gate  * and the buffer size (ilen).  Returns the return value from the ioctl()
4847c478bd9Sstevel@tonic-gate  * call.
4857c478bd9Sstevel@tonic-gate  */
4867c478bd9Sstevel@tonic-gate static int
strioctl(int fd,int cmd,void * ptr,int ilen)4877c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen)
4887c478bd9Sstevel@tonic-gate {
4897c478bd9Sstevel@tonic-gate 	struct strioctl str;
4907c478bd9Sstevel@tonic-gate 	int retv;
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	str.ic_cmd = cmd;
4937c478bd9Sstevel@tonic-gate 	str.ic_timout = 0;
4947c478bd9Sstevel@tonic-gate 	str.ic_len = ilen;
4957c478bd9Sstevel@tonic-gate 	str.ic_dp = ptr;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	while ((retv = ioctl(fd, I_STR, &str)) == -1) {
4987c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
4997c478bd9Sstevel@tonic-gate 			break;
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	return (retv);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate static void
usage(void)5057c478bd9Sstevel@tonic-gate usage(void)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
5087c478bd9Sstevel@tonic-gate 	    "Usage: %s\n"
5097c478bd9Sstevel@tonic-gate 	    "       %s -f <filename>\n"
5107c478bd9Sstevel@tonic-gate 	    "       %s -d\n"), myname, myname, myname);
5117c478bd9Sstevel@tonic-gate }
512