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