1 /* $NetBSD: in6_gif.c,v 1.60 2014/05/18 14:46:16 rmind Exp $ */ 2 /* $KAME: in6_gif.c,v 1.62 2001/07/29 04:27:25 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 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 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: in6_gif.c,v 1.60 2014/05/18 14:46:16 rmind Exp $"); 35 36 #include "opt_inet.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/socket.h> 41 #include <sys/sockio.h> 42 #include <sys/mbuf.h> 43 #include <sys/errno.h> 44 #include <sys/ioctl.h> 45 #include <sys/queue.h> 46 #include <sys/syslog.h> 47 #include <sys/protosw.h> 48 #include <sys/kernel.h> 49 50 #include <net/if.h> 51 #include <net/route.h> 52 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #ifdef INET 56 #include <netinet/ip.h> 57 #endif 58 #include <netinet/ip_encap.h> 59 #ifdef INET6 60 #include <netinet/ip6.h> 61 #include <netinet6/ip6_var.h> 62 #include <netinet6/ip6_private.h> 63 #include <netinet6/in6_gif.h> 64 #include <netinet6/in6_var.h> 65 #endif 66 #include <netinet6/ip6protosw.h> 67 #include <netinet/ip_ecn.h> 68 69 #include <net/if_gif.h> 70 71 #include <net/net_osdep.h> 72 73 static int gif_validate6(const struct ip6_hdr *, struct gif_softc *, 74 struct ifnet *); 75 76 int ip6_gif_hlim = GIF_HLIM; 77 78 extern LIST_HEAD(, gif_softc) gif_softc_list; 79 80 extern const struct ip6protosw in6_gif_protosw; 81 82 /* 83 * family - family of the packet to be encapsulate. 84 */ 85 86 int 87 in6_gif_output(struct ifnet *ifp, int family, struct mbuf *m) 88 { 89 struct rtentry *rt; 90 struct gif_softc *sc = ifp->if_softc; 91 struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc; 92 struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; 93 struct ip6_hdr *ip6; 94 int proto, error; 95 u_int8_t itos, otos; 96 union { 97 struct sockaddr dst; 98 struct sockaddr_in6 dst6; 99 } u; 100 101 if (sin6_src == NULL || sin6_dst == NULL || 102 sin6_src->sin6_family != AF_INET6 || 103 sin6_dst->sin6_family != AF_INET6) { 104 m_freem(m); 105 return EAFNOSUPPORT; 106 } 107 108 switch (family) { 109 #ifdef INET 110 case AF_INET: 111 { 112 struct ip *ip; 113 114 proto = IPPROTO_IPV4; 115 if (m->m_len < sizeof(*ip)) { 116 m = m_pullup(m, sizeof(*ip)); 117 if (!m) 118 return ENOBUFS; 119 } 120 ip = mtod(m, struct ip *); 121 itos = ip->ip_tos; 122 break; 123 } 124 #endif 125 #ifdef INET6 126 case AF_INET6: 127 { 128 proto = IPPROTO_IPV6; 129 if (m->m_len < sizeof(*ip6)) { 130 m = m_pullup(m, sizeof(*ip6)); 131 if (!m) 132 return ENOBUFS; 133 } 134 ip6 = mtod(m, struct ip6_hdr *); 135 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 136 break; 137 } 138 #endif 139 default: 140 #ifdef DEBUG 141 printf("in6_gif_output: warning: unknown family %d passed\n", 142 family); 143 #endif 144 m_freem(m); 145 return EAFNOSUPPORT; 146 } 147 148 /* prepend new IP header */ 149 M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); 150 if (m && m->m_len < sizeof(struct ip6_hdr)) 151 m = m_pullup(m, sizeof(struct ip6_hdr)); 152 if (m == NULL) 153 return ENOBUFS; 154 155 ip6 = mtod(m, struct ip6_hdr *); 156 ip6->ip6_flow = 0; 157 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 158 ip6->ip6_vfc |= IPV6_VERSION; 159 #if 0 /* ip6->ip6_plen will be filled by ip6_output */ 160 ip6->ip6_plen = htons((u_int16_t)m->m_pkthdr.len); 161 #endif 162 ip6->ip6_nxt = proto; 163 ip6->ip6_hlim = ip6_gif_hlim; 164 ip6->ip6_src = sin6_src->sin6_addr; 165 /* bidirectional configured tunnel mode */ 166 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) 167 ip6->ip6_dst = sin6_dst->sin6_addr; 168 else { 169 m_freem(m); 170 return ENETUNREACH; 171 } 172 if (ifp->if_flags & IFF_LINK1) 173 ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); 174 else 175 ip_ecn_ingress(ECN_NOCARE, &otos, &itos); 176 ip6->ip6_flow &= ~ntohl(0xff00000); 177 ip6->ip6_flow |= htonl((u_int32_t)otos << 20); 178 179 sockaddr_in6_init(&u.dst6, &sin6_dst->sin6_addr, 0, 0, 0); 180 if ((rt = rtcache_lookup(&sc->gif_ro, &u.dst)) == NULL) { 181 m_freem(m); 182 return ENETUNREACH; 183 } 184 185 /* If the route constitutes infinite encapsulation, punt. */ 186 if (rt->rt_ifp == ifp) { 187 m_freem(m); 188 return ENETUNREACH; /* XXX */ 189 } 190 191 #ifdef IPV6_MINMTU 192 /* 193 * force fragmentation to minimum MTU, to avoid path MTU discovery. 194 * it is too painful to ask for resend of inner packet, to achieve 195 * path MTU discovery for encapsulated packets. 196 */ 197 error = ip6_output(m, 0, &sc->gif_ro, IPV6_MINMTU, NULL, NULL, NULL); 198 #else 199 error = ip6_output(m, 0, &sc->gif_ro, 0, NULL, NULL, NULL); 200 #endif 201 202 return (error); 203 } 204 205 int 206 in6_gif_input(struct mbuf **mp, int *offp, int proto) 207 { 208 struct mbuf *m = *mp; 209 struct ifnet *gifp = NULL; 210 struct ip6_hdr *ip6; 211 int af = 0; 212 u_int32_t otos; 213 214 ip6 = mtod(m, struct ip6_hdr *); 215 216 gifp = (struct ifnet *)encap_getarg(m); 217 218 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 219 m_freem(m); 220 IP6_STATINC(IP6_STAT_NOGIF); 221 return IPPROTO_DONE; 222 } 223 #ifndef GIF_ENCAPCHECK 224 if (!gif_validate6(ip6, gifp->if_softc, m->m_pkthdr.rcvif)) { 225 m_freem(m); 226 IP6_STATINC(IP6_STAT_NOGIF); 227 return IPPROTO_DONE; 228 } 229 #endif 230 231 otos = ip6->ip6_flow; 232 m_adj(m, *offp); 233 234 switch (proto) { 235 #ifdef INET 236 case IPPROTO_IPV4: 237 { 238 struct ip *ip; 239 u_int8_t otos8; 240 af = AF_INET; 241 otos8 = (ntohl(otos) >> 20) & 0xff; 242 if (m->m_len < sizeof(*ip)) { 243 m = m_pullup(m, sizeof(*ip)); 244 if (!m) 245 return IPPROTO_DONE; 246 } 247 ip = mtod(m, struct ip *); 248 if (gifp->if_flags & IFF_LINK1) 249 ip_ecn_egress(ECN_ALLOWED, &otos8, &ip->ip_tos); 250 else 251 ip_ecn_egress(ECN_NOCARE, &otos8, &ip->ip_tos); 252 break; 253 } 254 #endif /* INET */ 255 #ifdef INET6 256 case IPPROTO_IPV6: 257 { 258 struct ip6_hdr *ip6x; 259 af = AF_INET6; 260 if (m->m_len < sizeof(*ip6x)) { 261 m = m_pullup(m, sizeof(*ip6x)); 262 if (!m) 263 return IPPROTO_DONE; 264 } 265 ip6x = mtod(m, struct ip6_hdr *); 266 if (gifp->if_flags & IFF_LINK1) 267 ip6_ecn_egress(ECN_ALLOWED, &otos, &ip6x->ip6_flow); 268 else 269 ip6_ecn_egress(ECN_NOCARE, &otos, &ip6x->ip6_flow); 270 break; 271 } 272 #endif 273 default: 274 IP6_STATINC(IP6_STAT_NOGIF); 275 m_freem(m); 276 return IPPROTO_DONE; 277 } 278 279 gif_input(m, af, gifp); 280 return IPPROTO_DONE; 281 } 282 283 /* 284 * validate outer address. 285 */ 286 static int 287 gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc, 288 struct ifnet *ifp) 289 { 290 const struct sockaddr_in6 *src, *dst; 291 292 src = (struct sockaddr_in6 *)sc->gif_psrc; 293 dst = (struct sockaddr_in6 *)sc->gif_pdst; 294 295 /* check for address match */ 296 if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) || 297 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src)) 298 return 0; 299 300 /* martian filters on outer source - done in ip6_input */ 301 302 /* ingress filters on outer source */ 303 if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) { 304 union { 305 struct sockaddr sa; 306 struct sockaddr_in6 sin6; 307 } u; 308 struct rtentry *rt; 309 310 /* XXX scopeid */ 311 sockaddr_in6_init(&u.sin6, &ip6->ip6_src, 0, 0, 0); 312 rt = rtalloc1(&u.sa, 0); 313 if (rt == NULL || rt->rt_ifp != ifp) { 314 #if 0 315 log(LOG_WARNING, "%s: packet from %s dropped " 316 "due to ingress filter\n", if_name(&sc->gif_if), 317 ip6_sprintf(&u.sin6.sin6_addr)); 318 #endif 319 if (rt != NULL) 320 rtfree(rt); 321 return 0; 322 } 323 rtfree(rt); 324 } 325 326 return 128 * 2; 327 } 328 329 #ifdef GIF_ENCAPCHECK 330 /* 331 * we know that we are in IFF_UP, outer address available, and outer family 332 * matched the physical addr family. see gif_encapcheck(). 333 */ 334 int 335 gif_encapcheck6(struct mbuf *m, int off, int proto, void *arg) 336 { 337 struct ip6_hdr ip6; 338 struct gif_softc *sc; 339 struct ifnet *ifp; 340 341 /* sanity check done in caller */ 342 sc = arg; 343 344 m_copydata(m, 0, sizeof(ip6), (void *)&ip6); 345 ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL; 346 347 return gif_validate6(&ip6, sc, ifp); 348 } 349 #endif 350 351 int 352 in6_gif_attach(struct gif_softc *sc) 353 { 354 #ifndef GIF_ENCAPCHECK 355 struct sockaddr_in6 mask6; 356 357 memset(&mask6, 0, sizeof(mask6)); 358 mask6.sin6_len = sizeof(struct sockaddr_in6); 359 mask6.sin6_addr.s6_addr32[0] = mask6.sin6_addr.s6_addr32[1] = 360 mask6.sin6_addr.s6_addr32[2] = mask6.sin6_addr.s6_addr32[3] = ~0; 361 362 if (!sc->gif_psrc || !sc->gif_pdst) 363 return EINVAL; 364 sc->encap_cookie6 = encap_attach(AF_INET6, -1, sc->gif_psrc, 365 (struct sockaddr *)&mask6, sc->gif_pdst, (struct sockaddr *)&mask6, 366 (const void *)&in6_gif_protosw, sc); 367 #else 368 sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck, 369 (struct protosw *)&in6_gif_protosw, sc); 370 #endif 371 if (sc->encap_cookie6 == NULL) 372 return EEXIST; 373 return 0; 374 } 375 376 int 377 in6_gif_detach(struct gif_softc *sc) 378 { 379 int error; 380 381 error = encap_detach(sc->encap_cookie6); 382 if (error == 0) 383 sc->encap_cookie6 = NULL; 384 385 rtcache_free(&sc->gif_ro); 386 387 return error; 388 } 389 390 void * 391 in6_gif_ctlinput(int cmd, const struct sockaddr *sa, void *d) 392 { 393 struct gif_softc *sc; 394 struct ip6ctlparam *ip6cp = NULL; 395 struct ip6_hdr *ip6; 396 const struct sockaddr_in6 *dst6; 397 398 if (sa->sa_family != AF_INET6 || 399 sa->sa_len != sizeof(struct sockaddr_in6)) 400 return NULL; 401 402 if ((unsigned)cmd >= PRC_NCMDS) 403 return NULL; 404 if (cmd == PRC_HOSTDEAD) 405 d = NULL; 406 else if (inet6ctlerrmap[cmd] == 0) 407 return NULL; 408 409 /* if the parameter is from icmp6, decode it. */ 410 if (d != NULL) { 411 ip6cp = (struct ip6ctlparam *)d; 412 ip6 = ip6cp->ip6c_ip6; 413 } else { 414 ip6 = NULL; 415 } 416 417 if (!ip6) 418 return NULL; 419 420 /* 421 * for now we don't care which type it was, just flush the route cache. 422 * XXX slow. sc (or sc->encap_cookie6) should be passed from 423 * ip_encap.c. 424 */ 425 LIST_FOREACH(sc, &gif_softc_list, gif_list) { 426 if ((sc->gif_if.if_flags & IFF_RUNNING) == 0) 427 continue; 428 if (sc->gif_psrc->sa_family != AF_INET6) 429 continue; 430 431 dst6 = satocsin6(rtcache_getdst(&sc->gif_ro)); 432 /* XXX scope */ 433 if (dst6 == NULL) 434 ; 435 else if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst6->sin6_addr)) 436 rtcache_free(&sc->gif_ro); 437 } 438 439 return NULL; 440 } 441 442 PR_WRAP_CTLINPUT(in6_gif_ctlinput) 443 PR_WRAP_CTLOUTPUT(rip6_ctloutput) 444 445 #define in6_gif_ctlinput in6_gif_ctlinput_wrapper 446 #define rip6_ctloutput rip6_ctloutput_wrapper 447 448 extern struct domain inet6domain; 449 450 const struct ip6protosw in6_gif_protosw = { 451 .pr_type = SOCK_RAW, 452 .pr_domain = &inet6domain, 453 .pr_protocol = 0 /* IPPROTO_IPV[46] */, 454 .pr_flags = PR_ATOMIC | PR_ADDR, 455 .pr_input = in6_gif_input, 456 .pr_output = rip6_output, 457 .pr_ctlinput = in6_gif_ctlinput, 458 .pr_ctloutput = rip6_ctloutput, 459 .pr_usrreqs = &rip6_usrreqs, 460 }; 461