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
printkstatus(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
modifyroute(unsigned int cmd,in6_addr_t * in_gw)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
usage(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
main(int argc,char ** argv)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