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 5*2b24ab6bSSebastien Roy * Common Development and Distribution License (the "License"). 6*2b24ab6bSSebastien Roy * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*2b24ab6bSSebastien Roy * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/socket.h> 277c478bd9Sstevel@tonic-gate #include <sys/stream.h> 287c478bd9Sstevel@tonic-gate #include <sys/param.h> 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <net/route.h> 317c478bd9Sstevel@tonic-gate #include <net/if.h> 327c478bd9Sstevel@tonic-gate #include <netinet/in.h> 337c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <locale.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include <unistd.h> 397c478bd9Sstevel@tonic-gate #include <stdio.h> 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <strings.h> 427c478bd9Sstevel@tonic-gate #include <string.h> 437c478bd9Sstevel@tonic-gate #include <stropts.h> 447c478bd9Sstevel@tonic-gate #include <fcntl.h> 45*2b24ab6bSSebastien Roy #include <libdliptun.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate static void usage(void); 487c478bd9Sstevel@tonic-gate 49*2b24ab6bSSebastien Roy static dladm_handle_t handle; 507c478bd9Sstevel@tonic-gate /* booleans corresponding to command line flags */ 517c478bd9Sstevel@tonic-gate static boolean_t eflag = B_FALSE; 527c478bd9Sstevel@tonic-gate static boolean_t dflag = B_FALSE; 537c478bd9Sstevel@tonic-gate static boolean_t aflag = B_FALSE; 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * printkstatus() 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * Queries the kernel for the current 6to4 Relay Router value, prints 607c478bd9Sstevel@tonic-gate * a status message based on the value and exits this command. 617c478bd9Sstevel@tonic-gate * INADDR_ANY is used to denote that Relay Router communication support is 627c478bd9Sstevel@tonic-gate * disabled within the kernel. 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate static void 657c478bd9Sstevel@tonic-gate printkstatus(void) 667c478bd9Sstevel@tonic-gate { 67*2b24ab6bSSebastien Roy struct in_addr rr_addr; 687c478bd9Sstevel@tonic-gate char buf[INET6_ADDRSTRLEN]; 69*2b24ab6bSSebastien Roy char errstr[DLADM_STRSIZE]; 70*2b24ab6bSSebastien Roy dladm_status_t status; 717c478bd9Sstevel@tonic-gate 72*2b24ab6bSSebastien Roy status = dladm_iptun_get6to4relay(handle, &rr_addr); 73*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) { 74*2b24ab6bSSebastien Roy (void) fprintf(stderr, gettext("6to4relay: unable to get " 75*2b24ab6bSSebastien Roy "6to4 relay status: %s\n"), 76*2b24ab6bSSebastien Roy dladm_status2str(status, errstr)); 77*2b24ab6bSSebastien Roy return; 78*2b24ab6bSSebastien Roy } 797c478bd9Sstevel@tonic-gate (void) printf("6to4relay: "); 80*2b24ab6bSSebastien Roy if (rr_addr.s_addr == INADDR_ANY) { 817c478bd9Sstevel@tonic-gate (void) printf(gettext("6to4 Relay Router communication " 827c478bd9Sstevel@tonic-gate "support is disabled.\n")); 837c478bd9Sstevel@tonic-gate } else { 847c478bd9Sstevel@tonic-gate (void) printf(gettext("6to4 Relay Router communication " 857c478bd9Sstevel@tonic-gate "support is enabled.\n")); 867c478bd9Sstevel@tonic-gate (void) printf(gettext("IPv4 destination address of Relay " 877c478bd9Sstevel@tonic-gate "Router = ")); 887c478bd9Sstevel@tonic-gate (void) printf("%s\n", 897c478bd9Sstevel@tonic-gate inet_ntop(AF_INET, &rr_addr, buf, sizeof (buf))); 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate } 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate * modifyroute(cmd, in_gw) 957c478bd9Sstevel@tonic-gate * 967c478bd9Sstevel@tonic-gate * Modifies a default IPv6 route with DST = ::, GATEWAY = in_gw, NETMASK = :: 977c478bd9Sstevel@tonic-gate * and flags = <GATEWAY, STATIC>. 987c478bd9Sstevel@tonic-gate * This route is to be propagated through the 6to4 site so that 6to4 hosts 997c478bd9Sstevel@tonic-gate * can send packets to native IPv6 hosts behind a remote 6to4 Relay Router. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate static void 1027c478bd9Sstevel@tonic-gate modifyroute(unsigned int cmd, in6_addr_t *in_gw) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate static int rtmseq; 1057c478bd9Sstevel@tonic-gate int rtsock; 1067c478bd9Sstevel@tonic-gate int rlen; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static struct { 1097c478bd9Sstevel@tonic-gate struct rt_msghdr rt_hdr; 1107c478bd9Sstevel@tonic-gate struct sockaddr_in6 rt_dst; 1117c478bd9Sstevel@tonic-gate struct sockaddr_in6 rt_gate; 1127c478bd9Sstevel@tonic-gate struct sockaddr_in6 rt_mask; 1137c478bd9Sstevel@tonic-gate } rt_msg; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate /* Open a routing socket for passing route commands */ 1167c478bd9Sstevel@tonic-gate if ((rtsock = socket(AF_ROUTE, SOCK_RAW, AF_INET)) < 0) { 117*2b24ab6bSSebastien Roy (void) fprintf(stderr, gettext("6to4relay: unable to modify " 118*2b24ab6bSSebastien Roy "default IPv6 route: socket: %s\n"), strerror(errno)); 119*2b24ab6bSSebastien Roy return; 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate (void) memset(&rt_msg, 0, sizeof (rt_msg)); 1237c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_msglen = sizeof (rt_msg); 1247c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_version = RTM_VERSION; 1257c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; 1267c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_pid = getpid(); 1277c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_type = cmd; 1287c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_seq = ++rtmseq; 1297c478bd9Sstevel@tonic-gate rt_msg.rt_hdr.rtm_flags = RTF_STATIC | RTF_GATEWAY; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate /* DST */ 1327c478bd9Sstevel@tonic-gate rt_msg.rt_dst.sin6_family = AF_INET6; 1337c478bd9Sstevel@tonic-gate (void) memset(&rt_msg.rt_dst.sin6_addr.s6_addr, 0, 1347c478bd9Sstevel@tonic-gate sizeof (in6_addr_t)); 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate /* GATEWAY */ 1377c478bd9Sstevel@tonic-gate rt_msg.rt_gate.sin6_family = AF_INET6; 1387c478bd9Sstevel@tonic-gate bcopy(in_gw->s6_addr, &rt_msg.rt_gate.sin6_addr.s6_addr, 1397c478bd9Sstevel@tonic-gate sizeof (in6_addr_t)); 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate /* NETMASK */ 1427c478bd9Sstevel@tonic-gate rt_msg.rt_mask.sin6_family = AF_INET6; 1437c478bd9Sstevel@tonic-gate (void) memset(&rt_msg.rt_mask.sin6_addr.s6_addr, 0, 1447c478bd9Sstevel@tonic-gate sizeof (in6_addr_t)); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate /* Send the routing message */ 1477c478bd9Sstevel@tonic-gate rlen = write(rtsock, &rt_msg, rt_msg.rt_hdr.rtm_msglen); 1487c478bd9Sstevel@tonic-gate if (rlen < rt_msg.rt_hdr.rtm_msglen) { 1497c478bd9Sstevel@tonic-gate if (rlen < 0) { 1507c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1517c478bd9Sstevel@tonic-gate gettext("6to4relay: write to routing socket: %s\n"), 1527c478bd9Sstevel@tonic-gate strerror(errno)); 1537c478bd9Sstevel@tonic-gate } else { 1547c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("6to4relay: write to " 1557c478bd9Sstevel@tonic-gate "routing socket got only %d for rlen\n"), rlen); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate (void) close(rtsock); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate static void 1627c478bd9Sstevel@tonic-gate usage(void) 1637c478bd9Sstevel@tonic-gate { 1647c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 1657c478bd9Sstevel@tonic-gate gettext("usage:\n" 1667c478bd9Sstevel@tonic-gate "\t6to4relay\n" 1677c478bd9Sstevel@tonic-gate "\t6to4relay -e [-a <addr>]\n" 1687c478bd9Sstevel@tonic-gate "\t6to4relay -d\n" 1697c478bd9Sstevel@tonic-gate "\t6to4relay -h\n")); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate int 1737c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate int ch; 176*2b24ab6bSSebastien Roy char *relay_arg = NULL; 177*2b24ab6bSSebastien Roy dladm_status_t status; 178*2b24ab6bSSebastien Roy char errstr[DLADM_STRSIZE]; 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 1837c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 1847c478bd9Sstevel@tonic-gate #endif 1857c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1867c478bd9Sstevel@tonic-gate 187*2b24ab6bSSebastien Roy if ((status = dladm_open(&handle)) != DLADM_STATUS_OK) { 188*2b24ab6bSSebastien Roy (void) fprintf(stderr, gettext("6to4relay: error opening " 189*2b24ab6bSSebastien Roy "dladm handle: %s\n"), dladm_status2str(status, errstr)); 190*2b24ab6bSSebastien Roy return (EXIT_FAILURE); 1917c478bd9Sstevel@tonic-gate } 1927c478bd9Sstevel@tonic-gate 193*2b24ab6bSSebastien Roy /* If no args are specified, print the current status. */ 1947c478bd9Sstevel@tonic-gate if (argc < 2) { 1957c478bd9Sstevel@tonic-gate printkstatus(); 196*2b24ab6bSSebastien Roy return (EXIT_SUCCESS); 1977c478bd9Sstevel@tonic-gate } 198*2b24ab6bSSebastien Roy 1997c478bd9Sstevel@tonic-gate while ((ch = getopt(argc, argv, "ea:dh")) != EOF) { 2007c478bd9Sstevel@tonic-gate switch (ch) { 2017c478bd9Sstevel@tonic-gate case 'e': 2027c478bd9Sstevel@tonic-gate eflag = B_TRUE; 2037c478bd9Sstevel@tonic-gate break; 2047c478bd9Sstevel@tonic-gate case 'd': 2057c478bd9Sstevel@tonic-gate dflag = B_TRUE; 2067c478bd9Sstevel@tonic-gate break; 2077c478bd9Sstevel@tonic-gate case 'a': 2087c478bd9Sstevel@tonic-gate aflag = B_TRUE; 209*2b24ab6bSSebastien Roy relay_arg = optarg; 2107c478bd9Sstevel@tonic-gate break; 2117c478bd9Sstevel@tonic-gate case 'h': 2127c478bd9Sstevel@tonic-gate usage(); 213*2b24ab6bSSebastien Roy return (EXIT_SUCCESS); 2147c478bd9Sstevel@tonic-gate default: 2157c478bd9Sstevel@tonic-gate usage(); 216*2b24ab6bSSebastien Roy return (EXIT_FAILURE); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * If -a is specified, -e must also be specified. Also, the 2217c478bd9Sstevel@tonic-gate * combination of -e and -d is illegal. Fail on either case. 2227c478bd9Sstevel@tonic-gate */ 2237c478bd9Sstevel@tonic-gate if ((aflag && !eflag) || (eflag && dflag)) { 2247c478bd9Sstevel@tonic-gate usage(); 225*2b24ab6bSSebastien Roy return (EXIT_FAILURE); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * Enable Relay Router communication support in the kernel. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate if (eflag) { 232*2b24ab6bSSebastien Roy struct in_addr current_addr; 233*2b24ab6bSSebastien Roy struct in_addr new_addr; 2347c478bd9Sstevel@tonic-gate in6_addr_t v6_rt; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate /* 2377c478bd9Sstevel@tonic-gate * if -a was not specified, the well-known anycast will 2387c478bd9Sstevel@tonic-gate * be used. 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate if (!aflag) { 2417c478bd9Sstevel@tonic-gate new_addr.s_addr = htonl(INADDR_6TO4RRANYCAST); 242*2b24ab6bSSebastien Roy } else if (inet_pton(AF_INET, relay_arg, &new_addr) <= 0) { 2437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("6to4relay: input " 2447c478bd9Sstevel@tonic-gate "address (%s) is not a valid IPv4 dotted-decimal " 245*2b24ab6bSSebastien Roy "string.\n"), relay_arg); 246*2b24ab6bSSebastien Roy return (EXIT_FAILURE); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 249*2b24ab6bSSebastien Roy status = dladm_iptun_get6to4relay(handle, ¤t_addr); 250*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) { 251*2b24ab6bSSebastien Roy (void) fprintf(stderr, gettext("6to4relay: " 252*2b24ab6bSSebastien Roy "unable to obtain current 6to4 relay address: %s"), 253*2b24ab6bSSebastien Roy dladm_status2str(status, errstr)); 254*2b24ab6bSSebastien Roy return (EXIT_FAILURE); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 257*2b24ab6bSSebastien Roy if (current_addr.s_addr == new_addr.s_addr) 258*2b24ab6bSSebastien Roy return (EXIT_SUCCESS); 2597c478bd9Sstevel@tonic-gate 260*2b24ab6bSSebastien Roy status = dladm_iptun_set6to4relay(handle, &new_addr); 261*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) { 262*2b24ab6bSSebastien Roy (void) fprintf(stderr, gettext("6to4relay: " 263*2b24ab6bSSebastien Roy "unable to set the 6to4 relay router address: " 264*2b24ab6bSSebastien Roy "%s\n"), dladm_status2str(status, errstr)); 265*2b24ab6bSSebastien Roy return (EXIT_FAILURE); 266*2b24ab6bSSebastien Roy } 267*2b24ab6bSSebastien Roy 268*2b24ab6bSSebastien Roy if (current_addr.s_addr != INADDR_ANY) { 2697c478bd9Sstevel@tonic-gate /* remove old default IPv6 route */ 270*2b24ab6bSSebastien Roy IN6_V4ADDR_TO_6TO4(¤t_addr, &v6_rt); 2717c478bd9Sstevel@tonic-gate modifyroute(RTM_DELETE, &v6_rt); 2727c478bd9Sstevel@tonic-gate } 273*2b24ab6bSSebastien Roy 274*2b24ab6bSSebastien Roy IN6_V4ADDR_TO_6TO4(&new_addr, &v6_rt); 275*2b24ab6bSSebastien Roy modifyroute(RTM_ADD, &v6_rt); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* 2797c478bd9Sstevel@tonic-gate * Disable Relay Router communication support in kernel. 2807c478bd9Sstevel@tonic-gate */ 2817c478bd9Sstevel@tonic-gate if (dflag) { 282*2b24ab6bSSebastien Roy struct in_addr rr_addr; 2837c478bd9Sstevel@tonic-gate in6_addr_t v6_rt; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate /* 2867c478bd9Sstevel@tonic-gate * get Relay Router address from the kernel and delete 2877c478bd9Sstevel@tonic-gate * default IPv6 route that was added for it. 2887c478bd9Sstevel@tonic-gate */ 289*2b24ab6bSSebastien Roy status = dladm_iptun_get6to4relay(handle, &rr_addr); 290*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) { 291*2b24ab6bSSebastien Roy (void) fprintf(stderr, gettext("6to4relay: " 292*2b24ab6bSSebastien Roy "unable to obtain current 6to4 relay address: %s"), 293*2b24ab6bSSebastien Roy dladm_status2str(status, errstr)); 294*2b24ab6bSSebastien Roy return (EXIT_FAILURE); 2957c478bd9Sstevel@tonic-gate } 296*2b24ab6bSSebastien Roy if (rr_addr.s_addr == INADDR_ANY) 297*2b24ab6bSSebastien Roy return (EXIT_SUCCESS); 2987c478bd9Sstevel@tonic-gate 299*2b24ab6bSSebastien Roy IN6_V4ADDR_TO_6TO4(&rr_addr, &v6_rt); 3007c478bd9Sstevel@tonic-gate modifyroute(RTM_DELETE, &v6_rt); 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* 3037c478bd9Sstevel@tonic-gate * INADDR_ANY (0.0.0.0) is used by the kernel to disable Relay 3047c478bd9Sstevel@tonic-gate * Router communication support. 3057c478bd9Sstevel@tonic-gate */ 306*2b24ab6bSSebastien Roy rr_addr.s_addr = INADDR_ANY; 307*2b24ab6bSSebastien Roy status = dladm_iptun_set6to4relay(handle, &rr_addr); 308*2b24ab6bSSebastien Roy if (status != DLADM_STATUS_OK) { 309*2b24ab6bSSebastien Roy (void) fprintf(stderr, gettext("6to4relay: " 310*2b24ab6bSSebastien Roy "unable to disable tunneling to 6to4 relay router: " 311*2b24ab6bSSebastien Roy "%s\n"), dladm_status2str(status, errstr)); 312*2b24ab6bSSebastien Roy return (EXIT_FAILURE); 3137c478bd9Sstevel@tonic-gate } 314*2b24ab6bSSebastien Roy } 315*2b24ab6bSSebastien Roy 316*2b24ab6bSSebastien Roy return (EXIT_SUCCESS); 3177c478bd9Sstevel@tonic-gate } 318