]> arthur.barton.de Git - netdata.git/commitdiff
new feature: added data collection for SYNPROXY - netfilter TCP anti-DDoS protection...
authorCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Fri, 8 Apr 2016 21:19:05 +0000 (00:19 +0300)
committerCosta Tsaousis (ktsaou) <costa@tsaousis.gr>
Fri, 8 Apr 2016 21:19:05 +0000 (00:19 +0300)
src/Makefile.am
src/plugin_nfacct.c
src/plugin_proc.c
src/plugin_proc.h
src/proc_net_stat_conntrack.c
src/proc_net_stat_synproxy.c [new file with mode: 0755]
web/index.html

index f2c15e92216b216dc61101f424f83450cb463988..a6808f4242570197ff7af75fc0ec0061ac6be149 100644 (file)
@@ -50,6 +50,7 @@ netdata_SOURCES = \
        proc_net_snmp.c \
        proc_net_snmp6.c \
        proc_net_stat_conntrack.c \
+       proc_net_stat_synproxy.c \
        proc_stat.c \
        proc_sys_kernel_random_entropy_avail.c \
        proc_vmstat.c \
index 45a65b4347beeb3cd38270ab701e6680835de0c6..6cde66e0c70f77e7e86313e419b569383a1b057a 100644 (file)
@@ -168,9 +168,9 @@ void *nfacct_main(void *ptr) {
                if(nfacct_list && nfacct_list->len) {
                        int i;
 
-                       st = rrdset_find_bytype("nfacct", "packets");
+                       st = rrdset_find_bytype("netfilter", "nfacct_packets");
                        if(!st) {
-                               st = rrdset_create("nfacct", "packets", NULL, "netfilter", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
+                               st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
 
                                for(i = 0; i < nfacct_list->len ; i++)
                                        rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
@@ -188,9 +188,9 @@ void *nfacct_main(void *ptr) {
 
                        // ----------------------------------------------------------------
 
-                       st = rrdset_find_bytype("nfacct", "bytes");
+                       st = rrdset_find_bytype("netfilter", "nfacct_bytes");
                        if(!st) {
-                               st = rrdset_create("nfacct", "bytes", NULL, "netfilter", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
+                               st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
 
                                for(i = 0; i < nfacct_list->len ; i++)
                                        rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
index c0ed40cd0bb68638ee4df746df947ae20add7e07..4cd20afc56a5f594ba61c6745dca97229e353336 100644 (file)
@@ -47,6 +47,7 @@ void *proc_main(void *ptr)
        int vdo_proc_net_netstat                = !config_get_boolean("plugin:proc", "/proc/net/netstat", 1);
        int vdo_proc_net_stat_conntrack = !config_get_boolean("plugin:proc", "/proc/net/stat/conntrack", 1);
        int vdo_proc_net_ip_vs_stats    = !config_get_boolean("plugin:proc", "/proc/net/ip_vs/stats", 1);
+       int vdo_proc_net_stat_synproxy  = !config_get_boolean("plugin:proc", "/proc/net/stat/synproxy", 1);
        int vdo_proc_stat                               = !config_get_boolean("plugin:proc", "/proc/stat", 1);
        int vdo_proc_meminfo                    = !config_get_boolean("plugin:proc", "/proc/meminfo", 1);
        int vdo_proc_vmstat                     = !config_get_boolean("plugin:proc", "/proc/vmstat", 1);
@@ -66,6 +67,7 @@ void *proc_main(void *ptr)
        unsigned long long sutime_proc_net_netstat = 0ULL;
        unsigned long long sutime_proc_net_stat_conntrack = 0ULL;
        unsigned long long sutime_proc_net_ip_vs_stats = 0ULL;
+       unsigned long long sutime_proc_net_stat_synproxy = 0ULL;
        unsigned long long sutime_proc_stat = 0ULL;
        unsigned long long sutime_proc_meminfo = 0ULL;
        unsigned long long sutime_proc_vmstat = 0ULL;
@@ -194,6 +196,14 @@ void *proc_main(void *ptr)
                }
                if(unlikely(netdata_exit)) break;
 
+               if(!vdo_proc_net_stat_synproxy) {
+                       debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
+                       sunow = sutime();
+                       vdo_proc_net_stat_synproxy = do_proc_net_stat_synproxy(rrd_update_every, (sutime_proc_net_stat_synproxy > 0)?sunow - sutime_proc_net_stat_synproxy:0ULL);
+                       sutime_proc_net_stat_synproxy = sunow;
+               }
+               if(unlikely(netdata_exit)) break;
+
                if(!vdo_proc_stat) {
                        debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
                        sunow = sutime();
index 4f35f7b31b34ecd432ac83fb639de9a2da878271..a512e1cdf9d44c58a5008436e85d98a3ee8035cd 100644 (file)
@@ -19,5 +19,6 @@ extern int do_proc_interrupts(int update_every, unsigned long long dt);
 extern int do_proc_softirqs(int update_every, unsigned long long dt);
 extern int do_sys_kernel_mm_ksm(int update_every, unsigned long long dt);
 extern int do_proc_loadavg(int update_every, unsigned long long dt);
+extern int do_proc_net_stat_synproxy(int update_every, unsigned long long dt);
 
 #endif /* NETDATA_PLUGIN_PROC_H */
index 912c3eef0b0181196b3632daf61600c5827da85f..f7e5c45b260ba0a89ba80af09bf25ae8f9c2e558 100644 (file)
@@ -12,7 +12,8 @@
 #include "rrd.h"
 #include "plugin_proc.h"
 
-#define RRD_TYPE_NET_STAT_CONNTRACK    "netfilter"
+#define RRD_TYPE_NET_STAT_NETFILTER            "netfilter"
+#define RRD_TYPE_NET_STAT_CONNTRACK    "conntrack"
 #define RRD_TYPE_NET_STAT_CONNTRACK_LEN        strlen(RRD_TYPE_NET_STAT_CONNTRACK)
 
 int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
@@ -97,9 +98,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
        // --------------------------------------------------------------------
 
        if(do_sockets) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".sockets");
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
                if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Connections", "active connections", 1000, update_every, RRDSET_TYPE_LINE);
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_sockets", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Connections", "active connections", 1000, update_every, RRDSET_TYPE_LINE);
 
                        rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
                }
@@ -112,9 +113,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
        // --------------------------------------------------------------------
 
        if(do_new) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".new");
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
                if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_new", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker New Connections", "connections/s", 1001, update_every, RRDSET_TYPE_LINE);
 
                        rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
                        rrddim_add(st, "ignore", NULL, -1, 1, RRDDIM_INCREMENTAL);
@@ -131,9 +132,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
        // --------------------------------------------------------------------
 
        if(do_changes) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".changes");
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
                if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Connection Changes", "changes/s", 1002, update_every, RRDSET_TYPE_LINE);
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_changes", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Changes", "changes/s", 1002, update_every, RRDSET_TYPE_LINE);
                        st->isdetail = 1;
 
                        rrddim_add(st, "inserted", NULL, 1, 1, RRDDIM_INCREMENTAL);
