netprotocols 2.6.0__tar.gz → 2.7.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.
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/workflows/ci.yml +8 -8
- netprotocols-2.7.0/.github/workflows/codeql.yml +100 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/workflows/fuzz.yml +4 -4
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/workflows/mutation.yml +2 -2
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/workflows/release.yml +3 -3
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/workflows/scorecard.yml +2 -2
- {netprotocols-2.6.0 → netprotocols-2.7.0}/ARCHITECTURE.md +220 -10
- {netprotocols-2.6.0 → netprotocols-2.7.0}/CHANGELOG.md +28 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/CONTRIBUTING.md +4 -2
- {netprotocols-2.6.0 → netprotocols-2.7.0}/PKG-INFO +39 -23
- {netprotocols-2.6.0 → netprotocols-2.7.0}/README.md +38 -22
- {netprotocols-2.6.0 → netprotocols-2.7.0}/docs/CLAIMS.md +228 -30
- {netprotocols-2.6.0 → netprotocols-2.7.0}/pyproject.toml +16 -4
- netprotocols-2.7.0/scripts/capture_fixtures_hsrp.sh +305 -0
- netprotocols-2.7.0/scripts/capture_fixtures_ntp.sh +346 -0
- netprotocols-2.7.0/scripts/capture_fixtures_radius.sh +338 -0
- netprotocols-2.7.0/scripts/capture_fixtures_stun.sh +530 -0
- netprotocols-2.7.0/scripts/capture_fixtures_tftp.sh +312 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/check_fixtures.py +488 -8
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/check_mutmut_survivors.py +1 -1
- netprotocols-2.7.0/scripts/filter_codeql_sarif.py +348 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/__init__.py +16 -1
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/_base.py +20 -6
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/_defaults.py +36 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/_tlv.py +20 -3
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/checksum.py +172 -24
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/flow.py +22 -6
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/ipv6_ext.py +132 -2
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer4/sctp.py +4 -3
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer7/__init__.py +15 -0
- netprotocols-2.7.0/src/netprotocols/layer7/hsrp.py +395 -0
- netprotocols-2.7.0/src/netprotocols/layer7/ntp.py +757 -0
- netprotocols-2.7.0/src/netprotocols/layer7/radius.py +559 -0
- netprotocols-2.7.0/src/netprotocols/layer7/stun.py +784 -0
- netprotocols-2.7.0/src/netprotocols/layer7/tftp.py +551 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/packet.py +89 -23
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/walk.py +3 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/conftest.py +60 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/MANIFEST.md +259 -8
- netprotocols-2.7.0/tests/fixtures/codeql/python.sarif +1 -0
- netprotocols-2.7.0/tests/fixtures/hsrp.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/ntp.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/radius.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/staging/hsrp.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/staging/ntp.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/staging/radius.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/staging/stun/stun_rfc3489.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/staging/stun.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/staging/tftp.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/stun/stun_rfc3489.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/stun.pcap +0 -0
- netprotocols-2.7.0/tests/fixtures/tftp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/strategies.py +143 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_checksum.py +1076 -4
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_contract.py +90 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_corpus.py +10 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_docs.py +5 -0
- netprotocols-2.7.0/tests/test_filter_codeql_sarif.py +685 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_flow.py +2 -3
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_fuzz.py +538 -0
- netprotocols-2.7.0/tests/test_hsrp.py +1257 -0
- netprotocols-2.7.0/tests/test_ipv6_routing_final_dst.py +200 -0
- netprotocols-2.7.0/tests/test_ntp.py +897 -0
- netprotocols-2.7.0/tests/test_radius.py +853 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_sctp.py +38 -0
- netprotocols-2.7.0/tests/test_stun.py +1103 -0
- netprotocols-2.7.0/tests/test_tftp.py +732 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_tlv.py +93 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_workflows.py +277 -6
- {netprotocols-2.6.0 → netprotocols-2.7.0}/uv.lock +103 -98
- netprotocols-2.6.0/.github/workflows/codeql.yml +0 -50
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.claude/skills/steward/SKILL.md +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.gitattributes +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/CODEOWNERS +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/ISSUE_TEMPLATE/protocol_request.yml +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/dependabot.yml +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/pull_request_template.md +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/workflows/docs-lint.yml +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.github/workflows/pr-title-lint.yml +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/.gitignore +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/LICENSE +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/SECURITY.md +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/benchmarks/baseline.json +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/_pcap.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/benchmark.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/benchmark_encode.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/benchmark_import.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_bgp.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_dhcp.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_dns_tcp.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_gre.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_http.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_igmp.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_ipip.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_ipsec.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_llc.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_lldp.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_mpls.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_ospf.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_pim.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_rip.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_sctp.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_supplement.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_vlan.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_vrrp.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/capture_fixtures_vxlan.sh +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/extract_http_streams.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/ipsec_fixture_packets.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/llc_fixture_frames.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/mpls_fixture_packets.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/mutmut_survivors.txt +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/pyodide/check_in_pyodide.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/pyodide/package-lock.json +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/pyodide/package.json +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/scripts/pyodide/run_in_pyodide.mjs +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/_enums.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/__init__.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/arp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/cdp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/ethernet.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/llc.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/lldp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/mpls.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/stp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer2/vlan.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/__init__.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/ah.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/esp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/gre.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/icmp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/igmp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/ip.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/ospf.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/pim.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer3/vrrp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer4/__init__.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer4/_ports.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer4/tcp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer4/udp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer7/bgp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer7/dhcp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer7/dns.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer7/http.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer7/rip.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/layer7/vxlan.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/pcap.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/py.typed +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/registry.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/utils/__init__.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/utils/exceptions.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/utils/ipv4.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/src/netprotocols/utils/mac.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/ah.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/arp_exchange.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/bgp/bgp_session.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/bgp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/dhcp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/dns_tcp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/esp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/gre.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/01.request +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/01.response +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/02.request +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/02.response +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/03.request +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/03.response +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/04.request +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/04.response +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/05.request +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/05.response +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/06.request +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/06.response +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/07.request +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/07.response +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/http/http.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/icmpv4_echo_lo.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/icmpv4_external.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/icmpv4_ttl_exceeded.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/icmpv6_echo_lo.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/igmp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/ipip.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/ipv4_fragments.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/ipv6_fragments.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/ipv6_mld.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/ipv6_ndp_mld.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/llc.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/lldp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/mpls/mpls_snaplen.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/mpls.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/ospf.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/pim.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/rip.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/sctp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/ah.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/arp_exchange.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/bgp/bgp_session.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/bgp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/dhcp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/dns_tcp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/esp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/gre.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/http.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/icmpv4_echo_lo.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/icmpv4_external.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/icmpv4_ttl_exceeded.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/icmpv6_echo_lo.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/igmp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/ipip.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/ipv4_fragments.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/ipv6_fragments.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/ipv6_mld.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/ipv6_ndp_mld.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/llc.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/lldp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/mpls/mpls_snaplen.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/mpls.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/ospf.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/pim.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/rip.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/sctp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/tcp_http.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/tcp_https.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/udp_dns.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/vlan_icmp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/vrrp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/staging/vxlan.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/tcp_http.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/tcp_https.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/udp_dns.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/vlan_icmp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/vrrp.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fixtures/vxlan.pcap +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fuzz/fuzz_decode_frame.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/fuzz/fuzz_http_decode.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_ah.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_arp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_bgp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_cdp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_dhcp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_diagnostics.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_dns.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_enums.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_esp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_ethernet.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_exports.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_extract_http_streams.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_gre.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_http.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_icmp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_igmp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_ip.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_ipip.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_ipv6_ext.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_llc.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_lldp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_mpls.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_mutmut_gate.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_ospf.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_packet.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_pattern_matching.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_pcap.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_pim.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_registry.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_rip.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_stp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_tcp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_udp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_utils.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_version.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_vlan.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_vrrp.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_vxlan.py +0 -0
- {netprotocols-2.6.0 → netprotocols-2.7.0}/tests/test_walk.py +0 -0
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
runs-on: ubuntu-latest
|
|
34
34
|
steps:
|
|
35
35
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
36
|
-
- uses: astral-sh/setup-uv@
|
|
36
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
37
37
|
with:
|
|
38
38
|
python-version: "3.12"
|
|
39
39
|
- run: uv run ruff check
|
|
@@ -43,7 +43,7 @@ jobs:
|
|
|
43
43
|
runs-on: ubuntu-latest
|
|
44
44
|
steps:
|
|
45
45
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
46
|
-
- uses: astral-sh/setup-uv@
|
|
46
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
47
47
|
with:
|
|
48
48
|
python-version: "3.12"
|
|
49
49
|
- run: uv run mypy
|
|
@@ -55,7 +55,7 @@ jobs:
|
|
|
55
55
|
python-version: ["3.12", "3.13", "3.14"]
|
|
56
56
|
steps:
|
|
57
57
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
58
|
-
- uses: astral-sh/setup-uv@
|
|
58
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
59
59
|
with:
|
|
60
60
|
python-version: ${{ matrix.python-version }}
|
|
61
61
|
- run: uv run --frozen pytest --cov=netprotocols --cov-report=term
|
|
@@ -70,7 +70,7 @@ jobs:
|
|
|
70
70
|
runs-on: ubuntu-latest
|
|
71
71
|
steps:
|
|
72
72
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
73
|
-
- uses: astral-sh/setup-uv@
|
|
73
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
74
74
|
with:
|
|
75
75
|
python-version: "3.12"
|
|
76
76
|
- name: Export dev dependencies
|
|
@@ -86,7 +86,7 @@ jobs:
|
|
|
86
86
|
runs-on: ubuntu-latest
|
|
87
87
|
steps:
|
|
88
88
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
89
|
-
- uses: astral-sh/setup-uv@
|
|
89
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
90
90
|
- run: uv build
|
|
91
91
|
- run: uv run --isolated --no-project --with dist/*.whl python -c "import netprotocols; print(netprotocols.__version__)"
|
|
92
92
|
# Builds are supposed to be a pure function of the source tree, so
|
|
@@ -119,11 +119,11 @@ jobs:
|
|
|
119
119
|
runs-on: ubuntu-latest
|
|
120
120
|
steps:
|
|
121
121
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
122
|
-
- uses: astral-sh/setup-uv@
|
|
122
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
123
123
|
with:
|
|
124
124
|
python-version: "3.12"
|
|
125
125
|
- run: uv build
|
|
126
|
-
- uses: actions/setup-node@
|
|
126
|
+
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
|
127
127
|
with:
|
|
128
128
|
node-version: "22"
|
|
129
129
|
- run: npm ci
|
|
@@ -151,7 +151,7 @@ jobs:
|
|
|
151
151
|
runs-on: ubuntu-latest
|
|
152
152
|
steps:
|
|
153
153
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
154
|
-
- uses: astral-sh/setup-uv@
|
|
154
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
155
155
|
with:
|
|
156
156
|
python-version: "3.12"
|
|
157
157
|
- name: Corpus decode throughput
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: CodeQL
|
|
2
|
+
|
|
3
|
+
# Advanced-setup workflow (a checked-in file) rather than GitHub's
|
|
4
|
+
# built-in "default setup", so this analysis lives in version control
|
|
5
|
+
# alongside the rest of this repository's CI (ci.yml, fuzz.yml,
|
|
6
|
+
# release.yml, mutation.yml, scorecard.yml) and its action pins are
|
|
7
|
+
# reviewable the same way theirs are. Default setup is configured
|
|
8
|
+
# through repository settings instead of a file, so it isn't available
|
|
9
|
+
# to author from here.
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [master]
|
|
13
|
+
pull_request:
|
|
14
|
+
branches: [master]
|
|
15
|
+
schedule:
|
|
16
|
+
# Arbitrary; weekly on Sundays, clear of fuzz.yml's and mutation.yml's
|
|
17
|
+
# daily 03:00/04:00 UTC slots and scorecard.yml's own Sunday 05:00
|
|
18
|
+
# UTC slot.
|
|
19
|
+
- cron: "0 6 * * 0"
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
|
|
24
|
+
concurrency:
|
|
25
|
+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
26
|
+
cancel-in-progress: true
|
|
27
|
+
|
|
28
|
+
jobs:
|
|
29
|
+
analyze:
|
|
30
|
+
name: Analyze (python)
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
permissions:
|
|
33
|
+
actions: read
|
|
34
|
+
contents: read
|
|
35
|
+
security-events: write
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
38
|
+
|
|
39
|
+
# Python is interpreted, so there is nothing for autobuild (or a
|
|
40
|
+
# manual build step) to do: build-mode: none has CodeQL extract
|
|
41
|
+
# the database straight from source instead. This is the build
|
|
42
|
+
# mode the CodeQL Action's own docs recommend for interpreted
|
|
43
|
+
# languages, and it sidesteps the question of an autobuild step
|
|
44
|
+
# fitting this project's uv-based build at all.
|
|
45
|
+
- uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
|
46
|
+
with:
|
|
47
|
+
languages: python
|
|
48
|
+
build-mode: none
|
|
49
|
+
|
|
50
|
+
# analyze writes the SARIF without uploading it, the filter step
|
|
51
|
+
# drops one query's results on two paths, and upload-sarif uploads
|
|
52
|
+
# what is left. py/weak-sensitive-data-hashing flags the MD5 that
|
|
53
|
+
# RADIUS (#265) and STUN (#267) mandate, which their tests and
|
|
54
|
+
# scripts/check_fixtures.py compute over published test secrets
|
|
55
|
+
# with usedforsecurity=False to verify captured traffic.
|
|
56
|
+
# The CodeQL config can't scope a query to paths: query-filters
|
|
57
|
+
# drops it everywhere, src/ included, and paths-ignore drops the
|
|
58
|
+
# paths from every query. So the filter removes only that query's
|
|
59
|
+
# results whose primary location is under tests/ or scripts/; the
|
|
60
|
+
# query still runs on src/, every other query on all three.
|
|
61
|
+
#
|
|
62
|
+
# upload: failure-only is the action's documented mode for a
|
|
63
|
+
# workflow that post-processes the SARIF: analyze uploads nothing
|
|
64
|
+
# when it succeeds. It still marks the analysis as completed, so
|
|
65
|
+
# init's post step does not upload a failed-run SARIF for a later
|
|
66
|
+
# step's failure either: if the filter or upload-sarif fails, the
|
|
67
|
+
# job goes red and no new analysis replaces the previous one
|
|
68
|
+
# (upload-sarif can fail after uploading, while it waits for
|
|
69
|
+
# processing). That fails closed; unfiltered SARIF is never
|
|
70
|
+
# uploaded. (Any value the action does not recognize means
|
|
71
|
+
# `always`, which would upload before the filter runs.)
|
|
72
|
+
#
|
|
73
|
+
# Neither analyze nor upload-sarif sets `category`, and that is
|
|
74
|
+
# what keeps the analysis the same one: with no category the CLI
|
|
75
|
+
# writes no runs[].automationDetails, and both actions then fill
|
|
76
|
+
# it in from the workflow path, job id and matrix,
|
|
77
|
+
# ".github/workflows/codeql.yml:analyze/", the same in both
|
|
78
|
+
# steps of this job. Existing alerts keep tracking (fixed ones
|
|
79
|
+
# close, the rest stay) rather than reappearing under a new
|
|
80
|
+
# category. Setting one on either step alone would start a second
|
|
81
|
+
# analysis next to the first.
|
|
82
|
+
- id: analyze
|
|
83
|
+
uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
|
84
|
+
with:
|
|
85
|
+
upload: failure-only
|
|
86
|
+
|
|
87
|
+
# Rewrites each *.sarif under analyze's output directory, at any
|
|
88
|
+
# depth and skipping symlinks (as upload-sarif finds them), in
|
|
89
|
+
# place and logs one line per file, by its path under the
|
|
90
|
+
# directory, naming every result it dropped; malformed SARIF fails
|
|
91
|
+
# the job instead of uploading unfiltered results.
|
|
92
|
+
# Stdlib only, so the runner's own python3 runs it.
|
|
93
|
+
- name: Drop weak-hashing results on tests/ and scripts/
|
|
94
|
+
env:
|
|
95
|
+
SARIF_DIR: ${{ steps.analyze.outputs.sarif-output }}
|
|
96
|
+
run: python3 scripts/filter_codeql_sarif.py "$SARIF_DIR"
|
|
97
|
+
|
|
98
|
+
- uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
|
99
|
+
with:
|
|
100
|
+
sarif_file: ${{ steps.analyze.outputs.sarif-output }}
|
|
@@ -38,7 +38,7 @@ jobs:
|
|
|
38
38
|
runs-on: ubuntu-latest
|
|
39
39
|
steps:
|
|
40
40
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
41
|
-
- uses: astral-sh/setup-uv@
|
|
41
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
42
42
|
with:
|
|
43
43
|
python-version: "3.12"
|
|
44
44
|
# Keyed by run id with a prefix restore-key: a fixed key would
|
|
@@ -65,7 +65,7 @@ jobs:
|
|
|
65
65
|
# repo write access to re-run the job locally.
|
|
66
66
|
- name: Upload the failing example database
|
|
67
67
|
if: failure()
|
|
68
|
-
uses: actions/upload-artifact@
|
|
68
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
69
69
|
with:
|
|
70
70
|
name: hypothesis-nightly-failure-${{ github.run_id }}
|
|
71
71
|
path: .hypothesis
|
|
@@ -85,7 +85,7 @@ jobs:
|
|
|
85
85
|
runs-on: ubuntu-latest
|
|
86
86
|
steps:
|
|
87
87
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
88
|
-
- uses: astral-sh/setup-uv@
|
|
88
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
89
89
|
with:
|
|
90
90
|
python-version: "3.12"
|
|
91
91
|
- name: Run Atheris against decode_frame
|
|
@@ -98,7 +98,7 @@ jobs:
|
|
|
98
98
|
python tests/fuzz/fuzz_http_decode.py -max_total_time=300
|
|
99
99
|
- name: Upload crash artifacts
|
|
100
100
|
if: failure()
|
|
101
|
-
uses: actions/upload-artifact@
|
|
101
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
102
102
|
with:
|
|
103
103
|
name: atheris-crash-${{ github.run_id }}
|
|
104
104
|
path: crash-*
|
|
@@ -30,7 +30,7 @@ jobs:
|
|
|
30
30
|
runs-on: ubuntu-latest
|
|
31
31
|
steps:
|
|
32
32
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
33
|
-
- uses: astral-sh/setup-uv@
|
|
33
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
34
34
|
with:
|
|
35
35
|
python-version: "3.12"
|
|
36
36
|
# mutmut hashes each mutated file plus the tests that cover it and
|
|
@@ -104,7 +104,7 @@ jobs:
|
|
|
104
104
|
# doesn't exist is silently skipped.
|
|
105
105
|
- name: Upload mutmut results on failure
|
|
106
106
|
if: failure()
|
|
107
|
-
uses: actions/upload-artifact@
|
|
107
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
108
108
|
with:
|
|
109
109
|
name: mutmut-nightly-failure-${{ github.run_id }}
|
|
110
110
|
path: |
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
contents: read
|
|
36
36
|
steps:
|
|
37
37
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
38
|
-
- uses: astral-sh/setup-uv@
|
|
38
|
+
- uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
|
|
39
39
|
- run: uv build
|
|
40
40
|
# The QA ladder cannot catch a mistagged release: every check
|
|
41
41
|
# passes because the code is fine and only the tag is wrong. Read
|
|
@@ -99,7 +99,7 @@ jobs:
|
|
|
99
99
|
--pyproject pyproject.toml --mc-type library \
|
|
100
100
|
-o "netprotocols-${GITHUB_REF_NAME#v}.cdx.json"
|
|
101
101
|
- name: Upload release assets
|
|
102
|
-
uses: actions/upload-artifact@
|
|
102
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
103
103
|
with:
|
|
104
104
|
name: release-assets
|
|
105
105
|
path: |
|
|
@@ -123,7 +123,7 @@ jobs:
|
|
|
123
123
|
steps:
|
|
124
124
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
125
125
|
- name: Download release assets
|
|
126
|
-
uses: actions/download-artifact@
|
|
126
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
127
127
|
with:
|
|
128
128
|
name: release-assets
|
|
129
129
|
# CHANGELOG.md is the single source of truth for release notes, so
|
|
@@ -48,7 +48,7 @@ jobs:
|
|
|
48
48
|
# Upload the SARIF results as a workflow artifact, per the action's
|
|
49
49
|
# standard setup.
|
|
50
50
|
- name: Upload artifact
|
|
51
|
-
uses: actions/upload-artifact@
|
|
51
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
52
52
|
with:
|
|
53
53
|
name: SARIF file
|
|
54
54
|
path: results.sarif
|
|
@@ -56,6 +56,6 @@ jobs:
|
|
|
56
56
|
|
|
57
57
|
# Upload the results to GitHub's code scanning dashboard.
|
|
58
58
|
- name: Upload to code-scanning
|
|
59
|
-
uses: github/codeql-action/upload-sarif@
|
|
59
|
+
uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
|
|
60
60
|
with:
|
|
61
61
|
sarif_file: results.sarif
|
|
@@ -214,6 +214,42 @@ raises. Ethernet's zero padding reaches only a message with no entries,
|
|
|
214
214
|
since one entry already fills the minimum frame. See
|
|
215
215
|
[`layer7/rip.py`](src/netprotocols/layer7/rip.py)'s module docstring.
|
|
216
216
|
|
|
217
|
+
`NTP` is the same case: after its 48-byte header come NTPv4 extension
|
|
218
|
+
fields (RFC 7822) and a MAC, both optional, up to the end of the UDP
|
|
219
|
+
datagram, which nothing in the message bounds. It keeps the whole
|
|
220
|
+
buffer after the header, so `bytes(NTP.decode(x)) == x`, and its
|
|
221
|
+
accessors split it: extension fields until what is left has a MAC's
|
|
222
|
+
length (4, 20 or 24 bytes, the rule RFC 7822 §3's minimum field length
|
|
223
|
+
is there for), then the MAC, and anything else as `remainder`. A
|
|
224
|
+
4-byte Ethernet FCS after a plain message has a crypto-NAK's length,
|
|
225
|
+
and only the UDP length could tell them apart. Past the header
|
|
226
|
+
neither `decode()` nor any accessor raises, and Ethernet's padding
|
|
227
|
+
never reaches it: the header alone fills the minimum frame. See
|
|
228
|
+
[`layer7/ntp.py`](src/netprotocols/layer7/ntp.py)'s module docstring.
|
|
229
|
+
|
|
230
|
+
`TFTP` has no length field either, but most of its messages bound
|
|
231
|
+
themselves: an ACK is 4 bytes, an ERROR ends at the zero byte after its
|
|
232
|
+
message, and a request or an OACK after its last whole option pair, a
|
|
233
|
+
zero byte where the next name would start ending the options. So it
|
|
234
|
+
obeys rule 3 like a header with a length field,
|
|
235
|
+
`bytes(TFTP.decode(x)) == x[:header_len]`, and leaves Ethernet's
|
|
236
|
+
padding (which every ACK, at 4 bytes, gets in an untagged frame over
|
|
237
|
+
IPv4 with no options) and an FCS undecoded, except that a trailer
|
|
238
|
+
holding a zero byte can be read in, which only the UDP length could
|
|
239
|
+
rule out (#235): after a name with no value, the trailer's first zero
|
|
240
|
+
byte ends that value, so padding decodes `("tsize", "")` and takes one
|
|
241
|
+
byte, and after whole pairs an FCS that holds a name, a zero byte, a
|
|
242
|
+
value and a zero byte, such as `12 00 34 00`, reads as one more pair. A
|
|
243
|
+
DATA message cannot bound itself at all: its data has no terminator, so
|
|
244
|
+
it runs to the end of the buffer, and a trailer joins it, as it joins
|
|
245
|
+
an ICMP `body`. Its
|
|
246
|
+
strings are terminated rather than length-prefixed, so a missing
|
|
247
|
+
terminator is TFTP's truncation case: a filename, mode or error message
|
|
248
|
+
with no zero byte after it raises `TruncatedHeaderError`, as a lying
|
|
249
|
+
length does in rule 2, while an option pair cut short is left undecoded,
|
|
250
|
+
since only UDP's length could tell it from a trailer. See
|
|
251
|
+
[`layer7/tftp.py`](src/netprotocols/layer7/tftp.py)'s module docstring.
|
|
252
|
+
|
|
217
253
|
`VRRP` has no length field either, but needs no walk: its version and
|
|
218
254
|
address count give its exact length (8 bytes, the addresses, and
|
|
219
255
|
VRRPv2's 8 bytes of authentication data), so it obeys rule 3 like a
|
|
@@ -363,12 +399,15 @@ unless the Security Association uses a confidentiality-free transform
|
|
|
363
399
|
(e.g. NULL, RFC 2410, or AES-GMAC, RFC 4543), and at an offset only
|
|
364
400
|
the SA determines, so the decoder never reads it).
|
|
365
401
|
|
|
366
|
-
`BGP`, `MPLS` and `LLC` are the
|
|
367
|
-
decode context rather than from a wire field alone. A BGP message
|
|
402
|
+
`BGP`, `STUN`, `MPLS` and `LLC` are the four exceptions: they answer
|
|
403
|
+
from decode context rather than from a wire field alone. A BGP message
|
|
368
404
|
carries no payload: a TCP segment can hold several messages back to
|
|
369
405
|
back, each decoded as its own layer, so `BGP.next_protocol()` names the
|
|
370
406
|
next message *beside* it — `BGP` when the bytes after this message
|
|
371
|
-
begin another one, `None` when they do not.
|
|
407
|
+
begin another one, `None` when they do not. STUN over TCP is the same
|
|
408
|
+
case, and `STUN.next_protocol()` answers `STUN` the same way, when the
|
|
409
|
+
8 bytes after the message begin like a message's header, its magic
|
|
410
|
+
cookie in place. An MPLS label stack carries
|
|
372
411
|
a packet but no field naming its protocol (see *MPLS: dispatch by
|
|
373
412
|
convention* below), so `MPLS.next_protocol()` infers one, partly from
|
|
374
413
|
the first byte after the stack. SAP 0x42 carries GARP's PDUs (Protocol
|
|
@@ -382,11 +421,12 @@ records what it saw on the instance in a field kept out of the
|
|
|
382
421
|
dataclass's comparison and hash (`compare=False`, the mechanism `HTTP`
|
|
383
422
|
uses for its `_message` parse cache). Two equal headers compare equal
|
|
384
423
|
however they were found, and can still chain differently. The rules of
|
|
385
|
-
the decode contract hold for all
|
|
424
|
+
the decode contract hold for all four unchanged; see *Port-based
|
|
386
425
|
dispatch is best-effort* below,
|
|
387
426
|
[`_base.py`](src/netprotocols/_base.py)'s *Decode context in
|
|
388
427
|
next_protocol*, the module docstrings of
|
|
389
|
-
[`layer7/bgp.py`](src/netprotocols/layer7/bgp.py)
|
|
428
|
+
[`layer7/bgp.py`](src/netprotocols/layer7/bgp.py),
|
|
429
|
+
[`layer7/stun.py`](src/netprotocols/layer7/stun.py) and
|
|
390
430
|
[`layer2/mpls.py`](src/netprotocols/layer2/mpls.py), and
|
|
391
431
|
[`layer2/llc.py`](src/netprotocols/layer2/llc.py)'s *DSAP 0x42*.
|
|
392
432
|
|
|
@@ -453,8 +493,15 @@ flowchart LR
|
|
|
453
493
|
U -->|4789| VX[VXLAN]
|
|
454
494
|
VX -->|always| E
|
|
455
495
|
U -->|520| R[RIP]
|
|
496
|
+
U -->|69, the request only| TF[TFTP]
|
|
497
|
+
U -->|1812, 1813| RAD[RADIUS]
|
|
498
|
+
U -->|123| NT[NTP]
|
|
499
|
+
U -->|1985| HS[HSRP]
|
|
456
500
|
T -->|179| BGP[BGP message]
|
|
457
501
|
BGP -->|another message in the segment| BGP
|
|
502
|
+
U -->|3478| STUN[STUN message]
|
|
503
|
+
T -->|3478| STUN
|
|
504
|
+
STUN -->|another message in the segment| STUN
|
|
458
505
|
```
|
|
459
506
|
|
|
460
507
|
IPv6 extension headers (Hop-by-Hop Options, Routing, Fragment,
|
|
@@ -722,7 +769,7 @@ header cannot reject more than it does: RFC 7348 says to ignore its
|
|
|
722
769
|
reserved bits, so rejecting those would refuse real traffic, such as
|
|
723
770
|
the Group Based Policy extension's.
|
|
724
771
|
|
|
725
|
-
RIP on UDP 520 rejects
|
|
772
|
+
RIP on UDP 520 rejects far more, because two of its four header bytes
|
|
726
773
|
have values no RIP message carries: `RIP.decode()` requires version 1
|
|
727
774
|
or 2 and a nonzero command, which 510 of the 65,536 two-byte prefixes
|
|
728
775
|
satisfy, so about 99.2% of random datagrams are rejected. Measured the
|
|
@@ -736,6 +783,112 @@ does a RIPv1 message with nonzero must-be-zero fields, which RFC 1058
|
|
|
736
783
|
tells a receiver to ignore but a decoder should show. Past the header,
|
|
737
784
|
any 20 bytes are an entry.
|
|
738
785
|
|
|
786
|
+
RADIUS on UDP 1812 and 1813 (RFC 2865, RFC 2866) rejects a little
|
|
787
|
+
more again, through its Length alone: `RADIUS.decode()` requires at least
|
|
788
|
+
the 20 bytes of its header (`InvalidFieldError` below that) and no more
|
|
789
|
+
than the buffer holds (`TruncatedHeaderError` past it). A random
|
|
790
|
+
300-byte payload therefore passes only when its third and fourth bytes
|
|
791
|
+
read 20-300, 281 of 65,536 values, and one of n bytes with n - 19 of
|
|
792
|
+
them, which over lengths drawn uniformly from 0-600 averages 281 too.
|
|
793
|
+
Measured the same way (`random.Random` seeds 0-2), the walk stopped
|
|
794
|
+
for about 99.6% in each case (99.57% expected): the 300-byte payloads
|
|
795
|
+
and the 0-600 byte ones, padded or not, on either port. The Code is
|
|
796
|
+
not checked: every value decodes, and the codes of RFC 2865, RFC 2866,
|
|
797
|
+
RFC 5997 and RFC 5176 are named (IANA assigns others, such as 6-10,
|
|
798
|
+
21-34 and 50-52, which are not). Nor are the attributes: a packet
|
|
799
|
+
whose attribute list does not walk still decodes, and
|
|
800
|
+
`parsed_attributes` raises when asked, so an accepted guess can still
|
|
801
|
+
read as garbage. Bytes past the Length are padding (RFC 2865 §3) and
|
|
802
|
+
stay undecoded, past `packet.consumed`. The walk does not yet end the
|
|
803
|
+
buffer at UDP's length (#235), though, so a Length that overstates the
|
|
804
|
+
datagram reaches into whatever follows it in the frame, such as an
|
|
805
|
+
Ethernet FCS, and reads it as attributes instead of raising. Only 1812
|
|
806
|
+
and 1813 are registered: the legacy 1645 and 1646, and Dynamic
|
|
807
|
+
Authorization's 3799 (RFC 5176, whose Disconnect and CoA packets share
|
|
808
|
+
the format), need `decode_as`.
|
|
809
|
+
|
|
810
|
+
TFTP on UDP 69 (RFC 1350) rejects more: `TFTP.decode()` requires an
|
|
811
|
+
opcode of 1-6, which 6 of the 65,536 two-byte prefixes are, and then the
|
|
812
|
+
mandatory fields that opcode carries, whole. Measured the same way, over
|
|
813
|
+
three seeds, the walk stopped for 99.98-100% of the 300-byte payloads
|
|
814
|
+
sent to 69 and of the 0-600 byte ones unpadded and padded: about 5 of
|
|
815
|
+
the 90,000 decoded a `TFTP` layer, a count small enough to vary by a few
|
|
816
|
+
between runs. The opcode alone lets through 6 in 65,536, about 8 of
|
|
817
|
+
90,000; of those, a DATA, ACK or OACK almost always decodes, but an RRQ
|
|
818
|
+
or WRQ needs two zero bytes after its opcode and an ERROR one after its
|
|
819
|
+
code, which random bytes lack about two thirds and one third of the
|
|
820
|
+
time, so about 6 are expected. What the port cannot do is find the
|
|
821
|
+
transfer. Only the request goes to port 69: the server answers from an
|
|
822
|
+
ephemeral port of its own, its transfer identifier, and every DATA, ACK,
|
|
823
|
+
OACK and ERROR after that runs between two ephemeral ports (RFC 1350
|
|
824
|
+
§4), which no port table can name. So a stateless walk decodes a `TFTP`
|
|
825
|
+
layer for the RRQ or WRQ alone, and stops at UDP for the rest of the
|
|
826
|
+
transfer, as for any datagram between unregistered ports; of the 33
|
|
827
|
+
frames in `tests/fixtures/tftp.pcap`, the 6 requests decode one. A
|
|
828
|
+
caller who follows the transfer has the server's port from the source
|
|
829
|
+
port of its first reply, and names it for the walk,
|
|
830
|
+
`decode_as={"udp.port": {tid: TFTP}}`, which covers both directions
|
|
831
|
+
since every later datagram has it as one of its two ports; tracking the
|
|
832
|
+
transfer is the caller's, as reassembly is for `HTTP` and `BGP`. A
|
|
833
|
+
server that answers from port 69 itself, which RFC 1350 does not allow,
|
|
834
|
+
has its replies dispatched by the source-port fallback.
|
|
835
|
+
|
|
836
|
+
NTP on UDP 123 (RFC 5905) rejects less: of the first byte's 256
|
|
837
|
+
values, 96 are a time message, a version from 1 to 4 and a mode other
|
|
838
|
+
than 6 or 7, the control messages (RFC 9327's mode 6, ntpd's private
|
|
839
|
+
mode 7) whose headers `NTP.decode()` does not read; anything shorter
|
|
840
|
+
than the 48-byte header is rejected too. Measured the same way, the
|
|
841
|
+
walk stopped for 61.2-62.9% of the 300-byte payloads (`random.Random`
|
|
842
|
+
seeds 0-2), against the 62.5% the first byte predicts, and for
|
|
843
|
+
65.5-66.3% of the 0-600 byte ones, padded or not: padding never makes
|
|
844
|
+
a payload 48 bytes long. Past the first byte any 47 bytes are a
|
|
845
|
+
header, and the stratum, the Reference ID and the timestamps are not
|
|
846
|
+
judged, so a Kiss-o'-Death and a reserved stratum decode.
|
|
847
|
+
|
|
848
|
+
The first byte is judged before the length, so every control message
|
|
849
|
+
raises `InvalidFieldError` with `field` `"mode"`, however long, and a
|
|
850
|
+
bad version raises with `field` `"version"`; only a time message's
|
|
851
|
+
first byte, or an empty buffer, can end in `TruncatedHeaderError`.
|
|
852
|
+
That makes real traffic fail a strict walk: `ntpq` (mode 6, a 12-byte
|
|
853
|
+
request and longer responses) and `ntpdc` (mode 7) talk to port 123,
|
|
854
|
+
and `decode_frame()` raises on every one of their messages. Walk them
|
|
855
|
+
with `lax=True`, which keeps Ethernet, IP and UDP and reports the
|
|
856
|
+
rejection as `stopped_by`. A typed way to take a port out of dispatch for one
|
|
857
|
+
walk, and decoding mode 6, are planned follow-ups.
|
|
858
|
+
|
|
859
|
+
HSRP on UDP 1985 (RFC 2281) rejects far more, though less than BGP and
|
|
860
|
+
STUN below: its first three bytes must be a Version of 0, one of the
|
|
861
|
+
three Op Codes (Hello, Coup, Resign) and one of the six States, which
|
|
862
|
+
18 of the 2^24 values of those bytes are, about one in 932,000, and
|
|
863
|
+
the payload must then hold the whole 20-byte message. Measured the
|
|
864
|
+
same way (`random.Random` seeds 0-2, each 10,000 random 300-byte
|
|
865
|
+
payloads and 10,000 of uniformly random length 0-600, the latter
|
|
866
|
+
walked both unpadded and padded: 90,000 walks to port 1985 in all),
|
|
867
|
+
about 0.1 of those walks are expected to decode an HSRP layer
|
|
868
|
+
(90,000 x 18 / 2^24 = 0.097, a little less in fact, since a few of the
|
|
869
|
+
random-length payloads are too short to reach 20 bytes), and 2 did:
|
|
870
|
+
the same 46-byte payload of seed 2, whose first
|
|
871
|
+
bytes, `00 00 04`, are a Hello in Speak, once unpadded and once padded.
|
|
872
|
+
The other 89,998 ended with `stopped_by` set. Padding cannot make a message,
|
|
873
|
+
since a minimum-size frame leaves 18 bytes after the UDP header. With
|
|
874
|
+
the Version forced to 0,
|
|
875
|
+
`HSRP.decode()` accepted 31 of 100,000 random 300-byte payloads
|
|
876
|
+
(`random.Random(0)`), near the 27 expected. Past those three bytes any
|
|
877
|
+
17 are a message: the timers, the Priority, the Group, the Reserved
|
|
878
|
+
byte, the Authentication Data and the Virtual IP Address are not
|
|
879
|
+
judged.
|
|
880
|
+
|
|
881
|
+
The guard is also what keeps HSRPv2 (Cisco's TLV-based successor,
|
|
882
|
+
sent to 224.0.0.102 on the same port) from being read as HSRPv1: an
|
|
883
|
+
HSRPv2 message starts with a TLV type, 1, where HSRPv1 has its
|
|
884
|
+
Version, so `HSRP.decode()` rejects every one at `version`, and it
|
|
885
|
+
rejects Cisco's Op Code 3 interface-state Advertise, version 0 but
|
|
886
|
+
laid out as a TLV, at `opcode`. Each byte is judged before the length,
|
|
887
|
+
so either is reported as what it is however short. Neither is decoded,
|
|
888
|
+
and as with NTP's control messages a strict walk raises on them: walk
|
|
889
|
+
such traffic with `lax=True`. Only 1985 is registered; HSRPv2 over
|
|
890
|
+
IPv6 uses port 2029, which nothing here decodes.
|
|
891
|
+
|
|
739
892
|
BGP on TCP 179 (RFC 4271) has the strongest guard of any port entry:
|
|
740
893
|
every message opens with a 16-byte Marker of all ones, which random
|
|
741
894
|
bytes match once in 2^128, and then a Length and Type whose bounds
|
|
@@ -770,6 +923,32 @@ offload off, carries 7. Reassembling
|
|
|
770
923
|
the stream is the caller's, as it is for `HTTP` below: see
|
|
771
924
|
[`layer7/bgp.py`](src/netprotocols/layer7/bgp.py)'s module docstring.
|
|
772
925
|
|
|
926
|
+
STUN on UDP and TCP 3478 (RFC 8489, RFC 5389) is guarded nearly as
|
|
927
|
+
well, by its fixed header: the two bits above the Message Type must be
|
|
928
|
+
zero, the 32-bit Magic Cookie `0x2112A442` must follow the Message
|
|
929
|
+
Length, and the Length must be a multiple of 4, so random bytes pass
|
|
930
|
+
once in 2^36, before the Length is held against the buffer. Measured
|
|
931
|
+
the same way, every walk to port 3478 ended with `stopped_by` set and
|
|
932
|
+
none decoded a STUN layer, over UDP for 10,000 random 300-byte payloads
|
|
933
|
+
and 10,000 of uniformly random length 0-600, padded or not, and over
|
|
934
|
+
TCP for 10,000 random 300-byte segments (`random.Random` seeds 0-2).
|
|
935
|
+
With the cookie forced in place, `STUN.decode()` accepted 28 of
|
|
936
|
+
100,000 random 300-byte payloads (`random.Random(0)`), near the 27
|
|
937
|
+
expected: a quarter have the two top bits clear, and 71 of the 65,536
|
|
938
|
+
Lengths are multiples of 4 that fit in the 280 bytes after the header.
|
|
939
|
+
The cookie is also what separates STUN from RFC 3489, its first
|
|
940
|
+
version, whose 16-byte transaction ID took the cookie's place:
|
|
941
|
+
`STUN.decode()` rejects a classic message at `magic_cookie`, which is
|
|
942
|
+
what RFC 5389 put the cookie there for. Over TCP, messages follow one
|
|
943
|
+
another with no framing but their own Length, as BGP's do, and chain
|
|
944
|
+
the same way, so `max_depth` bounds correctness here too: a message
|
|
945
|
+
can be a bare 20-byte header, the default leaves room for 29 after
|
|
946
|
+
Ethernet, IPv4 and TCP, and a 1448-byte segment holds 72, so a strict
|
|
947
|
+
walk of a valid segment can raise `MaxDepthExceededError` and a lax
|
|
948
|
+
one stop short. BGP's two ways past it work the same, with
|
|
949
|
+
`start=STUN`; the corpus's TCP segments carry 2. See
|
|
950
|
+
[`layer7/stun.py`](src/netprotocols/layer7/stun.py)'s module docstring.
|
|
951
|
+
|
|
773
952
|
A rejected guess takes the ordinary decode-error path: the chain keeps
|
|
774
953
|
the layers it did decode and records the failure. An accepted one
|
|
775
954
|
yields a layer that decoded cleanly and is wrong, and nothing in the
|
|
@@ -842,6 +1021,16 @@ one transport that does not use the internet checksum: its CRC32c
|
|
|
842
1021
|
(`crc32c()`, RFC 9260 Appendix A) covers the whole packet with no
|
|
843
1022
|
pseudo-header, and goes on the wire least significant byte first, so
|
|
844
1023
|
`compute()` returns it byte-swapped to match the field as decoded.
|
|
1024
|
+
STUN's FINGERPRINT is a checksum that lives in an attribute rather
|
|
1025
|
+
than a header field: the IEEE CRC-32 of the message up to it, XORed
|
|
1026
|
+
with `0x5354554E` (RFC 8489 §14.7). `compute()` returns it for a
|
|
1027
|
+
message whose last attribute is one, `verify()` accepts a message with
|
|
1028
|
+
none, and `with_checksums()` rewrites it. A message has none only when
|
|
1029
|
+
its attributes walk whole, none of them a FINGERPRINT, and its last 8
|
|
1030
|
+
bytes do not begin like one, so a corrupted earlier Length cannot hide
|
|
1031
|
+
it from `verify()`. MESSAGE-INTEGRITY, the keyed
|
|
1032
|
+
HMAC beside it, needs the credential's key, which this library never
|
|
1033
|
+
has, so it is carried raw, like an AH ICV.
|
|
845
1034
|
VRRP's checksum is the internet checksum of the message alone in
|
|
846
1035
|
VRRPv2 and behind the IP pseudo-header in VRRPv3. RFC 5798 §5.2.8
|
|
847
1036
|
cites only IPv6's pseudo-header; adding IPv4's too is keepalived's
|
|
@@ -849,6 +1038,20 @@ default, and `compute()`'s. RFC 9568, which obsoletes RFC 5798, leaves
|
|
|
849
1038
|
it out over IPv4, and `verify()` returns `False` for an advert
|
|
850
1039
|
checksummed that way.
|
|
851
1040
|
|
|
1041
|
+
Behind an IPv6 Routing header with segments left, RFC 8200 §8.1 puts
|
|
1042
|
+
the route's *final* destination in the pseudo-header, while `ip.dst`
|
|
1043
|
+
is the next hop. `compute()`, `verify()` and `flow_key()` take the
|
|
1044
|
+
Routing header as a keyword-only `routing`, and `Packet.with_checksums()`
|
|
1045
|
+
and `Packet.flow_key()` pass the last one with segments left between
|
|
1046
|
+
the nearest IP header and the transport (a receiver skips one with
|
|
1047
|
+
none left: RFC 8200 §4.4 for unrecognized types, and each type's own
|
|
1048
|
+
processing rules, RFC 2460 §4.4, RFC 6554 §4.2 and RFC 8754 §4.3, so
|
|
1049
|
+
the route ends at the last that has some).
|
|
1050
|
+
`IPv6Routing.final_destination(dst)` resolves it for types 0, 2, 3
|
|
1051
|
+
(RPL, from `dst`'s prefix) and 4 (SRH, Segment List[0]); for another
|
|
1052
|
+
type, malformed data, no segments left or IPv4 the address stays
|
|
1053
|
+
`ip.dst`.
|
|
1054
|
+
|
|
852
1055
|
That is also why `SCTP.decode()` bounds its own extent (see "The decode
|
|
853
1056
|
contract" above): otherwise Ethernet's padding would land inside the
|
|
854
1057
|
CRC's span, and a packet under 46 bytes from a real NIC would fail to
|
|
@@ -879,15 +1082,17 @@ src/netprotocols/
|
|
|
879
1082
|
├── __init__.py public API re-exports, __version__, registry install
|
|
880
1083
|
├── _base.py Protocol ABC, decode contract, address helpers
|
|
881
1084
|
├── _tlv.py walk_kind_length_value(): shared TCP/IPv4/IPv6
|
|
882
|
-
│ options
|
|
1085
|
+
│ options, PIM Hello options and STUN attributes
|
|
1086
|
+
│ TLV walker
|
|
883
1087
|
├── _enums.py EtherType, IPProtocol, ARPOperation (imports nothing)
|
|
884
1088
|
├── registry.py public dispatch tables: register(), Registry
|
|
885
1089
|
├── walk.py decode_frame(): the shipped chain walker
|
|
886
1090
|
├── _defaults.py the built-in decoder map, installed at import
|
|
887
1091
|
├── packet.py Packet composition, with_checksums(), flow_key()
|
|
888
1092
|
├── checksum.py RFC 1071 internet_checksum, SCTP's crc32c,
|
|
889
|
-
│ compute, verify (CDP's odd-byte sum
|
|
890
|
-
│ OSPF's LSA Fletcher
|
|
1093
|
+
│ compute, verify (CDP's odd-byte sum and STUN's
|
|
1094
|
+
│ FINGERPRINT among them), OSPF's LSA Fletcher
|
|
1095
|
+
│ checksum
|
|
891
1096
|
├── flow.py FlowKey, flow_key(): canonical bidirectional keys
|
|
892
1097
|
├── pcap.py read_captures()/read_pcap()/read_pcapng(): classic
|
|
893
1098
|
│ pcap and pcapng readers, from bytes not filenames
|
|
@@ -909,7 +1114,12 @@ src/netprotocols/
|
|
|
909
1114
|
│ dispatch)
|
|
910
1115
|
├── layer7/ dns.py, dhcp.py, http.py (the HTTP/1.1 grammar
|
|
911
1116
|
│ and the HTTP codec class), vxlan.py, rip.py
|
|
912
|
-
│ (RIPv1 + RIPv2), bgp.py (BGP-4 messages)
|
|
1117
|
+
│ (RIPv1 + RIPv2), bgp.py (BGP-4 messages),
|
|
1118
|
+
│ tftp.py (TFTP, with RFC 2347 options),
|
|
1119
|
+
│ radius.py (RADIUS + RADIUSAttribute),
|
|
1120
|
+
│ stun.py (STUN messages, over UDP and TCP),
|
|
1121
|
+
│ ntp.py (NTPv1-v4 time messages),
|
|
1122
|
+
│ hsrp.py (HSRPv1 Hello, Coup and Resign)
|
|
913
1123
|
└── utils/ validators (mac.py, ipv4.py), exceptions.py
|
|
914
1124
|
tests/ one file per protocol + test_contract.py
|
|
915
1125
|
(truncation, lying lengths, chain walks),
|