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 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 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 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 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 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 * 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 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 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