@@ -151,9 +152,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
        // --------------------------------------------------------------------
 
        if(do_expect) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".expect");
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
                if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Connection Expectations", "expectations/s", 1003, update_every, RRDSET_TYPE_LINE);
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_expect", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Expectations", "expectations/s", 1003, update_every, RRDSET_TYPE_LINE);
                        st->isdetail = 1;
 
                        rrddim_add(st, "created", NULL, 1, 1, RRDDIM_INCREMENTAL);
@@ -171,9 +172,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
        // --------------------------------------------------------------------
 
        if(do_search) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".search");
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
                if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Connection Searches", "searches/s", 1010, update_every, RRDSET_TYPE_LINE);
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_search", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Searches", "searches/s", 1010, update_every, RRDSET_TYPE_LINE);
                        st->isdetail = 1;
 
                        rrddim_add(st, "searched", NULL, 1, 1, RRDDIM_INCREMENTAL);
@@ -191,9 +192,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
        // --------------------------------------------------------------------
 
        if(do_errors) {
-               st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".errors");
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
                if(!st) {
-                       st = rrdset_create(RRD_TYPE_NET_STAT_CONNTRACK, "errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Netfilter Errors", "events/s", 1005, update_every, RRDSET_TYPE_LINE);
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_CONNTRACK "_errors", NULL, RRD_TYPE_NET_STAT_CONNTRACK, NULL, "Connection Tracker Errors", "events/s", 1005, update_every, RRDSET_TYPE_LINE);
                        st->isdetail = 1;
 
                        rrddim_add(st, "icmp_error", NULL, 1, 1, RRDDIM_INCREMENTAL);
