xref: /netbsd-src/sys/external/bsd/ipf/netinet/ip_ipsec_pxy.c (revision 13885a665959c62f13a82b3caedf986eaa17aa31)
1*13885a66Sdarrenr /*	$NetBSD: ip_ipsec_pxy.c,v 1.3 2012/07/22 14:27:51 darrenr Exp $	*/
2c2aa585cSchristos 
3c2aa585cSchristos /*
4*13885a66Sdarrenr  * Copyright (C) 2012 by Darren Reed.
5c2aa585cSchristos  *
6c2aa585cSchristos  * See the IPFILTER.LICENCE file for details on licencing.
7c2aa585cSchristos  *
8c2aa585cSchristos  * Simple ISAKMP transparent proxy for in-kernel use.  For use with the NAT
9c2aa585cSchristos  * code.
10c2aa585cSchristos  *
11*13885a66Sdarrenr  * Id: ip_ipsec_pxy.c,v 1.1.1.2 2012/07/22 13:45:19 darrenr Exp
12c2aa585cSchristos  *
13c2aa585cSchristos  */
140c6adecaSchristos 
150c6adecaSchristos #include <sys/cdefs.h>
16*13885a66Sdarrenr __KERNEL_RCSID(1, "$NetBSD: ip_ipsec_pxy.c,v 1.3 2012/07/22 14:27:51 darrenr Exp $");
170c6adecaSchristos 
18c2aa585cSchristos #define	IPF_IPSEC_PROXY
19c2aa585cSchristos 
20c2aa585cSchristos 
21*13885a66Sdarrenr /*
22*13885a66Sdarrenr  * IPSec proxy
23*13885a66Sdarrenr  */
24*13885a66Sdarrenr typedef struct ipf_ipsec_softc_s {
25*13885a66Sdarrenr 	frentry_t	ipsec_fr;
26*13885a66Sdarrenr 	int		ipsec_proxy_init;
27*13885a66Sdarrenr 	int		ipsec_proxy_ttl;
28*13885a66Sdarrenr 	ipftq_t		*ipsec_nat_tqe;
29*13885a66Sdarrenr 	ipftq_t		*ipsec_state_tqe;
30*13885a66Sdarrenr 	char		ipsec_buffer[1500];
31*13885a66Sdarrenr } ipf_ipsec_softc_t;
32*13885a66Sdarrenr 
33*13885a66Sdarrenr 
340c6adecaSchristos void *ipf_p_ipsec_soft_create(ipf_main_softc_t *);
350c6adecaSchristos void ipf_p_ipsec_soft_destroy(ipf_main_softc_t *, void *);
360c6adecaSchristos int ipf_p_ipsec_soft_init(ipf_main_softc_t *, void *);
370c6adecaSchristos void ipf_p_ipsec_soft_fini(ipf_main_softc_t *, void *);
380c6adecaSchristos int ipf_p_ipsec_init(void);
390c6adecaSchristos void ipf_p_ipsec_fini(void);
400c6adecaSchristos int ipf_p_ipsec_new(void *, fr_info_t *, ap_session_t *, nat_t *);
410c6adecaSchristos void ipf_p_ipsec_del(ipf_main_softc_t *, ap_session_t *);
420c6adecaSchristos int ipf_p_ipsec_inout(void *, fr_info_t *, ap_session_t *, nat_t *);
430c6adecaSchristos int ipf_p_ipsec_match(fr_info_t *, ap_session_t *, nat_t *);
44c2aa585cSchristos 
45c2aa585cSchristos 
46c2aa585cSchristos /*
47c2aa585cSchristos  * IPSec application proxy initialization.
48c2aa585cSchristos  */
49c2aa585cSchristos void *
ipf_p_ipsec_soft_create(ipf_main_softc_t * softc)500c6adecaSchristos ipf_p_ipsec_soft_create(ipf_main_softc_t *softc)
51c2aa585cSchristos {
52c2aa585cSchristos 	ipf_ipsec_softc_t *softi;
53c2aa585cSchristos 
54c2aa585cSchristos 	KMALLOC(softi, ipf_ipsec_softc_t *);
55c2aa585cSchristos 	if (softi == NULL)
56c2aa585cSchristos 		return NULL;
57c2aa585cSchristos 
58c2aa585cSchristos 	bzero((char *)softi, sizeof(*softi));
59c2aa585cSchristos 	softi->ipsec_fr.fr_ref = 1;
60c2aa585cSchristos 	softi->ipsec_fr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
61c2aa585cSchristos 	MUTEX_INIT(&softi->ipsec_fr.fr_lock, "IPsec proxy rule lock");
62c2aa585cSchristos 	softi->ipsec_proxy_init = 1;
63c2aa585cSchristos 	softi->ipsec_proxy_ttl = 60;
64c2aa585cSchristos 
65c2aa585cSchristos 	return softi;
66c2aa585cSchristos }
67c2aa585cSchristos 
68c2aa585cSchristos 
69c2aa585cSchristos int
ipf_p_ipsec_soft_init(ipf_main_softc_t * softc,void * arg)700c6adecaSchristos ipf_p_ipsec_soft_init(ipf_main_softc_t *softc, void *arg)
71c2aa585cSchristos {
72c2aa585cSchristos 	ipf_ipsec_softc_t *softi = arg;
73c2aa585cSchristos 
74c2aa585cSchristos 	softi->ipsec_nat_tqe = ipf_state_add_tq(softc, softi->ipsec_proxy_ttl);
75c2aa585cSchristos 	if (softi->ipsec_nat_tqe == NULL)
76c2aa585cSchristos 		return -1;
77c2aa585cSchristos 	softi->ipsec_state_tqe = ipf_nat_add_tq(softc, softi->ipsec_proxy_ttl);
78c2aa585cSchristos 	if (softi->ipsec_state_tqe == NULL) {
79c2aa585cSchristos 		if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
80c2aa585cSchristos 			ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
81c2aa585cSchristos 		softi->ipsec_nat_tqe = NULL;
82c2aa585cSchristos 		return -1;
83c2aa585cSchristos 	}
84c2aa585cSchristos 
85c2aa585cSchristos 	softi->ipsec_nat_tqe->ifq_flags |= IFQF_PROXY;
86c2aa585cSchristos 	softi->ipsec_state_tqe->ifq_flags |= IFQF_PROXY;
87c2aa585cSchristos 	softi->ipsec_fr.fr_age[0] = softi->ipsec_proxy_ttl;
88c2aa585cSchristos 	softi->ipsec_fr.fr_age[1] = softi->ipsec_proxy_ttl;
89c2aa585cSchristos 	return 0;
90c2aa585cSchristos }
91c2aa585cSchristos 
92c2aa585cSchristos 
93c2aa585cSchristos void
ipf_p_ipsec_soft_fini(ipf_main_softc_t * softc,void * arg)940c6adecaSchristos ipf_p_ipsec_soft_fini(ipf_main_softc_t *softc, void *arg)
95c2aa585cSchristos {
96c2aa585cSchristos 	ipf_ipsec_softc_t *softi = arg;
97c2aa585cSchristos 
98c2aa585cSchristos 	if (arg == NULL)
99c2aa585cSchristos 		return;
100c2aa585cSchristos 
101c2aa585cSchristos 	if (softi->ipsec_nat_tqe != NULL) {
102c2aa585cSchristos 		if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
103c2aa585cSchristos 			ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
104c2aa585cSchristos 	}
105c2aa585cSchristos 	softi->ipsec_nat_tqe = NULL;
106c2aa585cSchristos 	if (softi->ipsec_state_tqe != NULL) {
107c2aa585cSchristos 		if (ipf_deletetimeoutqueue(softi->ipsec_state_tqe) == 0)
108c2aa585cSchristos 			ipf_freetimeoutqueue(softc, softi->ipsec_state_tqe);
109c2aa585cSchristos 	}
110c2aa585cSchristos 	softi->ipsec_state_tqe = NULL;
111c2aa585cSchristos }
112c2aa585cSchristos 
113c2aa585cSchristos 
114c2aa585cSchristos void
ipf_p_ipsec_soft_destroy(ipf_main_softc_t * softc,void * arg)1150c6adecaSchristos ipf_p_ipsec_soft_destroy(ipf_main_softc_t *softc, void *arg)
116c2aa585cSchristos {
117c2aa585cSchristos 	ipf_ipsec_softc_t *softi = arg;
118c2aa585cSchristos 
119c2aa585cSchristos 	if (softi->ipsec_proxy_init == 1) {
120c2aa585cSchristos 		MUTEX_DESTROY(&softi->ipsec_fr.fr_lock);
121c2aa585cSchristos 		softi->ipsec_proxy_init = 0;
122c2aa585cSchristos 	}
123c2aa585cSchristos 
124c2aa585cSchristos 	KFREE(softi);
125c2aa585cSchristos }
126c2aa585cSchristos 
127c2aa585cSchristos 
128c2aa585cSchristos /*
129c2aa585cSchristos  * Setup for a new IPSEC proxy.
130c2aa585cSchristos  */
131c2aa585cSchristos int
ipf_p_ipsec_new(void * arg,fr_info_t * fin,ap_session_t * aps,nat_t * nat)1320c6adecaSchristos ipf_p_ipsec_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
133c2aa585cSchristos {
134c2aa585cSchristos 	ipf_ipsec_softc_t *softi = arg;
135c2aa585cSchristos 	ipf_main_softc_t *softc = fin->fin_main_soft;
136c2aa585cSchristos #ifdef USE_MUTEXES
137c2aa585cSchristos 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
138c2aa585cSchristos #endif
139*13885a66Sdarrenr 	int p, off, dlen, ttl;
140c2aa585cSchristos 	ipsec_pxy_t *ipsec;
141c2aa585cSchristos 	ipnat_t *ipn, *np;
142c2aa585cSchristos 	fr_info_t fi;
143c2aa585cSchristos 	char *ptr;
144*13885a66Sdarrenr 	int size;
145c2aa585cSchristos 	ip_t *ip;
146*13885a66Sdarrenr 	mb_t *m;
147*13885a66Sdarrenr 
148*13885a66Sdarrenr 	if (fin->fin_v != 4)
149*13885a66Sdarrenr 		return -1;
150c2aa585cSchristos 
151c2aa585cSchristos 	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
152c2aa585cSchristos 	bzero(softi->ipsec_buffer, sizeof(softi->ipsec_buffer));
153c2aa585cSchristos 	ip = fin->fin_ip;
154c2aa585cSchristos 	m = fin->fin_m;
155c2aa585cSchristos 
156c2aa585cSchristos 	dlen = M_LEN(m) - off;
157c2aa585cSchristos 	if (dlen < 16)
158c2aa585cSchristos 		return -1;
159c2aa585cSchristos 	COPYDATA(m, off, MIN(sizeof(softi->ipsec_buffer), dlen),
160c2aa585cSchristos 		 softi->ipsec_buffer);
161c2aa585cSchristos 
162c2aa585cSchristos 	if (ipf_nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_nsrcip,
163c2aa585cSchristos 			  ip->ip_dst) != NULL)
164c2aa585cSchristos 		return -1;
165c2aa585cSchristos 
166c2aa585cSchristos 	np = nat->nat_ptr;
167*13885a66Sdarrenr 	size = np->in_size;
168*13885a66Sdarrenr 	KMALLOC(ipsec, ipsec_pxy_t *);
169*13885a66Sdarrenr 	if (ipsec == NULL)
170c2aa585cSchristos 		return -1;
171c2aa585cSchristos 
172*13885a66Sdarrenr 	KMALLOCS(ipn, ipnat_t *, size);
173*13885a66Sdarrenr 	if (ipn == NULL) {
174*13885a66Sdarrenr 		KFREE(ipsec);
175*13885a66Sdarrenr 		return -1;
176*13885a66Sdarrenr 	}
177*13885a66Sdarrenr 
178*13885a66Sdarrenr 	aps->aps_data = ipsec;
179*13885a66Sdarrenr 	aps->aps_psiz = sizeof(*ipsec);
180c2aa585cSchristos 	bzero((char *)ipsec, sizeof(*ipsec));
181*13885a66Sdarrenr 	bzero((char *)ipn, size);
182*13885a66Sdarrenr 	ipsec->ipsc_rule = ipn;
183c2aa585cSchristos 
184c2aa585cSchristos 	/*
185c2aa585cSchristos 	 * Create NAT rule against which the tunnel/transport mapping is
186c2aa585cSchristos 	 * created.  This is required because the current NAT rule does not
187c2aa585cSchristos 	 * describe ESP but UDP instead.
188c2aa585cSchristos 	 */
189*13885a66Sdarrenr 	ipn->in_size = size;
190c2aa585cSchristos 	ttl = IPF_TTLVAL(softi->ipsec_nat_tqe->ifq_ttl);
191c2aa585cSchristos 	ipn->in_tqehead[0] = ipf_nat_add_tq(softc, ttl);
192c2aa585cSchristos 	ipn->in_tqehead[1] = ipf_nat_add_tq(softc, ttl);
193c2aa585cSchristos 	ipn->in_ifps[0] = fin->fin_ifp;
194c2aa585cSchristos 	ipn->in_apr = NULL;
195c2aa585cSchristos 	ipn->in_use = 1;
196c2aa585cSchristos 	ipn->in_hits = 1;
197c2aa585cSchristos 	ipn->in_snip = ntohl(nat->nat_nsrcaddr);
198c2aa585cSchristos 	ipn->in_ippip = 1;
199c2aa585cSchristos 	ipn->in_osrcip = nat->nat_osrcip;
200c2aa585cSchristos 	ipn->in_osrcmsk = 0xffffffff;
201c2aa585cSchristos 	ipn->in_nsrcip = nat->nat_nsrcip;
202c2aa585cSchristos 	ipn->in_nsrcmsk = 0xffffffff;
203c2aa585cSchristos 	ipn->in_odstip = nat->nat_odstip;
204c2aa585cSchristos 	ipn->in_odstmsk = 0xffffffff;
205c2aa585cSchristos 	ipn->in_ndstip = nat->nat_ndstip;
206c2aa585cSchristos 	ipn->in_ndstmsk = 0xffffffff;
207c2aa585cSchristos 	ipn->in_redir = NAT_MAP;
208c2aa585cSchristos 	ipn->in_pr[0] = IPPROTO_ESP;
209c2aa585cSchristos 	ipn->in_pr[1] = IPPROTO_ESP;
210*13885a66Sdarrenr 	ipn->in_flags = (np->in_flags | IPN_PROXYRULE);
211c2aa585cSchristos 	MUTEX_INIT(&ipn->in_lock, "IPSec proxy NAT rule");
212c2aa585cSchristos 
213c2aa585cSchristos 	ipn->in_namelen = np->in_namelen;
214c2aa585cSchristos 	bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
215c2aa585cSchristos 	ipn->in_ifnames[0] = np->in_ifnames[0];
216c2aa585cSchristos 	ipn->in_ifnames[1] = np->in_ifnames[1];
217c2aa585cSchristos 
218c2aa585cSchristos 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
219c2aa585cSchristos 	fi.fin_fi.fi_p = IPPROTO_ESP;
220c2aa585cSchristos 	fi.fin_fr = &softi->ipsec_fr;
221c2aa585cSchristos 	fi.fin_data[0] = 0;
222c2aa585cSchristos 	fi.fin_data[1] = 0;
223c2aa585cSchristos 	p = ip->ip_p;
224c2aa585cSchristos 	ip->ip_p = IPPROTO_ESP;
225c2aa585cSchristos 	fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
226c2aa585cSchristos 	fi.fin_flx |= FI_IGNORE;
227c2aa585cSchristos 
228c2aa585cSchristos 	ptr = softi->ipsec_buffer;
229c2aa585cSchristos 	bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
230c2aa585cSchristos 	ptr += sizeof(ipsec_cookie_t);
231c2aa585cSchristos 	bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
232c2aa585cSchristos 	/*
233c2aa585cSchristos 	 * The responder cookie should only be non-zero if the initiator
234c2aa585cSchristos 	 * cookie is non-zero.  Therefore, it is safe to assume(!) that the
235c2aa585cSchristos 	 * cookies are both set after copying if the responder is non-zero.
236c2aa585cSchristos 	 */
237c2aa585cSchristos 	if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
238c2aa585cSchristos 		ipsec->ipsc_rckset = 1;
239c2aa585cSchristos 
240c2aa585cSchristos 	MUTEX_ENTER(&softn->ipf_nat_new);
241c2aa585cSchristos 	ipsec->ipsc_nat = ipf_nat_add(&fi, ipn, &ipsec->ipsc_nat,
242c2aa585cSchristos 				      NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
243c2aa585cSchristos 	MUTEX_EXIT(&softn->ipf_nat_new);
244c2aa585cSchristos 	if (ipsec->ipsc_nat != NULL) {
245c2aa585cSchristos 		(void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
246c2aa585cSchristos 		MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
247c2aa585cSchristos 		ipf_nat_update(&fi, ipsec->ipsc_nat);
248c2aa585cSchristos 		MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
249c2aa585cSchristos 
250c2aa585cSchristos 		fi.fin_data[0] = 0;
251c2aa585cSchristos 		fi.fin_data[1] = 0;
252c2aa585cSchristos 		(void) ipf_state_add(softc, &fi, &ipsec->ipsc_state, SI_WILDP);
253c2aa585cSchristos 	}
254c2aa585cSchristos 	ip->ip_p = p & 0xff;
255c2aa585cSchristos 	return 0;
256c2aa585cSchristos }
257c2aa585cSchristos 
258c2aa585cSchristos 
259c2aa585cSchristos /*
260c2aa585cSchristos  * For outgoing IKE packets.  refresh timeouts for NAT & state entries, if
261c2aa585cSchristos  * we can.  If they have disappeared, recreate them.
262c2aa585cSchristos  */
263c2aa585cSchristos int
ipf_p_ipsec_inout(void * arg,fr_info_t * fin,ap_session_t * aps,nat_t * nat)2640c6adecaSchristos ipf_p_ipsec_inout(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
265c2aa585cSchristos {
266c2aa585cSchristos 	ipf_ipsec_softc_t *softi = arg;
267c2aa585cSchristos 	ipf_main_softc_t *softc = fin->fin_main_soft;
268c2aa585cSchristos 	ipsec_pxy_t *ipsec;
269c2aa585cSchristos 	fr_info_t fi;
270c2aa585cSchristos 	ip_t *ip;
271c2aa585cSchristos 	int p;
272c2aa585cSchristos 
273c2aa585cSchristos 	if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
274c2aa585cSchristos 		return 0;
275c2aa585cSchristos 
276c2aa585cSchristos 	if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
277c2aa585cSchristos 		return 0;
278c2aa585cSchristos 
279c2aa585cSchristos 	ipsec = aps->aps_data;
280c2aa585cSchristos 
281c2aa585cSchristos 	if (ipsec != NULL) {
282c2aa585cSchristos 		ip = fin->fin_ip;
283c2aa585cSchristos 		p = ip->ip_p;
284c2aa585cSchristos 
285c2aa585cSchristos 		if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
286c2aa585cSchristos 			bcopy((char *)fin, (char *)&fi, sizeof(fi));
287c2aa585cSchristos 			fi.fin_fi.fi_p = IPPROTO_ESP;
288c2aa585cSchristos 			fi.fin_fr = &softi->ipsec_fr;
289c2aa585cSchristos 			fi.fin_data[0] = 0;
290c2aa585cSchristos 			fi.fin_data[1] = 0;
291c2aa585cSchristos 			ip->ip_p = IPPROTO_ESP;
292c2aa585cSchristos 			fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
293c2aa585cSchristos 			fi.fin_flx |= FI_IGNORE;
294c2aa585cSchristos 		}
295c2aa585cSchristos 
296c2aa585cSchristos 		/*
297c2aa585cSchristos 		 * Update NAT timeout/create NAT if missing.
298c2aa585cSchristos 		 */
299c2aa585cSchristos 		if (ipsec->ipsc_nat != NULL)
300c2aa585cSchristos 			ipf_queueback(softc->ipf_ticks,
301c2aa585cSchristos 				      &ipsec->ipsc_nat->nat_tqe);
302c2aa585cSchristos 		else {
303c2aa585cSchristos #ifdef USE_MUTEXES
304c2aa585cSchristos 			ipf_nat_softc_t *softn = softc->ipf_nat_soft;
305c2aa585cSchristos #endif
306c2aa585cSchristos 
307c2aa585cSchristos 			MUTEX_ENTER(&softn->ipf_nat_new);
308*13885a66Sdarrenr 			ipsec->ipsc_nat = ipf_nat_add(&fi, ipsec->ipsc_rule,
309c2aa585cSchristos 						      &ipsec->ipsc_nat,
310c2aa585cSchristos 						      NAT_SLAVE|SI_WILDP,
311c2aa585cSchristos 						      nat->nat_dir);
312c2aa585cSchristos 			MUTEX_EXIT(&softn->ipf_nat_new);
313c2aa585cSchristos 			if (ipsec->ipsc_nat != NULL) {
314c2aa585cSchristos 				(void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
315c2aa585cSchristos 				MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
316c2aa585cSchristos 				ipf_nat_update(&fi, ipsec->ipsc_nat);
317c2aa585cSchristos 				MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
318c2aa585cSchristos 			}
319c2aa585cSchristos 		}
320c2aa585cSchristos 
321c2aa585cSchristos 		/*
322c2aa585cSchristos 		 * Update state timeout/create state if missing.
323c2aa585cSchristos 		 */
324c2aa585cSchristos 		READ_ENTER(&softc->ipf_state);
325c2aa585cSchristos 		if (ipsec->ipsc_state != NULL) {
326c2aa585cSchristos 			ipf_queueback(softc->ipf_ticks,
327c2aa585cSchristos 				      &ipsec->ipsc_state->is_sti);
328c2aa585cSchristos 			ipsec->ipsc_state->is_die = nat->nat_age;
329c2aa585cSchristos 			RWLOCK_EXIT(&softc->ipf_state);
330c2aa585cSchristos 		} else {
331c2aa585cSchristos 			RWLOCK_EXIT(&softc->ipf_state);
332c2aa585cSchristos 			fi.fin_data[0] = 0;
333c2aa585cSchristos 			fi.fin_data[1] = 0;
334c2aa585cSchristos 			(void) ipf_state_add(softc, &fi, &ipsec->ipsc_state,
335c2aa585cSchristos 					     SI_WILDP);
336c2aa585cSchristos 		}
337c2aa585cSchristos 		ip->ip_p = p;
338c2aa585cSchristos 	}
339c2aa585cSchristos 	return 0;
340c2aa585cSchristos }
341c2aa585cSchristos 
342c2aa585cSchristos 
343c2aa585cSchristos /*
344c2aa585cSchristos  * This extends the NAT matching to be based on the cookies associated with
345c2aa585cSchristos  * a session and found at the front of IKE packets.  The cookies are always
346c2aa585cSchristos  * in the same order (not reversed depending on packet flow direction as with
347c2aa585cSchristos  * UDP/TCP port numbers).
348c2aa585cSchristos  */
349c2aa585cSchristos int
ipf_p_ipsec_match(fr_info_t * fin,ap_session_t * aps,nat_t * nat)3500c6adecaSchristos ipf_p_ipsec_match(fr_info_t *fin, ap_session_t *aps, nat_t *nat)
351c2aa585cSchristos {
352c2aa585cSchristos 	ipsec_pxy_t *ipsec;
353c2aa585cSchristos 	u_32_t cookies[4];
354c2aa585cSchristos 	mb_t *m;
355c2aa585cSchristos 	int off;
356c2aa585cSchristos 
357c2aa585cSchristos 	nat = nat;	/* LINT */
358c2aa585cSchristos 
359c2aa585cSchristos 	if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
360c2aa585cSchristos 		return -1;
361c2aa585cSchristos 
362c2aa585cSchristos 	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
363c2aa585cSchristos 	ipsec = aps->aps_data;
364c2aa585cSchristos 	m = fin->fin_m;
365c2aa585cSchristos 	COPYDATA(m, off, sizeof(cookies), (char *)cookies);
366c2aa585cSchristos 
367c2aa585cSchristos 	if ((cookies[0] != ipsec->ipsc_icookie[0]) ||
368c2aa585cSchristos 	    (cookies[1] != ipsec->ipsc_icookie[1]))
369c2aa585cSchristos 		return -1;
370c2aa585cSchristos 
371c2aa585cSchristos 	if (ipsec->ipsc_rckset == 0) {
372c2aa585cSchristos 		if ((cookies[2]|cookies[3]) == 0) {
373c2aa585cSchristos 			return 0;
374c2aa585cSchristos 		}
375c2aa585cSchristos 		ipsec->ipsc_rckset = 1;
376c2aa585cSchristos 		ipsec->ipsc_rcookie[0] = cookies[2];
377c2aa585cSchristos 		ipsec->ipsc_rcookie[1] = cookies[3];
378c2aa585cSchristos 		return 0;
379c2aa585cSchristos 	}
380c2aa585cSchristos 
381c2aa585cSchristos 	if ((cookies[2] != ipsec->ipsc_rcookie[0]) ||
382c2aa585cSchristos 	    (cookies[3] != ipsec->ipsc_rcookie[1]))
383c2aa585cSchristos 		return -1;
384c2aa585cSchristos 	return 0;
385c2aa585cSchristos }
386c2aa585cSchristos 
387c2aa585cSchristos 
388c2aa585cSchristos /*
389c2aa585cSchristos  * clean up after ourselves.
390c2aa585cSchristos  */
391c2aa585cSchristos void
ipf_p_ipsec_del(ipf_main_softc_t * softc,ap_session_t * aps)3920c6adecaSchristos ipf_p_ipsec_del(ipf_main_softc_t *softc, ap_session_t *aps)
393c2aa585cSchristos {
394c2aa585cSchristos 	ipsec_pxy_t *ipsec;
395c2aa585cSchristos 
396c2aa585cSchristos 	ipsec = aps->aps_data;
397c2aa585cSchristos 
398c2aa585cSchristos 	if (ipsec != NULL) {
399c2aa585cSchristos 		/*
400c2aa585cSchristos 		 * Don't bother changing any of the NAT structure details,
401c2aa585cSchristos 		 * *_del() is on a callback from aps_free(), from nat_delete()
402c2aa585cSchristos 		 */
403c2aa585cSchristos 
404c2aa585cSchristos 		READ_ENTER(&softc->ipf_state);
405c2aa585cSchristos 		if (ipsec->ipsc_state != NULL) {
406c2aa585cSchristos 			ipsec->ipsc_state->is_die = softc->ipf_ticks + 1;
407c2aa585cSchristos 			ipsec->ipsc_state->is_me = NULL;
408c2aa585cSchristos 			ipf_queuefront(&ipsec->ipsc_state->is_sti);
409c2aa585cSchristos 		}
410c2aa585cSchristos 		RWLOCK_EXIT(&softc->ipf_state);
411c2aa585cSchristos 
412c2aa585cSchristos 		ipsec->ipsc_state = NULL;
413c2aa585cSchristos 		ipsec->ipsc_nat = NULL;
414*13885a66Sdarrenr 		ipsec->ipsc_rule->in_flags |= IPN_DELETE;
415*13885a66Sdarrenr 		ipf_nat_rule_deref(softc, &ipsec->ipsc_rule);
416c2aa585cSchristos 	}
417c2aa585cSchristos }
418