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/netinet6/esp_input.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: esp_input.c,v 1.41 2006/11/16 01:33:45 christos Exp $  */
    2 /*      $KAME: esp_input.c,v 1.60 2001/09/04 08:43:19 itojun 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 /*
   34  * RFC1827/2406 Encapsulated Security Payload.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: esp_input.c,v 1.41 2006/11/16 01:33:45 christos Exp $");
   39 
   40 #include "opt_inet.h"
   41 #include "opt_ipsec.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/malloc.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/domain.h>
   48 #include <sys/protosw.h>
   49 #include <sys/socket.h>
   50 #include <sys/errno.h>
   51 #include <sys/time.h>
   52 #include <sys/kernel.h>
   53 #include <sys/syslog.h>
   54 
   55 #include <net/if.h>
   56 #include <net/route.h>
   57 #include <net/netisr.h>
   58 #include <machine/cpu.h>
   59 
   60 #include <netinet/in.h>
   61 #include <netinet/in_systm.h>
   62 #include <netinet/ip.h>
   63 #include <netinet/ip_var.h>
   64 #include <netinet/in_var.h>
   65 #include <netinet/in_proto.h>
   66 #include <netinet/ip_ecn.h>
   67 #include <netinet/ip_icmp.h>
   68 
   69 #ifdef INET6
   70 #include <netinet/ip6.h>
   71 #include <netinet6/ip6_var.h>
   72 #include <netinet/icmp6.h>
   73 #include <netinet6/ip6protosw.h>
   74 #endif
   75 
   76 #include <netinet6/ipsec.h>
   77 #include <netinet6/ah.h>
   78 #include <netinet6/esp.h>
   79 #include <netkey/key.h>
   80 #include <netkey/keydb.h>
   81 #include <netkey/key_debug.h>
   82 
   83 #include <machine/stdarg.h>
   84 
   85 #include <net/net_osdep.h>
   86 
   87 /*#define IPLEN_FLIPPED*/
   88 
   89 #define ESPMAXLEN \
   90         (sizeof(struct esp) < sizeof(struct newesp) \
   91                 ? sizeof(struct newesp) : sizeof(struct esp))
   92 
   93 #ifdef INET
   94 void
   95 #if __STDC__
   96 esp4_input(struct mbuf *m, ...)
   97 #else
   98 esp4_input(m, va_alist)
   99         struct mbuf *m;
  100         va_dcl
  101 #endif
  102 {
  103         struct ip *ip;
  104         struct esp *esp;
  105         struct esptail esptail;
  106         u_int32_t spi;
  107         struct secasvar *sav = NULL;
  108         size_t taillen;
  109         u_int16_t nxt;
  110         const struct esp_algorithm *algo;
  111         int ivlen;
  112         size_t hlen;
  113         size_t esplen;
  114         int s;
  115         va_list ap;
  116         int off;
  117         u_int16_t sport = 0;
  118         u_int16_t dport = 0;
  119 #ifdef IPSEC_NAT_T
  120         struct m_tag *tag = NULL;
  121 #endif
  122 
  123         va_start(ap, m);
  124         off = va_arg(ap, int);
  125         (void)va_arg(ap, int);          /* ignore value, advance ap */
  126         va_end(ap);
  127 
  128         /* sanity check for alignment. */
  129         if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
  130                 ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem "
  131                         "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
  132                 ipsecstat.in_inval++;
  133                 goto bad;
  134         }
  135 
  136         if (m->m_len < off + ESPMAXLEN) {
  137                 m = m_pullup(m, off + ESPMAXLEN);
  138                 if (!m) {
  139                         ipseclog((LOG_DEBUG,
  140                             "IPv4 ESP input: can't pullup in esp4_input\n"));
  141                         ipsecstat.in_inval++;
  142                         goto bad;
  143                 }
  144         }
  145 
  146 #ifdef IPSEC_NAT_T
  147         /* find the source port for NAT_T */
  148         if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL)) != NULL) {
  149                 sport = ((u_int16_t *)(tag + 1))[0];
  150                 dport = ((u_int16_t *)(tag + 1))[1];
  151         }
  152 #endif
  153 
  154         ip = mtod(m, struct ip *);
  155         esp = (struct esp *)(((u_int8_t *)ip) + off);
  156         hlen = ip->ip_hl << 2;
  157 
  158         /* find the sassoc. */
  159         spi = esp->esp_spi;
  160 
  161         if ((sav = key_allocsa(AF_INET,
  162                               (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
  163                               IPPROTO_ESP, spi, sport, dport)) == 0) {
  164                 ipseclog((LOG_WARNING,
  165                     "IPv4 ESP input: no key association found for spi %u\n",
  166                     (u_int32_t)ntohl(spi)));
  167                 ipsecstat.in_nosa++;
  168                 goto bad;
  169         }
  170         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  171                 printf("DP esp4_input called to allocate SA:%p\n", sav));
  172         if (sav->state != SADB_SASTATE_MATURE &&
  173             sav->state != SADB_SASTATE_DYING) {
  174                 ipseclog((LOG_DEBUG,
  175                     "IPv4 ESP input: non-mature/dying SA found for spi %u\n",
  176                     (u_int32_t)ntohl(spi)));
  177                 ipsecstat.in_badspi++;
  178                 goto bad;
  179         }
  180         algo = esp_algorithm_lookup(sav->alg_enc);
  181         if (!algo) {
  182                 ipseclog((LOG_DEBUG, "IPv4 ESP input: "
  183                     "unsupported encryption algorithm for spi %u\n",
  184                     (u_int32_t)ntohl(spi)));
  185                 ipsecstat.in_badspi++;
  186                 goto bad;
  187         }
  188 
  189         /* check if we have proper ivlen information */
  190         ivlen = sav->ivlen;
  191         if (ivlen < 0) {
  192                 ipseclog((LOG_ERR, "inproper ivlen in IPv4 ESP input: %s %s\n",
  193                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  194                 ipsecstat.in_inval++;
  195                 goto bad;
  196         }
  197 
  198         if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay &&
  199             sav->alg_auth && sav->key_auth))
  200                 goto noreplaycheck;
  201 
  202         if (sav->alg_auth == SADB_X_AALG_NULL ||
  203             sav->alg_auth == SADB_AALG_NONE)
  204                 goto noreplaycheck;
  205 
  206         /*
  207          * check for sequence number.
  208          */
  209         if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav))
  210                 ; /* okey */
  211         else {
  212                 ipsecstat.in_espreplay++;
  213                 ipseclog((LOG_WARNING,
  214                     "replay packet in IPv4 ESP input: %s %s\n",
  215                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  216                 goto bad;
  217         }
  218 
  219         /* check ICV */
  220     {
  221         u_int8_t sum0[AH_MAXSUMSIZE];
  222         u_int8_t sum[AH_MAXSUMSIZE];
  223         const struct ah_algorithm *sumalgo;
  224         size_t siz;
  225 
  226         sumalgo = ah_algorithm_lookup(sav->alg_auth);
  227         if (!sumalgo)
  228                 goto noreplaycheck;
  229         siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
  230         if (m->m_pkthdr.len < off + ESPMAXLEN + siz) {
  231                 ipsecstat.in_inval++;
  232                 goto bad;
  233         }
  234         if (AH_MAXSUMSIZE < siz) {
  235                 ipseclog((LOG_DEBUG,
  236                     "internal error: AH_MAXSUMSIZE must be larger than %lu\n",
  237                     (u_long)siz));
  238                 ipsecstat.in_inval++;
  239                 goto bad;
  240         }
  241 
  242         m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t)&sum0[0]);
  243 
  244         if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
  245                 ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
  246                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  247                 ipsecstat.in_espauthfail++;
  248                 goto bad;
  249         }
  250 
  251         if (bcmp(sum0, sum, siz) != 0) {
  252                 ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n",
  253                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  254                 ipsecstat.in_espauthfail++;
  255                 goto bad;
  256         }
  257 
  258         /* strip off the authentication data */
  259         m_adj(m, -siz);
  260         ip = mtod(m, struct ip *);
  261 #ifdef IPLEN_FLIPPED
  262         ip->ip_len = ip->ip_len - siz;
  263 #else
  264         ip->ip_len = htons(ntohs(ip->ip_len) - siz);
  265 #endif
  266         m->m_flags |= M_AUTHIPDGM;
  267         ipsecstat.in_espauthsucc++;
  268     }
  269 
  270         /*
  271          * update sequence number.
  272          */
  273         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
  274                 if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) {
  275                         ipsecstat.in_espreplay++;
  276                         goto bad;
  277                 }
  278         }
  279 
  280 noreplaycheck:
  281 
  282         /* process main esp header. */
  283         if (sav->flags & SADB_X_EXT_OLD) {
  284                 /* RFC 1827 */
  285                 esplen = sizeof(struct esp);
  286         } else {
  287                 /* RFC 2406 */
  288                 if (sav->flags & SADB_X_EXT_DERIV)
  289                         esplen = sizeof(struct esp);
  290                 else
  291                         esplen = sizeof(struct newesp);
  292         }
  293 
  294         if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
  295                 ipseclog((LOG_WARNING,
  296                     "IPv4 ESP input: packet too short\n"));
  297                 ipsecstat.in_inval++;
  298                 goto bad;
  299         }
  300 
  301         if (m->m_len < off + esplen + ivlen) {
  302                 m = m_pullup(m, off + esplen + ivlen);
  303                 if (!m) {
  304                         ipseclog((LOG_DEBUG,
  305                             "IPv4 ESP input: can't pullup in esp4_input\n"));
  306                         ipsecstat.in_inval++;
  307                         goto bad;
  308                 }
  309         }
  310 
  311         /*
  312          * pre-compute and cache intermediate key
  313          */
  314         if (esp_schedule(algo, sav) != 0) {
  315                 ipsecstat.in_inval++;
  316                 goto bad;
  317         }
  318 
  319         /*
  320          * decrypt the packet.
  321          */
  322         if (!algo->decrypt)
  323                 panic("internal error: no decrypt function");
  324         if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
  325                 /* m is already freed */
  326                 m = NULL;
  327                 ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n",
  328                     ipsec_logsastr(sav)));
  329                 ipsecstat.in_inval++;
  330                 goto bad;
  331         }
  332         ipsecstat.in_esphist[sav->alg_enc]++;
  333 
  334         m->m_flags |= M_DECRYPTED;
  335 
  336         /*
  337          * find the trailer of the ESP.
  338          */
  339         m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
  340              (caddr_t)&esptail);
  341         nxt = esptail.esp_nxt;
  342         taillen = esptail.esp_padlen + sizeof(esptail);
  343 
  344         if (m->m_pkthdr.len < taillen ||
  345             m->m_pkthdr.len - taillen < off + esplen + ivlen + sizeof(esptail)) {
  346                 ipseclog((LOG_WARNING,
  347                     "bad pad length in IPv4 ESP input: %s %s\n",
  348                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  349                 ipsecstat.in_inval++;
  350                 goto bad;
  351         }
  352 
  353         /* strip off the trailing pad area. */
  354         m_adj(m, -taillen);
  355 
  356 #ifdef IPLEN_FLIPPED
  357         ip->ip_len = ip->ip_len - taillen;
  358 #else
  359         ip->ip_len = htons(ntohs(ip->ip_len) - taillen);
  360 #endif
  361 
  362         /* was it transmitted over the IPsec tunnel SA? */
  363         if (ipsec4_tunnel_validate(ip, nxt, sav)) {
  364                 /*
  365                  * strip off all the headers that precedes ESP header.
  366                  *      IP4 xx ESP IP4' payload -> IP4' payload
  367                  *
  368                  * XXX more sanity checks
  369                  * XXX relationship with gif?
  370                  */
  371                 u_int8_t tos;
  372 
  373                 tos = ip->ip_tos;
  374                 m_adj(m, off + esplen + ivlen);
  375                 if (m->m_len < sizeof(*ip)) {
  376                         m = m_pullup(m, sizeof(*ip));
  377                         if (!m) {
  378                                 ipsecstat.in_inval++;
  379                                 goto bad;
  380                         }
  381                 }
  382                 ip = mtod(m, struct ip *);
  383                 /* ECN consideration. */
  384                 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
  385                 if (!key_checktunnelsanity(sav, AF_INET,
  386                             (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
  387                         ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
  388                             "in IPv4 ESP input: %s %s\n",
  389                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  390                         ipsecstat.in_inval++;
  391                         goto bad;
  392                 }
  393 
  394                 key_sa_recordxfer(sav, m);
  395                 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
  396                     ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
  397                         ipsecstat.in_nomem++;
  398                         goto bad;
  399                 }
  400 
  401                 s = splnet();
  402                 if (IF_QFULL(&ipintrq)) {
  403                         ipsecstat.in_inval++;
  404                         splx(s);
  405                         goto bad;
  406                 }
  407                 IF_ENQUEUE(&ipintrq, m);
  408                 m = NULL;
  409                 schednetisr(NETISR_IP); /* can be skipped but to make sure */
  410                 splx(s);
  411                 nxt = IPPROTO_DONE;
  412         } else {
  413                 /*
  414                  * strip off ESP header and IV.
  415                  * even in m_pulldown case, we need to strip off ESP so that
  416                  * we can always compute checksum for AH correctly.
  417                  */
  418                 size_t stripsiz;
  419 
  420                 stripsiz = esplen + ivlen;
  421 
  422                 ip = mtod(m, struct ip *);
  423                 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
  424                 m->m_data += stripsiz;
  425                 m->m_len -= stripsiz;
  426                 m->m_pkthdr.len -= stripsiz;
  427 
  428                 ip = mtod(m, struct ip *);
  429 #ifdef IPLEN_FLIPPED
  430                 ip->ip_len = ip->ip_len - stripsiz;
  431 #else
  432                 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
  433 #endif
  434                 ip->ip_p = nxt;
  435 
  436                 key_sa_recordxfer(sav, m);
  437                 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
  438                         ipsecstat.in_nomem++;
  439                         goto bad;
  440                 }
  441 
  442                 if (nxt != IPPROTO_DONE) {
  443                         if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
  444                             ipsec4_in_reject(m, NULL)) {
  445                                 ipsecstat.in_polvio++;
  446                                 goto bad;
  447                         }
  448                         (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
  449                 } else
  450                         m_freem(m);
  451                 m = NULL;
  452         }
  453 
  454         if (sav) {
  455                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  456                         printf("DP esp4_input call free SA:%p\n", sav));
  457                 key_freesav(sav);
  458         }
  459         ipsecstat.in_success++;
  460         return;
  461 
  462 bad:
  463         if (sav) {
  464                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  465                         printf("DP esp4_input call free SA:%p\n", sav));
  466                 key_freesav(sav);
  467         }
  468         if (m)
  469                 m_freem(m);
  470         return;
  471 }
  472 
  473 /* assumes that ip header and esp header are contiguous on mbuf */
  474 void *
  475 esp4_ctlinput(cmd, sa, v)
  476         int cmd;
  477         struct sockaddr *sa;
  478         void *v;
  479 {
  480         struct ip *ip = v;
  481         struct esp *esp;
  482         struct icmp *icp;
  483         struct secasvar *sav;
  484 
  485         if (sa->sa_family != AF_INET ||
  486             sa->sa_len != sizeof(struct sockaddr_in))
  487                 return NULL;
  488         if ((unsigned)cmd >= PRC_NCMDS)
  489                 return NULL;
  490         if (cmd == PRC_MSGSIZE && ip_mtudisc && ip && ip->ip_v == 4) {
  491                 /*
  492                  * Check to see if we have a valid SA corresponding to
  493                  * the address in the ICMP message payload.
  494                  */
  495                 esp = (struct esp *)((caddr_t)ip + (ip->ip_hl << 2));
  496                 if ((sav = key_allocsa(AF_INET,
  497                                        (caddr_t) &ip->ip_src,
  498                                        (caddr_t) &ip->ip_dst,
  499                                        IPPROTO_ESP, esp->esp_spi,
  500                                        0, 0)) == NULL)
  501                         return NULL;
  502                 if (sav->state != SADB_SASTATE_MATURE &&
  503                     sav->state != SADB_SASTATE_DYING) {
  504                         key_freesav(sav);
  505                         return NULL;
  506                 }
  507 
  508                 /* XXX Further validation? */
  509 
  510                 key_freesav(sav);
  511 
  512                 /*
  513                  * Now that we've validated that we are actually communicating
  514                  * with the host indicated in the ICMP message, locate the
  515                  * ICMP header, recalculate the new MTU, and create the
  516                  * corresponding routing entry.
  517                  */
  518                 icp = (struct icmp *)((caddr_t)ip -
  519                     offsetof(struct icmp, icmp_ip));
  520                 icmp_mtudisc(icp, ip->ip_dst);
  521 
  522                 return NULL;
  523         }
  524 
  525         return NULL;
  526 }
  527 
  528 #endif /* INET */
  529 
  530 #ifdef INET6
  531 int
  532 esp6_input(struct mbuf **mp, int *offp, int proto)
  533 {
  534         struct mbuf *m = *mp;
  535         int off = *offp;
  536         struct ip6_hdr *ip6;
  537         struct esp *esp;
  538         struct esptail esptail;
  539         u_int32_t spi;
  540         struct secasvar *sav = NULL;
  541         size_t taillen;
  542         u_int16_t nxt;
  543         const struct esp_algorithm *algo;
  544         int ivlen;
  545         size_t esplen;
  546         int s;
  547 
  548         /* sanity check for alignment. */
  549         if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) {
  550                 ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem "
  551                         "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len));
  552                 ipsec6stat.in_inval++;
  553                 goto bad;
  554         }
  555 
  556         IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN);
  557         if (esp == NULL) {
  558                 ipsec6stat.in_inval++;
  559                 return IPPROTO_DONE;
  560         }
  561         ip6 = mtod(m, struct ip6_hdr *);
  562 
  563         if (ntohs(ip6->ip6_plen) == 0) {
  564                 ipseclog((LOG_ERR, "IPv6 ESP input: "
  565                     "ESP with IPv6 jumbogram is not supported.\n"));
  566                 ipsec6stat.in_inval++;
  567                 goto bad;
  568         }
  569 
  570         /* find the sassoc. */
  571         spi = esp->esp_spi;
  572 
  573         if ((sav = key_allocsa(AF_INET6,
  574                               (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
  575                               IPPROTO_ESP, spi, 0, 0)) == 0) {
  576                 ipseclog((LOG_WARNING,
  577                     "IPv6 ESP input: no key association found for spi %u\n",
  578                     (u_int32_t)ntohl(spi)));
  579                 ipsec6stat.in_nosa++;
  580                 goto bad;
  581         }
  582         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  583                 printf("DP esp6_input called to allocate SA:%p\n", sav));
  584         if (sav->state != SADB_SASTATE_MATURE &&
  585             sav->state != SADB_SASTATE_DYING) {
  586                 ipseclog((LOG_DEBUG,
  587                     "IPv6 ESP input: non-mature/dying SA found for spi %u\n",
  588                     (u_int32_t)ntohl(spi)));
  589                 ipsec6stat.in_badspi++;
  590                 goto bad;
  591         }
  592         algo = esp_algorithm_lookup(sav->alg_enc);
  593         if (!algo) {
  594                 ipseclog((LOG_DEBUG, "IPv6 ESP input: "
  595                     "unsupported encryption algorithm for spi %u\n",
  596                     (u_int32_t)ntohl(spi)));
  597                 ipsec6stat.in_badspi++;
  598                 goto bad;
  599         }
  600 
  601         /* check if we have proper ivlen information */
  602         ivlen = sav->ivlen;
  603         if (ivlen < 0) {
  604                 ipseclog((LOG_ERR, "inproper ivlen in IPv6 ESP input: %s %s\n",
  605                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
  606                 ipsec6stat.in_badspi++;
  607                 goto bad;
  608         }
  609 
  610         if (!((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay &&
  611             sav->alg_auth && sav->key_auth))
  612                 goto noreplaycheck;
  613 
  614         if (sav->alg_auth == SADB_X_AALG_NULL ||
  615             sav->alg_auth == SADB_AALG_NONE)
  616                 goto noreplaycheck;
  617 
  618         /*
  619          * check for sequence number.
  620          */
  621         if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav))
  622                 ; /* okey */
  623         else {
  624                 ipsec6stat.in_espreplay++;
  625                 ipseclog((LOG_WARNING,
  626                     "replay packet in IPv6 ESP input: %s %s\n",
  627                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
  628                 goto bad;
  629         }
  630 
  631         /* check ICV */
  632     {
  633         u_char sum0[AH_MAXSUMSIZE];
  634         u_char sum[AH_MAXSUMSIZE];
  635         const struct ah_algorithm *sumalgo;
  636         size_t siz;
  637 
  638         sumalgo = ah_algorithm_lookup(sav->alg_auth);
  639         if (!sumalgo)
  640                 goto noreplaycheck;
  641         siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1));
  642         if (m->m_pkthdr.len < off + ESPMAXLEN + siz) {
  643                 ipsec6stat.in_inval++;
  644                 goto bad;
  645         }
  646         if (AH_MAXSUMSIZE < siz) {
  647                 ipseclog((LOG_DEBUG,
  648                     "internal error: AH_MAXSUMSIZE must be larger than %lu\n",
  649                     (u_long)siz));
  650                 ipsec6stat.in_inval++;
  651                 goto bad;
  652         }
  653 
  654         m_copydata(m, m->m_pkthdr.len - siz, siz, (caddr_t)&sum0[0]);
  655 
  656         if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) {
  657                 ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
  658                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
  659                 ipsec6stat.in_espauthfail++;
  660                 goto bad;
  661         }
  662 
  663         if (bcmp(sum0, sum, siz) != 0) {
  664                 ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n",
  665                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
  666                 ipsec6stat.in_espauthfail++;
  667                 goto bad;
  668         }
  669 
  670         /* strip off the authentication data */
  671         m_adj(m, -siz);
  672         ip6 = mtod(m, struct ip6_hdr *);
  673         ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - siz);
  674 
  675         m->m_flags |= M_AUTHIPDGM;
  676         ipsec6stat.in_espauthsucc++;
  677     }
  678 
  679         /*
  680          * update sequence number.
  681          */
  682         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
  683                 if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) {
  684                         ipsec6stat.in_espreplay++;
  685                         goto bad;
  686                 }
  687         }
  688 
  689 noreplaycheck:
  690 
  691         /* process main esp header. */
  692         if (sav->flags & SADB_X_EXT_OLD) {
  693                 /* RFC 1827 */
  694                 esplen = sizeof(struct esp);
  695         } else {
  696                 /* RFC 2406 */
  697                 if (sav->flags & SADB_X_EXT_DERIV)
  698                         esplen = sizeof(struct esp);
  699                 else
  700                         esplen = sizeof(struct newesp);
  701         }
  702 
  703         if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) {
  704                 ipseclog((LOG_WARNING,
  705                     "IPv6 ESP input: packet too short\n"));
  706                 ipsec6stat.in_inval++;
  707                 goto bad;
  708         }
  709 
  710         IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen);
  711         if (esp == NULL) {
  712                 ipsec6stat.in_inval++;
  713                 m = NULL;
  714                 goto bad;
  715         }
  716         ip6 = mtod(m, struct ip6_hdr *);        /* set it again just in case */
  717 
  718         /*
  719          * pre-compute and cache intermediate key
  720          */
  721         if (esp_schedule(algo, sav) != 0) {
  722                 ipsec6stat.in_inval++;
  723                 goto bad;
  724         }
  725 
  726         /*
  727          * decrypt the packet.
  728          */
  729         if (!algo->decrypt)
  730                 panic("internal error: no decrypt function");
  731         if ((*algo->decrypt)(m, off, sav, algo, ivlen)) {
  732                 /* m is already freed */
  733                 m = NULL;
  734                 ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n",
  735                     ipsec_logsastr(sav)));
  736                 ipsec6stat.in_inval++;
  737                 goto bad;
  738         }
  739         ipsec6stat.in_esphist[sav->alg_enc]++;
  740 
  741         m->m_flags |= M_DECRYPTED;
  742 
  743         /*
  744          * find the trailer of the ESP.
  745          */
  746         m_copydata(m, m->m_pkthdr.len - sizeof(esptail), sizeof(esptail),
  747              (caddr_t)&esptail);
  748         nxt = esptail.esp_nxt;
  749         taillen = esptail.esp_padlen + sizeof(esptail);
  750 
  751         if (m->m_pkthdr.len < taillen
  752          || m->m_pkthdr.len - taillen < sizeof(struct ip6_hdr)) {       /* ? */
  753                 ipseclog((LOG_WARNING,
  754                     "bad pad length in IPv6 ESP input: %s %s\n",
  755                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
  756                 ipsec6stat.in_inval++;
  757                 goto bad;
  758         }
  759 
  760         /* strip off the trailing pad area. */
  761         m_adj(m, -taillen);
  762 
  763         ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - taillen);
  764 
  765         /* was it transmitted over the IPsec tunnel SA? */
  766         if (ipsec6_tunnel_validate(ip6, nxt, sav)) {
  767                 /*
  768                  * strip off all the headers that precedes ESP header.
  769                  *      IP6 xx ESP IP6' payload -> IP6' payload
  770                  *
  771                  * XXX more sanity checks
  772                  * XXX relationship with gif?
  773                  */
  774                 u_int32_t flowinfo;     /* net endian */
  775                 flowinfo = ip6->ip6_flow;
  776                 m_adj(m, off + esplen + ivlen);
  777                 if (m->m_len < sizeof(*ip6)) {
  778                         m = m_pullup(m, sizeof(*ip6));
  779                         if (!m) {
  780                                 ipsec6stat.in_inval++;
  781                                 goto bad;
  782                         }
  783                 }
  784                 ip6 = mtod(m, struct ip6_hdr *);
  785                 /* ECN consideration. */
  786                 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
  787                 if (!key_checktunnelsanity(sav, AF_INET6,
  788                             (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
  789                         ipseclog((LOG_ERR, "ipsec tunnel address mismatch "
  790                             "in IPv6 ESP input: %s %s\n",
  791                             ipsec6_logpacketstr(ip6, spi),
  792                             ipsec_logsastr(sav)));
  793                         ipsec6stat.in_inval++;
  794                         goto bad;
  795                 }
  796 
  797                 key_sa_recordxfer(sav, m);
  798                 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 ||
  799                     ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
  800                         ipsec6stat.in_nomem++;
  801                         goto bad;
  802                 }
  803 
  804                 s = splnet();
  805                 if (IF_QFULL(&ip6intrq)) {
  806                         ipsec6stat.in_inval++;
  807                         splx(s);
  808                         goto bad;
  809                 }
  810                 IF_ENQUEUE(&ip6intrq, m);
  811                 m = NULL;
  812                 schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
  813                 splx(s);
  814                 nxt = IPPROTO_DONE;
  815         } else {
  816                 /*
  817                  * strip off ESP header and IV.
  818                  * even in m_pulldown case, we need to strip off ESP so that
  819                  * we can always compute checksum for AH correctly.
  820                  */
  821                 size_t stripsiz;
  822                 u_int8_t *prvnxtp;
  823 
  824                 /*
  825                  * Set the next header field of the previous header correctly.
  826                  */
  827                 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
  828                 *prvnxtp = nxt;
  829 
  830                 stripsiz = esplen + ivlen;
  831 
  832                 ip6 = mtod(m, struct ip6_hdr *);
  833                 if (m->m_len >= stripsiz + off) {
  834                         ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
  835                         m->m_data += stripsiz;
  836                         m->m_len -= stripsiz;
  837                         m->m_pkthdr.len -= stripsiz;
  838                 } else {
  839                         /*
  840                          * this comes with no copy if the boundary is on
  841                          * cluster
  842                          */
  843                         struct mbuf *n;
  844 
  845                         n = m_split(m, off, M_DONTWAIT);
  846                         if (n == NULL) {
  847                                 /* m is retained by m_split */
  848                                 goto bad;
  849                         }
  850                         m_adj(n, stripsiz);
  851                         /* m_cat does not update m_pkthdr.len */
  852                         m->m_pkthdr.len += n->m_pkthdr.len;
  853                         m_cat(m, n);
  854                 }
  855 
  856                 ip6 = mtod(m, struct ip6_hdr *);
  857                 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
  858 
  859                 key_sa_recordxfer(sav, m);
  860                 if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) {
  861                         ipsec6stat.in_nomem++;
  862                         goto bad;
  863                 }
  864         }
  865 
  866         *offp = off;
  867         *mp = m;
  868 
  869         if (sav) {
  870                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  871                         printf("DP esp6_input call free SA:%p\n", sav));
  872                 key_freesav(sav);
  873         }
  874         ipsec6stat.in_success++;
  875         return nxt;
  876 
  877 bad:
  878         if (sav) {
  879                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  880                         printf("DP esp6_input call free SA:%p\n", sav));
  881                 key_freesav(sav);
  882         }
  883         if (m)
  884                 m_freem(m);
  885         return IPPROTO_DONE;
  886 }
  887 
  888 void
  889 esp6_ctlinput(cmd, sa, d)
  890         int cmd;
  891         struct sockaddr *sa;
  892         void *d;
  893 {
  894         const struct newesp *espp;
  895         struct newesp esp;
  896         struct ip6ctlparam *ip6cp = NULL, ip6cp1;
  897         struct secasvar *sav;
  898         struct ip6_hdr *ip6;
  899         struct mbuf *m;
  900         int off;
  901         struct sockaddr_in6 *sa6_src, *sa6_dst;
  902 
  903         if (sa->sa_family != AF_INET6 ||
  904             sa->sa_len != sizeof(struct sockaddr_in6))
  905                 return;
  906         if ((unsigned)cmd >= PRC_NCMDS)
  907                 return;
  908 
  909         /* if the parameter is from icmp6, decode it. */
  910         if (d != NULL) {
  911                 ip6cp = (struct ip6ctlparam *)d;
  912                 m = ip6cp->ip6c_m;
  913                 ip6 = ip6cp->ip6c_ip6;
  914                 off = ip6cp->ip6c_off;
  915         } else {
  916                 m = NULL;
  917                 ip6 = NULL;
  918                 off = 0;
  919         }
  920 
  921         if (ip6) {
  922                 /*
  923                  * Notify the error to all possible sockets via pfctlinput2.
  924                  * Since the upper layer information (such as protocol type,
  925                  * source and destination ports) is embedded in the encrypted
  926                  * data and might have been cut, we can't directly call
  927                  * an upper layer ctlinput function. However, the pcbnotify
  928                  * function will consider source and destination addresses
  929                  * as well as the flow info value, and may be able to find
  930                  * some PCB that should be notified.
  931                  * Although pfctlinput2 will call esp6_ctlinput(), there is
  932                  * no possibility of an infinite loop of function calls,
  933                  * because we don't pass the inner IPv6 header.
  934                  */
  935                 bzero(&ip6cp1, sizeof(ip6cp1));
  936                 ip6cp1.ip6c_src = ip6cp->ip6c_src;
  937                 pfctlinput2(cmd, sa, (void *)&ip6cp1);
  938 
  939                 /*
  940                  * Then go to special cases that need ESP header information.
  941                  * XXX: We assume that when ip6 is non NULL,
  942                  * M and OFF are valid.
  943                  */
  944 
  945                 /* check if we can safely examine src and dst ports */
  946                 if (m->m_pkthdr.len < off + sizeof(esp))
  947                         return;
  948 
  949                 if (m->m_len < off + sizeof(esp)) {
  950                         /*
  951                          * this should be rare case,
  952                          * so we compromise on this copy...
  953                          */
  954                         m_copydata(m, off, sizeof(esp), (caddr_t)&esp);
  955                         espp = &esp;
  956                 } else
  957                         espp = (struct newesp*)(mtod(m, caddr_t) + off);
  958 
  959                 if (cmd == PRC_MSGSIZE) {
  960                         int valid = 0;
  961 
  962                         /*
  963                          * Check to see if we have a valid SA corresponding to
  964                          * the address in the ICMP message payload.
  965                          */
  966                         sa6_src = ip6cp->ip6c_src;
  967                         sa6_dst = (struct sockaddr_in6 *)sa;
  968                         sav = key_allocsa(AF_INET6,
  969                                           (caddr_t)&sa6_src->sin6_addr,
  970                                           (caddr_t)&sa6_dst->sin6_addr,
  971                                           IPPROTO_ESP, espp->esp_spi, 0, 0);
  972                         if (sav) {
  973                                 if (sav->state == SADB_SASTATE_MATURE ||
  974                                     sav->state == SADB_SASTATE_DYING)
  975                                         valid++;
  976                                 key_freesav(sav);
  977                         }
  978 
  979                         /* XXX Further validation? */
  980 
  981                         /*
  982                          * Depending on the value of "valid" and routing table
  983                          * size (mtudisc_{hi,lo}wat), we will:
  984                          * - recalcurate the new MTU and create the
  985                          *   corresponding routing entry, or
  986                          * - ignore the MTU change notification.
  987                          */
  988                         icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
  989                 }
  990         } else {
  991                 /* we normally notify any pcb here */
  992         }
  993 }
  994 #endif /* INET6 */

Cache object: bee128890e7f7bc3bed78ecc51ade707


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