aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil/pf/pf_nl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netpfil/pf/pf_nl.c')
-rw-r--r--sys/netpfil/pf/pf_nl.c660
1 files changed, 637 insertions, 23 deletions
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index 5f33e49b4a2e..510aac2af48a 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -26,6 +26,9 @@
* SUCH DAMAGE.
*
*/
+#include <sys/cdefs.h>
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/malloc.h>
@@ -145,6 +148,8 @@ dump_state(struct nlpcb *nlp, const struct nlmsghdr *hdr, struct pf_kstate *s,
int af;
struct pf_state_key *key;
+ PF_STATE_LOCK_ASSERT(s);
+
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
goto enomem;
@@ -226,7 +231,7 @@ handle_dumpstates(struct nlpcb *nlp, struct nl_parsed_state *attrs,
hdr->nlmsg_flags |= NLM_F_MULTI;
- for (int i = 0; i <= pf_hashmask; i++) {
+ for (int i = 0; i <= V_pf_hashmask; i++) {
struct pf_idhash *ih = &V_pf_idhash[i];
struct pf_kstate *s;
@@ -279,10 +284,16 @@ static int
handle_getstate(struct nlpcb *nlp, struct nl_parsed_state *attrs,
struct nlmsghdr *hdr, struct nl_pstate *npt)
{
- struct pf_kstate *s = pf_find_state_byid(attrs->id, attrs->creatorid);
+ struct pf_kstate *s;
+ int ret;
+
+ s = pf_find_state_byid(attrs->id, attrs->creatorid);
if (s == NULL)
return (ENOENT);
- return (dump_state(nlp, hdr, s, npt));
+ ret = dump_state(nlp, hdr, s, npt);
+ PF_STATE_UNLOCK(s);
+
+ return (ret);
}
static int
@@ -335,7 +346,7 @@ pf_handle_getcreators(struct nlmsghdr *hdr, struct nl_pstate *npt)
bzero(creators, sizeof(creators));
- for (int i = 0; i < pf_hashmask; i++) {
+ for (int i = 0; i < V_pf_hashmask; i++) {
struct pf_idhash *ih = &V_pf_idhash[i];
struct pf_kstate *s;
@@ -405,7 +416,6 @@ 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);
@@ -414,22 +424,10 @@ nlattr_add_addr_wrap(struct nl_writer *nw, int attrtype, struct pf_addr_wrap *a)
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);
+ nlattr_add_u32(nw, PF_AT_DYNCNT, a->p.dyncnt);
} 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_add_u32(nw, PF_AT_TBLCNT, a->p.tblcnt);
}
nlattr_set_len(nw, off);
@@ -451,9 +449,13 @@ NL_DECLARE_ATTR_PARSER(rule_addr_parser, nla_p_ruleaddr);
static bool
nlattr_add_rule_addr(struct nl_writer *nw, int attrtype, struct pf_rule_addr *r)
{
+ struct pf_addr_wrap aw = {0};
int off = nlattr_add_nested(nw, attrtype);
- nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &r->addr);
+ bcopy(&(r->addr), &aw, sizeof(struct pf_addr_wrap));
+ pf_addr_copyout(&aw);
+
+ nlattr_add_addr_wrap(nw, PF_RAT_ADDR, &aw);
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);
@@ -529,7 +531,7 @@ nlattr_get_nested_pf_rule_labels(struct nlattr *nla, struct nl_pstate *npt, cons
if (error != 0)
return (error);
- memcpy(target, parsed_labels.labels, sizeof(parsed_labels));
+ memcpy(target, parsed_labels.labels, sizeof(parsed_labels.labels));
return (0);
}
@@ -728,6 +730,7 @@ static const struct nlattr_parser nla_p_rule[] = {
{ .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 },
+ { .type = PF_RT_RCV_IFNAME, .off = _OUT(rcv_ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
};
NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
#undef _OUT
@@ -939,6 +942,8 @@ pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
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_string(nw, PF_RT_RCV_IFNAME, rule->rcv_ifname);
+
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);
@@ -982,7 +987,7 @@ pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
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);
+ error = pf_kanchor_copyout(ruleset, rule, anchor_call, sizeof(anchor_call));
MPASS(error == 0);
nlattr_add_string(nw, PF_RT_ANCHOR_CALL, anchor_call);
@@ -1109,12 +1114,537 @@ pf_handle_set_statusif(struct nlmsghdr *hdr, struct nl_pstate *npt)
return (0);
}
+static bool
+nlattr_add_counters(struct nl_writer *nw, int attr, size_t number, char **names,
+ counter_u64_t *counters)
+{
+ for (int i = 0; i < number; i++) {
+ int off = nlattr_add_nested(nw, attr);
+ nlattr_add_u32(nw, PF_C_ID, i);
+ nlattr_add_string(nw, PF_C_NAME, names[i]);
+ nlattr_add_u64(nw, PF_C_COUNTER, counter_u64_fetch(counters[i]));
+ nlattr_set_len(nw, off);
+ }
+
+ return (true);
+}
+
+static bool
+nlattr_add_fcounters(struct nl_writer *nw, int attr, size_t number, char **names,
+ struct pf_counter_u64 *counters)
+{
+ for (int i = 0; i < number; i++) {
+ int off = nlattr_add_nested(nw, attr);
+ nlattr_add_u32(nw, PF_C_ID, i);
+ nlattr_add_string(nw, PF_C_NAME, names[i]);
+ nlattr_add_u64(nw, PF_C_COUNTER, pf_counter_u64_fetch(&counters[i]));
+ nlattr_set_len(nw, off);
+ }
+
+ return (true);
+}
+
+static bool
+nlattr_add_u64_array(struct nl_writer *nw, int attr, size_t number, uint64_t *array)
+{
+ int off = nlattr_add_nested(nw, attr);
+
+ for (size_t i = 0; i < number; i++)
+ nlattr_add_u64(nw, 0, array[i]);
+
+ nlattr_set_len(nw, off);
+
+ return (true);
+}
+
+static int
+pf_handle_get_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_status s;
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES;
+ char *pf_lcounter[KLCNT_MAX+1] = KLCNT_NAMES;
+ char *pf_fcounter[FCNT_MAX+1] = FCNT_NAMES;
+ int error;
+
+ PF_RULES_RLOCK_TRACKER;
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr)))
+ return (ENOMEM);
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = PFNL_CMD_GET_STATUS;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ PF_RULES_RLOCK();
+
+ nlattr_add_string(nw, PF_GS_IFNAME, V_pf_status.ifname);
+ nlattr_add_bool(nw, PF_GS_RUNNING, V_pf_status.running);
+ nlattr_add_u32(nw, PF_GS_SINCE, V_pf_status.since);
+ nlattr_add_u32(nw, PF_GS_DEBUG, V_pf_status.debug);
+ nlattr_add_u32(nw, PF_GS_HOSTID, ntohl(V_pf_status.hostid));
+ nlattr_add_u32(nw, PF_GS_STATES, V_pf_status.states);
+ nlattr_add_u32(nw, PF_GS_SRC_NODES, V_pf_status.src_nodes);
+ nlattr_add_u32(nw, PF_GS_REASSEMBLE, V_pf_status.reass);
+ nlattr_add_u32(nw, PF_GS_SYNCOOKIES_ACTIVE, V_pf_status.syncookies_active);
+
+ nlattr_add_counters(nw, PF_GS_COUNTERS, PFRES_MAX, pf_reasons,
+ V_pf_status.counters);
+ nlattr_add_counters(nw, PF_GS_LCOUNTERS, KLCNT_MAX, pf_lcounter,
+ V_pf_status.lcounters);
+ nlattr_add_fcounters(nw, PF_GS_FCOUNTERS, FCNT_MAX, pf_fcounter,
+ V_pf_status.fcounters);
+ nlattr_add_counters(nw, PF_GS_SCOUNTERS, SCNT_MAX, pf_fcounter,
+ V_pf_status.scounters);
+
+ pfi_update_status(V_pf_status.ifname, &s);
+ nlattr_add_u64_array(nw, PF_GS_BCOUNTERS, 2 * 2, (uint64_t *)s.bcounters);
+ nlattr_add_u64_array(nw, PF_GS_PCOUNTERS, 2 * 2 * 2, (uint64_t *)s.pcounters);
+
+ nlattr_add(nw, PF_GS_CHKSUM, PF_MD5_DIGEST_LENGTH, V_pf_status.pf_chksum);
+
+ PF_RULES_RUNLOCK();
+
+ if (!nlmsg_end(nw)) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ return (0);
+
+out:
+ nlmsg_abort(nw);
+ return (error);
+}
+
+static int
+pf_handle_clear_status(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ pf_ioctl_clear_status();
+
+ return (0);
+}
+
+struct pf_nl_natlook {
+ sa_family_t af;
+ uint8_t direction;
+ uint8_t proto;
+ struct pf_addr src;
+ struct pf_addr dst;
+ uint16_t sport;
+ uint16_t dport;
+};
+
+#define _IN(_field) offsetof(struct genlmsghdr, _field)
+#define _OUT(_field) offsetof(struct pf_nl_natlook, _field)
+static const struct nlattr_parser nla_p_natlook[] = {
+ { .type = PF_NL_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
+ { .type = PF_NL_DIRECTION, .off = _OUT(direction), .cb = nlattr_get_uint8 },
+ { .type = PF_NL_PROTO, .off = _OUT(proto), .cb = nlattr_get_uint8 },
+ { .type = PF_NL_SRC_ADDR, .off = _OUT(src), .cb = nlattr_get_in6_addr },
+ { .type = PF_NL_DST_ADDR, .off = _OUT(dst), .cb = nlattr_get_in6_addr },
+ { .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = nlattr_get_uint16 },
+ { .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = nlattr_get_uint16 },
+};
+static const struct nlfield_parser nlf_p_natlook[] = {};
+#undef _IN
+#undef _OUT
+NL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, nlf_p_natlook, nla_p_natlook);
+
+static int
+pf_handle_natlook(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_nl_natlook attrs = {};
+ struct pf_state_key_cmp key = {};
+ struct nl_writer *nw = npt->nw;
+ struct pf_state_key *sk;
+ struct pf_kstate *state;
+ struct genlmsghdr *ghdr_new;
+ int error, m;
+ int sidx, didx;
+
+ error = nl_parse_nlmsg(hdr, &natlook_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ if (attrs.proto == 0 ||
+ PF_AZERO(&attrs.src, attrs.af) ||
+ PF_AZERO(&attrs.dst, attrs.af) ||
+ ((attrs.proto == IPPROTO_TCP || attrs.proto == IPPROTO_UDP) &&
+ (attrs.sport == 0 || attrs.dport == 0)))
+ return (EINVAL);
+
+ /* NATLOOK src and dst are reversed, so reverse sidx/didx */
+ sidx = (attrs.direction == PF_IN) ? 1 : 0;
+ didx = (attrs.direction == PF_IN) ? 0 : 1;
+
+ key.af = attrs.af;
+ key.proto = attrs.proto;
+ PF_ACPY(&key.addr[sidx], &attrs.src, attrs.af);
+ key.port[sidx] = attrs.sport;
+ PF_ACPY(&key.addr[didx], &attrs.dst, attrs.af);
+ key.port[didx] = attrs.dport;
+
+ state = pf_find_state_all(&key, attrs.direction, &m);
+ if (state == NULL)
+ return (ENOENT);
+ if (m > 1) {
+ PF_STATE_UNLOCK(state);
+ return (E2BIG);
+ }
+
+ if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
+ PF_STATE_UNLOCK(state);
+ return (ENOMEM);
+ }
+
+ ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
+ ghdr_new->cmd = PFNL_CMD_NATLOOK;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ sk = state->key[sidx];
+
+ nlattr_add_in6_addr(nw, PF_NL_SRC_ADDR, &sk->addr[sidx].v6);
+ nlattr_add_in6_addr(nw, PF_NL_DST_ADDR, &sk->addr[didx].v6);
+ nlattr_add_u16(nw, PF_NL_SRC_PORT, sk->port[sidx]);
+ nlattr_add_u16(nw, PF_NL_DST_PORT, sk->port[didx]);
+
+ PF_STATE_UNLOCK(state);
+
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
+
+struct pf_nl_set_debug
+{
+ uint32_t level;
+};
+#define _OUT(_field) offsetof(struct pf_nl_set_debug, _field)
+static const struct nlattr_parser nla_p_set_debug[] = {
+ { .type = PF_SD_LEVEL, .off = _OUT(level), .cb = nlattr_get_uint32 },
+};
+static const struct nlfield_parser nlf_p_set_debug[] = {};
+#undef _OUT
+NL_DECLARE_PARSER(set_debug_parser, struct genlmsghdr, nlf_p_set_debug, nla_p_set_debug);
+
+static int
+pf_handle_set_debug(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_nl_set_debug attrs = {};
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &set_debug_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ PF_RULES_WLOCK();
+ V_pf_status.debug = attrs.level;
+ PF_RULES_WUNLOCK();
+
+ return (0);
+}
+
+struct pf_nl_set_timeout
+{
+ uint32_t timeout;
+ uint32_t seconds;
+};
+#define _OUT(_field) offsetof(struct pf_nl_set_timeout, _field)
+static const struct nlattr_parser nla_p_set_timeout[] = {
+ { .type = PF_TO_TIMEOUT, .off = _OUT(timeout), .cb = nlattr_get_uint32 },
+ { .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = nlattr_get_uint32 },
+};
+static const struct nlfield_parser nlf_p_set_timeout[] = {};
+#undef _OUT
+NL_DECLARE_PARSER(set_timeout_parser, struct genlmsghdr, nlf_p_set_timeout, nla_p_set_timeout);
+
+static int
+pf_handle_set_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_nl_set_timeout attrs = {};
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ return (pf_ioctl_set_timeout(attrs.timeout, attrs.seconds, NULL));
+}
+
+static int
+pf_handle_get_timeout(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_nl_set_timeout attrs = {};
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &set_timeout_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_ioctl_get_timeout(attrs.timeout, &attrs.seconds);
+ 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_GET_TIMEOUT;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ nlattr_add_u32(nw, PF_TO_SECONDS, attrs.seconds);
+
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
+
+struct pf_nl_set_limit
+{
+ uint32_t index;
+ uint32_t limit;
+};
+#define _OUT(_field) offsetof(struct pf_nl_set_limit, _field)
+static const struct nlattr_parser nla_p_set_limit[] = {
+ { .type = PF_LI_INDEX, .off = _OUT(index), .cb = nlattr_get_uint32 },
+ { .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = nlattr_get_uint32 },
+};
+static const struct nlfield_parser nlf_p_set_limit[] = {};
+#undef _OUT
+NL_DECLARE_PARSER(set_limit_parser, struct genlmsghdr, nlf_p_set_limit, nla_p_set_limit);
+
+static int
+pf_handle_set_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_nl_set_limit attrs = {};
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ return (pf_ioctl_set_limit(attrs.index, attrs.limit, NULL));
+}
+
+static int
+pf_handle_get_limit(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pf_nl_set_limit attrs = {};
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &set_limit_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_ioctl_get_limit(attrs.index, &attrs.limit);
+ 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_GET_LIMIT;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ nlattr_add_u32(nw, PF_LI_LIMIT, attrs.limit);
+
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
+
+static int
+pf_handle_begin_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ uint32_t ticket;
+ int error;
+
+ error = pf_ioctl_begin_addrs(&ticket);
+ 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_BEGIN_ADDRS;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ nlattr_add_u32(nw, PF_BA_TICKET, ticket);
+
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
+
+static bool
+nlattr_add_pool_addr(struct nl_writer *nw, int attrtype, struct pf_pooladdr *a)
+{
+ int off;
+
+ off = nlattr_add_nested(nw, attrtype);
+
+ nlattr_add_addr_wrap(nw, PF_PA_ADDR, &a->addr);
+ nlattr_add_string(nw, PF_PA_IFNAME, a->ifname);
+
+ nlattr_set_len(nw, off);
+
+ return (true);
+}
+
+#define _OUT(_field) offsetof(struct pf_pooladdr, _field)
+static const struct nlattr_parser nla_p_pool_addr[] = {
+ { .type = PF_PA_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = nlattr_get_nested },
+ { .type = PF_PA_IFNAME, .off = _OUT(ifname), .arg = (void *)IFNAMSIZ, .cb = nlattr_get_chara },
+};
+NL_DECLARE_ATTR_PARSER(pool_addr_parser, nla_p_pool_addr);
+#undef _OUT
+
+#define _OUT(_field) offsetof(struct pfioc_pooladdr, _field)
+static const struct nlattr_parser nla_p_add_addr[] = {
+ { .type = PF_AA_ACTION, .off = _OUT(action), .cb = nlattr_get_uint32 },
+ { .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = nlattr_get_uint32 },
+ { .type = PF_AA_NR, .off = _OUT(nr), .cb = nlattr_get_uint32 },
+ { .type = PF_AA_R_NUM, .off = _OUT(r_num), .cb = nlattr_get_uint32 },
+ { .type = PF_AA_R_ACTION, .off = _OUT(r_action), .cb = nlattr_get_uint8 },
+ { .type = PF_AA_R_LAST, .off = _OUT(r_last), .cb = nlattr_get_uint8 },
+ { .type = PF_AA_AF, .off = _OUT(af), .cb = nlattr_get_uint8 },
+ { .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg = (void *)MAXPATHLEN, .cb = nlattr_get_chara },
+ { .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = nlattr_get_nested },
+};
+static const struct nlfield_parser nlf_p_add_addr[] = {};
+#undef _OUT
+NL_DECLARE_PARSER(add_addr_parser, struct genlmsghdr, nlf_p_add_addr, nla_p_add_addr);
+
+static int
+pf_handle_add_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_pooladdr attrs = { 0 };
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_ioctl_add_addr(&attrs);
+
+ return (error);
+}
+
+static int
+pf_handle_get_addrs(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_pooladdr attrs = { 0 };
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_ioctl_get_addrs(&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_GET_ADDRS;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
+
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ return (ENOMEM);
+ }
+
+ return (error);
+}
+
+static int
+pf_handle_get_addr(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct pfioc_pooladdr attrs = { 0 };
+ struct nl_writer *nw = npt->nw;
+ struct genlmsghdr *ghdr_new;
+ int error;
+
+ error = nl_parse_nlmsg(hdr, &add_addr_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ error = pf_ioctl_get_addr(&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_GET_ADDRS;
+ ghdr_new->version = 0;
+ ghdr_new->reserved = 0;
+
+ nlattr_add_u32(nw, PF_AA_ACTION, attrs.action);
+ nlattr_add_u32(nw, PF_AA_TICKET, attrs.ticket);
+ nlattr_add_u32(nw, PF_AA_NR, attrs.nr);
+ nlattr_add_u32(nw, PF_AA_R_NUM, attrs.r_num);
+ nlattr_add_u8(nw, PF_AA_R_ACTION, attrs.r_action);
+ nlattr_add_u8(nw, PF_AA_R_LAST, attrs.r_last);
+ nlattr_add_u8(nw, PF_AA_AF, attrs.af);
+ nlattr_add_string(nw, PF_AA_ANCHOR, attrs.anchor);
+ nlattr_add_pool_addr(nw, PF_AA_ADDR, &attrs.addr);
+
+ if (!nlmsg_end(nw)) {
+ nlmsg_abort(nw);
+ return (ENOMEM);
+ }
+
+ return (0);
+}
+
static const struct nlhdr_parser *all_parsers[] = {
&state_parser,
&addrule_parser,
&getrules_parser,
&clear_states_parser,
&set_statusif_parser,
+ &natlook_parser,
+ &set_debug_parser,
+ &set_timeout_parser,
+ &set_limit_parser,
+ &pool_addr_parser,
+ &add_addr_parser,
};
static int family_id;
@@ -1189,7 +1719,91 @@ static const struct genl_cmd pf_cmds[] = {
.cmd_cb = pf_handle_set_statusif,
.cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
.cmd_priv = PRIV_NETINET_PF,
- }
+ },
+ {
+ .cmd_num = PFNL_CMD_GET_STATUS,
+ .cmd_name = "GETSTATUS",
+ .cmd_cb = pf_handle_get_status,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_CLEAR_STATUS,
+ .cmd_name = "CLEARSTATUS",
+ .cmd_cb = pf_handle_clear_status,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_NATLOOK,
+ .cmd_name = "NATLOOK",
+ .cmd_cb = pf_handle_natlook,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SET_DEBUG,
+ .cmd_name = "SET_DEBUG",
+ .cmd_cb = pf_handle_set_debug,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SET_TIMEOUT,
+ .cmd_name = "SET_TIMEOUT",
+ .cmd_cb = pf_handle_set_timeout,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_GET_TIMEOUT,
+ .cmd_name = "GET_TIMEOUT",
+ .cmd_cb = pf_handle_get_timeout,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_SET_LIMIT,
+ .cmd_name = "SET_LIMIT",
+ .cmd_cb = pf_handle_set_limit,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_GET_LIMIT,
+ .cmd_name = "GET_LIMIT",
+ .cmd_cb = pf_handle_get_limit,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_BEGIN_ADDRS,
+ .cmd_name = "BEGIN_ADDRS",
+ .cmd_cb = pf_handle_begin_addrs,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_ADD_ADDR,
+ .cmd_name = "ADD_ADDR",
+ .cmd_cb = pf_handle_add_addr,
+ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_GET_ADDRS,
+ .cmd_name = "GET_ADDRS",
+ .cmd_cb = pf_handle_get_addrs,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
+ {
+ .cmd_num = PFNL_CMD_GET_ADDR,
+ .cmd_name = "GET_ADDRS",
+ .cmd_cb = pf_handle_get_addr,
+ .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
+ .cmd_priv = PRIV_NETINET_PF,
+ },
};
void