mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-21 18:50:50 +01:00
pf: add a way to list creator ids
Allow userspace to retrieve a list of distinct creator ids for the current states. This is used by pfSense, and used to require dumping all states to userspace. It's rather inefficient to export a (potentially extremely large) state table to obtain a handful (typically 2) of 32-bit integers. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D42092
This commit is contained in:
parent
f218b851da
commit
a7191e5d7b
@ -1106,6 +1106,71 @@ pfctl_set_keepcounters(int dev, bool keep)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
struct pfctl_creator {
|
||||
uint32_t id;
|
||||
};
|
||||
#define _IN(_field) offsetof(struct genlmsghdr, _field)
|
||||
#define _OUT(_field) offsetof(struct pfctl_creator, _field)
|
||||
static struct snl_attr_parser ap_creators[] = {
|
||||
{ .type = PF_ST_CREATORID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
|
||||
};
|
||||
static struct snl_field_parser fp_creators[] = {
|
||||
};
|
||||
#undef _IN
|
||||
#undef _OUT
|
||||
SNL_DECLARE_PARSER(creator_parser, struct genlmsghdr, fp_creators, ap_creators);
|
||||
|
||||
static int
|
||||
pfctl_get_creators_nl(struct snl_state *ss, uint32_t *creators, size_t *len)
|
||||
{
|
||||
|
||||
int family_id = snl_get_genl_family(ss, PFNL_FAMILY_NAME);
|
||||
size_t i = 0;
|
||||
|
||||
struct nlmsghdr *hdr;
|
||||
struct snl_writer nw;
|
||||
|
||||
snl_init_writer(ss, &nw);
|
||||
hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETCREATORS);
|
||||
hdr->nlmsg_flags |= NLM_F_DUMP;
|
||||
snl_finalize_msg(&nw);
|
||||
uint32_t seq_id = hdr->nlmsg_seq;
|
||||
|
||||
snl_send_message(ss, hdr);
|
||||
|
||||
struct snl_errmsg_data e = {};
|
||||
while ((hdr = snl_read_reply_multi(ss, seq_id, &e)) != NULL) {
|
||||
struct pfctl_creator c;
|
||||
bzero(&c, sizeof(c));
|
||||
|
||||
if (!snl_parse_nlmsg(ss, hdr, &creator_parser, &c))
|
||||
continue;
|
||||
|
||||
creators[i] = c.id;
|
||||
i++;
|
||||
if (i > *len)
|
||||
return (E2BIG);
|
||||
}
|
||||
|
||||
*len = i;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_get_creatorids(uint32_t *creators, size_t *len)
|
||||
{
|
||||
struct snl_state ss = {};
|
||||
int error;
|
||||
|
||||
snl_init(&ss, NETLINK_GENERIC);
|
||||
error = pfctl_get_creators_nl(&ss, creators, len);
|
||||
snl_free(&ss);
|
||||
|
||||
return (error);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
pfctl_nv_add_state_cmp(nvlist_t *nvl, const char *name,
|
||||
const struct pfctl_state_cmp *cmp)
|
||||
@ -1199,7 +1264,8 @@ static struct snl_field_parser fp_state[] = {
|
||||
SNL_DECLARE_PARSER(state_parser, struct genlmsghdr, fp_state, ap_state);
|
||||
|
||||
static const struct snl_hdr_parser *all_parsers[] = {
|
||||
&state_parser, &skey_parser, &speer_parser
|
||||
&state_parser, &skey_parser, &speer_parser,
|
||||
&creator_parser,
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -413,6 +413,7 @@ 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);
|
||||
int pfctl_set_keepcounters(int dev, bool keep);
|
||||
int pfctl_get_creatorids(uint32_t *creators, size_t *len);
|
||||
typedef int (*pfctl_get_state_fn)(struct pfctl_state *, void *);
|
||||
int pfctl_get_states_iter(pfctl_get_state_fn f, void *arg);
|
||||
int pfctl_get_states(int dev, struct pfctl_states *states);
|
||||
|
@ -233,7 +233,7 @@ static const char * const clearopt_list[] = {
|
||||
static const char * const showopt_list[] = {
|
||||
"ether", "nat", "queue", "rules", "Anchors", "Sources", "states",
|
||||
"info", "Interfaces", "labels", "timeouts", "memory", "Tables",
|
||||
"osfp", "Running", "all", NULL
|
||||
"osfp", "Running", "all", "creatorids", NULL
|
||||
};
|
||||
|
||||
static const char * const tblcmdopt_list[] = {
|
||||
@ -1639,6 +1639,22 @@ pfctl_show_limits(int dev, int opts)
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
pfctl_show_creators(int opts)
|
||||
{
|
||||
int ret;
|
||||
uint32_t creators[16];
|
||||
size_t count = nitems(creators);
|
||||
|
||||
ret = pfctl_get_creatorids(creators, &count);
|
||||
if (ret != 0)
|
||||
errx(ret, "Failed to retrieve creators");
|
||||
|
||||
printf("Creator IDs:\n");
|
||||
for (size_t i = 0; i < count; i++)
|
||||
printf("%08x\n", creators[i]);
|
||||
}
|
||||
|
||||
/* callbacks for rule/nat/rdr/addr */
|
||||
int
|
||||
pfctl_add_pool(struct pfctl *pf, struct pfctl_pool *p, sa_family_t af)
|
||||
@ -3121,6 +3137,9 @@ main(int argc, char *argv[])
|
||||
case 'I':
|
||||
pfctl_show_ifaces(ifaceopt, opts);
|
||||
break;
|
||||
case 'c':
|
||||
pfctl_show_creators(opts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,7 @@ int pfctl_command_tables(int, char *[], char *, const char *, char *,
|
||||
int pfctl_show_altq(int, const char *, int, int);
|
||||
void warn_namespace_collision(const char *);
|
||||
int pfctl_show_ifaces(const char *, int);
|
||||
void pfctl_show_creators(int);
|
||||
FILE *pfctl_fopen(const char *, const char *);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
@ -246,6 +246,30 @@ handle_getstate(struct nlpcb *nlp, struct nl_parsed_state *attrs,
|
||||
return (dump_state(nlp, hdr, s, npt));
|
||||
}
|
||||
|
||||
static int
|
||||
dump_creatorid(struct nlpcb *nlp, const struct nlmsghdr *hdr, uint32_t creator,
|
||||
struct nl_pstate *npt)
|
||||
{
|
||||
struct nl_writer *nw = npt->nw;
|
||||
|
||||
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
|
||||
goto enomem;
|
||||
|
||||
struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
|
||||
ghdr_new->cmd = PFNL_CMD_GETCREATORS;
|
||||
ghdr_new->version = 0;
|
||||
ghdr_new->reserved = 0;
|
||||
|
||||
nlattr_add_u32(nw, PF_ST_CREATORID, htonl(creator));
|
||||
|
||||
if (nlmsg_end(nw))
|
||||
return (0);
|
||||
|
||||
enomem:
|
||||
nlmsg_abort(nw);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
static int
|
||||
pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
||||
{
|
||||
@ -264,6 +288,56 @@ pf_handle_getstates(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
||||
{
|
||||
uint32_t creators[16];
|
||||
int error = 0;
|
||||
|
||||
bzero(creators, sizeof(creators));
|
||||
|
||||
for (int i = 0; i < pf_hashmask; i++) {
|
||||
struct pf_idhash *ih = &V_pf_idhash[i];
|
||||
struct pf_kstate *s;
|
||||
|
||||
if (LIST_EMPTY(&ih->states))
|
||||
continue;
|
||||
|
||||
PF_HASHROW_LOCK(ih);
|
||||
LIST_FOREACH(s, &ih->states, entry) {
|
||||
int j;
|
||||
if (s->timeout == PFTM_UNLINKED)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < nitems(creators); j++) {
|
||||
if (creators[j] == s->creatorid)
|
||||
break;
|
||||
if (creators[j] == 0) {
|
||||
creators[j] = s->creatorid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == nitems(creators))
|
||||
printf("Warning: too many creators!\n");
|
||||
}
|
||||
PF_HASHROW_UNLOCK(ih);
|
||||
}
|
||||
|
||||
hdr->nlmsg_flags |= NLM_F_MULTI;
|
||||
for (int i = 0; i < nitems(creators); i++) {
|
||||
if (creators[i] == 0)
|
||||
break;
|
||||
error = dump_creatorid(npt->nlp, hdr, creators[i], npt);
|
||||
}
|
||||
|
||||
if (!nlmsg_end_dump(npt->nw, error, hdr)) {
|
||||
NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static const struct nlhdr_parser *all_parsers[] = { &state_parser };
|
||||
|
||||
static int family_id;
|
||||
@ -275,6 +349,12 @@ static const struct genl_cmd pf_cmds[] = {
|
||||
.cmd_cb = pf_handle_getstates,
|
||||
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
|
||||
},
|
||||
{
|
||||
.cmd_num = PFNL_CMD_GETCREATORS,
|
||||
.cmd_name = "GETCREATORS",
|
||||
.cmd_cb = pf_handle_getcreators,
|
||||
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
|
||||
},
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -37,6 +37,7 @@
|
||||
enum {
|
||||
PFNL_CMD_UNSPEC = 0,
|
||||
PFNL_CMD_GETSTATES = 1,
|
||||
PFNL_CMD_GETCREATORS = 2,
|
||||
__PFNL_CMD_MAX,
|
||||
};
|
||||
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
|
||||
|
@ -78,6 +78,8 @@ common_body()
|
||||
"set skip on ${epair_sync}b" \
|
||||
"pass out keep state"
|
||||
|
||||
hostid_one=$(jexec one pfctl -si -v | awk '/Hostid:/ { gsub(/0x/, "", $2); printf($2); }')
|
||||
|
||||
ifconfig ${epair_one}b 198.51.100.254/24 up
|
||||
|
||||
ping -c 1 -S 198.51.100.254 198.51.100.1
|
||||
@ -89,6 +91,12 @@ common_body()
|
||||
grep 198.51.100.254 ; then
|
||||
atf_fail "state not found on synced host"
|
||||
fi
|
||||
|
||||
if ! jexec two pfctl -sc | grep ""${hostid_one}"";
|
||||
then
|
||||
jexec two pfctl -sc
|
||||
atf_fail "HostID for host one not found on two"
|
||||
fi
|
||||
}
|
||||
|
||||
basic_cleanup()
|
||||
|
Loading…
Reference in New Issue
Block a user