13b9b51feSCy Schubert /*
23b9b51feSCy Schubert  * Copyright (C) 2012 by Darren Reed.
33b9b51feSCy Schubert  *
43b9b51feSCy Schubert  * See the IPFILTER.LICENCE file for details on licencing.
53b9b51feSCy Schubert  *
63b9b51feSCy Schubert  * Simple ISAKMP transparent proxy for in-kernel use.  For use with the NAT
73b9b51feSCy Schubert  * code.
83b9b51feSCy Schubert  *
93b9b51feSCy Schubert  * $Id$
103b9b51feSCy Schubert  *
113b9b51feSCy Schubert  */
123b9b51feSCy Schubert #define	IPF_IPSEC_PROXY
133b9b51feSCy Schubert 
143b9b51feSCy Schubert 
153b9b51feSCy Schubert /*
163b9b51feSCy Schubert  * IPSec proxy
173b9b51feSCy Schubert  */
183b9b51feSCy Schubert typedef struct ipf_ipsec_softc_s {
193b9b51feSCy Schubert 	frentry_t	ipsec_fr;
203b9b51feSCy Schubert 	int		ipsec_proxy_init;
213b9b51feSCy Schubert 	int		ipsec_proxy_ttl;
223b9b51feSCy Schubert 	ipftq_t		*ipsec_nat_tqe;
233b9b51feSCy Schubert 	ipftq_t		*ipsec_state_tqe;
243b9b51feSCy Schubert 	char		ipsec_buffer[1500];
253b9b51feSCy Schubert } ipf_ipsec_softc_t;
263b9b51feSCy Schubert 
273b9b51feSCy Schubert 
283b9b51feSCy Schubert void *ipf_p_ipsec_soft_create(ipf_main_softc_t *);
293b9b51feSCy Schubert void ipf_p_ipsec_soft_destroy(ipf_main_softc_t *, void *);
303b9b51feSCy Schubert int ipf_p_ipsec_soft_init(ipf_main_softc_t *, void *);
313b9b51feSCy Schubert void ipf_p_ipsec_soft_fini(ipf_main_softc_t *, void *);
323b9b51feSCy Schubert int ipf_p_ipsec_init(void);
333b9b51feSCy Schubert void ipf_p_ipsec_fini(void);
343b9b51feSCy Schubert int ipf_p_ipsec_new(void *, fr_info_t *, ap_session_t *, nat_t *);
353b9b51feSCy Schubert void ipf_p_ipsec_del(ipf_main_softc_t *, ap_session_t *);
363b9b51feSCy Schubert int ipf_p_ipsec_inout(void *, fr_info_t *, ap_session_t *, nat_t *);
373b9b51feSCy Schubert int ipf_p_ipsec_match(fr_info_t *, ap_session_t *, nat_t *);
383b9b51feSCy Schubert 
393b9b51feSCy Schubert 
403b9b51feSCy Schubert /*
413b9b51feSCy Schubert  * IPSec application proxy initialization.
423b9b51feSCy Schubert  */
433b9b51feSCy Schubert void *
ipf_p_ipsec_soft_create(ipf_main_softc_t * softc)44064a5a95SCy Schubert ipf_p_ipsec_soft_create(ipf_main_softc_t *softc)
453b9b51feSCy Schubert {
463b9b51feSCy Schubert 	ipf_ipsec_softc_t *softi;
473b9b51feSCy Schubert 
483b9b51feSCy Schubert 	KMALLOC(softi, ipf_ipsec_softc_t *);
493b9b51feSCy Schubert 	if (softi == NULL)
508c82b374SCy Schubert 		return (NULL);
513b9b51feSCy Schubert 
523b9b51feSCy Schubert 	bzero((char *)softi, sizeof(*softi));
533b9b51feSCy Schubert 	softi->ipsec_fr.fr_ref = 1;
543b9b51feSCy Schubert 	softi->ipsec_fr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
553b9b51feSCy Schubert 	MUTEX_INIT(&softi->ipsec_fr.fr_lock, "IPsec proxy rule lock");
563b9b51feSCy Schubert 	softi->ipsec_proxy_init = 1;
573b9b51feSCy Schubert 	softi->ipsec_proxy_ttl = 60;
583b9b51feSCy Schubert 
598c82b374SCy Schubert 	return (softi);
603b9b51feSCy Schubert }
613b9b51feSCy Schubert 
623b9b51feSCy Schubert 
633b9b51feSCy Schubert int
ipf_p_ipsec_soft_init(ipf_main_softc_t * softc,void * arg)64064a5a95SCy Schubert ipf_p_ipsec_soft_init(ipf_main_softc_t *softc, void *arg)
653b9b51feSCy Schubert {
663b9b51feSCy Schubert 	ipf_ipsec_softc_t *softi = arg;
673b9b51feSCy Schubert 
683b9b51feSCy Schubert 	softi->ipsec_nat_tqe = ipf_state_add_tq(softc, softi->ipsec_proxy_ttl);
693b9b51feSCy Schubert 	if (softi->ipsec_nat_tqe == NULL)
708c82b374SCy Schubert 		return (-1);
713b9b51feSCy Schubert 	softi->ipsec_state_tqe = ipf_nat_add_tq(softc, softi->ipsec_proxy_ttl);
723b9b51feSCy Schubert 	if (softi->ipsec_state_tqe == NULL) {
733b9b51feSCy Schubert 		if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
743b9b51feSCy Schubert 			ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
753b9b51feSCy Schubert 		softi->ipsec_nat_tqe = NULL;
768c82b374SCy Schubert 		return (-1);
773b9b51feSCy Schubert 	}
783b9b51feSCy Schubert 
793b9b51feSCy Schubert 	softi->ipsec_nat_tqe->ifq_flags |= IFQF_PROXY;
803b9b51feSCy Schubert 	softi->ipsec_state_tqe->ifq_flags |= IFQF_PROXY;
813b9b51feSCy Schubert 	softi->ipsec_fr.fr_age[0] = softi->ipsec_proxy_ttl;
823b9b51feSCy Schubert 	softi->ipsec_fr.fr_age[1] = softi->ipsec_proxy_ttl;
838c82b374SCy Schubert 	return (0);
843b9b51feSCy Schubert }
853b9b51feSCy Schubert 
863b9b51feSCy Schubert 
873b9b51feSCy Schubert void
ipf_p_ipsec_soft_fini(ipf_main_softc_t * softc,void * arg)88064a5a95SCy Schubert ipf_p_ipsec_soft_fini(ipf_main_softc_t *softc, void *arg)
893b9b51feSCy Schubert {
903b9b51feSCy Schubert 	ipf_ipsec_softc_t *softi = arg;
913b9b51feSCy Schubert 
923b9b51feSCy Schubert 	if (arg == NULL)
933b9b51feSCy Schubert 		return;
943b9b51feSCy Schubert 
953b9b51feSCy Schubert 	if (softi->ipsec_nat_tqe != NULL) {
963b9b51feSCy Schubert 		if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
973b9b51feSCy Schubert 			ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
983b9b51feSCy Schubert 	}
993b9b51feSCy Schubert 	softi->ipsec_nat_tqe = NULL;
1003b9b51feSCy Schubert 	if (softi->ipsec_state_tqe != NULL) {
1013b9b51feSCy Schubert 		if (ipf_deletetimeoutqueue(softi->ipsec_state_tqe) == 0)
1023b9b51feSCy Schubert 			ipf_freetimeoutqueue(softc, softi->ipsec_state_tqe);
1033b9b51feSCy Schubert 	}
1043b9b51feSCy Schubert 	softi->ipsec_state_tqe = NULL;
1053b9b51feSCy Schubert }
1063b9b51feSCy Schubert 
1073b9b51feSCy Schubert 
1083b9b51feSCy Schubert void
ipf_p_ipsec_soft_destroy(ipf_main_softc_t * softc,void * arg)109064a5a95SCy Schubert ipf_p_ipsec_soft_destroy(ipf_main_softc_t *softc, void *arg)
1103b9b51feSCy Schubert {
1113b9b51feSCy Schubert 	ipf_ipsec_softc_t *softi = arg;
1123b9b51feSCy Schubert 
1133b9b51feSCy Schubert 	if (softi->ipsec_proxy_init == 1) {
1143b9b51feSCy Schubert 		MUTEX_DESTROY(&softi->ipsec_fr.fr_lock);
1153b9b51feSCy Schubert 		softi->ipsec_proxy_init = 0;
1163b9b51feSCy Schubert 	}
1173b9b51feSCy Schubert 
1183b9b51feSCy Schubert 	KFREE(softi);
1193b9b51feSCy Schubert }
1203b9b51feSCy Schubert 
1213b9b51feSCy Schubert 
1223b9b51feSCy Schubert /*
1233b9b51feSCy Schubert  * Setup for a new IPSEC proxy.
1243b9b51feSCy Schubert  */
1253b9b51feSCy Schubert int
ipf_p_ipsec_new(void * arg,fr_info_t * fin,ap_session_t * aps,nat_t * nat)126064a5a95SCy Schubert ipf_p_ipsec_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
1273b9b51feSCy Schubert {
1283b9b51feSCy Schubert 	ipf_ipsec_softc_t *softi = arg;
1293b9b51feSCy Schubert 	ipf_main_softc_t *softc = fin->fin_main_soft;
1303b9b51feSCy Schubert #ifdef USE_MUTEXES
1313b9b51feSCy Schubert 	ipf_nat_softc_t *softn = softc->ipf_nat_soft;
1323b9b51feSCy Schubert #endif
1333b9b51feSCy Schubert 	int p, off, dlen, ttl;
1343b9b51feSCy Schubert 	ipsec_pxy_t *ipsec;
1353b9b51feSCy Schubert 	ipnat_t *ipn, *np;
1363b9b51feSCy Schubert 	fr_info_t fi;
1373b9b51feSCy Schubert 	char *ptr;
1383b9b51feSCy Schubert 	int size;
1393b9b51feSCy Schubert 	ip_t *ip;
1403b9b51feSCy Schubert 	mb_t *m;
1413b9b51feSCy Schubert 
1423b9b51feSCy Schubert 	if (fin->fin_v != 4)
1438c82b374SCy Schubert 		return (-1);
1443b9b51feSCy Schubert 
1453b9b51feSCy Schubert 	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
1463b9b51feSCy Schubert 	bzero(softi->ipsec_buffer, sizeof(softi->ipsec_buffer));
1473b9b51feSCy Schubert 	ip = fin->fin_ip;
1483b9b51feSCy Schubert 	m = fin->fin_m;
1493b9b51feSCy Schubert 
1503b9b51feSCy Schubert 	dlen = M_LEN(m) - off;
1513b9b51feSCy Schubert 	if (dlen < 16)
1528c82b374SCy Schubert 		return (-1);
1533b9b51feSCy Schubert 	COPYDATA(m, off, MIN(sizeof(softi->ipsec_buffer), dlen),
1543b9b51feSCy Schubert 		 softi->ipsec_buffer);
1553b9b51feSCy Schubert 
1563b9b51feSCy Schubert 	if (ipf_nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_nsrcip,
1573b9b51feSCy Schubert 			  ip->ip_dst) != NULL)
1588c82b374SCy Schubert 		return (-1);
1593b9b51feSCy Schubert 
1603b9b51feSCy Schubert 	np = nat->nat_ptr;
1613b9b51feSCy Schubert 	size = np->in_size;
1623b9b51feSCy Schubert 	KMALLOC(ipsec, ipsec_pxy_t *);
1633b9b51feSCy Schubert 	if (ipsec == NULL)
1648c82b374SCy Schubert 		return (-1);
1653b9b51feSCy Schubert 
1663b9b51feSCy Schubert 	KMALLOCS(ipn, ipnat_t *, size);
1673b9b51feSCy Schubert 	if (ipn == NULL) {
1683b9b51feSCy Schubert 		KFREE(ipsec);
1698c82b374SCy Schubert 		return (-1);
1703b9b51feSCy Schubert 	}
1713b9b51feSCy Schubert 
1723b9b51feSCy Schubert 	aps->aps_data = ipsec;
1733b9b51feSCy Schubert 	aps->aps_psiz = sizeof(*ipsec);
1743b9b51feSCy Schubert 	bzero((char *)ipsec, sizeof(*ipsec));
1753b9b51feSCy Schubert 	bzero((char *)ipn, size);
1763b9b51feSCy Schubert 	ipsec->ipsc_rule = ipn;
1773b9b51feSCy Schubert 
1783b9b51feSCy Schubert 	/*
1793b9b51feSCy Schubert 	 * Create NAT rule against which the tunnel/transport mapping is
1803b9b51feSCy Schubert 	 * created.  This is required because the current NAT rule does not
1813b9b51feSCy Schubert 	 * describe ESP but UDP instead.
1823b9b51feSCy Schubert 	 */
1833b9b51feSCy Schubert 	ipn->in_size = size;
1843b9b51feSCy Schubert 	ttl = IPF_TTLVAL(softi->ipsec_nat_tqe->ifq_ttl);
1853b9b51feSCy Schubert 	ipn->in_tqehead[0] = ipf_nat_add_tq(softc, ttl);
1863b9b51feSCy Schubert 	ipn->in_tqehead[1] = ipf_nat_add_tq(softc, ttl);
1873b9b51feSCy Schubert 	ipn->in_ifps[0] = fin->fin_ifp;
1883b9b51feSCy Schubert 	ipn->in_apr = NULL;
1893b9b51feSCy Schubert 	ipn->in_use = 1;
1903b9b51feSCy Schubert 	ipn->in_hits = 1;
1913b9b51feSCy Schubert 	ipn->in_snip = ntohl(nat->nat_nsrcaddr);
1923b9b51feSCy Schubert 	ipn->in_ippip = 1;
1933b9b51feSCy Schubert 	ipn->in_osrcip = nat->nat_osrcip;
1943b9b51feSCy Schubert 	ipn->in_osrcmsk = 0xffffffff;
1953b9b51feSCy Schubert 	ipn->in_nsrcip = nat->nat_nsrcip;
1963b9b51feSCy Schubert 	ipn->in_nsrcmsk = 0xffffffff;
1973b9b51feSCy Schubert 	ipn->in_odstip = nat->nat_odstip;
1983b9b51feSCy Schubert 	ipn->in_odstmsk = 0xffffffff;
1993b9b51feSCy Schubert 	ipn->in_ndstip = nat->nat_ndstip;
2003b9b51feSCy Schubert 	ipn->in_ndstmsk = 0xffffffff;
2013b9b51feSCy Schubert 	ipn->in_redir = NAT_MAP;
2023b9b51feSCy Schubert 	ipn->in_pr[0] = IPPROTO_ESP;
2033b9b51feSCy Schubert 	ipn->in_pr[1] = IPPROTO_ESP;
2043b9b51feSCy Schubert 	ipn->in_flags = (np->in_flags | IPN_PROXYRULE);
2053b9b51feSCy Schubert 	MUTEX_INIT(&ipn->in_lock, "IPSec proxy NAT rule");
2063b9b51feSCy Schubert 
2073b9b51feSCy Schubert 	ipn->in_namelen = np->in_namelen;
2083b9b51feSCy Schubert 	bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
2093b9b51feSCy Schubert 	ipn->in_ifnames[0] = np->in_ifnames[0];
2103b9b51feSCy Schubert 	ipn->in_ifnames[1] = np->in_ifnames[1];
2113b9b51feSCy Schubert 
2123b9b51feSCy Schubert 	bcopy((char *)fin, (char *)&fi, sizeof(fi));
2133b9b51feSCy Schubert 	fi.fin_fi.fi_p = IPPROTO_ESP;
2143b9b51feSCy Schubert 	fi.fin_fr = &softi->ipsec_fr;
2153b9b51feSCy Schubert 	fi.fin_data[0] = 0;
2163b9b51feSCy Schubert 	fi.fin_data[1] = 0;
2173b9b51feSCy Schubert 	p = ip->ip_p;
2183b9b51feSCy Schubert 	ip->ip_p = IPPROTO_ESP;
2193b9b51feSCy Schubert 	fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
2203b9b51feSCy Schubert 	fi.fin_flx |= FI_IGNORE;
2213b9b51feSCy Schubert 
2223b9b51feSCy Schubert 	ptr = softi->ipsec_buffer;
2233b9b51feSCy Schubert 	bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
2243b9b51feSCy Schubert 	ptr += sizeof(ipsec_cookie_t);
2253b9b51feSCy Schubert 	bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
2263b9b51feSCy Schubert 	/*
2273b9b51feSCy Schubert 	 * The responder cookie should only be non-zero if the initiator
2283b9b51feSCy Schubert 	 * cookie is non-zero.  Therefore, it is safe to assume(!) that the
2293b9b51feSCy Schubert 	 * cookies are both set after copying if the responder is non-zero.
2303b9b51feSCy Schubert 	 */
2313b9b51feSCy Schubert 	if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
2323b9b51feSCy Schubert 		ipsec->ipsc_rckset = 1;
2333b9b51feSCy Schubert 
2343b9b51feSCy Schubert 	MUTEX_ENTER(&softn->ipf_nat_new);
2353b9b51feSCy Schubert 	ipsec->ipsc_nat = ipf_nat_add(&fi, ipn, &ipsec->ipsc_nat,
2363b9b51feSCy Schubert 				      NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
2373b9b51feSCy Schubert 	MUTEX_EXIT(&softn->ipf_nat_new);
2383b9b51feSCy Schubert 	if (ipsec->ipsc_nat != NULL) {
2393b9b51feSCy Schubert 		(void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
2403b9b51feSCy Schubert 		MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
2413b9b51feSCy Schubert 		ipf_nat_update(&fi, ipsec->ipsc_nat);
2423b9b51feSCy Schubert 		MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
2433b9b51feSCy Schubert 
2443b9b51feSCy Schubert 		fi.fin_data[0] = 0;
2453b9b51feSCy Schubert 		fi.fin_data[1] = 0;
2463b9b51feSCy Schubert 		(void) ipf_state_add(softc, &fi, &ipsec->ipsc_state, SI_WILDP);
2473b9b51feSCy Schubert 	}
2483b9b51feSCy Schubert 	ip->ip_p = p & 0xff;
2498c82b374SCy Schubert 	return (0);
2503b9b51feSCy Schubert }
2513b9b51feSCy Schubert 
2523b9b51feSCy Schubert 
2533b9b51feSCy Schubert /*
2543b9b51feSCy Schubert  * For outgoing IKE packets.  refresh timeouts for NAT & state entries, if
2553b9b51feSCy Schubert  * we can.  If they have disappeared, recreate them.
2563b9b51feSCy Schubert  */
2573b9b51feSCy Schubert int
ipf_p_ipsec_inout(void * arg,fr_info_t * fin,ap_session_t * aps,nat_t * nat)258064a5a95SCy Schubert ipf_p_ipsec_inout(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat)
2593b9b51feSCy Schubert {
2603b9b51feSCy Schubert 	ipf_ipsec_softc_t *softi = arg;
2613b9b51feSCy Schubert 	ipf_main_softc_t *softc = fin->fin_main_soft;
2623b9b51feSCy Schubert 	ipsec_pxy_t *ipsec;
2633b9b51feSCy Schubert 	fr_info_t fi;
2643b9b51feSCy Schubert 	ip_t *ip;
2653b9b51feSCy Schubert 	int p;
2663b9b51feSCy Schubert 
2673b9b51feSCy Schubert 	if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
2688c82b374SCy Schubert 		return (0);
2693b9b51feSCy Schubert 
2703b9b51feSCy Schubert 	if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
2718c82b374SCy Schubert 		return (0);
2723b9b51feSCy Schubert 
2733b9b51feSCy Schubert 	ipsec = aps->aps_data;
2743b9b51feSCy Schubert 
2753b9b51feSCy Schubert 	if (ipsec != NULL) {
2763b9b51feSCy Schubert 		ip = fin->fin_ip;
2773b9b51feSCy Schubert 		p = ip->ip_p;
2783b9b51feSCy Schubert 
2793b9b51feSCy Schubert 		if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
2803b9b51feSCy Schubert 			bcopy((char *)fin, (char *)&fi, sizeof(fi));
2813b9b51feSCy Schubert 			fi.fin_fi.fi_p = IPPROTO_ESP;
2823b9b51feSCy Schubert 			fi.fin_fr = &softi->ipsec_fr;
2833b9b51feSCy Schubert 			fi.fin_data[0] = 0;
2843b9b51feSCy Schubert 			fi.fin_data[1] = 0;
2853b9b51feSCy Schubert 			ip->ip_p = IPPROTO_ESP;
2863b9b51feSCy Schubert 			fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
2873b9b51feSCy Schubert 			fi.fin_flx |= FI_IGNORE;
2883b9b51feSCy Schubert 		}
2893b9b51feSCy Schubert 
2903b9b51feSCy Schubert 		/*
2913b9b51feSCy Schubert 		 * Update NAT timeout/create NAT if missing.
2923b9b51feSCy Schubert 		 */
2933b9b51feSCy Schubert 		if (ipsec->ipsc_nat != NULL)
2943b9b51feSCy Schubert 			ipf_queueback(softc->ipf_ticks,
2953b9b51feSCy Schubert 				      &ipsec->ipsc_nat->nat_tqe);
2963b9b51feSCy Schubert 		else {
2973b9b51feSCy Schubert #ifdef USE_MUTEXES
2983b9b51feSCy Schubert 			ipf_nat_softc_t *softn = softc->ipf_nat_soft;
2993b9b51feSCy Schubert #endif
3003b9b51feSCy Schubert 
3013b9b51feSCy Schubert 			MUTEX_ENTER(&softn->ipf_nat_new);
3023b9b51feSCy Schubert 			ipsec->ipsc_nat = ipf_nat_add(&fi, ipsec->ipsc_rule,
3033b9b51feSCy Schubert 						      &ipsec->ipsc_nat,
3043b9b51feSCy Schubert 						      NAT_SLAVE|SI_WILDP,
3053b9b51feSCy Schubert 						      nat->nat_dir);
3063b9b51feSCy Schubert 			MUTEX_EXIT(&softn->ipf_nat_new);
3073b9b51feSCy Schubert 			if (ipsec->ipsc_nat != NULL) {
3083b9b51feSCy Schubert 				(void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
3093b9b51feSCy Schubert 				MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
3103b9b51feSCy Schubert 				ipf_nat_update(&fi, ipsec->ipsc_nat);
3113b9b51feSCy Schubert 				MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
3123b9b51feSCy Schubert 			}
3133b9b51feSCy Schubert 		}
3143b9b51feSCy Schubert 
3153b9b51feSCy Schubert 		/*
3163b9b51feSCy Schubert 		 * Update state timeout/create state if missing.
3173b9b51feSCy Schubert 		 */
3183b9b51feSCy Schubert 		READ_ENTER(&softc->ipf_state);
3193b9b51feSCy Schubert 		if (ipsec->ipsc_state != NULL) {
3203b9b51feSCy Schubert 			ipf_queueback(softc->ipf_ticks,
3213b9b51feSCy Schubert 				      &ipsec->ipsc_state->is_sti);
3223b9b51feSCy Schubert 			ipsec->ipsc_state->is_die = nat->nat_age;
3233b9b51feSCy Schubert 			RWLOCK_EXIT(&softc->ipf_state);
3243b9b51feSCy Schubert 		} else {
3253b9b51feSCy Schubert 			RWLOCK_EXIT(&softc->ipf_state);
3263b9b51feSCy Schubert 			fi.fin_data[0] = 0;
3273b9b51feSCy Schubert 			fi.fin_data[1] = 0;
3283b9b51feSCy Schubert 			(void) ipf_state_add(softc, &fi, &ipsec->ipsc_state,
3293b9b51feSCy Schubert 					     SI_WILDP);
3303b9b51feSCy Schubert 		}
3313b9b51feSCy Schubert 		ip->ip_p = p;
3323b9b51feSCy Schubert 	}
3338c82b374SCy Schubert 	return (0);
3343b9b51feSCy Schubert }
3353b9b51feSCy Schubert 
3363b9b51feSCy Schubert 
3373b9b51feSCy Schubert /*
3383b9b51feSCy Schubert  * This extends the NAT matching to be based on the cookies associated with
3393b9b51feSCy Schubert  * a session and found at the front of IKE packets.  The cookies are always
3403b9b51feSCy Schubert  * in the same order (not reversed depending on packet flow direction as with
3413b9b51feSCy Schubert  * UDP/TCP port numbers).
3423b9b51feSCy Schubert  */
3433b9b51feSCy Schubert int
ipf_p_ipsec_match(fr_info_t * fin,ap_session_t * aps,nat_t * nat)344064a5a95SCy Schubert ipf_p_ipsec_match(fr_info_t *fin, ap_session_t *aps, nat_t *nat)
3453b9b51feSCy Schubert {
3463b9b51feSCy Schubert 	ipsec_pxy_t *ipsec;
3473b9b51feSCy Schubert 	u_32_t cookies[4];
3483b9b51feSCy Schubert 	mb_t *m;
3493b9b51feSCy Schubert 	int off;
3503b9b51feSCy Schubert 
3513b9b51feSCy Schubert 	nat = nat;	/* LINT */
3523b9b51feSCy Schubert 
3533b9b51feSCy Schubert 	if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
3548c82b374SCy Schubert 		return (-1);
3553b9b51feSCy Schubert 
3563b9b51feSCy Schubert 	off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
3573b9b51feSCy Schubert 	ipsec = aps->aps_data;
3583b9b51feSCy Schubert 	m = fin->fin_m;
3593b9b51feSCy Schubert 	COPYDATA(m, off, sizeof(cookies), (char *)cookies);
3603b9b51feSCy Schubert 
3613b9b51feSCy Schubert 	if ((cookies[0] != ipsec->ipsc_icookie[0]) ||
3623b9b51feSCy Schubert 	    (cookies[1] != ipsec->ipsc_icookie[1]))
3638c82b374SCy Schubert 		return (-1);
3643b9b51feSCy Schubert 
3653b9b51feSCy Schubert 	if (ipsec->ipsc_rckset == 0) {
3663b9b51feSCy Schubert 		if ((cookies[2]|cookies[3]) == 0) {
3678c82b374SCy Schubert 			return (0);
3683b9b51feSCy Schubert 		}
3693b9b51feSCy Schubert 		ipsec->ipsc_rckset = 1;
3703b9b51feSCy Schubert 		ipsec->ipsc_rcookie[0] = cookies[2];
3713b9b51feSCy Schubert 		ipsec->ipsc_rcookie[1] = cookies[3];
3728c82b374SCy Schubert 		return (0);
3733b9b51feSCy Schubert 	}
3743b9b51feSCy Schubert 
3753b9b51feSCy Schubert 	if ((cookies[2] != ipsec->ipsc_rcookie[0]) ||
3763b9b51feSCy Schubert 	    (cookies[3] != ipsec->ipsc_rcookie[1]))
3778c82b374SCy Schubert 		return (-1);
3788c82b374SCy Schubert 	return (0);
3793b9b51feSCy Schubert }
3803b9b51feSCy Schubert 
3813b9b51feSCy Schubert 
3823b9b51feSCy Schubert /*
3833b9b51feSCy Schubert  * clean up after ourselves.
3843b9b51feSCy Schubert  */
3853b9b51feSCy Schubert void
ipf_p_ipsec_del(ipf_main_softc_t * softc,ap_session_t * aps)386064a5a95SCy Schubert ipf_p_ipsec_del(ipf_main_softc_t *softc, ap_session_t *aps)
3873b9b51feSCy Schubert {
3883b9b51feSCy Schubert 	ipsec_pxy_t *ipsec;
3893b9b51feSCy Schubert 
3903b9b51feSCy Schubert 	ipsec = aps->aps_data;
3913b9b51feSCy Schubert 
3923b9b51feSCy Schubert 	if (ipsec != NULL) {
3933b9b51feSCy Schubert 		/*
3943b9b51feSCy Schubert 		 * Don't bother changing any of the NAT structure details,
3953b9b51feSCy Schubert 		 * *_del() is on a callback from aps_free(), from nat_delete()
3963b9b51feSCy Schubert 		 */
3973b9b51feSCy Schubert 
3983b9b51feSCy Schubert 		READ_ENTER(&softc->ipf_state);
3993b9b51feSCy Schubert 		if (ipsec->ipsc_state != NULL) {
4003b9b51feSCy Schubert 			ipsec->ipsc_state->is_die = softc->ipf_ticks + 1;
4013b9b51feSCy Schubert 			ipsec->ipsc_state->is_me = NULL;
4023b9b51feSCy Schubert 			ipf_queuefront(&ipsec->ipsc_state->is_sti);
4033b9b51feSCy Schubert 		}
4043b9b51feSCy Schubert 		RWLOCK_EXIT(&softc->ipf_state);
4053b9b51feSCy Schubert 
4063b9b51feSCy Schubert 		ipsec->ipsc_state = NULL;
4073b9b51feSCy Schubert 		ipsec->ipsc_nat = NULL;
4083b9b51feSCy Schubert 		ipsec->ipsc_rule->in_flags |= IPN_DELETE;
4093b9b51feSCy Schubert 		ipf_nat_rule_deref(softc, &ipsec->ipsc_rule);
4103b9b51feSCy Schubert 	}
4113b9b51feSCy Schubert }
412