aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorArseny Smalyuk <smalukav@gmail.com>2022-06-04 16:12:29 +0000
committerAndrey V. Elsukov <ae@FreeBSD.org>2022-06-04 16:12:29 +0000
commit81cac3906eb9c14f81e03b7bcb6893b8d30e5432 (patch)
tree9aa441c93a516a29ab333ae3ca8b1f7bdda9dc09 /sbin
parent32a01b2b8691453b59a26cf273a5a5eae7643985 (diff)
Diffstat (limited to 'sbin')
-rw-r--r--sbin/ipfw/ipfw.838
-rw-r--r--sbin/ipfw/ipfw2.c132
-rw-r--r--sbin/ipfw/ipfw2.h2
-rw-r--r--sbin/ipfw/tables.c29
4 files changed, 162 insertions, 39 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 0e663fa44bdf..db8a11525b4d 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 14, 2021
+.Dd June 4, 2022
.Dt IPFW 8
.Os
.Sh NAME
@@ -1610,6 +1610,20 @@ Matches IPv6 packets containing any of the flow labels given in
.Ar labels .
.Ar labels
is a comma separated list of numeric flow labels.
+.It Cm dst-mac Ar table Ns Pq Ar name Ns Op , Ns Ar value
+Search for the destination MAC address entry in lookup table
+.Ar name .
+If not found, the match fails.
+Otherwise, the match succeeds and
+.Cm tablearg
+is set to the value extracted from the table.
+.It Cm src-mac Ar table Ns Pq Ar name Ns Op , Ns Ar value
+Search for the source MAC address entry in lookup table
+.Ar name .
+If not found, the match fails.
+Otherwise, the match succeeds and
+.Cm tablearg
+is set to the value extracted from the table.
.It Cm frag Ar spec
Matches IPv4 packets whose
.Cm ip_off
@@ -1823,7 +1837,7 @@ set of parameters as specified in the rule.
One or more
of source and destination addresses and ports can be
specified.
-.It Cm lookup Bro Cm dst-ip | dst-port | src-ip | src-port | uid | jail Brc Ar name
+.It Cm lookup Bro Cm dst-ip | dst-port | dst-mac | src-ip | src-port | src-mac | uid | jail Brc Ar name
Search an entry in lookup table
.Ar name
that matches the field specified as argument.
@@ -2133,7 +2147,7 @@ There may be up to 65535 different lookup tables.
.Pp
The following table types are supported:
.Bl -tag -width indent
-.It Ar table-type : Ar addr | iface | number | flow
+.It Ar table-type : Ar addr | iface | number | flow | mac
.It Ar table-key : Ar addr Ns Oo / Ns Ar masklen Oc | iface-name | number | flow-spec
.It Ar flow-spec : Ar flow-field Ns Op , Ns Ar flow-spec
.It Ar flow-field : src-ip | proto | src-port | dst-ip | dst-port
@@ -2163,6 +2177,20 @@ Ranges are not supported.
Matches packet fields specified by
.Ar flow
type suboptions with table entries.
+.It Cm mac
+Matches MAC address.
+Each entry is represented by an
+.Ar addr Ns Op / Ns Ar masklen
+and will match all addresses with base
+.Ar addr
+and mask width of
+.Ar masklen
+bits.
+If
+.Ar masklen
+is not specified, it defaults to 48.
+When looking up an MAC address in a table, the most specific
+entry will match.
.El
.Pp
Tables require explicit creation via
@@ -2266,7 +2294,7 @@ Shows generic table information and algo-specific data.
The following lookup algorithms are supported:
.Bl -tag -width indent
.It Ar algo-desc : algo-name | "algo-name algo-data"
-.It Ar algo-name : Ar addr: radix | addr: hash | iface: array | number: array | flow: hash
+.It Ar algo-name : Ar addr: radix | addr: hash | iface: array | number: array | flow: hash | mac: radix
.It Cm addr: radix
Separate Radix trees for IPv4 and IPv6, the same way as the routing table (see
.Xr route 4 ) .
@@ -2291,6 +2319,8 @@ Array storing sorted u32 numbers.
Auto-growing hash storing flow entries.
Search calculates hash on required packet fields and searches for matching
entries in selected bucket.
+.It Cm mac: radix
+Radix tree for MAC address
.El
.Pp
The
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index e210cbfd02ec..7d820698a25d 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -300,12 +300,20 @@ static struct _s_x rule_action_params[] = {
/*
* The 'lookup' instruction accepts one of the following arguments.
- * -1 is a terminator for the list.
* Arguments are passed as v[1] in O_DST_LOOKUP options.
*/
-static int lookup_key[] = {
- TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT,
- TOK_UID, TOK_JAIL, TOK_DSCP, -1 };
+static struct _s_x lookup_keys[] = {
+ { "dst-ip", LOOKUP_DST_IP },
+ { "src-ip", LOOKUP_SRC_IP },
+ { "dst-port", LOOKUP_DST_PORT },
+ { "src-port", LOOKUP_SRC_PORT },
+ { "dst-mac", LOOKUP_DST_MAC },
+ { "src-mac", LOOKUP_SRC_MAC },
+ { "uid", LOOKUP_UID },
+ { "jail", LOOKUP_JAIL },
+ { "dscp", LOOKUP_DSCP },
+ { NULL, 0 },
+};
static struct _s_x rule_options[] = {
{ "tagged", TOK_TAGGED },
@@ -358,6 +366,8 @@ static struct _s_x rule_options[] = {
{ "src-ip", TOK_SRCIP },
{ "dst-port", TOK_DSTPORT },
{ "src-port", TOK_SRCPORT },
+ { "dst-mac", TOK_DSTMAC },
+ { "src-mac", TOK_SRCMAC },
{ "proto", TOK_PROTO },
{ "MAC", TOK_MAC },
{ "mac", TOK_MAC },
@@ -368,18 +378,18 @@ static struct _s_x rule_options[] = {
{ "ipsec", TOK_IPSEC },
{ "icmp6type", TOK_ICMP6TYPES },
{ "icmp6types", TOK_ICMP6TYPES },
- { "ext6hdr", TOK_EXT6HDR},
- { "flow-id", TOK_FLOWID},
- { "ipv6", TOK_IPV6},
- { "ip6", TOK_IPV6},
- { "ipv4", TOK_IPV4},
- { "ip4", TOK_IPV4},
- { "dst-ipv6", TOK_DSTIP6},
- { "dst-ip6", TOK_DSTIP6},
- { "src-ipv6", TOK_SRCIP6},
- { "src-ip6", TOK_SRCIP6},
- { "lookup", TOK_LOOKUP},
- { "flow", TOK_FLOW},
+ { "ext6hdr", TOK_EXT6HDR },
+ { "flow-id", TOK_FLOWID },
+ { "ipv6", TOK_IPV6 },
+ { "ip6", TOK_IPV6 },
+ { "ipv4", TOK_IPV4 },
+ { "ip4", TOK_IPV4 },
+ { "dst-ipv6", TOK_DSTIP6 },
+ { "dst-ip6", TOK_DSTIP6 },
+ { "src-ipv6", TOK_SRCIP6 },
+ { "src-ip6", TOK_SRCIP6 },
+ { "lookup", TOK_LOOKUP },
+ { "flow", TOK_FLOW },
{ "defer-action", TOK_SKIPACTION },
{ "defer-immediate-action", TOK_SKIPACTION },
{ "//", TOK_COMMENT },
@@ -1211,11 +1221,9 @@ print_ip(struct buf_pr *bp, const struct format_opts *fo,
bprintf(bp, " ");
if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
- uint32_t d = a[1];
- const char *arg = "<invalid>";
+ const char *arg;
- if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
- arg = match_value(rule_options, lookup_key[d]);
+ arg = match_value(lookup_keys, a[1]);
t = table_search_ctlv(fo->tstate,
((const ipfw_insn *)cmd)->arg1);
bprintf(bp, "lookup %s %s", arg, t);
@@ -1332,6 +1340,22 @@ print_mac(struct buf_pr *bp, const ipfw_insn_mac *mac)
}
static void
+print_mac_lookup(struct buf_pr *bp, const struct format_opts *fo,
+ const ipfw_insn *cmd)
+{
+ uint32_t len = F_LEN(cmd);
+ char *t;
+
+ bprintf(bp, " ");
+
+ t = table_search_ctlv(fo->tstate, cmd->arg1);
+ bprintf(bp, "table(%s", t);
+ if (len == F_INSN_SIZE(ipfw_insn_u32))
+ bprintf(bp, ",%u", ((const ipfw_insn_u32 *)cmd)->d[0]);
+ bprintf(bp, ")");
+}
+
+static void
fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
{
uint8_t type;
@@ -1518,6 +1542,14 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
bprintf(bp, " dst-ip6");
print_ip6(bp, insntod(cmd, ip6));
break;
+ case O_MAC_SRC_LOOKUP:
+ bprintf(bp, " src-mac");
+ print_mac_lookup(bp, fo, cmd);
+ break;
+ case O_MAC_DST_LOOKUP:
+ bprintf(bp, " dst-mac");
+ print_mac_lookup(bp, fo, cmd);
+ break;
case O_FLOW6ID:
print_flow6id(bp, insntod(cmd, u32));
break;
@@ -2650,7 +2682,6 @@ list_static_range(struct cmdline_opts *co, struct format_opts *fo,
int n, seen;
struct ip_fw_rule *r;
struct ip_fw_bcounter *cntr;
- int c = 0;
for (n = seen = 0; n < rcnt; n++,
rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) {
@@ -2669,7 +2700,6 @@ list_static_range(struct cmdline_opts *co, struct format_opts *fo,
if (r->rulenum >= fo->first && r->rulenum <= fo->last) {
show_static_rule(co, fo, bp, r, cntr);
printf("%s", bp->buf);
- c += rtlv->length;
bp_flush(bp);
seen++;
}
@@ -2788,13 +2818,12 @@ ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
char *endptr;
size_t readsz;
struct buf_pr bp;
- ipfw_obj_ctlv *ctlv, *tstate;
+ ipfw_obj_ctlv *ctlv;
ipfw_obj_tlv *rbase;
/*
* Handle tablenames TLV first, if any
*/
- tstate = NULL;
rbase = NULL;
dynbase = NULL;
dynsz = 0;
@@ -3682,6 +3711,29 @@ add_dstip(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
return cmd;
}
+static ipfw_insn *
+add_srcmac(ipfw_insn *cmd, char *av, struct tidx *tstate)
+{
+
+ if (strncmp(av, "table(", 6) == 0)
+ fill_table(cmd, av, O_MAC_SRC_LOOKUP, tstate);
+ else
+ errx(EX_DATAERR, "only mac table lookup is supported %s", av);
+ return cmd;
+}
+
+static ipfw_insn *
+add_dstmac(ipfw_insn *cmd, char *av, struct tidx *tstate)
+{
+
+ if (strncmp(av, "table(", 6) == 0)
+ fill_table(cmd, av, O_MAC_DST_LOOKUP, tstate);
+ else
+ errx(EX_DATAERR, "only mac table lookup is supported %s", av);
+ return cmd;
+}
+
+
static struct _s_x f_reserved_keywords[] = {
{ "altq", TOK_OR },
{ "//", TOK_OR },
@@ -4912,6 +4964,21 @@ read_options:
}
break;
+
+ case TOK_SRCMAC:
+ NEED1("missing source MAC");
+ if (add_srcmac(cmd, *av, tstate)) {
+ av++;
+ }
+ break;
+
+ case TOK_DSTMAC:
+ NEED1("missing destination MAC");
+ if (add_dstmac(cmd, *av, tstate)) {
+ av++;
+ }
+ break;
+
case TOK_SRCPORT:
NEED1("missing source port");
if (_substrcmp(*av, "any") == 0 ||
@@ -5013,28 +5080,23 @@ read_options:
case TOK_LOOKUP: {
ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
- int j;
if (!av[0] || !av[1])
errx(EX_USAGE, "format: lookup argument tablenum");
cmd->opcode = O_IP_DST_LOOKUP;
cmd->len |= F_INSN_SIZE(ipfw_insn) + 2;
- i = match_token(rule_options, *av);
- for (j = 0; lookup_key[j] >= 0 ; j++) {
- if (i == lookup_key[j])
- break;
- }
- if (lookup_key[j] <= 0)
+ i = match_token(lookup_keys, *av);
+ if (i == -1)
errx(EX_USAGE, "format: cannot lookup on %s", *av);
- __PAST_END(c->d, 1) = j; // i converted to option
+ __PAST_END(c->d, 1) = i;
av++;
- if ((j = pack_table(tstate, *av)) == 0)
+ if ((i = pack_table(tstate, *av)) == 0)
errx(EX_DATAERR, "Invalid table name: %s", *av);
- cmd->arg1 = j;
+ cmd->arg1 = i;
av++;
- }
+ }
break;
case TOK_FLOW:
NEED1("missing table name");
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index 9a39c215692d..dd7699987434 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -177,6 +177,8 @@ enum tokens {
TOK_SRCIP,
TOK_DSTPORT,
TOK_SRCPORT,
+ TOK_DSTMAC,
+ TOK_SRCMAC,
TOK_ALL,
TOK_MASK,
TOK_FLOW_MASK,
diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c
index 81cf7e392586..9e6390492e96 100644
--- a/sbin/ipfw/tables.c
+++ b/sbin/ipfw/tables.c
@@ -31,6 +31,7 @@
#include <string.h>
#include <sysexits.h>
+#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip_fw.h>
@@ -77,6 +78,7 @@ static int tables_foreach(table_cb_t *f, void *arg, int sort);
static struct _s_x tabletypes[] = {
{ "addr", IPFW_TABLE_ADDR },
+ { "mac", IPFW_TABLE_MAC },
{ "iface", IPFW_TABLE_INTERFACE },
{ "number", IPFW_TABLE_NUMBER },
{ "flow", IPFW_TABLE_FLOW },
@@ -1188,6 +1190,7 @@ tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
char *p, *pp;
int mask, af;
struct in6_addr *paddr, tmp;
+ struct ether_addr *mac;
struct tflow_entry *tfe;
uint32_t key, *pkey;
uint16_t port;
@@ -1234,6 +1237,24 @@ tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
af = AF_INET;
}
break;
+ case IPFW_TABLE_MAC:
+ /* Remove / if exists */
+ if ((p = strchr(arg, '/')) != NULL) {
+ *p = '\0';
+ mask = atoi(p + 1);
+ }
+
+ if (p != NULL && mask > 8 * ETHER_ADDR_LEN)
+ errx(EX_DATAERR, "bad MAC mask width: %s",
+ p + 1);
+
+ if ((mac = ether_aton(arg)) == NULL)
+ errx(EX_DATAERR, "Incorrect MAC address");
+
+ memcpy(tentry->k.mac, mac->octet, ETHER_ADDR_LEN);
+ masklen = p ? mask : 8 * ETHER_ADDR_LEN;
+ af = AF_LINK;
+ break;
case IPFW_TABLE_INTERFACE:
/* Assume interface name. Copy significant data only */
mask = MIN(strlen(arg), IF_NAMESIZE - 1);
@@ -1872,6 +1893,7 @@ table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
{
char tbuf[128], pval[128];
const char *comma;
+ const u_char *mac;
void *paddr;
struct tflow_entry *tfe;
@@ -1884,6 +1906,13 @@ table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
printf("%s/%u %s\n", tbuf, tent->masklen, pval);
break;
+ case IPFW_TABLE_MAC:
+ /* MAC prefixes */
+ mac = tent->k.mac;
+ printf("%02x:%02x:%02x:%02x:%02x:%02x/%u %s\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
+ tent->masklen, pval);
+ break;
case IPFW_TABLE_INTERFACE:
/* Interface names */
printf("%s %s\n", tent->k.iface, pval);