mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 04:43:53 +00:00
pf: implement addrule via netlink
Sponsored by: Rubicon Communications, LLC ("Netgate")
This commit is contained in:
parent
b8ef285f6c
commit
777a4702c5
|
@ -1229,7 +1229,287 @@ pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket, const char *anchor,
|
||||||
anchor_call, false));
|
anchor_call, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
int pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket,
|
#define _OUT(_field) offsetof(struct pf_addr_wrap, _field)
|
||||||
|
static const struct snl_attr_parser ap_addr_wrap[] = {
|
||||||
|
{ .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = snl_attr_get_in6_addr },
|
||||||
|
{ .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = snl_attr_get_in6_addr },
|
||||||
|
{ .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = snl_attr_copy_string },
|
||||||
|
{ .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
|
||||||
|
{ .type = PF_AT_TYPE, .off = _OUT(type), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_AT_TBLCNT, .off = _OUT(p.tblcnt), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_AT_DYNCNT, .off = _OUT(p.dyncnt), .cb = snl_attr_get_uint32 },
|
||||||
|
};
|
||||||
|
SNL_DECLARE_ATTR_PARSER(addr_wrap_parser, ap_addr_wrap);
|
||||||
|
#undef _OUT
|
||||||
|
|
||||||
|
#define _OUT(_field) offsetof(struct pf_rule_addr, _field)
|
||||||
|
static struct snl_attr_parser ap_rule_addr[] = {
|
||||||
|
{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = snl_attr_get_nested },
|
||||||
|
{ .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RAT_NEG, .off = _OUT(neg), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RAT_OP, .off = _OUT(port_op), .cb = snl_attr_get_uint8 },
|
||||||
|
};
|
||||||
|
#undef _OUT
|
||||||
|
SNL_DECLARE_ATTR_PARSER(rule_addr_parser, ap_rule_addr);
|
||||||
|
|
||||||
|
struct snl_parsed_labels
|
||||||
|
{
|
||||||
|
char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
|
||||||
|
uint32_t i;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
snl_attr_get_pf_rule_labels(struct snl_state *ss, struct nlattr *nla,
|
||||||
|
const void *arg __unused, void *target)
|
||||||
|
{
|
||||||
|
struct snl_parsed_labels *l = (struct snl_parsed_labels *)target;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
if (l->i >= PF_RULE_MAX_LABEL_COUNT)
|
||||||
|
return (E2BIG);
|
||||||
|
|
||||||
|
ret = snl_attr_copy_string(ss, nla, (void *)PF_RULE_LABEL_SIZE,
|
||||||
|
l->labels[l->i]);
|
||||||
|
if (ret)
|
||||||
|
l->i++;
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _OUT(_field) offsetof(struct nl_parsed_labels, _field)
|
||||||
|
static const struct snl_attr_parser ap_labels[] = {
|
||||||
|
{ .type = PF_LT_LABEL, .off = 0, .cb = snl_attr_get_pf_rule_labels },
|
||||||
|
};
|
||||||
|
SNL_DECLARE_ATTR_PARSER(rule_labels_parser, ap_labels);
|
||||||
|
#undef _OUT
|
||||||
|
|
||||||
|
static bool
|
||||||
|
snl_attr_get_nested_pf_rule_labels(struct snl_state *ss, struct nlattr *nla,
|
||||||
|
const void *arg __unused, void *target)
|
||||||
|
{
|
||||||
|
struct snl_parsed_labels parsed_labels = { };
|
||||||
|
bool error;
|
||||||
|
|
||||||
|
/* Assumes target points to the beginning of the structure */
|
||||||
|
error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, &parsed_labels);
|
||||||
|
if (! error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
memcpy(target, parsed_labels.labels, sizeof(parsed_labels));
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _OUT(_field) offsetof(struct pf_mape_portset, _field)
|
||||||
|
static const struct snl_attr_parser ap_mape_portset[] = {
|
||||||
|
{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = snl_attr_get_uint8 },
|
||||||
|
{. type = PF_MET_PSID, .off = _OUT(psid), .cb = snl_attr_get_uint16 },
|
||||||
|
};
|
||||||
|
SNL_DECLARE_ATTR_PARSER(mape_portset_parser, ap_mape_portset);
|
||||||
|
#undef _OUT
|
||||||
|
|
||||||
|
#define _OUT(_field) offsetof(struct pfctl_pool, _field)
|
||||||
|
static const struct snl_attr_parser ap_pool[] = {
|
||||||
|
{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = snl_attr_get_bytes },
|
||||||
|
{ .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = snl_attr_get_in6_addr },
|
||||||
|
{ .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_PT_OPTS, .off = _OUT(opts), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = snl_attr_get_nested },
|
||||||
|
};
|
||||||
|
SNL_DECLARE_ATTR_PARSER(pool_parser, ap_pool);
|
||||||
|
#undef _OUT
|
||||||
|
|
||||||
|
struct nl_parsed_timeouts
|
||||||
|
{
|
||||||
|
uint32_t timeouts[PFTM_MAX];
|
||||||
|
uint32_t i;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool
|
||||||
|
snl_attr_get_pf_timeout(struct snl_state *ss, struct nlattr *nla,
|
||||||
|
const void *arg __unused, void *target)
|
||||||
|
{
|
||||||
|
struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
if (t->i >= PFTM_MAX)
|
||||||
|
return (E2BIG);
|
||||||
|
|
||||||
|
ret = snl_attr_get_uint32(ss, nla, NULL, &t->timeouts[t->i]);
|
||||||
|
if (ret)
|
||||||
|
t->i++;
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _OUT(_field) offsetof(struct nl_parsed_timeout, _field)
|
||||||
|
static const struct snl_attr_parser ap_timeouts[] = {
|
||||||
|
{ .type = PF_TT_TIMEOUT, .off = 0, .cb = snl_attr_get_pf_timeout },
|
||||||
|
};
|
||||||
|
SNL_DECLARE_ATTR_PARSER(timeout_parser, ap_timeouts);
|
||||||
|
#undef _OUT
|
||||||
|
|
||||||
|
static bool
|
||||||
|
snl_attr_get_nested_timeouts(struct snl_state *ss, struct nlattr *nla,
|
||||||
|
const void *arg __unused, void *target)
|
||||||
|
{
|
||||||
|
struct nl_parsed_timeouts parsed_timeouts = { };
|
||||||
|
bool error;
|
||||||
|
|
||||||
|
/* Assumes target points to the beginning of the structure */
|
||||||
|
error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, &parsed_timeouts);
|
||||||
|
if (! error)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _OUT(_field) offsetof(struct pf_rule_uid, _field)
|
||||||
|
static const struct snl_attr_parser ap_rule_uid[] = {
|
||||||
|
{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RUT_OP, .off = _OUT(op), .cb = snl_attr_get_uint8 },
|
||||||
|
};
|
||||||
|
SNL_DECLARE_ATTR_PARSER(rule_uid_parser, ap_rule_uid);
|
||||||
|
#undef _OUT
|
||||||
|
|
||||||
|
struct pfctl_nl_get_rule {
|
||||||
|
struct pfctl_rule r;
|
||||||
|
char anchor_call[MAXPATHLEN];
|
||||||
|
};
|
||||||
|
#define _OUT(_field) offsetof(struct pfctl_nl_get_rule, _field)
|
||||||
|
static struct snl_attr_parser ap_getrule[] = {
|
||||||
|
{ .type = PF_RT_SRC, .off = _OUT(r.src), .arg = &rule_addr_parser,.cb = snl_attr_get_nested },
|
||||||
|
{ .type = PF_RT_DST, .off = _OUT(r.dst), .arg = &rule_addr_parser,.cb = snl_attr_get_nested },
|
||||||
|
{ .type = PF_RT_RIDENTIFIER, .off = _OUT(r.ridentifier), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_LABELS, .off = _OUT(r.label), .arg = &rule_labels_parser,.cb = snl_attr_get_nested_pf_rule_labels },
|
||||||
|
{ .type = PF_RT_IFNAME, .off = _OUT(r.ifname), .arg = (void *)IFNAMSIZ, .cb = snl_attr_copy_string },
|
||||||
|
{ .type = PF_RT_QNAME, .off = _OUT(r.qname), .arg = (void *)PF_QNAME_SIZE, .cb = snl_attr_copy_string },
|
||||||
|
{ .type = PF_RT_PQNAME, .off = _OUT(r.pqname), .arg = (void *)PF_QNAME_SIZE, .cb = snl_attr_copy_string },
|
||||||
|
{ .type = PF_RT_TAGNAME, .off = _OUT(r.tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = snl_attr_copy_string },
|
||||||
|
{ .type = PF_RT_MATCH_TAGNAME, .off = _OUT(r.match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = snl_attr_copy_string },
|
||||||
|
{ .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(r.overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
|
||||||
|
{ .type = PF_RT_RPOOL, .off = _OUT(r.rpool), .arg = &pool_parser, .cb = snl_attr_get_nested },
|
||||||
|
{ .type = PF_RT_OS_FINGERPRINT, .off = _OUT(r.os_fingerprint), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_RTABLEID, .off = _OUT(r.rtableid), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_TIMEOUT, .off = _OUT(r.timeout), .arg = &timeout_parser, .cb = snl_attr_get_nested_timeouts },
|
||||||
|
{ .type = PF_RT_MAX_STATES, .off = _OUT(r.max_states), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_MAX_SRC_NODES, .off = _OUT(r.max_src_nodes), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_MAX_SRC_STATES, .off = _OUT(r.max_src_states), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(r.max_src_conn_rate.limit), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(r.max_src_conn_rate.seconds), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_DNPIPE, .off = _OUT(r.dnpipe), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RT_DNRPIPE, .off = _OUT(r.dnrpipe), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RT_DNFLAGS, .off = _OUT(r.free_flags), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_NR, .off = _OUT(r.nr), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_PROB, .off = _OUT(r.prob), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_CUID, .off = _OUT(r.cuid), .cb = snl_attr_get_uint32 },
|
||||||
|
{. type = PF_RT_CPID, .off = _OUT(r.cpid), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_RETURN_ICMP, .off = _OUT(r.return_icmp), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RT_RETURN_ICMP6, .off = _OUT(r.return_icmp6), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RT_MAX_MSS, .off = _OUT(r.max_mss), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RT_SCRUB_FLAGS, .off = _OUT(r.scrub_flags), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RT_UID, .off = _OUT(r.uid), .arg = &rule_uid_parser, .cb = snl_attr_get_nested },
|
||||||
|
{ .type = PF_RT_GID, .off = _OUT(r.gid), .arg = &rule_uid_parser, .cb = snl_attr_get_nested },
|
||||||
|
{ .type = PF_RT_RULE_FLAG, .off = _OUT(r.rule_flag), .cb = snl_attr_get_uint32 },
|
||||||
|
{ .type = PF_RT_ACTION, .off = _OUT(r.action), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_DIRECTION, .off = _OUT(r.direction), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_LOG, .off = _OUT(r.log), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_LOGIF, .off = _OUT(r.logif), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_QUICK, .off = _OUT(r.quick), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_IF_NOT, .off = _OUT(r.ifnot), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(r.match_tag_not), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_NATPASS, .off = _OUT(r.natpass), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_KEEP_STATE, .off = _OUT(r.keep_state), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_AF, .off = _OUT(r.af), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_PROTO, .off = _OUT(r.proto), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_TYPE, .off = _OUT(r.type), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_CODE, .off = _OUT(r.code), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_FLAGS, .off = _OUT(r.flags), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_FLAGSET, .off = _OUT(r.flagset), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_MIN_TTL, .off = _OUT(r.min_ttl), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_ALLOW_OPTS, .off = _OUT(r.allow_opts), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_RT, .off = _OUT(r.rt), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_RETURN_TTL, .off = _OUT(r.return_ttl), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_TOS, .off = _OUT(r.tos), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_SET_TOS, .off = _OUT(r.set_tos), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(r.anchor_relative), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(r.anchor_wildcard), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_FLUSH, .off = _OUT(r.flush), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_PRIO, .off = _OUT(r.prio), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_SET_PRIO, .off = _OUT(r.set_prio[0]), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(r.set_prio[1]), .cb = snl_attr_get_uint8 },
|
||||||
|
{ .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(r.divert.addr), .cb = snl_attr_get_in6_addr },
|
||||||
|
{ .type = PF_RT_DIVERT_PORT, .off = _OUT(r.divert.port), .cb = snl_attr_get_uint16 },
|
||||||
|
{ .type = PF_RT_PACKETS_IN, .off = _OUT(r.packets[0]), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_PACKETS_OUT, .off = _OUT(r.packets[1]), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_BYTES_IN, .off = _OUT(r.bytes[0]), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_BYTES_OUT, .off = _OUT(r.bytes[1]), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_EVALUATIONS, .off = _OUT(r.evaluations), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_TIMESTAMP, .off = _OUT(r.last_active_timestamp), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_STATES_CUR, .off = _OUT(r.states_cur), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_STATES_TOTAL, .off = _OUT(r.states_tot), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_SRC_NODES, .off = _OUT(r.src_nodes), .cb = snl_attr_get_uint64 },
|
||||||
|
{ .type = PF_RT_ANCHOR_CALL, .off = _OUT(anchor_call), .arg = (void*)MAXPATHLEN, .cb = snl_attr_copy_string },
|
||||||
|
};
|
||||||
|
static struct snl_field_parser fp_getrule[] = {};
|
||||||
|
#undef _OUT
|
||||||
|
SNL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, fp_getrule, ap_getrule);
|
||||||
|
|
||||||
|
int
|
||||||
|
pfctl_get_clear_rule_h(struct pfctl_handle *h, uint32_t nr, uint32_t ticket,
|
||||||
|
const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
|
||||||
|
char *anchor_call, bool clear)
|
||||||
|
{
|
||||||
|
struct pfctl_nl_get_rule attrs = {};
|
||||||
|
struct snl_errmsg_data e = {};
|
||||||
|
struct nlmsghdr *hdr;
|
||||||
|
struct snl_writer nw;
|
||||||
|
uint32_t seq_id;
|
||||||
|
int family_id;
|
||||||
|
|
||||||
|
family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
|
||||||
|
if (family_id == 0)
|
||||||
|
return (ENOTSUP);
|
||||||
|
|
||||||
|
snl_init_writer(&h->ss, &nw);
|
||||||
|
hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETRULE);
|
||||||
|
hdr->nlmsg_flags |= NLM_F_DUMP;
|
||||||
|
|
||||||
|
snl_add_msg_attr_string(&nw, PF_GR_ANCHOR, anchor);
|
||||||
|
snl_add_msg_attr_u8(&nw, PF_GR_ACTION, ruleset);
|
||||||
|
snl_add_msg_attr_u32(&nw, PF_GR_NR, nr);
|
||||||
|
snl_add_msg_attr_u32(&nw, PF_GR_TICKET, ticket);
|
||||||
|
snl_add_msg_attr_u8(&nw, PF_GR_CLEAR, clear);
|
||||||
|
|
||||||
|
hdr = snl_finalize_msg(&nw);
|
||||||
|
if (hdr == NULL)
|
||||||
|
return (ENOMEM);
|
||||||
|
|
||||||
|
seq_id = hdr->nlmsg_seq;
|
||||||
|
if (! snl_send_message(&h->ss, hdr))
|
||||||
|
return (ENXIO);
|
||||||
|
|
||||||
|
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
|
||||||
|
if (! snl_parse_nlmsg(&h->ss, hdr, &getrule_parser, &attrs))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(rule, &attrs.r, sizeof(attrs.r));
|
||||||
|
strlcpy(anchor_call, attrs.anchor_call, MAXPATHLEN);
|
||||||
|
|
||||||
|
return (e.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket,
|
||||||
const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
|
const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
|
||||||
char *anchor_call, bool clear)
|
char *anchor_call, bool clear)
|
||||||
{
|
{
|
||||||
|
|
|
@ -418,6 +418,9 @@ int pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket,
|
||||||
int pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket,
|
int pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket,
|
||||||
const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
|
const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
|
||||||
char *anchor_call, bool clear);
|
char *anchor_call, bool clear);
|
||||||
|
int pfctl_get_clear_rule_h(struct pfctl_handle *h, uint32_t nr, uint32_t ticket,
|
||||||
|
const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
|
||||||
|
char *anchor_call, bool clear);
|
||||||
int pfctl_add_rule(int dev, const struct pfctl_rule *r,
|
int pfctl_add_rule(int dev, const struct pfctl_rule *r,
|
||||||
const char *anchor, const char *anchor_call, uint32_t ticket,
|
const char *anchor, const char *anchor_call, uint32_t ticket,
|
||||||
uint32_t pool_ticket);
|
uint32_t pool_ticket);
|
||||||
|
|
|
@ -1303,7 +1303,7 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (nr = 0; nr < ri.nr; ++nr) {
|
for (nr = 0; nr < ri.nr; ++nr) {
|
||||||
if (pfctl_get_clear_rule(dev, nr, ri.ticket, path, PF_SCRUB,
|
if (pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_SCRUB,
|
||||||
&rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) {
|
&rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) {
|
||||||
warn("DIOCGETRULENV");
|
warn("DIOCGETRULENV");
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1334,7 +1334,7 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
for (nr = 0; nr < ri.nr; ++nr) {
|
for (nr = 0; nr < ri.nr; ++nr) {
|
||||||
if (pfctl_get_clear_rule(dev, nr, ri.ticket, path, PF_PASS,
|
if (pfctl_get_clear_rule_h(pfh, nr, ri.ticket, path, PF_PASS,
|
||||||
&rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) {
|
&rule, anchor_call, opts & PF_OPT_CLRRULECTRS)) {
|
||||||
warn("DIOCGETRULE");
|
warn("DIOCGETRULE");
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -2470,10 +2470,10 @@ void pf_init_kruleset(struct pf_kruleset *);
|
||||||
void pf_init_keth(struct pf_keth_ruleset *);
|
void pf_init_keth(struct pf_keth_ruleset *);
|
||||||
int pf_kanchor_setup(struct pf_krule *,
|
int pf_kanchor_setup(struct pf_krule *,
|
||||||
const struct pf_kruleset *, const char *);
|
const struct pf_kruleset *, const char *);
|
||||||
|
int pf_kanchor_copyout(const struct pf_kruleset *,
|
||||||
|
const struct pf_krule *, char *);
|
||||||
int pf_kanchor_nvcopyout(const struct pf_kruleset *,
|
int pf_kanchor_nvcopyout(const struct pf_kruleset *,
|
||||||
const struct pf_krule *, nvlist_t *);
|
const struct pf_krule *, nvlist_t *);
|
||||||
int pf_kanchor_copyout(const struct pf_kruleset *,
|
|
||||||
const struct pf_krule *, struct pfioc_rule *);
|
|
||||||
void pf_kanchor_remove(struct pf_krule *);
|
void pf_kanchor_remove(struct pf_krule *);
|
||||||
void pf_remove_if_empty_kruleset(struct pf_kruleset *);
|
void pf_remove_if_empty_kruleset(struct pf_kruleset *);
|
||||||
struct pf_kruleset *pf_find_kruleset(const char *);
|
struct pf_kruleset *pf_find_kruleset(const char *);
|
||||||
|
@ -2501,6 +2501,7 @@ int pf_ioctl_addrule(struct pf_krule *, uint32_t,
|
||||||
pid_t);
|
pid_t);
|
||||||
|
|
||||||
void pf_krule_free(struct pf_krule *);
|
void pf_krule_free(struct pf_krule *);
|
||||||
|
void pf_krule_clear_counters(struct pf_krule *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The fingerprint functions can be linked into userland programs (tcpdump) */
|
/* The fingerprint functions can be linked into userland programs (tcpdump) */
|
||||||
|
|
|
@ -513,6 +513,18 @@ snl_attr_get_flag(struct snl_state *ss __unused, struct nlattr *nla, const void
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
snl_attr_get_bytes(struct snl_state *ss __unused, struct nlattr *nla, const void *arg,
|
||||||
|
void *target)
|
||||||
|
{
|
||||||
|
if ((size_t)NLA_DATA_LEN(nla) != (size_t)arg)
|
||||||
|
return (false);
|
||||||
|
|
||||||
|
memcpy(target, NLA_DATA_CONST(nla), (size_t)arg);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
snl_attr_get_uint8(struct snl_state *ss __unused, struct nlattr *nla,
|
snl_attr_get_uint8(struct snl_state *ss __unused, struct nlattr *nla,
|
||||||
const void *arg __unused, void *target)
|
const void *arg __unused, void *target)
|
||||||
|
|
|
@ -1867,6 +1867,17 @@ pf_krule_free(struct pf_krule *rule)
|
||||||
free(rule, M_PFRULE);
|
free(rule, M_PFRULE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pf_krule_clear_counters(struct pf_krule *rule)
|
||||||
|
{
|
||||||
|
pf_counter_u64_zero(&rule->evaluations);
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
pf_counter_u64_zero(&rule->packets[i]);
|
||||||
|
pf_counter_u64_zero(&rule->bytes[i]);
|
||||||
|
}
|
||||||
|
counter_u64_zero(rule->states_tot);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pf_kpooladdr_to_pooladdr(const struct pf_kpooladdr *kpool,
|
pf_kpooladdr_to_pooladdr(const struct pf_kpooladdr *kpool,
|
||||||
struct pf_pooladdr *pool)
|
struct pf_pooladdr *pool)
|
||||||
|
@ -3266,14 +3277,9 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
|
||||||
ERROUT(ENOSPC);
|
ERROUT(ENOSPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clear_counter) {
|
if (clear_counter)
|
||||||
pf_counter_u64_zero(&rule->evaluations);
|
pf_krule_clear_counters(rule);
|
||||||
for (int i = 0; i < 2; i++) {
|
|
||||||
pf_counter_u64_zero(&rule->packets[i]);
|
|
||||||
pf_counter_u64_zero(&rule->bytes[i]);
|
|
||||||
}
|
|
||||||
counter_u64_zero(rule->states_tot);
|
|
||||||
}
|
|
||||||
PF_RULES_WUNLOCK();
|
PF_RULES_WUNLOCK();
|
||||||
|
|
||||||
error = copyout(nvlpacked, nv->data, nv->len);
|
error = copyout(nvlpacked, nv->data, nv->len);
|
||||||
|
|
|
@ -401,6 +401,42 @@ static const struct nlattr_parser nla_p_addr_wrap[] = {
|
||||||
NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
|
NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
|
||||||
#undef _OUT
|
#undef _OUT
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nlattr_add_addr_wrap(struct nl_writer *nw, int attrtype, struct pf_addr_wrap *a)
|
||||||
|
{
|
||||||
|
int off = nlattr_add_nested(nw, attrtype);
|
||||||
|
int num;
|
||||||
|
|
||||||
|
nlattr_add_in6_addr(nw, PF_AT_ADDR, &a->v.a.addr.v6);
|
||||||
|
nlattr_add_in6_addr(nw, PF_AT_MASK, &a->v.a.mask.v6);
|
||||||
|
nlattr_add_u8(nw, PF_AT_TYPE, a->type);
|
||||||
|
nlattr_add_u8(nw, PF_AT_IFLAGS, a->iflags);
|
||||||
|
|
||||||
|
if (a->type == PF_ADDR_DYNIFTL) {
|
||||||
|
nlattr_add_string(nw, PF_AT_IFNAME, a->v.ifname);
|
||||||
|
num = 0;
|
||||||
|
if (a->p.dyn != NULL)
|
||||||
|
num = a->p.dyn->pfid_acnt4 + a->p.dyn->pfid_acnt6;
|
||||||
|
nlattr_add_u32(nw, PF_AT_DYNCNT, num);
|
||||||
|
} else if (a->type == PF_ADDR_TABLE) {
|
||||||
|
struct pfr_ktable *kt;
|
||||||
|
|
||||||
|
nlattr_add_string(nw, PF_AT_TABLENAME, a->v.tblname);
|
||||||
|
num = -1;
|
||||||
|
kt = a->p.tbl;
|
||||||
|
if ((kt->pfrkt_flags & PFR_TFLAG_ACTIVE) &&
|
||||||
|
kt->pfrkt_root != NULL)
|
||||||
|
kt = kt->pfrkt_root;
|
||||||
|
if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE)
|
||||||
|
num = kt->pfrkt_cnt;
|
||||||
|
nlattr_add_u32(nw, PF_AT_TBLCNT, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
nlattr_set_len(nw, off);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
#define _OUT(_field) offsetof(struct pf_rule_addr, _field)
|
#define _OUT(_field) offsetof(struct pf_rule_addr, _field)
|
||||||
static const struct nlattr_parser nla_p_ruleaddr[] = {
|
static const struct nlattr_parser nla_p_ruleaddr[] = {
|
||||||
{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
|
{ .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
|
||||||
|
@ -412,6 +448,22 @@ static const struct nlattr_parser nla_p_ruleaddr[] = {
|
||||||
NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
|
NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
|
||||||
#undef _OUT
|
#undef _OUT
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nlattr_add_rule_addr(struct nl_writer *nw, int attrtype, struct pf_rule_addr *r)
|
||||||
|
{
|
||||||
|
int off = nlattr_add_nested(nw, attrtype);
|
||||||
|
|
||||||
|
nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &r->addr);
|
||||||
|
nlattr_add_u16(nw, PF_RAT_SRC_PORT, r->port[0]);
|
||||||
|
nlattr_add_u16(nw, PF_RAT_DST_PORT, r->port[1]);
|
||||||
|
nlattr_add_u8(nw, PF_RAT_NEG, r->neg);
|
||||||
|
nlattr_add_u8(nw, PF_RAT_OP, r->port_op);
|
||||||
|
|
||||||
|
nlattr_set_len(nw, off);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
#define _OUT(_field) offsetof(struct pf_mape_portset, _field)
|
#define _OUT(_field) offsetof(struct pf_mape_portset, _field)
|
||||||
static const struct nlattr_parser nla_p_mape_portset[] = {
|
static const struct nlattr_parser nla_p_mape_portset[] = {
|
||||||
{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
|
{ .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
|
||||||
|
@ -421,6 +473,20 @@ static const struct nlattr_parser nla_p_mape_portset[] = {
|
||||||
NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
|
NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
|
||||||
#undef _OUT
|
#undef _OUT
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nlattr_add_mape_portset(struct nl_writer *nw, int attrtype, const struct pf_mape_portset *m)
|
||||||
|
{
|
||||||
|
int off = nlattr_add_nested(nw, attrtype);
|
||||||
|
|
||||||
|
nlattr_add_u8(nw, PF_MET_OFFSET, m->offset);
|
||||||
|
nlattr_add_u8(nw, PF_MET_PSID_LEN, m->psidlen);
|
||||||
|
nlattr_add_u16(nw, PF_MET_PSID, m->psid);
|
||||||
|
|
||||||
|
nlattr_set_len(nw, off);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
struct nl_parsed_labels
|
struct nl_parsed_labels
|
||||||
{
|
{
|
||||||
char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
|
char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
|
||||||
|
@ -468,6 +534,23 @@ nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, cons
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nlattr_add_labels(struct nl_writer *nw, int attrtype, const struct pf_krule *r)
|
||||||
|
{
|
||||||
|
int off = nlattr_add_nested(nw, attrtype);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (r->label[i][0] != 0
|
||||||
|
&& i < PF_RULE_MAX_LABEL_COUNT) {
|
||||||
|
nlattr_add_string(nw, PF_LT_LABEL, r->label[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlattr_set_len(nw, off);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
#define _OUT(_field) offsetof(struct pf_kpool, _field)
|
#define _OUT(_field) offsetof(struct pf_kpool, _field)
|
||||||
static const struct nlattr_parser nla_p_pool[] = {
|
static const struct nlattr_parser nla_p_pool[] = {
|
||||||
{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
|
{ .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = nlattr_get_bytes },
|
||||||
|
@ -481,6 +564,24 @@ static const struct nlattr_parser nla_p_pool[] = {
|
||||||
NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
|
NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
|
||||||
#undef _OUT
|
#undef _OUT
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nlattr_add_pool(struct nl_writer *nw, int attrtype, const struct pf_kpool *pool)
|
||||||
|
{
|
||||||
|
int off = nlattr_add_nested(nw, attrtype);
|
||||||
|
|
||||||
|
nlattr_add(nw, PF_PT_KEY, sizeof(struct pf_poolhashkey), &pool->key);
|
||||||
|
nlattr_add_in6_addr(nw, PF_PT_COUNTER, (const struct in6_addr *)&pool->counter);
|
||||||
|
nlattr_add_u32(nw, PF_PT_TBLIDX, pool->tblidx);
|
||||||
|
nlattr_add_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
|
||||||
|
nlattr_add_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
|
||||||
|
nlattr_add_u8(nw, PF_PT_OPTS, pool->opts);
|
||||||
|
nlattr_add_mape_portset(nw, PF_PT_MAPE, &pool->mape);
|
||||||
|
|
||||||
|
nlattr_set_len(nw, off);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
#define _OUT(_field) offsetof(struct pf_rule_uid, _field)
|
#define _OUT(_field) offsetof(struct pf_rule_uid, _field)
|
||||||
static const struct nlattr_parser nla_p_rule_uid[] = {
|
static const struct nlattr_parser nla_p_rule_uid[] = {
|
||||||
{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
|
{ .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = nlattr_get_uint32 },
|
||||||
|
@ -490,6 +591,20 @@ static const struct nlattr_parser nla_p_rule_uid[] = {
|
||||||
NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
|
NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
|
||||||
#undef _OUT
|
#undef _OUT
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nlattr_add_rule_uid(struct nl_writer *nw, int attrtype, const struct pf_rule_uid *u)
|
||||||
|
{
|
||||||
|
int off = nlattr_add_nested(nw, attrtype);
|
||||||
|
|
||||||
|
nlattr_add_u32(nw, PF_RUT_UID_LOW, u->uid[0]);
|
||||||
|
nlattr_add_u32(nw, PF_RUT_UID_HIGH, u->uid[1]);
|
||||||
|
nlattr_add_u8(nw, PF_RUT_OP, u->op);
|
||||||
|
|
||||||
|
nlattr_set_len(nw, off);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
struct nl_parsed_timeouts
|
struct nl_parsed_timeouts
|
||||||
{
|
{
|
||||||
uint32_t timeouts[PFTM_MAX];
|
uint32_t timeouts[PFTM_MAX];
|
||||||
|
@ -536,6 +651,19 @@ nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
nlattr_add_timeout(struct nl_writer *nw, int attrtype, uint32_t *timeout)
|
||||||
|
{
|
||||||
|
int off = nlattr_add_nested(nw, attrtype);
|
||||||
|
|
||||||
|
for (int i = 0; i < PFTM_MAX; i++)
|
||||||
|
nlattr_add_u32(nw, PF_RT_TIMEOUT, timeout[i]);
|
||||||
|
|
||||||
|
nlattr_set_len(nw, off);
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
#define _OUT(_field) offsetof(struct pf_krule, _field)
|
#define _OUT(_field) offsetof(struct pf_krule, _field)
|
||||||
static const struct nlattr_parser nla_p_rule[] = {
|
static const struct nlattr_parser nla_p_rule[] = {
|
||||||
{ .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
|
{ .type = PF_RT_SRC, .off = _OUT(src), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
|
||||||
|
@ -654,6 +782,7 @@ static const struct nlattr_parser nla_p_getrules[] = {
|
||||||
};
|
};
|
||||||
static const struct nlfield_parser nlf_p_getrules[] = {
|
static const struct nlfield_parser nlf_p_getrules[] = {
|
||||||
};
|
};
|
||||||
|
#undef _OUT
|
||||||
NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_getrules, nla_p_getrules);
|
NL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, nlf_p_getrules, nla_p_getrules);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -695,6 +824,182 @@ pf_handle_getrules(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nl_parsed_get_rule {
|
||||||
|
char anchor[MAXPATHLEN];
|
||||||
|
uint8_t action;
|
||||||
|
uint32_t nr;
|
||||||
|
uint32_t ticket;
|
||||||
|
uint8_t clear;
|
||||||
|
};
|
||||||
|
#define _IN(_field) offsetof(struct genlmsghdr, _field)
|
||||||
|
#define _OUT(_field) offsetof(struct nl_parsed_get_rule, _field)
|
||||||
|
static const struct nlattr_parser nla_p_getrule[] = {
|
||||||
|
{ .type = PF_GR_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
|
||||||
|
{ .type = PF_GR_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
|
||||||
|
{ .type = PF_GR_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
|
||||||
|
{ .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
|
||||||
|
{ .type = PF_GR_CLEAR, .off = _OUT(clear), .cb = nlattr_get_uint8 },
|
||||||
|
};
|
||||||
|
static const struct nlfield_parser nlf_p_getrule[] = {
|
||||||
|
};
|
||||||
|
NL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, nlf_p_getrule, nla_p_getrule);
|
||||||
|
|
||||||
|
static int
|
||||||
|
pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
||||||
|
{
|
||||||
|
char anchor_call[MAXPATHLEN];
|
||||||
|
struct nl_parsed_get_rule attrs = {};
|
||||||
|
struct nl_writer *nw = npt->nw;
|
||||||
|
struct genlmsghdr *ghdr_new;
|
||||||
|
struct pf_kruleset *ruleset;
|
||||||
|
struct pf_krule *rule;
|
||||||
|
int rs_num;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = nl_parse_nlmsg(hdr, &getrule_parser, npt, &attrs);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
|
||||||
|
return (ENOMEM);
|
||||||
|
|
||||||
|
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
|
||||||
|
ghdr_new->cmd = PFNL_CMD_GETRULE;
|
||||||
|
ghdr_new->version = 0;
|
||||||
|
ghdr_new->reserved = 0;
|
||||||
|
|
||||||
|
PF_RULES_WLOCK();
|
||||||
|
ruleset = pf_find_kruleset(attrs.anchor);
|
||||||
|
if (ruleset == NULL) {
|
||||||
|
PF_RULES_WUNLOCK();
|
||||||
|
error = ENOENT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rs_num = pf_get_ruleset_number(attrs.action);
|
||||||
|
if (rs_num >= PF_RULESET_MAX) {
|
||||||
|
PF_RULES_WUNLOCK();
|
||||||
|
error = EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrs.ticket != ruleset->rules[rs_num].active.ticket) {
|
||||||
|
PF_RULES_WUNLOCK();
|
||||||
|
error = EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
|
||||||
|
while ((rule != NULL) && (rule->nr != attrs.nr))
|
||||||
|
rule = TAILQ_NEXT(rule, entries);
|
||||||
|
if (rule == NULL) {
|
||||||
|
PF_RULES_WUNLOCK();
|
||||||
|
error = EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlattr_add_rule_addr(nw, PF_RT_SRC, &rule->src);
|
||||||
|
nlattr_add_rule_addr(nw, PF_RT_DST, &rule->dst);
|
||||||
|
nlattr_add_u32(nw, PF_RT_RIDENTIFIER, rule->ridentifier);
|
||||||
|
nlattr_add_labels(nw, PF_RT_LABELS, rule);
|
||||||
|
nlattr_add_string(nw, PF_RT_IFNAME, rule->ifname);
|
||||||
|
nlattr_add_string(nw, PF_RT_QNAME, rule->qname);
|
||||||
|
nlattr_add_string(nw, PF_RT_PQNAME, rule->pqname);
|
||||||
|
nlattr_add_string(nw, PF_RT_TAGNAME, rule->tagname);
|
||||||
|
nlattr_add_string(nw, PF_RT_MATCH_TAGNAME, rule->match_tagname);
|
||||||
|
nlattr_add_string(nw, PF_RT_OVERLOAD_TBLNAME, rule->overload_tblname);
|
||||||
|
nlattr_add_pool(nw, PF_RT_RPOOL, &rule->rpool);
|
||||||
|
nlattr_add_u32(nw, PF_RT_OS_FINGERPRINT, rule->os_fingerprint);
|
||||||
|
nlattr_add_u32(nw, PF_RT_RTABLEID, rule->rtableid);
|
||||||
|
nlattr_add_timeout(nw, PF_RT_TIMEOUT, rule->timeout);
|
||||||
|
nlattr_add_u32(nw, PF_RT_MAX_STATES, rule->max_states);
|
||||||
|
nlattr_add_u32(nw, PF_RT_MAX_SRC_NODES, rule->max_src_nodes);
|
||||||
|
nlattr_add_u32(nw, PF_RT_MAX_SRC_STATES, rule->max_src_states);
|
||||||
|
nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, rule->max_src_conn_rate.limit);
|
||||||
|
nlattr_add_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, rule->max_src_conn_rate.seconds);
|
||||||
|
|
||||||
|
nlattr_add_u16(nw, PF_RT_DNPIPE, rule->dnpipe);
|
||||||
|
nlattr_add_u16(nw, PF_RT_DNRPIPE, rule->dnrpipe);
|
||||||
|
nlattr_add_u32(nw, PF_RT_DNFLAGS, rule->free_flags);
|
||||||
|
|
||||||
|
nlattr_add_u32(nw, PF_RT_NR, rule->nr);
|
||||||
|
nlattr_add_u32(nw, PF_RT_PROB, rule->prob);
|
||||||
|
nlattr_add_u32(nw, PF_RT_CUID, rule->cuid);
|
||||||
|
nlattr_add_u32(nw, PF_RT_CPID, rule->cpid);
|
||||||
|
|
||||||
|
nlattr_add_u16(nw, PF_RT_RETURN_ICMP, rule->return_icmp);
|
||||||
|
nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
|
||||||
|
nlattr_add_u16(nw, PF_RT_RETURN_ICMP6, rule->return_icmp6);
|
||||||
|
nlattr_add_u16(nw, PF_RT_MAX_MSS, rule->max_mss);
|
||||||
|
nlattr_add_u16(nw, PF_RT_SCRUB_FLAGS, rule->scrub_flags);
|
||||||
|
|
||||||
|
nlattr_add_rule_uid(nw, PF_RT_UID, &rule->uid);
|
||||||
|
nlattr_add_rule_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&rule->gid);
|
||||||
|
|
||||||
|
nlattr_add_u32(nw, PF_RT_RULE_FLAG, rule->rule_flag);
|
||||||
|
nlattr_add_u8(nw, PF_RT_ACTION, rule->action);
|
||||||
|
nlattr_add_u8(nw, PF_RT_DIRECTION, rule->direction);
|
||||||
|
nlattr_add_u8(nw, PF_RT_LOG, rule->log);
|
||||||
|
nlattr_add_u8(nw, PF_RT_LOGIF, rule->logif);
|
||||||
|
nlattr_add_u8(nw, PF_RT_QUICK, rule->quick);
|
||||||
|
nlattr_add_u8(nw, PF_RT_IF_NOT, rule->ifnot);
|
||||||
|
nlattr_add_u8(nw, PF_RT_MATCH_TAG_NOT, rule->match_tag_not);
|
||||||
|
nlattr_add_u8(nw, PF_RT_NATPASS, rule->natpass);
|
||||||
|
nlattr_add_u8(nw, PF_RT_KEEP_STATE, rule->keep_state);
|
||||||
|
|
||||||
|
nlattr_add_u8(nw, PF_RT_AF, rule->af);
|
||||||
|
nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
|
||||||
|
nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
|
||||||
|
nlattr_add_u8(nw, PF_RT_CODE, rule->code);
|
||||||
|
nlattr_add_u8(nw, PF_RT_FLAGS, rule->flags);
|
||||||
|
nlattr_add_u8(nw, PF_RT_FLAGSET, rule->flagset);
|
||||||
|
nlattr_add_u8(nw, PF_RT_MIN_TTL, rule->min_ttl);
|
||||||
|
nlattr_add_u8(nw, PF_RT_ALLOW_OPTS, rule->allow_opts);
|
||||||
|
nlattr_add_u8(nw, PF_RT_RT, rule->rt);
|
||||||
|
nlattr_add_u8(nw, PF_RT_RETURN_TTL, rule->return_ttl);
|
||||||
|
nlattr_add_u8(nw, PF_RT_TOS, rule->tos);
|
||||||
|
nlattr_add_u8(nw, PF_RT_SET_TOS, rule->set_tos);
|
||||||
|
nlattr_add_u8(nw, PF_RT_ANCHOR_RELATIVE, rule->anchor_relative);
|
||||||
|
nlattr_add_u8(nw, PF_RT_ANCHOR_WILDCARD, rule->anchor_wildcard);
|
||||||
|
nlattr_add_u8(nw, PF_RT_FLUSH, rule->flush);
|
||||||
|
nlattr_add_u8(nw, PF_RT_PRIO, rule->prio);
|
||||||
|
nlattr_add_u8(nw, PF_RT_SET_PRIO, rule->set_prio[0]);
|
||||||
|
nlattr_add_u8(nw, PF_RT_SET_PRIO_REPLY, rule->set_prio[1]);
|
||||||
|
|
||||||
|
nlattr_add_in6_addr(nw, PF_RT_DIVERT_ADDRESS, &rule->divert.addr.v6);
|
||||||
|
nlattr_add_u16(nw, PF_RT_DIVERT_PORT, rule->divert.port);
|
||||||
|
|
||||||
|
nlattr_add_u64(nw, PF_RT_PACKETS_IN, pf_counter_u64_fetch(&rule->packets[0]));
|
||||||
|
nlattr_add_u64(nw, PF_RT_PACKETS_OUT, pf_counter_u64_fetch(&rule->packets[1]));
|
||||||
|
nlattr_add_u64(nw, PF_RT_BYTES_IN, pf_counter_u64_fetch(&rule->bytes[0]));
|
||||||
|
nlattr_add_u64(nw, PF_RT_BYTES_OUT, pf_counter_u64_fetch(&rule->bytes[1]));
|
||||||
|
nlattr_add_u64(nw, PF_RT_EVALUATIONS, pf_counter_u64_fetch(&rule->evaluations));
|
||||||
|
nlattr_add_u64(nw, PF_RT_TIMESTAMP, pf_get_timestamp(rule));
|
||||||
|
nlattr_add_u64(nw, PF_RT_STATES_CUR, counter_u64_fetch(rule->states_cur));
|
||||||
|
nlattr_add_u64(nw, PF_RT_STATES_TOTAL, counter_u64_fetch(rule->states_tot));
|
||||||
|
nlattr_add_u64(nw, PF_RT_SRC_NODES, counter_u64_fetch(rule->src_nodes));
|
||||||
|
|
||||||
|
error = pf_kanchor_copyout(ruleset, rule, anchor_call);
|
||||||
|
MPASS(error == 0);
|
||||||
|
|
||||||
|
nlattr_add_string(nw, PF_RT_ANCHOR_CALL, anchor_call);
|
||||||
|
|
||||||
|
if (attrs.clear)
|
||||||
|
pf_krule_clear_counters(rule);
|
||||||
|
|
||||||
|
PF_RULES_WUNLOCK();
|
||||||
|
|
||||||
|
if (!nlmsg_end(nw)) {
|
||||||
|
error = ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
out:
|
||||||
|
nlmsg_abort(nw);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct nlhdr_parser *all_parsers[] = {
|
static const struct nlhdr_parser *all_parsers[] = {
|
||||||
&state_parser,
|
&state_parser,
|
||||||
&addrule_parser,
|
&addrule_parser,
|
||||||
|
@ -746,6 +1051,13 @@ static const struct genl_cmd pf_cmds[] = {
|
||||||
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
|
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
|
||||||
.cmd_priv = PRIV_NETINET_PF,
|
.cmd_priv = PRIV_NETINET_PF,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.cmd_num = PFNL_CMD_GETRULE,
|
||||||
|
.cmd_name = "GETRULE",
|
||||||
|
.cmd_cb = pf_handle_getrule,
|
||||||
|
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
|
||||||
|
.cmd_priv = PRIV_NETINET_PF,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -42,6 +42,7 @@ enum {
|
||||||
PFNL_CMD_STOP = 4,
|
PFNL_CMD_STOP = 4,
|
||||||
PFNL_CMD_ADDRULE = 5,
|
PFNL_CMD_ADDRULE = 5,
|
||||||
PFNL_CMD_GETRULES = 6,
|
PFNL_CMD_GETRULES = 6,
|
||||||
|
PFNL_CMD_GETRULE = 7,
|
||||||
__PFNL_CMD_MAX,
|
__PFNL_CMD_MAX,
|
||||||
};
|
};
|
||||||
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
|
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
|
||||||
|
@ -117,6 +118,8 @@ enum pf_addr_type_t {
|
||||||
PF_AT_TABLENAME = 4, /* string */
|
PF_AT_TABLENAME = 4, /* string */
|
||||||
PF_AT_TYPE = 5, /* u8 */
|
PF_AT_TYPE = 5, /* u8 */
|
||||||
PF_AT_IFLAGS = 6, /* u8 */
|
PF_AT_IFLAGS = 6, /* u8 */
|
||||||
|
PF_AT_TBLCNT = 7, /* u32 */
|
||||||
|
PF_AT_DYNCNT = 8, /* u32 */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum pfrule_addr_type_t {
|
enum pfrule_addr_type_t {
|
||||||
|
@ -229,6 +232,16 @@ enum pf_rule_type_t {
|
||||||
PF_RT_SET_PRIO_REPLY = 60, /* u8 */
|
PF_RT_SET_PRIO_REPLY = 60, /* u8 */
|
||||||
PF_RT_DIVERT_ADDRESS = 61, /* in6_addr */
|
PF_RT_DIVERT_ADDRESS = 61, /* in6_addr */
|
||||||
PF_RT_DIVERT_PORT = 62, /* u16 */
|
PF_RT_DIVERT_PORT = 62, /* u16 */
|
||||||
|
PF_RT_PACKETS_IN = 63, /* u64 */
|
||||||
|
PF_RT_PACKETS_OUT = 64, /* u64 */
|
||||||
|
PF_RT_BYTES_IN = 65, /* u64 */
|
||||||
|
PF_RT_BYTES_OUT = 66, /* u64 */
|
||||||
|
PF_RT_EVALUATIONS = 67, /* u64 */
|
||||||
|
PF_RT_TIMESTAMP = 68, /* u64 */
|
||||||
|
PF_RT_STATES_CUR = 69, /* u64 */
|
||||||
|
PF_RT_STATES_TOTAL = 70, /* u64 */
|
||||||
|
PF_RT_SRC_NODES = 71, /* u64 */
|
||||||
|
PF_RT_ANCHOR_CALL = 72, /* string */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum pf_addrule_type_t {
|
enum pf_addrule_type_t {
|
||||||
|
@ -246,6 +259,7 @@ enum pf_getrules_type_t {
|
||||||
PF_GR_ACTION = 2, /* u8 */
|
PF_GR_ACTION = 2, /* u8 */
|
||||||
PF_GR_NR = 3, /* u32 */
|
PF_GR_NR = 3, /* u32 */
|
||||||
PF_GR_TICKET = 4, /* u32 */
|
PF_GR_TICKET = 4, /* u32 */
|
||||||
|
PF_GR_CLEAR = 5, /* u8 */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
|
|
|
@ -367,10 +367,10 @@ pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
|
pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
|
||||||
nvlist_t *nvl)
|
char *anchor_call)
|
||||||
{
|
{
|
||||||
char anchor_call[MAXPATHLEN] = { 0 };
|
anchor_call[0] = 0;
|
||||||
|
|
||||||
if (r->anchor == NULL)
|
if (r->anchor == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -408,11 +408,25 @@ pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
|
||||||
sizeof(anchor_call));
|
sizeof(anchor_call));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
nvlist_add_string(nvl, "anchor_call", anchor_call);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
|
||||||
|
nvlist_t *nvl)
|
||||||
|
{
|
||||||
|
char anchor_call[MAXPATHLEN] = { 0 };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pf_kanchor_copyout(rs, r, anchor_call);
|
||||||
|
MPASS(ret == 0);
|
||||||
|
|
||||||
|
nvlist_add_string(nvl, "anchor_call", anchor_call);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset *rs,
|
pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset *rs,
|
||||||
const struct pf_keth_rule *r, nvlist_t *nvl)
|
const struct pf_keth_rule *r, nvlist_t *nvl)
|
||||||
|
@ -460,52 +474,6 @@ pf_keth_anchor_nvcopyout(const struct pf_keth_ruleset *rs,
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
|
|
||||||
struct pfioc_rule *pr)
|
|
||||||
{
|
|
||||||
pr->anchor_call[0] = 0;
|
|
||||||
if (r->anchor == NULL)
|
|
||||||
return (0);
|
|
||||||
if (!r->anchor_relative) {
|
|
||||||
strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
|
|
||||||
strlcat(pr->anchor_call, r->anchor->path,
|
|
||||||
sizeof(pr->anchor_call));
|
|
||||||
} else {
|
|
||||||
char *a, *p;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
a = (char *)rs_malloc(MAXPATHLEN);
|
|
||||||
if (a == NULL)
|
|
||||||
return (1);
|
|
||||||
if (rs->anchor == NULL)
|
|
||||||
a[0] = 0;
|
|
||||||
else
|
|
||||||
strlcpy(a, rs->anchor->path, MAXPATHLEN);
|
|
||||||
for (i = 1; i < r->anchor_relative; ++i) {
|
|
||||||
if ((p = strrchr(a, '/')) == NULL)
|
|
||||||
p = a;
|
|
||||||
*p = 0;
|
|
||||||
strlcat(pr->anchor_call, "../",
|
|
||||||
sizeof(pr->anchor_call));
|
|
||||||
}
|
|
||||||
if (strncmp(a, r->anchor->path, strlen(a))) {
|
|
||||||
printf("pf_anchor_copyout: '%s' '%s'\n", a,
|
|
||||||
r->anchor->path);
|
|
||||||
rs_free(a);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
if (strlen(r->anchor->path) > strlen(a))
|
|
||||||
strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
|
|
||||||
strlen(a) + 1 : 0), sizeof(pr->anchor_call));
|
|
||||||
rs_free(a);
|
|
||||||
}
|
|
||||||
if (r->anchor_wildcard)
|
|
||||||
strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
|
|
||||||
sizeof(pr->anchor_call));
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
pf_kanchor_remove(struct pf_krule *r)
|
pf_kanchor_remove(struct pf_krule *r)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue