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/ipsec_output.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) 2002, 2003 Sam Leffler, Errno Consulting
    3  * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    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 AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD: releng/11.2/sys/netipsec/ipsec_output.c 322966 2017-08-28 10:02:47Z ae $
   28  */
   29 
   30 /*
   31  * IPsec output processing.
   32  */
   33 #include "opt_inet.h"
   34 #include "opt_inet6.h"
   35 #include "opt_ipsec.h"
   36 #include "opt_sctp.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/mbuf.h>
   41 #include <sys/domain.h>
   42 #include <sys/protosw.h>
   43 #include <sys/socket.h>
   44 #include <sys/errno.h>
   45 #include <sys/hhook.h>
   46 #include <sys/syslog.h>
   47 
   48 #include <net/if.h>
   49 #include <net/if_enc.h>
   50 #include <net/if_var.h>
   51 #include <net/vnet.h>
   52 
   53 #include <netinet/in.h>
   54 #include <netinet/in_systm.h>
   55 #include <netinet/ip.h>
   56 #include <netinet/ip_var.h>
   57 #include <netinet/in_var.h>
   58 #include <netinet/ip_ecn.h>
   59 #ifdef INET6
   60 #include <netinet6/ip6_ecn.h>
   61 #endif
   62 
   63 #include <netinet/ip6.h>
   64 #ifdef INET6
   65 #include <netinet6/ip6_var.h>
   66 #include <netinet6/scope6_var.h>
   67 #endif
   68 #include <netinet/in_pcb.h>
   69 #ifdef INET6
   70 #include <netinet/icmp6.h>
   71 #endif
   72 #ifdef SCTP
   73 #include <netinet/sctp_crc32.h>
   74 #endif
   75 
   76 #include <netinet/udp.h>
   77 #include <netipsec/ah.h>
   78 #include <netipsec/esp.h>
   79 #include <netipsec/ipsec.h>
   80 #ifdef INET6
   81 #include <netipsec/ipsec6.h>
   82 #endif
   83 #include <netipsec/ah_var.h>
   84 #include <netipsec/esp_var.h>
   85 #include <netipsec/ipcomp_var.h>
   86 
   87 #include <netipsec/xform.h>
   88 
   89 #include <netipsec/key.h>
   90 #include <netipsec/keydb.h>
   91 #include <netipsec/key_debug.h>
   92 
   93 #include <machine/in_cksum.h>
   94 
   95 #define IPSEC_OSTAT_INC(proto, name)    do {            \
   96         if ((proto) == IPPROTO_ESP)     \
   97                 ESPSTAT_INC(esps_##name);       \
   98         else if ((proto) == IPPROTO_AH)\
   99                 AHSTAT_INC(ahs_##name);         \
  100         else                                    \
  101                 IPCOMPSTAT_INC(ipcomps_##name); \
  102 } while (0)
  103 
  104 static int ipsec_encap(struct mbuf **mp, struct secasindex *saidx);
  105 
  106 #ifdef INET
  107 static struct secasvar *
  108 ipsec4_allocsa(struct mbuf *m, struct secpolicy *sp, u_int *pidx, int *error)
  109 {
  110         struct secasindex *saidx, tmpsaidx;
  111         struct ipsecrequest *isr;
  112         struct sockaddr_in *sin;
  113         struct secasvar *sav;
  114         struct ip *ip;
  115 
  116         /*
  117          * Check system global policy controls.
  118          */
  119 next:
  120         isr = sp->req[*pidx];
  121         if ((isr->saidx.proto == IPPROTO_ESP && !V_esp_enable) ||
  122             (isr->saidx.proto == IPPROTO_AH && !V_ah_enable) ||
  123             (isr->saidx.proto == IPPROTO_IPCOMP && !V_ipcomp_enable)) {
  124                 DPRINTF(("%s: IPsec outbound packet dropped due"
  125                         " to policy (check your sysctls)\n", __func__));
  126                 IPSEC_OSTAT_INC(isr->saidx.proto, pdrops);
  127                 *error = EHOSTUNREACH;
  128                 return (NULL);
  129         }
  130         /*
  131          * Craft SA index to search for proper SA.  Note that
  132          * we only initialize unspecified SA peers for transport
  133          * mode; for tunnel mode they must already be filled in.
  134          */
  135         if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
  136                 saidx = &tmpsaidx;
  137                 *saidx = isr->saidx;
  138                 ip = mtod(m, struct ip *);
  139                 if (saidx->src.sa.sa_len == 0) {
  140                         sin = &saidx->src.sin;
  141                         sin->sin_len = sizeof(*sin);
  142                         sin->sin_family = AF_INET;
  143                         sin->sin_port = IPSEC_PORT_ANY;
  144                         sin->sin_addr = ip->ip_src;
  145                 }
  146                 if (saidx->dst.sa.sa_len == 0) {
  147                         sin = &saidx->dst.sin;
  148                         sin->sin_len = sizeof(*sin);
  149                         sin->sin_family = AF_INET;
  150                         sin->sin_port = IPSEC_PORT_ANY;
  151                         sin->sin_addr = ip->ip_dst;
  152                 }
  153         } else
  154                 saidx = &sp->req[*pidx]->saidx;
  155         /*
  156          * Lookup SA and validate it.
  157          */
  158         sav = key_allocsa_policy(sp, saidx, error);
  159         if (sav == NULL) {
  160                 IPSECSTAT_INC(ips_out_nosa);
  161                 if (*error != 0)
  162                         return (NULL);
  163                 if (ipsec_get_reqlevel(sp, *pidx) != IPSEC_LEVEL_REQUIRE) {
  164                         /*
  165                          * We have no SA and policy that doesn't require
  166                          * this IPsec transform, thus we can continue w/o
  167                          * IPsec processing, i.e. return EJUSTRETURN.
  168                          * But first check if there is some bundled transform.
  169                          */
  170                         if (sp->tcount > ++(*pidx))
  171                                 goto next;
  172                         *error = EJUSTRETURN;
  173                 }
  174                 return (NULL);
  175         }
  176         IPSEC_ASSERT(sav->tdb_xform != NULL, ("SA with NULL tdb_xform"));
  177         return (sav);
  178 }
  179 
  180 /*
  181  * IPsec output logic for IPv4.
  182  */
  183 static int
  184 ipsec4_perform_request(struct mbuf *m, struct secpolicy *sp,
  185     struct inpcb *inp, u_int idx)
  186 {
  187         struct ipsec_ctx_data ctx;
  188         union sockaddr_union *dst;
  189         struct secasvar *sav;
  190         struct ip *ip;
  191         int error, i, off;
  192 
  193         IPSEC_ASSERT(idx < sp->tcount, ("Wrong IPsec request index %d", idx));
  194 
  195         /*
  196          * We hold the reference to SP. Content of SP couldn't be changed.
  197          * Craft secasindex and do lookup for suitable SA.
  198          * Then do encapsulation if needed and call xform's output.
  199          * We need to store SP in the xform callback parameters.
  200          * In xform callback we will extract SP and it can be used to
  201          * determine next transform. At the end of transform we can
  202          * release reference to SP.
  203          */
  204         sav = ipsec4_allocsa(m, sp, &idx, &error);
  205         if (sav == NULL) {
  206                 if (error == EJUSTRETURN) { /* No IPsec required */
  207                         key_freesp(&sp);
  208                         return (error);
  209                 }
  210                 goto bad;
  211         }
  212         /*
  213          * XXXAE: most likely ip_sum at this point is wrong.
  214          */
  215         IPSEC_INIT_CTX(&ctx, &m, inp, sav, AF_INET, IPSEC_ENC_BEFORE);
  216         if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
  217                 goto bad;
  218 
  219         ip = mtod(m, struct ip *);
  220         dst = &sav->sah->saidx.dst;
  221         /* Do the appropriate encapsulation, if necessary */
  222         if (sp->req[idx]->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
  223             dst->sa.sa_family != AF_INET ||         /* PF mismatch */
  224             (dst->sa.sa_family == AF_INET &&        /* Proxy */
  225              dst->sin.sin_addr.s_addr != INADDR_ANY &&
  226              dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
  227                 /* Fix IPv4 header checksum and length */
  228                 ip->ip_len = htons(m->m_pkthdr.len);
  229                 ip->ip_sum = 0;
  230                 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
  231                 error = ipsec_encap(&m, &sav->sah->saidx);
  232                 if (error != 0) {
  233                         DPRINTF(("%s: encapsulation for SPI 0x%08x failed "
  234                             "with error %d\n", __func__, ntohl(sav->spi),
  235                             error));
  236                         /* XXXAE: IPSEC_OSTAT_INC(tunnel); */
  237                         goto bad;
  238                 }
  239                 inp = NULL;
  240         }
  241 
  242         IPSEC_INIT_CTX(&ctx, &m, inp, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
  243         if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
  244                 goto bad;
  245 
  246         /*
  247          * Dispatch to the appropriate IPsec transform logic.  The
  248          * packet will be returned for transmission after crypto
  249          * processing, etc. are completed.
  250          *
  251          * NB: m & sav are ``passed to caller'' who's responsible for
  252          *     reclaiming their resources.
  253          */
  254         switch(dst->sa.sa_family) {
  255         case AF_INET:
  256                 ip = mtod(m, struct ip *);
  257                 i = ip->ip_hl << 2;
  258                 off = offsetof(struct ip, ip_p);
  259                 break;
  260 #ifdef INET6
  261         case AF_INET6:
  262                 i = sizeof(struct ip6_hdr);
  263                 off = offsetof(struct ip6_hdr, ip6_nxt);
  264                 break;
  265 #endif /* INET6 */
  266         default:
  267                 DPRINTF(("%s: unsupported protocol family %u\n",
  268                     __func__, dst->sa.sa_family));
  269                 error = EPFNOSUPPORT;
  270                 IPSEC_OSTAT_INC(sav->sah->saidx.proto, nopf);
  271                 goto bad;
  272         }
  273         error = (*sav->tdb_xform->xf_output)(m, sp, sav, idx, i, off);
  274         return (error);
  275 bad:
  276         IPSECSTAT_INC(ips_out_inval);
  277         if (m != NULL)
  278                 m_freem(m);
  279         if (sav != NULL)
  280                 key_freesav(&sav);
  281         key_freesp(&sp);
  282         return (error);
  283 }
  284 
  285 int
  286 ipsec4_process_packet(struct mbuf *m, struct secpolicy *sp,
  287     struct inpcb *inp)
  288 {
  289 
  290         return (ipsec4_perform_request(m, sp, inp, 0));
  291 }
  292 
  293 static int
  294 ipsec4_common_output(struct mbuf *m, struct inpcb *inp, int forwarding)
  295 {
  296         struct secpolicy *sp;
  297         int error;
  298 
  299         /* Lookup for the corresponding outbound security policy */
  300         sp = ipsec4_checkpolicy(m, inp, &error, !forwarding);
  301         if (sp == NULL) {
  302                 if (error == -EINVAL) {
  303                         /* Discarded by policy. */
  304                         m_freem(m);
  305                         return (EACCES);
  306                 }
  307                 return (0); /* No IPsec required. */
  308         }
  309 
  310         /*
  311          * Usually we have to have tunnel mode IPsec security policy
  312          * when we are forwarding a packet. Otherwise we could not handle
  313          * encrypted replies, because they are not destined for us. But
  314          * some users are doing source address translation for forwarded
  315          * packets, and thus, even if they are forwarded, the replies will
  316          * return back to us.
  317          */
  318         if (!forwarding) {
  319                 /*
  320                  * Do delayed checksums now because we send before
  321                  * this is done in the normal processing path.
  322                  */
  323                 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
  324                         in_delayed_cksum(m);
  325                         m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
  326                 }
  327 #ifdef SCTP
  328                 if (m->m_pkthdr.csum_flags & CSUM_SCTP) {
  329                         struct ip *ip = mtod(m, struct ip *);
  330 
  331                         sctp_delayed_cksum(m, (uint32_t)(ip->ip_hl << 2));
  332                         m->m_pkthdr.csum_flags &= ~CSUM_SCTP;
  333                 }
  334 #endif
  335         }
  336         /* NB: callee frees mbuf and releases reference to SP */
  337         error = ipsec4_process_packet(m, sp, inp);
  338         if (error == EJUSTRETURN) {
  339                 /*
  340                  * We had a SP with a level of 'use' and no SA. We
  341                  * will just continue to process the packet without
  342                  * IPsec processing and return without error.
  343                  */
  344                 return (0);
  345         }
  346         if (error == 0)
  347                 return (EINPROGRESS); /* consumed by IPsec */
  348         return (error);
  349 }
  350 
  351 /*
  352  * IPSEC_OUTPUT() method implementation for IPv4.
  353  * 0 - no IPsec handling needed
  354  * other values - mbuf consumed by IPsec.
  355  */
  356 int
  357 ipsec4_output(struct mbuf *m, struct inpcb *inp)
  358 {
  359 
  360         /*
  361          * If the packet is resubmitted to ip_output (e.g. after
  362          * AH, ESP, etc. processing), there will be a tag to bypass
  363          * the lookup and related policy checking.
  364          */
  365         if (m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL) != NULL)
  366                 return (0);
  367 
  368         return (ipsec4_common_output(m, inp, 0));
  369 }
  370 
  371 /*
  372  * IPSEC_FORWARD() method implementation for IPv4.
  373  * 0 - no IPsec handling needed
  374  * other values - mbuf consumed by IPsec.
  375  */
  376 int
  377 ipsec4_forward(struct mbuf *m)
  378 {
  379 
  380         /*
  381          * Check if this packet has an active inbound SP and needs to be
  382          * dropped instead of forwarded.
  383          */
  384         if (ipsec4_in_reject(m, NULL) != 0) {
  385                 m_freem(m);
  386                 return (EACCES);
  387         }
  388         return (ipsec4_common_output(m, NULL, 1));
  389 }
  390 #endif
  391 
  392 #ifdef INET6
  393 static int
  394 in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa,
  395     const struct in6_addr *ia)
  396 {
  397         struct in6_addr ia2;
  398 
  399         if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr)) {
  400                 memcpy(&ia2, &sa->sin6_addr, sizeof(ia2));
  401                 ia2.s6_addr16[1] = htons(sa->sin6_scope_id);
  402                 return (IN6_ARE_ADDR_EQUAL(ia, &ia2));
  403         }
  404         return (IN6_ARE_ADDR_EQUAL(&sa->sin6_addr, ia));
  405 }
  406 
  407 static struct secasvar *
  408 ipsec6_allocsa(struct mbuf *m, struct secpolicy *sp, u_int *pidx, int *error)
  409 {
  410         struct secasindex *saidx, tmpsaidx;
  411         struct ipsecrequest *isr;
  412         struct sockaddr_in6 *sin6;
  413         struct secasvar *sav;
  414         struct ip6_hdr *ip6;
  415 
  416         /*
  417          * Check system global policy controls.
  418          */
  419 next:
  420         isr = sp->req[*pidx];
  421         if ((isr->saidx.proto == IPPROTO_ESP && !V_esp_enable) ||
  422             (isr->saidx.proto == IPPROTO_AH && !V_ah_enable) ||
  423             (isr->saidx.proto == IPPROTO_IPCOMP && !V_ipcomp_enable)) {
  424                 DPRINTF(("%s: IPsec outbound packet dropped due"
  425                         " to policy (check your sysctls)\n", __func__));
  426                 IPSEC_OSTAT_INC(isr->saidx.proto, pdrops);
  427                 *error = EHOSTUNREACH;
  428                 return (NULL);
  429         }
  430         /*
  431          * Craft SA index to search for proper SA.  Note that
  432          * we only fillin unspecified SA peers for transport
  433          * mode; for tunnel mode they must already be filled in.
  434          */
  435         if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
  436                 saidx = &tmpsaidx;
  437                 *saidx = isr->saidx;
  438                 ip6 = mtod(m, struct ip6_hdr *);
  439                 if (saidx->src.sin6.sin6_len == 0) {
  440                         sin6 = (struct sockaddr_in6 *)&saidx->src;
  441                         sin6->sin6_len = sizeof(*sin6);
  442                         sin6->sin6_family = AF_INET6;
  443                         sin6->sin6_port = IPSEC_PORT_ANY;
  444                         sin6->sin6_addr = ip6->ip6_src;
  445                         if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
  446                                 /* fix scope id for comparing SPD */
  447                                 sin6->sin6_addr.s6_addr16[1] = 0;
  448                                 sin6->sin6_scope_id =
  449                                     ntohs(ip6->ip6_src.s6_addr16[1]);
  450                         }
  451                 }
  452                 if (saidx->dst.sin6.sin6_len == 0) {
  453                         sin6 = (struct sockaddr_in6 *)&saidx->dst;
  454                         sin6->sin6_len = sizeof(*sin6);
  455                         sin6->sin6_family = AF_INET6;
  456                         sin6->sin6_port = IPSEC_PORT_ANY;
  457                         sin6->sin6_addr = ip6->ip6_dst;
  458                         if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
  459                                 /* fix scope id for comparing SPD */
  460                                 sin6->sin6_addr.s6_addr16[1] = 0;
  461                                 sin6->sin6_scope_id =
  462                                     ntohs(ip6->ip6_dst.s6_addr16[1]);
  463                         }
  464                 }
  465         } else
  466                 saidx = &sp->req[*pidx]->saidx;
  467         /*
  468          * Lookup SA and validate it.
  469          */
  470         sav = key_allocsa_policy(sp, saidx, error);
  471         if (sav == NULL) {
  472                 IPSEC6STAT_INC(ips_out_nosa);
  473                 if (*error != 0)
  474                         return (NULL);
  475                 if (ipsec_get_reqlevel(sp, *pidx) != IPSEC_LEVEL_REQUIRE) {
  476                         /*
  477                          * We have no SA and policy that doesn't require
  478                          * this IPsec transform, thus we can continue w/o
  479                          * IPsec processing, i.e. return EJUSTRETURN.
  480                          * But first check if there is some bundled transform.
  481                          */
  482                         if (sp->tcount > ++(*pidx))
  483                                 goto next;
  484                         *error = EJUSTRETURN;
  485                 }
  486                 return (NULL);
  487         }
  488         IPSEC_ASSERT(sav->tdb_xform != NULL, ("SA with NULL tdb_xform"));
  489         return (sav);
  490 }
  491 
  492 /*
  493  * IPsec output logic for IPv6.
  494  */
  495 static int
  496 ipsec6_perform_request(struct mbuf *m, struct secpolicy *sp,
  497     struct inpcb *inp, u_int idx)
  498 {
  499         struct ipsec_ctx_data ctx;
  500         union sockaddr_union *dst;
  501         struct secasvar *sav;
  502         struct ip6_hdr *ip6;
  503         int error, i, off;
  504 
  505         IPSEC_ASSERT(idx < sp->tcount, ("Wrong IPsec request index %d", idx));
  506 
  507         sav = ipsec6_allocsa(m, sp, &idx, &error);
  508         if (sav == NULL) {
  509                 if (error == EJUSTRETURN) { /* No IPsec required */
  510                         key_freesp(&sp);
  511                         return (error);
  512                 }
  513                 goto bad;
  514         }
  515 
  516         /* Fix IP length in case if it is not set yet. */
  517         ip6 = mtod(m, struct ip6_hdr *);
  518         ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
  519 
  520         IPSEC_INIT_CTX(&ctx, &m, inp, sav, AF_INET6, IPSEC_ENC_BEFORE);
  521         if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
  522                 goto bad;
  523 
  524         ip6 = mtod(m, struct ip6_hdr *); /* pfil can change mbuf */
  525         dst = &sav->sah->saidx.dst;
  526 
  527         /* Do the appropriate encapsulation, if necessary */
  528         if (sp->req[idx]->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
  529             dst->sa.sa_family != AF_INET6 ||        /* PF mismatch */
  530             ((dst->sa.sa_family == AF_INET6) &&
  531              (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
  532              (!in6_sa_equal_addrwithscope(&dst->sin6, &ip6->ip6_dst)))) {
  533                 if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
  534                         /* No jumbogram support. */
  535                         error = ENXIO;   /*XXX*/
  536                         goto bad;
  537                 }
  538                 error = ipsec_encap(&m, &sav->sah->saidx);
  539                 if (error != 0) {
  540                         DPRINTF(("%s: encapsulation for SPI 0x%08x failed "
  541                             "with error %d\n", __func__, ntohl(sav->spi),
  542                             error));
  543                         /* XXXAE: IPSEC_OSTAT_INC(tunnel); */
  544                         goto bad;
  545                 }
  546                 inp = NULL;
  547         }
  548 
  549         IPSEC_INIT_CTX(&ctx, &m, inp, sav, dst->sa.sa_family, IPSEC_ENC_AFTER);
  550         if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0)
  551                 goto bad;
  552 
  553         switch(dst->sa.sa_family) {
  554 #ifdef INET
  555         case AF_INET:
  556                 {
  557                 struct ip *ip;
  558                 ip = mtod(m, struct ip *);
  559                 i = ip->ip_hl << 2;
  560                 off = offsetof(struct ip, ip_p);
  561                 }
  562                 break;
  563 #endif /* AF_INET */
  564         case AF_INET6:
  565                 i = sizeof(struct ip6_hdr);
  566                 off = offsetof(struct ip6_hdr, ip6_nxt);
  567                 break;
  568         default:
  569                 DPRINTF(("%s: unsupported protocol family %u\n",
  570                                  __func__, dst->sa.sa_family));
  571                 error = EPFNOSUPPORT;
  572                 IPSEC_OSTAT_INC(sav->sah->saidx.proto, nopf);
  573                 goto bad;
  574         }
  575         error = (*sav->tdb_xform->xf_output)(m, sp, sav, idx, i, off);
  576         return (error);
  577 bad:
  578         IPSEC6STAT_INC(ips_out_inval);
  579         if (m != NULL)
  580                 m_freem(m);
  581         if (sav != NULL)
  582                 key_freesav(&sav);
  583         key_freesp(&sp);
  584         return (error);
  585 }
  586 
  587 int
  588 ipsec6_process_packet(struct mbuf *m, struct secpolicy *sp,
  589     struct inpcb *inp)
  590 {
  591 
  592         return (ipsec6_perform_request(m, sp, inp, 0));
  593 }
  594 
  595 static int
  596 ipsec6_common_output(struct mbuf *m, struct inpcb *inp, int forwarding)
  597 {
  598         struct secpolicy *sp;
  599         int error;
  600 
  601         /* Lookup for the corresponding outbound security policy */
  602         sp = ipsec6_checkpolicy(m, inp, &error, !forwarding);
  603         if (sp == NULL) {
  604                 if (error == -EINVAL) {
  605                         /* Discarded by policy. */
  606                         m_freem(m);
  607                         return (EACCES);
  608                 }
  609                 return (0); /* No IPsec required. */
  610         }
  611 
  612         if (!forwarding) {
  613                 /*
  614                  * Do delayed checksums now because we send before
  615                  * this is done in the normal processing path.
  616                  */
  617                 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) {
  618                         in6_delayed_cksum(m, m->m_pkthdr.len -
  619                             sizeof(struct ip6_hdr), sizeof(struct ip6_hdr));
  620                 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6;
  621                 }
  622 #ifdef SCTP
  623                 if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) {
  624                         sctp_delayed_cksum(m, sizeof(struct ip6_hdr));
  625                         m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6;
  626                 }
  627 #endif
  628         }
  629         /* NB: callee frees mbuf and releases reference to SP */
  630         error = ipsec6_process_packet(m, sp, inp);
  631         if (error == EJUSTRETURN) {
  632                 /*
  633                  * We had a SP with a level of 'use' and no SA. We
  634                  * will just continue to process the packet without
  635                  * IPsec processing and return without error.
  636                  */
  637                 return (0);
  638         }
  639         if (error == 0)
  640                 return (EINPROGRESS); /* consumed by IPsec */
  641         return (error);
  642 }
  643 
  644 /*
  645  * IPSEC_OUTPUT() method implementation for IPv6.
  646  * 0 - no IPsec handling needed
  647  * other values - mbuf consumed by IPsec.
  648  */
  649 int
  650 ipsec6_output(struct mbuf *m, struct inpcb *inp)
  651 {
  652 
  653         /*
  654          * If the packet is resubmitted to ip_output (e.g. after
  655          * AH, ESP, etc. processing), there will be a tag to bypass
  656          * the lookup and related policy checking.
  657          */
  658         if (m_tag_find(m, PACKET_TAG_IPSEC_OUT_DONE, NULL) != NULL)
  659                 return (0);
  660 
  661         return (ipsec6_common_output(m, inp, 0));
  662 }
  663 
  664 /*
  665  * IPSEC_FORWARD() method implementation for IPv6.
  666  * 0 - no IPsec handling needed
  667  * other values - mbuf consumed by IPsec.
  668  */
  669 int
  670 ipsec6_forward(struct mbuf *m)
  671 {
  672 
  673         /*
  674          * Check if this packet has an active inbound SP and needs to be
  675          * dropped instead of forwarded.
  676          */
  677         if (ipsec6_in_reject(m, NULL) != 0) {
  678                 m_freem(m);
  679                 return (EACCES);
  680         }
  681         return (ipsec6_common_output(m, NULL, 1));
  682 }
  683 #endif /* INET6 */
  684 
  685 int
  686 ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
  687     u_int idx)
  688 {
  689         struct xform_history *xh;
  690         struct secasindex *saidx;
  691         struct m_tag *mtag;
  692         int error;
  693 
  694         saidx = &sav->sah->saidx;
  695         switch (saidx->dst.sa.sa_family) {
  696 #ifdef INET
  697         case AF_INET:
  698                 /* Fix the header length, for AH processing. */
  699                 mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
  700                 break;
  701 #endif /* INET */
  702 #ifdef INET6
  703         case AF_INET6:
  704                 /* Fix the header length, for AH processing. */
  705                 if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
  706                         error = ENXIO;
  707                         goto bad;
  708                 }
  709                 if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
  710                         /* No jumbogram support. */
  711                         error = ENXIO;  /*?*/
  712                         goto bad;
  713                 }
  714                 mtod(m, struct ip6_hdr *)->ip6_plen =
  715                         htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
  716                 break;
  717 #endif /* INET6 */
  718         default:
  719                 DPRINTF(("%s: unknown protocol family %u\n", __func__,
  720                     saidx->dst.sa.sa_family));
  721                 error = ENXIO;
  722                 goto bad;
  723         }
  724 
  725         /*
  726          * Add a record of what we've done to the packet.
  727          */
  728         mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, sizeof(*xh), M_NOWAIT);
  729         if (mtag == NULL) {
  730                 DPRINTF(("%s: could not get packet tag\n", __func__));
  731                 error = ENOMEM;
  732                 goto bad;
  733         }
  734 
  735         xh = (struct xform_history *)(mtag + 1);
  736         xh->dst = saidx->dst;
  737         xh->proto = saidx->proto;
  738         xh->mode = saidx->mode;
  739         xh->spi = sav->spi;
  740         m_tag_prepend(m, mtag);
  741 
  742         key_sa_recordxfer(sav, m);              /* record data transfer */
  743 
  744         /*
  745          * If there's another (bundled) SA to apply, do so.
  746          * Note that this puts a burden on the kernel stack size.
  747          * If this is a problem we'll need to introduce a queue
  748          * to set the packet on so we can unwind the stack before
  749          * doing further processing.
  750          */
  751         if (++idx < sp->tcount) {
  752                 switch (saidx->dst.sa.sa_family) {
  753 #ifdef INET
  754                 case AF_INET:
  755                         key_freesav(&sav);
  756                         IPSECSTAT_INC(ips_out_bundlesa);
  757                         return (ipsec4_perform_request(m, sp, NULL, idx));
  758                         /* NOTREACHED */
  759 #endif
  760 #ifdef INET6
  761                 case AF_INET6:
  762                         key_freesav(&sav);
  763                         IPSEC6STAT_INC(ips_out_bundlesa);
  764                         return (ipsec6_perform_request(m, sp, NULL, idx));
  765                         /* NOTREACHED */
  766 #endif /* INET6 */
  767                 default:
  768                         DPRINTF(("%s: unknown protocol family %u\n", __func__,
  769                             saidx->dst.sa.sa_family));
  770                         error = EPFNOSUPPORT;
  771                         goto bad;
  772                 }
  773         }
  774 
  775         key_freesp(&sp), sp = NULL;     /* Release reference to SP */
  776 #ifdef INET
  777         /*
  778          * Do UDP encapsulation if SA requires it.
  779          */
  780         if (sav->natt != NULL) {
  781                 error = udp_ipsec_output(m, sav);
  782                 if (error != 0)
  783                         goto bad;
  784         }
  785 #endif /* INET */
  786         /*
  787          * We're done with IPsec processing, transmit the packet using the
  788          * appropriate network protocol (IP or IPv6).
  789          */
  790         switch (saidx->dst.sa.sa_family) {
  791 #ifdef INET
  792         case AF_INET:
  793                 key_freesav(&sav);
  794                 return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL);
  795 #endif /* INET */
  796 #ifdef INET6
  797         case AF_INET6:
  798                 key_freesav(&sav);
  799                 return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
  800 #endif /* INET6 */
  801         }
  802         panic("ipsec_process_done");
  803 bad:
  804         m_freem(m);
  805         key_freesav(&sav);
  806         if (sp != NULL)
  807                 key_freesp(&sp);
  808         return (error);
  809 }
  810 
  811 /*
  812  * ipsec_prepend() is optimized version of M_PREPEND().
  813  * ipsec_encap() is called by IPsec output routine for tunnel mode SA.
  814  * It is expected that after IP encapsulation some IPsec transform will
  815  * be performed. Each IPsec transform inserts its variable length header
  816  * just after outer IP header using m_makespace(). If given mbuf has not
  817  * enough free space at the beginning, we allocate new mbuf and reserve
  818  * some space at the beginning and at the end.
  819  * This helps avoid allocating of new mbuf and data copying in m_makespace(),
  820  * we place outer header in the middle of mbuf's data with reserved leading
  821  * and trailing space:
  822  *      [ LEADINGSPACE ][ Outer IP header ][ TRAILINGSPACE ]
  823  * LEADINGSPACE will be used to add ethernet header, TRAILINGSPACE will
  824  * be used to inject AH/ESP/IPCOMP header.
  825  */
  826 #define IPSEC_TRAILINGSPACE     (sizeof(struct udphdr) +/* NAT-T */     \
  827     max(sizeof(struct newesp) + EALG_MAX_BLOCK_LEN,     /* ESP + IV */  \
  828         sizeof(struct newah) + HASH_MAX_LEN             /* AH + ICV */))
  829 static struct mbuf *
  830 ipsec_prepend(struct mbuf *m, int len, int how)
  831 {
  832         struct mbuf *n;
  833 
  834         M_ASSERTPKTHDR(m);
  835         IPSEC_ASSERT(len < MHLEN, ("wrong length"));
  836         if (M_LEADINGSPACE(m) >= len) {
  837                 /* No need to allocate new mbuf. */
  838                 m->m_data -= len;
  839                 m->m_len += len;
  840                 m->m_pkthdr.len += len;
  841                 return (m);
  842         }
  843         n = m_gethdr(how, m->m_type);
  844         if (n == NULL) {
  845                 m_freem(m);
  846                 return (NULL);
  847         }
  848         m_move_pkthdr(n, m);
  849         n->m_next = m;
  850         if (len + IPSEC_TRAILINGSPACE < M_SIZE(n))
  851                 m_align(n, len + IPSEC_TRAILINGSPACE);
  852         n->m_len = len;
  853         n->m_pkthdr.len += len;
  854         return (n);
  855 }
  856 
  857 static int
  858 ipsec_encap(struct mbuf **mp, struct secasindex *saidx)
  859 {
  860 #ifdef INET6
  861         struct ip6_hdr *ip6;
  862 #endif
  863         struct ip *ip;
  864         int setdf;
  865         uint8_t itos, proto;
  866 
  867         ip = mtod(*mp, struct ip *);
  868         switch (ip->ip_v) {
  869 #ifdef INET
  870         case IPVERSION:
  871                 proto = IPPROTO_IPIP;
  872                 /*
  873                  * Collect IP_DF state from the inner header
  874                  * and honor system-wide control of how to handle it.
  875                  */
  876                 switch (V_ip4_ipsec_dfbit) {
  877                 case 0: /* clear in outer header */
  878                 case 1: /* set in outer header */
  879                         setdf = V_ip4_ipsec_dfbit;
  880                         break;
  881                 default:/* propagate to outer header */
  882                         setdf = (ip->ip_off & htons(IP_DF)) != 0;
  883                 }
  884                 itos = ip->ip_tos;
  885                 break;
  886 #endif
  887 #ifdef INET6
  888         case (IPV6_VERSION >> 4):
  889                 proto = IPPROTO_IPV6;
  890                 ip6 = mtod(*mp, struct ip6_hdr *);
  891                 itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
  892                 setdf = V_ip4_ipsec_dfbit ? 1: 0;
  893                 /* scoped address handling */
  894                 in6_clearscope(&ip6->ip6_src);
  895                 in6_clearscope(&ip6->ip6_dst);
  896                 break;
  897 #endif
  898         default:
  899                 return (EAFNOSUPPORT);
  900         }
  901         switch (saidx->dst.sa.sa_family) {
  902 #ifdef INET
  903         case AF_INET:
  904                 if (saidx->src.sa.sa_family != AF_INET ||
  905                     saidx->src.sin.sin_addr.s_addr == INADDR_ANY ||
  906                     saidx->dst.sin.sin_addr.s_addr == INADDR_ANY)
  907                         return (EINVAL);
  908                 *mp = ipsec_prepend(*mp, sizeof(struct ip), M_NOWAIT);
  909                 if (*mp == NULL)
  910                         return (ENOBUFS);
  911                 ip = mtod(*mp, struct ip *);
  912                 ip->ip_v = IPVERSION;
  913                 ip->ip_hl = sizeof(struct ip) >> 2;
  914                 ip->ip_p = proto;
  915                 ip->ip_len = htons((*mp)->m_pkthdr.len);
  916                 ip->ip_ttl = V_ip_defttl;
  917                 ip->ip_sum = 0;
  918                 ip->ip_off = setdf ? htons(IP_DF): 0;
  919                 ip->ip_src = saidx->src.sin.sin_addr;
  920                 ip->ip_dst = saidx->dst.sin.sin_addr;
  921                 ip_ecn_ingress(V_ip4_ipsec_ecn, &ip->ip_tos, &itos);
  922                 ip_fillid(ip);
  923                 break;
  924 #endif /* INET */
  925 #ifdef INET6
  926         case AF_INET6:
  927                 if (saidx->src.sa.sa_family != AF_INET6 ||
  928                     IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr) ||
  929                     IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr))
  930                         return (EINVAL);
  931                 *mp = ipsec_prepend(*mp, sizeof(struct ip6_hdr), M_NOWAIT);
  932                 if (*mp == NULL)
  933                         return (ENOBUFS);
  934                 ip6 = mtod(*mp, struct ip6_hdr *);
  935                 ip6->ip6_flow = 0;
  936                 ip6->ip6_vfc = IPV6_VERSION;
  937                 ip6->ip6_hlim = V_ip6_defhlim;
  938                 ip6->ip6_nxt = proto;
  939                 ip6->ip6_dst = saidx->dst.sin6.sin6_addr;
  940                 /* For link-local address embed scope zone id */
  941                 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
  942                         ip6->ip6_dst.s6_addr16[1] =
  943                             htons(saidx->dst.sin6.sin6_scope_id & 0xffff);
  944                 ip6->ip6_src = saidx->src.sin6.sin6_addr;
  945                 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
  946                         ip6->ip6_src.s6_addr16[1] =
  947                             htons(saidx->src.sin6.sin6_scope_id & 0xffff);
  948                 ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6));
  949                 ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos);
  950                 ip6->ip6_flow |= htonl((uint32_t)proto << 20);
  951                 break;
  952 #endif /* INET6 */
  953         default:
  954                 return (EAFNOSUPPORT);
  955         }
  956         (*mp)->m_flags &= ~(M_BCAST | M_MCAST);
  957         return (0);
  958 }
  959 

Cache object: a98d4ef13cb7e8a179656d92a3e0ba83


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