ipsec_input.c revision 159215
1249259Sdim/*	$FreeBSD: head/sys/netipsec/ipsec_input.c 159215 2006-06-04 03:11:09Z gnn $	*/
2249259Sdim/*	$OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $	*/
3249259Sdim/*-
4249259Sdim * The authors of this code are John Ioannidis (ji@tla.org),
5249259Sdim * Angelos D. Keromytis (kermit@csd.uch.gr) and
6249259Sdim * Niels Provos (provos@physnet.uni-hamburg.de).
7249259Sdim *
8249259Sdim * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
9249259Sdim * in November 1995.
10249259Sdim *
11249259Sdim * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
12249259Sdim * by Angelos D. Keromytis.
13249259Sdim *
14249259Sdim * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
15249259Sdim * and Niels Provos.
16249259Sdim *
17249259Sdim * Additional features in 1999 by Angelos D. Keromytis.
18249259Sdim *
19249259Sdim * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
20249259Sdim * Angelos D. Keromytis and Niels Provos.
21249259Sdim * Copyright (c) 2001, Angelos D. Keromytis.
22249259Sdim *
23249259Sdim * Permission to use, copy, and modify this software with or without fee
24249259Sdim * is hereby granted, provided that this entire notice is included in
25249259Sdim * all copies of any software which is or includes a copy or
26249259Sdim * modification of this software.
27249259Sdim * You may use this code under the GNU public license if you so wish. Please
28249259Sdim * contribute changes back to the authors under this freer than GPL license
29249259Sdim * so that we may further the use of strong encryption without limitations to
30249259Sdim * all.
31249259Sdim *
32249259Sdim * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
33249259Sdim * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
34266759Sdim * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
35266759Sdim * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
36249259Sdim * PURPOSE.
37249259Sdim */
38249259Sdim
39263509Sdim/*
40249259Sdim * IPsec input processing.
41263509Sdim */
42263509Sdim
43249259Sdim#include "opt_inet.h"
44249259Sdim#include "opt_inet6.h"
45249259Sdim#include "opt_ipsec.h"
46249259Sdim
47249259Sdim#include <sys/param.h>
48249259Sdim#include <sys/systm.h>
49249259Sdim#include <sys/malloc.h>
50263509Sdim#include <sys/mbuf.h>
51263509Sdim#include <sys/domain.h>
52263509Sdim#include <sys/protosw.h>
53263509Sdim#include <sys/socket.h>
54263509Sdim#include <sys/errno.h>
55263509Sdim#include <sys/syslog.h>
56263509Sdim
57263509Sdim#include <net/if.h>
58263509Sdim#include <net/route.h>
59263509Sdim#include <net/netisr.h>
60263509Sdim
61263509Sdim#include <netinet/in.h>
62263509Sdim#include <netinet/in_systm.h>
63263509Sdim#include <netinet/ip.h>
64263509Sdim#include <netinet/ip_var.h>
65263509Sdim#include <netinet/in_var.h>
66263509Sdim
67263509Sdim#include <netinet/ip6.h>
68263509Sdim#ifdef INET6
69263509Sdim#include <netinet6/ip6_var.h>
70263509Sdim#endif
71263509Sdim#include <netinet/in_pcb.h>
72263509Sdim#ifdef INET6
73263509Sdim#include <netinet/icmp6.h>
74263509Sdim#endif
75263509Sdim
76263509Sdim#include <netipsec/ipsec.h>
77263509Sdim#ifdef INET6
78249259Sdim#include <netipsec/ipsec6.h>
79249259Sdim#endif
80249259Sdim#include <netipsec/ah_var.h>
81249259Sdim#include <netipsec/esp.h>
82249259Sdim#include <netipsec/esp_var.h>
83249259Sdim#include <netipsec/ipcomp_var.h>
84249259Sdim
85263509Sdim#include <netipsec/key.h>
86263509Sdim#include <netipsec/keydb.h>
87249259Sdim
88263509Sdim#include <netipsec/xform.h>
89263509Sdim#include <netinet6/ip6protosw.h>
90263509Sdim
91263509Sdim#include <machine/in_cksum.h>
92249259Sdim#include <machine/stdarg.h>
93249259Sdim
94249259Sdim#define IPSEC_ISTAT(p,x,y,z) ((p) == IPPROTO_ESP ? (x)++ : \
95249259Sdim			    (p) == IPPROTO_AH ? (y)++ : (z)++)
96249259Sdim
97249259Sdimstatic void ipsec4_common_ctlinput(int, struct sockaddr *, void *, int);
98249259Sdim
99249259Sdim/*
100249259Sdim * ipsec_common_input gets called when an IPsec-protected packet
101249259Sdim * is received by IPv4 or IPv6.  It's job is to find the right SA
102249259Sdim # and call the appropriate transform.  The transform callback
103249259Sdim * takes care of further processing (like ingress filtering).
104249259Sdim */
105249259Sdimstatic int
106249259Sdimipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
107249259Sdim{
108249259Sdim	union sockaddr_union dst_address;
109249259Sdim	struct secasvar *sav;
110249259Sdim	u_int32_t spi;
111249259Sdim	int error;
112249259Sdim
113249259Sdim	IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input,
114249259Sdim		ipcompstat.ipcomps_input);
115249259Sdim
116249259Sdim	IPSEC_ASSERT(m != NULL, ("null packet"));
117249259Sdim
118249259Sdim	if ((sproto == IPPROTO_ESP && !esp_enable) ||
119249259Sdim	    (sproto == IPPROTO_AH && !ah_enable) ||
120249259Sdim	    (sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
121249259Sdim		m_freem(m);
122249259Sdim		IPSEC_ISTAT(sproto, espstat.esps_pdrops, ahstat.ahs_pdrops,
123249259Sdim		    ipcompstat.ipcomps_pdrops);
124249259Sdim		return EOPNOTSUPP;
125249259Sdim	}
126249259Sdim
127249259Sdim	if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) {
128249259Sdim		m_freem(m);
129249259Sdim		IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
130249259Sdim		    ipcompstat.ipcomps_hdrops);
131249259Sdim		DPRINTF(("%s: packet too small\n", __func__));
132249259Sdim		return EINVAL;
133249259Sdim	}
134249259Sdim
135249259Sdim	/* Retrieve the SPI from the relevant IPsec header */
136249259Sdim	if (sproto == IPPROTO_ESP)
137249259Sdim		m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
138249259Sdim	else if (sproto == IPPROTO_AH)
139249259Sdim		m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
140249259Sdim		    (caddr_t) &spi);
141249259Sdim	else if (sproto == IPPROTO_IPCOMP) {
142249259Sdim		u_int16_t cpi;
143249259Sdim		m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
144249259Sdim		    (caddr_t) &cpi);
145249259Sdim		spi = ntohl(htons(cpi));
146249259Sdim	}
147249259Sdim
148249259Sdim	/*
149249259Sdim	 * Find the SA and (indirectly) call the appropriate
150249259Sdim	 * kernel crypto routine. The resulting mbuf chain is a valid
151249259Sdim	 * IP packet ready to go through input processing.
152249259Sdim	 */
153249259Sdim	bzero(&dst_address, sizeof (dst_address));
154249259Sdim	dst_address.sa.sa_family = af;
155249259Sdim	switch (af) {
156249259Sdim#ifdef INET
157249259Sdim	case AF_INET:
158249259Sdim		dst_address.sin.sin_len = sizeof(struct sockaddr_in);
159249259Sdim		m_copydata(m, offsetof(struct ip, ip_dst),
160249259Sdim		    sizeof(struct in_addr),
161249259Sdim		    (caddr_t) &dst_address.sin.sin_addr);
162249259Sdim		break;
163249259Sdim#endif /* INET */
164249259Sdim#ifdef INET6
165249259Sdim	case AF_INET6:
166249259Sdim		dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
167249259Sdim		m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
168249259Sdim		    sizeof(struct in6_addr),
169249259Sdim		    (caddr_t) &dst_address.sin6.sin6_addr);
170249259Sdim		break;
171249259Sdim#endif /* INET6 */
172249259Sdim	default:
173249259Sdim		DPRINTF(("%s: unsupported protocol family %u\n", __func__, af));
174249259Sdim		m_freem(m);
175249259Sdim		IPSEC_ISTAT(sproto, espstat.esps_nopf, ahstat.ahs_nopf,
176249259Sdim		    ipcompstat.ipcomps_nopf);
177249259Sdim		return EPFNOSUPPORT;
178249259Sdim	}
179249259Sdim
180249259Sdim	/* NB: only pass dst since key_allocsa follows RFC2401 */
181249259Sdim	sav = KEY_ALLOCSA(&dst_address, sproto, spi);
182249259Sdim	if (sav == NULL) {
183249259Sdim		DPRINTF(("%s: no key association found for SA %s/%08lx/%u\n",
184249259Sdim			  __func__, ipsec_address(&dst_address),
185249259Sdim			  (u_long) ntohl(spi), sproto));
186249259Sdim		IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb,
187249259Sdim		    ipcompstat.ipcomps_notdb);
188249259Sdim		m_freem(m);
189249259Sdim		return ENOENT;
190249259Sdim	}
191249259Sdim
192249259Sdim	if (sav->tdb_xform == NULL) {
193249259Sdim		DPRINTF(("%s: attempted to use uninitialized SA %s/%08lx/%u\n",
194249259Sdim			 __func__, ipsec_address(&dst_address),
195249259Sdim			 (u_long) ntohl(spi), sproto));
196249259Sdim		IPSEC_ISTAT(sproto, espstat.esps_noxform, ahstat.ahs_noxform,
197249259Sdim		    ipcompstat.ipcomps_noxform);
198249259Sdim		KEY_FREESAV(&sav);
199249259Sdim		m_freem(m);
200249259Sdim		return ENXIO;
201249259Sdim	}
202249259Sdim
203249259Sdim	/*
204249259Sdim	 * Call appropriate transform and return -- callback takes care of
205249259Sdim	 * everything else.
206249259Sdim	 */
207249259Sdim	error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff);
208249259Sdim	KEY_FREESAV(&sav);
209249259Sdim	return error;
210249259Sdim}
211249259Sdim
212249259Sdim#ifdef INET
213249259Sdim/*
214249259Sdim * Common input handler for IPv4 AH, ESP, and IPCOMP.
215249259Sdim */
216249259Sdimint
217249259Sdimipsec4_common_input(struct mbuf *m, ...)
218249259Sdim{
219249259Sdim	va_list ap;
220249259Sdim	int off, nxt;
221249259Sdim
222249259Sdim	va_start(ap, m);
223249259Sdim	off = va_arg(ap, int);
224249259Sdim	nxt = va_arg(ap, int);
225249259Sdim	va_end(ap);
226249259Sdim
227249259Sdim	return ipsec_common_input(m, off, offsetof(struct ip, ip_p),
228249259Sdim				  AF_INET, nxt);
229249259Sdim}
230249259Sdim
231249259Sdimvoid
232249259Sdimah4_input(struct mbuf *m, int off)
233249259Sdim{
234249259Sdim	ipsec4_common_input(m, off, IPPROTO_AH);
235249259Sdim}
236249259Sdimvoid
237249259Sdimah4_ctlinput(int cmd, struct sockaddr *sa, void *v)
238249259Sdim{
239249259Sdim	if (sa->sa_family == AF_INET &&
240249259Sdim	    sa->sa_len == sizeof(struct sockaddr_in))
241249259Sdim		ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_AH);
242249259Sdim}
243249259Sdim
244249259Sdimvoid
245249259Sdimesp4_input(struct mbuf *m, int off)
246249259Sdim{
247249259Sdim	ipsec4_common_input(m, off, IPPROTO_ESP);
248249259Sdim}
249249259Sdimvoid
250249259Sdimesp4_ctlinput(int cmd, struct sockaddr *sa, void *v)
251249259Sdim{
252249259Sdim	if (sa->sa_family == AF_INET &&
253249259Sdim	    sa->sa_len == sizeof(struct sockaddr_in))
254249259Sdim		ipsec4_common_ctlinput(cmd, sa, v, IPPROTO_ESP);
255249259Sdim}
256249259Sdim
257249259Sdimvoid
258249259Sdimipcomp4_input(struct mbuf *m, int off)
259249259Sdim{
260249259Sdim	ipsec4_common_input(m, off, IPPROTO_IPCOMP);
261249259Sdim}
262249259Sdim
263249259Sdim/*
264249259Sdim * IPsec input callback for INET protocols.
265249259Sdim * This routine is called as the transform callback.
266249259Sdim * Takes care of filtering and other sanity checks on
267249259Sdim * the processed packet.
268249259Sdim */
269249259Sdimint
270249259Sdimipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
271249259Sdim			int skip, int protoff, struct m_tag *mt)
272249259Sdim{
273249259Sdim	int prot, af, sproto;
274249259Sdim	struct ip *ip;
275249259Sdim	struct m_tag *mtag;
276249259Sdim	struct tdb_ident *tdbi;
277249259Sdim	struct secasindex *saidx;
278249259Sdim	int error;
279249259Sdim
280249259Sdim	IPSEC_SPLASSERT_SOFTNET(__func__);
281249259Sdim
282263509Sdim	IPSEC_ASSERT(m != NULL, ("null mbuf"));
283263509Sdim	IPSEC_ASSERT(sav != NULL, ("null SA"));
284263509Sdim	IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
285263509Sdim	saidx = &sav->sah->saidx;
286263509Sdim	af = saidx->dst.sa.sa_family;
287263509Sdim	IPSEC_ASSERT(af == AF_INET, ("unexpected af %u", af));
288263509Sdim	sproto = saidx->proto;
289263509Sdim	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
290263509Sdim		sproto == IPPROTO_IPCOMP,
291263509Sdim		("unexpected security protocol %u", sproto));
292263509Sdim
293263509Sdim	/* Sanity check */
294263509Sdim	if (m == NULL) {
295263509Sdim		DPRINTF(("%s: null mbuf", __func__));
296263509Sdim		IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
297263509Sdim		    ipcompstat.ipcomps_badkcr);
298263509Sdim		KEY_FREESAV(&sav);
299263509Sdim		return EINVAL;
300263509Sdim	}
301263509Sdim
302263509Sdim	if (skip != 0) {
303263509Sdim		/* Fix IPv4 header */
304263509Sdim		if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
305263509Sdim			DPRINTF(("%s: processing failed for SA %s/%08lx\n",
306263509Sdim			    __func__, ipsec_address(&sav->sah->saidx.dst),
307263509Sdim			    (u_long) ntohl(sav->spi)));
308263509Sdim			IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
309263509Sdim			    ipcompstat.ipcomps_hdrops);
310263509Sdim			error = ENOBUFS;
311263509Sdim			goto bad;
312263509Sdim		}
313263509Sdim
314263509Sdim		ip = mtod(m, struct ip *);
315263509Sdim		ip->ip_len = htons(m->m_pkthdr.len);
316263509Sdim		ip->ip_off = htons(ip->ip_off);
317263509Sdim		ip->ip_sum = 0;
318263509Sdim		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
319263509Sdim	} else {
320263509Sdim		ip = mtod(m, struct ip *);
321263509Sdim	}
322263509Sdim	prot = ip->ip_p;
323263509Sdim
324263509Sdim#ifdef notyet
325263509Sdim	/* IP-in-IP encapsulation */
326263509Sdim	if (prot == IPPROTO_IPIP) {
327263509Sdim		struct ip ipn;
328263509Sdim
329263509Sdim		if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
330263509Sdim			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
331263509Sdim			    ahstat.ahs_hdrops,
332263509Sdim			    ipcompstat.ipcomps_hdrops);
333263509Sdim			error = EINVAL;
334263509Sdim			goto bad;
335263509Sdim		}
336263509Sdim		/* ipn will now contain the inner IPv4 header */
337263509Sdim		m_copydata(m, ip->ip_hl << 2, sizeof(struct ip),
338263509Sdim		    (caddr_t) &ipn);
339263509Sdim
340263509Sdim		/* XXX PROXY address isn't recorded in SAH */
341263509Sdim		/*
342263509Sdim		 * Check that the inner source address is the same as
343263509Sdim		 * the proxy address, if available.
344263509Sdim		 */
345263509Sdim		if ((saidx->proxy.sa.sa_family == AF_INET &&
346263509Sdim		    saidx->proxy.sin.sin_addr.s_addr !=
347263509Sdim		    INADDR_ANY &&
348263509Sdim		    ipn.ip_src.s_addr !=
349263509Sdim		    saidx->proxy.sin.sin_addr.s_addr) ||
350263509Sdim		    (saidx->proxy.sa.sa_family != AF_INET &&
351263509Sdim			saidx->proxy.sa.sa_family != 0)) {
352263509Sdim
353263509Sdim			DPRINTF(("%s: inner source address %s doesn't "
354263509Sdim			    "correspond to expected proxy source %s, "
355263509Sdim			    "SA %s/%08lx\n", __func__,
356263509Sdim			    inet_ntoa4(ipn.ip_src),
357263509Sdim			    ipsp_address(saidx->proxy),
358263509Sdim			    ipsp_address(saidx->dst),
359263509Sdim			    (u_long) ntohl(sav->spi)));
360263509Sdim
361263509Sdim			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
362263509Sdim			    ahstat.ahs_pdrops,
363263509Sdim			    ipcompstat.ipcomps_pdrops);
364263509Sdim			error = EACCES;
365263509Sdim			goto bad;
366263509Sdim		}
367263509Sdim	}
368249259Sdim#if INET6
369249259Sdim	/* IPv6-in-IP encapsulation. */
370263509Sdim	if (prot == IPPROTO_IPV6) {
371249259Sdim		struct ip6_hdr ip6n;
372249259Sdim
373249259Sdim		if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
374249259Sdim			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
375249259Sdim			    ahstat.ahs_hdrops,
376249259Sdim			    ipcompstat.ipcomps_hdrops);
377249259Sdim			error = EINVAL;
378252723Sdim			goto bad;
379252723Sdim		}
380252723Sdim		/* ip6n will now contain the inner IPv6 header. */
381263509Sdim		m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr),
382263509Sdim		    (caddr_t) &ip6n);
383263509Sdim
384263509Sdim		/*
385263509Sdim		 * Check that the inner source address is the same as
386263509Sdim		 * the proxy address, if available.
387263509Sdim		 */
388263509Sdim		if ((saidx->proxy.sa.sa_family == AF_INET6 &&
389252723Sdim		    !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
390263509Sdim		    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
391252723Sdim			&saidx->proxy.sin6.sin6_addr)) ||
392252723Sdim		    (saidx->proxy.sa.sa_family != AF_INET6 &&
393252723Sdim			saidx->proxy.sa.sa_family != 0)) {
394252723Sdim
395252723Sdim			DPRINTF(("%s: inner source address %s doesn't "
396252723Sdim			    "correspond to expected proxy source %s, "
397252723Sdim			    "SA %s/%08lx\n", __func__,
398252723Sdim			    ip6_sprintf(&ip6n.ip6_src),
399252723Sdim			    ipsec_address(&saidx->proxy),
400252723Sdim			    ipsec_address(&saidx->dst),
401252723Sdim			    (u_long) ntohl(sav->spi)));
402252723Sdim
403252723Sdim			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
404252723Sdim			    ahstat.ahs_pdrops,
405252723Sdim			    ipcompstat.ipcomps_pdrops);
406249259Sdim			error = EACCES;
407249259Sdim			goto bad;
408263509Sdim		}
409263509Sdim	}
410263509Sdim#endif /* INET6 */
411263509Sdim#endif /*XXX*/
412263509Sdim
413263509Sdim	/*
414263509Sdim	 * Record what we've done to the packet (under what SA it was
415263509Sdim	 * processed). If we've been passed an mtag, it means the packet
416263509Sdim	 * was already processed by an ethernet/crypto combo card and
417263509Sdim	 * thus has a tag attached with all the right information, but
418263509Sdim	 * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
419263509Sdim	 * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
420263509Sdim	 */
421263509Sdim	if (mt == NULL && sproto != IPPROTO_IPCOMP) {
422263509Sdim		mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
423263509Sdim		    sizeof(struct tdb_ident), M_NOWAIT);
424263509Sdim		if (mtag == NULL) {
425263509Sdim			DPRINTF(("%s: failed to get tag\n", __func__));
426263509Sdim			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
427263509Sdim			    ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
428263509Sdim			error = ENOMEM;
429263509Sdim			goto bad;
430263509Sdim		}
431249259Sdim
432249259Sdim		tdbi = (struct tdb_ident *)(mtag + 1);
433249259Sdim		bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len);
434249259Sdim		tdbi->proto = sproto;
435249259Sdim		tdbi->spi = sav->spi;
436249259Sdim
437249259Sdim		m_tag_prepend(m, mtag);
438249259Sdim	} else {
439249259Sdim		mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
440249259Sdim		/* XXX do we need to mark m_flags??? */
441249259Sdim	}
442249259Sdim
443249259Sdim	key_sa_recordxfer(sav, m);		/* record data transfer */
444249259Sdim
445249259Sdim	/*
446252723Sdim	 * Re-dispatch via software interrupt.
447249259Sdim	 */
448249259Sdim	if ((error = netisr_queue(NETISR_IP, m))) {
449249259Sdim		IPSEC_ISTAT(sproto, espstat.esps_qfull, ahstat.ahs_qfull,
450249259Sdim			    ipcompstat.ipcomps_qfull);
451249259Sdim
452252723Sdim		DPRINTF(("%s: queue full; proto %u packet dropped\n",
453249259Sdim			__func__, sproto));
454249259Sdim		return error;
455249259Sdim	}
456249259Sdim	return 0;
457249259Sdimbad:
458249259Sdim	m_freem(m);
459249259Sdim	return error;
460249259Sdim}
461249259Sdim
462249259Sdimvoid
463249259Sdimipsec4_common_ctlinput(int cmd, struct sockaddr *sa, void *v, int proto)
464249259Sdim{
465249259Sdim	/* XXX nothing just yet */
466249259Sdim}
467249259Sdim#endif /* INET */
468249259Sdim
469249259Sdim#ifdef INET6
470249259Sdim/* IPv6 AH wrapper. */
471249259Sdimint
472249259Sdimipsec6_common_input(struct mbuf **mp, int *offp, int proto)
473249259Sdim{
474249259Sdim	int l = 0;
475249259Sdim	int protoff;
476249259Sdim	struct ip6_ext ip6e;
477249259Sdim
478249259Sdim	if (*offp < sizeof(struct ip6_hdr)) {
479249259Sdim		DPRINTF(("%s: bad offset %u\n", __func__, *offp));
480249259Sdim		return IPPROTO_DONE;
481249259Sdim	} else if (*offp == sizeof(struct ip6_hdr)) {
482249259Sdim		protoff = offsetof(struct ip6_hdr, ip6_nxt);
483249259Sdim	} else {
484249259Sdim		/* Chase down the header chain... */
485249259Sdim		protoff = sizeof(struct ip6_hdr);
486249259Sdim
487249259Sdim		do {
488249259Sdim			protoff += l;
489249259Sdim			m_copydata(*mp, protoff, sizeof(ip6e),
490249259Sdim			    (caddr_t) &ip6e);
491249259Sdim
492249259Sdim			if (ip6e.ip6e_nxt == IPPROTO_AH)
493249259Sdim				l = (ip6e.ip6e_len + 2) << 2;
494249259Sdim			else
495249259Sdim				l = (ip6e.ip6e_len + 1) << 3;
496249259Sdim			IPSEC_ASSERT(l > 0, ("l went zero or negative"));
497249259Sdim		} while (protoff + l < *offp);
498249259Sdim
499249259Sdim		/* Malformed packet check */
500249259Sdim		if (protoff + l != *offp) {
501249259Sdim			DPRINTF(("%s: bad packet header chain, protoff %u, "
502249259Sdim				"l %u, off %u\n", __func__, protoff, l, *offp));
503249259Sdim			IPSEC_ISTAT(proto, espstat.esps_hdrops,
504249259Sdim				    ahstat.ahs_hdrops,
505249259Sdim				    ipcompstat.ipcomps_hdrops);
506249259Sdim			m_freem(*mp);
507249259Sdim			*mp = NULL;
508249259Sdim			return IPPROTO_DONE;
509249259Sdim		}
510249259Sdim		protoff += offsetof(struct ip6_ext, ip6e_nxt);
511249259Sdim	}
512249259Sdim	(void) ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto);
513249259Sdim	return IPPROTO_DONE;
514249259Sdim}
515249259Sdim
516249259Sdim/*
517249259Sdim * IPsec input callback, called by the transform callback. Takes care of
518249259Sdim * filtering and other sanity checks on the processed packet.
519249259Sdim */
520249259Sdimint
521249259Sdimipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff,
522249259Sdim    struct m_tag *mt)
523249259Sdim{
524249259Sdim	int prot, af, sproto;
525249259Sdim	struct ip6_hdr *ip6;
526249259Sdim	struct m_tag *mtag;
527249259Sdim	struct tdb_ident *tdbi;
528249259Sdim	struct secasindex *saidx;
529249259Sdim	int nxt;
530249259Sdim	u_int8_t nxt8;
531252723Sdim	int error, nest;
532252723Sdim
533249259Sdim	IPSEC_ASSERT(m != NULL, ("null mbuf"));
534249259Sdim	IPSEC_ASSERT(sav != NULL, ("null SA"));
535249259Sdim	IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
536249259Sdim	saidx = &sav->sah->saidx;
537249259Sdim	af = saidx->dst.sa.sa_family;
538249259Sdim	IPSEC_ASSERT(af == AF_INET6, ("unexpected af %u", af));
539249259Sdim	sproto = saidx->proto;
540249259Sdim	IPSEC_ASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
541249259Sdim		sproto == IPPROTO_IPCOMP,
542249259Sdim		("unexpected security protocol %u", sproto));
543249259Sdim
544249259Sdim	/* Sanity check */
545249259Sdim	if (m == NULL) {
546249259Sdim		DPRINTF(("%s: null mbuf", __func__));
547252723Sdim		IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
548249259Sdim		    ipcompstat.ipcomps_badkcr);
549249259Sdim		error = EINVAL;
550249259Sdim		goto bad;
551249259Sdim	}
552249259Sdim
553249259Sdim	/* Fix IPv6 header */
554249259Sdim	if (m->m_len < sizeof(struct ip6_hdr) &&
555249259Sdim	    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
556249259Sdim
557249259Sdim		DPRINTF(("%s: processing failed for SA %s/%08lx\n",
558249259Sdim		    __func__, ipsec_address(&sav->sah->saidx.dst),
559249259Sdim		    (u_long) ntohl(sav->spi)));
560249259Sdim
561249259Sdim		IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
562249259Sdim		    ipcompstat.ipcomps_hdrops);
563249259Sdim		error = EACCES;
564249259Sdim		goto bad;
565249259Sdim	}
566249259Sdim
567249259Sdim	ip6 = mtod(m, struct ip6_hdr *);
568249259Sdim	ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
569249259Sdim
570249259Sdim	/* Save protocol */
571249259Sdim	m_copydata(m, protoff, 1, (unsigned char *) &prot);
572249259Sdim
573249259Sdim#ifdef notyet
574249259Sdim#ifdef INET
575249259Sdim	/* IP-in-IP encapsulation */
576249259Sdim	if (prot == IPPROTO_IPIP) {
577249259Sdim		struct ip ipn;
578249259Sdim
579249259Sdim		if (m->m_pkthdr.len - skip < sizeof(struct ip)) {
580249259Sdim			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
581249259Sdim			    ahstat.ahs_hdrops,
582249259Sdim			    ipcompstat.ipcomps_hdrops);
583249259Sdim			error = EINVAL;
584249259Sdim			goto bad;
585249259Sdim		}
586249259Sdim		/* ipn will now contain the inner IPv4 header */
587249259Sdim		m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);
588249259Sdim
589249259Sdim		/*
590249259Sdim		 * Check that the inner source address is the same as
591249259Sdim		 * the proxy address, if available.
592249259Sdim		 */
593249259Sdim		if ((saidx->proxy.sa.sa_family == AF_INET &&
594249259Sdim		    saidx->proxy.sin.sin_addr.s_addr != INADDR_ANY &&
595249259Sdim		    ipn.ip_src.s_addr != saidx->proxy.sin.sin_addr.s_addr) ||
596249259Sdim		    (saidx->proxy.sa.sa_family != AF_INET &&
597249259Sdim			saidx->proxy.sa.sa_family != 0)) {
598249259Sdim
599249259Sdim			DPRINTF(("%s: inner source address %s doesn't "
600249259Sdim			    "correspond to expected proxy source %s, "
601249259Sdim			    "SA %s/%08lx\n", __func__,
602249259Sdim			    inet_ntoa4(ipn.ip_src),
603249259Sdim			    ipsec_address(&saidx->proxy),
604249259Sdim			    ipsec_address(&saidx->dst),
605249259Sdim			    (u_long) ntohl(sav->spi)));
606249259Sdim
607249259Sdim			IPSEC_ISTATsproto, (espstat.esps_pdrops,
608249259Sdim			    ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
609249259Sdim			error = EACCES;
610249259Sdim			goto bad;
611249259Sdim		}
612249259Sdim	}
613249259Sdim#endif /* INET */
614249259Sdim
615252723Sdim	/* IPv6-in-IP encapsulation */
616249259Sdim	if (prot == IPPROTO_IPV6) {
617249259Sdim		struct ip6_hdr ip6n;
618249259Sdim
619249259Sdim		if (m->m_pkthdr.len - skip < sizeof(struct ip6_hdr)) {
620249259Sdim			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
621249259Sdim			    ahstat.ahs_hdrops,
622249259Sdim			    ipcompstat.ipcomps_hdrops);
623249259Sdim			error = EINVAL;
624252723Sdim			goto bad;
625249259Sdim		}
626249259Sdim		/* ip6n will now contain the inner IPv6 header. */
627249259Sdim		m_copydata(m, skip, sizeof(struct ip6_hdr),
628249259Sdim		    (caddr_t) &ip6n);
629249259Sdim
630249259Sdim		/*
631249259Sdim		 * Check that the inner source address is the same as
632249259Sdim		 * the proxy address, if available.
633249259Sdim		 */
634249259Sdim		if ((saidx->proxy.sa.sa_family == AF_INET6 &&
635249259Sdim		    !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
636249259Sdim		    !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
637249259Sdim			&saidx->proxy.sin6.sin6_addr)) ||
638249259Sdim		    (saidx->proxy.sa.sa_family != AF_INET6 &&
639249259Sdim			saidx->proxy.sa.sa_family != 0)) {
640249259Sdim
641249259Sdim			DPRINTF(("%s: inner source address %s doesn't "
642249259Sdim			    "correspond to expected proxy source %s, "
643249259Sdim			    "SA %s/%08lx\n", __func__,
644249259Sdim			    ip6_sprintf(&ip6n.ip6_src),
645249259Sdim			    ipsec_address(&saidx->proxy),
646249259Sdim			    ipsec_address(&saidx->dst),
647249259Sdim			    (u_long) ntohl(sav->spi)));
648249259Sdim
649249259Sdim			IPSEC_ISTAT(sproto, espstat.esps_pdrops,
650249259Sdim			    ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
651249259Sdim			error = EACCES;
652249259Sdim			goto bad;
653249259Sdim		}
654249259Sdim	}
655249259Sdim#endif /*XXX*/
656249259Sdim
657249259Sdim	/*
658249259Sdim	 * Record what we've done to the packet (under what SA it was
659249259Sdim	 * processed). If we've been passed an mtag, it means the packet
660249259Sdim	 * was already processed by an ethernet/crypto combo card and
661249259Sdim	 * thus has a tag attached with all the right information, but
662249259Sdim	 * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
663249259Sdim	 * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
664249259Sdim	 */
665249259Sdim	if (mt == NULL && sproto != IPPROTO_IPCOMP) {
666249259Sdim		mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
667249259Sdim		    sizeof(struct tdb_ident), M_NOWAIT);
668249259Sdim		if (mtag == NULL) {
669249259Sdim			DPRINTF(("%s: failed to get tag\n", __func__));
670249259Sdim			IPSEC_ISTAT(sproto, espstat.esps_hdrops,
671249259Sdim			    ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
672249259Sdim			error = ENOMEM;
673249259Sdim			goto bad;
674249259Sdim		}
675249259Sdim
676249259Sdim		tdbi = (struct tdb_ident *)(mtag + 1);
677249259Sdim		bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union));
678249259Sdim		tdbi->proto = sproto;
679249259Sdim		tdbi->spi = sav->spi;
680249259Sdim
681249259Sdim		m_tag_prepend(m, mtag);
682249259Sdim	} else {
683249259Sdim		if (mt != NULL)
684249259Sdim			mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
685249259Sdim		/* XXX do we need to mark m_flags??? */
686249259Sdim	}
687249259Sdim
688249259Sdim	key_sa_recordxfer(sav, m);
689249259Sdim
690249259Sdim	/* Retrieve new protocol */
691249259Sdim	m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8);
692249259Sdim
693249259Sdim	/*
694249259Sdim	 * See the end of ip6_input for this logic.
695249259Sdim	 * IPPROTO_IPV[46] case will be processed just like other ones
696249259Sdim	 */
697249259Sdim	nest = 0;
698249259Sdim	nxt = nxt8;
699249259Sdim	while (nxt != IPPROTO_DONE) {
700249259Sdim		if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
701249259Sdim			ip6stat.ip6s_toomanyhdr++;
702249259Sdim			error = EINVAL;
703249259Sdim			goto bad;
704249259Sdim		}
705249259Sdim
706249259Sdim		/*
707249259Sdim		 * Protection against faulty packet - there should be
708249259Sdim		 * more sanity checks in header chain processing.
709249259Sdim		 */
710249259Sdim		if (m->m_pkthdr.len < skip) {
711249259Sdim			ip6stat.ip6s_tooshort++;
712249259Sdim			in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
713249259Sdim			error = EINVAL;
714249259Sdim			goto bad;
715249259Sdim		}
716249259Sdim		/*
717249259Sdim		 * Enforce IPsec policy checking if we are seeing last header.
718249259Sdim		 * note that we do not visit this with protocols with pcb layer
719249259Sdim		 * code - like udp/tcp/raw ip.
720249259Sdim		 */
721249259Sdim		if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
722249259Sdim		    ipsec6_in_reject(m, NULL)) {
723249259Sdim			error = EINVAL;
724249259Sdim			goto bad;
725249259Sdim		}
726249259Sdim		nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt);
727249259Sdim	}
728249259Sdim	return 0;
729249259Sdimbad:
730249259Sdim	if (m)
731249259Sdim		m_freem(m);
732249259Sdim	return error;
733249259Sdim}
734249259Sdim
735249259Sdimvoid
736249259Sdimesp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
737249259Sdim{
738249259Sdim	if (sa->sa_family != AF_INET6 ||
739249259Sdim	    sa->sa_len != sizeof(struct sockaddr_in6))
740249259Sdim		return;
741249259Sdim	if ((unsigned)cmd >= PRC_NCMDS)
742249259Sdim		return;
743249259Sdim
744249259Sdim	/* if the parameter is from icmp6, decode it. */
745249259Sdim	if (d !=  NULL) {
746249259Sdim		struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
747249259Sdim		struct mbuf *m = ip6cp->ip6c_m;
748249259Sdim		int off = ip6cp->ip6c_off;
749249259Sdim
750249259Sdim		struct ip6ctlparam ip6cp1;
751249259Sdim
752249259Sdim		/*
753249259Sdim		 * Notify the error to all possible sockets via pfctlinput2.
754249259Sdim		 * Since the upper layer information (such as protocol type,
755249259Sdim		 * source and destination ports) is embedded in the encrypted
756263509Sdim		 * data and might have been cut, we can't directly call
757263509Sdim		 * an upper layer ctlinput function. However, the pcbnotify
758263509Sdim		 * function will consider source and destination addresses
759263509Sdim		 * as well as the flow info value, and may be able to find
760263509Sdim		 * some PCB that should be notified.
761263509Sdim		 * Although pfctlinput2 will call esp6_ctlinput(), there is
762249259Sdim		 * no possibility of an infinite loop of function calls,
763249259Sdim		 * because we don't pass the inner IPv6 header.
764249259Sdim		 */
765249259Sdim		bzero(&ip6cp1, sizeof(ip6cp1));
766249259Sdim		ip6cp1.ip6c_src = ip6cp->ip6c_src;
767249259Sdim		pfctlinput2(cmd, sa, (void *)&ip6cp1);
768249259Sdim
769249259Sdim		/*
770249259Sdim		 * Then go to special cases that need ESP header information.
771249259Sdim		 * XXX: We assume that when ip6 is non NULL,
772249259Sdim		 * M and OFF are valid.
773249259Sdim		 */
774249259Sdim
775249259Sdim		if (cmd == PRC_MSGSIZE) {
776249259Sdim			struct secasvar *sav;
777249259Sdim			u_int32_t spi;
778249259Sdim			int valid;
779249259Sdim
780249259Sdim			/* check header length before using m_copydata */
781249259Sdim			if (m->m_pkthdr.len < off + sizeof (struct esp))
782249259Sdim				return;
783249259Sdim			m_copydata(m, off + offsetof(struct esp, esp_spi),
784249259Sdim				sizeof(u_int32_t), (caddr_t) &spi);
785249259Sdim			/*
786249259Sdim			 * Check to see if we have a valid SA corresponding to
787249259Sdim			 * the address in the ICMP message payload.
788249259Sdim			 */
789249259Sdim			sav = KEY_ALLOCSA((union sockaddr_union *)sa,
790249259Sdim					IPPROTO_ESP, spi);
791249259Sdim			valid = (sav != NULL);
792249259Sdim			if (sav)
793249259Sdim				KEY_FREESAV(&sav);
794249259Sdim
795249259Sdim			/* XXX Further validation? */
796249259Sdim
797249259Sdim			/*
798249259Sdim			 * Depending on whether the SA is "valid" and
799249259Sdim			 * routing table size (mtudisc_{hi,lo}wat), we will:
800249259Sdim			 * - recalcurate the new MTU and create the
801249259Sdim			 *   corresponding routing entry, or
802249259Sdim			 * - ignore the MTU change notification.
803249259Sdim			 */
804249259Sdim			icmp6_mtudisc_update(ip6cp, valid);
805249259Sdim		}
806249259Sdim	} else {
807249259Sdim		/* we normally notify any pcb here */
808249259Sdim	}
809249259Sdim}
810249259Sdim#endif /* INET6 */
811249259Sdim