]>
Commit | Line | Data |
---|---|---|
0ec1854a MT |
1 | #!/usr/bin/python |
2 | ############################################################################### | |
3 | # # | |
4 | # collecty - A system statistics collection daemon for IPFire # | |
5 | # Copyright (C) 2015 IPFire development team # | |
6 | # # | |
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. # | |
11 | # # | |
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. # | |
16 | # # | |
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/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | import os | |
23 | ||
24 | import base | |
25 | ||
26 | CONNTRACK_FILE = "/proc/net/nf_conntrack" | |
27 | ||
28 | class ConntrackTable(object): | |
29 | _layer3_protocols = ( | |
30 | "ipv6", | |
31 | "ipv4", | |
32 | "other", | |
33 | ) | |
34 | ||
35 | _layer4_protocols = ( | |
36 | "dccp", | |
37 | "icmp", | |
38 | "igmp", | |
39 | "sctp", | |
40 | "tcp", | |
41 | "udp", | |
42 | "udplite", | |
43 | "other", | |
44 | ) | |
45 | ||
46 | _stateful_layer4_protocols = { | |
47 | "dccp" : ( | |
48 | "CLOSEREQ", | |
49 | "CLOSING", | |
50 | "IGNORE", | |
51 | "INVALID", | |
52 | "NONE", | |
53 | "OPEN", | |
54 | "PARTOPEN", | |
55 | "REQUEST", | |
56 | "RESPOND", | |
57 | "TIME_WAIT", | |
58 | ), | |
59 | "sctp" : ( | |
60 | "CLOSED", | |
61 | "COOKIE_ECHOED", | |
62 | "COOKIE_WAIT", | |
63 | "ESTABLISHED", | |
64 | "NONE", | |
65 | "SHUTDOWN_ACK_SENT", | |
66 | "SHUTDOWN_RECD", | |
67 | "SHUTDOWN_SENT", | |
68 | ), | |
69 | "tcp" : ( | |
70 | "CLOSE", | |
71 | "CLOSE_WAIT", | |
72 | "ESTABLISHED", | |
73 | "FIN_WAIT", | |
74 | "LAST_ACK", | |
75 | "NONE", | |
76 | "SYN_RECV", | |
77 | "SYN_SENT", | |
78 | "SYN_SENT2", | |
79 | "TIME_WAIT", | |
80 | ), | |
81 | } | |
82 | ||
83 | def __init__(self, filename): | |
84 | with open(filename) as f: | |
85 | self.layer3_protocols = {} | |
86 | for proto in self._layer3_protocols: | |
87 | self.layer3_protocols[proto] = 0 | |
88 | ||
89 | self.layer4_protocols = {} | |
90 | for proto in self._layer4_protocols: | |
91 | self.layer4_protocols[proto] = 0 | |
92 | ||
93 | self.protocol_states = {} | |
94 | for proto, states in self._stateful_layer4_protocols.items(): | |
95 | self.protocol_states[proto] = dict((state, 0) for state in states) | |
96 | ||
97 | for line in f.readlines(): | |
98 | line = line.split() | |
99 | ||
100 | # Layer 3 protocol | |
101 | layer3_protocol = line[0] | |
102 | ||
103 | try: | |
104 | self.layer3_protocols[layer3_protocol] += 1 | |
105 | except KeyError: | |
106 | self.layer3_protocols["other"] += 1 | |
107 | ||
108 | # Layer 4 protocol | |
109 | layer4_protocol = line[2] | |
110 | ||
111 | try: | |
112 | self.layer4_protocols[layer4_protocol] += 1 | |
113 | except KeyError: | |
114 | self.layer4_protocols["other"] += 1 | |
115 | layer4_protocol = "other" | |
116 | ||
117 | # Count connection states | |
118 | if self.protocol_states.has_key(layer4_protocol): | |
119 | state = line[5] | |
120 | ||
121 | try: | |
122 | self.protocol_states[layer4_protocol][state] += 1 | |
123 | except KeyError: | |
124 | pass | |
125 | ||
126 | ||
127 | class ConntrackObject(base.Object): | |
128 | protocol = None | |
129 | ||
130 | def init(self, conntrack_table): | |
131 | self.conntrack_table = conntrack_table | |
132 | ||
133 | @property | |
134 | def id(self): | |
135 | return self.protocol | |
136 | ||
137 | ||
138 | class ConntrackLayer3ProtocolsObject(ConntrackObject): | |
139 | protocols = ConntrackTable._layer3_protocols | |
140 | ||
141 | rrd_schema = [ | |
142 | "DS:%s:GAUGE:0:U" % p for p in protocols | |
143 | ] | |
144 | ||
145 | @property | |
146 | def id(self): | |
147 | return "layer3-protocols" | |
148 | ||
149 | def collect(self): | |
150 | results = [] | |
151 | ||
152 | for proto in self.protocols: | |
153 | r = self.conntrack_table.layer3_protocols.get(proto, 0) | |
154 | results.append("%s" % r) | |
155 | ||
156 | return ":".join(results) | |
157 | ||
158 | ||
159 | class ConntrackLayer4ProtocolsObject(ConntrackObject): | |
160 | protocols = ConntrackTable._layer4_protocols | |
161 | ||
162 | rrd_schema = [ | |
163 | "DS:%s:GAUGE:0:U" % p for p in protocols | |
164 | ] | |
165 | ||
166 | @property | |
167 | def id(self): | |
168 | return "layer4-protocols" | |
169 | ||
170 | def collect(self): | |
171 | results = [] | |
172 | ||
173 | for proto in self.protocols: | |
174 | r = self.conntrack_table.layer4_protocols.get(proto, 0) | |
175 | results.append("%s" % r) | |
176 | ||
177 | return ":".join(results) | |
178 | ||
179 | ||
180 | class ConntrackProtocolWithStatesObject(ConntrackObject): | |
181 | def init(self, conntrack_table, protocol): | |
182 | ConntrackObject.init(self, conntrack_table) | |
183 | self.protocol = protocol | |
184 | ||
b54c3e02 MT |
185 | def __repr__(self): |
186 | return "<%s %s>" % (self.__class__.__name__, self.protocol) | |
187 | ||
0ec1854a MT |
188 | @property |
189 | def states(self): | |
190 | return ConntrackTable._stateful_layer4_protocols.get(self.protocol) | |
191 | ||
192 | @property | |
193 | def rrd_schema(self): | |
194 | return ["DS:%s:GAUGE:0:U" % state for state in self.states] | |
195 | ||
196 | def get_states(self): | |
197 | results = [] | |
198 | ||
199 | for state in self.states: | |
200 | r = self.conntrack_table.protocol_states[self.protocol].get(state, 0) | |
201 | results.append("%s" % r) | |
202 | ||
203 | return results | |
204 | ||
205 | def collect(self): | |
206 | return ":".join(self.get_states()) | |
207 | ||
208 | ||
209 | class ConntrackPlugin(base.Plugin): | |
210 | name = "conntrack" | |
211 | description = "Conntrack Plugin" | |
212 | ||
213 | templates = [] | |
214 | ||
215 | @property | |
216 | def objects(self): | |
217 | ct = self.get_conntrack_table() | |
218 | ||
219 | if ct: | |
220 | yield ConntrackLayer3ProtocolsObject(self, ct) | |
221 | yield ConntrackLayer4ProtocolsObject(self, ct) | |
222 | ||
223 | for protocol in ConntrackTable._stateful_layer4_protocols: | |
224 | yield ConntrackProtocolWithStatesObject(self, ct, protocol) | |
225 | ||
226 | def get_conntrack_table(self): | |
227 | if not os.path.exists(CONNTRACK_FILE): | |
228 | return | |
229 | ||
230 | return ConntrackTable(CONNTRACK_FILE) |