pf: allow the use of tables in ethernet rules
Allow tables to be used for the l3 source/destination matching. This requires taking the PF_RULES read lock. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D34917
This commit is contained in:
parent
583bb9c530
commit
812839e5aa
@ -3262,13 +3262,15 @@ l3fromto : /* empty */ {
|
|||||||
}
|
}
|
||||||
| L3 fromto {
|
| L3 fromto {
|
||||||
if ($2.src.host != NULL &&
|
if ($2.src.host != NULL &&
|
||||||
$2.src.host->addr.type != PF_ADDR_ADDRMASK) {
|
$2.src.host->addr.type != PF_ADDR_ADDRMASK &&
|
||||||
yyerror("from must be an address");
|
$2.src.host->addr.type != PF_ADDR_TABLE) {
|
||||||
|
yyerror("from must be an address or table");
|
||||||
YYERROR;
|
YYERROR;
|
||||||
}
|
}
|
||||||
if ($2.dst.host != NULL &&
|
if ($2.dst.host != NULL &&
|
||||||
$2.dst.host->addr.type != PF_ADDR_ADDRMASK) {
|
$2.dst.host->addr.type != PF_ADDR_ADDRMASK &&
|
||||||
yyerror("to must be an address");
|
$2.dst.host->addr.type != PF_ADDR_TABLE) {
|
||||||
|
yyerror("to must be an address or table");
|
||||||
YYERROR;
|
YYERROR;
|
||||||
}
|
}
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
|
@ -2153,6 +2153,8 @@ int pfr_pool_get(struct pfr_ktable *, int *, struct pf_addr *, sa_family_t);
|
|||||||
void pfr_dynaddr_update(struct pfr_ktable *, struct pfi_dynaddr *);
|
void pfr_dynaddr_update(struct pfr_ktable *, struct pfi_dynaddr *);
|
||||||
struct pfr_ktable *
|
struct pfr_ktable *
|
||||||
pfr_attach_table(struct pf_kruleset *, char *);
|
pfr_attach_table(struct pf_kruleset *, char *);
|
||||||
|
struct pfr_ktable *
|
||||||
|
pfr_eth_attach_table(struct pf_keth_ruleset *, char *);
|
||||||
void pfr_detach_table(struct pfr_ktable *);
|
void pfr_detach_table(struct pfr_ktable *);
|
||||||
int pfr_clr_tables(struct pfr_table *, int *, int);
|
int pfr_clr_tables(struct pfr_table *, int *, int);
|
||||||
int pfr_add_tables(struct pfr_table *, int, int *, int);
|
int pfr_add_tables(struct pfr_table *, int, int *, int);
|
||||||
|
@ -3845,6 +3845,8 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
|
|||||||
MPASS(kif->pfik_ifp->if_vnet == curvnet);
|
MPASS(kif->pfik_ifp->if_vnet == curvnet);
|
||||||
NET_EPOCH_ASSERT();
|
NET_EPOCH_ASSERT();
|
||||||
|
|
||||||
|
PF_RULES_RLOCK_TRACKER;
|
||||||
|
|
||||||
SDT_PROBE3(pf, eth, test_rule, entry, dir, kif->pfik_ifp, m);
|
SDT_PROBE3(pf, eth, test_rule, entry, dir, kif->pfik_ifp, m);
|
||||||
|
|
||||||
ruleset = V_pf_keth;
|
ruleset = V_pf_keth;
|
||||||
@ -3892,6 +3894,8 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
|
|||||||
e = mtod(m, struct ether_header *);
|
e = mtod(m, struct ether_header *);
|
||||||
*m0 = m;
|
*m0 = m;
|
||||||
|
|
||||||
|
PF_RULES_RLOCK();
|
||||||
|
|
||||||
while (r != NULL) {
|
while (r != NULL) {
|
||||||
counter_u64_add(r->evaluations, 1);
|
counter_u64_add(r->evaluations, 1);
|
||||||
SDT_PROBE2(pf, eth, test_rule, test, r->nr, r);
|
SDT_PROBE2(pf, eth, test_rule, test, r->nr, r);
|
||||||
@ -3959,20 +3963,25 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
|
|||||||
SDT_PROBE2(pf, eth, test_rule, final_match, (r != NULL ? r->nr : -1), r);
|
SDT_PROBE2(pf, eth, test_rule, final_match, (r != NULL ? r->nr : -1), r);
|
||||||
|
|
||||||
/* Default to pass. */
|
/* Default to pass. */
|
||||||
if (r == NULL)
|
if (r == NULL) {
|
||||||
|
PF_RULES_RUNLOCK();
|
||||||
return (PF_PASS);
|
return (PF_PASS);
|
||||||
|
}
|
||||||
|
|
||||||
/* Execute action. */
|
/* Execute action. */
|
||||||
counter_u64_add(r->packets[dir == PF_OUT], 1);
|
counter_u64_add(r->packets[dir == PF_OUT], 1);
|
||||||
counter_u64_add(r->bytes[dir == PF_OUT], m_length(m, NULL));
|
counter_u64_add(r->bytes[dir == PF_OUT], m_length(m, NULL));
|
||||||
|
|
||||||
/* Shortcut. Don't tag if we're just going to drop anyway. */
|
/* Shortcut. Don't tag if we're just going to drop anyway. */
|
||||||
if (r->action == PF_DROP)
|
if (r->action == PF_DROP) {
|
||||||
|
PF_RULES_RUNLOCK();
|
||||||
return (PF_DROP);
|
return (PF_DROP);
|
||||||
|
}
|
||||||
|
|
||||||
if (r->tag > 0) {
|
if (r->tag > 0) {
|
||||||
mtag = pf_get_mtag(m);
|
mtag = pf_get_mtag(m);
|
||||||
if (mtag == NULL) {
|
if (mtag == NULL) {
|
||||||
|
PF_RULES_RUNLOCK();
|
||||||
counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1);
|
counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1);
|
||||||
return (PF_DROP);
|
return (PF_DROP);
|
||||||
}
|
}
|
||||||
@ -3982,6 +3991,7 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
|
|||||||
if (r->qid != 0) {
|
if (r->qid != 0) {
|
||||||
mtag = pf_get_mtag(m);
|
mtag = pf_get_mtag(m);
|
||||||
if (mtag == NULL) {
|
if (mtag == NULL) {
|
||||||
|
PF_RULES_RUNLOCK();
|
||||||
counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1);
|
counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1);
|
||||||
return (PF_DROP);
|
return (PF_DROP);
|
||||||
}
|
}
|
||||||
@ -3997,6 +4007,7 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
|
|||||||
**/
|
**/
|
||||||
mtag = pf_get_mtag(m);
|
mtag = pf_get_mtag(m);
|
||||||
if (mtag == NULL) {
|
if (mtag == NULL) {
|
||||||
|
PF_RULES_RUNLOCK();
|
||||||
counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1);
|
counter_u64_add(V_pf_status.counters[PFRES_MEMORY], 1);
|
||||||
return (PF_DROP);
|
return (PF_DROP);
|
||||||
}
|
}
|
||||||
@ -4006,6 +4017,8 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
|
|||||||
|
|
||||||
action = r->action;
|
action = r->action;
|
||||||
|
|
||||||
|
PF_RULES_RUNLOCK();
|
||||||
|
|
||||||
return (action);
|
return (action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +520,11 @@ pf_free_eth_rule(struct pf_keth_rule *rule)
|
|||||||
if (rule->kif)
|
if (rule->kif)
|
||||||
pfi_kkif_unref(rule->kif);
|
pfi_kkif_unref(rule->kif);
|
||||||
|
|
||||||
|
if (rule->ipsrc.addr.type == PF_ADDR_TABLE)
|
||||||
|
pfr_detach_table(rule->ipsrc.addr.p.tbl);
|
||||||
|
if (rule->ipdst.addr.type == PF_ADDR_TABLE)
|
||||||
|
pfr_detach_table(rule->ipdst.addr.p.tbl);
|
||||||
|
|
||||||
counter_u64_free(rule->evaluations);
|
counter_u64_free(rule->evaluations);
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
counter_u64_free(rule->packets[i]);
|
counter_u64_free(rule->packets[i]);
|
||||||
@ -1427,6 +1432,24 @@ pf_setup_pfsync_matching(struct pf_kruleset *rs)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pf_eth_addr_setup(struct pf_keth_ruleset *ruleset, struct pf_addr_wrap *addr)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
switch (addr->type) {
|
||||||
|
case PF_ADDR_TABLE:
|
||||||
|
addr->p.tbl = pfr_eth_attach_table(ruleset, addr->v.tblname);
|
||||||
|
if (addr->p.tbl == NULL)
|
||||||
|
error = ENOMEM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pf_addr_setup(struct pf_kruleset *ruleset, struct pf_addr_wrap *addr,
|
pf_addr_setup(struct pf_kruleset *ruleset, struct pf_addr_wrap *addr,
|
||||||
sa_family_t af)
|
sa_family_t af)
|
||||||
@ -2843,6 +2866,11 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
|||||||
if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
|
if ((rule->tag = pf_tagname2tag(rule->tagname)) == 0)
|
||||||
error = EBUSY;
|
error = EBUSY;
|
||||||
|
|
||||||
|
if (error == 0 && rule->ipdst.addr.type == PF_ADDR_TABLE)
|
||||||
|
error = pf_eth_addr_setup(ruleset, &rule->ipdst.addr);
|
||||||
|
if (error == 0 && rule->ipsrc.addr.type == PF_ADDR_TABLE)
|
||||||
|
error = pf_eth_addr_setup(ruleset, &rule->ipsrc.addr);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
pf_free_eth_rule(rule);
|
pf_free_eth_rule(rule);
|
||||||
PF_RULES_WUNLOCK();
|
PF_RULES_WUNLOCK();
|
||||||
|
@ -1147,7 +1147,8 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl,
|
|||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
if (krule->ipsrc.addr.type != PF_ADDR_ADDRMASK)
|
if (krule->ipsrc.addr.type != PF_ADDR_ADDRMASK &&
|
||||||
|
krule->ipsrc.addr.type != PF_ADDR_TABLE)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1157,7 +1158,8 @@ pf_nveth_rule_to_keth_rule(const nvlist_t *nvl,
|
|||||||
if (error != 0)
|
if (error != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
if (krule->ipdst.addr.type != PF_ADDR_ADDRMASK)
|
if (krule->ipdst.addr.type != PF_ADDR_ADDRMASK &&
|
||||||
|
krule->ipdst.addr.type != PF_ADDR_TABLE)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2151,6 +2151,44 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pfr_ktable *
|
||||||
|
pfr_eth_attach_table(struct pf_keth_ruleset *rs, char *name)
|
||||||
|
{
|
||||||
|
struct pfr_ktable *kt, *rt;
|
||||||
|
struct pfr_table tbl;
|
||||||
|
struct pf_keth_anchor *ac = rs->anchor;
|
||||||
|
|
||||||
|
PF_RULES_WASSERT();
|
||||||
|
|
||||||
|
bzero(&tbl, sizeof(tbl));
|
||||||
|
strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name));
|
||||||
|
if (ac != NULL)
|
||||||
|
strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor));
|
||||||
|
kt = pfr_lookup_table(&tbl);
|
||||||
|
if (kt == NULL) {
|
||||||
|
kt = pfr_create_ktable(&tbl, time_second, 1);
|
||||||
|
if (kt == NULL)
|
||||||
|
return (NULL);
|
||||||
|
if (ac != NULL) {
|
||||||
|
bzero(tbl.pfrt_anchor, sizeof(tbl.pfrt_anchor));
|
||||||
|
rt = pfr_lookup_table(&tbl);
|
||||||
|
if (rt == NULL) {
|
||||||
|
rt = pfr_create_ktable(&tbl, 0, 1);
|
||||||
|
if (rt == NULL) {
|
||||||
|
pfr_destroy_ktable(kt, 0);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
pfr_insert_ktable(rt);
|
||||||
|
}
|
||||||
|
kt->pfrkt_root = rt;
|
||||||
|
}
|
||||||
|
pfr_insert_ktable(kt);
|
||||||
|
}
|
||||||
|
if (!kt->pfrkt_refcnt[PFR_REFCNT_RULE]++)
|
||||||
|
pfr_setflags_ktable(kt, kt->pfrkt_flags|PFR_TFLAG_REFERENCED);
|
||||||
|
return (kt);
|
||||||
|
}
|
||||||
|
|
||||||
struct pfr_ktable *
|
struct pfr_ktable *
|
||||||
pfr_attach_table(struct pf_kruleset *rs, char *name)
|
pfr_attach_table(struct pf_kruleset *rs, char *name)
|
||||||
{
|
{
|
||||||
|
@ -537,10 +537,12 @@ ip_body()
|
|||||||
"ether block out l3 to 192.0.2.3"
|
"ether block out l3 to 192.0.2.3"
|
||||||
atf_check -s exit:2 -o ignore ping -c 1 192.0.2.2
|
atf_check -s exit:2 -o ignore ping -c 1 192.0.2.2
|
||||||
|
|
||||||
# We can't use tables in these rules
|
# Test table
|
||||||
echo "ether pass out l3 from <test>" | \
|
pft_set_rules alcatraz \
|
||||||
atf_check -s exit:1 -o ignore -e ignore \
|
"table <tbl> { 192.0.2.3 }" \
|
||||||
jexec alcatraz pfctl -g -f -
|
"ether pass" \
|
||||||
|
"ether block out l3 to <tbl>"
|
||||||
|
atf_check -s exit:2 -o ignore ping -c 1 192.0.2.2
|
||||||
}
|
}
|
||||||
|
|
||||||
ip_cleanup()
|
ip_cleanup()
|
||||||
|
Loading…
Reference in New Issue
Block a user