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

295 statements  

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""" 

15 

16from collections import namedtuple 

17from math import sqrt 

18from .utils import NFEvent 

19 

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) 

54 

55 

56class UDPS(object): 

57 """dummy class that add udps slot the flexibility required for extensions""" 

58 

59 

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 

75 

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 ) 

106 

107 

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. 

116 

117 """ 

118 

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 ) 

215 

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 = "" 

372 

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. 

420 

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 

433 

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. 

575 

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 

579 

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 

611 

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 

627 

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