On Mon, Jan 22, 2018 at 04:23:59PM +0100, Martin Pieuchot wrote:
> Diff below adds a new feature to bridge(4), similar to Cisco's Protected
> Port but with more possibilities.
>
> The idea is to prevent traffic to flow between some members of a bridge(4).
> For example:
> - you want to prevent some of your servers to talk to each others, or
> - you want employees/students/clients to have access to internet and a
> printer but not to each other, or
> - you want VMs to have access to an uplink but not to each other
I think the last example is really useful and makes sense.
For the other cases there would most likely be a switch between the other
host and the OpenBSD box. Then you need to enforce the policy on that switch.
> With the diff below it is now possible to defined "protected groups".
> Interface that are part of such groups cannot send/receive traffic
> to/from any other member of the group.
Why several protected groups and not just a single one?
>
> In the example below, em1 and em2 can only send/receive traffic through
> em0 because they are both in the protected group 2.
>
> bridge0: flags=41<UP,RUNNING>
> index 9 llprio 3
> groups: bridge
> priority 32768 hellotime 2 fwddelay 15 maxage 20 holdcnt 6 proto rstp
> designated: id 00:00:00:00:00:00 priority 0
> em0 flags=3<LEARNING,DISCOVER>
> port 6 ifpriority 0 ifcost 0
> em1 flags=3<LEARNING,DISCOVER>
> port 7 ifpriority 0 ifcost 0 protected 2
> em2 flags=3<LEARNING,DISCOVER>
> port 8 ifpriority 0 ifcost 0 protected 2
>
> Adding an interface to a protected group is as simple as:
>
> # ifconfig bridge0 protected em1 2
>
> Removing it:
>
> # ifconfig bridge0 -protected em1
>
> Comments? Oks?
>
> Index: sys/net/if_bridge.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_bridge.c,v
> retrieving revision 1.301
> diff -u -p -r1.301 if_bridge.c
> --- sys/net/if_bridge.c 10 Jan 2018 23:50:39 -0000 1.301
> +++ sys/net/if_bridge.c 22 Jan 2018 14:27:41 -0000
> @@ -409,6 +409,7 @@ bridge_ioctl(struct ifnet *ifp, u_long c
> }
> req->ifbr_ifsflags = p->bif_flags;
> req->ifbr_portno = p->ifp->if_index & 0xfff;
> + req->ifbr_protected = p->bif_protected;
> if (p->bif_flags & IFBIF_STP) {
> bp = p->bif_stp;
> req->ifbr_state = bstp_getstate(bs, bp);
> @@ -496,6 +497,19 @@ bridge_ioctl(struct ifnet *ifp, u_long c
> brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec;
> brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec;
> break;
> + case SIOCBRDGSIFPROT:
> + ifs = ifunit(req->ifbr_ifsname);
> + if (ifs == NULL) {
> + error = ENOENT;
> + break;
> + }
> + p = (struct bridge_iflist *)ifs->if_bridgeport;
> + if (p == NULL || p->bridge_sc != sc) {
> + error = ESRCH;
> + break;
> + }
> + p->bif_protected = req->ifbr_protected;
> + break;
> case SIOCBRDGRTS:
> case SIOCBRDGGCACHE:
> case SIOCBRDGGPRI:
> @@ -594,6 +608,7 @@ bridge_bifconf(struct bridge_softc *sc,
> strlcpy(breq->ifbr_ifsname, p->ifp->if_xname, IFNAMSIZ);
> breq->ifbr_ifsflags = p->bif_flags;
> breq->ifbr_portno = p->ifp->if_index & 0xfff;
> + breq->ifbr_protected = p->bif_protected;
> if (p->bif_flags & IFBIF_STP) {
> bp = p->bif_stp;
> breq->ifbr_state = bstp_getstate(sc->sc_stp, bp);
> @@ -848,6 +863,7 @@ bridgeintr_frame(struct bridge_softc *sc
> struct bridge_rtnode *dst_p;
> struct ether_addr *dst, *src;
> struct ether_header eh;
> + u_int32_t protected;
> int len;
>
>
> @@ -960,6 +976,7 @@ bridgeintr_frame(struct bridge_softc *sc
> bridge_broadcast(sc, src_if, &eh, m);
> return;
> }
> + protected = ifl->bif_protected;
>
> /*
> * At this point, we're dealing with a unicast frame going to a
> @@ -975,6 +992,14 @@ bridgeintr_frame(struct bridge_softc *sc
> m_freem(m);
> return;
> }
> + /*
> + * Do not transmit if both ports are part of the same protected
> + * group.
> + */
> + if (protected != 0 && protected == ifl->bif_protected) {
> + m_freem(m);
> + return;
> + }
> if (bridge_filterrule(&ifl->bif_brlout, &eh, m) == BRL_ACTION_BLOCK) {
> m_freem(m);
> return;
> @@ -1159,6 +1184,10 @@ bridge_broadcast(struct bridge_softc *sc
> struct mbuf *mc;
> struct ifnet *dst_if;
> int len, used = 0;
> + u_int32_t protected;
> +
> + p = (struct bridge_iflist *)ifp->if_bridgeport;
> + protected = p->bif_protected;
>
> TAILQ_FOREACH(p, &sc->sc_iflist, next) {
> dst_if = p->ifp;
> @@ -1177,6 +1206,13 @@ bridge_broadcast(struct bridge_softc *sc
> /* Drop non-IP frames if the appropriate flag is set. */
> if (p->bif_flags & IFBIF_BLOCKNONIP &&
> bridge_blocknonip(eh, m))
> + continue;
> +
> + /*
> + * Do not transmit if both ports are part of the same
> + * protected group.
> + */
> + if (protected != 0 && protected == p->bif_protected)
> continue;
>
> if (bridge_filterrule(&p->bif_brlout, eh, m) ==
> BRL_ACTION_BLOCK)
> Index: sys/net/if_bridge.h
> ===================================================================
> RCS file: /cvs/src/sys/net/if_bridge.h,v
> retrieving revision 1.55
> diff -u -p -r1.55 if_bridge.h
> --- sys/net/if_bridge.h 20 Jan 2017 05:03:48 -0000 1.55
> +++ sys/net/if_bridge.h 22 Jan 2018 15:13:07 -0000
> @@ -46,6 +46,7 @@ struct ifbreq {
> char ifbr_ifsname[IFNAMSIZ]; /* member ifs name */
> u_int32_t ifbr_ifsflags; /* member ifs flags */
> u_int32_t ifbr_portno; /* member port number */
> + u_int32_t ifbr_protected; /* protected group number */
>
> u_int8_t ifbr_state; /* member stp state */
> u_int8_t ifbr_priority; /* member stp priority */
> @@ -398,6 +399,7 @@ struct bridge_iflist {
> struct brl_head bif_brlout; /* output rules */
> struct ifnet *ifp; /* member interface */
> u_int32_t bif_flags; /* member flags */
> + u_int32_t bif_protected; /* protected group */
> void *bif_dhcookie;
> };
> #define bif_state bif_stp->bp_state
> Index: sys/sys/sockio.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/sockio.h,v
> retrieving revision 1.72
> diff -u -p -r1.72 sockio.h
> --- sys/sys/sockio.h 24 Oct 2017 09:36:13 -0000 1.72
> +++ sys/sys/sockio.h 22 Jan 2018 14:09:09 -0000
> @@ -89,6 +89,7 @@
> #define SIOCBRDGDADDR _IOW('i', 71, struct ifbareq) /* delete addr
> */
> #define SIOCBRDGFLUSH _IOW('i', 72, struct ifbreq) /* flush addr
> cache */
> #define SIOCBRDGADDL _IOW('i', 73, struct ifbreq) /* add local
> port */
> +#define SIOCBRDGSIFPROT _IOW('i', 74, struct ifbreq) /* set
> protected grp */
>
> #define SIOCBRDGARL _IOW('i', 77, struct ifbrlreq) /* add bridge rule */
> #define SIOCBRDGFRL _IOW('i', 78, struct ifbrlreq) /* flush brdg rules */
> Index: sbin/ifconfig/brconfig.c
> ===================================================================
> RCS file: /cvs/src/sbin/ifconfig/brconfig.c,v
> retrieving revision 1.16
> diff -u -p -r1.16 brconfig.c
> --- sbin/ifconfig/brconfig.c 31 Jul 2017 02:32:11 -0000 1.16
> +++ sbin/ifconfig/brconfig.c 22 Jan 2018 14:30:38 -0000
> @@ -336,6 +336,8 @@ bridge_list(char *delim)
> printf("port %u ifpriority %u ifcost %u",
> reqp->ifbr_portno, reqp->ifbr_priority,
> reqp->ifbr_path_cost);
> + if (reqp->ifbr_protected)
> + printf(" protected %u", reqp->ifbr_protected);
> if (reqp->ifbr_ifsflags & IFBIF_STP)
> printf(" %s role %s",
> stpstates[reqp->ifbr_state],
> @@ -452,6 +454,41 @@ bridge_priority(const char *arg, int d)
> bp.ifbrp_prio = v;
> if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0)
> err(1, "%s", name);
> +}
> +
> +void
> +bridge_protect(const char *ifname, const char *val)
> +{
> + struct ifbreq breq;
> + unsigned long v;
> + char *endptr;
> +
> + strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
> + strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
> +
> + errno = 0;
> + v = strtoul(val, &endptr, 0);
> + if (val[0] == '\0' || endptr[0] != '\0' || v == 0 || v > UINT32_MAX ||
> + (errno == ERANGE && v == ULONG_MAX))
> + err(1, "invalid arg for protected group: %s", val);
> + breq.ifbr_protected = v;
> +
> + if (ioctl(s, SIOCBRDGSIFPROT, (caddr_t)&breq) < 0)
> + err(1, "%s: %s", name, val);
> +}
> +
> +void
> +bridge_unprotect(const char *ifname, int d)
> +{
> + struct ifbreq breq;
> +
> + strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
> + strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
> +
> + breq.ifbr_protected = 0;
> +
> + if (ioctl(s, SIOCBRDGSIFPROT, (caddr_t)&breq) < 0)
> + err(1, "%s: %d", name, 0);
> }
>
> void
> Index: sbin/ifconfig/brconfig.h
> ===================================================================
> RCS file: /cvs/src/sbin/ifconfig/brconfig.h,v
> retrieving revision 1.12
> diff -u -p -r1.12 brconfig.h
> --- sbin/ifconfig/brconfig.h 16 Jan 2018 10:33:55 -0000 1.12
> +++ sbin/ifconfig/brconfig.h 22 Jan 2018 14:12:39 -0000
> @@ -52,6 +52,8 @@ void bridge_addrs(const char *, int);
> void bridge_hellotime(const char *, int);
> void bridge_fwddelay(const char *, int);
> void bridge_maxage(const char *, int);
> +void bridge_protect(const char *, const char *);
> +void bridge_unprotect(const char *, int);
> void bridge_proto(const char *, int);
> void bridge_ifprio(const char *, const char *);
> void bridge_ifcost(const char *, const char *);
> Index: sbin/ifconfig/ifconfig.8
> ===================================================================
> RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v
> retrieving revision 1.292
> diff -u -p -r1.292 ifconfig.8
> --- sbin/ifconfig/ifconfig.8 16 Jan 2018 10:33:55 -0000 1.292
> +++ sbin/ifconfig/ifconfig.8 22 Jan 2018 15:11:32 -0000
> @@ -662,6 +662,13 @@ The default is 100 entries.
> .It Cm maxage Ar time
> Set the time (in seconds) that a spanning tree protocol configuration is
> valid.
> Defaults to 20 seconds, minimum of 6, maximum of 40.
> +.It Cm protected Ar interface Ar id
> +Put
> +.Ar interface
> +in protected mode.
> +A protected interface does not forward traffic to any other protected
> interface
> +having the same
> +.Ar id .
> .It Cm proto Ar value
> Force the spanning tree protocol version.
> The available values are
> Index: sbin/ifconfig/ifconfig.c
> ===================================================================
> RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
> retrieving revision 1.353
> diff -u -p -r1.353 ifconfig.c
> --- sbin/ifconfig/ifconfig.c 16 Jan 2018 10:33:55 -0000 1.353
> +++ sbin/ifconfig/ifconfig.c 22 Jan 2018 14:17:17 -0000
> @@ -472,6 +472,8 @@ const struct cmd {
> { "-edge", NEXTARG, 0, unsetedge },
> { "autoedge", NEXTARG, 0, setautoedge },
> { "-autoedge", NEXTARG, 0, unsetautoedge },
> + { "protected", NEXTARG2, 0, NULL, bridge_protect },
> + { "-protected", NEXTARG, 0, bridge_unprotect },
> { "ptp", NEXTARG, 0, setptp },
> { "-ptp", NEXTARG, 0, unsetptp },
> { "autoptp", NEXTARG, 0, setautoptp },