xref: /titanic_50/usr/src/cmd/cmd-inet/usr.sbin/6to4relay.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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(&current_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(&current_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(&current_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(&current_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