1 /* $NetBSD: tunnel.c,v 1.20 2013/10/19 15:59:15 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: tunnel.c,v 1.20 2013/10/19 15:59:15 christos Exp $"); 35 #endif /* not lint */ 36 37 #include <sys/param.h> 38 #include <sys/ioctl.h> 39 #include <sys/socket.h> 40 41 #include <net/if.h> 42 43 #ifdef INET6 44 #include <netinet/in.h> 45 #endif 46 47 #include <ctype.h> 48 #include <err.h> 49 #include <errno.h> 50 #include <netdb.h> 51 #include <string.h> 52 #include <stdlib.h> 53 #include <stdio.h> 54 #include <util.h> 55 56 #include "env.h" 57 #include "extern.h" 58 #include "parse.h" 59 #include "util.h" 60 61 static status_func_t status; 62 static usage_func_t usage; 63 static cmdloop_branch_t branch; 64 65 static void tunnel_constructor(void) __attribute__((constructor)); 66 static int settunnel(prop_dictionary_t, prop_dictionary_t); 67 static int deletetunnel(prop_dictionary_t, prop_dictionary_t); 68 static void tunnel_status(prop_dictionary_t, prop_dictionary_t); 69 70 struct paddr tundst = PADDR_INITIALIZER(&tundst, "tundst", settunnel, 71 "tundst", NULL, NULL, NULL, &command_root.pb_parser); 72 73 struct paddr tunsrc = PADDR_INITIALIZER(&tunsrc, "tunsrc", NULL, 74 "tunsrc", NULL, NULL, NULL, &tundst.pa_parser); 75 76 static const struct kwinst tunnelkw[] = { 77 {.k_word = "deletetunnel", .k_exec = deletetunnel, 78 .k_nextparser = &command_root.pb_parser} 79 , {.k_word = "tunnel", .k_nextparser = &tunsrc.pa_parser} 80 }; 81 82 struct pkw tunnel = PKW_INITIALIZER(&tunnel, "tunnel", NULL, NULL, 83 tunnelkw, __arraycount(tunnelkw), NULL); 84 85 static int 86 settunnel(prop_dictionary_t env, prop_dictionary_t oenv) 87 { 88 const struct paddr_prefix *srcpfx, *dstpfx; 89 struct if_laddrreq req; 90 prop_data_t srcdata, dstdata; 91 92 srcdata = (prop_data_t)prop_dictionary_get(env, "tunsrc"); 93 dstdata = (prop_data_t)prop_dictionary_get(env, "tundst"); 94 95 if (srcdata == NULL || dstdata == NULL) { 96 warnx("%s.%d", __func__, __LINE__); 97 errno = ENOENT; 98 return -1; 99 } 100 101 srcpfx = prop_data_data_nocopy(srcdata); 102 dstpfx = prop_data_data_nocopy(dstdata); 103 104 if (srcpfx->pfx_addr.sa_family != dstpfx->pfx_addr.sa_family) 105 errx(EXIT_FAILURE, 106 "source and destination address families do not match"); 107 108 memset(&req, 0, sizeof(req)); 109 memcpy(&req.addr, &srcpfx->pfx_addr, 110 MIN(sizeof(req.addr), srcpfx->pfx_addr.sa_len)); 111 memcpy(&req.dstaddr, &dstpfx->pfx_addr, 112 MIN(sizeof(req.dstaddr), dstpfx->pfx_addr.sa_len)); 113 114 #ifdef INET6 115 if (req.addr.ss_family == AF_INET6) { 116 struct sockaddr_in6 *s6, *d; 117 118 s6 = (struct sockaddr_in6 *)&req.addr; 119 d = (struct sockaddr_in6 *)&req.dstaddr; 120 if (s6->sin6_scope_id != d->sin6_scope_id) { 121 errx(EXIT_FAILURE, "scope mismatch"); 122 /* NOTREACHED */ 123 } 124 if (IN6_IS_ADDR_MULTICAST(&d->sin6_addr) || 125 IN6_IS_ADDR_MULTICAST(&s6->sin6_addr)) 126 errx(EXIT_FAILURE, "tunnel src/dst is multicast"); 127 /* embed scopeid */ 128 inet6_putscopeid(s6, INET6_IS_ADDR_LINKLOCAL); 129 inet6_putscopeid(d, INET6_IS_ADDR_LINKLOCAL); 130 } 131 #endif /* INET6 */ 132 133 if (direct_ioctl(env, SIOCSLIFPHYADDR, &req) == -1) 134 warn("SIOCSLIFPHYADDR"); 135 return 0; 136 } 137 138 static int 139 deletetunnel(prop_dictionary_t env, prop_dictionary_t oenv) 140 { 141 if (indirect_ioctl(env, SIOCDIFPHYADDR, NULL) == -1) 142 err(EXIT_FAILURE, "SIOCDIFPHYADDR"); 143 return 0; 144 } 145 146 static void 147 tunnel_status(prop_dictionary_t env, prop_dictionary_t oenv) 148 { 149 char dstserv[sizeof(",65535")]; 150 char srcserv[sizeof(",65535")]; 151 char psrcaddr[NI_MAXHOST]; 152 char pdstaddr[NI_MAXHOST]; 153 const int niflag = Nflag ? 0 : (NI_NUMERICHOST|NI_NUMERICSERV); 154 struct if_laddrreq req; 155 const struct afswtch *afp; 156 157 psrcaddr[0] = pdstaddr[0] = '\0'; 158 159 memset(&req, 0, sizeof(req)); 160 if (direct_ioctl(env, SIOCGLIFPHYADDR, &req) == -1) 161 return; 162 afp = lookup_af_bynum(req.addr.ss_family); 163 #ifdef INET6 164 if (req.addr.ss_family == AF_INET6) 165 inet6_getscopeid((struct sockaddr_in6 *)&req.addr, 166 INET6_IS_ADDR_LINKLOCAL); 167 #endif /* INET6 */ 168 getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len, 169 psrcaddr, sizeof(psrcaddr), &srcserv[1], sizeof(srcserv) - 1, 170 niflag); 171 172 #ifdef INET6 173 if (req.dstaddr.ss_family == AF_INET6) 174 inet6_getscopeid((struct sockaddr_in6 *)&req.dstaddr, 175 INET6_IS_ADDR_LINKLOCAL); 176 #endif 177 getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len, 178 pdstaddr, sizeof(pdstaddr), &dstserv[1], sizeof(dstserv) - 1, 179 niflag); 180 181 srcserv[0] = (strcmp(&srcserv[1], "0") == 0) ? '\0' : ','; 182 dstserv[0] = (strcmp(&dstserv[1], "0") == 0) ? '\0' : ','; 183 184 printf("\ttunnel %s %s%s --> %s%s\n", afp ? afp->af_name : "???", 185 psrcaddr, srcserv, pdstaddr, dstserv); 186 } 187 188 static void 189 tunnel_usage(prop_dictionary_t env) 190 { 191 fprintf(stderr, 192 "\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"); 193 } 194 195 static void 196 tunnel_constructor(void) 197 { 198 cmdloop_branch_init(&branch, &tunnel.pk_parser); 199 register_cmdloop_branch(&branch); 200 status_func_init(&status, tunnel_status); 201 usage_func_init(&usage, tunnel_usage); 202 register_status(&status); 203 register_usage(&usage); 204 } 205