-/* $OpenBSD: brconfig.c,v 1.16 2017/07/31 02:32:11 jsg Exp $ */
+/* $OpenBSD: brconfig.c,v 1.17 2018/02/05 03:51:53 henning Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
#include <errno.h>
#include <getopt.h>
#include <limits.h>
+#include <arpa/inet.h>
#include "brconfig.h"
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 \
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");
}
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)
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");
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) {
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)
-.\" $OpenBSD: ifconfig.8,v 1.292 2018/01/16 10:33:55 mpi Exp $
+.\" $OpenBSD: ifconfig.8,v 1.293 2018/02/05 03:51:53 henning 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 $
.\"
.\"
.\" @(#)ifconfig.8 8.4 (Berkeley) 6/1/94
.\"
-.Dd $Mdocdate: January 16 2018 $
+.Dd $Mdocdate: February 5 2018 $
.Dt IFCONFIG 8
.Os
.Sh NAME
.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
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 target 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.
-/* $OpenBSD: bridgectl.c,v 1.6 2017/05/04 15:00:24 bluhm Exp $ */
+/* $OpenBSD: bridgectl.c,v 1.7 2018/02/05 03:51:53 henning Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
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)
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)
return (error);
}
+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)
{
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;
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);
-/* $OpenBSD: if_bridge.c,v 1.301 2018/01/10 23:50:39 dlg Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.302 2018/02/05 03:51:53 henning Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
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. */
}
}
+ 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)
continue;
-/* $OpenBSD: if_bridge.h,v 1.55 2017/01/20 05:03:48 claudio Exp $ */
+/* $OpenBSD: if_bridge.h,v 1.56 2018/02/05 03:51:53 henning Exp $ */
/*
* Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
/*
* 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 */
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 */
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 {