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 <sys/socket.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/stream.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <net/route.h> 34*7c478bd9Sstevel@tonic-gate #include <net/if.h> 35*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 36*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 37*7c478bd9Sstevel@tonic-gate #include <inet/tun.h> 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate #include <locale.h> 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #include <errno.h> 42*7c478bd9Sstevel@tonic-gate #include <unistd.h> 43*7c478bd9Sstevel@tonic-gate #include <stdio.h> 44*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 45*7c478bd9Sstevel@tonic-gate #include <strings.h> 46*7c478bd9Sstevel@tonic-gate #include <string.h> 47*7c478bd9Sstevel@tonic-gate #include <stropts.h> 48*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate /* 51*7c478bd9Sstevel@tonic-gate * Converts an IPv4 address to a 6to4 /64 route. Address is of the form 52*7c478bd9Sstevel@tonic-gate * 2002:<V4ADDR>:<SUBNETID>::/64 where SUBNETID will always be 0 and V4ADDR 53*7c478bd9Sstevel@tonic-gate * equals the input IPv4 address. IN6_V4ADDR_TO_6TO4(v4, v6) creates an 54*7c478bd9Sstevel@tonic-gate * address of form 2002:<V4ADDR>:<SUBNETID>::<HOSTID>, where SUBNETID equals 0 55*7c478bd9Sstevel@tonic-gate * and HOSTID equals 1. For this route, we are not concerned about the 56*7c478bd9Sstevel@tonic-gate * HOSTID portion of the address, thus it can be set to 0. 57*7c478bd9Sstevel@tonic-gate * 58*7c478bd9Sstevel@tonic-gate * void V4ADDR_TO_6TO4_RT(const struct in_addr *v4, in6_addr_t *v6) 59*7c478bd9Sstevel@tonic-gate */ 60*7c478bd9Sstevel@tonic-gate #define V4ADDR_TO_6TO4_RT(v4, v6) \ 61*7c478bd9Sstevel@tonic-gate (IN6_V4ADDR_TO_6TO4(v4, v6), (v6)->_S6_un._S6_u32[3] = 0) 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate static void strioctl(int, void *, size_t); 64*7c478bd9Sstevel@tonic-gate static void getkstatus(ipaddr_t *); 65*7c478bd9Sstevel@tonic-gate static void printkstatus(void); 66*7c478bd9Sstevel@tonic-gate static void modifyroute(unsigned int, in6_addr_t *); 67*7c478bd9Sstevel@tonic-gate static void setkrraddr(ipaddr_t); 68*7c478bd9Sstevel@tonic-gate static void printerror(char *); 69*7c478bd9Sstevel@tonic-gate static void usage(void); 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate /* booleans corresponding to command line flags */ 72*7c478bd9Sstevel@tonic-gate static boolean_t eflag = B_FALSE; 73*7c478bd9Sstevel@tonic-gate static boolean_t dflag = B_FALSE; 74*7c478bd9Sstevel@tonic-gate static boolean_t aflag = B_FALSE; 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate static int fd = -1; 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * srtioctl(cmd, buf, size) 80*7c478bd9Sstevel@tonic-gate * 81*7c478bd9Sstevel@tonic-gate * Passes the contents of 'buf' using the ioctl specified by 'cmd', by way of 82*7c478bd9Sstevel@tonic-gate * the I_STR ioctl mechanism. The response of the ioctl will be stored in buf 83*7c478bd9Sstevel@tonic-gate * when this function returns. The input 'size' specifies the size of the 84*7c478bd9Sstevel@tonic-gate * buffer to be passed. 85*7c478bd9Sstevel@tonic-gate */ 86*7c478bd9Sstevel@tonic-gate static void 87*7c478bd9Sstevel@tonic-gate strioctl(int cmd, void *buf, size_t size) 88*7c478bd9Sstevel@tonic-gate { 89*7c478bd9Sstevel@tonic-gate struct strioctl ioc; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate (void) memset(&ioc, 0, sizeof (ioc)); 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate ioc.ic_cmd = cmd; 94*7c478bd9Sstevel@tonic-gate ioc.ic_timout = 0; 95*7c478bd9Sstevel@tonic-gate ioc.ic_len = size; 96*7c478bd9Sstevel@tonic-gate ioc.ic_dp = (char *)buf; 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_STR, &ioc) < 0) { 99*7c478bd9Sstevel@tonic-gate printerror("ioctl (I_STR)"); 100*7c478bd9Sstevel@tonic-gate (void) close(fd); 101*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 102*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 103*7c478bd9Sstevel@tonic-gate } 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate /* 108*7c478bd9Sstevel@tonic-gate * getkstatus(out_addr) 109*7c478bd9Sstevel@tonic-gate * 110*7c478bd9Sstevel@tonic-gate * Queries the kernel for the 6to4 Relay Router destination address by sending 111*7c478bd9Sstevel@tonic-gate * the SIOCG6TO4TUNRRADDR ioctl to the tunnel module using the I_STR ioctl 112*7c478bd9Sstevel@tonic-gate * mechanism. The value returned, through the ioctl, will be an ipaddr_t 113*7c478bd9Sstevel@tonic-gate * embedded in a strioctl. Output parameter is set with result. 114*7c478bd9Sstevel@tonic-gate */ 115*7c478bd9Sstevel@tonic-gate static void 116*7c478bd9Sstevel@tonic-gate getkstatus(ipaddr_t *out_addr) 117*7c478bd9Sstevel@tonic-gate { 118*7c478bd9Sstevel@tonic-gate ipaddr_t an_addr; 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate /* Get the Relay Router address from the kernel */ 121*7c478bd9Sstevel@tonic-gate strioctl(SIOCG6TO4TUNRRADDR, &an_addr, sizeof (an_addr)); 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate *out_addr = an_addr; /* set output parameter */ 124*7c478bd9Sstevel@tonic-gate } 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate /* 128*7c478bd9Sstevel@tonic-gate * printkstatus() 129*7c478bd9Sstevel@tonic-gate * 130*7c478bd9Sstevel@tonic-gate * Queries the kernel for the current 6to4 Relay Router value, prints 131*7c478bd9Sstevel@tonic-gate * a status message based on the value and exits this command. 132*7c478bd9Sstevel@tonic-gate * INADDR_ANY is used to denote that Relay Router communication support is 133*7c478bd9Sstevel@tonic-gate * disabled within the kernel. 134*7c478bd9Sstevel@tonic-gate */ 135*7c478bd9Sstevel@tonic-gate static void 136*7c478bd9Sstevel@tonic-gate printkstatus(void) 137*7c478bd9Sstevel@tonic-gate { 138*7c478bd9Sstevel@tonic-gate ipaddr_t rr_addr; 139*7c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate getkstatus(&rr_addr); /* get value from kernel */ 142*7c478bd9Sstevel@tonic-gate (void) printf("6to4relay: "); 143*7c478bd9Sstevel@tonic-gate if (rr_addr == INADDR_ANY) { 144*7c478bd9Sstevel@tonic-gate (void) printf(gettext("6to4 Relay Router communication " 145*7c478bd9Sstevel@tonic-gate "support is disabled.\n")); 146*7c478bd9Sstevel@tonic-gate } else { 147*7c478bd9Sstevel@tonic-gate (void) printf(gettext("6to4 Relay Router communication " 148*7c478bd9Sstevel@tonic-gate "support is enabled.\n")); 149*7c478bd9Sstevel@tonic-gate (void) printf(gettext("IPv4 destination address of Relay " 150*7c478bd9Sstevel@tonic-gate "Router = ")); 151*7c478bd9Sstevel@tonic-gate (void) printf("%s\n", 152*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET, &rr_addr, buf, sizeof (buf))); 153*7c478bd9Sstevel@tonic-gate } 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate /* 157*7c478bd9Sstevel@tonic-gate * modifyroute(cmd, in_gw) 158*7c478bd9Sstevel@tonic-gate * 159*7c478bd9Sstevel@tonic-gate * Modifies a default IPv6 route with DST = ::, GATEWAY = in_gw, NETMASK = :: 160*7c478bd9Sstevel@tonic-gate * and flags = <GATEWAY, STATIC>. 161*7c478bd9Sstevel@tonic-gate * This route is to be propagated through the 6to4 site so that 6to4 hosts 162*7c478bd9Sstevel@tonic-gate * can send packets to native IPv6 hosts behind a remote 6to4 Relay Router. 163*7c478bd9Sstevel@tonic-gate */ 164*7c478bd9Sstevel@tonic-gate static void 165*7c478bd9Sstevel@tonic-gate modifyroute(unsigned int cmd, in6_addr_t *in_gw) 166*7c478bd9Sstevel@tonic-gate { 167*7c478bd9Sstevel@tonic-gate static int rtmseq; 168*7c478bd9Sstevel@tonic-gate int rtsock; 169*7c478bd9Sstevel@tonic-gate int rlen; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate static struct { 172*7c478bd9Sstevel@tonic-gate struct rt_msghdr rt_hdr; 173*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 rt_dst; 174*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 rt_gate; 175*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 rt_mask; 176*7c478bd9Sstevel@tonic-gate } rt_msg; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /* Open a routing socket for passing route commands */ 179*7c478bd9Sstevel@tonic-gate if ((rtsock = socket(AF_ROUTE, SOCK_RAW, AF_INET)) < 0) { 180*7c478bd9Sstevel@tonic-gate printerror("socket"); 181*7c478bd9Sstevel@tonic-gate (void) close(fd); 182*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 183*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate (void) memset(&rt_msg, 0, sizeof (rt_msg)); 187*7c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_msglen = sizeof (rt_msg); 188*7c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_version = RTM_VERSION; 189*7c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 190*7c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_pid = getpid(); 191*7c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_type = cmd; 192*7c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_seq = ++rtmseq; 193*7c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY; 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* DST */ 196*7c478bd9Sstevel@tonic-gate rt_msg.rt_dst.sin6_family = AF_INET6; 197*7c478bd9Sstevel@tonic-gate (void) memset(&rt_msg.rt_dst.sin6_addr.s6_addr, 0, 198*7c478bd9Sstevel@tonic-gate sizeof (in6_addr_t)); 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate /* GATEWAY */ 201*7c478bd9Sstevel@tonic-gate rt_msg.rt_gate.sin6_family = AF_INET6; 202*7c478bd9Sstevel@tonic-gate bcopy(in_gw->s6_addr, &rt_msg.rt_gate.sin6_addr.s6_addr, 203*7c478bd9Sstevel@tonic-gate sizeof (in6_addr_t)); 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate /* NETMASK */ 206*7c478bd9Sstevel@tonic-gate rt_msg.rt_mask.sin6_family = AF_INET6; 207*7c478bd9Sstevel@tonic-gate (void) memset(&rt_msg.rt_mask.sin6_addr.s6_addr, 0, 208*7c478bd9Sstevel@tonic-gate sizeof (in6_addr_t)); 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate /* Send the routing message */ 211*7c478bd9Sstevel@tonic-gate rlen = write(rtsock, &rt_msg, rt_msg.rt_hdr.rtm_msglen); 212*7c478bd9Sstevel@tonic-gate if (rlen < rt_msg.rt_hdr.rtm_msglen) { 213*7c478bd9Sstevel@tonic-gate if (rlen < 0) { 214*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 215*7c478bd9Sstevel@tonic-gate gettext("6to4relay: write to routing socket: %s\n"), 216*7c478bd9Sstevel@tonic-gate strerror(errno)); 217*7c478bd9Sstevel@tonic-gate } else { 218*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("6to4relay: write to " 219*7c478bd9Sstevel@tonic-gate "routing socket got only %d for rlen\n"), rlen); 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate (void) close(rtsock); 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* 226*7c478bd9Sstevel@tonic-gate * setkrraddr(in_addr) 227*7c478bd9Sstevel@tonic-gate * 228*7c478bd9Sstevel@tonic-gate * Sets the 6to4 Relay Router destination address value in the kernel using 229*7c478bd9Sstevel@tonic-gate * the SIOCS6TO4TUNRRADDR ioctl using the I_STR ioctl mechanism. 230*7c478bd9Sstevel@tonic-gate * The address is sent to the kernel, as an ipaddr_t, embedded in an strioctl. 231*7c478bd9Sstevel@tonic-gate */ 232*7c478bd9Sstevel@tonic-gate static void 233*7c478bd9Sstevel@tonic-gate setkrraddr(ipaddr_t in_addr) 234*7c478bd9Sstevel@tonic-gate { 235*7c478bd9Sstevel@tonic-gate /* set Relay Router address */ 236*7c478bd9Sstevel@tonic-gate strioctl(SIOCS6TO4TUNRRADDR, &in_addr, sizeof (in_addr)); 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate static void 240*7c478bd9Sstevel@tonic-gate printerror(char *s) 241*7c478bd9Sstevel@tonic-gate { 242*7c478bd9Sstevel@tonic-gate int sverrno = errno; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "6to4relay: "); 245*7c478bd9Sstevel@tonic-gate if (s != NULL) 246*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", s); 247*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s\n", strerror(sverrno)); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate static void 251*7c478bd9Sstevel@tonic-gate usage(void) 252*7c478bd9Sstevel@tonic-gate { 253*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 254*7c478bd9Sstevel@tonic-gate gettext("usage:\n" 255*7c478bd9Sstevel@tonic-gate "\t6to4relay\n" 256*7c478bd9Sstevel@tonic-gate "\t6to4relay -e [-a <addr>]\n" 257*7c478bd9Sstevel@tonic-gate "\t6to4relay -d\n" 258*7c478bd9Sstevel@tonic-gate "\t6to4relay -h\n")); 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate int 262*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 263*7c478bd9Sstevel@tonic-gate { 264*7c478bd9Sstevel@tonic-gate int ch; 265*7c478bd9Sstevel@tonic-gate char *in_addr = NULL; 266*7c478bd9Sstevel@tonic-gate int ret = EXIT_SUCCESS; 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 271*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 272*7c478bd9Sstevel@tonic-gate #endif 273*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate /* open /dev/ip for use */ 276*7c478bd9Sstevel@tonic-gate if ((fd = open("/dev/ip", O_RDWR)) == -1) { 277*7c478bd9Sstevel@tonic-gate printerror(gettext("can't open /dev/ip")); 278*7c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE); 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate if (ioctl(fd, I_PUSH, TUN_NAME) < 0) { 282*7c478bd9Sstevel@tonic-gate printerror("ioctl (I_PUSH)"); 283*7c478bd9Sstevel@tonic-gate ret = EXIT_FAILURE; 284*7c478bd9Sstevel@tonic-gate goto done; 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate /* If no args are specified, print status as queried from kernel */ 288*7c478bd9Sstevel@tonic-gate if (argc < 2) { 289*7c478bd9Sstevel@tonic-gate printkstatus(); 290*7c478bd9Sstevel@tonic-gate goto done; 291*7c478bd9Sstevel@tonic-gate } 292*7c478bd9Sstevel@tonic-gate while ((ch = getopt(argc, argv, "ea:dh")) != EOF) { 293*7c478bd9Sstevel@tonic-gate switch (ch) { 294*7c478bd9Sstevel@tonic-gate case 'e': 295*7c478bd9Sstevel@tonic-gate eflag = B_TRUE; 296*7c478bd9Sstevel@tonic-gate break; 297*7c478bd9Sstevel@tonic-gate case 'd': 298*7c478bd9Sstevel@tonic-gate dflag = B_TRUE; 299*7c478bd9Sstevel@tonic-gate break; 300*7c478bd9Sstevel@tonic-gate case 'a': 301*7c478bd9Sstevel@tonic-gate aflag = B_TRUE; 302*7c478bd9Sstevel@tonic-gate in_addr = optarg; 303*7c478bd9Sstevel@tonic-gate break; 304*7c478bd9Sstevel@tonic-gate case 'h': 305*7c478bd9Sstevel@tonic-gate usage(); 306*7c478bd9Sstevel@tonic-gate goto done; 307*7c478bd9Sstevel@tonic-gate default: 308*7c478bd9Sstevel@tonic-gate usage(); 309*7c478bd9Sstevel@tonic-gate ret = EXIT_FAILURE; 310*7c478bd9Sstevel@tonic-gate goto done; 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate /* 314*7c478bd9Sstevel@tonic-gate * If -a is specified, -e must also be specified. Also, the 315*7c478bd9Sstevel@tonic-gate * combination of -e and -d is illegal. Fail on either case. 316*7c478bd9Sstevel@tonic-gate */ 317*7c478bd9Sstevel@tonic-gate if ((aflag && !eflag) || (eflag && dflag)) { 318*7c478bd9Sstevel@tonic-gate usage(); 319*7c478bd9Sstevel@tonic-gate ret = EXIT_FAILURE; 320*7c478bd9Sstevel@tonic-gate goto done; 321*7c478bd9Sstevel@tonic-gate } 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate /* 324*7c478bd9Sstevel@tonic-gate * Enable Relay Router communication support in the kernel. 325*7c478bd9Sstevel@tonic-gate */ 326*7c478bd9Sstevel@tonic-gate if (eflag) { 327*7c478bd9Sstevel@tonic-gate struct in_addr current_addr; /* addr currently set in kernel */ 328*7c478bd9Sstevel@tonic-gate struct in_addr new_addr; /* new addr we plan to set */ 329*7c478bd9Sstevel@tonic-gate in6_addr_t v6_rt; 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * if -a was not specified, the well-known anycast will 333*7c478bd9Sstevel@tonic-gate * be used. 334*7c478bd9Sstevel@tonic-gate */ 335*7c478bd9Sstevel@tonic-gate if (!aflag) { 336*7c478bd9Sstevel@tonic-gate new_addr.s_addr = htonl(INADDR_6TO4RRANYCAST); 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate } else if (inet_pton(AF_INET, in_addr, &new_addr) <= 0) { 339*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("6to4relay: input " 340*7c478bd9Sstevel@tonic-gate "address (%s) is not a valid IPv4 dotted-decimal " 341*7c478bd9Sstevel@tonic-gate "string.\n"), in_addr); 342*7c478bd9Sstevel@tonic-gate ret = EXIT_FAILURE; 343*7c478bd9Sstevel@tonic-gate goto done; 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate /* 347*7c478bd9Sstevel@tonic-gate * INADDR_ANY has special meaning in the kernel, reject this 348*7c478bd9Sstevel@tonic-gate * input and exit. 349*7c478bd9Sstevel@tonic-gate */ 350*7c478bd9Sstevel@tonic-gate if (new_addr.s_addr == INADDR_ANY) { 351*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("6to4relay: input " 352*7c478bd9Sstevel@tonic-gate "(0.0.0.0) is not a valid IPv4 unicast " 353*7c478bd9Sstevel@tonic-gate "address.\n")); 354*7c478bd9Sstevel@tonic-gate ret = EXIT_FAILURE; 355*7c478bd9Sstevel@tonic-gate goto done; 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /* 359*7c478bd9Sstevel@tonic-gate * get the current Relay Router address from the kernel. 360*7c478bd9Sstevel@tonic-gate * 361*7c478bd9Sstevel@tonic-gate * 1. If the current address is INADDR_ANY, set the new 362*7c478bd9Sstevel@tonic-gate * address in the kernel and add a default IPv6 route using 363*7c478bd9Sstevel@tonic-gate * the new address. 364*7c478bd9Sstevel@tonic-gate * 365*7c478bd9Sstevel@tonic-gate * 2. If the current address is different than the new address, 366*7c478bd9Sstevel@tonic-gate * set the new address in the kernel, delete the 367*7c478bd9Sstevel@tonic-gate * old default IPv6 route and add a new default IPv6 route 368*7c478bd9Sstevel@tonic-gate * (using the new address). 369*7c478bd9Sstevel@tonic-gate * 370*7c478bd9Sstevel@tonic-gate * 3. If the kernel address is the same as the one we are 371*7c478bd9Sstevel@tonic-gate * adding, no additional processing is needed. 372*7c478bd9Sstevel@tonic-gate */ 373*7c478bd9Sstevel@tonic-gate getkstatus(¤t_addr.s_addr); 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate if (current_addr.s_addr == INADDR_ANY) { 376*7c478bd9Sstevel@tonic-gate setkrraddr(new_addr.s_addr); 377*7c478bd9Sstevel@tonic-gate V4ADDR_TO_6TO4_RT(&new_addr, &v6_rt); 378*7c478bd9Sstevel@tonic-gate modifyroute(RTM_ADD, &v6_rt); 379*7c478bd9Sstevel@tonic-gate } else if (new_addr.s_addr != current_addr.s_addr) { 380*7c478bd9Sstevel@tonic-gate setkrraddr(new_addr.s_addr); 381*7c478bd9Sstevel@tonic-gate /* remove old default IPv6 route */ 382*7c478bd9Sstevel@tonic-gate V4ADDR_TO_6TO4_RT(¤t_addr, &v6_rt); 383*7c478bd9Sstevel@tonic-gate modifyroute(RTM_DELETE, &v6_rt); 384*7c478bd9Sstevel@tonic-gate /* 385*7c478bd9Sstevel@tonic-gate * Add new default IPv6 route using a 6to4 address 386*7c478bd9Sstevel@tonic-gate * created from the address we just set in the kernel. 387*7c478bd9Sstevel@tonic-gate */ 388*7c478bd9Sstevel@tonic-gate V4ADDR_TO_6TO4_RT(&new_addr, &v6_rt); 389*7c478bd9Sstevel@tonic-gate modifyroute(RTM_ADD, &v6_rt); 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate /* 394*7c478bd9Sstevel@tonic-gate * Disable Relay Router communication support in kernel. 395*7c478bd9Sstevel@tonic-gate */ 396*7c478bd9Sstevel@tonic-gate if (dflag) { 397*7c478bd9Sstevel@tonic-gate struct in_addr current_addr; /* addr currently set in kernel */ 398*7c478bd9Sstevel@tonic-gate in6_addr_t v6_rt; 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate /* 401*7c478bd9Sstevel@tonic-gate * get Relay Router address from the kernel and delete 402*7c478bd9Sstevel@tonic-gate * default IPv6 route that was added for it. 403*7c478bd9Sstevel@tonic-gate */ 404*7c478bd9Sstevel@tonic-gate getkstatus(¤t_addr.s_addr); 405*7c478bd9Sstevel@tonic-gate if (current_addr.s_addr == INADDR_ANY) { 406*7c478bd9Sstevel@tonic-gate /* 407*7c478bd9Sstevel@tonic-gate * Feature is already disabled in kernel, no 408*7c478bd9Sstevel@tonic-gate * additional processing is needed. 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate goto done; 411*7c478bd9Sstevel@tonic-gate } 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate V4ADDR_TO_6TO4_RT(¤t_addr, &v6_rt); 414*7c478bd9Sstevel@tonic-gate modifyroute(RTM_DELETE, &v6_rt); 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate /* 417*7c478bd9Sstevel@tonic-gate * INADDR_ANY (0.0.0.0) is used by the kernel to disable Relay 418*7c478bd9Sstevel@tonic-gate * Router communication support. 419*7c478bd9Sstevel@tonic-gate */ 420*7c478bd9Sstevel@tonic-gate setkrraddr(INADDR_ANY); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate done: 423*7c478bd9Sstevel@tonic-gate (void) close(fd); 424*7c478bd9Sstevel@tonic-gate return (ret); 425*7c478bd9Sstevel@tonic-gate } 426