pypcapkit 1.3.3.post1__cp313-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. pcapkit/__init__.py +126 -0
  2. pcapkit/__main__.py +138 -0
  3. pcapkit/all.py +136 -0
  4. pcapkit/const/__init__.py +81 -0
  5. pcapkit/const/arp/__init__.py +25 -0
  6. pcapkit/const/arp/hardware.py +181 -0
  7. pcapkit/const/arp/operation.py +131 -0
  8. pcapkit/const/ftp/__init__.py +25 -0
  9. pcapkit/const/ftp/command.py +309 -0
  10. pcapkit/const/ftp/return_code.py +304 -0
  11. pcapkit/const/hip/__init__.py +94 -0
  12. pcapkit/const/hip/certificate.py +77 -0
  13. pcapkit/const/hip/cipher.py +65 -0
  14. pcapkit/const/hip/di.py +59 -0
  15. pcapkit/const/hip/ecdsa_curve.py +59 -0
  16. pcapkit/const/hip/ecdsa_low_curve.py +56 -0
  17. pcapkit/const/hip/eddsa_curve.py +65 -0
  18. pcapkit/const/hip/esp_transform_suite.py +98 -0
  19. pcapkit/const/hip/group.py +86 -0
  20. pcapkit/const/hip/hi_algorithm.py +86 -0
  21. pcapkit/const/hip/hit_suite.py +68 -0
  22. pcapkit/const/hip/nat_traversal.py +62 -0
  23. pcapkit/const/hip/notify_message.py +200 -0
  24. pcapkit/const/hip/packet.py +89 -0
  25. pcapkit/const/hip/parameter.py +377 -0
  26. pcapkit/const/hip/registration.py +68 -0
  27. pcapkit/const/hip/registration_failure.py +84 -0
  28. pcapkit/const/hip/suite.py +71 -0
  29. pcapkit/const/hip/transport.py +59 -0
  30. pcapkit/const/http/__init__.py +39 -0
  31. pcapkit/const/http/error_code.py +95 -0
  32. pcapkit/const/http/frame.py +95 -0
  33. pcapkit/const/http/method.py +184 -0
  34. pcapkit/const/http/setting.py +96 -0
  35. pcapkit/const/http/status_code.py +294 -0
  36. pcapkit/const/ipv4/__init__.py +57 -0
  37. pcapkit/const/ipv4/classification_level.py +64 -0
  38. pcapkit/const/ipv4/option_class.py +55 -0
  39. pcapkit/const/ipv4/option_number.py +137 -0
  40. pcapkit/const/ipv4/protection_authority.py +63 -0
  41. pcapkit/const/ipv4/qs_function.py +51 -0
  42. pcapkit/const/ipv4/router_alert.py +251 -0
  43. pcapkit/const/ipv4/tos_del.py +51 -0
  44. pcapkit/const/ipv4/tos_ecn.py +55 -0
  45. pcapkit/const/ipv4/tos_pre.py +63 -0
  46. pcapkit/const/ipv4/tos_rel.py +51 -0
  47. pcapkit/const/ipv4/tos_thr.py +51 -0
  48. pcapkit/const/ipv4/ts_flag.py +53 -0
  49. pcapkit/const/ipv6/__init__.py +53 -0
  50. pcapkit/const/ipv6/extension_header.py +66 -0
  51. pcapkit/const/ipv6/option.py +137 -0
  52. pcapkit/const/ipv6/option_action.py +55 -0
  53. pcapkit/const/ipv6/qs_function.py +51 -0
  54. pcapkit/const/ipv6/router_alert.py +266 -0
  55. pcapkit/const/ipv6/routing.py +80 -0
  56. pcapkit/const/ipv6/seed_id.py +55 -0
  57. pcapkit/const/ipv6/smf_dpd_mode.py +51 -0
  58. pcapkit/const/ipv6/tagger_id.py +62 -0
  59. pcapkit/const/ipx/__init__.py +27 -0
  60. pcapkit/const/ipx/packet.py +72 -0
  61. pcapkit/const/ipx/socket.py +104 -0
  62. pcapkit/const/l2tp/__init__.py +21 -0
  63. pcapkit/const/l2tp/type.py +51 -0
  64. pcapkit/const/mh/__init__.py +204 -0
  65. pcapkit/const/mh/access_type.py +92 -0
  66. pcapkit/const/mh/ack_status_code.py +71 -0
  67. pcapkit/const/mh/ani_suboption.py +74 -0
  68. pcapkit/const/mh/auth_subtype.py +53 -0
  69. pcapkit/const/mh/binding_ack_flag.py +66 -0
  70. pcapkit/const/mh/binding_error.py +51 -0
  71. pcapkit/const/mh/binding_revocation.py +59 -0
  72. pcapkit/const/mh/binding_update_flag.py +81 -0
  73. pcapkit/const/mh/cga_extension.py +66 -0
  74. pcapkit/const/mh/cga_sec.py +57 -0
  75. pcapkit/const/mh/cga_type.py +68 -0
  76. pcapkit/const/mh/dhcp_support_mode.py +53 -0
  77. pcapkit/const/mh/dns_status_code.py +65 -0
  78. pcapkit/const/mh/dsmip6_tls_packet.py +62 -0
  79. pcapkit/const/mh/dsmipv6_home_address.py +74 -0
  80. pcapkit/const/mh/enumerating_algorithm.py +56 -0
  81. pcapkit/const/mh/fb_ack_status.py +62 -0
  82. pcapkit/const/mh/fb_action.py +71 -0
  83. pcapkit/const/mh/fb_indication_trigger.py +65 -0
  84. pcapkit/const/mh/fb_type.py +59 -0
  85. pcapkit/const/mh/flow_id_status.py +77 -0
  86. pcapkit/const/mh/flow_id_suboption.py +71 -0
  87. pcapkit/const/mh/handoff_type.py +71 -0
  88. pcapkit/const/mh/handover_ack_flag.py +54 -0
  89. pcapkit/const/mh/handover_ack_status.py +92 -0
  90. pcapkit/const/mh/handover_initiate_flag.py +57 -0
  91. pcapkit/const/mh/handover_initiate_status.py +62 -0
  92. pcapkit/const/mh/home_address_reply.py +71 -0
  93. pcapkit/const/mh/lla_code.py +63 -0
  94. pcapkit/const/mh/lma_mag_suboption.py +59 -0
  95. pcapkit/const/mh/mn_group_id.py +59 -0
  96. pcapkit/const/mh/mn_id_subtype.py +77 -0
  97. pcapkit/const/mh/operator_id.py +63 -0
  98. pcapkit/const/mh/option.py +260 -0
  99. pcapkit/const/mh/packet.py +119 -0
  100. pcapkit/const/mh/qos_attribute.py +89 -0
  101. pcapkit/const/mh/revocation_status_code.py +83 -0
  102. pcapkit/const/mh/revocation_trigger.py +86 -0
  103. pcapkit/const/mh/status_code.py +232 -0
  104. pcapkit/const/mh/traffic_selector.py +62 -0
  105. pcapkit/const/mh/upa_status.py +71 -0
  106. pcapkit/const/mh/upn_reason.py +80 -0
  107. pcapkit/const/ospf/__init__.py +27 -0
  108. pcapkit/const/ospf/authentication.py +65 -0
  109. pcapkit/const/ospf/packet.py +71 -0
  110. pcapkit/const/pcapng/__init__.py +51 -0
  111. pcapkit/const/pcapng/block_type.py +152 -0
  112. pcapkit/const/pcapng/filter_type.py +48 -0
  113. pcapkit/const/pcapng/hash_algorithm.py +59 -0
  114. pcapkit/const/pcapng/option_type.py +233 -0
  115. pcapkit/const/pcapng/record_type.py +57 -0
  116. pcapkit/const/pcapng/secrets_type.py +56 -0
  117. pcapkit/const/pcapng/verdict_type.py +53 -0
  118. pcapkit/const/reg/__init__.py +34 -0
  119. pcapkit/const/reg/apptype.py +32702 -0
  120. pcapkit/const/reg/ethertype.py +714 -0
  121. pcapkit/const/reg/linktype.py +902 -0
  122. pcapkit/const/reg/transtype.py +523 -0
  123. pcapkit/const/tcp/__init__.py +35 -0
  124. pcapkit/const/tcp/checksum.py +55 -0
  125. pcapkit/const/tcp/flags.py +73 -0
  126. pcapkit/const/tcp/mp_tcp_option.py +80 -0
  127. pcapkit/const/tcp/option.py +198 -0
  128. pcapkit/const/vlan/__init__.py +23 -0
  129. pcapkit/const/vlan/priority_level.py +71 -0
  130. pcapkit/corekit/__init__.py +59 -0
  131. pcapkit/corekit/fields/__init__.py +45 -0
  132. pcapkit/corekit/fields/collections.py +282 -0
  133. pcapkit/corekit/fields/field.py +269 -0
  134. pcapkit/corekit/fields/ipaddress.py +274 -0
  135. pcapkit/corekit/fields/misc.py +722 -0
  136. pcapkit/corekit/fields/numbers.py +375 -0
  137. pcapkit/corekit/fields/strings.py +245 -0
  138. pcapkit/corekit/infoclass.py +394 -0
  139. pcapkit/corekit/io.py +506 -0
  140. pcapkit/corekit/module.py +39 -0
  141. pcapkit/corekit/multidict.py +626 -0
  142. pcapkit/corekit/protochain.py +263 -0
  143. pcapkit/corekit/version.py +33 -0
  144. pcapkit/dumpkit/__init__.py +15 -0
  145. pcapkit/dumpkit/common.py +199 -0
  146. pcapkit/dumpkit/null.py +77 -0
  147. pcapkit/dumpkit/pcap.py +144 -0
  148. pcapkit/foundation/__init__.py +45 -0
  149. pcapkit/foundation/engines/__init__.py +36 -0
  150. pcapkit/foundation/engines/dpkt.py +230 -0
  151. pcapkit/foundation/engines/engine.py +194 -0
  152. pcapkit/foundation/engines/pcap.py +188 -0
  153. pcapkit/foundation/engines/pcapng.py +310 -0
  154. pcapkit/foundation/engines/pyshark.py +166 -0
  155. pcapkit/foundation/engines/scapy.py +161 -0
  156. pcapkit/foundation/extraction.py +915 -0
  157. pcapkit/foundation/reassembly/__init__.py +49 -0
  158. pcapkit/foundation/reassembly/data/__init__.py +48 -0
  159. pcapkit/foundation/reassembly/data/ip.py +117 -0
  160. pcapkit/foundation/reassembly/data/tcp.py +145 -0
  161. pcapkit/foundation/reassembly/ip.py +192 -0
  162. pcapkit/foundation/reassembly/ipv4.py +50 -0
  163. pcapkit/foundation/reassembly/ipv6.py +50 -0
  164. pcapkit/foundation/reassembly/reassembly.py +389 -0
  165. pcapkit/foundation/reassembly/tcp.py +249 -0
  166. pcapkit/foundation/registry/__init__.py +41 -0
  167. pcapkit/foundation/registry/foundation.py +327 -0
  168. pcapkit/foundation/registry/protocols.py +885 -0
  169. pcapkit/foundation/traceflow/__init__.py +44 -0
  170. pcapkit/foundation/traceflow/data/__init__.py +30 -0
  171. pcapkit/foundation/traceflow/data/tcp.py +105 -0
  172. pcapkit/foundation/traceflow/tcp.py +159 -0
  173. pcapkit/foundation/traceflow/traceflow.py +390 -0
  174. pcapkit/interface/__init__.py +22 -0
  175. pcapkit/interface/core.py +185 -0
  176. pcapkit/interface/misc.py +120 -0
  177. pcapkit/protocols/__init__.py +85 -0
  178. pcapkit/protocols/application/NotImplemented/bgp.py +0 -0
  179. pcapkit/protocols/application/NotImplemented/dhcp.py +0 -0
  180. pcapkit/protocols/application/NotImplemented/dhcpv6.py +0 -0
  181. pcapkit/protocols/application/NotImplemented/dns.py +0 -0
  182. pcapkit/protocols/application/NotImplemented/imap.py +0 -0
  183. pcapkit/protocols/application/NotImplemented/ldap.py +0 -0
  184. pcapkit/protocols/application/NotImplemented/mqtt.py +0 -0
  185. pcapkit/protocols/application/NotImplemented/nntp.py +0 -0
  186. pcapkit/protocols/application/NotImplemented/ntp.py +0 -0
  187. pcapkit/protocols/application/NotImplemented/onc_rpc.py +0 -0
  188. pcapkit/protocols/application/NotImplemented/pop.py +0 -0
  189. pcapkit/protocols/application/NotImplemented/rip.py +0 -0
  190. pcapkit/protocols/application/NotImplemented/rtp.py +0 -0
  191. pcapkit/protocols/application/NotImplemented/sip.py +0 -0
  192. pcapkit/protocols/application/NotImplemented/smtp.py +0 -0
  193. pcapkit/protocols/application/NotImplemented/snmp.py +0 -0
  194. pcapkit/protocols/application/NotImplemented/ssh.py +0 -0
  195. pcapkit/protocols/application/NotImplemented/telnet.py +0 -0
  196. pcapkit/protocols/application/NotImplemented/tls.py +0 -0
  197. pcapkit/protocols/application/NotImplemented/xmpp.py +0 -0
  198. pcapkit/protocols/application/__init__.py +34 -0
  199. pcapkit/protocols/application/application.py +114 -0
  200. pcapkit/protocols/application/ftp.py +206 -0
  201. pcapkit/protocols/application/http.py +176 -0
  202. pcapkit/protocols/application/httpv1.py +320 -0
  203. pcapkit/protocols/application/httpv2.py +1255 -0
  204. pcapkit/protocols/data/__init__.py +192 -0
  205. pcapkit/protocols/data/application/__init__.py +57 -0
  206. pcapkit/protocols/data/application/ftp.py +59 -0
  207. pcapkit/protocols/data/application/httpv1.py +79 -0
  208. pcapkit/protocols/data/application/httpv2.py +293 -0
  209. pcapkit/protocols/data/data.py +25 -0
  210. pcapkit/protocols/data/internet/__init__.py +298 -0
  211. pcapkit/protocols/data/internet/ah.py +31 -0
  212. pcapkit/protocols/data/internet/hip.py +804 -0
  213. pcapkit/protocols/data/internet/hopopt.py +351 -0
  214. pcapkit/protocols/data/internet/ipv4.py +369 -0
  215. pcapkit/protocols/data/internet/ipv6.py +67 -0
  216. pcapkit/protocols/data/internet/ipv6_frag.py +29 -0
  217. pcapkit/protocols/data/internet/ipv6_opts.py +368 -0
  218. pcapkit/protocols/data/internet/ipv6_route.py +86 -0
  219. pcapkit/protocols/data/internet/ipx.py +56 -0
  220. pcapkit/protocols/data/internet/mh.py +509 -0
  221. pcapkit/protocols/data/link/__init__.py +33 -0
  222. pcapkit/protocols/data/link/arp.py +74 -0
  223. pcapkit/protocols/data/link/ethernet.py +28 -0
  224. pcapkit/protocols/data/link/l2tp.py +63 -0
  225. pcapkit/protocols/data/link/ospf.py +58 -0
  226. pcapkit/protocols/data/link/vlan.py +42 -0
  227. pcapkit/protocols/data/misc/__init__.py +109 -0
  228. pcapkit/protocols/data/misc/null.py +18 -0
  229. pcapkit/protocols/data/misc/pcap/__init__.py +18 -0
  230. pcapkit/protocols/data/misc/pcap/frame.py +56 -0
  231. pcapkit/protocols/data/misc/pcap/header.py +53 -0
  232. pcapkit/protocols/data/misc/pcapng.py +925 -0
  233. pcapkit/protocols/data/misc/raw.py +25 -0
  234. pcapkit/protocols/data/protocol.py +32 -0
  235. pcapkit/protocols/data/transport/__init__.py +71 -0
  236. pcapkit/protocols/data/transport/tcp.py +555 -0
  237. pcapkit/protocols/data/transport/udp.py +29 -0
  238. pcapkit/protocols/internet/NotImplemented/ecn.py +0 -0
  239. pcapkit/protocols/internet/NotImplemented/esp.py +97 -0
  240. pcapkit/protocols/internet/NotImplemented/icmp.py +0 -0
  241. pcapkit/protocols/internet/NotImplemented/icmpv6.py +0 -0
  242. pcapkit/protocols/internet/NotImplemented/igmp.py +0 -0
  243. pcapkit/protocols/internet/NotImplemented/shim6.py +0 -0
  244. pcapkit/protocols/internet/__init__.py +43 -0
  245. pcapkit/protocols/internet/ah.py +275 -0
  246. pcapkit/protocols/internet/hip.py +4727 -0
  247. pcapkit/protocols/internet/hopopt.py +1879 -0
  248. pcapkit/protocols/internet/internet.py +240 -0
  249. pcapkit/protocols/internet/ip.py +51 -0
  250. pcapkit/protocols/internet/ipsec.py +50 -0
  251. pcapkit/protocols/internet/ipv4.py +1782 -0
  252. pcapkit/protocols/internet/ipv6.py +361 -0
  253. pcapkit/protocols/internet/ipv6_frag.py +258 -0
  254. pcapkit/protocols/internet/ipv6_opts.py +1890 -0
  255. pcapkit/protocols/internet/ipv6_route.py +710 -0
  256. pcapkit/protocols/internet/ipx.py +230 -0
  257. pcapkit/protocols/internet/mh.py +2764 -0
  258. pcapkit/protocols/link/NotImplemented/dsl.py +0 -0
  259. pcapkit/protocols/link/NotImplemented/eapol.py +1 -0
  260. pcapkit/protocols/link/NotImplemented/fddi.py +0 -0
  261. pcapkit/protocols/link/NotImplemented/isdn.py +0 -0
  262. pcapkit/protocols/link/NotImplemented/ndp.py +0 -0
  263. pcapkit/protocols/link/NotImplemented/ppp.py +0 -0
  264. pcapkit/protocols/link/__init__.py +35 -0
  265. pcapkit/protocols/link/arp.py +421 -0
  266. pcapkit/protocols/link/ethernet.py +248 -0
  267. pcapkit/protocols/link/l2tp.py +267 -0
  268. pcapkit/protocols/link/link.py +140 -0
  269. pcapkit/protocols/link/ospf.py +342 -0
  270. pcapkit/protocols/link/rarp.py +82 -0
  271. pcapkit/protocols/link/vlan.py +225 -0
  272. pcapkit/protocols/misc/__init__.py +37 -0
  273. pcapkit/protocols/misc/null.py +129 -0
  274. pcapkit/protocols/misc/pcap/__init__.py +17 -0
  275. pcapkit/protocols/misc/pcap/frame.py +478 -0
  276. pcapkit/protocols/misc/pcap/header.py +358 -0
  277. pcapkit/protocols/misc/pcapng.py +5520 -0
  278. pcapkit/protocols/misc/raw.py +180 -0
  279. pcapkit/protocols/protocol.py +1216 -0
  280. pcapkit/protocols/schema/__init__.py +140 -0
  281. pcapkit/protocols/schema/application/__init__.py +40 -0
  282. pcapkit/protocols/schema/application/ftp.py +21 -0
  283. pcapkit/protocols/schema/application/httpv1.py +21 -0
  284. pcapkit/protocols/schema/application/httpv2.py +384 -0
  285. pcapkit/protocols/schema/internet/__init__.py +294 -0
  286. pcapkit/protocols/schema/internet/ah.py +40 -0
  287. pcapkit/protocols/schema/internet/hip.py +1184 -0
  288. pcapkit/protocols/schema/internet/hopopt.py +679 -0
  289. pcapkit/protocols/schema/internet/ipv4.py +576 -0
  290. pcapkit/protocols/schema/internet/ipv6.py +63 -0
  291. pcapkit/protocols/schema/internet/ipv6_frag.py +48 -0
  292. pcapkit/protocols/schema/internet/ipv6_opts.py +680 -0
  293. pcapkit/protocols/schema/internet/ipv6_route.py +198 -0
  294. pcapkit/protocols/schema/internet/ipx.py +40 -0
  295. pcapkit/protocols/schema/internet/mh.py +718 -0
  296. pcapkit/protocols/schema/link/__init__.py +19 -0
  297. pcapkit/protocols/schema/link/arp.py +39 -0
  298. pcapkit/protocols/schema/link/ethernet.py +51 -0
  299. pcapkit/protocols/schema/link/l2tp.py +88 -0
  300. pcapkit/protocols/schema/link/ospf.py +90 -0
  301. pcapkit/protocols/schema/link/vlan.py +69 -0
  302. pcapkit/protocols/schema/misc/__init__.py +108 -0
  303. pcapkit/protocols/schema/misc/null.py +18 -0
  304. pcapkit/protocols/schema/misc/pcap/__init__.py +10 -0
  305. pcapkit/protocols/schema/misc/pcap/frame.py +51 -0
  306. pcapkit/protocols/schema/misc/pcap/header.py +63 -0
  307. pcapkit/protocols/schema/misc/pcapng.py +1689 -0
  308. pcapkit/protocols/schema/misc/raw.py +24 -0
  309. pcapkit/protocols/schema/schema.py +809 -0
  310. pcapkit/protocols/schema/transport/__init__.py +69 -0
  311. pcapkit/protocols/schema/transport/tcp.py +928 -0
  312. pcapkit/protocols/schema/transport/udp.py +90 -0
  313. pcapkit/protocols/transport/NotImplemented/dccp.py +0 -0
  314. pcapkit/protocols/transport/NotImplemented/rsvp.py +0 -0
  315. pcapkit/protocols/transport/NotImplemented/sctp.py +0 -0
  316. pcapkit/protocols/transport/__init__.py +27 -0
  317. pcapkit/protocols/transport/tcp.py +3025 -0
  318. pcapkit/protocols/transport/transport.py +158 -0
  319. pcapkit/protocols/transport/udp.py +214 -0
  320. pcapkit/py.typed +0 -0
  321. pcapkit/toolkit/__init__.py +57 -0
  322. pcapkit/toolkit/dpkt.py +306 -0
  323. pcapkit/toolkit/pcap.py +212 -0
  324. pcapkit/toolkit/pcapng.py +251 -0
  325. pcapkit/toolkit/pyshark.py +99 -0
  326. pcapkit/toolkit/scapy.py +297 -0
  327. pcapkit/utilities/__init__.py +20 -0
  328. pcapkit/utilities/compat.py +196 -0
  329. pcapkit/utilities/decorators.py +192 -0
  330. pcapkit/utilities/exceptions.py +365 -0
  331. pcapkit/utilities/logging.py +55 -0
  332. pcapkit/utilities/warnings.py +185 -0
  333. pcapkit/vendor/__init__.py +105 -0
  334. pcapkit/vendor/__main__.py +92 -0
  335. pcapkit/vendor/arp/__init__.py +27 -0
  336. pcapkit/vendor/arp/hardware.py +29 -0
  337. pcapkit/vendor/arp/operation.py +29 -0
  338. pcapkit/vendor/default.py +474 -0
  339. pcapkit/vendor/ftp/__init__.py +27 -0
  340. pcapkit/vendor/ftp/command.py +244 -0
  341. pcapkit/vendor/ftp/return_code.py +256 -0
  342. pcapkit/vendor/hip/__init__.py +94 -0
  343. pcapkit/vendor/hip/certificate.py +29 -0
  344. pcapkit/vendor/hip/cipher.py +29 -0
  345. pcapkit/vendor/hip/di.py +29 -0
  346. pcapkit/vendor/hip/ecdsa_curve.py +29 -0
  347. pcapkit/vendor/hip/ecdsa_low_curve.py +29 -0
  348. pcapkit/vendor/hip/eddsa_curve.py +85 -0
  349. pcapkit/vendor/hip/esp_transform_suite.py +29 -0
  350. pcapkit/vendor/hip/group.py +87 -0
  351. pcapkit/vendor/hip/hi_algorithm.py +29 -0
  352. pcapkit/vendor/hip/hit_suite.py +29 -0
  353. pcapkit/vendor/hip/nat_traversal.py +29 -0
  354. pcapkit/vendor/hip/notify_message.py +29 -0
  355. pcapkit/vendor/hip/packet.py +88 -0
  356. pcapkit/vendor/hip/parameter.py +88 -0
  357. pcapkit/vendor/hip/registration.py +29 -0
  358. pcapkit/vendor/hip/registration_failure.py +29 -0
  359. pcapkit/vendor/hip/suite.py +29 -0
  360. pcapkit/vendor/hip/transport.py +29 -0
  361. pcapkit/vendor/http/__init__.py +39 -0
  362. pcapkit/vendor/http/error_code.py +95 -0
  363. pcapkit/vendor/http/frame.py +91 -0
  364. pcapkit/vendor/http/method.py +167 -0
  365. pcapkit/vendor/http/setting.py +93 -0
  366. pcapkit/vendor/http/status_code.py +185 -0
  367. pcapkit/vendor/ipv4/__init__.py +57 -0
  368. pcapkit/vendor/ipv4/classification_level.py +91 -0
  369. pcapkit/vendor/ipv4/option_class.py +80 -0
  370. pcapkit/vendor/ipv4/option_number.py +105 -0
  371. pcapkit/vendor/ipv4/protection_authority.py +84 -0
  372. pcapkit/vendor/ipv4/qs_function.py +78 -0
  373. pcapkit/vendor/ipv4/router_alert.py +93 -0
  374. pcapkit/vendor/ipv4/tos_del.py +78 -0
  375. pcapkit/vendor/ipv4/tos_ecn.py +95 -0
  376. pcapkit/vendor/ipv4/tos_pre.py +84 -0
  377. pcapkit/vendor/ipv4/tos_rel.py +78 -0
  378. pcapkit/vendor/ipv4/tos_thr.py +77 -0
  379. pcapkit/vendor/ipv4/ts_flag.py +79 -0
  380. pcapkit/vendor/ipv6/__init__.py +53 -0
  381. pcapkit/vendor/ipv6/extension_header.py +171 -0
  382. pcapkit/vendor/ipv6/option.py +104 -0
  383. pcapkit/vendor/ipv6/option_action.py +90 -0
  384. pcapkit/vendor/ipv6/qs_function.py +78 -0
  385. pcapkit/vendor/ipv6/router_alert.py +93 -0
  386. pcapkit/vendor/ipv6/routing.py +87 -0
  387. pcapkit/vendor/ipv6/seed_id.py +81 -0
  388. pcapkit/vendor/ipv6/smf_dpd_mode.py +78 -0
  389. pcapkit/vendor/ipv6/tagger_id.py +81 -0
  390. pcapkit/vendor/ipx/__init__.py +37 -0
  391. pcapkit/vendor/ipx/packet.py +123 -0
  392. pcapkit/vendor/ipx/socket.py +125 -0
  393. pcapkit/vendor/l2tp/__init__.py +21 -0
  394. pcapkit/vendor/l2tp/type.py +78 -0
  395. pcapkit/vendor/mh/__init__.py +204 -0
  396. pcapkit/vendor/mh/access_type.py +87 -0
  397. pcapkit/vendor/mh/ack_status_code.py +88 -0
  398. pcapkit/vendor/mh/ani_suboption.py +88 -0
  399. pcapkit/vendor/mh/auth_subtype.py +83 -0
  400. pcapkit/vendor/mh/binding_ack_flag.py +148 -0
  401. pcapkit/vendor/mh/binding_error.py +78 -0
  402. pcapkit/vendor/mh/binding_revocation.py +87 -0
  403. pcapkit/vendor/mh/binding_update_flag.py +147 -0
  404. pcapkit/vendor/mh/cga_extension.py +91 -0
  405. pcapkit/vendor/mh/cga_sec.py +91 -0
  406. pcapkit/vendor/mh/cga_type.py +74 -0
  407. pcapkit/vendor/mh/dhcp_support_mode.py +77 -0
  408. pcapkit/vendor/mh/dns_status_code.py +87 -0
  409. pcapkit/vendor/mh/dsmip6_tls_packet.py +87 -0
  410. pcapkit/vendor/mh/dsmipv6_home_address.py +87 -0
  411. pcapkit/vendor/mh/enumerating_algorithm.py +82 -0
  412. pcapkit/vendor/mh/fb_ack_status.py +87 -0
  413. pcapkit/vendor/mh/fb_action.py +88 -0
  414. pcapkit/vendor/mh/fb_indication_trigger.py +87 -0
  415. pcapkit/vendor/mh/fb_type.py +88 -0
  416. pcapkit/vendor/mh/flow_id_status.py +87 -0
  417. pcapkit/vendor/mh/flow_id_suboption.py +87 -0
  418. pcapkit/vendor/mh/handoff_type.py +87 -0
  419. pcapkit/vendor/mh/handover_ack_flag.py +143 -0
  420. pcapkit/vendor/mh/handover_ack_status.py +87 -0
  421. pcapkit/vendor/mh/handover_initiate_flag.py +143 -0
  422. pcapkit/vendor/mh/handover_initiate_status.py +87 -0
  423. pcapkit/vendor/mh/home_address_reply.py +87 -0
  424. pcapkit/vendor/mh/lla_code.py +97 -0
  425. pcapkit/vendor/mh/lma_mag_suboption.py +88 -0
  426. pcapkit/vendor/mh/mn_group_id.py +87 -0
  427. pcapkit/vendor/mh/mn_id_subtype.py +87 -0
  428. pcapkit/vendor/mh/operator_id.py +87 -0
  429. pcapkit/vendor/mh/option.py +83 -0
  430. pcapkit/vendor/mh/packet.py +82 -0
  431. pcapkit/vendor/mh/qos_attribute.py +87 -0
  432. pcapkit/vendor/mh/revocation_status_code.py +87 -0
  433. pcapkit/vendor/mh/revocation_trigger.py +87 -0
  434. pcapkit/vendor/mh/status_code.py +91 -0
  435. pcapkit/vendor/mh/traffic_selector.py +87 -0
  436. pcapkit/vendor/mh/upa_status.py +87 -0
  437. pcapkit/vendor/mh/upn_reason.py +87 -0
  438. pcapkit/vendor/ospf/__init__.py +27 -0
  439. pcapkit/vendor/ospf/authentication.py +29 -0
  440. pcapkit/vendor/ospf/packet.py +29 -0
  441. pcapkit/vendor/pcapng/__init__.py +51 -0
  442. pcapkit/vendor/pcapng/block_type.py +94 -0
  443. pcapkit/vendor/pcapng/filter_type.py +77 -0
  444. pcapkit/vendor/pcapng/hash_algorithm.py +82 -0
  445. pcapkit/vendor/pcapng/option_type.py +287 -0
  446. pcapkit/vendor/pcapng/record_type.py +81 -0
  447. pcapkit/vendor/pcapng/secrets_type.py +81 -0
  448. pcapkit/vendor/pcapng/verdict_type.py +79 -0
  449. pcapkit/vendor/reg/__init__.py +34 -0
  450. pcapkit/vendor/reg/apptype.py +338 -0
  451. pcapkit/vendor/reg/ethertype.py +121 -0
  452. pcapkit/vendor/reg/linktype.py +110 -0
  453. pcapkit/vendor/reg/transtype.py +111 -0
  454. pcapkit/vendor/tcp/__init__.py +35 -0
  455. pcapkit/vendor/tcp/checksum.py +80 -0
  456. pcapkit/vendor/tcp/flags.py +149 -0
  457. pcapkit/vendor/tcp/mp_tcp_option.py +90 -0
  458. pcapkit/vendor/tcp/option.py +103 -0
  459. pcapkit/vendor/vlan/__init__.py +23 -0
  460. pcapkit/vendor/vlan/priority_level.py +97 -0
  461. pypcapkit-1.3.3.post1.dist-info/LICENSE +29 -0
  462. pypcapkit-1.3.3.post1.dist-info/METADATA +236 -0
  463. pypcapkit-1.3.3.post1.dist-info/RECORD +466 -0
  464. pypcapkit-1.3.3.post1.dist-info/WHEEL +5 -0
  465. pypcapkit-1.3.3.post1.dist-info/entry_points.txt +3 -0
  466. pypcapkit-1.3.3.post1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,915 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint: disable=import-outside-toplevel,fixme
