ipsec_input.c revision 159965
1105197Ssam/*	$FreeBSD: head/sys/netipsec/ipsec_input.c 159965 2006-06-26 22:30:08Z thompsa $	*/
2112758Ssam/*	$OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $	*/
3139823Simp/*-
4112758Ssam * The authors of this code are John Ioannidis (ji@tla.org),
5112758Ssam * Angelos D. Keromytis (kermit@csd.uch.gr) and
6112758Ssam * Niels Provos (provos@physnet.uni-hamburg.de).
7112758Ssam *
8112758Ssam * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
9112758Ssam * in November 1995.
10112758Ssam *
11112758Ssam * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
12112758Ssam * by Angelos D. Keromytis.
13112758Ssam *
14112758Ssam * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
15112758Ssam * and Niels Provos.
16112758Ssam *
17112758Ssam * Additional features in 1999 by Angelos D. Keromytis.
18112758Ssam *
19112758Ssam * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
20112758Ssam * Angelos D. Keromytis and Niels Provos.
21112758Ssam * Copyright (c) 2001, Angelos D. Keromytis.
22112758Ssam *
23112758Ssam * Permission to use, copy, and modify this software with or without fee
24112758Ssam * is hereby granted, provided that this entire notice is included in
25112758Ssam * all copies of any software which is or includes a copy or
26112758Ssam * modification of this software.
27112758Ssam * You may use this code under the GNU public license if you so wish. Please
28112758Ssam * contribute changes back to the authors under this freer than GPL license
29112758Ssam * so that we may further the use of strong encryption without limitations to
30112758Ssam * all.
31112758Ssam *
32112758Ssam * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
33112758Ssam * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
34112758Ssam * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
35112758Ssam * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
36112758Ssam * PURPOSE.
37112758Ssam */
38105197Ssam
39105197Ssam/*
40105197Ssam * IPsec input processing.
41105197Ssam */
42105197Ssam
43105197Ssam#include "opt_inet.h"
44105197Ssam#include "opt_inet6.h"
45105197Ssam#include "opt_ipsec.h"
46159965Sthompsa#include "opt_enc.h"
47105197Ssam
48105197Ssam#include <sys/param.h>
49105197Ssam#include <sys/systm.h>
50105197Ssam#include <sys/malloc.h>
51105197Ssam#include <sys/mbuf.h>
52105197Ssam#include <sys/domain.h>
53105197Ssam#include <sys/protosw.h>
54105197Ssam#include <sys/socket.h>
55105197Ssam#include <sys/errno.h>
56105197Ssam#include <sys/syslog.h>
57105197Ssam
58105197Ssam#include <net/if.h>
59105197Ssam#include <net/route.h>
60105197Ssam#include <net/netisr.h>
61105197Ssam
62105197Ssam#include <netinet/in.h>
63105197Ssam#include <netinet/in_systm.h>
64105197Ssam#include <netinet/ip.h>
65105197Ssam#include <netinet/ip_var.h>
66105197Ssam#include <netinet/in_var.h>
67105197Ssam
68105197Ssam#include <netinet/ip6.h>
69105197Ssam#ifdef INET6
70105197Ssam#include <netinet6/ip6_var.h>
71105197Ssam#endif
72105197Ssam#include <netinet/in_pcb.h>
73105197Ssam#ifdef INET6
74105197Ssam#include <netinet/icmp6.h>
75105197Ssam#endif
76105197Ssam
77105197Ssam#include <netipsec/ipsec.h>
78105197Ssam#ifdef INET6
79105197Ssam#include <netipsec/ipsec6.h>
80105197Ssam#endif
81105197Ssam#include <netipsec/ah_var.h>
82105197Ssam#include <netipsec/esp.h>
83105197Ssam#include <netipsec/esp_var.h>
84105197Ssam#include <netipsec/ipcomp_var.h>
85105197Ssam
86105197Ssam#include <netipsec/key.h>
87105197Ssam#include <netipsec/keydb.h>
88105197Ssam
89105197Ssam#include <netipsec/xform.h>
90105197Ssam#include <netinet6/ip6protosw.h>
91105197Ssam
92105197Ssam#include <machine/in_cksum.h>
93105197Ssam#include <machine/stdarg.h>
94105197Ssam
95105197Ssam#define IPSEC_ISTAT(p,x,y,z) ((p) == IPPROTO_ESP ? (x)++ : \
96105197Ssam			    (p) == IPPROTO_AH ? (y)++ : (z)++)
97105197Ssam
98120585Ssamstatic void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int);
99120585Ssam
100105197Ssam/*
101105197Ssam * ipsec_common_input gets called when an IPsec-protected packet
102105197Ssam * is received by IPv4 or IPv6.  It's job is to find the right SA
103105197Ssam # and call the appropriate transform.  The transform callback
104105197Ssam * takes care of further processing (like ingress filtering).
105105197Ssam */
106105197Ssamstatic int
107105197Ssamipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
108105197Ssam{
109105197Ssam	union sockaddr_union dst_address;
110105197Ssam	struct secasvar *sav;
111105197Ssam	u_int32_t spi;
112119643Ssam	int error;
113105197Ssam
114105197Ssam	IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input,
115105197Ssam		ipcompstat.ipcomps_input);
116105197Ssam
117120585Ssam	IPSEC_ASSERT(m != NULL, ("null packet"));
118105197Ssam
119105197Ssam	if ((sproto == IPPROTO_ESP && !esp_enable) ||
120105197Ssam	    (sproto == IPPROTO_AH && !ah_enable) ||
121105197Ssam	    (sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
122105197Ssam		m_freem(m);
123105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_pdrops, ahstat.ahs_pdrops,
124105197Ssam		    ipcompstat.ipcomps_pdrops);
125105197Ssam		return EOPNOTSUPP;
126105197Ssam	}
127105197Ssam
128105197Ssam	if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) {
129105197Ssam		m_freem(m);
130105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
131105197Ssam		    ipcompstat.ipcomps_hdrops);
132120585Ssam		DPRINTF(("%s: packet too small\n", __func__));
133105197Ssam		return EINVAL;
134105197Ssam	}
135105197Ssam
136105197Ssam	/* Retrieve the SPI from the relevant IPsec header */
137105197Ssam	if (sproto == IPPROTO_ESP)
138105197Ssam		m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
139105197Ssam	else if (sproto == IPPROTO_AH)
140105197Ssam		m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
141105197Ssam		    (caddr_t) &spi);
142105197Ssam	else if (sproto == IPPROTO_IPCOMP) {
143105197Ssam		u_int16_t cpi;
144105197Ssam		m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
145105197Ssam		    (caddr_t) &cpi);
146105197Ssam		spi = ntohl(htons(cpi));
147105197Ssam	}
148105197Ssam
149105197Ssam	/*
150105197Ssam	 * Find the SA and (indirectly) call the appropriate
151105197Ssam	 * kernel crypto routine. The resulting mbuf chain is a valid
152105197Ssam	 * IP packet ready to go through input processing.
153105197Ssam	 */
154105197Ssam	bzero(&dst_address, sizeof (dst_address));
155105197Ssam	dst_address.sa.sa_family = af;
156105197Ssam	switch (af) {
157105197Ssam#ifdef INET
158105197Ssam	case AF_INET:
159105197Ssam		dst_address.sin.sin_len = sizeof(struct sockaddr_in);
160105197Ssam		m_copydata(m, offsetof(struct ip, ip_dst),
161105197Ssam		    sizeof(struct in_addr),
162105197Ssam		    (caddr_t) &dst_address.sin.sin_addr);
163105197Ssam		break;
164105197Ssam#endif /* INET */
165105197Ssam#ifdef INET6
166105197Ssam	case AF_INET6:
167105197Ssam		dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
168105197Ssam		m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
169105197Ssam		    sizeof(struct in6_addr),
170105197Ssam		    (caddr_t) &dst_address.sin6.sin6_addr);
171105197Ssam		break;
172105197Ssam#endif /* INET6 */
173105197Ssam	default:
174120585Ssam		DPRINTF(("%s: unsupported protocol family %u\n", __func__, af));
175105197Ssam		m_freem(m);
176105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_nopf, ahstat.ahs_nopf,
177105197Ssam		    ipcompstat.ipcomps_nopf);
178105197Ssam		return EPFNOSUPPORT;
179105197Ssam	}
180105197Ssam
181105197Ssam	/* NB: only pass dst since key_allocsa follows RFC2401 */
182105197Ssam	sav = KEY_ALLOCSA(&dst_address, sproto, spi);
183105197Ssam	if (sav == NULL) {
184120585Ssam		DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n",
185120585Ssam			  __func__, ipsec_address(&dst_address),
186105197Ssam			  (u_long) ntohl(spi), sproto));
187105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb,
188105197Ssam		    ipcompstat.ipcomps_notdb);
189105197Ssam		m_freem(m);
190105197Ssam		return ENOENT;
191105197Ssam	}
192105197Ssam
193105197Ssam	if (sav->tdb_xform == NULL) {
194120585Ssam		DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n",
195120585Ssam			 __func__, ipsec_address(&dst_address),
196105197Ssam			 (u_long) ntohl(spi), sproto));
197105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_noxform, ahstat.ahs_noxform,
198105197Ssam		    ipcompstat.ipcomps_noxform);
199105197Ssam		KEY_FREESAV(&sav);
200105197Ssam		m_freem(m);
201105197Ssam		return ENXIO;
202105197Ssam	}
203105197Ssam
204105197Ssam	/*
205105197Ssam	 * Call appropriate transform and return -- callback takes care of
206105197Ssam	 * everything else.
207105197Ssam	 */
208105197Ssam	error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff);
209105197Ssam	KEY_FREESAV(&sav);
210105197Ssam	return error;
211105197Ssam}
212105197Ssam
213105197Ssam#ifdef INET
214105197Ssam/*
215105197Ssam * Common input handler for IPv4 AH, ESP, and IPCOMP.
216105197Ssam */
217105197Ssamint
218105197Ssamipsec4_common_input(struct mbuf *m, ...)
219105197Ssam{
220105197Ssam	va_list ap;
221105197Ssam	int off, nxt;
222105197Ssam
223105197Ssam	va_start(ap, m);
224105197Ssam	off = va_arg(ap, int);
225105197Ssam	nxt = va_arg(ap, int);
226105197Ssam	va_end(ap);
227105197Ssam
228105197Ssam	return ipsec_common_input(m, off, offsetof(struct ip, ip_p),
229105197Ssam				  AF_INET, nxt);
230105197Ssam}
231105197Ssam
232106680Ssamvoid
233106680Ssamah4_input(struct mbuf *m, int off)
234106680Ssam{
235106680Ssam	ipsec4_common_input(m, off, IPPROTO_AH);
236106680Ssam}
237120585Ssamvoid
238120585Ssamah4_ctlinput(int cmd, struct sockaddr *sa, void *v)
239120585Ssam{
240120585Ssam	if (sa->sa_family == AF_INET &&
241120585Ssam	    sa->sa_len == sizeof(struct sockaddr_in))
242120585Ssam		ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_AH);
243120585Ssam}
244106680Ssam
245106680Ssamvoid
246106680Ssamesp4_input(struct mbuf *m, int off)
247106680Ssam{
248106680Ssam	ipsec4_common_input(m, off, IPPROTO_ESP);
249106680Ssam}
250120585Ssamvoid
251120585Ssamesp4_ctlinput(int cmd, struct sockaddr *sa, void *v)
252120585Ssam{
253120585Ssam	if (sa->sa_family == AF_INET &&
254120585Ssam	    sa->sa_len == sizeof(struct sockaddr_in))
255120585Ssam		ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_ESP);
256120585Ssam}
257106680Ssam
258106680Ssamvoid
259106680Ssamipcomp4_input(struct mbuf *m, int off)
260106680Ssam{
261106680Ssam	ipsec4_common_input(m, off, IPPROTO_IPCOMP);
262106680Ssam}
263106680Ssam
264105197Ssam/*
265105197Ssam * IPsec input callback for INET protocols.
266105197Ssam * This routine is called as the transform callback.
267105197Ssam * Takes care of filtering and other sanity checks on
268105197Ssam * the processed packet.
269105197Ssam */
270105197Ssamint
271105197Ssamipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
272105197Ssam			int skip, int protoff, struct m_tag *mt)
273105197Ssam{
274105197Ssam	int prot, af, sproto;
275105197Ssam	struct ip *ip;
276105197Ssam	struct m_tag *mtag;
277105197Ssam	struct tdb_ident *tdbi;
278105197Ssam	struct secasindex *saidx;
279105197Ssam	int error;
280105197Ssam
281120585Ssam	IPSEC_SPLASSERT_SOFTNET(__func__);
282105197Ssam
283120585Ssam	IPSEC_ASSERT(m != NULL, ("null mbuf"));
284120585Ssam	IPSEC_ASSERT(sav != NULL, ("null SA"));
285120585Ssam	IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
286105197Ssam	saidx = &sav->sah->saidx;
287105197Ssam	af = saidx->dst.sa.sa_family;
288120585Ssam	IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af));
289105197Ssam	sproto = saidx->proto;
290120585Ssam	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
291105197Ssam		sproto == IPPROTO_IPCOMP,
292120585Ssam		("unexpected security protocol %u", sproto));
293105197Ssam
294105197Ssam	/* Sanity check */
295105197Ssam	if (m == NULL) {
296120585Ssam		DPRINTF(("%s: null mbuf", __func__));
297105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
298105197Ssam		    ipcompstat.ipcomps_badkcr);
299105197Ssam		KEY_FREESAV(&sav);
300105197Ssam		return EINVAL;
301105197Ssam	}
302105197Ssam
303105197Ssam	if (skip != 0) {
304105197Ssam		/* Fix IPv4 header */
305105197Ssam		if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
306120585Ssam			DPRINTF(("%s: processing failed for SA %s/%08lx\n",
307120585Ssam			    __func__, ipsec_address(&sav->sah->saidx.dst),
308105197Ssam			    (u_long) ntohl(sav->spi)));
309105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
310105197Ssam			    ipcompstat.ipcomps_hdrops);
311105197Ssam			error = ENOBUFS;
312105197Ssam			goto bad;
313105197Ssam		}
314105197Ssam
315105197Ssam		ip = mtod(m, struct ip *);
316105197Ssam		ip->ip_len = htons(m->m_pkthdr.len);
317105197Ssam		ip->ip_off = htons(ip->ip_off);
318105197Ssam		ip->ip_sum = 0;
319105197Ssam		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
320105197Ssam	} else {
321105197Ssam		ip = mtod(m, struct ip *);
322105197Ssam	}
323105197Ssam	prot = ip->ip_p;
324105197Ssam
325159215Sgnn#ifdef notyet
326105197Ssam	/* IP-in-IP encapsulation */
327105197Ssam	if (prot == IPPROTO_IPIP) {
328105197Ssam		struct ip ipn;
329105197Ssam
330118888Ssam		if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
331118888Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
332118888Ssam			    ahstat.ahs_hdrops,
333118888Ssam			    ipcompstat.ipcomps_hdrops);
334118888Ssam			error = EINVAL;
335118888Ssam			goto bad;
336118888Ssam		}
337105197Ssam		/* ipn will now contain the inner IPv4 header */
338105197Ssam		m_copydata(m, ip->ip_hl << 2, sizeof(struct ip),
339105197Ssam		    (caddr_t) &ipn);
340105197Ssam
341105197Ssam		/* XXX PROXY address isn't recorded in SAH */
342105197Ssam		/*
343105197Ssam		 * Check that the inner source address is the same as
344105197Ssam		 * the proxy address, if available.
345105197Ssam		 */
346105197Ssam		if ((saidx->proxy.sa.sa_family == AF_INET &&
347105197Ssam		    saidx->proxy.sin.sin_addr.s_addr !=
348105197Ssam		    INADDR_ANY &&
349105197Ssam		    ipn.ip_src.s_addr !=
350105197Ssam		    saidx->proxy.sin.sin_addr.s_addr) ||
351105197Ssam		    (saidx->proxy.sa.sa_family != AF_INET &&
352105197Ssam			saidx->proxy.sa.sa_family != 0)) {
353105197Ssam
354120585Ssam			DPRINTF(("%s: inner source address %s doesn't "
355120585Ssam			    "correspond to expected proxy source %s, "
356120585Ssam			    "SA %s/%08lx\n", __func__,
357105197Ssam			    inet_ntoa4(ipn.ip_src),
358105197Ssam			    ipsp_address(saidx->proxy),
359105197Ssam			    ipsp_address(saidx->dst),
360105197Ssam			    (u_long) ntohl(sav->spi)));
361105197Ssam
362105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
363105197Ssam			    ahstat.ahs_pdrops,
364105197Ssam			    ipcompstat.ipcomps_pdrops);
365105197Ssam			error = EACCES;
366105197Ssam			goto bad;
367105197Ssam		}
368105197Ssam	}
369159237Spjd#ifdef INET6
370105197Ssam	/* IPv6-in-IP encapsulation. */
371105197Ssam	if (prot == IPPROTO_IPV6) {
372105197Ssam		struct ip6_hdr ip6n;
373105197Ssam
374118888Ssam		if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
375118888Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
376118888Ssam			    ahstat.ahs_hdrops,
377118888Ssam			    ipcompstat.ipcomps_hdrops);
378118888Ssam			error = EINVAL;
379118888Ssam			goto bad;
380118888Ssam		}
381105197Ssam		/* ip6n will now contain the inner IPv6 header. */
382105197Ssam		m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr),
383105197Ssam		    (caddr_t) &ip6n);
384105197Ssam
385105197Ssam		/*
386105197Ssam		 * Check that the inner source address is the same as
387105197Ssam		 * the proxy address, if available.
388105197Ssam		 */
389105197Ssam		if ((saidx->proxy.sa.sa_family == AF_INET6 &&
390105197Ssam		    !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
391105197Ssam		    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
392105197Ssam			&saidx->proxy.sin6.sin6_addr)) ||
393105197Ssam		    (saidx->proxy.sa.sa_family != AF_INET6 &&
394105197Ssam			saidx->proxy.sa.sa_family != 0)) {
395105197Ssam
396120585Ssam			DPRINTF(("%s: inner source address %s doesn't "
397120585Ssam			    "correspond to expected proxy source %s, "
398120585Ssam			    "SA %s/%08lx\n", __func__,
399105197Ssam			    ip6_sprintf(&ip6n.ip6_src),
400105197Ssam			    ipsec_address(&saidx->proxy),
401105197Ssam			    ipsec_address(&saidx->dst),
402105197Ssam			    (u_long) ntohl(sav->spi)));
403105197Ssam
404105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
405105197Ssam			    ahstat.ahs_pdrops,
406105197Ssam			    ipcompstat.ipcomps_pdrops);
407105197Ssam			error = EACCES;
408105197Ssam			goto bad;
409105197Ssam		}
410105197Ssam	}
411105197Ssam#endif /* INET6 */
412159215Sgnn#endif /*XXX*/
413105197Ssam
414105197Ssam	/*
415105197Ssam	 * Record what we've done to the packet (under what SA it was
416105197Ssam	 * processed). If we've been passed an mtag, it means the packet
417105197Ssam	 * was already processed by an ethernet/crypto combo card and
418105197Ssam	 * thus has a tag attached with all the right information, but
419105197Ssam	 * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
420105197Ssam	 * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
421105197Ssam	 */
422105197Ssam	if (mt == NULL && sproto != IPPROTO_IPCOMP) {
423105197Ssam		mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
424105197Ssam		    sizeof(struct tdb_ident), M_NOWAIT);
425105197Ssam		if (mtag == NULL) {
426120585Ssam			DPRINTF(("%s: failed to get tag\n", __func__));
427105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
428105197Ssam			    ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
429105197Ssam			error = ENOMEM;
430105197Ssam			goto bad;
431105197Ssam		}
432105197Ssam
433105197Ssam		tdbi = (struct tdb_ident *)(mtag + 1);
434105197Ssam		bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len);
435105197Ssam		tdbi->proto = sproto;
436105197Ssam		tdbi->spi = sav->spi;
437105197Ssam
438105197Ssam		m_tag_prepend(m, mtag);
439105197Ssam	} else {
440105197Ssam		mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
441105197Ssam		/* XXX do we need to mark m_flags??? */
442105197Ssam	}
443105197Ssam
444105197Ssam	key_sa_recordxfer(sav, m);		/* record data transfer */
445105197Ssam
446159965Sthompsa#ifdef DEV_ENC
447105197Ssam	/*
448159965Sthompsa	 * Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP
449159965Sthompsa	 * packet later after it has been decapsulated.
450159965Sthompsa	 */
451159965Sthompsa	ipsec_bpf(m, sav, AF_INET);
452159965Sthompsa
453159965Sthompsa	if (prot != IPPROTO_IPIP)
454159965Sthompsa		if ((error = ipsec_filter(&m, 1)) != 0)
455159965Sthompsa			return (error);
456159965Sthompsa#endif
457159965Sthompsa
458159965Sthompsa	/*
459105197Ssam	 * Re-dispatch via software interrupt.
460105197Ssam	 */
461134391Sandre	if ((error = netisr_queue(NETISR_IP, m))) {
462105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_qfull, ahstat.ahs_qfull,
463105197Ssam			    ipcompstat.ipcomps_qfull);
464105197Ssam
465120585Ssam		DPRINTF(("%s: queue full; proto %u packet dropped\n",
466120585Ssam			__func__, sproto));
467134391Sandre		return error;
468105197Ssam	}
469105197Ssam	return 0;
470105197Ssambad:
471105197Ssam	m_freem(m);
472105197Ssam	return error;
473105197Ssam}
474120585Ssam
475120585Ssamvoid
476120585Ssamipsec4_common_ctlinput(int cmd, struct sockaddr *sa, void *v, int proto)
477120585Ssam{
478120585Ssam	/* XXX nothing just yet */
479120585Ssam}
480105197Ssam#endif /* INET */
481105197Ssam
482105197Ssam#ifdef INET6
483105197Ssam/* IPv6 AH wrapper. */
484105197Ssamint
485105197Ssamipsec6_common_input(struct mbuf **mp, int *offp, int proto)
486105197Ssam{
487105197Ssam	int l = 0;
488105197Ssam	int protoff;
489105197Ssam	struct ip6_ext ip6e;
490105197Ssam
491105197Ssam	if (*offp < sizeof(struct ip6_hdr)) {
492120585Ssam		DPRINTF(("%s: bad offset %u\n", __func__, *offp));
493105197Ssam		return IPPROTO_DONE;
494105197Ssam	} else if (*offp == sizeof(struct ip6_hdr)) {
495105197Ssam		protoff = offsetof(struct ip6_hdr, ip6_nxt);
496105197Ssam	} else {
497105197Ssam		/* Chase down the header chain... */
498105197Ssam		protoff = sizeof(struct ip6_hdr);
499105197Ssam
500105197Ssam		do {
501105197Ssam			protoff += l;
502105197Ssam			m_copydata(*mp, protoff, sizeof(ip6e),
503105197Ssam			    (caddr_t) &ip6e);
504105197Ssam
505105197Ssam			if (ip6e.ip6e_nxt == IPPROTO_AH)
506105197Ssam				l = (ip6e.ip6e_len + 2) << 2;
507105197Ssam			else
508105197Ssam				l = (ip6e.ip6e_len + 1) << 3;
509120585Ssam			IPSEC_ASSERT(l > 0, ("l went zero or negative"));
510105197Ssam		} while (protoff + l < *offp);
511105197Ssam
512105197Ssam		/* Malformed packet check */
513105197Ssam		if (protoff + l != *offp) {
514120585Ssam			DPRINTF(("%s: bad packet header chain, protoff %u, "
515120585Ssam				"l %u, off %u\n", __func__, protoff, l, *offp));
516105197Ssam			IPSEC_ISTAT(proto, espstat.esps_hdrops,
517105197Ssam				    ahstat.ahs_hdrops,
518105197Ssam				    ipcompstat.ipcomps_hdrops);
519105197Ssam			m_freem(*mp);
520105197Ssam			*mp = NULL;
521105197Ssam			return IPPROTO_DONE;
522105197Ssam		}
523105197Ssam		protoff += offsetof(struct ip6_ext, ip6e_nxt);
524105197Ssam	}
525105197Ssam	(void) ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto);
526105197Ssam	return IPPROTO_DONE;
527105197Ssam}
528105197Ssam
529105197Ssam/*
530105197Ssam * IPsec input callback, called by the transform callback. Takes care of
531105197Ssam * filtering and other sanity checks on the processed packet.
532105197Ssam */
533105197Ssamint
534105197Ssamipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff,
535105197Ssam    struct m_tag *mt)
536105197Ssam{
537105197Ssam	int prot, af, sproto;
538105197Ssam	struct ip6_hdr *ip6;
539105197Ssam	struct m_tag *mtag;
540105197Ssam	struct tdb_ident *tdbi;
541105197Ssam	struct secasindex *saidx;
542105197Ssam	int nxt;
543105197Ssam	u_int8_t nxt8;
544105197Ssam	int error, nest;
545105197Ssam
546120585Ssam	IPSEC_ASSERT(m != NULL, ("null mbuf"));
547120585Ssam	IPSEC_ASSERT(sav != NULL, ("null SA"));
548120585Ssam	IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
549105197Ssam	saidx = &sav->sah->saidx;
550105197Ssam	af = saidx->dst.sa.sa_family;
551120585Ssam	IPSEC_ASSERT(af == AF_INET6, ("unexpected af %u", af));
552105197Ssam	sproto = saidx->proto;
553120585Ssam	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
554105197Ssam		sproto == IPPROTO_IPCOMP,
555120585Ssam		("unexpected security protocol %u", sproto));
556105197Ssam
557105197Ssam	/* Sanity check */
558105197Ssam	if (m == NULL) {
559120585Ssam		DPRINTF(("%s: null mbuf", __func__));
560105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
561105197Ssam		    ipcompstat.ipcomps_badkcr);
562105197Ssam		error = EINVAL;
563105197Ssam		goto bad;
564105197Ssam	}
565105197Ssam
566105197Ssam	/* Fix IPv6 header */
567105197Ssam	if (m->m_len < sizeof(struct ip6_hdr) &&
568105197Ssam	    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
569105197Ssam
570120585Ssam		DPRINTF(("%s: processing failed for SA %s/%08lx\n",
571120585Ssam		    __func__, ipsec_address(&sav->sah->saidx.dst),
572105197Ssam		    (u_long) ntohl(sav->spi)));
573105197Ssam
574105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
575105197Ssam		    ipcompstat.ipcomps_hdrops);
576105197Ssam		error = EACCES;
577105197Ssam		goto bad;
578105197Ssam	}
579105197Ssam
580105197Ssam	ip6 = mtod(m, struct ip6_hdr *);
581105197Ssam	ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
582105197Ssam
583105197Ssam	/* Save protocol */
584105197Ssam	m_copydata(m, protoff, 1, (unsigned char *) &prot);
585105197Ssam
586159215Sgnn#ifdef notyet
587105197Ssam#ifdef INET
588105197Ssam	/* IP-in-IP encapsulation */
589105197Ssam	if (prot == IPPROTO_IPIP) {
590105197Ssam		struct ip ipn;
591105197Ssam
592118888Ssam		if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
593118888Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
594118888Ssam			    ahstat.ahs_hdrops,
595118888Ssam			    ipcompstat.ipcomps_hdrops);
596118888Ssam			error = EINVAL;
597118888Ssam			goto bad;
598118888Ssam		}
599105197Ssam		/* ipn will now contain the inner IPv4 header */
600105197Ssam		m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);
601105197Ssam
602105197Ssam		/*
603105197Ssam		 * Check that the inner source address is the same as
604105197Ssam		 * the proxy address, if available.
605105197Ssam		 */
606105197Ssam		if ((saidx->proxy.sa.sa_family == AF_INET &&
607105197Ssam		    saidx->proxy.sin.sin_addr.s_addr != INADDR_ANY &&
608105197Ssam		    ipn.ip_src.s_addr != saidx->proxy.sin.sin_addr.s_addr) ||
609105197Ssam		    (saidx->proxy.sa.sa_family != AF_INET &&
610105197Ssam			saidx->proxy.sa.sa_family != 0)) {
611105197Ssam
612120585Ssam			DPRINTF(("%s: inner source address %s doesn't "
613120585Ssam			    "correspond to expected proxy source %s, "
614120585Ssam			    "SA %s/%08lx\n", __func__,
615105197Ssam			    inet_ntoa4(ipn.ip_src),
616105197Ssam			    ipsec_address(&saidx->proxy),
617105197Ssam			    ipsec_address(&saidx->dst),
618105197Ssam			    (u_long) ntohl(sav->spi)));
619105197Ssam
620105197Ssam			IPSEC_ISTATsproto, (espstat.esps_pdrops,
621105197Ssam			    ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
622105197Ssam			error = EACCES;
623105197Ssam			goto bad;
624105197Ssam		}
625105197Ssam	}
626105197Ssam#endif /* INET */
627105197Ssam
628105197Ssam	/* IPv6-in-IP encapsulation */
629105197Ssam	if (prot == IPPROTO_IPV6) {
630105197Ssam		struct ip6_hdr ip6n;
631105197Ssam
632118888Ssam		if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
633118888Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
634118888Ssam			    ahstat.ahs_hdrops,
635118888Ssam			    ipcompstat.ipcomps_hdrops);
636118888Ssam			error = EINVAL;
637118888Ssam			goto bad;
638118888Ssam		}
639105197Ssam		/* ip6n will now contain the inner IPv6 header. */
640105197Ssam		m_copydata(m, skip, sizeof(struct ip6_hdr),
641105197Ssam		    (caddr_t) &ip6n);
642105197Ssam
643105197Ssam		/*
644105197Ssam		 * Check that the inner source address is the same as
645105197Ssam		 * the proxy address, if available.
646105197Ssam		 */
647105197Ssam		if ((saidx->proxy.sa.sa_family == AF_INET6 &&
648105197Ssam		    !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
649105197Ssam		    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
650105197Ssam			&saidx->proxy.sin6.sin6_addr)) ||
651105197Ssam		    (saidx->proxy.sa.sa_family != AF_INET6 &&
652105197Ssam			saidx->proxy.sa.sa_family != 0)) {
653105197Ssam
654120585Ssam			DPRINTF(("%s: inner source address %s doesn't "
655120585Ssam			    "correspond to expected proxy source %s, "
656120585Ssam			    "SA %s/%08lx\n", __func__,
657105197Ssam			    ip6_sprintf(&ip6n.ip6_src),
658105197Ssam			    ipsec_address(&saidx->proxy),
659105197Ssam			    ipsec_address(&saidx->dst),
660105197Ssam			    (u_long) ntohl(sav->spi)));
661105197Ssam
662105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
663105197Ssam			    ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
664105197Ssam			error = EACCES;
665105197Ssam			goto bad;
666105197Ssam		}
667159215Sgnn	}
668105197Ssam#endif /*XXX*/
669105197Ssam
670105197Ssam	/*
671105197Ssam	 * Record what we've done to the packet (under what SA it was
672105197Ssam	 * processed). If we've been passed an mtag, it means the packet
673105197Ssam	 * was already processed by an ethernet/crypto combo card and
674105197Ssam	 * thus has a tag attached with all the right information, but
675105197Ssam	 * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
676105197Ssam	 * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
677105197Ssam	 */
678105197Ssam	if (mt == NULL && sproto != IPPROTO_IPCOMP) {
679105197Ssam		mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
680105197Ssam		    sizeof(struct tdb_ident), M_NOWAIT);
681105197Ssam		if (mtag == NULL) {
682120585Ssam			DPRINTF(("%s: failed to get tag\n", __func__));
683105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
684105197Ssam			    ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
685105197Ssam			error = ENOMEM;
686105197Ssam			goto bad;
687105197Ssam		}
688105197Ssam
689105197Ssam		tdbi = (struct tdb_ident *)(mtag + 1);
690105197Ssam		bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union));
691105197Ssam		tdbi->proto = sproto;
692105197Ssam		tdbi->spi = sav->spi;
693105197Ssam
694105197Ssam		m_tag_prepend(m, mtag);
695105197Ssam	} else {
696120585Ssam		if (mt != NULL)
697120585Ssam			mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
698105197Ssam		/* XXX do we need to mark m_flags??? */
699105197Ssam	}
700105197Ssam
701105197Ssam	key_sa_recordxfer(sav, m);
702105197Ssam
703105197Ssam	/* Retrieve new protocol */
704105197Ssam	m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8);
705105197Ssam
706105197Ssam	/*
707105197Ssam	 * See the end of ip6_input for this logic.
708105197Ssam	 * IPPROTO_IPV[46] case will be processed just like other ones
709105197Ssam	 */
710105197Ssam	nest = 0;
711105197Ssam	nxt = nxt8;
712105197Ssam	while (nxt != IPPROTO_DONE) {
713105197Ssam		if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
714105197Ssam			ip6stat.ip6s_toomanyhdr++;
715105197Ssam			error = EINVAL;
716105197Ssam			goto bad;
717105197Ssam		}
718105197Ssam
719105197Ssam		/*
720105197Ssam		 * Protection against faulty packet - there should be
721105197Ssam		 * more sanity checks in header chain processing.
722105197Ssam		 */
723105197Ssam		if (m->m_pkthdr.len < skip) {
724105197Ssam			ip6stat.ip6s_tooshort++;
725105197Ssam			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
726105197Ssam			error = EINVAL;
727105197Ssam			goto bad;
728105197Ssam		}
729105197Ssam		/*
730105197Ssam		 * Enforce IPsec policy checking if we are seeing last header.
731105197Ssam		 * note that we do not visit this with protocols with pcb layer
732105197Ssam		 * code - like udp/tcp/raw ip.
733105197Ssam		 */
734105197Ssam		if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
735105197Ssam		    ipsec6_in_reject(m, NULL)) {
736105197Ssam			error = EINVAL;
737105197Ssam			goto bad;
738105197Ssam		}
739105197Ssam		nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt);
740105197Ssam	}
741105197Ssam	return 0;
742105197Ssambad:
743105197Ssam	if (m)
744105197Ssam		m_freem(m);
745105197Ssam	return error;
746105197Ssam}
747120585Ssam
748120585Ssamvoid
749120585Ssamesp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
750120585Ssam{
751120585Ssam	if (sa->sa_family != AF_INET6 ||
752120585Ssam	    sa->sa_len != sizeof(struct sockaddr_in6))
753120585Ssam		return;
754120585Ssam	if ((unsigned)cmd >= PRC_NCMDS)
755120585Ssam		return;
756120585Ssam
757120585Ssam	/* if the parameter is from icmp6, decode it. */
758120585Ssam	if (d !=  NULL) {
759120585Ssam		struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
760120585Ssam		struct mbuf *m = ip6cp->ip6c_m;
761120585Ssam		int off = ip6cp->ip6c_off;
762120585Ssam
763120585Ssam		struct ip6ctlparam ip6cp1;
764120585Ssam
765120585Ssam		/*
766120585Ssam		 * Notify the error to all possible sockets via pfctlinput2.
767120585Ssam		 * Since the upper layer information (such as protocol type,
768120585Ssam		 * source and destination ports) is embedded in the encrypted
769120585Ssam		 * data and might have been cut, we can't directly call
770120585Ssam		 * an upper layer ctlinput function. However, the pcbnotify
771120585Ssam		 * function will consider source and destination addresses
772120585Ssam		 * as well as the flow info value, and may be able to find
773120585Ssam		 * some PCB that should be notified.
774120585Ssam		 * Although pfctlinput2 will call esp6_ctlinput(), there is
775120585Ssam		 * no possibility of an infinite loop of function calls,
776120585Ssam		 * because we don't pass the inner IPv6 header.
777120585Ssam		 */
778120585Ssam		bzero(&ip6cp1, sizeof(ip6cp1));
779120585Ssam		ip6cp1.ip6c_src = ip6cp->ip6c_src;
780120585Ssam		pfctlinput2(cmd, sa, (void *)&ip6cp1);
781120585Ssam
782120585Ssam		/*
783120585Ssam		 * Then go to special cases that need ESP header information.
784120585Ssam		 * XXX: We assume that when ip6 is non NULL,
785120585Ssam		 * M and OFF are valid.
786120585Ssam		 */
787120585Ssam
788120585Ssam		if (cmd == PRC_MSGSIZE) {
789120585Ssam			struct secasvar *sav;
790120585Ssam			u_int32_t spi;
791120585Ssam			int valid;
792120585Ssam
793120585Ssam			/* check header length before using m_copydata */
794120585Ssam			if (m->m_pkthdr.len < off + sizeof (struct esp))
795120585Ssam				return;
796120585Ssam			m_copydata(m, off + offsetof(struct esp, esp_spi),
797120585Ssam				sizeof(u_int32_t), (caddr_t) &spi);
798120585Ssam			/*
799120585Ssam			 * Check to see if we have a valid SA corresponding to
800120585Ssam			 * the address in the ICMP message payload.
801120585Ssam			 */
802120585Ssam			sav = KEY_ALLOCSA((union sockaddr_union *)sa,
803120585Ssam					IPPROTO_ESP, spi);
804120585Ssam			valid = (sav != NULL);
805120585Ssam			if (sav)
806120585Ssam				KEY_FREESAV(&sav);
807120585Ssam
808120585Ssam			/* XXX Further validation? */
809120585Ssam
810120585Ssam			/*
811120585Ssam			 * Depending on whether the SA is "valid" and
812120585Ssam			 * routing table size (mtudisc_{hi,lo}wat), we will:
813120585Ssam			 * - recalcurate the new MTU and create the
814120585Ssam			 *   corresponding routing entry, or
815120585Ssam			 * - ignore the MTU change notification.
816120585Ssam			 */
817120585Ssam			icmp6_mtudisc_update(ip6cp, valid);
818120585Ssam		}
819120585Ssam	} else {
820120585Ssam		/* we normally notify any pcb here */
821120585Ssam	}
822120585Ssam}
823105197Ssam#endif /* INET6 */
824