1 /* $NetBSD: tunnel.c,v 1.9 2007/03/26 05:02:44 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.9 2007/03/26 05:02:44 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 <netdb.h> 50 #include <string.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 #include <util.h> 54 55 #include "extern.h" 56 #include "tunnel.h" 57 58 #ifdef INET6 59 #include "af_inet6.h" 60 #endif 61 62 void 63 settunnel(const char *src0, const char *dst0) 64 { 65 struct addrinfo hints, *srcres, *dstres; 66 char *dst, *dstport, *src, *srcport; 67 int ecode; 68 struct if_laddrreq req; 69 70 memset(&hints, 0, sizeof(hints)); 71 hints.ai_family = afp->af_af; 72 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 73 74 if ((src = strdup(src0)) == NULL) 75 err(EXIT_FAILURE, "%s: strdup", __func__); 76 if ((dst = strdup(dst0)) == NULL) 77 err(EXIT_FAILURE, "%s: strdup", __func__); 78 79 srcport = src; 80 (void)strsep(&srcport, ","); 81 dstport = dst; 82 (void)strsep(&dstport, ","); 83 84 if ((ecode = getaddrinfo(src, srcport, &hints, &srcres)) != 0) 85 errx(EXIT_FAILURE, "error in parsing address string: %s", 86 gai_strerror(ecode)); 87 88 if ((ecode = getaddrinfo(dst, dstport, &hints, &dstres)) != 0) 89 errx(EXIT_FAILURE, "error in parsing address string: %s", 90 gai_strerror(ecode)); 91 92 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) 93 errx(EXIT_FAILURE, 94 "source and destination address families do not match"); 95 96 if (srcres->ai_addrlen > sizeof(req.addr) || 97 dstres->ai_addrlen > sizeof(req.dstaddr)) 98 errx(EXIT_FAILURE, "invalid sockaddr"); 99 100 memset(&req, 0, sizeof(req)); 101 estrlcpy(req.iflr_name, name, sizeof(req.iflr_name)); 102 memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen); 103 memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen); 104 105 #ifdef INET6 106 if (req.addr.ss_family == AF_INET6) { 107 struct sockaddr_in6 *s6, *d; 108 109 s6 = (struct sockaddr_in6 *)&req.addr; 110 d = (struct sockaddr_in6 *)&req.dstaddr; 111 if (s6->sin6_scope_id != d->sin6_scope_id) { 112 errx(EXIT_FAILURE, "scope mismatch"); 113 /* NOTREACHED */ 114 } 115 #ifdef __KAME__ 116 /* embed scopeid */ 117 if (s6->sin6_scope_id && 118 (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) || 119 IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr))) { 120 *(u_int16_t *)&s6->sin6_addr.s6_addr[2] = 121 htons(s6->sin6_scope_id); 122 } 123 if (d->sin6_scope_id && 124 (IN6_IS_ADDR_LINKLOCAL(&d->sin6_addr) || 125 IN6_IS_ADDR_MC_LINKLOCAL(&d->sin6_addr))) { 126 *(u_int16_t *)&d->sin6_addr.s6_addr[2] = 127 htons(d->sin6_scope_id); 128 } 129 #endif /* __KAME__ */ 130 } 131 #endif /* INET6 */ 132 133 if (ioctl(s, SIOCSLIFPHYADDR, &req) == -1) 134 warn("SIOCSLIFPHYADDR"); 135 136 freeaddrinfo(srcres); 137 freeaddrinfo(dstres); 138 free(src); 139 free(dst); 140 } 141 142 /*ARGSUSED*/ 143 void 144 deletetunnel(const char *ifname, int param) 145 { 146 147 if (ioctl(s, SIOCDIFPHYADDR, &ifr) == -1) 148 err(EXIT_FAILURE, "SIOCDIFPHYADDR"); 149 } 150 151 void 152 tunnel_status(void) 153 { 154 char dstserv[sizeof(",65535")]; 155 char srcserv[sizeof(",65535")]; 156 char psrcaddr[NI_MAXHOST]; 157 char pdstaddr[NI_MAXHOST]; 158 const int niflag = NI_NUMERICHOST|NI_NUMERICSERV; 159 struct if_laddrreq req; 160 const struct afswtch *lafp; 161 162 psrcaddr[0] = pdstaddr[0] = '\0'; 163 164 memset(&req, 0, sizeof(req)); 165 estrlcpy(req.iflr_name, name, IFNAMSIZ); 166 if (ioctl(s, SIOCGLIFPHYADDR, &req) == -1) 167 return; 168 lafp = lookup_af_bynum(req.addr.ss_family); 169 #ifdef INET6 170 if (req.addr.ss_family == AF_INET6) 171 in6_fillscopeid((struct sockaddr_in6 *)&req.addr); 172 #endif /* INET6 */ 173 getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len, 174 psrcaddr, sizeof(psrcaddr), &srcserv[1], sizeof(srcserv) - 1, 175 niflag); 176 177 #ifdef INET6 178 if (req.dstaddr.ss_family == AF_INET6) 179 in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr); 180 #endif 181 getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len, 182 pdstaddr, sizeof(pdstaddr), &dstserv[1], sizeof(dstserv) - 1, 183 niflag); 184 185 srcserv[0] = (strcmp(&srcserv[1], "0") == 0) ? '\0' : ','; 186 dstserv[0] = (strcmp(&dstserv[1], "0") == 0) ? '\0' : ','; 187 188 printf("\ttunnel %s %s%s --> %s%s\n", lafp ? lafp->af_name : "???", 189 psrcaddr, srcserv, pdstaddr, dstserv); 190 } 191