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:
parent
5b5c5125f4
commit
e25f2a0d87
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue