From 0a04437d42d10beec112812e851a51f673d7ab0c Mon Sep 17 00:00:00 2001 From: mpi Date: Thu, 8 Feb 2018 13:15:31 +0000 Subject: [PATCH] Add a new '-protected' option for bridge members. Bridge members that are part of the same protected domain, refered by a number between 1 and 31, cannot talk to each others. This is useful to isolate VMs or untrusted networks at layer 2. Members can be part of multiple protected domain making it possible to create complex protected setups. ok ccardenas@, claudio@, dlg@, henning@ --- sbin/ifconfig/brconfig.c | 60 +++++++++++++++++++++++++++++++++++++++- sbin/ifconfig/brconfig.h | 4 ++- sbin/ifconfig/ifconfig.8 | 12 ++++++-- sbin/ifconfig/ifconfig.c | 4 ++- sys/net/if_bridge.c | 38 ++++++++++++++++++++++++- sys/net/if_bridge.h | 4 ++- sys/sys/sockio.h | 3 +- 7 files changed, 117 insertions(+), 8 deletions(-) diff --git a/sbin/ifconfig/brconfig.c b/sbin/ifconfig/brconfig.c index 1e3415b0ebb..86d59394569 100644 --- a/sbin/ifconfig/brconfig.c +++ b/sbin/ifconfig/brconfig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: brconfig.c,v 1.17 2018/02/05 03:51:53 henning Exp $ */ +/* $OpenBSD: brconfig.c,v 1.18 2018/02/08 13:15:32 mpi Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -338,6 +338,16 @@ 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) { + int v; + + v = ffs(reqp->ifbr_protected); + printf(" protected %u", v); + while (++v < 32) { + if ((1 << (v - 1)) & reqp->ifbr_protected) + printf(",%u", v); + } + }; if (reqp->ifbr_ifsflags & IFBIF_STP) printf(" %s role %s", stpstates[reqp->ifbr_state], @@ -456,6 +466,54 @@ bridge_priority(const char *arg, int d) err(1, "%s", name); } +void +bridge_protect(const char *ifname, const char *val) +{ + struct ifbreq breq; + unsigned long v; + char *optlist, *str; + char *endptr; + + strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); + strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); + breq.ifbr_protected = 0; + + /* We muck with the string, so copy it. */ + optlist = strdup(val); + if (optlist == NULL) + err(1, "strdup"); + + str = strtok(optlist, ","); + while (str != NULL) { + errno = 0; + v = strtoul(str, &endptr, 0); + if (str[0] == '\0' || endptr[0] != '\0' || v == 0 || v > 31 || + (errno == ERANGE && v == ULONG_MAX)) + err(1, "invalid value for protected domain: %s", str); + breq.ifbr_protected |= (1 << (v - 1)); + str = strtok(NULL, ","); + } + + if (ioctl(s, SIOCBRDGSIFPROT, (caddr_t)&breq) < 0) + err(1, "%s: %s", name, val); + + free(optlist); +} + +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 bridge_proto(const char *arg, int d) { diff --git a/sbin/ifconfig/brconfig.h b/sbin/ifconfig/brconfig.h index 9efee215192..e8342f4c9e8 100644 --- a/sbin/ifconfig/brconfig.h +++ b/sbin/ifconfig/brconfig.h @@ -1,4 +1,4 @@ -/* $OpenBSD: brconfig.h,v 1.12 2018/01/16 10:33:55 mpi Exp $ */ +/* $OpenBSD: brconfig.h,v 1.13 2018/02/08 13:15:32 mpi Exp $ */ /* * Copyright (c) 2009 Claudio Jeker @@ -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 *); diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index 8b91bc8f810..e87b51b0945 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ifconfig.8,v 1.294 2018/02/05 07:16:13 jmc Exp $ +.\" $OpenBSD: ifconfig.8,v 1.295 2018/02/08 13:15:32 mpi Exp $ .\" $NetBSD: ifconfig.8,v 1.11 1996/01/04 21:27:29 pk Exp $ .\" $FreeBSD: ifconfig.8,v 1.16 1998/02/01 07:03:29 steve Exp $ .\" @@ -31,7 +31,7 @@ .\" .\" @(#)ifconfig.8 8.4 (Berkeley) 6/1/94 .\" -.Dd $Mdocdate: February 5 2018 $ +.Dd $Mdocdate: February 8 2018 $ .Dt IFCONFIG 8 .Os .Sh NAME @@ -662,6 +662,14 @@ 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 ids +Put +.Ar interface +in protected domains. +.Ar ids +is a comma delimited list of domain IDs to put the interface in. +Interfaces that are part of a protected domain cannot forward traffic to any +other interface in that domain . .It Cm proto Ar value Force the spanning tree protocol version. The available values are diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index ab1e3c918f4..6cb2b394159 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ifconfig.c,v 1.354 2018/02/02 13:39:52 stsp Exp $ */ +/* $OpenBSD: ifconfig.c,v 1.355 2018/02/08 13:15:32 mpi Exp $ */ /* $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $ */ /* @@ -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 }, diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 8465fcac0ee..839f6460deb 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.c,v 1.304 2018/02/07 11:30:01 mpi Exp $ */ +/* $OpenBSD: if_bridge.c,v 1.305 2018/02/08 13:15:31 mpi Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -409,6 +409,7 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } 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 cmd, caddr_t data) 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, struct ifbifconf *bifc) 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); @@ -855,6 +870,7 @@ bridgeintr_frame(struct bridge_softc *sc, struct ifnet *src_if, struct mbuf *m) struct bridge_rtnode *dst_p; struct ether_addr *dst, *src; struct ether_header eh; + u_int32_t protected; int len; @@ -967,6 +983,7 @@ bridgeintr_frame(struct bridge_softc *sc, struct ifnet *src_if, struct mbuf *m) 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 @@ -982,6 +999,14 @@ bridgeintr_frame(struct bridge_softc *sc, struct ifnet *src_if, struct mbuf *m) m_freem(m); return; } + /* + * Do not transmit if both ports are part of the same protected + * domain. + */ + 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; @@ -1173,6 +1198,10 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *ifp, 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; @@ -1193,6 +1222,13 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *ifp, bridge_blocknonip(eh, m)) continue; + /* + * Do not transmit if both ports are part of the same + * protected domain. + */ + if (protected != 0 && (protected & p->bif_protected)) + continue; + if (bridge_filterrule(&p->bif_brlout, eh, m) == BRL_ACTION_BLOCK) continue; diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h index 75596a5b040..abb5d643bf6 100644 --- a/sys/net/if_bridge.h +++ b/sys/net/if_bridge.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.h,v 1.56 2018/02/05 03:51:53 henning Exp $ */ +/* $OpenBSD: if_bridge.h,v 1.57 2018/02/08 13:15:32 mpi Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -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 domains */ u_int8_t ifbr_state; /* member stp state */ u_int8_t ifbr_priority; /* member stp priority */ @@ -415,6 +416,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 domains */ void *bif_dhcookie; }; #define bif_state bif_stp->bp_state diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index 4d630796c44..7e9fdf21b8c 100644 --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sockio.h,v 1.72 2017/10/24 09:36:13 jsg Exp $ */ +/* $OpenBSD: sockio.h,v 1.73 2018/02/08 13:15:32 mpi Exp $ */ /* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */ /*- @@ -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 */ -- 2.20.1