xref: /netbsd-src/sys/netipsec/ipsec.c (revision 5142f0296136d74a7facfc851453f2223c3a725d)
1*5142f029Smsaitoh /* $NetBSD: ipsec.c,v 1.179 2024/05/13 00:12:33 msaitoh Exp $ */
2e2c8a664Smaxv /* $FreeBSD: ipsec.c,v 1.2.2.2 2003/07/01 01:38:13 sam Exp $ */
374029031Sjonathan /* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
474029031Sjonathan 
574029031Sjonathan /*
674029031Sjonathan  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
774029031Sjonathan  * All rights reserved.
874029031Sjonathan  *
974029031Sjonathan  * Redistribution and use in source and binary forms, with or without
1074029031Sjonathan  * modification, are permitted provided that the following conditions
1174029031Sjonathan  * are met:
1274029031Sjonathan  * 1. Redistributions of source code must retain the above copyright
1374029031Sjonathan  *	notice, this list of conditions and the following disclaimer.
1474029031Sjonathan  * 2. Redistributions in binary form must reproduce the above copyright
1574029031Sjonathan  *	notice, this list of conditions and the following disclaimer in the
1674029031Sjonathan  *	documentation and/or other materials provided with the distribution.
1774029031Sjonathan  * 3. Neither the name of the project nor the names of its contributors
1874029031Sjonathan  *	may be used to endorse or promote products derived from this software
1974029031Sjonathan  *	without specific prior written permission.
2074029031Sjonathan  *
2174029031Sjonathan  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2274029031Sjonathan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2374029031Sjonathan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2474029031Sjonathan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2574029031Sjonathan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2674029031Sjonathan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2774029031Sjonathan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2874029031Sjonathan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2974029031Sjonathan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3074029031Sjonathan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3174029031Sjonathan  * SUCH DAMAGE.
3274029031Sjonathan  */
3374029031Sjonathan 
3474029031Sjonathan #include <sys/cdefs.h>
35*5142f029Smsaitoh __KERNEL_RCSID(0, "$NetBSD: ipsec.c,v 1.179 2024/05/13 00:12:33 msaitoh Exp $");
3674029031Sjonathan 
3774029031Sjonathan /*
3874029031Sjonathan  * IPsec controller part.
3974029031Sjonathan  */
4074029031Sjonathan 
4180d40a78Sozaki-r #if defined(_KERNEL_OPT)
4274029031Sjonathan #include "opt_inet.h"
4374029031Sjonathan #include "opt_ipsec.h"
4480d40a78Sozaki-r #endif
4574029031Sjonathan 
4674029031Sjonathan #include <sys/param.h>
4774029031Sjonathan #include <sys/systm.h>
4874029031Sjonathan #include <sys/mbuf.h>
4974029031Sjonathan #include <sys/domain.h>
5074029031Sjonathan #include <sys/protosw.h>
5174029031Sjonathan #include <sys/socket.h>
5274029031Sjonathan #include <sys/socketvar.h>
5374029031Sjonathan #include <sys/errno.h>
5474029031Sjonathan #include <sys/time.h>
5574029031Sjonathan #include <sys/kernel.h>
5674029031Sjonathan #include <sys/syslog.h>
5774029031Sjonathan #include <sys/sysctl.h>
5874029031Sjonathan #include <sys/proc.h>
59efeb620eSelad #include <sys/kauth.h>
6020448372Sozaki-r #include <sys/cpu.h>
6120448372Sozaki-r #include <sys/kmem.h>
620c084e85Sozaki-r #include <sys/pserialize.h>
6374029031Sjonathan 
6474029031Sjonathan #include <net/if.h>
6574029031Sjonathan #include <net/route.h>
6674029031Sjonathan 
6774029031Sjonathan #include <netinet/in.h>
6874029031Sjonathan #include <netinet/in_systm.h>
6974029031Sjonathan #include <netinet/ip.h>
7074029031Sjonathan #include <netinet/ip_var.h>
7174029031Sjonathan #include <netinet/in_var.h>
7274029031Sjonathan #include <netinet/udp.h>
7374029031Sjonathan #include <netinet/udp_var.h>
7474029031Sjonathan #include <netinet/tcp.h>
7574029031Sjonathan #include <netinet/udp.h>
76fa014c63Smlelstv #include <netinet/ip_icmp.h>
777cb08cfdSrmind #include <netinet/ip_private.h>
7874029031Sjonathan 
7974029031Sjonathan #include <netinet/ip6.h>
8074029031Sjonathan #ifdef INET6
8174029031Sjonathan #include <netinet6/ip6_var.h>
8274029031Sjonathan #endif
8374029031Sjonathan #include <netinet/in_pcb.h>
843574e990Smaxv #include <netinet/in_offload.h>
8574029031Sjonathan #ifdef INET6
86e139b206Sjonathan #include <netinet6/in6_pcb.h>
8774029031Sjonathan #include <netinet/icmp6.h>
8874029031Sjonathan #endif
8974029031Sjonathan 
9074029031Sjonathan #include <netipsec/ipsec.h>
9185b3ba5bSjonathan #include <netipsec/ipsec_var.h>
92caf49ea5Sthorpej #include <netipsec/ipsec_private.h>
9374029031Sjonathan #ifdef INET6
9474029031Sjonathan #include <netipsec/ipsec6.h>
9574029031Sjonathan #endif
9674029031Sjonathan #include <netipsec/ah_var.h>
9774029031Sjonathan #include <netipsec/esp_var.h>
9874029031Sjonathan #include <netipsec/ipcomp.h>		/*XXX*/
9974029031Sjonathan #include <netipsec/ipcomp_var.h>
10074029031Sjonathan 
1019355900eStls #include <netipsec/key.h>
1029355900eStls #include <netipsec/keydb.h>
1039355900eStls #include <netipsec/key_debug.h>
10474029031Sjonathan 
10574029031Sjonathan #include <netipsec/xform.h>
10674029031Sjonathan 
1075d61e6c0Schristos int ipsec_used = 0;
1085d61e6c0Schristos int ipsec_enabled = 1;
1095d61e6c0Schristos 
11074029031Sjonathan #ifdef IPSEC_DEBUG
11174029031Sjonathan int ipsec_debug = 1;
11268699904Srpaulo 
11368699904Srpaulo /*
11468699904Srpaulo  * When set to 1, IPsec will send packets with the same sequence number.
11568699904Srpaulo  * This allows to verify if the other side has proper replay attacks detection.
11668699904Srpaulo  */
11768699904Srpaulo int ipsec_replay = 0;
11868699904Srpaulo 
11968699904Srpaulo /*
12068699904Srpaulo  * When set 1, IPsec will send packets with corrupted HMAC.
12168699904Srpaulo  * This allows to verify if the other side properly detects modified packets.
12268699904Srpaulo  */
12368699904Srpaulo int ipsec_integrity = 0;
12474029031Sjonathan #else
12574029031Sjonathan int ipsec_debug = 0;
12674029031Sjonathan #endif
12774029031Sjonathan 
128caf49ea5Sthorpej percpu_t *ipsecstat_percpu;
1299a3c5d51Smaxv 
13074029031Sjonathan int ip4_ah_offsetmask = 0;	/* maybe IP_DF? */
1319152d0e1Schristos int ip4_ipsec_dfbit = 2;	/* DF bit on encap. 0: clear 1: set 2: copy */
13274029031Sjonathan int ip4_esp_trans_deflev = IPSEC_LEVEL_USE;
13374029031Sjonathan int ip4_esp_net_deflev = IPSEC_LEVEL_USE;
13474029031Sjonathan int ip4_ah_trans_deflev = IPSEC_LEVEL_USE;
13574029031Sjonathan int ip4_ah_net_deflev = IPSEC_LEVEL_USE;
13674029031Sjonathan struct secpolicy ip4_def_policy;
13774029031Sjonathan int ip4_ipsec_ecn = 0;		/* ECN ignore(-1)/forbidden(0)/allowed(1) */
138ce5ecc33Sthorpej 
139ce5ecc33Sthorpej u_int ipsec_spdgen = 1;		/* SPD generation # */
140ce5ecc33Sthorpej 
141603defb9Sozaki-r static struct secpolicy ipsec_dummy_sp __read_mostly = {
142603defb9Sozaki-r 	.state		= IPSEC_SPSTATE_ALIVE,
143603defb9Sozaki-r 	/* If ENTRUST, the dummy SP never be used. See ipsec_getpolicybysock. */
144603defb9Sozaki-r 	.policy		= IPSEC_POLICY_ENTRUST,
145603defb9Sozaki-r };
146603defb9Sozaki-r 
147a382db0aSdegroote static struct secpolicy *ipsec_checkpcbcache(struct mbuf *,
148a382db0aSdegroote     struct inpcbpolicy *, int);
149a382db0aSdegroote static int ipsec_fillpcbcache(struct inpcbpolicy *, struct mbuf *,
150a382db0aSdegroote     struct secpolicy *, int);
151a382db0aSdegroote static int ipsec_invalpcbcache(struct inpcbpolicy *, int);
152ce5ecc33Sthorpej 
15374029031Sjonathan /*
15474029031Sjonathan  * Crypto support requirements:
15574029031Sjonathan  *
15674029031Sjonathan  *  1	require hardware support
15774029031Sjonathan  * -1	require software support
15874029031Sjonathan  *  0	take anything
15974029031Sjonathan  */
16074029031Sjonathan int crypto_support = 0;
16174029031Sjonathan 
162e139b206Sjonathan static struct secpolicy *ipsec_getpolicybysock(struct mbuf *, u_int,
1630e390eeeSozaki-r     struct inpcb *, int *);
164e139b206Sjonathan 
16574029031Sjonathan #ifdef INET6
16674029031Sjonathan int ip6_esp_trans_deflev = IPSEC_LEVEL_USE;
16774029031Sjonathan int ip6_esp_net_deflev = IPSEC_LEVEL_USE;
16874029031Sjonathan int ip6_ah_trans_deflev = IPSEC_LEVEL_USE;
16974029031Sjonathan int ip6_ah_net_deflev = IPSEC_LEVEL_USE;
170e139b206Sjonathan struct secpolicy ip6_def_policy;
17174029031Sjonathan int ip6_ipsec_ecn = 0;		/* ECN ignore(-1)/forbidden(0)/allowed(1) */
1729a3c5d51Smaxv #endif
17374029031Sjonathan 
1740e390eeeSozaki-r static int ipsec_setspidx_inpcb(struct mbuf *, struct inpcb *);
175e201bd44Smaxv static int ipsec_setspidx(struct mbuf *, struct secpolicyindex *, int, int);
176a382db0aSdegroote static void ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *, int);
177a382db0aSdegroote static int ipsec4_setspidx_ipaddr(struct mbuf *, struct secpolicyindex *);
17874029031Sjonathan #ifdef INET6
179a382db0aSdegroote static void ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *, int);
180a382db0aSdegroote static int ipsec6_setspidx_ipaddr(struct mbuf *, struct secpolicyindex *);
18174029031Sjonathan #endif
182a382db0aSdegroote static void ipsec_delpcbpolicy(struct inpcbpolicy *);
1830c084e85Sozaki-r static void ipsec_destroy_policy(struct secpolicy *);
184af69f639Smaxv static int ipsec_sp_reject(const struct secpolicy *, const struct mbuf *);
185a382db0aSdegroote static void vshiftl(unsigned char *, int, int);
186af69f639Smaxv static size_t ipsec_sp_hdrsiz(const struct secpolicy *, const struct mbuf *);
18774029031Sjonathan 
188ce5ecc33Sthorpej /*
189ce5ecc33Sthorpej  * Try to validate and use cached policy on a PCB.
190ce5ecc33Sthorpej  */
191ce5ecc33Sthorpej static struct secpolicy *
ipsec_checkpcbcache(struct mbuf * m,struct inpcbpolicy * pcbsp,int dir)192ce5ecc33Sthorpej ipsec_checkpcbcache(struct mbuf *m, struct inpcbpolicy *pcbsp, int dir)
193ce5ecc33Sthorpej {
194ce5ecc33Sthorpej 	struct secpolicyindex spidx;
1950c084e85Sozaki-r 	struct secpolicy *sp = NULL;
1960c084e85Sozaki-r 	int s;
197ce5ecc33Sthorpej 
1980df8f574Sozaki-r 	KASSERT(IPSEC_DIR_IS_VALID(dir));
19950d790a0Sozaki-r 	KASSERT(pcbsp != NULL);
2008db5286dSozaki-r 	KASSERT(dir < __arraycount(pcbsp->sp_cache));
2010e390eeeSozaki-r 	KASSERT(inp_locked(pcbsp->sp_inp));
20250d790a0Sozaki-r 
2030c084e85Sozaki-r 	/*
2040c084e85Sozaki-r 	 * Checking the generation and sp->state and taking a reference to an SP
2050c084e85Sozaki-r 	 * must be in a critical section of pserialize. See key_unlink_sp.
2060c084e85Sozaki-r 	 */
2070c084e85Sozaki-r 	s = pserialize_read_enter();
208ce5ecc33Sthorpej 	/* SPD table change invalidate all the caches. */
209ce5ecc33Sthorpej 	if (ipsec_spdgen != pcbsp->sp_cache[dir].cachegen) {
210ce5ecc33Sthorpej 		ipsec_invalpcbcache(pcbsp, dir);
2110c084e85Sozaki-r 		goto out;
212ce5ecc33Sthorpej 	}
2130c084e85Sozaki-r 	sp = pcbsp->sp_cache[dir].cachesp;
2140c084e85Sozaki-r 	if (sp == NULL)
2150c084e85Sozaki-r 		goto out;
2160c084e85Sozaki-r 	if (sp->state != IPSEC_SPSTATE_ALIVE) {
2170c084e85Sozaki-r 		sp = NULL;
218ce5ecc33Sthorpej 		ipsec_invalpcbcache(pcbsp, dir);
2190c084e85Sozaki-r 		goto out;
220ce5ecc33Sthorpej 	}
221ce5ecc33Sthorpej 	if ((pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) == 0) {
2220c084e85Sozaki-r 		/* NB: assume ipsec_setspidx never sleep */
223e201bd44Smaxv 		if (ipsec_setspidx(m, &spidx, dir, 1) != 0) {
2240c084e85Sozaki-r 			sp = NULL;
2250c084e85Sozaki-r 			goto out;
2260c084e85Sozaki-r 		}
22740cf3d18Sdegroote 
22840cf3d18Sdegroote 		/*
22940cf3d18Sdegroote 		 * We have to make an exact match here since the cached rule
23040cf3d18Sdegroote 		 * might have lower priority than a rule that would otherwise
23140cf3d18Sdegroote 		 * have matched the packet.
23240cf3d18Sdegroote 		 */
2330c084e85Sozaki-r 		if (memcmp(&pcbsp->sp_cache[dir].cacheidx, &spidx,
2340c084e85Sozaki-r 		    sizeof(spidx))) {
2350c084e85Sozaki-r 			sp = NULL;
2360c084e85Sozaki-r 			goto out;
2370c084e85Sozaki-r 		}
238ce5ecc33Sthorpej 	} else {
239ce5ecc33Sthorpej 		/*
240ce5ecc33Sthorpej 		 * The pcb is connected, and the L4 code is sure that:
241ce5ecc33Sthorpej 		 * - outgoing side uses inp_[lf]addr
242ce5ecc33Sthorpej 		 * - incoming side looks up policy after inpcb lookup
243ce5ecc33Sthorpej 		 * and address pair is know to be stable.  We do not need
244ce5ecc33Sthorpej 		 * to generate spidx again, nor check the address match again.
245ce5ecc33Sthorpej 		 *
246ce5ecc33Sthorpej 		 * For IPv4/v6 SOCK_STREAM sockets, this assumptions holds
2472ba9f052Sozaki-r 		 * and there are calls to ipsec_pcbconn() from inpcb_connect().
248ce5ecc33Sthorpej 		 */
249ce5ecc33Sthorpej 	}
250ce5ecc33Sthorpej 
251fea168e1Sknakahara 	key_sp_touch(sp);
2520c084e85Sozaki-r 	KEY_SP_REF(sp);
2536208c225Sozaki-r 	KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
2546208c225Sozaki-r 	    "DP cause refcnt++:%d SP:%p\n",
2550c084e85Sozaki-r 	    key_sp_refcnt(sp), pcbsp->sp_cache[dir].cachesp);
2560c084e85Sozaki-r out:
2570c084e85Sozaki-r 	pserialize_read_exit(s);
2580c084e85Sozaki-r 	return sp;
259ce5ecc33Sthorpej }
260ce5ecc33Sthorpej 
261ce5ecc33Sthorpej static int
ipsec_fillpcbcache(struct inpcbpolicy * pcbsp,struct mbuf * m,struct secpolicy * sp,int dir)262ce5ecc33Sthorpej ipsec_fillpcbcache(struct inpcbpolicy *pcbsp, struct mbuf *m,
263ce5ecc33Sthorpej     struct secpolicy *sp, int dir)
264ce5ecc33Sthorpej {
265ce5ecc33Sthorpej 
2660df8f574Sozaki-r 	KASSERT(IPSEC_DIR_IS_INOROUT(dir));
2678db5286dSozaki-r 	KASSERT(dir < __arraycount(pcbsp->sp_cache));
2680e390eeeSozaki-r 	KASSERT(inp_locked(pcbsp->sp_inp));
269ce5ecc33Sthorpej 
270ce5ecc33Sthorpej 	pcbsp->sp_cache[dir].cachesp = NULL;
271a11fe343Sozaki-r 	pcbsp->sp_cache[dir].cachehint = IPSEC_PCBHINT_UNKNOWN;
272e201bd44Smaxv 	if (ipsec_setspidx(m, &pcbsp->sp_cache[dir].cacheidx, dir, 1) != 0) {
273ce5ecc33Sthorpej 		return EINVAL;
274ce5ecc33Sthorpej 	}
275ce5ecc33Sthorpej 	pcbsp->sp_cache[dir].cachesp = sp;
276ce5ecc33Sthorpej 	if (pcbsp->sp_cache[dir].cachesp) {
277ce5ecc33Sthorpej 		/*
278ce5ecc33Sthorpej 		 * If the PCB is connected, we can remember a hint to
279ce5ecc33Sthorpej 		 * possibly short-circuit IPsec processing in other places.
280ce5ecc33Sthorpej 		 */
281ce5ecc33Sthorpej 		if (pcbsp->sp_cacheflags & IPSEC_PCBSP_CONNECTED) {
282ce5ecc33Sthorpej 			switch (pcbsp->sp_cache[dir].cachesp->policy) {
283ce5ecc33Sthorpej 			case IPSEC_POLICY_NONE:
284ce5ecc33Sthorpej 			case IPSEC_POLICY_BYPASS:
285ce5ecc33Sthorpej 				pcbsp->sp_cache[dir].cachehint =
286ce5ecc33Sthorpej 				    IPSEC_PCBHINT_NO;
287ce5ecc33Sthorpej 				break;
288ce5ecc33Sthorpej 			default:
289ce5ecc33Sthorpej 				pcbsp->sp_cache[dir].cachehint =
290ce5ecc33Sthorpej 				    IPSEC_PCBHINT_YES;
291ce5ecc33Sthorpej 			}
292ce5ecc33Sthorpej 		}
293ce5ecc33Sthorpej 	}
294ce5ecc33Sthorpej 	pcbsp->sp_cache[dir].cachegen = ipsec_spdgen;
295ce5ecc33Sthorpej 
296ce5ecc33Sthorpej 	return 0;
297ce5ecc33Sthorpej }
298ce5ecc33Sthorpej 
299ce5ecc33Sthorpej static int
ipsec_invalpcbcache(struct inpcbpolicy * pcbsp,int dir)300ce5ecc33Sthorpej ipsec_invalpcbcache(struct inpcbpolicy *pcbsp, int dir)
301ce5ecc33Sthorpej {
302ce5ecc33Sthorpej 	int i;
303ce5ecc33Sthorpej 
3040e390eeeSozaki-r 	KASSERT(inp_locked(pcbsp->sp_inp));
3055cfcce1fSozaki-r 
306ce5ecc33Sthorpej 	for (i = IPSEC_DIR_INBOUND; i <= IPSEC_DIR_OUTBOUND; i++) {
307ce5ecc33Sthorpej 		if (dir != IPSEC_DIR_ANY && i != dir)
308ce5ecc33Sthorpej 			continue;
309ce5ecc33Sthorpej 		pcbsp->sp_cache[i].cachesp = NULL;
310a11fe343Sozaki-r 		pcbsp->sp_cache[i].cachehint = IPSEC_PCBHINT_UNKNOWN;
311ce5ecc33Sthorpej 		pcbsp->sp_cache[i].cachegen = 0;
312c363a9cbScegger 		memset(&pcbsp->sp_cache[i].cacheidx, 0,
313ce5ecc33Sthorpej 		    sizeof(pcbsp->sp_cache[i].cacheidx));
314ce5ecc33Sthorpej 	}
315ce5ecc33Sthorpej 	return 0;
316ce5ecc33Sthorpej }
317ce5ecc33Sthorpej 
318ce5ecc33Sthorpej void
ipsec_pcbconn(struct inpcbpolicy * pcbsp)319ce5ecc33Sthorpej ipsec_pcbconn(struct inpcbpolicy *pcbsp)
320ce5ecc33Sthorpej {
321ce5ecc33Sthorpej 
3220e390eeeSozaki-r 	KASSERT(inp_locked(pcbsp->sp_inp));
3235cfcce1fSozaki-r 
324ce5ecc33Sthorpej 	pcbsp->sp_cacheflags |= IPSEC_PCBSP_CONNECTED;
325ce5ecc33Sthorpej 	ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY);
326ce5ecc33Sthorpej }
327ce5ecc33Sthorpej 
328ce5ecc33Sthorpej void
ipsec_pcbdisconn(struct inpcbpolicy * pcbsp)329ce5ecc33Sthorpej ipsec_pcbdisconn(struct inpcbpolicy *pcbsp)
330ce5ecc33Sthorpej {
331ce5ecc33Sthorpej 
3320e390eeeSozaki-r 	KASSERT(inp_locked(pcbsp->sp_inp));
3335cfcce1fSozaki-r 
334ce5ecc33Sthorpej 	pcbsp->sp_cacheflags &= ~IPSEC_PCBSP_CONNECTED;
335ce5ecc33Sthorpej 	ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY);
336ce5ecc33Sthorpej }
337ce5ecc33Sthorpej 
338ce5ecc33Sthorpej void
ipsec_invalpcbcacheall(void)339ce5ecc33Sthorpej ipsec_invalpcbcacheall(void)
340ce5ecc33Sthorpej {
341ce5ecc33Sthorpej 
342ce5ecc33Sthorpej 	if (ipsec_spdgen == UINT_MAX)
343ce5ecc33Sthorpej 		ipsec_spdgen = 1;
344ce5ecc33Sthorpej 	else
345ce5ecc33Sthorpej 		ipsec_spdgen++;
346ce5ecc33Sthorpej }
347ce5ecc33Sthorpej 
34874029031Sjonathan /*
34974029031Sjonathan  * Return a held reference to the default SP.
35074029031Sjonathan  */
35174029031Sjonathan static struct secpolicy *
key_get_default_sp(int af,const char * where,int tag)3526f13f59fSozaki-r key_get_default_sp(int af, const char *where, int tag)
35374029031Sjonathan {
35474029031Sjonathan 	struct secpolicy *sp;
35574029031Sjonathan 
3566208c225Sozaki-r 	KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP, "DP from %s:%u\n", where, tag);
35774029031Sjonathan 
3586997fa5fSdegroote 	switch(af) {
3596997fa5fSdegroote 	case AF_INET:
36074029031Sjonathan 		sp = &ip4_def_policy;
3616997fa5fSdegroote 		break;
3626997fa5fSdegroote #ifdef INET6
3636997fa5fSdegroote 	case AF_INET6:
3646997fa5fSdegroote 		sp = &ip6_def_policy;
3656997fa5fSdegroote 		break;
3666997fa5fSdegroote #endif
3676997fa5fSdegroote 	default:
3686208c225Sozaki-r 		KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
3696208c225Sozaki-r 		    "unexpected protocol family %u\n", af);
3706997fa5fSdegroote 		return NULL;
3716997fa5fSdegroote 	}
3726997fa5fSdegroote 
37374029031Sjonathan 	if (sp->policy != IPSEC_POLICY_DISCARD &&
37474029031Sjonathan 	    sp->policy != IPSEC_POLICY_NONE) {
375290dc492Sozaki-r 		IPSECLOG(LOG_INFO, "fixed system default policy: %d->%d\n",
376290dc492Sozaki-r 		    sp->policy, IPSEC_POLICY_NONE);
37774029031Sjonathan 		sp->policy = IPSEC_POLICY_NONE;
37874029031Sjonathan 	}
37990bba4b2Sozaki-r 	KEY_SP_REF(sp);
38074029031Sjonathan 
3816208c225Sozaki-r 	KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP, "DP returns SP:%p (%u)\n",
382a0f7ae36Sozaki-r 	    sp, key_sp_refcnt(sp));
38374029031Sjonathan 	return sp;
38474029031Sjonathan }
3859a3c5d51Smaxv 
3866f13f59fSozaki-r #define	KEY_GET_DEFAULT_SP(af) \
3876f13f59fSozaki-r 	key_get_default_sp((af), __func__, __LINE__)
38874029031Sjonathan 
38974029031Sjonathan /*
39074029031Sjonathan  * For OUTBOUND packet having a socket. Searching SPD for packet,
39174029031Sjonathan  * and return a pointer to SP.
39265b46b60Smaxv  * OUT:	NULL:	no appropriate SP found, the following value is set to error.
39374029031Sjonathan  *		0	: bypass
39474029031Sjonathan  *		EACCES	: discard packet.
39574029031Sjonathan  *		ENOENT	: ipsec_acquire() in progress, maybe.
396f05e6f1aSwiz  *		others	: error occurred.
39774029031Sjonathan  *	others:	a pointer to SP
39874029031Sjonathan  *
3995d1e8b27Swiz  * NOTE: IPv6 mapped address concern is implemented here.
40074029031Sjonathan  */
401e139b206Sjonathan static struct secpolicy *
ipsec_getpolicybysock(struct mbuf * m,u_int dir,struct inpcb * inp,int * error)4020e390eeeSozaki-r ipsec_getpolicybysock(struct mbuf *m, u_int dir, struct inpcb *inp,
403ef67739aSozaki-r     int *error)
40474029031Sjonathan {
40574029031Sjonathan 	struct inpcbpolicy *pcbsp = NULL;
40674029031Sjonathan 	struct secpolicy *currsp = NULL;	/* policy on socket */
40774029031Sjonathan 	struct secpolicy *sp;
40874029031Sjonathan 	int af;
40974029031Sjonathan 
4102620e166Sozaki-r 	KASSERT(m != NULL);
4110e390eeeSozaki-r 	KASSERT(inp != NULL);
4122620e166Sozaki-r 	KASSERT(error != NULL);
4130df8f574Sozaki-r 	KASSERTMSG(IPSEC_DIR_IS_INOROUT(dir), "invalid direction %u", dir);
41474029031Sjonathan 
4150e390eeeSozaki-r 	KASSERT(inp->inp_socket != NULL);
4160e390eeeSozaki-r 	KASSERT(inp_locked(inp));
417e139b206Sjonathan 
4180e390eeeSozaki-r 	/* XXX FIXME inpcb vs socket*/
4190e390eeeSozaki-r 	af = inp->inp_af;
4202620e166Sozaki-r 	KASSERTMSG(af == AF_INET || af == AF_INET6,
4212620e166Sozaki-r 	    "unexpected protocol family %u", af);
42274029031Sjonathan 
4230e390eeeSozaki-r 	KASSERT(inp->inp_sp != NULL);
424ce5ecc33Sthorpej 	/* If we have a cached entry, and if it is still valid, use it. */
425caf49ea5Sthorpej 	IPSEC_STATINC(IPSEC_STAT_SPDCACHELOOKUP);
4260e390eeeSozaki-r 	currsp = ipsec_checkpcbcache(m, inp->inp_sp, dir);
427ce5ecc33Sthorpej 	if (currsp) {
428ce5ecc33Sthorpej 		*error = 0;
429ce5ecc33Sthorpej 		return currsp;
430ce5ecc33Sthorpej 	}
431caf49ea5Sthorpej 	IPSEC_STATINC(IPSEC_STAT_SPDCACHEMISS);
432ce5ecc33Sthorpej 
43374029031Sjonathan 	switch (af) {
434d219e3b4Smaxv 	case AF_INET:
435e139b206Sjonathan #if defined(INET6)
436d219e3b4Smaxv 	case AF_INET6:
43774029031Sjonathan #endif
4380e390eeeSozaki-r 		*error = ipsec_setspidx_inpcb(m, inp);
4390e390eeeSozaki-r 		pcbsp = inp->inp_sp;
440d219e3b4Smaxv 		break;
44174029031Sjonathan 	default:
44274029031Sjonathan 		*error = EPFNOSUPPORT;
44374029031Sjonathan 		break;
44474029031Sjonathan 	}
44574029031Sjonathan 	if (*error)
44674029031Sjonathan 		return NULL;
44774029031Sjonathan 
4482620e166Sozaki-r 	KASSERT(pcbsp != NULL);
44974029031Sjonathan 	switch (dir) {
45074029031Sjonathan 	case IPSEC_DIR_INBOUND:
45174029031Sjonathan 		currsp = pcbsp->sp_in;
45274029031Sjonathan 		break;
45374029031Sjonathan 	case IPSEC_DIR_OUTBOUND:
45474029031Sjonathan 		currsp = pcbsp->sp_out;
45574029031Sjonathan 		break;
45674029031Sjonathan 	}
4572620e166Sozaki-r 	KASSERT(currsp != NULL);
45874029031Sjonathan 
45952489f2bSmaxv 	if (pcbsp->priv) {	/* when privileged socket */
46074029031Sjonathan 		switch (currsp->policy) {
46174029031Sjonathan 		case IPSEC_POLICY_BYPASS:
46274029031Sjonathan 		case IPSEC_POLICY_IPSEC:
46390bba4b2Sozaki-r 			KEY_SP_REF(currsp);
46474029031Sjonathan 			sp = currsp;
46574029031Sjonathan 			break;
46674029031Sjonathan 
46774029031Sjonathan 		case IPSEC_POLICY_ENTRUST:
46874029031Sjonathan 			/* look for a policy in SPD */
469683fe570Sknakahara 			if (key_havesp(dir))
4706f13f59fSozaki-r 				sp = KEY_LOOKUP_SP_BYSPIDX(&currsp->spidx, dir);
471683fe570Sknakahara 			else
472683fe570Sknakahara 				sp = NULL;
47374029031Sjonathan 			if (sp == NULL)		/* no SP found */
4746f13f59fSozaki-r 				sp = KEY_GET_DEFAULT_SP(af);
47574029031Sjonathan 			break;
47674029031Sjonathan 
47774029031Sjonathan 		default:
478290dc492Sozaki-r 			IPSECLOG(LOG_ERR, "Invalid policy for PCB %d\n",
479290dc492Sozaki-r 			    currsp->policy);
48074029031Sjonathan 			*error = EINVAL;
48174029031Sjonathan 			return NULL;
48274029031Sjonathan 		}
48374029031Sjonathan 	} else {				/* unpriv, SPD has policy */
484683fe570Sknakahara 		if (key_havesp(dir))
4856f13f59fSozaki-r 			sp = KEY_LOOKUP_SP_BYSPIDX(&currsp->spidx, dir);
486683fe570Sknakahara 		else
487683fe570Sknakahara 			sp = NULL;
48874029031Sjonathan 		if (sp == NULL) {		/* no SP found */
48974029031Sjonathan 			switch (currsp->policy) {
49074029031Sjonathan 			case IPSEC_POLICY_BYPASS:
491290dc492Sozaki-r 				IPSECLOG(LOG_ERR, "Illegal policy for "
492*5142f029Smsaitoh 				    "non-privileged defined %d\n",
493290dc492Sozaki-r 				    currsp->policy);
49474029031Sjonathan 				*error = EINVAL;
49574029031Sjonathan 				return NULL;
49674029031Sjonathan 
49774029031Sjonathan 			case IPSEC_POLICY_ENTRUST:
4986f13f59fSozaki-r 				sp = KEY_GET_DEFAULT_SP(af);
49974029031Sjonathan 				break;
50074029031Sjonathan 
50174029031Sjonathan 			case IPSEC_POLICY_IPSEC:
50290bba4b2Sozaki-r 				KEY_SP_REF(currsp);
50374029031Sjonathan 				sp = currsp;
50474029031Sjonathan 				break;
50574029031Sjonathan 
50674029031Sjonathan 			default:
507290dc492Sozaki-r 				IPSECLOG(LOG_ERR, "Invalid policy for "
508290dc492Sozaki-r 				    "PCB %d\n", currsp->policy);
50974029031Sjonathan 				*error = EINVAL;
51074029031Sjonathan 				return NULL;
51174029031Sjonathan 			}
51274029031Sjonathan 		}
51374029031Sjonathan 	}
5142620e166Sozaki-r 	KASSERTMSG(sp != NULL, "null SP (priv %u policy %u", pcbsp->priv,
5152620e166Sozaki-r 	    currsp->policy);
5166208c225Sozaki-r 	KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_STAMP,
5176208c225Sozaki-r 	    "DP (priv %u policy %u) allocates SP:%p (refcnt %u)\n",
518a0f7ae36Sozaki-r 	    pcbsp->priv, currsp->policy, sp, key_sp_refcnt(sp));
519ce5ecc33Sthorpej 	ipsec_fillpcbcache(pcbsp, m, sp, dir);
52074029031Sjonathan 	return sp;
52174029031Sjonathan }
52274029031Sjonathan 
52374029031Sjonathan /*
524af69f639Smaxv  * For FORWARDING packet or OUTBOUND without a socket. Searching SPD for packet,
52574029031Sjonathan  * and return a pointer to SP.
52674029031Sjonathan  * OUT:	positive: a pointer to the entry for security policy leaf matched.
52765b46b60Smaxv  *	NULL:	no appropriate SP found, the following value is set to error.
52874029031Sjonathan  *		0	: bypass
52974029031Sjonathan  *		EACCES	: discard packet.
53074029031Sjonathan  *		ENOENT	: ipsec_acquire() in progress, maybe.
531f05e6f1aSwiz  *		others	: error occurred.
53274029031Sjonathan  */
53322e66c74Smaxv static struct secpolicy *
ipsec_getpolicybyaddr(struct mbuf * m,u_int dir,int flag,int * error)534a382db0aSdegroote ipsec_getpolicybyaddr(struct mbuf *m, u_int dir, int flag, int *error)
53574029031Sjonathan {
53674029031Sjonathan 	struct secpolicyindex spidx;
53774029031Sjonathan 	struct secpolicy *sp;
53874029031Sjonathan 
5392620e166Sozaki-r 	KASSERT(m != NULL);
5402620e166Sozaki-r 	KASSERT(error != NULL);
5410df8f574Sozaki-r 	KASSERTMSG(IPSEC_DIR_IS_INOROUT(dir), "invalid direction %u", dir);
54274029031Sjonathan 
54374029031Sjonathan 	sp = NULL;
5445f72dadbSdegroote 
54574029031Sjonathan 	/* Make an index to look for a policy. */
5464a727625Sknakahara 	*error = ipsec_setspidx(m, &spidx, dir, 1);
54774029031Sjonathan 	if (*error != 0) {
548290dc492Sozaki-r 		IPSECLOG(LOG_DEBUG, "setpidx failed, dir %u flag %u\n", dir, flag);
549c363a9cbScegger 		memset(&spidx, 0, sizeof(spidx));
55074029031Sjonathan 		return NULL;
55174029031Sjonathan 	}
5525f72dadbSdegroote 
55374029031Sjonathan 	spidx.dir = dir;
55474029031Sjonathan 
5555f72dadbSdegroote 	if (key_havesp(dir)) {
5566f13f59fSozaki-r 		sp = KEY_LOOKUP_SP_BYSPIDX(&spidx, dir);
55774029031Sjonathan 	}
55825be83d5Smaxv 	if (sp == NULL) {
55925be83d5Smaxv 		/* no SP found, use system default */
5606f13f59fSozaki-r 		sp = KEY_GET_DEFAULT_SP(spidx.dst.sa.sa_family);
56125be83d5Smaxv 	}
56225be83d5Smaxv 
5632620e166Sozaki-r 	KASSERT(sp != NULL);
56474029031Sjonathan 	return sp;
56574029031Sjonathan }
56674029031Sjonathan 
56722e66c74Smaxv static struct secpolicy *
ipsec_checkpolicy(struct mbuf * m,u_int dir,u_int flag,int * error,struct inpcb * inp)5682953bb25Smaxv ipsec_checkpolicy(struct mbuf *m, u_int dir, u_int flag, int *error,
5690e390eeeSozaki-r     struct inpcb *inp)
57074029031Sjonathan {
57174029031Sjonathan 	struct secpolicy *sp;
57274029031Sjonathan 
57374029031Sjonathan 	*error = 0;
574e139b206Sjonathan 
575ed8b1986Sozaki-r 	if (inp == NULL) {
57674029031Sjonathan 		sp = ipsec_getpolicybyaddr(m, dir, flag, error);
577ed8b1986Sozaki-r 	} else {
5780e390eeeSozaki-r 		KASSERT(inp->inp_socket != NULL);
5790e390eeeSozaki-r 		sp = ipsec_getpolicybysock(m, dir, inp, error);
580ed8b1986Sozaki-r 	}
58174029031Sjonathan 	if (sp == NULL) {
5822620e166Sozaki-r 		KASSERTMSG(*error != 0, "getpolicy failed w/o error");
583caf49ea5Sthorpej 		IPSEC_STATINC(IPSEC_STAT_OUT_INVAL);
58474029031Sjonathan 		return NULL;
58574029031Sjonathan 	}
5862620e166Sozaki-r 	KASSERTMSG(*error == 0, "sp w/ error set to %u", *error);
58716a6b570Smaxv 
58874029031Sjonathan 	switch (sp->policy) {
58974029031Sjonathan 	case IPSEC_POLICY_ENTRUST:
59074029031Sjonathan 	default:
59136443d4aSchristos 		printf("%s: invalid policy %u\n", __func__, sp->policy);
59274029031Sjonathan 		/* fall thru... */
59374029031Sjonathan 	case IPSEC_POLICY_DISCARD:
594caf49ea5Sthorpej 		IPSEC_STATINC(IPSEC_STAT_OUT_POLVIO);
59574029031Sjonathan 		*error = -EINVAL;	/* packet is discarded by caller */
59674029031Sjonathan 		break;
59774029031Sjonathan 	case IPSEC_POLICY_BYPASS:
59874029031Sjonathan 	case IPSEC_POLICY_NONE:
5990c084e85Sozaki-r 		KEY_SP_UNREF(&sp);
60074029031Sjonathan 		sp = NULL;		/* NB: force NULL result */
60174029031Sjonathan 		break;
60274029031Sjonathan 	case IPSEC_POLICY_IPSEC:
60318db854eSozaki-r 		KASSERT(sp->req != NULL);
60474029031Sjonathan 		break;
60574029031Sjonathan 	}
60616a6b570Smaxv 
60774029031Sjonathan 	if (*error != 0) {
6080c084e85Sozaki-r 		KEY_SP_UNREF(&sp);
60974029031Sjonathan 		sp = NULL;
610290dc492Sozaki-r 		IPSECLOG(LOG_DEBUG, "done, error %d\n", *error);
61174029031Sjonathan 	}
61216a6b570Smaxv 
61374029031Sjonathan 	return sp;
61474029031Sjonathan }
61574029031Sjonathan 
616e4506547Srmind int
ipsec4_output(struct mbuf * m,struct inpcb * inp,int flags,u_long * mtu,bool * natt_frag,bool * done,bool * count_drop)6172495e7a0Sozaki-r ipsec4_output(struct mbuf *m, struct inpcb *inp, int flags,
618c1e00d7dSozaki-r     u_long *mtu, bool *natt_frag, bool *done, bool *count_drop)
619e4506547Srmind {
620e4506547Srmind 	struct secpolicy *sp = NULL;
62152489f2bSmaxv 	u_long _mtu = 0;
622986909fbSozaki-r 	int error;
623e4506547Srmind 
624e4506547Srmind 	/*
625e4506547Srmind 	 * Check the security policy (SP) for the packet and, if required,
626e4506547Srmind 	 * do IPsec-related processing.  There are two cases here; the first
627e4506547Srmind 	 * time a packet is sent through it will be untagged and handled by
6282953bb25Smaxv 	 * ipsec_checkpolicy().  If the packet is resubmitted to ip_output
629e4506547Srmind 	 * (e.g. after AH, ESP, etc. processing), there will be a tag to
630e4506547Srmind 	 * bypass the lookup and related policy checking.
631e4506547Srmind 	 */
632e4506547Srmind 	if (ipsec_outdone(m)) {
633e4506547Srmind 		return 0;
634e4506547Srmind 	}
6354ce45a79Sozaki-r 	if (inp && ipsec_pcb_skip_ipsec(inp->inp_sp, IPSEC_DIR_OUTBOUND)) {
636e4506547Srmind 		return 0;
637e4506547Srmind 	}
6382953bb25Smaxv 	sp = ipsec_checkpolicy(m, IPSEC_DIR_OUTBOUND, flags, &error, inp);
639e4506547Srmind 
640e4506547Srmind 	/*
641e4506547Srmind 	 * There are four return cases:
642e4506547Srmind 	 *	sp != NULL                    apply IPsec policy
643e4506547Srmind 	 *	sp == NULL, error == 0        no IPsec handling needed
644e4506547Srmind 	 *	sp == NULL, error == -EINVAL  discard packet w/o error
645e4506547Srmind 	 *	sp == NULL, error != 0        discard packet, report error
646e4506547Srmind 	 */
647e4506547Srmind 	if (sp == NULL) {
648e4506547Srmind 		if (error) {
649e4506547Srmind 			/*
650e4506547Srmind 			 * Hack: -EINVAL is used to signal that a packet
651e4506547Srmind 			 * should be silently discarded.  This is typically
652e4506547Srmind 			 * because we asked key management for an SA and
653e4506547Srmind 			 * it was delayed (e.g. kicked up to IKE).
654e4506547Srmind 			 */
655e4506547Srmind 			if (error == -EINVAL)
656e4506547Srmind 				error = 0;
657e4506547Srmind 			m_freem(m);
658e4506547Srmind 			*done = true;
659c1e00d7dSozaki-r 			*count_drop = true;
660e4506547Srmind 			return error;
661e4506547Srmind 		}
662e4506547Srmind 		/* No IPsec processing for this packet. */
663e4506547Srmind 		return 0;
664e4506547Srmind 	}
665e4506547Srmind 
666e4506547Srmind 	/*
667e4506547Srmind 	 * Do delayed checksums now because we send before
668e4506547Srmind 	 * this is done in the normal processing path.
669e4506547Srmind 	 */
670e4506547Srmind 	if (m->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) {
6713574e990Smaxv 		in_undefer_cksum_tcpudp(m);
672e4506547Srmind 		m->m_pkthdr.csum_flags &= ~(M_CSUM_TCPv4|M_CSUM_UDPv4);
673e4506547Srmind 	}
674e4506547Srmind 
675ea86b0a9Sozaki-r 	error = ipsec4_process_packet(m, sp->req, &_mtu);
676ea86b0a9Sozaki-r 	if (error == 0 && _mtu != 0) {
677ea86b0a9Sozaki-r 		/*
678ea86b0a9Sozaki-r 		 * NAT-T ESP fragmentation: do not do IPSec processing
679ea86b0a9Sozaki-r 		 * now, we will do it on each fragmented packet.
680ea86b0a9Sozaki-r 		 */
681ea86b0a9Sozaki-r 		*mtu = _mtu;
682ea86b0a9Sozaki-r 		*natt_frag = true;
6830c084e85Sozaki-r 		KEY_SP_UNREF(&sp);
684ea86b0a9Sozaki-r 		return 0;
685ea86b0a9Sozaki-r 	}
68616a6b570Smaxv 
687e4506547Srmind 	/*
688e4506547Srmind 	 * Preserve KAME behaviour: ENOENT can be returned
689e4506547Srmind 	 * when an SA acquire is in progress.  Don't propagate
690e4506547Srmind 	 * this to user-level; it confuses applications.
691e4506547Srmind 	 *
692e4506547Srmind 	 * XXX this will go away when the SADB is redone.
693e4506547Srmind 	 */
694e4506547Srmind 	if (error == ENOENT)
695e4506547Srmind 		error = 0;
6960c084e85Sozaki-r 	KEY_SP_UNREF(&sp);
697e4506547Srmind 	*done = true;
698e4506547Srmind 	return error;
699e4506547Srmind }
700e4506547Srmind 
7017cb08cfdSrmind int
ipsec_ip_input_checkpolicy(struct mbuf * m,bool forward)702b494441dSozaki-r ipsec_ip_input_checkpolicy(struct mbuf *m, bool forward)
7037cb08cfdSrmind {
7047cb08cfdSrmind 	struct secpolicy *sp;
705986909fbSozaki-r 	int error;
7067cb08cfdSrmind 
7070695fe90Smaxv 	error = ipsec_in_reject(m, NULL);
7087cb08cfdSrmind 	if (error) {
7090695fe90Smaxv 		return EINVAL;
7107cb08cfdSrmind 	}
7117cb08cfdSrmind 
71200ff305aSmaxv 	if (!forward || !(m->m_flags & M_CANFASTFWD)) {
7137cb08cfdSrmind 		return 0;
7147cb08cfdSrmind 	}
7157cb08cfdSrmind 
71685265168Sozaki-r 	/*
71785265168Sozaki-r 	 * Peek at the outbound SP for this packet to determine if
71885265168Sozaki-r 	 * it is a Fast Forward candidate.
71985265168Sozaki-r 	 */
72000ff305aSmaxv 	sp = ipsec_checkpolicy(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING,
72100ff305aSmaxv 	    &error, NULL);
7227cb08cfdSrmind 	if (sp != NULL) {
7237cb08cfdSrmind 		m->m_flags &= ~M_CANFASTFWD;
7240c084e85Sozaki-r 		KEY_SP_UNREF(&sp);
7257cb08cfdSrmind 	}
72600ff305aSmaxv 
7277cb08cfdSrmind 	return 0;
7287cb08cfdSrmind }
7297cb08cfdSrmind 
73025be83d5Smaxv /*
73125be83d5Smaxv  * If the packet is routed over IPsec tunnel, tell the originator the
73225be83d5Smaxv  * tunnel MTU.
73325be83d5Smaxv  *     tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
73425be83d5Smaxv  *
73525be83d5Smaxv  * XXX: Quick hack!!!
73625be83d5Smaxv  *
73725be83d5Smaxv  * XXX: And what if the MTU goes negative?
73825be83d5Smaxv  */
739f813c44dSmaxv void
ipsec_mtu(struct mbuf * m,int * destmtu)740f813c44dSmaxv ipsec_mtu(struct mbuf *m, int *destmtu)
7417cb08cfdSrmind {
7427cb08cfdSrmind 	struct secpolicy *sp;
7437cb08cfdSrmind 	size_t ipsechdr;
7447cb08cfdSrmind 	int error;
7457cb08cfdSrmind 
74616a6b570Smaxv 	sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING,
74716a6b570Smaxv 	    &error);
7487cb08cfdSrmind 	if (sp == NULL) {
749f813c44dSmaxv 		return;
7507cb08cfdSrmind 	}
7517cb08cfdSrmind 
7527cb08cfdSrmind 	/* Count IPsec header size. */
753215e1b41Smaxv 	ipsechdr = ipsec_sp_hdrsiz(sp, m);
7547cb08cfdSrmind 
7557cb08cfdSrmind 	/*
756f813c44dSmaxv 	 * Find the correct route for outer IP header, compute tunnel MTU.
7577cb08cfdSrmind 	 */
7583bd6a580Sozaki-r 	if (sp->req) {
75913270c39Sozaki-r 		struct secasvar *sav;
76013270c39Sozaki-r 
76113270c39Sozaki-r 		sav = ipsec_lookup_sa(sp->req, m);
76213270c39Sozaki-r 		if (sav != NULL) {
7637cb08cfdSrmind 			struct route *ro;
7647cb08cfdSrmind 			struct rtentry *rt;
7657cb08cfdSrmind 
7663bd6a580Sozaki-r 			ro = &sav->sah->sa_route;
7677cb08cfdSrmind 			rt = rtcache_validate(ro);
7687cb08cfdSrmind 			if (rt && rt->rt_ifp) {
7697cb08cfdSrmind 				*destmtu = rt->rt_rmx.rmx_mtu ?
7707cb08cfdSrmind 				    rt->rt_rmx.rmx_mtu : rt->rt_ifp->if_mtu;
7717cb08cfdSrmind 				*destmtu -= ipsechdr;
7727cb08cfdSrmind 			}
7734c25fb2fSozaki-r 			rtcache_unref(rt, ro);
7748be5cabcSozaki-r 			KEY_SA_UNREF(&sav);
7757cb08cfdSrmind 		}
77613270c39Sozaki-r 	}
7770c084e85Sozaki-r 	KEY_SP_UNREF(&sp);
7787cb08cfdSrmind }
7797cb08cfdSrmind 
78074029031Sjonathan static int
ipsec_setspidx_inpcb(struct mbuf * m,struct inpcb * inp)7810e390eeeSozaki-r ipsec_setspidx_inpcb(struct mbuf *m, struct inpcb *inp)
78274029031Sjonathan {
78374029031Sjonathan 	int error;
78474029031Sjonathan 
7850e390eeeSozaki-r 	KASSERT(inp != NULL);
7860e390eeeSozaki-r 	KASSERT(inp->inp_sp != NULL);
7870e390eeeSozaki-r 	KASSERT(inp->inp_sp->sp_out != NULL);
7880e390eeeSozaki-r 	KASSERT(inp->inp_sp->sp_in != NULL);
78974029031Sjonathan 
7900e390eeeSozaki-r 	error = ipsec_setspidx(m, &inp->inp_sp->sp_in->spidx,
791e201bd44Smaxv 	    IPSEC_DIR_INBOUND, 1);
79274029031Sjonathan 	if (error == 0) {
7930e390eeeSozaki-r 		inp->inp_sp->sp_out->spidx = inp->inp_sp->sp_in->spidx;
7940e390eeeSozaki-r 		inp->inp_sp->sp_out->spidx.dir = IPSEC_DIR_OUTBOUND;
79574029031Sjonathan 	} else {
7960e390eeeSozaki-r 		memset(&inp->inp_sp->sp_in->spidx, 0,
7970e390eeeSozaki-r 		    sizeof(inp->inp_sp->sp_in->spidx));
7980e390eeeSozaki-r 		memset(&inp->inp_sp->sp_out->spidx, 0,
7990e390eeeSozaki-r 		    sizeof(inp->inp_sp->sp_out->spidx));
80074029031Sjonathan 	}
80174029031Sjonathan 	return error;
80274029031Sjonathan }
80374029031Sjonathan 
80474029031Sjonathan /*
80574029031Sjonathan  * configure security policy index (src/dst/proto/sport/dport)
80674029031Sjonathan  * by looking at the content of mbuf.
80774029031Sjonathan  * the caller is responsible for error recovery (like clearing up spidx).
80874029031Sjonathan  */
80974029031Sjonathan static int
ipsec_setspidx(struct mbuf * m,struct secpolicyindex * spidx,int dir,int needport)810e201bd44Smaxv ipsec_setspidx(struct mbuf *m, struct secpolicyindex *spidx, int dir,
811e201bd44Smaxv     int needport)
81274029031Sjonathan {
81374029031Sjonathan 	struct ip *ip = NULL;
81474029031Sjonathan 	struct ip ipbuf;
81574029031Sjonathan 	u_int v;
81674029031Sjonathan 	int error;
81774029031Sjonathan 
8182620e166Sozaki-r 	KASSERT(m != NULL);
81959275f73Smaxv 	M_VERIFY_PACKET(m);
82074029031Sjonathan 
82174029031Sjonathan 	if (m->m_pkthdr.len < sizeof(struct ip)) {
8226208c225Sozaki-r 		KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_DUMP,
8236208c225Sozaki-r 		    "pkthdr.len(%d) < sizeof(struct ip), ignored.\n",
8246208c225Sozaki-r 		    m->m_pkthdr.len);
82574029031Sjonathan 		return EINVAL;
82674029031Sjonathan 	}
82774029031Sjonathan 
828e201bd44Smaxv 	memset(spidx, 0, sizeof(*spidx));
829e201bd44Smaxv 	spidx->dir = dir;
830e201bd44Smaxv 
8319a3c5d51Smaxv 	if (m->m_len >= sizeof(*ip)) {
83274029031Sjonathan 		ip = mtod(m, struct ip *);
8339a3c5d51Smaxv 	} else {
834dd86ba72Sdegroote 		m_copydata(m, 0, sizeof(ipbuf), &ipbuf);
83574029031Sjonathan 		ip = &ipbuf;
83674029031Sjonathan 	}
83774029031Sjonathan 	v = ip->ip_v;
83874029031Sjonathan 	switch (v) {
83974029031Sjonathan 	case 4:
84074029031Sjonathan 		error = ipsec4_setspidx_ipaddr(m, spidx);
84174029031Sjonathan 		if (error)
84274029031Sjonathan 			return error;
84374029031Sjonathan 		ipsec4_get_ulp(m, spidx, needport);
84474029031Sjonathan 		return 0;
84574029031Sjonathan #ifdef INET6
84674029031Sjonathan 	case 6:
84774029031Sjonathan 		if (m->m_pkthdr.len < sizeof(struct ip6_hdr)) {
8486208c225Sozaki-r 			KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_DUMP,
84974029031Sjonathan 			    "pkthdr.len(%d) < sizeof(struct ip6_hdr), "
8506208c225Sozaki-r 			    "ignored.\n", m->m_pkthdr.len);
85174029031Sjonathan 			return EINVAL;
85274029031Sjonathan 		}
85374029031Sjonathan 		error = ipsec6_setspidx_ipaddr(m, spidx);
85474029031Sjonathan 		if (error)
85574029031Sjonathan 			return error;
85674029031Sjonathan 		ipsec6_get_ulp(m, spidx, needport);
85774029031Sjonathan 		return 0;
85874029031Sjonathan #endif
85974029031Sjonathan 	default:
8606208c225Sozaki-r 		KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_DUMP,
8616208c225Sozaki-r 		    "unknown IP version %u, ignored.\n", v);
86274029031Sjonathan 		return EINVAL;
86374029031Sjonathan 	}
86474029031Sjonathan }
86574029031Sjonathan 
86674029031Sjonathan static void
ipsec4_get_ulp(struct mbuf * m,struct secpolicyindex * spidx,int needport)86774029031Sjonathan ipsec4_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport)
86874029031Sjonathan {
86974029031Sjonathan 	u_int8_t nxt;
87074029031Sjonathan 	int off;
87174029031Sjonathan 
8722620e166Sozaki-r 	KASSERT(m != NULL);
8732620e166Sozaki-r 	KASSERTMSG(m->m_pkthdr.len >= sizeof(struct ip), "packet too short");
87474029031Sjonathan 
87574029031Sjonathan 	/* NB: ip_input() flips it into host endian XXX need more checking */
87668020cebSthorpej 	if (m->m_len >= sizeof(struct ip)) {
87774029031Sjonathan 		struct ip *ip = mtod(m, struct ip *);
878ef67739aSozaki-r 		if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
87974029031Sjonathan 			goto done;
88074029031Sjonathan 		off = ip->ip_hl << 2;
88174029031Sjonathan 		nxt = ip->ip_p;
88274029031Sjonathan 	} else {
88374029031Sjonathan 		struct ip ih;
88474029031Sjonathan 
885dd86ba72Sdegroote 		m_copydata(m, 0, sizeof(struct ip), &ih);
886ef67739aSozaki-r 		if (ih.ip_off & htons(IP_MF | IP_OFFMASK))
88774029031Sjonathan 			goto done;
88874029031Sjonathan 		off = ih.ip_hl << 2;
88974029031Sjonathan 		nxt = ih.ip_p;
89074029031Sjonathan 	}
89174029031Sjonathan 
89274029031Sjonathan 	while (off < m->m_pkthdr.len) {
89374029031Sjonathan 		struct ip6_ext ip6e;
89474029031Sjonathan 		struct tcphdr th;
89574029031Sjonathan 		struct udphdr uh;
896fa014c63Smlelstv 		struct icmp icmph;
89774029031Sjonathan 
89874029031Sjonathan 		switch (nxt) {
89974029031Sjonathan 		case IPPROTO_TCP:
90074029031Sjonathan 			spidx->ul_proto = nxt;
90174029031Sjonathan 			if (!needport)
90274029031Sjonathan 				goto done_proto;
90374029031Sjonathan 			if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
90474029031Sjonathan 				goto done;
905dd86ba72Sdegroote 			m_copydata(m, off, sizeof(th), &th);
90674029031Sjonathan 			spidx->src.sin.sin_port = th.th_sport;
90774029031Sjonathan 			spidx->dst.sin.sin_port = th.th_dport;
90874029031Sjonathan 			return;
90974029031Sjonathan 		case IPPROTO_UDP:
91074029031Sjonathan 			spidx->ul_proto = nxt;
91174029031Sjonathan 			if (!needport)
91274029031Sjonathan 				goto done_proto;
91374029031Sjonathan 			if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
91474029031Sjonathan 				goto done;
915dd86ba72Sdegroote 			m_copydata(m, off, sizeof(uh), &uh);
91674029031Sjonathan 			spidx->src.sin.sin_port = uh.uh_sport;
91774029031Sjonathan 			spidx->dst.sin.sin_port = uh.uh_dport;
91874029031Sjonathan 			return;
91974029031Sjonathan 		case IPPROTO_AH:
9202603d1d6Smaxv 			if (off + sizeof(ip6e) > m->m_pkthdr.len)
92174029031Sjonathan 				goto done;
92274029031Sjonathan 			/* XXX sigh, this works but is totally bogus */
923dd86ba72Sdegroote 			m_copydata(m, off, sizeof(ip6e), &ip6e);
92474029031Sjonathan 			off += (ip6e.ip6e_len + 2) << 2;
92574029031Sjonathan 			nxt = ip6e.ip6e_nxt;
92674029031Sjonathan 			break;
92774029031Sjonathan 		case IPPROTO_ICMP:
928fa014c63Smlelstv 			spidx->ul_proto = nxt;
929fa014c63Smlelstv 			if (off + sizeof(struct icmp) > m->m_pkthdr.len)
930b9badffcSmaxv 				goto done;
931ba4ebf7eSdegroote 			m_copydata(m, off, sizeof(icmph), &icmph);
932fa014c63Smlelstv 			((struct sockaddr_in *)&spidx->src)->sin_port =
933fa014c63Smlelstv 			    htons((uint16_t)icmph.icmp_type);
934fa014c63Smlelstv 			((struct sockaddr_in *)&spidx->dst)->sin_port =
935fa014c63Smlelstv 			    htons((uint16_t)icmph.icmp_code);
936fa014c63Smlelstv 			return;
93774029031Sjonathan 		default:
93874029031Sjonathan 			/* XXX intermediate headers??? */
93974029031Sjonathan 			spidx->ul_proto = nxt;
94074029031Sjonathan 			goto done_proto;
94174029031Sjonathan 		}
94274029031Sjonathan 	}
94374029031Sjonathan done:
94474029031Sjonathan 	spidx->ul_proto = IPSEC_ULPROTO_ANY;
94574029031Sjonathan done_proto:
94674029031Sjonathan 	spidx->src.sin.sin_port = IPSEC_PORT_ANY;
94774029031Sjonathan 	spidx->dst.sin.sin_port = IPSEC_PORT_ANY;
94874029031Sjonathan }
94974029031Sjonathan 
95074029031Sjonathan static int
ipsec4_setspidx_ipaddr(struct mbuf * m,struct secpolicyindex * spidx)95174029031Sjonathan ipsec4_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx)
95274029031Sjonathan {
95374029031Sjonathan 	static const struct sockaddr_in template = {
95474029031Sjonathan 		sizeof(struct sockaddr_in),
95574029031Sjonathan 		AF_INET,
95674029031Sjonathan 		0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
95774029031Sjonathan 	};
95874029031Sjonathan 
95974029031Sjonathan 	spidx->src.sin = template;
96074029031Sjonathan 	spidx->dst.sin = template;
96174029031Sjonathan 
96274029031Sjonathan 	if (m->m_len < sizeof(struct ip)) {
96374029031Sjonathan 		m_copydata(m, offsetof(struct ip, ip_src),
96492b56eb3Sozaki-r 		    sizeof(struct in_addr), &spidx->src.sin.sin_addr);
96574029031Sjonathan 		m_copydata(m, offsetof(struct ip, ip_dst),
96692b56eb3Sozaki-r 		    sizeof(struct in_addr), &spidx->dst.sin.sin_addr);
96774029031Sjonathan 	} else {
96874029031Sjonathan 		struct ip *ip = mtod(m, struct ip *);
96974029031Sjonathan 		spidx->src.sin.sin_addr = ip->ip_src;
97074029031Sjonathan 		spidx->dst.sin.sin_addr = ip->ip_dst;
97174029031Sjonathan 	}
97274029031Sjonathan 
97374029031Sjonathan 	spidx->prefs = sizeof(struct in_addr) << 3;
97474029031Sjonathan 	spidx->prefd = sizeof(struct in_addr) << 3;
97574029031Sjonathan 
97674029031Sjonathan 	return 0;
97774029031Sjonathan }
97874029031Sjonathan 
97974029031Sjonathan #ifdef INET6
98074029031Sjonathan static void
ipsec6_get_ulp(struct mbuf * m,struct secpolicyindex * spidx,int needport)9819a3c5d51Smaxv ipsec6_get_ulp(struct mbuf *m, struct secpolicyindex *spidx, int needport)
98274029031Sjonathan {
98374029031Sjonathan 	int off, nxt;
98474029031Sjonathan 	struct tcphdr th;
98574029031Sjonathan 	struct udphdr uh;
986fa014c63Smlelstv 	struct icmp6_hdr icmph;
98774029031Sjonathan 
9881d3af2e6Sozaki-r 	KASSERT(m != NULL);
98974029031Sjonathan 
9906208c225Sozaki-r 	if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DUMP)) {
991d6d612dcSchristos 		kdebug_mbuf(__func__, m);
9926208c225Sozaki-r 	}
99374029031Sjonathan 
99474029031Sjonathan 	/* set default */
99574029031Sjonathan 	spidx->ul_proto = IPSEC_ULPROTO_ANY;
99674029031Sjonathan 	((struct sockaddr_in6 *)&spidx->src)->sin6_port = IPSEC_PORT_ANY;
99774029031Sjonathan 	((struct sockaddr_in6 *)&spidx->dst)->sin6_port = IPSEC_PORT_ANY;
99874029031Sjonathan 
99974029031Sjonathan 	nxt = -1;
100074029031Sjonathan 	off = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
100174029031Sjonathan 	if (off < 0 || m->m_pkthdr.len < off)
100274029031Sjonathan 		return;
100374029031Sjonathan 
100474029031Sjonathan 	switch (nxt) {
100574029031Sjonathan 	case IPPROTO_TCP:
100674029031Sjonathan 		spidx->ul_proto = nxt;
100774029031Sjonathan 		if (!needport)
100874029031Sjonathan 			break;
100974029031Sjonathan 		if (off + sizeof(struct tcphdr) > m->m_pkthdr.len)
101074029031Sjonathan 			break;
1011dd86ba72Sdegroote 		m_copydata(m, off, sizeof(th), &th);
101274029031Sjonathan 		((struct sockaddr_in6 *)&spidx->src)->sin6_port = th.th_sport;
101374029031Sjonathan 		((struct sockaddr_in6 *)&spidx->dst)->sin6_port = th.th_dport;
101474029031Sjonathan 		break;
101574029031Sjonathan 	case IPPROTO_UDP:
101674029031Sjonathan 		spidx->ul_proto = nxt;
101774029031Sjonathan 		if (!needport)
101874029031Sjonathan 			break;
101974029031Sjonathan 		if (off + sizeof(struct udphdr) > m->m_pkthdr.len)
102074029031Sjonathan 			break;
1021dd86ba72Sdegroote 		m_copydata(m, off, sizeof(uh), &uh);
102274029031Sjonathan 		((struct sockaddr_in6 *)&spidx->src)->sin6_port = uh.uh_sport;
102374029031Sjonathan 		((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport;
102474029031Sjonathan 		break;
102574029031Sjonathan 	case IPPROTO_ICMPV6:
1026fa014c63Smlelstv 		spidx->ul_proto = nxt;
1027fa014c63Smlelstv 		if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len)
1028fa014c63Smlelstv 			break;
1029ba4ebf7eSdegroote 		m_copydata(m, off, sizeof(icmph), &icmph);
1030fa014c63Smlelstv 		((struct sockaddr_in6 *)&spidx->src)->sin6_port =
1031fa014c63Smlelstv 		    htons((uint16_t)icmph.icmp6_type);
1032fa014c63Smlelstv 		((struct sockaddr_in6 *)&spidx->dst)->sin6_port =
1033fa014c63Smlelstv 		    htons((uint16_t)icmph.icmp6_code);
1034fa014c63Smlelstv 		break;
103574029031Sjonathan 	default:
103674029031Sjonathan 		/* XXX intermediate headers??? */
103774029031Sjonathan 		spidx->ul_proto = nxt;
103874029031Sjonathan 		break;
103974029031Sjonathan 	}
104074029031Sjonathan }
104174029031Sjonathan 
104274029031Sjonathan static int
ipsec6_setspidx_ipaddr(struct mbuf * m,struct secpolicyindex * spidx)1043a382db0aSdegroote ipsec6_setspidx_ipaddr(struct mbuf *m, struct secpolicyindex *spidx)
104474029031Sjonathan {
104574029031Sjonathan 	struct ip6_hdr *ip6 = NULL;
104674029031Sjonathan 	struct ip6_hdr ip6buf;
104774029031Sjonathan 	struct sockaddr_in6 *sin6;
104874029031Sjonathan 
104925be83d5Smaxv 	if (m->m_len >= sizeof(*ip6)) {
105074029031Sjonathan 		ip6 = mtod(m, struct ip6_hdr *);
105125be83d5Smaxv 	} else {
1052dd86ba72Sdegroote 		m_copydata(m, 0, sizeof(ip6buf), &ip6buf);
105374029031Sjonathan 		ip6 = &ip6buf;
105474029031Sjonathan 	}
105574029031Sjonathan 
105674029031Sjonathan 	sin6 = (struct sockaddr_in6 *)&spidx->src;
1057c363a9cbScegger 	memset(sin6, 0, sizeof(*sin6));
105874029031Sjonathan 	sin6->sin6_family = AF_INET6;
105974029031Sjonathan 	sin6->sin6_len = sizeof(struct sockaddr_in6);
1060e2cb8590Scegger 	memcpy(&sin6->sin6_addr, &ip6->ip6_src, sizeof(ip6->ip6_src));
106174029031Sjonathan 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
106274029031Sjonathan 		sin6->sin6_addr.s6_addr16[1] = 0;
106374029031Sjonathan 		sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
106474029031Sjonathan 	}
106574029031Sjonathan 	spidx->prefs = sizeof(struct in6_addr) << 3;
106674029031Sjonathan 
106774029031Sjonathan 	sin6 = (struct sockaddr_in6 *)&spidx->dst;
1068c363a9cbScegger 	memset(sin6, 0, sizeof(*sin6));
106974029031Sjonathan 	sin6->sin6_family = AF_INET6;
107074029031Sjonathan 	sin6->sin6_len = sizeof(struct sockaddr_in6);
1071e2cb8590Scegger 	memcpy(&sin6->sin6_addr, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
107274029031Sjonathan 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
107374029031Sjonathan 		sin6->sin6_addr.s6_addr16[1] = 0;
107474029031Sjonathan 		sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
107574029031Sjonathan 	}
107674029031Sjonathan 	spidx->prefd = sizeof(struct in6_addr) << 3;
107774029031Sjonathan 
107874029031Sjonathan 	return 0;
107974029031Sjonathan }
108074029031Sjonathan #endif
108174029031Sjonathan 
108274029031Sjonathan static void
ipsec_delpcbpolicy(struct inpcbpolicy * p)1083a382db0aSdegroote ipsec_delpcbpolicy(struct inpcbpolicy *p)
108474029031Sjonathan {
108520448372Sozaki-r 
1086b5d03f64Sozaki-r 	kmem_intr_free(p, sizeof(*p));
108774029031Sjonathan }
108874029031Sjonathan 
108974029031Sjonathan int
ipsec_init_pcbpolicy(struct socket * so,struct inpcbpolicy ** policy)109019f9cae6Smaxv ipsec_init_pcbpolicy(struct socket *so, struct inpcbpolicy **policy)
109174029031Sjonathan {
109274029031Sjonathan 	struct inpcbpolicy *new;
109374029031Sjonathan 
10941d3af2e6Sozaki-r 	KASSERT(so != NULL);
10951d3af2e6Sozaki-r 	KASSERT(policy != NULL);
109674029031Sjonathan 
1097b5d03f64Sozaki-r 	new = kmem_intr_zalloc(sizeof(*new), KM_NOSLEEP);
1098b5d03f64Sozaki-r 	if (new == NULL) {
1099290dc492Sozaki-r 		IPSECLOG(LOG_DEBUG, "No more memory.\n");
1100b5d03f64Sozaki-r 		return ENOBUFS;
1101b5d03f64Sozaki-r 	}
110274029031Sjonathan 
110374029031Sjonathan 	if (IPSEC_PRIVILEGED_SO(so))
110474029031Sjonathan 		new->priv = 1;
110574029031Sjonathan 	else
110674029031Sjonathan 		new->priv = 0;
110774029031Sjonathan 
11080c084e85Sozaki-r 	/*
1109603defb9Sozaki-r 	 * Set dummy SPs. Actual SPs will be allocated later if needed.
11100c084e85Sozaki-r 	 */
1111603defb9Sozaki-r 	new->sp_in = &ipsec_dummy_sp;
1112603defb9Sozaki-r 	new->sp_out = &ipsec_dummy_sp;
111374029031Sjonathan 
111462903782Schristos 	*policy = new;
111574029031Sjonathan 
111674029031Sjonathan 	return 0;
111774029031Sjonathan }
111874029031Sjonathan 
11190c084e85Sozaki-r static void
ipsec_destroy_policy(struct secpolicy * sp)11200c084e85Sozaki-r ipsec_destroy_policy(struct secpolicy *sp)
11210c084e85Sozaki-r {
11220c084e85Sozaki-r 
112325be83d5Smaxv 	if (sp == &ipsec_dummy_sp) {
1124603defb9Sozaki-r 		; /* It's dummy. No need to free it. */
112525be83d5Smaxv 	} else {
11260c084e85Sozaki-r 		/*
11270c084e85Sozaki-r 		 * We cannot destroy here because it can be called in
11280c084e85Sozaki-r 		 * softint. So mark the SP as DEAD and let the timer
11290c084e85Sozaki-r 		 * destroy it. See key_timehandler_spd.
11300c084e85Sozaki-r 		 */
11310c084e85Sozaki-r 		sp->state = IPSEC_SPSTATE_DEAD;
11320c084e85Sozaki-r 	}
11330c084e85Sozaki-r }
11340c084e85Sozaki-r 
1135faad9849Smaxv int
ipsec_set_policy(struct inpcb * inp,const void * request,size_t len,kauth_cred_t cred)11360e390eeeSozaki-r ipsec_set_policy(struct inpcb *inp, const void *request, size_t len,
1137faad9849Smaxv     kauth_cred_t cred)
113874029031Sjonathan {
11392cd69bbbSdrochner 	const struct sadb_x_policy *xpl;
11406fd7a9a7Smaxv 	struct secpolicy *newsp, *oldsp;
1141faad9849Smaxv 	struct secpolicy **policy;
114274029031Sjonathan 	int error;
114374029031Sjonathan 
114420448372Sozaki-r 	KASSERT(!cpu_softintr_p());
11450e390eeeSozaki-r 	KASSERT(inp != NULL);
11460e390eeeSozaki-r 	KASSERT(inp_locked(inp));
1147faad9849Smaxv 	KASSERT(request != NULL);
1148faad9849Smaxv 
1149faad9849Smaxv 	if (len < sizeof(*xpl))
1150faad9849Smaxv 		return EINVAL;
1151faad9849Smaxv 	xpl = (const struct sadb_x_policy *)request;
1152faad9849Smaxv 
11530e390eeeSozaki-r 	KASSERT(inp->inp_sp != NULL);
1154faad9849Smaxv 
1155faad9849Smaxv 	/* select direction */
1156faad9849Smaxv 	switch (xpl->sadb_x_policy_dir) {
1157faad9849Smaxv 	case IPSEC_DIR_INBOUND:
11580e390eeeSozaki-r 		policy = &inp->inp_sp->sp_in;
1159faad9849Smaxv 		break;
1160faad9849Smaxv 	case IPSEC_DIR_OUTBOUND:
11610e390eeeSozaki-r 		policy = &inp->inp_sp->sp_out;
1162faad9849Smaxv 		break;
1163faad9849Smaxv 	default:
1164faad9849Smaxv 		IPSECLOG(LOG_ERR, "invalid direction=%u\n",
1165faad9849Smaxv 		    xpl->sadb_x_policy_dir);
1166faad9849Smaxv 		return EINVAL;
1167faad9849Smaxv 	}
116820448372Sozaki-r 
116974029031Sjonathan 	/* sanity check. */
11706fd7a9a7Smaxv 	if (policy == NULL || *policy == NULL)
117174029031Sjonathan 		return EINVAL;
117274029031Sjonathan 
11736208c225Sozaki-r 	if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DUMP)) {
1174d6d612dcSchristos 		kdebug_sadb_xpolicy("set passed policy", request);
11756208c225Sozaki-r 	}
117674029031Sjonathan 
117774029031Sjonathan 	/* check policy type */
117874029031Sjonathan 	/* ipsec_set_policy() accepts IPSEC, ENTRUST and BYPASS. */
11799a3c5d51Smaxv 	if (xpl->sadb_x_policy_type == IPSEC_POLICY_DISCARD ||
11809a3c5d51Smaxv 	    xpl->sadb_x_policy_type == IPSEC_POLICY_NONE)
118174029031Sjonathan 		return EINVAL;
118274029031Sjonathan 
118374029031Sjonathan 	/* check privileged socket */
1184efeb620eSelad 	if (xpl->sadb_x_policy_type == IPSEC_POLICY_BYPASS) {
11850c9d8d15Selad 		error = kauth_authorize_network(cred, KAUTH_NETWORK_IPSEC,
11860c9d8d15Selad 		    KAUTH_REQ_NETWORK_IPSEC_BYPASS, NULL, NULL, NULL);
1187efeb620eSelad 		if (error)
11889a3c5d51Smaxv 			return error;
1189efeb620eSelad 	}
119074029031Sjonathan 
119174029031Sjonathan 	/* allocation new SP entry */
119274029031Sjonathan 	if ((newsp = key_msg2sp(xpl, len, &error)) == NULL)
119374029031Sjonathan 		return error;
119474029031Sjonathan 
11950c084e85Sozaki-r 	key_init_sp(newsp);
11960c084e85Sozaki-r 	newsp->created = time_uptime;
11970c084e85Sozaki-r 	/* Insert the global list for SPs for sockets */
11980c084e85Sozaki-r 	key_socksplist_add(newsp);
119974029031Sjonathan 
120074029031Sjonathan 	/* clear old SP and set new SP */
12010c084e85Sozaki-r 	oldsp = *policy;
120262903782Schristos 	*policy = newsp;
12030c084e85Sozaki-r 	ipsec_destroy_policy(oldsp);
12040c084e85Sozaki-r 
12056208c225Sozaki-r 	if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DUMP)) {
12066208c225Sozaki-r 		printf("%s: new policy\n", __func__);
12076208c225Sozaki-r 		kdebug_secpolicy(newsp);
12086208c225Sozaki-r 	}
120974029031Sjonathan 
121074029031Sjonathan 	return 0;
121174029031Sjonathan }
121274029031Sjonathan 
121374029031Sjonathan int
ipsec_get_policy(struct inpcb * inp,const void * request,size_t len,struct mbuf ** mp)12140e390eeeSozaki-r ipsec_get_policy(struct inpcb *inp, const void *request, size_t len,
1215a382db0aSdegroote     struct mbuf **mp)
121674029031Sjonathan {
12172cd69bbbSdrochner 	const struct sadb_x_policy *xpl;
121862903782Schristos 	struct secpolicy *policy;
121974029031Sjonathan 
122074029031Sjonathan 	/* sanity check. */
12210e390eeeSozaki-r 	if (inp == NULL || request == NULL || mp == NULL)
122274029031Sjonathan 		return EINVAL;
12230e390eeeSozaki-r 	KASSERT(inp->inp_sp != NULL);
122474029031Sjonathan 	if (len < sizeof(*xpl))
122574029031Sjonathan 		return EINVAL;
12262cd69bbbSdrochner 	xpl = (const struct sadb_x_policy *)request;
122774029031Sjonathan 
122874029031Sjonathan 	/* select direction */
122974029031Sjonathan 	switch (xpl->sadb_x_policy_dir) {
123074029031Sjonathan 	case IPSEC_DIR_INBOUND:
12310e390eeeSozaki-r 		policy = inp->inp_sp->sp_in;
123274029031Sjonathan 		break;
123374029031Sjonathan 	case IPSEC_DIR_OUTBOUND:
12340e390eeeSozaki-r 		policy = inp->inp_sp->sp_out;
123574029031Sjonathan 		break;
123674029031Sjonathan 	default:
1237290dc492Sozaki-r 		IPSECLOG(LOG_ERR, "invalid direction=%u\n",
1238290dc492Sozaki-r 		    xpl->sadb_x_policy_dir);
123974029031Sjonathan 		return EINVAL;
124074029031Sjonathan 	}
124174029031Sjonathan 
12426fd7a9a7Smaxv 	if (policy == NULL)
1243580ac4beSmaxv 		return EINVAL;
1244580ac4beSmaxv 
1245580ac4beSmaxv 	*mp = key_sp2msg(policy, M_NOWAIT);
1246580ac4beSmaxv 	if (!*mp) {
1247580ac4beSmaxv 		IPSECLOG(LOG_DEBUG, "No more memory.\n");
1248580ac4beSmaxv 		return ENOBUFS;
1249580ac4beSmaxv 	}
1250580ac4beSmaxv 
1251580ac4beSmaxv 	if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DUMP)) {
1252580ac4beSmaxv 		kdebug_mbuf(__func__, *mp);
1253580ac4beSmaxv 	}
1254580ac4beSmaxv 
1255580ac4beSmaxv 	return 0;
125674029031Sjonathan }
125774029031Sjonathan 
125874029031Sjonathan int
ipsec_delete_pcbpolicy(struct inpcb * inp)12590e390eeeSozaki-r ipsec_delete_pcbpolicy(struct inpcb *inp)
126074029031Sjonathan {
12612620e166Sozaki-r 
12620e390eeeSozaki-r 	KASSERT(inp != NULL);
126374029031Sjonathan 
12640e390eeeSozaki-r 	if (inp->inp_sp == NULL)
126574029031Sjonathan 		return 0;
126674029031Sjonathan 
12670e390eeeSozaki-r 	if (inp->inp_sp->sp_in != NULL)
12680e390eeeSozaki-r 		ipsec_destroy_policy(inp->inp_sp->sp_in);
126974029031Sjonathan 
12700e390eeeSozaki-r 	if (inp->inp_sp->sp_out != NULL)
12710e390eeeSozaki-r 		ipsec_destroy_policy(inp->inp_sp->sp_out);
127274029031Sjonathan 
12730e390eeeSozaki-r 	ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY);
12747d0822f8Sdrochner 
12750e390eeeSozaki-r 	ipsec_delpcbpolicy(inp->inp_sp);
12760e390eeeSozaki-r 	inp->inp_sp = NULL;
127774029031Sjonathan 
127874029031Sjonathan 	return 0;
127974029031Sjonathan }
128074029031Sjonathan 
128174029031Sjonathan /*
128216a6b570Smaxv  * Return the current level (either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE).
128374029031Sjonathan  */
128474029031Sjonathan u_int
ipsec_get_reqlevel(const struct ipsecrequest * isr)1285dd877261Schristos ipsec_get_reqlevel(const struct ipsecrequest *isr)
128674029031Sjonathan {
128774029031Sjonathan 	u_int level = 0;
128874029031Sjonathan 	u_int esp_trans_deflev, esp_net_deflev;
128974029031Sjonathan 	u_int ah_trans_deflev, ah_net_deflev;
129074029031Sjonathan 
12912620e166Sozaki-r 	KASSERT(isr != NULL);
12922620e166Sozaki-r 	KASSERT(isr->sp != NULL);
12932620e166Sozaki-r 	KASSERTMSG(
12942620e166Sozaki-r 	    isr->sp->spidx.src.sa.sa_family == isr->sp->spidx.dst.sa.sa_family,
12952620e166Sozaki-r 	    "af family mismatch, src %u, dst %u",
12962620e166Sozaki-r 	    isr->sp->spidx.src.sa.sa_family, isr->sp->spidx.dst.sa.sa_family);
129774029031Sjonathan 
129874029031Sjonathan /* XXX note that we have ipseclog() expanded here - code sync issue */
129974029031Sjonathan #define IPSEC_CHECK_DEFAULT(lev)					\
130074029031Sjonathan     (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE		\
130136443d4aSchristos     && (lev) != IPSEC_LEVEL_UNIQUE) ?					\
130236443d4aSchristos 	(ipsec_debug ? log(LOG_INFO, "fixed system default level " #lev \
13037300f5c7Splunky 	":%d->%d\n", (lev), IPSEC_LEVEL_REQUIRE) : (void)0),		\
130436443d4aSchristos 	(lev) = IPSEC_LEVEL_REQUIRE, (lev)				\
130574029031Sjonathan     : (lev))
130674029031Sjonathan 
130774029031Sjonathan 	/* set default level */
130874029031Sjonathan 	switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) {
130974029031Sjonathan #ifdef INET
131074029031Sjonathan 	case AF_INET:
131174029031Sjonathan 		esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_trans_deflev);
131274029031Sjonathan 		esp_net_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_net_deflev);
131374029031Sjonathan 		ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_trans_deflev);
131474029031Sjonathan 		ah_net_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_net_deflev);
131574029031Sjonathan 		break;
131674029031Sjonathan #endif
131774029031Sjonathan #ifdef INET6
131874029031Sjonathan 	case AF_INET6:
131974029031Sjonathan 		esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_trans_deflev);
132074029031Sjonathan 		esp_net_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_net_deflev);
132174029031Sjonathan 		ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_trans_deflev);
132274029031Sjonathan 		ah_net_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_net_deflev);
132374029031Sjonathan 		break;
132425be83d5Smaxv #endif
132574029031Sjonathan 	default:
132636443d4aSchristos 		panic("%s: unknown af %u", __func__,
132774029031Sjonathan 		    isr->sp->spidx.src.sa.sa_family);
132874029031Sjonathan 	}
132974029031Sjonathan 
133074029031Sjonathan #undef IPSEC_CHECK_DEFAULT
133174029031Sjonathan 
133274029031Sjonathan 	/* set level */
133374029031Sjonathan 	switch (isr->level) {
133474029031Sjonathan 	case IPSEC_LEVEL_DEFAULT:
133574029031Sjonathan 		switch (isr->saidx.proto) {
133674029031Sjonathan 		case IPPROTO_ESP:
133774029031Sjonathan 			if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
133874029031Sjonathan 				level = esp_net_deflev;
133974029031Sjonathan 			else
134074029031Sjonathan 				level = esp_trans_deflev;
134174029031Sjonathan 			break;
134274029031Sjonathan 		case IPPROTO_AH:
134374029031Sjonathan 			if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
134474029031Sjonathan 				level = ah_net_deflev;
134574029031Sjonathan 			else
134674029031Sjonathan 				level = ah_trans_deflev;
13472bee2ad8Sjonathan 			break;
134874029031Sjonathan 		case IPPROTO_IPCOMP:
134974029031Sjonathan 			/*
135074029031Sjonathan 			 * we don't really care, as IPcomp document says that
135174029031Sjonathan 			 * we shouldn't compress small packets
135274029031Sjonathan 			 */
135374029031Sjonathan 			level = IPSEC_LEVEL_USE;
135474029031Sjonathan 			break;
135574029031Sjonathan 		default:
135636443d4aSchristos 			panic("%s: Illegal protocol defined %u", __func__,
135774029031Sjonathan 			    isr->saidx.proto);
135874029031Sjonathan 		}
135974029031Sjonathan 		break;
136074029031Sjonathan 
136174029031Sjonathan 	case IPSEC_LEVEL_USE:
136274029031Sjonathan 	case IPSEC_LEVEL_REQUIRE:
136374029031Sjonathan 		level = isr->level;
136474029031Sjonathan 		break;
136574029031Sjonathan 	case IPSEC_LEVEL_UNIQUE:
136674029031Sjonathan 		level = IPSEC_LEVEL_REQUIRE;
136774029031Sjonathan 		break;
136874029031Sjonathan 
136974029031Sjonathan 	default:
137036443d4aSchristos 		panic("%s: Illegal IPsec level %u", __func__, isr->level);
137174029031Sjonathan 	}
137274029031Sjonathan 
137374029031Sjonathan 	return level;
137474029031Sjonathan }
137574029031Sjonathan 
137674029031Sjonathan /*
137722e66c74Smaxv  * Check security policy requirements against the actual packet contents.
137874029031Sjonathan  *
137922e66c74Smaxv  * If the SP requires an IPsec packet, and the packet was neither AH nor ESP,
138022e66c74Smaxv  * then kick it.
138174029031Sjonathan  */
1382f3215192Smaxv static int
ipsec_sp_reject(const struct secpolicy * sp,const struct mbuf * m)1383af69f639Smaxv ipsec_sp_reject(const struct secpolicy *sp, const struct mbuf *m)
138474029031Sjonathan {
138574029031Sjonathan 	struct ipsecrequest *isr;
138674029031Sjonathan 
13876208c225Sozaki-r 	if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DATA)) {
13886208c225Sozaki-r 		printf("%s: using SP\n", __func__);
13896208c225Sozaki-r 		kdebug_secpolicy(sp);
13906208c225Sozaki-r 	}
139174029031Sjonathan 
139274029031Sjonathan 	/* check policy */
139374029031Sjonathan 	switch (sp->policy) {
139474029031Sjonathan 	case IPSEC_POLICY_DISCARD:
139574029031Sjonathan 		return 1;
139674029031Sjonathan 	case IPSEC_POLICY_BYPASS:
139774029031Sjonathan 	case IPSEC_POLICY_NONE:
139874029031Sjonathan 		return 0;
139974029031Sjonathan 	}
140074029031Sjonathan 
14012620e166Sozaki-r 	KASSERTMSG(sp->policy == IPSEC_POLICY_IPSEC,
14022620e166Sozaki-r 	    "invalid policy %u", sp->policy);
140374029031Sjonathan 
140474029031Sjonathan 	/* XXX should compare policy against ipsec header history */
140574029031Sjonathan 
140674029031Sjonathan 	for (isr = sp->req; isr != NULL; isr = isr->next) {
140774029031Sjonathan 		if (ipsec_get_reqlevel(isr) != IPSEC_LEVEL_REQUIRE)
140874029031Sjonathan 			continue;
140974029031Sjonathan 		switch (isr->saidx.proto) {
141074029031Sjonathan 		case IPPROTO_ESP:
141174029031Sjonathan 			if ((m->m_flags & M_DECRYPTED) == 0) {
14126208c225Sozaki-r 				KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_DUMP,
14136208c225Sozaki-r 				    "ESP m_flags:%x\n", m->m_flags);
141474029031Sjonathan 				return 1;
141574029031Sjonathan 			}
141674029031Sjonathan 			break;
141774029031Sjonathan 		case IPPROTO_AH:
141874029031Sjonathan 			if ((m->m_flags & M_AUTHIPHDR) == 0) {
14196208c225Sozaki-r 				KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_DUMP,
14206208c225Sozaki-r 				    "AH m_flags:%x\n", m->m_flags);
142174029031Sjonathan 				return 1;
142274029031Sjonathan 			}
142374029031Sjonathan 			break;
142474029031Sjonathan 		case IPPROTO_IPCOMP:
142574029031Sjonathan 			/*
142622e66c74Smaxv 			 * We don't really care, as IPcomp document
142774029031Sjonathan 			 * says that we shouldn't compress small
142874029031Sjonathan 			 * packets, IPComp policy should always be
142974029031Sjonathan 			 * treated as being in "use" level.
143074029031Sjonathan 			 */
143174029031Sjonathan 			break;
143274029031Sjonathan 		}
143374029031Sjonathan 	}
1434af69f639Smaxv 
1435af69f639Smaxv 	return 0;
143674029031Sjonathan }
143774029031Sjonathan 
143874029031Sjonathan /*
1439b39a0dd1Smaxv  * Check security policy requirements.
144074029031Sjonathan  */
144174029031Sjonathan int
ipsec_in_reject(struct mbuf * m,struct inpcb * inp)14420e390eeeSozaki-r ipsec_in_reject(struct mbuf *m, struct inpcb *inp)
144374029031Sjonathan {
144474029031Sjonathan 	struct secpolicy *sp;
144574029031Sjonathan 	int error;
144674029031Sjonathan 	int result;
144774029031Sjonathan 
14482620e166Sozaki-r 	KASSERT(m != NULL);
144974029031Sjonathan 
14500e390eeeSozaki-r 	if (inp == NULL)
145122e66c74Smaxv 		sp = ipsec_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
145222e66c74Smaxv 		    IP_FORWARDING, &error);
145374029031Sjonathan 	else
1454e139b206Sjonathan 		sp = ipsec_getpolicybysock(m, IPSEC_DIR_INBOUND,
14550e390eeeSozaki-r 		    inp, &error);
145674029031Sjonathan 
145774029031Sjonathan 	if (sp != NULL) {
1458af69f639Smaxv 		result = ipsec_sp_reject(sp, m);
145974029031Sjonathan 		if (result)
1460caf49ea5Sthorpej 			IPSEC_STATINC(IPSEC_STAT_IN_POLVIO);
14610c084e85Sozaki-r 		KEY_SP_UNREF(&sp);
146274029031Sjonathan 	} else {
146322e66c74Smaxv 		result = 0;
146474029031Sjonathan 	}
146574029031Sjonathan 	return result;
146674029031Sjonathan }
146774029031Sjonathan 
146874029031Sjonathan /*
1469af69f639Smaxv  * Compute the byte size to be occupied by the IPsec header. If it is
1470af69f639Smaxv  * tunneled, it includes the size of outer IP header.
147174029031Sjonathan  */
147274029031Sjonathan static size_t
ipsec_sp_hdrsiz(const struct secpolicy * sp,const struct mbuf * m)1473af69f639Smaxv ipsec_sp_hdrsiz(const struct secpolicy *sp, const struct mbuf *m)
147474029031Sjonathan {
14755e860e54Sozaki-r 	struct ipsecrequest *isr;
147674029031Sjonathan 	size_t siz;
147774029031Sjonathan 
14786208c225Sozaki-r 	if (KEYDEBUG_ON(KEYDEBUG_IPSEC_DATA)) {
14796208c225Sozaki-r 		printf("%s: using SP\n", __func__);
14806208c225Sozaki-r 		kdebug_secpolicy(sp);
14816208c225Sozaki-r 	}
148274029031Sjonathan 
148374029031Sjonathan 	switch (sp->policy) {
148474029031Sjonathan 	case IPSEC_POLICY_DISCARD:
148574029031Sjonathan 	case IPSEC_POLICY_BYPASS:
148674029031Sjonathan 	case IPSEC_POLICY_NONE:
148774029031Sjonathan 		return 0;
148874029031Sjonathan 	}
148974029031Sjonathan 
14902620e166Sozaki-r 	KASSERTMSG(sp->policy == IPSEC_POLICY_IPSEC,
14912620e166Sozaki-r 	    "invalid policy %u", sp->policy);
149274029031Sjonathan 
149374029031Sjonathan 	siz = 0;
149474029031Sjonathan 	for (isr = sp->req; isr != NULL; isr = isr->next) {
149574029031Sjonathan 		size_t clen = 0;
149613270c39Sozaki-r 		struct secasvar *sav;
149774029031Sjonathan 
149874029031Sjonathan 		switch (isr->saidx.proto) {
149974029031Sjonathan 		case IPPROTO_ESP:
150013270c39Sozaki-r 			sav = ipsec_lookup_sa(isr, m);
150113270c39Sozaki-r 			if (sav != NULL) {
15025e860e54Sozaki-r 				clen = esp_hdrsiz(sav);
15038be5cabcSozaki-r 				KEY_SA_UNREF(&sav);
15045e860e54Sozaki-r 			} else
15055e860e54Sozaki-r 				clen = esp_hdrsiz(NULL);
150674029031Sjonathan 			break;
150774029031Sjonathan 		case IPPROTO_AH:
150813270c39Sozaki-r 			sav = ipsec_lookup_sa(isr, m);
150913270c39Sozaki-r 			if (sav != NULL) {
15105e860e54Sozaki-r 				clen = ah_hdrsiz(sav);
15118be5cabcSozaki-r 				KEY_SA_UNREF(&sav);
15125e860e54Sozaki-r 			} else
15135e860e54Sozaki-r 				clen = ah_hdrsiz(NULL);
151474029031Sjonathan 			break;
151574029031Sjonathan 		case IPPROTO_IPCOMP:
151674029031Sjonathan 			clen = sizeof(struct ipcomp);
151774029031Sjonathan 			break;
151874029031Sjonathan 		}
151974029031Sjonathan 
152074029031Sjonathan 		if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
152174029031Sjonathan 			switch (isr->saidx.dst.sa.sa_family) {
152274029031Sjonathan 			case AF_INET:
152374029031Sjonathan 				clen += sizeof(struct ip);
152474029031Sjonathan 				break;
152574029031Sjonathan #ifdef INET6
152674029031Sjonathan 			case AF_INET6:
152774029031Sjonathan 				clen += sizeof(struct ip6_hdr);
152874029031Sjonathan 				break;
152974029031Sjonathan #endif
153074029031Sjonathan 			default:
1531290dc492Sozaki-r 				IPSECLOG(LOG_ERR, "unknown AF %d in "
1532290dc492Sozaki-r 				    "IPsec tunnel SA\n",
153336443d4aSchristos 				    ((const struct sockaddr *)&isr->saidx.dst)
1534290dc492Sozaki-r 				    ->sa_family);
153574029031Sjonathan 				break;
153674029031Sjonathan 			}
153774029031Sjonathan 		}
153874029031Sjonathan 		siz += clen;
153974029031Sjonathan 	}
154074029031Sjonathan 
154174029031Sjonathan 	return siz;
154274029031Sjonathan }
154374029031Sjonathan 
154474029031Sjonathan size_t
ipsec_hdrsiz(struct mbuf * m,u_int dir,struct inpcb * inp)15450e390eeeSozaki-r ipsec_hdrsiz(struct mbuf *m, u_int dir, struct inpcb *inp)
154674029031Sjonathan {
154774029031Sjonathan 	struct secpolicy *sp;
154874029031Sjonathan 	int error;
154974029031Sjonathan 	size_t size;
155074029031Sjonathan 
15512620e166Sozaki-r 	KASSERT(m != NULL);
15520e390eeeSozaki-r 	KASSERTMSG(inp == NULL || inp->inp_socket != NULL,
15538df55a52Smaxv 	    "socket w/o inpcb");
155474029031Sjonathan 
15550e390eeeSozaki-r 	if (inp == NULL)
155674029031Sjonathan 		sp = ipsec_getpolicybyaddr(m, dir, IP_FORWARDING, &error);
155774029031Sjonathan 	else
15580e390eeeSozaki-r 		sp = ipsec_getpolicybysock(m, dir, inp, &error);
155974029031Sjonathan 
156074029031Sjonathan 	if (sp != NULL) {
1561af69f639Smaxv 		size = ipsec_sp_hdrsiz(sp, m);
156222e66c74Smaxv 		KEYDEBUG_PRINTF(KEYDEBUG_IPSEC_DATA, "size:%zu.\n", size);
15630c084e85Sozaki-r 		KEY_SP_UNREF(&sp);
156474029031Sjonathan 	} else {
15658df55a52Smaxv 		size = 0;
156674029031Sjonathan 	}
156722e66c74Smaxv 
156874029031Sjonathan 	return size;
156974029031Sjonathan }
157074029031Sjonathan 
157174029031Sjonathan /*
157274029031Sjonathan  * Check the variable replay window.
157374029031Sjonathan  * ipsec_chkreplay() performs replay check before ICV verification.
157474029031Sjonathan  * ipsec_updatereplay() updates replay bitmap.  This must be called after
157574029031Sjonathan  * ICV verification (it also performs replay check, which is usually done
157674029031Sjonathan  * beforehand).
157774029031Sjonathan  * 0 (zero) is returned if packet disallowed, 1 if packet permitted.
157874029031Sjonathan  *
157974029031Sjonathan  * based on RFC 2401.
158074029031Sjonathan  */
158174029031Sjonathan int
ipsec_chkreplay(u_int32_t seq,const struct secasvar * sav)1582bbd82ed1Sdrochner ipsec_chkreplay(u_int32_t seq, const struct secasvar *sav)
158374029031Sjonathan {
158474029031Sjonathan 	const struct secreplay *replay;
158574029031Sjonathan 	u_int32_t diff;
158674029031Sjonathan 	int fr;
158774029031Sjonathan 	u_int32_t wsizeb;	/* constant: bits of window size */
158874029031Sjonathan 	int frlast;		/* constant: last frame */
158974029031Sjonathan 
15902620e166Sozaki-r 	KASSERT(sav != NULL);
15912620e166Sozaki-r 	KASSERT(sav->replay != NULL);
159274029031Sjonathan 
159374029031Sjonathan 	replay = sav->replay;
159474029031Sjonathan 
159574029031Sjonathan 	if (replay->wsize == 0)
159674029031Sjonathan 		return 1;	/* no need to check replay. */
159774029031Sjonathan 
159874029031Sjonathan 	/* constant */
159974029031Sjonathan 	frlast = replay->wsize - 1;
160074029031Sjonathan 	wsizeb = replay->wsize << 3;
160174029031Sjonathan 
160274029031Sjonathan 	/* sequence number of 0 is invalid */
160374029031Sjonathan 	if (seq == 0)
160474029031Sjonathan 		return 0;
160574029031Sjonathan 
160674029031Sjonathan 	/* first time is always okay */
160774029031Sjonathan 	if (replay->count == 0)
160874029031Sjonathan 		return 1;
160974029031Sjonathan 
161074029031Sjonathan 	if (seq > replay->lastseq) {
161174029031Sjonathan 		/* larger sequences are okay */
161274029031Sjonathan 		return 1;
161374029031Sjonathan 	} else {
161474029031Sjonathan 		/* seq is equal or less than lastseq. */
161574029031Sjonathan 		diff = replay->lastseq - seq;
161674029031Sjonathan 
161774029031Sjonathan 		/* over range to check, i.e. too old or wrapped */
161874029031Sjonathan 		if (diff >= wsizeb)
161974029031Sjonathan 			return 0;
162074029031Sjonathan 
162174029031Sjonathan 		fr = frlast - diff / 8;
162274029031Sjonathan 
162374029031Sjonathan 		/* this packet already seen ? */
162474029031Sjonathan 		if ((replay->bitmap)[fr] & (1 << (diff % 8)))
162574029031Sjonathan 			return 0;
162674029031Sjonathan 
162774029031Sjonathan 		/* out of order but good */
162874029031Sjonathan 		return 1;
162974029031Sjonathan 	}
163074029031Sjonathan }
163174029031Sjonathan 
163274029031Sjonathan /*
163374029031Sjonathan  * check replay counter whether to update or not.
163474029031Sjonathan  * OUT:	0:	OK
163574029031Sjonathan  *	1:	NG
163674029031Sjonathan  */
163774029031Sjonathan int
ipsec_updatereplay(u_int32_t seq,const struct secasvar * sav)1638bbd82ed1Sdrochner ipsec_updatereplay(u_int32_t seq, const struct secasvar *sav)
163974029031Sjonathan {
164074029031Sjonathan 	struct secreplay *replay;
164174029031Sjonathan 	u_int32_t diff;
164274029031Sjonathan 	int fr;
164374029031Sjonathan 	u_int32_t wsizeb;	/* constant: bits of window size */
164474029031Sjonathan 	int frlast;		/* constant: last frame */
164574029031Sjonathan 
16462620e166Sozaki-r 	KASSERT(sav != NULL);
16472620e166Sozaki-r 	KASSERT(sav->replay != NULL);
164874029031Sjonathan 
164974029031Sjonathan 	replay = sav->replay;
165074029031Sjonathan 
165174029031Sjonathan 	if (replay->wsize == 0)
165274029031Sjonathan 		goto ok;	/* no need to check replay. */
165374029031Sjonathan 
165474029031Sjonathan 	/* constant */
165574029031Sjonathan 	frlast = replay->wsize - 1;
165674029031Sjonathan 	wsizeb = replay->wsize << 3;
165774029031Sjonathan 
165874029031Sjonathan 	/* sequence number of 0 is invalid */
165974029031Sjonathan 	if (seq == 0)
166074029031Sjonathan 		return 1;
166174029031Sjonathan 
166274029031Sjonathan 	/* first time */
166374029031Sjonathan 	if (replay->count == 0) {
166474029031Sjonathan 		replay->lastseq = seq;
1665c363a9cbScegger 		memset(replay->bitmap, 0, replay->wsize);
166674029031Sjonathan 		(replay->bitmap)[frlast] = 1;
166774029031Sjonathan 		goto ok;
166874029031Sjonathan 	}
166974029031Sjonathan 
167074029031Sjonathan 	if (seq > replay->lastseq) {
167174029031Sjonathan 		/* seq is larger than lastseq. */
167274029031Sjonathan 		diff = seq - replay->lastseq;
167374029031Sjonathan 
167474029031Sjonathan 		/* new larger sequence number */
167574029031Sjonathan 		if (diff < wsizeb) {
167674029031Sjonathan 			/* In window */
167774029031Sjonathan 			/* set bit for this packet */
167874029031Sjonathan 			vshiftl(replay->bitmap, diff, replay->wsize);
167974029031Sjonathan 			(replay->bitmap)[frlast] |= 1;
168074029031Sjonathan 		} else {
168174029031Sjonathan 			/* this packet has a "way larger" */
1682c363a9cbScegger 			memset(replay->bitmap, 0, replay->wsize);
168374029031Sjonathan 			(replay->bitmap)[frlast] = 1;
168474029031Sjonathan 		}
168574029031Sjonathan 		replay->lastseq = seq;
168674029031Sjonathan 
168774029031Sjonathan 		/* larger is good */
168874029031Sjonathan 	} else {
168974029031Sjonathan 		/* seq is equal or less than lastseq. */
169074029031Sjonathan 		diff = replay->lastseq - seq;
169174029031Sjonathan 
169274029031Sjonathan 		/* over range to check, i.e. too old or wrapped */
169374029031Sjonathan 		if (diff >= wsizeb)
169474029031Sjonathan 			return 1;
169574029031Sjonathan 
169674029031Sjonathan 		fr = frlast - diff / 8;
169774029031Sjonathan 
169874029031Sjonathan 		/* this packet already seen ? */
169974029031Sjonathan 		if ((replay->bitmap)[fr] & (1 << (diff % 8)))
170074029031Sjonathan 			return 1;
170174029031Sjonathan 
170274029031Sjonathan 		/* mark as seen */
170374029031Sjonathan 		(replay->bitmap)[fr] |= (1 << (diff % 8));
170474029031Sjonathan 
170574029031Sjonathan 		/* out of order but good */
170674029031Sjonathan 	}
170774029031Sjonathan 
170874029031Sjonathan ok:
170974029031Sjonathan 	if (replay->count == ~0) {
1710a05a27d7Sozaki-r 		char buf[IPSEC_LOGSASTRLEN];
171174029031Sjonathan 
171274029031Sjonathan 		/* set overflow flag */
171374029031Sjonathan 		replay->overflow++;
171474029031Sjonathan 
171574029031Sjonathan 		/* don't increment, no more packets accepted */
171674029031Sjonathan 		if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0)
171774029031Sjonathan 			return 1;
171874029031Sjonathan 
1719290dc492Sozaki-r 		IPSECLOG(LOG_WARNING, "replay counter made %d cycle. %s\n",
1720290dc492Sozaki-r 		    replay->overflow, ipsec_logsastr(sav, buf, sizeof(buf)));
172174029031Sjonathan 	}
172274029031Sjonathan 
172374029031Sjonathan 	replay->count++;
172474029031Sjonathan 
172574029031Sjonathan 	return 0;
172674029031Sjonathan }
172774029031Sjonathan 
172874029031Sjonathan /*
1729af69f639Smaxv  * shift variable length buffer to left.
173074029031Sjonathan  * IN:	bitmap: pointer to the buffer
173174029031Sjonathan  *	nbit:	the number of to shift.
173274029031Sjonathan  *	wsize:	buffer size (bytes).
173374029031Sjonathan  */
173474029031Sjonathan static void
vshiftl(unsigned char * bitmap,int nbit,int wsize)1735a382db0aSdegroote vshiftl(unsigned char *bitmap, int nbit, int wsize)
173674029031Sjonathan {
173774029031Sjonathan 	int s, j, i;
173874029031Sjonathan 	unsigned char over;
173974029031Sjonathan 
174074029031Sjonathan 	for (j = 0; j < nbit; j += 8) {
174174029031Sjonathan 		s = (nbit - j < 8) ? (nbit - j): 8;
174274029031Sjonathan 		bitmap[0] <<= s;
174374029031Sjonathan 		for (i = 1; i < wsize; i++) {
174474029031Sjonathan 			over = (bitmap[i] >> (8 - s));
174574029031Sjonathan 			bitmap[i] <<= s;
174674029031Sjonathan 			bitmap[i-1] |= over;
174774029031Sjonathan 		}
174874029031Sjonathan 	}
174974029031Sjonathan 
175074029031Sjonathan 	return;
175174029031Sjonathan }
175274029031Sjonathan 
175374029031Sjonathan /* Return a printable string for the address. */
1754f1171a42Schristos const char *
ipsec_address(const union sockaddr_union * sa,char * buf,size_t size)1755dd8c81f5Sryo ipsec_address(const union sockaddr_union *sa, char *buf, size_t size)
175674029031Sjonathan {
175774029031Sjonathan 	switch (sa->sa.sa_family) {
175874029031Sjonathan 	case AF_INET:
1759dd8c81f5Sryo 		in_print(buf, size, &sa->sin.sin_addr);
1760dd8c81f5Sryo 		return buf;
176174029031Sjonathan #if INET6
176274029031Sjonathan 	case AF_INET6:
1763dd8c81f5Sryo 		in6_print(buf, size, &sa->sin6.sin6_addr);
1764dd8c81f5Sryo 		return buf;
17659a3c5d51Smaxv #endif
176674029031Sjonathan 	default:
176774029031Sjonathan 		return "(unknown address family)";
176874029031Sjonathan 	}
176974029031Sjonathan }
177074029031Sjonathan 
177174029031Sjonathan const char *
ipsec_logsastr(const struct secasvar * sav,char * buf,size_t size)1772dd8c81f5Sryo ipsec_logsastr(const struct secasvar *sav, char *buf, size_t size)
177374029031Sjonathan {
1774bbd82ed1Sdrochner 	const struct secasindex *saidx = &sav->sah->saidx;
1775dd8c81f5Sryo 	char sbuf[IPSEC_ADDRSTRLEN], dbuf[IPSEC_ADDRSTRLEN];
177674029031Sjonathan 
177743d1c237Sozaki-r 	KASSERTMSG(saidx->src.sa.sa_family == saidx->dst.sa.sa_family,
177843d1c237Sozaki-r 	    "af family mismatch, src %u, dst %u",
177943d1c237Sozaki-r 	    saidx->src.sa.sa_family, saidx->dst.sa.sa_family);
178074029031Sjonathan 
1781dd8c81f5Sryo 	snprintf(buf, size, "SA(SPI=%u src=%s dst=%s)",
1782dd8c81f5Sryo 	    (u_int32_t)ntohl(sav->spi),
1783dd8c81f5Sryo 	    ipsec_address(&saidx->src, sbuf, sizeof(sbuf)),
1784dd8c81f5Sryo 	    ipsec_address(&saidx->dst, dbuf, sizeof(dbuf)));
178574029031Sjonathan 
178674029031Sjonathan 	return buf;
178774029031Sjonathan }
178874029031Sjonathan 
1789e2211411Sdegroote #ifdef INET6
1790e2211411Sdegroote struct secpolicy *
ipsec6_check_policy(struct mbuf * m,struct inpcb * inp,int flags,int * needipsecp,int * errorp)17910e390eeeSozaki-r ipsec6_check_policy(struct mbuf *m, struct inpcb *inp, int flags,
17929a3c5d51Smaxv     int *needipsecp, int *errorp)
1793e2211411Sdegroote {
1794e2211411Sdegroote 	struct secpolicy *sp = NULL;
1795e2211411Sdegroote 	int error = 0;
1796e2211411Sdegroote 	int needipsec = 0;
1797e2211411Sdegroote 
179852489f2bSmaxv 	if (ipsec_outdone(m)) {
179952489f2bSmaxv 		goto skippolicycheck;
180052489f2bSmaxv 	}
18010e390eeeSozaki-r 	if (inp && ipsec_pcb_skip_ipsec(inp->inp_sp, IPSEC_DIR_OUTBOUND)) {
1802e2211411Sdegroote 		goto skippolicycheck;
18037d100c18Sjakllsch 	}
18040e390eeeSozaki-r 	sp = ipsec_checkpolicy(m, IPSEC_DIR_OUTBOUND, flags, &error, inp);
1805e2211411Sdegroote 
1806e2211411Sdegroote 	/*
1807e2211411Sdegroote 	 * There are four return cases:
1808e2211411Sdegroote 	 *	sp != NULL                    apply IPsec policy
1809e2211411Sdegroote 	 *	sp == NULL, error == 0        no IPsec handling needed
1810e2211411Sdegroote 	 *	sp == NULL, error == -EINVAL  discard packet w/o error
1811e2211411Sdegroote 	 *	sp == NULL, error != 0        discard packet, report error
1812e2211411Sdegroote 	 */
1813e2211411Sdegroote 	if (sp == NULL) {
1814e2211411Sdegroote 		needipsec = 0;
1815e2211411Sdegroote 	} else {
1816e2211411Sdegroote 		needipsec = 1;
1817e2211411Sdegroote 	}
1818e2211411Sdegroote 
181952489f2bSmaxv skippolicycheck:
1820e2211411Sdegroote 	*errorp = error;
1821e2211411Sdegroote 	*needipsecp = needipsec;
1822e2211411Sdegroote 	return sp;
1823e2211411Sdegroote }
1824890dda53Sknakahara 
1825890dda53Sknakahara /*
1826890dda53Sknakahara  * calculate UDP checksum for UDP encapsulated ESP for IPv6.
1827890dda53Sknakahara  *
1828890dda53Sknakahara  * RFC2460(Internet Protocol, Version 6 Specification) says:
1829890dda53Sknakahara  *
1830890dda53Sknakahara  *   IPv6 receivers MUST discard UDP packets with a zero checksum.
1831890dda53Sknakahara  *
1832ee19b386Sandvar  * There is more relaxed specification RFC6935(IPv6 and UDP Checksums for
1833890dda53Sknakahara  * Tunneled Packets). The document allows zero checksum. It's too
1834890dda53Sknakahara  * late to publish, there are a lot of interoperability problems...
1835890dda53Sknakahara  */
1836890dda53Sknakahara void
ipsec6_udp_cksum(struct mbuf * m)1837890dda53Sknakahara ipsec6_udp_cksum(struct mbuf *m)
1838890dda53Sknakahara {
1839890dda53Sknakahara 	struct ip6_hdr *ip6;
1840890dda53Sknakahara 	uint16_t plen, uh_sum;
1841890dda53Sknakahara 	int off;
1842890dda53Sknakahara 
1843890dda53Sknakahara 	/* must called after m_pullup() */
1844890dda53Sknakahara 	KASSERT(m->m_len >= sizeof(struct ip6_hdr));
1845890dda53Sknakahara 
1846890dda53Sknakahara 	ip6 = mtod(m, struct ip6_hdr *);
1847890dda53Sknakahara 	KASSERT(ip6->ip6_nxt == IPPROTO_UDP);
1848890dda53Sknakahara 
1849890dda53Sknakahara 	/* ip6->ip6_plen can not be updated before ip6_output() */
1850890dda53Sknakahara 	plen = m->m_pkthdr.len - sizeof(*ip6);
1851890dda53Sknakahara 	KASSERT(plen >= sizeof(struct udphdr));
1852890dda53Sknakahara 
1853890dda53Sknakahara 	uh_sum = in6_cksum(m, IPPROTO_UDP, sizeof(*ip6), plen);
1854890dda53Sknakahara 	if (uh_sum == 0)
1855890dda53Sknakahara 		uh_sum = 0xffff;
1856890dda53Sknakahara 
1857890dda53Sknakahara 	off = sizeof(*ip6) + offsetof(struct udphdr, uh_sum);
1858890dda53Sknakahara 	m_copyback(m, off, sizeof(uh_sum), (void *)&uh_sum);
1859890dda53Sknakahara }
1860eefc30d5Sozaki-r #endif /* INET6 */
1861e2211411Sdegroote 
186216a6b570Smaxv /*
186316a6b570Smaxv  * -----------------------------------------------------------------------------
186416a6b570Smaxv  */
1865e2211411Sdegroote 
186674029031Sjonathan /* XXX this stuff doesn't belong here... */
186774029031Sjonathan 
186874029031Sjonathan static struct xformsw *xforms = NULL;
186974029031Sjonathan 
187074029031Sjonathan /*
187174029031Sjonathan  * Register a transform; typically at system startup.
187274029031Sjonathan  */
187374029031Sjonathan void
xform_register(struct xformsw * xsp)187474029031Sjonathan xform_register(struct xformsw *xsp)
187574029031Sjonathan {
187674029031Sjonathan 	xsp->xf_next = xforms;
187774029031Sjonathan 	xforms = xsp;
187874029031Sjonathan }
187974029031Sjonathan 
188074029031Sjonathan /*
188174029031Sjonathan  * Initialize transform support in an sav.
188274029031Sjonathan  */
188374029031Sjonathan int
xform_init(struct secasvar * sav,int xftype)188474029031Sjonathan xform_init(struct secasvar *sav, int xftype)
188574029031Sjonathan {
188674029031Sjonathan 	struct xformsw *xsp;
188774029031Sjonathan 
188874029031Sjonathan 	if (sav->tdb_xform != NULL)	/* previously initialized */
188974029031Sjonathan 		return 0;
189074029031Sjonathan 	for (xsp = xforms; xsp; xsp = xsp->xf_next)
189174029031Sjonathan 		if (xsp->xf_type == xftype)
189274029031Sjonathan 			return (*xsp->xf_init)(sav, xsp);
189374029031Sjonathan 
1894290dc492Sozaki-r 	IPSECLOG(LOG_DEBUG, "no match for xform type %d\n", xftype);
189574029031Sjonathan 	return EINVAL;
189674029031Sjonathan }
189774029031Sjonathan 
1898caf49ea5Sthorpej /*
1899caf49ea5Sthorpej  * XXXJRT This should be done as a protosw init call.
1900caf49ea5Sthorpej  */
190174029031Sjonathan void
ipsec_attach(void)190274029031Sjonathan ipsec_attach(void)
190374029031Sjonathan {
1904caf49ea5Sthorpej 
190564e64168Sozaki-r 	ipsec_output_init();
190664e64168Sozaki-r 
1907caf49ea5Sthorpej 	ipsecstat_percpu = percpu_alloc(sizeof(uint64_t) * IPSEC_NSTATS);
1908caf49ea5Sthorpej 
190980d40a78Sozaki-r 	sysctl_net_inet_ipsec_setup(NULL);
191080d40a78Sozaki-r #ifdef INET6
191180d40a78Sozaki-r 	sysctl_net_inet6_ipsec6_setup(NULL);
191280d40a78Sozaki-r #endif
191380d40a78Sozaki-r 
191474029031Sjonathan 	ah_attach();
191574029031Sjonathan 	esp_attach();
191674029031Sjonathan 	ipcomp_attach();
191774029031Sjonathan 	ipe4_attach();
1918887b782bSjonathan #ifdef TCP_SIGNATURE
1919887b782bSjonathan 	tcpsignature_attach();
1920887b782bSjonathan #endif
192174029031Sjonathan }
1922