stackforge 0.4.0__tar.gz → 0.6.0__tar.gz
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.
- {stackforge-0.4.0 → stackforge-0.6.0}/Cargo.lock +3 -3
- {stackforge-0.4.0 → stackforge-0.6.0}/Cargo.toml +1 -1
- {stackforge-0.4.0 → stackforge-0.6.0}/PKG-INFO +42 -3
- {stackforge-0.4.0 → stackforge-0.6.0}/README.md +41 -2
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/config.rs +8 -0
- stackforge-0.6.0/crates/stackforge-core/src/flow/icmp_state.rs +144 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/key.rs +53 -1
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/mod.rs +3 -1
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/state.rs +41 -4
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/table.rs +28 -1
- {stackforge-0.4.0 → stackforge-0.6.0}/src/lib.rs +88 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_flow.py +135 -0
- stackforge-0.6.0/tests/python/test_max_packet_flow_len.py +252 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/.github/workflows/release.yml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/.github/workflows/test.yml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/.gitignore +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/.pre-commit-config.yaml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/.python-version +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/CLAUDE.md +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/CODE_OF_CONDUCT.md +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/CONTRIBUTING.md +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/LICENSE +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/cliff.toml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/cog.toml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-automata/Cargo.toml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-automata/src/lib.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/Cargo.toml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/error.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/error.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/tcp_reassembly.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/tcp_state.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/flow/udp_state.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/arp.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/bindings.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/bitmap.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/edns.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/header.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/query.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/rdata.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/rr.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/svcb.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dns/types.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/control.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/data.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/ie.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/management.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/radiotap.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/security.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot11/types.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot15d4/beacon.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot15d4/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot15d4/command.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot15d4/crc.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot15d4/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot15d4/security.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/dot15d4/types.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ethernet.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/field.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/field_ext.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ftp/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ftp/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/generic/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/generic/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http/detection.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http/request.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http/response.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http2/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http2/frames.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http2/hpack.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/http2/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/icmp/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/icmp/checksum.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/icmp/error.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/icmp/extensions.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/icmp/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/icmp/types.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/icmpv6/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/icmpv6/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/imap/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/imap/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/checksum.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/fragmentation.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/header.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/options.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/protocol.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/routing.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv4/ttl.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv6/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv6/ext_headers.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ipv6/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/l2tp/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/l2tp/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/modbus/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/modbus/crc.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/modbus/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/mqtt/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/mqtt/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/mqttsn/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/mqttsn/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/neighbor.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/pop3/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/pop3/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/quic/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/quic/frames.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/quic/headers.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/quic/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/quic/varint.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/raw.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/smtp/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/smtp/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ssh/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/ssh/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/stack.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tcp/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tcp/checksum.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tcp/flags.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tcp/header.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tcp/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tcp/options.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tcp/services.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tftp/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tftp/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/cert.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/cipher_aead.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/cipher_block.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/cipher_stream.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/compression.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/groups.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/hash.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/hkdf_tls13.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/hmac_tls.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/prf.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/crypto/suites.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/extensions/common.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/extensions/key_share.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/extensions/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/extensions/signature_algorithms.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/extensions/sni.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/extensions/supported_versions.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/handshake/certificate.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/handshake/client_hello.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/handshake/finished.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/handshake/key_exchange.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/handshake/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/handshake/server_hello.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/keyexchange/ecdhe.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/keyexchange/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/record.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/session.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/sslv2/handshake.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/sslv2/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/sslv2/record.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/tls/types.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/udp/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/udp/checksum.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/udp/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/zwave/builder.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/layer/zwave/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/lib.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/packet.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/pcap/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/pcap/reader.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/pcap/writer.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/utils/bits.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/utils/checksum.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/utils/compare.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/utils/hex.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/utils/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/utils/padding.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/crates/stackforge-core/src/utils/random.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/pyproject.toml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/python/stackforge/__init__.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/python/stackforge/custom.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/rust-toolchain.toml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/rustfmt.toml +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/arp.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/arp_compat.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/ethernet_compat.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/icmp_compat.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/ipv4_compat.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/mod.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/ssh_compat.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/tcp_compat.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/tls_compat.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/compat_tests/udp_compat.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/dns.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/dot11.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/dot15d4.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/ethernet.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/field.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/ftp.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/http.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/http2.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/icmpv6.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/imap.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/ipv6.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/layer.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/main.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/modbus.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/mqtt.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/packet.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/pop3.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/quic.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/smtp.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/ssh.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/tftp.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/tls.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/util.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/integration/zwave.rs +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/__init__.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/conftest.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_arp_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_checksums_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_edge_cases_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_ethernet_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_icmp_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_ipv4_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_pcap_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_stacking_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_tcp_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_udp_compat.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/scapy_compat/test_uts_integration.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_core.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_custom.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_dns.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_dot11.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_dot15d4.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_ftp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_http.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_icmpv6.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_imap.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_ipv6.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_l2tp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_modbus.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_mqtt.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_mqttsn.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_pcap.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_pop3.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_quic.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_smtp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_ssh.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_tftp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_tls.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_udp_icmp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_ftp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_http.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_http2.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_imap.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_ipv6.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_l2tp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_modbus.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_mqtt.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_mqttsn.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_pop3.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_quic.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_smtp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_tftp.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_uts_zwave.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/python/test_zwave.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/http2_h2c.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/http_chunk.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/http_compressed-brotli.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/http_compressed-zstd.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/http_compressed.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/http_content_length.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/http_head.pcapng +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/http_tcp_psh.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/ssh_ed25519.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/tcprelay/PCAP.md +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/tcprelay/smallFlows.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/sample_pcap/tcprelay/test.pcap +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/scripts/compare_packets.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/scripts/generate_scapy_fixtures.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/dns.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/dns_dnssec.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/dns_edns0.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/dot11.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/dot15d4.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/fields.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/ftp.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/http.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/http2.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/imap.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/inet.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/inet6 copy.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/inet6.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/l2.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/l2tp.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/modbus.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/mqtt.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/mqttsn.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/pop3.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/quic.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/smtp.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/ssh.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tftp.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/__init__.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/cert.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/example_client.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/example_server.py +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/README.md +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/ca_cert.pem +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/ca_key.pem +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/cli_cert.pem +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/cli_key.pem +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/srv_cert.pem +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/srv_cert_ed25519.pem +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/srv_key.pem +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/pki/srv_key_ed25519.pem +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/sslv2.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/tls.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/tls13.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/tls/tlsclientserver.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/tests/uts/zwave.uts +0 -0
- {stackforge-0.4.0 → stackforge-0.6.0}/uv.lock +0 -0
|
@@ -1030,7 +1030,7 @@ dependencies = [
|
|
|
1030
1030
|
|
|
1031
1031
|
[[package]]
|
|
1032
1032
|
name = "stackforge"
|
|
1033
|
-
version = "0.
|
|
1033
|
+
version = "0.6.0"
|
|
1034
1034
|
dependencies = [
|
|
1035
1035
|
"pyo3",
|
|
1036
1036
|
"stackforge-automata",
|
|
@@ -1039,7 +1039,7 @@ dependencies = [
|
|
|
1039
1039
|
|
|
1040
1040
|
[[package]]
|
|
1041
1041
|
name = "stackforge-automata"
|
|
1042
|
-
version = "0.
|
|
1042
|
+
version = "0.6.0"
|
|
1043
1043
|
dependencies = [
|
|
1044
1044
|
"bytes",
|
|
1045
1045
|
"stackforge-core",
|
|
@@ -1047,7 +1047,7 @@ dependencies = [
|
|
|
1047
1047
|
|
|
1048
1048
|
[[package]]
|
|
1049
1049
|
name = "stackforge-core"
|
|
1050
|
-
version = "0.
|
|
1050
|
+
version = "0.6.0"
|
|
1051
1051
|
dependencies = [
|
|
1052
1052
|
"aes",
|
|
1053
1053
|
"aes-gcm",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stackforge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: Intended Audience :: System Administrators
|
|
@@ -35,8 +35,8 @@ Project-URL: Repository, https://github.com/LaBackDoor/stackforge
|
|
|
35
35
|
|
|
36
36
|
- **Scapy-style API** — Stack layers with `Ether() / IP() / TCP()`, set fields with keyword arguments
|
|
37
37
|
- **High Performance** — Core logic in Rust, zero-copy parsing, copy-on-write mutation
|
|
38
|
-
- **Broad Protocol Support** — Ethernet, ARP, IPv4/IPv6, TCP, UDP, ICMP
|
|
39
|
-
- **Stateful Flow Extraction** — Extract bidirectional conversations from PCAP files with TCP state tracking, stream reassembly,
|
|
38
|
+
- **Broad Protocol Support** — Ethernet, ARP, IPv4/IPv6, TCP, UDP, ICMP/ICMPv6 (with echo correlation), DNS, HTTP/1.x, HTTP/2, QUIC, L2TP, 802.11 (Wi-Fi), 802.15.4 (Zigbee), and custom protocols
|
|
39
|
+
- **Stateful Flow Extraction** — Extract bidirectional conversations from PCAP files with TCP state tracking, stream reassembly, UDP timeout handling, and optional max packet/flow length tracking
|
|
40
40
|
- **PCAP I/O** — Read and write pcap files with `rdpcap()` / `wrpcap()`
|
|
41
41
|
- **Python Bindings** — Seamless integration via PyO3/maturin
|
|
42
42
|
- **Custom Protocols** — Define runtime protocols with `CustomLayer` and typed fields
|
|
@@ -327,6 +327,45 @@ config = FlowConfig(
|
|
|
327
327
|
conversations = extract_flows("capture.pcap", config=config)
|
|
328
328
|
```
|
|
329
329
|
|
|
330
|
+
Optional: Track maximum packet sizes during flow extraction:
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
config = FlowConfig(
|
|
334
|
+
track_max_packet_len=True, # Track max per-direction (forward_max_packet_len, reverse_max_packet_len)
|
|
335
|
+
track_max_flow_len=True, # Track overall max (max_flow_len)
|
|
336
|
+
)
|
|
337
|
+
conversations = extract_flows("capture.pcap", config=config)
|
|
338
|
+
|
|
339
|
+
for conv in conversations:
|
|
340
|
+
print(f"Max fwd packet: {conv.forward_max_packet_len} bytes")
|
|
341
|
+
print(f"Max rev packet: {conv.reverse_max_packet_len} bytes")
|
|
342
|
+
print(f"Max overall: {conv.max_flow_len} bytes")
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Disabled by default (zero overhead). Enable only when needed for flow analysis.
|
|
346
|
+
|
|
347
|
+
#### ICMP and ICMPv6 Flow Tracking
|
|
348
|
+
|
|
349
|
+
Automatically correlate ICMP echo request/reply pairs and track other ICMP message types:
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
conversations = extract_flows("capture.pcap")
|
|
353
|
+
|
|
354
|
+
for conv in conversations:
|
|
355
|
+
if conv.protocol == "ICMP" or conv.protocol == "ICMPv6":
|
|
356
|
+
print(f"ICMP Echo: {conv.src_addr} <-> {conv.dst_addr}")
|
|
357
|
+
print(f" Type: {conv.icmp_type}, Code: {conv.icmp_code}")
|
|
358
|
+
print(f" Identifier: {conv.icmp_identifier}")
|
|
359
|
+
print(f" Requests: {conv.icmp_request_count}, Replies: {conv.icmp_reply_count}")
|
|
360
|
+
print(f" Last seq: {conv.icmp_last_seq}")
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Features:
|
|
364
|
+
- Echo request/reply pairs correlated via identifier (symmetric src/dst ports)
|
|
365
|
+
- Non-echo message types tracked via (type, code) substitution
|
|
366
|
+
- Properties: `icmp_type`, `icmp_code`, `icmp_identifier`, `icmp_request_count`, `icmp_reply_count`, `icmp_last_seq`
|
|
367
|
+
- Returns `None` for non-ICMP flows
|
|
368
|
+
|
|
330
369
|
## Rust Crate
|
|
331
370
|
|
|
332
371
|
The core library is available as a standalone Rust crate:
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
- **Scapy-style API** — Stack layers with `Ether() / IP() / TCP()`, set fields with keyword arguments
|
|
13
13
|
- **High Performance** — Core logic in Rust, zero-copy parsing, copy-on-write mutation
|
|
14
|
-
- **Broad Protocol Support** — Ethernet, ARP, IPv4/IPv6, TCP, UDP, ICMP
|
|
15
|
-
- **Stateful Flow Extraction** — Extract bidirectional conversations from PCAP files with TCP state tracking, stream reassembly,
|
|
14
|
+
- **Broad Protocol Support** — Ethernet, ARP, IPv4/IPv6, TCP, UDP, ICMP/ICMPv6 (with echo correlation), DNS, HTTP/1.x, HTTP/2, QUIC, L2TP, 802.11 (Wi-Fi), 802.15.4 (Zigbee), and custom protocols
|
|
15
|
+
- **Stateful Flow Extraction** — Extract bidirectional conversations from PCAP files with TCP state tracking, stream reassembly, UDP timeout handling, and optional max packet/flow length tracking
|
|
16
16
|
- **PCAP I/O** — Read and write pcap files with `rdpcap()` / `wrpcap()`
|
|
17
17
|
- **Python Bindings** — Seamless integration via PyO3/maturin
|
|
18
18
|
- **Custom Protocols** — Define runtime protocols with `CustomLayer` and typed fields
|
|
@@ -303,6 +303,45 @@ config = FlowConfig(
|
|
|
303
303
|
conversations = extract_flows("capture.pcap", config=config)
|
|
304
304
|
```
|
|
305
305
|
|
|
306
|
+
Optional: Track maximum packet sizes during flow extraction:
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
config = FlowConfig(
|
|
310
|
+
track_max_packet_len=True, # Track max per-direction (forward_max_packet_len, reverse_max_packet_len)
|
|
311
|
+
track_max_flow_len=True, # Track overall max (max_flow_len)
|
|
312
|
+
)
|
|
313
|
+
conversations = extract_flows("capture.pcap", config=config)
|
|
314
|
+
|
|
315
|
+
for conv in conversations:
|
|
316
|
+
print(f"Max fwd packet: {conv.forward_max_packet_len} bytes")
|
|
317
|
+
print(f"Max rev packet: {conv.reverse_max_packet_len} bytes")
|
|
318
|
+
print(f"Max overall: {conv.max_flow_len} bytes")
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Disabled by default (zero overhead). Enable only when needed for flow analysis.
|
|
322
|
+
|
|
323
|
+
#### ICMP and ICMPv6 Flow Tracking
|
|
324
|
+
|
|
325
|
+
Automatically correlate ICMP echo request/reply pairs and track other ICMP message types:
|
|
326
|
+
|
|
327
|
+
```python
|
|
328
|
+
conversations = extract_flows("capture.pcap")
|
|
329
|
+
|
|
330
|
+
for conv in conversations:
|
|
331
|
+
if conv.protocol == "ICMP" or conv.protocol == "ICMPv6":
|
|
332
|
+
print(f"ICMP Echo: {conv.src_addr} <-> {conv.dst_addr}")
|
|
333
|
+
print(f" Type: {conv.icmp_type}, Code: {conv.icmp_code}")
|
|
334
|
+
print(f" Identifier: {conv.icmp_identifier}")
|
|
335
|
+
print(f" Requests: {conv.icmp_request_count}, Replies: {conv.icmp_reply_count}")
|
|
336
|
+
print(f" Last seq: {conv.icmp_last_seq}")
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Features:
|
|
340
|
+
- Echo request/reply pairs correlated via identifier (symmetric src/dst ports)
|
|
341
|
+
- Non-echo message types tracked via (type, code) substitution
|
|
342
|
+
- Properties: `icmp_type`, `icmp_code`, `icmp_identifier`, `icmp_request_count`, `icmp_reply_count`, `icmp_last_seq`
|
|
343
|
+
- Returns `None` for non-ICMP flows
|
|
344
|
+
|
|
306
345
|
## Rust Crate
|
|
307
346
|
|
|
308
347
|
The core library is available as a standalone Rust crate:
|
|
@@ -20,6 +20,10 @@ pub struct FlowConfig {
|
|
|
20
20
|
pub max_ooo_fragments: usize,
|
|
21
21
|
/// Interval between idle conversation eviction sweeps (default: 30s).
|
|
22
22
|
pub eviction_interval: Duration,
|
|
23
|
+
/// Track maximum packet length per direction (default: false).
|
|
24
|
+
pub track_max_packet_len: bool,
|
|
25
|
+
/// Track maximum flow length per direction (default: false).
|
|
26
|
+
pub track_max_flow_len: bool,
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
impl Default for FlowConfig {
|
|
@@ -32,6 +36,8 @@ impl Default for FlowConfig {
|
|
|
32
36
|
max_reassembly_buffer: 16 * 1024 * 1024, // 16 MB
|
|
33
37
|
max_ooo_fragments: 100,
|
|
34
38
|
eviction_interval: Duration::from_secs(30),
|
|
39
|
+
track_max_packet_len: false,
|
|
40
|
+
track_max_flow_len: false,
|
|
35
41
|
}
|
|
36
42
|
}
|
|
37
43
|
}
|
|
@@ -50,5 +56,7 @@ mod tests {
|
|
|
50
56
|
assert_eq!(config.max_reassembly_buffer, 16 * 1024 * 1024);
|
|
51
57
|
assert_eq!(config.max_ooo_fragments, 100);
|
|
52
58
|
assert_eq!(config.eviction_interval, Duration::from_secs(30));
|
|
59
|
+
assert!(!config.track_max_packet_len);
|
|
60
|
+
assert!(!config.track_max_flow_len);
|
|
53
61
|
}
|
|
54
62
|
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
use std::time::Duration;
|
|
2
|
+
|
|
3
|
+
use crate::Packet;
|
|
4
|
+
|
|
5
|
+
use super::config::FlowConfig;
|
|
6
|
+
use super::state::ConversationStatus;
|
|
7
|
+
|
|
8
|
+
/// ICMP/ICMPv6 conversation state.
|
|
9
|
+
///
|
|
10
|
+
/// Tracks ICMP-specific metadata for echo request/reply pairs and other ICMP types.
|
|
11
|
+
/// Echo requests and replies are correlated using the ICMP identifier field.
|
|
12
|
+
#[derive(Debug, Clone)]
|
|
13
|
+
pub struct IcmpFlowState {
|
|
14
|
+
/// ICMP type (e.g., 8 for Echo Request, 0 for Echo Reply).
|
|
15
|
+
pub icmp_type: u8,
|
|
16
|
+
/// ICMP code.
|
|
17
|
+
pub icmp_code: u8,
|
|
18
|
+
/// ICMP identifier (for echo, timestamp, and other types that use it).
|
|
19
|
+
pub identifier: Option<u16>,
|
|
20
|
+
/// Number of echo requests (type 8 for ICMP, 128 for ICMPv6).
|
|
21
|
+
pub request_count: u64,
|
|
22
|
+
/// Number of echo replies (type 0 for ICMP, 129 for ICMPv6).
|
|
23
|
+
pub reply_count: u64,
|
|
24
|
+
/// Last sequence number seen in an echo packet.
|
|
25
|
+
pub last_seq: Option<u16>,
|
|
26
|
+
/// Conversation status.
|
|
27
|
+
pub status: ConversationStatus,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
impl IcmpFlowState {
|
|
31
|
+
#[must_use]
|
|
32
|
+
pub fn new(icmp_type: u8, icmp_code: u8) -> Self {
|
|
33
|
+
Self {
|
|
34
|
+
icmp_type,
|
|
35
|
+
icmp_code,
|
|
36
|
+
identifier: None,
|
|
37
|
+
request_count: 0,
|
|
38
|
+
reply_count: 0,
|
|
39
|
+
last_seq: None,
|
|
40
|
+
status: ConversationStatus::Active,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Update state when a new ICMP packet is received.
|
|
45
|
+
///
|
|
46
|
+
/// Increments request or reply count based on ICMP type, and updates
|
|
47
|
+
/// the identifier and sequence number fields if present.
|
|
48
|
+
pub fn process_packet(&mut self, packet: &Packet, buf: &[u8], icmp_type: u8, icmp_code: u8) {
|
|
49
|
+
// Update type/code on every packet (they should be consistent)
|
|
50
|
+
self.icmp_type = icmp_type;
|
|
51
|
+
self.icmp_code = icmp_code;
|
|
52
|
+
|
|
53
|
+
// Get ICMP layer bounds to extract fields
|
|
54
|
+
if let Some(icmp_layer) = crate::layer::LayerKind::Icmp
|
|
55
|
+
.try_into()
|
|
56
|
+
.ok()
|
|
57
|
+
.and_then(|kind| packet.get_layer(kind))
|
|
58
|
+
{
|
|
59
|
+
let icmp_start = icmp_layer.start;
|
|
60
|
+
|
|
61
|
+
// Extract identifier (bytes 4-5) if present
|
|
62
|
+
if buf.len() >= icmp_start + 6 {
|
|
63
|
+
self.identifier = Some(u16::from_be_bytes([
|
|
64
|
+
buf[icmp_start + 4],
|
|
65
|
+
buf[icmp_start + 5],
|
|
66
|
+
]));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Extract sequence number (bytes 6-7) if present
|
|
70
|
+
if buf.len() >= icmp_start + 8 {
|
|
71
|
+
self.last_seq = Some(u16::from_be_bytes([
|
|
72
|
+
buf[icmp_start + 6],
|
|
73
|
+
buf[icmp_start + 7],
|
|
74
|
+
]));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Count requests and replies based on ICMP type
|
|
78
|
+
match icmp_type {
|
|
79
|
+
8 => {
|
|
80
|
+
// ICMP Echo Request
|
|
81
|
+
self.request_count += 1;
|
|
82
|
+
},
|
|
83
|
+
0 => {
|
|
84
|
+
// ICMP Echo Reply
|
|
85
|
+
self.reply_count += 1;
|
|
86
|
+
},
|
|
87
|
+
128 => {
|
|
88
|
+
// ICMPv6 Echo Request
|
|
89
|
+
self.request_count += 1;
|
|
90
|
+
},
|
|
91
|
+
129 => {
|
|
92
|
+
// ICMPv6 Echo Reply
|
|
93
|
+
self.reply_count += 1;
|
|
94
|
+
},
|
|
95
|
+
_ => {
|
|
96
|
+
// Other ICMP types: no counting
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
self.status = ConversationStatus::Active;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/// Check whether this flow has timed out.
|
|
105
|
+
#[must_use]
|
|
106
|
+
pub fn check_timeout(&self, last_seen: Duration, now: Duration, config: &FlowConfig) -> bool {
|
|
107
|
+
// ICMP uses UDP timeout
|
|
108
|
+
now.saturating_sub(last_seen) > config.udp_timeout
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
impl Default for IcmpFlowState {
|
|
113
|
+
fn default() -> Self {
|
|
114
|
+
Self::new(0, 0)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
#[cfg(test)]
|
|
119
|
+
mod tests {
|
|
120
|
+
use super::*;
|
|
121
|
+
|
|
122
|
+
#[test]
|
|
123
|
+
fn test_icmp_state_new() {
|
|
124
|
+
let state = IcmpFlowState::new(8, 0);
|
|
125
|
+
assert_eq!(state.icmp_type, 8);
|
|
126
|
+
assert_eq!(state.icmp_code, 0);
|
|
127
|
+
assert_eq!(state.request_count, 0);
|
|
128
|
+
assert_eq!(state.reply_count, 0);
|
|
129
|
+
assert_eq!(state.identifier, None);
|
|
130
|
+
assert_eq!(state.last_seq, None);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
#[test]
|
|
134
|
+
fn test_icmp_timeout() {
|
|
135
|
+
let config = FlowConfig::default(); // 120s UDP timeout
|
|
136
|
+
let state = IcmpFlowState::new(8, 0);
|
|
137
|
+
|
|
138
|
+
// Not timed out
|
|
139
|
+
assert!(!state.check_timeout(Duration::from_secs(100), Duration::from_secs(200), &config));
|
|
140
|
+
|
|
141
|
+
// Timed out
|
|
142
|
+
assert!(state.check_timeout(Duration::from_secs(100), Duration::from_secs(300), &config));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -291,7 +291,59 @@ pub fn extract_key(packet: &Packet) -> Result<(CanonicalKey, FlowDirection), Flo
|
|
|
291
291
|
.map_err(|e| FlowError::PacketError(e.into()))?;
|
|
292
292
|
(sport, dport)
|
|
293
293
|
},
|
|
294
|
-
|
|
294
|
+
TransportProtocol::Icmp => {
|
|
295
|
+
// For ICMP, use identifier (for echo/timestamp types) for both ports
|
|
296
|
+
// (symmetric), or type+code as port substitute for other types.
|
|
297
|
+
// Using identifier symmetrically ensures request and reply have
|
|
298
|
+
// the same canonical key regardless of direction.
|
|
299
|
+
if let Some(icmp_layer) = packet.get_layer(LayerKind::Icmp) {
|
|
300
|
+
if buf.len() >= icmp_layer.start + 8 {
|
|
301
|
+
let icmp_type = buf[icmp_layer.start];
|
|
302
|
+
let is_echo = icmp_type == 0 || icmp_type == 8;
|
|
303
|
+
if is_echo {
|
|
304
|
+
let id = u16::from_be_bytes([
|
|
305
|
+
buf[icmp_layer.start + 4],
|
|
306
|
+
buf[icmp_layer.start + 5],
|
|
307
|
+
]);
|
|
308
|
+
(id, id) // Use identifier symmetrically for both ports
|
|
309
|
+
} else {
|
|
310
|
+
let code = buf[icmp_layer.start + 1];
|
|
311
|
+
(icmp_type as u16, code as u16)
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
(0u16, 0u16)
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
(0u16, 0u16)
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
TransportProtocol::Icmpv6 => {
|
|
321
|
+
// For ICMPv6, use identifier (for echo/timestamp types) for both ports
|
|
322
|
+
// (symmetric), or type+code as port substitute for other types.
|
|
323
|
+
// Using identifier symmetrically ensures request and reply have
|
|
324
|
+
// the same canonical key regardless of direction.
|
|
325
|
+
if let Some(icmpv6_layer) = packet.get_layer(LayerKind::Icmpv6) {
|
|
326
|
+
if buf.len() >= icmpv6_layer.start + 8 {
|
|
327
|
+
let icmpv6_type = buf[icmpv6_layer.start];
|
|
328
|
+
let is_echo = icmpv6_type == 128 || icmpv6_type == 129;
|
|
329
|
+
if is_echo {
|
|
330
|
+
let id = u16::from_be_bytes([
|
|
331
|
+
buf[icmpv6_layer.start + 4],
|
|
332
|
+
buf[icmpv6_layer.start + 5],
|
|
333
|
+
]);
|
|
334
|
+
(id, id) // Use identifier symmetrically for both ports
|
|
335
|
+
} else {
|
|
336
|
+
let code = buf[icmpv6_layer.start + 1];
|
|
337
|
+
(icmpv6_type as u16, code as u16)
|
|
338
|
+
}
|
|
339
|
+
} else {
|
|
340
|
+
(0u16, 0u16)
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
(0u16, 0u16)
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
// Other protocols have no ports
|
|
295
347
|
_ => (0u16, 0u16),
|
|
296
348
|
};
|
|
297
349
|
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
pub mod config;
|
|
29
29
|
pub mod error;
|
|
30
|
+
pub mod icmp_state;
|
|
30
31
|
pub mod key;
|
|
31
32
|
pub mod state;
|
|
32
33
|
pub mod table;
|
|
@@ -37,6 +38,7 @@ pub mod udp_state;
|
|
|
37
38
|
// Re-exports
|
|
38
39
|
pub use config::FlowConfig;
|
|
39
40
|
pub use error::FlowError;
|
|
41
|
+
pub use icmp_state::IcmpFlowState;
|
|
40
42
|
pub use key::{
|
|
41
43
|
CanonicalKey, FlowDirection, TransportProtocol, ZWaveKey, extract_key, extract_zwave_key,
|
|
42
44
|
};
|
|
@@ -119,7 +121,7 @@ pub fn extract_zwave_flows(
|
|
|
119
121
|
state
|
|
120
122
|
});
|
|
121
123
|
|
|
122
|
-
conv.record_packet(direction, byte_count, timestamp, index);
|
|
124
|
+
conv.record_packet(direction, byte_count, timestamp, index, false, false);
|
|
123
125
|
|
|
124
126
|
// Track ACK vs command frames
|
|
125
127
|
if let ProtocolState::ZWave(ref mut zw) = conv.protocol_state
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
use std::time::Duration;
|
|
2
2
|
|
|
3
3
|
use super::config::FlowConfig;
|
|
4
|
+
use super::icmp_state::IcmpFlowState;
|
|
4
5
|
use super::key::{CanonicalKey, FlowDirection, TransportProtocol};
|
|
5
6
|
use super::tcp_state::TcpConversationState;
|
|
6
7
|
use super::udp_state::UdpFlowState;
|
|
@@ -47,6 +48,8 @@ pub struct DirectionStats {
|
|
|
47
48
|
pub first_seen: Duration,
|
|
48
49
|
/// Timestamp of the most recent packet in this direction.
|
|
49
50
|
pub last_seen: Duration,
|
|
51
|
+
/// Maximum packet length in this direction (if tracking enabled).
|
|
52
|
+
pub max_packet_len: Option<u64>,
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
impl DirectionStats {
|
|
@@ -57,14 +60,18 @@ impl DirectionStats {
|
|
|
57
60
|
bytes: 0,
|
|
58
61
|
first_seen: timestamp,
|
|
59
62
|
last_seen: timestamp,
|
|
63
|
+
max_packet_len: None,
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
/// Record a new packet in this direction.
|
|
64
|
-
pub fn record_packet(&mut self, byte_count: u64, timestamp: Duration) {
|
|
68
|
+
pub fn record_packet(&mut self, byte_count: u64, timestamp: Duration, track_max_len: bool) {
|
|
65
69
|
self.packets += 1;
|
|
66
70
|
self.bytes += byte_count;
|
|
67
71
|
self.last_seen = timestamp;
|
|
72
|
+
if track_max_len {
|
|
73
|
+
self.max_packet_len = Some(self.max_packet_len.unwrap_or(0).max(byte_count));
|
|
74
|
+
}
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
77
|
|
|
@@ -75,9 +82,13 @@ pub enum ProtocolState {
|
|
|
75
82
|
Tcp(TcpConversationState),
|
|
76
83
|
/// UDP pseudo-conversation with timeout tracking.
|
|
77
84
|
Udp(UdpFlowState),
|
|
85
|
+
/// ICMP conversation with echo request/reply tracking.
|
|
86
|
+
Icmp(IcmpFlowState),
|
|
87
|
+
/// ICMPv6 conversation with echo request/reply tracking.
|
|
88
|
+
Icmpv6(IcmpFlowState),
|
|
78
89
|
/// Z-Wave wireless conversation with home ID and node tracking.
|
|
79
90
|
ZWave(ZWaveFlowState),
|
|
80
|
-
/// Other protocols
|
|
91
|
+
/// Other protocols — no specific state tracking.
|
|
81
92
|
Other,
|
|
82
93
|
}
|
|
83
94
|
|
|
@@ -115,6 +126,8 @@ pub struct ConversationState {
|
|
|
115
126
|
pub packet_indices: Vec<usize>,
|
|
116
127
|
/// Protocol-specific state.
|
|
117
128
|
pub protocol_state: ProtocolState,
|
|
129
|
+
/// Maximum packet length across both directions (if tracking enabled).
|
|
130
|
+
pub max_flow_len: Option<u64>,
|
|
118
131
|
}
|
|
119
132
|
|
|
120
133
|
impl ConversationState {
|
|
@@ -124,6 +137,8 @@ impl ConversationState {
|
|
|
124
137
|
let protocol_state = match key.protocol {
|
|
125
138
|
TransportProtocol::Tcp => ProtocolState::Tcp(TcpConversationState::new()),
|
|
126
139
|
TransportProtocol::Udp => ProtocolState::Udp(UdpFlowState::new()),
|
|
140
|
+
TransportProtocol::Icmp => ProtocolState::Icmp(IcmpFlowState::new(0, 0)),
|
|
141
|
+
TransportProtocol::Icmpv6 => ProtocolState::Icmpv6(IcmpFlowState::new(0, 0)),
|
|
127
142
|
_ => ProtocolState::Other,
|
|
128
143
|
};
|
|
129
144
|
|
|
@@ -136,6 +151,7 @@ impl ConversationState {
|
|
|
136
151
|
reverse: DirectionStats::new(timestamp),
|
|
137
152
|
packet_indices: Vec::new(),
|
|
138
153
|
protocol_state,
|
|
154
|
+
max_flow_len: None,
|
|
139
155
|
}
|
|
140
156
|
}
|
|
141
157
|
|
|
@@ -172,6 +188,7 @@ impl ConversationState {
|
|
|
172
188
|
command_count: 0,
|
|
173
189
|
ack_count: 0,
|
|
174
190
|
}),
|
|
191
|
+
max_flow_len: None,
|
|
175
192
|
}
|
|
176
193
|
}
|
|
177
194
|
|
|
@@ -200,13 +217,26 @@ impl ConversationState {
|
|
|
200
217
|
byte_count: u64,
|
|
201
218
|
timestamp: Duration,
|
|
202
219
|
packet_index: usize,
|
|
220
|
+
track_max_packet_len: bool,
|
|
221
|
+
track_max_flow_len: bool,
|
|
203
222
|
) {
|
|
204
223
|
self.last_seen = timestamp;
|
|
205
224
|
self.packet_indices.push(packet_index);
|
|
206
225
|
|
|
207
226
|
match direction {
|
|
208
|
-
FlowDirection::Forward =>
|
|
209
|
-
|
|
227
|
+
FlowDirection::Forward => {
|
|
228
|
+
self.forward
|
|
229
|
+
.record_packet(byte_count, timestamp, track_max_packet_len);
|
|
230
|
+
},
|
|
231
|
+
FlowDirection::Reverse => {
|
|
232
|
+
self.reverse
|
|
233
|
+
.record_packet(byte_count, timestamp, track_max_packet_len);
|
|
234
|
+
},
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Update max flow length if tracking is enabled
|
|
238
|
+
if track_max_flow_len {
|
|
239
|
+
self.max_flow_len = Some(self.max_flow_len.unwrap_or(0).max(byte_count));
|
|
210
240
|
}
|
|
211
241
|
}
|
|
212
242
|
|
|
@@ -230,6 +260,12 @@ impl ConversationState {
|
|
|
230
260
|
ProtocolState::Udp(udp) => {
|
|
231
261
|
self.status = udp.status;
|
|
232
262
|
},
|
|
263
|
+
ProtocolState::Icmp(icmp) => {
|
|
264
|
+
self.status = icmp.status;
|
|
265
|
+
},
|
|
266
|
+
ProtocolState::Icmpv6(icmpv6) => {
|
|
267
|
+
self.status = icmpv6.status;
|
|
268
|
+
},
|
|
233
269
|
ProtocolState::ZWave(_) => {},
|
|
234
270
|
ProtocolState::Other => {},
|
|
235
271
|
}
|
|
@@ -250,6 +286,7 @@ impl ConversationState {
|
|
|
250
286
|
}
|
|
251
287
|
},
|
|
252
288
|
ProtocolState::Udp(_) => elapsed > config.udp_timeout,
|
|
289
|
+
ProtocolState::Icmp(_) | ProtocolState::Icmpv6(_) => elapsed > config.udp_timeout,
|
|
253
290
|
ProtocolState::ZWave(_) => elapsed > config.udp_timeout,
|
|
254
291
|
ProtocolState::Other => elapsed > config.udp_timeout,
|
|
255
292
|
}
|
|
@@ -72,7 +72,14 @@ impl ConversationTable {
|
|
|
72
72
|
let conv = entry.value_mut();
|
|
73
73
|
|
|
74
74
|
// Record packet stats
|
|
75
|
-
conv.record_packet(
|
|
75
|
+
conv.record_packet(
|
|
76
|
+
direction,
|
|
77
|
+
byte_count,
|
|
78
|
+
timestamp,
|
|
79
|
+
packet_index,
|
|
80
|
+
self.config.track_max_packet_len,
|
|
81
|
+
self.config.track_max_flow_len,
|
|
82
|
+
);
|
|
76
83
|
|
|
77
84
|
// Process protocol-specific state
|
|
78
85
|
let buf = packet.as_bytes();
|
|
@@ -85,6 +92,26 @@ impl ConversationTable {
|
|
|
85
92
|
ProtocolState::Udp(udp_state) => {
|
|
86
93
|
udp_state.process_packet();
|
|
87
94
|
},
|
|
95
|
+
ProtocolState::Icmp(icmp_state) => {
|
|
96
|
+
// Get ICMP type and code from buffer
|
|
97
|
+
if let Some(icmp_layer) = packet.get_layer(crate::layer::LayerKind::Icmp) {
|
|
98
|
+
if buf.len() >= icmp_layer.start + 2 {
|
|
99
|
+
let icmp_type = buf[icmp_layer.start];
|
|
100
|
+
let icmp_code = buf[icmp_layer.start + 1];
|
|
101
|
+
icmp_state.process_packet(packet, buf, icmp_type, icmp_code);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
ProtocolState::Icmpv6(icmpv6_state) => {
|
|
106
|
+
// Get ICMPv6 type and code from buffer
|
|
107
|
+
if let Some(icmpv6_layer) = packet.get_layer(crate::layer::LayerKind::Icmpv6) {
|
|
108
|
+
if buf.len() >= icmpv6_layer.start + 2 {
|
|
109
|
+
let icmpv6_type = buf[icmpv6_layer.start];
|
|
110
|
+
let icmpv6_code = buf[icmpv6_layer.start + 1];
|
|
111
|
+
icmpv6_state.process_packet(packet, buf, icmpv6_type, icmpv6_code);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
88
115
|
ProtocolState::ZWave(_) => {},
|
|
89
116
|
ProtocolState::Other => {},
|
|
90
117
|
}
|