Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/nfstream/flow.py: 6%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2------------------------------------------------------------------------------------------------------------------------
3flow.py
4Copyright (C) 2019-22 - NFStream Developers
5This file is part of NFStream, a Flexible Network Data Analysis Framework (https://www.nfstream.org/).
6NFStream is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
7License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
8version.
9NFStream is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
10of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11You should have received a copy of the GNU Lesser General Public License along with NFStream.
12If not, see <http://www.gnu.org/licenses/>.
13------------------------------------------------------------------------------------------------------------------------
14"""
16from collections import namedtuple
17from math import sqrt
18from .utils import NFEvent
20# When NFStream is extended with plugins, packer C structure is pythonized using the following namedtuple.
21nf_packet = namedtuple(
22 "NFPacket",
23 [
24 "time",
25 "delta_time",
26 "direction",
27 "raw_size",
28 "ip_size",
29 "transport_size",
30 "payload_size",
31 "src_ip",
32 "src_mac",
33 "src_oui",
34 "dst_ip",
35 "dst_mac",
36 "dst_oui",
37 "src_port",
38 "dst_port",
39 "protocol",
40 "vlan_id",
41 "ip_version",
42 "ip_packet",
43 "syn",
44 "cwr",
45 "ece",
46 "urg",
47 "ack",
48 "psh",
49 "rst",
50 "fin",
51 "tunnel_id",
52 ],
53)
56class UDPS(object):
57 """dummy class that add udps slot the flexibility required for extensions"""
60def pythonize_packet(packet, ffi, flow):
61 """convert a cdata packet to a namedtuple"""
62 src_ip = flow.src_ip
63 dst_ip = flow.dst_ip
64 src_mac = flow.src_mac
65 dst_mac = flow.dst_mac
66 src_oui = flow.src_oui
67 dst_oui = flow.dst_oui
68 if packet.direction:
69 src_ip = flow.dst_ip
70 dst_ip = flow.src_ip
71 src_mac = flow.dst_mac
72 dst_mac = flow.src_mac
73 src_oui = flow.dst_oui
74 dst_oui = flow.src_oui
76 return nf_packet(
77 time=packet.time,
78 delta_time=packet.delta_time,
79 direction=packet.direction,
80 raw_size=packet.raw_size,
81 ip_size=packet.ip_size,
82 transport_size=packet.transport_size,
83 payload_size=packet.payload_size,
84 src_ip=src_ip,
85 src_mac=src_mac,
86 src_oui=src_oui,
87 dst_ip=dst_ip,
88 dst_mac=dst_mac,
89 dst_oui=dst_oui,
90 src_port=packet.src_port,
91 dst_port=packet.dst_port,
92 protocol=packet.protocol,
93 vlan_id=packet.vlan_id,
94 ip_version=packet.ip_version,
95 ip_packet=bytes(ffi.buffer(packet.ip_content, packet.ip_content_len)),
96 syn=packet.syn,
97 cwr=packet.cwr,
98 ece=packet.ece,
99 urg=packet.urg,
100 ack=packet.ack,
101 psh=packet.psh,
102 rst=packet.rst,
103 fin=packet.fin,
104 tunnel_id=packet.tunnel_id,
105 )
108class NFlow(object):
109 """
110 NFlow is NFStream representation of a network flow.
111 It is a slotted class for performances reasons, and slots are initiated according to NFStream detected mode.
112 If nfstream is used with extension, we refer to it as sync mode, and we need to update slots from C structure.
113 If not, nfstream will compute all configured metrics within C structure and update it only at init and expire.
114 Such logic allows us to provide maximum performances when running without extensions. When set with extension
115 we pay the cost of flexibility with attributes access/update.
117 """
119 __slots__ = (
120 "id",
121 "expiration_id",
122 "src_ip",
123 "src_mac",
124 "src_oui",
125 "src_port",
126 "dst_ip",
127 "dst_mac",
128 "dst_oui",
129 "dst_port",
130 "protocol",
131 "ip_version",
132 "vlan_id",
133 "tunnel_id",
134 "bidirectional_first_seen_ms",
135 "bidirectional_last_seen_ms",
136 "bidirectional_duration_ms",
137 "bidirectional_packets",
138 "bidirectional_bytes",
139 "src2dst_first_seen_ms",
140 "src2dst_last_seen_ms",
141 "src2dst_duration_ms",
142 "src2dst_packets",
143 "src2dst_bytes",
144 "dst2src_first_seen_ms",
145 "dst2src_last_seen_ms",
146 "dst2src_duration_ms",
147 "dst2src_packets",
148 "dst2src_bytes",
149 "bidirectional_min_ps",
150 "bidirectional_mean_ps",
151 "bidirectional_stddev_ps",
152 "bidirectional_max_ps",
153 "src2dst_min_ps",
154 "src2dst_mean_ps",
155 "src2dst_stddev_ps",
156 "src2dst_max_ps",
157 "dst2src_min_ps",
158 "dst2src_mean_ps",
159 "dst2src_stddev_ps",
160 "dst2src_max_ps",
161 "bidirectional_min_piat_ms",
162 "bidirectional_mean_piat_ms",
163 "bidirectional_stddev_piat_ms",
164 "bidirectional_max_piat_ms",
165 "src2dst_min_piat_ms",
166 "src2dst_mean_piat_ms",
167 "src2dst_stddev_piat_ms",
168 "src2dst_max_piat_ms",
169 "dst2src_min_piat_ms",
170 "dst2src_mean_piat_ms",
171 "dst2src_stddev_piat_ms",
172 "dst2src_max_piat_ms",
173 "bidirectional_syn_packets",
174 "bidirectional_cwr_packets",
175 "bidirectional_ece_packets",
176 "bidirectional_urg_packets",
177 "bidirectional_ack_packets",
178 "bidirectional_psh_packets",
179 "bidirectional_rst_packets",
180 "bidirectional_fin_packets",
181 "src2dst_syn_packets",
182 "src2dst_cwr_packets",
183 "src2dst_ece_packets",
184 "src2dst_urg_packets",
185 "src2dst_ack_packets",
186 "src2dst_psh_packets",
187 "src2dst_rst_packets",
188 "src2dst_fin_packets",
189 "dst2src_syn_packets",
190 "dst2src_cwr_packets",
191 "dst2src_ece_packets",
192 "dst2src_urg_packets",
193 "dst2src_ack_packets",
194 "dst2src_psh_packets",
195 "dst2src_rst_packets",
196 "dst2src_fin_packets",
197 "splt_direction",
198 "splt_ps",
199 "splt_piat_ms",
200 "application_name",
201 "application_category_name",
202 "application_is_guessed",
203 "application_confidence",
204 "requested_server_name",
205 "client_fingerprint",
206 "server_fingerprint",
207 "user_agent",
208 "content_type",
209 "_C",
210 "udps",
211 "system_process_pid",
212 "system_process_name",
213 "system_browser_tab",
214 )
216 def __init__(
217 self,
218 packet,
219 ffi,
220 lib,
221 udps,
222 sync,
223 accounting_mode,
224 n_dissections,
225 statistics,
226 splt,
227 dissector,
228 decode_tunnels,
229 system_visibility_mode,
230 ):
231 self.id = (
232 NFEvent.FLOW
233 ) # id set to NFLOW for internal communications and handled (incremented) by NFStreamer.
234 self.expiration_id = 0
235 # Initialize C structure.
236 self._C = lib.meter_initialize_flow(
237 packet, accounting_mode, statistics, splt, n_dissections, dissector, sync
238 )
239 if self._C == ffi.NULL: # raise OSError in order to be handled by meter.
240 raise OSError("Not enough memory for new flow creation.")
241 # Here we go for the first copy in order to make defined slots available
242 self.src_ip = ffi.string(self._C.src_ip_str).decode("utf-8", errors="ignore")
243 self.src_mac = ffi.string(self._C.src_mac_str).decode("utf-8", errors="ignore")
244 self.src_oui = ffi.string(self._C.src_oui).decode("utf-8", errors="ignore")
245 self.src_port = self._C.src_port
246 self.dst_ip = ffi.string(self._C.dst_ip_str).decode("utf-8", errors="ignore")
247 self.dst_mac = ffi.string(self._C.dst_mac_str).decode("utf-8", errors="ignore")
248 self.dst_oui = ffi.string(self._C.dst_oui).decode("utf-8", errors="ignore")
249 self.dst_port = self._C.dst_port
250 self.protocol = self._C.protocol
251 self.ip_version = self._C.ip_version
252 self.vlan_id = self._C.vlan_id
253 self.bidirectional_first_seen_ms = self._C.bidirectional_first_seen_ms
254 self.bidirectional_last_seen_ms = self._C.bidirectional_last_seen_ms
255 self.bidirectional_duration_ms = self._C.bidirectional_duration_ms
256 self.bidirectional_packets = self._C.bidirectional_packets
257 self.bidirectional_bytes = self._C.bidirectional_bytes
258 self.src2dst_first_seen_ms = self._C.src2dst_first_seen_ms
259 self.src2dst_last_seen_ms = self._C.src2dst_last_seen_ms
260 self.src2dst_duration_ms = self._C.src2dst_duration_ms
261 self.src2dst_packets = self._C.src2dst_packets
262 self.src2dst_bytes = self._C.src2dst_bytes
263 self.dst2src_first_seen_ms = self._C.dst2src_first_seen_ms
264 self.dst2src_last_seen_ms = self._C.dst2src_last_seen_ms
265 self.dst2src_duration_ms = self._C.dst2src_duration_ms
266 self.dst2src_packets = self._C.dst2src_packets
267 self.dst2src_bytes = self._C.dst2src_bytes
268 if decode_tunnels:
269 self.tunnel_id = self._C.tunnel_id
270 if statistics: # if statistical analysis set, we activate statistical slots.
271 self.bidirectional_min_ps = self._C.bidirectional_min_ps
272 self.bidirectional_mean_ps = self._C.bidirectional_mean_ps
273 self.bidirectional_stddev_ps = self._C.bidirectional_stddev_ps
274 self.bidirectional_max_ps = self._C.bidirectional_max_ps
275 self.src2dst_min_ps = self._C.src2dst_min_ps
276 self.src2dst_mean_ps = self._C.src2dst_mean_ps
277 self.src2dst_stddev_ps = self._C.src2dst_stddev_ps
278 self.src2dst_max_ps = self._C.src2dst_max_ps
279 self.dst2src_min_ps = self._C.dst2src_min_ps
280 self.dst2src_mean_ps = self._C.dst2src_mean_ps
281 self.dst2src_stddev_ps = self._C.dst2src_stddev_ps
282 self.dst2src_max_ps = self._C.dst2src_max_ps
283 self.bidirectional_min_piat_ms = self._C.bidirectional_min_piat_ms
284 self.bidirectional_mean_piat_ms = self._C.bidirectional_mean_piat_ms
285 self.bidirectional_stddev_piat_ms = self._C.bidirectional_stddev_piat_ms
286 self.bidirectional_max_piat_ms = self._C.bidirectional_max_piat_ms
287 self.src2dst_min_piat_ms = self._C.src2dst_min_piat_ms
288 self.src2dst_mean_piat_ms = self._C.src2dst_mean_piat_ms
289 self.src2dst_stddev_piat_ms = self._C.src2dst_stddev_piat_ms
290 self.src2dst_max_piat_ms = self._C.src2dst_max_piat_ms
291 self.dst2src_min_piat_ms = self._C.dst2src_min_piat_ms
292 self.dst2src_mean_piat_ms = self._C.dst2src_mean_piat_ms
293 self.dst2src_stddev_piat_ms = self._C.dst2src_stddev_piat_ms
294 self.dst2src_max_piat_ms = self._C.dst2src_max_piat_ms
295 self.bidirectional_syn_packets = self._C.bidirectional_syn_packets
296 self.bidirectional_cwr_packets = self._C.bidirectional_cwr_packets
297 self.bidirectional_ece_packets = self._C.bidirectional_ece_packets
298 self.bidirectional_urg_packets = self._C.bidirectional_urg_packets
299 self.bidirectional_ack_packets = self._C.bidirectional_ack_packets
300 self.bidirectional_psh_packets = self._C.bidirectional_psh_packets
301 self.bidirectional_rst_packets = self._C.bidirectional_rst_packets
302 self.bidirectional_fin_packets = self._C.bidirectional_fin_packets
303 self.src2dst_syn_packets = self._C.src2dst_syn_packets
304 self.src2dst_cwr_packets = self._C.src2dst_cwr_packets
305 self.src2dst_ece_packets = self._C.src2dst_ece_packets
306 self.src2dst_urg_packets = self._C.src2dst_urg_packets
307 self.src2dst_ack_packets = self._C.src2dst_ack_packets
308 self.src2dst_psh_packets = self._C.src2dst_psh_packets
309 self.src2dst_rst_packets = self._C.src2dst_rst_packets
310 self.src2dst_fin_packets = self._C.src2dst_fin_packets
311 self.dst2src_syn_packets = self._C.dst2src_syn_packets
312 self.dst2src_cwr_packets = self._C.dst2src_cwr_packets
313 self.dst2src_ece_packets = self._C.dst2src_ece_packets
314 self.dst2src_urg_packets = self._C.dst2src_urg_packets
315 self.dst2src_ack_packets = self._C.dst2src_ack_packets
316 self.dst2src_psh_packets = self._C.dst2src_psh_packets
317 self.dst2src_rst_packets = self._C.dst2src_rst_packets
318 self.dst2src_fin_packets = self._C.dst2src_fin_packets
319 if n_dissections: # Same for dissection when > 0
320 if sync:
321 self.application_name = ffi.string(self._C.application_name).decode(
322 "utf-8", errors="ignore"
323 )
324 self.application_category_name = ffi.string(
325 self._C.category_name
326 ).decode("utf-8", errors="ignore")
327 self.application_is_guessed = self._C.guessed
328 self.application_confidence = self._C.confidence
329 self.requested_server_name = (
330 ffi.string(self._C.requested_server_name).decode(
331 "utf-8", errors="ignore"
332 )
333 or None
334 )
335 self.client_fingerprint = (
336 ffi.string(self._C.c_hash).decode("utf-8", errors="ignore") or None
337 )
338 self.server_fingerprint = (
339 ffi.string(self._C.s_hash).decode("utf-8", errors="ignore") or None
340 )
341 self.user_agent = (
342 ffi.string(self._C.user_agent).decode("utf-8", errors="ignore")
343 or None
344 )
345 self.content_type = (
346 ffi.string(self._C.content_type).decode("utf-8", errors="ignore")
347 or None
348 )
349 else:
350 self.application_name = None
351 self.application_category_name = None
352 self.application_is_guessed = None
353 self.application_confidence = None
354 self.requested_server_name = None
355 self.client_fingerprint = None
356 self.server_fingerprint = None
357 self.user_agent = None
358 self.content_type = None
359 if splt: # If splt_analysis set (>0), we unpack the arrays structures.
360 self.splt_direction = ffi.unpack(self._C.splt_direction, splt)
361 self.splt_ps = ffi.unpack(self._C.splt_ps, splt)
362 self.splt_piat_ms = ffi.unpack(self._C.splt_piat_ms, splt)
363 if sync: # NFStream running with Plugins
364 self.udps = UDPS()
365 for udp in udps: # on_init entrypoint
366 udp.on_init(pythonize_packet(packet, ffi, self), self)
367 if system_visibility_mode > 0:
368 self.system_process_pid = -1
369 self.system_process_name = ""
370 if system_visibility_mode == 2:
371 self.system_browser_tab = ""
373 def update(
374 self,
375 packet,
376 idle_timeout,
377 active_timeout,
378 ffi,
379 lib,
380 udps,
381 sync,
382 accounting_mode,
383 n_dissections,
384 statistics,
385 splt,
386 dissector,
387 ):
388 """NFlow update method"""
389 # First, we update internal C structure.
390 ret = lib.meter_update_flow(
391 self._C,
392 packet,
393 idle_timeout,
394 active_timeout,
395 accounting_mode,
396 statistics,
397 splt,
398 n_dissections,
399 dissector,
400 sync,
401 )
402 if (
403 ret > 0
404 ): # If update done it will be zero, idle and active are matched to 1 and 2.
405 self.expiration_id = ret - 1
406 return self.expire(
407 udps, sync, n_dissections, statistics, splt, ffi, lib, dissector
408 ) # expire it.
409 if sync: # If running with Plugins
410 self.sync(n_dissections, statistics, splt, ffi, lib, sync)
411 # We need to copy computed values on C struct.
412 for udp in udps: # Then call each plugin on_update entrypoint.
413 udp.on_update(pythonize_packet(packet, ffi, self), self)
414 if (
415 self.expiration_id == -1
416 ): # One of the plugins set expiration to custom value (-1)
417 return self.expire(
418 udps, sync, n_dissections, statistics, splt, ffi, lib, dissector
419 ) # Expire it.
421 def expire(self, udps, sync, n_dissections, statistics, splt, ffi, lib, dissector):
422 """NFlow expiration method"""
423 # Call expiration of C structure.
424 lib.meter_expire_flow(self._C, n_dissections, dissector)
425 # Then sync (second copy in case of non sync mode)
426 self.sync(n_dissections, statistics, splt, ffi, lib, sync)
427 if sync: # Running with NFPlugins
428 for udp in udps:
429 udp.on_expire(self) # Call each Plugin on_expire entrypoint
430 lib.meter_free_flow(self._C, n_dissections, splt, 1) # then free C struct
431 del self._C # and remove it from NFlow slots.
432 return self
434 def sync(self, n_dissections, statistics, splt, ffi, lib, sync_mode):
435 """
436 NFlow synchronizer method
437 Will be called only twice when running without Plugins
438 Will be called at each update when running with Plugins
439 """
440 self.bidirectional_last_seen_ms = self._C.bidirectional_last_seen_ms
441 self.bidirectional_duration_ms = self._C.bidirectional_duration_ms
442 self.bidirectional_packets = self._C.bidirectional_packets
443 self.bidirectional_bytes = self._C.bidirectional_bytes
444 self.src2dst_last_seen_ms = self._C.src2dst_last_seen_ms
445 self.src2dst_duration_ms = self._C.src2dst_duration_ms
446 self.src2dst_packets = self._C.src2dst_packets
447 self.src2dst_bytes = self._C.src2dst_bytes
448 self.dst2src_first_seen_ms = self._C.dst2src_first_seen_ms
449 self.dst2src_last_seen_ms = self._C.dst2src_last_seen_ms
450 self.dst2src_duration_ms = self._C.dst2src_duration_ms
451 self.dst2src_packets = self._C.dst2src_packets
452 self.dst2src_bytes = self._C.dst2src_bytes
453 if statistics: # Statistical analysis activated
454 self.bidirectional_min_ps = self._C.bidirectional_min_ps
455 self.bidirectional_mean_ps = self._C.bidirectional_mean_ps
456 bidirectional_packets = self.bidirectional_packets
457 # NOTE: We need the root square of the variance to provide sample stddev (Var**0.5)/(n-1)
458 if bidirectional_packets > 1:
459 self.bidirectional_stddev_ps = sqrt(
460 self._C.bidirectional_stddev_ps / (bidirectional_packets - 1)
461 )
462 self.bidirectional_max_ps = self._C.bidirectional_max_ps
463 self.src2dst_min_ps = self._C.src2dst_min_ps
464 self.src2dst_mean_ps = self._C.src2dst_mean_ps
465 src2dst_packets = self.src2dst_packets
466 if src2dst_packets > 1:
467 self.src2dst_stddev_ps = sqrt(
468 self._C.src2dst_stddev_ps / (src2dst_packets - 1)
469 )
470 self.src2dst_max_ps = self._C.src2dst_max_ps
471 self.dst2src_min_ps = self._C.dst2src_min_ps
472 self.dst2src_mean_ps = self._C.dst2src_mean_ps
473 dst2src_packets = self.dst2src_packets
474 if dst2src_packets > 1:
475 self.dst2src_stddev_ps = sqrt(
476 self._C.dst2src_stddev_ps / (dst2src_packets - 1)
477 )
478 self.dst2src_max_ps = self._C.dst2src_max_ps
479 self.bidirectional_min_piat_ms = self._C.bidirectional_min_piat_ms
480 self.bidirectional_mean_piat_ms = self._C.bidirectional_mean_piat_ms
481 if bidirectional_packets > 2:
482 self.bidirectional_stddev_piat_ms = sqrt(
483 self._C.bidirectional_stddev_piat_ms / (bidirectional_packets - 2)
484 )
485 self.bidirectional_max_piat_ms = self._C.bidirectional_max_piat_ms
486 self.src2dst_min_piat_ms = self._C.src2dst_min_piat_ms
487 self.src2dst_mean_piat_ms = self._C.src2dst_mean_piat_ms
488 if src2dst_packets > 2:
489 self.src2dst_stddev_piat_ms = sqrt(
490 self._C.src2dst_stddev_piat_ms / (src2dst_packets - 2)
491 )
492 self.src2dst_max_piat_ms = self._C.src2dst_max_piat_ms
493 self.dst2src_min_piat_ms = self._C.dst2src_min_piat_ms
494 self.dst2src_mean_piat_ms = self._C.dst2src_mean_piat_ms
495 if dst2src_packets > 2:
496 self.dst2src_stddev_piat_ms = sqrt(
497 self._C.dst2src_stddev_piat_ms / (dst2src_packets - 2)
498 )
499 self.dst2src_max_piat_ms = self._C.dst2src_max_piat_ms
500 self.bidirectional_syn_packets = self._C.bidirectional_syn_packets
501 self.bidirectional_cwr_packets = self._C.bidirectional_cwr_packets
502 self.bidirectional_ece_packets = self._C.bidirectional_ece_packets
503 self.bidirectional_urg_packets = self._C.bidirectional_urg_packets
504 self.bidirectional_ack_packets = self._C.bidirectional_ack_packets
505 self.bidirectional_psh_packets = self._C.bidirectional_psh_packets
506 self.bidirectional_rst_packets = self._C.bidirectional_rst_packets
507 self.bidirectional_fin_packets = self._C.bidirectional_fin_packets
508 self.src2dst_syn_packets = self._C.src2dst_syn_packets
509 self.src2dst_cwr_packets = self._C.src2dst_cwr_packets
510 self.src2dst_ece_packets = self._C.src2dst_ece_packets
511 self.src2dst_urg_packets = self._C.src2dst_urg_packets
512 self.src2dst_ack_packets = self._C.src2dst_ack_packets
513 self.src2dst_psh_packets = self._C.src2dst_psh_packets
514 self.src2dst_rst_packets = self._C.src2dst_rst_packets
515 self.src2dst_fin_packets = self._C.src2dst_fin_packets
516 self.dst2src_syn_packets = self._C.dst2src_syn_packets
517 self.dst2src_cwr_packets = self._C.dst2src_cwr_packets
518 self.dst2src_ece_packets = self._C.dst2src_ece_packets
519 self.dst2src_urg_packets = self._C.dst2src_urg_packets
520 self.dst2src_ack_packets = self._C.dst2src_ack_packets
521 self.dst2src_psh_packets = self._C.dst2src_psh_packets
522 self.dst2src_rst_packets = self._C.dst2src_rst_packets
523 self.dst2src_fin_packets = self._C.dst2src_fin_packets
524 if n_dissections: # If dissection set (>0)
525 # We minimize updates to a single one, when detection completed.
526 if self._C.detection_completed < 2:
527 self.application_name = ffi.string(self._C.application_name).decode(
528 "utf-8", errors="ignore"
529 )
530 self.application_category_name = ffi.string(
531 self._C.category_name
532 ).decode("utf-8", errors="ignore")
533 self.requested_server_name = (
534 ffi.string(self._C.requested_server_name).decode(
535 "utf-8", errors="ignore"
536 )
537 or None
538 )
539 self.client_fingerprint = (
540 ffi.string(self._C.c_hash).decode("utf-8", errors="ignore") or None
541 )
542 self.server_fingerprint = (
543 ffi.string(self._C.s_hash).decode("utf-8", errors="ignore") or None
544 )
545 self.user_agent = (
546 ffi.string(self._C.user_agent).decode("utf-8", errors="ignore")
547 or None
548 )
549 self.content_type = (
550 ffi.string(self._C.content_type).decode("utf-8", errors="ignore")
551 or None
552 )
553 self.application_is_guessed = self._C.guessed
554 self.application_confidence = self._C.confidence
555 if splt:
556 if (
557 sync_mode
558 ): # Same for splt, once we reach splt limit, there is no need to sync it anymore.
559 if self._C.bidirectional_packets <= splt:
560 self.splt_direction = ffi.unpack(self._C.splt_direction, splt)
561 self.splt_ps = ffi.unpack(self._C.splt_ps, splt)
562 self.splt_piat_ms = ffi.unpack(self._C.splt_piat_ms, splt)
563 else:
564 if (
565 self._C.splt_closed == 0
566 ): # we also release the memory to keep only the obtained list.
567 lib.meter_free_flow(
568 self._C, n_dissections, splt, 0
569 ) # free SPLT
570 else:
571 self.splt_direction = ffi.unpack(self._C.splt_direction, splt)
572 self.splt_ps = ffi.unpack(self._C.splt_ps, splt)
573 self.splt_piat_ms = ffi.unpack(self._C.splt_piat_ms, splt)
574 # Memory will be released by freer.
576 def is_idle(self, tick, idle_timeout):
577 """is_idle method to check if NFlow is idle accoring to configured timeout"""
578 return (tick - idle_timeout) >= self._C.bidirectional_last_seen_ms
580 def __str__(self):
581 """String representation of NFlow"""
582 started = False
583 printable = "NFlow("
584 for attr_name in self.__slots__:
585 try:
586 if not started:
587 printable += attr_name + "=" + str(getattr(self, attr_name))
588 started = True
589 else:
590 if attr_name == "udps":
591 for udp_name in self.udps.__dict__.keys():
592 printable += (
593 ",\n "
594 + attr_name
595 + "."
596 + udp_name
597 + "="
598 + str(getattr(self.udps, udp_name))
599 )
600 else:
601 printable += (
602 ",\n "
603 + attr_name
604 + "="
605 + str(getattr(self, attr_name))
606 )
607 except AttributeError:
608 pass
609 printable += ")"
610 return printable
612 def keys(self):
613 """get NFlow keys"""
614 # Note we transform udps to udps.value_name as preprocessing for csv/pandas interfaces
615 ret = []
616 for attr_name in self.__slots__:
617 try:
618 getattr(self, attr_name)
619 if attr_name == "udps":
620 for udp_name in self.udps.__dict__.keys():
621 ret.append(attr_name + "." + udp_name)
622 else:
623 ret.append(attr_name)
624 except AttributeError:
625 pass
626 return ret
628 def values(self):
629 """get flow values"""
630 # Note: same indexing as keys.
631 ret = []
632 for attr_name in self.__slots__:
633 try:
634 attr_value = getattr(self, attr_name)
635 if attr_name == "udps":
636 for udp_value in self.udps.__dict__.values():
637 ret.append(udp_value)
638 else:
639 ret.append(attr_value)
640 except AttributeError:
641 pass
642 return ret