pf: support listing ethernet anchors
Sponsored by: Rubicon Communications, LLC ("Netgate")
This commit is contained in:
parent
5473dee730
commit
9bb06778f8
@ -622,6 +622,81 @@ pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule)
|
||||
rule->action = nvlist_get_number(nvl, "action");
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_get_eth_rulesets_info(int dev, struct pfctl_eth_rulesets_info *ri,
|
||||
const char *path)
|
||||
{
|
||||
uint8_t buf[1024];
|
||||
struct pfioc_nv nv;
|
||||
nvlist_t *nvl;
|
||||
void *packed;
|
||||
size_t len;
|
||||
|
||||
bzero(ri, sizeof(*ri));
|
||||
|
||||
nvl = nvlist_create(0);
|
||||
nvlist_add_string(nvl, "path", path);
|
||||
packed = nvlist_pack(nvl, &len);
|
||||
memcpy(buf, packed, len);
|
||||
free(packed);
|
||||
nvlist_destroy(nvl);
|
||||
|
||||
nv.data = buf;
|
||||
nv.len = len;
|
||||
nv.size = sizeof(buf);
|
||||
|
||||
if (ioctl(dev, DIOCGETETHRULESETS, &nv) != 0)
|
||||
return (errno);
|
||||
|
||||
nvl = nvlist_unpack(buf, nv.len, 0);
|
||||
if (nvl == NULL)
|
||||
return (EIO);
|
||||
|
||||
ri->nr = nvlist_get_number(nvl, "nr");
|
||||
|
||||
nvlist_destroy(nvl);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_get_eth_ruleset(int dev, const char *path, int nr,
|
||||
struct pfctl_eth_ruleset_info *ri)
|
||||
{
|
||||
uint8_t buf[1024];
|
||||
struct pfioc_nv nv;
|
||||
nvlist_t *nvl;
|
||||
void *packed;
|
||||
size_t len;
|
||||
|
||||
bzero(ri, sizeof(*ri));
|
||||
|
||||
nvl = nvlist_create(0);
|
||||
nvlist_add_string(nvl, "path", path);
|
||||
nvlist_add_number(nvl, "nr", nr);
|
||||
packed = nvlist_pack(nvl, &len);
|
||||
memcpy(buf, packed, len);
|
||||
free(packed);
|
||||
nvlist_destroy(nvl);
|
||||
|
||||
nv.data = buf;
|
||||
nv.len = len;
|
||||
nv.size = sizeof(buf);
|
||||
|
||||
if (ioctl(dev, DIOCGETETHRULESET, &nv) != 0)
|
||||
return (errno);
|
||||
|
||||
nvl = nvlist_unpack(buf, nv.len, 0);
|
||||
if (nvl == NULL)
|
||||
return (EIO);
|
||||
|
||||
ri->nr = nvlist_get_number(nvl, "nr");
|
||||
strlcpy(ri->path, nvlist_get_string(nvl, "path"), MAXPATHLEN);
|
||||
strlcpy(ri->name, nvlist_get_string(nvl, "name"),
|
||||
PF_ANCHOR_NAME_SIZE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules,
|
||||
const char *path)
|
||||
|
@ -66,6 +66,10 @@ struct pfctl_status {
|
||||
uint64_t bcounters[2][2];
|
||||
};
|
||||
|
||||
struct pfctl_eth_rulesets_info {
|
||||
uint32_t nr;
|
||||
};
|
||||
|
||||
struct pfctl_eth_rules_info {
|
||||
uint32_t nr;
|
||||
uint32_t ticket;
|
||||
@ -111,6 +115,12 @@ struct pfctl_eth_rule {
|
||||
};
|
||||
TAILQ_HEAD(pfctl_eth_rules, pfctl_eth_rule);
|
||||
|
||||
struct pfctl_eth_ruleset_info {
|
||||
uint32_t nr;
|
||||
char name[PF_ANCHOR_NAME_SIZE];
|
||||
char path[MAXPATHLEN];
|
||||
};
|
||||
|
||||
struct pfctl_eth_ruleset {
|
||||
struct pfctl_eth_rules rules;
|
||||
struct pfctl_eth_anchor *anchor;
|
||||
@ -356,6 +366,10 @@ struct pfctl_syncookies {
|
||||
struct pfctl_status* pfctl_get_status(int dev);
|
||||
void pfctl_free_status(struct pfctl_status *status);
|
||||
|
||||
int pfctl_get_eth_rulesets_info(int dev,
|
||||
struct pfctl_eth_rulesets_info *ri, const char *path);
|
||||
int pfctl_get_eth_ruleset(int dev, const char *path, int nr,
|
||||
struct pfctl_eth_ruleset_info *ri);
|
||||
int pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules,
|
||||
const char *path);
|
||||
int pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
|
||||
|
@ -111,6 +111,7 @@ int pfctl_show_limits(int, int);
|
||||
void pfctl_debug(int, u_int32_t, int);
|
||||
int pfctl_test_altqsupport(int, int);
|
||||
int pfctl_show_anchors(int, int, char *);
|
||||
int pfctl_show_eth_anchors(int, int, char *);
|
||||
int pfctl_ruleset_trans(struct pfctl *, char *, struct pfctl_anchor *, bool);
|
||||
int pfctl_eth_ruleset_trans(struct pfctl *, char *,
|
||||
struct pfctl_eth_anchor *);
|
||||
@ -2604,6 +2605,44 @@ pfctl_show_anchors(int dev, int opts, char *anchorname)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_show_eth_anchors(int dev, int opts, char *anchorname)
|
||||
{
|
||||
struct pfctl_eth_rulesets_info ri;
|
||||
struct pfctl_eth_ruleset_info rs;
|
||||
int ret;
|
||||
|
||||
if ((ret = pfctl_get_eth_rulesets_info(dev, &ri, anchorname)) != 0) {
|
||||
if (ret == ENOENT)
|
||||
fprintf(stderr, "Anchor '%s' not found.\n",
|
||||
anchorname);
|
||||
else
|
||||
err(1, "DIOCGETETHRULESETS");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (int nr = 0; nr < ri.nr; nr++) {
|
||||
char sub[MAXPATHLEN];
|
||||
|
||||
if (pfctl_get_eth_ruleset(dev, anchorname, nr, &rs) != 0)
|
||||
err(1, "DIOCGETETHRULESET");
|
||||
|
||||
if (!strcmp(rs.name, PF_RESERVED_ANCHOR))
|
||||
continue;
|
||||
sub[0] = 0;
|
||||
if (rs.path[0]) {
|
||||
strlcat(sub, rs.path, sizeof(sub));
|
||||
strlcat(sub, "/", sizeof(sub));
|
||||
}
|
||||
strlcat(sub, rs.name, sizeof(sub));
|
||||
if (sub[0] != '_' || (opts & PF_OPT_VERBOSE))
|
||||
printf(" %s\n", sub);
|
||||
if ((opts & PF_OPT_VERBOSE) && pfctl_show_eth_anchors(dev, opts, sub))
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
const char *
|
||||
pfctl_lookup_option(char *cmd, const char * const *list)
|
||||
{
|
||||
@ -2830,6 +2869,7 @@ main(int argc, char *argv[])
|
||||
switch (*showopt) {
|
||||
case 'A':
|
||||
pfctl_show_anchors(dev, opts, anchorname);
|
||||
pfctl_show_eth_anchors(dev, opts, anchorname);
|
||||
break;
|
||||
case 'r':
|
||||
pfctl_load_fingerprints(dev, opts);
|
||||
|
@ -1865,6 +1865,8 @@ struct pfioc_iface {
|
||||
#define DIOCADDETHRULE _IOWR('D', 97, struct pfioc_nv)
|
||||
#define DIOCGETETHRULE _IOWR('D', 98, struct pfioc_nv)
|
||||
#define DIOCGETETHRULES _IOWR('D', 99, struct pfioc_nv)
|
||||
#define DIOCGETETHRULESETS _IOWR('D', 100, struct pfioc_nv)
|
||||
#define DIOCGETETHRULESET _IOWR('D', 101, struct pfioc_nv)
|
||||
|
||||
struct pf_ifspeed_v0 {
|
||||
char ifname[IFNAMSIZ];
|
||||
|
@ -2463,6 +2463,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
||||
case DIOCCLRIFFLAG:
|
||||
case DIOCGETETHRULES:
|
||||
case DIOCGETETHRULE:
|
||||
case DIOCGETETHRULESETS:
|
||||
case DIOCGETETHRULESET:
|
||||
break;
|
||||
case DIOCRCLRTABLES:
|
||||
case DIOCRADDTABLES:
|
||||
@ -2512,6 +2514,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
||||
case DIOCGETRULENV:
|
||||
case DIOCGETETHRULES:
|
||||
case DIOCGETETHRULE:
|
||||
case DIOCGETETHRULESETS:
|
||||
case DIOCGETETHRULESET:
|
||||
break;
|
||||
case DIOCRCLRTABLES:
|
||||
case DIOCRADDTABLES:
|
||||
@ -2864,6 +2868,184 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
||||
break;
|
||||
}
|
||||
|
||||
case DIOCGETETHRULESETS: {
|
||||
struct epoch_tracker et;
|
||||
struct pfioc_nv *nv = (struct pfioc_nv *)addr;
|
||||
nvlist_t *nvl = NULL;
|
||||
void *nvlpacked = NULL;
|
||||
struct pf_keth_ruleset *ruleset;
|
||||
struct pf_keth_anchor *anchor;
|
||||
int nr = 0;
|
||||
|
||||
#define ERROUT(x) do { error = (x); goto DIOCGETETHRULESETS_error; } while (0)
|
||||
|
||||
if (nv->len > pf_ioctl_maxcount)
|
||||
ERROUT(ENOMEM);
|
||||
|
||||
nvlpacked = malloc(nv->len, M_NVLIST, M_WAITOK);
|
||||
if (nvlpacked == NULL)
|
||||
ERROUT(ENOMEM);
|
||||
|
||||
error = copyin(nv->data, nvlpacked, nv->len);
|
||||
if (error)
|
||||
ERROUT(error);
|
||||
|
||||
nvl = nvlist_unpack(nvlpacked, nv->len, 0);
|
||||
if (nvl == NULL)
|
||||
ERROUT(EBADMSG);
|
||||
if (! nvlist_exists_string(nvl, "path"))
|
||||
ERROUT(EBADMSG);
|
||||
|
||||
NET_EPOCH_ENTER(et);
|
||||
|
||||
if ((ruleset = pf_find_keth_ruleset(
|
||||
nvlist_get_string(nvl, "path"))) == NULL) {
|
||||
NET_EPOCH_EXIT(et);
|
||||
ERROUT(ENOENT);
|
||||
}
|
||||
|
||||
if (ruleset->anchor == NULL) {
|
||||
RB_FOREACH(anchor, pf_keth_anchor_global, &V_pf_keth_anchors)
|
||||
if (anchor->parent == NULL)
|
||||
nr++;
|
||||
} else {
|
||||
RB_FOREACH(anchor, pf_keth_anchor_node,
|
||||
&ruleset->anchor->children)
|
||||
nr++;
|
||||
}
|
||||
|
||||
NET_EPOCH_EXIT(et);
|
||||
|
||||
nvlist_destroy(nvl);
|
||||
nvl = NULL;
|
||||
free(nvlpacked, M_NVLIST);
|
||||
nvlpacked = NULL;
|
||||
|
||||
nvl = nvlist_create(0);
|
||||
if (nvl == NULL)
|
||||
ERROUT(ENOMEM);
|
||||
|
||||
nvlist_add_number(nvl, "nr", nr);
|
||||
|
||||
nvlpacked = nvlist_pack(nvl, &nv->len);
|
||||
if (nvlpacked == NULL)
|
||||
ERROUT(ENOMEM);
|
||||
|
||||
if (nv->size == 0)
|
||||
ERROUT(0);
|
||||
else if (nv->size < nv->len)
|
||||
ERROUT(ENOSPC);
|
||||
|
||||
error = copyout(nvlpacked, nv->data, nv->len);
|
||||
|
||||
#undef ERROUT
|
||||
DIOCGETETHRULESETS_error:
|
||||
free(nvlpacked, M_NVLIST);
|
||||
nvlist_destroy(nvl);
|
||||
break;
|
||||
}
|
||||
|
||||
case DIOCGETETHRULESET: {
|
||||
struct epoch_tracker et;
|
||||
struct pfioc_nv *nv = (struct pfioc_nv *)addr;
|
||||
nvlist_t *nvl = NULL;
|
||||
void *nvlpacked = NULL;
|
||||
struct pf_keth_ruleset *ruleset;
|
||||
struct pf_keth_anchor *anchor;
|
||||
int nr = 0, req_nr = 0;
|
||||
bool found = false;
|
||||
|
||||
#define ERROUT(x) do { error = (x); goto DIOCGETETHRULESET_error; } while (0)
|
||||
|
||||
if (nv->len > pf_ioctl_maxcount)
|
||||
ERROUT(ENOMEM);
|
||||
|
||||
nvlpacked = malloc(nv->len, M_NVLIST, M_WAITOK);
|
||||
if (nvlpacked == NULL)
|
||||
ERROUT(ENOMEM);
|
||||
|
||||
error = copyin(nv->data, nvlpacked, nv->len);
|
||||
if (error)
|
||||
ERROUT(error);
|
||||
|
||||
nvl = nvlist_unpack(nvlpacked, nv->len, 0);
|
||||
if (nvl == NULL)
|
||||
ERROUT(EBADMSG);
|
||||
if (! nvlist_exists_string(nvl, "path"))
|
||||
ERROUT(EBADMSG);
|
||||
if (! nvlist_exists_number(nvl, "nr"))
|
||||
ERROUT(EBADMSG);
|
||||
|
||||
req_nr = nvlist_get_number(nvl, "nr");
|
||||
|
||||
NET_EPOCH_ENTER(et);
|
||||
|
||||
if ((ruleset = pf_find_keth_ruleset(
|
||||
nvlist_get_string(nvl, "path"))) == NULL) {
|
||||
NET_EPOCH_EXIT(et);
|
||||
ERROUT(ENOENT);
|
||||
}
|
||||
|
||||
nvlist_destroy(nvl);
|
||||
nvl = NULL;
|
||||
free(nvlpacked, M_NVLIST);
|
||||
nvlpacked = NULL;
|
||||
|
||||
nvl = nvlist_create(0);
|
||||
if (nvl == NULL) {
|
||||
NET_EPOCH_EXIT(et);
|
||||
ERROUT(ENOMEM);
|
||||
}
|
||||
|
||||
if (ruleset->anchor == NULL) {
|
||||
RB_FOREACH(anchor, pf_keth_anchor_global,
|
||||
&V_pf_keth_anchors) {
|
||||
if (anchor->parent == NULL && nr++ == req_nr) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RB_FOREACH(anchor, pf_keth_anchor_node,
|
||||
&ruleset->anchor->children) {
|
||||
if (nr++ == req_nr) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NET_EPOCH_EXIT(et);
|
||||
if (found) {
|
||||
nvlist_add_number(nvl, "nr", nr);
|
||||
nvlist_add_string(nvl, "name", anchor->name);
|
||||
if (ruleset->anchor)
|
||||
nvlist_add_string(nvl, "path",
|
||||
ruleset->anchor->path);
|
||||
else
|
||||
nvlist_add_string(nvl, "path", "");
|
||||
} else {
|
||||
ERROUT(EBUSY);
|
||||
}
|
||||
|
||||
nvlpacked = nvlist_pack(nvl, &nv->len);
|
||||
if (nvlpacked == NULL)
|
||||
ERROUT(ENOMEM);
|
||||
|
||||
if (nv->size == 0)
|
||||
ERROUT(0);
|
||||
else if (nv->size < nv->len)
|
||||
ERROUT(ENOSPC);
|
||||
|
||||
error = copyout(nvlpacked, nv->data, nv->len);
|
||||
|
||||
#undef ERROUT
|
||||
DIOCGETETHRULESET_error:
|
||||
free(nvlpacked, M_NVLIST);
|
||||
nvlist_destroy(nvl);
|
||||
break;
|
||||
}
|
||||
|
||||
case DIOCADDRULENV: {
|
||||
struct pfioc_nv *nv = (struct pfioc_nv *)addr;
|
||||
nvlist_t *nvl = NULL;
|
||||
|
@ -490,6 +490,8 @@ anchor_body()
|
||||
"}" \
|
||||
"ether pass in from ${epair_a_mac}"
|
||||
atf_check -s exit:0 -o ignore ping -c 1 192.0.2.2
|
||||
|
||||
atf_check -s exit:0 -o match:'baz' jexec alcatraz pfctl -sA
|
||||
}
|
||||
|
||||
anchor_cleanup()
|
||||
|
Loading…
Reference in New Issue
Block a user