pf: handle duplicate rules gracefully

Reviewed by:	kp
Reported by:	dch
PR:		262971
Sponsored by:	Rubicon Communications, LLC ("Netgate")
This commit is contained in:
Mateusz Guzik 2022-04-01 15:04:03 +00:00
parent b3b462229f
commit c4a08ef2af
3 changed files with 22 additions and 4 deletions

View File

@ -961,6 +961,8 @@ pfctl_add_rule(int dev, const struct pfctl_rule *r, const char *anchor,
nv.size = nv.len;
ret = ioctl(dev, DIOCADDRULENV, &nv);
if (ret == -1)
ret = errno;
free(nv.data);
nvlist_destroy(nvl);

View File

@ -1846,6 +1846,8 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth)
u_int32_t ticket;
char anchor[PF_ANCHOR_NAME_SIZE];
int len = strlen(path);
int error;
bool was_present;
/* set up anchor before adding to path for anchor_call */
if ((pf->opts & PF_OPT_NOACTION) == 0)
@ -1867,12 +1869,23 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth)
} else
name = "";
was_present = false;
if ((pf->opts & PF_OPT_NOACTION) == 0) {
if (pfctl_add_pool(pf, &r->rpool, r->af))
return (1);
if (pfctl_add_rule(pf->dev, r, anchor, name, ticket,
pf->paddr.ticket))
error = pfctl_add_rule(pf->dev, r, anchor, name, ticket,
pf->paddr.ticket);
switch (error) {
case 0:
/* things worked, do nothing */
break;
case EEXIST:
/* an identical rule is already present */
was_present = true;
break;
default:
err(1, "DIOCADDRULENV");
}
}
if (pf->opts & PF_OPT_VERBOSE) {
@ -1880,6 +1893,8 @@ pfctl_load_rule(struct pfctl *pf, char *path, struct pfctl_rule *r, int depth)
print_rule(r, r->anchor ? r->anchor->name : "",
pf->opts & PF_OPT_VERBOSE2,
pf->opts & PF_OPT_NUMERIC);
if (was_present)
printf(" -- rule was already present");
}
path[len] = '\0';
pfctl_clear_pool(&r->rpool);

View File

@ -2240,10 +2240,11 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
pf_hash_rule(rule);
if (RB_INSERT(pf_krule_global, ruleset->rules[rs_num].inactive.tree, rule) != NULL) {
PF_RULES_WLOCK();
TAILQ_REMOVE(ruleset->rules[rs_num].inactive.ptr, rule, entries);
ruleset->rules[rs_num].inactive.rcount--;
pf_free_rule(rule);
rule = NULL;
error = EINVAL;
ERROUT(error);
ERROUT(EEXIST);
}
PF_CONFIG_UNLOCK();