arp filters for bridge.
matches arp|rarp request|reply.
can match on source and target hardware and protocol addresses.
hardware addresses = MAC addrs
protocol addresses = IPv4
sha = src hw addr
spa = src proto addr
tha = target hw addr
tha = target proto addr
The keywords from the spec are being used, those into arp should be
familiar with them.
examples:
  block in quick on bnx0 src 00:11:22:33:44:55 arp request spa 10.0.0.1
  block in quick on bnx0 arp reply sha 11:22:33:33:55:55 tpa 192.168.0.1

ok?

Index: sys/net/bridgectl.c
===================================================================
RCS file: /cvs/src/sys/net/bridgectl.c,v
retrieving revision 1.6
diff -u -p -r1.6 bridgectl.c
--- sys/net/bridgectl.c 4 May 2017 15:00:24 -0000       1.6
+++ sys/net/bridgectl.c 4 Nov 2017 22:09:01 -0000
@@ -573,6 +573,7 @@ bridge_brlconf(struct bridge_softc *sc, 
                req.ifbr_flags = n->brl_flags;
                req.ifbr_src = n->brl_src;
                req.ifbr_dst = n->brl_dst;
+               req.ifbr_arpf = n->brl_arpf;
 #if NPF > 0
                req.ifbr_tagname[0] = '\0';
                if (n->brl_tag)
@@ -596,6 +597,7 @@ bridge_brlconf(struct bridge_softc *sc, 
                req.ifbr_flags = n->brl_flags;
                req.ifbr_src = n->brl_src;
                req.ifbr_dst = n->brl_dst;
+               req.ifbr_arpf = n->brl_arpf;
 #if NPF > 0
                req.ifbr_tagname[0] = '\0';
                if (n->brl_tag)
@@ -615,12 +617,59 @@ done:
 }
 
 u_int8_t
+bridge_arpfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m)
+{
+       struct ether_arp         ea;
+
+       if (!(n->brl_arpf.brla_flags & (BRLA_ARP|BRLA_RARP)))
+               return (1);
+
+       if (ntohs(eh->ether_type) != ETHERTYPE_ARP)
+               return (0);
+       if (m->m_pkthdr.len <= ETHER_HDR_LEN + sizeof(ea))
+               return (0);     /* log error? */
+       m_copydata(m, ETHER_HDR_LEN, sizeof(ea), (caddr_t)&ea);
+
+       if (ntohs(ea.arp_hrd) != ARPHRD_ETHER ||
+           ntohs(ea.arp_pro) != ETHERTYPE_IP ||
+           ea.arp_hln != ETHER_ADDR_LEN ||
+           ea.arp_pln != sizeof(struct in_addr))
+               return (0);
+       if ((n->brl_arpf.brla_flags & BRLA_ARP) &&
+           ntohs(ea.arp_op) != ARPOP_REQUEST &&
+           ntohs(ea.arp_op) != ARPOP_REPLY)
+               return (0);
+       if ((n->brl_arpf.brla_flags & BRLA_RARP) &&
+           ntohs(ea.arp_op) != ARPOP_REVREQUEST &&
+           ntohs(ea.arp_op) != ARPOP_REVREPLY)
+               return (0);
+       if (n->brl_arpf.brla_op && ntohs(ea.arp_op) != n->brl_arpf.brla_op)
+               return (0);
+       if (n->brl_arpf.brla_flags & BRLA_SHA &&
+           bcmp(ea.arp_sha, &n->brl_arpf.brla_sha, ETHER_ADDR_LEN))
+               return (0);
+       if (n->brl_arpf.brla_flags & BRLA_THA &&
+           bcmp(ea.arp_tha, &n->brl_arpf.brla_tha, ETHER_ADDR_LEN))
+               return (0);
+       if (n->brl_arpf.brla_flags & BRLA_SPA &&
+           bcmp(ea.arp_spa, &n->brl_arpf.brla_spa, sizeof(struct in_addr)))
+               return (0);
+       if (n->brl_arpf.brla_flags & BRLA_TPA &&
+           bcmp(ea.arp_tpa, &n->brl_arpf.brla_tpa, sizeof(struct in_addr)))
+               return (0);
+
+       return (1);
+}
+
+u_int8_t
 bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
 {
        struct brl_node *n;
        u_int8_t flags;
 
        SIMPLEQ_FOREACH(n, h, brl_next) {
+               if (!bridge_arpfilter(n, eh, m))
+                       continue;
                flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
                if (flags == 0)
                        goto return_action;
@@ -663,6 +712,7 @@ bridge_addrule(struct bridge_iflist *bif
        bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
        n->brl_action = req->ifbr_action;
        n->brl_flags = req->ifbr_flags;
+       n->brl_arpf = req->ifbr_arpf;
 #if NPF > 0
        if (req->ifbr_tagname[0])
                n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
Index: sys/net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.298
diff -u -p -r1.298 if_bridge.c
--- sys/net/if_bridge.c 17 Aug 2017 10:14:08 -0000      1.298
+++ sys/net/if_bridge.c 25 Oct 2017 13:32:36 -0000
@@ -734,6 +734,7 @@ bridge_output(struct ifnet *ifp, struct 
        struct ether_addr *dst;
        struct bridge_softc *sc;
        struct bridge_tunneltag *brtag;
+       struct bridge_iflist *ifl;
        int error;
 
        /* ifp must be a member interface of the bridge. */
@@ -819,6 +820,12 @@ bridge_output(struct ifnet *ifp, struct 
                                        continue;
                                }
                        }
+
+                       ifl = (struct bridge_iflist *)dst_if->if_bridgeport;
+                       KASSERT(ifl != NULL);
+                       if (bridge_filterrule(&ifl->bif_brlout, eh, mc) ==
+                           BRL_ACTION_BLOCK)
+                               continue;
 
                        error = bridge_ifenqueue(sc, dst_if, mc);
                        if (error)
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 1 Nov 2017 14:41:30 -0000
@@ -196,6 +196,21 @@ struct ifbropreq {
 /*
  * Bridge mac rules
  */
+struct ifbrarpf {
+       u_int16_t               brla_flags;
+       u_int16_t               brla_op;
+       struct ether_addr       brla_sha;
+       struct in_addr          brla_spa;
+       struct ether_addr       brla_tha;
+       struct in_addr          brla_tpa;
+};
+#define        BRLA_ARP        0x01
+#define        BRLA_RARP       0x02
+#define        BRLA_SHA        0x10
+#define        BRLA_SPA        0x20
+#define        BRLA_THA        0x40
+#define        BRLA_TPA        0x80
+
 struct ifbrlreq {
        char                    ifbr_name[IFNAMSIZ];    /* bridge ifs name */
        char                    ifbr_ifsname[IFNAMSIZ]; /* member ifs name */
@@ -204,6 +219,7 @@ struct ifbrlreq {
        struct ether_addr       ifbr_src;               /* source mac */
        struct ether_addr       ifbr_dst;               /* destination mac */
        char                    ifbr_tagname[PF_TAG_NAME_SIZE]; /* pf tagname */
+       struct ifbrarpf         ifbr_arpf;              /* arp filter */
 };
 #define        BRL_ACTION_BLOCK        0x01                    /* block frame 
*/
 #define        BRL_ACTION_PASS         0x02                    /* pass frame */
@@ -269,6 +285,7 @@ struct brl_node {
        u_int16_t               brl_tag;        /* pf tag ID */
        u_int8_t                brl_action;     /* what to do with match */
        u_int8_t                brl_flags;      /* comparision flags */
+       struct ifbrarpf         brl_arpf;       /* arp filter */
 };
 
 struct bstp_timer {
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    8 Nov 2017 16:19:32 -0000
@@ -46,6 +46,7 @@
 #include <errno.h>
 #include <getopt.h>
 #include <limits.h>
+#include <arpa/inet.h>
 
 #include "brconfig.h"
 
@@ -57,6 +58,7 @@ void bridge_cfg(const char *);
 void bridge_badrule(int, char **, int);
 void bridge_showrule(struct ifbrlreq *);
 int is_switch(char *);
+int bridge_arprule(struct ifbrlreq *, int *, char ***);
 
 #define        IFBAFBITS       "\020\1STATIC"
 #define        IFBIFBITS       \
@@ -821,6 +823,25 @@ bridge_showrule(struct ifbrlreq *r)
        if (r->ifbr_tagname[0])
                printf(" tag %s", r->ifbr_tagname);
 
+       if (r->ifbr_arpf.brla_flags & BRLA_ARP)
+               printf(" arp");
+       if (r->ifbr_arpf.brla_flags & BRLA_RARP)
+               printf(" rarp");
+       if (r->ifbr_arpf.brla_op == ARPOP_REQUEST ||
+           r->ifbr_arpf.brla_op == ARPOP_REVREQUEST)
+               printf(" request");
+       if (r->ifbr_arpf.brla_op == ARPOP_REPLY ||
+           r->ifbr_arpf.brla_op == ARPOP_REVREPLY)
+               printf(" reply");
+       if (r->ifbr_arpf.brla_flags & BRLA_SHA)
+               printf(" sha %s", ether_ntoa(&r->ifbr_arpf.brla_sha));
+       if (r->ifbr_arpf.brla_flags & BRLA_THA)
+               printf(" tha %s", ether_ntoa(&r->ifbr_arpf.brla_tha));
+       if (r->ifbr_arpf.brla_flags & BRLA_SPA)
+               printf(" spa %s", inet_ntoa(r->ifbr_arpf.brla_spa));
+       if (r->ifbr_arpf.brla_flags & BRLA_TPA)
+               printf(" tpa %s", inet_ntoa(r->ifbr_arpf.brla_tpa));
+
        printf("\n");
 }
 
@@ -837,14 +858,13 @@ bridge_rule(int targc, char **targv, int
        int argc = targc;
        struct ifbrlreq rule;
        struct ether_addr *ea, *dea;
+       struct in_addr *ia;
 
        if (argc == 0) {
                warnx("invalid rule");
                return (1);
        }
-       rule.ifbr_tagname[0] = 0;
-       rule.ifbr_flags = 0;
-       rule.ifbr_action = 0;
+       bzero(&rule, sizeof(rule));
        strlcpy(rule.ifbr_name, name, sizeof(rule.ifbr_name));
 
        if (strcmp(argv[0], "block") == 0)
@@ -882,16 +902,19 @@ bridge_rule(int targc, char **targv, int
        argc--; argv++;
 
        while (argc) {
+               dea = NULL;
                if (strcmp(argv[0], "dst") == 0) {
                        if (rule.ifbr_flags & BRL_FLAG_DSTVALID)
                                goto bad_rule;
                        rule.ifbr_flags |= BRL_FLAG_DSTVALID;
                        dea = &rule.ifbr_dst;
+                       argc--; argv++;
                } else if (strcmp(argv[0], "src") == 0) {
                        if (rule.ifbr_flags & BRL_FLAG_SRCVALID)
                                goto bad_rule;
                        rule.ifbr_flags |= BRL_FLAG_SRCVALID;
                        dea = &rule.ifbr_src;
+                       argc--; argv++;
                } else if (strcmp(argv[0], "tag") == 0) {
                        if (argc < 2) {
                                warnx("missing tag name");
@@ -901,28 +924,37 @@ bridge_rule(int targc, char **targv, int
                                warnx("tag already defined");
                                goto bad_rule;
                        }
-                       if (strlcpy(rule.ifbr_tagname, argv[1],
+                       argc--; argv++;
+                       if (strlcpy(rule.ifbr_tagname, argv[0],
                            PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
-                               warnx("tag name '%s' too long", argv[1]);
+                               warnx("tag name '%s' too long", argv[0]);
                                goto bad_rule;
                        }
-                       dea = NULL;
+                       argc--; argv++;
+               } else if (strcmp(argv[0], "arp") == 0) {
+                       rule.ifbr_arpf.brla_flags |= BRLA_ARP;
+                       argc--; argv++;
+                       if (bridge_arprule(&rule, &argc, &argv) == -1)
+                               goto bad_rule;
+               } else if (strcmp(argv[0], "rarp") == 0) {
+                       rule.ifbr_arpf.brla_flags |= BRLA_RARP;
+                       argc--; argv++;
+                       if (bridge_arprule(&rule, &argc, &argv) == -1)
+                               goto bad_rule;
                } else
                        goto bad_rule;
 
-               argc--; argv++;
-
-               if (argc == 0)
-                       goto bad_rule;
                if (dea != NULL) {
+                       if (argc == 0)
+                               goto bad_rule;
                        ea = ether_aton(argv[0]);
                        if (ea == NULL) {
                                warnx("invalid address: %s", argv[0]);
                                return (1);
                        }
                        bcopy(ea, dea, sizeof(*dea));
+                       argc--; argv++;
                }
-               argc--; argv++;
        }
 
        if (ioctl(s, SIOCBRDGARL, &rule) < 0) {
@@ -936,7 +968,71 @@ bad_rule:
        return (1);
 }
 
-#define MAXRULEWORDS 8
+int
+bridge_arprule(struct ifbrlreq *rule, int *argc, char ***argv)
+{
+       while (*argc) {
+               struct ether_addr       *ea, *dea = NULL;
+               struct in_addr           ia, *dia = NULL;
+
+               if (strcmp((*argv)[0], "request") == 0) {
+                       if (rule->ifbr_arpf.brla_flags & BRLA_ARP)
+                               rule->ifbr_arpf.brla_op = ARPOP_REQUEST;
+                       else if (rule->ifbr_arpf.brla_flags & BRLA_RARP)
+                               rule->ifbr_arpf.brla_op = ARPOP_REVREQUEST;
+                       else
+                               errx(1, "bridge_arprule: arp/rarp undefined");
+               } else if (strcmp((*argv)[0], "reply") == 0) {
+                       if (rule->ifbr_arpf.brla_flags & BRLA_ARP)
+                               rule->ifbr_arpf.brla_op = ARPOP_REPLY;
+                       else if (rule->ifbr_arpf.brla_flags & BRLA_RARP)
+                               rule->ifbr_arpf.brla_op = ARPOP_REVREPLY;
+                       else
+                               errx(1, "bridge_arprule: arp/rarp undefined");
+               } else if (strcmp((*argv)[0], "sha") == 0) {
+                       rule->ifbr_arpf.brla_flags |= BRLA_SHA;
+                       dea = &rule->ifbr_arpf.brla_sha;
+               } else if (strcmp((*argv)[0], "tha") == 0) {
+                       rule->ifbr_arpf.brla_flags |= BRLA_THA;
+                       dea = &rule->ifbr_arpf.brla_tha;
+               } else if (strcmp((*argv)[0], "spa") == 0) {
+                       rule->ifbr_arpf.brla_flags |= BRLA_SPA;
+                       dia = &rule->ifbr_arpf.brla_spa;
+               } else if (strcmp((*argv)[0], "tpa") == 0) {
+                       rule->ifbr_arpf.brla_flags |= BRLA_TPA;
+                       dia = &rule->ifbr_arpf.brla_tpa;
+               } else
+                       return (0);
+
+               (*argc)--; (*argv)++;
+               if (dea != NULL) {
+                       if (*argc == 0)
+                               return (-1);
+                       ea = ether_aton((*argv)[0]);
+                       if (ea == NULL) {
+                               warnx("invalid address: %s", (*argv)[0]);
+                               return (-1);
+                       }
+                       bcopy(ea, dea, sizeof(*dea));
+                       (*argc)--; (*argv)++;
+               }
+               if (dia != NULL) {
+                       if (*argc == 0)
+                               return (-1);
+                       ia.s_addr = inet_addr((*argv)[0]);
+                       if (ia.s_addr == INADDR_NONE) {
+                               warnx("invalid address: %s", (*argv)[0]);
+                               return (-1);
+                       }
+                       bcopy(&ia, dia, sizeof(*dia));
+                       (*argc)--; (*argv)++;
+               }
+       }
+       return (0);
+}
+
+
+#define MAXRULEWORDS 32
 
 void
 bridge_rulefile(const char *fname, int d)
Index: sbin/ifconfig/ifconfig.8
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.288
diff -u -p -r1.288 ifconfig.8
--- sbin/ifconfig/ifconfig.8    14 Sep 2017 13:02:12 -0000      1.288
+++ sbin/ifconfig/ifconfig.8    7 Nov 2017 10:09:01 -0000
@@ -685,9 +685,10 @@ like a hub or a wireless network.
 .Cm block Ns | Ns Cm pass
 .Op Cm in | out
 .Cm on Ar interface
-.Op Cm src Ar address
-.Op Cm dst Ar address
+.Op Cm src Ar lladdr
+.Op Cm dst Ar lladdr
 .Op Cm tag Ar tagname
+.Op Cm arp | rarp Ar [ request | reply ] [ Cm sha Ar lladdr ] [ Cm spa Ar 
ipaddr ] [ Cm tha Ar lladdr ] [ Cm tpa Ar ipaddr ]
 .Xc
 Add a filtering rule to an interface.
 Rules have a similar syntax to those in
@@ -697,6 +698,25 @@ MAC addresses.
 They can also tag packets for
 .Xr pf 4
 to filter on.
+.Xr arp 4
+packets can be matched with the
+.Cm arp
+keyword for regular and
+.Cm rarp
+for reverse arp packets.
+.Ar request
+and
+.Ar reply
+limit matches to requests or replies.
+The source and destination host addresses can be matched with the
+.Cm sha
+and
+.Cm tha
+keywords,
+the protocol addresses with
+.Cm spa
+and
+.Cm tpa .
 Rules are processed in the order in which they were added
 to the interface, and the first rule matched takes the action (block or pass)
 and, if given, the tag of the rule.

-- 
Henning Brauer, [email protected], [email protected]
BS Web Services GmbH, http://bsws.de, Full-Service ISP
Secure Hosting, Mail and DNS. Virtual & Dedicated Servers, Root to Fully Managed
Henning Brauer Consulting, http://henningbrauer.com/

Reply via email to