ip6_ipsec.c revision 283901
144743Smarkm/*-
244743Smarkm * Copyright (c) 1982, 1986, 1988, 1993
344743Smarkm *      The Regents of the University of California.  All rights reserved.
444743Smarkm *
544743Smarkm * Redistribution and use in source and binary forms, with or without
644743Smarkm * modification, are permitted provided that the following conditions
744743Smarkm * are met:
844743Smarkm * 1. Redistributions of source code must retain the above copyright
944743Smarkm *    notice, this list of conditions and the following disclaimer.
1044743Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1144743Smarkm *    notice, this list of conditions and the following disclaimer in the
1244743Smarkm *    documentation and/or other materials provided with the distribution.
1344743Smarkm * 4. Neither the name of the University nor the names of its contributors
1444743Smarkm *    may be used to endorse or promote products derived from this software
1544743Smarkm *    without specific prior written permission.
1644743Smarkm *
1744743Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1844743Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1944743Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2044743Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2144743Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2244743Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2344743Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2444743Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2544743Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2644743Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2744743Smarkm * SUCH DAMAGE.
2844743Smarkm */
2944743Smarkm
3044743Smarkm#include <sys/cdefs.h>
3144743Smarkm__FBSDID("$FreeBSD: stable/10/sys/netinet6/ip6_ipsec.c 283901 2015-06-02 03:14:42Z ae $");
3244743Smarkm
3344743Smarkm#include "opt_inet.h"
3444743Smarkm#include "opt_inet6.h"
3544743Smarkm#include "opt_ipsec.h"
3644743Smarkm
3744743Smarkm#include <sys/param.h>
3844743Smarkm#include <sys/systm.h>
3944743Smarkm#include <sys/kernel.h>
4044743Smarkm#include <sys/mac.h>
4144743Smarkm#include <sys/malloc.h>
4244743Smarkm#include <sys/mbuf.h>
4344743Smarkm#include <sys/protosw.h>
4444743Smarkm#include <sys/socket.h>
4544743Smarkm#include <sys/socketvar.h>
4644743Smarkm#include <sys/sysctl.h>
4744743Smarkm#include <sys/syslog.h>
4844743Smarkm
4944743Smarkm#include <net/if.h>
5044743Smarkm#include <net/vnet.h>
5144743Smarkm
5244743Smarkm#include <netinet/in.h>
5344743Smarkm#include <netinet/in_systm.h>
5444743Smarkm#include <netinet/in_var.h>
5544743Smarkm#include <netinet/ip.h>
5644743Smarkm#include <netinet/ip6.h>
5744743Smarkm#include <netinet/in_pcb.h>
5844743Smarkm#include <netinet/ip_var.h>
5944743Smarkm#include <netinet/ip_options.h>
6044743Smarkm
6144743Smarkm#include <machine/in_cksum.h>
6244743Smarkm
6344743Smarkm#ifdef IPSEC
6444743Smarkm#include <netipsec/ipsec.h>
6544743Smarkm#include <netipsec/ipsec6.h>
6644743Smarkm#include <netipsec/xform.h>
6744743Smarkm#include <netipsec/key.h>
6844743Smarkm#ifdef IPSEC_DEBUG
6944743Smarkm#include <netipsec/key_debug.h>
7044743Smarkm#else
7144743Smarkm#define	KEYDEBUG(lev,arg)
7244743Smarkm#endif
7344743Smarkm#endif /*IPSEC*/
7444743Smarkm
7544743Smarkm#include <netinet6/ip6_ipsec.h>
7644743Smarkm#include <netinet6/ip6_var.h>
7744743Smarkm
7844743Smarkmextern	struct protosw inet6sw[];
7944743Smarkm
8044743Smarkm
8144743Smarkm#ifdef INET6
8244743Smarkm#ifdef IPSEC
8344743Smarkm#ifdef IPSEC_FILTERTUNNEL
8444743Smarkmstatic VNET_DEFINE(int, ip6_ipsec6_filtertunnel) = 1;
8544743Smarkm#else
8644743Smarkmstatic VNET_DEFINE(int, ip6_ipsec6_filtertunnel) = 0;
8744743Smarkm#endif
8844743Smarkm#define	V_ip6_ipsec6_filtertunnel	VNET(ip6_ipsec6_filtertunnel)
8944743Smarkm
9044743SmarkmSYSCTL_DECL(_net_inet6_ipsec6);
9144743SmarkmSYSCTL_VNET_INT(_net_inet6_ipsec6, OID_AUTO,
9244743Smarkm	filtertunnel, CTLFLAG_RW, &VNET_NAME(ip6_ipsec6_filtertunnel),  0,
9344743Smarkm	"If set filter packets from an IPsec tunnel.");
9444743Smarkm#endif /* IPSEC */
9544743Smarkm#endif /* INET6 */
9644743Smarkm
9744743Smarkm/*
9844743Smarkm * Check if we have to jump over firewall processing for this packet.
9944743Smarkm * Called from ip6_input().
10044743Smarkm * 1 = jump over firewall, 0 = packet goes through firewall.
10144743Smarkm */
10244743Smarkmint
10344743Smarkmip6_ipsec_filtertunnel(struct mbuf *m)
10444743Smarkm{
10544743Smarkm#ifdef IPSEC
10644743Smarkm
10744743Smarkm	/*
10844743Smarkm	 * Bypass packet filtering for packets previously handled by IPsec.
10944743Smarkm	 */
11044743Smarkm	if (!V_ip6_ipsec6_filtertunnel &&
11144743Smarkm	    m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) != NULL)
11244743Smarkm		return 1;
11344743Smarkm#endif
11444743Smarkm	return 0;
11544743Smarkm}
11644743Smarkm
11744743Smarkm/*
11844743Smarkm * Check if this packet has an active SA and needs to be dropped instead
11944743Smarkm * of forwarded.
12044743Smarkm * Called from ip6_input().
12144743Smarkm * 1 = drop packet, 0 = forward packet.
12244743Smarkm */
12344743Smarkmint
12444743Smarkmip6_ipsec_fwd(struct mbuf *m)
12544743Smarkm{
12644743Smarkm#ifdef IPSEC
12744743Smarkm	struct m_tag *mtag;
12844743Smarkm	struct tdb_ident *tdbi;
12944743Smarkm	struct secpolicy *sp;
13044743Smarkm	int error;
13144743Smarkm	mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
13244743Smarkm	if (mtag != NULL) {
13344743Smarkm		tdbi = (struct tdb_ident *)(mtag + 1);
13444743Smarkm		sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
13544743Smarkm	} else {
13644743Smarkm		sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
13744743Smarkm					   IP_FORWARDING, &error);
13844743Smarkm	}
13944743Smarkm	if (sp == NULL) {	/* NB: can happen if error */
14044743Smarkm		/*XXX error stat???*/
14144743Smarkm		DPRINTF(("%s: no SP for forwarding\n", __func__));	/*XXX*/
14244743Smarkm		return 1;
14344743Smarkm	}
14444743Smarkm
14544743Smarkm	/*
14644743Smarkm	 * Check security policy against packet attributes.
14744743Smarkm	 */
14844743Smarkm	error = ipsec_in_reject(sp, m);
14944743Smarkm	KEY_FREESP(&sp);
15044743Smarkm	if (error) {
15144743Smarkm		IP6STAT_INC(ip6s_cantforward);
15244743Smarkm		return 1;
15344743Smarkm	}
15444743Smarkm#endif /* IPSEC */
15544743Smarkm	return 0;
15644743Smarkm}
15744743Smarkm
15844743Smarkm/*
15944743Smarkm * Check if protocol type doesn't have a further header and do IPSEC
16044743Smarkm * decryption or reject right now.  Protocols with further headers get
16144743Smarkm * their IPSEC treatment within the protocol specific processing.
16244743Smarkm * Called from ip6_input().
16344743Smarkm * 1 = drop packet, 0 = continue processing packet.
16444743Smarkm */
16544743Smarkmint
16644743Smarkmip6_ipsec_input(struct mbuf *m, int nxt)
16744743Smarkm{
16844743Smarkm#ifdef IPSEC
16944743Smarkm	struct m_tag *mtag;
17044743Smarkm	struct tdb_ident *tdbi;
17144743Smarkm	struct secpolicy *sp;
17244743Smarkm	int error;
17344743Smarkm	/*
17444743Smarkm	 * enforce IPsec policy checking if we are seeing last header.
17544743Smarkm	 * note that we do not visit this with protocols with pcb layer
17644743Smarkm	 * code - like udp/tcp/raw ip.
17744743Smarkm	 */
17844743Smarkm	if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
17944743Smarkm	    ipsec6_in_reject(m, NULL)) {
18044743Smarkm
18144743Smarkm		/*
18244743Smarkm		 * Check if the packet has already had IPsec processing
18344743Smarkm		 * done.  If so, then just pass it along.  This tag gets
18444743Smarkm		 * set during AH, ESP, etc. input handling, before the
18544743Smarkm		 * packet is returned to the ip input queue for delivery.
18644743Smarkm		 */
18744743Smarkm		mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL);
18844743Smarkm		if (mtag != NULL) {
18944743Smarkm			tdbi = (struct tdb_ident *)(mtag + 1);
19044743Smarkm			sp = ipsec_getpolicy(tdbi, IPSEC_DIR_INBOUND);
19144743Smarkm		} else {
19244743Smarkm			sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
19344743Smarkm						   IP_FORWARDING, &error);
19444743Smarkm		}
19544743Smarkm		if (sp != NULL) {
19644743Smarkm			/*
19744743Smarkm			 * Check security policy against packet attributes.
19844743Smarkm			 */
19944743Smarkm			error = ipsec_in_reject(sp, m);
20044743Smarkm			KEY_FREESP(&sp);
20144743Smarkm		} else {
20244743Smarkm			/* XXX error stat??? */
20344743Smarkm			error = EINVAL;
20444743Smarkm			DPRINTF(("%s: no SP, packet discarded\n", __func__));/*XXX*/
20544743Smarkm			return 1;
20644743Smarkm		}
20744743Smarkm		if (error)
20844743Smarkm			return 1;
20944743Smarkm	}
21044743Smarkm#endif /* IPSEC */
21144743Smarkm	return 0;
21244743Smarkm}
21344743Smarkm
21444743Smarkm/*
21544743Smarkm * Called from ip6_output().
21644743Smarkm * 1 = drop packet, 0 = continue processing packet,
21744743Smarkm * -1 = packet was reinjected and stop processing packet
21844743Smarkm */
21944743Smarkm
22044743Smarkmint
22144743Smarkmip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error,
22244743Smarkm    struct ifnet **ifp)
22344743Smarkm{
22444743Smarkm#ifdef IPSEC
22544743Smarkm	struct secpolicy *sp = NULL;
22644743Smarkm	struct tdb_ident *tdbi;
22744743Smarkm	struct m_tag *mtag;
22844743Smarkm	/* XXX int s; */
22944743Smarkm	mtag = m_tag_find(*m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
23044743Smarkm	if (mtag != NULL) {
23144743Smarkm		tdbi = (struct tdb_ident *)(mtag + 1);
23244743Smarkm		sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND);
23344743Smarkm		if (sp == NULL)
23444743Smarkm			*error = -EINVAL;	/* force silent drop */
23544743Smarkm		m_tag_delete(*m, mtag);
23644743Smarkm	} else {
23744743Smarkm		sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, *flags,
23844743Smarkm					error, inp);
23944743Smarkm	}
24044743Smarkm
24144743Smarkm	/*
24244743Smarkm	 * There are four return cases:
24344743Smarkm	 *    sp != NULL		    apply IPsec policy
24444743Smarkm	 *    sp == NULL, error == 0	    no IPsec handling needed
24544743Smarkm	 *    sp == NULL, error == -EINVAL  discard packet w/o error
24644743Smarkm	 *    sp == NULL, error != 0	    discard packet, report error
24744743Smarkm	 */
24844743Smarkm	if (sp != NULL) {
24944743Smarkm		/* Loop detection, check if ipsec processing already done */
25044743Smarkm		KASSERT(sp->req != NULL, ("ip_output: no ipsec request"));
25144743Smarkm		for (mtag = m_tag_first(*m); mtag != NULL;
25244743Smarkm		     mtag = m_tag_next(*m, mtag)) {
25344743Smarkm			if (mtag->m_tag_cookie != MTAG_ABI_COMPAT)
25444743Smarkm				continue;
25544743Smarkm			if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE &&
25644743Smarkm			    mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED)
25744743Smarkm				continue;
25844743Smarkm			/*
25944743Smarkm			 * Check if policy has no SA associated with it.
26044743Smarkm			 * This can happen when an SP has yet to acquire
26144743Smarkm			 * an SA; e.g. on first reference.  If it occurs,
26244743Smarkm			 * then we let ipsec4_process_packet do its thing.
26344743Smarkm			 */
26444743Smarkm			if (sp->req->sav == NULL)
26544743Smarkm				break;
26644743Smarkm			tdbi = (struct tdb_ident *)(mtag + 1);
26744743Smarkm			if (tdbi->spi == sp->req->sav->spi &&
26844743Smarkm			    tdbi->proto == sp->req->sav->sah->saidx.proto &&
26944743Smarkm			    bcmp(&tdbi->dst, &sp->req->sav->sah->saidx.dst,
27044743Smarkm				 sizeof (union sockaddr_union)) == 0) {
27144743Smarkm				/*
27244743Smarkm				 * No IPsec processing is needed, free
27344743Smarkm				 * reference to SP.
27444743Smarkm				 */
27544743Smarkm				goto done;
27644743Smarkm			}
27744743Smarkm		}
27844743Smarkm
27944743Smarkm		/*
28044743Smarkm		 * Do delayed checksums now because we send before
28144743Smarkm		 * this is done in the normal processing path.
28244743Smarkm		 */
28344743Smarkm#ifdef INET
28444743Smarkm		if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
28544743Smarkm			in_delayed_cksum(*m);
28644743Smarkm			(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
28744743Smarkm		}
28844743Smarkm#endif
28944743Smarkm		if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
29044743Smarkm			in6_delayed_cksum(*m, (*m)->m_pkthdr.len - sizeof(struct ip6_hdr),
29144743Smarkm							sizeof(struct ip6_hdr));
29244743Smarkm			(*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
29344743Smarkm		}
29444743Smarkm#ifdef SCTP
29544743Smarkm		if ((*m)->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) {
29644743Smarkm			sctp_delayed_cksum(*m, sizeof(struct ip6_hdr));
29744743Smarkm			(*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6;
29844743Smarkm		}
29944743Smarkm#endif
30044743Smarkm
30144743Smarkm		/* NB: callee frees mbuf */
30244743Smarkm		*error = ipsec6_process_packet(*m, sp->req);
30344743Smarkm
30444743Smarkm		if (*error == EJUSTRETURN) {
30544743Smarkm			/*
30644743Smarkm			 * We had a SP with a level of 'use' and no SA. We
30744743Smarkm			 * will just continue to process the packet without
30844743Smarkm			 * IPsec processing.
30944743Smarkm			 */
31044743Smarkm			*error = 0;
31144743Smarkm			goto done;
31244743Smarkm		}
31344743Smarkm
31444743Smarkm		/*
31544743Smarkm		 * Preserve KAME behaviour: ENOENT can be returned
31644743Smarkm		 * when an SA acquire is in progress.  Don't propagate
31744743Smarkm		 * this to user-level; it confuses applications.
31844743Smarkm		 *
31944743Smarkm		 * XXX this will go away when the SADB is redone.
32044743Smarkm		 */
32144743Smarkm		if (*error == ENOENT)
32244743Smarkm			*error = 0;
32344743Smarkm		goto reinjected;
32444743Smarkm	} else {	/* sp == NULL */
32544743Smarkm		if (*error != 0) {
32644743Smarkm			/*
32744743Smarkm			 * Hack: -EINVAL is used to signal that a packet
32844743Smarkm			 * should be silently discarded.  This is typically
32944743Smarkm			 * because we asked key management for an SA and
33044743Smarkm			 * it was delayed (e.g. kicked up to IKE).
33144743Smarkm			 */
33244743Smarkm			if (*error == -EINVAL)
33344743Smarkm				*error = 0;
33444743Smarkm			goto bad;
33544743Smarkm		} else {
33644743Smarkm			/* No IPsec processing for this packet. */
33744743Smarkm		}
33844743Smarkm	}
33944743Smarkmdone:
34044743Smarkm	if (sp != NULL)
34144743Smarkm		KEY_FREESP(&sp);
34244743Smarkm	return 0;
34344743Smarkmreinjected:
34444743Smarkm	if (sp != NULL)
34544743Smarkm		KEY_FREESP(&sp);
34644743Smarkm	return -1;
34744743Smarkmbad:
34844743Smarkm	if (sp != NULL)
34944743Smarkm		KEY_FREESP(&sp);
35044743Smarkm	return 1;
35144743Smarkm#endif /* IPSEC */
35244743Smarkm	return 0;
35344743Smarkm}
35444743Smarkm
35544743Smarkm#if 0
35644743Smarkm/*
35744743Smarkm * Compute the MTU for a forwarded packet that gets IPSEC encapsulated.
35844743Smarkm * Called from ip_forward().
35944743Smarkm * Returns MTU suggestion for ICMP needfrag reply.
36044743Smarkm */
36144743Smarkmint
36244743Smarkmip6_ipsec_mtu(struct mbuf *m)
36344743Smarkm{
36444743Smarkm	int mtu = 0;
36544743Smarkm	/*
36644743Smarkm	 * If the packet is routed over IPsec tunnel, tell the
36744743Smarkm	 * originator the tunnel MTU.
36844743Smarkm	 *	tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
36944743Smarkm	 * XXX quickhack!!!
37044743Smarkm	 */
37144743Smarkm#ifdef IPSEC
37244743Smarkm	struct secpolicy *sp = NULL;
37344743Smarkm	int ipsecerror;
37444743Smarkm	int ipsechdr;
37544743Smarkm	struct route *ro;
37644743Smarkm	sp = ipsec_getpolicybyaddr(m,
37744743Smarkm				   IPSEC_DIR_OUTBOUND,
37844743Smarkm				   IP_FORWARDING,
37944743Smarkm				   &ipsecerror);
38044743Smarkm	if (sp != NULL) {
38144743Smarkm		/* count IPsec header size */
38244743Smarkm		ipsechdr = ipsec_hdrsiz(m, IPSEC_DIR_OUTBOUND, NULL);
38344743Smarkm
38444743Smarkm		/*
38544743Smarkm		 * find the correct route for outer IPv4
38644743Smarkm		 * header, compute tunnel MTU.
38744743Smarkm		 */
38844743Smarkm		if (sp->req != NULL &&
38944743Smarkm		    sp->req->sav != NULL &&
39044743Smarkm		    sp->req->sav->sah != NULL) {
39144743Smarkm			ro = &sp->req->sav->sah->route_cache.sa_route;
39244743Smarkm			if (ro->ro_rt && ro->ro_rt->rt_ifp) {
39344743Smarkm				mtu = ro->ro_rt->rt_mtu ? ro->ro_rt->rt_mtu :
39444743Smarkm				    ro->ro_rt->rt_ifp->if_mtu;
39544743Smarkm				mtu -= ipsechdr;
39644743Smarkm			}
39744743Smarkm		}
39844743Smarkm		KEY_FREESP(&sp);
39944743Smarkm	}
40044743Smarkm#endif /* IPSEC */
40144743Smarkm	/* XXX else case missing. */
40244743Smarkm	return mtu;
40344743Smarkm}
40444743Smarkm#endif
40544743Smarkm