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/ipcomp_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: ipcomp_input.c,v 1.36.10.1 2011/04/03 06:08:35 jdc Exp $       */
    2 /*      $KAME: ipcomp_input.c,v 1.29 2001/09/04 08:43:19 itojun Exp $   */
    3 
    4 /*
    5  * Copyright (C) 1999 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  * RFC2393 IP payload compression protocol (IPComp).
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: ipcomp_input.c,v 1.36.10.1 2011/04/03 06:08:35 jdc 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 <net/zlib.h>
   59 #include <sys/cpu.h>
   60 
   61 #include <netinet/in.h>
   62 #include <netinet/in_systm.h>
   63 #include <netinet/in_var.h>
   64 #include <netinet/in_proto.h>
   65 #include <netinet/ip.h>
   66 #include <netinet/ip_var.h>
   67 #include <netinet/ip_ecn.h>
   68 
   69 #ifdef INET6
   70 #include <netinet/ip6.h>
   71 #include <netinet6/ip6_var.h>
   72 #endif
   73 #include <netinet6/ipcomp.h>
   74 
   75 #include <netinet6/ipsec.h>
   76 #include <netinet6/ipsec_private.h>
   77 #include <netkey/key.h>
   78 #include <netkey/keydb.h>
   79 
   80 #include <machine/stdarg.h>
   81 
   82 #include <net/net_osdep.h>
   83 
   84 /*#define IPLEN_FLIPPED*/
   85 
   86 #ifdef INET
   87 void
   88 ipcomp4_init(void)
   89 {
   90 
   91         ipsec4_init();
   92 }
   93 
   94 void
   95 #if __STDC__
   96 ipcomp4_input(struct mbuf *m, ...)
   97 #else
   98 ipcomp4_input(m, va_alist)
   99         struct mbuf *m;
  100         va_dcl
  101 #endif
  102 {
  103         struct mbuf *md;
  104         struct ip *ip;
  105         struct ipcomp *ipcomp;
  106         const struct ipcomp_algorithm *algo;
  107         u_int16_t cpi;  /* host order */
  108         u_int16_t nxt;
  109         size_t hlen;
  110         int error;
  111         size_t newlen, olen;
  112         struct secasvar *sav = NULL;
  113         int off, proto;
  114         va_list ap;
  115         u_int16_t sport = 0;
  116         u_int16_t dport = 0;
  117 #ifdef IPSEC_NAT_T
  118         struct m_tag *tag = NULL;
  119 #endif
  120 
  121         va_start(ap, m);
  122         off = va_arg(ap, int);
  123         proto = va_arg(ap, int);
  124         va_end(ap);
  125 
  126         if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) {
  127                 ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
  128                     "(packet too short)\n"));
  129                 IPSEC_STATINC(IPSEC_STAT_IN_INVAL);
  130                 goto fail;
  131         }
  132 #ifdef IPSEC_NAT_T
  133         /* find the source port for NAT-T */
  134         if ((tag = m_tag_find(m, PACKET_TAG_IPSEC_NAT_T_PORTS, NULL)) != NULL) {
  135                 sport = ((u_int16_t *)(tag + 1))[0];
  136                 dport = ((u_int16_t *)(tag + 1))[1];
  137         }
  138 #endif
  139 
  140         md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
  141         if (!md) {
  142                 m = NULL;       /* already freed */
  143                 ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
  144                     "(pulldown failure)\n"));
  145                 IPSEC_STATINC(IPSEC_STAT_IN_INVAL);
  146                 goto fail;
  147         }
  148         ipcomp = mtod(md, struct ipcomp *);
  149         ip = mtod(m, struct ip *);
  150         nxt = ipcomp->comp_nxt;
  151         if (nxt == IPPROTO_IPCOMP || nxt == IPPROTO_AH || nxt == IPPROTO_ESP) {
  152                 /* nested ipcomp - possible attack, not likely useful */
  153                 ipseclog((LOG_DEBUG, "IPv4 IPComp input: nested ipcomp "
  154                     "(bailing)\n"));
  155                 IPSEC_STATINC(IPSEC_STAT_IN_INVAL);
  156                 goto fail;
  157         }
  158         hlen = ip->ip_hl << 2;
  159 
  160         cpi = ntohs(ipcomp->comp_cpi);
  161 
  162         if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
  163                 sav = key_allocsa(AF_INET, (void *)&ip->ip_src,
  164                         (void *)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi), 
  165                         sport, dport);
  166                 if (sav != NULL &&
  167                     (sav->state == SADB_SASTATE_MATURE ||
  168                      sav->state == SADB_SASTATE_DYING)) {
  169                         cpi = sav->alg_enc;     /* XXX */
  170                         /* other parameters to look at? */
  171                 }
  172         }
  173         algo = ipcomp_algorithm_lookup(cpi);
  174         if (!algo) {
  175                 ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n",
  176                         cpi));
  177                 IPSEC_STATINC(IPSEC_STAT_IN_NOSA);
  178                 goto fail;
  179         }
  180 
  181         /* chop ipcomp header */
  182         ipcomp = NULL;
  183         md->m_data += sizeof(struct ipcomp);
  184         md->m_len -= sizeof(struct ipcomp);
  185         m->m_pkthdr.len -= sizeof(struct ipcomp);
  186 #ifdef IPLEN_FLIPPED
  187         ip->ip_len -= sizeof(struct ipcomp);
  188 #else
  189         ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp));
  190 #endif
  191 
  192         olen = m->m_pkthdr.len;
  193         newlen = m->m_pkthdr.len - off;
  194         error = (*algo->decompress)(m, m->m_next, &newlen);
  195         if (error != 0) {
  196                 if (error == EINVAL)
  197                         IPSEC_STATINC(IPSEC_STAT_IN_INVAL);
  198                 else if (error == ENOBUFS)
  199                         IPSEC_STATINC(IPSEC_STAT_IN_NOMEM);
  200                 m = NULL;
  201                 goto fail;
  202         }
  203         IPSEC_STATINC(IPSEC_STAT_IN_COMPHIST + cpi);
  204 
  205         /*
  206          * returning decompressed packet onto icmp is meaningless.
  207          * mark it decrypted to prevent icmp from attaching original packet.
  208          */
  209         m->m_flags |= M_DECRYPTED;
  210 
  211         m->m_pkthdr.len = off + newlen;
  212         ip = mtod(m, struct ip *);
  213     {
  214         size_t len;
  215 #ifdef IPLEN_FLIPPED
  216         len = ip->ip_len;
  217 #else
  218         len = ntohs(ip->ip_len);
  219 #endif
  220         /*
  221          * be careful about underflow.  also, do not assign exact value
  222          * as ip_len is manipulated differently on *BSDs.
  223          */
  224         len += m->m_pkthdr.len;
  225         len -= olen;
  226         if (len & ~0xffff) {
  227                 /* packet too big after decompress */
  228                 IPSEC_STATINC(IPSEC_STAT_IN_INVAL);
  229                 goto fail;
  230         }
  231 #ifdef IPLEN_FLIPPED
  232         ip->ip_len = len & 0xffff;
  233 #else
  234         ip->ip_len = htons(len & 0xffff);
  235 #endif
  236         ip->ip_p = nxt;
  237     }
  238 
  239         if (sav) {
  240                 key_sa_recordxfer(sav, m);
  241                 if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
  242                         IPSEC_STATINC(IPSEC_STAT_IN_NOMEM);
  243                         goto fail;
  244                 }
  245                 key_freesav(sav);
  246                 sav = NULL;
  247         }
  248 
  249         if (nxt != IPPROTO_DONE) {
  250                 if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
  251                     ipsec4_in_reject(m, NULL)) {
  252                         IPSEC_STATINC(IPSEC_STAT_IN_POLVIO);
  253                         goto fail;
  254                 }
  255                 (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
  256         } else
  257                 m_freem(m);
  258         m = NULL;
  259 
  260         IPSEC_STATINC(IPSEC_STAT_IN_SUCCESS);
  261         return;
  262 
  263 fail:
  264         if (sav)
  265                 key_freesav(sav);
  266         if (m)
  267                 m_freem(m);
  268         return;
  269 }
  270 #endif /* INET */
  271 
  272 #ifdef INET6
  273 void
  274 ipcomp6_init(void)
  275 {
  276 
  277         ipsec6_init();
  278 }
  279 
  280 int
  281 ipcomp6_input(struct mbuf **mp, int *offp, int proto)
  282 {
  283         struct mbuf *m, *md;
  284         int off;
  285         struct ip6_hdr *ip6;
  286         struct ipcomp *ipcomp;
  287         const struct ipcomp_algorithm *algo;
  288         u_int16_t cpi;  /* host order */
  289         u_int16_t nxt;
  290         int error;
  291         size_t newlen;
  292         struct secasvar *sav = NULL;
  293         u_int8_t *prvnxtp;
  294 
  295         m = *mp;
  296         off = *offp;
  297 
  298         md = m_pulldown(m, off, sizeof(*ipcomp), NULL);
  299         if (!md) {
  300                 m = NULL;       /* already freed */
  301                 ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed "
  302                     "(pulldown failure)\n"));
  303                 IPSEC6_STATINC(IPSEC_STAT_IN_INVAL);
  304                 goto fail;
  305         }
  306         ipcomp = mtod(md, struct ipcomp *);
  307         ip6 = mtod(m, struct ip6_hdr *);
  308         nxt = ipcomp->comp_nxt;
  309 
  310         cpi = ntohs(ipcomp->comp_cpi);
  311 
  312         if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
  313                 sav = key_allocsa(AF_INET6, (void *)&ip6->ip6_src,
  314                         (void *)&ip6->ip6_dst, IPPROTO_IPCOMP, 
  315                         htonl(cpi), 0, 0);
  316                 if (sav != NULL &&
  317                     (sav->state == SADB_SASTATE_MATURE ||
  318                      sav->state == SADB_SASTATE_DYING)) {
  319                         cpi = sav->alg_enc;     /* XXX */
  320                         /* other parameters to look at? */
  321                 }
  322         }
  323         algo = ipcomp_algorithm_lookup(cpi);
  324         if (!algo) {
  325                 ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; "
  326                         "dropping the packet for simplicity\n", cpi));
  327                 IPSEC6_STATINC(IPSEC_STAT_IN_NOSA);
  328                 goto fail;
  329         }
  330 
  331         /* chop ipcomp header */
  332         ipcomp = NULL;
  333         md->m_data += sizeof(struct ipcomp);
  334         md->m_len -= sizeof(struct ipcomp);
  335         m->m_pkthdr.len -= sizeof(struct ipcomp);
  336 
  337         newlen = m->m_pkthdr.len - off;
  338         error = (*algo->decompress)(m, md, &newlen);
  339         if (error != 0) {
  340                 if (error == EINVAL)
  341                         IPSEC6_STATINC(IPSEC_STAT_IN_INVAL);
  342                 else if (error == ENOBUFS)
  343                         IPSEC6_STATINC(IPSEC_STAT_IN_NOMEM);
  344                 m = NULL;
  345                 goto fail;
  346         }
  347         IPSEC6_STATINC(IPSEC_STAT_IN_COMPHIST + cpi);
  348         m->m_pkthdr.len = off + newlen;
  349 
  350         /*
  351          * returning decompressed packet onto icmp is meaningless.
  352          * mark it decrypted to prevent icmp from attaching original packet.
  353          */
  354         m->m_flags |= M_DECRYPTED;
  355 
  356         /* update next header field */
  357         prvnxtp = ip6_get_prevhdr(m, off);
  358         *prvnxtp = nxt;
  359 
  360         /*
  361          * no need to adjust payload length, as all the IPv6 protocols
  362          * look at m->m_pkthdr.len
  363          */
  364 
  365         if (sav) {
  366                 key_sa_recordxfer(sav, m);
  367                 if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) {
  368                         IPSEC6_STATINC(IPSEC_STAT_IN_NOMEM);
  369                         goto fail;
  370                 }
  371                 key_freesav(sav);
  372                 sav = NULL;
  373         }
  374         *offp = off;
  375         *mp = m;
  376         IPSEC6_STATINC(IPSEC_STAT_IN_SUCCESS);
  377         return nxt;
  378 
  379 fail:
  380         if (m)
  381                 m_freem(m);
  382         if (sav)
  383                 key_freesav(sav);
  384         return IPPROTO_DONE;
  385 }
  386 #endif /* INET6 */

Cache object: 995e1903a96b113335112a71a0869324


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