The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netipsec/ipsec_input.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $FreeBSD: stable/4/sys/netipsec/ipsec_input.c 112759 2003-03-28 20:32:53Z sam $ */
    2 /*      $OpenBSD: ipsec_input.c,v 1.63 2003/02/20 18:35:43 deraadt Exp $        */
    3 /*
    4  * The authors of this code are John Ioannidis (ji@tla.org),
    5  * Angelos D. Keromytis (kermit@csd.uch.gr) and
    6  * Niels Provos (provos@physnet.uni-hamburg.de).
    7  *
    8  * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
    9  * in November 1995.
   10  *
   11  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
   12  * by Angelos D. Keromytis.
   13  *
   14  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
   15  * and Niels Provos.
   16  *
   17  * Additional features in 1999 by Angelos D. Keromytis.
   18  *
   19  * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
   20  * Angelos D. Keromytis and Niels Provos.
   21  * Copyright (c) 2001, Angelos D. Keromytis.
   22  *
   23  * Permission to use, copy, and modify this software with or without fee
   24  * is hereby granted, provided that this entire notice is included in
   25  * all copies of any software which is or includes a copy or
   26  * modification of this software.
   27  * You may use this code under the GNU public license if you so wish. Please
   28  * contribute changes back to the authors under this freer than GPL license
   29  * so that we may further the use of strong encryption without limitations to
   30  * all.
   31  *
   32  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
   33  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
   34  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
   35  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
   36  * PURPOSE.
   37  */
   38 
   39 /*
   40  * IPsec input processing.
   41  */
   42 
   43 #include "opt_inet.h"
   44 #include "opt_inet6.h"
   45 #include "opt_ipsec.h"
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/malloc.h>
   50 #include <sys/mbuf.h>
   51 #include <sys/domain.h>
   52 #include <sys/protosw.h>
   53 #include <sys/socket.h>
   54 #include <sys/errno.h>
   55 #include <sys/syslog.h>
   56 
   57 #include <net/if.h>
   58 #include <net/route.h>
   59 #include <net/netisr.h>
   60 
   61 #include <netinet/in.h>
   62 #include <netinet/in_systm.h>
   63 #include <netinet/ip.h>
   64 #include <netinet/ip_var.h>
   65 #include <netinet/in_var.h>
   66 
   67 #include <netinet/ip6.h>
   68 #ifdef INET6
   69 #include <netinet6/ip6_var.h>
   70 #endif
   71 #include <netinet/in_pcb.h>
   72 #ifdef INET6
   73 #include <netinet/icmp6.h>
   74 #endif
   75 
   76 #include <netipsec/ipsec.h>
   77 #ifdef INET6
   78 #include <netipsec/ipsec6.h>
   79 #endif
   80 #include <netipsec/ah_var.h>
   81 #include <netipsec/esp.h>
   82 #include <netipsec/esp_var.h>
   83 #include <netipsec/ipcomp_var.h>
   84 
   85 #include <netipsec/key.h>
   86 #include <netipsec/keydb.h>
   87 
   88 #include <netipsec/xform.h>
   89 #include <netinet6/ip6protosw.h>
   90 
   91 #include <machine/in_cksum.h>
   92 #include <machine/stdarg.h>
   93 
   94 #include <net/net_osdep.h>
   95 
   96 #define IPSEC_ISTAT(p,x,y,z) ((p) == IPPROTO_ESP ? (x)++ : \
   97                             (p) == IPPROTO_AH ? (y)++ : (z)++)
   98 
   99 /*
  100  * ipsec_common_input gets called when an IPsec-protected packet
  101  * is received by IPv4 or IPv6.  It's job is to find the right SA
  102  # and call the appropriate transform.  The transform callback
  103  * takes care of further processing (like ingress filtering).
  104  */
  105 static int
  106 ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
  107 {
  108         union sockaddr_union dst_address;
  109         struct secasvar *sav;
  110         u_int32_t spi;
  111         int s, error;
  112 
  113         IPSEC_ISTAT(sproto, espstat.esps_input, ahstat.ahs_input,
  114                 ipcompstat.ipcomps_input);
  115 
  116         KASSERT(m != NULL, ("ipsec_common_input: null packet"));
  117 
  118         if ((sproto == IPPROTO_ESP && !esp_enable) ||
  119             (sproto == IPPROTO_AH && !ah_enable) ||
  120             (sproto == IPPROTO_IPCOMP && !ipcomp_enable)) {
  121                 m_freem(m);
  122                 IPSEC_ISTAT(sproto, espstat.esps_pdrops, ahstat.ahs_pdrops,
  123                     ipcompstat.ipcomps_pdrops);
  124                 return EOPNOTSUPP;
  125         }
  126 
  127         if (m->m_pkthdr.len - skip < 2 * sizeof (u_int32_t)) {
  128                 m_freem(m);
  129                 IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
  130                     ipcompstat.ipcomps_hdrops);
  131                 DPRINTF(("ipsec_common_input: packet too small\n"));
  132                 return EINVAL;
  133         }
  134 
  135         /* Retrieve the SPI from the relevant IPsec header */
  136         if (sproto == IPPROTO_ESP)
  137                 m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi);
  138         else if (sproto == IPPROTO_AH)
  139                 m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t),
  140                     (caddr_t) &spi);
  141         else if (sproto == IPPROTO_IPCOMP) {
  142                 u_int16_t cpi;
  143                 m_copydata(m, skip + sizeof(u_int16_t), sizeof(u_int16_t),
  144                     (caddr_t) &cpi);
  145                 spi = ntohl(htons(cpi));
  146         }
  147 
  148         /*
  149          * Find the SA and (indirectly) call the appropriate
  150          * kernel crypto routine. The resulting mbuf chain is a valid
  151          * IP packet ready to go through input processing.
  152          */
  153         bzero(&dst_address, sizeof (dst_address));
  154         dst_address.sa.sa_family = af;
  155         switch (af) {
  156 #ifdef INET
  157         case AF_INET:
  158                 dst_address.sin.sin_len = sizeof(struct sockaddr_in);
  159                 m_copydata(m, offsetof(struct ip, ip_dst),
  160                     sizeof(struct in_addr),
  161                     (caddr_t) &dst_address.sin.sin_addr);
  162                 break;
  163 #endif /* INET */
  164 #ifdef INET6
  165         case AF_INET6:
  166                 dst_address.sin6.sin6_len = sizeof(struct sockaddr_in6);
  167                 m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
  168                     sizeof(struct in6_addr),
  169                     (caddr_t) &dst_address.sin6.sin6_addr);
  170                 break;
  171 #endif /* INET6 */
  172         default:
  173                 DPRINTF(("ipsec_common_input: unsupported protocol "
  174                         "family %u\n", af));
  175                 m_freem(m);
  176                 IPSEC_ISTAT(sproto, espstat.esps_nopf, ahstat.ahs_nopf,
  177                     ipcompstat.ipcomps_nopf);
  178                 return EPFNOSUPPORT;
  179         }
  180 
  181         s = splnet();
  182 
  183         /* NB: only pass dst since key_allocsa follows RFC2401 */
  184         sav = KEY_ALLOCSA(&dst_address, sproto, spi);
  185         if (sav == NULL) {
  186                 DPRINTF(("ipsec_common_input: no key association found for"
  187                           " SA %s/%08lx/%u\n",
  188                           ipsec_address(&dst_address),
  189                           (u_long) ntohl(spi), sproto));
  190                 IPSEC_ISTAT(sproto, espstat.esps_notdb, ahstat.ahs_notdb,
  191                     ipcompstat.ipcomps_notdb);
  192                 splx(s);
  193                 m_freem(m);
  194                 return ENOENT;
  195         }
  196 
  197         if (sav->tdb_xform == NULL) {
  198                 DPRINTF(("ipsec_common_input: attempted to use uninitialized"
  199                          " SA %s/%08lx/%u\n",
  200                          ipsec_address(&dst_address),
  201                          (u_long) ntohl(spi), sproto));
  202                 IPSEC_ISTAT(sproto, espstat.esps_noxform, ahstat.ahs_noxform,
  203                     ipcompstat.ipcomps_noxform);
  204                 KEY_FREESAV(&sav);
  205                 splx(s);
  206                 m_freem(m);
  207                 return ENXIO;
  208         }
  209 
  210         /*
  211          * Call appropriate transform and return -- callback takes care of
  212          * everything else.
  213          */
  214         error = (*sav->tdb_xform->xf_input)(m, sav, skip, protoff);
  215         KEY_FREESAV(&sav);
  216         splx(s);
  217         return error;
  218 }
  219 
  220 #ifdef INET
  221 /*
  222  * Common input handler for IPv4 AH, ESP, and IPCOMP.
  223  */
  224 int
  225 ipsec4_common_input(struct mbuf *m, ...)
  226 {
  227         va_list ap;
  228         int off, nxt;
  229 
  230         va_start(ap, m);
  231         off = va_arg(ap, int);
  232         nxt = va_arg(ap, int);
  233         va_end(ap);
  234 
  235         return ipsec_common_input(m, off, offsetof(struct ip, ip_p),
  236                                   AF_INET, nxt);
  237 }
  238 
  239 /*
  240  * IPsec input callback for INET protocols.
  241  * This routine is called as the transform callback.
  242  * Takes care of filtering and other sanity checks on
  243  * the processed packet.
  244  */
  245 int
  246 ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav,
  247                         int skip, int protoff, struct m_tag *mt)
  248 {
  249         int prot, af, sproto;
  250         struct ip *ip;
  251         struct m_tag *mtag;
  252         struct tdb_ident *tdbi;
  253         struct secasindex *saidx;
  254         int error;
  255 
  256         SPLASSERT(net, "ipsec4_common_input_cb");
  257 
  258         KASSERT(m != NULL, ("ipsec4_common_input_cb: null mbuf"));
  259         KASSERT(sav != NULL, ("ipsec4_common_input_cb: null SA"));
  260         KASSERT(sav->sah != NULL, ("ipsec4_common_input_cb: null SAH"));
  261         saidx = &sav->sah->saidx;
  262         af = saidx->dst.sa.sa_family;
  263         KASSERT(af == AF_INET, ("ipsec4_common_input_cb: unexpected af %u",af));
  264         sproto = saidx->proto;
  265         KASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
  266                 sproto == IPPROTO_IPCOMP,
  267                 ("ipsec4_common_input_cb: unexpected security protocol %u",
  268                 sproto));
  269 
  270         /* Sanity check */
  271         if (m == NULL) {
  272                 DPRINTF(("ipsec4_common_input_cb: null mbuf"));
  273                 IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
  274                     ipcompstat.ipcomps_badkcr);
  275                 KEY_FREESAV(&sav);
  276                 return EINVAL;
  277         }
  278 
  279         if (skip != 0) {
  280                 /* Fix IPv4 header */
  281                 if (m->m_len < skip && (m = m_pullup(m, skip)) == NULL) {
  282                         DPRINTF(("ipsec4_common_input_cb: processing failed "
  283                             "for SA %s/%08lx\n",
  284                             ipsec_address(&sav->sah->saidx.dst),
  285                             (u_long) ntohl(sav->spi)));
  286                         IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
  287                             ipcompstat.ipcomps_hdrops);
  288                         error = ENOBUFS;
  289                         goto bad;
  290                 }
  291 
  292                 ip = mtod(m, struct ip *);
  293                 ip->ip_len = htons(m->m_pkthdr.len);
  294                 ip->ip_off = htons(ip->ip_off);
  295                 ip->ip_sum = 0;
  296                 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
  297         } else {
  298                 ip = mtod(m, struct ip *);
  299         }
  300         prot = ip->ip_p;
  301 
  302         /* IP-in-IP encapsulation */
  303         if (prot == IPPROTO_IPIP) {
  304                 struct ip ipn;
  305 
  306                 /* ipn will now contain the inner IPv4 header */
  307                 m_copydata(m, ip->ip_hl << 2, sizeof(struct ip),
  308                     (caddr_t) &ipn);
  309 
  310 #ifdef notyet
  311                 /* XXX PROXY address isn't recorded in SAH */
  312                 /*
  313                  * Check that the inner source address is the same as
  314                  * the proxy address, if available.
  315                  */
  316                 if ((saidx->proxy.sa.sa_family == AF_INET &&
  317                     saidx->proxy.sin.sin_addr.s_addr !=
  318                     INADDR_ANY &&
  319                     ipn.ip_src.s_addr !=
  320                     saidx->proxy.sin.sin_addr.s_addr) ||
  321                     (saidx->proxy.sa.sa_family != AF_INET &&
  322                         saidx->proxy.sa.sa_family != 0)) {
  323 
  324                         DPRINTF(("ipsec4_common_input_cb: inner "
  325                             "source address %s doesn't correspond to "
  326                             "expected proxy source %s, SA %s/%08lx\n",
  327                             inet_ntoa4(ipn.ip_src),
  328                             ipsp_address(saidx->proxy),
  329                             ipsp_address(saidx->dst),
  330                             (u_long) ntohl(sav->spi)));
  331 
  332                         IPSEC_ISTAT(sproto, espstat.esps_pdrops,
  333                             ahstat.ahs_pdrops,
  334                             ipcompstat.ipcomps_pdrops);
  335                         error = EACCES;
  336                         goto bad;
  337                 }
  338 #endif /*XXX*/
  339         }
  340 #if INET6
  341         /* IPv6-in-IP encapsulation. */
  342         if (prot == IPPROTO_IPV6) {
  343                 struct ip6_hdr ip6n;
  344 
  345                 /* ip6n will now contain the inner IPv6 header. */
  346                 m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr),
  347                     (caddr_t) &ip6n);
  348 
  349 #ifdef notyet
  350                 /*
  351                  * Check that the inner source address is the same as
  352                  * the proxy address, if available.
  353                  */
  354                 if ((saidx->proxy.sa.sa_family == AF_INET6 &&
  355                     !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
  356                     !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
  357                         &saidx->proxy.sin6.sin6_addr)) ||
  358                     (saidx->proxy.sa.sa_family != AF_INET6 &&
  359                         saidx->proxy.sa.sa_family != 0)) {
  360 
  361                         DPRINTF(("ipsec4_common_input_cb: inner "
  362                             "source address %s doesn't correspond to "
  363                             "expected proxy source %s, SA %s/%08lx\n",
  364                             ip6_sprintf(&ip6n.ip6_src),
  365                             ipsec_address(&saidx->proxy),
  366                             ipsec_address(&saidx->dst),
  367                             (u_long) ntohl(sav->spi)));
  368 
  369                         IPSEC_ISTAT(sproto, espstat.esps_pdrops,
  370                             ahstat.ahs_pdrops,
  371                             ipcompstat.ipcomps_pdrops);
  372                         error = EACCES;
  373                         goto bad;
  374                 }
  375 #endif /*XXX*/
  376         }
  377 #endif /* INET6 */
  378 
  379         /*
  380          * Record what we've done to the packet (under what SA it was
  381          * processed). If we've been passed an mtag, it means the packet
  382          * was already processed by an ethernet/crypto combo card and
  383          * thus has a tag attached with all the right information, but
  384          * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
  385          * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
  386          */
  387         if (mt == NULL && sproto != IPPROTO_IPCOMP) {
  388                 mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
  389                     sizeof(struct tdb_ident), M_NOWAIT);
  390                 if (mtag == NULL) {
  391                         DPRINTF(("ipsec4_common_input_cb: failed to get tag\n"));
  392                         IPSEC_ISTAT(sproto, espstat.esps_hdrops,
  393                             ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
  394                         error = ENOMEM;
  395                         goto bad;
  396                 }
  397 
  398                 tdbi = (struct tdb_ident *)(mtag + 1);
  399                 bcopy(&saidx->dst, &tdbi->dst, saidx->dst.sa.sa_len);
  400                 tdbi->proto = sproto;
  401                 tdbi->spi = sav->spi;
  402 
  403                 m_tag_prepend(m, mtag);
  404         } else {
  405                 mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
  406                 /* XXX do we need to mark m_flags??? */
  407         }
  408 
  409         key_sa_recordxfer(sav, m);              /* record data transfer */
  410 
  411         /*
  412          * Re-dispatch via software interrupt.
  413          */
  414         if (!IF_HANDOFF(&ipintrq, m, NULL)) {
  415                 IPSEC_ISTAT(sproto, espstat.esps_qfull, ahstat.ahs_qfull,
  416                             ipcompstat.ipcomps_qfull);
  417 
  418                 DPRINTF(("ipsec4_common_input_cb: queue full; "
  419                         "proto %u packet dropped\n", sproto));
  420                 return ENOBUFS;
  421         }
  422         schednetisr(NETISR_IP);
  423         return 0;
  424 bad:
  425         m_freem(m);
  426         return error;
  427 }
  428 #endif /* INET */
  429 
  430 #ifdef INET6
  431 /* IPv6 AH wrapper. */
  432 int
  433 ipsec6_common_input(struct mbuf **mp, int *offp, int proto)
  434 {
  435         int l = 0;
  436         int protoff;
  437         struct ip6_ext ip6e;
  438 
  439         if (*offp < sizeof(struct ip6_hdr)) {
  440                 DPRINTF(("ipsec6_common_input: bad offset %u\n", *offp));
  441                 return IPPROTO_DONE;
  442         } else if (*offp == sizeof(struct ip6_hdr)) {
  443                 protoff = offsetof(struct ip6_hdr, ip6_nxt);
  444         } else {
  445                 /* Chase down the header chain... */
  446                 protoff = sizeof(struct ip6_hdr);
  447 
  448                 do {
  449                         protoff += l;
  450                         m_copydata(*mp, protoff, sizeof(ip6e),
  451                             (caddr_t) &ip6e);
  452 
  453                         if (ip6e.ip6e_nxt == IPPROTO_AH)
  454                                 l = (ip6e.ip6e_len + 2) << 2;
  455                         else
  456                                 l = (ip6e.ip6e_len + 1) << 3;
  457                         KASSERT(l > 0, ("ah6_input: l went zero or negative"));
  458                 } while (protoff + l < *offp);
  459 
  460                 /* Malformed packet check */
  461                 if (protoff + l != *offp) {
  462                         DPRINTF(("ipsec6_common_input: bad packet header chain, "
  463                                 "protoff %u, l %u, off %u\n", protoff, l, *offp));
  464                         IPSEC_ISTAT(proto, espstat.esps_hdrops,
  465                                     ahstat.ahs_hdrops,
  466                                     ipcompstat.ipcomps_hdrops);
  467                         m_freem(*mp);
  468                         *mp = NULL;
  469                         return IPPROTO_DONE;
  470                 }
  471                 protoff += offsetof(struct ip6_ext, ip6e_nxt);
  472         }
  473         (void) ipsec_common_input(*mp, *offp, protoff, AF_INET6, proto);
  474         return IPPROTO_DONE;
  475 }
  476 
  477 void
  478 esp6_ctlinput(int cmd, struct sockaddr *sa, void *d)
  479 {
  480         if (sa->sa_family != AF_INET6 ||
  481             sa->sa_len != sizeof(struct sockaddr_in6))
  482                 return;
  483         if ((unsigned)cmd >= PRC_NCMDS)
  484                 return;
  485 
  486         /* if the parameter is from icmp6, decode it. */
  487         if (d !=  NULL) {
  488                 struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d;
  489                 struct mbuf *m = ip6cp->ip6c_m;
  490                 int off = ip6cp->ip6c_off;
  491 
  492                 struct ip6ctlparam ip6cp1;
  493 
  494                 /*
  495                  * Notify the error to all possible sockets via pfctlinput2.
  496                  * Since the upper layer information (such as protocol type,
  497                  * source and destination ports) is embedded in the encrypted
  498                  * data and might have been cut, we can't directly call
  499                  * an upper layer ctlinput function. However, the pcbnotify
  500                  * function will consider source and destination addresses
  501                  * as well as the flow info value, and may be able to find
  502                  * some PCB that should be notified.
  503                  * Although pfctlinput2 will call esp6_ctlinput(), there is
  504                  * no possibility of an infinite loop of function calls,
  505                  * because we don't pass the inner IPv6 header.
  506                  */
  507                 bzero(&ip6cp1, sizeof(ip6cp1));
  508                 ip6cp1.ip6c_src = ip6cp->ip6c_src;
  509                 pfctlinput2(cmd, sa, (void *)&ip6cp1);
  510 
  511                 /*
  512                  * Then go to special cases that need ESP header information.
  513                  * XXX: We assume that when ip6 is non NULL,
  514                  * M and OFF are valid.
  515                  */
  516 
  517                 if (cmd == PRC_MSGSIZE) {
  518                         struct secasvar *sav;
  519                         u_int32_t spi;
  520                         int valid;
  521 
  522                         /* check header length before using m_copydata */
  523                         if (m->m_pkthdr.len < off + sizeof (struct esp))
  524                                 return;
  525                         m_copydata(m, off + offsetof(struct esp, esp_spi),
  526                                 sizeof(u_int32_t), (caddr_t) &spi);
  527                         /*
  528                          * Check to see if we have a valid SA corresponding to
  529                          * the address in the ICMP message payload.
  530                          */
  531                         sav = KEY_ALLOCSA((union sockaddr_union *)sa,
  532                                         IPPROTO_ESP, spi);
  533                         valid = (sav != NULL);
  534                         if (sav)
  535                                 KEY_FREESAV(&sav);
  536 
  537                         /* XXX Further validation? */
  538 
  539                         /*
  540                          * Depending on whether the SA is "valid" and
  541                          * routing table size (mtudisc_{hi,lo}wat), we will:
  542                          * - recalcurate the new MTU and create the
  543                          *   corresponding routing entry, or
  544                          * - ignore the MTU change notification.
  545                          */
  546                         icmp6_mtudisc_update(ip6cp, valid);
  547                 }
  548         } else {
  549                 /* we normally notify any pcb here */
  550         }
  551 }
  552 
  553 extern  struct ip6protosw inet6sw[];
  554 extern  u_char ip6_protox[];
  555 
  556 /*
  557  * IPsec input callback, called by the transform callback. Takes care of
  558  * filtering and other sanity checks on the processed packet.
  559  */
  560 int
  561 ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, int protoff,
  562     struct m_tag *mt)
  563 {
  564         int prot, af, sproto;
  565         struct ip6_hdr *ip6;
  566         struct m_tag *mtag;
  567         struct tdb_ident *tdbi;
  568         struct secasindex *saidx;
  569         int nxt;
  570         u_int8_t nxt8;
  571         int error, nest;
  572 
  573         KASSERT(m != NULL, ("ipsec6_common_input_cb: null mbuf"));
  574         KASSERT(sav != NULL, ("ipsec6_common_input_cb: null SA"));
  575         KASSERT(sav->sah != NULL, ("ipsec6_common_input_cb: null SAH"));
  576         saidx = &sav->sah->saidx;
  577         af = saidx->dst.sa.sa_family;
  578         KASSERT(af == AF_INET6,
  579                 ("ipsec6_common_input_cb: unexpected af %u", af));
  580         sproto = saidx->proto;
  581         KASSERT(sproto == IPPROTO_ESP || sproto == IPPROTO_AH ||
  582                 sproto == IPPROTO_IPCOMP,
  583                 ("ipsec6_common_input_cb: unexpected security protocol %u",
  584                 sproto));
  585 
  586         /* Sanity check */
  587         if (m == NULL) {
  588                 DPRINTF(("ipsec4_common_input_cb: null mbuf"));
  589                 IPSEC_ISTAT(sproto, espstat.esps_badkcr, ahstat.ahs_badkcr,
  590                     ipcompstat.ipcomps_badkcr);
  591                 error = EINVAL;
  592                 goto bad;
  593         }
  594 
  595         /* Fix IPv6 header */
  596         if (m->m_len < sizeof(struct ip6_hdr) &&
  597             (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
  598 
  599                 DPRINTF(("ipsec_common_input_cb: processing failed "
  600                     "for SA %s/%08lx\n", ipsec_address(&sav->sah->saidx.dst),
  601                     (u_long) ntohl(sav->spi)));
  602 
  603                 IPSEC_ISTAT(sproto, espstat.esps_hdrops, ahstat.ahs_hdrops,
  604                     ipcompstat.ipcomps_hdrops);
  605                 error = EACCES;
  606                 goto bad;
  607         }
  608 
  609         ip6 = mtod(m, struct ip6_hdr *);
  610         ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
  611 
  612         /* Save protocol */
  613         m_copydata(m, protoff, 1, (unsigned char *) &prot);
  614 
  615 #ifdef INET
  616         /* IP-in-IP encapsulation */
  617         if (prot == IPPROTO_IPIP) {
  618                 struct ip ipn;
  619 
  620                 /* ipn will now contain the inner IPv4 header */
  621                 m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn);
  622 
  623 #ifdef notyet
  624                 /*
  625                  * Check that the inner source address is the same as
  626                  * the proxy address, if available.
  627                  */
  628                 if ((saidx->proxy.sa.sa_family == AF_INET &&
  629                     saidx->proxy.sin.sin_addr.s_addr != INADDR_ANY &&
  630                     ipn.ip_src.s_addr != saidx->proxy.sin.sin_addr.s_addr) ||
  631                     (saidx->proxy.sa.sa_family != AF_INET &&
  632                         saidx->proxy.sa.sa_family != 0)) {
  633 
  634                         DPRINTF(("ipsec_common_input_cb: inner "
  635                             "source address %s doesn't correspond to "
  636                             "expected proxy source %s, SA %s/%08lx\n",
  637                             inet_ntoa4(ipn.ip_src),
  638                             ipsec_address(&saidx->proxy),
  639                             ipsec_address(&saidx->dst),
  640                             (u_long) ntohl(sav->spi)));
  641 
  642                         IPSEC_ISTATsproto, (espstat.esps_pdrops,
  643                             ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
  644                         error = EACCES;
  645                         goto bad;
  646                 }
  647 #endif /*XXX*/
  648         }
  649 #endif /* INET */
  650 
  651         /* IPv6-in-IP encapsulation */
  652         if (prot == IPPROTO_IPV6) {
  653                 struct ip6_hdr ip6n;
  654 
  655                 /* ip6n will now contain the inner IPv6 header. */
  656                 m_copydata(m, skip, sizeof(struct ip6_hdr),
  657                     (caddr_t) &ip6n);
  658 
  659 #ifdef notyet
  660                 /*
  661                  * Check that the inner source address is the same as
  662                  * the proxy address, if available.
  663                  */
  664                 if ((saidx->proxy.sa.sa_family == AF_INET6 &&
  665                     !IN6_IS_ADDR_UNSPECIFIED(&saidx->proxy.sin6.sin6_addr) &&
  666                     !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src,
  667                         &saidx->proxy.sin6.sin6_addr)) ||
  668                     (saidx->proxy.sa.sa_family != AF_INET6 &&
  669                         saidx->proxy.sa.sa_family != 0)) {
  670 
  671                         DPRINTF(("ipsec_common_input_cb: inner "
  672                             "source address %s doesn't correspond to "
  673                             "expected proxy source %s, SA %s/%08lx\n",
  674                             ip6_sprintf(&ip6n.ip6_src),
  675                             ipsec_address(&saidx->proxy),
  676                             ipsec_address(&saidx->dst),
  677                             (u_long) ntohl(sav->spi)));
  678 
  679                         IPSEC_ISTAT(sproto, espstat.esps_pdrops,
  680                             ahstat.ahs_pdrops, ipcompstat.ipcomps_pdrops);
  681                         error = EACCES;
  682                         goto bad;
  683                 }
  684 #endif /*XXX*/
  685         }
  686 
  687         /*
  688          * Record what we've done to the packet (under what SA it was
  689          * processed). If we've been passed an mtag, it means the packet
  690          * was already processed by an ethernet/crypto combo card and
  691          * thus has a tag attached with all the right information, but
  692          * with a PACKET_TAG_IPSEC_IN_CRYPTO_DONE as opposed to
  693          * PACKET_TAG_IPSEC_IN_DONE type; in that case, just change the type.
  694          */
  695         if (mt == NULL && sproto != IPPROTO_IPCOMP) {
  696                 mtag = m_tag_get(PACKET_TAG_IPSEC_IN_DONE,
  697                     sizeof(struct tdb_ident), M_NOWAIT);
  698                 if (mtag == NULL) {
  699                         DPRINTF(("ipsec_common_input_cb: failed to "
  700                             "get tag\n"));
  701                         IPSEC_ISTAT(sproto, espstat.esps_hdrops,
  702                             ahstat.ahs_hdrops, ipcompstat.ipcomps_hdrops);
  703                         error = ENOMEM;
  704                         goto bad;
  705                 }
  706 
  707                 tdbi = (struct tdb_ident *)(mtag + 1);
  708                 bcopy(&saidx->dst, &tdbi->dst, sizeof(union sockaddr_union));
  709                 tdbi->proto = sproto;
  710                 tdbi->spi = sav->spi;
  711 
  712                 m_tag_prepend(m, mtag);
  713         } else {
  714                 mt->m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
  715                 /* XXX do we need to mark m_flags??? */
  716         }
  717 
  718         key_sa_recordxfer(sav, m);
  719 
  720         /* Retrieve new protocol */
  721         m_copydata(m, protoff, sizeof(u_int8_t), (caddr_t) &nxt8);
  722 
  723         /*
  724          * See the end of ip6_input for this logic.
  725          * IPPROTO_IPV[46] case will be processed just like other ones
  726          */
  727         nest = 0;
  728         nxt = nxt8;
  729         while (nxt != IPPROTO_DONE) {
  730                 if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
  731                         ip6stat.ip6s_toomanyhdr++;
  732                         error = EINVAL;
  733                         goto bad;
  734                 }
  735 
  736                 /*
  737                  * Protection against faulty packet - there should be
  738                  * more sanity checks in header chain processing.
  739                  */
  740                 if (m->m_pkthdr.len < skip) {
  741                         ip6stat.ip6s_tooshort++;
  742                         in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
  743                         error = EINVAL;
  744                         goto bad;
  745                 }
  746                 /*
  747                  * Enforce IPsec policy checking if we are seeing last header.
  748                  * note that we do not visit this with protocols with pcb layer
  749                  * code - like udp/tcp/raw ip.
  750                  */
  751                 if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
  752                     ipsec6_in_reject(m, NULL)) {
  753                         error = EINVAL;
  754                         goto bad;
  755                 }
  756                 nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt);
  757         }
  758         return 0;
  759 bad:
  760         if (m)
  761                 m_freem(m);
  762         return error;
  763 }
  764 #endif /* INET6 */

Cache object: ad816a3214c628dc4f7d4723d90059f6


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