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