Restore to working order; this has apparently been nonworking since

the decapsulator dispatch changes in 2001.  Problems found and fixed
by Christine Jones of BBN.  Specifically:

Check for a packet's protocol to be ENCAP_PROTO, not AF_INET.

Remove one-back cache for last vif, because vif_encapcheck is called
for each vif, rather than being expected to find the appropriate vif.
The cache usage caused packets to be input on the wrong vif and hence
usually dropped.

In vif_encapcheck, verify the local source as well.  While mrouted
endeavors not to create multiple tunnels with a peer, a packet
arriving with the wrong local address is still wrong and should not be
accepted.  (This is a correctness nit, not a security issue.)  Order
checks to fail quickly for packets being checked to see if they match
a vif other than the one they belong on (essentially, check peer
source address in outer header first).

Claim 69 bits of match (32 each from outer src/dst and 5 from checking
that inner dst is within 224/5).  This should result in the vif having
a higher priority for multicast packets compared to a parallel gif(4)
tunnel, and that both seems appropriate if both are configured and
seems to match the semantics expected by the decapsulator dispatch
machinery.

(These changes were made in 2.99.15 and about a dozen nodes are
running them with many vifs.  ip_mroute.c has not changed
significantly since then (February 2005) and the changes applied
cleanly to current and compile cleanly.)
This commit is contained in:
gdt 2005-08-03 18:20:11 +00:00
parent 5b5c5125f4
commit e25f2a0d87
1 changed files with 51 additions and 38 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_mroute.c,v 1.94 2005/06/06 06:06:50 martin Exp $ */ /* $NetBSD: ip_mroute.c,v 1.95 2005/08/03 18:20:11 gdt Exp $ */
/* /*
* Copyright (c) 1992, 1993 * Copyright (c) 1992, 1993
@ -93,7 +93,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.94 2005/06/06 06:06:50 martin Exp $"); __KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.95 2005/08/03 18:20:11 gdt Exp $");
#include "opt_inet.h" #include "opt_inet.h"
#include "opt_ipsec.h" #include "opt_ipsec.h"
@ -381,13 +381,6 @@ static vifi_t numvifs = 0;
static struct callout expire_upcalls_ch; static struct callout expire_upcalls_ch;
/*
* one-back cache used by vif_encapcheck to locate a tunnel's vif
* given a datagram's src ip address.
*/
static struct in_addr last_encap_src;
static struct vif *last_encap_vif;
/* /*
* whether or not special PIM assert processing is enabled. * whether or not special PIM assert processing is enabled.
*/ */
@ -926,6 +919,13 @@ add_vif(struct mbuf *m)
} }
/* attach this vif to decapsulator dispatch table */ /* attach this vif to decapsulator dispatch table */
/*
* XXX Use addresses in registration so that matching
* can be done with radix tree in decapsulator. But,
* we need to check inner header for multicast, so
* this requires both radix tree lookup and then a
* function to check, and this is not supported yet.
*/
vifp->v_encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV4, vifp->v_encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV4,
vif_encapcheck, &vif_protosw, vifp); vif_encapcheck, &vif_protosw, vifp);
if (!vifp->v_encap_cookie) if (!vifp->v_encap_cookie)
@ -1037,13 +1037,9 @@ reset_vif(struct vif *vifp)
m_freem(m); m_freem(m);
} }
if (vifp->v_flags & VIFF_TUNNEL) { if (vifp->v_flags & VIFF_TUNNEL)
free(vifp->v_ifp, M_MRTABLE); free(vifp->v_ifp, M_MRTABLE);
if (vifp == last_encap_vif) { else if (vifp->v_flags & VIFF_REGISTER) {
last_encap_vif = NULL;
last_encap_src = zeroin_addr;
}
} else if (vifp->v_flags & VIFF_REGISTER) {
#ifdef PIM #ifdef PIM
reg_vif_num = VIFI_INVALID; reg_vif_num = VIFI_INVALID;
#endif #endif
@ -1984,7 +1980,7 @@ vif_input(struct mbuf *m, ...)
va_end(ap); va_end(ap);
vifp = (struct vif *)encap_getarg(m); vifp = (struct vif *)encap_getarg(m);
if (!vifp || proto != AF_INET) { if (!vifp || proto != ENCAP_PROTO) {
m_freem(m); m_freem(m);
mrtstat.mrts_bad_tunnel++; mrtstat.mrts_bad_tunnel++;
return; return;
@ -2011,7 +2007,9 @@ vif_input(struct mbuf *m, ...)
} }
/* /*
* Check if the packet should be grabbed by us. * Check if the packet should be received on the vif denoted by arg.
* (The encap selection code will call this once per vif since each is
* registered separately.)
*/ */
static int static int
vif_encapcheck(struct mbuf *m, int off, int proto, void *arg) vif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
@ -2025,32 +2023,47 @@ vif_encapcheck(struct mbuf *m, int off, int proto, void *arg)
#endif #endif
/* /*
* do not grab the packet if it's not to a multicast destination or if * Accept the packet only if the inner heaader is multicast
* we don't have an encapsulating tunnel with the source. * and the outer header matches a tunnel-mode vif. Order
* Note: This code assumes that the remote site IP address * checks in the hope that common non-matching packets will be
* uniquely identifies the tunnel (i.e., that this site has * rejected quickly. Assume that unicast IPv4 traffic in a
* at most one tunnel with the remote site). * parallel tunnel (e.g. gif(4)) is unlikely.
*/ */
m_copydata(m, off, sizeof(ip), (caddr_t)&ip); /* Obtain the outer IP header and the vif pointer. */
m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
vifp = (struct vif *)arg;
/*
* The outer source must match the vif's remote peer address.
* For a multicast router with several tunnels, this is the
* only check that will fail on packets in other tunnels,
* assuming the local address is the same.
*/
if (!in_hosteq(vifp->v_rmt_addr, ip.ip_src))
return 0;
/* The outer destination must match the vif's local address. */
if (!in_hosteq(vifp->v_lcl_addr, ip.ip_dst))
return 0;
/* The vif must be of tunnel type. */
if ((vifp->v_flags & VIFF_TUNNEL) == 0)
return 0;
/* Check that the inner destination is multicast. */
m_copydata((struct mbuf *)m, off, sizeof(ip), (caddr_t)&ip);
if (!IN_MULTICAST(ip.ip_dst.s_addr)) if (!IN_MULTICAST(ip.ip_dst.s_addr))
return 0; return 0;
m_copydata(m, 0, sizeof(ip), (caddr_t)&ip); /*
if (!in_hosteq(ip.ip_src, last_encap_src)) { * We have checked that both the outer src and dst addresses
vifp = (struct vif *)arg; * match the vif, and that the inner destination is multicast
if (vifp->v_flags & VIFF_TUNNEL && * (224/5). By claiming more than 64, we intend to
in_hosteq(vifp->v_rmt_addr, ip.ip_src)) * preferentially take packets that also match a parallel
; * gif(4).
else */
return 0; return 32 + 32 + 5;
last_encap_vif = vifp;
last_encap_src = ip.ip_src;
} else
vifp = last_encap_vif;
/* 32bit match, since we have checked ip_src only */
return 32;
} }
/* /*