git: ffbf25951e7b - main - pf: convert rule addition to netlink
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 23 Oct 2023 15:10:33 UTC
The branch main has been updated by kp:
URL: https://cgit.FreeBSD.org/src/commit/?id=ffbf25951e7b7f867989b621b2c07e9dad9441fb
commit ffbf25951e7b7f867989b621b2c07e9dad9441fb
Author: Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-10-14 13:10:03 +0000
Commit: Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-10-23 14:24:51 +0000
pf: convert rule addition to netlink
The nvlist-based version will be removed in FreeBSD 16.
Sponsored by: Rubicon Communications, LLC ("Netgate")
Differential Revision: https://reviews.freebsd.org/D42279
---
lib/libpfctl/libpfctl.c | 385 ++++++++++++++++++++++++++--------------------
sys/net/pfvar.h | 4 +
sys/netpfil/pf/pf_ioctl.c | 14 +-
sys/netpfil/pf/pf_nl.c | 268 +++++++++++++++++++++++++++++++-
sys/netpfil/pf/pf_nl.h | 132 ++++++++++++++++
5 files changed, 626 insertions(+), 177 deletions(-)
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 571fabae4359..3865dc85aea1 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -438,40 +438,6 @@ pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
addr->port_op = nvlist_get_number(nvl, "port_op");
}
-static void
-pfctl_nv_add_mape(nvlist_t *nvparent, const char *name,
- const struct pf_mape_portset *mape)
-{
- nvlist_t *nvl = nvlist_create(0);
-
- nvlist_add_number(nvl, "offset", mape->offset);
- nvlist_add_number(nvl, "psidlen", mape->psidlen);
- nvlist_add_number(nvl, "psid", mape->psid);
- nvlist_add_nvlist(nvparent, name, nvl);
- nvlist_destroy(nvl);
-}
-
-static void
-pfctl_nv_add_pool(nvlist_t *nvparent, const char *name,
- const struct pfctl_pool *pool)
-{
- uint64_t ports[2];
- nvlist_t *nvl = nvlist_create(0);
-
- nvlist_add_binary(nvl, "key", &pool->key, sizeof(pool->key));
- pfctl_nv_add_addr(nvl, "counter", &pool->counter);
- nvlist_add_number(nvl, "tblidx", pool->tblidx);
-
- ports[0] = pool->proxy_port[0];
- ports[1] = pool->proxy_port[1];
- nvlist_add_number_array(nvl, "proxy_port", ports, 2);
- nvlist_add_number(nvl, "opts", pool->opts);
- pfctl_nv_add_mape(nvl, "mape", &pool->mape);
-
- nvlist_add_nvlist(nvparent, name, nvl);
- nvlist_destroy(nvl);
-}
-
static void
pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape)
{
@@ -500,22 +466,6 @@ pf_nvpool_to_pool(const nvlist_t *nvl, struct pfctl_pool *pool)
pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"), &pool->mape);
}
-static void
-pfctl_nv_add_uid(nvlist_t *nvparent, const char *name,
- const struct pf_rule_uid *uid)
-{
- uint64_t uids[2];
- nvlist_t *nvl = nvlist_create(0);
-
- uids[0] = uid->uid[0];
- uids[1] = uid->uid[1];
- nvlist_add_number_array(nvl, "uid", uids, 2);
- nvlist_add_number(nvl, "op", uid->op);
-
- nvlist_add_nvlist(nvparent, name, nvl);
- nvlist_destroy(nvl);
-}
-
static void
pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
{
@@ -523,19 +473,6 @@ pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
uid->op = nvlist_get_number(nvl, "op");
}
-static void
-pfctl_nv_add_divert(nvlist_t *nvparent, const char *name,
- const struct pfctl_rule *r)
-{
- nvlist_t *nvl = nvlist_create(0);
-
- pfctl_nv_add_addr(nvl, "addr", &r->divert.addr);
- nvlist_add_number(nvl, "port", r->divert.port);
-
- nvlist_add_nvlist(nvparent, name, nvl);
- nvlist_destroy(nvl);
-}
-
static void
pf_nvdivert_to_divert(const nvlist_t *nvl, struct pfctl_rule *rule)
{
@@ -926,127 +863,235 @@ pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor,
return (error);
}
-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)
+static void
+snl_add_msg_attr_addr_wrap(struct snl_writer *nw, uint32_t type, const struct pf_addr_wrap *addr)
{
- struct pfioc_nv nv;
- uint64_t timeouts[PFTM_MAX];
- uint64_t set_prio[2];
- nvlist_t *nvl, *nvlr;
- size_t labelcount;
- int ret;
+ int off;
- nvl = nvlist_create(0);
- nvlr = nvlist_create(0);
+ off = snl_add_msg_attr_nested(nw, type);
- nvlist_add_number(nvl, "ticket", ticket);
- nvlist_add_number(nvl, "pool_ticket", pool_ticket);
- nvlist_add_string(nvl, "anchor", anchor);
- nvlist_add_string(nvl, "anchor_call", anchor_call);
+ snl_add_msg_attr_ip6(nw, PF_AT_ADDR, &addr->v.a.addr.v6);
+ snl_add_msg_attr_ip6(nw, PF_AT_MASK, &addr->v.a.mask.v6);
- nvlist_add_number(nvlr, "nr", r->nr);
- pfctl_nv_add_rule_addr(nvlr, "src", &r->src);
- pfctl_nv_add_rule_addr(nvlr, "dst", &r->dst);
+ if (addr->type == PF_ADDR_DYNIFTL)
+ snl_add_msg_attr_string(nw, PF_AT_IFNAME, addr->v.ifname);
+ if (addr->type == PF_ADDR_TABLE)
+ snl_add_msg_attr_string(nw, PF_AT_TABLENAME, addr->v.tblname);
+ snl_add_msg_attr_u8(nw, PF_AT_TYPE, addr->type);
+ snl_add_msg_attr_u8(nw, PF_AT_IFLAGS, addr->iflags);
- labelcount = 0;
- while (r->label[labelcount][0] != 0 &&
- labelcount < PF_RULE_MAX_LABEL_COUNT) {
- nvlist_append_string_array(nvlr, "labels",
- r->label[labelcount]);
- labelcount++;
+ snl_end_attr_nested(nw, off);
+}
+
+static void
+snl_add_msg_attr_rule_addr(struct snl_writer *nw, uint32_t type, const struct pf_rule_addr *addr)
+{
+ int off;
+
+ off = snl_add_msg_attr_nested(nw, type);
+
+ snl_add_msg_attr_addr_wrap(nw, PF_RAT_ADDR, &addr->addr);
+ snl_add_msg_attr_u16(nw, PF_RAT_SRC_PORT, addr->port[0]);
+ snl_add_msg_attr_u16(nw, PF_RAT_DST_PORT, addr->port[1]);
+ snl_add_msg_attr_u8(nw, PF_RAT_NEG, addr->neg);
+ snl_add_msg_attr_u8(nw, PF_RAT_OP, addr->port_op);
+
+ snl_end_attr_nested(nw, off);
+}
+
+static void
+snl_add_msg_attr_rule_labels(struct snl_writer *nw, uint32_t type, const char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE])
+{
+ int off, i = 0;
+
+ off = snl_add_msg_attr_nested(nw, type);
+
+ while (labels[i][0] != 0 &&
+ i < PF_RULE_MAX_LABEL_COUNT) {
+ snl_add_msg_attr_string(nw, PF_LT_LABEL, labels[i]);
+ i++;
}
- nvlist_add_number(nvlr, "ridentifier", r->ridentifier);
- nvlist_add_string(nvlr, "ifname", r->ifname);
- nvlist_add_string(nvlr, "qname", r->qname);
- nvlist_add_string(nvlr, "pqname", r->pqname);
- nvlist_add_string(nvlr, "tagname", r->tagname);
- nvlist_add_string(nvlr, "match_tagname", r->match_tagname);
- nvlist_add_string(nvlr, "overload_tblname", r->overload_tblname);
+ snl_end_attr_nested(nw, off);
+}
+
+static void
+snl_add_msg_attr_mape(struct snl_writer *nw, uint32_t type, const struct pf_mape_portset *me)
+{
+ int off;
+
+ off = snl_add_msg_attr_nested(nw, type);
+
+ snl_add_msg_attr_u8(nw, PF_MET_OFFSET, me->offset);
+ snl_add_msg_attr_u8(nw, PF_MET_PSID_LEN, me->psidlen);
+ snl_add_msg_attr_u16(nw, PF_MET_PSID, me->psid);
+
+ snl_end_attr_nested(nw, off);
+}
+
+static void
+snl_add_msg_attr_rpool(struct snl_writer *nw, uint32_t type, const struct pfctl_pool *pool)
+{
+ int off;
+
+ off = snl_add_msg_attr_nested(nw, type);
- pfctl_nv_add_pool(nvlr, "rpool", &r->rpool);
+ snl_add_msg_attr(nw, PF_PT_KEY, sizeof(pool->key), &pool->key);
+ snl_add_msg_attr_ip6(nw, PF_PT_COUNTER, &pool->counter.v6);
+ snl_add_msg_attr_u32(nw, PF_PT_TBLIDX, pool->tblidx);
+ snl_add_msg_attr_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
+ snl_add_msg_attr_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
+ snl_add_msg_attr_u8(nw, PF_PT_OPTS, pool->opts);
+ snl_add_msg_attr_mape(nw, PF_PT_MAPE, &pool->mape);
- nvlist_add_number(nvlr, "os_fingerprint", r->os_fingerprint);
+ snl_end_attr_nested(nw, off);
+}
+
+static void
+snl_add_msg_attr_timeouts(struct snl_writer *nw, uint32_t type, const uint32_t *timeouts)
+{
+ int off;
+
+ off = snl_add_msg_attr_nested(nw, type);
- nvlist_add_number(nvlr, "rtableid", r->rtableid);
for (int i = 0; i < PFTM_MAX; i++)
- timeouts[i] = r->timeout[i];
- nvlist_add_number_array(nvlr, "timeout", timeouts, PFTM_MAX);
- nvlist_add_number(nvlr, "max_states", r->max_states);
- nvlist_add_number(nvlr, "max_src_nodes", r->max_src_nodes);
- nvlist_add_number(nvlr, "max_src_states", r->max_src_states);
- nvlist_add_number(nvlr, "max_src_conn", r->max_src_conn);
- nvlist_add_number(nvlr, "max_src_conn_rate.limit",
- r->max_src_conn_rate.limit);
- nvlist_add_number(nvlr, "max_src_conn_rate.seconds",
- r->max_src_conn_rate.seconds);
- nvlist_add_number(nvlr, "dnpipe", r->dnpipe);
- nvlist_add_number(nvlr, "dnrpipe", r->dnrpipe);
- nvlist_add_number(nvlr, "dnflags", r->free_flags);
- nvlist_add_number(nvlr, "prob", r->prob);
- nvlist_add_number(nvlr, "cuid", r->cuid);
- nvlist_add_number(nvlr, "cpid", r->cpid);
-
- nvlist_add_number(nvlr, "return_icmp", r->return_icmp);
- nvlist_add_number(nvlr, "return_icmp6", r->return_icmp6);
-
- nvlist_add_number(nvlr, "max_mss", r->max_mss);
- nvlist_add_number(nvlr, "scrub_flags", r->scrub_flags);
-
- pfctl_nv_add_uid(nvlr, "uid", &r->uid);
- pfctl_nv_add_uid(nvlr, "gid", (const struct pf_rule_uid *)&r->gid);
-
- nvlist_add_number(nvlr, "rule_flag", r->rule_flag);
- nvlist_add_number(nvlr, "action", r->action);
- nvlist_add_number(nvlr, "direction", r->direction);
- nvlist_add_number(nvlr, "log", r->log);
- nvlist_add_number(nvlr, "logif", r->logif);
- nvlist_add_number(nvlr, "quick", r->quick);
- nvlist_add_number(nvlr, "ifnot", r->ifnot);
- nvlist_add_number(nvlr, "match_tag_not", r->match_tag_not);
- nvlist_add_number(nvlr, "natpass", r->natpass);
-
- nvlist_add_number(nvlr, "keep_state", r->keep_state);
- nvlist_add_number(nvlr, "af", r->af);
- nvlist_add_number(nvlr, "proto", r->proto);
- nvlist_add_number(nvlr, "type", r->type);
- nvlist_add_number(nvlr, "code", r->code);
- nvlist_add_number(nvlr, "flags", r->flags);
- nvlist_add_number(nvlr, "flagset", r->flagset);
- nvlist_add_number(nvlr, "min_ttl", r->min_ttl);
- nvlist_add_number(nvlr, "allow_opts", r->allow_opts);
- nvlist_add_number(nvlr, "rt", r->rt);
- nvlist_add_number(nvlr, "return_ttl", r->return_ttl);
- nvlist_add_number(nvlr, "tos", r->tos);
- nvlist_add_number(nvlr, "set_tos", r->set_tos);
- nvlist_add_number(nvlr, "anchor_relative", r->anchor_relative);
- nvlist_add_number(nvlr, "anchor_wildcard", r->anchor_wildcard);
-
- nvlist_add_number(nvlr, "flush", r->flush);
-
- nvlist_add_number(nvlr, "prio", r->prio);
- set_prio[0] = r->set_prio[0];
- set_prio[1] = r->set_prio[1];
- nvlist_add_number_array(nvlr, "set_prio", set_prio, 2);
-
- pfctl_nv_add_divert(nvlr, "divert", r);
-
- nvlist_add_nvlist(nvl, "rule", nvlr);
- nvlist_destroy(nvlr);
-
- /* Now do the call. */
- nv.data = nvlist_pack(nvl, &nv.len);
- nv.size = nv.len;
+ snl_add_msg_attr_u32(nw, PF_TT_TIMEOUT, timeouts[i]);
- ret = ioctl(dev, DIOCADDRULENV, &nv);
- if (ret == -1)
- ret = errno;
+ snl_end_attr_nested(nw, off);
+}
- free(nv.data);
- nvlist_destroy(nvl);
+static void
+snl_add_msg_attr_uid(struct snl_writer *nw, uint32_t type, const struct pf_rule_uid *uid)
+{
+ int off;
- return (ret);
+ off = snl_add_msg_attr_nested(nw, type);
+
+ snl_add_msg_attr_u32(nw, PF_RUT_UID_LOW, uid->uid[0]);
+ snl_add_msg_attr_u32(nw, PF_RUT_UID_HIGH, uid->uid[1]);
+ snl_add_msg_attr_u8(nw, PF_RUT_OP, uid->op);
+
+ snl_end_attr_nested(nw, off);
+}
+
+static void
+snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfctl_rule *r)
+{
+ int off;
+
+ off = snl_add_msg_attr_nested(nw, type);
+
+ snl_add_msg_attr_rule_addr(nw, PF_RT_SRC, &r->src);
+ snl_add_msg_attr_rule_addr(nw, PF_RT_DST, &r->dst);
+ snl_add_msg_attr_rule_labels(nw, PF_RT_LABELS, r->label);
+ snl_add_msg_attr_u32(nw, PF_RT_RIDENTIFIER, r->ridentifier);
+ snl_add_msg_attr_string(nw, PF_RT_IFNAME, r->ifname);
+ snl_add_msg_attr_string(nw, PF_RT_QNAME, r->qname);
+ snl_add_msg_attr_string(nw, PF_RT_PQNAME, r->pqname);
+ snl_add_msg_attr_string(nw, PF_RT_TAGNAME, r->tagname);
+ snl_add_msg_attr_string(nw, PF_RT_MATCH_TAGNAME, r->match_tagname);
+ snl_add_msg_attr_string(nw, PF_RT_OVERLOAD_TBLNAME, r->overload_tblname);
+ snl_add_msg_attr_rpool(nw, PF_RT_RPOOL, &r->rpool);
+ snl_add_msg_attr_u32(nw, PF_RT_OS_FINGERPRINT, r->os_fingerprint);
+ snl_add_msg_attr_u32(nw, PF_RT_RTABLEID, r->rtableid);
+ snl_add_msg_attr_timeouts(nw, PF_RT_TIMEOUT, r->timeout);
+ snl_add_msg_attr_u32(nw, PF_RT_MAX_STATES, r->max_states);
+ snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_NODES, r->max_src_nodes);
+ snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_STATES, r->max_src_states);
+ snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, r->max_src_conn_rate.limit);
+ snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, r->max_src_conn_rate.seconds);
+
+ snl_add_msg_attr_u16(nw, PF_RT_DNPIPE, r->dnpipe);
+ snl_add_msg_attr_u16(nw, PF_RT_DNRPIPE, r->dnrpipe);
+ snl_add_msg_attr_u32(nw, PF_RT_DNFLAGS, r->free_flags);
+
+ snl_add_msg_attr_u32(nw, PF_RT_NR, r->nr);
+ snl_add_msg_attr_u32(nw, PF_RT_PROB, r->prob);
+ snl_add_msg_attr_u32(nw, PF_RT_CUID, r->cuid);
+ snl_add_msg_attr_u32(nw, PF_RT_CPID, r->cpid);
+
+ snl_add_msg_attr_u16(nw, PF_RT_RETURN_ICMP, r->return_icmp);
+ snl_add_msg_attr_u16(nw, PF_RT_RETURN_ICMP6, r->return_icmp6);
+ snl_add_msg_attr_u16(nw, PF_RT_MAX_MSS, r->max_mss);
+ snl_add_msg_attr_u16(nw, PF_RT_SCRUB_FLAGS, r->scrub_flags);
+
+ snl_add_msg_attr_uid(nw, PF_RT_UID, &r->uid);
+ snl_add_msg_attr_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&r->gid);
+
+ snl_add_msg_attr_u32(nw, PF_RT_RULE_FLAG, r->rule_flag);
+ snl_add_msg_attr_u8(nw, PF_RT_ACTION, r->action);
+ snl_add_msg_attr_u8(nw, PF_RT_DIRECTION, r->direction);
+ snl_add_msg_attr_u8(nw, PF_RT_LOG, r->log);
+ snl_add_msg_attr_u8(nw, PF_RT_LOGIF, r->logif);
+ snl_add_msg_attr_u8(nw, PF_RT_QUICK, r->quick);
+ snl_add_msg_attr_u8(nw, PF_RT_IF_NOT, r->ifnot);
+ snl_add_msg_attr_u8(nw, PF_RT_MATCH_TAG_NOT, r->match_tag_not);
+ snl_add_msg_attr_u8(nw, PF_RT_NATPASS, r->natpass);
+ snl_add_msg_attr_u8(nw, PF_RT_KEEP_STATE, r->keep_state);
+ snl_add_msg_attr_u8(nw, PF_RT_AF, r->af);
+ snl_add_msg_attr_u8(nw, PF_RT_PROTO, r->proto);
+ snl_add_msg_attr_u8(nw, PF_RT_TYPE, r->type);
+ snl_add_msg_attr_u8(nw, PF_RT_CODE, r->code);
+ snl_add_msg_attr_u8(nw, PF_RT_FLAGS, r->flags);
+ snl_add_msg_attr_u8(nw, PF_RT_FLAGSET, r->flagset);
+ snl_add_msg_attr_u8(nw, PF_RT_MIN_TTL, r->min_ttl);
+ snl_add_msg_attr_u8(nw, PF_RT_ALLOW_OPTS, r->allow_opts);
+ snl_add_msg_attr_u8(nw, PF_RT_RT, r->rt);
+ snl_add_msg_attr_u8(nw, PF_RT_RETURN_TTL, r->return_ttl);
+ snl_add_msg_attr_u8(nw, PF_RT_TOS, r->tos);
+ snl_add_msg_attr_u8(nw, PF_RT_SET_TOS, r->set_tos);
+
+ snl_add_msg_attr_u8(nw, PF_RT_ANCHOR_RELATIVE, r->anchor_relative);
+ snl_add_msg_attr_u8(nw, PF_RT_ANCHOR_WILDCARD, r->anchor_wildcard);
+ snl_add_msg_attr_u8(nw, PF_RT_FLUSH, r->flush);
+ snl_add_msg_attr_u8(nw, PF_RT_PRIO, r->prio);
+ snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO, r->set_prio[0]);
+ snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO_REPLY, r->set_prio[1]);
+
+ snl_add_msg_attr_ip6(nw, PF_RT_DIVERT_ADDRESS, &r->divert.addr.v6);
+ snl_add_msg_attr_u16(nw, PF_RT_DIVERT_PORT, r->divert.port);
+
+ snl_end_attr_nested(nw, off);
+}
+
+int
+pfctl_add_rule(int dev __unused, const struct pfctl_rule *r, const char *anchor,
+ const char *anchor_call, uint32_t ticket, uint32_t pool_ticket)
+{
+ struct snl_writer nw;
+ struct snl_state ss = {};
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+
+ snl_init(&ss, NETLINK_GENERIC);
+ family_id = snl_get_genl_family(&ss, PFNL_FAMILY_NAME);
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_ADDRULE);
+ hdr->nlmsg_flags |= NLM_F_DUMP;
+ snl_add_msg_attr_u32(&nw, PF_ART_TICKET, ticket);
+ snl_add_msg_attr_u32(&nw, PF_ART_POOL_TICKET, pool_ticket);
+ snl_add_msg_attr_string(&nw, PF_ART_ANCHOR, anchor);
+ snl_add_msg_attr_string(&nw, PF_ART_ANCHOR_CALL, anchor_call);
+
+ snl_add_msg_attr_pf_rule(&nw, PF_ART_RULE, r);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+
+ seq_id = hdr->nlmsg_seq;
+
+ if (! snl_send_message(&ss, hdr)) {
+ printf("Send failed\n");
+ return (ENXIO);
+ }
+
+ while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) {
+ }
+
+ return (e.error);
}
int
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index ec8f8293945b..b2aa1c450c50 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -2465,6 +2465,10 @@ int pf_keth_anchor_nvcopyout(
struct pf_keth_ruleset *pf_find_or_create_keth_ruleset(const char *);
void pf_keth_anchor_remove(struct pf_keth_rule *);
+int pf_ioctl_addrule(struct pf_krule *, uint32_t,
+ uint32_t, const char *, const char *, uid_t uid,
+ pid_t);
+
void pf_krule_free(struct pf_krule *);
#endif
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 38c09303a543..2eae03a908ec 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2016,10 +2016,10 @@ pf_rule_to_krule(const struct pf_rule *rule, struct pf_krule *krule)
return (0);
}
-static int
+int
pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
uint32_t pool_ticket, const char *anchor, const char *anchor_call,
- struct thread *td)
+ uid_t uid, pid_t pid)
{
struct pf_kruleset *ruleset;
struct pf_krule *tail;
@@ -2045,8 +2045,8 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
rule->states_cur = counter_u64_alloc(M_WAITOK);
rule->states_tot = counter_u64_alloc(M_WAITOK);
rule->src_nodes = counter_u64_alloc(M_WAITOK);
- rule->cuid = td->td_ucred->cr_ruid;
- rule->cpid = td->td_proc ? td->td_proc->p_pid : 0;
+ rule->cuid = uid;
+ rule->cpid = pid;
TAILQ_INIT(&rule->rpool.list);
PF_CONFIG_LOCK();
@@ -3076,7 +3076,8 @@ DIOCGETETHRULESET_error:
/* Frees rule on error */
error = pf_ioctl_addrule(rule, ticket, pool_ticket, anchor,
- anchor_call, td);
+ anchor_call, td->td_ucred->cr_ruid,
+ td->td_proc ? td->td_proc->p_pid : 0);
nvlist_destroy(nvl);
free(nvlpacked, M_NVLIST);
@@ -3104,7 +3105,8 @@ DIOCADDRULENV_error:
/* Frees rule on error */
error = pf_ioctl_addrule(rule, pr->ticket, pr->pool_ticket,
- pr->anchor, pr->anchor_call, td);
+ pr->anchor, pr->anchor_call, td->td_ucred->cr_ruid,
+ td->td_proc ? td->td_proc->p_pid : 0);
break;
}
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index e079edcc166d..d5d294134b1f 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -348,7 +348,265 @@ pf_handle_stop(struct nlmsghdr *hdr __unused, struct nl_pstate *npt __unused)
return (pf_stop());
}
-static const struct nlhdr_parser *all_parsers[] = { &state_parser };
+#define _OUT(_field) offsetof(struct pf_addr_wrap, _field)
+static const struct nlattr_parser nla_p_addr_wrap[] = {
+ { .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = nlattr_get_in6_addr },
+ { .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = nlattr_get_in6_addr },
+ { .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = nlattr_get_chara },
+ { .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
+ { .type = PF_AT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
+ { .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = nlattr_get_uint8 },
+};
+NL_DECLARE_ATTR_PARSER(addr_wrap_parser, nla_p_addr_wrap);
+#undef _OUT
+
+#define _OUT(_field) offsetof(struct pf_rule_addr, _field)
+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_SRC_PORT, .off = _OUT(port[0]), .cb = nlattr_get_uint16 },
+ { .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = nlattr_get_uint16 },
+ { .type = PF_RAT_NEG, .off = _OUT(neg), .cb = nlattr_get_uint8 },
+ { .type = PF_RAT_OP, .off = _OUT(port_op), .cb = nlattr_get_uint8 },
+};
+NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
+#undef _OUT
+
+#define _OUT(_field) offsetof(struct pf_mape_portset, _field)
+static const struct nlattr_parser nla_p_mape_portset[] = {
+ { .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = nlattr_get_uint8 },
+ { .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = nlattr_get_uint8 },
+ {. type = PF_MET_PSID, .off = _OUT(psid), .cb = nlattr_get_uint16 },
+};
+NL_DECLARE_ATTR_PARSER(mape_portset_parser, nla_p_mape_portset);
+#undef _OUT
+
+struct nl_parsed_labels
+{
+ char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
+ uint32_t i;
+};
+
+static int
+nlattr_get_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt,
+ const void *arg, void *target)
+{
+ struct nl_parsed_labels *l = (struct nl_parsed_labels *)target;
+ int ret;
+
+ if (l->i >= PF_RULE_MAX_LABEL_COUNT)
+ return (E2BIG);
+
+ ret = nlattr_get_chara(nla, npt, (void *)PF_RULE_LABEL_SIZE,
+ l->labels[l->i]);
+ if (ret == 0)
+ l->i++;
+
+ return (ret);
+}
+
+#define _OUT(_field) offsetof(struct nl_parsed_labels, _field)
+static const struct nlattr_parser nla_p_labels[] = {
+ { .type = PF_LT_LABEL, .off = 0, .cb = nlattr_get_pf_rule_labels },
+};
+NL_DECLARE_ATTR_PARSER(rule_labels_parser, nla_p_labels);
+#undef _OUT
+
+static int
+nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
+{
+ struct nl_parsed_labels parsed_labels = { };
+ int error;
+
+ /* Assumes target points to the beginning of the structure */
+ error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, npt, &parsed_labels);
+ if (error != 0)
+ return (error);
+
+ memcpy(target, parsed_labels.labels, sizeof(parsed_labels));
+
+ return (0);
+}
+
+#define _OUT(_field) offsetof(struct pf_kpool, _field)
+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_COUNTER, .off = _OUT(counter), .cb = nlattr_get_in6_addr },
+ { .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = nlattr_get_uint32 },
+ { .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = nlattr_get_uint16 },
+ { .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = nlattr_get_uint16 },
+ { .type = PF_PT_OPTS, .off = _OUT(opts), .cb = nlattr_get_uint8 },
+ { .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = nlattr_get_nested },
+};
+NL_DECLARE_ATTR_PARSER(pool_parser, nla_p_pool);
+#undef _OUT
+
+#define _OUT(_field) offsetof(struct pf_rule_uid, _field)
+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_HIGH, .off = _OUT(uid[1]), .cb = nlattr_get_uint32 },
+ { .type = PF_RUT_OP, .off = _OUT(op), .cb = nlattr_get_uint8 },
+};
+NL_DECLARE_ATTR_PARSER(rule_uid_parser, nla_p_rule_uid);
+#undef _OUT
+
+struct nl_parsed_timeouts
+{
+ uint32_t timeouts[PFTM_MAX];
+ uint32_t i;
+};
+
+static int
+nlattr_get_pf_timeout(struct nlattr *nla, struct nl_pstate *npt,
+ const void *arg, void *target)
+{
+ struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
+ int ret;
+
+ if (t->i >= PFTM_MAX)
+ return (E2BIG);
+
+ ret = nlattr_get_uint32(nla, npt, NULL, &t->timeouts[t->i]);
+ if (ret == 0)
+ t->i++;
+
+ return (ret);
+}
+
+#define _OUT(_field) offsetof(struct nl_parsed_timeout, _field)
+static const struct nlattr_parser nla_p_timeouts[] = {
+ { .type = PF_TT_TIMEOUT, .off = 0, .cb = nlattr_get_pf_timeout },
+};
+NL_DECLARE_ATTR_PARSER(timeout_parser, nla_p_timeouts);
+#undef _OUT
+
+static int
+nlattr_get_nested_timeouts(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
+{
+ struct nl_parsed_timeouts parsed_timeouts = { };
+ int error;
+
+ /* Assumes target points to the beginning of the structure */
+ error = nl_parse_header(NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, npt, &parsed_timeouts);
+ if (error != 0)
+ return (error);
+
+ memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
+
+ return (0);
+}
+
+#define _OUT(_field) offsetof(struct pf_krule, _field)
+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_DST, .off = _OUT(dst), .arg = &rule_addr_parser,.cb = nlattr_get_nested },
+ { .type = PF_RT_RIDENTIFIER, .off = _OUT(ridentifier), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_LABELS, .off = _OUT(label), .arg = &rule_labels_parser,.cb = nlattr_get_nested_pf_rule_labels },
+ { .type = PF_RT_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
+ { .type = PF_RT_QNAME, .off = _OUT(qname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
+ { .type = PF_RT_PQNAME, .off = _OUT(pqname), .arg = (void *)PF_QNAME_SIZE, .cb = nlattr_get_chara },
+ { .type = PF_RT_TAGNAME, .off = _OUT(tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
+ { .type = PF_RT_MATCH_TAGNAME, .off = _OUT(match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = nlattr_get_chara },
+ { .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = nlattr_get_chara },
+ { .type = PF_RT_RPOOL, .off = _OUT(rpool), .arg = &pool_parser, .cb = nlattr_get_nested },
+ { .type = PF_RT_OS_FINGERPRINT, .off = _OUT(os_fingerprint), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_RTABLEID, .off = _OUT(rtableid), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_TIMEOUT, .off = _OUT(timeout), .arg = &timeout_parser, .cb = nlattr_get_nested_timeouts },
+ { .type = PF_RT_MAX_STATES, .off = _OUT(max_states), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_MAX_SRC_NODES, .off = _OUT(max_src_nodes), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_MAX_SRC_STATES, .off = _OUT(max_src_states), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(max_src_conn_rate.limit), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(max_src_conn_rate.seconds), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_DNPIPE, .off = _OUT(dnpipe), .cb = nlattr_get_uint16 },
+ { .type = PF_RT_DNRPIPE, .off = _OUT(dnrpipe), .cb = nlattr_get_uint16 },
+ { .type = PF_RT_DNFLAGS, .off = _OUT(free_flags), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_PROB, .off = _OUT(prob), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_CUID, .off = _OUT(cuid), .cb = nlattr_get_uint32 },
+ {. type = PF_RT_CPID, .off = _OUT(cpid), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_RETURN_ICMP, .off = _OUT(return_icmp), .cb = nlattr_get_uint16 },
+ { .type = PF_RT_RETURN_ICMP6, .off = _OUT(return_icmp6), .cb = nlattr_get_uint16 },
+ { .type = PF_RT_MAX_MSS, .off = _OUT(max_mss), .cb = nlattr_get_uint16 },
+ { .type = PF_RT_SCRUB_FLAGS, .off = _OUT(scrub_flags), .cb = nlattr_get_uint16 },
+ { .type = PF_RT_UID, .off = _OUT(uid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
+ { .type = PF_RT_GID, .off = _OUT(gid), .arg = &rule_uid_parser, .cb = nlattr_get_nested },
+ { .type = PF_RT_RULE_FLAG, .off = _OUT(rule_flag), .cb = nlattr_get_uint32 },
+ { .type = PF_RT_ACTION, .off = _OUT(action), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_LOG, .off = _OUT(log), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_LOGIF, .off = _OUT(logif), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_QUICK, .off = _OUT(quick), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_IF_NOT, .off = _OUT(ifnot), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(match_tag_not), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_NATPASS, .off = _OUT(natpass), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_KEEP_STATE, .off = _OUT(keep_state), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_TYPE, .off = _OUT(type), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_CODE, .off = _OUT(code), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_FLAGS, .off = _OUT(flags), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_FLAGSET, .off = _OUT(flagset), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_MIN_TTL, .off = _OUT(min_ttl), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_ALLOW_OPTS, .off = _OUT(allow_opts), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_RT, .off = _OUT(rt), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_RETURN_TTL, .off = _OUT(return_ttl), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_TOS, .off = _OUT(tos), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_SET_TOS, .off = _OUT(set_tos), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(anchor_relative), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(anchor_wildcard), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_FLUSH, .off = _OUT(flush), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_PRIO, .off = _OUT(prio), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_SET_PRIO, .off = _OUT(set_prio[0]), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(set_prio[1]), .cb = nlattr_get_uint8 },
+ { .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(divert.addr), .cb = nlattr_get_in6_addr },
+ { .type = PF_RT_DIVERT_PORT, .off = _OUT(divert.port), .cb = nlattr_get_uint16 },
+};
+NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
+#undef _OUT
+struct nl_parsed_addrule {
+ struct pf_krule *rule;
+ uint32_t ticket;
+ uint32_t pool_ticket;
+ char *anchor;
+ char *anchor_call;
+};
+#define _IN(_field) offsetof(struct genlmsghdr, _field)
+#define _OUT(_field) offsetof(struct nl_parsed_addrule, _field)
+static const struct nlattr_parser nla_p_addrule[] = {
+ { .type = PF_ART_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
+ { .type = PF_ART_POOL_TICKET, .off = _OUT(pool_ticket), .cb = nlattr_get_uint32 },
+ { .type = PF_ART_ANCHOR, .off = _OUT(anchor), .cb = nlattr_get_string },
+ { .type = PF_ART_ANCHOR_CALL, .off = _OUT(anchor_call), .cb = nlattr_get_string },
+ { .type = PF_ART_RULE, .off = _OUT(rule), .arg = &rule_parser, .cb = nlattr_get_nested_ptr }
+};
+static const struct nlfield_parser nlf_p_addrule[] = {
+};
+#undef _IN
+#undef _OUT
+NL_DECLARE_PARSER(addrule_parser, struct genlmsghdr, nlf_p_addrule, nla_p_addrule);
+
+static int
+pf_handle_addrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ int error;
+ struct nl_parsed_addrule attrs = {};
+
+ attrs.rule = pf_krule_alloc();
+
+ error = nl_parse_nlmsg(hdr, &addrule_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_ioctl_addrule(attrs.rule, attrs.ticket, attrs.pool_ticket,
+ attrs.anchor, attrs.anchor_call, nlp_get_cred(npt->nlp)->cr_uid,
+ hdr->nlmsg_pid);
+
+ if (error != 0)
+ pf_krule_free(attrs.rule);
+
+ return (error);
+}
+
+static const struct nlhdr_parser *all_parsers[] = { &state_parser, &addrule_parser };
static int family_id;
@@ -377,12 +635,20 @@ static const struct genl_cmd pf_cmds[] = {
.cmd_cb = pf_handle_stop,
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
},
+ {
+ .cmd_num = PFNL_CMD_ADDRULE,
+ .cmd_name = "ADDRULE",
+ .cmd_cb = pf_handle_addrule,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ },
+
};
void
pf_nl_register(void)
{
NL_VERIFY_PARSERS(all_parsers);
+
family_id = genl_register_family(PFNL_FAMILY_NAME, 0, 2, PFNL_CMD_MAX);
genl_register_cmds(PFNL_FAMILY_NAME, pf_cmds, NL_ARRAY_LEN(pf_cmds));
}
diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h
index 3c8c6d3b8ed4..d936044c0d7d 100644
--- a/sys/netpfil/pf/pf_nl.h
+++ b/sys/netpfil/pf/pf_nl.h
@@ -40,6 +40,7 @@ enum {
PFNL_CMD_GETCREATORS = 2,
PFNL_CMD_START = 3,
PFNL_CMD_STOP = 4,
+ PFNL_CMD_ADDRULE = 5,
__PFNL_CMD_MAX,
};
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
@@ -98,6 +99,137 @@ enum pfstate_type_t {
PF_ST_VERSION = 28, /* u64 */
};
+enum pf_addr_type_t {
+ PF_AT_UNSPEC,
+ PF_AT_ADDR = 1, /* in6_addr */
+ PF_AT_MASK = 2, /* in6_addr */
+ PF_AT_IFNAME = 3, /* string */
+ PF_AT_TABLENAME = 4, /* string */
+ PF_AT_TYPE = 5, /* u8 */
+ PF_AT_IFLAGS = 6, /* u8 */
+};
+
+enum pfrule_addr_type_t {
+ PF_RAT_UNSPEC,
+ PF_RAT_ADDR = 1, /* nested, pf_addr_type_t */
+ PF_RAT_SRC_PORT = 2, /* u16 */
+ PF_RAT_DST_PORT = 3, /* u16 */
+ PF_RAT_NEG = 4, /* u8 */
+ PF_RAT_OP = 5, /* u8 */
+};
+
+enum pf_labels_type_t {
+ PF_LT_UNSPEC,
+ PF_LT_LABEL = 1, /* string */
+};
+
+enum pf_mape_portset_type_t
+{
+ PF_MET_UNSPEC,
+ PF_MET_OFFSET = 1, /* u8 */
+ PF_MET_PSID_LEN = 2, /* u8 */
+ PF_MET_PSID = 3, /* u16 */
+};
+
+enum pf_rpool_type_t
+{
+ PF_PT_UNSPEC,
+ PF_PT_KEY = 1, /* bytes, sizeof(struct pf_poolhashkey) */
+ PF_PT_COUNTER = 2, /* in6_addr */
+ PF_PT_TBLIDX = 3, /* u32 */
+ PF_PT_PROXY_SRC_PORT = 4, /* u16 */
+ PF_PT_PROXY_DST_PORT = 5, /* u16 */
+ PF_PT_OPTS = 6, /* u8 */
+ PF_PT_MAPE = 7, /* nested, pf_mape_portset_type_t */
+};
+
+enum pf_timeout_type_t {
+ PF_TT_UNSPEC,
+ PF_TT_TIMEOUT = 1, /* u32 */
+};
+
+enum pf_rule_uid_type_t {
+ PF_RUT_UNSPEC,
+ PF_RUT_UID_LOW = 1, /* u32 */
+ PF_RUT_UID_HIGH = 2, /* u32 */
+ PF_RUT_OP = 3, /* u8 */
+};
+
+enum pf_rule_type_t {
+ PF_RT_UNSPEC,
+ PF_RT_SRC = 1, /* nested, pf_rule_addr_type_t */
+ PF_RT_DST = 2, /* nested, pf_rule_addr_type_t */
+ PF_RT_RIDENTIFIER = 3, /* u32 */
+ PF_RT_LABELS = 4, /* nested, pf_labels_type_t */
+ PF_RT_IFNAME = 5, /* string */
+ PF_RT_QNAME = 6, /* string */
+ PF_RT_PQNAME = 7, /* string */
+ PF_RT_TAGNAME = 8, /* string */
+ PF_RT_MATCH_TAGNAME = 9, /* string */
+ PF_RT_OVERLOAD_TBLNAME = 10, /* string */
+ PF_RT_RPOOL = 11, /* nested, pf_rpool_type_t */
+ PF_RT_OS_FINGERPRINT = 12, /* u32 */
+ PF_RT_RTABLEID = 13, /* u32 */
+ PF_RT_TIMEOUT = 14, /* nested, pf_timeout_type_t */
+ PF_RT_MAX_STATES = 15, /* u32 */
+ PF_RT_MAX_SRC_NODES = 16, /* u32 */
+ PF_RT_MAX_SRC_STATES = 17, /* u32 */
+ PF_RT_MAX_SRC_CONN_RATE_LIMIT = 18, /* u32 */
+ PF_RT_MAX_SRC_CONN_RATE_SECS = 19, /* u32 */
+ PF_RT_DNPIPE = 20, /* u16 */
+ PF_RT_DNRPIPE = 21, /* u16 */
+ PF_RT_DNFLAGS = 22, /* u32 */
+ PF_RT_NR = 23, /* u32 */
+ PF_RT_PROB = 24, /* u32 */
+ PF_RT_CUID = 25, /* u32 */
+ PF_RT_CPID = 26, /* u32 */
+ PF_RT_RETURN_ICMP = 27, /* u16 */
+ PF_RT_RETURN_ICMP6 = 28, /* u16 */
+ PF_RT_MAX_MSS = 29, /* u16 */
+ PF_RT_SCRUB_FLAGS = 30, /* u16 */
+ PF_RT_UID = 31, /* nested, pf_rule_uid_type_t */
+ PF_RT_GID = 32, /* nested, pf_rule_uid_type_t */
+ PF_RT_RULE_FLAG = 33, /* u32 */
+ PF_RT_ACTION = 34, /* u8 */
+ PF_RT_DIRECTION = 35, /* u8 */
+ PF_RT_LOG = 36, /* u8 */
+ PF_RT_LOGIF = 37, /* u8 */
+ PF_RT_QUICK = 38, /* u8 */
+ PF_RT_IF_NOT = 39, /* u8 */
+ PF_RT_MATCH_TAG_NOT = 40, /* u8 */
+ PF_RT_NATPASS = 41, /* u8 */
+ PF_RT_KEEP_STATE = 42, /* u8 */
+ PF_RT_AF = 43, /* u8 */
+ PF_RT_PROTO = 44, /* u8 */
+ PF_RT_TYPE = 45, /* u8 */
+ PF_RT_CODE = 46, /* u8 */
+ PF_RT_FLAGS = 47, /* u8 */
+ PF_RT_FLAGSET = 48, /* u8 */
+ PF_RT_MIN_TTL = 49, /* u8 */
+ PF_RT_ALLOW_OPTS = 50, /* u8 */
+ PF_RT_RT = 51, /* u8 */
+ PF_RT_RETURN_TTL = 52, /* u8 */
+ PF_RT_TOS = 53, /* u8 */
+ PF_RT_SET_TOS = 54, /* u8 */
+ PF_RT_ANCHOR_RELATIVE = 55, /* u8 */
+ PF_RT_ANCHOR_WILDCARD = 56, /* u8 */
+ PF_RT_FLUSH = 57, /* u8 */
+ PF_RT_PRIO = 58, /* u8 */
+ PF_RT_SET_PRIO = 59, /* u8 */
+ PF_RT_SET_PRIO_REPLY = 60, /* u8 */
+ PF_RT_DIVERT_ADDRESS = 61, /* in6_addr */
+ PF_RT_DIVERT_PORT = 62, /* u16 */
+};
+
+enum pf_addrule_type_t {
+ PF_ART_UNSPEC,
+ PF_ART_TICKET = 1, /* u32 */
+ PF_ART_POOL_TICKET = 2, /* u32 */
+ PF_ART_ANCHOR = 3, /* string */
+ PF_ART_ANCHOR_CALL = 4, /* string */
+ PF_ART_RULE = 5, /* nested, pfrule_type_t */
+};
+
#ifdef _KERNEL
void pf_nl_register(void);