mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-21 10:41:46 +01:00
pf: convert DIOCGETSRCNODES to netlink
Sponsored by: Rubicon Communications, LLC ("Netgate")
This commit is contained in:
parent
96f1dfc1be
commit
9c12533672
@ -2998,3 +2998,71 @@ pfctl_get_ruleset(struct pfctl_handle *h, const char *path, uint32_t nr, struct
|
||||
return (e.error);
|
||||
}
|
||||
|
||||
#define _OUT(_field) offsetof(struct pfctl_threshold, _field)
|
||||
static const struct snl_attr_parser ap_pfctl_threshold[] = {
|
||||
{ .type = PF_TH_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
|
||||
{ .type = PF_TH_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
|
||||
{ .type = PF_TH_COUNT, .off = _OUT(count), .cb = snl_attr_get_uint32 },
|
||||
{ .type = PF_TH_LAST, .off = _OUT(last), .cb = snl_attr_get_uint32 },
|
||||
};
|
||||
SNL_DECLARE_ATTR_PARSER(pfctl_threshold_parser, ap_pfctl_threshold);
|
||||
#undef _OUT
|
||||
|
||||
#define _OUT(_field) offsetof(struct pfctl_src_node, _field)
|
||||
static struct snl_attr_parser ap_srcnode[] = {
|
||||
{ .type = PF_SN_ADDR, .off = _OUT(addr), .cb = snl_attr_get_in6_addr },
|
||||
{ .type = PF_SN_RADDR, .off = _OUT(raddr), .cb = snl_attr_get_in6_addr },
|
||||
{ .type = PF_SN_RULE_NR, .off = _OUT(rule), .cb = snl_attr_get_uint32 },
|
||||
{ .type = PF_SN_BYTES_IN, .off = _OUT(bytes[0]), .cb = snl_attr_get_uint64 },
|
||||
{ .type = PF_SN_BYTES_OUT, .off = _OUT(bytes[1]), .cb = snl_attr_get_uint64 },
|
||||
{ .type = PF_SN_PACKETS_IN, .off = _OUT(packets[0]), .cb = snl_attr_get_uint64 },
|
||||
{ .type = PF_SN_PACKETS_OUT, .off = _OUT(packets[1]), .cb = snl_attr_get_uint64 },
|
||||
{ .type = PF_SN_STATES, .off = _OUT(states), .cb = snl_attr_get_uint32 },
|
||||
{ .type = PF_SN_CONNECTIONS, .off = _OUT(conn), .cb = snl_attr_get_uint32 },
|
||||
{ .type = PF_SN_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
|
||||
{ .type = PF_SN_RULE_TYPE, .off = _OUT(ruletype), .cb = snl_attr_get_uint8 },
|
||||
{ .type = PF_SN_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint64 },
|
||||
{ .type = PF_SN_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint64 },
|
||||
{ .type = PF_SN_CONNECTION_RATE, .off = _OUT(conn_rate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested },
|
||||
};
|
||||
static struct snl_field_parser fp_srcnode[] = {};
|
||||
#undef _OUT
|
||||
SNL_DECLARE_PARSER(srcnode_parser, struct genlmsghdr, fp_srcnode, ap_srcnode);
|
||||
|
||||
int
|
||||
pfctl_get_srcnodes(struct pfctl_handle *h, pfctl_get_srcnode_fn fn, void *arg)
|
||||
{
|
||||
struct snl_writer nw;
|
||||
struct pfctl_src_node sn;
|
||||
struct snl_errmsg_data e = {};
|
||||
struct nlmsghdr *hdr;
|
||||
uint32_t seq_id;
|
||||
int family_id;
|
||||
int ret;
|
||||
|
||||
family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
|
||||
if (family_id == 0)
|
||||
return (ENOTSUP);
|
||||
|
||||
snl_init_writer(&h->ss, &nw);
|
||||
hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_SRCNODES);
|
||||
|
||||
if ((hdr = snl_finalize_msg(&nw)) == NULL)
|
||||
return (ENXIO);
|
||||
|
||||
seq_id = hdr->nlmsg_seq;
|
||||
|
||||
if (!snl_send_message(&h->ss, hdr))
|
||||
return (ENXIO);
|
||||
|
||||
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
|
||||
if (!snl_parse_nlmsg(&h->ss, hdr, &srcnode_parser, &sn))
|
||||
continue;
|
||||
|
||||
ret = fn(&sn, arg);
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
return (e.error);
|
||||
}
|
||||
|
@ -386,6 +386,28 @@ struct pfctl_syncookies {
|
||||
uint32_t halfopen_states;
|
||||
};
|
||||
|
||||
struct pfctl_threshold {
|
||||
uint32_t limit;
|
||||
uint32_t seconds;
|
||||
uint32_t count;
|
||||
uint32_t last;
|
||||
};
|
||||
|
||||
struct pfctl_src_node {
|
||||
struct pf_addr addr;
|
||||
struct pf_addr raddr;
|
||||
int rule;
|
||||
uint64_t bytes[2];
|
||||
uint64_t packets[2];
|
||||
uint32_t states;
|
||||
uint32_t conn;
|
||||
sa_family_t af;
|
||||
uint8_t ruletype;
|
||||
uint64_t creation;
|
||||
uint64_t expire;
|
||||
struct pfctl_threshold conn_rate;
|
||||
};
|
||||
|
||||
#define PF_DEVICE "/dev/pf"
|
||||
|
||||
struct pfctl_handle;
|
||||
@ -506,5 +528,7 @@ int pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,
|
||||
uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa);
|
||||
int pfctl_get_rulesets(struct pfctl_handle *h, const char *path, uint32_t *nr);
|
||||
int pfctl_get_ruleset(struct pfctl_handle *h, const char *path, uint32_t nr, struct pfioc_ruleset *rs);
|
||||
typedef int (*pfctl_get_srcnode_fn)(struct pfctl_src_node*, void *);
|
||||
int pfctl_get_srcnodes(struct pfctl_handle *h, pfctl_get_srcnode_fn fn, void *arg);
|
||||
|
||||
#endif
|
||||
|
@ -1519,49 +1519,29 @@ pfctl_show_nat(int dev, char *path, int opts, char *anchorname, int depth,
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
pfctl_print_src_node(struct pfctl_src_node *sn, void *arg)
|
||||
{
|
||||
int *opts = (int *)arg;
|
||||
|
||||
if (*opts & PF_OPT_SHOWALL) {
|
||||
pfctl_print_title("SOURCE TRACKING NODES:");
|
||||
*opts &= ~PF_OPT_SHOWALL;
|
||||
}
|
||||
|
||||
print_src_node(sn, *opts);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
pfctl_show_src_nodes(int dev, int opts)
|
||||
{
|
||||
struct pfioc_src_nodes psn;
|
||||
struct pf_src_node *p;
|
||||
char *inbuf = NULL, *newinbuf = NULL;
|
||||
unsigned int len = 0;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
memset(&psn, 0, sizeof(psn));
|
||||
for (;;) {
|
||||
psn.psn_len = len;
|
||||
if (len) {
|
||||
newinbuf = realloc(inbuf, len);
|
||||
if (newinbuf == NULL)
|
||||
err(1, "realloc");
|
||||
psn.psn_buf = inbuf = newinbuf;
|
||||
}
|
||||
if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) {
|
||||
warn("DIOCGETSRCNODES");
|
||||
free(inbuf);
|
||||
return (-1);
|
||||
}
|
||||
if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len)
|
||||
break;
|
||||
if (len == 0 && psn.psn_len == 0)
|
||||
goto done;
|
||||
if (len == 0 && psn.psn_len != 0)
|
||||
len = psn.psn_len;
|
||||
if (psn.psn_len == 0)
|
||||
goto done; /* no src_nodes */
|
||||
len *= 2;
|
||||
}
|
||||
p = psn.psn_src_nodes;
|
||||
if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL))
|
||||
pfctl_print_title("SOURCE TRACKING NODES:");
|
||||
for (i = 0; i < psn.psn_len; i += sizeof(*p)) {
|
||||
print_src_node(p, opts);
|
||||
p++;
|
||||
}
|
||||
done:
|
||||
free(inbuf);
|
||||
return (0);
|
||||
error = pfctl_get_srcnodes(pfh, pfctl_print_src_node, &opts);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
struct pfctl_show_state_arg {
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pfctl_parser.h"
|
||||
@ -648,10 +649,10 @@ print_running(struct pfctl_status *status)
|
||||
}
|
||||
|
||||
void
|
||||
print_src_node(struct pf_src_node *sn, int opts)
|
||||
print_src_node(struct pfctl_src_node *sn, int opts)
|
||||
{
|
||||
struct pf_addr_wrap aw;
|
||||
int min, sec;
|
||||
uint64_t min, sec;
|
||||
|
||||
memset(&aw, 0, sizeof(aw));
|
||||
if (sn->af == AF_INET)
|
||||
@ -672,36 +673,32 @@ print_src_node(struct pf_src_node *sn, int opts)
|
||||
sn->creation /= 60;
|
||||
min = sn->creation % 60;
|
||||
sn->creation /= 60;
|
||||
printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec);
|
||||
printf(" age %.2" PRIu64 ":%.2" PRIu64 ":%.2" PRIu64,
|
||||
sn->creation, min, sec);
|
||||
if (sn->states == 0) {
|
||||
sec = sn->expire % 60;
|
||||
sn->expire /= 60;
|
||||
min = sn->expire % 60;
|
||||
sn->expire /= 60;
|
||||
printf(", expires in %.2u:%.2u:%.2u",
|
||||
printf(", expires in %.2" PRIu64 ":%.2" PRIu64 ":%.2" PRIu64,
|
||||
sn->expire, min, sec);
|
||||
}
|
||||
printf(", %llu pkts, %llu bytes",
|
||||
#ifdef __FreeBSD__
|
||||
(unsigned long long)(sn->packets[0] + sn->packets[1]),
|
||||
(unsigned long long)(sn->bytes[0] + sn->bytes[1]));
|
||||
#else
|
||||
printf(", %" PRIu64 " pkts, %" PRIu64 " bytes",
|
||||
sn->packets[0] + sn->packets[1],
|
||||
sn->bytes[0] + sn->bytes[1]);
|
||||
#endif
|
||||
switch (sn->ruletype) {
|
||||
case PF_NAT:
|
||||
if (sn->rule.nr != -1)
|
||||
printf(", nat rule %u", sn->rule.nr);
|
||||
if (sn->rule != -1)
|
||||
printf(", nat rule %u", sn->rule);
|
||||
break;
|
||||
case PF_RDR:
|
||||
if (sn->rule.nr != -1)
|
||||
printf(", rdr rule %u", sn->rule.nr);
|
||||
if (sn->rule != -1)
|
||||
printf(", rdr rule %u", sn->rule);
|
||||
break;
|
||||
case PF_PASS:
|
||||
case PF_MATCH:
|
||||
if (sn->rule.nr != -1)
|
||||
printf(", filter rule %u", sn->rule.nr);
|
||||
if (sn->rule != -1)
|
||||
printf(", filter rule %u", sn->rule);
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
|
@ -302,7 +302,7 @@ int parse_flags(char *);
|
||||
int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *);
|
||||
|
||||
void print_pool(struct pfctl_pool *, u_int16_t, u_int16_t, sa_family_t, int);
|
||||
void print_src_node(struct pf_src_node *, int);
|
||||
void print_src_node(struct pfctl_src_node *, int);
|
||||
void print_eth_rule(struct pfctl_eth_rule *, const char *, int);
|
||||
void print_rule(struct pfctl_rule *, const char *, int, int);
|
||||
void print_tabledef(const char *, int, int, struct node_tinithead *);
|
||||
|
@ -1713,6 +1713,77 @@ pf_handle_get_ruleset(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static bool
|
||||
nlattr_add_pf_threshold(struct nl_writer *nw, int attrtype, struct pf_threshold *t)
|
||||
{
|
||||
int off = nlattr_add_nested(nw, attrtype);
|
||||
|
||||
nlattr_add_u32(nw, PF_TH_LIMIT, t->limit);
|
||||
nlattr_add_u32(nw, PF_TH_SECONDS, t->seconds);
|
||||
nlattr_add_u32(nw, PF_TH_COUNT, t->count);
|
||||
nlattr_add_u32(nw, PF_TH_LAST, t->last);
|
||||
|
||||
nlattr_set_len(nw, off);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
static int
|
||||
pf_handle_get_srcnodes(struct nlmsghdr *hdr, struct nl_pstate *npt)
|
||||
{
|
||||
struct nl_writer *nw = npt->nw;
|
||||
struct genlmsghdr *ghdr_new;
|
||||
struct pf_ksrc_node *n;
|
||||
struct pf_srchash *sh;
|
||||
int i;
|
||||
|
||||
hdr->nlmsg_flags |= NLM_F_MULTI;
|
||||
|
||||
for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask;
|
||||
i++, sh++) {
|
||||
/* Avoid locking empty rows. */
|
||||
if (LIST_EMPTY(&sh->nodes))
|
||||
continue;
|
||||
|
||||
PF_HASHROW_LOCK(sh);
|
||||
LIST_FOREACH(n, &sh->nodes, entry) {
|
||||
if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) {
|
||||
nlmsg_abort(nw);
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr);
|
||||
ghdr_new->cmd = PFNL_CMD_GET_SRCNODES;
|
||||
ghdr_new->version = 0;
|
||||
ghdr_new->reserved = 0;
|
||||
|
||||
nlattr_add_in6_addr(nw, PF_SN_ADDR, &n->addr.v6);
|
||||
nlattr_add_in6_addr(nw, PF_SN_RADDR, &n->raddr.v6);
|
||||
nlattr_add_u32(nw, PF_SN_RULE_NR, n->rule->nr);
|
||||
nlattr_add_u64(nw, PF_SN_BYTES_IN, counter_u64_fetch(n->bytes[0]));
|
||||
nlattr_add_u64(nw, PF_SN_BYTES_OUT, counter_u64_fetch(n->bytes[1]));
|
||||
nlattr_add_u64(nw, PF_SN_PACKETS_IN, counter_u64_fetch(n->packets[0]));
|
||||
nlattr_add_u64(nw, PF_SN_PACKETS_OUT, counter_u64_fetch(n->packets[1]));
|
||||
nlattr_add_u32(nw, PF_SN_STATES, n->states);
|
||||
nlattr_add_u32(nw, PF_SN_CONNECTIONS, n->conn);
|
||||
nlattr_add_u8(nw, PF_SN_AF, n->af);
|
||||
nlattr_add_u8(nw, PF_SN_RULE_TYPE, n->ruletype);
|
||||
nlattr_add_u64(nw, PF_SN_CREATION, n->creation);
|
||||
nlattr_add_u64(nw, PF_SN_EXPIRE, n->expire);
|
||||
nlattr_add_pf_threshold(nw, PF_SN_CONNECTION_RATE, &n->conn_rate);
|
||||
|
||||
if (!nlmsg_end(nw)) {
|
||||
PF_HASHROW_UNLOCK(sh);
|
||||
nlmsg_abort(nw);
|
||||
return (ENOMEM);
|
||||
}
|
||||
}
|
||||
PF_HASHROW_UNLOCK(sh);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static const struct nlhdr_parser *all_parsers[] = {
|
||||
&state_parser,
|
||||
&addrule_parser,
|
||||
@ -1899,6 +1970,13 @@ static const struct genl_cmd pf_cmds[] = {
|
||||
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
|
||||
.cmd_priv = PRIV_NETINET_PF,
|
||||
},
|
||||
{
|
||||
.cmd_num = PFNL_CMD_GET_SRCNODES,
|
||||
.cmd_name = "GET_SRCNODES",
|
||||
.cmd_cb = pf_handle_get_srcnodes,
|
||||
.cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL,
|
||||
.cmd_priv = PRIV_NETINET_PF,
|
||||
},
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -60,6 +60,7 @@ enum {
|
||||
PFNL_CMD_GET_ADDR = 22,
|
||||
PFNL_CMD_GET_RULESETS = 23,
|
||||
PFNL_CMD_GET_RULESET = 24,
|
||||
PFNL_CMD_GET_SRCNODES = 25,
|
||||
__PFNL_CMD_MAX,
|
||||
};
|
||||
#define PFNL_CMD_MAX (__PFNL_CMD_MAX -1)
|
||||
@ -389,6 +390,32 @@ enum pf_get_rulesets_types_t {
|
||||
PF_RS_NAME = 3, /* string */
|
||||
};
|
||||
|
||||
enum pf_threshold_types_t {
|
||||
PF_TH_UNSPEC,
|
||||
PF_TH_LIMIT = 1, /* u32 */
|
||||
PF_TH_SECONDS = 2, /* u32 */
|
||||
PF_TH_COUNT = 3, /* u32 */
|
||||
PF_TH_LAST = 4, /* u32 */
|
||||
};
|
||||
|
||||
enum pf_srcnodes_types_t {
|
||||
PF_SN_UNSPEC,
|
||||
PF_SN_ADDR = 1, /* nested, pf_addr */
|
||||
PF_SN_RADDR = 2, /* nested, pf_addr */
|
||||
PF_SN_RULE_NR = 3, /* u32 */
|
||||
PF_SN_BYTES_IN = 4, /* u64 */
|
||||
PF_SN_BYTES_OUT = 5, /* u64 */
|
||||
PF_SN_PACKETS_IN = 6, /* u64 */
|
||||
PF_SN_PACKETS_OUT = 7, /* u64 */
|
||||
PF_SN_STATES = 8, /* u32 */
|
||||
PF_SN_CONNECTIONS = 9, /* u32 */
|
||||
PF_SN_AF = 10, /* u8 */
|
||||
PF_SN_RULE_TYPE = 11, /* u8 */
|
||||
PF_SN_CREATION = 12, /* u64 */
|
||||
PF_SN_EXPIRE = 13, /* u64 */
|
||||
PF_SN_CONNECTION_RATE = 14, /* nested, pf_threshold */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
void pf_nl_register(void);
|
||||
|
Loading…
Reference in New Issue
Block a user