17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (C) 2001-2003 by Darren Reed
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * See the IPFILTER.LICENCE file for details on licencing.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  * Simple ISAKMP transparent proxy for in-kernel use.  For use with the NAT
77c478bd9Sstevel@tonic-gate  * code.
8ab25eeb5Syz  *
9ab25eeb5Syz  * $Id: ip_ipsec_pxy.c,v 2.20.2.7 2005/07/15 21:56:50 darrenr Exp $
10ab25eeb5Syz  *
11*33f2fefdSDarren Reed  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
12ab25eeb5Syz  * Use is subject to license terms.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #define	IPF_IPSEC_PROXY
167c478bd9Sstevel@tonic-gate 
17f4b3ec61Sdh typedef struct ifs_ipsecpxy {
18f4b3ec61Sdh 	frentry_t		ipsecfr;
19f4b3ec61Sdh 	ipftq_t			*ipsecnattqe;
20f4b3ec61Sdh 	ipftq_t			*ipsecstatetqe;
21f4b3ec61Sdh 	char			ipsec_buffer[1500];
22f4b3ec61Sdh 	int			ipsec_proxy_init;
23f4b3ec61Sdh 	int			ipsec_proxy_ttl;
24f4b3ec61Sdh } ifs_ipsecpxy_t;
25f4b3ec61Sdh 
26f4b3ec61Sdh int ippr_ipsec_init __P((void **, ipf_stack_t *));
27f4b3ec61Sdh void ippr_ipsec_fini __P((void **, ipf_stack_t *));
28f4b3ec61Sdh int ippr_ipsec_new __P((fr_info_t *, ap_session_t *, nat_t *, void *));
29f4b3ec61Sdh void ippr_ipsec_del __P((ap_session_t *, void *, ipf_stack_t *));
30f4b3ec61Sdh int ippr_ipsec_inout __P((fr_info_t *, ap_session_t *, nat_t *, void *));
31f4b3ec61Sdh int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *, void *));
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * IPSec application proxy initialization.
357c478bd9Sstevel@tonic-gate  */
ippr_ipsec_init(private,ifs)36f4b3ec61Sdh int ippr_ipsec_init(private, ifs)
37f4b3ec61Sdh void **private;
38f4b3ec61Sdh ipf_stack_t *ifs;
397c478bd9Sstevel@tonic-gate {
40f4b3ec61Sdh 	ifs_ipsecpxy_t *ifsipsec;
41f4b3ec61Sdh 
42f4b3ec61Sdh 	KMALLOC(ifsipsec, ifs_ipsecpxy_t *);
43f4b3ec61Sdh 	if (ifsipsec == NULL)
447c478bd9Sstevel@tonic-gate 		return -1;
45f4b3ec61Sdh 
46f4b3ec61Sdh 	bzero((char *)&ifsipsec->ipsecfr, sizeof(ifsipsec->ipsecfr));
47f4b3ec61Sdh 	ifsipsec->ipsecfr.fr_ref = 1;
48f4b3ec61Sdh 	ifsipsec->ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
49f4b3ec61Sdh 	MUTEX_INIT(&ifsipsec->ipsecfr.fr_lock, "IPsec proxy rule lock");
50f4b3ec61Sdh 	ifsipsec->ipsec_proxy_init = 1;
51f4b3ec61Sdh 	ifsipsec->ipsec_proxy_ttl = 60;
52f4b3ec61Sdh 
53f4b3ec61Sdh 	ifsipsec->ipsecnattqe = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, ifsipsec->ipsec_proxy_ttl, ifs);
54f4b3ec61Sdh 	if (ifsipsec->ipsecnattqe == NULL) {
55f4b3ec61Sdh 		MUTEX_DESTROY(&ifsipsec->ipsecfr.fr_lock);
56f4b3ec61Sdh 		KFREE(ifsipsec);
577c478bd9Sstevel@tonic-gate 		return -1;
587c478bd9Sstevel@tonic-gate 	}
59f4b3ec61Sdh 	ifsipsec->ipsecstatetqe = fr_addtimeoutqueue(&ifs->ifs_ips_utqe, ifsipsec->ipsec_proxy_ttl, ifs);
60f4b3ec61Sdh 	if (ifsipsec->ipsecstatetqe == NULL) {
61f4b3ec61Sdh 		if (fr_deletetimeoutqueue(ifsipsec->ipsecnattqe) == 0)
62f4b3ec61Sdh 			fr_freetimeoutqueue(ifsipsec->ipsecnattqe, ifs);
63f4b3ec61Sdh 		ifsipsec->ipsecnattqe = NULL;
64f4b3ec61Sdh 		MUTEX_DESTROY(&ifsipsec->ipsecfr.fr_lock);
65f4b3ec61Sdh 		KFREE(ifsipsec);
66f4b3ec61Sdh 		return -1;
67f4b3ec61Sdh 	}
68f4b3ec61Sdh 
69f4b3ec61Sdh 	ifsipsec->ipsecnattqe->ifq_flags |= IFQF_PROXY;
70f4b3ec61Sdh 	ifsipsec->ipsecstatetqe->ifq_flags |= IFQF_PROXY;
71f4b3ec61Sdh 
72f4b3ec61Sdh 	ifsipsec->ipsecfr.fr_age[0] = ifsipsec->ipsec_proxy_ttl;
73f4b3ec61Sdh 	ifsipsec->ipsecfr.fr_age[1] = ifsipsec->ipsec_proxy_ttl;
74ab25eeb5Syz 
75f4b3ec61Sdh 	*private = (void *)ifsipsec;
76ab25eeb5Syz 
777c478bd9Sstevel@tonic-gate 	return 0;
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 
ippr_ipsec_fini(private,ifs)81f4b3ec61Sdh void ippr_ipsec_fini(private, ifs)
82f4b3ec61Sdh void **private;
83f4b3ec61Sdh ipf_stack_t *ifs;
847c478bd9Sstevel@tonic-gate {
85f4b3ec61Sdh 	ifs_ipsecpxy_t *ifsipsec = *((ifs_ipsecpxy_t **)private);
86f4b3ec61Sdh 
87f4b3ec61Sdh 	if (ifsipsec->ipsecnattqe != NULL) {
88f4b3ec61Sdh 		if (fr_deletetimeoutqueue(ifsipsec->ipsecnattqe) == 0)
89f4b3ec61Sdh 			fr_freetimeoutqueue(ifsipsec->ipsecnattqe, ifs);
90ab25eeb5Syz 	}
91f4b3ec61Sdh 	ifsipsec->ipsecnattqe = NULL;
92f4b3ec61Sdh 	if (ifsipsec->ipsecstatetqe != NULL) {
93f4b3ec61Sdh 		if (fr_deletetimeoutqueue(ifsipsec->ipsecstatetqe) == 0)
94f4b3ec61Sdh 			fr_freetimeoutqueue(ifsipsec->ipsecstatetqe, ifs);
95ab25eeb5Syz 	}
96f4b3ec61Sdh 	ifsipsec->ipsecstatetqe = NULL;
977c478bd9Sstevel@tonic-gate 
98f4b3ec61Sdh 	if (ifsipsec->ipsec_proxy_init == 1) {
99f4b3ec61Sdh 		MUTEX_DESTROY(&ifsipsec->ipsecfr.fr_lock);
100f4b3ec61Sdh 		ifsipsec->ipsec_proxy_init = 0;
1017c478bd9Sstevel@tonic-gate 	}
102f4b3ec61Sdh 
103f4b3ec61Sdh 	KFREE(ifsipsec);
104f4b3ec61Sdh 	*private = NULL;
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate  * Setup for a new IPSEC proxy.
1107c478bd9Sstevel@tonic-gate  */
ippr_ipsec_new(fin,aps,nat,private)111f4b3ec61Sdh int ippr_ipsec_new(fin, aps, nat, private)
1127c478bd9Sstevel@tonic-gate fr_info_t *fin;
1137c478bd9Sstevel@tonic-gate ap_session_t *aps;
1147c478bd9Sstevel@tonic-gate nat_t *nat;
115f4b3ec61Sdh void *private;
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	ipsec_pxy_t *ipsec;
1187c478bd9Sstevel@tonic-gate 	fr_info_t fi;
1197c478bd9Sstevel@tonic-gate 	ipnat_t *ipn;
1207c478bd9Sstevel@tonic-gate 	char *ptr;
121ab25eeb5Syz 	int p, off, dlen, ttl;
1227c478bd9Sstevel@tonic-gate 	mb_t *m;
1237c478bd9Sstevel@tonic-gate 	ip_t *ip;
124f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
125f4b3ec61Sdh 	ifs_ipsecpxy_t *ifsipsec = (ifs_ipsecpxy_t *)private;
1267c478bd9Sstevel@tonic-gate 
127ab25eeb5Syz 	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
128f4b3ec61Sdh 	bzero(ifsipsec->ipsec_buffer, sizeof(ifsipsec->ipsec_buffer));
1297c478bd9Sstevel@tonic-gate 	ip = fin->fin_ip;
1307c478bd9Sstevel@tonic-gate 	m = fin->fin_m;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	dlen = M_LEN(m) - off;
1337c478bd9Sstevel@tonic-gate 	if (dlen < 16)
1347c478bd9Sstevel@tonic-gate 		return -1;
135f4b3ec61Sdh 	COPYDATA(m, off, MIN(sizeof(ifsipsec->ipsec_buffer), dlen),
136f4b3ec61Sdh 		 ifsipsec->ipsec_buffer);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip,
1397c478bd9Sstevel@tonic-gate 			  ip->ip_dst) != NULL)
1407c478bd9Sstevel@tonic-gate 		return -1;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	aps->aps_psiz = sizeof(*ipsec);
1437c478bd9Sstevel@tonic-gate 	KMALLOCS(aps->aps_data, ipsec_pxy_t *, sizeof(*ipsec));
1447c478bd9Sstevel@tonic-gate 	if (aps->aps_data == NULL)
1457c478bd9Sstevel@tonic-gate 		return -1;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	ipsec = aps->aps_data;
1487c478bd9Sstevel@tonic-gate 	bzero((char *)ipsec, sizeof(*ipsec));
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/*
1517c478bd9Sstevel@tonic-gate 	 * Create NAT rule against which the tunnel/transport mapping is
1527c478bd9Sstevel@tonic-gate 	 * created.  This is required because the current NAT rule does not
1537c478bd9Sstevel@tonic-gate 	 * describe ESP but UDP instead.
1547c478bd9Sstevel@tonic-gate 	 */
1557c478bd9Sstevel@tonic-gate 	ipn = &ipsec->ipsc_rule;
156f4b3ec61Sdh 	ttl = IPF_TTLVAL(ifsipsec->ipsecnattqe->ifq_ttl);
157f4b3ec61Sdh 	ipn->in_tqehead[0] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, ttl, ifs);
158f4b3ec61Sdh 	ipn->in_tqehead[1] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe, ttl, ifs);
1597c478bd9Sstevel@tonic-gate 	ipn->in_ifps[0] = fin->fin_ifp;
1607c478bd9Sstevel@tonic-gate 	ipn->in_apr = NULL;
1617c478bd9Sstevel@tonic-gate 	ipn->in_use = 1;
1627c478bd9Sstevel@tonic-gate 	ipn->in_hits = 1;
163ab25eeb5Syz 	ipn->in_nip = ntohl(nat->nat_outip.s_addr);
1647c478bd9Sstevel@tonic-gate 	ipn->in_ippip = 1;
1657c478bd9Sstevel@tonic-gate 	ipn->in_inip = nat->nat_inip.s_addr;
1667c478bd9Sstevel@tonic-gate 	ipn->in_inmsk = 0xffffffff;
1677c478bd9Sstevel@tonic-gate 	ipn->in_outip = fin->fin_saddr;
1687c478bd9Sstevel@tonic-gate 	ipn->in_outmsk = nat->nat_outip.s_addr;
1697c478bd9Sstevel@tonic-gate 	ipn->in_srcip = fin->fin_saddr;
1707c478bd9Sstevel@tonic-gate 	ipn->in_srcmsk = 0xffffffff;
1717c478bd9Sstevel@tonic-gate 	ipn->in_redir = NAT_MAP;
1727c478bd9Sstevel@tonic-gate 	bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
1737c478bd9Sstevel@tonic-gate 	      sizeof(ipn->in_ifnames[0]));
1747c478bd9Sstevel@tonic-gate 	ipn->in_p = IPPROTO_ESP;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
1777c478bd9Sstevel@tonic-gate 	fi.fin_fi.fi_p = IPPROTO_ESP;
178f4b3ec61Sdh 	fi.fin_fr = &ifsipsec->ipsecfr;
1797c478bd9Sstevel@tonic-gate 	fi.fin_data[0] = 0;
1807c478bd9Sstevel@tonic-gate 	fi.fin_data[1] = 0;
1817c478bd9Sstevel@tonic-gate 	p = ip->ip_p;
1827c478bd9Sstevel@tonic-gate 	ip->ip_p = IPPROTO_ESP;
183ab25eeb5Syz 	fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
1847c478bd9Sstevel@tonic-gate 	fi.fin_flx |= FI_IGNORE;
1857c478bd9Sstevel@tonic-gate 
186f4b3ec61Sdh 	ptr = ifsipsec->ipsec_buffer;
1877c478bd9Sstevel@tonic-gate 	bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
1887c478bd9Sstevel@tonic-gate 	ptr += sizeof(ipsec_cookie_t);
1897c478bd9Sstevel@tonic-gate 	bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
1907c478bd9Sstevel@tonic-gate 	/*
1917c478bd9Sstevel@tonic-gate 	 * The responder cookie should only be non-zero if the initiator
1927c478bd9Sstevel@tonic-gate 	 * cookie is non-zero.  Therefore, it is safe to assume(!) that the
1937c478bd9Sstevel@tonic-gate 	 * cookies are both set after copying if the responder is non-zero.
1947c478bd9Sstevel@tonic-gate 	 */
1957c478bd9Sstevel@tonic-gate 	if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
1967c478bd9Sstevel@tonic-gate 		ipsec->ipsc_rckset = 1;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat,
1997c478bd9Sstevel@tonic-gate 				  NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
2007c478bd9Sstevel@tonic-gate 	if (ipsec->ipsc_nat != NULL) {
2017c478bd9Sstevel@tonic-gate 		(void) nat_proto(&fi, ipsec->ipsc_nat, 0);
2027c478bd9Sstevel@tonic-gate 		nat_update(&fi, ipsec->ipsc_nat, ipn);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 		fi.fin_data[0] = 0;
2057c478bd9Sstevel@tonic-gate 		fi.fin_data[1] = 0;
2067c478bd9Sstevel@tonic-gate 		ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state,
2077c478bd9Sstevel@tonic-gate 						SI_WILDP);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 	ip->ip_p = p & 0xff;
2107c478bd9Sstevel@tonic-gate 	return 0;
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate  * For outgoing IKE packets.  refresh timeouts for NAT & state entries, if
2167c478bd9Sstevel@tonic-gate  * we can.  If they have disappeared, recreate them.
2177c478bd9Sstevel@tonic-gate  */
ippr_ipsec_inout(fin,aps,nat,private)218f4b3ec61Sdh int ippr_ipsec_inout(fin, aps, nat, private)
2197c478bd9Sstevel@tonic-gate fr_info_t *fin;
2207c478bd9Sstevel@tonic-gate ap_session_t *aps;
2217c478bd9Sstevel@tonic-gate nat_t *nat;
222f4b3ec61Sdh void *private;
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate 	ipsec_pxy_t *ipsec;
2257c478bd9Sstevel@tonic-gate 	fr_info_t fi;
2267c478bd9Sstevel@tonic-gate 	ip_t *ip;
2277c478bd9Sstevel@tonic-gate 	int p;
228f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
229f4b3ec61Sdh 	ifs_ipsecpxy_t *ifsipsec = (ifs_ipsecpxy_t *)private;
2307c478bd9Sstevel@tonic-gate 
231ab25eeb5Syz 	if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
232ab25eeb5Syz 		return 0;
233ab25eeb5Syz 
234ab25eeb5Syz 	if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
235ab25eeb5Syz 		return 0;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	ipsec = aps->aps_data;
238ab25eeb5Syz 
2397c478bd9Sstevel@tonic-gate 	if (ipsec != NULL) {
240ab25eeb5Syz 		ip = fin->fin_ip;
241ab25eeb5Syz 		p = ip->ip_p;
242ab25eeb5Syz 
243ab25eeb5Syz 		if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
244ab25eeb5Syz 			bcopy((char *)fin, (char *)&fi, sizeof(fi));
245ab25eeb5Syz 			fi.fin_fi.fi_p = IPPROTO_ESP;
246f4b3ec61Sdh 			fi.fin_fr = &ifsipsec->ipsecfr;
247ab25eeb5Syz 			fi.fin_data[0] = 0;
248ab25eeb5Syz 			fi.fin_data[1] = 0;
249ab25eeb5Syz 			ip->ip_p = IPPROTO_ESP;
250ab25eeb5Syz 			fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
251ab25eeb5Syz 			fi.fin_flx |= FI_IGNORE;
252ab25eeb5Syz 		}
253ab25eeb5Syz 
2547c478bd9Sstevel@tonic-gate 		/*
2557c478bd9Sstevel@tonic-gate 		 * Update NAT timeout/create NAT if missing.
2567c478bd9Sstevel@tonic-gate 		 */
2577c478bd9Sstevel@tonic-gate 		if (ipsec->ipsc_nat != NULL)
258f4b3ec61Sdh 			fr_queueback(&ipsec->ipsc_nat->nat_tqe, ifs);
2597c478bd9Sstevel@tonic-gate 		else {
2607c478bd9Sstevel@tonic-gate 			ipsec->ipsc_nat = nat_new(&fi, &ipsec->ipsc_rule,
2617c478bd9Sstevel@tonic-gate 						  &ipsec->ipsc_nat,
2627c478bd9Sstevel@tonic-gate 						  NAT_SLAVE|SI_WILDP,
263ab25eeb5Syz 						  nat->nat_dir);
2647c478bd9Sstevel@tonic-gate 			if (ipsec->ipsc_nat != NULL) {
2657c478bd9Sstevel@tonic-gate 				(void) nat_proto(&fi, ipsec->ipsc_nat, 0);
2667c478bd9Sstevel@tonic-gate 				nat_update(&fi, ipsec->ipsc_nat,
2677c478bd9Sstevel@tonic-gate 					   &ipsec->ipsc_rule);
2687c478bd9Sstevel@tonic-gate 			}
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		/*
2727c478bd9Sstevel@tonic-gate 		 * Update state timeout/create state if missing.
2737c478bd9Sstevel@tonic-gate 		 */
274f4b3ec61Sdh 		READ_ENTER(&ifs->ifs_ipf_state);
2757c478bd9Sstevel@tonic-gate 		if (ipsec->ipsc_state != NULL) {
276f4b3ec61Sdh 			fr_queueback(&ipsec->ipsc_state->is_sti, ifs);
2777c478bd9Sstevel@tonic-gate 			ipsec->ipsc_state->is_die = nat->nat_age;
278f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_state);
2797c478bd9Sstevel@tonic-gate 		} else {
280f4b3ec61Sdh 			RWLOCK_EXIT(&ifs->ifs_ipf_state);
2817c478bd9Sstevel@tonic-gate 			fi.fin_data[0] = 0;
2827c478bd9Sstevel@tonic-gate 			fi.fin_data[1] = 0;
2837c478bd9Sstevel@tonic-gate 			ipsec->ipsc_state = fr_addstate(&fi,
2847c478bd9Sstevel@tonic-gate 							&ipsec->ipsc_state,
2857c478bd9Sstevel@tonic-gate 							SI_WILDP);
2867c478bd9Sstevel@tonic-gate 		}
287ab25eeb5Syz 		ip->ip_p = p;
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 	return 0;
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate  * This extends the NAT matching to be based on the cookies associated with
2957c478bd9Sstevel@tonic-gate  * a session and found at the front of IKE packets.  The cookies are always
2967c478bd9Sstevel@tonic-gate  * in the same order (not reversed depending on packet flow direction as with
2977c478bd9Sstevel@tonic-gate  * UDP/TCP port numbers).
2987c478bd9Sstevel@tonic-gate  */
299f4b3ec61Sdh /*ARGSUSED*/
ippr_ipsec_match(fin,aps,nat,private)300f4b3ec61Sdh int ippr_ipsec_match(fin, aps, nat, private)
3017c478bd9Sstevel@tonic-gate fr_info_t *fin;
3027c478bd9Sstevel@tonic-gate ap_session_t *aps;
3037c478bd9Sstevel@tonic-gate nat_t *nat;
304f4b3ec61Sdh void *private;
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	ipsec_pxy_t *ipsec;
3077c478bd9Sstevel@tonic-gate 	u_32_t cookies[4];
3087c478bd9Sstevel@tonic-gate 	mb_t *m;
3097c478bd9Sstevel@tonic-gate 	int off;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	nat = nat;	/* LINT */
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
3147c478bd9Sstevel@tonic-gate 		return -1;
3157c478bd9Sstevel@tonic-gate 
316ab25eeb5Syz 	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
3177c478bd9Sstevel@tonic-gate 	ipsec = aps->aps_data;
3187c478bd9Sstevel@tonic-gate 	m = fin->fin_m;
3197c478bd9Sstevel@tonic-gate 	COPYDATA(m, off, sizeof(cookies), (char *)cookies);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if ((cookies[0] != ipsec->ipsc_icookie[0]) ||
3227c478bd9Sstevel@tonic-gate 	    (cookies[1] != ipsec->ipsc_icookie[1]))
3237c478bd9Sstevel@tonic-gate 		return -1;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	if (ipsec->ipsc_rckset == 0) {
3267c478bd9Sstevel@tonic-gate 		if ((cookies[2]|cookies[3]) == 0) {
3277c478bd9Sstevel@tonic-gate 			return 0;
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 		ipsec->ipsc_rckset = 1;
3307c478bd9Sstevel@tonic-gate 		ipsec->ipsc_rcookie[0] = cookies[2];
3317c478bd9Sstevel@tonic-gate 		ipsec->ipsc_rcookie[1] = cookies[3];
3327c478bd9Sstevel@tonic-gate 		return 0;
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	if ((cookies[2] != ipsec->ipsc_rcookie[0]) ||
3367c478bd9Sstevel@tonic-gate 	    (cookies[3] != ipsec->ipsc_rcookie[1]))
3377c478bd9Sstevel@tonic-gate 		return -1;
3387c478bd9Sstevel@tonic-gate 	return 0;
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate /*
3437c478bd9Sstevel@tonic-gate  * clean up after ourselves.
3447c478bd9Sstevel@tonic-gate  */
345f4b3ec61Sdh /*ARGSUSED*/
ippr_ipsec_del(aps,private,ifs)346f4b3ec61Sdh void ippr_ipsec_del(aps, private, ifs)
3477c478bd9Sstevel@tonic-gate ap_session_t *aps;
348f4b3ec61Sdh void *private;
349f4b3ec61Sdh ipf_stack_t *ifs;
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate 	ipsec_pxy_t *ipsec;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	ipsec = aps->aps_data;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	if (ipsec != NULL) {
3567c478bd9Sstevel@tonic-gate 		/*
357ab25eeb5Syz 		 * Don't bother changing any of the NAT structure details,
358ab25eeb5Syz 		 * *_del() is on a callback from aps_free(), from nat_delete()
3597c478bd9Sstevel@tonic-gate 		 */
3607c478bd9Sstevel@tonic-gate 
361f4b3ec61Sdh 		READ_ENTER(&ifs->ifs_ipf_state);
3627c478bd9Sstevel@tonic-gate 		if (ipsec->ipsc_state != NULL) {
363f4b3ec61Sdh 			ipsec->ipsc_state->is_die = ifs->ifs_fr_ticks + 1;
364ab25eeb5Syz 			ipsec->ipsc_state->is_me = NULL;
3657c478bd9Sstevel@tonic-gate 			fr_queuefront(&ipsec->ipsc_state->is_sti);
3667c478bd9Sstevel@tonic-gate 		}
367f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_state);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 		ipsec->ipsc_state = NULL;
3707c478bd9Sstevel@tonic-gate 		ipsec->ipsc_nat = NULL;
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate }
373