The branch main has been updated by kp:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=ffbf25951e7b7f867989b621b2c07e9dad9441fb

commit ffbf25951e7b7f867989b621b2c07e9dad9441fb
Author:     Kristof Provost <[email protected]>
AuthorDate: 2023-10-14 13:10:03 +0000
Commit:     Kristof Provost <[email protected]>
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);

Reply via email to