1/* $NetBSD: tunnel.c,v 1.22 2020/06/07 06:02:58 thorpej 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.22 2020/06/07 06:02:58 thorpej 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_value(srcdata); 102 dstpfx = prop_data_value(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 138static int 139deletetunnel(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 146static void 147tunnel_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 188static void 189tunnel_usage(prop_dictionary_t env) 190{ 191 fprintf(stderr, 192 "\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"); 193} 194 195static void 196tunnel_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