1/* 2 * Copyright (c) 2000-2012 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#if MROUTING 89#include <netinet/ip_mroute.h> 90#endif /* MROUTING */ 91 92#include <net/if_gif.h> 93 94#include <net/net_osdep.h> 95 96int ip_gif_ttl = GIF_TTL; 97SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW | CTLFLAG_LOCKED, 98 &ip_gif_ttl, 0, ""); 99 100int 101in_gif_output( 102 struct ifnet *ifp, 103 int family, 104 struct mbuf *m, 105 __unused struct rtentry *rt) 106{ 107 struct gif_softc *sc = ifnet_softc(ifp); 108 struct sockaddr_in *dst = (struct sockaddr_in *)(void *)&sc->gif_ro.ro_dst; 109 struct sockaddr_in *sin_src = (struct sockaddr_in *)(void *)sc->gif_psrc; 110 struct sockaddr_in *sin_dst = (struct sockaddr_in *)(void *)sc->gif_pdst; 111 struct ip iphdr; /* capsule IP header, host byte ordered */ 112 int proto, error; 113 u_int8_t tos; 114 struct ip_out_args ipoa = { IFSCOPE_NONE, { 0 }, IPOAF_SELECT_SRCIF }; 115 116 if (sin_src == NULL || sin_dst == NULL || 117 sin_src->sin_family != AF_INET || 118 sin_dst->sin_family != AF_INET) { 119 m_freem(m); 120 return EAFNOSUPPORT; 121 } 122 123 switch (family) { 124#if INET 125 case AF_INET: 126 { 127 struct ip *ip; 128 129 proto = IPPROTO_IPV4; 130 if (mbuf_len(m) < sizeof(*ip)) { 131 m = m_pullup(m, sizeof(*ip)); 132 if (!m) 133 return ENOBUFS; 134 } 135 ip = mtod(m, struct ip *); 136 tos = ip->ip_tos; 137 break; 138 } 139#endif /*INET*/ 140#if INET6 141 case AF_INET6: 142 { 143 struct ip6_hdr *ip6; 144 proto = IPPROTO_IPV6; 145 if (mbuf_len(m) < sizeof(*ip6)) { 146 m = m_pullup(m, sizeof(*ip6)); 147 if (!m) 148 return ENOBUFS; 149 } 150 ip6 = mtod(m, struct ip6_hdr *); 151 tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 152 break; 153 } 154#endif /*INET6*/ 155 default: 156#if DEBUG 157 printf("in_gif_output: warning: unknown family %d passed\n", 158 family); 159#endif 160 m_freem(m); 161 return EAFNOSUPPORT; 162 } 163 164 bzero(&iphdr, sizeof(iphdr)); 165 iphdr.ip_src = sin_src->sin_addr; 166 /* bidirectional configured tunnel mode */ 167 if (sin_dst->sin_addr.s_addr != INADDR_ANY) 168 iphdr.ip_dst = sin_dst->sin_addr; 169 else { 170 m_freem(m); 171 return ENETUNREACH; 172 } 173 iphdr.ip_p = proto; 174 /* version will be set in ip_output() */ 175 iphdr.ip_ttl = ip_gif_ttl; 176 iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); 177 if (ifp->if_flags & IFF_LINK1) 178 ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); 179 else 180 ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos); 181 182 /* prepend new IP header */ 183 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 184 if (m && mbuf_len(m) < sizeof(struct ip)) 185 m = m_pullup(m, sizeof(struct ip)); 186 if (m == NULL) { 187 printf("ENOBUFS in in_gif_output %d\n", __LINE__); 188 return ENOBUFS; 189 } 190 bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip)); 191 192 if (dst->sin_family != sin_dst->sin_family || 193 dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr || 194 (sc->gif_ro.ro_rt != NULL && 195 (sc->gif_ro.ro_rt->generation_id != route_generation || 196 sc->gif_ro.ro_rt->rt_ifp == ifp))) { 197 /* cache route doesn't match or recursive route */ 198 dst->sin_family = sin_dst->sin_family; 199 dst->sin_len = sizeof(struct sockaddr_in); 200 dst->sin_addr = sin_dst->sin_addr; 201 if (sc->gif_ro.ro_rt) { 202 rtfree(sc->gif_ro.ro_rt); 203 sc->gif_ro.ro_rt = NULL; 204 } 205#if 0 206 sc->gif_if.if_mtu = GIF_MTU; 207#endif 208 } 209 210 if (sc->gif_ro.ro_rt == NULL) { 211 rtalloc(&sc->gif_ro); 212 if (sc->gif_ro.ro_rt == NULL) { 213 m_freem(m); 214 return ENETUNREACH; 215 } 216 217 /* if it constitutes infinite encapsulation, punt. */ 218 RT_LOCK(sc->gif_ro.ro_rt); 219 if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 220 RT_UNLOCK(sc->gif_ro.ro_rt); 221 m_freem(m); 222 return ENETUNREACH; /*XXX*/ 223 } 224#if 0 225 ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu 226 - sizeof(struct ip); 227#endif 228 RT_UNLOCK(sc->gif_ro.ro_rt); 229 } 230 231 error = ip_output(m, NULL, &sc->gif_ro, IP_OUTARGS, NULL, &ipoa); 232 return(error); 233} 234 235void 236in_gif_input(m, off) 237 struct mbuf *m; 238 int off; 239{ 240 struct ifnet *gifp = NULL; 241 struct ip *ip; 242 int af, proto; 243 u_int8_t otos; 244 245 ip = mtod(m, struct ip *); 246 proto = ip->ip_p; 247 248 249 gifp = ((struct gif_softc*)encap_getarg(m))->gif_if; 250 251 if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { 252 m_freem(m); 253 OSAddAtomic(1, &ipstat.ips_nogif); 254 return; 255 } 256 257 otos = ip->ip_tos; 258 m_adj(m, off); 259 260 switch (proto) { 261#if INET 262 case IPPROTO_IPV4: 263 { 264 af = AF_INET; 265 if (mbuf_len(m) < sizeof(*ip)) { 266 m = m_pullup(m, sizeof(*ip)); 267 if (!m) 268 return; 269 } 270 ip = mtod(m, struct ip *); 271 if (gifp->if_flags & IFF_LINK1) 272 ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); 273 else 274 ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos); 275 break; 276 } 277#endif 278#if INET6 279 case IPPROTO_IPV6: 280 { 281 struct ip6_hdr *ip6; 282 u_int8_t itos; 283 af = AF_INET6; 284 if (mbuf_len(m) < sizeof(*ip6)) { 285 m = m_pullup(m, sizeof(*ip6)); 286 if (!m) 287 return; 288 } 289 ip6 = mtod(m, struct ip6_hdr *); 290 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 291 if (gifp->if_flags & IFF_LINK1) 292 ip_ecn_egress(ECN_ALLOWED, &otos, &itos); 293 else 294 ip_ecn_egress(ECN_NOCARE, &otos, &itos); 295 ip6->ip6_flow &= ~htonl(0xff << 20); 296 ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 297 break; 298 } 299#endif /* INET6 */ 300 default: 301 OSAddAtomic(1, &ipstat.ips_nogif); 302 m_freem(m); 303 return; 304 } 305#ifdef __APPLE__ 306 /* Should we free m if dlil_input returns an error? */ 307 if (m->m_pkthdr.rcvif) /* replace the rcvif by gifp for dlil to route it correctly */ 308 m->m_pkthdr.rcvif = gifp; 309 ifnet_input(gifp, m, NULL); 310#else 311 gif_input(m, af, gifp); 312#endif 313 return; 314} 315 316static __inline__ void* 317_cast_non_const(const void * ptr) { 318 union { 319 const void* cval; 320 void* val; 321 } ret; 322 323 ret.cval = ptr; 324 return (ret.val); 325} 326 327/* 328 * we know that we are in IFF_UP, outer address available, and outer family 329 * matched the physical addr family. see gif_encapcheck(). 330 */ 331int 332gif_encapcheck4( 333 const struct mbuf *m, 334 __unused int off, 335 __unused int proto, 336 void *arg) 337{ 338 struct ip ip; 339 struct gif_softc *sc; 340 struct sockaddr_in *src, *dst; 341 int addrmatch; 342 struct in_ifaddr *ia4; 343 344 /* sanity check done in caller */ 345 sc = (struct gif_softc *)arg; 346 src = (struct sockaddr_in *)(void *)sc->gif_psrc; 347 dst = (struct sockaddr_in *)(void *)sc->gif_pdst; 348 349 mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof(ip), &ip); 350 351 /* check for address match */ 352 addrmatch = 0; 353 if (src->sin_addr.s_addr == ip.ip_dst.s_addr) 354 addrmatch |= 1; 355 if (dst->sin_addr.s_addr == ip.ip_src.s_addr) 356 addrmatch |= 2; 357 if (addrmatch != 3) 358 return 0; 359 360 /* martian filters on outer source - NOT done in ip_input! */ 361 if (IN_MULTICAST(ntohl(ip.ip_src.s_addr))) 362 return 0; 363 switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) { 364 case 0: case 127: case 255: 365 return 0; 366 } 367 /* reject packets with broadcast on source */ 368 lck_rw_lock_shared(in_ifaddr_rwlock); 369 for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4; 370 ia4 = TAILQ_NEXT(ia4, ia_link)) 371 { 372 if ((ifnet_flags(ia4->ia_ifa.ifa_ifp) & IFF_BROADCAST) == 0) 373 continue; 374 IFA_LOCK(&ia4->ia_ifa); 375 if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { 376 IFA_UNLOCK(&ia4->ia_ifa); 377 lck_rw_done(in_ifaddr_rwlock); 378 return 0; 379 } 380 IFA_UNLOCK(&ia4->ia_ifa); 381 } 382 lck_rw_done(in_ifaddr_rwlock); 383 384 /* ingress filters on outer source */ 385 if ((ifnet_flags(sc->gif_if) & IFF_LINK2) == 0 && 386 (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { 387 struct sockaddr_in sin; 388 struct rtentry *rt; 389 390 bzero(&sin, sizeof(sin)); 391 sin.sin_family = AF_INET; 392 sin.sin_len = sizeof(struct sockaddr_in); 393 sin.sin_addr = ip.ip_src; 394 rt = rtalloc1_scoped((struct sockaddr *)&sin, 0, 0, 395 m->m_pkthdr.rcvif->if_index); 396 if (rt != NULL) 397 RT_LOCK(rt); 398 if (rt == NULL || rt->rt_ifp != m->m_pkthdr.rcvif) { 399 if (rt != NULL) { 400 RT_UNLOCK(rt); 401 rtfree(rt); 402 } 403 return 0; 404 } 405 RT_UNLOCK(rt); 406 rtfree(rt); 407 } 408 409 return 32 * 2; 410} 411