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

Cache object: ec4a0d5e76f12225d988464fcfa5a6d3


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