in_gif.c revision 105340
198944Sobrien/*	$FreeBSD: head/sys/netinet/in_gif.c 105340 2002-10-17 17:47:55Z ume $	*/
298944Sobrien/*	$KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $	*/
398944Sobrien
498944Sobrien/*
598944Sobrien * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
698944Sobrien * All rights reserved.
798944Sobrien *
819370Spst * Redistribution and use in source and binary forms, with or without
998944Sobrien * modification, are permitted provided that the following conditions
1098944Sobrien * are met:
1119370Spst * 1. Redistributions of source code must retain the above copyright
1298944Sobrien *    notice, this list of conditions and the following disclaimer.
1398944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1498944Sobrien *    notice, this list of conditions and the following disclaimer in the
1598944Sobrien *    documentation and/or other materials provided with the distribution.
1619370Spst * 3. Neither the name of the project nor the names of its contributors
1798944Sobrien *    may be used to endorse or promote products derived from this software
1898944Sobrien *    without specific prior written permission.
1998944Sobrien *
2098944Sobrien * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2119370Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2298944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2398944Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2498944Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2598944Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2619370Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2719370Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2819370Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2919370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3019370Spst * SUCH DAMAGE.
3198944Sobrien */
3219370Spst
3319370Spst#include "opt_mrouting.h"
3419370Spst#include "opt_inet.h"
3519370Spst#include "opt_inet6.h"
3619370Spst
3719370Spst#include <sys/param.h>
3819370Spst#include <sys/systm.h>
3919370Spst#include <sys/socket.h>
4019370Spst#include <sys/sockio.h>
4119370Spst#include <sys/mbuf.h>
4219370Spst#include <sys/errno.h>
4319370Spst#include <sys/kernel.h>
4419370Spst#include <sys/sysctl.h>
4519370Spst#include <sys/protosw.h>
4619370Spst
4719370Spst#include <sys/malloc.h>
4819370Spst
4919370Spst#include <net/if.h>
5019370Spst#include <net/route.h>
5119370Spst
5219370Spst#include <netinet/in.h>
5346283Sdfr#include <netinet/in_systm.h>
5446283Sdfr#include <netinet/ip.h>
5546283Sdfr#include <netinet/ip_var.h>
5646283Sdfr#include <netinet/in_gif.h>
5746283Sdfr#include <netinet/in_var.h>
5846283Sdfr#include <netinet/ip_encap.h>
5946283Sdfr#include <netinet/ip_ecn.h>
6046283Sdfr
6119370Spst#ifdef INET6
6219370Spst#include <netinet/ip6.h>
6319370Spst#endif
6419370Spst
6519370Spst#ifdef MROUTING
6619370Spst#include <netinet/ip_mroute.h>
6719370Spst#endif /* MROUTING */
6819370Spst
6919370Spst#include <net/if_gif.h>
7019370Spst
7119370Spst#include <net/net_osdep.h>
7219370Spst
7319370Spststatic int gif_validate4(const struct ip *, struct gif_softc *,
7419370Spst	struct ifnet *);
7519370Spst
7619370Spstextern  struct domain inetdomain;
7719370Spststruct protosw in_gif_protosw =
7819370Spst{ SOCK_RAW,	&inetdomain,	0/*IPPROTO_IPV[46]*/,	PR_ATOMIC|PR_ADDR,
7919370Spst  in_gif_input,	(pr_output_t*)rip_output, 0,		rip_ctloutput,
8019370Spst  0,
8119370Spst  0,		0,		0,		0,
8219370Spst  &rip_usrreqs
8319370Spst};
8419370Spst
8519370Spststatic int ip_gif_ttl = GIF_TTL;
8619370SpstSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
8719370Spst	&ip_gif_ttl,	0, "");
8819370Spst
8919370Spstint
9019370Spstin_gif_output(ifp, family, m)
9119370Spst	struct ifnet	*ifp;
9219370Spst	int		family;
9319370Spst	struct mbuf	*m;
9419370Spst{
9519370Spst	struct gif_softc *sc = (struct gif_softc*)ifp;
9619370Spst	struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
9719370Spst	struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
9819370Spst	struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
9919370Spst	struct ip iphdr;	/* capsule IP header, host byte ordered */
10019370Spst	int proto, error;
10119370Spst	u_int8_t tos;
10219370Spst
10319370Spst	if (sin_src == NULL || sin_dst == NULL ||
10419370Spst	    sin_src->sin_family != AF_INET ||
10598944Sobrien	    sin_dst->sin_family != AF_INET) {
10698944Sobrien		m_freem(m);
10798944Sobrien		return EAFNOSUPPORT;
10898944Sobrien	}
10919370Spst
11019370Spst	switch (family) {
11119370Spst#ifdef INET
11219370Spst	case AF_INET:
11398944Sobrien	    {
11419370Spst		struct ip *ip;
11598944Sobrien
11619370Spst		proto = IPPROTO_IPV4;
11798944Sobrien		if (m->m_len < sizeof(*ip)) {
11898944Sobrien			m = m_pullup(m, sizeof(*ip));
11998944Sobrien			if (!m)
12098944Sobrien				return ENOBUFS;
12119370Spst		}
12298944Sobrien		ip = mtod(m, struct ip *);
123		tos = ip->ip_tos;
124		break;
125	    }
126#endif /* INET */
127#ifdef INET6
128	case AF_INET6:
129	    {
130		struct ip6_hdr *ip6;
131		proto = IPPROTO_IPV6;
132		if (m->m_len < sizeof(*ip6)) {
133			m = m_pullup(m, sizeof(*ip6));
134			if (!m)
135				return ENOBUFS;
136		}
137		ip6 = mtod(m, struct ip6_hdr *);
138		tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
139		break;
140	    }
141#endif /* INET6 */
142	default:
143#ifdef DEBUG
144		printf("in_gif_output: warning: unknown family %d passed\n",
145			family);
146#endif
147		m_freem(m);
148		return EAFNOSUPPORT;
149	}
150
151	bzero(&iphdr, sizeof(iphdr));
152	iphdr.ip_src = sin_src->sin_addr;
153	/* bidirectional configured tunnel mode */
154	if (sin_dst->sin_addr.s_addr != INADDR_ANY)
155		iphdr.ip_dst = sin_dst->sin_addr;
156	else {
157		m_freem(m);
158		return ENETUNREACH;
159	}
160	iphdr.ip_p = proto;
161	/* version will be set in ip_output() */
162	iphdr.ip_ttl = ip_gif_ttl;
163	iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
164	if (ifp->if_flags & IFF_LINK1)
165		ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos);
166	else
167		ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos);
168
169	/* prepend new IP header */
170	M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
171	if (m && m->m_len < sizeof(struct ip))
172		m = m_pullup(m, sizeof(struct ip));
173	if (m == NULL) {
174		printf("ENOBUFS in in_gif_output %d\n", __LINE__);
175		return ENOBUFS;
176	}
177	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
178
179	if (dst->sin_family != sin_dst->sin_family ||
180	    dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
181		/* cache route doesn't match */
182		dst->sin_family = sin_dst->sin_family;
183		dst->sin_len = sizeof(struct sockaddr_in);
184		dst->sin_addr = sin_dst->sin_addr;
185		if (sc->gif_ro.ro_rt) {
186			RTFREE(sc->gif_ro.ro_rt);
187			sc->gif_ro.ro_rt = NULL;
188		}
189#if 0
190		sc->gif_if.if_mtu = GIF_MTU;
191#endif
192	}
193
194	if (sc->gif_ro.ro_rt == NULL) {
195		rtalloc(&sc->gif_ro);
196		if (sc->gif_ro.ro_rt == NULL) {
197			m_freem(m);
198			return ENETUNREACH;
199		}
200
201		/* if it constitutes infinite encapsulation, punt. */
202		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
203			m_freem(m);
204			return ENETUNREACH;	/* XXX */
205		}
206#if 0
207		ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
208			- sizeof(struct ip);
209#endif
210	}
211
212	error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL);
213	return(error);
214}
215
216void
217in_gif_input(m, off)
218	struct mbuf *m;
219	int off;
220{
221	struct ifnet *gifp = NULL;
222	struct ip *ip;
223	int af;
224	u_int8_t otos;
225	int proto;
226
227	ip = mtod(m, struct ip *);
228	proto = ip->ip_p;
229
230	gifp = (struct ifnet *)encap_getarg(m);
231
232	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
233		m_freem(m);
234		ipstat.ips_nogif++;
235		return;
236	}
237
238	otos = ip->ip_tos;
239	m_adj(m, off);
240
241	switch (proto) {
242#ifdef INET
243	case IPPROTO_IPV4:
244	    {
245		struct ip *ip;
246		af = AF_INET;
247		if (m->m_len < sizeof(*ip)) {
248			m = m_pullup(m, sizeof(*ip));
249			if (!m)
250				return;
251		}
252		ip = mtod(m, struct ip *);
253		if (gifp->if_flags & IFF_LINK1)
254			ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos);
255		else
256			ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos);
257		break;
258	    }
259#endif
260#ifdef INET6
261	case IPPROTO_IPV6:
262	    {
263		struct ip6_hdr *ip6;
264		u_int8_t itos;
265		af = AF_INET6;
266		if (m->m_len < sizeof(*ip6)) {
267			m = m_pullup(m, sizeof(*ip6));
268			if (!m)
269				return;
270		}
271		ip6 = mtod(m, struct ip6_hdr *);
272		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
273		if (gifp->if_flags & IFF_LINK1)
274			ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
275		else
276			ip_ecn_egress(ECN_NOCARE, &otos, &itos);
277		ip6->ip6_flow &= ~htonl(0xff << 20);
278		ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
279		break;
280	    }
281#endif /* INET6 */
282	default:
283		ipstat.ips_nogif++;
284		m_freem(m);
285		return;
286	}
287	gif_input(m, af, gifp);
288	return;
289}
290
291/*
292 * validate outer address.
293 */
294static int
295gif_validate4(ip, sc, ifp)
296	const struct ip *ip;
297	struct gif_softc *sc;
298	struct ifnet *ifp;
299{
300	struct sockaddr_in *src, *dst;
301	struct in_ifaddr *ia4;
302
303	src = (struct sockaddr_in *)sc->gif_psrc;
304	dst = (struct sockaddr_in *)sc->gif_pdst;
305
306	/* check for address match */
307	if (src->sin_addr.s_addr != ip->ip_dst.s_addr ||
308	    dst->sin_addr.s_addr != ip->ip_src.s_addr)
309		return 0;
310
311	/* martian filters on outer source - NOT done in ip_input! */
312	if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)))
313		return 0;
314	switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) {
315	case 0: case 127: case 255:
316		return 0;
317	}
318	/* reject packets with broadcast on source */
319	TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link)
320	{
321		if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
322			continue;
323		if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
324			return 0;
325	}
326
327	/* ingress filters on outer source */
328	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
329		struct sockaddr_in sin;
330		struct rtentry *rt;
331
332		bzero(&sin, sizeof(sin));
333		sin.sin_family = AF_INET;
334		sin.sin_len = sizeof(struct sockaddr_in);
335		sin.sin_addr = ip->ip_src;
336		rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
337		if (!rt || rt->rt_ifp != ifp) {
338#if 0
339			log(LOG_WARNING, "%s: packet from 0x%x dropped "
340			    "due to ingress filter\n", if_name(&sc->gif_if),
341			    (u_int32_t)ntohl(sin.sin_addr.s_addr));
342#endif
343			if (rt)
344				rtfree(rt);
345			return 0;
346		}
347		rtfree(rt);
348	}
349
350	return 32 * 2;
351}
352
353/*
354 * we know that we are in IFF_UP, outer address available, and outer family
355 * matched the physical addr family.  see gif_encapcheck().
356 */
357int
358gif_encapcheck4(m, off, proto, arg)
359	const struct mbuf *m;
360	int off;
361	int proto;
362	void *arg;
363{
364	struct ip ip;
365	struct gif_softc *sc;
366	struct ifnet *ifp;
367
368	/* sanity check done in caller */
369	sc = (struct gif_softc *)arg;
370
371	/* LINTED const cast */
372	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
373	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
374
375	return gif_validate4(&ip, sc, ifp);
376}
377
378int
379in_gif_attach(sc)
380	struct gif_softc *sc;
381{
382	sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck,
383	    &in_gif_protosw, sc);
384	if (sc->encap_cookie4 == NULL)
385		return EEXIST;
386	return 0;
387}
388
389int
390in_gif_detach(sc)
391	struct gif_softc *sc;
392{
393	int error;
394
395	error = encap_detach(sc->encap_cookie4);
396	if (error == 0)
397		sc->encap_cookie4 = NULL;
398	return error;
399}
400