Add support for creating span ports so that one can snoop bridged traffic

from another interface/machine/network.

Obtained from:	OpenBSD
MFC after:	2 weeks
This commit is contained in:
Andrew Thompson 2005-12-14 02:52:13 +00:00
parent dbcf945af6
commit 91f6764e93
4 changed files with 187 additions and 1 deletions

View File

@ -289,6 +289,28 @@ unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
do_bridgeflag(s, val, IFBIF_LEARNING, 0);
}
static void
setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0)
err(1, "BRDGADDS %s", val);
}
static void
unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp)
{
struct ifbreq req;
memset(&req, 0, sizeof(req));
strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0)
err(1, "BRDGDELS %s", val);
}
static void
setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
{
@ -506,6 +528,8 @@ static struct cmd bridge_cmds[] = {
DEF_CMD_ARG("-discover", unsetbridge_discover),
DEF_CMD_ARG("learn", setbridge_learn),
DEF_CMD_ARG("-learn", unsetbridge_learn),
DEF_CMD_ARG("span", setbridge_span),
DEF_CMD_ARG("-span", unsetbridge_span),
DEF_CMD_ARG("stp", setbridge_stp),
DEF_CMD_ARG("-stp", unsetbridge_stp),
DEF_CMD("flush", 0, setbridge_flush),

View File

@ -1106,6 +1106,17 @@ This is the default for all interfaces added to a bridge.
Clear the
.Dq learning
attribute on a member interface.
.It Cm span Ar interface
Add the interface named by
.Ar interface
as a span port on the bridge.
Span ports transmit a copy of every frame received by the bridge.
This is most useful for snooping a bridged network passively on
another host connected to one of the span ports of the bridge.
.It Cm -span Ar interface
Delete the interface named by
.Ar interface
from the list of span ports of the bridge.
.It Cm stp Ar interface
Enable Spanning Tree protocol on
.Ar interface .

View File

@ -193,6 +193,7 @@ static void bridge_timer(void *);
static void bridge_broadcast(struct bridge_softc *, struct ifnet *,
struct mbuf *, int);
static void bridge_span(struct bridge_softc *, struct mbuf *);
static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
struct ifnet *, int, uint8_t);
@ -242,6 +243,8 @@ static int bridge_ioctl_gma(struct bridge_softc *, void *);
static int bridge_ioctl_sma(struct bridge_softc *, void *);
static int bridge_ioctl_sifprio(struct bridge_softc *, void *);
static int bridge_ioctl_sifcost(struct bridge_softc *, void *);
static int bridge_ioctl_addspan(struct bridge_softc *, void *);
static int bridge_ioctl_delspan(struct bridge_softc *, void *);
static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *,
int);
static int bridge_ip_checkbasic(struct mbuf **mp);
@ -330,6 +333,11 @@ const struct bridge_control bridge_control_table[] = {
{ bridge_ioctl_sifcost, sizeof(struct ifbreq),
BC_F_COPYIN|BC_F_SUSER },
{ bridge_ioctl_addspan, sizeof(struct ifbreq),
BC_F_COPYIN|BC_F_SUSER },
{ bridge_ioctl_delspan, sizeof(struct ifbreq),
BC_F_COPYIN|BC_F_SUSER },
};
const int bridge_control_table_size =
sizeof(bridge_control_table) / sizeof(bridge_control_table[0]);
@ -443,6 +451,7 @@ bridge_clone_create(struct if_clone *ifc, int unit)
callout_init_mtx(&sc->sc_bstpcallout, &sc->sc_mtx, 0);
LIST_INIT(&sc->sc_iflist);
LIST_INIT(&sc->sc_spanlist);
ifp->if_softc = sc;
if_initname(ifp, ifc->ifc_name, unit);
@ -494,6 +503,11 @@ bridge_clone_destroy(struct ifnet *ifp)
while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL)
bridge_delete_member(sc, bif, 0);
while ((bif = LIST_FIRST(&sc->sc_spanlist)) != NULL) {
LIST_REMOVE(bif, bif_next);
free(bif, M_DEVBUF);
}
BRIDGE_UNLOCK(sc);
callout_drain(&sc->sc_brcallout);
@ -724,6 +738,11 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
if (ifs == NULL)
return (ENOENT);
/* If it's in the span list, it can't be a member. */
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
if (ifs == bif->bif_ifp)
return (EBUSY);
/* Allow the first member to define the MTU */
if (LIST_EMPTY(&sc->sc_iflist))
sc->sc_ifp->if_mtu = ifs->if_mtu;
@ -834,6 +853,10 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
if (bif == NULL)
return (ENOENT);
if (req->ifbr_ifsflags & IFBIF_SPAN)
/* SPAN is readonly */
return (EINVAL);
if (req->ifbr_ifsflags & IFBIF_STP) {
switch (bif->bif_ifp->if_type) {
case IFT_ETHER:
@ -892,6 +915,8 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
count = 0;
LIST_FOREACH(bif, &sc->sc_iflist, bif_next)
count++;
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
count++;
if (bifc->ifbic_len == 0) {
bifc->ifbic_len = sizeof(breq) * count;
@ -917,6 +942,23 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
count++;
len -= sizeof(breq);
}
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) {
if (len < sizeof(breq))
break;
strlcpy(breq.ifbr_ifsname, bif->bif_ifp->if_xname,
sizeof(breq.ifbr_ifsname));
breq.ifbr_ifsflags = bif->bif_flags;
breq.ifbr_state = bif->bif_state;
breq.ifbr_priority = bif->bif_priority;
breq.ifbr_path_cost = bif->bif_path_cost;
breq.ifbr_portno = bif->bif_ifp->if_index & 0xff;
error = copyout(&breq, bifc->ifbic_req + count, sizeof(breq));
if (error)
break;
count++;
len -= sizeof(breq);
}
bifc->ifbic_len = sizeof(breq) * count;
return (error);
@ -1182,6 +1224,73 @@ bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
return (0);
}
static int
bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
{
struct ifbreq *req = arg;
struct bridge_iflist *bif = NULL;
struct ifnet *ifs;
BRIDGE_LOCK_ASSERT(sc);
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL)
return (ENOENT);
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
if (ifs == bif->bif_ifp)
return (EBUSY);
if (ifs->if_bridge != NULL)
return (EBUSY);
switch (ifs->if_type) {
case IFT_ETHER:
case IFT_L2VLAN:
break;
default:
return (EINVAL);
}
bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
if (bif == NULL)
return (ENOMEM);
bif->bif_ifp = ifs;
bif->bif_flags = IFBIF_SPAN;
LIST_INSERT_HEAD(&sc->sc_spanlist, bif, bif_next);
return (0);
}
static int
bridge_ioctl_delspan(struct bridge_softc *sc, void *arg)
{
struct ifbreq *req = arg;
struct bridge_iflist *bif;
struct ifnet *ifs;
BRIDGE_LOCK_ASSERT(sc);
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL)
return (ENOENT);
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
if (ifs == bif->bif_ifp)
break;
if (bif == NULL)
return (ENOENT);
LIST_REMOVE(bif, bif_next);
free(bif, M_DEVBUF);
return (0);
}
/*
* bridge_ifdetach:
*
@ -1386,6 +1495,9 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
m_freem(m);
return (0);
}
bridge_span(sc, m);
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
dst_if = bif->bif_ifp;
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0)
@ -1431,6 +1543,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
* XXX Spanning tree consideration here?
*/
bridge_span(sc, m);
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) {
m_freem(m);
BRIDGE_UNLOCK(sc);
@ -1694,6 +1807,8 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
return (m);
}
bridge_span(sc, m);
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
/* Tap off 802.1D packets; they do not get forwarded. */
if (memcmp(eh->ether_dhost, bstp_etheraddr,
@ -1886,6 +2001,38 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if,
BRIDGE_UNREF(sc);
}
/*
* bridge_span:
*
* Duplicate a packet out one or more interfaces that are in span mode,
* the original mbuf is unmodified.
*/
static void
bridge_span(struct bridge_softc *sc, struct mbuf *m)
{
struct bridge_iflist *bif;
struct ifnet *dst_if;
struct mbuf *mc;
if (LIST_EMPTY(&sc->sc_spanlist))
return;
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next) {
dst_if = bif->bif_ifp;
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0)
continue;
mc = m_copypacket(m, M_DONTWAIT);
if (mc == NULL) {
sc->sc_ifp->if_oerrors++;
continue;
}
bridge_enqueue(sc, dst_if, mc);
}
}
/*
* bridge_rtupdate:
*

View File

@ -106,6 +106,8 @@
#define BRDGSMA 20 /* set max age (ifbrparam) */
#define BRDGSIFPRIO 21 /* set if priority (ifbreq) */
#define BRDGSIFCOST 22 /* set if path cost (ifbreq) */
#define BRDGADDS 23 /* add bridge span member (ifbreq) */
#define BRDGDELS 24 /* delete bridge span member (ifbreq) */
/*
* Generic bridge control request.
@ -123,8 +125,9 @@ struct ifbreq {
#define IFBIF_LEARNING 0x01 /* if can learn */
#define IFBIF_DISCOVER 0x02 /* if sends packets w/ unknown dest. */
#define IFBIF_STP 0x04 /* if participates in spanning tree */
#define IFBIF_SPAN 0x08 /* if is a span port */
#define IFBIFBITS "\020\1LEARNING\2DISCOVER\3STP"
#define IFBIFBITS "\020\1LEARNING\2DISCOVER\3STP\4SPAN"
/* BRDGFLUSH */
#define IFBF_FLUSHDYN 0x00 /* flush learned addresses only */
@ -295,6 +298,7 @@ struct bridge_softc {
LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */
LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */
uint32_t sc_rthash_key; /* key for hash */
LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */
};
#define BRIDGE_LOCK_INIT(_sc) do { \