1/* $NetBSD: tunnel.c,v 1.16 2008/07/15 21:27:58 dyoung 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.16 2008/07/15 21:27:58 dyoung 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 61static status_func_t status; 62static usage_func_t usage; 63static cmdloop_branch_t branch; 64 65static void tunnel_constructor(void) __attribute__((constructor)); 66static int settunnel(prop_dictionary_t, prop_dictionary_t); 67static int deletetunnel(prop_dictionary_t, prop_dictionary_t); 68static void tunnel_status(prop_dictionary_t, prop_dictionary_t); 69 70struct paddr tundst = PADDR_INITIALIZER(&tundst, "tundst", settunnel, 71 "tundst", NULL, NULL, NULL, &command_root.pb_parser); 72 73struct paddr tunsrc = PADDR_INITIALIZER(&tunsrc, "tunsrc", NULL, 74 "tunsrc", NULL, NULL, NULL, &tundst.pa_parser); 75 76static 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 82struct pkw tunnel = PKW_INITIALIZER(&tunnel, "tunnel", NULL, NULL, 83 tunnelkw, __arraycount(tunnelkw), NULL); 84 85static int 86settunnel(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 if (s6->sin6_scope_id && 129 IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr)) { 130 *(u_int16_t *)&s6->sin6_addr.s6_addr[2] = 131 htons(s6->sin6_scope_id); 132 } 133 if (d->sin6_scope_id && IN6_IS_ADDR_LINKLOCAL(&d->sin6_addr)) { 134 *(u_int16_t *)&d->sin6_addr.s6_addr[2] = 135 htons(d->sin6_scope_id); 136 } 137 } 138#endif /* INET6 */ 139 140 if (direct_ioctl(env, SIOCSLIFPHYADDR, &req) == -1) 141 warn("SIOCSLIFPHYADDR"); 142 return 0; 143} 144 145static int 146deletetunnel(prop_dictionary_t env, prop_dictionary_t oenv) 147{ 148 if (indirect_ioctl(env, SIOCDIFPHYADDR, NULL) == -1) 149 err(EXIT_FAILURE, "SIOCDIFPHYADDR"); 150 return 0; 151} 152 153static void 154tunnel_status(prop_dictionary_t env, prop_dictionary_t oenv) 155{ 156 char dstserv[sizeof(",65535")]; 157 char srcserv[sizeof(",65535")]; 158 char psrcaddr[NI_MAXHOST]; 159 char pdstaddr[NI_MAXHOST]; 160 const int niflag = Nflag ? 0 : (NI_NUMERICHOST|NI_NUMERICSERV); 161 struct if_laddrreq req; 162 const struct afswtch *afp; 163 164 psrcaddr[0] = pdstaddr[0] = '\0'; 165 166 memset(&req, 0, sizeof(req)); 167 if (direct_ioctl(env, SIOCGLIFPHYADDR, &req) == -1) 168 return; 169 afp = lookup_af_bynum(req.addr.ss_family); 170#ifdef INET6 171 if (req.addr.ss_family == AF_INET6) 172 in6_fillscopeid((struct sockaddr_in6 *)&req.addr); 173#endif /* INET6 */ 174 getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len, 175 psrcaddr, sizeof(psrcaddr), &srcserv[1], sizeof(srcserv) - 1, 176 niflag); 177 178#ifdef INET6 179 if (req.dstaddr.ss_family == AF_INET6) 180 in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr); 181#endif 182 getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len, 183 pdstaddr, sizeof(pdstaddr), &dstserv[1], sizeof(dstserv) - 1, 184 niflag); 185 186 srcserv[0] = (strcmp(&srcserv[1], "0") == 0) ? '\0' : ','; 187 dstserv[0] = (strcmp(&dstserv[1], "0") == 0) ? '\0' : ','; 188 189 printf("\ttunnel %s %s%s --> %s%s\n", afp ? afp->af_name : "???", 190 psrcaddr, srcserv, pdstaddr, dstserv); 191} 192 193static void 194tunnel_usage(prop_dictionary_t env) 195{ 196 fprintf(stderr, 197 "\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"); 198} 199 200static void 201tunnel_constructor(void) 202{ 203 cmdloop_branch_init(&branch, &tunnel.pk_parser); 204 register_cmdloop_branch(&branch); 205 status_func_init(&status, tunnel_status); 206 usage_func_init(&usage, tunnel_usage); 207 register_status(&status); 208 register_usage(&usage); 209} 210