new feature: added data collection for SYNPROXY - netfilter TCP anti-DDoS protection; renamed the conntrack and nfacct charts to group them under netfilter; updated the dashboard for netfilter;
Costa Tsaousis (ktsaou) committed
Apr 9, 2016 at 00:19 UTC
31a1faf7ad89b66a68b0ac548f1c9a9dfc3c37af
7 files changed
+183
-17
src/Makefile.am
+1
@@ -50,6 +50,7 @@ netdata_SOURCES = \
50
proc_net_snmp.c \
51
proc_net_snmp6.c \
52
proc_net_stat_conntrack.c \
53
+ proc_net_stat_synproxy.c \
54
proc_stat.c \
55
proc_sys_kernel_random_entropy_avail.c \
56
proc_vmstat.c \
src/plugin_nfacct.c
+4
-4
@@ -168,9 +168,9 @@ void *nfacct_main(void *ptr) {
168
if(nfacct_list && nfacct_list->len) {
169
int i;
170
171
- st = rrdset_find_bytype("nfacct", "packets");
171
+ st = rrdset_find_bytype("netfilter", "nfacct_packets");
172
if(!st) {
173
- st = rrdset_create("nfacct", "packets", NULL, "netfilter", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
173
+ st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 1006, rrd_update_every, RRDSET_TYPE_STACKED);
174
175
for(i = 0; i < nfacct_list->len ; i++)
176
rrddim_add(st, nfacct_list->data[i].name, NULL, 1, rrd_update_every, RRDDIM_INCREMENTAL);
@@ -188,9 +188,9 @@ void *nfacct_main(void *ptr) {
188
189
// ----------------------------------------------------------------
190
191
- st = rrdset_find_bytype("nfacct", "bytes");
191
+ st = rrdset_find_bytype("netfilter", "nfacct_bytes");
192
if(!st) {
193
- st = rrdset_create("nfacct", "bytes", NULL, "netfilter", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
193
+ st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 1007, rrd_update_every, RRDSET_TYPE_STACKED);
194
195
for(i = 0; i < nfacct_list->len ; i++)
196
rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * rrd_update_every, RRDDIM_INCREMENTAL);
src/plugin_proc.c
+10
@@ -47,6 +47,7 @@ void *proc_main(void *ptr)
47
int vdo_proc_net_netstat = !config_get_boolean("plugin:proc", "/proc/net/netstat", 1);
48
int vdo_proc_net_stat_conntrack = !config_get_boolean("plugin:proc", "/proc/net/stat/conntrack", 1);
49
int vdo_proc_net_ip_vs_stats = !config_get_boolean("plugin:proc", "/proc/net/ip_vs/stats", 1);
50
+ int vdo_proc_net_stat_synproxy = !config_get_boolean("plugin:proc", "/proc/net/stat/synproxy", 1);
51
int vdo_proc_stat = !config_get_boolean("plugin:proc", "/proc/stat", 1);
52
int vdo_proc_meminfo = !config_get_boolean("plugin:proc", "/proc/meminfo", 1);
53
int vdo_proc_vmstat = !config_get_boolean("plugin:proc", "/proc/vmstat", 1);
@@ -66,6 +67,7 @@ void *proc_main(void *ptr)
67
unsigned long long sutime_proc_net_netstat = 0ULL;
68
unsigned long long sutime_proc_net_stat_conntrack = 0ULL;
69
unsigned long long sutime_proc_net_ip_vs_stats = 0ULL;
70
+ unsigned long long sutime_proc_net_stat_synproxy = 0ULL;
71
unsigned long long sutime_proc_stat = 0ULL;
72
unsigned long long sutime_proc_meminfo = 0ULL;
73
unsigned long long sutime_proc_vmstat = 0ULL;
@@ -194,6 +196,14 @@ void *proc_main(void *ptr)
196
}
197
if(unlikely(netdata_exit)) break;
198
199
+ if(!vdo_proc_net_stat_synproxy) {
200
+ debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling vdo_proc_net_stat_synproxy().");
201
+ sunow = sutime();
202
+ 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);
203
+ sutime_proc_net_stat_synproxy = sunow;
204
+ }
205
+ if(unlikely(netdata_exit)) break;
206
+
207
if(!vdo_proc_stat) {
208
debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
209
sunow = sutime();
src/plugin_proc.h
+1
@@ -19,5 +19,6 @@ extern int do_proc_interrupts(int update_every, unsigned long long dt);
19
extern int do_proc_softirqs(int update_every, unsigned long long dt);
20
extern int do_sys_kernel_mm_ksm(int update_every, unsigned long long dt);
21
extern int do_proc_loadavg(int update_every, unsigned long long dt);
22
+extern int do_proc_net_stat_synproxy(int update_every, unsigned long long dt);
23
24
#endif /* NETDATA_PLUGIN_PROC_H */
src/proc_net_stat_conntrack.c
+14
-13
@@ -12,7 +12,8 @@
12
#include "rrd.h"
13
#include "plugin_proc.h"
14
15
-#define RRD_TYPE_NET_STAT_CONNTRACK "netfilter"
15
+#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
16
+#define RRD_TYPE_NET_STAT_CONNTRACK "conntrack"
17
#define RRD_TYPE_NET_STAT_CONNTRACK_LEN strlen(RRD_TYPE_NET_STAT_CONNTRACK)
18
19
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) {
98
// --------------------------------------------------------------------
99
100
if(do_sockets) {
100
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".sockets");
101
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_sockets");
102
if(!st) {
102
- 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);
103
+ 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);
104
105
rrddim_add(st, "connections", NULL, 1, 1, RRDDIM_ABSOLUTE);
106
}
@@ -112,9 +113,9 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
113
// --------------------------------------------------------------------
114
115
if(do_new) {
115
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".new");
116
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_new");
117
if(!st) {
117
- 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);
118
+ 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);
119
120
rrddim_add(st, "new", NULL, 1, 1, RRDDIM_INCREMENTAL);
121
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) {
132
// --------------------------------------------------------------------
133
134
if(do_changes) {
134
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".changes");
135
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_changes");
136
if(!st) {
136
- 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);
137
+ 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);
138
st->isdetail = 1;
139
140
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) {
152
// --------------------------------------------------------------------
153
154
if(do_expect) {
154
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".expect");
155
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_expect");
156
if(!st) {
156
- 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);
157
+ 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);
158
st->isdetail = 1;
159
160
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) {
172
// --------------------------------------------------------------------
173
174
if(do_search) {
174
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".search");
175
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_search");
176
if(!st) {
176
- 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);
177
+ 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);
178
st->isdetail = 1;
179
180
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) {
192
// --------------------------------------------------------------------
193
194
if(do_errors) {
194
- st = rrdset_find(RRD_TYPE_NET_STAT_CONNTRACK ".errors");
195
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_CONNTRACK "_errors");
196
if(!st) {
196
- 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);
197
+ 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);
198
st->isdetail = 1;
199
200
rrddim_add(st, "icmp_error", NULL, 1, 1, RRDDIM_INCREMENTAL);
src/proc_net_stat_synproxy.c
new
+138
@@ -0,0 +1,138 @@
1
+#ifdef HAVE_CONFIG_H
2
+#include <config.h>
3
+#endif
4
+#include <stdio.h>
5
+#include <stdlib.h>
6
+
7
+#include "common.h"
8
+#include "appconfig.h"
9
+#include "procfile.h"
10
+#include "rrd.h"
11
+#include "plugin_proc.h"
12
+#include "log.h"
13
+
14
+#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
15
+#define RRD_TYPE_NET_STAT_SYNPROXY "synproxy"
16
+#define RRD_TYPE_NET_STAT_SYNPROXY_LEN strlen(RRD_TYPE_NET_STAT_SYNPROXY)
17
+
18
+int do_proc_net_stat_synproxy(int update_every, unsigned long long dt) {
19
+ static int do_entries = -1, do_cookies = -1, do_syns = -1, do_reopened = -1;
20
+ static procfile *ff = NULL;
21
+
22
+ if(do_entries == -1) do_entries = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY entries", CONFIG_ONDEMAND_ONDEMAND);
23
+ if(do_cookies == -1) do_cookies = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY cookies", CONFIG_ONDEMAND_ONDEMAND);
24
+ if(do_syns == -1) do_syns = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY SYN received", CONFIG_ONDEMAND_ONDEMAND);
25
+ if(do_reopened == -1) do_reopened = config_get_boolean_ondemand("plugin:proc:/proc/net/stat/synproxy", "SYNPROXY connections reopened", CONFIG_ONDEMAND_ONDEMAND);
26
+
27
+ if(dt) {};
28
+
29
+ if(!ff) {
30
+ char filename[FILENAME_MAX + 1];
31
+ snprintf(filename, FILENAME_MAX, "%s%s", global_host_prefix, "/proc/net/stat/synproxy");
32
+ ff = procfile_open(config_get("plugin:proc:/proc/net/stat/synproxy", "filename to monitor", filename), " \t,:|", PROCFILE_FLAG_DEFAULT);
33
+ }
34
+ if(!ff) return 1;
35
+
36
+ ff = procfile_readall(ff);
37
+ if(!ff) return 0; // we return 0, so that we will retry to open it next time
38
+
39
+ // make sure we have 3 lines
40
+ unsigned long lines = procfile_lines(ff), l;
41
+ if(lines < 2) {
42
+ error("/proc/net/stat/synproxy has %d lines, expected no less than 2. Disabling it.", lines);
43
+ return 1;
44
+ }
45
+
46
+ unsigned long long entries = 0, syn_received = 0, cookie_invalid = 0, cookie_valid = 0, cookie_retrans = 0, conn_reopened = 0;
47
+
48
+ // synproxy gives its values per CPU
49
+ for(l = 1; l < lines ;l++) {
50
+ int words = procfile_linewords(ff, l);
51
+ if(words < 6) continue;
52
+
53
+ entries += strtoull(procfile_lineword(ff, l, 0), NULL, 16);
54
+ syn_received += strtoull(procfile_lineword(ff, l, 1), NULL, 16);
55
+ cookie_invalid += strtoull(procfile_lineword(ff, l, 2), NULL, 16);
56
+ cookie_valid += strtoull(procfile_lineword(ff, l, 3), NULL, 16);
57
+ cookie_retrans += strtoull(procfile_lineword(ff, l, 4), NULL, 16);
58
+ conn_reopened += strtoull(procfile_lineword(ff, l, 5), NULL, 16);
59
+ }
60
+
61
+ unsigned long long events = entries + syn_received + cookie_invalid + cookie_valid + cookie_retrans + conn_reopened;
62
+
63
+ RRDSET *st;
64
+
65
+ // --------------------------------------------------------------------
66
+
67
+ if((do_entries == CONFIG_ONDEMAND_ONDEMAND && events) || do_entries == CONFIG_ONDEMAND_YES) {
68
+ do_entries = CONFIG_ONDEMAND_YES;
69
+
70
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_entries");
71
+ if(!st) {
72
+ 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);
73
+
74
+ rrddim_add(st, "entries", NULL, 1, 1, RRDDIM_ABSOLUTE);
75
+ }
76
+ else rrdset_next(st);
77
+
78
+ rrddim_set(st, "entries", entries);
79
+ rrdset_done(st);
80
+ }
81
+
82
+ // --------------------------------------------------------------------
83
+
84
+ if((do_syns == CONFIG_ONDEMAND_ONDEMAND && events) || do_syns == CONFIG_ONDEMAND_YES) {
85
+ do_syns = CONFIG_ONDEMAND_YES;
86
+
87
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_syn_received");
88
+ if(!st) {
89
+ 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);
90
+
91
+ rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
92
+ }
93
+ else rrdset_next(st);
94
+
95
+ rrddim_set(st, "received", syn_received);
96
+ rrdset_done(st);
97
+ }
98
+
99
+ // --------------------------------------------------------------------
100
+
101
+ if((do_reopened == CONFIG_ONDEMAND_ONDEMAND && events) || do_reopened == CONFIG_ONDEMAND_YES) {
102
+ do_reopened = CONFIG_ONDEMAND_YES;
103
+
104
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_conn_reopened");
105
+ if(!st) {
106
+ 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);
107
+
108
+ rrddim_add(st, "reopened", NULL, 1, 1, RRDDIM_INCREMENTAL);
109
+ }
110
+ else rrdset_next(st);
111
+
112
+ rrddim_set(st, "reopened", conn_reopened);
113
+ rrdset_done(st);
114
+ }
115
+
116
+ // --------------------------------------------------------------------
117
+
118
+ if((do_cookies == CONFIG_ONDEMAND_ONDEMAND && events) || do_cookies == CONFIG_ONDEMAND_YES) {
119
+ do_cookies = CONFIG_ONDEMAND_YES;
120
+
121
+ st = rrdset_find(RRD_TYPE_NET_STAT_NETFILTER "." RRD_TYPE_NET_STAT_SYNPROXY "_cookies");
122
+ if(!st) {
123
+ 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);
124
+
125
+ rrddim_add(st, "valid", NULL, 1, 1, RRDDIM_INCREMENTAL);
126
+ rrddim_add(st, "invalid", NULL, -1, 1, RRDDIM_INCREMENTAL);
127
+ rrddim_add(st, "retransmits", NULL, 1, 1, RRDDIM_INCREMENTAL);
128
+ }
129
+ else rrdset_next(st);
130
+
131
+ rrddim_set(st, "valid", cookie_valid);
132
+ rrddim_set(st, "invalid", cookie_invalid);
133
+ rrddim_set(st, "retransmits", cookie_retrans);
134
+ rrdset_done(st);
135
+ }
136
+
137
+ return 0;
138
+}
web/index.html
+15
@@ -966,6 +966,21 @@ var submenuData = {
966
'mem.ksm': {
967
title: 'Memory Deduper',
968
info: 'Kernel Same-page Merging (KSM) is the kernel memory de-duper.'
969
+ },
970
+
971
+ 'netfilter.conntrack': {
972
+ title: 'Connection Tracker',
973
+ 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.'
974
+ },
975
+
976
+ 'netfilter.nfacct': {
977
+ title: 'Bandwidth Accounting',
978
+ info: 'The following information is read using the <code>nfacct.plugin</code>.'
979
+ },
980
+
981
+ 'netfilter.synproxy': {
982
+ title: 'Anti-DDoS Protection',
983
+ 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.'
984
}
985
};
986