1 1.96 knakahar /* $NetBSD: in_gif.c,v 1.96 2022/12/07 08:30:15 knakahara Exp $ */ 2 1.22 itojun /* $KAME: in_gif.c,v 1.66 2001/07/29 04:46:09 itojun Exp $ */ 3 1.3 thorpej 4 1.2 itojun /* 5 1.2 itojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 1.2 itojun * All rights reserved. 7 1.12 itojun * 8 1.2 itojun * Redistribution and use in source and binary forms, with or without 9 1.2 itojun * modification, are permitted provided that the following conditions 10 1.2 itojun * are met: 11 1.2 itojun * 1. Redistributions of source code must retain the above copyright 12 1.2 itojun * notice, this list of conditions and the following disclaimer. 13 1.2 itojun * 2. Redistributions in binary form must reproduce the above copyright 14 1.2 itojun * notice, this list of conditions and the following disclaimer in the 15 1.2 itojun * documentation and/or other materials provided with the distribution. 16 1.2 itojun * 3. Neither the name of the project nor the names of its contributors 17 1.2 itojun * may be used to endorse or promote products derived from this software 18 1.2 itojun * without specific prior written permission. 19 1.12 itojun * 20 1.2 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 1.2 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.2 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.2 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 1.2 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.2 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.2 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.2 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.2 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.2 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.2 itojun * SUCH DAMAGE. 31 1.2 itojun */ 32 1.25 lukem 33 1.25 lukem #include <sys/cdefs.h> 34 1.96 knakahar __KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.96 2022/12/07 08:30:15 knakahara Exp $"); 35 1.2 itojun 36 1.65 pooka #ifdef _KERNEL_OPT 37 1.2 itojun #include "opt_inet.h" 38 1.65 pooka #endif 39 1.2 itojun 40 1.2 itojun #include <sys/param.h> 41 1.2 itojun #include <sys/systm.h> 42 1.2 itojun #include <sys/socket.h> 43 1.2 itojun #include <sys/sockio.h> 44 1.2 itojun #include <sys/mbuf.h> 45 1.2 itojun #include <sys/errno.h> 46 1.2 itojun #include <sys/ioctl.h> 47 1.16 itojun #include <sys/syslog.h> 48 1.45 mlelstv #include <sys/kernel.h> 49 1.12 itojun 50 1.2 itojun #include <net/if.h> 51 1.2 itojun #include <net/route.h> 52 1.2 itojun 53 1.2 itojun #include <netinet/in.h> 54 1.2 itojun #include <netinet/in_systm.h> 55 1.2 itojun #include <netinet/ip.h> 56 1.2 itojun #include <netinet/ip_var.h> 57 1.2 itojun #include <netinet/in_gif.h> 58 1.12 itojun #include <netinet/in_var.h> 59 1.12 itojun #include <netinet/ip_encap.h> 60 1.2 itojun #include <netinet/ip_ecn.h> 61 1.2 itojun 62 1.2 itojun #ifdef INET6 63 1.2 itojun #include <netinet/ip6.h> 64 1.2 itojun #endif 65 1.2 itojun 66 1.27 itojun #include <net/if_gif.h> 67 1.2 itojun 68 1.90 knakahar static int gif_validate4(const struct ip *, struct gif_variant *, 69 1.39 perry struct ifnet *); 70 1.22 itojun 71 1.4 itojun int ip_gif_ttl = GIF_TTL; 72 1.2 itojun 73 1.74 knakahar static const struct encapsw in_gif_encapsw = { 74 1.74 knakahar .encapsw4 = { 75 1.74 knakahar .pr_input = in_gif_input, 76 1.74 knakahar .pr_ctlinput = NULL, 77 1.74 knakahar } 78 1.26 itojun }; 79 1.22 itojun 80 1.90 knakahar static int 81 1.90 knakahar in_gif_output(struct gif_variant *var, int family, struct mbuf *m) 82 1.2 itojun { 83 1.57 dyoung struct rtentry *rt; 84 1.90 knakahar struct gif_softc *sc; 85 1.90 knakahar struct sockaddr_in *sin_src; 86 1.90 knakahar struct sockaddr_in *sin_dst; 87 1.90 knakahar struct ifnet *ifp; 88 1.95 knakahar struct route *ro_pc; 89 1.95 knakahar kmutex_t *lock_pc; 90 1.2 itojun struct ip iphdr; /* capsule IP header, host byte ordered */ 91 1.2 itojun int proto, error; 92 1.2 itojun u_int8_t tos; 93 1.2 itojun 94 1.90 knakahar KASSERT(gif_heldref_variant(var)); 95 1.90 knakahar 96 1.90 knakahar sin_src = satosin(var->gv_psrc); 97 1.90 knakahar sin_dst = satosin(var->gv_pdst); 98 1.90 knakahar ifp = &var->gv_softc->gif_if; 99 1.90 knakahar 100 1.2 itojun if (sin_src == NULL || sin_dst == NULL || 101 1.2 itojun sin_src->sin_family != AF_INET || 102 1.2 itojun sin_dst->sin_family != AF_INET) { 103 1.2 itojun m_freem(m); 104 1.2 itojun return EAFNOSUPPORT; 105 1.2 itojun } 106 1.2 itojun 107 1.2 itojun switch (family) { 108 1.2 itojun #ifdef INET 109 1.2 itojun case AF_INET: 110 1.2 itojun { 111 1.48 dyoung const struct ip *ip; 112 1.2 itojun 113 1.2 itojun proto = IPPROTO_IPV4; 114 1.2 itojun if (m->m_len < sizeof(*ip)) { 115 1.2 itojun m = m_pullup(m, sizeof(*ip)); 116 1.49 dyoung if (m == NULL) 117 1.2 itojun return ENOBUFS; 118 1.2 itojun } 119 1.48 dyoung ip = mtod(m, const struct ip *); 120 1.2 itojun tos = ip->ip_tos; 121 1.2 itojun break; 122 1.2 itojun } 123 1.26 itojun #endif /* INET */ 124 1.2 itojun #ifdef INET6 125 1.2 itojun case AF_INET6: 126 1.2 itojun { 127 1.48 dyoung const struct ip6_hdr *ip6; 128 1.2 itojun proto = IPPROTO_IPV6; 129 1.2 itojun if (m->m_len < sizeof(*ip6)) { 130 1.2 itojun m = m_pullup(m, sizeof(*ip6)); 131 1.62 liamjfoy if (m == NULL) 132 1.2 itojun return ENOBUFS; 133 1.2 itojun } 134 1.48 dyoung ip6 = mtod(m, const struct ip6_hdr *); 135 1.2 itojun tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 136 1.2 itojun break; 137 1.2 itojun } 138 1.26 itojun #endif /* INET6 */ 139 1.2 itojun default: 140 1.9 itojun #ifdef DEBUG 141 1.2 itojun printf("in_gif_output: warning: unknown family %d passed\n", 142 1.2 itojun family); 143 1.2 itojun #endif 144 1.2 itojun m_freem(m); 145 1.2 itojun return EAFNOSUPPORT; 146 1.2 itojun } 147 1.2 itojun 148 1.60 dyoung memset(&iphdr, 0, sizeof(iphdr)); 149 1.2 itojun iphdr.ip_src = sin_src->sin_addr; 150 1.21 itojun /* bidirectional configured tunnel mode */ 151 1.21 itojun if (sin_dst->sin_addr.s_addr != INADDR_ANY) 152 1.21 itojun iphdr.ip_dst = sin_dst->sin_addr; 153 1.21 itojun else { 154 1.21 itojun m_freem(m); 155 1.21 itojun return ENETUNREACH; 156 1.2 itojun } 157 1.2 itojun iphdr.ip_p = proto; 158 1.2 itojun /* version will be set in ip_output() */ 159 1.4 itojun iphdr.ip_ttl = ip_gif_ttl; 160 1.29 itojun iphdr.ip_len = htons(m->m_pkthdr.len + sizeof(struct ip)); 161 1.2 itojun if (ifp->if_flags & IFF_LINK1) 162 1.2 itojun ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); 163 1.20 itojun else 164 1.20 itojun ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos); 165 1.2 itojun 166 1.2 itojun /* prepend new IP header */ 167 1.2 itojun M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 168 1.48 dyoung /* XXX Is m_pullup really necessary after M_PREPEND? */ 169 1.50 dyoung if (m != NULL && M_UNWRITABLE(m, sizeof(struct ip))) 170 1.2 itojun m = m_pullup(m, sizeof(struct ip)); 171 1.22 itojun if (m == NULL) 172 1.2 itojun return ENOBUFS; 173 1.12 itojun bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); 174 1.2 itojun 175 1.90 knakahar sc = var->gv_softc; 176 1.95 knakahar if_tunnel_get_ro(sc->gif_ro_percpu, &ro_pc, &lock_pc); 177 1.95 knakahar if ((rt = rtcache_lookup(ro_pc, var->gv_pdst)) == NULL) { 178 1.95 knakahar if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc); 179 1.56 dyoung m_freem(m); 180 1.56 dyoung return ENETUNREACH; 181 1.53 joerg } 182 1.12 itojun 183 1.53 joerg /* If the route constitutes infinite encapsulation, punt. */ 184 1.57 dyoung if (rt->rt_ifp == ifp) { 185 1.95 knakahar rtcache_unref(rt, ro_pc); 186 1.95 knakahar rtcache_free(ro_pc); 187 1.95 knakahar if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc); 188 1.53 joerg m_freem(m); 189 1.53 joerg return ENETUNREACH; /*XXX*/ 190 1.2 itojun } 191 1.95 knakahar rtcache_unref(rt, ro_pc); 192 1.12 itojun 193 1.95 knakahar error = ip_output(m, NULL, ro_pc, 0, NULL, NULL); 194 1.95 knakahar if_tunnel_put_ro(sc->gif_ro_percpu, lock_pc); 195 1.30 itojun return (error); 196 1.2 itojun } 197 1.2 itojun 198 1.2 itojun void 199 1.89 knakahar in_gif_input(struct mbuf *m, int off, int proto, void *eparg) 200 1.2 itojun { 201 1.90 knakahar struct gif_softc *sc = eparg; 202 1.90 knakahar struct ifnet *gifp = &sc->gif_if; 203 1.49 dyoung const struct ip *ip; 204 1.12 itojun int af; 205 1.2 itojun u_int8_t otos; 206 1.2 itojun 207 1.90 knakahar KASSERT(sc != NULL); 208 1.89 knakahar 209 1.49 dyoung ip = mtod(m, const struct ip *); 210 1.2 itojun 211 1.90 knakahar gifp = &sc->gif_if; 212 1.91 knakahar if ((gifp->if_flags & IFF_UP) == 0) { 213 1.2 itojun m_freem(m); 214 1.59 thorpej ip_statinc(IP_STAT_NOGIF); 215 1.2 itojun return; 216 1.2 itojun } 217 1.32 itojun #ifndef GIF_ENCAPCHECK 218 1.90 knakahar struct psref psref_var; 219 1.90 knakahar struct gif_variant *var = gif_getref_variant(sc, &psref_var); 220 1.66 knakahar /* other CPU do delete_tunnel */ 221 1.90 knakahar if (var->gv_psrc == NULL || var->gv_pdst == NULL) { 222 1.90 knakahar gif_putref_variant(var, &psref_var); 223 1.66 knakahar m_freem(m); 224 1.66 knakahar ip_statinc(IP_STAT_NOGIF); 225 1.66 knakahar return; 226 1.66 knakahar } 227 1.66 knakahar 228 1.80 knakahar struct ifnet *rcvif; 229 1.90 knakahar struct psref psref_rcvif; 230 1.90 knakahar rcvif = m_get_rcvif_psref(m, &psref_rcvif); 231 1.90 knakahar if (!gif_validate4(ip, var, rcvif)) { 232 1.90 knakahar m_put_rcvif_psref(rcvif, &psref_rcvif); 233 1.90 knakahar gif_putref_variant(var, &psref_var); 234 1.22 itojun m_freem(m); 235 1.59 thorpej ip_statinc(IP_STAT_NOGIF); 236 1.22 itojun return; 237 1.22 itojun } 238 1.90 knakahar m_put_rcvif_psref(rcvif, &psref_rcvif); 239 1.90 knakahar gif_putref_variant(var, &psref_var); 240 1.22 itojun #endif 241 1.2 itojun otos = ip->ip_tos; 242 1.2 itojun m_adj(m, off); 243 1.2 itojun 244 1.2 itojun switch (proto) { 245 1.2 itojun #ifdef INET 246 1.2 itojun case IPPROTO_IPV4: 247 1.2 itojun { 248 1.42 christos struct ip *xip; 249 1.2 itojun af = AF_INET; 250 1.50 dyoung if (M_UNWRITABLE(m, sizeof(*xip))) { 251 1.49 dyoung if ((m = m_pullup(m, sizeof(*xip))) == NULL) 252 1.2 itojun return; 253 1.2 itojun } 254 1.42 christos xip = mtod(m, struct ip *); 255 1.2 itojun if (gifp->if_flags & IFF_LINK1) 256 1.42 christos ip_ecn_egress(ECN_ALLOWED, &otos, &xip->ip_tos); 257 1.20 itojun else 258 1.42 christos ip_ecn_egress(ECN_NOCARE, &otos, &xip->ip_tos); 259 1.2 itojun break; 260 1.2 itojun } 261 1.2 itojun #endif 262 1.2 itojun #ifdef INET6 263 1.2 itojun case IPPROTO_IPV6: 264 1.2 itojun { 265 1.2 itojun struct ip6_hdr *ip6; 266 1.2 itojun u_int8_t itos; 267 1.2 itojun af = AF_INET6; 268 1.50 dyoung if (M_UNWRITABLE(m, sizeof(*ip6))) { 269 1.49 dyoung if ((m = m_pullup(m, sizeof(*ip6))) == NULL) 270 1.2 itojun return; 271 1.2 itojun } 272 1.2 itojun ip6 = mtod(m, struct ip6_hdr *); 273 1.2 itojun itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 274 1.2 itojun if (gifp->if_flags & IFF_LINK1) 275 1.2 itojun ip_ecn_egress(ECN_ALLOWED, &otos, &itos); 276 1.20 itojun else 277 1.20 itojun ip_ecn_egress(ECN_NOCARE, &otos, &itos); 278 1.2 itojun ip6->ip6_flow &= ~htonl(0xff << 20); 279 1.2 itojun ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 280 1.2 itojun break; 281 1.2 itojun } 282 1.2 itojun #endif /* INET6 */ 283 1.2 itojun default: 284 1.59 thorpej ip_statinc(IP_STAT_NOGIF); 285 1.2 itojun m_freem(m); 286 1.2 itojun return; 287 1.2 itojun } 288 1.2 itojun gif_input(m, af, gifp); 289 1.2 itojun return; 290 1.12 itojun } 291 1.12 itojun 292 1.12 itojun /* 293 1.22 itojun * validate outer address. 294 1.12 itojun */ 295 1.22 itojun static int 296 1.90 knakahar gif_validate4(const struct ip *ip, struct gif_variant *var, struct ifnet *ifp) 297 1.12 itojun { 298 1.12 itojun struct sockaddr_in *src, *dst; 299 1.92 knakahar int ret; 300 1.12 itojun 301 1.90 knakahar src = satosin(var->gv_psrc); 302 1.90 knakahar dst = satosin(var->gv_pdst); 303 1.12 itojun 304 1.92 knakahar ret = in_tunnel_validate(ip, src->sin_addr, dst->sin_addr); 305 1.92 knakahar if (ret == 0) 306 1.12 itojun return 0; 307 1.12 itojun 308 1.12 itojun /* ingress filters on outer source */ 309 1.90 knakahar if ((var->gv_softc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { 310 1.60 dyoung union { 311 1.60 dyoung struct sockaddr sa; 312 1.60 dyoung struct sockaddr_in sin; 313 1.60 dyoung } u; 314 1.12 itojun struct rtentry *rt; 315 1.12 itojun 316 1.60 dyoung sockaddr_in_init(&u.sin, &ip->ip_src, 0); 317 1.60 dyoung rt = rtalloc1(&u.sa, 0); 318 1.60 dyoung if (rt == NULL || rt->rt_ifp != ifp) { 319 1.16 itojun #if 0 320 1.16 itojun log(LOG_WARNING, "%s: packet from 0x%x dropped " 321 1.90 knakahar "due to ingress filter\n", 322 1.90 knakahar if_name(&var->gv_softc->gif_if), 323 1.60 dyoung (u_int32_t)ntohl(u.sin.sin_addr.s_addr)); 324 1.16 itojun #endif 325 1.60 dyoung if (rt != NULL) 326 1.85 ozaki rt_unref(rt); 327 1.12 itojun return 0; 328 1.12 itojun } 329 1.85 ozaki rt_unref(rt); 330 1.12 itojun } 331 1.12 itojun 332 1.92 knakahar return ret; 333 1.22 itojun } 334 1.22 itojun 335 1.32 itojun #ifdef GIF_ENCAPCHECK 336 1.22 itojun /* 337 1.22 itojun * we know that we are in IFF_UP, outer address available, and outer family 338 1.22 itojun * matched the physical addr family. see gif_encapcheck(). 339 1.22 itojun */ 340 1.22 itojun int 341 1.90 knakahar gif_encapcheck4(struct mbuf *m, int off, int proto, struct gif_variant *var) 342 1.22 itojun { 343 1.22 itojun struct ip ip; 344 1.90 knakahar 345 1.79 ozaki struct ifnet *ifp = NULL; 346 1.79 ozaki int r; 347 1.79 ozaki struct psref psref; 348 1.22 itojun 349 1.60 dyoung m_copydata(m, 0, sizeof(ip), &ip); 350 1.79 ozaki if ((m->m_flags & M_PKTHDR) != 0) 351 1.79 ozaki ifp = m_get_rcvif_psref(m, &psref); 352 1.79 ozaki 353 1.90 knakahar r = gif_validate4(&ip, var, ifp); 354 1.22 itojun 355 1.79 ozaki m_put_rcvif_psref(ifp, &psref); 356 1.79 ozaki return r; 357 1.22 itojun } 358 1.32 itojun #endif 359 1.22 itojun 360 1.22 itojun int 361 1.90 knakahar in_gif_attach(struct gif_variant *var) 362 1.22 itojun { 363 1.32 itojun #ifndef GIF_ENCAPCHECK 364 1.22 itojun struct sockaddr_in mask4; 365 1.22 itojun 366 1.60 dyoung memset(&mask4, 0, sizeof(mask4)); 367 1.22 itojun mask4.sin_len = sizeof(struct sockaddr_in); 368 1.22 itojun mask4.sin_addr.s_addr = ~0; 369 1.22 itojun 370 1.90 knakahar if (!var->gv_psrc || !var->gv_pdst) 371 1.22 itojun return EINVAL; 372 1.96 knakahar 373 1.96 knakahar var->gv_encap_cookie4 = encap_attach_addr(AF_INET, -1, var->gv_psrc, 374 1.96 knakahar var->gv_pdst, NULL, &in_gif_encapsw, var->gv_softc); 375 1.22 itojun #else 376 1.96 knakahar var->gv_encap_cookie4 = encap_attach_addr(AF_INET, -1, var->gv_psrc, 377 1.96 knakahar var->gv_pdst, gif_encapcheck, &in_gif_encapsw, var->gv_softc); 378 1.22 itojun #endif 379 1.90 knakahar if (var->gv_encap_cookie4 == NULL) 380 1.22 itojun return EEXIST; 381 1.90 knakahar 382 1.90 knakahar var->gv_output = in_gif_output; 383 1.22 itojun return 0; 384 1.22 itojun } 385 1.22 itojun 386 1.22 itojun int 387 1.90 knakahar in_gif_detach(struct gif_variant *var) 388 1.22 itojun { 389 1.22 itojun int error; 390 1.90 knakahar struct gif_softc *sc = var->gv_softc; 391 1.22 itojun 392 1.90 knakahar error = encap_detach(var->gv_encap_cookie4); 393 1.90 knakahar if (error == 0) 394 1.90 knakahar var->gv_encap_cookie4 = NULL; 395 1.78 knakahar 396 1.95 knakahar if_tunnel_ro_percpu_rtcache_free(sc->gif_ro_percpu); 397 1.78 knakahar 398 1.78 knakahar return error; 399 1.78 knakahar } 400