13#include <netinet/in.h>
16#include <sys/select.h>
18#include <libmnl/libmnl.h>
19#include <linux/netlink.h>
20#include <linux/netfilter/nfnetlink.h>
21#include <linux/netfilter/nfnetlink_conntrack.h>
37static LIST_HEAD(nstats_head,
nstats) nstats_head;
39static int parse_counters_cb(
const struct nlattr *attr,
void *data)
41 const struct nlattr **tb = data;
48 case CTA_COUNTERS_PACKETS:
49 case CTA_COUNTERS_BYTES:
51 perror(
"mnl_attr_validate");
60static void parse_counters(
const struct nlattr *nest,
struct nstats *ns)
62 struct nlattr *tb[CTA_COUNTERS_MAX+1] = {};
65 if (tb[CTA_COUNTERS_PACKETS])
68 if (tb[CTA_COUNTERS_BYTES])
72static int parse_ip_cb(
const struct nlattr *attr,
void *data)
74 const struct nlattr **tb = data;
84 perror(
"mnl_attr_validate");
91 sizeof(
struct in6_addr)) < 0) {
92 perror(
"mnl_attr_validate2");
101static void parse_ip(
const struct nlattr *nest,
struct nstats *ns)
103 struct nlattr *tb[CTA_IP_MAX+1] = {};
106 if (tb[CTA_IP_V4_SRC]) {
109 ns->family = AF_INET;
111 if (tb[CTA_IP_V6_SRC]) {
114 ns->family = AF_INET6;
118static int parse_tuple_cb(
const struct nlattr *attr,
void *data)
120 const struct nlattr **tb = data;
129 perror(
"mnl_attr_validate");
138static void parse_tuple(
const struct nlattr *nest,
struct nstats *ns)
140 struct nlattr *tb[CTA_TUPLE_MAX+1] = {};
143 if (tb[CTA_TUPLE_IP])
144 parse_ip(tb[CTA_TUPLE_IP], ns);
147static int data_attr_cb(
const struct nlattr *attr,
void *data)
149 const struct nlattr **tb = data;
157 case CTA_COUNTERS_ORIG:
158 case CTA_COUNTERS_REPLY:
160 perror(
"mnl_attr_validate");
169static int data_cb(
const struct nlmsghdr *nlh,
void *data)
171 struct nlattr *tb[CTA_MAX+1] = {};
173 struct nstats ns = {}, *cur, *
new;
176 if (tb[CTA_TUPLE_ORIG])
177 parse_tuple(tb[CTA_TUPLE_ORIG], &ns);
179 if (tb[CTA_COUNTERS_ORIG])
180 parse_counters(tb[CTA_COUNTERS_ORIG], &ns);
182 if (tb[CTA_COUNTERS_REPLY])
183 parse_counters(tb[CTA_COUNTERS_REPLY], &ns);
186 LIST_FOREACH(cur, &nstats_head, list) {
187 if (memcmp(&ns.ip6, &cur->ip6,
sizeof(
struct in6_addr)) == 0) {
189 cur->pkts += ns.pkts;
190 cur->bytes += ns.bytes;
196 new = calloc(1,
sizeof(
struct nstats));
200 new->family = ns.family;
203 new->bytes = ns.bytes;
205 LIST_INSERT_HEAD(&nstats_head,
new, list);
210static int handle(
struct mnl_socket *nl)
212 char buf[MNL_SOCKET_BUFFER_SIZE];
220 if (errno == ENOBUFS) {
221 fprintf(stderr,
"The daemon has hit ENOBUFS, you can "
222 "increase the size of your receiver "
223 "buffer to mitigate this or enable "
224 "reliable delivery.\n");
226 perror(
"mnl_socket_recvfrom");
231 ret =
mnl_cb_run(buf, ret, 0, 0, data_cb, NULL);
233 perror(
"mnl_cb_run");
235 }
else if (ret <= MNL_CB_STOP)
241int main(
int argc,
char *argv[])
243 struct mnl_socket *nl;
244 char buf[MNL_SOCKET_BUFFER_SIZE];
245 struct nlmsghdr *nlh;
246 struct nfgenmsg *nfh;
248 struct timeval tv = {};
249 int ret, secs, on = 1, buffersize = (1 << 22);
252 printf(
"Usage: %s <poll-secs>\n", argv[0]);
255 secs = atoi(argv[1]);
257 LIST_INIT(&nstats_head);
259 printf(
"Polling every %d seconds from kernel...\n", secs);
270 perror(
"mnl_socket_open");
278 MNL_SOCKET_AUTOPID) < 0) {
279 perror(
"mnl_socket_bind");
285 &buffersize,
sizeof(socklen_t));
303 nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) |
304 IPCTNL_MSG_CT_GET_CTRZERO;
305 nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
308 nfh->nfgen_family = AF_INET;
309 nfh->version = NFNETLINK_V0;
321 if (tv.tv_sec == 0 && tv.tv_usec == 0) {
325 perror(
"mnl_socket_sendto");
332 LIST_FOREACH(cur, &nstats_head, list) {
333 char out[INET6_ADDRSTRLEN];
335 if (inet_ntop(cur->family, &cur->ip, out,
sizeof(out)))
336 printf(
"src=%s ", out);
338 printf(
"counters %"PRIu64
" %"PRIu64
"\n",
339 cur->pkts, cur->bytes);
346 ret = select(fd_max+1, &readfds, NULL, NULL, &tv);
int mnl_attr_parse_nested(const struct nlattr *nested, mnl_attr_cb_t cb, void *data)
uint64_t mnl_attr_get_u64(const struct nlattr *attr)
void * mnl_attr_get_payload(const struct nlattr *attr)
int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, void *data)
int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
uint16_t mnl_attr_get_type(const struct nlattr *attr)
int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, size_t exp_len)
void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data)
int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq, unsigned int portid, mnl_cb_t cb_data, void *data)
void * mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
struct nlmsghdr * mnl_nlmsg_put_header(void *buf)
void * mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size)
int mnl_socket_get_fd(const struct mnl_socket *nl)
int mnl_socket_close(struct mnl_socket *nl)
int mnl_socket_setsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t len)
struct mnl_socket * mnl_socket_open(int bus)
ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t bufsiz)
int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid)
ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *buf, size_t len)