xref: /titanic_50/usr/src/cmd/cmd-inet/usr.sbin/ipaddrsel.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <libintl.h>
30*7c478bd9Sstevel@tonic-gate #include <locale.h>
31*7c478bd9Sstevel@tonic-gate #include <unistd.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <errno.h>
35*7c478bd9Sstevel@tonic-gate #include <string.h>
36*7c478bd9Sstevel@tonic-gate #include <ctype.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
39*7c478bd9Sstevel@tonic-gate #include <stropts.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
43*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
44*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
45*7c478bd9Sstevel@tonic-gate #include <inet/ip.h>
46*7c478bd9Sstevel@tonic-gate #include <inet/ip6_asp.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * The size of the table we initially use to retrieve the kernel's policy
50*7c478bd9Sstevel@tonic-gate  * table.  If this value is too small, we use the value returned from the
51*7c478bd9Sstevel@tonic-gate  * SIOCGIP6ADDRPOLICY ioctl.
52*7c478bd9Sstevel@tonic-gate  */
53*7c478bd9Sstevel@tonic-gate #define	KERN_POLICY_SIZE	32
54*7c478bd9Sstevel@tonic-gate #define	IPV6DAS_MAXLINELEN	1024
55*7c478bd9Sstevel@tonic-gate #define	IPV6DAS_MAXENTRIES	512
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate typedef enum {
58*7c478bd9Sstevel@tonic-gate 	IPV6DAS_PRINTPOLICY,
59*7c478bd9Sstevel@tonic-gate 	IPV6DAS_SETPOLICY,
60*7c478bd9Sstevel@tonic-gate 	IPV6DAS_SETDEFAULT
61*7c478bd9Sstevel@tonic-gate } ipv6das_cmd_t;
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate static char *myname;	/* Copied from argv[0] */
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate static int	parseconf(const char *, ip6_asp_t **);
66*7c478bd9Sstevel@tonic-gate static int	setpolicy(int, ip6_asp_t *, int);
67*7c478bd9Sstevel@tonic-gate static int	printpolicy(int);
68*7c478bd9Sstevel@tonic-gate static int	ip_mask_to_plen_v6(const in6_addr_t *);
69*7c478bd9Sstevel@tonic-gate static in6_addr_t *ip_plen_to_mask_v6(int, in6_addr_t *);
70*7c478bd9Sstevel@tonic-gate static int	strioctl(int, int, void *, int);
71*7c478bd9Sstevel@tonic-gate static void	usage(void);
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate int
74*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
75*7c478bd9Sstevel@tonic-gate {
76*7c478bd9Sstevel@tonic-gate 	int		opt, status, sock, count;
77*7c478bd9Sstevel@tonic-gate 	char		*conf_filename;
78*7c478bd9Sstevel@tonic-gate 	ipv6das_cmd_t	ipv6das_cmd = IPV6DAS_PRINTPOLICY;
79*7c478bd9Sstevel@tonic-gate 	ip6_asp_t	*policy_table;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	myname = *argv;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
86*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
87*7c478bd9Sstevel@tonic-gate #endif
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "df:")) != EOF)
92*7c478bd9Sstevel@tonic-gate 		switch (opt) {
93*7c478bd9Sstevel@tonic-gate 		case 'd':
94*7c478bd9Sstevel@tonic-gate 			ipv6das_cmd = IPV6DAS_SETDEFAULT;
95*7c478bd9Sstevel@tonic-gate 			break;
96*7c478bd9Sstevel@tonic-gate 		case 'f':
97*7c478bd9Sstevel@tonic-gate 			conf_filename = optarg;
98*7c478bd9Sstevel@tonic-gate 			ipv6das_cmd = IPV6DAS_SETPOLICY;
99*7c478bd9Sstevel@tonic-gate 			break;
100*7c478bd9Sstevel@tonic-gate 		default:
101*7c478bd9Sstevel@tonic-gate 			usage();
102*7c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
103*7c478bd9Sstevel@tonic-gate 		}
104*7c478bd9Sstevel@tonic-gate 	if (argc > optind) {
105*7c478bd9Sstevel@tonic-gate 		/* shouldn't be any extra args */
106*7c478bd9Sstevel@tonic-gate 		usage();
107*7c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
108*7c478bd9Sstevel@tonic-gate 	}
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	/* Open a socket that we can use to send ioctls down to IP. */
111*7c478bd9Sstevel@tonic-gate 	if ((sock = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) {
112*7c478bd9Sstevel@tonic-gate 		perror("socket");
113*7c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
114*7c478bd9Sstevel@tonic-gate 	}
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	switch (ipv6das_cmd) {
117*7c478bd9Sstevel@tonic-gate 	case IPV6DAS_SETPOLICY:
118*7c478bd9Sstevel@tonic-gate 		if ((count = parseconf(conf_filename, &policy_table)) <= 0)
119*7c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
120*7c478bd9Sstevel@tonic-gate 		status = setpolicy(sock, policy_table, count);
121*7c478bd9Sstevel@tonic-gate 		free(policy_table);
122*7c478bd9Sstevel@tonic-gate 		break;
123*7c478bd9Sstevel@tonic-gate 	case IPV6DAS_SETDEFAULT:
124*7c478bd9Sstevel@tonic-gate 		status = setpolicy(sock, NULL, 0);
125*7c478bd9Sstevel@tonic-gate 		break;
126*7c478bd9Sstevel@tonic-gate 	case IPV6DAS_PRINTPOLICY:
127*7c478bd9Sstevel@tonic-gate 	default:
128*7c478bd9Sstevel@tonic-gate 		status = printpolicy(sock);
129*7c478bd9Sstevel@tonic-gate 		break;
130*7c478bd9Sstevel@tonic-gate 	}
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	(void) close(sock);
133*7c478bd9Sstevel@tonic-gate 	return (status);
134*7c478bd9Sstevel@tonic-gate }
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate /*
137*7c478bd9Sstevel@tonic-gate  * parseconf(filename, new_policy)
138*7c478bd9Sstevel@tonic-gate  *
139*7c478bd9Sstevel@tonic-gate  * Parses the file identified by filename, filling in new_policy
140*7c478bd9Sstevel@tonic-gate  * with the address selection policy table specified in filename.
141*7c478bd9Sstevel@tonic-gate  * Returns -1 on failure, or the number of table entries found
142*7c478bd9Sstevel@tonic-gate  * on success.
143*7c478bd9Sstevel@tonic-gate  */
144*7c478bd9Sstevel@tonic-gate static int
145*7c478bd9Sstevel@tonic-gate parseconf(const char *filename, ip6_asp_t **new_policy)
146*7c478bd9Sstevel@tonic-gate {
147*7c478bd9Sstevel@tonic-gate 	FILE		*fp;
148*7c478bd9Sstevel@tonic-gate 	char		line[IPV6DAS_MAXLINELEN];
149*7c478bd9Sstevel@tonic-gate 	char		*cp, *end;
150*7c478bd9Sstevel@tonic-gate 	char		*prefixstr;
151*7c478bd9Sstevel@tonic-gate 	uint_t		lineno = 0, entryindex = 0;
152*7c478bd9Sstevel@tonic-gate 	int		plen, precedence;
153*7c478bd9Sstevel@tonic-gate 	char		*label;
154*7c478bd9Sstevel@tonic-gate 	size_t		labellen;
155*7c478bd9Sstevel@tonic-gate 	int		retval;
156*7c478bd9Sstevel@tonic-gate 	ip6_asp_t	tmp_policy[IPV6DAS_MAXENTRIES];
157*7c478bd9Sstevel@tonic-gate 	boolean_t	have_default = B_FALSE;
158*7c478bd9Sstevel@tonic-gate 	in6_addr_t	prefix, mask;
159*7c478bd9Sstevel@tonic-gate 	boolean_t	comment_found = B_FALSE, end_of_line = B_FALSE;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	if ((fp = fopen(filename, "r")) == NULL) {
162*7c478bd9Sstevel@tonic-gate 		perror(filename);
163*7c478bd9Sstevel@tonic-gate 		return (-1);
164*7c478bd9Sstevel@tonic-gate 	}
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	while (fgets(line, sizeof (line), fp) != NULL) {
167*7c478bd9Sstevel@tonic-gate 		if (entryindex == IPV6DAS_MAXENTRIES) {
168*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
169*7c478bd9Sstevel@tonic-gate 			    gettext("%s: too many entries\n"), filename);
170*7c478bd9Sstevel@tonic-gate 			retval = -1;
171*7c478bd9Sstevel@tonic-gate 			goto end_parse;
172*7c478bd9Sstevel@tonic-gate 		}
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 		lineno++;
175*7c478bd9Sstevel@tonic-gate 		cp = line;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 		/* Skip leading whitespace */
178*7c478bd9Sstevel@tonic-gate 		while (isspace(*cp))
179*7c478bd9Sstevel@tonic-gate 			cp++;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 		/* Is this a comment or blank line? */
182*7c478bd9Sstevel@tonic-gate 		if (*cp == '#' || *cp == '\0')
183*7c478bd9Sstevel@tonic-gate 			continue;
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 		/*
186*7c478bd9Sstevel@tonic-gate 		 * Anything else must be of the form:
187*7c478bd9Sstevel@tonic-gate 		 * <IPv6-addr>/<plen> <precedence> <label>
188*7c478bd9Sstevel@tonic-gate 		 */
189*7c478bd9Sstevel@tonic-gate 		prefixstr = cp;
190*7c478bd9Sstevel@tonic-gate 		if ((cp = strchr(cp, '/')) == NULL) {
191*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
192*7c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid prefix on line %d: %s\n"),
193*7c478bd9Sstevel@tonic-gate 			    filename, lineno, prefixstr);
194*7c478bd9Sstevel@tonic-gate 			continue;
195*7c478bd9Sstevel@tonic-gate 		}
196*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
197*7c478bd9Sstevel@tonic-gate 		if (inet_pton(AF_INET6, prefixstr, &prefix) != 1) {
198*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
199*7c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid prefix on line %d: %s\n"),
200*7c478bd9Sstevel@tonic-gate 			    filename, lineno, prefixstr);
201*7c478bd9Sstevel@tonic-gate 			continue;
202*7c478bd9Sstevel@tonic-gate 		}
203*7c478bd9Sstevel@tonic-gate 		cp++;
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 		errno = 0;
206*7c478bd9Sstevel@tonic-gate 		plen = strtol(cp, &end, 10);
207*7c478bd9Sstevel@tonic-gate 		if (cp == end || errno != 0) {
208*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
209*7c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid prefix length on line %d\n"),
210*7c478bd9Sstevel@tonic-gate 			    filename, lineno);
211*7c478bd9Sstevel@tonic-gate 			continue;
212*7c478bd9Sstevel@tonic-gate 		}
213*7c478bd9Sstevel@tonic-gate 		if (ip_plen_to_mask_v6(plen, &mask) == NULL) {
214*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
215*7c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid prefix length on line %d:"
216*7c478bd9Sstevel@tonic-gate 			    " %d\n"), filename, lineno, plen);
217*7c478bd9Sstevel@tonic-gate 			continue;
218*7c478bd9Sstevel@tonic-gate 		}
219*7c478bd9Sstevel@tonic-gate 		cp = end;
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 		errno = 0;
222*7c478bd9Sstevel@tonic-gate 		precedence = strtol(cp, &end, 10);
223*7c478bd9Sstevel@tonic-gate 		if (cp == end || precedence < 0 || errno != 0) {
224*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
225*7c478bd9Sstevel@tonic-gate 			    gettext("%s: invalid precedence on line %d\n"),
226*7c478bd9Sstevel@tonic-gate 			    filename, lineno);
227*7c478bd9Sstevel@tonic-gate 			continue;
228*7c478bd9Sstevel@tonic-gate 		}
229*7c478bd9Sstevel@tonic-gate 		cp = end;
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 		while (isspace(*cp))
232*7c478bd9Sstevel@tonic-gate 			cp++;
233*7c478bd9Sstevel@tonic-gate 		label = cp;
234*7c478bd9Sstevel@tonic-gate 		/*
235*7c478bd9Sstevel@tonic-gate 		 * NULL terminate the label string.  The label string is
236*7c478bd9Sstevel@tonic-gate 		 * composed of non-blank characters, and can optionally be
237*7c478bd9Sstevel@tonic-gate 		 * followed by a comment.
238*7c478bd9Sstevel@tonic-gate 		 */
239*7c478bd9Sstevel@tonic-gate 		while (*cp != '\0' && !isspace(*cp) && *cp != '#')
240*7c478bd9Sstevel@tonic-gate 			cp++;
241*7c478bd9Sstevel@tonic-gate 		if (*cp == '#')
242*7c478bd9Sstevel@tonic-gate 			comment_found = B_TRUE;
243*7c478bd9Sstevel@tonic-gate 		else if (*cp == '\0' || *cp == '\n')
244*7c478bd9Sstevel@tonic-gate 			end_of_line = B_TRUE;
245*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 		labellen = cp - label;
248*7c478bd9Sstevel@tonic-gate 		if (labellen == 0) {
249*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
250*7c478bd9Sstevel@tonic-gate 			    gettext("%s: missing label on line %d\n"),
251*7c478bd9Sstevel@tonic-gate 			    filename, lineno);
252*7c478bd9Sstevel@tonic-gate 			continue;
253*7c478bd9Sstevel@tonic-gate 		}
254*7c478bd9Sstevel@tonic-gate 		if (labellen >= IP6_ASP_MAXLABELSIZE) {
255*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
256*7c478bd9Sstevel@tonic-gate 			    gettext("%s: label too long on line %d, labels "
257*7c478bd9Sstevel@tonic-gate 			    "have a %d character limit.\n"), filename, lineno,
258*7c478bd9Sstevel@tonic-gate 			    IP6_ASP_MAXLABELSIZE - 1);
259*7c478bd9Sstevel@tonic-gate 			continue;
260*7c478bd9Sstevel@tonic-gate 		}
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 		tmp_policy[entryindex].ip6_asp_prefix = prefix;
263*7c478bd9Sstevel@tonic-gate 		tmp_policy[entryindex].ip6_asp_mask = mask;
264*7c478bd9Sstevel@tonic-gate 		tmp_policy[entryindex].ip6_asp_precedence = precedence;
265*7c478bd9Sstevel@tonic-gate 		/*
266*7c478bd9Sstevel@tonic-gate 		 * We're specifically using strncpy() to copy the label
267*7c478bd9Sstevel@tonic-gate 		 * to take advantage of the fact that strncpy will add
268*7c478bd9Sstevel@tonic-gate 		 * NULL characters to the target string up to the given
269*7c478bd9Sstevel@tonic-gate 		 * length, so don't change the call to strncpy() with
270*7c478bd9Sstevel@tonic-gate 		 * out also taking into account this requirement.  The
271*7c478bd9Sstevel@tonic-gate 		 * labels are stored in the kernel in that way in order
272*7c478bd9Sstevel@tonic-gate 		 * to make comparisons more efficient: all 16 bytes of
273*7c478bd9Sstevel@tonic-gate 		 * the labels are compared to each other; random bytes
274*7c478bd9Sstevel@tonic-gate 		 * after the NULL terminator would yield incorrect
275*7c478bd9Sstevel@tonic-gate 		 * comparisons.
276*7c478bd9Sstevel@tonic-gate 		 */
277*7c478bd9Sstevel@tonic-gate 		(void) strncpy(tmp_policy[entryindex].ip6_asp_label, label,
278*7c478bd9Sstevel@tonic-gate 		    IP6_ASP_MAXLABELSIZE);
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 		/*
281*7c478bd9Sstevel@tonic-gate 		 * Anything else on the line should be a comment; print
282*7c478bd9Sstevel@tonic-gate 		 * a warning if that's not the case.
283*7c478bd9Sstevel@tonic-gate 		 */
284*7c478bd9Sstevel@tonic-gate 		if (!comment_found && !end_of_line) {
285*7c478bd9Sstevel@tonic-gate 			cp++;
286*7c478bd9Sstevel@tonic-gate 			while (*cp != '\0' && isspace(*cp) && *cp != '#')
287*7c478bd9Sstevel@tonic-gate 				cp++;
288*7c478bd9Sstevel@tonic-gate 			if (*cp != '\0' && *cp != '#') {
289*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
290*7c478bd9Sstevel@tonic-gate 				    gettext("%s: characters following label "
291*7c478bd9Sstevel@tonic-gate 				    "on line %d will be ignored\n"),
292*7c478bd9Sstevel@tonic-gate 				    filename, lineno);
293*7c478bd9Sstevel@tonic-gate 			}
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&prefix) && plen == 0)
297*7c478bd9Sstevel@tonic-gate 			have_default = B_TRUE;
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 		comment_found = B_FALSE;
300*7c478bd9Sstevel@tonic-gate 		end_of_line = B_FALSE;
301*7c478bd9Sstevel@tonic-gate 		entryindex++;
302*7c478bd9Sstevel@tonic-gate 	}
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	if (!have_default) {
305*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
306*7c478bd9Sstevel@tonic-gate 		    gettext("%s: config doesn't contain a default entry.\n"),
307*7c478bd9Sstevel@tonic-gate 		    filename);
308*7c478bd9Sstevel@tonic-gate 		retval = -1;
309*7c478bd9Sstevel@tonic-gate 		goto end_parse;
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	/* Allocate the caller's array. */
313*7c478bd9Sstevel@tonic-gate 	if ((*new_policy = malloc(entryindex * sizeof (ip6_asp_t))) == NULL) {
314*7c478bd9Sstevel@tonic-gate 		perror("malloc");
315*7c478bd9Sstevel@tonic-gate 		retval = -1;
316*7c478bd9Sstevel@tonic-gate 		goto end_parse;
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 	(void) memcpy(*new_policy, tmp_policy, entryindex * sizeof (ip6_asp_t));
320*7c478bd9Sstevel@tonic-gate 	retval = entryindex;
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate end_parse:
323*7c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
324*7c478bd9Sstevel@tonic-gate 	return (retval);
325*7c478bd9Sstevel@tonic-gate }
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate /*
328*7c478bd9Sstevel@tonic-gate  * setpolicy(sock, new_policy, count)
329*7c478bd9Sstevel@tonic-gate  *
330*7c478bd9Sstevel@tonic-gate  * Sends an SIOCSIP6ADDRPOLICY ioctl to the kernel to set the address
331*7c478bd9Sstevel@tonic-gate  * selection policy table pointed to by new_policy.  count should be
332*7c478bd9Sstevel@tonic-gate  * the number of entries in the table; sock should be an open INET6
333*7c478bd9Sstevel@tonic-gate  * socket.  Returns EXIT_FAILURE or EXIT_SUCCESS.
334*7c478bd9Sstevel@tonic-gate  */
335*7c478bd9Sstevel@tonic-gate static int
336*7c478bd9Sstevel@tonic-gate setpolicy(int sock, ip6_asp_t *new_policy, int count)
337*7c478bd9Sstevel@tonic-gate {
338*7c478bd9Sstevel@tonic-gate 	if (strioctl(sock, SIOCSIP6ADDRPOLICY, new_policy,
339*7c478bd9Sstevel@tonic-gate 	    count * sizeof (ip6_asp_t)) < 0) {
340*7c478bd9Sstevel@tonic-gate 		perror("SIOCSIP6ADDRPOLICY");
341*7c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
342*7c478bd9Sstevel@tonic-gate 	}
343*7c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate /*
347*7c478bd9Sstevel@tonic-gate  * printpolicy(sock)
348*7c478bd9Sstevel@tonic-gate  *
349*7c478bd9Sstevel@tonic-gate  * Queries the kernel for the current address selection policy using
350*7c478bd9Sstevel@tonic-gate  * the open socket sock, and prints the result.  Returns EXIT_FAILURE
351*7c478bd9Sstevel@tonic-gate  * if the table cannot be obtained, or EXIT_SUCCESS if the table is
352*7c478bd9Sstevel@tonic-gate  * obtained and printed successfully.
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate static int
355*7c478bd9Sstevel@tonic-gate printpolicy(int sock)
356*7c478bd9Sstevel@tonic-gate {
357*7c478bd9Sstevel@tonic-gate 	ip6_asp_t	policy[KERN_POLICY_SIZE];
358*7c478bd9Sstevel@tonic-gate 	ip6_asp_t	*policy_ptr = policy;
359*7c478bd9Sstevel@tonic-gate 	int		count, policy_index;
360*7c478bd9Sstevel@tonic-gate 	char		prefixstr[INET6_ADDRSTRLEN + sizeof ("/128")];
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	if ((count = strioctl(sock, SIOCGIP6ADDRPOLICY, policy_ptr,
363*7c478bd9Sstevel@tonic-gate 	    KERN_POLICY_SIZE * sizeof (ip6_asp_t))) < 0) {
364*7c478bd9Sstevel@tonic-gate 		perror("SIOCGIP6ADDRPOLICY");
365*7c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 	if (count > KERN_POLICY_SIZE) {
368*7c478bd9Sstevel@tonic-gate 		policy_ptr = malloc(count * sizeof (ip6_asp_t));
369*7c478bd9Sstevel@tonic-gate 		if (policy_ptr == NULL) {
370*7c478bd9Sstevel@tonic-gate 			perror("malloc");
371*7c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
372*7c478bd9Sstevel@tonic-gate 		}
373*7c478bd9Sstevel@tonic-gate 		if ((count = strioctl(sock, SIOCGIP6ADDRPOLICY, policy_ptr,
374*7c478bd9Sstevel@tonic-gate 		    count * sizeof (ip6_asp_t))) < 0) {
375*7c478bd9Sstevel@tonic-gate 			perror("SIOCGIP6ADDRPOLICY");
376*7c478bd9Sstevel@tonic-gate 			return (EXIT_FAILURE);
377*7c478bd9Sstevel@tonic-gate 		}
378*7c478bd9Sstevel@tonic-gate 	}
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	if (count == 0) {
381*7c478bd9Sstevel@tonic-gate 		/*
382*7c478bd9Sstevel@tonic-gate 		 * There should always at least be a default entry in the
383*7c478bd9Sstevel@tonic-gate 		 * policy table, so the minimum acceptable value of
384*7c478bd9Sstevel@tonic-gate 		 * policy_count is 1.
385*7c478bd9Sstevel@tonic-gate 		 */
386*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("%s: ERROR: "
387*7c478bd9Sstevel@tonic-gate 		    "IPv6 address selection policy is empty.\n"), myname);
388*7c478bd9Sstevel@tonic-gate 		return (EXIT_FAILURE);
389*7c478bd9Sstevel@tonic-gate 	}
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	/*
392*7c478bd9Sstevel@tonic-gate 	 * The format printed here must also be parsable by parseconf(),
393*7c478bd9Sstevel@tonic-gate 	 * since we expect users to be able to redirect this output to
394*7c478bd9Sstevel@tonic-gate 	 * a usable configuration file if need be.
395*7c478bd9Sstevel@tonic-gate 	 */
396*7c478bd9Sstevel@tonic-gate 	(void) printf("# Prefix                  Precedence Label\n");
397*7c478bd9Sstevel@tonic-gate 	for (policy_index = 0; policy_index < count; policy_index++) {
398*7c478bd9Sstevel@tonic-gate 		(void) snprintf(prefixstr, sizeof (prefixstr), "%s/%d",
399*7c478bd9Sstevel@tonic-gate 		    inet_ntop(AF_INET6,
400*7c478bd9Sstevel@tonic-gate 			&policy_ptr[policy_index].ip6_asp_prefix, prefixstr,
401*7c478bd9Sstevel@tonic-gate 			sizeof (prefixstr)),
402*7c478bd9Sstevel@tonic-gate 		    ip_mask_to_plen_v6(&policy_ptr[policy_index].ip6_asp_mask));
403*7c478bd9Sstevel@tonic-gate 		(void) printf("%-25s %10d %s\n", prefixstr,
404*7c478bd9Sstevel@tonic-gate 		    policy_ptr[policy_index].ip6_asp_precedence,
405*7c478bd9Sstevel@tonic-gate 		    policy_ptr[policy_index].ip6_asp_label);
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	if (policy_ptr != policy)
409*7c478bd9Sstevel@tonic-gate 		free(policy_ptr);
410*7c478bd9Sstevel@tonic-gate 	return (EXIT_SUCCESS);
411*7c478bd9Sstevel@tonic-gate }
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate /*
414*7c478bd9Sstevel@tonic-gate  * ip_mask_to_plen_v6(v6mask)
415*7c478bd9Sstevel@tonic-gate  *
416*7c478bd9Sstevel@tonic-gate  * This function takes a mask and returns number of bits set in the
417*7c478bd9Sstevel@tonic-gate  * mask (the represented prefix length).  Assumes a contigious mask.
418*7c478bd9Sstevel@tonic-gate  */
419*7c478bd9Sstevel@tonic-gate int
420*7c478bd9Sstevel@tonic-gate ip_mask_to_plen_v6(const in6_addr_t *v6mask)
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	uint8_t		bits;
423*7c478bd9Sstevel@tonic-gate 	uint32_t	mask;
424*7c478bd9Sstevel@tonic-gate 	int		i;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	if (v6mask->_S6_un._S6_u32[3] == 0xffffffff) /* check for all ones */
427*7c478bd9Sstevel@tonic-gate 		return (IPV6_ABITS);
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	/* Find number of words with 32 ones */
430*7c478bd9Sstevel@tonic-gate 	bits = 0;
431*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 4; i++) {
432*7c478bd9Sstevel@tonic-gate 		if (v6mask->_S6_un._S6_u32[i] == 0xffffffff) {
433*7c478bd9Sstevel@tonic-gate 			bits += 32;
434*7c478bd9Sstevel@tonic-gate 			continue;
435*7c478bd9Sstevel@tonic-gate 		}
436*7c478bd9Sstevel@tonic-gate 		break;
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	/*
440*7c478bd9Sstevel@tonic-gate 	 * Find number of bits in the last word by searching
441*7c478bd9Sstevel@tonic-gate 	 * for the first one from the right
442*7c478bd9Sstevel@tonic-gate 	 */
443*7c478bd9Sstevel@tonic-gate 	mask = ntohl(v6mask->_S6_un._S6_u32[i]);
444*7c478bd9Sstevel@tonic-gate 	if (mask == 0)
445*7c478bd9Sstevel@tonic-gate 		return (bits);
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	return (bits + 32 - (ffs(mask) - 1));
448*7c478bd9Sstevel@tonic-gate }
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate /*
451*7c478bd9Sstevel@tonic-gate  * ip_plen_to_mask_v6(plen, bitmask)
452*7c478bd9Sstevel@tonic-gate  *
453*7c478bd9Sstevel@tonic-gate  * Convert a prefix length to the mask for that prefix.
454*7c478bd9Sstevel@tonic-gate  * Returns the argument bitmask.
455*7c478bd9Sstevel@tonic-gate  */
456*7c478bd9Sstevel@tonic-gate in6_addr_t *
457*7c478bd9Sstevel@tonic-gate ip_plen_to_mask_v6(int plen, in6_addr_t *bitmask)
458*7c478bd9Sstevel@tonic-gate {
459*7c478bd9Sstevel@tonic-gate 	uint32_t *ptr;
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate 	if (plen > IPV6_ABITS || plen < 0)
462*7c478bd9Sstevel@tonic-gate 		return (NULL);
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	(void) memset(bitmask, 0, sizeof (in6_addr_t));
465*7c478bd9Sstevel@tonic-gate 	if (plen == 0)
466*7c478bd9Sstevel@tonic-gate 		return (bitmask);
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	ptr = (uint32_t *)bitmask;
469*7c478bd9Sstevel@tonic-gate 	while (plen > 32) {
470*7c478bd9Sstevel@tonic-gate 		*ptr++ = 0xffffffffU;
471*7c478bd9Sstevel@tonic-gate 		plen -= 32;
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 	*ptr = htonl(0xffffffffU << (32 - plen));
474*7c478bd9Sstevel@tonic-gate 	return (bitmask);
475*7c478bd9Sstevel@tonic-gate }
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate /*
478*7c478bd9Sstevel@tonic-gate  * strioctl(fd, cmd, ptr, ilen)
479*7c478bd9Sstevel@tonic-gate  *
480*7c478bd9Sstevel@tonic-gate  * Passes an I_STR ioctl to fd.  The ioctl type is specified by cmd, and
481*7c478bd9Sstevel@tonic-gate  * any date to be sent down is specified by a pointer to the buffer (ptr)
482*7c478bd9Sstevel@tonic-gate  * and the buffer size (ilen).  Returns the return value from the ioctl()
483*7c478bd9Sstevel@tonic-gate  * call.
484*7c478bd9Sstevel@tonic-gate  */
485*7c478bd9Sstevel@tonic-gate static int
486*7c478bd9Sstevel@tonic-gate strioctl(int fd, int cmd, void *ptr, int ilen)
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	struct strioctl str;
489*7c478bd9Sstevel@tonic-gate 	int retv;
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	str.ic_cmd = cmd;
492*7c478bd9Sstevel@tonic-gate 	str.ic_timout = 0;
493*7c478bd9Sstevel@tonic-gate 	str.ic_len = ilen;
494*7c478bd9Sstevel@tonic-gate 	str.ic_dp = ptr;
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	while ((retv = ioctl(fd, I_STR, &str)) == -1) {
497*7c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
498*7c478bd9Sstevel@tonic-gate 			break;
499*7c478bd9Sstevel@tonic-gate 	}
500*7c478bd9Sstevel@tonic-gate 	return (retv);
501*7c478bd9Sstevel@tonic-gate }
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate static void
504*7c478bd9Sstevel@tonic-gate usage(void)
505*7c478bd9Sstevel@tonic-gate {
506*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
507*7c478bd9Sstevel@tonic-gate 	    "Usage: %s\n"
508*7c478bd9Sstevel@tonic-gate 	    "       %s -f <filename>\n"
509*7c478bd9Sstevel@tonic-gate 	    "       %s -d\n"), myname, myname, myname);
510*7c478bd9Sstevel@tonic-gate }
511