pfctl: Print Ethernet rules
Extent pfctl to be able to read configured Ethernet filtering rules from the kernel and print them. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D31738
This commit is contained in:
parent
e732e742b3
commit
2b29ceb86f
@ -546,6 +546,185 @@ pf_nvrule_to_rule(const nvlist_t *nvl, struct pfctl_rule *rule)
|
||||
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)
|
||||
|
@ -65,6 +65,43 @@ struct pfctl_status {
|
||||
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_syncookies {
|
||||
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);
|
||||
|
@ -122,12 +122,19 @@ int atoul(char *, u_long *);
|
||||
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_port(const char *, char *, size_t,
|
||||
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 @@ typedef struct {
|
||||
} 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 @@ typedef struct {
|
||||
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 @@ int parseport(char *, struct range *r, int);
|
||||
%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 @@ int parseport(char *, struct range *r, int);
|
||||
%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 @@ int parseport(char *, struct range *r, int);
|
||||
%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 @@ int parseport(char *, struct range *r, int);
|
||||
%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 @@ int parseport(char *, struct range *r, int);
|
||||
%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 @@ scrubaction : no SCRUB {
|
||||
}
|
||||
;
|
||||
|
||||
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 @@ af : /* empty */ { $$ = 0; }
|
||||
| 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 @@ protoval : STRING {
|
||||
}
|
||||
;
|
||||
|
||||
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 @@ label : LABEL STRING {
|
||||
}
|
||||
;
|
||||
|
||||
etherqname : QUEUE STRING {
|
||||
$$.qname = $2;
|
||||
}
|
||||
| QUEUE '(' STRING ')' {
|
||||
$$.qname = $3;
|
||||
}
|
||||
;
|
||||
|
||||
qname : QUEUE STRING {
|
||||
$$.qname = $2;
|
||||
$$.pqname = NULL;
|
||||
@ -5422,6 +5604,31 @@ expand_queue(struct pf_altq *a, struct node_if *interfaces,
|
||||
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 @@ int
|
||||
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 @@ lookup(char *s)
|
||||
{ "drop", DROP},
|
||||
{ "drop-ovl", FRAGDROP},
|
||||
{ "dup-to", DUPTO},
|
||||
{ "ether", ETHER},
|
||||
{ "fail-policy", FAILPOLICY},
|
||||
{ "fairq", FAIRQ},
|
||||
{ "fastroute", FASTROUTE},
|
||||
|
@ -96,7 +96,9 @@ int pfctl_load_hostid(struct pfctl *, u_int32_t);
|
||||
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 @@ void pfctl_debug(int, u_int32_t, int);
|
||||
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 clearopt_list[] = {
|
||||
};
|
||||
|
||||
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 @@ pfctl_clear_pool(struct pfctl_pool *pool)
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ pfctl_print_title(char *title)
|
||||
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 @@ pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a)
|
||||
{
|
||||
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 @@ pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pfctl_anchor *a)
|
||||
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 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
||||
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 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
||||
*/
|
||||
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 @@ pfctl_rules(int dev, char *filename, int opts, int optimize,
|
||||
|
||||
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 @@ main(int argc, char *argv[])
|
||||
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);
|
||||
|
@ -691,6 +691,50 @@ print_src_node(struct pf_src_node *sn, int opts)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -90,6 +90,9 @@ struct pfctl {
|
||||
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 @@ int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *);
|
||||
|
||||
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 @@ struct pf_timeout {
|
||||
#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[];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user