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/netinet/ip_encap.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$       */
    2 /*      $KAME: ip_encap.c,v 1.41 2001/03/15 08:35:08 itojun Exp $       */
    3 
    4 /*
    5  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the project nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 /*
   33  * My grandfather said that there's a devil inside tunnelling technology...
   34  *
   35  * We have surprisingly many protocols that want packets with IP protocol
   36  * #4 or #41.  Here's a list of protocols that want protocol #41:
   37  *      RFC1933 configured tunnel
   38  *      RFC1933 automatic tunnel
   39  *      RFC2401 IPsec tunnel
   40  *      RFC2473 IPv6 generic packet tunnelling
   41  *      RFC2529 6over4 tunnel
   42  *      mobile-ip6 (uses RFC2473)
   43  *      RFC3056 6to4 tunnel
   44  *      isatap tunnel
   45  * Here's a list of protocol that want protocol #4:
   46  *      RFC1853 IPv4-in-IPv4 tunnelling
   47  *      RFC2003 IPv4 encapsulation within IPv4
   48  *      RFC2344 reverse tunnelling for mobile-ip4
   49  *      RFC2401 IPsec tunnel
   50  * Well, what can I say.  They impose different en/decapsulation mechanism
   51  * from each other, so they need separate protocol handler.  The only one
   52  * we can easily determine by protocol # is IPsec, which always has
   53  * AH/ESP/IPComp header right after outer IP header.
   54  *
   55  * So, clearly good old protosw does not work for protocol #4 and #41.
   56  * The code will let you match protocol via src/dst address pair.
   57  */
   58 /* XXX is M_NETADDR correct? */
   59 
   60 #include "opt_inet.h"
   61 #include "opt_inet6.h"
   62 
   63 #include <sys/param.h>
   64 #include <sys/systm.h>
   65 #include <sys/socket.h>
   66 #include <sys/sockio.h>
   67 #include <sys/mbuf.h>
   68 #include <sys/errno.h>
   69 #include <sys/protosw.h>
   70 #include <sys/queue.h>
   71 
   72 #include <net/if.h>
   73 #include <net/route.h>
   74 
   75 #include <netinet/in.h>
   76 #include <netinet/in_systm.h>
   77 #include <netinet/ip.h>
   78 #include <netinet/ip_var.h>
   79 #include <netinet/ip_encap.h>
   80 #include <netinet/ipprotosw.h>
   81 
   82 #ifdef INET6
   83 #include <netinet/ip6.h>
   84 #include <netinet6/ip6_var.h>
   85 #include <netinet6/ip6protosw.h>
   86 #endif
   87 
   88 #include <machine/stdarg.h>
   89 
   90 #include <net/net_osdep.h>
   91 
   92 #include <sys/kernel.h>
   93 #include <sys/malloc.h>
   94 MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
   95 
   96 static void encap_add __P((struct encaptab *));
   97 static int mask_match __P((const struct encaptab *, const struct sockaddr *,
   98                 const struct sockaddr *));
   99 static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
  100 
  101 #ifndef LIST_HEAD_INITIALIZER
  102 /* rely upon BSS initialization */
  103 LIST_HEAD(, encaptab) encaptab;
  104 #else
  105 LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab);
  106 #endif
  107 
  108 void     (*ipip_input)(struct mbuf *, int, int); /* hook for mrouting */
  109 
  110 void
  111 encap_init()
  112 {
  113         static int initialized = 0;
  114 
  115         if (initialized)
  116                 return;
  117         initialized++;
  118 #if 0
  119         /*
  120          * we cannot use LIST_INIT() here, since drivers may want to call
  121          * encap_attach(), on driver attach.  encap_init() will be called
  122          * on AF_INET{,6} initialization, which happens after driver
  123          * initialization - using LIST_INIT() here can nuke encap_attach()
  124          * from drivers.
  125          */
  126         LIST_INIT(&encaptab);
  127 #endif
  128 }
  129 
  130 #ifdef INET
  131 void
  132 encap4_input(struct mbuf *m, int off, int proto)
  133 {
  134         struct ip *ip;
  135         struct sockaddr_in s, d;
  136         const struct ipprotosw *psw;
  137         struct encaptab *ep, *match;
  138         int prio, matchprio;
  139 
  140         ip = mtod(m, struct ip *);
  141 
  142         bzero(&s, sizeof(s));
  143         s.sin_family = AF_INET;
  144         s.sin_len = sizeof(struct sockaddr_in);
  145         s.sin_addr = ip->ip_src;
  146         bzero(&d, sizeof(d));
  147         d.sin_family = AF_INET;
  148         d.sin_len = sizeof(struct sockaddr_in);
  149         d.sin_addr = ip->ip_dst;
  150 
  151         match = NULL;
  152         matchprio = 0;
  153         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  154                 if (ep->af != AF_INET)
  155                         continue;
  156                 if (ep->proto >= 0 && ep->proto != proto)
  157                         continue;
  158                 if (ep->func)
  159                         prio = (*ep->func)(m, off, proto, ep->arg);
  160                 else {
  161                         /*
  162                          * it's inbound traffic, we need to match in reverse
  163                          * order
  164                          */
  165                         prio = mask_match(ep, (struct sockaddr *)&d,
  166                             (struct sockaddr *)&s);
  167                 }
  168 
  169                 /*
  170                  * We prioritize the matches by using bit length of the
  171                  * matches.  mask_match() and user-supplied matching function
  172                  * should return the bit length of the matches (for example,
  173                  * if both src/dst are matched for IPv4, 64 should be returned).
  174                  * 0 or negative return value means "it did not match".
  175                  *
  176                  * The question is, since we have two "mask" portion, we
  177                  * cannot really define total order between entries.
  178                  * For example, which of these should be preferred?
  179                  * mask_match() returns 48 (32 + 16) for both of them.
  180                  *      src=3ffe::/16, dst=3ffe:501::/32
  181                  *      src=3ffe:501::/32, dst=3ffe::/16
  182                  *
  183                  * We need to loop through all the possible candidates
  184                  * to get the best match - the search takes O(n) for
  185                  * n attachments (i.e. interfaces).
  186                  */
  187                 if (prio <= 0)
  188                         continue;
  189                 if (prio > matchprio) {
  190                         matchprio = prio;
  191                         match = ep;
  192                 }
  193         }
  194 
  195         if (match) {
  196                 /* found a match, "match" has the best one */
  197                 psw = (const struct ipprotosw *)match->psw;
  198                 if (psw && psw->pr_input) {
  199                         encap_fillarg(m, match);
  200                         (*psw->pr_input)(m, off, proto);
  201                 } else
  202                         m_freem(m);
  203                 return;
  204         }
  205 
  206         /* for backward compatibility */
  207         if (proto == IPPROTO_IPV4 && ipip_input) {
  208                 ipip_input(m, off, proto);
  209                 return;
  210         }
  211 
  212         /* last resort: inject to raw socket */
  213         rip_input(m, off, proto);
  214 }
  215 #endif
  216 
  217 #ifdef INET6
  218 int
  219 encap6_input(mp, offp, proto)
  220         struct mbuf **mp;
  221         int *offp;
  222         int proto;
  223 {
  224         struct mbuf *m = *mp;
  225         struct ip6_hdr *ip6;
  226         struct sockaddr_in6 s, d;
  227         const struct ip6protosw *psw;
  228         struct encaptab *ep, *match;
  229         int prio, matchprio;
  230 
  231         ip6 = mtod(m, struct ip6_hdr *);
  232 
  233         bzero(&s, sizeof(s));
  234         s.sin6_family = AF_INET6;
  235         s.sin6_len = sizeof(struct sockaddr_in6);
  236         s.sin6_addr = ip6->ip6_src;
  237         bzero(&d, sizeof(d));
  238         d.sin6_family = AF_INET6;
  239         d.sin6_len = sizeof(struct sockaddr_in6);
  240         d.sin6_addr = ip6->ip6_dst;
  241 
  242         match = NULL;
  243         matchprio = 0;
  244         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  245                 if (ep->af != AF_INET6)
  246                         continue;
  247                 if (ep->proto >= 0 && ep->proto != proto)
  248                         continue;
  249                 if (ep->func)
  250                         prio = (*ep->func)(m, *offp, proto, ep->arg);
  251                 else {
  252                         /*
  253                          * it's inbound traffic, we need to match in reverse
  254                          * order
  255                          */
  256                         prio = mask_match(ep, (struct sockaddr *)&d,
  257                             (struct sockaddr *)&s);
  258                 }
  259 
  260                 /* see encap4_input() for issues here */
  261                 if (prio <= 0)
  262                         continue;
  263                 if (prio > matchprio) {
  264                         matchprio = prio;
  265                         match = ep;
  266                 }
  267         }
  268 
  269         if (match) {
  270                 /* found a match */
  271                 psw = (const struct ip6protosw *)match->psw;
  272                 if (psw && psw->pr_input) {
  273                         encap_fillarg(m, match);
  274                         return (*psw->pr_input)(mp, offp, proto);
  275                 } else {
  276                         m_freem(m);
  277                         return IPPROTO_DONE;
  278                 }
  279         }
  280 
  281         /* last resort: inject to raw socket */
  282         return rip6_input(mp, offp, proto);
  283 }
  284 #endif
  285 
  286 static void
  287 encap_add(ep)
  288         struct encaptab *ep;
  289 {
  290 
  291         LIST_INSERT_HEAD(&encaptab, ep, chain);
  292 }
  293 
  294 /*
  295  * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
  296  * length of mask (sm and dm) is assumed to be same as sp/dp.
  297  * Return value will be necessary as input (cookie) for encap_detach().
  298  */
  299 const struct encaptab *
  300 encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
  301         int af;
  302         int proto;
  303         const struct sockaddr *sp, *sm;
  304         const struct sockaddr *dp, *dm;
  305         const struct protosw *psw;
  306         void *arg;
  307 {
  308         struct encaptab *ep;
  309         int error;
  310         int s;
  311 
  312         s = splnet();
  313         /* sanity check on args */
  314         if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst)) {
  315                 error = EINVAL;
  316                 goto fail;
  317         }
  318         if (sp->sa_len != dp->sa_len) {
  319                 error = EINVAL;
  320                 goto fail;
  321         }
  322         if (af != sp->sa_family || af != dp->sa_family) {
  323                 error = EINVAL;
  324                 goto fail;
  325         }
  326 
  327         /* check if anyone have already attached with exactly same config */
  328         for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
  329                 if (ep->af != af)
  330                         continue;
  331                 if (ep->proto != proto)
  332                         continue;
  333                 if (ep->src.ss_len != sp->sa_len ||
  334                     bcmp(&ep->src, sp, sp->sa_len) != 0 ||
  335                     bcmp(&ep->srcmask, sm, sp->sa_len) != 0)
  336                         continue;
  337                 if (ep->dst.ss_len != dp->sa_len ||
  338                     bcmp(&ep->dst, dp, dp->sa_len) != 0 ||
  339                     bcmp(&ep->dstmask, dm, dp->sa_len) != 0)
  340                         continue;
  341 
  342                 error = EEXIST;
  343                 goto fail;
  344         }
  345 
  346         ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);  /*XXX*/
  347         if (ep == NULL) {
  348                 error = ENOBUFS;
  349                 goto fail;
  350         }
  351         bzero(ep, sizeof(*ep));
  352 
  353         ep->af = af;
  354         ep->proto = proto;
  355         bcopy(sp, &ep->src, sp->sa_len);
  356         bcopy(sm, &ep->srcmask, sp->sa_len);
  357         bcopy(dp, &ep->dst, dp->sa_len);
  358         bcopy(dm, &ep->dstmask, dp->sa_len);
  359         ep->psw = psw;
  360         ep->arg = arg;
  361 
  362         encap_add(ep);
  363 
  364         error = 0;
  365         splx(s);
  366         return ep;
  367 
  368 fail:
  369         splx(s);
  370         return NULL;
  371 }
  372 
  373 const struct encaptab *
  374 encap_attach_func(af, proto, func, psw, arg)
  375         int af;
  376         int proto;
  377         int (*func) __P((const struct mbuf *, int, int, void *));
  378         const struct protosw *psw;
  379         void *arg;
  380 {
  381         struct encaptab *ep;
  382         int error;
  383         int s;
  384 
  385         s = splnet();
  386         /* sanity check on args */
  387         if (!func) {
  388                 error = EINVAL;
  389                 goto fail;
  390         }
  391 
  392         ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT);  /*XXX*/
  393         if (ep == NULL) {
  394                 error = ENOBUFS;
  395                 goto fail;
  396         }
  397         bzero(ep, sizeof(*ep));
  398 
  399         ep->af = af;
  400         ep->proto = proto;
  401         ep->func = func;
  402         ep->psw = psw;
  403         ep->arg = arg;
  404 
  405         encap_add(ep);
  406 
  407         error = 0;
  408         splx(s);
  409         return ep;
  410 
  411 fail:
  412         splx(s);
  413         return NULL;
  414 }
  415 
  416 int
  417 encap_detach(cookie)
  418         const struct encaptab *cookie;
  419 {
  420         const struct encaptab *ep = cookie;
  421         struct encaptab *p;
  422 
  423         for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
  424                 if (p == ep) {
  425                         LIST_REMOVE(p, chain);
  426                         free(p, M_NETADDR);     /*XXX*/
  427                         return 0;
  428                 }
  429         }
  430 
  431         return EINVAL;
  432 }
  433 
  434 static int
  435 mask_match(ep, sp, dp)
  436         const struct encaptab *ep;
  437         const struct sockaddr *sp;
  438         const struct sockaddr *dp;
  439 {
  440         struct sockaddr_storage s;
  441         struct sockaddr_storage d;
  442         int i;
  443         const u_int8_t *p, *q;
  444         u_int8_t *r;
  445         int matchlen;
  446 
  447         if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
  448                 return 0;
  449         if (sp->sa_family != ep->af || dp->sa_family != ep->af)
  450                 return 0;
  451         if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len)
  452                 return 0;
  453 
  454         matchlen = 0;
  455 
  456         p = (const u_int8_t *)sp;
  457         q = (const u_int8_t *)&ep->srcmask;
  458         r = (u_int8_t *)&s;
  459         for (i = 0 ; i < sp->sa_len; i++) {
  460                 r[i] = p[i] & q[i];
  461                 /* XXX estimate */
  462                 matchlen += (q[i] ? 8 : 0);
  463         }
  464 
  465         p = (const u_int8_t *)dp;
  466         q = (const u_int8_t *)&ep->dstmask;
  467         r = (u_int8_t *)&d;
  468         for (i = 0 ; i < dp->sa_len; i++) {
  469                 r[i] = p[i] & q[i];
  470                 /* XXX rough estimate */
  471                 matchlen += (q[i] ? 8 : 0);
  472         }
  473 
  474         /* need to overwrite len/family portion as we don't compare them */
  475         s.ss_len = sp->sa_len;
  476         s.ss_family = sp->sa_family;
  477         d.ss_len = dp->sa_len;
  478         d.ss_family = dp->sa_family;
  479 
  480         if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 &&
  481             bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) {
  482                 return matchlen;
  483         } else
  484                 return 0;
  485 }
  486 
  487 static void
  488 encap_fillarg(m, ep)
  489         struct mbuf *m;
  490         const struct encaptab *ep;
  491 {
  492         struct m_tag *tag;
  493 
  494         tag = m_tag_get(PACKET_TAG_ENCAP, sizeof (void*), M_NOWAIT);
  495         if (tag) {
  496                 *(void**)(tag+1) = ep->arg;
  497                 m_tag_prepend(m, tag);
  498         }
  499 }
  500 
  501 void *
  502 encap_getarg(m)
  503         struct mbuf *m;
  504 {
  505         void *p = NULL;
  506         struct m_tag *tag;
  507 
  508         tag = m_tag_find(m, PACKET_TAG_ENCAP, NULL);
  509         if (tag) {
  510                 p = *(void**)(tag+1);
  511                 m_tag_delete(m, tag);
  512         }
  513         return p;
  514 }

Cache object: 9db2b75ab43a8f891fe570f389b12687


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