The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfilter/netinet/ip_ipsec_pxy.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 7274e55ad2979088b1bc7b8aead7e013


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.