diff --git a/src/proc_net_stat_synproxy.c b/src/proc_net_stat_synproxy.c
new file mode 100755 (executable)
index 0000000..62296d7
--- /dev/null
@@ -0,0 +1,138 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "appconfig.h"
+#include "procfile.h"
+#include "rrd.h"
+#include "plugin_proc.h"
+#include "log.h"
+
+#define RRD_TYPE_NET_STAT_NETFILTER                    "netfilter"
+#define RRD_TYPE_NET_STAT_SYNPROXY                     "synproxy"
+#define RRD_TYPE_NET_STAT_SYNPROXY_LEN         strlen(RRD_TYPE_NET_STAT_SYNPROXY)
+
+int do_proc_net_stat_synproxy(int update_every, unsigned long long dt) {
+       static int do_entries = -1, do_cookies = -1, do_syns = -1, do_reopened = -1;
+       static procfile *ff = NULL;
+
+       if(do_entries == -1)    do_entries      = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_ONDEMAND_ONDEMAND);
+       if(do_cookies == -1)    do_cookies      = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_ONDEMAND_ONDEMAND);
+       if(do_syns == -1)               do_syns         = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_ONDEMAND_ONDEMAND);
+       if(do_reopened == -1)   do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_ONDEMAND_ONDEMAND);
+
+       if(dt) {};
+
+       if(!ff) {
+               char filename[FILENAME_MAX + 1];
+               snprintf(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/synproxy");
+               ff = procfile_open(config_get("plugin:proc:/proc/net/stat/synproxy", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
+       }
+       if(!ff) return 1;
+
+       ff = procfile_readall(ff);
+       if(!ff) return 0; // we return 0, so that we will retry to open it next time
+
+       // make sure we have 3 lines
+       unsigned long lines = procfile_lines(ff), l;
+       if(lines < 2) {
+               error("/proc/net/stat/synproxy has %d lines, expected no less than 2. Disabling it.", lines);
+               return 1;
+       }
+
+       unsigned long long entries = 0, syn_received = 0, cookie_invalid = 0, cookie_valid = 0, cookie_retrans = 0, conn_reopened = 0;
+
+       // synproxy gives its values per CPU
+       for(l = 1; l < lines ;l++) {
+               int words = procfile_linewords(ff, l);
+               if(words < 6) continue;
+
+               entries                 += strtoull(procfile_lineword(ff, l, 0), NULL, 16);
+               syn_received    += strtoull(procfile_lineword(ff, l, 1), NULL, 16);
+               cookie_invalid  += strtoull(procfile_lineword(ff, l, 2), NULL, 16);
+               cookie_valid    += strtoull(procfile_lineword(ff, l, 3), NULL, 16);
+               cookie_retrans  += strtoull(procfile_lineword(ff, l, 4), NULL, 16);
+               conn_reopened   += strtoull(procfile_lineword(ff, l, 5), NULL, 16);
+       }
+
+       unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened;
+
+       RRDSET *st;
+
+       // --------------------------------------------------------------------
+
+       if((do_entries == CONFIG_ONDEMAND_ONDEMAND && events) || do_entries == CONFIG_ONDEMAND_YES) {
+               do_entries = CONFIG_ONDEMAND_YES;
+
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
+               if(!st) {
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_entries", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Entries Used", "entries", 1004, update_every, RRDSET_TYPE_LINE);
+
+                       rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
+               }
+               else rrdset_next(st);
+
+               rrddim_set(st, "entries", entries);
+               rrdset_done(st);
+       }
+
+       // --------------------------------------------------------------------
+
+       if((do_syns == CONFIG_ONDEMAND_ONDEMAND && events) || do_syns == CONFIG_ONDEMAND_YES) {
+               do_syns = CONFIG_ONDEMAND_YES;
+
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
+               if(!st) {
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_syn_received", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY SYN Packets received", "SYN/s", 1001, update_every, RRDSET_TYPE_LINE);
+
+                       rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+               }
+               else rrdset_next(st);
+
+               rrddim_set(st, "received", syn_received);
+               rrdset_done(st);
+       }
+
+       // --------------------------------------------------------------------
+
+       if((do_reopened == CONFIG_ONDEMAND_ONDEMAND && events) || do_reopened == CONFIG_ONDEMAND_YES) {
+               do_reopened = CONFIG_ONDEMAND_YES;
+
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
+               if(!st) {
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY Connections Reopened", "connections/s", 1003, update_every, RRDSET_TYPE_LINE);
+
+                       rrddim_add(st, "reopened", NULL, 1, 1, RRDDIM_INCREMENTAL);
+               }
+               else rrdset_next(st);
+
+               rrddim_set(st, "reopened", conn_reopened);
+               rrdset_done(st);
+       }
+
+       // --------------------------------------------------------------------
+
+       if((do_cookies == CONFIG_ONDEMAND_ONDEMAND && events) || do_cookies == CONFIG_ONDEMAND_YES) {
+               do_cookies = CONFIG_ONDEMAND_YES;
+
+               st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
+               if(!st) {
+                       st = rrdset_create(RRD_TYPE_NET_STAT_NETFILTER, RRD_TYPE_NET_STAT_SYNPROXY "_cookies", NULL, RRD_TYPE_NET_STAT_SYNPROXY, NULL, "SYNPROXY TCP Cookies", "cookies/s", 1002, update_every, RRDSET_TYPE_LINE);
+
+                       rrddim_add(st, "valid", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                       rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                       rrddim_add(st, "retransmits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+               }
+               else rrdset_next(st);
+
+               rrddim_set(st, "valid", cookie_valid);
+               rrddim_set(st, "invalid", cookie_invalid);
+               rrddim_set(st, "retransmits", cookie_retrans);
+               rrdset_done(st);
+       }
+
+       return 0;
+}
index b9b1785a2b7a945bf7ad0ca751ca8030b184cb75..f4afaad2d389a31321ec4c2213df834b803eeed7 100644 (file)
@@ -966,6 +966,21 @@ var submenuData = {
        'mem.ksm': {
                title: 'Memory Deduper',
                info: 'Kernel Same-page Merging (KSM) is the kernel memory de-duper.'
+       },
+
+       'netfilter.conntrack': {
+               title: 'Connection Tracker',
+               info: 'The following information is taken from <code>/proc/net/stat/nf_conntrack</code>. The connection tracker keeps track of all connections of the machine, inbound and outbound. It works by keeping a database with all open connections, tracking network and address translation and connection expectations.'
+       },
+
+       'netfilter.nfacct': {
+               title: 'Bandwidth Accounting',
+               info: 'The following information is read using the <code>nfacct.plugin</code>.'
+       },
+
+       'netfilter.synproxy': {
+               title: 'Anti-DDoS Protection',
+               info: 'The following information is taken from <code>/proc/net/stat/synproxy</code>. <a href="https://github.com/firehol/firehol/wiki/Working-with-SYNPROXY" target="_blank">SYNPROXY</a> is a TCP SYN packets proxy. It is used to protect any TCP server (like a web server) from SYN floods and similar DDoS attacks. It is a netfilter module, in the Linux kernel (since version 3.12). It is optimized to handle millions of packets per second utilizing all CPUs available without any concurrency locking between the connections. It can be used for any kind of TCP traffic (even encrypted), since it does not interfere with the content itself.'
        }
 };