4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/socket.h>
27 #include <sys/stream.h>
28 #include <sys/param.h>
30 #include <net/route.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
45 #include <libdliptun.h>
47 /* Well known 6to4 Relay Router Anycast address defined in RFC 3068 */
48 #define INADDR_6TO4RRANYCAST 0xc0586301U /* 192.88.99.1 */
50 static void usage(void);
52 static dladm_handle_t handle
;
53 /* booleans corresponding to command line flags */
54 static boolean_t eflag
= B_FALSE
;
55 static boolean_t dflag
= B_FALSE
;
56 static boolean_t aflag
= B_FALSE
;
62 * Queries the kernel for the current 6to4 Relay Router value, prints
63 * a status message based on the value and exits this command.
64 * INADDR_ANY is used to denote that Relay Router communication support is
65 * disabled within the kernel.
70 struct in_addr rr_addr
;
71 char buf
[INET6_ADDRSTRLEN
];
72 char errstr
[DLADM_STRSIZE
];
73 dladm_status_t status
;
75 status
= dladm_iptun_get6to4relay(handle
, &rr_addr
);
76 if (status
!= DLADM_STATUS_OK
) {
77 (void) fprintf(stderr
, gettext("6to4relay: unable to get "
78 "6to4 relay status: %s\n"),
79 dladm_status2str(status
, errstr
));
82 (void) printf("6to4relay: ");
83 if (rr_addr
.s_addr
== INADDR_ANY
) {
84 (void) printf(gettext("6to4 Relay Router communication "
85 "support is disabled.\n"));
87 (void) printf(gettext("6to4 Relay Router communication "
88 "support is enabled.\n"));
89 (void) printf(gettext("IPv4 destination address of Relay "
92 inet_ntop(AF_INET
, &rr_addr
, buf
, sizeof (buf
)));
97 * modifyroute(cmd, in_gw)
99 * Modifies a default IPv6 route with DST = ::, GATEWAY = in_gw, NETMASK = ::
100 * and flags = <GATEWAY, STATIC>.
101 * This route is to be propagated through the 6to4 site so that 6to4 hosts
102 * can send packets to native IPv6 hosts behind a remote 6to4 Relay Router.
105 modifyroute(unsigned int cmd
, in6_addr_t
*in_gw
)
112 struct rt_msghdr rt_hdr
;
113 struct sockaddr_in6 rt_dst
;
114 struct sockaddr_in6 rt_gate
;
115 struct sockaddr_in6 rt_mask
;
118 /* Open a routing socket for passing route commands */
119 if ((rtsock
= socket(AF_ROUTE
, SOCK_RAW
, AF_INET
)) < 0) {
120 (void) fprintf(stderr
, gettext("6to4relay: unable to modify "
121 "default IPv6 route: socket: %s\n"), strerror(errno
));
125 (void) memset(&rt_msg
, 0, sizeof (rt_msg
));
126 rt_msg
.rt_hdr
.rtm_msglen
= sizeof (rt_msg
);
127 rt_msg
.rt_hdr
.rtm_version
= RTM_VERSION
;
128 rt_msg
.rt_hdr
.rtm_addrs
= RTA_DST
| RTA_GATEWAY
| RTA_NETMASK
;
129 rt_msg
.rt_hdr
.rtm_pid
= getpid();
130 rt_msg
.rt_hdr
.rtm_type
= cmd
;
131 rt_msg
.rt_hdr
.rtm_seq
= ++rtmseq
;
132 rt_msg
.rt_hdr
.rtm_flags
= RTF_STATIC
| RTF_GATEWAY
;
135 rt_msg
.rt_dst
.sin6_family
= AF_INET6
;
136 (void) memset(&rt_msg
.rt_dst
.sin6_addr
.s6_addr
, 0,
137 sizeof (in6_addr_t
));
140 rt_msg
.rt_gate
.sin6_family
= AF_INET6
;
141 bcopy(in_gw
->s6_addr
, &rt_msg
.rt_gate
.sin6_addr
.s6_addr
,
142 sizeof (in6_addr_t
));
145 rt_msg
.rt_mask
.sin6_family
= AF_INET6
;
146 (void) memset(&rt_msg
.rt_mask
.sin6_addr
.s6_addr
, 0,
147 sizeof (in6_addr_t
));
149 /* Send the routing message */
150 rlen
= write(rtsock
, &rt_msg
, rt_msg
.rt_hdr
.rtm_msglen
);
151 if (rlen
< rt_msg
.rt_hdr
.rtm_msglen
) {
153 (void) fprintf(stderr
,
154 gettext("6to4relay: write to routing socket: %s\n"),
157 (void) fprintf(stderr
, gettext("6to4relay: write to "
158 "routing socket got only %d for rlen\n"), rlen
);
161 (void) close(rtsock
);
167 (void) fprintf(stderr
,
170 "\t6to4relay -e [-a <addr>]\n"
172 "\t6to4relay -h\n"));
176 main(int argc
, char **argv
)
179 char *relay_arg
= NULL
;
180 dladm_status_t status
;
181 char errstr
[DLADM_STRSIZE
];
183 (void) setlocale(LC_ALL
, "");
185 #if !defined(TEXT_DOMAIN)
186 #define TEXT_DOMAIN "SYS_TEST"
188 (void) textdomain(TEXT_DOMAIN
);
190 if ((status
= dladm_open(&handle
)) != DLADM_STATUS_OK
) {
191 (void) fprintf(stderr
, gettext("6to4relay: error opening "
192 "dladm handle: %s\n"), dladm_status2str(status
, errstr
));
193 return (EXIT_FAILURE
);
196 /* If no args are specified, print the current status. */
199 return (EXIT_SUCCESS
);
202 while ((ch
= getopt(argc
, argv
, "ea:dh")) != EOF
) {
216 return (EXIT_SUCCESS
);
219 return (EXIT_FAILURE
);
223 * If -a is specified, -e must also be specified. Also, the
224 * combination of -e and -d is illegal. Fail on either case.
226 if ((aflag
&& !eflag
) || (eflag
&& dflag
)) {
228 return (EXIT_FAILURE
);
232 * Enable Relay Router communication support in the kernel.
235 struct in_addr current_addr
;
236 struct in_addr new_addr
;
240 * if -a was not specified, the well-known anycast will
244 new_addr
.s_addr
= htonl(INADDR_6TO4RRANYCAST
);
245 } else if (inet_pton(AF_INET
, relay_arg
, &new_addr
) <= 0) {
246 (void) fprintf(stderr
, gettext("6to4relay: input "
247 "address (%s) is not a valid IPv4 dotted-decimal "
248 "string.\n"), relay_arg
);
249 return (EXIT_FAILURE
);
252 status
= dladm_iptun_get6to4relay(handle
, ¤t_addr
);
253 if (status
!= DLADM_STATUS_OK
) {
254 (void) fprintf(stderr
, gettext("6to4relay: "
255 "unable to obtain current 6to4 relay address: %s"),
256 dladm_status2str(status
, errstr
));
257 return (EXIT_FAILURE
);
260 if (current_addr
.s_addr
== new_addr
.s_addr
)
261 return (EXIT_SUCCESS
);
263 status
= dladm_iptun_set6to4relay(handle
, &new_addr
);
264 if (status
!= DLADM_STATUS_OK
) {
265 (void) fprintf(stderr
, gettext("6to4relay: "
266 "unable to set the 6to4 relay router address: "
267 "%s\n"), dladm_status2str(status
, errstr
));
268 return (EXIT_FAILURE
);
271 if (current_addr
.s_addr
!= INADDR_ANY
) {
272 /* remove old default IPv6 route */
273 IN6_V4ADDR_TO_6TO4(¤t_addr
, &v6_rt
);
274 modifyroute(RTM_DELETE
, &v6_rt
);
277 IN6_V4ADDR_TO_6TO4(&new_addr
, &v6_rt
);
278 modifyroute(RTM_ADD
, &v6_rt
);
282 * Disable Relay Router communication support in kernel.
285 struct in_addr rr_addr
;
289 * get Relay Router address from the kernel and delete
290 * default IPv6 route that was added for it.
292 status
= dladm_iptun_get6to4relay(handle
, &rr_addr
);
293 if (status
!= DLADM_STATUS_OK
) {
294 (void) fprintf(stderr
, gettext("6to4relay: "
295 "unable to obtain current 6to4 relay address: %s"),
296 dladm_status2str(status
, errstr
));
297 return (EXIT_FAILURE
);
299 if (rr_addr
.s_addr
== INADDR_ANY
)
300 return (EXIT_SUCCESS
);
302 IN6_V4ADDR_TO_6TO4(&rr_addr
, &v6_rt
);
303 modifyroute(RTM_DELETE
, &v6_rt
);
306 * INADDR_ANY (0.0.0.0) is used by the kernel to disable Relay
307 * Router communication support.
309 rr_addr
.s_addr
= INADDR_ANY
;
310 status
= dladm_iptun_set6to4relay(handle
, &rr_addr
);
311 if (status
!= DLADM_STATUS_OK
) {
312 (void) fprintf(stderr
, gettext("6to4relay: "
313 "unable to disable tunneling to 6to4 relay router: "
314 "%s\n"), dladm_status2str(status
, errstr
));
315 return (EXIT_FAILURE
);
319 return (EXIT_SUCCESS
);