1/* 2 * Copyright (c) 2000-2007 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 96extern u_long route_generation; 97 98int ip_gif_ttl = GIF_TTL; 99SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, 100 &ip_gif_ttl, 0, ""); 101 102int 103in_gif_output( 104 struct ifnet *ifp, 105 int family, 106 struct mbuf *m, 107 __unused struct rtentry *rt) 108{ 109 struct gif_softc *sc = ifnet_softc(ifp); 110 struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; 111 struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; 112 struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; 113 struct ip iphdr; /* capsule IP header, host byte ordered */ 114 int proto, error; 115 u_int8_t tos; 116 struct ip_out_args ipoa = { IFSCOPE_NONE }; 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 (dst->sin_family != sin_dst->sin_family || 195 dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr || 196 (sc->gif_ro.ro_rt != NULL && 197 (sc->gif_ro.ro_rt->generation_id != route_generation || 198 sc->gif_ro.ro_rt->rt_ifp == ifp))) { 199 /* cache route doesn't match */ 200 dst->sin_family = sin_dst->sin_family; 201 dst->sin_len = sizeof(struct sockaddr_in); 202 dst->sin_addr = sin_dst->sin_addr; 203 if (sc->gif_ro.ro_rt) { 204 rtfree(sc->gif_ro.ro_rt); 205 sc->gif_ro.ro_rt = NULL; 206 } 207#if 0 208 sc->gif_if.if_mtu = GIF_MTU; 209#endif 210 } 211 212 if (sc->gif_ro.ro_rt == NULL) { 213 rtalloc(&sc->gif_ro); 214 if (sc->gif_ro.ro_rt == NULL) { 215 m_freem(m); 216 return ENETUNREACH; 217 } 218 219 /* if it constitutes infinite encapsulation, punt. */ 220 if (sc->gif_ro.ro_rt->rt_ifp == ifp) { 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 } 229 230 error = ip_output(m, NULL, &sc->gif_ro, IP_OUTARGS, NULL, &ipoa); 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, (SInt32*)&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, (SInt32*)&ipstat.ips_nogif); 301 m_freem(m); 302 return; 303 } 304#ifdef __APPLE__ 305 /* Should we free m if dlil_input returns an error? */ 306 if (m->m_pkthdr.rcvif) /* replace the rcvif by gifp for dlil to route it correctly */ 307 m->m_pkthdr.rcvif = gifp; 308 ifnet_input(gifp, m, NULL); 309#else 310 gif_input(m, af, gifp); 311#endif 312 return; 313} 314 315static __inline__ void* 316_cast_non_const(const void * ptr) { 317 union { 318 const void* cval; 319 void* val; 320 } ret; 321 322 ret.cval = ptr; 323 return (ret.val); 324} 325 326/* 327 * we know that we are in IFF_UP, outer address available, and outer family 328 * matched the physical addr family. see gif_encapcheck(). 329 */ 330int 331gif_encapcheck4( 332 const struct mbuf *m, 333 __unused int off, 334 __unused int proto, 335 void *arg) 336{ 337 struct ip ip; 338 struct gif_softc *sc; 339 struct sockaddr_in *src, *dst; 340 int addrmatch; 341 struct in_ifaddr *ia4; 342 343 /* sanity check done in caller */ 344 sc = (struct gif_softc *)arg; 345 src = (struct sockaddr_in *)sc->gif_psrc; 346 dst = (struct sockaddr_in *)sc->gif_pdst; 347 348 mbuf_copydata(m, 0, sizeof(ip), &ip); 349 350 /* check for address match */ 351 addrmatch = 0; 352 if (src->sin_addr.s_addr == ip.ip_dst.s_addr) 353 addrmatch |= 1; 354 if (dst->sin_addr.s_addr == ip.ip_src.s_addr) 355 addrmatch |= 2; 356 if (addrmatch != 3) 357 return 0; 358 359 /* martian filters on outer source - NOT done in ip_input! */ 360 if (IN_MULTICAST(ntohl(ip.ip_src.s_addr))) 361 return 0; 362 switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) { 363 case 0: case 127: case 255: 364 return 0; 365 } 366 /* reject packets with broadcast on source */ 367 lck_mtx_lock(rt_mtx); 368 for (ia4 = TAILQ_FIRST(&in_ifaddrhead); ia4; 369 ia4 = TAILQ_NEXT(ia4, ia_link)) 370 { 371 if ((ifnet_flags(ia4->ia_ifa.ifa_ifp) & IFF_BROADCAST) == 0) 372 continue; 373 if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { 374 lck_mtx_unlock(rt_mtx); 375 return 0; 376 } 377 } 378 lck_mtx_unlock(rt_mtx); 379 380 /* ingress filters on outer source */ 381 if ((ifnet_flags(sc->gif_if) & IFF_LINK2) == 0 && 382 (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { 383 struct sockaddr_in sin; 384 struct rtentry *rt; 385 386 bzero(&sin, sizeof(sin)); 387 sin.sin_family = AF_INET; 388 sin.sin_len = sizeof(struct sockaddr_in); 389 sin.sin_addr = ip.ip_src; 390 lck_mtx_lock(rt_mtx); 391 rt = rtalloc1_scoped_locked((struct sockaddr *)&sin, 0, 0, 392 m->m_pkthdr.rcvif->if_index); 393 lck_mtx_unlock(rt_mtx); 394 if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) { 395#if 0 396 log(LOG_WARNING, "%s: packet from 0x%x dropped " 397 "due to ingress filter\n", if_name(&sc->gif_if), 398 (u_int32_t)ntohl(sin.sin_addr.s_addr)); 399#endif 400 if (rt) 401 rtfree(rt); 402 return 0; 403 } 404 rtfree(rt); 405 } 406 407 return 32 * 2; 408} 409