Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F110152406
D31738.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D31738.diff
View Options
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -65,6 +65,43 @@
uint64_t bcounters[2][2];
};
+struct pfctl_eth_rules_info {
+ uint32_t nr;
+ uint32_t ticket;
+};
+
+struct pfctl_eth_addr {
+ uint8_t addr[ETHER_ADDR_LEN];
+ bool neg;
+};
+
+struct pfctl_eth_rule {
+ uint32_t nr;
+
+ bool quick;
+
+ /* Filter */
+ char ifname[IFNAMSIZ];
+ uint8_t ifnot;
+ uint8_t direction;
+ uint16_t proto;
+ struct pfctl_eth_addr src, dst;
+
+ /* Stats */
+ uint64_t evaluations;
+ uint64_t packets[2];
+ uint64_t bytes[2];
+
+ /* Action */
+ char qname[PF_QNAME_SIZE];
+ char tagname[PF_TAG_NAME_SIZE];
+ uint8_t action;
+
+ TAILQ_ENTRY(pfctl_eth_rule) entries;
+};
+
+TAILQ_HEAD(pfctl_eth_rules, pfctl_eth_rule);
+
struct pfctl_pool {
struct pf_palist list;
struct pf_pooladdr *cur;
@@ -291,6 +328,11 @@
struct pfctl_status* pfctl_get_status(int dev);
void pfctl_free_status(struct pfctl_status *status);
+int pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules);
+int pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
+ struct pfctl_eth_rule *rule, bool clear);
+int pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r,
+ uint32_t ticket);
int pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket,
const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
char *anchor_call);
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -546,6 +546,185 @@
rule->src_nodes = nvlist_get_number(nvl, "src_nodes");
}
+static void
+pfctl_nveth_addr_to_eth_addr(const nvlist_t *nvl, struct pfctl_eth_addr *addr)
+{
+ size_t len;
+ const void *data;
+
+ data = nvlist_get_binary(nvl, "addr", &len);
+ assert(len == sizeof(addr->addr));
+ memcpy(addr->addr, data, sizeof(addr->addr));
+
+ addr->neg = nvlist_get_bool(nvl, "neg");
+}
+
+static nvlist_t *
+pfctl_eth_addr_to_nveth_addr(const struct pfctl_eth_addr *addr)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ if (nvl == NULL)
+ return (NULL);
+
+ nvlist_add_bool(nvl, "neg", addr->neg);
+ nvlist_add_binary(nvl, "addr", &addr->addr, ETHER_ADDR_LEN);
+
+ return (nvl);
+}
+
+static void
+pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule)
+{
+ rule->nr = nvlist_get_number(nvl, "nr");
+ rule->quick = nvlist_get_bool(nvl, "quick");
+ strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
+ rule->ifnot = nvlist_get_bool(nvl, "ifnot");
+ rule->direction = nvlist_get_number(nvl, "direction");
+ rule->proto = nvlist_get_number(nvl, "proto");
+
+ pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "src"),
+ &rule->src);
+ pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "dst"),
+ &rule->dst);
+
+ rule->evaluations = nvlist_get_number(nvl, "evaluations");
+ rule->packets[0] = nvlist_get_number(nvl, "packets-in");
+ rule->packets[1] = nvlist_get_number(nvl, "packets-out");
+ rule->bytes[0] = nvlist_get_number(nvl, "bytes-in");
+ rule->bytes[1] = nvlist_get_number(nvl, "bytes-out");
+
+ strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE);
+ strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"),
+ PF_TAG_NAME_SIZE);
+
+ rule->action = nvlist_get_number(nvl, "action");
+}
+
+int
+pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules)
+{
+ uint8_t buf[1024];
+ struct pfioc_nv nv;
+ nvlist_t *nvl;
+
+ bzero(rules, sizeof(*rules));
+
+ nv.data = buf;
+ nv.len = nv.size = sizeof(buf);
+
+ if (ioctl(dev, DIOCGETETHRULES, &nv) != 0)
+ return (errno);
+
+ nvl = nvlist_unpack(buf, nv.len, 0);
+ if (nvl == NULL)
+ return (EIO);
+
+ rules->nr = nvlist_get_number(nvl, "nr");
+ rules->ticket = nvlist_get_number(nvl, "ticket");
+
+ nvlist_destroy(nvl);
+ return (0);
+}
+
+int
+pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
+ struct pfctl_eth_rule *rule, bool clear)
+{
+ uint8_t buf[1024];
+ struct pfioc_nv nv;
+ nvlist_t *nvl;
+ void *data;
+ size_t len;
+
+ nvl = nvlist_create(0);
+
+ nvlist_add_number(nvl, "ticket", ticket);
+ nvlist_add_number(nvl, "nr", nr);
+ nvlist_add_bool(nvl, "clear", clear);
+
+ data = nvlist_pack(nvl, &len);
+ nv.data = buf;
+ memcpy(buf, data, len);
+ free(data);
+ nv.len = len;
+ nv.size = sizeof(buf);
+ if (ioctl(dev, DIOCGETETHRULE, &nv)) {
+ nvlist_destroy(nvl);
+ return (errno);
+ }
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_unpack(buf, nv.len, 0);
+ if (nvl == NULL) {
+ return (EIO);
+ }
+
+ pfctl_nveth_rule_to_eth_rule(nvl, rule);
+
+ nvlist_destroy(nvl);
+ return (0);
+}
+
+int
+pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, uint32_t ticket)
+{
+ struct pfioc_nv nv;
+ nvlist_t *nvl, *addr;
+ void *packed;
+ int error;
+ size_t size;
+
+ nvl = nvlist_create(0);
+
+ nvlist_add_number(nvl, "ticket", ticket);
+
+ nvlist_add_number(nvl, "nr", r->nr);
+ nvlist_add_bool(nvl, "quick", r->quick);
+ nvlist_add_string(nvl, "ifname", r->ifname);
+ nvlist_add_bool(nvl, "ifnot", r->ifnot);
+ nvlist_add_number(nvl, "direction", r->direction);
+ nvlist_add_number(nvl, "proto", r->proto);
+
+ addr = pfctl_eth_addr_to_nveth_addr(&r->src);
+ if (addr == NULL) {
+ nvlist_destroy(nvl);
+ return (ENOMEM);
+ }
+ nvlist_add_nvlist(nvl, "src", addr);
+ nvlist_destroy(addr);
+
+ addr = pfctl_eth_addr_to_nveth_addr(&r->dst);
+ if (addr == NULL) {
+ nvlist_destroy(nvl);
+ return (ENOMEM);
+ }
+ nvlist_add_nvlist(nvl, "dst", addr);
+ nvlist_destroy(addr);
+
+ nvlist_add_string(nvl, "qname", r->qname);
+ nvlist_add_string(nvl, "tagname", r->tagname);
+ nvlist_add_number(nvl, "action", r->action);
+
+ packed = nvlist_pack(nvl, &size);
+ if (packed == NULL) {
+ nvlist_destroy(nvl);
+ return (ENOMEM);
+ }
+
+ nv.len = size;
+ nv.size = size;
+ nv.data = packed;
+
+ error = ioctl(dev, DIOCADDETHRULE, &nv);
+
+ free(packed);
+ nvlist_destroy(nvl);
+
+ return (error);
+}
+
int
pfctl_add_rule(int dev, const struct pfctl_rule *r, const char *anchor,
const char *anchor_call, uint32_t ticket, uint32_t pool_ticket)
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -122,12 +122,19 @@
enum {
PFCTL_STATE_NONE,
PFCTL_STATE_OPTION,
+ PFCTL_STATE_ETHER,
PFCTL_STATE_SCRUB,
PFCTL_STATE_QUEUE,
PFCTL_STATE_NAT,
PFCTL_STATE_FILTER
};
+struct node_etherproto {
+ u_int16_t proto;
+ struct node_etherproto *next;
+ struct node_etherproto *tail;
+};
+
struct node_proto {
u_int8_t proto;
struct node_proto *next;
@@ -341,6 +348,8 @@
void expand_label_proto(const char *, char *, size_t, u_int8_t);
void expand_label_nr(const char *, char *, size_t,
struct pfctl_rule *);
+void expand_eth_rule(struct pfctl_eth_rule *,
+ struct node_if *, struct node_etherproto *);
void expand_rule(struct pfctl_rule *, struct node_if *,
struct node_host *, struct node_proto *, struct node_os *,
struct node_host *, struct node_port *, struct node_host *,
@@ -396,6 +405,7 @@
} range;
struct node_if *interface;
struct node_proto *proto;
+ struct node_etherproto *etherproto;
struct node_icmp *icmp;
struct node_host *host;
struct node_os *os;
@@ -408,6 +418,17 @@
struct peer src, dst;
struct node_os *src_os;
} fromto;
+ struct {
+ u_int8_t src[ETHER_ADDR_LEN];
+ u_int8_t srcneg;
+ u_int8_t dst[ETHER_ADDR_LEN];
+ u_int8_t dstneg;
+ } etherfromto;
+ u_int8_t mac[ETHER_ADDR_LEN];
+ struct {
+ uint8_t mac[ETHER_ADDR_LEN];
+ u_int8_t neg;
+ } etheraddr;
struct {
struct node_host *host;
u_int8_t rt;
@@ -470,6 +491,7 @@
%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY FAILPOLICY
%token RANDOMID REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
%token ANTISPOOF FOR INCLUDE KEEPCOUNTERS SYNCOOKIES
+%token ETHER
%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY MAPEPORTSET
%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME
%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL
@@ -488,6 +510,7 @@
%type <v.probability> probability
%type <v.i> no dir af fragcache optimizer syncookie_val
%type <v.i> sourcetrack flush unaryop statelock
+%type <v.i> etherprotoval
%type <v.b> action nataction natpasslog scrubaction
%type <v.b> flags flag blockspec prio
%type <v.range> portplain portstar portrange
@@ -515,7 +538,7 @@
%type <v.state_opt> state_opt_spec state_opt_list state_opt_item
%type <v.logquick> logquick quick log logopts logopt
%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if
-%type <v.qassign> qname
+%type <v.qassign> qname etherqname
%type <v.queue> qassign qassign_list qassign_item
%type <v.queue_options> scheduler
%type <v.number> cbqflags_list cbqflags_item
@@ -524,7 +547,7 @@
%type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts
%type <v.codel_opts> codelopts_list codelopts_item codel_opts
%type <v.queue_bwspec> bandwidth
-%type <v.filter_opts> filter_opts filter_opt filter_opts_l
+%type <v.filter_opts> filter_opts filter_opt filter_opts_l etherfilter_opts etherfilter_opt etherfilter_opts_l
%type <v.filter_opts> filter_sets filter_set filter_sets_l
%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l
%type <v.queue_opts> queue_opts queue_opt queue_opts_l
@@ -534,12 +557,17 @@
%type <v.tagged> tagged
%type <v.rtableid> rtable
%type <v.watermarks> syncookie_opts
+%type <v.etherproto> etherproto etherproto_list etherproto_item
+%type <v.etherfromto> etherfromto
+%type <v.etheraddr> etherfrom etherto
+%type <v.mac> mac
%%
ruleset : /* empty */
| ruleset include '\n'
| ruleset '\n'
| ruleset option '\n'
+ | ruleset etherrule '\n'
| ruleset scrubrule '\n'
| ruleset natrule '\n'
| ruleset binatrule '\n'
@@ -1151,6 +1179,58 @@
}
;
+etherrule : ETHER action dir quick interface etherproto etherfromto etherfilter_opts
+ {
+ struct pfctl_eth_rule r;
+
+ bzero(&r, sizeof(r));
+
+ if (check_rulestate(PFCTL_STATE_ETHER))
+ YYERROR;
+
+ r.action = $2.b1;
+ r.direction = $3;
+ r.quick = $4.quick;
+ /* XXX TODO: ! support */
+ memcpy(&r.src.addr, $7.src, sizeof(r.src.addr));
+ r.src.neg = $7.srcneg;
+ memcpy(&r.dst.addr, $7.dst, sizeof(r.dst.addr));
+ r.dst.neg = $7.dstneg;
+ if ($8.tag != NULL)
+ memcpy(&r.tagname, $8.tag, sizeof(r.tagname));
+ if ($8.queues.qname != NULL)
+ memcpy(&r.qname, $8.queues.qname, sizeof(r.qname));
+
+ expand_eth_rule(&r, $5, $6);
+ }
+ ;
+
+etherfilter_opts : {
+ bzero(&filter_opts, sizeof filter_opts);
+ }
+ etherfilter_opts_l
+ { $$ = filter_opts; }
+ | /* empty */ {
+ bzero(&filter_opts, sizeof filter_opts);
+ $$ = filter_opts;
+ }
+ ;
+
+etherfilter_opts_l : etherfilter_opts_l etherfilter_opt
+ | etherfilter_opt
+
+etherfilter_opt : etherqname {
+ if (filter_opts.queues.qname) {
+ yyerror("queue cannot be redefined");
+ YYERROR;
+ }
+ filter_opts.queues = $1;
+ }
+ | TAG string {
+ filter_opts.tag = $2;
+ }
+ ;
+
scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts
{
struct pfctl_rule r;
@@ -2978,6 +3058,56 @@
| INET6 { $$ = AF_INET6; }
;
+etherproto : /* empty */ { $$ = NULL; }
+ | PROTO etherproto_item { $$ = $2; }
+ | PROTO '{' optnl etherproto_list '}' { $$ = $4; }
+ ;
+
+etherproto_list : etherproto_item optnl { $$ = $1; }
+ | etherproto_list comma etherproto_item optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
+
+etherproto_item : etherprotoval {
+ u_int16_t pr;
+
+ pr = (u_int16_t)$1;
+ if (pr == 0) {
+ yyerror("proto 0 cannot be used");
+ YYERROR;
+ }
+ $$ = calloc(1, sizeof(struct node_proto));
+ if ($$ == NULL)
+ err(1, "proto_item: calloc");
+ $$->proto = pr;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
+ ;
+
+etherprotoval : NUMBER {
+ if ($1 < 0 || $1 > 65565) {
+ yyerror("protocol outside range");
+ YYERROR;
+ }
+ }
+ | STRING
+ {
+ if (!strncmp($1, "0x", 2)) {
+ if (sscanf($1, "0x%4x", &$$) != 1) {
+ free($1);
+ yyerror("invalid EtherType hex");
+ YYERROR;
+ }
+ } else {
+ yyerror("Symbolic EtherType not yet supported");
+ }
+ }
+ ;
+
proto : /* empty */ { $$ = NULL; }
| PROTO proto_item { $$ = $2; }
| PROTO '{' optnl proto_list '}' { $$ = $4; }
@@ -3028,6 +3158,50 @@
}
;
+etherfromto : ALL {
+ bzero($$.src, sizeof($$.src));
+ $$.srcneg = 0;
+ bzero($$.dst, sizeof($$.dst));
+ $$.dstneg = 0;
+ }
+ | etherfrom etherto {
+ memcpy(&$$.src, $1.mac, sizeof($$.src));
+ $$.srcneg = $1.neg;
+ memcpy(&$$.dst, $2.mac, sizeof($$.dst));
+ $$.dstneg = $2.neg;
+ }
+ ;
+
+etherfrom : /* emtpy */ {
+ bzero(&$$, sizeof($$));
+ }
+ | FROM not mac {
+ memcpy(&$$.mac, $3, sizeof($$));
+ $$.neg = $2;
+ }
+ ;
+
+etherto : /* empty */ {
+ bzero(&$$, sizeof($$));
+ }
+ | TO not mac {
+ memcpy(&$$.mac, $3, sizeof($$));
+ $$.neg = $2;
+ }
+ ;
+
+mac : string {
+ if (sscanf($1, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &$$[0], &$$[1], &$$[2], &$$[3], &$$[4],
+ &$$[5]) != 6) {
+ free($$);
+ free($1);
+ yyerror("invalid MAC address");
+ YYERROR;
+ }
+ }
+ ;
+
fromto : ALL {
$$.src.host = NULL;
$$.src.port = NULL;
@@ -3965,6 +4139,14 @@
}
;
+etherqname : QUEUE STRING {
+ $$.qname = $2;
+ }
+ | QUEUE '(' STRING ')' {
+ $$.qname = $3;
+ }
+ ;
+
qname : QUEUE STRING {
$$.qname = $2;
$$.pqname = NULL;
@@ -5422,6 +5604,31 @@
return (0);
}
+void
+expand_eth_rule(struct pfctl_eth_rule *r,
+ struct node_if *interfaces, struct node_etherproto *protos)
+{
+ struct pfctl_eth_rule *rule;
+
+ LOOP_THROUGH(struct node_if, interface, interfaces,
+ LOOP_THROUGH(struct node_etherproto, proto, protos,
+ r->nr = pf->eth_nr++;
+ strlcpy(r->ifname, interface->ifname,
+ sizeof(r->ifname));
+ r->ifnot = interface->not;
+ r->proto = proto->proto;
+
+ if ((rule = calloc(1, sizeof(*rule))) == NULL)
+ err(1, "calloc");
+ bcopy(r, rule, sizeof(*rule));
+
+ TAILQ_INSERT_TAIL(&pf->eth_rules, rule, entries);
+ ));
+
+ FREE_LIST(struct node_if, interfaces);
+ FREE_LIST(struct node_etherproto, protos);
+}
+
void
expand_rule(struct pfctl_rule *r,
struct node_if *interfaces, struct node_host *rpool_hosts,
@@ -5638,8 +5845,8 @@
check_rulestate(int desired_state)
{
if (require_order && (rulestate > desired_state)) {
- yyerror("Rules must be in order: options, normalization, "
- "queueing, translation, filtering");
+ yyerror("Rules must be in order: options, ethernet, "
+ "normalization, queueing, translation, filtering");
return (1);
}
rulestate = desired_state;
@@ -5682,6 +5889,7 @@
{ "drop", DROP},
{ "drop-ovl", FRAGDROP},
{ "dup-to", DUPTO},
+ { "ether", ETHER},
{ "fail-policy", FAILPOLICY},
{ "fairq", FAIRQ},
{ "fastroute", FASTROUTE},
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -96,7 +96,9 @@
int pfctl_load_syncookies(struct pfctl *, u_int8_t);
int pfctl_get_pool(int, struct pfctl_pool *, u_int32_t, u_int32_t, int,
char *);
+void pfctl_print_eth_rule_counters(struct pfctl_eth_rule *, int);
void pfctl_print_rule_counters(struct pfctl_rule *, int);
+int pfctl_show_eth_rules(int, int);
int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int);
int pfctl_show_nat(int, int, char *);
int pfctl_show_src_nodes(int, int);
@@ -109,6 +111,7 @@
int pfctl_test_altqsupport(int, int);
int pfctl_show_anchors(int, int, char *);
int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *);
+int pfctl_load_eth_ruleset(struct pfctl *);
int pfctl_load_ruleset(struct pfctl *, char *,
struct pfctl_ruleset *, int, int);
int pfctl_load_rule(struct pfctl *, char *, struct pfctl_rule *, int);
@@ -222,9 +225,9 @@
};
static const char * const showopt_list[] = {
- "nat", "queue", "rules", "Anchors", "Sources", "states", "info",
- "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp",
- "Running", "all", NULL
+ "ether", "nat", "queue", "rules", "Anchors", "Sources", "states",
+ "info", "Interfaces", "labels", "timeouts", "memory", "Tables",
+ "osfp", "Running", "all", NULL
};
static const char * const tblcmdopt_list[] = {
@@ -986,6 +989,20 @@
}
}
+void
+pfctl_print_eth_rule_counters(struct pfctl_eth_rule *rule, int opts)
+{
+ if (opts & PF_OPT_VERBOSE) {
+ printf(" [ Evaluations: %-8llu Packets: %-8llu "
+ "Bytes: %-10llu]\n",
+ (unsigned long long)rule->evaluations,
+ (unsigned long long)(rule->packets[0] +
+ rule->packets[1]),
+ (unsigned long long)(rule->bytes[0] +
+ rule->bytes[1]));
+ }
+}
+
void
pfctl_print_rule_counters(struct pfctl_rule *rule, int opts)
{
@@ -1034,6 +1051,35 @@
printf("%s\n", title);
}
+int
+pfctl_show_eth_rules(int dev, int opts)
+{
+ struct pfctl_eth_rules_info info;
+ struct pfctl_eth_rule rule;
+ int dotitle = opts & PF_OPT_SHOWALL;
+
+ if (pfctl_get_eth_rules_info(dev, &info)) {
+ warn("DIOCGETETHRULES");
+ return (-1);
+ }
+ for (int nr = 0; nr < info.nr; nr++) {
+ if (pfctl_get_eth_rule(dev, nr, info.ticket, &rule, false)
+ != 0) {
+ warn("DIOCGETETHRULE");
+ return (-1);
+ }
+ if (dotitle) {
+ pfctl_print_title("ETH RULES:");
+ dotitle = 0;
+ }
+ print_eth_rule(&rule, opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG));
+ printf("\n");
+ pfctl_print_eth_rule_counters(&rule, opts);
+ }
+
+ return (0);
+}
+
int
pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
char *anchorname, int depth)
@@ -1466,6 +1512,12 @@
{
int osize = pf->trans->pfrb_size;
+ if ((pf->loadopt & PFCTL_FLAG_ETH) != 0) {
+ if (! path[0]) {
+ if (pfctl_add_trans(pf->trans, PF_RULESET_ETH, path))
+ return (1);
+ }
+ }
if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) {
if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) ||
pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) ||
@@ -1491,6 +1543,27 @@
return (0);
}
+int
+pfctl_load_eth_ruleset(struct pfctl *pf)
+{
+ struct pfctl_eth_rule *r;
+ int error;
+
+ while ((r = TAILQ_FIRST(&pf->eth_rules)) != NULL) {
+ TAILQ_REMOVE(&pf->eth_rules, r, entries);
+
+ if ((pf->opts & PF_OPT_NOACTION) == 0) {
+ error = pfctl_add_eth_rule(pf->dev, r, pf->eth_ticket);
+ if (error)
+ return (error);
+ }
+
+ free(r);
+ }
+
+ return (0);
+}
+
int
pfctl_load_ruleset(struct pfctl *pf, char *path, struct pfctl_ruleset *rs,
int rs_num, int depth)
@@ -1669,6 +1742,7 @@
pf.opts = opts;
pf.optimize = optimize;
pf.loadopt = loadopt;
+ TAILQ_INIT(&pf.eth_rules);
/* non-brace anchor, create without resolving the path */
if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL)
@@ -1700,6 +1774,8 @@
*/
if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor))
ERRX("pfctl_rules");
+ if (pf.loadopt & PFCTL_FLAG_ETH)
+ pf.eth_ticket = pfctl_get_ticket(t, PF_RULESET_ETH, anchorname);
if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ))
pa.ticket =
pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname);
@@ -1720,6 +1796,8 @@
if ((pf.loadopt & PFCTL_FLAG_FILTER &&
(pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) ||
+ (pf.loadopt & PFCTL_FLAG_ETH &&
+ (pfctl_load_eth_ruleset(&pf))) ||
(pf.loadopt & PFCTL_FLAG_NAT &&
(pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) ||
pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) ||
@@ -2561,10 +2639,15 @@
case 'm':
pfctl_show_limits(dev, opts);
break;
+ case 'e':
+ pfctl_show_eth_rules(dev, opts);
+ break;
case 'a':
opts |= PF_OPT_SHOWALL;
pfctl_load_fingerprints(dev, opts);
+ pfctl_show_eth_rules(dev, opts);
+
pfctl_show_nat(dev, opts, anchorname);
pfctl_show_rules(dev, path, opts, 0, anchorname, 0);
pfctl_show_altq(dev, ifaceopt, opts, 0);
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -90,6 +90,9 @@
struct pfioc_queue *pqueue;
struct pfr_buffer *trans;
struct pfctl_anchor *anchor, *alast;
+ int eth_nr;
+ struct pfctl_eth_rules eth_rules;
+ u_int32_t eth_ticket;
const char *ruleset;
/* 'set foo' options */
@@ -284,6 +287,7 @@
void print_pool(struct pfctl_pool *, u_int16_t, u_int16_t, sa_family_t, int);
void print_src_node(struct pf_src_node *, int);
+void print_eth_rule(struct pfctl_eth_rule *, int);
void print_rule(struct pfctl_rule *, const char *, int, int);
void print_tabledef(const char *, int, int, struct node_tinithead *);
void print_status(struct pfctl_status *, struct pfctl_syncookies *, int);
@@ -336,6 +340,7 @@
#define PFCTL_FLAG_OPTION 0x08
#define PFCTL_FLAG_ALTQ 0x10
#define PFCTL_FLAG_TABLE 0x20
+#define PFCTL_FLAG_ETH 0x40
extern const struct pf_timeout pf_timeouts[];
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -691,6 +691,50 @@
}
}
+static void
+print_eth_addr(const struct pfctl_eth_addr *a)
+{
+ printf("%s%02x:%02x:%02x:%02x:%02x:%02x", a->neg ? "! " : "",
+ a->addr[0], a->addr[1], a->addr[2], a->addr[3], a->addr[4],
+ a->addr[5]);
+}
+
+void
+print_eth_rule(struct pfctl_eth_rule *r, int rule_numbers)
+{
+ static const char *actiontypes[] = { "pass", "block" };
+
+ if (rule_numbers)
+ printf("@%u ", r->nr);
+
+ printf("ether %s", actiontypes[r->action]);
+ if (r->direction == PF_IN)
+ printf(" in");
+ else if (r->direction == PF_OUT)
+ printf(" out");
+
+ if (r->quick)
+ printf(" quick");
+ if (r->ifname[0]) {
+ if (r->ifnot)
+ printf(" on ! %s", r->ifname);
+ else
+ printf(" on %s", r->ifname);
+ }
+ if (r->proto)
+ printf(" proto 0x%04x", r->proto);
+
+ printf(" from ");
+ print_eth_addr(&r->src);
+ printf(" to ");
+ print_eth_addr(&r->dst);
+
+ if (r->qname[0])
+ printf(" queue %s", r->qname);
+ if (r->tagname[0])
+ printf(" tag %s", r->tagname);
+}
+
void
print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numeric)
{
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Feb 15, 8:35 AM (9 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16655823
Default Alt Text
D31738.diff (21 KB)
Attached To
Mode
D31738: pfctl: Print Ethernet rules
Attached
Detach File
Event Timeline
Log In to Comment