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/ah_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 /*      $FreeBSD: releng/5.0/sys/netinet6/ah_input.c 95023 2002-04-19 04:46:24Z suz $   */
    2 /*      $KAME: ah_input.c,v 1.67 2002/01/07 11:39:56 kjc 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  * RFC1826/2402 authentication header.
   35  */
   36 
   37 #include "opt_inet.h"
   38 #include "opt_inet6.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/malloc.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/domain.h>
   45 #include <sys/protosw.h>
   46 #include <sys/socket.h>
   47 #include <sys/errno.h>
   48 #include <sys/time.h>
   49 #include <sys/syslog.h>
   50 
   51 #include <net/if.h>
   52 #include <net/route.h>
   53 #include <net/netisr.h>
   54 #include <machine/cpu.h>
   55 
   56 #include <netinet/in.h>
   57 #include <netinet/in_systm.h>
   58 #include <netinet/in_var.h>
   59 #include <netinet/ip.h>
   60 #include <netinet/ip_var.h>
   61 #include <netinet/ip_ecn.h>
   62 #ifdef INET6
   63 #include <netinet6/ip6_ecn.h>
   64 #endif
   65 
   66 #ifdef INET6
   67 #include <netinet/ip6.h>
   68 #include <netinet6/ip6_var.h>
   69 #include <netinet/in_pcb.h>
   70 #include <netinet6/in6_pcb.h>
   71 #include <netinet/icmp6.h>
   72 #include <netinet6/ip6protosw.h>
   73 #endif
   74 
   75 #include <netinet6/ipsec.h>
   76 #ifdef INET6
   77 #include <netinet6/ipsec6.h>
   78 #endif
   79 #include <netinet6/ah.h>
   80 #ifdef INET6
   81 #include <netinet6/ah6.h>
   82 #endif
   83 #include <netkey/key.h>
   84 #include <netkey/keydb.h>
   85 #ifdef IPSEC_DEBUG
   86 #include <netkey/key_debug.h>
   87 #else
   88 #define KEYDEBUG(lev,arg)
   89 #endif
   90 
   91 #include <machine/stdarg.h>
   92 
   93 #include <net/net_osdep.h>
   94 
   95 #define IPLEN_FLIPPED
   96 
   97 #ifdef INET
   98 extern struct protosw inetsw[];
   99 
  100 void
  101 ah4_input(m, off)
  102         struct mbuf *m;
  103         int off;
  104 {
  105         struct ip *ip;
  106         struct ah *ah;
  107         u_int32_t spi;
  108         const struct ah_algorithm *algo;
  109         size_t siz;
  110         size_t siz1;
  111         u_char *cksum;
  112         struct secasvar *sav = NULL;
  113         u_int16_t nxt;
  114         size_t hlen;
  115         int proto;
  116         size_t stripsiz = 0;
  117 
  118 #ifndef PULLDOWN_TEST
  119         if (m->m_len < off + sizeof(struct newah)) {
  120                 m = m_pullup(m, off + sizeof(struct newah));
  121                 if (!m) {
  122                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
  123                                 "dropping the packet for simplicity\n"));
  124                         ipsecstat.in_inval++;
  125                         goto fail;
  126                 }
  127         }
  128 
  129         ip = mtod(m, struct ip *);
  130         proto = ip->ip_p;
  131         ah = (struct ah *)(((caddr_t)ip) + off);
  132 #else
  133         ip = mtod(m, struct ip *);
  134         proto = ip->ip_p;
  135         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
  136         if (ah == NULL) {
  137                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;"
  138                         "dropping the packet for simplicity\n"));
  139                 ipsecstat.in_inval++;
  140                 goto fail;
  141         }
  142 #endif
  143         nxt = ah->ah_nxt;
  144 #ifdef _IP_VHL
  145         hlen = IP_VHL_HL(ip->ip_vhl) << 2;
  146 #else
  147         hlen = ip->ip_hl << 2;
  148 #endif
  149 
  150         /* find the sassoc. */
  151         spi = ah->ah_spi;
  152 
  153         if ((sav = key_allocsa(AF_INET,
  154                               (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst,
  155                               IPPROTO_AH, spi)) == 0) {
  156                 ipseclog((LOG_WARNING,
  157                     "IPv4 AH input: no key association found for spi %u\n",
  158                     (u_int32_t)ntohl(spi)));
  159                 ipsecstat.in_nosa++;
  160                 goto fail;
  161         }
  162         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  163                 printf("DP ah4_input called to allocate SA:%p\n", sav));
  164         if (sav->state != SADB_SASTATE_MATURE
  165          && sav->state != SADB_SASTATE_DYING) {
  166                 ipseclog((LOG_DEBUG,
  167                     "IPv4 AH input: non-mature/dying SA found for spi %u\n",
  168                     (u_int32_t)ntohl(spi)));
  169                 ipsecstat.in_badspi++;
  170                 goto fail;
  171         }
  172 
  173         algo = ah_algorithm_lookup(sav->alg_auth);
  174         if (!algo) {
  175                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
  176                     "unsupported authentication algorithm for spi %u\n",
  177                     (u_int32_t)ntohl(spi)));
  178                 ipsecstat.in_badspi++;
  179                 goto fail;
  180         }
  181 
  182         siz = (*algo->sumsiz)(sav);
  183         siz1 = ((siz + 3) & ~(4 - 1));
  184 
  185         /*
  186          * sanity checks for header, 1.
  187          */
  188     {
  189         int sizoff;
  190 
  191         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
  192 
  193         /*
  194          * Here, we do not do "siz1 == siz".  This is because the way
  195          * RFC240[34] section 2 is written.  They do not require truncation
  196          * to 96 bits.
  197          * For example, Microsoft IPsec stack attaches 160 bits of
  198          * authentication data for both hmac-md5 and hmac-sha1.  For hmac-sha1,
  199          * 32 bits of padding is attached.
  200          *
  201          * There are two downsides to this specification.
  202          * They have no real harm, however, they leave us fuzzy feeling.
  203          * - if we attach more than 96 bits of authentication data onto AH,
  204          *   we will never notice about possible modification by rogue
  205          *   intermediate nodes.
  206          *   Since extra bits in AH checksum is never used, this constitutes
  207          *   no real issue, however, it is wacky.
  208          * - even if the peer attaches big authentication data, we will never
  209          *   notice the difference, since longer authentication data will just
  210          *   work.
  211          *
  212          * We may need some clarification in the spec.
  213          */
  214         if (siz1 < siz) {
  215                 ipseclog((LOG_NOTICE, "sum length too short in IPv4 AH input "
  216                     "(%lu, should be at least %lu): %s\n",
  217                     (u_long)siz1, (u_long)siz,
  218                     ipsec4_logpacketstr(ip, spi)));
  219                 ipsecstat.in_inval++;
  220                 goto fail;
  221         }
  222         if ((ah->ah_len << 2) - sizoff != siz1) {
  223                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv4 AH input "
  224                     "(%d should be %lu): %s\n",
  225                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
  226                     ipsec4_logpacketstr(ip, spi)));
  227                 ipsecstat.in_inval++;
  228                 goto fail;
  229         }
  230 
  231 #ifndef PULLDOWN_TEST
  232         if (m->m_len < off + sizeof(struct ah) + sizoff + siz1) {
  233                 m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1);
  234                 if (!m) {
  235                         ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
  236                         ipsecstat.in_inval++;
  237                         goto fail;
  238                 }
  239 
  240                 ip = mtod(m, struct ip *);
  241                 ah = (struct ah *)(((caddr_t)ip) + off);
  242         }
  243 #else
  244         IP6_EXTHDR_GET(ah, struct ah *, m, off,
  245                 sizeof(struct ah) + sizoff + siz1);
  246         if (ah == NULL) {
  247                 ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n"));
  248                 ipsecstat.in_inval++;
  249                 goto fail;
  250         }
  251 #endif
  252     }
  253 
  254         /*
  255          * check for sequence number.
  256          */
  257         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
  258                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
  259                         ; /* okey */
  260                 else {
  261                         ipsecstat.in_ahreplay++;
  262                         ipseclog((LOG_WARNING,
  263                             "replay packet in IPv4 AH input: %s %s\n",
  264                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  265                         goto fail;
  266                 }
  267         }
  268 
  269         /*
  270          * alright, it seems sane.  now we are going to check the
  271          * cryptographic checksum.
  272          */
  273         cksum = malloc(siz1, M_TEMP, M_NOWAIT);
  274         if (!cksum) {
  275                 ipseclog((LOG_DEBUG, "IPv4 AH input: "
  276                     "couldn't alloc temporary region for cksum\n"));
  277                 ipsecstat.in_inval++;
  278                 goto fail;
  279         }
  280         
  281         /*
  282          * some of IP header fields are flipped to the host endian.
  283          * convert them back to network endian.  VERY stupid.
  284          */
  285         ip->ip_len = htons(ip->ip_len + hlen);
  286         ip->ip_off = htons(ip->ip_off);
  287         if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
  288                 free(cksum, M_TEMP);
  289                 ipsecstat.in_inval++;
  290                 goto fail;
  291         }
  292         ipsecstat.in_ahhist[sav->alg_auth]++;
  293         /*
  294          * flip them back.
  295          */
  296         ip->ip_len = ntohs(ip->ip_len) - hlen;
  297         ip->ip_off = ntohs(ip->ip_off);
  298 
  299     {
  300         caddr_t sumpos = NULL;
  301 
  302         if (sav->flags & SADB_X_EXT_OLD) {
  303                 /* RFC 1826 */
  304                 sumpos = (caddr_t)(ah + 1);
  305         } else {
  306                 /* RFC 2402 */
  307                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
  308         }
  309 
  310         if (bcmp(sumpos, cksum, siz) != 0) {
  311                 ipseclog((LOG_WARNING,
  312                     "checksum mismatch in IPv4 AH input: %s %s\n",
  313                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  314                 free(cksum, M_TEMP);
  315                 ipsecstat.in_ahauthfail++;
  316                 goto fail;
  317         }
  318     }
  319 
  320         free(cksum, M_TEMP);
  321 
  322         m->m_flags |= M_AUTHIPHDR;
  323         m->m_flags |= M_AUTHIPDGM;
  324 
  325 #if 0
  326         /*
  327          * looks okey, but we need more sanity check.
  328          * XXX should elaborate.
  329          */
  330         if (ah->ah_nxt == IPPROTO_IPIP || ah->ah_nxt == IPPROTO_IP) {
  331                 struct ip *nip;
  332                 size_t sizoff;
  333 
  334                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
  335 
  336                 if (m->m_len < off + sizeof(struct ah) + sizoff + siz1 + hlen) {
  337                         m = m_pullup(m, off + sizeof(struct ah)
  338                                         + sizoff + siz1 + hlen);
  339                         if (!m) {
  340                                 ipseclog((LOG_DEBUG,
  341                                     "IPv4 AH input: can't pullup\n"));
  342                                 ipsecstat.in_inval++;
  343                                 goto fail;
  344                         }
  345                 }
  346 
  347                 nip = (struct ip *)((u_char *)(ah + 1) + sizoff + siz1);
  348                 if (nip->ip_src.s_addr != ip->ip_src.s_addr
  349                  || nip->ip_dst.s_addr != ip->ip_dst.s_addr) {
  350                         m->m_flags &= ~M_AUTHIPHDR;
  351                         m->m_flags &= ~M_AUTHIPDGM;
  352                 }
  353         }
  354 #ifdef INET6
  355         else if (ah->ah_nxt == IPPROTO_IPV6) {
  356                 m->m_flags &= ~M_AUTHIPHDR;
  357                 m->m_flags &= ~M_AUTHIPDGM;
  358         }
  359 #endif /* INET6 */
  360 #endif /* 0 */
  361 
  362         if (m->m_flags & M_AUTHIPHDR
  363          && m->m_flags & M_AUTHIPDGM) {
  364 #if 0
  365                 ipseclog((LOG_DEBUG,
  366                     "IPv4 AH input: authentication succeess\n"));
  367 #endif
  368                 ipsecstat.in_ahauthsucc++;
  369         } else {
  370                 ipseclog((LOG_WARNING,
  371                     "authentication failed in IPv4 AH input: %s %s\n",
  372                     ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  373                 ipsecstat.in_ahauthfail++;
  374                 goto fail;
  375         }
  376 
  377         /*
  378          * update sequence number.
  379          */
  380         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
  381                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
  382                         ipsecstat.in_ahreplay++;
  383                         goto fail;
  384                 }
  385         }
  386 
  387         /* was it transmitted over the IPsec tunnel SA? */
  388         if (sav->flags & SADB_X_EXT_OLD) {
  389                 /* RFC 1826 */
  390                 stripsiz = sizeof(struct ah) + siz1;
  391         } else {
  392                 /* RFC 2402 */
  393                 stripsiz = sizeof(struct newah) + siz1;
  394         }
  395         if (ipsec4_tunnel_validate(m, off + stripsiz, nxt, sav)) {
  396                 /*
  397                  * strip off all the headers that precedes AH.
  398                  *      IP xx AH IP' payload -> IP' payload
  399                  *
  400                  * XXX more sanity checks
  401                  * XXX relationship with gif?
  402                  */
  403                 u_int8_t tos;
  404 
  405                 tos = ip->ip_tos;
  406                 m_adj(m, off + stripsiz);
  407                 if (m->m_len < sizeof(*ip)) {
  408                         m = m_pullup(m, sizeof(*ip));
  409                         if (!m) {
  410                                 ipsecstat.in_inval++;
  411                                 goto fail;
  412                         }
  413                 }
  414                 ip = mtod(m, struct ip *);
  415                 /* ECN consideration. */
  416                 ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos);
  417                 if (!key_checktunnelsanity(sav, AF_INET,
  418                             (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) {
  419                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
  420                             "in IPv4 AH input: %s %s\n",
  421                             ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav)));
  422                         ipsecstat.in_inval++;
  423                         goto fail;
  424                 }
  425 
  426 #if 1
  427                 /*
  428                  * Should the inner packet be considered authentic?
  429                  * My current answer is: NO.
  430                  *
  431                  * host1 -- gw1 === gw2 -- host2
  432                  *      In this case, gw2 can trust the authenticity of the
  433                  *      outer packet, but NOT inner.  Packet may be altered
  434                  *      between host1 and gw1.
  435                  *
  436                  * host1 -- gw1 === host2
  437                  *      This case falls into the same scenario as above.
  438                  *
  439                  * host1 === host2
  440                  *      This case is the only case when we may be able to leave
  441                  *      M_AUTHIPHDR and M_AUTHIPDGM set.
  442                  *      However, if host1 is wrongly configured, and allows
  443                  *      attacker to inject some packet with src=host1 and
  444                  *      dst=host2, you are in risk.
  445                  */
  446                 m->m_flags &= ~M_AUTHIPHDR;
  447                 m->m_flags &= ~M_AUTHIPDGM;
  448 #endif
  449 
  450                 key_sa_recordxfer(sav, m);
  451                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
  452                     ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) {
  453                         ipsecstat.in_nomem++;
  454                         goto fail;
  455                 }
  456 
  457                 if (! IF_HANDOFF(&ipintrq, m, NULL)) {
  458                         ipsecstat.in_inval++;
  459                         m = NULL;
  460                         goto fail;
  461                 }
  462                 m = NULL;
  463                 schednetisr(NETISR_IP); /* can be skipped but to make sure */
  464                 nxt = IPPROTO_DONE;
  465         } else {
  466                 /*
  467                  * strip off AH.
  468                  */
  469 
  470                 ip = mtod(m, struct ip *);
  471 #ifndef PULLDOWN_TEST
  472                 /*
  473                  * We do deep-copy since KAME requires that
  474                  * the packet is placed in a single external mbuf.
  475                  */
  476                 ovbcopy((caddr_t)ip, (caddr_t)(((u_char *)ip) + stripsiz), off);
  477                 m->m_data += stripsiz;
  478                 m->m_len -= stripsiz;
  479                 m->m_pkthdr.len -= stripsiz;
  480 #else
  481                 /*
  482                  * even in m_pulldown case, we need to strip off AH so that
  483                  * we can compute checksum for multiple AH correctly.
  484                  */
  485                 if (m->m_len >= stripsiz + off) {
  486                         ovbcopy((caddr_t)ip, ((caddr_t)ip) + stripsiz, off);
  487                         m->m_data += stripsiz;
  488                         m->m_len -= stripsiz;
  489                         m->m_pkthdr.len -= stripsiz;
  490                 } else {
  491                         /*
  492                          * this comes with no copy if the boundary is on
  493                          * cluster
  494                          */
  495                         struct mbuf *n;
  496 
  497                         n = m_split(m, off, M_DONTWAIT);
  498                         if (n == NULL) {
  499                                 /* m is retained by m_split */
  500                                 goto fail;
  501                         }
  502                         m_adj(n, stripsiz);
  503                         m_cat(m, n);
  504                         /* m_cat does not update m_pkthdr.len */
  505                         m->m_pkthdr.len += n->m_pkthdr.len;
  506                 }
  507 #endif
  508 
  509                 if (m->m_len < sizeof(*ip)) {
  510                         m = m_pullup(m, sizeof(*ip));
  511                         if (m == NULL) {
  512                                 ipsecstat.in_inval++;
  513                                 goto fail;
  514                         }
  515                 }
  516                 ip = mtod(m, struct ip *);
  517 #ifdef IPLEN_FLIPPED
  518                 ip->ip_len = ip->ip_len - stripsiz;
  519 #else
  520                 ip->ip_len = htons(ntohs(ip->ip_len) - stripsiz);
  521 #endif
  522                 ip->ip_p = nxt;
  523                 /* forget about IP hdr checksum, the check has already been passed */
  524 
  525                 key_sa_recordxfer(sav, m);
  526                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
  527                         ipsecstat.in_nomem++;
  528                         goto fail;
  529                 }
  530 
  531                 if (nxt != IPPROTO_DONE) {
  532                         if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
  533                             ipsec4_in_reject(m, NULL)) {
  534                                 ipsecstat.in_polvio++;
  535                                 goto fail;
  536                         }
  537                         (*inetsw[ip_protox[nxt]].pr_input)(m, off);
  538                 } else
  539                         m_freem(m);
  540                 m = NULL;
  541         }
  542 
  543         if (sav) {
  544                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  545                         printf("DP ah4_input call free SA:%p\n", sav));
  546                 key_freesav(sav);
  547         }
  548         ipsecstat.in_success++;
  549         return;
  550 
  551 fail:
  552         if (sav) {
  553                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  554                         printf("DP ah4_input call free SA:%p\n", sav));
  555                 key_freesav(sav);
  556         }
  557         if (m)
  558                 m_freem(m);
  559         return;
  560 }
  561 #endif /* INET */
  562 
  563 #ifdef INET6
  564 int
  565 ah6_input(mp, offp, proto)
  566         struct mbuf **mp;
  567         int *offp, proto;
  568 {
  569         struct mbuf *m = *mp;
  570         int off = *offp;
  571         struct ip6_hdr *ip6;
  572         struct ah *ah;
  573         u_int32_t spi;
  574         const struct ah_algorithm *algo;
  575         size_t siz;
  576         size_t siz1;
  577         u_char *cksum;
  578         struct secasvar *sav = NULL;
  579         u_int16_t nxt;
  580         size_t stripsiz = 0;
  581 
  582 #ifndef PULLDOWN_TEST
  583         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE);
  584         ah = (struct ah *)(mtod(m, caddr_t) + off);
  585 #else
  586         IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah));
  587         if (ah == NULL) {
  588                 ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n"));
  589                 ipsec6stat.in_inval++;
  590                 return IPPROTO_DONE;
  591         }
  592 #endif
  593         ip6 = mtod(m, struct ip6_hdr *);
  594         nxt = ah->ah_nxt;
  595 
  596         /* find the sassoc. */
  597         spi = ah->ah_spi;
  598 
  599         if (ntohs(ip6->ip6_plen) == 0) {
  600                 ipseclog((LOG_ERR, "IPv6 AH input: "
  601                     "AH with IPv6 jumbogram is not supported.\n"));
  602                 ipsec6stat.in_inval++;
  603                 goto fail;
  604         }
  605 
  606         if ((sav = key_allocsa(AF_INET6,
  607                               (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst,
  608                               IPPROTO_AH, spi)) == 0) {
  609                 ipseclog((LOG_WARNING,
  610                     "IPv6 AH input: no key association found for spi %u\n",
  611                     (u_int32_t)ntohl(spi)));
  612                 ipsec6stat.in_nosa++;
  613                 goto fail;
  614         }
  615         KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  616                 printf("DP ah6_input called to allocate SA:%p\n", sav));
  617         if (sav->state != SADB_SASTATE_MATURE
  618          && sav->state != SADB_SASTATE_DYING) {
  619                 ipseclog((LOG_DEBUG,
  620                     "IPv6 AH input: non-mature/dying SA found for spi %u; ",
  621                     (u_int32_t)ntohl(spi)));
  622                 ipsec6stat.in_badspi++;
  623                 goto fail;
  624         }
  625 
  626         algo = ah_algorithm_lookup(sav->alg_auth);
  627         if (!algo) {
  628                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
  629                     "unsupported authentication algorithm for spi %u\n",
  630                     (u_int32_t)ntohl(spi)));
  631                 ipsec6stat.in_badspi++;
  632                 goto fail;
  633         }
  634 
  635         siz = (*algo->sumsiz)(sav);
  636         siz1 = ((siz + 3) & ~(4 - 1));
  637 
  638         /*
  639          * sanity checks for header, 1.
  640          */
  641     {
  642         int sizoff;
  643 
  644         sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
  645 
  646         /*
  647          * Here, we do not do "siz1 == siz".  See ah4_input() for complete
  648          * description.
  649          */
  650         if (siz1 < siz) {
  651                 ipseclog((LOG_NOTICE, "sum length too short in IPv6 AH input "
  652                     "(%lu, should be at least %lu): %s\n",
  653                     (u_long)siz1, (u_long)siz,
  654                     ipsec6_logpacketstr(ip6, spi)));
  655                 ipsec6stat.in_inval++;
  656                 goto fail;
  657         }
  658         if ((ah->ah_len << 2) - sizoff != siz1) {
  659                 ipseclog((LOG_NOTICE, "sum length mismatch in IPv6 AH input "
  660                     "(%d should be %lu): %s\n",
  661                     (ah->ah_len << 2) - sizoff, (u_long)siz1,
  662                     ipsec6_logpacketstr(ip6, spi)));
  663                 ipsec6stat.in_inval++;
  664                 goto fail;
  665         }
  666 #ifndef PULLDOWN_TEST
  667         IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, IPPROTO_DONE);
  668 #else
  669         IP6_EXTHDR_GET(ah, struct ah *, m, off,
  670                 sizeof(struct ah) + sizoff + siz1);
  671         if (ah == NULL) {
  672                 ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part"));
  673                 ipsec6stat.in_inval++;
  674                 m = NULL;
  675                 goto fail;
  676         }
  677 #endif
  678     }
  679 
  680         /*
  681          * check for sequence number.
  682          */
  683         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
  684                 if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav))
  685                         ; /* okey */
  686                 else {
  687                         ipsec6stat.in_ahreplay++;
  688                         ipseclog((LOG_WARNING,
  689                             "replay packet in IPv6 AH input: %s %s\n",
  690                             ipsec6_logpacketstr(ip6, spi),
  691                             ipsec_logsastr(sav)));
  692                         goto fail;
  693                 }
  694         }
  695 
  696         /*
  697          * alright, it seems sane.  now we are going to check the
  698          * cryptographic checksum.
  699          */
  700         cksum = malloc(siz1, M_TEMP, M_NOWAIT);
  701         if (!cksum) {
  702                 ipseclog((LOG_DEBUG, "IPv6 AH input: "
  703                     "couldn't alloc temporary region for cksum\n"));
  704                 ipsec6stat.in_inval++;
  705                 goto fail;
  706         }
  707         
  708         if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) {
  709                 free(cksum, M_TEMP);
  710                 ipsec6stat.in_inval++;
  711                 goto fail;
  712         }
  713         ipsec6stat.in_ahhist[sav->alg_auth]++;
  714 
  715     {
  716         caddr_t sumpos = NULL;
  717 
  718         if (sav->flags & SADB_X_EXT_OLD) {
  719                 /* RFC 1826 */
  720                 sumpos = (caddr_t)(ah + 1);
  721         } else {
  722                 /* RFC 2402 */
  723                 sumpos = (caddr_t)(((struct newah *)ah) + 1);
  724         }
  725 
  726         if (bcmp(sumpos, cksum, siz) != 0) {
  727                 ipseclog((LOG_WARNING,
  728                     "checksum mismatch in IPv6 AH input: %s %s\n",
  729                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
  730                 free(cksum, M_TEMP);
  731                 ipsec6stat.in_ahauthfail++;
  732                 goto fail;
  733         }
  734     }
  735 
  736         free(cksum, M_TEMP);
  737 
  738         m->m_flags |= M_AUTHIPHDR;
  739         m->m_flags |= M_AUTHIPDGM;
  740 
  741 #if 0
  742         /*
  743          * looks okey, but we need more sanity check.
  744          * XXX should elaborate.
  745          */
  746         if (ah->ah_nxt == IPPROTO_IPV6) {
  747                 struct ip6_hdr *nip6;
  748                 size_t sizoff;
  749 
  750                 sizoff = (sav->flags & SADB_X_EXT_OLD) ? 0 : 4;
  751 
  752                 IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1
  753                                 + sizeof(struct ip6_hdr), IPPROTO_DONE);
  754 
  755                 nip6 = (struct ip6_hdr *)((u_char *)(ah + 1) + sizoff + siz1);
  756                 if (!IN6_ARE_ADDR_EQUAL(&nip6->ip6_src, &ip6->ip6_src)
  757                  || !IN6_ARE_ADDR_EQUAL(&nip6->ip6_dst, &ip6->ip6_dst)) {
  758                         m->m_flags &= ~M_AUTHIPHDR;
  759                         m->m_flags &= ~M_AUTHIPDGM;
  760                 }
  761         } else if (ah->ah_nxt == IPPROTO_IPIP) {
  762                 m->m_flags &= ~M_AUTHIPHDR;
  763                 m->m_flags &= ~M_AUTHIPDGM;
  764         } else if (ah->ah_nxt == IPPROTO_IP) {
  765                 m->m_flags &= ~M_AUTHIPHDR;
  766                 m->m_flags &= ~M_AUTHIPDGM;
  767         }
  768 #endif
  769 
  770         if (m->m_flags & M_AUTHIPHDR
  771          && m->m_flags & M_AUTHIPDGM) {
  772 #if 0
  773                 ipseclog((LOG_DEBUG,
  774                     "IPv6 AH input: authentication succeess\n"));
  775 #endif
  776                 ipsec6stat.in_ahauthsucc++;
  777         } else {
  778                 ipseclog((LOG_WARNING,
  779                     "authentication failed in IPv6 AH input: %s %s\n",
  780                     ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav)));
  781                 ipsec6stat.in_ahauthfail++;
  782                 goto fail;
  783         }
  784 
  785         /*
  786          * update sequence number.
  787          */
  788         if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) {
  789                 if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) {
  790                         ipsec6stat.in_ahreplay++;
  791                         goto fail;
  792                 }
  793         }
  794 
  795         /* was it transmitted over the IPsec tunnel SA? */
  796         if (sav->flags & SADB_X_EXT_OLD) {
  797                 /* RFC 1826 */
  798                 stripsiz = sizeof(struct ah) + siz1;
  799         } else {
  800                 /* RFC 2402 */
  801                 stripsiz = sizeof(struct newah) + siz1;
  802         }
  803         if (ipsec6_tunnel_validate(m, off + stripsiz, nxt, sav)) {
  804                 /*
  805                  * strip off all the headers that precedes AH.
  806                  *      IP6 xx AH IP6' payload -> IP6' payload
  807                  *
  808                  * XXX more sanity checks
  809                  * XXX relationship with gif?
  810                  */
  811                 u_int32_t flowinfo;     /* net endian */
  812 
  813                 flowinfo = ip6->ip6_flow;
  814                 m_adj(m, off + stripsiz);
  815                 if (m->m_len < sizeof(*ip6)) {
  816                         /*
  817                          * m_pullup is prohibited in KAME IPv6 input processing
  818                          * but there's no other way!
  819                          */
  820                         m = m_pullup(m, sizeof(*ip6));
  821                         if (!m) {
  822                                 ipsec6stat.in_inval++;
  823                                 goto fail;
  824                         }
  825                 }
  826                 ip6 = mtod(m, struct ip6_hdr *);
  827                 /* ECN consideration. */
  828                 ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow);
  829                 if (!key_checktunnelsanity(sav, AF_INET6,
  830                             (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) {
  831                         ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch "
  832                             "in IPv6 AH input: %s %s\n",
  833                             ipsec6_logpacketstr(ip6, spi),
  834                             ipsec_logsastr(sav)));
  835                         ipsec6stat.in_inval++;
  836                         goto fail;
  837                 }
  838 
  839 #if 1
  840                 /*
  841                  * should the inner packet be considered authentic?
  842                  * see comment in ah4_input().
  843                  */
  844                 m->m_flags &= ~M_AUTHIPHDR;
  845                 m->m_flags &= ~M_AUTHIPDGM;
  846 #endif
  847 
  848                 key_sa_recordxfer(sav, m);
  849                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 ||
  850                     ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) {
  851                         ipsec6stat.in_nomem++;
  852                         goto fail;
  853                 }
  854 
  855                 if (! IF_HANDOFF(&ip6intrq, m, NULL)) {
  856                         ipsec6stat.in_inval++;
  857                         m = NULL;
  858                         goto fail;
  859                 }
  860                 m = NULL;
  861                 schednetisr(NETISR_IPV6); /* can be skipped but to make sure */
  862                 nxt = IPPROTO_DONE;
  863         } else {
  864                 /*
  865                  * strip off AH.
  866                  */
  867                 char *prvnxtp;
  868 
  869                 /*
  870                  * Copy the value of the next header field of AH to the
  871                  * next header field of the previous header.
  872                  * This is necessary because AH will be stripped off below.
  873                  */
  874                 prvnxtp = ip6_get_prevhdr(m, off); /* XXX */
  875                 *prvnxtp = nxt;
  876 
  877                 ip6 = mtod(m, struct ip6_hdr *);
  878 #ifndef PULLDOWN_TEST
  879                 /*
  880                  * We do deep-copy since KAME requires that
  881                  * the packet is placed in a single mbuf.
  882                  */
  883                 ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
  884                 m->m_data += stripsiz;
  885                 m->m_len -= stripsiz;
  886                 m->m_pkthdr.len -= stripsiz;
  887 #else
  888                 /*
  889                  * even in m_pulldown case, we need to strip off AH so that
  890                  * we can compute checksum for multiple AH correctly.
  891                  */
  892                 if (m->m_len >= stripsiz + off) {
  893                         ovbcopy((caddr_t)ip6, ((caddr_t)ip6) + stripsiz, off);
  894                         m->m_data += stripsiz;
  895                         m->m_len -= stripsiz;
  896                         m->m_pkthdr.len -= stripsiz;
  897                 } else {
  898                         /*
  899                          * this comes with no copy if the boundary is on
  900                          * cluster
  901                          */
  902                         struct mbuf *n;
  903 
  904                         n = m_split(m, off, M_DONTWAIT);
  905                         if (n == NULL) {
  906                                 /* m is retained by m_split */
  907                                 goto fail;
  908                         }
  909                         m_adj(n, stripsiz);
  910                         m_cat(m, n);
  911                         /* m_cat does not update m_pkthdr.len */
  912                         m->m_pkthdr.len += n->m_pkthdr.len;
  913                 }
  914 #endif
  915                 ip6 = mtod(m, struct ip6_hdr *);
  916                 /* XXX jumbogram */
  917                 ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - stripsiz);
  918 
  919                 key_sa_recordxfer(sav, m);
  920                 if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) {
  921                         ipsec6stat.in_nomem++;
  922                         goto fail;
  923                 }
  924         }
  925 
  926         *offp = off;
  927         *mp = m;
  928 
  929         if (sav) {
  930                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  931                         printf("DP ah6_input call free SA:%p\n", sav));
  932                 key_freesav(sav);
  933         }
  934         ipsec6stat.in_success++;
  935         return nxt;
  936 
  937 fail:
  938         if (sav) {
  939                 KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
  940                         printf("DP ah6_input call free SA:%p\n", sav));
  941                 key_freesav(sav);
  942         }
  943         if (m)
  944                 m_freem(m);
  945         return IPPROTO_DONE;
  946 }
  947 
  948 void
  949 ah6_ctlinput(cmd, sa, d)
  950         int cmd;
  951         struct sockaddr *sa;
  952         void *d;
  953 {
  954         const struct newah *ahp;
  955         struct newah ah;
  956         struct secasvar *sav;
  957         struct ip6_hdr *ip6;
  958         struct mbuf *m;
  959         struct ip6ctlparam *ip6cp = NULL;
  960         int off;
  961         struct sockaddr_in6 *sa6_src, *sa6_dst;
  962 
  963         if (sa->sa_family != AF_INET6 ||
  964             sa->sa_len != sizeof(struct sockaddr_in6))
  965                 return;
  966         if ((unsigned)cmd >= PRC_NCMDS)
  967                 return;
  968 
  969         /* if the parameter is from icmp6, decode it. */
  970         if (d != NULL) {
  971                 ip6cp = (struct ip6ctlparam *)d;
  972                 m = ip6cp->ip6c_m;
  973                 ip6 = ip6cp->ip6c_ip6;
  974                 off = ip6cp->ip6c_off;
  975         } else {
  976                 m = NULL;
  977                 ip6 = NULL;
  978                 off = 0;        /* calm gcc */
  979         }
  980 
  981         if (ip6) {
  982                 /*
  983                  * XXX: We assume that when ip6 is non NULL,
  984                  * M and OFF are valid.
  985                  */
  986 
  987                 /* check if we can safely examine src and dst ports */
  988                 if (m->m_pkthdr.len < off + sizeof(ah))
  989                         return;
  990 
  991                 if (m->m_len < off + sizeof(ah)) {
  992                         /*
  993                          * this should be rare case,
  994                          * so we compromise on this copy...
  995                          */
  996                         m_copydata(m, off, sizeof(ah), (caddr_t)&ah);
  997                         ahp = &ah;
  998                 } else
  999                         ahp = (struct newah *)(mtod(m, caddr_t) + off);
 1000 
 1001                 if (cmd == PRC_MSGSIZE) {
 1002                         int valid = 0;
 1003 
 1004                         /*
 1005                          * Check to see if we have a valid SA corresponding to
 1006                          * the address in the ICMP message payload.
 1007                          */
 1008                         sa6_src = ip6cp->ip6c_src;
 1009                         sa6_dst = (struct sockaddr_in6 *)sa;
 1010                         sav = key_allocsa(AF_INET6,
 1011                                           (caddr_t)&sa6_src->sin6_addr,
 1012                                           (caddr_t)&sa6_dst->sin6_addr,
 1013                                           IPPROTO_AH, ahp->ah_spi);
 1014                         if (sav) {
 1015                                 if (sav->state == SADB_SASTATE_MATURE ||
 1016                                     sav->state == SADB_SASTATE_DYING)
 1017                                         valid++;
 1018                                 key_freesav(sav);
 1019                         }
 1020 
 1021                         /* XXX Further validation? */
 1022 
 1023                         /*
 1024                          * Depending on the value of "valid" and routing table
 1025                          * size (mtudisc_{hi,lo}wat), we will:
 1026                          * - recalcurate the new MTU and create the
 1027                          *   corresponding routing entry, or
 1028                          * - ignore the MTU change notification.
 1029                          */
 1030                         icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
 1031                 }
 1032 
 1033                 /* we normally notify single pcb here */
 1034         } else {
 1035                 /* we normally notify any pcb here */
 1036         }
 1037 }
 1038 #endif /* INET6 */

Cache object: 4e4a417e63c241be71d743a301775354


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