ipsec_input.c revision 165222
1105197Ssam/*	$FreeBSD: head/sys/netipsec/ipsec_input.c 165222 2006-12-14 17:33:46Z bz $	*/
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;
280165222Sbz#ifdef INET6
281165118Sbz#ifdef notyet
282165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
283165118Sbz#endif
284165118Sbz#endif
285105197Ssam
286120585Ssam	IPSEC_SPLASSERT_SOFTNET(__func__);
287105197Ssam
288120585Ssam	IPSEC_ASSERT(m != NULL, ("null mbuf"));
289120585Ssam	IPSEC_ASSERT(sav != NULL, ("null SA"));
290120585Ssam	IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
291105197Ssam	saidx = &sav->sah->saidx;
292105197Ssam	af = saidx->dst.sa.sa_family;
293120585Ssam	IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af));
294105197Ssam	sproto = saidx->proto;
295120585Ssam	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
296105197Ssam		sproto == IPPROTO_IPCOMP,
297120585Ssam		("unexpected security protocol %u", sproto));
298105197Ssam
299105197Ssam	/* Sanity check */
300105197Ssam	if (m == NULL) {
301120585Ssam		DPRINTF(("%s: null mbuf", __func__));
302105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
303105197Ssam		    ipcompstat.ipcomps_badkcr);
304105197Ssam		KEY_FREESAV(&sav);
305105197Ssam		return EINVAL;
306105197Ssam	}
307105197Ssam
308105197Ssam	if (skip != 0) {
309105197Ssam		/* Fix IPv4 header */
310105197Ssam		if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
311120585Ssam			DPRINTF(("%s: processing failed for SA %s/%08lx\n",
312120585Ssam			    __func__, ipsec_address(&sav->sah->saidx.dst),
313105197Ssam			    (u_long) ntohl(sav->spi)));
314105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
315105197Ssam			    ipcompstat.ipcomps_hdrops);
316105197Ssam			error = ENOBUFS;
317105197Ssam			goto bad;
318105197Ssam		}
319105197Ssam
320105197Ssam		ip = mtod(m, struct ip *);
321105197Ssam		ip->ip_len = htons(m->m_pkthdr.len);
322105197Ssam		ip->ip_off = htons(ip->ip_off);
323105197Ssam		ip->ip_sum = 0;
324105197Ssam		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
325105197Ssam	} else {
326105197Ssam		ip = mtod(m, struct ip *);
327105197Ssam	}
328105197Ssam	prot = ip->ip_p;
329105197Ssam
330159215Sgnn#ifdef notyet
331105197Ssam	/* IP-in-IP encapsulation */
332105197Ssam	if (prot == IPPROTO_IPIP) {
333105197Ssam		struct ip ipn;
334105197Ssam
335118888Ssam		if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
336118888Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
337118888Ssam			    ahstat.ahs_hdrops,
338118888Ssam			    ipcompstat.ipcomps_hdrops);
339118888Ssam			error = EINVAL;
340118888Ssam			goto bad;
341118888Ssam		}
342105197Ssam		/* ipn will now contain the inner IPv4 header */
343105197Ssam		m_copydata(m, ip->ip_hl << 2, sizeof(struct ip),
344105197Ssam		    (caddr_t) &ipn);
345105197Ssam
346105197Ssam		/* XXX PROXY address isn't recorded in SAH */
347105197Ssam		/*
348105197Ssam		 * Check that the inner source address is the same as
349105197Ssam		 * the proxy address, if available.
350105197Ssam		 */
351105197Ssam		if ((saidx->proxy.sa.sa_family == AF_INET &&
352105197Ssam		    saidx->proxy.sin.sin_addr.s_addr !=
353105197Ssam		    INADDR_ANY &&
354105197Ssam		    ipn.ip_src.s_addr !=
355105197Ssam		    saidx->proxy.sin.sin_addr.s_addr) ||
356105197Ssam		    (saidx->proxy.sa.sa_family != AF_INET &&
357105197Ssam			saidx->proxy.sa.sa_family != 0)) {
358105197Ssam
359120585Ssam			DPRINTF(("%s: inner source address %s doesn't "
360120585Ssam			    "correspond to expected proxy source %s, "
361120585Ssam			    "SA %s/%08lx\n", __func__,
362105197Ssam			    inet_ntoa4(ipn.ip_src),
363105197Ssam			    ipsp_address(saidx->proxy),
364105197Ssam			    ipsp_address(saidx->dst),
365105197Ssam			    (u_long) ntohl(sav->spi)));
366105197Ssam
367105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
368105197Ssam			    ahstat.ahs_pdrops,
369105197Ssam			    ipcompstat.ipcomps_pdrops);
370105197Ssam			error = EACCES;
371105197Ssam			goto bad;
372105197Ssam		}
373105197Ssam	}
374159237Spjd#ifdef INET6
375105197Ssam	/* IPv6-in-IP encapsulation. */
376105197Ssam	if (prot == IPPROTO_IPV6) {
377105197Ssam		struct ip6_hdr ip6n;
378105197Ssam
379118888Ssam		if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
380118888Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
381118888Ssam			    ahstat.ahs_hdrops,
382118888Ssam			    ipcompstat.ipcomps_hdrops);
383118888Ssam			error = EINVAL;
384118888Ssam			goto bad;
385118888Ssam		}
386105197Ssam		/* ip6n will now contain the inner IPv6 header. */
387105197Ssam		m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr),
388105197Ssam		    (caddr_t) &ip6n);
389105197Ssam
390105197Ssam		/*
391105197Ssam		 * Check that the inner source address is the same as
392105197Ssam		 * the proxy address, if available.
393105197Ssam		 */
394105197Ssam		if ((saidx->proxy.sa.sa_family == AF_INET6 &&
395105197Ssam		    !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
396105197Ssam		    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
397105197Ssam			&saidx->proxy.sin6.sin6_addr)) ||
398105197Ssam		    (saidx->proxy.sa.sa_family != AF_INET6 &&
399105197Ssam			saidx->proxy.sa.sa_family != 0)) {
400105197Ssam
401120585Ssam			DPRINTF(("%s: inner source address %s doesn't "
402120585Ssam			    "correspond to expected proxy source %s, "
403120585Ssam			    "SA %s/%08lx\n", __func__,
404165118Sbz			    ip6_sprintf(ip6buf, &ip6n.ip6_src),
405105197Ssam			    ipsec_address(&saidx->proxy),
406105197Ssam			    ipsec_address(&saidx->dst),
407105197Ssam			    (u_long) ntohl(sav->spi)));
408105197Ssam
409105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
410105197Ssam			    ahstat.ahs_pdrops,
411105197Ssam			    ipcompstat.ipcomps_pdrops);
412105197Ssam			error = EACCES;
413105197Ssam			goto bad;
414105197Ssam		}
415105197Ssam	}
416105197Ssam#endif /* INET6 */
417159215Sgnn#endif /*XXX*/
418105197Ssam
419105197Ssam	/*
420105197Ssam	 * Record what we've done to the packet (under what SA it was
421105197Ssam	 * processed). If we've been passed an mtag, it means the packet
422105197Ssam	 * was already processed by an ethernet/crypto combo card and
423105197Ssam	 * thus has a tag attached with all the right information, but
424105197Ssam	 * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
425105197Ssam	 * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
426105197Ssam	 */
427105197Ssam	if (mt == NULL && sproto != IPPROTO_IPCOMP) {
428105197Ssam		mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
429105197Ssam		    sizeof(struct tdb_ident), M_NOWAIT);
430105197Ssam		if (mtag == NULL) {
431120585Ssam			DPRINTF(("%s: failed to get tag\n", __func__));
432105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
433105197Ssam			    ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
434105197Ssam			error = ENOMEM;
435105197Ssam			goto bad;
436105197Ssam		}
437105197Ssam
438105197Ssam		tdbi = (struct tdb_ident *)(mtag + 1);
439105197Ssam		bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len);
440105197Ssam		tdbi->proto = sproto;
441105197Ssam		tdbi->spi = sav->spi;
442105197Ssam
443105197Ssam		m_tag_prepend(m, mtag);
444105197Ssam	} else {
445105197Ssam		mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
446105197Ssam		/* XXX do we need to mark m_flags??? */
447105197Ssam	}
448105197Ssam
449105197Ssam	key_sa_recordxfer(sav, m);		/* record data transfer */
450105197Ssam
451159965Sthompsa#ifdef DEV_ENC
452105197Ssam	/*
453159965Sthompsa	 * Pass the mbuf to enc0 for bpf and pfil. We will filter the IPIP
454159965Sthompsa	 * packet later after it has been decapsulated.
455159965Sthompsa	 */
456159965Sthompsa	ipsec_bpf(m, sav, AF_INET);
457159965Sthompsa
458159965Sthompsa	if (prot != IPPROTO_IPIP)
459159965Sthompsa		if ((error = ipsec_filter(&m, 1)) != 0)
460159965Sthompsa			return (error);
461159965Sthompsa#endif
462159965Sthompsa
463159965Sthompsa	/*
464105197Ssam	 * Re-dispatch via software interrupt.
465105197Ssam	 */
466134391Sandre	if ((error = netisr_queue(NETISR_IP, m))) {
467105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_qfull, ahstat.ahs_qfull,
468105197Ssam			    ipcompstat.ipcomps_qfull);
469105197Ssam
470120585Ssam		DPRINTF(("%s: queue full; proto %u packet dropped\n",
471120585Ssam			__func__, sproto));
472134391Sandre		return error;
473105197Ssam	}
474105197Ssam	return 0;
475105197Ssambad:
476105197Ssam	m_freem(m);
477105197Ssam	return error;
478105197Ssam}
479120585Ssam
480120585Ssamvoid
481120585Ssamipsec4_common_ctlinput(int cmd, struct sockaddr *sa, void *v, int proto)
482120585Ssam{
483120585Ssam	/* XXX nothing just yet */
484120585Ssam}
485105197Ssam#endif /* INET */
486105197Ssam
487105197Ssam#ifdef INET6
488105197Ssam/* IPv6 AH wrapper. */
489105197Ssamint
490105197Ssamipsec6_common_input(struct mbuf **mp, int *offp, int proto)
491105197Ssam{
492105197Ssam	int l = 0;
493105197Ssam	int protoff;
494105197Ssam	struct ip6_ext ip6e;
495105197Ssam
496105197Ssam	if (*offp < sizeof(struct ip6_hdr)) {
497120585Ssam		DPRINTF(("%s: bad offset %u\n", __func__, *offp));
498105197Ssam		return IPPROTO_DONE;
499105197Ssam	} else if (*offp == sizeof(struct ip6_hdr)) {
500105197Ssam		protoff = offsetof(struct ip6_hdr, ip6_nxt);
501105197Ssam	} else {
502105197Ssam		/* Chase down the header chain... */
503105197Ssam		protoff = sizeof(struct ip6_hdr);
504105197Ssam
505105197Ssam		do {
506105197Ssam			protoff += l;
507105197Ssam			m_copydata(*mp, protoff, sizeof(ip6e),
508105197Ssam			    (caddr_t) &ip6e);
509105197Ssam
510105197Ssam			if (ip6e.ip6e_nxt == IPPROTO_AH)
511105197Ssam				l = (ip6e.ip6e_len + 2) << 2;
512105197Ssam			else
513105197Ssam				l = (ip6e.ip6e_len + 1) << 3;
514120585Ssam			IPSEC_ASSERT(l > 0, ("l went zero or negative"));
515105197Ssam		} while (protoff + l < *offp);
516105197Ssam
517105197Ssam		/* Malformed packet check */
518105197Ssam		if (protoff + l != *offp) {
519120585Ssam			DPRINTF(("%s: bad packet header chain, protoff %u, "
520120585Ssam				"l %u, off %u\n", __func__, protoff, l, *offp));
521105197Ssam			IPSEC_ISTAT(proto, espstat.esps_hdrops,
522105197Ssam				    ahstat.ahs_hdrops,
523105197Ssam				    ipcompstat.ipcomps_hdrops);
524105197Ssam			m_freem(*mp);
525105197Ssam			*mp = NULL;
526105197Ssam			return IPPROTO_DONE;
527105197Ssam		}
528105197Ssam		protoff += offsetof(struct ip6_ext, ip6e_nxt);
529105197Ssam	}
530105197Ssam	(void) ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto);
531105197Ssam	return IPPROTO_DONE;
532105197Ssam}
533105197Ssam
534105197Ssam/*
535105197Ssam * IPsec input callback, called by the transform callback. Takes care of
536105197Ssam * filtering and other sanity checks on the processed packet.
537105197Ssam */
538105197Ssamint
539105197Ssamipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff,
540105197Ssam    struct m_tag *mt)
541105197Ssam{
542105197Ssam	int prot, af, sproto;
543105197Ssam	struct ip6_hdr *ip6;
544105197Ssam	struct m_tag *mtag;
545105197Ssam	struct tdb_ident *tdbi;
546105197Ssam	struct secasindex *saidx;
547105197Ssam	int nxt;
548105197Ssam	u_int8_t nxt8;
549105197Ssam	int error, nest;
550165118Sbz#ifdef notyet
551165118Sbz	char ip6buf[INET6_ADDRSTRLEN];
552165118Sbz#endif
553105197Ssam
554120585Ssam	IPSEC_ASSERT(m != NULL, ("null mbuf"));
555120585Ssam	IPSEC_ASSERT(sav != NULL, ("null SA"));
556120585Ssam	IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
557105197Ssam	saidx = &sav->sah->saidx;
558105197Ssam	af = saidx->dst.sa.sa_family;
559120585Ssam	IPSEC_ASSERT(af == AF_INET6, ("unexpected af %u", af));
560105197Ssam	sproto = saidx->proto;
561120585Ssam	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
562105197Ssam		sproto == IPPROTO_IPCOMP,
563120585Ssam		("unexpected security protocol %u", sproto));
564105197Ssam
565105197Ssam	/* Sanity check */
566105197Ssam	if (m == NULL) {
567120585Ssam		DPRINTF(("%s: null mbuf", __func__));
568105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
569105197Ssam		    ipcompstat.ipcomps_badkcr);
570105197Ssam		error = EINVAL;
571105197Ssam		goto bad;
572105197Ssam	}
573105197Ssam
574105197Ssam	/* Fix IPv6 header */
575105197Ssam	if (m->m_len < sizeof(struct ip6_hdr) &&
576105197Ssam	    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
577105197Ssam
578120585Ssam		DPRINTF(("%s: processing failed for SA %s/%08lx\n",
579120585Ssam		    __func__, ipsec_address(&sav->sah->saidx.dst),
580105197Ssam		    (u_long) ntohl(sav->spi)));
581105197Ssam
582105197Ssam		IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
583105197Ssam		    ipcompstat.ipcomps_hdrops);
584105197Ssam		error = EACCES;
585105197Ssam		goto bad;
586105197Ssam	}
587105197Ssam
588105197Ssam	ip6 = mtod(m, struct ip6_hdr *);
589105197Ssam	ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
590105197Ssam
591105197Ssam	/* Save protocol */
592105197Ssam	m_copydata(m, protoff, 1, (unsigned char *) &prot);
593105197Ssam
594159215Sgnn#ifdef notyet
595105197Ssam#ifdef INET
596105197Ssam	/* IP-in-IP encapsulation */
597105197Ssam	if (prot == IPPROTO_IPIP) {
598105197Ssam		struct ip ipn;
599105197Ssam
600118888Ssam		if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
601118888Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
602118888Ssam			    ahstat.ahs_hdrops,
603118888Ssam			    ipcompstat.ipcomps_hdrops);
604118888Ssam			error = EINVAL;
605118888Ssam			goto bad;
606118888Ssam		}
607105197Ssam		/* ipn will now contain the inner IPv4 header */
608105197Ssam		m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);
609105197Ssam
610105197Ssam		/*
611105197Ssam		 * Check that the inner source address is the same as
612105197Ssam		 * the proxy address, if available.
613105197Ssam		 */
614105197Ssam		if ((saidx->proxy.sa.sa_family == AF_INET &&
615105197Ssam		    saidx->proxy.sin.sin_addr.s_addr != INADDR_ANY &&
616105197Ssam		    ipn.ip_src.s_addr != saidx->proxy.sin.sin_addr.s_addr) ||
617105197Ssam		    (saidx->proxy.sa.sa_family != AF_INET &&
618105197Ssam			saidx->proxy.sa.sa_family != 0)) {
619105197Ssam
620120585Ssam			DPRINTF(("%s: inner source address %s doesn't "
621120585Ssam			    "correspond to expected proxy source %s, "
622120585Ssam			    "SA %s/%08lx\n", __func__,
623105197Ssam			    inet_ntoa4(ipn.ip_src),
624105197Ssam			    ipsec_address(&saidx->proxy),
625105197Ssam			    ipsec_address(&saidx->dst),
626105197Ssam			    (u_long) ntohl(sav->spi)));
627105197Ssam
628105197Ssam			IPSEC_ISTATsproto, (espstat.esps_pdrops,
629105197Ssam			    ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
630105197Ssam			error = EACCES;
631105197Ssam			goto bad;
632105197Ssam		}
633105197Ssam	}
634105197Ssam#endif /* INET */
635105197Ssam
636105197Ssam	/* IPv6-in-IP encapsulation */
637105197Ssam	if (prot == IPPROTO_IPV6) {
638105197Ssam		struct ip6_hdr ip6n;
639105197Ssam
640118888Ssam		if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
641118888Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
642118888Ssam			    ahstat.ahs_hdrops,
643118888Ssam			    ipcompstat.ipcomps_hdrops);
644118888Ssam			error = EINVAL;
645118888Ssam			goto bad;
646118888Ssam		}
647105197Ssam		/* ip6n will now contain the inner IPv6 header. */
648105197Ssam		m_copydata(m, skip, sizeof(struct ip6_hdr),
649105197Ssam		    (caddr_t) &ip6n);
650105197Ssam
651105197Ssam		/*
652105197Ssam		 * Check that the inner source address is the same as
653105197Ssam		 * the proxy address, if available.
654105197Ssam		 */
655105197Ssam		if ((saidx->proxy.sa.sa_family == AF_INET6 &&
656105197Ssam		    !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
657105197Ssam		    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
658105197Ssam			&saidx->proxy.sin6.sin6_addr)) ||
659105197Ssam		    (saidx->proxy.sa.sa_family != AF_INET6 &&
660105197Ssam			saidx->proxy.sa.sa_family != 0)) {
661105197Ssam
662120585Ssam			DPRINTF(("%s: inner source address %s doesn't "
663120585Ssam			    "correspond to expected proxy source %s, "
664120585Ssam			    "SA %s/%08lx\n", __func__,
665165118Sbz			    ip6_sprintf(ip6buf, &ip6n.ip6_src),
666105197Ssam			    ipsec_address(&saidx->proxy),
667105197Ssam			    ipsec_address(&saidx->dst),
668105197Ssam			    (u_long) ntohl(sav->spi)));
669105197Ssam
670105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
671105197Ssam			    ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
672105197Ssam			error = EACCES;
673105197Ssam			goto bad;
674105197Ssam		}
675159215Sgnn	}
676105197Ssam#endif /*XXX*/
677105197Ssam
678105197Ssam	/*
679105197Ssam	 * Record what we've done to the packet (under what SA it was
680105197Ssam	 * processed). If we've been passed an mtag, it means the packet
681105197Ssam	 * was already processed by an ethernet/crypto combo card and
682105197Ssam	 * thus has a tag attached with all the right information, but
683105197Ssam	 * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
684105197Ssam	 * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
685105197Ssam	 */
686105197Ssam	if (mt == NULL && sproto != IPPROTO_IPCOMP) {
687105197Ssam		mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
688105197Ssam		    sizeof(struct tdb_ident), M_NOWAIT);
689105197Ssam		if (mtag == NULL) {
690120585Ssam			DPRINTF(("%s: failed to get tag\n", __func__));
691105197Ssam			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
692105197Ssam			    ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
693105197Ssam			error = ENOMEM;
694105197Ssam			goto bad;
695105197Ssam		}
696105197Ssam
697105197Ssam		tdbi = (struct tdb_ident *)(mtag + 1);
698105197Ssam		bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union));
699105197Ssam		tdbi->proto = sproto;
700105197Ssam		tdbi->spi = sav->spi;
701105197Ssam
702105197Ssam		m_tag_prepend(m, mtag);
703105197Ssam	} else {
704120585Ssam		if (mt != NULL)
705120585Ssam			mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
706105197Ssam		/* XXX do we need to mark m_flags??? */
707105197Ssam	}
708105197Ssam
709105197Ssam	key_sa_recordxfer(sav, m);
710105197Ssam
711105197Ssam	/* Retrieve new protocol */
712105197Ssam	m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8);
713105197Ssam
714105197Ssam	/*
715105197Ssam	 * See the end of ip6_input for this logic.
716105197Ssam	 * IPPROTO_IPV[46] case will be processed just like other ones
717105197Ssam	 */
718105197Ssam	nest = 0;
719105197Ssam	nxt = nxt8;
720105197Ssam	while (nxt != IPPROTO_DONE) {
721105197Ssam		if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
722105197Ssam			ip6stat.ip6s_toomanyhdr++;
723105197Ssam			error = EINVAL;
724105197Ssam			goto bad;
725105197Ssam		}
726105197Ssam
727105197Ssam		/*
728105197Ssam		 * Protection against faulty packet - there should be
729105197Ssam		 * more sanity checks in header chain processing.
730105197Ssam		 */
731105197Ssam		if (m->m_pkthdr.len < skip) {
732105197Ssam			ip6stat.ip6s_tooshort++;
733105197Ssam			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
734105197Ssam			error = EINVAL;
735105197Ssam			goto bad;
736105197Ssam		}
737105197Ssam		/*
738105197Ssam		 * Enforce IPsec policy checking if we are seeing last header.
739105197Ssam		 * note that we do not visit this with protocols with pcb layer
740105197Ssam		 * code - like udp/tcp/raw ip.
741105197Ssam		 */
742105197Ssam		if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
743105197Ssam		    ipsec6_in_reject(m, NULL)) {
744105197Ssam			error = EINVAL;
745105197Ssam			goto bad;
746105197Ssam		}
747105197Ssam		nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt);
748105197Ssam	}
749105197Ssam	return 0;
750105197Ssambad:
751105197Ssam	if (m)
752105197Ssam		m_freem(m);
753105197Ssam	return error;
754105197Ssam}
755120585Ssam
756120585Ssamvoid
757120585Ssamesp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
758120585Ssam{
759120585Ssam	if (sa->sa_family != AF_INET6 ||
760120585Ssam	    sa->sa_len != sizeof(struct sockaddr_in6))
761120585Ssam		return;
762120585Ssam	if ((unsigned)cmd >= PRC_NCMDS)
763120585Ssam		return;
764120585Ssam
765120585Ssam	/* if the parameter is from icmp6, decode it. */
766120585Ssam	if (d !=  NULL) {
767120585Ssam		struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
768120585Ssam		struct mbuf *m = ip6cp->ip6c_m;
769120585Ssam		int off = ip6cp->ip6c_off;
770120585Ssam
771120585Ssam		struct ip6ctlparam ip6cp1;
772120585Ssam
773120585Ssam		/*
774120585Ssam		 * Notify the error to all possible sockets via pfctlinput2.
775120585Ssam		 * Since the upper layer information (such as protocol type,
776120585Ssam		 * source and destination ports) is embedded in the encrypted
777120585Ssam		 * data and might have been cut, we can't directly call
778120585Ssam		 * an upper layer ctlinput function. However, the pcbnotify
779120585Ssam		 * function will consider source and destination addresses
780120585Ssam		 * as well as the flow info value, and may be able to find
781120585Ssam		 * some PCB that should be notified.
782120585Ssam		 * Although pfctlinput2 will call esp6_ctlinput(), there is
783120585Ssam		 * no possibility of an infinite loop of function calls,
784120585Ssam		 * because we don't pass the inner IPv6 header.
785120585Ssam		 */
786120585Ssam		bzero(&ip6cp1, sizeof(ip6cp1));
787120585Ssam		ip6cp1.ip6c_src = ip6cp->ip6c_src;
788120585Ssam		pfctlinput2(cmd, sa, (void *)&ip6cp1);
789120585Ssam
790120585Ssam		/*
791120585Ssam		 * Then go to special cases that need ESP header information.
792120585Ssam		 * XXX: We assume that when ip6 is non NULL,
793120585Ssam		 * M and OFF are valid.
794120585Ssam		 */
795120585Ssam
796120585Ssam		if (cmd == PRC_MSGSIZE) {
797120585Ssam			struct secasvar *sav;
798120585Ssam			u_int32_t spi;
799120585Ssam			int valid;
800120585Ssam
801120585Ssam			/* check header length before using m_copydata */
802120585Ssam			if (m->m_pkthdr.len < off + sizeof (struct esp))
803120585Ssam				return;
804120585Ssam			m_copydata(m, off + offsetof(struct esp, esp_spi),
805120585Ssam				sizeof(u_int32_t), (caddr_t) &spi);
806120585Ssam			/*
807120585Ssam			 * Check to see if we have a valid SA corresponding to
808120585Ssam			 * the address in the ICMP message payload.
809120585Ssam			 */
810120585Ssam			sav = KEY_ALLOCSA((union sockaddr_union *)sa,
811120585Ssam					IPPROTO_ESP, spi);
812120585Ssam			valid = (sav != NULL);
813120585Ssam			if (sav)
814120585Ssam				KEY_FREESAV(&sav);
815120585Ssam
816120585Ssam			/* XXX Further validation? */
817120585Ssam
818120585Ssam			/*
819120585Ssam			 * Depending on whether the SA is "valid" and
820120585Ssam			 * routing table size (mtudisc_{hi,lo}wat), we will:
821120585Ssam			 * - recalcurate the new MTU and create the
822120585Ssam			 *   corresponding routing entry, or
823120585Ssam			 * - ignore the MTU change notification.
824120585Ssam			 */
825120585Ssam			icmp6_mtudisc_update(ip6cp, valid);
826120585Ssam		}
827120585Ssam	} else {
828120585Ssam		/* we normally notify any pcb here */
829120585Ssam	}
830120585Ssam}
831105197Ssam#endif /* INET6 */
832