2 ###############################################################################
4 # collecty - A system statistics collection daemon for IPFire #
5 # Copyright (C) 2015 IPFire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
28 CONNTRACK_FILE
= "/proc/net/nf_conntrack"
30 class ConntrackTable(object):
48 _stateful_layer4_protocols
= {
85 def __init__(self
, filename
):
86 with
open(filename
) as f
:
87 self
.layer3_protocols
= {}
88 for proto
in self
._layer
3_protocols
:
89 self
.layer3_protocols
[proto
] = 0
91 self
.layer4_protocols
= {}
92 for proto
in self
._layer
4_protocols
:
93 self
.layer4_protocols
[proto
] = 0
95 self
.protocol_states
= {}
96 for proto
, states
in self
._stateful
_layer
4_protocols
.items():
97 self
.protocol_states
[proto
] = dict((state
, 0) for state
in states
)
99 for line
in f
.readlines():
103 layer3_protocol
= line
[0]
106 self
.layer3_protocols
[layer3_protocol
] += 1
108 self
.layer3_protocols
["other"] += 1
111 layer4_protocol
= line
[2]
114 self
.layer4_protocols
[layer4_protocol
] += 1
116 self
.layer4_protocols
["other"] += 1
117 layer4_protocol
= "other"
119 # Count connection states
120 if layer4_protocol
in self
.protocol_states
:
124 self
.protocol_states
[layer4_protocol
][state
] += 1
129 class ConntrackLayer3ProtocolsGraphTemplate(base
.GraphTemplate
):
130 name
= "conntrack-layer3-protocols"
132 protocols
= ConntrackTable
._layer
3_protocols
140 def protocol_descriptions(self
):
141 _
= self
.locale
.translate
146 "other" : _("Other"),
150 def graph_title(self
):
151 _
= self
.locale
.translate
152 return _("Connections by Layer 3 Protocols")
155 def graph_vertical_label(self
):
156 _
= self
.locale
.translate
157 return _("Number of open connections")
159 def get_object_table(self
, object_id
):
161 "file" : self
.plugin
.get_object("layer3-protocols"),
166 _
= self
.locale
.translate
169 for proto
in reversed(self
.protocols
):
171 "colour" : self
.protocol_colours
.get(proto
, "#000000"),
172 "description" : self
.protocol_descriptions
.get(proto
, proto
),
176 "legend_min" : "%10s\: %%8.0lf" % _("Minimum"),
177 "legend_max" : "%10s\: %%8.0lf" % _("Maximum"),
178 "legend_avg" : "%10s\: %%8.0lf" % _("Average"),
179 "legend_cur" : "%10s\: %%8.0lf" % _("Current"),
183 "DEF:%(proto)s=%%(file)s:%(proto)s:AVERAGE" % i
,
184 "AREA:%(proto)s%(colour)s:%(description)-15s:STACK" % i
,
185 "VDEF:%(proto)s_cur=%(proto)s,LAST" % i
,
186 "GPRINT:%(proto)s_cur:%(legend_cur)s" % i
,
187 "VDEF:%(proto)s_avg=%(proto)s,AVERAGE" % i
,
188 "GPRINT:%(proto)s_avg:%(legend_avg)s" % i
,
189 "VDEF:%(proto)s_min=%(proto)s,MINIMUM" % i
,
190 "GPRINT:%(proto)s_min:%(legend_min)s" % i
,
191 "VDEF:%(proto)s_max=%(proto)s,MAXIMUM" % i
,
192 "GPRINT:%(proto)s_max:%(legend_max)s\\n" % i
,
198 def rrd_graph_args(self
):
200 "--legend-direction=bottomup",
204 class ConntrackLayer4ProtocolsGraphTemplate(ConntrackLayer3ProtocolsGraphTemplate
):
205 name
= "conntrack-layer4-protocols"
212 "udplite" : "#3366cc",
218 def protocol_descriptions(self
):
219 _
= self
.locale
.translate
226 "udplite" : _("UDP Lite"),
229 "other" : _("Other"),
232 protocol_sortorder
= {
243 def graph_title(self
):
244 _
= self
.locale
.translate
245 return _("Connections by IP Protocols")
249 return sorted(ConntrackTable
._layer
4_protocols
,
250 key
=lambda x
: self
.protocol_sortorder
.get(x
, 99))
252 def get_object_table(self
, object_id
):
254 "file" : self
.plugin
.get_object("layer4-protocols"),
259 class ConntrackProtocolWithStatesGraphTemplate(base
.GraphTemplate
):
260 name
= "conntrack-protocol-states"
266 "CLOSEREQ" : "#000000",
267 "CLOSING" : "#111111",
268 "IGNORE" : "#222222",
269 "INVALID" : "#333333",
272 "PARTOPEN" : "#666666",
273 "REQUEST" : "#777777",
274 "RESPOND" : "#888888",
275 "TIME_WAIT" : "#999999",
278 "CLOSED" : "#000000",
279 "COOKIE_ECHOED" : "#111111",
280 "COOKIE_WAIT" : "#222222",
281 "ESTABLISHED" : "#333333",
283 "SHUTDOWN_ACK_SENT" : "#555555",
284 "SHUTDOWN_RECD" : "#666666",
285 "SHUTDOWN_SENT" : "#777777",
289 "CLOSE_WAIT" : "#999999",
290 "ESTABLISHED" : "#000000",
291 "FIN_WAIT" : "#888888",
292 "LAST_ACK" : "#777777",
294 "SYN_RECV" : "#111111",
295 "SYN_SENT" : "#222222",
296 "SYN_SENT2" : "#333333",
297 "TIME_WAIT" : "#444444",
301 states_descriptions
= {
326 "SHUTDOWN_ACK_SENT" : 0,
345 def graph_title(self
):
346 _
= self
.locale
.translate
347 return _("Protocol States of all %s connections") % self
.protocol
.upper()
350 def graph_vertical_label(self
):
351 _
= self
.locale
.translate
352 return _("Number of open connections")
356 return self
.object.protocol
360 return sorted(ConntrackTable
._stateful
_layer
4_protocols
[self
.protocol
],
361 key
=lambda x
: self
.states_sortorder
[self
.protocol
].get(x
, 99))
365 _
= self
.locale
.translate
368 for state
in reversed(self
.states
):
370 "colour" : self
.states_colours
[self
.protocol
].get(state
, "#000000"),
371 "description" : self
.states_descriptions
[self
.protocol
].get(state
, state
),
372 "proto" : self
.protocol
,
375 "legend_min" : "%10s\: %%8.0lf" % _("Minimum"),
376 "legend_max" : "%10s\: %%8.0lf" % _("Maximum"),
377 "legend_avg" : "%10s\: %%8.0lf" % _("Average"),
378 "legend_cur" : "%10s\: %%8.0lf" % _("Current"),
382 "DEF:%(state)s=%%(file)s:%(state)s:AVERAGE" % i
,
383 "AREA:%(state)s%(colour)s:%(description)-15s:STACK" % i
,
384 "VDEF:%(state)s_cur=%(state)s,LAST" % i
,
385 "GPRINT:%(state)s_cur:%(legend_cur)s" % i
,
386 "VDEF:%(state)s_avg=%(state)s,AVERAGE" % i
,
387 "GPRINT:%(state)s_avg:%(legend_avg)s" % i
,
388 "VDEF:%(state)s_min=%(state)s,MINIMUM" % i
,
389 "GPRINT:%(state)s_min:%(legend_min)s" % i
,
390 "VDEF:%(state)s_max=%(state)s,MAXIMUM" % i
,
391 "GPRINT:%(state)s_max:%(legend_max)s\\n" % i
,
397 def rrd_graph_args(self
):
399 "--legend-direction=bottomup",
403 class ConntrackObject(base
.Object
):
406 def init(self
, conntrack_table
):
407 self
.conntrack_table
= conntrack_table
414 class ConntrackLayer3ProtocolsObject(ConntrackObject
):
415 protocols
= ConntrackTable
._layer
3_protocols
418 "DS:%s:GAUGE:0:U" % p
for p
in protocols
423 return "layer3-protocols"
428 for proto
in self
.protocols
:
429 r
= self
.conntrack_table
.layer3_protocols
.get(proto
, 0)
430 results
.append("%s" % r
)
435 class ConntrackLayer4ProtocolsObject(ConntrackObject
):
436 protocols
= ConntrackTable
._layer
4_protocols
439 "DS:%s:GAUGE:0:U" % p
for p
in protocols
444 return "layer4-protocols"
449 for proto
in self
.protocols
:
450 r
= self
.conntrack_table
.layer4_protocols
.get(proto
, 0)
451 results
.append("%s" % r
)
456 class ConntrackProtocolWithStatesObject(ConntrackObject
):
457 def init(self
, conntrack_table
, protocol
):
458 ConntrackObject
.init(self
, conntrack_table
)
459 self
.protocol
= protocol
462 return "<%s %s>" % (self
.__class
__.__name
__, self
.protocol
)
466 return ConntrackTable
._stateful
_layer
4_protocols
.get(self
.protocol
)
469 def rrd_schema(self
):
470 return ["DS:%s:GAUGE:0:U" % state
for state
in self
.states
]
472 def get_states(self
):
475 for state
in self
.states
:
476 r
= self
.conntrack_table
.protocol_states
[self
.protocol
].get(state
, 0)
477 results
.append("%s" % r
)
482 return self
.get_states()
485 class ConntrackPlugin(base
.Plugin
):
487 description
= "Conntrack Plugin"
490 ConntrackLayer3ProtocolsGraphTemplate
,
491 ConntrackLayer4ProtocolsGraphTemplate
,
492 ConntrackProtocolWithStatesGraphTemplate
,
497 ct
= self
.get_conntrack_table()
500 yield ConntrackLayer3ProtocolsObject(self
, ct
)
501 yield ConntrackLayer4ProtocolsObject(self
, ct
)
503 for protocol
in ConntrackTable
._stateful
_layer
4_protocols
:
504 yield ConntrackProtocolWithStatesObject(self
, ct
, protocol
)
506 def get_conntrack_table(self
):
507 if not os
.path
.exists(CONNTRACK_FILE
):
510 return ConntrackTable(CONNTRACK_FILE
)