3
+ # mypy: disable-error-code=dict-item
4
+ """Extractor for PCAP Files
5
+ ==============================
6
+
7
+ .. module:: pcapkit.foundation.extraction
8
+
9
+ :mod:`pcapkit.foundation.extraction` contains
10
+ :class:`~pcapkit.foundation.extraction.Extractor` only,
11
+ which synthesises file I/O and protocol analysis,
12
+ coordinates information exchange in all network layers,
13
+ extracts parametres from a PCAP file.
14
+
15
+ """
16
+ import collections
17
+ import importlib
18
+ import io
19
+ import os
20
+ import sys
21
+ from typing import TYPE_CHECKING, Generic, TypeVar, cast
22
+
23
+ from dictdumper.dumper import Dumper
24
+
25
+ from pcapkit.corekit.io import SeekableReader
26
+ from pcapkit.corekit.module import ModuleDescriptor
27
+ from pcapkit.dumpkit.common import make_dumper
28
+ from pcapkit.foundation.engines.engine import Engine
29
+ from pcapkit.foundation.engines.pcap import PCAP as PCAP_Engine
30
+ from pcapkit.foundation.engines.pcapng import PCAPNG as PCAPNG_Engine
31
+ from pcapkit.foundation.reassembly import ReassemblyManager
32
+ from pcapkit.foundation.reassembly.data import ReassemblyData
33
+ from pcapkit.foundation.reassembly.reassembly import Reassembly
34
+ from pcapkit.foundation.traceflow import TraceFlowManager
35
+ from pcapkit.foundation.traceflow.data import TraceFlowData
36
+ from pcapkit.foundation.traceflow.traceflow import TraceFlow
37
+ from pcapkit.utilities.exceptions import (CallableError, FileNotFound, FormatError, IterableError,
38
+ RegistryError, UnsupportedCall, stacklevel)
39
+ from pcapkit.utilities.logging import logger
40
+ from pcapkit.utilities.warnings import (EngineWarning, ExtractionWarning, FormatWarning,
41
+ RegistryWarning, warn)
42
+
43
+ if TYPE_CHECKING:
44
+ from io import BufferedReader
45
+ from types import ModuleType, TracebackType
46
+ from typing import IO, Any, Callable, DefaultDict, Optional, Type, Union
47
+
48
+ from dpkt.dpkt import Packet as DPKTPacket
49
+ from pyshark.packet.packet import Packet as PySharkPacket
50
+ from scapy.packet import Packet as ScapyPacket
51
+ from typing_extensions import Literal
52
+
53
+ from pcapkit.foundation.reassembly.ipv4 import IPv4 as IPv4_Reassembly
54
+ from pcapkit.foundation.reassembly.ipv6 import IPv6 as IPv6_Reassembly
55
+ from pcapkit.foundation.reassembly.tcp import TCP as TCP_Reassembly
56
+ from pcapkit.foundation.traceflow.tcp import TCP as TCP_TraceFlow
57
+ from pcapkit.protocols.misc.pcap.frame import Frame
58
+ from pcapkit.protocols.misc.pcapng import PCAPNG
59
+ from pcapkit.protocols.protocol import ProtocolBase as Protocol
60
+
61
+ Formats = Literal['pcap', 'json', 'tree', 'plist']
62
+ Engines = Literal['default', 'pcapkit', 'dpkt', 'scapy', 'pyshark']
63
+ Layers = Literal['link', 'internet', 'transport', 'application', 'none']
64
+
65
+ Packet = Union[Frame, PCAPNG, ScapyPacket, DPKTPacket, PySharkPacket]
66
+
67
+ Protocols = Union[str, Protocol, Type[Protocol]]
68
+ VerboseHandler = Callable[['Extractor', Packet], Any]
69
+
70
+ __all__ = ['Extractor']
71
+
72
+ _P = TypeVar('_P')
73
+
74
+
75
+ class Extractor(Generic[_P]):
76
+ """Extractor for PCAP files.
77
+
78
+ Notes:
79
+ For supported engines, please refer to
80
+ :meth:`~pcapkit.foundation.extraction.Extractor.run`.
81
+
82
+ """
83
+ if TYPE_CHECKING:
84
+ #: Input file name.
85
+ _ifnm: 'str'
86
+ #: Output file name.
87
+ _ofnm: 'Optional[str]'
88
+ #: Output file extension.
89
+ _fext: 'Optional[str]'
90
+
91
+ #: Auto extract flag. It indicates if the extraction process should
92
+ #: continue automatically until the EOF is reached.
93
+ _flag_a: 'bool'
94
+ #: Store data flag. It indicates if the extracted frames should be
95
+ #: stored in memory.
96
+ _flag_d: 'bool'
97
+ #: EOF flag. It indicates if the EOF is reached.
98
+ _flag_e: 'bool'
99
+ #: Split file flag, i.e. dump each frame into different files.
100
+ _flag_f: 'bool'
101
+ #: No output file, i.e., no output file is to be generated.
102
+ _flag_q: 'bool'
103
+ #: Trace flag. It indicates if the flow tracing is enabled.
104
+ _flag_t: 'bool'
105
+ #: Verbose flag. This is used to determine if the verbose callback
106
+ #: function should be called at each frame.
107
+ _flag_v: 'bool'
108
+ #: No EOF flag. It is useful when the input file is a live capture,
109
+ #: as the extraction process will not stop until the user interrupt
110
+ #: the process.
111
+ _flag_n: 'bool'
112
+ #: Input filename flag. It indicates if the input file is a file
113
+ #: name or a binary IO object. For the latter, we should not close
114
+ #: the file object after extraction.
115
+ _flag_s: 'bool'
116
+
117
+ #: Verbose callback function.
118
+ #_vfunc: 'VerboseHandler'
119
+
120
+ #: Frame number.
121
+ _frnum: 'int'
122
+ #: Frame records.
123
+ _frame: 'list[Packet]'
124
+
125
+ #: Frame record for reassembly.
126
+ _reasm: 'ReassemblyManager'
127
+ #: Frame record for flow tracing.
128
+ _trace: 'TraceFlowManager'
129
+
130
+ #: IPv4 flag. It indicates if the IPv4 reassembly and/or flow tracing
131
+ #: is enabled.
132
+ _ipv4: 'bool'
133
+ #: IPv6 flag. It indicates if the IPv6 reassembly and/or flow tracing
134
+ #: is enabled.
135
+ _ipv6: 'bool'
136
+ #: TCP flag. It indicates if the TCP reassembly and/or flow tracing
137
+ #: is enabled.
138
+ _tcp: 'bool'
139
+
140
+ #: Extract til protocol.
141
+ _exptl: 'Protocols'
142
+ #: Extract til layer.
143
+ _exlyr: 'Layers'
144
+ #: Extraction engine name.
145
+ _exnam: 'Engines'
146
+ #: Extraction engine instance.
147
+ _exeng: 'Engine[_P]'
148
+
149
+ #: Input file object.
150
+ _ifile: 'BufferedReader'
151
+ #: Output file object.
152
+ _ofile: 'Dumper | Type[Dumper]'
153
+
154
+ #: Magic number.
155
+ _magic: 'bytes'
156
+ #: Output format.
157
+ _offmt: 'Formats'
158
+
159
+ #: List of potential PCAP file extentions.
160
+ PCAP_EXT = ['.pcap', '.cap', '.pcapng']
161
+
162
+ ##########################################################################
163
+ # Defaults.
164
+ ##########################################################################
165
+
166
+ #: Format dumper mapping for writing output files. The values should be a
167
+ #: tuple representing the module name and class name, or a
168
+ #: :class:`dictdumper.dumper.Dumper` subclass, and corresponding file extension.
169
+ __output__ = collections.defaultdict(
170
+ lambda: (ModuleDescriptor('pcapkit.dumpkit', 'NotImplementedIO'), None),
171
+ {
172
+ 'pcap': (ModuleDescriptor('pcapkit.dumpkit', 'PCAPIO'), '.pcap'),
173
+ 'cap': (ModuleDescriptor('pcapkit.dumpkit', 'PCAPIO'), '.pcap'),
174
+ 'plist': (ModuleDescriptor('dictdumper', 'PLIST'), '.plist'),
175
+ 'xml': (ModuleDescriptor('dictdumper', 'PLIST'), '.plist'),
176
+ 'json': (ModuleDescriptor('dictdumper', 'JSON'), '.json'),
177
+ 'tree': (ModuleDescriptor('dictdumper', 'Tree'), '.txt'),
178
+ 'text': (ModuleDescriptor('dictdumper', 'Text'), '.txt'),
179
+ 'txt': (ModuleDescriptor('dictdumper', 'Tree'), '.txt'),
180
+ },
181
+ ) # type: DefaultDict[str, tuple[ModuleDescriptor[Dumper] | Type[Dumper], str | None]]
182
+
183
+ #: Engine mapping for extracting frames. The values should be a tuple representing
184
+ #: the module name and class name, or an :class:`~pcapkit.foundation.engines.engine.Engine`
185
+ #: subclass.
186
+ __engine__ = {
187
+ 'scapy': ModuleDescriptor('pcapkit.foundation.engines.scapy', 'Scapy'),
188
+ 'dpkt': ModuleDescriptor('pcapkit.foundation.engines.dpkt', 'DPKT'),
189
+ 'pyshark': ModuleDescriptor('pcapkit.foundation.engines.pyshark', 'PyShark'),
190
+ } # type: dict[str, ModuleDescriptor[Engine] | Type[Engine]]
191
+
192
+ #: Reassembly support mapping for extracting frames. The values should be a tuple
193
+ #: representing the module name and class name, or a :class:`~pcapkit.foundation.reassembly.reassembly.Reassembly`
194
+ #: subclass.
195
+ __reassembly__ = {
196
+ 'ipv4': ModuleDescriptor('pcapkit.foundation.reassembly.ipv4', 'IPv4'),
197
+ 'ipv6': ModuleDescriptor('pcapkit.foundation.reassembly.ipv6', 'IPv6'),
198
+ 'tcp': ModuleDescriptor('pcapkit.foundation.reassembly.tcp', 'TCP'),
199
+ } # type: dict[str, ModuleDescriptor[Reassembly] | Type[Reassembly]]
200
+
201
+ #: Flow tracing support mapping for extracting frames. The values should be a tuple
202
+ #: representing the module name and class name, or a :class:`~pcapkit.foundation.traceflow.traceflow.TraceFlow`
203
+ #: subclass.
204
+ __traceflow__ = {
205
+ 'tcp': ModuleDescriptor('pcapkit.foundation.traceflow.tcp', 'TCP'),
206
+ } # type: dict[str, ModuleDescriptor[TraceFlow] | Type[TraceFlow]]
207
+
208
+ ##########################################################################
209
+ # Properties.
210
+ ##########################################################################
211
+
212
+ @property
213
+ def length(self) -> 'int':
214
+ """Frame number (of current extracted frame or all)."""
215
+ return self._frnum
216
+
217
+ @property
218
+ def format(self) -> 'Formats':
219
+ """Format of output file.
220
+
221
+ Raises:
222
+ UnsupportedCall: If :attr:`self._flag_q <pcapkit.foundation.extraction.Extractor._flag_q>`
223
+ is set as :data:`True`, as output is disabled by initialisation parameter.
224
+
225
+ """
226
+ if self._flag_q:
227
+ raise UnsupportedCall("'Extractor(nofile=True)' object has no attribute 'format'")
228
+ return self._offmt
229
+
230
+ @property
231
+ def input(self) -> 'str':
232
+ """Name of input PCAP file."""
233
+ return self._ifnm
234
+
235
+ @property
236
+ def output(self) -> 'str':
237
+ """Name of output file.
238
+
239
+ Raises:
240
+ UnsupportedCall: If :attr:`self._flag_q <pcapkit.foundation.extraction.Extractor._flag_q>`
241
+ is set as :data:`True`, as output is disabled by initialisation parameter.
242
+
243
+ """
244
+ if self._flag_q:
245
+ raise UnsupportedCall("'Extractor(nofile=True)' object has no attribute 'format'")
246
+ return cast('str', self._ofnm)
247
+
248
+ @property
249
+ def frame(self) -> 'tuple[Packet, ...]':
250
+ """Extracted frames.
251
+
252
+ Raises:
253
+ UnsupportedCall: If :attr:`self._flag_d <pcapkit.foundation.extraction.Extractor._flag_d>`
254
+ is :data:`False`, as storing frame data is disabled.
255
+
256
+ """
257
+ if self._flag_d:
258
+ return tuple(self._frame)
259
+ raise UnsupportedCall("'Extractor(store=False)' object has no attribute 'frame'")
260
+
261
+ @property
262
+ def reassembly(self) -> 'ReassemblyData':
263
+ """Frame record for reassembly.
264
+
265
+ * ``ipv4`` -- tuple of IPv4 payload fragment (:term:`reasm.ipv4.datagram`)
266
+ * ``ipv6`` -- tuple of IPv6 payload fragment (:term:`reasm.ipv6.datagram`)
267
+ * ``tcp`` -- tuple of TCP payload fragment (:term:`reasm.tcp.datagram`)
268
+
269
+ Raises:
270
+ UnsupportedCall: If :attr:`self._flag_r <pcapkit.foundation.extraction.Extractor._flag_r>`
271
+ is :data:`False`, as reassembly is disabled.
272
+
273
+ """
274
+ if self._flag_r:
275
+ data = ReassemblyData(
276
+ ipv4=tuple(self._reasm.ipv4.datagram) if self._ipv4 else None,
277
+ ipv6=tuple(self._reasm.ipv6.datagram) if self._ipv6 else None,
278
+ tcp=tuple(self._reasm.tcp.datagram) if self._tcp else None,
279
+ )
280
+ return data
281
+ raise UnsupportedCall("'Extractor(reassembly=False)' object has no attribute 'reassembly'")
282
+
283
+ @property
284
+ def trace(self) -> 'TraceFlowData':
285
+ """Index table for traced flow.
286
+
287
+ * ``tcp`` -- tuple of TCP flows (:term:`trace.tcp.index`)
288
+
289
+ Raises:
290
+ UnsupportedCall: If :attr:`self._flag_t <pcapkit.foundation.extraction.Extractor._flag_t>`
291
+ is :data:`False`, as flow tracing is disabled.
292
+
293
+ """
294
+ if self._flag_t:
295
+ data = TraceFlowData(
296
+ tcp=tuple(self._trace.tcp.index) if self._tcp else None,
297
+ )
298
+ return data
299
+ raise UnsupportedCall("'Extractor(trace=False)' object has no attribute 'trace'")
300
+
301
+ @property
302
+ def engine(self) -> 'Engine':
303
+ """PCAP extraction engine."""
304
+ return self._exeng
305
+
306
+ @property
307
+ def magic_number(self) -> 'bytes':
308
+ """Magic number of input PCAP file."""
309
+ return self._magic
310
+
311
+ ##########################################################################
312
+ # Methods.
313
+ ##########################################################################
314
+
315
+ @classmethod
316
+ def register_dumper(cls, format: 'str', dumper: 'ModuleDescriptor[Dumper] | Type[Dumper]', ext: 'str') -> 'None':
317
+ r"""Register a new dumper class.
318
+
319
+ Notes:
320
+ The full qualified class name of the new dumper class
321
+ should be as ``{dumper.module}.{dumper.name}``.
322
+
323
+ Arguments:
324
+ format: format name
325
+ dumper: module descriptor or a :class:`dictdumper.dumper.Dumper` subclass
326
+ ext: file extension
327
+
328
+ """
329
+ if isinstance(dumper, ModuleDescriptor):
330
+ dumper = dumper.klass
331
+ if not issubclass(dumper, Dumper):
332
+ raise RegistryError(f'dumper must be a Dumper subclass, not {dumper!r}')
333
+ if format in cls.__output__:
334
+ warn(f'dumper {format} already registered, overwriting', RegistryWarning)
335
+ cls.__output__[format] = (dumper, ext)
336
+
337
+ @classmethod
338
+ def register_engine(cls, name: 'str', engine: 'ModuleDescriptor[Engine] | Type[Engine]') -> 'None':
339
+ r"""Register a new extraction engine.
340
+
341
+ Notes:
342
+ The full qualified class name of the new extraction engine
343
+ should be as ``{engine.module}.{engine.name}``.
344
+
345
+ Arguments:
346
+ name: engine name
347
+ engine: module descriptor or an
348
+ :class:`~pcapkit.foundation.engines.engine.Engine` subclass
349
+
350
+ """
351
+ if isinstance(engine, ModuleDescriptor):
352
+ engine = engine.klass
353
+ if not issubclass(engine, Engine):
354
+ raise RegistryError(f'engine must be an Engine subclass, not {engine!r}')
355
+ if name in cls.__engine__:
356
+ warn(f'engine {name} already registered, overwriting', RegistryWarning)
357
+ cls.__engine__[name] = engine
358
+
359
+ @classmethod
360
+ def register_reassembly(cls, protocol: 'str', reassembly: 'ModuleDescriptor[Reassembly] | Type[Reassembly]') -> 'None':
361
+ r"""Register a new reassembly engine.
362
+
363
+ Notes:
364
+ The full qualified class name of the new reassembly engine
365
+ should be as ``{reassembly.module}.{reassembly.name}``.
366
+
367
+ Arguments:
368
+ protocol: protocol name
369
+ reassembly: module descriptor or a
370
+ :class:`~pcapkit.foundation.reassembly.reassembly.Reassembly` subclass
371
+
372
+ """
373
+ if isinstance(reassembly, ModuleDescriptor):
374
+ reassembly = reassembly.klass
375
+ if not issubclass(reassembly, Reassembly):
376
+ raise RegistryError(f'reassembly must be a Reassembly subclass, not {reassembly!r}')
377
+ if protocol in cls.__reassembly__:
378
+ warn(f'reassembly {protocol} already registered, overwriting', RegistryWarning)
379
+ cls.__reassembly__[protocol] = reassembly
380
+
381
+ @classmethod
382
+ def register_traceflow(cls, protocol: 'str', traceflow: 'ModuleDescriptor[TraceFlow] | Type[TraceFlow]') -> 'None':
383
+ r"""Register a new flow tracing engine.
384
+
385
+ Notes:
386
+ The full qualified class name of the new flow tracing engine
387
+ should be as ``{traceflow.module}.{traceflow.name}``.
388
+
389
+ Arguments:
390
+ protocol: protocol name
391
+ traceflow: module descriptor or a
392
+ :class:`~pcapkit.foundation.traceflow.traceflow.TraceFlow` subclass
393
+
394
+ """
395
+ if isinstance(traceflow, ModuleDescriptor):
396
+ traceflow = traceflow.klass
397
+ if not issubclass(traceflow, TraceFlow):
398
+ raise RegistryError(f'traceflow must be a TraceFlow subclass, not {traceflow!r}')
399
+ if protocol in cls.__traceflow__:
400
+ warn(f'traceflow {protocol} already registered, overwriting', RegistryWarning)
401
+ cls.__traceflow__[protocol] = traceflow
402
+
403
+ def run(self) -> 'None': # pylint: disable=inconsistent-return-statements
404
+ """Start extraction.
405
+
406
+ We uses :meth:`~pcapkit.foundation.extraction.Extractor.import_test` to check if
407
+ a certain engine is available or not. For supported engines, each engine has
408
+ different driver method:
409
+
410
+ * Default drivers:
411
+
412
+ - PCAP Format: :class:`pcapkit.foundation.engines.pcap.PCAP`
413
+ - PCAP-NG Format: :class:`pcapkit.foundation.engines.pcapng.PCAPNG`
414
+
415
+ * DPKT driver: :class:`pcapkit.foundation.engines.dpkt.DPKT`
416
+ * Scapy driver: :class:`pcapkit.foundation.engines.scapy.Scapy`
417
+ * PyShark driver: :class:`pcapkit.foundation.engines.pyshark.PyShark`
418
+
419
+ Warns:
420
+ pcapkit.utilities.warnings.EngineWarning: If the extraction engine is not
421
+ available. This is either due to dependency not installed, or supplied
422
+ engine unknown.
423
+
424
+ :rtype: None
425
+ """
426
+ if self._exnam in self.__engine__: # check if engine is supported
427
+ eng = self.__engine__[self._exnam]
428
+ if isinstance(eng, ModuleDescriptor):
429
+ eng = eng.klass
430
+
431
+ if self.import_test(eng.module, name=eng.name) is not None: # type: ignore[arg-type]
432
+ self._exeng = eng(self)
433
+ self._exeng.run()
434
+
435
+ # start iteration
436
+ self.record_frames()
437
+ return
438
+
439
+ warn(f'engine {eng.name} (`{eng.module}`) is not installed; '
440
+ 'using default engine instead', EngineWarning, stacklevel=stacklevel())
441
+ self._exnam = 'default' # using default/pcapkit engine
442
+
443
+ if self._exnam not in ('default', 'pcapkit'):
444
+ warn(f'unsupported extraction engine: {self._exnam}; '
445
+ 'using default engine instead', EngineWarning, stacklevel=stacklevel())
446
+ self._exnam = 'default' # using default/pcapkit engine
447
+
448
+ if self._magic in PCAP_Engine.MAGIC_NUMBER:
449
+ self._exeng = cast('Engine[_P]', PCAP_Engine(self))
450
+ elif self._magic in PCAPNG_Engine.MAGIC_NUMBER:
451
+ self._exeng = cast('Engine[_P]', PCAPNG_Engine(self))
452
+ else:
453
+ raise FormatError(f'unknown file format: {self._magic!r}')
454
+
455
+ # start engine
456
+ self._exeng.run()
457
+
458
+ # start iteration
459
+ self.record_frames()
460
+
461
+ @staticmethod
462
+ def import_test(engine: 'str', *, name: 'Optional[str]' = None) -> 'Optional[ModuleType]':
463
+ """Test import for extractcion engine.
464
+
465
+ Args:
466
+ engine: Extraction engine module name.
467
+ name: Extraction engine display name.
468
+
469
+ Warns:
470
+ pcapkit.utilities.warnings.EngineWarning: If the engine module is not installed.
471
+
472
+ Returns:
473
+ If succeeded, returns the module; otherwise, returns :data:`None`.
474
+
475
+ """
476
+ try:
477
+ module = importlib.import_module(engine)
478
+ except ImportError:
479
+ module = None
480
+ warn(f"extraction engine '{name or engine}' not available; "
481
+ 'using default engine instead', EngineWarning, stacklevel=stacklevel())
482
+ return module
483
+
484
+ @classmethod
485
+ def make_name(cls, fin: 'str | IO[bytes]' = 'in.pcap', fout: 'str' = 'out',
486
+ fmt: 'Formats' = 'tree', extension: 'bool' = True, *, files: 'bool' = False,
487
+ nofile: 'bool' = False) -> 'tuple[str, Optional[str], Formats, Optional[str], bool]':
488
+ """Generate input and output filenames.
489
+
490
+ The method will perform following processing:
491
+
492
+ 1. sanitise ``fin`` as the input PCAP filename; ``in.pcap`` as default value and
493
+ append ``.pcap`` extension if needed and ``extension`` is :data:`True`; as well
494
+ as test if the file exists;
495
+ 2. if ``nofile`` is :data:`True`, skips following processing;
496
+ 3. if ``fmt`` provided, then it presumes corresponding output file extension;
497
+ 4. if ``fout`` not provided, it presumes the output file name based on the presumptive
498
+ file extension; the stem of the output file name is set as ``out``; should the file
499
+ extension is not available, then it raises :exc:`~pcapkit.utilities.exceptions.FormatError`;
500
+ 5. if ``fout`` provided, it presumes corresponding output format if needed; should the
501
+ presumption cannot be made, then it raises :exc:`~pcapkit.utilities.exceptions.FormatError`;
502
+ 6. it will also append corresponding file extension to the output file name if needed
503
+ and ``extension`` is :data:`True`.
504
+
505
+ And the method returns the generated input and output filenames as follows:
506
+
507
+ 0. input filename
508
+ 1. output filename / directory name
509
+ 2. output format
510
+ 3. output file extension (without ``.``)
511
+ 4. if split each frame into different files
512
+
513
+ Args:
514
+ fin: Input filename or a binary IO object.
515
+ fout: Output filename.
516
+ fmt: Output file format.
517
+ extension: If append ``.pcap`` file extension to the input filename
518
+ if ``fin`` does not have such file extension; if check and append extensions
519
+ to output file.
520
+ files: If split each frame into different files.
521
+ nofile: If no output file is to be dumped.
522
+
523
+ Returns:
524
+ Generated input and output filenames.
525
+
526
+ Raises:
527
+ FileNotFound: If input file does not exists.
528
+ FormatError: If output format not provided and cannot be presumpted.
529
+
530
+ """
531
+ if isinstance(fin, str):
532
+ if extension: # pylint: disable=else-if-used
533
+ ifnm = fin if os.path.splitext(fin)[1] in cls.PCAP_EXT else f'{fin}.pcap'
534
+ else:
535
+ ifnm = fin
536
+
537
+ if not os.path.isfile(ifnm):
538
+ raise FileNotFound(2, 'No such file or directory', ifnm)
539
+ else:
540
+ ifnm = fin.name
541
+
542
+ if nofile:
543
+ ofnm = None
544
+ ext = None
545
+ else:
546
+ ext = cls.__output__[fmt][1]
547
+ if ext is None:
548
+ raise FormatError(f'unknown output format: {fmt}')
549
+
550
+ if (parent := os.path.split(fout)[0]):
551
+ os.makedirs(parent, exist_ok=True)
552
+
553
+ if files:
554
+ ofnm = fout
555
+ os.makedirs(ofnm, exist_ok=True)
556
+ elif extension:
557
+ ofnm = fout if os.path.splitext(fout)[1] == ext else f'{fout}{ext}'
558
+ else:
559
+ ofnm = fout
560
+
561
+ return ifnm, ofnm, fmt, ext, files
562
+
563
+ def record_header(self) -> 'Engine':
564
+ """Read global header.
565
+
566
+ The method will parse the PCAP global header and save the parsed result
567
+ to its extraction context. Information such as PCAP version, data link
568
+ layer protocol type, nanosecond flag and byteorder will also be save
569
+ the current :class:`~pcapkit.foundation.engins.engine.Engine` instance
570
+ as well.
571
+
572
+ If TCP flow tracing is enabled, the nanosecond flag and byteorder will
573
+ be used for the output PCAP file of the traced TCP flows.
574
+
575
+ For output, the method will dump the parsed PCAP global header under
576
+ the name of ``Global Header``.
577
+
578
+ """
579
+ # pylint: disable=attribute-defined-outside-init,protected-access
580
+ if self._magic in PCAP_Engine.MAGIC_NUMBER:
581
+ engine = PCAP_Engine(self)
582
+ engine.run()
583
+
584
+ self._ifile.seek(0, os.SEEK_SET)
585
+ return engine # type: ignore[return-value]
586
+
587
+ if self._magic in PCAPNG_Engine.MAGIC_NUMBER:
588
+ engine = PCAPNG_Engine(self) # type: ignore[assignment]
589
+ engine.run()
590
+
591
+ self._ifile.seek(0, os.SEEK_SET)
592
+ return engine # type: ignore[return-value]
593
+
594
+ raise FormatError(f'unknown file format: {self._magic!r}')
595
+
596
+ def record_frames(self) -> 'None':
597
+ """Read packet frames.
598
+
599
+ The method calls :meth:`self._exeng.read_frame <pcapkit.foundation.engines.engine.Engine.read_frame>`
600
+ to parse each frame from the input PCAP file; and
601
+ performs cleanup by calling :meth:`self._exeng.close <pcapkit.foundation.engines.engine.Engine.close>`
602
+ upon completion of the parsing process.
603
+
604
+ Notes:
605
+ Under non-auto mode, i.e. :attr:`self._flag_a <Extractor._flag_a>` is
606
+ :data:`False`, the method performs no action.
607
+
608
+ """
609
+ if self._flag_a:
610
+ while True:
611
+ try:
612
+ self._exeng.read_frame()
613
+ except (EOFError, StopIteration):
614
+ warn('EOF reached', ExtractionWarning, stacklevel=stacklevel())
615
+
616
+ if self._flag_n:
617
+ continue
618
+
619
+ # quit when EOF
620
+ break
621
+ except KeyboardInterrupt:
622
+ self._cleanup()
623
+ raise
624
+
625
+ self._cleanup()
626
+
627
+ ##########################################################################
628
+ # Data models.
629
+ ##########################################################################
630
+
631
+ def __init__(self,
632
+ fin: 'Optional[str | IO[bytes]]' = None, fout: 'Optional[str]' = None, format: 'Optional[Formats]' = None, # basic settings # pylint: disable=redefined-builtin
633
+ auto: 'bool' = True, extension: 'bool' = True, store: 'bool' = True, # internal settings # pylint: disable=line-too-long
634
+ files: 'bool' = False, nofile: 'bool' = False, verbose: 'bool | VerboseHandler' = False, # output settings # pylint: disable=line-too-long
635
+ engine: 'Optional[Engines]' = None, layer: 'Optional[Layers]' = None, protocol: 'Optional[Protocols]' = None, # extraction settings # pylint: disable=line-too-long
636
+ reassembly: 'bool' = False, reasm_strict: 'bool' = True, reasm_store: 'bool' = True, # reassembly settings # pylint: disable=line-too-long
637
+ trace: 'bool' = False, trace_fout: 'Optional[str]' = None, trace_format: 'Optional[Formats]' = None, # trace settings # pylint: disable=line-too-long
638
+ trace_byteorder: 'Literal["big", "little"]' = sys.byteorder, trace_nanosecond: 'bool' = False, # trace settings # pylint: disable=line-too-long
639
+ ip: 'bool' = False, ipv4: 'bool' = False, ipv6: 'bool' = False, tcp: 'bool' = False, # reassembly/trace settings # pylint: disable=line-too-long
640
+ buffer_size: 'int' = io.DEFAULT_BUFFER_SIZE, buffer_save: 'bool' = False, buffer_path: 'Optional[str]' = None, # buffer settings # pylint: disable=line-too-long
641
+ no_eof: 'bool' = False) -> 'None':
642
+ """Initialise PCAP Reader.
643
+
644
+ Args:
645
+ fin: file name to be read or a binary IO object;
646
+ if file not exist, raise :exc:`FileNotFound`
647
+ fout: file name to be written
648
+ format: file format of output
649
+
650
+ auto: if automatically run till EOF
651
+ extension: if check and append extensions to output file
652
+ store: if store extracted packet info
653
+
654
+ files: if split each frame into different files
655
+ nofile: if no output file is to be dumped
656
+ verbose: a :obj:`bool` value or a function takes the :class:`Extractor`
657
+ instance and current parsed frame (depends on engine selected) as
658
+ parameters to print verbose output information
659
+
660
+ engine: extraction engine to be used
661
+ layer: extract til which layer
662
+ protocol: extract til which protocol
663
+
664
+ reassembly: if perform reassembly
665
+ reasm_strict: if set strict flag for reassembly
666
+ reasm_store: if store reassembled datagrams
667
+
668
+ trace: if trace TCP traffic flows
669
+ trace_fout: path name for flow tracer if necessary
670
+ trace_format: output file format of flow tracer
671
+ trace_byteorder: output file byte order
672
+ trace_nanosecond: output nanosecond-resolution file flag
673
+
674
+ ip: if record data for IPv4 & IPv6 reassembly (must be used with ``reassembly=True``)
675
+ ipv4: if perform IPv4 reassembly (must be used with ``reassembly=True``)
676
+ ipv6: if perform IPv6 reassembly (must be used with ``reassembly=True``)
677
+ tcp: if perform TCP reassembly and/or flow tracing
678
+ (must be used with ``reassembly=True`` or ``trace=True``)
679
+
680
+ buffer_size: buffer size for reading input file (for :class:`~pcapkit.corekit.io.SeekableReader` only)
681
+ buffer_save: if save buffer to file (for :class:`~pcapkit.corekit.io.SeekableReader` only)
682
+ buffer_path: path name for buffer file if necessary (for :class:`~pcapkit.corekit.io.SeekableReader` only)
683
+
684
+ no_eof: if raise :exc:`EOFError` when EOF
685
+
686
+ Warns:
687
+ pcapkit.utilities.warnings.FormatWarning: Warns under following circumstances:
688
+
689
+ * If using PCAP output for TCP flow tracing while the extraction engine is PyShark.
690
+ * If output file format is not supported.
691
+
692
+ """
693
+ if fin is None:
694
+ fin = 'in.pcap'
695
+ if fout is None:
696
+ fout = 'out'
697
+ if format is None:
698
+ format = 'tree'
699
+
700
+ ifnm, ofnm, fmt, oext, files = self.make_name(fin, fout, format, extension, files=files, nofile=nofile)
701
+
702
+ self._ifnm = ifnm # input file name
703
+ self._ofnm = ofnm # output file name
704
+ self._fext = oext # output file extension
705
+
706
+ self._flag_a = auto # auto extract flag
707
+ self._flag_d = store # store data flag
708
+ self._flag_e = False # EOF flag
709
+ self._flag_f = files # split file flag
710
+ self._flag_q = nofile # no output flag
711
+ self._flag_r = reassembly # reassembly flag
712
+ self._flag_t = trace # trace flag
713
+ self._flag_v = False # verbose flag
714
+ self._flag_s = isinstance(fin, str) # input filename flag
715
+ self._flag_n = no_eof # no EOF flag
716
+
717
+ # verbose callback function
718
+ if isinstance(verbose, bool):
719
+ self._flag_v = verbose
720
+ if verbose:
721
+ self._vfunc = lambda e, f: print(
722
+ f'Frame {e._frnum:>3d}: {f.protochain}' # pylint: disable=protected-access
723
+ ) # pylint: disable=logging-fstring-interpolation
724
+ else:
725
+ self._vfunc = lambda e, f: None
726
+ else:
727
+ self._flag_v = True
728
+ self._vfunc = verbose
729
+
730
+ self._frnum = 0 # frame number
731
+ self._frame = [] # frame record
732
+
733
+ self._ipv4 = ipv4 or ip # IPv4 Reassembly
734
+ self._ipv6 = ipv6 or ip # IPv6 Reassembly
735
+ self._tcp = tcp # TCP Reassembly
736
+
737
+ self._exptl = protocol or 'null' # extract til protocol
738
+ self._exlyr = cast('Layers', (layer or 'none').lower()) # extract til layer
739
+ self._exnam = cast('Engines', (engine or 'default').lower()) # extract using engine
740
+
741
+ if reassembly:
742
+ reasm_obj_ipv4 = reasm_obj_ipv6 = reasm_obj_tcp = None
743
+
744
+ if self._ipv4:
745
+ logger.info('IPv4 reassembly enabled')
746
+
747
+ reasm_cls_ipv4 = self.__reassembly__['ipv4']
748
+ if isinstance(reasm_cls_ipv4, ModuleDescriptor):
749
+ reasm_cls_ipv4 = reasm_cls_ipv4.klass
750
+ self.__reassembly__['ipv4'] = reasm_cls_ipv4 # update mapping upon import
751
+ reasm_obj_ipv4 = cast('IPv4_Reassembly', reasm_cls_ipv4(strict=reasm_strict, store=reasm_store))
752
+ if self._ipv6:
753
+ logger.info('IPv6 reassembly enabled')
754
+
755
+ reasm_cls_ipv6 = self.__reassembly__['ipv6']
756
+ if isinstance(reasm_cls_ipv6, ModuleDescriptor):
757
+ reasm_cls_ipv6 = reasm_cls_ipv6.klass
758
+ self.__reassembly__['ipv6'] = reasm_cls_ipv6 # update mapping upon import
759
+ reasm_obj_ipv6 = cast('IPv6_Reassembly', reasm_cls_ipv6(strict=reasm_strict, store=reasm_store))
760
+ if self._tcp:
761
+ logger.info('TCP reassembly enabled')
762
+
763
+ reasm_cls_tcp = self.__reassembly__['tcp']
764
+ if isinstance(reasm_cls_tcp, ModuleDescriptor):
765
+ reasm_cls_tcp = reasm_cls_tcp.klass
766
+ self.__reassembly__['tcp'] = reasm_cls_tcp # update mapping upon import
767
+ reasm_obj_tcp = cast('TCP_Reassembly', reasm_cls_tcp(strict=reasm_strict, store=reasm_store))
768
+
769
+ self._reasm = ReassemblyManager(
770
+ ipv4=reasm_obj_ipv4,
771
+ ipv6=reasm_obj_ipv6,
772
+ tcp=reasm_obj_tcp,
773
+ )
774
+
775
+ if trace:
776
+ trace_obj_tcp = None
777
+
778
+ if self._exnam in ('pyshark',) and trace_format in ('pcap',):
779
+ warn(f"'Extractor(engine={self._exnam})' does not support 'trace_format={trace_format}'; "
780
+ "using 'trace_format=None' instead", FormatWarning, stacklevel=stacklevel())
781
+ trace_format = None
782
+
783
+ if self._tcp:
784
+ logger.info('TCP flow tracing enabled')
785
+
786
+ trace_cls_tcp = self.__traceflow__['tcp']
787
+ if isinstance(trace_cls_tcp, ModuleDescriptor):
788
+ trace_cls_tcp = trace_cls_tcp.klass
789
+ self.__traceflow__['tcp'] = trace_cls_tcp # update mapping upon import
790
+ trace_obj_tcp = cast('TCP_TraceFlow', trace_cls_tcp(fout=trace_fout, format=trace_format,
791
+ byteorder=trace_byteorder, nanosecond=trace_nanosecond))
792
+
793
+ self._trace = TraceFlowManager(
794
+ tcp=trace_obj_tcp,
795
+ )
796
+
797
+ if self._flag_s:
798
+ self._ifile = open(ifnm, 'rb') # input file # pylint: disable=unspecified-encoding,consider-using-with
799
+ else:
800
+ self._ifile = cast('BufferedReader', fin)
801
+
802
+ if not self._ifile.seekable():
803
+ self._ifile = SeekableReader(self._ifile, buffer_size, buffer_save, buffer_path,
804
+ stream_closing=not self._flag_s)
805
+
806
+ if not self._flag_q:
807
+ output, ext = self.__output__[fmt]
808
+ if ext is None:
809
+ warn(f'Unsupported output format: {fmt}; disabled file output feature',
810
+ FormatWarning, stacklevel=stacklevel())
811
+ if isinstance(output, ModuleDescriptor):
812
+ output = output.klass
813
+ self.__output__[fmt] = (output, ext) # update mapping upon import
814
+ dumper = make_dumper(output)
815
+
816
+ self._ofile = dumper if self._flag_f else dumper(ofnm) # output file
817
+
818
+ # NOTE: we use peek() to read the magic number, as the file pointer
819
+ # will not be moved after reading; however, the returned bytes object
820
+ # may not be exactly 4 bytes, so we use [:4] to get the first 4 bytes
821
+ self._magic = self._ifile.peek(4)[:4]
822
+ #self._magic = self._ifile.read(4) # magic number
823
+ #self._ifile.seek(0, os.SEEK_SET)
824
+
825
+ self.run() # start extraction
826
+
827
+ def __iter__(self) -> 'Extractor':
828
+ """Iterate and parse PCAP frame.
829
+
830
+ Raises:
831
+ IterableError: If :attr:`self._flag_a <pcapkit.foundation.extraction.Extractor._flag_a>`
832
+ is :data:`True`, as such operation is not applicable.
833
+
834
+ """
835
+ if not self._flag_a:
836
+ return self
837
+ raise IterableError("'Extractor(auto=True)' object is not iterable")
838
+
839
+ def __next__(self) -> '_P':
840
+ """Iterate and parse next PCAP frame.
841
+
842
+ It will call :meth:`self._exeng.read_frame <pcapkit.foundation.engines.engine.Engine.read_frame>`
843
+ to parse next PCAP frame internally, until the EOF reached;
844
+ then it calls :meth:`self._cleanup <_cleanup>` for the aftermath.
845
+
846
+ """
847
+ while True:
848
+ try:
849
+ return self._exeng.read_frame()
850
+ except (EOFError, StopIteration) as error:
851
+ warn('EOF reached', ExtractionWarning, stacklevel=stacklevel())
852
+
853
+ if self._flag_n:
854
+ continue
855
+
856
+ self._cleanup()
857
+ raise StopIteration from error # pylint: disable=raise-missing-from
858
+ except KeyboardInterrupt:
859
+ self._cleanup()
860
+ raise
861
+
862
+ def __call__(self) -> '_P':
863
+ """Works as a simple wrapper for the iteration protocol.
864
+
865
+ Raises:
866
+ IterableError: If :attr:`self._flag_a <pcapkit.foundation.extraction.Extractor._flag_a>`
867
+ is :data:`True`, as iteration is not applicable.
868
+
869
+ """
870
+ if not self._flag_a:
871
+ while True:
872
+ try:
873
+ return self._exeng.read_frame()
874
+ except (EOFError, StopIteration):
875
+ warn('EOF reached', ExtractionWarning, stacklevel=stacklevel())
876
+
877
+ if self._flag_n:
878
+ continue
879
+
880
+ self._cleanup()
881
+ raise
882
+ except KeyboardInterrupt:
883
+ self._cleanup()
884
+ raise
885
+ raise CallableError("'Extractor(auto=True)' object is not callable")
886
+
887
+ def __enter__(self) -> 'Extractor':
888
+ """Uses :class:`Extractor` as a context manager."""
889
+ return self
890
+
891
+ def __exit__(self, exc_type: 'Type[BaseException] | None', exc_value: 'BaseException | None',
892
+ traceback: 'TracebackType | None') -> 'None': # pylint: disable=unused-argument
893
+ """Close the input file when exits."""
894
+ self._ifile.close()
895
+ self._exeng.close()
896
+
897
+ ##########################################################################
898
+ # Utilities.
899
+ ##########################################################################
900
+
901
+ def _cleanup(self) -> 'None':
902
+ """Cleanup after extraction & analysis.
903
+
904
+ The method calls :meth:`self._exeng.close <pcapkit.foundation.engines.engine.Engine.close>`,
905
+ sets :attr:`self._flag_e <pcapkit.foundation.extraction.Extractor._flag_e>`
906
+ as :data:`True` and closes the input file (if necessary).
907
+
908
+ """
909
+ # pylint: disable=attribute-defined-outside-init
910
+ self._flag_e = True
911
+ if isinstance(self._ifile, SeekableReader):
912
+ self._ifile.close()
913
+ elif not self._flag_s:
914
+ self._ifile.close()
915
+ self._exeng.close()