ja4plus 1.2.2__tar.gz → 1.3.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.
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/rules/conformance.md +4 -3
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/rules/external-apis.md +18 -11
- {ja4plus-1.2.2 → ja4plus-1.3.0}/CHANGELOG.md +70 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/CLAUDE.md +1 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/PKG-INFO +17 -12
- {ja4plus-1.2.2 → ja4plus-1.3.0}/README.md +15 -11
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/api_reference.md +63 -8
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/implementation_notes.md +16 -10
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/index.md +20 -9
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4.md +3 -3
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4t.md +7 -3
- ja4plus-1.3.0/docs/methods/ja4tscan.md +141 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/migration-0.6-to-1.0.md +15 -13
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/output-schema.md +12 -5
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/performance.md +6 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/00-foundation.md +3 -2
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/01-spec-conformance.md +15 -5
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/03-concurrency-safety.md +14 -12
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/08-documentation.md +8 -4
- ja4plus-1.3.0/docs/specs/features/12-active-scan.md +406 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/JA4.md +2 -2
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/JA4L.md +6 -6
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/JA4SSH.md +1 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/JA4T.md +28 -3
- ja4plus-1.3.0/docs/specs/foxio/JA4TScan.md +408 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/JA4X.md +2 -2
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/README.md +11 -4
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/deleted-text-specifications.md +1 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/zeek.md +11 -3
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/spec.html +9 -4
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/spec.md +61 -19
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/usage.md +28 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/__init__.py +1 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/cli.py +128 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4.py +140 -6
- ja4plus-1.3.0/ja4plus/scan/__init__.py +11 -0
- ja4plus-1.3.0/ja4plus/scan/command.py +192 -0
- ja4plus-1.3.0/ja4plus/scan/frames.py +198 -0
- ja4plus-1.3.0/ja4plus/scan/link.py +183 -0
- ja4plus-1.3.0/ja4plus/scan/scanner.py +404 -0
- ja4plus-1.3.0/ja4plus/scan/value.py +83 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/types.py +3 -2
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/tcp_options.py +29 -12
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/tls_utils.py +40 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus.egg-info/PKG-INFO +17 -12
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus.egg-info/SOURCES.txt +22 -0
- ja4plus-1.3.0/ja4plus.egg-info/entry_points.txt +5 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus.egg-info/requires.txt +2 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/mkdocs.yml +3 -2
- {ja4plus-1.2.2 → ja4plus-1.3.0}/pyproject.toml +13 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/download_test_vectors.py +31 -6
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_citation_lines.py +11 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_deviations.json +0 -6
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_deviations.py +1 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vector_manifest.json +1 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/NOTICE +18 -7
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@chrome-cloudflare-quic-with-secrets.pcapng.snap +1 -2
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@gre-erspan-vxlan.pcap.snap +1 -2
- ja4plus-1.3.0/tests/foxio_vectors/rust_expected/ja4__insta@sigalg-grease.pcapng.snap +16 -0
- ja4plus-1.3.0/tests/foxio_vectors/sigalg-grease.pcapng +0 -0
- ja4plus-1.3.0/tests/foxio_vectors/sigalg-grease.pcapng.json +20 -0
- ja4plus-1.3.0/tests/scan_fakes.py +95 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_conformance_frame_discrimination.py +4 -4
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documentation_image_count.py +4 -3
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documented_method_count.py +71 -9
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documented_state_table_count.py +1 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_download_filter_fields.py +3 -3
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_empty_list_sentinel_ruling.py +4 -4
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_foxio_rust_parity.py +29 -29
- ja4plus-1.3.0/tests/test_ja4_signature_algorithm_grease.py +127 -0
- ja4plus-1.3.0/tests/test_ja4_tcp_client_hello_reassembly.py +328 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4s_raw_order.py +4 -4
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4t_form.py +48 -17
- ja4plus-1.3.0/tests/test_ja4tscan_boundary.py +245 -0
- ja4plus-1.3.0/tests/test_ja4tscan_command.py +476 -0
- ja4plus-1.3.0/tests/test_ja4tscan_frames.py +196 -0
- ja4plus-1.3.0/tests/test_ja4tscan_link.py +254 -0
- ja4plus-1.3.0/tests/test_ja4tscan_scanner.py +390 -0
- ja4plus-1.3.0/tests/test_ja4tscan_specification.py +119 -0
- ja4plus-1.3.0/tests/test_ja4tscan_value.py +227 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_key_log_interface_ruling.py +1 -1
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_memory_bounds.py +10 -9
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_method_pages.py +45 -35
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_precedence_exception.py +54 -29
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_processor_stats.py +4 -4
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_readme_contracts.py +16 -15
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_tcp_segment_bound_ruling.py +2 -2
- ja4plus-1.2.2/ja4plus.egg-info/entry_points.txt +0 -2
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/rules/agent-reports.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/rules/batch-gate.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/rules/ste.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/settings.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/skills/conformance/SKILL.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/skills/release/SKILL.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.claude/skills/test/SKILL.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.git-blame-ignore-revs +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.github/dependabot.yml +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.github/workflows/docs-build.yml +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.github/workflows/docs.yml +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.github/workflows/publish.yml +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.github/workflows/test.yml +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.github/workflows/update-db.yml +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.gitignore +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/.issue-flow.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/LICENSE +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/assets/logo.png +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/README.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/concurrency.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4d.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4d6.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4h.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4l.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4ls.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4s.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4ssh.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4ts.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/methods/ja4x.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/mutation_reports/412-utils.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/mutation_reports/413-fingerprinters.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/mutation_reports/414-interface.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/mutation_settlements/412-utils.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/mutation_settlements/413-fingerprinters.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/mutation_settlements/414-interface.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/mutation_sweep.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/reference/fingerprinters.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/reference/index.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/reference/ja4db.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/reference/processor.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/reference/types.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/02-correctness-audit.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/04-typed-api.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/05-structured-output.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/06-live-capture.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/07-db-enrichment.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/09-release.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/features/11-pre-release-validation.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/JA4D.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/JA4H.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/foxio/JA4S.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/docs/specs/mockups/01-cli-output.html +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/examples/demo_fingerprints.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/examples/live_traffic_fingerprinting.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/examples/pcap_analysis.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/examples/tcpdump_workflows.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/examples/threat_detection.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/data/ja4plus-mapping.csv +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/__init__.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/base.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4d.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4d6.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4h.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4l.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4s.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4ssh.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4t.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4ts.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/fingerprinters/ja4x.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/ja4db.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/output.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/processor.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/py.typed +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/__init__.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/http_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/icmp_quoted.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/loopback.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/packet_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/quic_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/ssh_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/state_table.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/tcp_stream.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/tunnels.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/utils/x509_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus/watch.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus.egg-info/dependency_links.txt +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/ja4plus.egg-info/top_level.txt +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/setup.cfg +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/__init__.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/batch_gate.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/build_alpn_condition_capture.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/build_ja4ts_rst.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/build_quic_ja4l_captures.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/build_ssh_retransmission.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/citation_line_allowlist.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/compare_zeek_baselines.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/conformance_index.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/conftest.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/data/dns.cap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/data/example_cert.der +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/data/filedownload.dmp +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/data/http.cap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/data/suspectemployeechat.dmp +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/data/test_cert.der +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/data/wrongdissector.dmp +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/dependency_entries.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/documentation_samples.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_deviation_owners.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_manifest.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/CVE-2018-6794.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/CVE-2018-6794.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/alpn-condition.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/alpn-condition.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/badcurveball.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/badcurveball.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/browsers-x509.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/browsers-x509.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/chrome-cloudflare-quic-with-secrets.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/chrome-cloudflare-quic-with-secrets.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/dhcp.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/dhcp.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/dhcpv6.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/dhcpv6.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/gre-erspan-vxlan.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/gre-erspan-vxlan.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/gre-sample.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/gre-sample.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/http-empty-useragent.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/http-empty-useragent.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/http1-with-cookies.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/http1-with-cookies.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/http1.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/http1.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/http2-with-cookies.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/http2-with-cookies.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/https-connect.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/https-connect.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/https3-301-get.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/https3-301-get.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ipv6.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ipv6.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/latest.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/latest.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/macos_tcp_flags.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/macos_tcp_flags.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/quic-tls-handshake.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/quic-tls-handshake.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/quic-with-several-tls-frames.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/quic-with-several-tls-frames.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@browsers-x509.pcapng.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@https-connect.pcap.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@latest.pcapng.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@quic-tls-handshake.pcapng.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@quic-with-several-tls-frames.pcapng.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@ssh2.pcapng.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@tls-handshake.pcapng.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@tls-sni.pcapng.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/rust_expected/ja4__insta@tls3.pcapng.snap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/single-packets.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/single-packets.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/socks-https-example.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/socks-https-example.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/socks4-https.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/socks4-https.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh-r.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh-r.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh-scp-1050.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh-scp-1050.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh2-malformed.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh2-malformed.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh2-moloch-crash.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh2-moloch-crash.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh2.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/ssh2.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/sshv1.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/sshv1.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tcpdump-geneve.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tcpdump-geneve.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls-alpn-h2.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls-alpn-h2.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls-handshake.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls-handshake.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls-non-ascii-alpn.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls-non-ascii-alpn.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls-sni.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls-sni.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls12.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls12.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls3.pcapng +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/tls3.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/v6.pcap +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/v6.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/CVE-2018-6794.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/badcurveball.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/browsers-x509.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/chrome-cloudflare-quic-with-secrets.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/dhcp.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/dhcpv6.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/gre-erspan-vxlan.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/http-empty-useragent.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/http1-with-cookies.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/http2-with-cookies.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/https-connect.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/https3-301-get.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/ipv6.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/latest.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/socks-https-example.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/socks4-https.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/ssh-r.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/ssh-scp-1050.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/ssh2-malformed.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/ssh2-moloch-crash.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/ssh2.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/sshv1.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/tcpdump-geneve.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/tls-alpn-h2.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/tls3.pcapng.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/wireshark_expected/v6.pcap.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/zeek_expected/Scripts.ja4-conn/conn.log +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/zeek_expected/Scripts.ja4-conn-quic/conn.log +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/zeek_expected/Scripts.ja4-conn-tls3/conn.log +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/zeek_expected/Scripts.ja4-dhcp/ja4d.log +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/zeek_expected/Scripts.ja4-http1-with-cookies/http.log +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/zeek_expected/Scripts.ja4-ssh2/ja4ssh.log +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/foxio_vectors/zeek_expected/Scripts.ja4-tls-handshake/ssl.log +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/README.md +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/__init__.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/conftest.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/support.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/test_icmp_quoted_header.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/test_length_fields.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/test_malformed_captures.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/test_server_hello_extensions.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/test_structural_validity.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/test_synthetic_hostile_input.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/fuzz/test_truncated_captures.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/generate_foxio_baseline.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/measure_random_client_hello.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/memory_ceiling_run.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/mutation_census.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/mutation_cover.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/mutation_sweep.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/quic_builder.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/release_body.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/release_verification.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/skip_gate.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/state_readers.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_agent_report_absence_rule.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_alpn_ruling_register.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_api_reference_interface_table.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_bare_exception_reading.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_batch_gate.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_batch_gate_protection_rule.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_bounded_state_table_adoption.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_breaking_change_record.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_changelog_round_agreement.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_changelog_sentence_exemption.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_cleanup_connection.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_cli.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_cli_closed_window_endpoints.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_cli_lookup_opt_in.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_cli_output_option.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_cli_processor.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_cli_types_ja4ls.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_compare_zeek_baselines.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_comprehensive.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_criterion_counts.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_db_cache_directory.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_db_item_access.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_db_lookup_many.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_db_offline.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_decryption_non_goal_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_delegated_ruling_rule.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_dependency_entries.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_dhcp_tunnel_inner_udp.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documentation_behaviour_rule.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documentation_fallback_rule.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documentation_publish.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documentation_samples.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documentation_site.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_documentation_version_claims.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_edge_cases.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_examples.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_foxio_citation_lines.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_foxio_deviations.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_foxio_ja4_transcription.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_foxio_license_register.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_foxio_manifest.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_foxio_wireshark_ja4ts.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_foxio_zeek_ja4ts.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_future_dated_packet_eviction.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_generate_foxio_baseline.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_get_stream_byte_cap_truncation.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_http_header_block_terminator.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_installed_wheel.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_installed_wheel_selection.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_integration.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_interpreter_set.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ipv6_support.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4_alpn.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4_alpn_condition.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4_deep.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4_empty_ext.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4_hello_retry.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4_original_order.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4_raw_branches.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4_ssl2_version.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4d.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4d6_foxio.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4d_decisions.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4d_foxio.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4d_fqdn_name_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4db.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4db_empty_list_alias.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_cookie_list.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_deep.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_emission_frame_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_large_cookie_header.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_line_endings.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_part_a_readings.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_raw.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_raw_sorted.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_reassembly.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_request_line_and_empty_header_list.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_retransmission.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4h_spec.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_connection_state.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_foxio.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_header_block_terminator.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_quic_eviction_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_quic_marker.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_quic_point_b_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_quic_point_d_emission.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_quic_repeated_connection.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_quic_server_hello.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_return_path.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_timing_fork_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4l_udp_direction.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4s.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4s_quic_direction.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4s_quic_split_server_hello.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_close_connection_window.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_deep.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_direction.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_interpret.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_message_count.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_packet_selection_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_parity_record.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_server_side.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_spec.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_window.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ssh_windows.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4t.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4t_citation_lines.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4t_deep.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4t_emission_model_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4t_icmp_quoted.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4t_syn_selection_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ts.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ts_delay_rounding_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ts_part_e.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ts_prefix_bound.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4ts_reset.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4x.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4x_deep.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4x_empty_ext.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4x_named_exceptions.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4x_raw.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4x_reassembly.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ja4x_record_scan.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_lint_gate_pin.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_loopback_link_type.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_mutation_census.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_mutation_cover.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_mutation_sweep_annotation_skip.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_mutation_sweep_commit.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_mutation_sweep_module_list.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_mutation_sweep_timeout.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_no_retained_packets.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_output_schema.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_packaging.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_packet_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_parity.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_parser_description.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ported_pattern_cost.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_processor.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_processor_typed_results.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_public_interface.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_publish_workflow.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_quic_coalesced_datagram_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_quic_crypto_buffer_bound.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_quic_crypto_gap.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_quic_integration.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_quic_multipacket.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_quic_server_initial.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_quic_tunnel_inner_udp.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_quic_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_release_body.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_release_notes.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_release_skill.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_requirement_scope.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_round_entry_existence.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_ruling_vocabulary.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_settlement_procedure.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_skip_gate.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_spec_validation.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_specification_changelog.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_specification_terms.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_state_table.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_statistics_thread_term.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_tcp_byte_cap_admission_ruling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_tcp_stream.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_thread_safety.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_throughput.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_tls_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_tunnels.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_types.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_us_english_spelling.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_utils.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_version_gate.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_watch.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_watch_capture.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_watch_drop_count.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_watch_statistics.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_watch_stop.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_wireshark_expected_counts.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_workflow_action_pins.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/test_x509_certificate_reader.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/throughput_run.py +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/universal_skips.json +0 -0
- {ja4plus-1.2.2 → ja4plus-1.3.0}/tests/version_gate.py +0 -0
|
@@ -88,11 +88,12 @@ and under the restored defect. These are the seven moves.
|
|
|
88
88
|
|
|
89
89
|
**The conformance value comparison reads the one source that frames nothing.** A per-frame
|
|
90
90
|
comparison is possible only where a source states the frame, and #736 read all four.
|
|
91
|
+
#772 added `sigalg-grease.pcapng`, and the first two counts below include it.
|
|
91
92
|
|
|
92
93
|
| Source | States a frame | Values |
|
|
93
94
|
|---|---|---|
|
|
94
|
-
| FoxIO Python expected output, `tests/foxio_vectors/*.json` | No |
|
|
95
|
-
| FoxIO Rust snapshots, `tests/foxio_vectors/rust_expected/*.snap` | No |
|
|
95
|
+
| FoxIO Python expected output, `tests/foxio_vectors/*.json` | No | 1211 |
|
|
96
|
+
| FoxIO Rust snapshots, `tests/foxio_vectors/rust_expected/*.snap` | No | 465 |
|
|
96
97
|
| Zeek baselines, `tests/foxio_vectors/zeek_expected/` | No | 7 baselines |
|
|
97
98
|
| FoxIO Wireshark dissector, `tests/foxio_vectors/wireshark_expected/*.json` | Yes, `frame.number` | 724 |
|
|
98
99
|
|
|
@@ -101,7 +102,7 @@ comparison is possible only where a source states the frame, and #736 read all f
|
|
|
101
102
|
names one of them. **The dissector frames every value it writes**, and #736 measured 724
|
|
102
103
|
framed values and none unframed across 26 files.
|
|
103
104
|
|
|
104
|
-
**The conformance suite builds all
|
|
105
|
+
**The conformance suite builds all 1211 of its value cases from the first source.** No case
|
|
105
106
|
of the suite can read a frame, because the source it reads states none.
|
|
106
107
|
|
|
107
108
|
### Why the suite compares no frame
|
|
@@ -153,10 +153,12 @@ reader checks each one.
|
|
|
153
153
|
5. The remaining sources hold one value between them.
|
|
154
154
|
|
|
155
155
|
**Read fact 1 from the vectors, and not from the key form alone.** A value-form key
|
|
156
|
-
states that the Python file holds a value, and
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
states that the Python file holds a value, and that statement can be false. Such a row
|
|
157
|
+
declines the value of another source, and the exception passes over it, because the
|
|
158
|
+
exception rests on a declined Python value. `gre-erspan-vxlan.pcap/0:65174/JA4T.1` was
|
|
159
|
+
that row until #772. The FoxIO Python file holds no JA4T value, and #215 declined the
|
|
160
|
+
FoxIO Rust value `8192__0_0`. The Rust snapshot at FoxIO commit `16b96d95` holds
|
|
161
|
+
`8192_00_00_00`, which `ja4plus` writes, so #772 removed the row.
|
|
160
162
|
|
|
161
163
|
**A capability decline bars the row.** The exception reaches a row only where the decline
|
|
162
164
|
records a disagreement about the value. It does not reach a row whose decline records a
|
|
@@ -179,9 +181,11 @@ prose of its cause.** Read the field.
|
|
|
179
181
|
values of #129 out of `SOURCE_VALUES`, so the exclusion enforced the bar a second time.
|
|
180
182
|
No case could then read what the field does on the one issue the bar exists for. The
|
|
181
183
|
table now holds all 35, measured against the pinned commit. With `capability` false on
|
|
182
|
-
every #129 entry the reach rises from 6 rows to
|
|
183
|
-
moved nothing.
|
|
184
|
-
|
|
184
|
+
every #129 entry the reach rises from 6 rows to 41. The same flip on the earlier table
|
|
185
|
+
moved nothing. **#772 read the table again at FoxIO `16b96d95`, and the flip reached 25
|
|
186
|
+
rows before that read.** FoxIO `478359f3` moved the 16 Rust JA4H values, and each one now
|
|
187
|
+
equals the Wireshark value. The disagreement bar therefore holds none of the 35, and the
|
|
188
|
+
field alone bars all of them.
|
|
185
189
|
|
|
186
190
|
**A disagreement between the remaining sources bars the row.** Where the remaining FoxIO
|
|
187
191
|
sources hold different values, **no source holds the reference and the row stays declined
|
|
@@ -211,7 +215,7 @@ decides what the bar covers.
|
|
|
211
215
|
reference value, and adoption is its own ruling. "Which baselines are usable as
|
|
212
216
|
vectors" in `docs/specs/foxio/zeek.md` holds that ruling for the Zeek package.
|
|
213
217
|
|
|
214
|
-
**The exception reaches 6 rows of the
|
|
218
|
+
**The exception reaches 6 rows of the 137 the register holds.**
|
|
215
219
|
`tests/test_precedence_exception.py` measures the reach and both counts, and #334 records
|
|
216
220
|
the search. A case reads this sentence, so a register move fails the gate here.
|
|
217
221
|
|
|
@@ -224,9 +228,12 @@ the search. A case reads this sentence, so a register move fails the gate here.
|
|
|
224
228
|
| `ssh2.pcapng/33:51810/JA4L-S.1` | #225 | Wireshark alone |
|
|
225
229
|
| `tls3.pcapng/25:61884/JA4L-S.1` | #225 | Wireshark alone |
|
|
226
230
|
|
|
227
|
-
**`FoxIO-LLC/ja4tscan` holds
|
|
228
|
-
JA4TScan example values against named operating systems, and
|
|
229
|
-
option kind 0 inside the
|
|
231
|
+
**`FoxIO-LLC/ja4tscan` holds source code and no baseline.** Its `README.md` gives eight
|
|
232
|
+
JA4TScan example values against named operating systems, and one of them records TCP
|
|
233
|
+
option kind 0 twice inside the option list. **`module_ja4tscan.c` is the normative
|
|
234
|
+
source**, and the maintainer named it so on 2026-09-30, in #775. Three of the eight
|
|
235
|
+
values do not fit that module. `docs/specs/foxio/JA4TScan.md` holds the transcription and
|
|
236
|
+
the measurement.
|
|
230
237
|
|
|
231
238
|
**Warning: FoxIO states that `FoxIO-LLC/ja4-nginx-module` is not correct.** Its
|
|
232
239
|
`README.md` opens with a `# NOTICE` section that reads "This version of JA4 has known
|
|
@@ -6,6 +6,37 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
- **`ja4plus scan` adds JA4TScan, the FoxIO active TCP server fingerprint** (#775, #776).
|
|
10
|
+
Round
|
|
11
|
+
269. **The maintainer reversed the decline of 2026-08-08 on 2026-09-30.** The scanner sends
|
|
12
|
+
one SYN to each IPv4 target and reads the SYN-ACK and its retransmissions. Parts a to d
|
|
13
|
+
use the JA4TS form of this project, so a scan value and the passive JA4TS value of one
|
|
14
|
+
SYN-ACK hold the same four parts. A target whose first answer carries RST writes
|
|
15
|
+
`0_rst-ack`. **The library changes no firewall state.** The command prints the four
|
|
16
|
+
`iptables` rules of the FoxIO wrapper, or four pf rules on macOS, and it warns when a
|
|
17
|
+
SYN-ACK arrives with no retransmission. The scanner lives in `ja4plus/scan/` behind the
|
|
18
|
+
`scan` extra, and no passive module imports it. `docs/specs/foxio/JA4TScan.md` transcribes
|
|
19
|
+
`FoxIO-LLC/ja4tscan` at `d01bfec4`, and `docs/specs/features/12-active-scan.md` states 35
|
|
20
|
+
acceptance criteria. The divergence register records the three places where the FoxIO
|
|
21
|
+
module writes another form. **The project now implements all twelve FoxIO methods.**
|
|
22
|
+
|
|
23
|
+
- **JA4 reads a ClientHello that spans TCP segments, and the FoxIO pin moves to `16b96d95`** (#772, #773, #774).
|
|
24
|
+
Round
|
|
25
|
+
268. **A post-quantum key share makes a browser ClientHello longer than one TCP segment**,
|
|
26
|
+
and the JA4 fingerprinter read each segment alone, so it wrote no value for such a hello.
|
|
27
|
+
`sigalg-grease.pcapng` of FoxIO release v1.0.1 holds a 2034-byte hello in two segments.
|
|
28
|
+
The fingerprinter now holds the client payload of a connection in a bounded table until
|
|
29
|
+
the hello is complete, and a gap stops the read at the first byte that has not arrived
|
|
30
|
+
(#772). **JA4 removes GREASE values from the signature algorithms** at both call sites, as
|
|
31
|
+
FoxIO `d66336ef` does, and the value of that capture now equals the FoxIO value in all
|
|
32
|
+
four forms (#773). **A repeated MSS option or window scale option keeps its last value**,
|
|
33
|
+
which the FoxIO Rust, Wireshark and Zeek sources each do at `16b96d95` (#774). The FoxIO
|
|
34
|
+
pin moves from `27f0cbf9` to `16b96d95`. The seven Zeek baselines stay at `27f0cbf9`
|
|
35
|
+
under `ZEEK_COMMIT`, because FoxIO `4e91886c` removed `zeek/tests/Traces`. **A replay of
|
|
36
|
+
77 captures writes one new value, the JA4 of `sigalg-grease.pcapng` frame 5, and every
|
|
37
|
+
other value is byte-identical.** The conformance suite reports 1684 passed, 142 skipped
|
|
38
|
+
and 138 xfailed before this round, and 1702 passed, 145 skipped and 137 xfailed after it.
|
|
39
|
+
|
|
9
40
|
- **The QUIC CRYPTO reader stops at the first byte that has not arrived** (#762).
|
|
10
41
|
Round
|
|
11
42
|
267. **An outside reporter measured the defect on Windows against a live capture.**
|
|
@@ -2087,6 +2118,45 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
2087
2118
|
**No file under `ja4plus/` changes and no fingerprint moves**, and the conformance suite
|
|
2088
2119
|
reports 1635 passed, 143 skipped and 140 xfailed.
|
|
2089
2120
|
|
|
2121
|
+
## [1.3.0] - 2026-09-30
|
|
2122
|
+
|
|
2123
|
+
Version 1.3.0 follows version 1.2.2, and no version stands between them. The date of the
|
|
2124
|
+
heading above is the date this release reaches `master`. It carries rounds 268 and 269.
|
|
2125
|
+
|
|
2126
|
+
**The bump is minor and never patch.** This release adds published names: the
|
|
2127
|
+
`ja4plus.scan` package, the `ja4plus scan` subcommand and the `scan` extra. It removes no
|
|
2128
|
+
name and it renames none.
|
|
2129
|
+
|
|
2130
|
+
**JA4 reads a ClientHello that spans TCP segments** (#772). A post-quantum key share makes
|
|
2131
|
+
a current browser ClientHello longer than one TCP segment, and the fingerprinter read each
|
|
2132
|
+
segment alone, so it wrote no JA4 value for such a hello. **A caller now receives a JA4
|
|
2133
|
+
value for that traffic where it received none before.** The fingerprinter holds the client
|
|
2134
|
+
payload of a connection in a bounded table until the hello is complete, and a gap stops
|
|
2135
|
+
the read at the first byte that has not arrived.
|
|
2136
|
+
|
|
2137
|
+
**Two readers now write the FoxIO value.**
|
|
2138
|
+
|
|
2139
|
+
| Method | Input | Version 1.2.2 | Version 1.3.0 | Issue |
|
|
2140
|
+
|---|---|---|---|---|
|
|
2141
|
+
| JA4 | A ClientHello with a GREASE value among its signature algorithms | Hashes the GREASE value | Removes it, as FoxIO `d66336ef` does | #773 |
|
|
2142
|
+
| JA4T, JA4TS | A SYN or SYN-ACK with a repeated MSS option or window scale option | Keeps the first value | Keeps the last value, as the FoxIO Rust, Wireshark and Zeek sources do | #774 |
|
|
2143
|
+
|
|
2144
|
+
**No value of the committed corpus moves.** A replay of 77 captures writes one new value,
|
|
2145
|
+
the JA4 of `sigalg-grease.pcapng` frame 5, which equals the FoxIO value. Every other value
|
|
2146
|
+
is byte-identical. No committed capture carries a repeated TCP option or a signature
|
|
2147
|
+
algorithm GREASE value.
|
|
2148
|
+
|
|
2149
|
+
**`ja4plus scan` adds JA4TScan, the FoxIO active TCP server fingerprint** (#775, #776). The
|
|
2150
|
+
scanner sends one SYN to each IPv4 target and reads the SYN-ACK and its retransmissions.
|
|
2151
|
+
**It is the one part of the package that sends packets**, so it lives behind the `scan`
|
|
2152
|
+
extra and no passive module imports it. **The library changes no firewall state**, and
|
|
2153
|
+
the command prints the rules the operator adds. `docs/specs/features/12-active-scan.md`
|
|
2154
|
+
states the requirements. The project now implements all twelve FoxIO methods.
|
|
2155
|
+
|
|
2156
|
+
**The FoxIO pin moves from `27f0cbf9` to `16b96d95`**, and `sigalg-grease.pcapng` joins the
|
|
2157
|
+
vectors. The conformance suite reports 1684 passed, 142 skipped and 138 xfailed at version
|
|
2158
|
+
1.2.2, and 1702 passed, 145 skipped and 137 xfailed here.
|
|
2159
|
+
|
|
2090
2160
|
## [1.2.2] - 2026-09-29
|
|
2091
2161
|
|
|
2092
2162
|
Version 1.2.2 follows version 1.2.1, and no version stands between them. The date of the
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
produces JA4+ fingerprints. FoxIO publishes the JA4+ standard. This project is an
|
|
5
5
|
independent implementation of it.
|
|
6
6
|
|
|
7
|
-
This repository declares version 1.
|
|
7
|
+
This repository declares version 1.3.0, and `ja4plus/__init__.py:101` holds that one
|
|
8
8
|
declaration. A publish to PyPI is a separate step, and the maintainer runs it.
|
|
9
9
|
|
|
10
10
|
Design lives in `docs/specs/`. Read `docs/specs/spec.md` and the relevant
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ja4plus
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: JA4+ network fingerprinting library for TLS, TCP, HTTP, SSH, X.509, and DHCP analysis
|
|
5
5
|
License: BSD-3-Clause AND LicenseRef-FoxIO-1.1
|
|
6
6
|
Project-URL: Homepage, https://github.com/Crank-Git/ja4plus
|
|
@@ -41,6 +41,7 @@ Requires-Dist: mkdocs-material==9.7.7; extra == "docs"
|
|
|
41
41
|
Requires-Dist: mkdocstrings==1.0.6; extra == "docs"
|
|
42
42
|
Requires-Dist: mkdocstrings-python==2.0.9; extra == "docs"
|
|
43
43
|
Requires-Dist: griffe==2.3.0; extra == "docs"
|
|
44
|
+
Provides-Extra: scan
|
|
44
45
|
Dynamic: license-file
|
|
45
46
|
|
|
46
47
|
<p align="center"><img src="assets/logo.png" width="300"></p>
|
|
@@ -49,9 +50,10 @@ A Python library and command-line program that produces JA4+ fingerprints. It re
|
|
|
49
50
|
TCP, HTTP, SSH and DHCP traffic, and it reads an X.509 certificate. It supports QUIC,
|
|
50
51
|
IPv4, IPv6 and multi-segment TCP reassembly.
|
|
51
52
|
|
|
52
|
-
**FoxIO publishes twelve JA4+ methods, and this project implements
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
**FoxIO publishes twelve JA4+ methods, and this project implements twelve of them.**
|
|
54
|
+
Eleven read traffic that already exists. The twelfth is JA4TScan, which sends packets, and
|
|
55
|
+
the `ja4plus scan` subcommand runs it. Ten fingerprinter classes carry the other eleven,
|
|
56
|
+
because `JA4LFingerprinter` writes both JA4L and JA4LS. `Methods` below names each method.
|
|
55
57
|
|
|
56
58
|
FoxIO owns the JA4+ standard, and [FoxIO](https://foxio.io) publishes it. This library is
|
|
57
59
|
an independent implementation of that standard. FoxIO wrote no part of it. For the
|
|
@@ -80,16 +82,19 @@ The `Implemented` column states whether this project builds the method.
|
|
|
80
82
|
| JA4SSH | SSH | Session type classification from traffic patterns | Yes |
|
|
81
83
|
| JA4T | TCP | Client OS fingerprint from SYN packets | Yes |
|
|
82
84
|
| JA4TS | TCP | Server fingerprint from SYN-ACK packets | Yes |
|
|
83
|
-
| JA4TScan | TCP | Active TCP fingerprint
|
|
85
|
+
| JA4TScan | TCP | Active TCP server fingerprint from SYN-ACK retransmissions, through `ja4plus scan` | Yes |
|
|
84
86
|
| JA4D | DHCPv4 | DHCP client/server fingerprint (FoxIO PR #267/#270) | Yes |
|
|
85
87
|
| JA4D6 | DHCPv6 | DHCPv6 client/server fingerprint (FoxIO PR #267/#270) | Yes |
|
|
86
88
|
|
|
87
|
-
**JA4TScan
|
|
88
|
-
to
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
**JA4TScan sends packets, so this project keeps it apart from the other eleven.** It
|
|
90
|
+
sends one TCP SYN to each host the operator names and reads the responses. The maintainer
|
|
91
|
+
reversed the decline of 2026-08-08 on 2026-09-30, in #775, and #776 built the scanner.
|
|
92
|
+
The scanner installs with `pip install ja4plus[scan]` and runs as `ja4plus scan`. The
|
|
93
|
+
`ja4plus.scan` module holds it, and no passive fingerprinter can send a packet. The
|
|
94
|
+
scanner changes no firewall state, and it states the rule the operator adds.
|
|
95
|
+
[`docs/methods/ja4tscan.md`](docs/methods/ja4tscan.md) describes the command, and
|
|
96
|
+
[`docs/specs/features/12-active-scan.md`](docs/specs/features/12-active-scan.md) holds the
|
|
97
|
+
design.
|
|
93
98
|
|
|
94
99
|
`JA4LFingerprinter` builds both JA4L and JA4LS, so ten fingerprinters carry eleven
|
|
95
100
|
methods. `--types ja4l` names the two together, and `--types ja4ls` names JA4LS alone.
|
|
@@ -535,7 +540,7 @@ pytest tests/ -v
|
|
|
535
540
|
|
|
536
541
|
This library is released under the **BSD 3-Clause License**.
|
|
537
542
|
|
|
538
|
-
The JA4+ fingerprinting specifications were created by [FoxIO](https://foxio.io). JA4 (TLS Client) is open source under BSD-3-Clause per FoxIO. The other methods this project implements carry the [FoxIO License 1.1](https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE): JA4S, JA4H, JA4L, JA4LS, JA4X, JA4SSH, JA4T, JA4TS, JA4D and JA4D6. That license is permissive for academic, internal business, and security research use. FoxIO names each of them at line 5 of [`License FAQ.md`](https://github.com/FoxIO-LLC/ja4/blob/main/License%20FAQ.md), at commit `27f0cbf9fd3000c072f82a0f7d0361dc99acf6c8`. That FoxIO list is wider than this one, because it also names methods this project does not implement.
|
|
543
|
+
The JA4+ fingerprinting specifications were created by [FoxIO](https://foxio.io). JA4 (TLS Client) is open source under BSD-3-Clause per FoxIO. The other methods this project implements carry the [FoxIO License 1.1](https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE): JA4S, JA4H, JA4L, JA4LS, JA4X, JA4SSH, JA4T, JA4TS, JA4TScan, JA4D and JA4D6. That license is permissive for academic, internal business, and security research use. FoxIO names each of them at line 5 of [`License FAQ.md`](https://github.com/FoxIO-LLC/ja4/blob/main/License%20FAQ.md), at commit `27f0cbf9fd3000c072f82a0f7d0361dc99acf6c8`. That FoxIO list is wider than this one, because it also names methods this project does not implement.
|
|
539
544
|
|
|
540
545
|
See [LICENSE](LICENSE) for full details.
|
|
541
546
|
|
|
@@ -4,9 +4,10 @@ A Python library and command-line program that produces JA4+ fingerprints. It re
|
|
|
4
4
|
TCP, HTTP, SSH and DHCP traffic, and it reads an X.509 certificate. It supports QUIC,
|
|
5
5
|
IPv4, IPv6 and multi-segment TCP reassembly.
|
|
6
6
|
|
|
7
|
-
**FoxIO publishes twelve JA4+ methods, and this project implements
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
**FoxIO publishes twelve JA4+ methods, and this project implements twelve of them.**
|
|
8
|
+
Eleven read traffic that already exists. The twelfth is JA4TScan, which sends packets, and
|
|
9
|
+
the `ja4plus scan` subcommand runs it. Ten fingerprinter classes carry the other eleven,
|
|
10
|
+
because `JA4LFingerprinter` writes both JA4L and JA4LS. `Methods` below names each method.
|
|
10
11
|
|
|
11
12
|
FoxIO owns the JA4+ standard, and [FoxIO](https://foxio.io) publishes it. This library is
|
|
12
13
|
an independent implementation of that standard. FoxIO wrote no part of it. For the
|
|
@@ -35,16 +36,19 @@ The `Implemented` column states whether this project builds the method.
|
|
|
35
36
|
| JA4SSH | SSH | Session type classification from traffic patterns | Yes |
|
|
36
37
|
| JA4T | TCP | Client OS fingerprint from SYN packets | Yes |
|
|
37
38
|
| JA4TS | TCP | Server fingerprint from SYN-ACK packets | Yes |
|
|
38
|
-
| JA4TScan | TCP | Active TCP fingerprint
|
|
39
|
+
| JA4TScan | TCP | Active TCP server fingerprint from SYN-ACK retransmissions, through `ja4plus scan` | Yes |
|
|
39
40
|
| JA4D | DHCPv4 | DHCP client/server fingerprint (FoxIO PR #267/#270) | Yes |
|
|
40
41
|
| JA4D6 | DHCPv6 | DHCPv6 client/server fingerprint (FoxIO PR #267/#270) | Yes |
|
|
41
42
|
|
|
42
|
-
**JA4TScan
|
|
43
|
-
to
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
**JA4TScan sends packets, so this project keeps it apart from the other eleven.** It
|
|
44
|
+
sends one TCP SYN to each host the operator names and reads the responses. The maintainer
|
|
45
|
+
reversed the decline of 2026-08-08 on 2026-09-30, in #775, and #776 built the scanner.
|
|
46
|
+
The scanner installs with `pip install ja4plus[scan]` and runs as `ja4plus scan`. The
|
|
47
|
+
`ja4plus.scan` module holds it, and no passive fingerprinter can send a packet. The
|
|
48
|
+
scanner changes no firewall state, and it states the rule the operator adds.
|
|
49
|
+
[`docs/methods/ja4tscan.md`](docs/methods/ja4tscan.md) describes the command, and
|
|
50
|
+
[`docs/specs/features/12-active-scan.md`](docs/specs/features/12-active-scan.md) holds the
|
|
51
|
+
design.
|
|
48
52
|
|
|
49
53
|
`JA4LFingerprinter` builds both JA4L and JA4LS, so ten fingerprinters carry eleven
|
|
50
54
|
methods. `--types ja4l` names the two together, and `--types ja4ls` names JA4LS alone.
|
|
@@ -490,7 +494,7 @@ pytest tests/ -v
|
|
|
490
494
|
|
|
491
495
|
This library is released under the **BSD 3-Clause License**.
|
|
492
496
|
|
|
493
|
-
The JA4+ fingerprinting specifications were created by [FoxIO](https://foxio.io). JA4 (TLS Client) is open source under BSD-3-Clause per FoxIO. The other methods this project implements carry the [FoxIO License 1.1](https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE): JA4S, JA4H, JA4L, JA4LS, JA4X, JA4SSH, JA4T, JA4TS, JA4D and JA4D6. That license is permissive for academic, internal business, and security research use. FoxIO names each of them at line 5 of [`License FAQ.md`](https://github.com/FoxIO-LLC/ja4/blob/main/License%20FAQ.md), at commit `27f0cbf9fd3000c072f82a0f7d0361dc99acf6c8`. That FoxIO list is wider than this one, because it also names methods this project does not implement.
|
|
497
|
+
The JA4+ fingerprinting specifications were created by [FoxIO](https://foxio.io). JA4 (TLS Client) is open source under BSD-3-Clause per FoxIO. The other methods this project implements carry the [FoxIO License 1.1](https://github.com/FoxIO-LLC/ja4/blob/main/LICENSE): JA4S, JA4H, JA4L, JA4LS, JA4X, JA4SSH, JA4T, JA4TS, JA4TScan, JA4D and JA4D6. That license is permissive for academic, internal business, and security research use. FoxIO names each of them at line 5 of [`License FAQ.md`](https://github.com/FoxIO-LLC/ja4/blob/main/License%20FAQ.md), at commit `27f0cbf9fd3000c072f82a0f7d0361dc99acf6c8`. That FoxIO list is wider than this one, because it also names methods this project does not implement.
|
|
494
498
|
|
|
495
499
|
See [LICENSE](LICENSE) for full details.
|
|
496
500
|
|
|
@@ -280,7 +280,7 @@ dataclass, because a result describes something that already happened.
|
|
|
280
280
|
|
|
281
281
|
| Field | Type | Constraint |
|
|
282
282
|
|---|---|---|
|
|
283
|
-
| `type` | `str` | The method name, lowercase. One of
|
|
283
|
+
| `type` | `str` | The method name, lowercase. One of eleven values. Ten values carry the eleven passive methods, and `ja4plus scan` writes the value `ja4tscan`. `--types` accepts the ten passive tokens and the token `ja4ls`. |
|
|
284
284
|
| `fingerprint` | `str` | The fingerprint string. Never empty. |
|
|
285
285
|
| `raw` | `str \| None` | The raw form, when the method defines one. |
|
|
286
286
|
| `raw_original_order` | `str \| None` | The original-order raw form, when the method defines one. |
|
|
@@ -382,8 +382,8 @@ log the error inside the loop that reads it.
|
|
|
382
382
|
reads no packet timestamp. The field holds `None`.
|
|
383
383
|
|
|
384
384
|
`stats()` reports what the state tables hold, and #41 built it. One processor holds
|
|
385
|
-
**
|
|
386
|
-
instances and the
|
|
385
|
+
**eighteen** state tables across the ten fingerprinters: the fifteen `BoundedStateTable`
|
|
386
|
+
instances and the three `TCPStreamReassembler` instances of JA4H, JA4X and JA4 (#772). A method that
|
|
387
387
|
holds no state reports an empty `tables` list.
|
|
388
388
|
|
|
389
389
|
| Field of `ProcessorStats` | Description |
|
|
@@ -435,8 +435,8 @@ one processor without that arrangement, and it guards a `reset` that runs beside
|
|
|
435
435
|
|
|
436
436
|
#### The memory bound of the processor
|
|
437
437
|
|
|
438
|
-
One processor holds
|
|
439
|
-
|
|
438
|
+
One processor holds eighteen state tables: fifteen `BoundedStateTable` instances and
|
|
439
|
+
three `TCPStreamReassembler` instances. `features/03-concurrency-safety.md` states the maximum
|
|
440
440
|
entry count and the maximum age of each one. A table that reaches its maximum entry count
|
|
441
441
|
evicts the least recently used entry. A long capture can therefore evict a connection
|
|
442
442
|
that later returns, and the fingerprint of a returned connection may be incomplete.
|
|
@@ -546,11 +546,11 @@ caller removed with `cleanup_connection` counts as a first sighting when it retu
|
|
|
546
546
|
because the caller asked for that removal.
|
|
547
547
|
|
|
548
548
|
A table remembers the keys it evicted, so that it can recognize a return. The memory
|
|
549
|
-
holds the entry bound of its own table. The
|
|
550
|
-
remembered keys between them, at 187 bytes for one key, so the memory costs 10.
|
|
549
|
+
holds the entry bound of its own table. The eighteen tables of one processor hold 58400
|
|
550
|
+
remembered keys between them, at 187 bytes for one key, so the memory costs 10.4 MiB
|
|
551
551
|
when every table is full and every entry of every table has been replaced.
|
|
552
552
|
|
|
553
|
-
Ten fingerprinters hold
|
|
553
|
+
Ten fingerprinters hold eighteen state tables between them. `JA4DFingerprinter` and
|
|
554
554
|
`JA4D6Fingerprinter` hold none, and each reports an empty `tables` dict.
|
|
555
555
|
|
|
556
556
|
`stats()` holds the lock of one fingerprinter across the read of that fingerprinter, so
|
|
@@ -562,6 +562,61 @@ tables that the counts describe.
|
|
|
562
562
|
|
|
563
563
|
`ProcessorStats` is a plain object. Epic 4 makes it a typed dataclass.
|
|
564
564
|
|
|
565
|
+
## Active scan
|
|
566
|
+
|
|
567
|
+
`ja4plus.scan` holds JA4TScan, the one method that sends packets. `import ja4plus` loads
|
|
568
|
+
no module of it, and no module outside it imports it. The `ja4plus scan` subcommand
|
|
569
|
+
reaches it through the `ja4plus.commands` entry point.
|
|
570
|
+
[The JA4TScan page](methods/ja4tscan.md) describes the command.
|
|
571
|
+
|
|
572
|
+
**The scan loop takes the send function, the receive function and the clock as
|
|
573
|
+
parameters.** A caller therefore runs it on a fake network, and `tests/scan_fakes.py`
|
|
574
|
+
holds one.
|
|
575
|
+
|
|
576
|
+
### ja4plus.scan.value
|
|
577
|
+
|
|
578
|
+
| Class/Function | Description |
|
|
579
|
+
|---|---|
|
|
580
|
+
| `Response(seconds, flags, window, options)` | The four fields of one TCP response that the value reads |
|
|
581
|
+
| `ja4tscan_value(responses)` | Return the JA4TScan value of one target, or `None` when it sent no response |
|
|
582
|
+
| `RST_ACK_VALUE` | The value `0_rst-ack`, which a target whose first response carries RST produces |
|
|
583
|
+
|
|
584
|
+
### ja4plus.scan.frames
|
|
585
|
+
|
|
586
|
+
| Class/Function | Description |
|
|
587
|
+
|---|---|
|
|
588
|
+
| `build_syn(*, src_mac, dst_mac, src_ip, dst_ip, src_port, dst_port, sequence, timestamp)` | Return the Ethernet frame of one FoxIO SYN, 74 bytes |
|
|
589
|
+
| `parse_frame(frame)` | Return the TCP fields of one received Ethernet frame, or `None` for a frame it cannot read |
|
|
590
|
+
| `Reply` | The TCP fields of one received segment that the scanner reads |
|
|
591
|
+
|
|
592
|
+
### ja4plus.scan.scanner
|
|
593
|
+
|
|
594
|
+
| Class/Function | Description |
|
|
595
|
+
|---|---|
|
|
596
|
+
| `Scanner(*, port, rate, retransmit, send, receive, clock, on_result, on_warning, rng)` | The scan loop. `run(targets)` sends one SYN to each target and waits for its responses |
|
|
597
|
+
| `ScanResult` | The value of one target and the endpoints of its responses |
|
|
598
|
+
| `parse_targets(text)` | Return the IPv4 targets that one address, one network or one file names |
|
|
599
|
+
| `TargetError` | The error `parse_targets` raises for a target the scanner cannot read |
|
|
600
|
+
| `firewall_rules(platform)` | Return the firewall rules the operator adds before a scan |
|
|
601
|
+
| `MAX_TARGETS` | The largest target count the state table holds, 10000 |
|
|
602
|
+
| `RETRANSMIT_WAIT_SECONDS` | The wait for later responses after each SYN, 120 seconds |
|
|
603
|
+
| `NO_RETRANSMIT_WAIT_SECONDS` | The wait under `--retransmit no`, 8 seconds |
|
|
604
|
+
|
|
605
|
+
### ja4plus.scan.command
|
|
606
|
+
|
|
607
|
+
| Class/Function | Description |
|
|
608
|
+
|---|---|
|
|
609
|
+
| `run(args, result_stream)` | Run the scan on the network of this host. The `ja4plus.commands` entry point names it |
|
|
610
|
+
| `scan_command(args, *, result_stream, platform, open_network, clock, rng)` | Run the scan over the network that `open_network` returns |
|
|
611
|
+
| `METHOD_TYPE` | The `type` value of a scan output line, `ja4tscan` |
|
|
612
|
+
|
|
613
|
+
### ja4plus.scan.link
|
|
614
|
+
|
|
615
|
+
| Class/Function | Description |
|
|
616
|
+
|---|---|
|
|
617
|
+
| `LinkNetwork(port, first_target, on_warning)` | The link-layer socket that sends each SYN and reads each response. It needs the privilege to open a raw socket |
|
|
618
|
+
| `privilege_refused(error)` | Return `True` when the error states that the host refused that privilege |
|
|
619
|
+
|
|
565
620
|
## Utility Modules
|
|
566
621
|
|
|
567
622
|
### ja4plus.utils.tls_utils
|
|
@@ -300,17 +300,23 @@ reported green on a comparison it never made. #216 closed it, and
|
|
|
300
300
|
| Measurement | Count |
|
|
301
301
|
|---|---|
|
|
302
302
|
| JA4T values in `python/test/testdata/` | 0 |
|
|
303
|
-
| JA4T values in the
|
|
304
|
-
| Values `ja4plus` reproduces exactly |
|
|
305
|
-
| Values that differ |
|
|
303
|
+
| JA4T values in the eight local Rust snapshots that hold one | 40 |
|
|
304
|
+
| Values `ja4plus` reproduces exactly | 40 |
|
|
305
|
+
| Values that differ | 0 |
|
|
306
306
|
| Streams on which `ja4plus` emits more than one value | 0 |
|
|
307
|
-
| Cases that stop running when `("JA4T", "ja4t")` leaves `SNAPSHOT_METHODS` |
|
|
307
|
+
| Cases that stop running when `("JA4T", "ja4t")` leaves `SNAPSHOT_METHODS` | 44 |
|
|
308
|
+
|
|
309
|
+
**#772 took the four counts above again on 2026-09-30, after it moved the pin of
|
|
310
|
+
`tests/foxio_vectors/` to FoxIO `16b96d95`.** `sigalg-grease.pcapng` adds one snapshot and
|
|
311
|
+
one value. The last count is the drop in the collected cases of
|
|
312
|
+
`tests/test_foxio_rust_parity.py` when the JA4T entry leaves `SNAPSHOT_METHODS`.
|
|
308
313
|
|
|
309
|
-
**The
|
|
310
|
-
`gre-erspan-vxlan.pcap/0:65174/JA4T.1`. The FoxIO Rust snapshot
|
|
311
|
-
`ja4plus` writes `8192_00_00_00`. The
|
|
312
|
-
|
|
313
|
-
|
|
314
|
+
**The register holds no JA4T key.** It held one until #772, which was
|
|
315
|
+
`gre-erspan-vxlan.pcap/0:65174/JA4T.1`. The FoxIO Rust snapshot held `8192__0_0` at the
|
|
316
|
+
earlier pin, and `ja4plus` writes `8192_00_00_00`. The user chose the two-digit form on
|
|
317
|
+
2026-08-08, and #215 records the ruling. FoxIO `08617cc3` moved the Rust implementation to
|
|
318
|
+
the same form, so the snapshot at `16b96d95` holds `8192_00_00_00` and #772 removed the
|
|
319
|
+
entry.
|
|
314
320
|
|
|
315
321
|
**Two entries this section named have gone, and the repairs removed them.**
|
|
316
322
|
`chrome-cloudflare-quic-with-secrets.pcapng/0:57098/JA4T.1` recorded a part b that held one
|
|
@@ -540,7 +546,7 @@ value. #132 holds the command and the full output.
|
|
|
540
546
|
Before #132, `ja4plus` emitted `9af15b336e6a` on these four streams. `JA4_o` now matches
|
|
541
547
|
all 160 reference values, and the count was 156 of 160.
|
|
542
548
|
|
|
543
|
-
**Location:** `ja4plus/fingerprinters/ja4.py:
|
|
549
|
+
**Location:** `ja4plus/fingerprinters/ja4.py:228`.
|
|
544
550
|
|
|
545
551
|
The JA4S section below records the `JA4S_o` reading.
|
|
546
552
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# The methods
|
|
2
2
|
|
|
3
|
-
FoxIO publishes twelve JA4+ methods. This project implements
|
|
3
|
+
FoxIO publishes twelve JA4+ methods. This project implements twelve of them. Ten
|
|
4
|
+
fingerprinter classes carry eleven of them, because `JA4LFingerprinter` writes both JA4L
|
|
5
|
+
and JA4LS. The `ja4plus scan` subcommand carries JA4TScan.
|
|
4
6
|
|
|
5
7
|
Each page below describes one method. It states the output format, the parts of the
|
|
6
8
|
value, the hash rule, and the FoxIO file that publishes the method. It also names one
|
|
@@ -23,7 +25,7 @@ the standard itself, read the
|
|
|
23
25
|
| JA4SSH | SSH | [The SSH session fingerprint](ja4ssh.md) | Yes |
|
|
24
26
|
| JA4T | TCP | [The TCP client fingerprint](ja4t.md) | Yes |
|
|
25
27
|
| JA4TS | TCP | [The TCP server fingerprint](ja4ts.md) | Yes |
|
|
26
|
-
| JA4TScan | TCP |
|
|
28
|
+
| JA4TScan | TCP | [The active TCP server fingerprint](ja4tscan.md) | Yes |
|
|
27
29
|
| JA4D | DHCPv4 | [The DHCPv4 fingerprint](ja4d.md) | Yes |
|
|
28
30
|
| JA4D6 | DHCPv6 | [The DHCPv6 fingerprint](ja4d6.md) | Yes |
|
|
29
31
|
|
|
@@ -40,15 +42,24 @@ under parity rule 2.
|
|
|
40
42
|
**Read the ten as a count of fingerprinter classes, and never as a count of methods.**
|
|
41
43
|
#387 records the three documents that made that mistake.
|
|
42
44
|
|
|
43
|
-
## Why
|
|
45
|
+
## Why JA4TScan stands apart from the other methods
|
|
44
46
|
|
|
45
|
-
**
|
|
46
|
-
sends
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
**JA4TScan sends packets, and every other method reads traffic that already exists.**
|
|
48
|
+
JA4TScan sends one TCP SYN to each host the operator names, and it reads the responses.
|
|
49
|
+
#776 built it as the `ja4plus scan` subcommand, in the `ja4plus.scan` module. No
|
|
50
|
+
fingerprinter of this table can send a packet.
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
The maintainer reversed the decline of 2026-08-08 on 2026-09-30, in #775.
|
|
53
|
+
`docs/specs/features/12-active-scan.md` holds the design, and [the JA4TScan page](ja4tscan.md)
|
|
54
|
+
describes the command. The superseded text is quoted below rather than rewritten.
|
|
55
|
+
|
|
56
|
+
> **This project declines JA4TScan by ruling, and the absence is no omission.** JA4TScan
|
|
57
|
+
> sends crafted packets to a host the operator names, and it reads the responses. Every
|
|
58
|
+
> other method reads traffic that already exists, so JA4TScan reaches a network the
|
|
59
|
+
> operator did not capture. That capability is larger than fingerprint production.
|
|
60
|
+
>
|
|
61
|
+
> `docs/specs/spec.md` holds the ruling under `Non-goals`, and #197 holds the reading.
|
|
62
|
+
> The ruling is reversible.
|
|
52
63
|
|
|
53
64
|
## What a fingerprint is evidence of
|
|
54
65
|
|
|
@@ -21,8 +21,8 @@ fingerprint.
|
|
|
21
21
|
<part a>_<cipher hash>_<extension hash>
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Part a holds ten characters. `ja4plus/fingerprinters/ja4.py:
|
|
25
|
-
`ja4plus/fingerprinters/ja4.py:
|
|
24
|
+
Part a holds ten characters. `ja4plus/fingerprinters/ja4.py:318` builds it, and
|
|
25
|
+
`ja4plus/fingerprinters/ja4.py:233` joins the three parts.
|
|
26
26
|
|
|
27
27
|
## The parts
|
|
28
28
|
|
|
@@ -35,7 +35,7 @@ Part a holds ten characters. `ja4plus/fingerprinters/ja4.py:316` builds it, and
|
|
|
35
35
|
| Extension count | 2 | The count of extensions, after the reader drops every GREASE value. It stops at `99`. |
|
|
36
36
|
| ALPN | 2 | The first character and the last character of the first ALPN value, or `00` when the client offers none. |
|
|
37
37
|
| Cipher hash | 12 | The hash of the sorted cipher list. |
|
|
38
|
-
| Extension hash | 12 | The hash of the sorted extension list, with the signature algorithms appended. |
|
|
38
|
+
| Extension hash | 12 | The hash of the sorted extension list, with the signature algorithms appended. The reader drops every GREASE value from the signature algorithms and keeps their wire order. |
|
|
39
39
|
|
|
40
40
|
## The hash rule
|
|
41
41
|
|
|
@@ -43,9 +43,13 @@ writes `00`, the MSS part writes two digits, and a window scale of zero writes `
|
|
|
43
43
|
window scale above zero writes its own digits and no padding, which is why the example
|
|
44
44
|
below ends in `7` and not `07`.
|
|
45
45
|
|
|
46
|
-
The Wireshark dissector
|
|
47
|
-
implementation
|
|
48
|
-
`Divergence register` of `docs/specs/spec.md` records the
|
|
46
|
+
The Wireshark dissector, the Zeek script and the FoxIO Rust implementation each write that
|
|
47
|
+
form. The Rust implementation wrote one digit until FoxIO `08617cc3`. #215 records the
|
|
48
|
+
ruling as D1, and the `Divergence register` of `docs/specs/spec.md` records the reading.
|
|
49
|
+
|
|
50
|
+
**A repeated option keeps its last value.** A SYN that carries two MSS options writes the
|
|
51
|
+
value of the second one, and a repeated window scale option works the same way. The three
|
|
52
|
+
FoxIO implementations each keep the last value. #774 records the reading.
|
|
49
53
|
|
|
50
54
|
## The hash rule
|
|
51
55
|
|