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/bsd/netinet6/esp_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 /*      $FreeBSD: src/sys/netinet6/esp_output.c,v 1.1.2.3 2002/04/28 05:40:26 suz Exp $ */
    2 /*      $KAME: esp_output.c,v 1.44 2001/07/26 06:53:15 jinmei Exp $     */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    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  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #define _IP_VHL
   34 
   35 /*
   36  * RFC1827/2406 Encapsulated Security Payload.
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/malloc.h>
   42 #include <sys/mbuf.h>
   43 #include <sys/domain.h>
   44 #include <sys/protosw.h>
   45 #include <sys/socket.h>
   46 #include <sys/socketvar.h>
   47 #include <sys/errno.h>
   48 #include <sys/time.h>
   49 #include <sys/kernel.h>
   50 #include <sys/syslog.h>
   51 
   52 #include <net/if.h>
   53 #include <net/route.h>
   54 
   55 #include <netinet/in.h>
   56 #include <netinet/in_systm.h>
   57 #include <netinet/ip.h>
   58 #include <netinet/in_var.h>
   59 #include <netinet/udp.h> /* for nat traversal */
   60 
   61 #if INET6
   62 #include <netinet/ip6.h>
   63 #include <netinet6/ip6_var.h>
   64 #include <netinet/icmp6.h>
   65 #endif
   66 
   67 #include <netinet6/ipsec.h>
   68 #if INET6
   69 #include <netinet6/ipsec6.h>
   70 #endif
   71 #include <netinet6/ah.h>
   72 #if INET6
   73 #include <netinet6/ah6.h>
   74 #endif
   75 #include <netinet6/esp.h>
   76 #if INET6
   77 #include <netinet6/esp6.h>
   78 #endif
   79 #include <netkey/key.h>
   80 #include <netkey/keydb.h>
   81 
   82 #include <net/net_osdep.h>
   83 
   84 #include <sys/kdebug.h>
   85 #define DBG_LAYER_BEG           NETDBG_CODE(DBG_NETIPSEC, 1)
   86 #define DBG_LAYER_END           NETDBG_CODE(DBG_NETIPSEC, 3)
   87 #define DBG_FNC_ESPOUT          NETDBG_CODE(DBG_NETIPSEC, (4 << 8))
   88 #define DBG_FNC_ENCRYPT         NETDBG_CODE(DBG_NETIPSEC, (5 << 8))
   89 
   90 static int esp_output __P((struct mbuf *, u_char *, struct mbuf *,
   91         struct ipsecrequest *, int));
   92 
   93 extern int      esp_udp_encap_port;
   94 extern u_int32_t natt_now;
   95 
   96 /*
   97  * compute ESP header size.
   98  */
   99 size_t
  100 esp_hdrsiz(isr)
  101         struct ipsecrequest *isr;
  102 {
  103         struct secasvar *sav;
  104         const struct esp_algorithm *algo;
  105         const struct ah_algorithm *aalgo;
  106         size_t ivlen;
  107         size_t authlen;
  108         size_t hdrsiz;
  109         size_t maxpad;
  110 
  111         /* sanity check */
  112         if (isr == NULL)
  113                 panic("esp_hdrsiz: NULL was passed.\n");
  114 
  115         sav = isr->sav;
  116 
  117         if (isr->saidx.proto != IPPROTO_ESP)
  118                 panic("unsupported mode passed to esp_hdrsiz");
  119 
  120         if (sav == NULL)
  121                 goto estimate;
  122         if (sav->state != SADB_SASTATE_MATURE
  123          && sav->state != SADB_SASTATE_DYING)
  124                 goto estimate;
  125 
  126         /* we need transport mode ESP. */
  127         algo = esp_algorithm_lookup(sav->alg_enc);
  128         if (!algo)
  129                 goto estimate;
  130         ivlen = sav->ivlen;
  131         if (ivlen < 0)
  132                 goto estimate;
  133 
  134         if (algo->padbound)
  135                 maxpad = algo->padbound;
  136         else
  137                 maxpad = 4;
  138         maxpad += 1; /* maximum 'extendsiz' is padbound + 1, see esp_output */
  139         
  140         if (sav->flags & SADB_X_EXT_OLD) {
  141                 /* RFC 1827 */
  142                 hdrsiz = sizeof(struct esp) + ivlen + maxpad;
  143         } else {
  144                 /* RFC 2406 */
  145                 aalgo = ah_algorithm_lookup(sav->alg_auth);
  146                 if (aalgo && sav->replay && sav->key_auth)
  147                         authlen = (aalgo->sumsiz)(sav);
  148                 else
  149                         authlen = 0;
  150                 hdrsiz = sizeof(struct newesp) + ivlen + maxpad + authlen;
  151         }
  152         
  153         /*
  154          * If the security association indicates that NATT is required,
  155          * add the size of the NATT encapsulation header:
  156          */
  157         if ((sav->flags & SADB_X_EXT_NATT) != 0) hdrsiz += sizeof(struct udphdr) + 4;
  158 
  159         return hdrsiz;
  160 
  161    estimate:
  162         /*
  163          * ASSUMING:
  164          *      sizeof(struct newesp) > sizeof(struct esp). (8)
  165          *      esp_max_ivlen() = max ivlen for CBC mode
  166          *      17 = (maximum padding length without random padding length)
  167          *         + (Pad Length field) + (Next Header field).
  168          *      16 = maximum ICV we support.
  169          *  sizeof(struct udphdr) in case NAT traversal is used
  170          */
  171         return sizeof(struct newesp) + esp_max_ivlen() + 17 + 16 + sizeof(struct udphdr);
  172 }
  173 
  174 /*
  175  * Modify the packet so that the payload is encrypted.
  176  * The mbuf (m) must start with IPv4 or IPv6 header.
  177  * On failure, free the given mbuf and return NULL.
  178  *
  179  * on invocation:
  180  *      m   nexthdrp md
  181  *      v   v        v
  182  *      IP ......... payload
  183  * during the encryption:
  184  *      m   nexthdrp mprev md
  185  *      v   v        v     v
  186  *      IP ............... esp iv payload pad padlen nxthdr
  187  *                         <--><-><------><--------------->
  188  *                         esplen plen    extendsiz
  189  *                             ivlen
  190  *                         <-----> esphlen
  191  *      <-> hlen
  192  *      <-----------------> espoff
  193  */
  194 static int
  195 esp_output(m, nexthdrp, md, isr, af)
  196         struct mbuf *m;
  197         u_char *nexthdrp;
  198         struct mbuf *md;
  199         struct ipsecrequest *isr;
  200         int af;
  201 {
  202         struct mbuf *n;
  203         struct mbuf *mprev;
  204         struct esp *esp;
  205         struct esptail *esptail;
  206         struct secasvar *sav = isr->sav;
  207         const struct esp_algorithm *algo;
  208         u_int32_t spi;
  209         u_int8_t nxt = 0;
  210         size_t plen;    /*payload length to be encrypted*/
  211         size_t espoff;
  212         int ivlen;
  213         int afnumber;
  214         size_t extendsiz;
  215         int error = 0;
  216         struct ipsecstat *stat;
  217         struct udphdr *udp = NULL;
  218         int     udp_encapsulate = (sav->flags & SADB_X_EXT_NATT && af == AF_INET &&
  219                         (esp_udp_encap_port & 0xFFFF) != 0);
  220 
  221         KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_START, sav->ivlen,0,0,0,0);
  222         switch (af) {
  223 #if INET
  224         case AF_INET:
  225                 afnumber = 4;
  226                 stat = &ipsecstat;
  227                 break;
  228 #endif
  229 #if INET6
  230         case AF_INET6:
  231                 afnumber = 6;
  232                 stat = &ipsec6stat;
  233                 break;
  234 #endif
  235         default:
  236                 ipseclog((LOG_ERR, "esp_output: unsupported af %d\n", af));
  237                 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 1,0,0,0,0);
  238                 return 0;       /* no change at all */
  239         }
  240 
  241         /* some sanity check */
  242         if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) {
  243                 switch (af) {
  244 #if INET
  245                 case AF_INET:
  246                     {
  247                         struct ip *ip;
  248 
  249                         ip = mtod(m, struct ip *);
  250                         ipseclog((LOG_DEBUG, "esp4_output: internal error: "
  251                                 "sav->replay is null: %x->%x, SPI=%u\n",
  252                                 (u_int32_t)ntohl(ip->ip_src.s_addr),
  253                                 (u_int32_t)ntohl(ip->ip_dst.s_addr),
  254                                 (u_int32_t)ntohl(sav->spi)));
  255                         ipsecstat.out_inval++;
  256                         break;
  257                     }
  258 #endif /*INET*/
  259 #if INET6
  260                 case AF_INET6:
  261                         ipseclog((LOG_DEBUG, "esp6_output: internal error: "
  262                                 "sav->replay is null: SPI=%u\n",
  263                                 (u_int32_t)ntohl(sav->spi)));
  264                         ipsec6stat.out_inval++;
  265                         break;
  266 #endif /*INET6*/
  267                 default:
  268                         panic("esp_output: should not reach here");
  269                 }
  270                 m_freem(m);
  271                 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 2,0,0,0,0);
  272                 return EINVAL;
  273         }
  274 
  275         algo = esp_algorithm_lookup(sav->alg_enc);
  276         if (!algo) {
  277                 ipseclog((LOG_ERR, "esp_output: unsupported algorithm: "
  278                     "SPI=%u\n", (u_int32_t)ntohl(sav->spi)));
  279                 m_freem(m);
  280                 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 3,0,0,0,0);
  281                 return EINVAL;
  282         }
  283         spi = sav->spi;
  284         ivlen = sav->ivlen;
  285         /* should be okey */
  286         if (ivlen < 0) {
  287                 panic("invalid ivlen");
  288         }
  289 
  290     {
  291         /*
  292          * insert ESP header.
  293          * XXX inserts ESP header right after IPv4 header.  should
  294          * chase the header chain.
  295          * XXX sequential number
  296          */
  297 #if INET
  298         struct ip *ip = NULL;
  299 #endif
  300 #if INET6
  301         struct ip6_hdr *ip6 = NULL;
  302 #endif
  303         size_t esplen;  /* sizeof(struct esp/newesp) */
  304         size_t esphlen; /* sizeof(struct esp/newesp) + ivlen */
  305         size_t hlen = 0;        /* ip header len */
  306 
  307         if (sav->flags & SADB_X_EXT_OLD) {
  308                 /* RFC 1827 */
  309                 esplen = sizeof(struct esp);
  310         } else {
  311                 /* RFC 2406 */
  312                 if (sav->flags & SADB_X_EXT_DERIV)
  313                         esplen = sizeof(struct esp);
  314                 else
  315                         esplen = sizeof(struct newesp);
  316         }
  317         esphlen = esplen + ivlen;
  318 
  319         for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
  320                 ;
  321         if (mprev == NULL || mprev->m_next != md) {
  322                 ipseclog((LOG_DEBUG, "esp%d_output: md is not in chain\n",
  323                     afnumber));
  324                 m_freem(m);
  325                 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 4,0,0,0,0);
  326                 return EINVAL;
  327         }
  328 
  329         plen = 0;
  330         for (n = md; n; n = n->m_next)
  331                 plen += n->m_len;
  332 
  333         switch (af) {
  334 #if INET
  335         case AF_INET:
  336                 ip = mtod(m, struct ip *);
  337 #ifdef _IP_VHL
  338                 hlen = IP_VHL_HL(ip->ip_vhl) << 2;
  339 #else
  340                 hlen = ip->ip_hl << 2;
  341 #endif
  342                 break;
  343 #endif
  344 #if INET6
  345         case AF_INET6:
  346                 ip6 = mtod(m, struct ip6_hdr *);
  347                 hlen = sizeof(*ip6);
  348                 break;
  349 #endif
  350         }
  351 
  352         /* make the packet over-writable */
  353         mprev->m_next = NULL;
  354         if ((md = ipsec_copypkt(md)) == NULL) {
  355                 m_freem(m);
  356                 error = ENOBUFS;
  357                 goto fail;
  358         }
  359         mprev->m_next = md;
  360 
  361         espoff = m->m_pkthdr.len - plen;
  362         
  363         if (udp_encapsulate) {
  364                 esphlen += sizeof(struct udphdr);
  365                 espoff += sizeof(struct udphdr);
  366         }
  367 
  368         /*
  369          * grow the mbuf to accomodate ESP header.
  370          * before: IP ... payload
  371          * after:  IP ... [UDP] ESP IV payload
  372          */
  373         if (M_LEADINGSPACE(md) < esphlen || (md->m_flags & M_EXT) != 0) {
  374                 MGET(n, M_DONTWAIT, MT_DATA);
  375                 if (!n) {
  376                         m_freem(m);
  377                         error = ENOBUFS;
  378                         goto fail;
  379                 }
  380                 n->m_len = esphlen;
  381                 mprev->m_next = n;
  382                 n->m_next = md;
  383                 m->m_pkthdr.len += esphlen;
  384                 if (udp_encapsulate) {
  385                         udp = mtod(n, struct udphdr *);
  386                         esp = (struct esp *)((caddr_t)udp + sizeof(struct udphdr));
  387                 } else {
  388                         esp = mtod(n, struct esp *);
  389                 }
  390         } else {
  391                 md->m_len += esphlen;
  392                 md->m_data -= esphlen;
  393                 m->m_pkthdr.len += esphlen;
  394                 esp = mtod(md, struct esp *);
  395                 if (udp_encapsulate) {
  396                         udp = mtod(md, struct udphdr *);
  397                         esp = (struct esp *)((caddr_t)udp + sizeof(struct udphdr));
  398                 } else {
  399                         esp = mtod(md, struct esp *);
  400                 }
  401         }
  402         
  403         switch (af) {
  404 #if INET
  405         case AF_INET:
  406                 if (esphlen < (IP_MAXPACKET - ntohs(ip->ip_len)))
  407                         ip->ip_len = htons(ntohs(ip->ip_len) + esphlen);
  408                 else {
  409                         ipseclog((LOG_ERR,
  410                             "IPv4 ESP output: size exceeds limit\n"));
  411                         ipsecstat.out_inval++;
  412                         m_freem(m);
  413                         error = EMSGSIZE;
  414                         goto fail;
  415                 }
  416                 break;
  417 #endif
  418 #if INET6
  419         case AF_INET6:
  420                 /* total packet length will be computed in ip6_output() */
  421                 break;
  422 #endif
  423         }
  424     }
  425 
  426         /* initialize esp header. */
  427         esp->esp_spi = spi;
  428         if ((sav->flags & SADB_X_EXT_OLD) == 0) {
  429                 struct newesp *nesp;
  430                 nesp = (struct newesp *)esp;
  431                 if (sav->replay->count == ~0) {
  432                         if ((sav->flags & SADB_X_EXT_CYCSEQ) == 0) {
  433                                 /* XXX Is it noisy ? */
  434                                 ipseclog((LOG_WARNING,
  435                                     "replay counter overflowed. %s\n",
  436                                     ipsec_logsastr(sav)));
  437                                 stat->out_inval++;
  438                                 m_freem(m);
  439                                 KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 5,0,0,0,0);
  440                                 return EINVAL;
  441                         }
  442                 }
  443                 sav->replay->count++;
  444                 /*
  445                  * XXX sequence number must not be cycled, if the SA is
  446                  * installed by IKE daemon.
  447                  */
  448                 nesp->esp_seq = htonl(sav->replay->count);
  449         }
  450 
  451     {
  452         /*
  453          * find the last mbuf. make some room for ESP trailer.
  454          */
  455 #if INET
  456         struct ip *ip = NULL;
  457 #endif
  458         size_t padbound;
  459         u_char *extend;
  460         int i;
  461         int randpadmax;
  462 
  463         if (algo->padbound)
  464                 padbound = algo->padbound;
  465         else
  466                 padbound = 4;
  467         /* ESP packet, including nxthdr field, must be length of 4n */
  468         if (padbound < 4)
  469                 padbound = 4;
  470         
  471         extendsiz = padbound - (plen % padbound);
  472         if (extendsiz == 1)
  473                 extendsiz = padbound + 1;
  474 
  475         /* random padding */
  476         switch (af) {
  477 #if INET
  478         case AF_INET:
  479                 randpadmax = ip4_esp_randpad;
  480                 break;
  481 #endif
  482 #if INET6
  483         case AF_INET6:
  484                 randpadmax = ip6_esp_randpad;
  485                 break;
  486 #endif
  487         default:
  488                 randpadmax = -1;
  489                 break;
  490         }
  491         if (randpadmax < 0 || plen + extendsiz >= randpadmax)
  492                 ;
  493         else {
  494                 int n;
  495 
  496                 /* round */
  497                 randpadmax = (randpadmax / padbound) * padbound;
  498                 n = (randpadmax - plen + extendsiz) / padbound;
  499 
  500                 if (n > 0)
  501                         n = (random() % n) * padbound;
  502                 else
  503                         n = 0;
  504 
  505                 /*
  506                  * make sure we do not pad too much.
  507                  * MLEN limitation comes from the trailer attachment
  508                  * code below.
  509                  * 256 limitation comes from sequential padding.
  510                  * also, the 1-octet length field in ESP trailer imposes
  511                  * limitation (but is less strict than sequential padding
  512                  * as length field do not count the last 2 octets).
  513                  */
  514                 if (extendsiz + n <= MLEN && extendsiz + n < 256)
  515                         extendsiz += n;
  516         }
  517 
  518 #if DIAGNOSTIC
  519         if (extendsiz > MLEN || extendsiz >= 256)
  520                 panic("extendsiz too big in esp_output");
  521 #endif
  522 
  523         n = m;
  524         while (n->m_next)
  525                 n = n->m_next;
  526 
  527         /*
  528          * if M_EXT, the external mbuf data may be shared among
  529          * two consequtive TCP packets, and it may be unsafe to use the
  530          * trailing space.
  531          */
  532         if (!(n->m_flags & M_EXT) && extendsiz < M_TRAILINGSPACE(n)) {
  533                 extend = mtod(n, u_char *) + n->m_len;
  534                 n->m_len += extendsiz;
  535                 m->m_pkthdr.len += extendsiz;
  536         } else {
  537                 struct mbuf *nn;
  538 
  539                 MGET(nn, M_DONTWAIT, MT_DATA);
  540                 if (!nn) {
  541                         ipseclog((LOG_DEBUG, "esp%d_output: can't alloc mbuf",
  542                             afnumber));
  543                         m_freem(m);
  544                         error = ENOBUFS;
  545                         goto fail;
  546                 }
  547                 extend = mtod(nn, u_char *);
  548                 nn->m_len = extendsiz;
  549                 nn->m_next = NULL;
  550                 n->m_next = nn;
  551                 n = nn;
  552                 m->m_pkthdr.len += extendsiz;
  553         }
  554         switch (sav->flags & SADB_X_EXT_PMASK) {
  555         case SADB_X_EXT_PRAND:
  556                 key_randomfill(extend, extendsiz);
  557                 break;
  558         case SADB_X_EXT_PZERO:
  559                 bzero(extend, extendsiz);
  560                 break;
  561         case SADB_X_EXT_PSEQ:
  562                 for (i = 0; i < extendsiz; i++)
  563                         extend[i] = (i + 1) & 0xff;
  564                 break;
  565         }
  566         
  567         nxt = *nexthdrp;
  568         if (udp_encapsulate) {
  569                 *nexthdrp = IPPROTO_UDP;
  570 
  571                 /* Fill out the UDP header */
  572                 udp->uh_sport = ntohs((u_short)esp_udp_encap_port);
  573                 udp->uh_dport = ntohs(sav->remote_ike_port);
  574 //              udp->uh_len set later, after all length tweaks are complete
  575                 udp->uh_sum = 0;
  576                 
  577                 /* Update last sent so we know if we need to send keepalive */
  578                 sav->natt_last_activity = natt_now;
  579         } else {
  580                 *nexthdrp = IPPROTO_ESP;
  581         }
  582 
  583         /* initialize esp trailer. */
  584         esptail = (struct esptail *)
  585                 (mtod(n, u_int8_t *) + n->m_len - sizeof(struct esptail));
  586         esptail->esp_nxt = nxt;
  587         esptail->esp_padlen = extendsiz - 2;
  588 
  589         /* modify IP header (for ESP header part only) */
  590         switch (af) {
  591 #if INET
  592         case AF_INET:
  593                 ip = mtod(m, struct ip *);
  594                 if (extendsiz < (IP_MAXPACKET - ntohs(ip->ip_len)))
  595                         ip->ip_len = htons(ntohs(ip->ip_len) + extendsiz);
  596                 else {
  597                         ipseclog((LOG_ERR,
  598                             "IPv4 ESP output: size exceeds limit\n"));
  599                         ipsecstat.out_inval++;
  600                         m_freem(m);
  601                         error = EMSGSIZE;
  602                         goto fail;
  603                 }
  604                 break;
  605 #endif
  606 #if INET6
  607         case AF_INET6:
  608                 /* total packet length will be computed in ip6_output() */
  609                 break;
  610 #endif
  611         }
  612     }
  613 
  614         /*
  615          * pre-compute and cache intermediate key
  616          */
  617         error = esp_schedule(algo, sav);
  618         if (error) {
  619                 m_freem(m);
  620                 stat->out_inval++;
  621                 goto fail;
  622         }
  623 
  624         /*
  625          * encrypt the packet, based on security association
  626          * and the algorithm specified.
  627          */
  628         if (!algo->encrypt)
  629                 panic("internal error: no encrypt function");
  630         KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_START, 0,0,0,0,0);
  631         if ((*algo->encrypt)(m, espoff, plen + extendsiz, sav, algo, ivlen)) {
  632                 /* m is already freed */
  633                 ipseclog((LOG_ERR, "packet encryption failure\n"));
  634                 stat->out_inval++;
  635                 error = EINVAL;
  636                 KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 1,error,0,0,0);
  637                 goto fail;
  638         }
  639         KERNEL_DEBUG(DBG_FNC_ENCRYPT | DBG_FUNC_END, 2,0,0,0,0);
  640 
  641         /*
  642          * calculate ICV if required.
  643          */
  644         if (!sav->replay)
  645                 goto noantireplay;
  646         if (!sav->key_auth)
  647                 goto noantireplay;
  648         if (sav->key_auth == SADB_AALG_NONE)
  649                 goto noantireplay;
  650 
  651     {
  652         const struct ah_algorithm *aalgo;
  653         u_char authbuf[AH_MAXSUMSIZE];
  654         struct mbuf *n;
  655         u_char *p;
  656         size_t siz;
  657 #if INET
  658         struct ip *ip;
  659 #endif
  660 
  661         aalgo = ah_algorithm_lookup(sav->alg_auth);
  662         if (!aalgo)
  663                 goto noantireplay;
  664         siz = ((aalgo->sumsiz)(sav) + 3) & ~(4 - 1);
  665         if (AH_MAXSUMSIZE < siz)
  666                 panic("assertion failed for AH_MAXSUMSIZE");
  667 
  668         if (esp_auth(m, espoff, m->m_pkthdr.len - espoff, sav, authbuf)) {
  669                 ipseclog((LOG_ERR, "ESP checksum generation failure\n"));
  670                 m_freem(m);
  671                 error = EINVAL;
  672                 stat->out_inval++;
  673                 goto fail;
  674         }
  675 
  676         n = m;
  677         while (n->m_next)
  678                 n = n->m_next;
  679 
  680         if (!(n->m_flags & M_EXT) && siz < M_TRAILINGSPACE(n)) { /* XXX */
  681                 n->m_len += siz;
  682                 m->m_pkthdr.len += siz;
  683                 p = mtod(n, u_char *) + n->m_len - siz;
  684         } else {
  685                 struct mbuf *nn;
  686 
  687                 MGET(nn, M_DONTWAIT, MT_DATA);
  688                 if (!nn) {
  689                         ipseclog((LOG_DEBUG, "can't alloc mbuf in esp%d_output",
  690                             afnumber));
  691                         m_freem(m);
  692                         error = ENOBUFS;
  693                         goto fail;
  694                 }
  695                 nn->m_len = siz;
  696                 nn->m_next = NULL;
  697                 n->m_next = nn;
  698                 n = nn;
  699                 m->m_pkthdr.len += siz;
  700                 p = mtod(nn, u_char *);
  701         }
  702         bcopy(authbuf, p, siz);
  703 
  704         /* modify IP header (for ESP header part only) */
  705         switch (af) {
  706 #if INET
  707         case AF_INET:
  708                 ip = mtod(m, struct ip *);
  709                 if (siz < (IP_MAXPACKET - ntohs(ip->ip_len)))
  710                         ip->ip_len = htons(ntohs(ip->ip_len) + siz);
  711                 else {
  712                         ipseclog((LOG_ERR,
  713                             "IPv4 ESP output: size exceeds limit\n"));
  714                         ipsecstat.out_inval++;
  715                         m_freem(m);
  716                         error = EMSGSIZE;
  717                         goto fail;
  718                 }
  719                 break;
  720 #endif
  721 #if INET6
  722         case AF_INET6:
  723                 /* total packet length will be computed in ip6_output() */
  724                 break;
  725 #endif
  726         }
  727     }
  728     
  729         if (udp_encapsulate) {
  730                 struct ip *ip;
  731                 ip = mtod(m, struct ip *);
  732                 udp->uh_ulen = htons(ntohs(ip->ip_len) - (IP_VHL_HL(ip->ip_vhl) << 2));
  733         }
  734 
  735 
  736 noantireplay:
  737         if (!m) {
  738                 ipseclog((LOG_ERR,
  739                     "NULL mbuf after encryption in esp%d_output", afnumber));
  740         } else
  741                 stat->out_success++;
  742         stat->out_esphist[sav->alg_enc]++;
  743         key_sa_recordxfer(sav, m);
  744         KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 6,0,0,0,0);
  745         return 0;
  746 
  747 fail:
  748 #if 1
  749         KERNEL_DEBUG(DBG_FNC_ESPOUT | DBG_FUNC_END, 7,error,0,0,0);
  750         return error;
  751 #else
  752         panic("something bad in esp_output");
  753 #endif
  754 }
  755 
  756 #if INET
  757 int
  758 esp4_output(m, isr)
  759         struct mbuf *m;
  760         struct ipsecrequest *isr;
  761 {
  762         struct ip *ip;
  763         if (m->m_len < sizeof(struct ip)) {
  764                 ipseclog((LOG_DEBUG, "esp4_output: first mbuf too short\n"));
  765                 m_freem(m);
  766                 return 0;
  767         }
  768         ip = mtod(m, struct ip *);
  769         /* XXX assumes that m->m_next points to payload */
  770         return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
  771 }
  772 #endif /*INET*/
  773 
  774 #if INET6
  775 int
  776 esp6_output(m, nexthdrp, md, isr)
  777         struct mbuf *m;
  778         u_char *nexthdrp;
  779         struct mbuf *md;
  780         struct ipsecrequest *isr;
  781 {
  782         if (m->m_len < sizeof(struct ip6_hdr)) {
  783                 ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n"));
  784                 m_freem(m);
  785                 return 0;
  786         }
  787         return esp_output(m, nexthdrp, md, isr, AF_INET6);
  788 }
  789 #endif /*INET6*/

Cache object: 9db26eda91b7ba3112d54a307e3690e7


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