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