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.
- pcapkit/__init__.py +126 -0
- pcapkit/__main__.py +138 -0
- pcapkit/all.py +136 -0
- pcapkit/const/__init__.py +81 -0
- pcapkit/const/arp/__init__.py +25 -0
- pcapkit/const/arp/hardware.py +181 -0
- pcapkit/const/arp/operation.py +131 -0
- pcapkit/const/ftp/__init__.py +25 -0
- pcapkit/const/ftp/command.py +309 -0
- pcapkit/const/ftp/return_code.py +304 -0
- pcapkit/const/hip/__init__.py +94 -0
- pcapkit/const/hip/certificate.py +77 -0
- pcapkit/const/hip/cipher.py +65 -0
- pcapkit/const/hip/di.py +59 -0
- pcapkit/const/hip/ecdsa_curve.py +59 -0
- pcapkit/const/hip/ecdsa_low_curve.py +56 -0
- pcapkit/const/hip/eddsa_curve.py +65 -0
- pcapkit/const/hip/esp_transform_suite.py +98 -0
- pcapkit/const/hip/group.py +86 -0
- pcapkit/const/hip/hi_algorithm.py +86 -0
- pcapkit/const/hip/hit_suite.py +68 -0
- pcapkit/const/hip/nat_traversal.py +62 -0
- pcapkit/const/hip/notify_message.py +200 -0
- pcapkit/const/hip/packet.py +89 -0
- pcapkit/const/hip/parameter.py +377 -0
- pcapkit/const/hip/registration.py +68 -0
- pcapkit/const/hip/registration_failure.py +84 -0
- pcapkit/const/hip/suite.py +71 -0
- pcapkit/const/hip/transport.py +59 -0
- pcapkit/const/http/__init__.py +39 -0
- pcapkit/const/http/error_code.py +95 -0
- pcapkit/const/http/frame.py +95 -0
- pcapkit/const/http/method.py +184 -0
- pcapkit/const/http/setting.py +96 -0
- pcapkit/const/http/status_code.py +294 -0
- pcapkit/const/ipv4/__init__.py +57 -0
- pcapkit/const/ipv4/classification_level.py +64 -0
- pcapkit/const/ipv4/option_class.py +55 -0
- pcapkit/const/ipv4/option_number.py +137 -0
- pcapkit/const/ipv4/protection_authority.py +63 -0
- pcapkit/const/ipv4/qs_function.py +51 -0
- pcapkit/const/ipv4/router_alert.py +251 -0
- pcapkit/const/ipv4/tos_del.py +51 -0
- pcapkit/const/ipv4/tos_ecn.py +55 -0
- pcapkit/const/ipv4/tos_pre.py +63 -0
- pcapkit/const/ipv4/tos_rel.py +51 -0
- pcapkit/const/ipv4/tos_thr.py +51 -0
- pcapkit/const/ipv4/ts_flag.py +53 -0
- pcapkit/const/ipv6/__init__.py +53 -0
- pcapkit/const/ipv6/extension_header.py +66 -0
- pcapkit/const/ipv6/option.py +137 -0
- pcapkit/const/ipv6/option_action.py +55 -0
- pcapkit/const/ipv6/qs_function.py +51 -0
- pcapkit/const/ipv6/router_alert.py +266 -0
- pcapkit/const/ipv6/routing.py +80 -0
- pcapkit/const/ipv6/seed_id.py +55 -0
- pcapkit/const/ipv6/smf_dpd_mode.py +51 -0
- pcapkit/const/ipv6/tagger_id.py +62 -0
- pcapkit/const/ipx/__init__.py +27 -0
- pcapkit/const/ipx/packet.py +72 -0
- pcapkit/const/ipx/socket.py +104 -0
- pcapkit/const/l2tp/__init__.py +21 -0
- pcapkit/const/l2tp/type.py +51 -0
- pcapkit/const/mh/__init__.py +204 -0
- pcapkit/const/mh/access_type.py +92 -0
- pcapkit/const/mh/ack_status_code.py +71 -0
- pcapkit/const/mh/ani_suboption.py +74 -0
- pcapkit/const/mh/auth_subtype.py +53 -0
- pcapkit/const/mh/binding_ack_flag.py +66 -0
- pcapkit/const/mh/binding_error.py +51 -0
- pcapkit/const/mh/binding_revocation.py +59 -0
- pcapkit/const/mh/binding_update_flag.py +81 -0
- pcapkit/const/mh/cga_extension.py +66 -0
- pcapkit/const/mh/cga_sec.py +57 -0
- pcapkit/const/mh/cga_type.py +68 -0
- pcapkit/const/mh/dhcp_support_mode.py +53 -0
- pcapkit/const/mh/dns_status_code.py +65 -0
- pcapkit/const/mh/dsmip6_tls_packet.py +62 -0
- pcapkit/const/mh/dsmipv6_home_address.py +74 -0
- pcapkit/const/mh/enumerating_algorithm.py +56 -0
- pcapkit/const/mh/fb_ack_status.py +62 -0
- pcapkit/const/mh/fb_action.py +71 -0
- pcapkit/const/mh/fb_indication_trigger.py +65 -0
- pcapkit/const/mh/fb_type.py +59 -0
- pcapkit/const/mh/flow_id_status.py +77 -0
- pcapkit/const/mh/flow_id_suboption.py +71 -0
- pcapkit/const/mh/handoff_type.py +71 -0
- pcapkit/const/mh/handover_ack_flag.py +54 -0
- pcapkit/const/mh/handover_ack_status.py +92 -0
- pcapkit/const/mh/handover_initiate_flag.py +57 -0
- pcapkit/const/mh/handover_initiate_status.py +62 -0
- pcapkit/const/mh/home_address_reply.py +71 -0
- pcapkit/const/mh/lla_code.py +63 -0
- pcapkit/const/mh/lma_mag_suboption.py +59 -0
- pcapkit/const/mh/mn_group_id.py +59 -0
- pcapkit/const/mh/mn_id_subtype.py +77 -0
- pcapkit/const/mh/operator_id.py +63 -0
- pcapkit/const/mh/option.py +260 -0
- pcapkit/const/mh/packet.py +119 -0
- pcapkit/const/mh/qos_attribute.py +89 -0
- pcapkit/const/mh/revocation_status_code.py +83 -0
- pcapkit/const/mh/revocation_trigger.py +86 -0
- pcapkit/const/mh/status_code.py +232 -0
- pcapkit/const/mh/traffic_selector.py +62 -0
- pcapkit/const/mh/upa_status.py +71 -0
- pcapkit/const/mh/upn_reason.py +80 -0
- pcapkit/const/ospf/__init__.py +27 -0
- pcapkit/const/ospf/authentication.py +65 -0
- pcapkit/const/ospf/packet.py +71 -0
- pcapkit/const/pcapng/__init__.py +51 -0
- pcapkit/const/pcapng/block_type.py +152 -0
- pcapkit/const/pcapng/filter_type.py +48 -0
- pcapkit/const/pcapng/hash_algorithm.py +59 -0
- pcapkit/const/pcapng/option_type.py +233 -0
- pcapkit/const/pcapng/record_type.py +57 -0
- pcapkit/const/pcapng/secrets_type.py +56 -0
- pcapkit/const/pcapng/verdict_type.py +53 -0
- pcapkit/const/reg/__init__.py +34 -0
- pcapkit/const/reg/apptype.py +32702 -0
- pcapkit/const/reg/ethertype.py +714 -0
- pcapkit/const/reg/linktype.py +902 -0
- pcapkit/const/reg/transtype.py +523 -0
- pcapkit/const/tcp/__init__.py +35 -0
- pcapkit/const/tcp/checksum.py +55 -0
- pcapkit/const/tcp/flags.py +73 -0
- pcapkit/const/tcp/mp_tcp_option.py +80 -0
- pcapkit/const/tcp/option.py +198 -0
- pcapkit/const/vlan/__init__.py +23 -0
- pcapkit/const/vlan/priority_level.py +71 -0
- pcapkit/corekit/__init__.py +59 -0
- pcapkit/corekit/fields/__init__.py +45 -0
- pcapkit/corekit/fields/collections.py +282 -0
- pcapkit/corekit/fields/field.py +269 -0
- pcapkit/corekit/fields/ipaddress.py +274 -0
- pcapkit/corekit/fields/misc.py +722 -0
- pcapkit/corekit/fields/numbers.py +375 -0
- pcapkit/corekit/fields/strings.py +245 -0
- pcapkit/corekit/infoclass.py +394 -0
- pcapkit/corekit/io.py +506 -0
- pcapkit/corekit/module.py +39 -0
- pcapkit/corekit/multidict.py +626 -0
- pcapkit/corekit/protochain.py +263 -0
- pcapkit/corekit/version.py +33 -0
- pcapkit/dumpkit/__init__.py +15 -0
- pcapkit/dumpkit/common.py +199 -0
- pcapkit/dumpkit/null.py +77 -0
- pcapkit/dumpkit/pcap.py +144 -0
- pcapkit/foundation/__init__.py +45 -0
- pcapkit/foundation/engines/__init__.py +36 -0
- pcapkit/foundation/engines/dpkt.py +230 -0
- pcapkit/foundation/engines/engine.py +194 -0
- pcapkit/foundation/engines/pcap.py +188 -0
- pcapkit/foundation/engines/pcapng.py +310 -0
- pcapkit/foundation/engines/pyshark.py +166 -0
- pcapkit/foundation/engines/scapy.py +161 -0
- pcapkit/foundation/extraction.py +915 -0
- pcapkit/foundation/reassembly/__init__.py +49 -0
- pcapkit/foundation/reassembly/data/__init__.py +48 -0
- pcapkit/foundation/reassembly/data/ip.py +117 -0
- pcapkit/foundation/reassembly/data/tcp.py +145 -0
- pcapkit/foundation/reassembly/ip.py +192 -0
- pcapkit/foundation/reassembly/ipv4.py +50 -0
- pcapkit/foundation/reassembly/ipv6.py +50 -0
- pcapkit/foundation/reassembly/reassembly.py +389 -0
- pcapkit/foundation/reassembly/tcp.py +249 -0
- pcapkit/foundation/registry/__init__.py +41 -0
- pcapkit/foundation/registry/foundation.py +327 -0
- pcapkit/foundation/registry/protocols.py +885 -0
- pcapkit/foundation/traceflow/__init__.py +44 -0
- pcapkit/foundation/traceflow/data/__init__.py +30 -0
- pcapkit/foundation/traceflow/data/tcp.py +105 -0
- pcapkit/foundation/traceflow/tcp.py +159 -0
- pcapkit/foundation/traceflow/traceflow.py +390 -0
- pcapkit/interface/__init__.py +22 -0
- pcapkit/interface/core.py +185 -0
- pcapkit/interface/misc.py +120 -0
- pcapkit/protocols/__init__.py +85 -0
- pcapkit/protocols/application/NotImplemented/bgp.py +0 -0
- pcapkit/protocols/application/NotImplemented/dhcp.py +0 -0
- pcapkit/protocols/application/NotImplemented/dhcpv6.py +0 -0
- pcapkit/protocols/application/NotImplemented/dns.py +0 -0
- pcapkit/protocols/application/NotImplemented/imap.py +0 -0
- pcapkit/protocols/application/NotImplemented/ldap.py +0 -0
- pcapkit/protocols/application/NotImplemented/mqtt.py +0 -0
- pcapkit/protocols/application/NotImplemented/nntp.py +0 -0
- pcapkit/protocols/application/NotImplemented/ntp.py +0 -0
- pcapkit/protocols/application/NotImplemented/onc_rpc.py +0 -0
- pcapkit/protocols/application/NotImplemented/pop.py +0 -0
- pcapkit/protocols/application/NotImplemented/rip.py +0 -0
- pcapkit/protocols/application/NotImplemented/rtp.py +0 -0
- pcapkit/protocols/application/NotImplemented/sip.py +0 -0
- pcapkit/protocols/application/NotImplemented/smtp.py +0 -0
- pcapkit/protocols/application/NotImplemented/snmp.py +0 -0
- pcapkit/protocols/application/NotImplemented/ssh.py +0 -0
- pcapkit/protocols/application/NotImplemented/telnet.py +0 -0
- pcapkit/protocols/application/NotImplemented/tls.py +0 -0
- pcapkit/protocols/application/NotImplemented/xmpp.py +0 -0
- pcapkit/protocols/application/__init__.py +34 -0
- pcapkit/protocols/application/application.py +114 -0
- pcapkit/protocols/application/ftp.py +206 -0
- pcapkit/protocols/application/http.py +176 -0
- pcapkit/protocols/application/httpv1.py +320 -0
- pcapkit/protocols/application/httpv2.py +1255 -0
- pcapkit/protocols/data/__init__.py +192 -0
- pcapkit/protocols/data/application/__init__.py +57 -0
- pcapkit/protocols/data/application/ftp.py +59 -0
- pcapkit/protocols/data/application/httpv1.py +79 -0
- pcapkit/protocols/data/application/httpv2.py +293 -0
- pcapkit/protocols/data/data.py +25 -0
- pcapkit/protocols/data/internet/__init__.py +298 -0
- pcapkit/protocols/data/internet/ah.py +31 -0
- pcapkit/protocols/data/internet/hip.py +804 -0
- pcapkit/protocols/data/internet/hopopt.py +351 -0
- pcapkit/protocols/data/internet/ipv4.py +369 -0
- pcapkit/protocols/data/internet/ipv6.py +67 -0
- pcapkit/protocols/data/internet/ipv6_frag.py +29 -0
- pcapkit/protocols/data/internet/ipv6_opts.py +368 -0
- pcapkit/protocols/data/internet/ipv6_route.py +86 -0
- pcapkit/protocols/data/internet/ipx.py +56 -0
- pcapkit/protocols/data/internet/mh.py +509 -0
- pcapkit/protocols/data/link/__init__.py +33 -0
- pcapkit/protocols/data/link/arp.py +74 -0
- pcapkit/protocols/data/link/ethernet.py +28 -0
- pcapkit/protocols/data/link/l2tp.py +63 -0
- pcapkit/protocols/data/link/ospf.py +58 -0
- pcapkit/protocols/data/link/vlan.py +42 -0
- pcapkit/protocols/data/misc/__init__.py +109 -0
- pcapkit/protocols/data/misc/null.py +18 -0
- pcapkit/protocols/data/misc/pcap/__init__.py +18 -0
- pcapkit/protocols/data/misc/pcap/frame.py +56 -0
- pcapkit/protocols/data/misc/pcap/header.py +53 -0
- pcapkit/protocols/data/misc/pcapng.py +925 -0
- pcapkit/protocols/data/misc/raw.py +25 -0
- pcapkit/protocols/data/protocol.py +32 -0
- pcapkit/protocols/data/transport/__init__.py +71 -0
- pcapkit/protocols/data/transport/tcp.py +555 -0
- pcapkit/protocols/data/transport/udp.py +29 -0
- pcapkit/protocols/internet/NotImplemented/ecn.py +0 -0
- pcapkit/protocols/internet/NotImplemented/esp.py +97 -0
- pcapkit/protocols/internet/NotImplemented/icmp.py +0 -0
- pcapkit/protocols/internet/NotImplemented/icmpv6.py +0 -0
- pcapkit/protocols/internet/NotImplemented/igmp.py +0 -0
- pcapkit/protocols/internet/NotImplemented/shim6.py +0 -0
- pcapkit/protocols/internet/__init__.py +43 -0
- pcapkit/protocols/internet/ah.py +275 -0
- pcapkit/protocols/internet/hip.py +4727 -0
- pcapkit/protocols/internet/hopopt.py +1879 -0
- pcapkit/protocols/internet/internet.py +240 -0
- pcapkit/protocols/internet/ip.py +51 -0
- pcapkit/protocols/internet/ipsec.py +50 -0
- pcapkit/protocols/internet/ipv4.py +1782 -0
- pcapkit/protocols/internet/ipv6.py +361 -0
- pcapkit/protocols/internet/ipv6_frag.py +258 -0
- pcapkit/protocols/internet/ipv6_opts.py +1890 -0
- pcapkit/protocols/internet/ipv6_route.py +710 -0
- pcapkit/protocols/internet/ipx.py +230 -0
- pcapkit/protocols/internet/mh.py +2764 -0
- pcapkit/protocols/link/NotImplemented/dsl.py +0 -0
- pcapkit/protocols/link/NotImplemented/eapol.py +1 -0
- pcapkit/protocols/link/NotImplemented/fddi.py +0 -0
- pcapkit/protocols/link/NotImplemented/isdn.py +0 -0
- pcapkit/protocols/link/NotImplemented/ndp.py +0 -0
- pcapkit/protocols/link/NotImplemented/ppp.py +0 -0
- pcapkit/protocols/link/__init__.py +35 -0
- pcapkit/protocols/link/arp.py +421 -0
- pcapkit/protocols/link/ethernet.py +248 -0
- pcapkit/protocols/link/l2tp.py +267 -0
- pcapkit/protocols/link/link.py +140 -0
- pcapkit/protocols/link/ospf.py +342 -0
- pcapkit/protocols/link/rarp.py +82 -0
- pcapkit/protocols/link/vlan.py +225 -0
- pcapkit/protocols/misc/__init__.py +37 -0
- pcapkit/protocols/misc/null.py +129 -0
- pcapkit/protocols/misc/pcap/__init__.py +17 -0
- pcapkit/protocols/misc/pcap/frame.py +478 -0
- pcapkit/protocols/misc/pcap/header.py +358 -0
- pcapkit/protocols/misc/pcapng.py +5520 -0
- pcapkit/protocols/misc/raw.py +180 -0
- pcapkit/protocols/protocol.py +1216 -0
- pcapkit/protocols/schema/__init__.py +140 -0
- pcapkit/protocols/schema/application/__init__.py +40 -0
- pcapkit/protocols/schema/application/ftp.py +21 -0
- pcapkit/protocols/schema/application/httpv1.py +21 -0
- pcapkit/protocols/schema/application/httpv2.py +384 -0
- pcapkit/protocols/schema/internet/__init__.py +294 -0
- pcapkit/protocols/schema/internet/ah.py +40 -0
- pcapkit/protocols/schema/internet/hip.py +1184 -0
- pcapkit/protocols/schema/internet/hopopt.py +679 -0
- pcapkit/protocols/schema/internet/ipv4.py +576 -0
- pcapkit/protocols/schema/internet/ipv6.py +63 -0
- pcapkit/protocols/schema/internet/ipv6_frag.py +48 -0
- pcapkit/protocols/schema/internet/ipv6_opts.py +680 -0
- pcapkit/protocols/schema/internet/ipv6_route.py +198 -0
- pcapkit/protocols/schema/internet/ipx.py +40 -0
- pcapkit/protocols/schema/internet/mh.py +718 -0
- pcapkit/protocols/schema/link/__init__.py +19 -0
- pcapkit/protocols/schema/link/arp.py +39 -0
- pcapkit/protocols/schema/link/ethernet.py +51 -0
- pcapkit/protocols/schema/link/l2tp.py +88 -0
- pcapkit/protocols/schema/link/ospf.py +90 -0
- pcapkit/protocols/schema/link/vlan.py +69 -0
- pcapkit/protocols/schema/misc/__init__.py +108 -0
- pcapkit/protocols/schema/misc/null.py +18 -0
- pcapkit/protocols/schema/misc/pcap/__init__.py +10 -0
- pcapkit/protocols/schema/misc/pcap/frame.py +51 -0
- pcapkit/protocols/schema/misc/pcap/header.py +63 -0
- pcapkit/protocols/schema/misc/pcapng.py +1689 -0
- pcapkit/protocols/schema/misc/raw.py +24 -0
- pcapkit/protocols/schema/schema.py +809 -0
- pcapkit/protocols/schema/transport/__init__.py +69 -0
- pcapkit/protocols/schema/transport/tcp.py +928 -0
- pcapkit/protocols/schema/transport/udp.py +90 -0
- pcapkit/protocols/transport/NotImplemented/dccp.py +0 -0
- pcapkit/protocols/transport/NotImplemented/rsvp.py +0 -0
- pcapkit/protocols/transport/NotImplemented/sctp.py +0 -0
- pcapkit/protocols/transport/__init__.py +27 -0
- pcapkit/protocols/transport/tcp.py +3025 -0
- pcapkit/protocols/transport/transport.py +158 -0
- pcapkit/protocols/transport/udp.py +214 -0
- pcapkit/py.typed +0 -0
- pcapkit/toolkit/__init__.py +57 -0
- pcapkit/toolkit/dpkt.py +306 -0
- pcapkit/toolkit/pcap.py +212 -0
- pcapkit/toolkit/pcapng.py +251 -0
- pcapkit/toolkit/pyshark.py +99 -0
- pcapkit/toolkit/scapy.py +297 -0
- pcapkit/utilities/__init__.py +20 -0
- pcapkit/utilities/compat.py +196 -0
- pcapkit/utilities/decorators.py +192 -0
- pcapkit/utilities/exceptions.py +365 -0
- pcapkit/utilities/logging.py +55 -0
- pcapkit/utilities/warnings.py +185 -0
- pcapkit/vendor/__init__.py +105 -0
- pcapkit/vendor/__main__.py +92 -0
- pcapkit/vendor/arp/__init__.py +27 -0
- pcapkit/vendor/arp/hardware.py +29 -0
- pcapkit/vendor/arp/operation.py +29 -0
- pcapkit/vendor/default.py +474 -0
- pcapkit/vendor/ftp/__init__.py +27 -0
- pcapkit/vendor/ftp/command.py +244 -0
- pcapkit/vendor/ftp/return_code.py +256 -0
- pcapkit/vendor/hip/__init__.py +94 -0
- pcapkit/vendor/hip/certificate.py +29 -0
- pcapkit/vendor/hip/cipher.py +29 -0
- pcapkit/vendor/hip/di.py +29 -0
- pcapkit/vendor/hip/ecdsa_curve.py +29 -0
- pcapkit/vendor/hip/ecdsa_low_curve.py +29 -0
- pcapkit/vendor/hip/eddsa_curve.py +85 -0
- pcapkit/vendor/hip/esp_transform_suite.py +29 -0
- pcapkit/vendor/hip/group.py +87 -0
- pcapkit/vendor/hip/hi_algorithm.py +29 -0
- pcapkit/vendor/hip/hit_suite.py +29 -0
- pcapkit/vendor/hip/nat_traversal.py +29 -0
- pcapkit/vendor/hip/notify_message.py +29 -0
- pcapkit/vendor/hip/packet.py +88 -0
- pcapkit/vendor/hip/parameter.py +88 -0
- pcapkit/vendor/hip/registration.py +29 -0
- pcapkit/vendor/hip/registration_failure.py +29 -0
- pcapkit/vendor/hip/suite.py +29 -0
- pcapkit/vendor/hip/transport.py +29 -0
- pcapkit/vendor/http/__init__.py +39 -0
- pcapkit/vendor/http/error_code.py +95 -0
- pcapkit/vendor/http/frame.py +91 -0
- pcapkit/vendor/http/method.py +167 -0
- pcapkit/vendor/http/setting.py +93 -0
- pcapkit/vendor/http/status_code.py +185 -0
- pcapkit/vendor/ipv4/__init__.py +57 -0
- pcapkit/vendor/ipv4/classification_level.py +91 -0
- pcapkit/vendor/ipv4/option_class.py +80 -0
- pcapkit/vendor/ipv4/option_number.py +105 -0
- pcapkit/vendor/ipv4/protection_authority.py +84 -0
- pcapkit/vendor/ipv4/qs_function.py +78 -0
- pcapkit/vendor/ipv4/router_alert.py +93 -0
- pcapkit/vendor/ipv4/tos_del.py +78 -0
- pcapkit/vendor/ipv4/tos_ecn.py +95 -0
- pcapkit/vendor/ipv4/tos_pre.py +84 -0
- pcapkit/vendor/ipv4/tos_rel.py +78 -0
- pcapkit/vendor/ipv4/tos_thr.py +77 -0
- pcapkit/vendor/ipv4/ts_flag.py +79 -0
- pcapkit/vendor/ipv6/__init__.py +53 -0
- pcapkit/vendor/ipv6/extension_header.py +171 -0
- pcapkit/vendor/ipv6/option.py +104 -0
- pcapkit/vendor/ipv6/option_action.py +90 -0
- pcapkit/vendor/ipv6/qs_function.py +78 -0
- pcapkit/vendor/ipv6/router_alert.py +93 -0
- pcapkit/vendor/ipv6/routing.py +87 -0
- pcapkit/vendor/ipv6/seed_id.py +81 -0
- pcapkit/vendor/ipv6/smf_dpd_mode.py +78 -0
- pcapkit/vendor/ipv6/tagger_id.py +81 -0
- pcapkit/vendor/ipx/__init__.py +37 -0
- pcapkit/vendor/ipx/packet.py +123 -0
- pcapkit/vendor/ipx/socket.py +125 -0
- pcapkit/vendor/l2tp/__init__.py +21 -0
- pcapkit/vendor/l2tp/type.py +78 -0
- pcapkit/vendor/mh/__init__.py +204 -0
- pcapkit/vendor/mh/access_type.py +87 -0
- pcapkit/vendor/mh/ack_status_code.py +88 -0
- pcapkit/vendor/mh/ani_suboption.py +88 -0
- pcapkit/vendor/mh/auth_subtype.py +83 -0
- pcapkit/vendor/mh/binding_ack_flag.py +148 -0
- pcapkit/vendor/mh/binding_error.py +78 -0
- pcapkit/vendor/mh/binding_revocation.py +87 -0
- pcapkit/vendor/mh/binding_update_flag.py +147 -0
- pcapkit/vendor/mh/cga_extension.py +91 -0
- pcapkit/vendor/mh/cga_sec.py +91 -0
- pcapkit/vendor/mh/cga_type.py +74 -0
- pcapkit/vendor/mh/dhcp_support_mode.py +77 -0
- pcapkit/vendor/mh/dns_status_code.py +87 -0
- pcapkit/vendor/mh/dsmip6_tls_packet.py +87 -0
- pcapkit/vendor/mh/dsmipv6_home_address.py +87 -0
- pcapkit/vendor/mh/enumerating_algorithm.py +82 -0
- pcapkit/vendor/mh/fb_ack_status.py +87 -0
- pcapkit/vendor/mh/fb_action.py +88 -0
- pcapkit/vendor/mh/fb_indication_trigger.py +87 -0
- pcapkit/vendor/mh/fb_type.py +88 -0
- pcapkit/vendor/mh/flow_id_status.py +87 -0
- pcapkit/vendor/mh/flow_id_suboption.py +87 -0
- pcapkit/vendor/mh/handoff_type.py +87 -0
- pcapkit/vendor/mh/handover_ack_flag.py +143 -0
- pcapkit/vendor/mh/handover_ack_status.py +87 -0
- pcapkit/vendor/mh/handover_initiate_flag.py +143 -0
- pcapkit/vendor/mh/handover_initiate_status.py +87 -0
- pcapkit/vendor/mh/home_address_reply.py +87 -0
- pcapkit/vendor/mh/lla_code.py +97 -0
- pcapkit/vendor/mh/lma_mag_suboption.py +88 -0
- pcapkit/vendor/mh/mn_group_id.py +87 -0
- pcapkit/vendor/mh/mn_id_subtype.py +87 -0
- pcapkit/vendor/mh/operator_id.py +87 -0
- pcapkit/vendor/mh/option.py +83 -0
- pcapkit/vendor/mh/packet.py +82 -0
- pcapkit/vendor/mh/qos_attribute.py +87 -0
- pcapkit/vendor/mh/revocation_status_code.py +87 -0
- pcapkit/vendor/mh/revocation_trigger.py +87 -0
- pcapkit/vendor/mh/status_code.py +91 -0
- pcapkit/vendor/mh/traffic_selector.py +87 -0
- pcapkit/vendor/mh/upa_status.py +87 -0
- pcapkit/vendor/mh/upn_reason.py +87 -0
- pcapkit/vendor/ospf/__init__.py +27 -0
- pcapkit/vendor/ospf/authentication.py +29 -0
- pcapkit/vendor/ospf/packet.py +29 -0
- pcapkit/vendor/pcapng/__init__.py +51 -0
- pcapkit/vendor/pcapng/block_type.py +94 -0
- pcapkit/vendor/pcapng/filter_type.py +77 -0
- pcapkit/vendor/pcapng/hash_algorithm.py +82 -0
- pcapkit/vendor/pcapng/option_type.py +287 -0
- pcapkit/vendor/pcapng/record_type.py +81 -0
- pcapkit/vendor/pcapng/secrets_type.py +81 -0
- pcapkit/vendor/pcapng/verdict_type.py +79 -0
- pcapkit/vendor/reg/__init__.py +34 -0
- pcapkit/vendor/reg/apptype.py +338 -0
- pcapkit/vendor/reg/ethertype.py +121 -0
- pcapkit/vendor/reg/linktype.py +110 -0
- pcapkit/vendor/reg/transtype.py +111 -0
- pcapkit/vendor/tcp/__init__.py +35 -0
- pcapkit/vendor/tcp/checksum.py +80 -0
- pcapkit/vendor/tcp/flags.py +149 -0
- pcapkit/vendor/tcp/mp_tcp_option.py +90 -0
- pcapkit/vendor/tcp/option.py +103 -0
- pcapkit/vendor/vlan/__init__.py +23 -0
- pcapkit/vendor/vlan/priority_level.py +97 -0
- pypcapkit-1.3.3.post1.dist-info/LICENSE +29 -0
- pypcapkit-1.3.3.post1.dist-info/METADATA +236 -0
- pypcapkit-1.3.3.post1.dist-info/RECORD +466 -0
- pypcapkit-1.3.3.post1.dist-info/WHEEL +5 -0
- pypcapkit-1.3.3.post1.dist-info/entry_points.txt +3 -0
- 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()
|