1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (c) 2018 Andrey V. Elsukov <ae@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $ 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include "opt_inet.h" 39 #include "opt_inet6.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/jail.h> 44 #include <sys/socket.h> 45 #include <sys/sockio.h> 46 #include <sys/mbuf.h> 47 #include <sys/errno.h> 48 #include <sys/kernel.h> 49 #include <sys/syslog.h> 50 #include <sys/sysctl.h> 51 #include <sys/malloc.h> 52 #include <sys/proc.h> 53 54 #include <net/ethernet.h> 55 #include <net/if.h> 56 #include <net/if_var.h> 57 #include <net/route.h> 58 #include <net/vnet.h> 59 60 #include <netinet/in.h> 61 #include <netinet/in_systm.h> 62 #ifdef INET 63 #include <netinet/ip.h> 64 #include <netinet/ip_ecn.h> 65 #endif 66 #include <netinet/ip_encap.h> 67 #include <netinet/ip6.h> 68 #include <netinet6/ip6_var.h> 69 #include <netinet6/in6_var.h> 70 #include <netinet6/scope6_var.h> 71 #include <netinet6/ip6_ecn.h> 72 #include <netinet6/in6_fib.h> 73 74 #include <net/if_gif.h> 75 76 #define GIF_HLIM 30 77 VNET_DEFINE_STATIC(int, ip6_gif_hlim) = GIF_HLIM; 78 #define V_ip6_gif_hlim VNET(ip6_gif_hlim) 79 80 SYSCTL_DECL(_net_inet6_ip6); 81 SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, 82 CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_gif_hlim), 0, 83 "Default hop limit for encapsulated packets"); 84 85 /* 86 * We keep interfaces in a hash table using src+dst as key. 87 * Interfaces with GIF_IGNORE_SOURCE flag are linked into plain list. 88 */ 89 VNET_DEFINE_STATIC(struct gif_list *, ipv6_hashtbl) = NULL; 90 VNET_DEFINE_STATIC(struct gif_list *, ipv6_srchashtbl) = NULL; 91 VNET_DEFINE_STATIC(struct gif_list, ipv6_list) = CK_LIST_HEAD_INITIALIZER(); 92 #define V_ipv6_hashtbl VNET(ipv6_hashtbl) 93 #define V_ipv6_srchashtbl VNET(ipv6_srchashtbl) 94 #define V_ipv6_list VNET(ipv6_list) 95 96 #define GIF_HASH(src, dst) (V_ipv6_hashtbl[\ 97 in6_gif_hashval((src), (dst)) & (GIF_HASH_SIZE - 1)]) 98 #define GIF_SRCHASH(src) (V_ipv6_srchashtbl[\ 99 fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GIF_HASH_SIZE - 1)]) 100 #define GIF_HASH_SC(sc) GIF_HASH(&(sc)->gif_ip6hdr->ip6_src,\ 101 &(sc)->gif_ip6hdr->ip6_dst) 102 static uint32_t 103 in6_gif_hashval(const struct in6_addr *src, const struct in6_addr *dst) 104 { 105 uint32_t ret; 106 107 ret = fnv_32_buf(src, sizeof(*src), FNV1_32_INIT); 108 return (fnv_32_buf(dst, sizeof(*dst), ret)); 109 } 110 111 static int 112 in6_gif_checkdup(const struct gif_softc *sc, const struct in6_addr *src, 113 const struct in6_addr *dst) 114 { 115 struct gif_softc *tmp; 116 117 if (sc->gif_family == AF_INET6 && 118 IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src, src) && 119 IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_dst, dst)) 120 return (EEXIST); 121 122 CK_LIST_FOREACH(tmp, &GIF_HASH(src, dst), chain) { 123 if (tmp == sc) 124 continue; 125 if (IN6_ARE_ADDR_EQUAL(&tmp->gif_ip6hdr->ip6_src, src) && 126 IN6_ARE_ADDR_EQUAL(&tmp->gif_ip6hdr->ip6_dst, dst)) 127 return (EADDRNOTAVAIL); 128 } 129 return (0); 130 } 131 132 /* 133 * Check that ingress address belongs to local host. 134 */ 135 static void 136 in6_gif_set_running(struct gif_softc *sc) 137 { 138 139 if (in6_localip(&sc->gif_ip6hdr->ip6_src)) 140 GIF2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING; 141 else 142 GIF2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; 143 } 144 145 /* 146 * ifaddr_event handler. 147 * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent 148 * source address spoofing. 149 */ 150 static void 151 in6_gif_srcaddr(void *arg __unused, const struct sockaddr *sa, int event) 152 { 153 const struct sockaddr_in6 *sin; 154 struct gif_softc *sc; 155 156 /* Check that VNET is ready */ 157 if (V_ipv6_hashtbl == NULL) 158 return; 159 160 NET_EPOCH_ASSERT(); 161 sin = (const struct sockaddr_in6 *)sa; 162 CK_LIST_FOREACH(sc, &GIF_SRCHASH(&sin->sin6_addr), srchash) { 163 if (IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src, 164 &sin->sin6_addr) == 0) 165 continue; 166 in6_gif_set_running(sc); 167 } 168 } 169 170 static void 171 in6_gif_attach(struct gif_softc *sc) 172 { 173 174 if (sc->gif_options & GIF_IGNORE_SOURCE) 175 CK_LIST_INSERT_HEAD(&V_ipv6_list, sc, chain); 176 else 177 CK_LIST_INSERT_HEAD(&GIF_HASH_SC(sc), sc, chain); 178 179 CK_LIST_INSERT_HEAD(&GIF_SRCHASH(&sc->gif_ip6hdr->ip6_src), 180 sc, srchash); 181 } 182 183 int 184 in6_gif_setopts(struct gif_softc *sc, u_int options) 185 { 186 187 /* NOTE: we are protected with gif_ioctl_sx lock */ 188 MPASS(sc->gif_family == AF_INET6); 189 MPASS(sc->gif_options != options); 190 191 if ((options & GIF_IGNORE_SOURCE) != 192 (sc->gif_options & GIF_IGNORE_SOURCE)) { 193 CK_LIST_REMOVE(sc, srchash); 194 CK_LIST_REMOVE(sc, chain); 195 sc->gif_options = options; 196 in6_gif_attach(sc); 197 } 198 return (0); 199 } 200 201 int 202 in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data) 203 { 204 struct in6_ifreq *ifr = (struct in6_ifreq *)data; 205 struct sockaddr_in6 *dst, *src; 206 struct ip6_hdr *ip6; 207 int error; 208 209 /* NOTE: we are protected with gif_ioctl_sx lock */ 210 error = EINVAL; 211 switch (cmd) { 212 case SIOCSIFPHYADDR_IN6: 213 src = &((struct in6_aliasreq *)data)->ifra_addr; 214 dst = &((struct in6_aliasreq *)data)->ifra_dstaddr; 215 216 /* sanity checks */ 217 if (src->sin6_family != dst->sin6_family || 218 src->sin6_family != AF_INET6 || 219 src->sin6_len != dst->sin6_len || 220 src->sin6_len != sizeof(*src)) 221 break; 222 if (IN6_IS_ADDR_UNSPECIFIED(&src->sin6_addr) || 223 IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) { 224 error = EADDRNOTAVAIL; 225 break; 226 } 227 /* 228 * Check validity of the scope zone ID of the 229 * addresses, and convert it into the kernel 230 * internal form if necessary. 231 */ 232 if ((error = sa6_embedscope(src, 0)) != 0 || 233 (error = sa6_embedscope(dst, 0)) != 0) 234 break; 235 236 if (V_ipv6_hashtbl == NULL) { 237 V_ipv6_hashtbl = gif_hashinit(); 238 V_ipv6_srchashtbl = gif_hashinit(); 239 } 240 error = in6_gif_checkdup(sc, &src->sin6_addr, 241 &dst->sin6_addr); 242 if (error == EADDRNOTAVAIL) 243 break; 244 if (error == EEXIST) { 245 /* Addresses are the same. Just return. */ 246 error = 0; 247 break; 248 } 249 ip6 = malloc(sizeof(*ip6), M_GIF, M_WAITOK | M_ZERO); 250 ip6->ip6_src = src->sin6_addr; 251 ip6->ip6_dst = dst->sin6_addr; 252 ip6->ip6_vfc = IPV6_VERSION; 253 if (sc->gif_family != 0) { 254 /* Detach existing tunnel first */ 255 CK_LIST_REMOVE(sc, srchash); 256 CK_LIST_REMOVE(sc, chain); 257 GIF_WAIT(); 258 free(sc->gif_hdr, M_GIF); 259 /* XXX: should we notify about link state change? */ 260 } 261 sc->gif_family = AF_INET6; 262 sc->gif_ip6hdr = ip6; 263 in6_gif_attach(sc); 264 in6_gif_set_running(sc); 265 break; 266 case SIOCGIFPSRCADDR_IN6: 267 case SIOCGIFPDSTADDR_IN6: 268 if (sc->gif_family != AF_INET6) { 269 error = EADDRNOTAVAIL; 270 break; 271 } 272 src = (struct sockaddr_in6 *)&ifr->ifr_addr; 273 memset(src, 0, sizeof(*src)); 274 src->sin6_family = AF_INET6; 275 src->sin6_len = sizeof(*src); 276 src->sin6_addr = (cmd == SIOCGIFPSRCADDR_IN6) ? 277 sc->gif_ip6hdr->ip6_src: sc->gif_ip6hdr->ip6_dst; 278 error = prison_if(curthread->td_ucred, (struct sockaddr *)src); 279 if (error == 0) 280 error = sa6_recoverscope(src); 281 if (error != 0) 282 memset(src, 0, sizeof(*src)); 283 break; 284 } 285 return (error); 286 } 287 288 int 289 in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) 290 { 291 struct gif_softc *sc = ifp->if_softc; 292 struct ip6_hdr *ip6; 293 int len; 294 295 /* prepend new IP header */ 296 NET_EPOCH_ASSERT(); 297 len = sizeof(struct ip6_hdr); 298 #ifndef __NO_STRICT_ALIGNMENT 299 if (proto == IPPROTO_ETHERIP) 300 len += ETHERIP_ALIGN; 301 #endif 302 M_PREPEND(m, len, M_NOWAIT); 303 if (m == NULL) 304 return (ENOBUFS); 305 #ifndef __NO_STRICT_ALIGNMENT 306 if (proto == IPPROTO_ETHERIP) { 307 len = mtod(m, vm_offset_t) & 3; 308 KASSERT(len == 0 || len == ETHERIP_ALIGN, 309 ("in6_gif_output: unexpected misalignment")); 310 m->m_data += len; 311 m->m_len -= ETHERIP_ALIGN; 312 } 313 #endif 314 315 ip6 = mtod(m, struct ip6_hdr *); 316 MPASS(sc->gif_family == AF_INET6); 317 bcopy(sc->gif_ip6hdr, ip6, sizeof(struct ip6_hdr)); 318 319 ip6->ip6_flow |= htonl((uint32_t)ecn << 20); 320 ip6->ip6_nxt = proto; 321 ip6->ip6_hlim = V_ip6_gif_hlim; 322 /* 323 * force fragmentation to minimum MTU, to avoid path MTU discovery. 324 * it is too painful to ask for resend of inner packet, to achieve 325 * path MTU discovery for encapsulated packets. 326 */ 327 return (ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL, NULL)); 328 } 329 330 static int 331 in6_gif_input(struct mbuf *m, int off, int proto, void *arg) 332 { 333 struct gif_softc *sc = arg; 334 struct ifnet *gifp; 335 struct ip6_hdr *ip6; 336 uint8_t ecn; 337 338 NET_EPOCH_ASSERT(); 339 if (sc == NULL) { 340 m_freem(m); 341 IP6STAT_INC(ip6s_nogif); 342 return (IPPROTO_DONE); 343 } 344 gifp = GIF2IFP(sc); 345 if ((gifp->if_flags & IFF_UP) != 0) { 346 ip6 = mtod(m, struct ip6_hdr *); 347 ecn = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 348 m_adj(m, off); 349 gif_input(m, gifp, proto, ecn); 350 } else { 351 m_freem(m); 352 IP6STAT_INC(ip6s_nogif); 353 } 354 return (IPPROTO_DONE); 355 } 356 357 static int 358 in6_gif_lookup(const struct mbuf *m, int off, int proto, void **arg) 359 { 360 const struct ip6_hdr *ip6; 361 struct gif_softc *sc; 362 int ret; 363 364 if (V_ipv6_hashtbl == NULL) 365 return (0); 366 367 NET_EPOCH_ASSERT(); 368 /* 369 * NOTE: it is safe to iterate without any locking here, because softc 370 * can be reclaimed only when we are not within net_epoch_preempt 371 * section, but ip_encap lookup+input are executed in epoch section. 372 */ 373 ip6 = mtod(m, const struct ip6_hdr *); 374 ret = 0; 375 CK_LIST_FOREACH(sc, &GIF_HASH(&ip6->ip6_dst, &ip6->ip6_src), chain) { 376 /* 377 * This is an inbound packet, its ip6_dst is source address 378 * in softc. 379 */ 380 if (IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src, 381 &ip6->ip6_dst) && 382 IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_dst, 383 &ip6->ip6_src)) { 384 ret = ENCAP_DRV_LOOKUP; 385 goto done; 386 } 387 } 388 /* 389 * No exact match. 390 * Check the list of interfaces with GIF_IGNORE_SOURCE flag. 391 */ 392 CK_LIST_FOREACH(sc, &V_ipv6_list, chain) { 393 if (IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src, 394 &ip6->ip6_dst)) { 395 ret = 128 + 8; /* src + proto */ 396 goto done; 397 } 398 } 399 return (0); 400 done: 401 if ((GIF2IFP(sc)->if_flags & IFF_UP) == 0) 402 return (0); 403 /* ingress filters on outer source */ 404 if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) { 405 struct nhop6_basic nh6; 406 407 if (fib6_lookup_nh_basic(sc->gif_fibnum, &ip6->ip6_src, 408 ntohs(in6_getscope(&ip6->ip6_src)), 0, 0, &nh6) != 0) 409 return (0); 410 411 if (nh6.nh_ifp != m->m_pkthdr.rcvif) 412 return (0); 413 } 414 *arg = sc; 415 return (ret); 416 } 417 418 static const struct srcaddrtab *ipv6_srcaddrtab; 419 static struct { 420 const struct encap_config encap; 421 const struct encaptab *cookie; 422 } ipv6_encap_cfg[] = { 423 #ifdef INET 424 { 425 .encap = { 426 .proto = IPPROTO_IPV4, 427 .min_length = sizeof(struct ip6_hdr) + 428 sizeof(struct ip), 429 .exact_match = ENCAP_DRV_LOOKUP, 430 .lookup = in6_gif_lookup, 431 .input = in6_gif_input 432 }, 433 }, 434 #endif 435 { 436 .encap = { 437 .proto = IPPROTO_IPV6, 438 .min_length = 2 * sizeof(struct ip6_hdr), 439 .exact_match = ENCAP_DRV_LOOKUP, 440 .lookup = in6_gif_lookup, 441 .input = in6_gif_input 442 }, 443 }, 444 { 445 .encap = { 446 .proto = IPPROTO_ETHERIP, 447 .min_length = sizeof(struct ip6_hdr) + 448 sizeof(struct etherip_header) + 449 sizeof(struct ether_header), 450 .exact_match = ENCAP_DRV_LOOKUP, 451 .lookup = in6_gif_lookup, 452 .input = in6_gif_input 453 }, 454 } 455 }; 456 457 void 458 in6_gif_init(void) 459 { 460 int i; 461 462 if (!IS_DEFAULT_VNET(curvnet)) 463 return; 464 465 ipv6_srcaddrtab = ip6_encap_register_srcaddr(in6_gif_srcaddr, 466 NULL, M_WAITOK); 467 for (i = 0; i < nitems(ipv6_encap_cfg); i++) 468 ipv6_encap_cfg[i].cookie = ip6_encap_attach( 469 &ipv6_encap_cfg[i].encap, NULL, M_WAITOK); 470 } 471 472 void 473 in6_gif_uninit(void) 474 { 475 int i; 476 477 if (IS_DEFAULT_VNET(curvnet)) { 478 for (i = 0; i < nitems(ipv6_encap_cfg); i++) 479 ip6_encap_detach(ipv6_encap_cfg[i].cookie); 480 ip6_encap_unregister_srcaddr(ipv6_srcaddrtab); 481 } 482 if (V_ipv6_hashtbl != NULL) { 483 gif_hashdestroy(V_ipv6_hashtbl); 484 V_ipv6_hashtbl = NULL; 485 GIF_WAIT(); 486 gif_hashdestroy(V_ipv6_srchashtbl); 487 } 488 } 489