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/netipsec/subr_ipsec.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) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include "opt_inet.h"
   28 #include "opt_inet6.h"
   29 #include "opt_ipsec.h"
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/12.0/sys/netipsec/subr_ipsec.c 338945 2018-09-26 14:47:51Z ae $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/lock.h>
   38 #include <sys/malloc.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/module.h>
   41 #include <sys/priv.h>
   42 #include <sys/socket.h>
   43 #include <sys/sockopt.h>
   44 #include <sys/syslog.h>
   45 #include <sys/proc.h>
   46 
   47 #include <netinet/in.h>
   48 #include <netinet/in_pcb.h>
   49 #include <netinet/ip.h>
   50 #include <netinet/ip6.h>
   51 
   52 #include <netipsec/ipsec_support.h>
   53 #include <netipsec/ipsec.h>
   54 #include <netipsec/ipsec6.h>
   55 #include <netipsec/key.h>
   56 #include <netipsec/key_debug.h>
   57 #include <netipsec/xform.h>
   58 
   59 #include <machine/atomic.h>
   60 /*
   61  * This file is build in the kernel only when 'options IPSEC' or
   62  * 'options IPSEC_SUPPORT' is enabled.
   63  */
   64 
   65 #ifdef INET
   66 void
   67 ipsec4_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
   68     union sockaddr_union *dst)
   69 {
   70         static const struct sockaddr_in template = {
   71                 sizeof (struct sockaddr_in),
   72                 AF_INET,
   73                 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
   74         };
   75 
   76         src->sin = template;
   77         dst->sin = template;
   78 
   79         if (m->m_len < sizeof (struct ip)) {
   80                 m_copydata(m, offsetof(struct ip, ip_src),
   81                            sizeof (struct  in_addr),
   82                            (caddr_t) &src->sin.sin_addr);
   83                 m_copydata(m, offsetof(struct ip, ip_dst),
   84                            sizeof (struct  in_addr),
   85                            (caddr_t) &dst->sin.sin_addr);
   86         } else {
   87                 const struct ip *ip = mtod(m, const struct ip *);
   88                 src->sin.sin_addr = ip->ip_src;
   89                 dst->sin.sin_addr = ip->ip_dst;
   90         }
   91 }
   92 #endif
   93 #ifdef INET6
   94 void
   95 ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
   96     union sockaddr_union *dst)
   97 {
   98         struct ip6_hdr ip6buf;
   99         const struct ip6_hdr *ip6;
  100 
  101         if (m->m_len >= sizeof(*ip6))
  102                 ip6 = mtod(m, const struct ip6_hdr *);
  103         else {
  104                 m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
  105                 ip6 = &ip6buf;
  106         }
  107 
  108         bzero(&src->sin6, sizeof(struct sockaddr_in6));
  109         src->sin6.sin6_family = AF_INET6;
  110         src->sin6.sin6_len = sizeof(struct sockaddr_in6);
  111         bcopy(&ip6->ip6_src, &src->sin6.sin6_addr, sizeof(ip6->ip6_src));
  112         if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
  113                 src->sin6.sin6_addr.s6_addr16[1] = 0;
  114                 src->sin6.sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
  115         }
  116 
  117         bzero(&dst->sin6, sizeof(struct sockaddr_in6));
  118         dst->sin6.sin6_family = AF_INET6;
  119         dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
  120         bcopy(&ip6->ip6_dst, &dst->sin6.sin6_addr, sizeof(ip6->ip6_dst));
  121         if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
  122                 dst->sin6.sin6_addr.s6_addr16[1] = 0;
  123                 dst->sin6.sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
  124         }
  125 }
  126 #endif
  127 
  128 #define IPSEC_MODULE_INCR       2
  129 static int
  130 ipsec_kmod_enter(volatile u_int *cntr)
  131 {
  132         u_int old, new;
  133 
  134         do {
  135                 old = *cntr;
  136                 if ((old & IPSEC_MODULE_ENABLED) == 0)
  137                         return (ENXIO);
  138                 new = old + IPSEC_MODULE_INCR;
  139         } while(atomic_cmpset_acq_int(cntr, old, new) == 0);
  140         return (0);
  141 }
  142 
  143 static void
  144 ipsec_kmod_exit(volatile u_int *cntr)
  145 {
  146         u_int old, new;
  147 
  148         do {
  149                 old = *cntr;
  150                 new = old - IPSEC_MODULE_INCR;
  151         } while (atomic_cmpset_rel_int(cntr, old, new) == 0);
  152 }
  153 
  154 static void
  155 ipsec_kmod_drain(volatile u_int *cntr)
  156 {
  157         u_int old, new;
  158 
  159         do {
  160                 old = *cntr;
  161                 new = old & ~IPSEC_MODULE_ENABLED;
  162         } while (atomic_cmpset_acq_int(cntr, old, new) == 0);
  163         while (atomic_cmpset_int(cntr, 0, 0) == 0)
  164                 pause("ipsecd", hz/2);
  165 }
  166 
  167 static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER();
  168 static struct mtx xforms_lock;
  169 MTX_SYSINIT(xfroms_list, &xforms_lock, "IPsec transforms list", MTX_DEF);
  170 #define XFORMS_LOCK()           mtx_lock(&xforms_lock)
  171 #define XFORMS_UNLOCK()         mtx_unlock(&xforms_lock)
  172 
  173 void
  174 xform_attach(void *data)
  175 {
  176         struct xformsw *xsp, *entry;
  177 
  178         xsp = (struct xformsw *)data;
  179         XFORMS_LOCK();
  180         LIST_FOREACH(entry, &xforms, chain) {
  181                 if (entry->xf_type == xsp->xf_type) {
  182                         XFORMS_UNLOCK();
  183                         printf("%s: failed to register %s xform\n",
  184                             __func__, xsp->xf_name);
  185                         return;
  186                 }
  187         }
  188         LIST_INSERT_HEAD(&xforms, xsp, chain);
  189         xsp->xf_cntr = IPSEC_MODULE_ENABLED;
  190         XFORMS_UNLOCK();
  191 }
  192 
  193 void
  194 xform_detach(void *data)
  195 {
  196         struct xformsw *xsp = (struct xformsw *)data;
  197 
  198         XFORMS_LOCK();
  199         LIST_REMOVE(xsp, chain);
  200         XFORMS_UNLOCK();
  201 
  202         /* Delete all SAs related to this xform. */
  203         key_delete_xform(xsp);
  204         if (xsp->xf_cntr & IPSEC_MODULE_ENABLED)
  205                 ipsec_kmod_drain(&xsp->xf_cntr);
  206 }
  207 
  208 /*
  209  * Initialize transform support in an sav.
  210  */
  211 int
  212 xform_init(struct secasvar *sav, u_short xftype)
  213 {
  214         struct xformsw *entry;
  215         int ret;
  216 
  217         IPSEC_ASSERT(sav->tdb_xform == NULL,
  218             ("tdb_xform is already initialized"));
  219 
  220         XFORMS_LOCK();
  221         LIST_FOREACH(entry, &xforms, chain) {
  222                 if (entry->xf_type == xftype) {
  223                         ret = ipsec_kmod_enter(&entry->xf_cntr);
  224                         XFORMS_UNLOCK();
  225                         if (ret != 0)
  226                                 return (ret);
  227                         ret = (*entry->xf_init)(sav, entry);
  228                         ipsec_kmod_exit(&entry->xf_cntr);
  229                         return (ret);
  230                 }
  231         }
  232         XFORMS_UNLOCK();
  233         return (EINVAL);
  234 }
  235 
  236 #ifdef IPSEC_SUPPORT
  237 /*
  238  * IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
  239  * IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
  240  * IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
  241  *   IPSEC_SUPPORT.
  242  */
  243 #if !defined(IPSEC) || !defined(TCP_SIGNATURE)
  244 #define METHOD_DECL(...)        __VA_ARGS__
  245 #define METHOD_ARGS(...)        __VA_ARGS__
  246 #define IPSEC_KMOD_METHOD(type, name, sc, method, decl, args)           \
  247 type name (decl)                                                        \
  248 {                                                                       \
  249         type ret = (type)ipsec_kmod_enter(&sc->enabled);                \
  250         if (ret == 0) {                                                 \
  251                 ret = (*sc->methods->method)(args);                     \
  252                 ipsec_kmod_exit(&sc->enabled);                          \
  253         }                                                               \
  254         return (ret);                                                   \
  255 }
  256 
  257 static int
  258 ipsec_support_modevent(module_t mod, int type, void *data)
  259 {
  260 
  261         switch (type) {
  262         case MOD_LOAD:
  263                 return (0);
  264         case MOD_UNLOAD:
  265                 return (EBUSY);
  266         default:
  267                 return (EOPNOTSUPP);
  268         }
  269 }
  270 
  271 static moduledata_t ipsec_support_mod = {
  272         "ipsec_support",
  273         ipsec_support_modevent,
  274         0
  275 };
  276 DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN,
  277     SI_ORDER_ANY);
  278 MODULE_VERSION(ipsec_support, 1);
  279 #endif /* !IPSEC || !TCP_SIGNATURE */
  280 
  281 #ifndef TCP_SIGNATURE
  282 /* Declare TCP-MD5 support as kernel module. */
  283 static struct tcpmd5_support tcpmd5_ipsec = {
  284         .enabled = 0,
  285         .methods = NULL
  286 };
  287 struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
  288 
  289 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_input, sc,
  290     input, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
  291         struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
  292 )
  293 
  294 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_output, sc,
  295     output, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
  296         struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
  297 )
  298 
  299 IPSEC_KMOD_METHOD(int, tcpmd5_kmod_pcbctl, sc,
  300     pcbctl, METHOD_DECL(struct tcpmd5_support * const sc, struct inpcb *inp,
  301         struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  302 )
  303 
  304 void
  305 tcpmd5_support_enable(const struct tcpmd5_methods * const methods)
  306 {
  307 
  308         KASSERT(tcp_ipsec_support->enabled == 0, ("TCP-MD5 already enabled"));
  309         tcp_ipsec_support->methods = methods;
  310         tcp_ipsec_support->enabled |= IPSEC_MODULE_ENABLED;
  311 }
  312 
  313 void
  314 tcpmd5_support_disable(void)
  315 {
  316 
  317         if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) {
  318                 ipsec_kmod_drain(&tcp_ipsec_support->enabled);
  319                 tcp_ipsec_support->methods = NULL;
  320         }
  321 }
  322 #endif /* !TCP_SIGNATURE */
  323 
  324 #ifndef IPSEC
  325 /*
  326  * IPsec support is build as kernel module.
  327  */
  328 #ifdef INET
  329 static struct ipsec_support ipv4_ipsec = {
  330         .enabled = 0,
  331         .methods = NULL
  332 };
  333 struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec;
  334 
  335 IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_input, sc,
  336     udp_input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  337         int off, int af), METHOD_ARGS(m, off, af)
  338 )
  339 
  340 IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_pcbctl, sc,
  341     udp_pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
  342         struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  343 )
  344 #endif
  345 
  346 #ifdef INET6
  347 static struct ipsec_support ipv6_ipsec = {
  348         .enabled = 0,
  349         .methods = NULL
  350 };
  351 struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec;
  352 #endif
  353 
  354 IPSEC_KMOD_METHOD(int, ipsec_kmod_input, sc,
  355     input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  356         int offset, int proto), METHOD_ARGS(m, offset, proto)
  357 )
  358 
  359 IPSEC_KMOD_METHOD(int, ipsec_kmod_check_policy, sc,
  360     check_policy, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  361         struct inpcb *inp), METHOD_ARGS(m, inp)
  362 )
  363 
  364 IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc,
  365     forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m),
  366     (m)
  367 )
  368 
  369 IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc,
  370     output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  371         struct inpcb *inp), METHOD_ARGS(m, inp)
  372 )
  373 
  374 IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
  375     pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
  376         struct sockopt *sopt), METHOD_ARGS(inp, sopt)
  377 )
  378 
  379 IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
  380     hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
  381     (inp)
  382 )
  383 
  384 static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
  385     capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
  386         u_int cap), METHOD_ARGS(m, cap)
  387 )
  388 
  389 int
  390 ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
  391     u_int cap)
  392 {
  393 
  394         /*
  395          * Since PF_KEY is build in the kernel, we can directly
  396          * call key_havesp() without additional synchronizations.
  397          */
  398         if (cap == IPSEC_CAP_OPERABLE)
  399                 return (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
  400                     key_havesp(IPSEC_DIR_OUTBOUND) != 0);
  401         return (ipsec_kmod_caps(sc, m, cap));
  402 }
  403 
  404 void
  405 ipsec_support_enable(struct ipsec_support * const sc,
  406     const struct ipsec_methods * const methods)
  407 {
  408 
  409         KASSERT(sc->enabled == 0, ("IPsec already enabled"));
  410         sc->methods = methods;
  411         sc->enabled |= IPSEC_MODULE_ENABLED;
  412 }
  413 
  414 void
  415 ipsec_support_disable(struct ipsec_support * const sc)
  416 {
  417 
  418         if (sc->enabled & IPSEC_MODULE_ENABLED) {
  419                 ipsec_kmod_drain(&sc->enabled);
  420                 sc->methods = NULL;
  421         }
  422 }
  423 #endif /* !IPSEC */
  424 #endif /* IPSEC_SUPPORT */

Cache object: fe31a3edefaf9237cc5f7c0e6747883e


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