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:
parent
dbcf945af6
commit
91f6764e93
@ -289,6 +289,28 @@ unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
|
|||||||
do_bridgeflag(s, val, IFBIF_LEARNING, 0);
|
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
|
static void
|
||||||
setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
|
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("-discover", unsetbridge_discover),
|
||||||
DEF_CMD_ARG("learn", setbridge_learn),
|
DEF_CMD_ARG("learn", setbridge_learn),
|
||||||
DEF_CMD_ARG("-learn", unsetbridge_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", setbridge_stp),
|
||||||
DEF_CMD_ARG("-stp", unsetbridge_stp),
|
DEF_CMD_ARG("-stp", unsetbridge_stp),
|
||||||
DEF_CMD("flush", 0, setbridge_flush),
|
DEF_CMD("flush", 0, setbridge_flush),
|
||||||
|
@ -1106,6 +1106,17 @@ This is the default for all interfaces added to a bridge.
|
|||||||
Clear the
|
Clear the
|
||||||
.Dq learning
|
.Dq learning
|
||||||
attribute on a member interface.
|
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
|
.It Cm stp Ar interface
|
||||||
Enable Spanning Tree protocol on
|
Enable Spanning Tree protocol on
|
||||||
.Ar interface .
|
.Ar interface .
|
||||||
|
@ -193,6 +193,7 @@ static void bridge_timer(void *);
|
|||||||
|
|
||||||
static void bridge_broadcast(struct bridge_softc *, struct ifnet *,
|
static void bridge_broadcast(struct bridge_softc *, struct ifnet *,
|
||||||
struct mbuf *, int);
|
struct mbuf *, int);
|
||||||
|
static void bridge_span(struct bridge_softc *, struct mbuf *);
|
||||||
|
|
||||||
static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
|
static int bridge_rtupdate(struct bridge_softc *, const uint8_t *,
|
||||||
struct ifnet *, int, 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_sma(struct bridge_softc *, void *);
|
||||||
static int bridge_ioctl_sifprio(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_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 *,
|
static int bridge_pfil(struct mbuf **, struct ifnet *, struct ifnet *,
|
||||||
int);
|
int);
|
||||||
static int bridge_ip_checkbasic(struct mbuf **mp);
|
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),
|
{ bridge_ioctl_sifcost, sizeof(struct ifbreq),
|
||||||
BC_F_COPYIN|BC_F_SUSER },
|
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 =
|
const int bridge_control_table_size =
|
||||||
sizeof(bridge_control_table) / sizeof(bridge_control_table[0]);
|
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);
|
callout_init_mtx(&sc->sc_bstpcallout, &sc->sc_mtx, 0);
|
||||||
|
|
||||||
LIST_INIT(&sc->sc_iflist);
|
LIST_INIT(&sc->sc_iflist);
|
||||||
|
LIST_INIT(&sc->sc_spanlist);
|
||||||
|
|
||||||
ifp->if_softc = sc;
|
ifp->if_softc = sc;
|
||||||
if_initname(ifp, ifc->ifc_name, unit);
|
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)
|
while ((bif = LIST_FIRST(&sc->sc_iflist)) != NULL)
|
||||||
bridge_delete_member(sc, bif, 0);
|
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);
|
BRIDGE_UNLOCK(sc);
|
||||||
|
|
||||||
callout_drain(&sc->sc_brcallout);
|
callout_drain(&sc->sc_brcallout);
|
||||||
@ -724,6 +738,11 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
|
|||||||
if (ifs == NULL)
|
if (ifs == NULL)
|
||||||
return (ENOENT);
|
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 */
|
/* Allow the first member to define the MTU */
|
||||||
if (LIST_EMPTY(&sc->sc_iflist))
|
if (LIST_EMPTY(&sc->sc_iflist))
|
||||||
sc->sc_ifp->if_mtu = ifs->if_mtu;
|
sc->sc_ifp->if_mtu = ifs->if_mtu;
|
||||||
@ -834,6 +853,10 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
|
|||||||
if (bif == NULL)
|
if (bif == NULL)
|
||||||
return (ENOENT);
|
return (ENOENT);
|
||||||
|
|
||||||
|
if (req->ifbr_ifsflags & IFBIF_SPAN)
|
||||||
|
/* SPAN is readonly */
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
if (req->ifbr_ifsflags & IFBIF_STP) {
|
if (req->ifbr_ifsflags & IFBIF_STP) {
|
||||||
switch (bif->bif_ifp->if_type) {
|
switch (bif->bif_ifp->if_type) {
|
||||||
case IFT_ETHER:
|
case IFT_ETHER:
|
||||||
@ -892,6 +915,8 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
|
|||||||
count = 0;
|
count = 0;
|
||||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next)
|
LIST_FOREACH(bif, &sc->sc_iflist, bif_next)
|
||||||
count++;
|
count++;
|
||||||
|
LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
|
||||||
|
count++;
|
||||||
|
|
||||||
if (bifc->ifbic_len == 0) {
|
if (bifc->ifbic_len == 0) {
|
||||||
bifc->ifbic_len = sizeof(breq) * count;
|
bifc->ifbic_len = sizeof(breq) * count;
|
||||||
@ -917,6 +942,23 @@ bridge_ioctl_gifs(struct bridge_softc *sc, void *arg)
|
|||||||
count++;
|
count++;
|
||||||
len -= sizeof(breq);
|
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;
|
bifc->ifbic_len = sizeof(breq) * count;
|
||||||
return (error);
|
return (error);
|
||||||
@ -1182,6 +1224,73 @@ bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
|
|||||||
return (0);
|
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:
|
* bridge_ifdetach:
|
||||||
*
|
*
|
||||||
@ -1386,6 +1495,9 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa,
|
|||||||
m_freem(m);
|
m_freem(m);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bridge_span(sc, m);
|
||||||
|
|
||||||
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
|
LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
|
||||||
dst_if = bif->bif_ifp;
|
dst_if = bif->bif_ifp;
|
||||||
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0)
|
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?
|
* XXX Spanning tree consideration here?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bridge_span(sc, m);
|
||||||
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) {
|
if ((dst_if->if_drv_flags & IFF_DRV_RUNNING) == 0) {
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
BRIDGE_UNLOCK(sc);
|
BRIDGE_UNLOCK(sc);
|
||||||
@ -1694,6 +1807,8 @@ bridge_input(struct ifnet *ifp, struct mbuf *m)
|
|||||||
return (m);
|
return (m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bridge_span(sc, m);
|
||||||
|
|
||||||
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
|
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
|
||||||
/* Tap off 802.1D packets; they do not get forwarded. */
|
/* Tap off 802.1D packets; they do not get forwarded. */
|
||||||
if (memcmp(eh->ether_dhost, bstp_etheraddr,
|
if (memcmp(eh->ether_dhost, bstp_etheraddr,
|
||||||
@ -1886,6 +2001,38 @@ out:
|
|||||||
BRIDGE_UNREF(sc);
|
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:
|
* bridge_rtupdate:
|
||||||
*
|
*
|
||||||
|
@ -106,6 +106,8 @@
|
|||||||
#define BRDGSMA 20 /* set max age (ifbrparam) */
|
#define BRDGSMA 20 /* set max age (ifbrparam) */
|
||||||
#define BRDGSIFPRIO 21 /* set if priority (ifbreq) */
|
#define BRDGSIFPRIO 21 /* set if priority (ifbreq) */
|
||||||
#define BRDGSIFCOST 22 /* set if path cost (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.
|
* Generic bridge control request.
|
||||||
@ -123,8 +125,9 @@ struct ifbreq {
|
|||||||
#define IFBIF_LEARNING 0x01 /* if can learn */
|
#define IFBIF_LEARNING 0x01 /* if can learn */
|
||||||
#define IFBIF_DISCOVER 0x02 /* if sends packets w/ unknown dest. */
|
#define IFBIF_DISCOVER 0x02 /* if sends packets w/ unknown dest. */
|
||||||
#define IFBIF_STP 0x04 /* if participates in spanning tree */
|
#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 */
|
/* BRDGFLUSH */
|
||||||
#define IFBF_FLUSHDYN 0x00 /* flush learned addresses only */
|
#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_rthash; /* our forwarding table */
|
||||||
LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */
|
LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */
|
||||||
uint32_t sc_rthash_key; /* key for hash */
|
uint32_t sc_rthash_key; /* key for hash */
|
||||||
|
LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BRIDGE_LOCK_INIT(_sc) do { \
|
#define BRIDGE_LOCK_INIT(_sc) do { \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user