// SPDX-License-Identifier: GPL-3.0-or-later
#include "libnetdata/libnetdata.h"
#include "libnetdata/required_dummies.h"
#include <linux/netfilter/nfnetlink_conntrack.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_acct/libnetfilter_acct.h>
#define PLUGIN_NFACCT_NAME "nfacct.plugin"
#define NETDATA_CHART_PRIO_NETFILTER_NEW 8701
#define NETDATA_CHART_PRIO_NETFILTER_CHANGES 8702
#define NETDATA_CHART_PRIO_NETFILTER_EXPECT 8703
#define NETDATA_CHART_PRIO_NETFILTER_ERRORS 8705
#define NETDATA_CHART_PRIO_NETFILTER_SEARCH 8710
#define NETDATA_CHART_PRIO_NETFILTER_PACKETS 8906
#define NETDATA_CHART_PRIO_NETFILTER_BYTES 8907
#define NFACCT_RESTART_EVERY_SECONDS 86400 // restart the plugin every this many seconds
static inline size_t mnl_buffer_size() {
long s = MNL_SOCKET_BUFFER_SIZE;
if(s <= 0) return 8192;
return (size_t)s;
}
// variables
static int debug = 0;
static int netdata_update_every = 1;
#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
#define RRD_TYPE_NET_STAT_CONNTRACK "netlink"
static struct {
int update_every;
char *buf;
size_t buf_size;
struct mnl_socket *mnl;
struct nlmsghdr *nlh;
struct nfgenmsg *nfh;
unsigned int seq;
uint32_t portid;
struct nlattr *tb[CTA_STATS_MAX+1];
const char *attr2name[CTA_STATS_MAX+1];
kernel_uint_t metrics[CTA_STATS_MAX+1];
struct nlattr *tb_exp[CTA_STATS_EXP_MAX+1];
const char *attr2name_exp[CTA_STATS_EXP_MAX+1];
kernel_uint_t metrics_exp[CTA_STATS_EXP_MAX+1];
} nfstat_root = {
.update_every = 1,
.buf = NULL,
.buf_size = 0,
.mnl = NULL,
.nlh = NULL,
.nfh = NULL,
.seq = 0,
.portid = 0,
.tb = {},
.attr2name = {
[CTA_STATS_SEARCHED] = "searched",
[CTA_STATS_FOUND] = "found",
[CTA_STATS_NEW] = "new",
[CTA_STATS_INVALID] = "invalid",
[CTA_STATS_IGNORE] = "ignore",
[CTA_STATS_DELETE] = "delete",
[CTA_STATS_DELETE_LIST] = "delete_list",
[CTA_STATS_INSERT] = "insert",
[CTA_STATS_INSERT_FAILED] = "insert_failed",
[CTA_STATS_DROP] = "drop",
[CTA_STATS_EARLY_DROP] = "early_drop",
[CTA_STATS_ERROR] = "icmp_error",
[CTA_STATS_SEARCH_RESTART] = "search_restart",
},
.metrics = {},
.tb_exp = {},
.attr2name_exp = {
[CTA_STATS_EXP_NEW] = "new",
[CTA_STATS_EXP_CREATE] = "created",
[CTA_STATS_EXP_DELETE] = "deleted",
},
.metrics_exp = {}
};
static int nfstat_init(int update_every) {
nfstat_root.update_every = update_every;
nfstat_root.buf_size = mnl_buffer_size();
nfstat_root.buf = mallocz(nfstat_root.buf_size);
nfstat_root.mnl = mnl_socket_open(NETLINK_NETFILTER);
if(!nfstat_root.mnl) {
collector_error("NFSTAT: mnl_socket_open() failed");
return 1;
}
nfstat_root.seq = (unsigned int)now_realtime_sec() - 1;
if(mnl_socket_bind(nfstat_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
collector_error("NFSTAT: mnl_socket_bind() failed");
return 1;
}
nfstat_root.portid = mnl_socket_get_portid(nfstat_root.mnl);
return 0;
}
static struct nlmsghdr * nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type, uint8_t family, uint32_t seq) {
struct nlmsghdr *nlh;
struct nfgenmsg *nfh;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = (subsys << 8) | type;
nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
nlh->nlmsg_seq = seq;
nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
nfh->nfgen_family = family;
nfh->version = NFNETLINK_V0;
nfh->res_id = 0;
return nlh;
}
static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) {
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
if (mnl_attr_type_valid(attr,