12 #include <arpa/inet.h> 
   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> 
   23 #include <sys/queue.h> 
   37 static LIST_HEAD(nstats_head, 
nstats) nstats_head;
 
   39 static 
int parse_counters_cb(const struct nlattr *attr, 
void *data)
 
   41         const struct nlattr **tb = data;
 
   42         int type = mnl_attr_get_type(attr);
 
   44         if (mnl_attr_type_valid(attr, CTA_COUNTERS_MAX) < 0)
 
   48         case CTA_COUNTERS_PACKETS:
 
   49         case CTA_COUNTERS_BYTES:
 
   50                 if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
 
   51                         perror(
"mnl_attr_validate");
 
   60 static void parse_counters(
const struct nlattr *nest, 
struct nstats *ns)
 
   62         struct nlattr *tb[CTA_COUNTERS_MAX+1] = {};
 
   64         mnl_attr_parse_nested(nest, parse_counters_cb, tb);
 
   65         if (tb[CTA_COUNTERS_PACKETS])
 
   66                 ns->pkts += be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_PACKETS]));
 
   68         if (tb[CTA_COUNTERS_BYTES])
 
   69                 ns->bytes += be64toh(mnl_attr_get_u64(tb[CTA_COUNTERS_BYTES]));
 
   72 static int parse_ip_cb(
const struct nlattr *attr, 
void *data)
 
   74         const struct nlattr **tb = data;
 
   75         int type = mnl_attr_get_type(attr);
 
   77         if (mnl_attr_type_valid(attr, CTA_IP_MAX) < 0)
 
   83                 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
 
   84                         perror(
"mnl_attr_validate");
 
   90                 if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
 
   91                                        sizeof(
struct in6_addr)) < 0) {
 
   92                         perror(
"mnl_attr_validate2");
 
  101 static void parse_ip(
const struct nlattr *nest, 
struct nstats *ns)
 
  103         struct nlattr *tb[CTA_IP_MAX+1] = {};
 
  105         mnl_attr_parse_nested(nest, parse_ip_cb, tb);
 
  106         if (tb[CTA_IP_V4_SRC]) {
 
  107                 struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]);
 
  109                 ns->family = AF_INET;
 
  111         if (tb[CTA_IP_V6_SRC]) {
 
  112                 struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_SRC]);
 
  114                 ns->family = AF_INET6;
 
  118 static int parse_tuple_cb(
const struct nlattr *attr, 
void *data)
 
  120         const struct nlattr **tb = data;
 
  121         int type = mnl_attr_get_type(attr);
 
  123         if (mnl_attr_type_valid(attr, CTA_TUPLE_MAX) < 0)
 
  128                 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
 
  129                         perror(
"mnl_attr_validate");
 
  138 static void parse_tuple(
const struct nlattr *nest, 
struct nstats *ns)
 
  140         struct nlattr *tb[CTA_TUPLE_MAX+1] = {};
 
  142         mnl_attr_parse_nested(nest, parse_tuple_cb, tb);
 
  143         if (tb[CTA_TUPLE_IP])
 
  144                 parse_ip(tb[CTA_TUPLE_IP], ns);
 
  147 static int data_attr_cb(
const struct nlattr *attr, 
void *data)
 
  149         const struct nlattr **tb = data;
 
  150         int type = mnl_attr_get_type(attr);
 
  152         if (mnl_attr_type_valid(attr, CTA_MAX) < 0)
 
  157         case CTA_COUNTERS_ORIG:
 
  158         case CTA_COUNTERS_REPLY:
 
  159                 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
 
  160                         perror(
"mnl_attr_validate");
 
  169 static int data_cb(
const struct nlmsghdr *nlh, 
void *data)
 
  171         struct nlattr *tb[CTA_MAX+1] = {};
 
  172         struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
 
  173         struct nstats ns = {}, *cur, *
new;
 
  175         mnl_attr_parse(nlh, 
sizeof(*nfg), data_attr_cb, tb);
 
  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);
 
  212         char buf[MNL_SOCKET_BUFFER_SIZE];
 
  215         ret = mnl_socket_recvfrom(nl, buf, 
sizeof(buf));
 
  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)
 
  241 int main(
int argc, 
char *argv[])
 
  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);
 
  268         nl = mnl_socket_open(NETLINK_NETFILTER);
 
  270                 perror(
"mnl_socket_open");
 
  277         if (mnl_socket_bind(nl, NF_NETLINK_CONNTRACK_DESTROY,
 
  278                                 MNL_SOCKET_AUTOPID) < 0) {
 
  279                 perror(
"mnl_socket_bind");
 
  284         setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUFFORCE,
 
  285                    &buffersize, 
sizeof(socklen_t));
 
  298         mnl_socket_setsockopt(nl, NETLINK_BROADCAST_ERROR, &on, 
sizeof(
int));
 
  299         mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &on, 
sizeof(
int));
 
  301         nlh = mnl_nlmsg_put_header(buf);
 
  303         nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) |
 
  304                           IPCTNL_MSG_CT_GET_CTRZERO;
 
  305         nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
 
  307         nfh = mnl_nlmsg_put_extra_header(nlh, 
sizeof(
struct nfgenmsg));
 
  308         nfh->nfgen_family = AF_INET;
 
  309         nfh->version = NFNETLINK_V0;
 
  313         mnl_attr_put_u32(nlh, CTA_MARK, htonl(0));
 
  314         mnl_attr_put_u32(nlh, CTA_MARK_MASK, htonl(0xffffffff));
 
  317                 int fd_max = mnl_socket_get_fd(nl);
 
  321                 if (tv.tv_sec == 0 && tv.tv_usec == 0) {
 
  323                         ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
 
  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);
 
  344                 FD_SET(mnl_socket_get_fd(nl), &readfds);
 
  346                 ret = select(fd_max+1, &readfds, NULL, NULL, &tv);
 
  356                 if (FD_ISSET(mnl_socket_get_fd(nl), &readfds)) {
 
  362         mnl_socket_close(nl);