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/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 /*      $NetBSD: ip_ipsec_pxy.c,v 1.3.2.1 2004/08/13 03:55:25 jmc Exp $ */
    2 
    3 /*
    4  * Copyright (C) 2001-2003 by Darren Reed
    5  *
    6  * See the IPFILTER.LICENCE file for details on licencing.
    7  *
    8  * Simple ISAKMP transparent proxy for in-kernel use.  For use with the NAT
    9  * code.
   10  *
   11  * Id: ip_ipsec_pxy.c,v 2.20.2.3 2004/06/07 14:20:05 darrenr Exp
   12  *
   13  */
   14 
   15 __KERNEL_RCSID(1, "$NetBSD: ip_ipsec_pxy.c,v 1.3.2.1 2004/08/13 03:55:25 jmc Exp $");
   16 
   17 #define IPF_IPSEC_PROXY
   18 
   19 
   20 int ippr_ipsec_init __P((void));
   21 void ippr_ipsec_fini __P((void));
   22 int ippr_ipsec_new __P((fr_info_t *, ap_session_t *, nat_t *));
   23 void ippr_ipsec_del __P((ap_session_t *));
   24 int ippr_ipsec_inout __P((fr_info_t *, ap_session_t *, nat_t *));
   25 int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *));
   26 
   27 static  frentry_t       ipsecfr;
   28 static  ipftq_t         *ipsecnattqe;
   29 static  ipftq_t         *ipsecstatetqe;
   30 static  char    ipsec_buffer[1500];
   31 
   32 int     ipsec_proxy_init = 0;
   33 
   34 /*
   35  * IPSec application proxy initialization.
   36  */
   37 int ippr_ipsec_init()
   38 {
   39         bzero((char *)&ipsecfr, sizeof(ipsecfr));
   40         ipsecfr.fr_ref = 1;
   41         ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
   42         MUTEX_INIT(&ipsecfr.fr_lock, "IPsec proxy rule lock");
   43         ipsec_proxy_init = 1;
   44 
   45         ipsecnattqe = fr_addtimeoutqueue(&nat_utqe, 60);
   46         if (ipsecnattqe == NULL)
   47                 return -1;
   48         ipsecstatetqe = fr_addtimeoutqueue(&ips_utqe, 60);
   49         if (ipsecstatetqe == NULL) {
   50                 fr_deletetimeoutqueue(ipsecnattqe);
   51                 ipsecnattqe = NULL;
   52                 return -1;
   53         }
   54         ipsecfr.fr_age[0] = 60;
   55         ipsecfr.fr_age[1] = 60;
   56         return 0;
   57 }
   58 
   59 
   60 void ippr_ipsec_fini()
   61 {
   62         if (ipsecnattqe != NULL)
   63                 fr_deletetimeoutqueue(ipsecnattqe);
   64         ipsecnattqe = NULL;
   65         if (ipsecstatetqe != NULL)
   66                 fr_deletetimeoutqueue(ipsecstatetqe);
   67         ipsecstatetqe = NULL;
   68 
   69         if (ipsec_proxy_init == 1) {
   70                 MUTEX_DESTROY(&ipsecfr.fr_lock);
   71                 ipsec_proxy_init = 0;
   72         }
   73 }
   74 
   75 
   76 /*
   77  * Setup for a new IPSEC proxy.
   78  */
   79 int ippr_ipsec_new(fin, aps, nat)
   80 fr_info_t *fin;
   81 ap_session_t *aps;
   82 nat_t *nat;
   83 {
   84         ipsec_pxy_t *ipsec;
   85         fr_info_t fi;
   86         ipnat_t *ipn;
   87         char *ptr;
   88         int p, off, dlen, ttl;
   89         mb_t *m;
   90         ip_t *ip;
   91 
   92         bzero(ipsec_buffer, sizeof(ipsec_buffer));
   93         off = fin->fin_hlen + sizeof(udphdr_t);
   94         ip = fin->fin_ip;
   95         m = fin->fin_m;
   96 
   97         dlen = M_LEN(m) - off;
   98         if (dlen < 16)
   99                 return -1;
  100         COPYDATA(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer);
  101 
  102         if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip,
  103                           ip->ip_dst) != NULL)
  104                 return -1;
  105 
  106         aps->aps_psiz = sizeof(*ipsec);
  107         KMALLOCS(aps->aps_data, ipsec_pxy_t *, sizeof(*ipsec));
  108         if (aps->aps_data == NULL)
  109                 return -1;
  110 
  111         ipsec = aps->aps_data;
  112         bzero((char *)ipsec, sizeof(*ipsec));
  113 
  114         /*
  115          * Create NAT rule against which the tunnel/transport mapping is
  116          * created.  This is required because the current NAT rule does not
  117          * describe ESP but UDP instead.
  118          */
  119         ipn = &ipsec->ipsc_rule;
  120         ttl = IPF_TTLVAL(ipsecnattqe->ifq_ttl);
  121         ipn->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, ttl);
  122         ipn->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, ttl);
  123         ipn->in_ifps[0] = fin->fin_ifp;
  124         ipn->in_apr = NULL;
  125         ipn->in_use = 1;
  126         ipn->in_hits = 1;
  127         ipn->in_nip = ntohl(nat->nat_outip.s_addr);
  128         ipn->in_ippip = 1;
  129         ipn->in_inip = nat->nat_inip.s_addr;
  130         ipn->in_inmsk = 0xffffffff;
  131         ipn->in_outip = fin->fin_saddr;
  132         ipn->in_outmsk = nat->nat_outip.s_addr;
  133         ipn->in_srcip = fin->fin_saddr;
  134         ipn->in_srcmsk = 0xffffffff;
  135         ipn->in_redir = NAT_MAP;
  136         bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
  137               sizeof(ipn->in_ifnames[0]));
  138         ipn->in_p = IPPROTO_ESP;
  139 
  140         bcopy((char *)fin, (char *)&fi, sizeof(fi));
  141         fi.fin_fi.fi_p = IPPROTO_ESP;
  142         fi.fin_fr = &ipsecfr;
  143         fi.fin_data[0] = 0;
  144         fi.fin_data[1] = 0;
  145         p = ip->ip_p;
  146         ip->ip_p = IPPROTO_ESP;
  147         fi.fin_flx &= ~FI_TCPUDP;
  148         fi.fin_flx |= FI_IGNORE;
  149 
  150         ptr = ipsec_buffer;
  151         bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
  152         ptr += sizeof(ipsec_cookie_t);
  153         bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
  154         /*
  155          * The responder cookie should only be non-zero if the initiator
  156          * cookie is non-zero.  Therefore, it is safe to assume(!) that the
  157          * cookies are both set after copying if the responder is non-zero.
  158          */
  159         if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
  160                 ipsec->ipsc_rckset = 1;
  161 
  162         ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat,
  163                                   NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
  164         if (ipsec->ipsc_nat != NULL) {
  165                 (void) nat_proto(&fi, ipsec->ipsc_nat, 0);
  166                 nat_update(&fi, ipsec->ipsc_nat, ipn);
  167 
  168                 fi.fin_data[0] = 0;
  169                 fi.fin_data[1] = 0;
  170                 ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state,
  171                                                 SI_WILDP);
  172         }
  173         ip->ip_p = p & 0xff;
  174         return 0;
  175 }
  176 
  177 
  178 /*
  179  * For outgoing IKE packets.  refresh timeouts for NAT & state entries, if
  180  * we can.  If they have disappeared, recreate them.
  181  */
  182 int ippr_ipsec_inout(fin, aps, nat)
  183 fr_info_t *fin;
  184 ap_session_t *aps;
  185 nat_t *nat;
  186 {
  187         ipsec_pxy_t *ipsec;
  188         fr_info_t fi;
  189         ip_t *ip;
  190         int p;
  191 
  192         if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
  193                 return 0;
  194 
  195         if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
  196                 return 0;
  197 
  198         ipsec = aps->aps_data;
  199 
  200         if (ipsec != NULL) {
  201                 ip = fin->fin_ip;
  202                 p = ip->ip_p;
  203 
  204                 if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
  205                         bcopy((char *)fin, (char *)&fi, sizeof(fi));
  206                         fi.fin_fi.fi_p = IPPROTO_ESP;
  207                         fi.fin_fr = &ipsecfr;
  208                         fi.fin_data[0] = 0;
  209                         fi.fin_data[1] = 0;
  210                         ip->ip_p = IPPROTO_ESP;
  211                         fi.fin_flx &= ~FI_TCPUDP;
  212                         fi.fin_flx |= FI_IGNORE;
  213                 }
  214 
  215                 /*
  216                  * Update NAT timeout/create NAT if missing.
  217                  */
  218                 if (ipsec->ipsc_nat != NULL)
  219                         fr_queueback(&ipsec->ipsc_nat->nat_tqe);
  220                 else {
  221                         ipsec->ipsc_nat = nat_new(&fi, &ipsec->ipsc_rule,
  222                                                   &ipsec->ipsc_nat,
  223                                                   NAT_SLAVE|SI_WILDP,
  224                                                   nat->nat_dir);
  225                         if (ipsec->ipsc_nat != NULL) {
  226                                 (void) nat_proto(&fi, ipsec->ipsc_nat, 0);
  227                                 nat_update(&fi, ipsec->ipsc_nat,
  228                                            &ipsec->ipsc_rule);
  229                         }
  230                 }
  231 
  232                 /*
  233                  * Update state timeout/create state if missing.
  234                  */
  235                 READ_ENTER(&ipf_state);
  236                 if (ipsec->ipsc_state != NULL) {
  237                         fr_queueback(&ipsec->ipsc_state->is_sti);
  238                         ipsec->ipsc_state->is_die = nat->nat_age;
  239                         RWLOCK_EXIT(&ipf_state);
  240                 } else {
  241                         RWLOCK_EXIT(&ipf_state);
  242                         fi.fin_data[0] = 0;
  243                         fi.fin_data[1] = 0;
  244                         ipsec->ipsc_state = fr_addstate(&fi,
  245                                                         &ipsec->ipsc_state,
  246                                                         SI_WILDP);
  247                 }
  248                 ip->ip_p = p;
  249         }
  250         return 0;
  251 }
  252 
  253 
  254 /*
  255  * This extends the NAT matching to be based on the cookies associated with
  256  * a session and found at the front of IKE packets.  The cookies are always
  257  * in the same order (not reversed depending on packet flow direction as with
  258  * UDP/TCP port numbers).
  259  */
  260 int ippr_ipsec_match(fin, aps, nat)
  261 fr_info_t *fin;
  262 ap_session_t *aps;
  263 nat_t *nat;
  264 {
  265         ipsec_pxy_t *ipsec;
  266         u_32_t cookies[4];
  267         mb_t *m;
  268         int off;
  269 
  270         nat = nat;      /* LINT */
  271 
  272         if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG))
  273                 return -1;
  274 
  275         ipsec = aps->aps_data;
  276         off = fin->fin_hlen + sizeof(udphdr_t);
  277         m = fin->fin_m;
  278         COPYDATA(m, off, sizeof(cookies), (char *)cookies);
  279 
  280         if ((cookies[0] != ipsec->ipsc_icookie[0]) ||
  281             (cookies[1] != ipsec->ipsc_icookie[1]))
  282                 return -1;
  283 
  284         if (ipsec->ipsc_rckset == 0) {
  285                 if ((cookies[2]|cookies[3]) == 0) {
  286                         return 0;
  287                 }
  288                 ipsec->ipsc_rckset = 1;
  289                 ipsec->ipsc_rcookie[0] = cookies[2];
  290                 ipsec->ipsc_rcookie[1] = cookies[3];
  291                 return 0;
  292         }
  293 
  294         if ((cookies[2] != ipsec->ipsc_rcookie[0]) ||
  295             (cookies[3] != ipsec->ipsc_rcookie[1]))
  296                 return -1;
  297         return 0;
  298 }
  299 
  300 
  301 /*
  302  * clean up after ourselves.
  303  */
  304 void ippr_ipsec_del(aps)
  305 ap_session_t *aps;
  306 {
  307         ipsec_pxy_t *ipsec;
  308 
  309         ipsec = aps->aps_data;
  310 
  311         if (ipsec != NULL) {
  312                 /*
  313                  * Don't bother changing any of the NAT structure details,
  314                  * *_del() is on a callback from aps_free(), from nat_delete()
  315                  */
  316 
  317                 READ_ENTER(&ipf_state);
  318                 if (ipsec->ipsc_state != NULL) {
  319                         ipsec->ipsc_state->is_die = fr_ticks + 1;
  320                         ipsec->ipsc_state->is_me = NULL;
  321                         fr_queuefront(&ipsec->ipsc_state->is_sti);
  322                 }
  323                 RWLOCK_EXIT(&ipf_state);
  324 
  325                 ipsec->ipsc_state = NULL;
  326                 ipsec->ipsc_nat = NULL;
  327         }
  328 }

Cache object: d184e8e0d58aa3a8a21c6a3f77bbe38a


[ 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.