1/* 2 * Copyright (c) 2000-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ 29 30/* 31 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 32 * All rights reserved. 33 * 34 * Redistribution and use in source and binary forms, with or without 35 * modification, are permitted provided that the following conditions 36 * are met: 37 * 1. Redistributions of source code must retain the above copyright 38 * notice, this list of conditions and the following disclaimer. 39 * 2. Redistributions in binary form must reproduce the above copyright 40 * notice, this list of conditions and the following disclaimer in the 41 * documentation and/or other materials provided with the distribution. 42 * 3. Neither the name of the project nor the names of its contributors 43 * may be used to endorse or promote products derived from this software 44 * without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 */ 58 59 60#include <sys/param.h> 61#include <sys/systm.h> 62#include <sys/socket.h> 63#include <sys/sockio.h> 64#include <sys/mbuf.h> 65#include <sys/errno.h> 66#include <sys/kernel.h> 67#include <sys/sysctl.h> 68 69#include <sys/malloc.h> 70#include <libkern/OSAtomic.h> 71 72#include <net/if.h> 73#include <net/route.h> 74 75#include <netinet/in.h> 76#include <netinet/in_systm.h> 77#include <netinet/ip.h> 78#include <netinet/ip_var.h> 79#include <netinet/in_gif.h> 80#include <netinet/in_var.h> 81#include <netinet/ip_encap.h> 82#include <netinet/ip_ecn.h> 83 84#if INET6 85#include <netinet/ip6.h> 86#endif 87 88#include <net/if_gif.h> 89 90#include <net/net_osdep.h> 91 92int ip_gif_ttl = GIF_TTL; 93SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW | CTLFLAG_LOCKED, 94 &ip_gif_ttl, 0, ""); 95 96int 97in_gif_output( 98 struct ifnet *ifp, 99 int family, 100 struct mbuf *m, 101 __unused struct rtentry *rt) 102{ 103 struct gif_softc *sc = ifnet_softc(ifp); 104 struct sockaddr_in *dst = (struct sockaddr_in *) 105 (void *)&sc->gif_ro.ro_dst; 106 struct sockaddr_in *sin_src = (struct sockaddr_in *) 107 (void *)sc->gif_psrc; 108 struct sockaddr_in *sin_dst = (struct sockaddr_in *) 109 (void *)sc->gif_pdst; 110 struct ip iphdr; /* capsule IP header, host byte ordered */ 111 int proto, error; 112 u_int8_t tos; 113 struct ip_out_args ipoa = 114 { IFSCOPE_NONE, { 0 }, IPOAF_SELECT_SRCIF, 0 }; 115 116 GIF_LOCK_ASSERT(sc); 117 118 if (sin_src == NULL || sin_dst == NULL || 119 sin_src->sin_family != AF_INET || 120 sin_dst->sin_family != AF_INET) { 121 m_freem(m); 122 return (EAFNOSUPPORT); 123 } 124 125 switch (family) { 126#if INET 127 case AF_INET: 128 { 129 struct ip *ip; 130 131 proto = IPPROTO_IPV4; 132 if (mbuf_len(m) < sizeof (*ip)) { 133 m = m_pullup(m, sizeof (*ip)); 134 if (!m) 135 return (ENOBUFS); 136 } 137 ip = mtod(m, struct ip *); 138 tos = ip->ip_tos; 139 break; 140 } 141#endif /* INET */ 142#if INET6 143 case AF_INET6: 144 { 145 struct ip6_hdr *ip6; 146 proto = IPPROTO_IPV6; 147 if (mbuf_len(m) < sizeof (*ip6)) { 148 m = m_pullup(m, sizeof (*ip6)); 149 if (!m) 150 return (ENOBUFS); 151 } 152 ip6 = mtod(m, struct ip6_hdr *); 153 tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 154 break; 155 } 156#endif /* INET6 */ 157 default: 158#if DEBUG 159 printf("in_gif_output: warning: unknown family %d passed\n", 160 family); 161#endif 162 m_freem(m); 163 return (EAFNOSUPPORT); 164 } 165 166 bzero(&iphdr, sizeof (iphdr)); 167 iphdr.ip_src = sin_src->sin_addr; 168 /* bidirectional configured tunnel mode */ 169 if (sin_dst->sin_addr.s_addr != INADDR_ANY) 170 iphdr.ip_dst = sin_dst->sin_addr; 171 else { 172 m_freem(m); 173 return (ENETUNREACH); 174 } 175 iphdr.ip_p = proto; 176 /* version will be set in ip_output() */ 177 iphdr.ip_ttl = ip_gif_ttl; 178 iphdr.ip_len = m->m_pkthdr.len + sizeof (struct ip); 179 if (ifp->if_flags & IFF_LINK1) 180 ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); 181 else 182 ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos); 183 184 /* prepend new IP header */ 185 M_PREPEND(m, sizeof (struct ip), M_DONTWAIT); 186 if (m && mbuf_len(m) < sizeof (struct ip)) 187 m = m_pullup(m, sizeof (struct ip)); 188 if (m == NULL) { 189 printf("ENOBUFS in in_gif_output %d\n", __LINE__); 190 return (ENOBUFS); 191 } 192 bcopy(&iphdr, mtod(m, struct ip *), sizeof (struct ip)); 193 194 if (ROUTE_UNUSABLE(&sc->gif_ro) || 195 dst->sin_family != sin_dst->sin_family || 196 dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr || 197 (sc->gif_ro.ro_rt != NULL && sc->gif_ro.ro_rt->rt_ifp == ifp)) { 198 /* cache route doesn't match or recursive route */ 199 dst->sin_family = sin_dst->sin_family; 200 dst->sin_len = sizeof (struct sockaddr_in); 201 dst->sin_addr = sin_dst->sin_addr; 202 ROUTE_RELEASE(&sc->gif_ro); 203#if 0 204 sc->gif_if.if_mtu = GIF_MTU; 205#endif 206 } 207 208 if (sc->gif_ro.ro_rt == NULL) { 209 rtalloc(&sc->gif_ro); 210 if (sc->gif_ro.ro_rt == NULL) { 211 m_freem(m); 212 return (ENETUNREACH); 213 } 214 215 /* if it constitutes infinite encapsulation, punt. */ 216 RT_LOCK(sc->gif_ro.ro_rt); 217 if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 218 RT_UNLOCK(sc->gif_ro.ro_rt); 219 m_freem(m); 220 return (ENETUNREACH); /* XXX */ 221 } 222#if 0 223 ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu 224 - sizeof (struct ip); 225#endif 226 RT_UNLOCK(sc->gif_ro.ro_rt); 227 } 228 229 error = ip_output(m, NULL, &sc->gif_ro, IP_OUTARGS, NULL, &ipoa); 230 231 return (error); 232} 233 234void 235in_gif_input(m, off) 236 struct mbuf *m; 237 int off; 238{ 239 struct ifnet *gifp = NULL; 240 struct ip *ip; 241 int af, proto; 242 u_int8_t otos; 243 244 ip = mtod(m, struct ip *); 245 proto = ip->ip_p; 246 247 248 gifp = ((struct gif_softc *)encap_getarg(m))->gif_if; 249 250 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 251 m_freem(m); 252 OSAddAtomic(1, &ipstat.ips_nogif); 253 return; 254 } 255 256 otos = ip->ip_tos; 257 m_adj(m, off); 258 259 switch (proto) { 260#if INET 261 case IPPROTO_IPV4: 262 { 263 af = AF_INET; 264 if (mbuf_len(m) < sizeof (*ip)) { 265 m = m_pullup(m, sizeof (*ip)); 266 if (!m) 267 return; 268 } 269 ip = mtod(m, struct ip *); 270 if (gifp->if_flags & IFF_LINK1) 271 ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); 272 else 273 ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos); 274 break; 275 } 276#endif 277#if INET6 278 case IPPROTO_IPV6: 279 { 280 struct ip6_hdr *ip6; 281 u_int8_t itos; 282 af = AF_INET6; 283 if (mbuf_len(m) < sizeof (*ip6)) { 284 m = m_pullup(m, sizeof (*ip6)); 285 if (!m) 286 return; 287 } 288 ip6 = mtod(m, struct ip6_hdr *); 289 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 290 if (gifp->if_flags & IFF_LINK1) 291 ip_ecn_egress(ECN_ALLOWED, &otos, &itos); 292 else 293 ip_ecn_egress(ECN_NOCARE, &otos, &itos); 294 ip6->ip6_flow &= ~htonl(0xff << 20); 295 ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 296 break; 297 } 298#endif /* INET6 */ 299 default: 300 OSAddAtomic(1, &ipstat.ips_nogif); 301 m_freem(m); 302 return; 303 } 304#ifdef __APPLE__ 305 /* Replace the rcvif by gifp for dlil to route it correctly */ 306 if (m->m_pkthdr.rcvif) 307 m->m_pkthdr.rcvif = gifp; 308 ifnet_input(gifp, m, NULL); 309#else 310 gif_input(m, af, gifp); 311#endif 312} 313 314/* 315 * We know that we are in IFF_UP, outer address available, and outer family 316 * matched the physical addr family. see gif_encapcheck(). 317 */ 318int 319gif_encapcheck4( 320 const struct mbuf *m, 321 __unused int off, 322 __unused int proto, 323 void *arg) 324{ 325 struct ip ip; 326 struct gif_softc *sc; 327 struct sockaddr_in *src, *dst; 328 int addrmatch; 329 struct in_ifaddr *ia4; 330 331 /* sanity check done in caller */ 332 sc = (struct gif_softc *)arg; 333 src = (struct sockaddr_in *)(void *)sc->gif_psrc; 334 dst = (struct sockaddr_in *)(void *)sc->gif_pdst; 335 336 GIF_LOCK_ASSERT(sc); 337 338 mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof (ip), &ip); 339 340 /* check for address match */ 341 addrmatch = 0; 342 if (src->sin_addr.s_addr == ip.ip_dst.s_addr) 343 addrmatch |= 1; 344 if (dst->sin_addr.s_addr == ip.ip_src.s_addr) 345 addrmatch |= 2; 346 if (addrmatch != 3) 347 return (0); 348 349 /* martian filters on outer source - NOT done in ip_input! */ 350 if (IN_MULTICAST(ntohl(ip.ip_src.s_addr))) 351 return (0); 352 switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) { 353 case 0: case 127: case 255: 354 return (0); 355 } 356 /* reject packets with broadcast on source */ 357 lck_rw_lock_shared(in_ifaddr_rwlock); 358 for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4; 359 ia4 = TAILQ_NEXT(ia4, ia_link)) { 360 if ((ifnet_flags(ia4->ia_ifa.ifa_ifp) & IFF_BROADCAST) == 0) 361 continue; 362 IFA_LOCK(&ia4->ia_ifa); 363 if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { 364 IFA_UNLOCK(&ia4->ia_ifa); 365 lck_rw_done(in_ifaddr_rwlock); 366 return (0); 367 } 368 IFA_UNLOCK(&ia4->ia_ifa); 369 } 370 lck_rw_done(in_ifaddr_rwlock); 371 372 /* ingress filters on outer source */ 373 if ((ifnet_flags(sc->gif_if) & IFF_LINK2) == 0 && 374 (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { 375 struct sockaddr_in sin; 376 struct rtentry *rt; 377 378 bzero(&sin, sizeof (sin)); 379 sin.sin_family = AF_INET; 380 sin.sin_len = sizeof (struct sockaddr_in); 381 sin.sin_addr = ip.ip_src; 382 rt = rtalloc1_scoped((struct sockaddr *)&sin, 0, 0, 383 m->m_pkthdr.rcvif->if_index); 384 if (rt != NULL) 385 RT_LOCK(rt); 386 if (rt == NULL || rt->rt_ifp != m->m_pkthdr.rcvif) { 387 if (rt != NULL) { 388 RT_UNLOCK(rt); 389 rtfree(rt); 390 } 391 return (0); 392 } 393 RT_UNLOCK(rt); 394 rtfree(rt); 395 } 396 397 return (32 * 2); 398} 399