File:  [DragonFly] / src / sys / netinet / ip_encap.c
Revision 1.4: download - view: text, annotated - select for diffs
Sat Aug 23 11:18:00 2003 UTC (11 years, 2 months ago) by rob
Branches: MAIN
CVS tags: HEAD
if ipv6 doesnt need oldstyle prototypes maybe its time we took them out
of ipv4's code

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