pypcapkit 1.3.3.post1__cp313-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pcapkit/__init__.py +126 -0
- pcapkit/__main__.py +138 -0
- pcapkit/all.py +136 -0
- pcapkit/const/__init__.py +81 -0
- pcapkit/const/arp/__init__.py +25 -0
- pcapkit/const/arp/hardware.py +181 -0
- pcapkit/const/arp/operation.py +131 -0
- pcapkit/const/ftp/__init__.py +25 -0
- pcapkit/const/ftp/command.py +309 -0
- pcapkit/const/ftp/return_code.py +304 -0
- pcapkit/const/hip/__init__.py +94 -0
- pcapkit/const/hip/certificate.py +77 -0
- pcapkit/const/hip/cipher.py +65 -0
- pcapkit/const/hip/di.py +59 -0
- pcapkit/const/hip/ecdsa_curve.py +59 -0
- pcapkit/const/hip/ecdsa_low_curve.py +56 -0
- pcapkit/const/hip/eddsa_curve.py +65 -0
- pcapkit/const/hip/esp_transform_suite.py +98 -0
- pcapkit/const/hip/group.py +86 -0
- pcapkit/const/hip/hi_algorithm.py +86 -0
- pcapkit/const/hip/hit_suite.py +68 -0
- pcapkit/const/hip/nat_traversal.py +62 -0
- pcapkit/const/hip/notify_message.py +200 -0
- pcapkit/const/hip/packet.py +89 -0
- pcapkit/const/hip/parameter.py +377 -0
- pcapkit/const/hip/registration.py +68 -0
- pcapkit/const/hip/registration_failure.py +84 -0
- pcapkit/const/hip/suite.py +71 -0
- pcapkit/const/hip/transport.py +59 -0
- pcapkit/const/http/__init__.py +39 -0
- pcapkit/const/http/error_code.py +95 -0
- pcapkit/const/http/frame.py +95 -0
- pcapkit/const/http/method.py +184 -0
- pcapkit/const/http/setting.py +96 -0
- pcapkit/const/http/status_code.py +294 -0
- pcapkit/const/ipv4/__init__.py +57 -0
- pcapkit/const/ipv4/classification_level.py +64 -0
- pcapkit/const/ipv4/option_class.py +55 -0
- pcapkit/const/ipv4/option_number.py +137 -0
- pcapkit/const/ipv4/protection_authority.py +63 -0
- pcapkit/const/ipv4/qs_function.py +51 -0
- pcapkit/const/ipv4/router_alert.py +251 -0
- pcapkit/const/ipv4/tos_del.py +51 -0
- pcapkit/const/ipv4/tos_ecn.py +55 -0
- pcapkit/const/ipv4/tos_pre.py +63 -0
- pcapkit/const/ipv4/tos_rel.py +51 -0
- pcapkit/const/ipv4/tos_thr.py +51 -0
- pcapkit/const/ipv4/ts_flag.py +53 -0
- pcapkit/const/ipv6/__init__.py +53 -0
- pcapkit/const/ipv6/extension_header.py +66 -0
- pcapkit/const/ipv6/option.py +137 -0
- pcapkit/const/ipv6/option_action.py +55 -0
- pcapkit/const/ipv6/qs_function.py +51 -0
- pcapkit/const/ipv6/router_alert.py +266 -0
- pcapkit/const/ipv6/routing.py +80 -0
- pcapkit/const/ipv6/seed_id.py +55 -0
- pcapkit/const/ipv6/smf_dpd_mode.py +51 -0
- pcapkit/const/ipv6/tagger_id.py +62 -0
- pcapkit/const/ipx/__init__.py +27 -0
- pcapkit/const/ipx/packet.py +72 -0
- pcapkit/const/ipx/socket.py +104 -0
- pcapkit/const/l2tp/__init__.py +21 -0
- pcapkit/const/l2tp/type.py +51 -0
- pcapkit/const/mh/__init__.py +204 -0
- pcapkit/const/mh/access_type.py +92 -0
- pcapkit/const/mh/ack_status_code.py +71 -0
- pcapkit/const/mh/ani_suboption.py +74 -0
- pcapkit/const/mh/auth_subtype.py +53 -0
- pcapkit/const/mh/binding_ack_flag.py +66 -0
- pcapkit/const/mh/binding_error.py +51 -0
- pcapkit/const/mh/binding_revocation.py +59 -0
- pcapkit/const/mh/binding_update_flag.py +81 -0
- pcapkit/const/mh/cga_extension.py +66 -0
- pcapkit/const/mh/cga_sec.py +57 -0
- pcapkit/const/mh/cga_type.py +68 -0
- pcapkit/const/mh/dhcp_support_mode.py +53 -0
- pcapkit/const/mh/dns_status_code.py +65 -0
- pcapkit/const/mh/dsmip6_tls_packet.py +62 -0
- pcapkit/const/mh/dsmipv6_home_address.py +74 -0
- pcapkit/const/mh/enumerating_algorithm.py +56 -0
- pcapkit/const/mh/fb_ack_status.py +62 -0
- pcapkit/const/mh/fb_action.py +71 -0
- pcapkit/const/mh/fb_indication_trigger.py +65 -0
- pcapkit/const/mh/fb_type.py +59 -0
- pcapkit/const/mh/flow_id_status.py +77 -0
- pcapkit/const/mh/flow_id_suboption.py +71 -0
- pcapkit/const/mh/handoff_type.py +71 -0
- pcapkit/const/mh/handover_ack_flag.py +54 -0
- pcapkit/const/mh/handover_ack_status.py +92 -0
- pcapkit/const/mh/handover_initiate_flag.py +57 -0
- pcapkit/const/mh/handover_initiate_status.py +62 -0
- pcapkit/const/mh/home_address_reply.py +71 -0
- pcapkit/const/mh/lla_code.py +63 -0
- pcapkit/const/mh/lma_mag_suboption.py +59 -0
- pcapkit/const/mh/mn_group_id.py +59 -0
- pcapkit/const/mh/mn_id_subtype.py +77 -0
- pcapkit/const/mh/operator_id.py +63 -0
- pcapkit/const/mh/option.py +260 -0
- pcapkit/const/mh/packet.py +119 -0
- pcapkit/const/mh/qos_attribute.py +89 -0
- pcapkit/const/mh/revocation_status_code.py +83 -0
- pcapkit/const/mh/revocation_trigger.py +86 -0
- pcapkit/const/mh/status_code.py +232 -0
- pcapkit/const/mh/traffic_selector.py +62 -0
- pcapkit/const/mh/upa_status.py +71 -0
- pcapkit/const/mh/upn_reason.py +80 -0
- pcapkit/const/ospf/__init__.py +27 -0
- pcapkit/const/ospf/authentication.py +65 -0
- pcapkit/const/ospf/packet.py +71 -0
- pcapkit/const/pcapng/__init__.py +51 -0
- pcapkit/const/pcapng/block_type.py +152 -0
- pcapkit/const/pcapng/filter_type.py +48 -0
- pcapkit/const/pcapng/hash_algorithm.py +59 -0
- pcapkit/const/pcapng/option_type.py +233 -0
- pcapkit/const/pcapng/record_type.py +57 -0
- pcapkit/const/pcapng/secrets_type.py +56 -0
- pcapkit/const/pcapng/verdict_type.py +53 -0
- pcapkit/const/reg/__init__.py +34 -0
- pcapkit/const/reg/apptype.py +32702 -0
- pcapkit/const/reg/ethertype.py +714 -0
- pcapkit/const/reg/linktype.py +902 -0
- pcapkit/const/reg/transtype.py +523 -0
- pcapkit/const/tcp/__init__.py +35 -0
- pcapkit/const/tcp/checksum.py +55 -0
- pcapkit/const/tcp/flags.py +73 -0
- pcapkit/const/tcp/mp_tcp_option.py +80 -0
- pcapkit/const/tcp/option.py +198 -0
- pcapkit/const/vlan/__init__.py +23 -0
- pcapkit/const/vlan/priority_level.py +71 -0
- pcapkit/corekit/__init__.py +59 -0
- pcapkit/corekit/fields/__init__.py +45 -0
- pcapkit/corekit/fields/collections.py +282 -0
- pcapkit/corekit/fields/field.py +269 -0
- pcapkit/corekit/fields/ipaddress.py +274 -0
- pcapkit/corekit/fields/misc.py +722 -0
- pcapkit/corekit/fields/numbers.py +375 -0
- pcapkit/corekit/fields/strings.py +245 -0
- pcapkit/corekit/infoclass.py +394 -0
- pcapkit/corekit/io.py +506 -0
- pcapkit/corekit/module.py +39 -0
- pcapkit/corekit/multidict.py +626 -0
- pcapkit/corekit/protochain.py +263 -0
- pcapkit/corekit/version.py +33 -0
- pcapkit/dumpkit/__init__.py +15 -0
- pcapkit/dumpkit/common.py +199 -0
- pcapkit/dumpkit/null.py +77 -0
- pcapkit/dumpkit/pcap.py +144 -0
- pcapkit/foundation/__init__.py +45 -0
- pcapkit/foundation/engines/__init__.py +36 -0
- pcapkit/foundation/engines/dpkt.py +230 -0
- pcapkit/foundation/engines/engine.py +194 -0
- pcapkit/foundation/engines/pcap.py +188 -0
- pcapkit/foundation/engines/pcapng.py +310 -0
- pcapkit/foundation/engines/pyshark.py +166 -0
- pcapkit/foundation/engines/scapy.py +161 -0
- pcapkit/foundation/extraction.py +915 -0
- pcapkit/foundation/reassembly/__init__.py +49 -0
- pcapkit/foundation/reassembly/data/__init__.py +48 -0
- pcapkit/foundation/reassembly/data/ip.py +117 -0
- pcapkit/foundation/reassembly/data/tcp.py +145 -0
- pcapkit/foundation/reassembly/ip.py +192 -0
- pcapkit/foundation/reassembly/ipv4.py +50 -0
- pcapkit/foundation/reassembly/ipv6.py +50 -0
- pcapkit/foundation/reassembly/reassembly.py +389 -0
- pcapkit/foundation/reassembly/tcp.py +249 -0
- pcapkit/foundation/registry/__init__.py +41 -0
- pcapkit/foundation/registry/foundation.py +327 -0
- pcapkit/foundation/registry/protocols.py +885 -0
- pcapkit/foundation/traceflow/__init__.py +44 -0
- pcapkit/foundation/traceflow/data/__init__.py +30 -0
- pcapkit/foundation/traceflow/data/tcp.py +105 -0
- pcapkit/foundation/traceflow/tcp.py +159 -0
- pcapkit/foundation/traceflow/traceflow.py +390 -0
- pcapkit/interface/__init__.py +22 -0
- pcapkit/interface/core.py +185 -0
- pcapkit/interface/misc.py +120 -0
- pcapkit/protocols/__init__.py +85 -0
- pcapkit/protocols/application/NotImplemented/bgp.py +0 -0
- pcapkit/protocols/application/NotImplemented/dhcp.py +0 -0
- pcapkit/protocols/application/NotImplemented/dhcpv6.py +0 -0
- pcapkit/protocols/application/NotImplemented/dns.py +0 -0
- pcapkit/protocols/application/NotImplemented/imap.py +0 -0
- pcapkit/protocols/application/NotImplemented/ldap.py +0 -0
- pcapkit/protocols/application/NotImplemented/mqtt.py +0 -0
- pcapkit/protocols/application/NotImplemented/nntp.py +0 -0
- pcapkit/protocols/application/NotImplemented/ntp.py +0 -0
- pcapkit/protocols/application/NotImplemented/onc_rpc.py +0 -0
- pcapkit/protocols/application/NotImplemented/pop.py +0 -0
- pcapkit/protocols/application/NotImplemented/rip.py +0 -0
- pcapkit/protocols/application/NotImplemented/rtp.py +0 -0
- pcapkit/protocols/application/NotImplemented/sip.py +0 -0
- pcapkit/protocols/application/NotImplemented/smtp.py +0 -0
- pcapkit/protocols/application/NotImplemented/snmp.py +0 -0
- pcapkit/protocols/application/NotImplemented/ssh.py +0 -0
- pcapkit/protocols/application/NotImplemented/telnet.py +0 -0
- pcapkit/protocols/application/NotImplemented/tls.py +0 -0
- pcapkit/protocols/application/NotImplemented/xmpp.py +0 -0
- pcapkit/protocols/application/__init__.py +34 -0
- pcapkit/protocols/application/application.py +114 -0
- pcapkit/protocols/application/ftp.py +206 -0
- pcapkit/protocols/application/http.py +176 -0
- pcapkit/protocols/application/httpv1.py +320 -0
- pcapkit/protocols/application/httpv2.py +1255 -0
- pcapkit/protocols/data/__init__.py +192 -0
- pcapkit/protocols/data/application/__init__.py +57 -0
- pcapkit/protocols/data/application/ftp.py +59 -0
- pcapkit/protocols/data/application/httpv1.py +79 -0
- pcapkit/protocols/data/application/httpv2.py +293 -0
- pcapkit/protocols/data/data.py +25 -0
- pcapkit/protocols/data/internet/__init__.py +298 -0
- pcapkit/protocols/data/internet/ah.py +31 -0
- pcapkit/protocols/data/internet/hip.py +804 -0
- pcapkit/protocols/data/internet/hopopt.py +351 -0
- pcapkit/protocols/data/internet/ipv4.py +369 -0
- pcapkit/protocols/data/internet/ipv6.py +67 -0
- pcapkit/protocols/data/internet/ipv6_frag.py +29 -0
- pcapkit/protocols/data/internet/ipv6_opts.py +368 -0
- pcapkit/protocols/data/internet/ipv6_route.py +86 -0
- pcapkit/protocols/data/internet/ipx.py +56 -0
- pcapkit/protocols/data/internet/mh.py +509 -0
- pcapkit/protocols/data/link/__init__.py +33 -0
- pcapkit/protocols/data/link/arp.py +74 -0
- pcapkit/protocols/data/link/ethernet.py +28 -0
- pcapkit/protocols/data/link/l2tp.py +63 -0
- pcapkit/protocols/data/link/ospf.py +58 -0
- pcapkit/protocols/data/link/vlan.py +42 -0
- pcapkit/protocols/data/misc/__init__.py +109 -0
- pcapkit/protocols/data/misc/null.py +18 -0
- pcapkit/protocols/data/misc/pcap/__init__.py +18 -0
- pcapkit/protocols/data/misc/pcap/frame.py +56 -0
- pcapkit/protocols/data/misc/pcap/header.py +53 -0
- pcapkit/protocols/data/misc/pcapng.py +925 -0
- pcapkit/protocols/data/misc/raw.py +25 -0
- pcapkit/protocols/data/protocol.py +32 -0
- pcapkit/protocols/data/transport/__init__.py +71 -0
- pcapkit/protocols/data/transport/tcp.py +555 -0
- pcapkit/protocols/data/transport/udp.py +29 -0
- pcapkit/protocols/internet/NotImplemented/ecn.py +0 -0
- pcapkit/protocols/internet/NotImplemented/esp.py +97 -0
- pcapkit/protocols/internet/NotImplemented/icmp.py +0 -0
- pcapkit/protocols/internet/NotImplemented/icmpv6.py +0 -0
- pcapkit/protocols/internet/NotImplemented/igmp.py +0 -0
- pcapkit/protocols/internet/NotImplemented/shim6.py +0 -0
- pcapkit/protocols/internet/__init__.py +43 -0
- pcapkit/protocols/internet/ah.py +275 -0
- pcapkit/protocols/internet/hip.py +4727 -0
- pcapkit/protocols/internet/hopopt.py +1879 -0
- pcapkit/protocols/internet/internet.py +240 -0
- pcapkit/protocols/internet/ip.py +51 -0
- pcapkit/protocols/internet/ipsec.py +50 -0
- pcapkit/protocols/internet/ipv4.py +1782 -0
- pcapkit/protocols/internet/ipv6.py +361 -0
- pcapkit/protocols/internet/ipv6_frag.py +258 -0
- pcapkit/protocols/internet/ipv6_opts.py +1890 -0
- pcapkit/protocols/internet/ipv6_route.py +710 -0
- pcapkit/protocols/internet/ipx.py +230 -0
- pcapkit/protocols/internet/mh.py +2764 -0
- pcapkit/protocols/link/NotImplemented/dsl.py +0 -0
- pcapkit/protocols/link/NotImplemented/eapol.py +1 -0
- pcapkit/protocols/link/NotImplemented/fddi.py +0 -0
- pcapkit/protocols/link/NotImplemented/isdn.py +0 -0
- pcapkit/protocols/link/NotImplemented/ndp.py +0 -0
- pcapkit/protocols/link/NotImplemented/ppp.py +0 -0
- pcapkit/protocols/link/__init__.py +35 -0
- pcapkit/protocols/link/arp.py +421 -0
- pcapkit/protocols/link/ethernet.py +248 -0
- pcapkit/protocols/link/l2tp.py +267 -0
- pcapkit/protocols/link/link.py +140 -0
- pcapkit/protocols/link/ospf.py +342 -0
- pcapkit/protocols/link/rarp.py +82 -0
- pcapkit/protocols/link/vlan.py +225 -0
- pcapkit/protocols/misc/__init__.py +37 -0
- pcapkit/protocols/misc/null.py +129 -0
- pcapkit/protocols/misc/pcap/__init__.py +17 -0
- pcapkit/protocols/misc/pcap/frame.py +478 -0
- pcapkit/protocols/misc/pcap/header.py +358 -0
- pcapkit/protocols/misc/pcapng.py +5520 -0
- pcapkit/protocols/misc/raw.py +180 -0
- pcapkit/protocols/protocol.py +1216 -0
- pcapkit/protocols/schema/__init__.py +140 -0
- pcapkit/protocols/schema/application/__init__.py +40 -0
- pcapkit/protocols/schema/application/ftp.py +21 -0
- pcapkit/protocols/schema/application/httpv1.py +21 -0
- pcapkit/protocols/schema/application/httpv2.py +384 -0
- pcapkit/protocols/schema/internet/__init__.py +294 -0
- pcapkit/protocols/schema/internet/ah.py +40 -0
- pcapkit/protocols/schema/internet/hip.py +1184 -0
- pcapkit/protocols/schema/internet/hopopt.py +679 -0
- pcapkit/protocols/schema/internet/ipv4.py +576 -0
- pcapkit/protocols/schema/internet/ipv6.py +63 -0
- pcapkit/protocols/schema/internet/ipv6_frag.py +48 -0
- pcapkit/protocols/schema/internet/ipv6_opts.py +680 -0
- pcapkit/protocols/schema/internet/ipv6_route.py +198 -0
- pcapkit/protocols/schema/internet/ipx.py +40 -0
- pcapkit/protocols/schema/internet/mh.py +718 -0
- pcapkit/protocols/schema/link/__init__.py +19 -0
- pcapkit/protocols/schema/link/arp.py +39 -0
- pcapkit/protocols/schema/link/ethernet.py +51 -0
- pcapkit/protocols/schema/link/l2tp.py +88 -0
- pcapkit/protocols/schema/link/ospf.py +90 -0
- pcapkit/protocols/schema/link/vlan.py +69 -0
- pcapkit/protocols/schema/misc/__init__.py +108 -0
- pcapkit/protocols/schema/misc/null.py +18 -0
- pcapkit/protocols/schema/misc/pcap/__init__.py +10 -0
- pcapkit/protocols/schema/misc/pcap/frame.py +51 -0
- pcapkit/protocols/schema/misc/pcap/header.py +63 -0
- pcapkit/protocols/schema/misc/pcapng.py +1689 -0
- pcapkit/protocols/schema/misc/raw.py +24 -0
- pcapkit/protocols/schema/schema.py +809 -0
- pcapkit/protocols/schema/transport/__init__.py +69 -0
- pcapkit/protocols/schema/transport/tcp.py +928 -0
- pcapkit/protocols/schema/transport/udp.py +90 -0
- pcapkit/protocols/transport/NotImplemented/dccp.py +0 -0
- pcapkit/protocols/transport/NotImplemented/rsvp.py +0 -0
- pcapkit/protocols/transport/NotImplemented/sctp.py +0 -0
- pcapkit/protocols/transport/__init__.py +27 -0
- pcapkit/protocols/transport/tcp.py +3025 -0
- pcapkit/protocols/transport/transport.py +158 -0
- pcapkit/protocols/transport/udp.py +214 -0
- pcapkit/py.typed +0 -0
- pcapkit/toolkit/__init__.py +57 -0
- pcapkit/toolkit/dpkt.py +306 -0
- pcapkit/toolkit/pcap.py +212 -0
- pcapkit/toolkit/pcapng.py +251 -0
- pcapkit/toolkit/pyshark.py +99 -0
- pcapkit/toolkit/scapy.py +297 -0
- pcapkit/utilities/__init__.py +20 -0
- pcapkit/utilities/compat.py +196 -0
- pcapkit/utilities/decorators.py +192 -0
- pcapkit/utilities/exceptions.py +365 -0
- pcapkit/utilities/logging.py +55 -0
- pcapkit/utilities/warnings.py +185 -0
- pcapkit/vendor/__init__.py +105 -0
- pcapkit/vendor/__main__.py +92 -0
- pcapkit/vendor/arp/__init__.py +27 -0
- pcapkit/vendor/arp/hardware.py +29 -0
- pcapkit/vendor/arp/operation.py +29 -0
- pcapkit/vendor/default.py +474 -0
- pcapkit/vendor/ftp/__init__.py +27 -0
- pcapkit/vendor/ftp/command.py +244 -0
- pcapkit/vendor/ftp/return_code.py +256 -0
- pcapkit/vendor/hip/__init__.py +94 -0
- pcapkit/vendor/hip/certificate.py +29 -0
- pcapkit/vendor/hip/cipher.py +29 -0
- pcapkit/vendor/hip/di.py +29 -0
- pcapkit/vendor/hip/ecdsa_curve.py +29 -0
- pcapkit/vendor/hip/ecdsa_low_curve.py +29 -0
- pcapkit/vendor/hip/eddsa_curve.py +85 -0
- pcapkit/vendor/hip/esp_transform_suite.py +29 -0
- pcapkit/vendor/hip/group.py +87 -0
- pcapkit/vendor/hip/hi_algorithm.py +29 -0
- pcapkit/vendor/hip/hit_suite.py +29 -0
- pcapkit/vendor/hip/nat_traversal.py +29 -0
- pcapkit/vendor/hip/notify_message.py +29 -0
- pcapkit/vendor/hip/packet.py +88 -0
- pcapkit/vendor/hip/parameter.py +88 -0
- pcapkit/vendor/hip/registration.py +29 -0
- pcapkit/vendor/hip/registration_failure.py +29 -0
- pcapkit/vendor/hip/suite.py +29 -0
- pcapkit/vendor/hip/transport.py +29 -0
- pcapkit/vendor/http/__init__.py +39 -0
- pcapkit/vendor/http/error_code.py +95 -0
- pcapkit/vendor/http/frame.py +91 -0
- pcapkit/vendor/http/method.py +167 -0
- pcapkit/vendor/http/setting.py +93 -0
- pcapkit/vendor/http/status_code.py +185 -0
- pcapkit/vendor/ipv4/__init__.py +57 -0
- pcapkit/vendor/ipv4/classification_level.py +91 -0
- pcapkit/vendor/ipv4/option_class.py +80 -0
- pcapkit/vendor/ipv4/option_number.py +105 -0
- pcapkit/vendor/ipv4/protection_authority.py +84 -0
- pcapkit/vendor/ipv4/qs_function.py +78 -0
- pcapkit/vendor/ipv4/router_alert.py +93 -0
- pcapkit/vendor/ipv4/tos_del.py +78 -0
- pcapkit/vendor/ipv4/tos_ecn.py +95 -0
- pcapkit/vendor/ipv4/tos_pre.py +84 -0
- pcapkit/vendor/ipv4/tos_rel.py +78 -0
- pcapkit/vendor/ipv4/tos_thr.py +77 -0
- pcapkit/vendor/ipv4/ts_flag.py +79 -0
- pcapkit/vendor/ipv6/__init__.py +53 -0
- pcapkit/vendor/ipv6/extension_header.py +171 -0
- pcapkit/vendor/ipv6/option.py +104 -0
- pcapkit/vendor/ipv6/option_action.py +90 -0
- pcapkit/vendor/ipv6/qs_function.py +78 -0
- pcapkit/vendor/ipv6/router_alert.py +93 -0
- pcapkit/vendor/ipv6/routing.py +87 -0
- pcapkit/vendor/ipv6/seed_id.py +81 -0
- pcapkit/vendor/ipv6/smf_dpd_mode.py +78 -0
- pcapkit/vendor/ipv6/tagger_id.py +81 -0
- pcapkit/vendor/ipx/__init__.py +37 -0
- pcapkit/vendor/ipx/packet.py +123 -0
- pcapkit/vendor/ipx/socket.py +125 -0
- pcapkit/vendor/l2tp/__init__.py +21 -0
- pcapkit/vendor/l2tp/type.py +78 -0
- pcapkit/vendor/mh/__init__.py +204 -0
- pcapkit/vendor/mh/access_type.py +87 -0
- pcapkit/vendor/mh/ack_status_code.py +88 -0
- pcapkit/vendor/mh/ani_suboption.py +88 -0
- pcapkit/vendor/mh/auth_subtype.py +83 -0
- pcapkit/vendor/mh/binding_ack_flag.py +148 -0
- pcapkit/vendor/mh/binding_error.py +78 -0
- pcapkit/vendor/mh/binding_revocation.py +87 -0
- pcapkit/vendor/mh/binding_update_flag.py +147 -0
- pcapkit/vendor/mh/cga_extension.py +91 -0
- pcapkit/vendor/mh/cga_sec.py +91 -0
- pcapkit/vendor/mh/cga_type.py +74 -0
- pcapkit/vendor/mh/dhcp_support_mode.py +77 -0
- pcapkit/vendor/mh/dns_status_code.py +87 -0
- pcapkit/vendor/mh/dsmip6_tls_packet.py +87 -0
- pcapkit/vendor/mh/dsmipv6_home_address.py +87 -0
- pcapkit/vendor/mh/enumerating_algorithm.py +82 -0
- pcapkit/vendor/mh/fb_ack_status.py +87 -0
- pcapkit/vendor/mh/fb_action.py +88 -0
- pcapkit/vendor/mh/fb_indication_trigger.py +87 -0
- pcapkit/vendor/mh/fb_type.py +88 -0
- pcapkit/vendor/mh/flow_id_status.py +87 -0
- pcapkit/vendor/mh/flow_id_suboption.py +87 -0
- pcapkit/vendor/mh/handoff_type.py +87 -0
- pcapkit/vendor/mh/handover_ack_flag.py +143 -0
- pcapkit/vendor/mh/handover_ack_status.py +87 -0
- pcapkit/vendor/mh/handover_initiate_flag.py +143 -0
- pcapkit/vendor/mh/handover_initiate_status.py +87 -0
- pcapkit/vendor/mh/home_address_reply.py +87 -0
- pcapkit/vendor/mh/lla_code.py +97 -0
- pcapkit/vendor/mh/lma_mag_suboption.py +88 -0
- pcapkit/vendor/mh/mn_group_id.py +87 -0
- pcapkit/vendor/mh/mn_id_subtype.py +87 -0
- pcapkit/vendor/mh/operator_id.py +87 -0
- pcapkit/vendor/mh/option.py +83 -0
- pcapkit/vendor/mh/packet.py +82 -0
- pcapkit/vendor/mh/qos_attribute.py +87 -0
- pcapkit/vendor/mh/revocation_status_code.py +87 -0
- pcapkit/vendor/mh/revocation_trigger.py +87 -0
- pcapkit/vendor/mh/status_code.py +91 -0
- pcapkit/vendor/mh/traffic_selector.py +87 -0
- pcapkit/vendor/mh/upa_status.py +87 -0
- pcapkit/vendor/mh/upn_reason.py +87 -0
- pcapkit/vendor/ospf/__init__.py +27 -0
- pcapkit/vendor/ospf/authentication.py +29 -0
- pcapkit/vendor/ospf/packet.py +29 -0
- pcapkit/vendor/pcapng/__init__.py +51 -0
- pcapkit/vendor/pcapng/block_type.py +94 -0
- pcapkit/vendor/pcapng/filter_type.py +77 -0
- pcapkit/vendor/pcapng/hash_algorithm.py +82 -0
- pcapkit/vendor/pcapng/option_type.py +287 -0
- pcapkit/vendor/pcapng/record_type.py +81 -0
- pcapkit/vendor/pcapng/secrets_type.py +81 -0
- pcapkit/vendor/pcapng/verdict_type.py +79 -0
- pcapkit/vendor/reg/__init__.py +34 -0
- pcapkit/vendor/reg/apptype.py +338 -0
- pcapkit/vendor/reg/ethertype.py +121 -0
- pcapkit/vendor/reg/linktype.py +110 -0
- pcapkit/vendor/reg/transtype.py +111 -0
- pcapkit/vendor/tcp/__init__.py +35 -0
- pcapkit/vendor/tcp/checksum.py +80 -0
- pcapkit/vendor/tcp/flags.py +149 -0
- pcapkit/vendor/tcp/mp_tcp_option.py +90 -0
- pcapkit/vendor/tcp/option.py +103 -0
- pcapkit/vendor/vlan/__init__.py +23 -0
- pcapkit/vendor/vlan/priority_level.py +97 -0
- pypcapkit-1.3.3.post1.dist-info/LICENSE +29 -0
- pypcapkit-1.3.3.post1.dist-info/METADATA +236 -0
- pypcapkit-1.3.3.post1.dist-info/RECORD +466 -0
- pypcapkit-1.3.3.post1.dist-info/WHEEL +5 -0
- pypcapkit-1.3.3.post1.dist-info/entry_points.txt +3 -0
- pypcapkit-1.3.3.post1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1879 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""HOPOPT - IPv6 Hop-by-Hop Options
|
3
|
+
======================================
|
4
|
+
|
5
|
+
.. module:: pcapkit.protocols.internet.hopopt
|
6
|
+
|
7
|
+
:mod:`pcapkit.protocols.internet.hopopt` contains
|
8
|
+
:class:`~pcapkit.protocols.internet.hopopt.HOPOPT`
|
9
|
+
only, which implements extractor for IPv6 Hop-by-Hop
|
10
|
+
Options header (HOPOPT) [*]_, whose structure is
|
11
|
+
described as below:
|
12
|
+
|
13
|
+
======= ========= =================== =================================
|
14
|
+
Octets Bits Name Description
|
15
|
+
======= ========= =================== =================================
|
16
|
+
0 0 ``hopopt.next`` Next Header
|
17
|
+
1 8 ``hopopt.length`` Header Extensive Length
|
18
|
+
2 16 ``hopopt.options`` Options
|
19
|
+
======= ========= =================== =================================
|
20
|
+
|
21
|
+
.. [*] https://en.wikipedia.org/wiki/IPv6_packet#Hop-by-hop_options_and_destination_options
|
22
|
+
|
23
|
+
"""
|
24
|
+
import collections
|
25
|
+
import datetime
|
26
|
+
import ipaddress
|
27
|
+
import math
|
28
|
+
from typing import TYPE_CHECKING, cast, overload
|
29
|
+
|
30
|
+
from pcapkit.const.ipv6.option import Option as Enum_Option
|
31
|
+
from pcapkit.const.ipv6.option_action import OptionAction as Enum_OptionAction
|
32
|
+
from pcapkit.const.ipv6.qs_function import QSFunction as Enum_QSFunction
|
33
|
+
from pcapkit.const.ipv6.router_alert import RouterAlert as Enum_RouterAlert
|
34
|
+
from pcapkit.const.ipv6.seed_id import SeedID as Enum_SeedID
|
35
|
+
from pcapkit.const.ipv6.smf_dpd_mode import SMFDPDMode as Enum_SMFDPDMode
|
36
|
+
from pcapkit.const.ipv6.tagger_id import TaggerID as Enum_TaggerID
|
37
|
+
from pcapkit.const.reg.transtype import TransType as Enum_TransType
|
38
|
+
from pcapkit.corekit.fields.field import NoValue
|
39
|
+
from pcapkit.corekit.multidict import OrderedMultiDict
|
40
|
+
from pcapkit.protocols.data.internet.hopopt import HOPOPT as Data_HOPOPT
|
41
|
+
from pcapkit.protocols.data.internet.hopopt import CALIPSOOption as Data_CALIPSOOption
|
42
|
+
from pcapkit.protocols.data.internet.hopopt import DFFFlags as Data_DFFFlags
|
43
|
+
from pcapkit.protocols.data.internet.hopopt import HomeAddressOption as Data_HomeAddressOption
|
44
|
+
from pcapkit.protocols.data.internet.hopopt import ILNPOption as Data_ILNPOption
|
45
|
+
from pcapkit.protocols.data.internet.hopopt import IPDFFOption as Data_IPDFFOption
|
46
|
+
from pcapkit.protocols.data.internet.hopopt import JumboPayloadOption as Data_JumboPayloadOption
|
47
|
+
from pcapkit.protocols.data.internet.hopopt import \
|
48
|
+
LineIdentificationOption as Data_LineIdentificationOption
|
49
|
+
from pcapkit.protocols.data.internet.hopopt import MPLFlags as Data_MPLFlags
|
50
|
+
from pcapkit.protocols.data.internet.hopopt import MPLOption as Data_MPLOption
|
51
|
+
from pcapkit.protocols.data.internet.hopopt import PadOption as Data_PadOption
|
52
|
+
from pcapkit.protocols.data.internet.hopopt import PDMOption as Data_PDMOption
|
53
|
+
from pcapkit.protocols.data.internet.hopopt import \
|
54
|
+
QuickStartReportOption as Data_QuickStartReportOption
|
55
|
+
from pcapkit.protocols.data.internet.hopopt import \
|
56
|
+
QuickStartRequestOption as Data_QuickStartRequestOption
|
57
|
+
from pcapkit.protocols.data.internet.hopopt import RouterAlertOption as Data_RouterAlertOption
|
58
|
+
from pcapkit.protocols.data.internet.hopopt import RPLFlags as Data_RPLFlags
|
59
|
+
from pcapkit.protocols.data.internet.hopopt import RPLOption as Data_RPLOption
|
60
|
+
from pcapkit.protocols.data.internet.hopopt import \
|
61
|
+
SMFHashBasedDPDOption as Data_SMFHashBasedDPDOption
|
62
|
+
from pcapkit.protocols.data.internet.hopopt import \
|
63
|
+
SMFIdentificationBasedDPDOption as Data_SMFIdentificationBasedDPDOption
|
64
|
+
from pcapkit.protocols.data.internet.hopopt import \
|
65
|
+
TunnelEncapsulationLimitOption as Data_TunnelEncapsulationLimitOption
|
66
|
+
from pcapkit.protocols.data.internet.hopopt import UnassignedOption as Data_UnassignedOption
|
67
|
+
from pcapkit.protocols.internet.internet import Internet
|
68
|
+
from pcapkit.protocols.schema.internet.hopopt import HOPOPT as Schema_HOPOPT
|
69
|
+
from pcapkit.protocols.schema.internet.hopopt import CALIPSOOption as Schema_CALIPSOOption
|
70
|
+
from pcapkit.protocols.schema.internet.hopopt import HomeAddressOption as Schema_HomeAddressOption
|
71
|
+
from pcapkit.protocols.schema.internet.hopopt import ILNPOption as Schema_ILNPOption
|
72
|
+
from pcapkit.protocols.schema.internet.hopopt import IPDFFOption as Schema_IPDFFOption
|
73
|
+
from pcapkit.protocols.schema.internet.hopopt import JumboPayloadOption as Schema_JumboPayloadOption
|
74
|
+
from pcapkit.protocols.schema.internet.hopopt import \
|
75
|
+
LineIdentificationOption as Schema_LineIdentificationOption
|
76
|
+
from pcapkit.protocols.schema.internet.hopopt import MPLOption as Schema_MPLOption
|
77
|
+
from pcapkit.protocols.schema.internet.hopopt import PadOption as Schema_PadOption
|
78
|
+
from pcapkit.protocols.schema.internet.hopopt import PDMOption as Schema_PDMOption
|
79
|
+
from pcapkit.protocols.schema.internet.hopopt import \
|
80
|
+
QuickStartReportOption as Schema_QuickStartReportOption
|
81
|
+
from pcapkit.protocols.schema.internet.hopopt import \
|
82
|
+
QuickStartRequestOption as Schema_QuickStartRequestOption
|
83
|
+
from pcapkit.protocols.schema.internet.hopopt import RouterAlertOption as Schema_RouterAlertOption
|
84
|
+
from pcapkit.protocols.schema.internet.hopopt import RPLOption as Schema_RPLOption
|
85
|
+
from pcapkit.protocols.schema.internet.hopopt import \
|
86
|
+
SMFHashBasedDPDOption as Schema_SMFHashBasedDPDOption
|
87
|
+
from pcapkit.protocols.schema.internet.hopopt import \
|
88
|
+
SMFIdentificationBasedDPDOption as Schema_SMFIdentificationBasedDPDOption
|
89
|
+
from pcapkit.protocols.schema.internet.hopopt import \
|
90
|
+
TunnelEncapsulationLimitOption as Schema_TunnelEncapsulationLimitOption
|
91
|
+
from pcapkit.protocols.schema.internet.hopopt import UnassignedOption as Schema_UnassignedOption
|
92
|
+
from pcapkit.protocols.schema.schema import Schema
|
93
|
+
from pcapkit.utilities.exceptions import ProtocolError, UnsupportedCall
|
94
|
+
from pcapkit.utilities.warnings import ProtocolWarning, RegistryWarning, warn
|
95
|
+
|
96
|
+
if TYPE_CHECKING:
|
97
|
+
from datetime import timedelta
|
98
|
+
from enum import IntEnum as StdlibEnum
|
99
|
+
from ipaddress import IPv4Address, IPv6Address
|
100
|
+
from typing import IO, Any, Callable, DefaultDict, NoReturn, Optional, Type
|
101
|
+
|
102
|
+
from aenum import IntEnum as AenumEnum
|
103
|
+
from mypy_extensions import DefaultArg, KwArg, NamedArg
|
104
|
+
from typing_extensions import Literal
|
105
|
+
|
106
|
+
from pcapkit.corekit.protochain import ProtoChain
|
107
|
+
from pcapkit.protocols.data.internet.hopopt import Option as Data_Option
|
108
|
+
from pcapkit.protocols.data.internet.hopopt import QuickStartOption as Data_QuickStartOption
|
109
|
+
from pcapkit.protocols.data.internet.hopopt import SMFDPDOption as Data_SMFDPDOption
|
110
|
+
from pcapkit.protocols.protocol import ProtocolBase as Protocol
|
111
|
+
from pcapkit.protocols.schema.internet.hopopt import Option as Schema_Option
|
112
|
+
from pcapkit.protocols.schema.internet.hopopt import QuickStartOption as Schema_QuickStartOption
|
113
|
+
from pcapkit.protocols.schema.internet.hopopt import SMFDPDOption as Schema_SMFDPDOption
|
114
|
+
|
115
|
+
Option = OrderedMultiDict[Enum_Option, Data_Option]
|
116
|
+
OptionParser = Callable[[Schema_Option, NamedArg(Option, 'options')], Data_Option]
|
117
|
+
OptionConstructor = Callable[[Enum_Option,
|
118
|
+
DefaultArg(Optional[Data_Option]), KwArg(Any)], Schema_Option]
|
119
|
+
|
120
|
+
__all__ = ['HOPOPT']
|
121
|
+
|
122
|
+
|
123
|
+
class HOPOPT(Internet[Data_HOPOPT, Schema_HOPOPT],
|
124
|
+
schema=Schema_HOPOPT, data=Data_HOPOPT):
|
125
|
+
"""This class implements IPv6 Hop-by-Hop Options.
|
126
|
+
|
127
|
+
This class currently supports parsing of the following IPv6 Hop-by-Hop
|
128
|
+
options, which are registered in the :attr:`self.__option__ <pcapkit.protocols.internet.hopopt.HOPOPT.__option__>`
|
129
|
+
attribute:
|
130
|
+
|
131
|
+
.. list-table::
|
132
|
+
:header-rows: 1
|
133
|
+
|
134
|
+
* - Option Code
|
135
|
+
- Option Parser
|
136
|
+
- Option Constructor
|
137
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.Pad1`
|
138
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_pad`
|
139
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_pad`
|
140
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.PadN`
|
141
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_pad`
|
142
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_pad`
|
143
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.Tunnel_Encapsulation_Limit`
|
144
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_tun`
|
145
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_tun`
|
146
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.Router_Alert`
|
147
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_ra`
|
148
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_ra`
|
149
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.CALIPSO`
|
150
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_calipso`
|
151
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_calipso`
|
152
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.SMF_DPD`
|
153
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_smf_dpd`
|
154
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_smf_dpd`
|
155
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.PDM`
|
156
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_pdm`
|
157
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_pdm`
|
158
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.Quick_Start`
|
159
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_qs`
|
160
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_qs`
|
161
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.RPL_Option_0x63`
|
162
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_rpl`
|
163
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_rpl`
|
164
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.MPL_Option`
|
165
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_mpl`
|
166
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_mpl`
|
167
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.ILNP_Nonce`
|
168
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_ilnp`
|
169
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_ilnp`
|
170
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.Line_Identification_Option`
|
171
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_lio`
|
172
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_lio`
|
173
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.Jumbo_Payload`
|
174
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_jumbo`
|
175
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_jumbo`
|
176
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.Home_Address`
|
177
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_home`
|
178
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_home`
|
179
|
+
* - :attr:`~pcapkit.const.ipv6.option.Option.IP_DFF`
|
180
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._read_opt_ip_dff`
|
181
|
+
- :meth:`~pcapkit.protocols.internet.hopopt.HOPOPT._make_opt_ip_dff`
|
182
|
+
|
183
|
+
"""
|
184
|
+
|
185
|
+
##########################################################################
|
186
|
+
# Defaults.
|
187
|
+
##########################################################################
|
188
|
+
|
189
|
+
#: DefaultDict[Enum_Option, str | tuple[OptionParser, OptionConstructor]]: Option
|
190
|
+
#: code to method mapping, c.f. :meth:`_read_hopopt_options` and/or
|
191
|
+
#: :meth:`_make_hopopt_options`. Method names are expected to be referred
|
192
|
+
#: to the class by ``_read_opt_${name}`` and/or ``_make_opt_${name}``, and
|
193
|
+
#: if such name not found, the value should then be a method that can parse
|
194
|
+
#: the option by itself.
|
195
|
+
__option__ = collections.defaultdict(
|
196
|
+
lambda: 'none',
|
197
|
+
{
|
198
|
+
Enum_Option.Pad1: 'pad', # [RFC 8200] 0
|
199
|
+
Enum_Option.PadN: 'pad', # [RFC 8200]
|
200
|
+
Enum_Option.Tunnel_Encapsulation_Limit: 'tun', # [RFC 2473] 1
|
201
|
+
Enum_Option.Router_Alert: 'ra', # [RFC 2711] 2
|
202
|
+
Enum_Option.CALIPSO: 'calipso', # [RFC 5570]
|
203
|
+
Enum_Option.SMF_DPD: 'smf_dpd', # [RFC 6621]
|
204
|
+
Enum_Option.PDM: 'pdm', # [RFC 8250] 10
|
205
|
+
Enum_Option.Quick_Start: 'qs', # [RFC 4782][RFC Errata 2034] 6
|
206
|
+
Enum_Option.RPL_Option_0x63: 'rpl', # [RFC 6553]
|
207
|
+
Enum_Option.MPL_Option: 'mpl', # [RFC 7731]
|
208
|
+
Enum_Option.ILNP_Nonce: 'ilnp', # [RFC 6744]
|
209
|
+
Enum_Option.Line_Identification_Option: 'lio', # [RFC 6788]
|
210
|
+
Enum_Option.Jumbo_Payload: 'jumbo', # [RFC 2675]
|
211
|
+
Enum_Option.Home_Address: 'home', # [RFC 6275]
|
212
|
+
Enum_Option.IP_DFF: 'ip_dff', # [RFC 6971]
|
213
|
+
},
|
214
|
+
) # type: DefaultDict[Enum_Option | int, str | tuple[OptionParser, OptionConstructor]]
|
215
|
+
|
216
|
+
##########################################################################
|
217
|
+
# Properties.
|
218
|
+
##########################################################################
|
219
|
+
|
220
|
+
@property
|
221
|
+
def name(self) -> 'Literal["IPv6 Hop-by-Hop Options"]':
|
222
|
+
"""Name of current protocol."""
|
223
|
+
return 'IPv6 Hop-by-Hop Options'
|
224
|
+
|
225
|
+
@property
|
226
|
+
def length(self) -> 'int':
|
227
|
+
"""Header length of current protocol."""
|
228
|
+
return self._info.length
|
229
|
+
|
230
|
+
@property
|
231
|
+
def payload(self) -> 'Protocol | NoReturn':
|
232
|
+
"""Payload of current instance.
|
233
|
+
|
234
|
+
Raises:
|
235
|
+
UnsupportedCall: if the protocol is used as an IPv6 extension header
|
236
|
+
|
237
|
+
:rtype: pcapkit.protocols.protocol.Protocol
|
238
|
+
"""
|
239
|
+
if self._extf:
|
240
|
+
raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'payload'")
|
241
|
+
return self._next
|
242
|
+
|
243
|
+
@property
|
244
|
+
def protocol(self) -> 'Optional[str] | NoReturn':
|
245
|
+
"""Name of next layer protocol (if any).
|
246
|
+
|
247
|
+
Raises:
|
248
|
+
UnsupportedCall: if the protocol is used as an IPv6 extension header
|
249
|
+
|
250
|
+
"""
|
251
|
+
if self._extf:
|
252
|
+
raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'protocol'")
|
253
|
+
return super().protocol
|
254
|
+
|
255
|
+
@property
|
256
|
+
def protochain(self) -> 'ProtoChain | NoReturn':
|
257
|
+
"""Protocol chain of current instance.
|
258
|
+
|
259
|
+
Raises:
|
260
|
+
UnsupportedCall: if the protocol is used as an IPv6 extension header
|
261
|
+
|
262
|
+
"""
|
263
|
+
if self._extf:
|
264
|
+
raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'protochain'")
|
265
|
+
return super().protochain
|
266
|
+
|
267
|
+
##########################################################################
|
268
|
+
# Methods.
|
269
|
+
##########################################################################
|
270
|
+
|
271
|
+
def read(self, length: 'Optional[int]' = None, *, extension: 'bool' = False, **kwargs: 'Any') -> 'Data_HOPOPT': # pylint: disable=arguments-differ,unused-argument
|
272
|
+
"""Read IPv6 Hop-by-Hop Options.
|
273
|
+
|
274
|
+
Structure of HOPOPT header [:rfc:`8200`]:
|
275
|
+
|
276
|
+
.. code-block:: text
|
277
|
+
|
278
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
279
|
+
| Next Header | Hdr Ext Len | |
|
280
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
|
281
|
+
| |
|
282
|
+
. .
|
283
|
+
. Options .
|
284
|
+
. .
|
285
|
+
| |
|
286
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
287
|
+
|
288
|
+
Args:
|
289
|
+
length: Length of packet data.
|
290
|
+
extension: If the packet is used as an IPv6 extension header.
|
291
|
+
**kwargs: Arbitrary keyword arguments.
|
292
|
+
|
293
|
+
Returns:
|
294
|
+
Parsed packet data.
|
295
|
+
|
296
|
+
"""
|
297
|
+
if length is None:
|
298
|
+
length = len(self)
|
299
|
+
schema = self.__schema__
|
300
|
+
|
301
|
+
hopopt = Data_HOPOPT(
|
302
|
+
next=schema.next,
|
303
|
+
length=(schema.len + 1) * 8,
|
304
|
+
options=self._read_hopopt_options(schema.len * 8 + 6),
|
305
|
+
)
|
306
|
+
|
307
|
+
if extension:
|
308
|
+
return hopopt
|
309
|
+
return self._decode_next_layer(hopopt, schema.next, length - hopopt.length)
|
310
|
+
|
311
|
+
def make(self,
|
312
|
+
next: 'Enum_TransType | StdlibEnum | AenumEnum | str | int' = Enum_TransType.UDP,
|
313
|
+
next_default: 'Optional[int]' = None,
|
314
|
+
next_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
315
|
+
next_reversed: 'bool' = False,
|
316
|
+
options: 'Optional[list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes] | Option]' = None, # pylint: disable=line-too-long
|
317
|
+
payload: 'bytes | Protocol | Schema' = b'',
|
318
|
+
**kwargs: 'Any') -> 'Schema_HOPOPT':
|
319
|
+
"""Make (construct) packet data.
|
320
|
+
|
321
|
+
Args:
|
322
|
+
next: Next header type.
|
323
|
+
next_default: Default value of next header type.
|
324
|
+
next_namespace: Namespace of next header type.
|
325
|
+
next_reversed: If the namespace of next header type is reversed.
|
326
|
+
option: Hop-by-Hop Options.
|
327
|
+
payload: Payload of current protocol.
|
328
|
+
**kwargs: Arbitrary keyword arguments.
|
329
|
+
|
330
|
+
Returns:
|
331
|
+
Constructed packet data.
|
332
|
+
|
333
|
+
"""
|
334
|
+
next_value = self._make_index(next, next_default, namespace=next_namespace,
|
335
|
+
reversed=next_reversed, pack=False)
|
336
|
+
|
337
|
+
if options is not None:
|
338
|
+
options_value, total_length = self._make_hopopt_options(options)
|
339
|
+
length = math.ceil((total_length - 6) / 8)
|
340
|
+
else:
|
341
|
+
options_value, length = [], 0
|
342
|
+
|
343
|
+
return Schema_HOPOPT(
|
344
|
+
next=next_value, # type: ignore[arg-type]
|
345
|
+
len=length,
|
346
|
+
options=options_value,
|
347
|
+
payload=payload,
|
348
|
+
)
|
349
|
+
|
350
|
+
@classmethod
|
351
|
+
def register_option(cls, code: 'Enum_Option', meth: 'str | tuple[OptionParser, OptionConstructor]') -> 'None':
|
352
|
+
"""Register an option parser.
|
353
|
+
|
354
|
+
Args:
|
355
|
+
code: HOPOPT option code.
|
356
|
+
meth: Method name or callable to parse and/or construct the option.
|
357
|
+
|
358
|
+
"""
|
359
|
+
if code in cls.__option__:
|
360
|
+
warn(f'option {code} already registered, overwriting', RegistryWarning)
|
361
|
+
cls.__option__[code] = meth
|
362
|
+
|
363
|
+
##########################################################################
|
364
|
+
# Data models.
|
365
|
+
##########################################################################
|
366
|
+
|
367
|
+
@overload
|
368
|
+
def __post_init__(self, file: 'IO[bytes] | bytes', length: 'Optional[int]' = ..., *, # pylint: disable=arguments-differ
|
369
|
+
extension: 'bool' = ..., **kwargs: 'Any') -> 'None': ...
|
370
|
+
|
371
|
+
@overload
|
372
|
+
def __post_init__(self, **kwargs: 'Any') -> 'None': ... # pylint: disable=arguments-differ
|
373
|
+
|
374
|
+
def __post_init__(self, file: 'Optional[IO[bytes] | bytes]' = None, length: 'Optional[int]' = None, *, # pylint: disable=arguments-differ
|
375
|
+
extension: 'bool' = False, **kwargs: 'Any') -> 'None':
|
376
|
+
"""Post initialisation hook.
|
377
|
+
|
378
|
+
Args:
|
379
|
+
file: Source packet stream.
|
380
|
+
length: Length of packet data.
|
381
|
+
extension: If the protocol is used as an IPv6 extension header.
|
382
|
+
**kwargs: Arbitrary keyword arguments.
|
383
|
+
|
384
|
+
See Also:
|
385
|
+
For construction argument, please refer to :meth:`make`.
|
386
|
+
|
387
|
+
"""
|
388
|
+
#: bool: If the protocol is used as an IPv6 extension header.
|
389
|
+
self._extf = extension
|
390
|
+
|
391
|
+
# call super __post_init__
|
392
|
+
super().__post_init__(file, length, extension=extension, **kwargs) # type: ignore[arg-type]
|
393
|
+
|
394
|
+
def __length_hint__(self) -> 'Literal[2]':
|
395
|
+
"""Return an estimated length for the object."""
|
396
|
+
return 2
|
397
|
+
|
398
|
+
@classmethod
|
399
|
+
def __index__(cls) -> 'Enum_TransType': # pylint: disable=invalid-index-returned
|
400
|
+
"""Numeral registry index of the protocol.
|
401
|
+
|
402
|
+
Returns:
|
403
|
+
Numeral registry index of the protocol in `IANA`_.
|
404
|
+
|
405
|
+
.. _IANA: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
406
|
+
|
407
|
+
"""
|
408
|
+
return Enum_TransType.HOPOPT # type: ignore[return-value]
|
409
|
+
|
410
|
+
##########################################################################
|
411
|
+
# Utilities.
|
412
|
+
##########################################################################
|
413
|
+
|
414
|
+
@classmethod
|
415
|
+
def _make_data(cls, data: 'Data_HOPOPT') -> 'dict[str, Any]': # type: ignore[override]
|
416
|
+
"""Create key-value pairs from ``data`` for protocol construction.
|
417
|
+
|
418
|
+
Args:
|
419
|
+
data: protocol data
|
420
|
+
|
421
|
+
Returns:
|
422
|
+
Key-value pairs for protocol construction.
|
423
|
+
|
424
|
+
"""
|
425
|
+
return {
|
426
|
+
'next': data.next,
|
427
|
+
'options': data.options,
|
428
|
+
'payload': cls._make_payload(data),
|
429
|
+
}
|
430
|
+
|
431
|
+
def _read_opt_type(self, kind: 'int') -> 'tuple[int, bool]':
|
432
|
+
"""Read option type field.
|
433
|
+
|
434
|
+
Arguments:
|
435
|
+
kind (int): option kind value
|
436
|
+
|
437
|
+
Returns:
|
438
|
+
Extracted HOPOPT option type field information (unknown option
|
439
|
+
action and change flag), c.f. [:rfc:`8200#section-4.2`].
|
440
|
+
|
441
|
+
"""
|
442
|
+
bin_ = bin(kind)[2:].zfill(8)
|
443
|
+
return int(bin_[:2], base=2), bool(int(bin_[2], base=2))
|
444
|
+
|
445
|
+
def _read_hopopt_options(self, length: 'int') -> 'Option':
|
446
|
+
"""Read HOPOPT options.
|
447
|
+
|
448
|
+
Positional arguments:
|
449
|
+
length: length of options
|
450
|
+
|
451
|
+
Returns:
|
452
|
+
Extracted HOPOPT options
|
453
|
+
|
454
|
+
Raises:
|
455
|
+
ProtocolError: If the threshold is **NOT** matching.
|
456
|
+
|
457
|
+
"""
|
458
|
+
counter = 0 # length of read options
|
459
|
+
options = OrderedMultiDict() # type: Option
|
460
|
+
|
461
|
+
for schema in self.__header__.options:
|
462
|
+
dscp = schema.type
|
463
|
+
name = self.__option__[dscp]
|
464
|
+
|
465
|
+
if isinstance(name, str):
|
466
|
+
meth_name = f'_read_opt_{name}'
|
467
|
+
meth = cast('OptionParser',
|
468
|
+
getattr(self, meth_name, self._read_opt_none))
|
469
|
+
else:
|
470
|
+
meth = name[0]
|
471
|
+
data = meth(schema, options=options)
|
472
|
+
|
473
|
+
# record option data
|
474
|
+
options.add(dscp, data)
|
475
|
+
counter += len(schema)
|
476
|
+
|
477
|
+
# check threshold
|
478
|
+
if counter != length:
|
479
|
+
raise ProtocolError('HOPOPT: invalid format')
|
480
|
+
return options
|
481
|
+
|
482
|
+
def _read_opt_none(self, schema: 'Schema_UnassignedOption', option: 'Option') -> 'Data_UnassignedOption': # pylint: disable=unused-argument
|
483
|
+
"""Read HOPOPT unassigned options.
|
484
|
+
|
485
|
+
Structure of HOPOPT unassigned options [:rfc:`8200`]:
|
486
|
+
|
487
|
+
.. code-block:: text
|
488
|
+
|
489
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
|
490
|
+
| Option Type | Opt Data Len | Option Data
|
491
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
|
492
|
+
|
493
|
+
Args:
|
494
|
+
schema: parsed parameter schema
|
495
|
+
option: extracted HOPOPT options
|
496
|
+
|
497
|
+
Returns:
|
498
|
+
Parsed option data.
|
499
|
+
|
500
|
+
"""
|
501
|
+
opt = Data_UnassignedOption(
|
502
|
+
type=schema.type,
|
503
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
504
|
+
change=bool(schema.type & 0b00100000),
|
505
|
+
length=schema.len + 2,
|
506
|
+
data=schema.data,
|
507
|
+
)
|
508
|
+
return opt
|
509
|
+
|
510
|
+
def _read_opt_pad(self, schema: 'Schema_PadOption', option: 'Option') -> 'Data_PadOption': # pylint: disable=unused-argument
|
511
|
+
"""Read HOPOPT padding options.
|
512
|
+
|
513
|
+
Structure of HOPOPT padding options [:rfc:`8200`]:
|
514
|
+
|
515
|
+
* ``Pad1`` option:
|
516
|
+
|
517
|
+
.. code-block:: text
|
518
|
+
|
519
|
+
+-+-+-+-+-+-+-+-+
|
520
|
+
| 0 |
|
521
|
+
+-+-+-+-+-+-+-+-+
|
522
|
+
|
523
|
+
* ``PadN`` option:
|
524
|
+
|
525
|
+
.. code-block:: text
|
526
|
+
|
527
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
|
528
|
+
| 1 | Opt Data Len | Option Data
|
529
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
|
530
|
+
|
531
|
+
Args:
|
532
|
+
schema: parsed parameter schema
|
533
|
+
option: extracted HOPOPT options
|
534
|
+
|
535
|
+
Returns:
|
536
|
+
Parsed option data.
|
537
|
+
|
538
|
+
Raises:
|
539
|
+
ProtocolError: If ``code`` is **NOT** ``0`` or ``1``.
|
540
|
+
|
541
|
+
"""
|
542
|
+
code, clen = schema.type, schema.len
|
543
|
+
|
544
|
+
if code not in (Enum_Option.Pad1, Enum_Option.PadN):
|
545
|
+
raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
|
546
|
+
if code == Enum_Option.Pad1 and clen != 0:
|
547
|
+
raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
|
548
|
+
if code == Enum_Option.PadN and clen == 0:
|
549
|
+
raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
|
550
|
+
|
551
|
+
if code == Enum_Option.Pad1:
|
552
|
+
_size = 1
|
553
|
+
else:
|
554
|
+
_size = schema.len + 2
|
555
|
+
|
556
|
+
opt = Data_PadOption(
|
557
|
+
type=schema.type,
|
558
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
559
|
+
change=bool(schema.type & 0b00100000),
|
560
|
+
length=_size,
|
561
|
+
)
|
562
|
+
return opt
|
563
|
+
|
564
|
+
def _read_opt_tun(self, schema: 'Schema_TunnelEncapsulationLimitOption', option: 'Option') -> 'Data_TunnelEncapsulationLimitOption': # pylint: disable=unused-argument
|
565
|
+
"""Read HOPOPT Tunnel Encapsulation Limit option.
|
566
|
+
|
567
|
+
Structure of HOPOPT Tunnel Encapsulation Limit option [:rfc:`2473`]:
|
568
|
+
|
569
|
+
.. code-block:: text
|
570
|
+
|
571
|
+
Option Type Opt Data Len Opt Data Len
|
572
|
+
0 1 2 3 4 5 6 7
|
573
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
574
|
+
|0 0 0 0 0 1 0 0| 1 | Tun Encap Lim |
|
575
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
576
|
+
|
577
|
+
Args:
|
578
|
+
schema: parsed parameter schema
|
579
|
+
option: extracted HOPOPT options
|
580
|
+
|
581
|
+
Returns:
|
582
|
+
Parsed option data.
|
583
|
+
|
584
|
+
Raises:
|
585
|
+
ProtocolError: If ``hopopt.tun.length`` is **NOT** ``1``.
|
586
|
+
|
587
|
+
"""
|
588
|
+
if schema.len != 1:
|
589
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
590
|
+
|
591
|
+
opt = Data_TunnelEncapsulationLimitOption(
|
592
|
+
type=schema.type,
|
593
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
594
|
+
change=bool(schema.type & 0b00100000),
|
595
|
+
length=schema.len + 2,
|
596
|
+
limit=schema.limit,
|
597
|
+
)
|
598
|
+
return opt
|
599
|
+
|
600
|
+
def _read_opt_ra(self, schema: 'Schema_RouterAlertOption', option: 'Option') -> 'Data_RouterAlertOption': # pylint: disable=unused-argument
|
601
|
+
"""Read HOPOPT Router Alert option.
|
602
|
+
|
603
|
+
Structure of HOPOPT Router Alert option [:rfc:`2711`]:
|
604
|
+
|
605
|
+
.. code-block:: text
|
606
|
+
|
607
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
608
|
+
|0 0 0|0 0 1 0 1|0 0 0 0 0 0 1 0| Value (2 octets) |
|
609
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
610
|
+
|
611
|
+
Args:
|
612
|
+
schema: parsed parameter schema
|
613
|
+
option: extracted HOPOPT options
|
614
|
+
|
615
|
+
Returns:
|
616
|
+
Parsed option data.
|
617
|
+
|
618
|
+
Raises:
|
619
|
+
ProtocolError: If ``hopopt.tun.length`` is **NOT** ``2``.
|
620
|
+
|
621
|
+
"""
|
622
|
+
if schema.len != 2:
|
623
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
624
|
+
|
625
|
+
opt = Data_RouterAlertOption(
|
626
|
+
type=schema.type,
|
627
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
628
|
+
change=bool(schema.type & 0b00100000),
|
629
|
+
length=schema.len + 2,
|
630
|
+
value=schema.alert,
|
631
|
+
)
|
632
|
+
return opt
|
633
|
+
|
634
|
+
def _read_opt_calipso(self, schema: 'Schema_CALIPSOOption', option: 'Option') -> 'Data_CALIPSOOption': # pylint: disable=unused-argument
|
635
|
+
"""Read HOPOPT Common Architecture Label IPv6 Security Option (CALIPSO) option.
|
636
|
+
|
637
|
+
Structure of HOPOPT CALIPSO option [:rfc:`5570`]:
|
638
|
+
|
639
|
+
.. code-block:: text
|
640
|
+
|
641
|
+
------------------------------------------------------------
|
642
|
+
| Next Header | Hdr Ext Len | Option Type | Option Length|
|
643
|
+
+-------------+---------------+-------------+--------------+
|
644
|
+
| CALIPSO Domain of Interpretation |
|
645
|
+
+-------------+---------------+-------------+--------------+
|
646
|
+
| Cmpt Length | Sens Level | Checksum (CRC-16) |
|
647
|
+
+-------------+---------------+-------------+--------------+
|
648
|
+
| Compartment Bitmap (Optional; variable length) |
|
649
|
+
+-------------+---------------+-------------+--------------+
|
650
|
+
|
651
|
+
Args:
|
652
|
+
schema: parsed parameter schema
|
653
|
+
option: extracted HOPOPT options
|
654
|
+
|
655
|
+
Returns:
|
656
|
+
Parsed option data.
|
657
|
+
|
658
|
+
Raises:
|
659
|
+
ProtocolError: If the option is malformed.
|
660
|
+
|
661
|
+
"""
|
662
|
+
if schema.len < 8 and schema.len % 8 != 0:
|
663
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
664
|
+
if schema.cmpt_len % 2 != 0:
|
665
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
666
|
+
|
667
|
+
opt = Data_CALIPSOOption(
|
668
|
+
type=schema.type,
|
669
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
670
|
+
change=bool(schema.type & 0b00100000),
|
671
|
+
length=schema.len + 2,
|
672
|
+
domain=schema.domain,
|
673
|
+
cmpt_len=schema.cmpt_len * 4,
|
674
|
+
level=schema.level,
|
675
|
+
checksum=schema.checksum,
|
676
|
+
)
|
677
|
+
|
678
|
+
if schema.cmpt_len > 0:
|
679
|
+
opt.__update__([
|
680
|
+
('cmpt_bitmap', tuple(schema.bitmap)),
|
681
|
+
])
|
682
|
+
return opt
|
683
|
+
|
684
|
+
def _read_opt_smf_dpd(self, schema: 'Schema_SMFDPDOption', option: 'Option') -> 'Data_SMFDPDOption': # pylint: disable=unused-argument,line-too-long
|
685
|
+
"""Read HOPOPT Simplified Multicast Forwarding Duplicate Packet Detection (``SMF_DPD``) option.
|
686
|
+
|
687
|
+
Structure of HOPOPT ``SMF_DPD`` option [:rfc:`6621`]:
|
688
|
+
|
689
|
+
* IPv6 ``SMF_DPD`` option header in **I-DPD** (Identification-Based DPD) mode
|
690
|
+
|
691
|
+
.. code-block:: text
|
692
|
+
|
693
|
+
0 1 2 3
|
694
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
695
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
696
|
+
... |0|0|0| 01000 | Opt. Data Len |
|
697
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
698
|
+
|0|TidTy| TidLen| TaggerID (optional) ... |
|
699
|
+
+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
700
|
+
| | Identifier ...
|
701
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
702
|
+
|
703
|
+
* IPv6 ``SMF_DPD`` option header in **H-DPD** (Hash-Based) mode
|
704
|
+
|
705
|
+
.. code-block:: text
|
706
|
+
|
707
|
+
0 1 2 3
|
708
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
709
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
710
|
+
... |0|0|0| OptType | Opt. Data Len |
|
711
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
712
|
+
|1| Hash Assist Value (HAV) ...
|
713
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
714
|
+
|
715
|
+
Args:
|
716
|
+
schema: parsed parameter schema
|
717
|
+
option: extracted HOPOPT options
|
718
|
+
|
719
|
+
Returns:
|
720
|
+
Parsed option data.
|
721
|
+
|
722
|
+
Raises:
|
723
|
+
ProtocolError: If the option is malformed.
|
724
|
+
|
725
|
+
"""
|
726
|
+
mode = schema.mode
|
727
|
+
if mode == Enum_SMFDPDMode.I_DPD: # I-DPD mode
|
728
|
+
if TYPE_CHECKING:
|
729
|
+
schema = cast('Schema_SMFIdentificationBasedDPDOption', schema)
|
730
|
+
|
731
|
+
tid_type = Enum_TaggerID.get(schema.info['type'])
|
732
|
+
tid_len = schema.info['len']
|
733
|
+
|
734
|
+
opt = Data_SMFIdentificationBasedDPDOption(
|
735
|
+
type=schema.type,
|
736
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
737
|
+
change=bool(schema.type & 0b00100000),
|
738
|
+
length=schema.len + 2,
|
739
|
+
dpd_type=mode,
|
740
|
+
tid_type=tid_type,
|
741
|
+
tid_len=tid_len,
|
742
|
+
tid=schema.tid,
|
743
|
+
id=schema.id,
|
744
|
+
) # type: Data_SMFDPDOption
|
745
|
+
elif mode == Enum_SMFDPDMode.H_DPD: # H-DPD mode
|
746
|
+
if TYPE_CHECKING:
|
747
|
+
schema = cast('Schema_SMFHashBasedDPDOption', schema)
|
748
|
+
|
749
|
+
opt = Data_SMFHashBasedDPDOption(
|
750
|
+
type=schema.type,
|
751
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
752
|
+
change=bool(schema.type & 0b00100000),
|
753
|
+
length=schema.len + 2,
|
754
|
+
dpd_type=mode,
|
755
|
+
hav=schema.hav,
|
756
|
+
)
|
757
|
+
else:
|
758
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid DPD mode: {mode}')
|
759
|
+
return opt
|
760
|
+
|
761
|
+
def _read_opt_pdm(self, schema: 'Schema_PDMOption', option: 'Option') -> 'Data_PDMOption': # pylint: disable=unused-argument
|
762
|
+
"""Read HOPOPT Performance and Diagnostic Metrics (PDM) option.
|
763
|
+
|
764
|
+
Structure of HOPOPT PDM option [:rfc:`8250`]:
|
765
|
+
|
766
|
+
.. code-block:: text
|
767
|
+
|
768
|
+
0 1 2 3
|
769
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
770
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
771
|
+
| Option Type | Option Length | ScaleDTLR | ScaleDTLS |
|
772
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
773
|
+
| PSN This Packet | PSN Last Received |
|
774
|
+
|-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
775
|
+
| Delta Time Last Received | Delta Time Last Sent |
|
776
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
777
|
+
|
778
|
+
Args:
|
779
|
+
schema: parsed parameter schema
|
780
|
+
option: extracted HOPOPT options
|
781
|
+
|
782
|
+
Returns:
|
783
|
+
Parsed option data.
|
784
|
+
|
785
|
+
Raises:
|
786
|
+
ProtocolError: If ``hopopt.pdm.length`` is **NOT** ``10``.
|
787
|
+
|
788
|
+
"""
|
789
|
+
if schema.len != 10:
|
790
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
791
|
+
|
792
|
+
opt = Data_PDMOption(
|
793
|
+
type=schema.type,
|
794
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
795
|
+
change=bool(schema.type & 0b00100000),
|
796
|
+
length=schema.len + 2,
|
797
|
+
scaledtlr=schema.scaledtlr,
|
798
|
+
scaledtls=schema.scaledtls,
|
799
|
+
psntp=schema.psntp,
|
800
|
+
psnlr=schema.psnlr,
|
801
|
+
deltatlr=schema.deltatlr << schema.scaledtlr,
|
802
|
+
deltatls=schema.deltatls << schema.scaledtls,
|
803
|
+
)
|
804
|
+
return opt
|
805
|
+
|
806
|
+
def _read_opt_qs(self, schema: 'Schema_QuickStartOption', option: 'Option') -> 'Data_QuickStartOption': # pylint: disable=unused-argument # pylint: disable=unused-argument
|
807
|
+
"""Read HOPOPT Quick Start option.
|
808
|
+
|
809
|
+
Structure of HOPOPT Quick-Start option [:rfc:`4782`]:
|
810
|
+
|
811
|
+
* A Quick-Start Request:
|
812
|
+
|
813
|
+
.. code-block:: text
|
814
|
+
|
815
|
+
0 1 2 3
|
816
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
817
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
818
|
+
| Option | Length=6 | Func. | Rate | QS TTL |
|
819
|
+
| | | 0000 |Request| |
|
820
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
821
|
+
| QS Nonce | R |
|
822
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
823
|
+
|
824
|
+
* Report of Approved Rate:
|
825
|
+
|
826
|
+
.. code-block:: text
|
827
|
+
|
828
|
+
0 1 2 3
|
829
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
830
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
831
|
+
| Option | Length=6 | Func. | Rate | Not Used |
|
832
|
+
| | | 1000 | Report| |
|
833
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
834
|
+
| QS Nonce | R |
|
835
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
836
|
+
|
837
|
+
Args:
|
838
|
+
schema: parsed parameter schema
|
839
|
+
option: extracted HOPOPT options
|
840
|
+
|
841
|
+
Returns:
|
842
|
+
Parsed option data.
|
843
|
+
|
844
|
+
Raises:
|
845
|
+
ProtocolError: If the option is malformed.
|
846
|
+
|
847
|
+
"""
|
848
|
+
if schema.len != 6:
|
849
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
850
|
+
|
851
|
+
func = schema.func
|
852
|
+
if func == Enum_QSFunction.Quick_Start_Request:
|
853
|
+
schema_req = cast('Schema_QuickStartRequestOption', schema)
|
854
|
+
|
855
|
+
rate = schema_req.flags['rate']
|
856
|
+
opt = Data_QuickStartRequestOption(
|
857
|
+
type=schema.type,
|
858
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
859
|
+
change=bool(schema.type & 0b00100000),
|
860
|
+
length=schema_req.len + 2,
|
861
|
+
func=func,
|
862
|
+
rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
|
863
|
+
ttl=datetime.timedelta(seconds=schema_req.ttl),
|
864
|
+
nonce=schema_req.nonce['nonce'],
|
865
|
+
) # type: Data_QuickStartOption
|
866
|
+
elif func == Enum_QSFunction.Report_of_Approved_Rate:
|
867
|
+
schema_rep = cast('Schema_QuickStartReportOption', schema)
|
868
|
+
|
869
|
+
rate = schema_rep.flags['rate']
|
870
|
+
opt = Data_QuickStartReportOption(
|
871
|
+
type=schema.type,
|
872
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
873
|
+
change=bool(schema.type & 0b00100000),
|
874
|
+
length=schema_rep.len + 2,
|
875
|
+
func=func,
|
876
|
+
rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
|
877
|
+
nonce=schema_rep.nonce['nonce'],
|
878
|
+
)
|
879
|
+
else:
|
880
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] unknown QS function: {func}')
|
881
|
+
return opt
|
882
|
+
|
883
|
+
def _read_opt_rpl(self, schema: 'Schema_RPLOption', option: 'Option') -> 'Data_RPLOption': # pylint: disable=unused-argument
|
884
|
+
"""Read HOPOPT Routing Protocol for Low-Power and Lossy Networks (RPL) option.
|
885
|
+
|
886
|
+
Structure of HOPOPT RPL option [:rfc:`6553`]:
|
887
|
+
|
888
|
+
.. code-block:: text
|
889
|
+
|
890
|
+
0 1 2 3
|
891
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
892
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
893
|
+
| Option Type | Opt Data Len |
|
894
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
895
|
+
|O|R|F|0|0|0|0|0| RPLInstanceID | SenderRank |
|
896
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
897
|
+
| (sub-TLVs) |
|
898
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
899
|
+
|
900
|
+
Args:
|
901
|
+
schema: parsed parameter schema
|
902
|
+
option: extracted HOPOPT options
|
903
|
+
|
904
|
+
Returns:
|
905
|
+
Parsed option data.
|
906
|
+
|
907
|
+
Raises:
|
908
|
+
ProtocolError: If ``hopopt.rpl.length`` is **NOT** ``4``.
|
909
|
+
|
910
|
+
"""
|
911
|
+
if schema.len != 4:
|
912
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
913
|
+
|
914
|
+
opt = Data_RPLOption(
|
915
|
+
type=schema.type,
|
916
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
917
|
+
change=bool(schema.type & 0b00100000),
|
918
|
+
length=schema.len + 2,
|
919
|
+
flags=Data_RPLFlags(
|
920
|
+
down=bool(schema.flags['down']),
|
921
|
+
rank_err=bool(schema.flags['rank_err']),
|
922
|
+
fwd_err=bool(schema.flags['fwd_err']),
|
923
|
+
),
|
924
|
+
id=schema.id,
|
925
|
+
rank=schema.rank,
|
926
|
+
)
|
927
|
+
return opt
|
928
|
+
|
929
|
+
def _read_opt_mpl(self, schema: 'Schema_MPLOption', option: 'Option') -> 'Data_MPLOption': # pylint: disable=unused-argument
|
930
|
+
"""Read HOPOPT Multicast Protocol for Low-Power and Lossy Networks (MPL) option.
|
931
|
+
|
932
|
+
Structure of HOPOPT MPL option [:rfc:`7731`]:
|
933
|
+
|
934
|
+
.. code-block:: text
|
935
|
+
|
936
|
+
0 1 2 3
|
937
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
938
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
939
|
+
| Option Type | Opt Data Len |
|
940
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
941
|
+
| S |M|V| rsv | sequence | seed-id (optional) |
|
942
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
943
|
+
|
944
|
+
Args:
|
945
|
+
schema: parsed parameter schema
|
946
|
+
option: extracted HOPOPT options
|
947
|
+
|
948
|
+
Returns:
|
949
|
+
Parsed option data.
|
950
|
+
|
951
|
+
Raises:
|
952
|
+
ProtocolError: If the option is malformed.
|
953
|
+
|
954
|
+
"""
|
955
|
+
kind = Enum_SeedID.get(schema.flags['type'])
|
956
|
+
clen = schema.len
|
957
|
+
|
958
|
+
if schema.len < 2:
|
959
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
960
|
+
if kind == kind.IPV6_SOURCE_ADDRESS:
|
961
|
+
if clen != 2:
|
962
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id length: {clen - 2}')
|
963
|
+
elif kind == kind.SEEDID_16_BIT_UNSIGNED_INTEGER:
|
964
|
+
if clen != 4:
|
965
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id length: {clen - 2}')
|
966
|
+
elif kind == kind.SEEDID_64_BIT_UNSIGNED_INTEGER:
|
967
|
+
if clen != 10:
|
968
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id length: {clen - 2}')
|
969
|
+
elif kind == kind.SEEDID_128_BIT_UNSIGNED_INTEGER:
|
970
|
+
if clen != 18:
|
971
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id length: {clen - 2}')
|
972
|
+
else:
|
973
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id type: {kind}')
|
974
|
+
|
975
|
+
opt = Data_MPLOption(
|
976
|
+
type=schema.type,
|
977
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
978
|
+
change=bool(schema.type & 0b00100000),
|
979
|
+
length=schema.len + 2,
|
980
|
+
seed_type=kind,
|
981
|
+
flags=Data_MPLFlags(
|
982
|
+
max=bool(schema.flags['max']),
|
983
|
+
drop=bool(schema.flags['drop']),
|
984
|
+
),
|
985
|
+
seq=schema.seq,
|
986
|
+
seed_id=schema.seed if schema.seed is not NoValue else None, # type: ignore[comparison-overlap]
|
987
|
+
)
|
988
|
+
return opt
|
989
|
+
|
990
|
+
def _read_opt_ilnp(self, schema: 'Schema_ILNPOption', option: 'Option') -> 'Data_ILNPOption': # pylint: disable=unused-argument
|
991
|
+
"""Read HOPOPT Identifier-Locator Network Protocol (ILNP) Nonce option.
|
992
|
+
|
993
|
+
Structure of HOPOPT ILNP Nonce option [:rfc:`6744`]:
|
994
|
+
|
995
|
+
.. code-block:: text
|
996
|
+
|
997
|
+
0 1 2 3
|
998
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
999
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1000
|
+
| Next Header | Hdr Ext Len | Option Type | Option Length |
|
1001
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1002
|
+
/ Nonce Value /
|
1003
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1004
|
+
|
1005
|
+
Args:
|
1006
|
+
schema: parsed parameter schema
|
1007
|
+
option: extracted HOPOPT options
|
1008
|
+
|
1009
|
+
Returns:
|
1010
|
+
Parsed option data.
|
1011
|
+
|
1012
|
+
"""
|
1013
|
+
opt = Data_ILNPOption(
|
1014
|
+
type=schema.type,
|
1015
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
1016
|
+
change=bool(schema.type & 0b00100000),
|
1017
|
+
length=schema.len + 2,
|
1018
|
+
nonce=schema.nonce,
|
1019
|
+
)
|
1020
|
+
return opt
|
1021
|
+
|
1022
|
+
def _read_opt_lio(self, schema: 'Schema_LineIdentificationOption', option: 'Option') -> 'Data_LineIdentificationOption': # pylint: disable=unused-argument
|
1023
|
+
"""Read HOPOPT Line-Identification option.
|
1024
|
+
|
1025
|
+
Structure of HOPOPT Line-Identification option [:rfc:`6788`]:
|
1026
|
+
|
1027
|
+
.. code-block:: text
|
1028
|
+
|
1029
|
+
0 1 2 3
|
1030
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
1031
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1032
|
+
| Option Type | Option Length |
|
1033
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1034
|
+
| LineIDLen | Line ID...
|
1035
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1036
|
+
|
1037
|
+
Args:
|
1038
|
+
schema: parsed parameter schema
|
1039
|
+
option: extracted HOPOPT options
|
1040
|
+
|
1041
|
+
Returns:
|
1042
|
+
Parsed option data.
|
1043
|
+
|
1044
|
+
"""
|
1045
|
+
opt = Data_LineIdentificationOption(
|
1046
|
+
type=schema.type,
|
1047
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
1048
|
+
change=bool(schema.type & 0b00100000),
|
1049
|
+
length=schema.len + 2,
|
1050
|
+
line_id_len=schema.id_len,
|
1051
|
+
line_id=schema.id,
|
1052
|
+
)
|
1053
|
+
return opt
|
1054
|
+
|
1055
|
+
def _read_opt_jumbo(self, schema: 'Schema_JumboPayloadOption', option: 'Option') -> 'Data_JumboPayloadOption': # pylint: disable=unused-argument
|
1056
|
+
"""Read HOPOPT Jumbo Payload option.
|
1057
|
+
|
1058
|
+
Structure of HOPOPT Jumbo Payload option [:rfc:`2675`]:
|
1059
|
+
|
1060
|
+
.. code-block:: text
|
1061
|
+
|
1062
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1063
|
+
| Option Type | Opt Data Len |
|
1064
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1065
|
+
| Jumbo Payload Length |
|
1066
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1067
|
+
|
1068
|
+
Args:
|
1069
|
+
schema: parsed parameter schema
|
1070
|
+
option: extracted HOPOPT options
|
1071
|
+
|
1072
|
+
Returns:
|
1073
|
+
Parsed option data.
|
1074
|
+
|
1075
|
+
Raises:
|
1076
|
+
ProtocolError: If ``hopopt.jumbo.length`` is **NOT** ``4``.
|
1077
|
+
|
1078
|
+
"""
|
1079
|
+
if schema.len != 4:
|
1080
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
1081
|
+
|
1082
|
+
opt = Data_JumboPayloadOption(
|
1083
|
+
type=schema.type,
|
1084
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
1085
|
+
change=bool(schema.type & 0b00100000),
|
1086
|
+
length=schema.len + 2,
|
1087
|
+
jumbo_len=schema.jumbo_len,
|
1088
|
+
)
|
1089
|
+
return opt
|
1090
|
+
|
1091
|
+
def _read_opt_home(self, schema: 'Schema_HomeAddressOption', option: 'Option') -> 'Data_HomeAddressOption': # pylint: disable=unused-argument
|
1092
|
+
"""Read HOPOPT Home Address option.
|
1093
|
+
|
1094
|
+
Structure of HOPOPT Home Address option [:rfc:`6275`]:
|
1095
|
+
|
1096
|
+
.. code-block:: text
|
1097
|
+
|
1098
|
+
0 1 2 3
|
1099
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
1100
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1101
|
+
| Option Type | Option Length |
|
1102
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1103
|
+
| |
|
1104
|
+
+ +
|
1105
|
+
| |
|
1106
|
+
+ Home Address +
|
1107
|
+
| |
|
1108
|
+
+ +
|
1109
|
+
| |
|
1110
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1111
|
+
|
1112
|
+
Args:
|
1113
|
+
schema: parsed parameter schema
|
1114
|
+
option: extracted HOPOPT options
|
1115
|
+
|
1116
|
+
Returns:
|
1117
|
+
Parsed option data.
|
1118
|
+
|
1119
|
+
Raises:
|
1120
|
+
ProtocolError: If ``hopopt.jumbo.length`` is **NOT** ``16``.
|
1121
|
+
|
1122
|
+
"""
|
1123
|
+
if schema.len != 16:
|
1124
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
1125
|
+
|
1126
|
+
opt = Data_HomeAddressOption(
|
1127
|
+
type=schema.type,
|
1128
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
1129
|
+
change=bool(schema.type & 0b00100000),
|
1130
|
+
length=schema.len + 2,
|
1131
|
+
address=schema.addr,
|
1132
|
+
)
|
1133
|
+
return opt
|
1134
|
+
|
1135
|
+
def _read_opt_ip_dff(self, schema: 'Schema_IPDFFOption', option: 'Option') -> 'Data_IPDFFOption': # pylint: disable=unused-argument
|
1136
|
+
"""Read HOPOPT Depth-First Forwarding (``IP_DFF``) option.
|
1137
|
+
|
1138
|
+
Structure of HOPOPT ``IP_DFF`` option [:rfc:`6971`]:
|
1139
|
+
|
1140
|
+
.. code-block:: text
|
1141
|
+
|
1142
|
+
1 2 3
|
1143
|
+
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
1144
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1145
|
+
| Next Header | Hdr Ext Len | OptTypeDFF | OptDataLenDFF |
|
1146
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1147
|
+
|VER|D|R|0|0|0|0| Sequence Number | Pad1 |
|
1148
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1149
|
+
|
1150
|
+
Args:
|
1151
|
+
schema: parsed parameter schema
|
1152
|
+
option: extracted HOPOPT options
|
1153
|
+
|
1154
|
+
Returns:
|
1155
|
+
Parsed option data.
|
1156
|
+
|
1157
|
+
Raises:
|
1158
|
+
ProtocolError: If ``hopopt.ip_dff.length`` is **NOT** ``2``.
|
1159
|
+
|
1160
|
+
"""
|
1161
|
+
if schema.len != 2:
|
1162
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
1163
|
+
|
1164
|
+
opt = Data_IPDFFOption(
|
1165
|
+
type=schema.type,
|
1166
|
+
action=Enum_OptionAction.get(schema.type >> 6),
|
1167
|
+
change=bool(schema.type & 0b00100000),
|
1168
|
+
length=schema.len + 2,
|
1169
|
+
version=schema.flags['ver'],
|
1170
|
+
flags=Data_DFFFlags(
|
1171
|
+
dup=bool(schema.flags['dup']),
|
1172
|
+
ret=bool(schema.flags['ret']),
|
1173
|
+
),
|
1174
|
+
seq=schema.seq,
|
1175
|
+
)
|
1176
|
+
return opt
|
1177
|
+
|
1178
|
+
def _make_hopopt_options(self, options: 'list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes] | Option') -> 'tuple[list[Schema_Option | bytes], int]':
|
1179
|
+
"""Make options for HOPOPT.
|
1180
|
+
|
1181
|
+
Args:
|
1182
|
+
option: HOPOPT options
|
1183
|
+
|
1184
|
+
Returns:
|
1185
|
+
Tuple of options and total length of options.
|
1186
|
+
|
1187
|
+
"""
|
1188
|
+
total_length = 0
|
1189
|
+
if isinstance(options, list):
|
1190
|
+
options_list = [] # type: list[Schema_Option | bytes]
|
1191
|
+
for schema in options:
|
1192
|
+
if isinstance(schema, bytes):
|
1193
|
+
code = Enum_Option.get(schema[0])
|
1194
|
+
if code in (Enum_Option.Pad1, Enum_Option.PadN): # ignore padding options by default
|
1195
|
+
continue
|
1196
|
+
|
1197
|
+
opt = schema # type: bytes | Schema_Option
|
1198
|
+
opt_len = len(schema)
|
1199
|
+
elif isinstance(schema, Schema):
|
1200
|
+
code = schema.type
|
1201
|
+
if code in (Enum_Option.Pad1, Enum_Option.PadN): # ignore padding options by default
|
1202
|
+
continue
|
1203
|
+
|
1204
|
+
opt = schema
|
1205
|
+
opt_len = len(schema.pack())
|
1206
|
+
else:
|
1207
|
+
code, args = cast('tuple[Enum_Option, dict[str, Any]]', schema)
|
1208
|
+
if code in (Enum_Option.Pad1, Enum_Option.PadN): # ignore padding options by default
|
1209
|
+
continue
|
1210
|
+
|
1211
|
+
name = self.__option__[code] # type: str | tuple[OptionParser, OptionConstructor]
|
1212
|
+
if isinstance(name, str):
|
1213
|
+
meth_name = f'_make_opt_{name}'
|
1214
|
+
meth = cast('OptionConstructor',
|
1215
|
+
getattr(self, meth_name, self._make_opt_none))
|
1216
|
+
else:
|
1217
|
+
meth = name[1]
|
1218
|
+
|
1219
|
+
opt = meth(code, **args)
|
1220
|
+
opt_len = len(opt.pack())
|
1221
|
+
|
1222
|
+
options_list.append(opt)
|
1223
|
+
total_length += opt_len
|
1224
|
+
|
1225
|
+
# force alignment to 8 octets
|
1226
|
+
if opt_len % 8:
|
1227
|
+
pad_len = 8 - (opt_len % 8)
|
1228
|
+
if pad_len in (1, 2):
|
1229
|
+
pad_opt = self._make_opt_pad(Enum_Option.Pad1, length=0) # type: ignore[arg-type]
|
1230
|
+
else:
|
1231
|
+
pad_opt = self._make_opt_pad(Enum_Option.PadN, length=pad_len) # type: ignore[arg-type]
|
1232
|
+
|
1233
|
+
options_list.append(pad_opt)
|
1234
|
+
if pad_len == 2: # need 2 Pad1 options
|
1235
|
+
options_list.append(pad_opt)
|
1236
|
+
total_length += pad_len
|
1237
|
+
return options_list, total_length
|
1238
|
+
|
1239
|
+
options_list = []
|
1240
|
+
for code, option in options.items(multi=True):
|
1241
|
+
# ignore padding options by default
|
1242
|
+
if code in (Enum_Option.Pad1, Enum_Option.PadN):
|
1243
|
+
continue
|
1244
|
+
|
1245
|
+
name = self.__option__[code]
|
1246
|
+
if isinstance(name, str):
|
1247
|
+
meth_name = f'_make_opt_{name}'
|
1248
|
+
meth = cast('OptionConstructor',
|
1249
|
+
getattr(self, meth_name, self._make_opt_none))
|
1250
|
+
else:
|
1251
|
+
meth = name[1]
|
1252
|
+
|
1253
|
+
opt = meth(code, option)
|
1254
|
+
opt_len = len(opt.pack())
|
1255
|
+
|
1256
|
+
options_list.append(opt)
|
1257
|
+
total_length += opt_len
|
1258
|
+
|
1259
|
+
# force alignment to 8 octets
|
1260
|
+
if opt_len % 8:
|
1261
|
+
pad_len = 8 - (opt_len % 8)
|
1262
|
+
if pad_len in (1, 2):
|
1263
|
+
pad_opt = self._make_opt_pad(Enum_Option.Pad1, length=0) # type: ignore[arg-type]
|
1264
|
+
else:
|
1265
|
+
pad_opt = self._make_opt_pad(Enum_Option.PadN, length=pad_len) # type: ignore[arg-type]
|
1266
|
+
|
1267
|
+
options_list.append(pad_opt)
|
1268
|
+
if pad_len == 2: # need 2 Pad1 options
|
1269
|
+
options_list.append(pad_opt)
|
1270
|
+
total_length += pad_len
|
1271
|
+
return options_list, total_length
|
1272
|
+
|
1273
|
+
def _make_opt_none(self, code: 'Enum_Option', opt: 'Optional[Data_UnassignedOption]' = None, *,
|
1274
|
+
data: 'bytes' = b'',
|
1275
|
+
**kwargs: 'Any') -> 'Schema_UnassignedOption':
|
1276
|
+
"""Make HOPOPT unassigned option.
|
1277
|
+
|
1278
|
+
Args:
|
1279
|
+
code: option type value
|
1280
|
+
opt: option data
|
1281
|
+
data: option payload in :obj:`bytes`
|
1282
|
+
**kwargs: arbitrary keyword arguments
|
1283
|
+
|
1284
|
+
Returns:
|
1285
|
+
Constructured option schema.
|
1286
|
+
|
1287
|
+
"""
|
1288
|
+
if opt is not None:
|
1289
|
+
data = opt.data
|
1290
|
+
|
1291
|
+
return Schema_UnassignedOption(
|
1292
|
+
type=code,
|
1293
|
+
len=len(data),
|
1294
|
+
data=data,
|
1295
|
+
)
|
1296
|
+
|
1297
|
+
def _make_opt_pad(self, code: 'Enum_Option', opt: 'Optional[Data_PadOption]' = None, *,
|
1298
|
+
length: 'int' = 0,
|
1299
|
+
**kwargs: 'Any') -> 'Schema_PadOption':
|
1300
|
+
"""Make HOPOPT pad option.
|
1301
|
+
|
1302
|
+
Args:
|
1303
|
+
code: option type value
|
1304
|
+
opt: option data
|
1305
|
+
length: padding length
|
1306
|
+
**kwargs: arbitrary keyword arguments
|
1307
|
+
|
1308
|
+
Returns:
|
1309
|
+
Constructured option schema.
|
1310
|
+
|
1311
|
+
"""
|
1312
|
+
if code == Enum_Option.Pad1 and length != 0:
|
1313
|
+
#raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
|
1314
|
+
warn(f'{self.alias}: [OptNo {code}] invalid format', ProtocolWarning)
|
1315
|
+
code = Enum_Option.PadN # type: ignore[assignment]
|
1316
|
+
if code == Enum_Option.PadN and length == 0:
|
1317
|
+
#raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
|
1318
|
+
warn(f'{self.alias}: [OptNo {code}] invalid format', ProtocolWarning)
|
1319
|
+
code = Enum_Option.Pad1 # type: ignore[assignment]
|
1320
|
+
|
1321
|
+
return Schema_PadOption(
|
1322
|
+
type=code,
|
1323
|
+
len=length,
|
1324
|
+
)
|
1325
|
+
|
1326
|
+
def _make_opt_tun(self, code: 'Enum_Option', opt: 'Optional[Data_TunnelEncapsulationLimitOption]' = None, *,
|
1327
|
+
limit: 'int' = 0,
|
1328
|
+
**kwargs: 'Any') -> 'Schema_TunnelEncapsulationLimitOption':
|
1329
|
+
"""Make HOPOPT tunnel encapsulation limit option.
|
1330
|
+
|
1331
|
+
Args:
|
1332
|
+
code: option type value
|
1333
|
+
opt: option data
|
1334
|
+
limit: tunnel encapsulation limit
|
1335
|
+
**kwargs: arbitrary keyword arguments
|
1336
|
+
|
1337
|
+
Returns:
|
1338
|
+
Constructured option schema.
|
1339
|
+
|
1340
|
+
"""
|
1341
|
+
if opt is not None:
|
1342
|
+
limit = opt.limit
|
1343
|
+
|
1344
|
+
return Schema_TunnelEncapsulationLimitOption(
|
1345
|
+
type=code,
|
1346
|
+
len=1,
|
1347
|
+
limit=limit,
|
1348
|
+
)
|
1349
|
+
|
1350
|
+
def _make_opt_ra(self, code: 'Enum_Option', opt: 'Optional[Data_RouterAlertOption]' = None, *,
|
1351
|
+
alert: 'Enum_RouterAlert | StdlibEnum | AenumEnum | str | int' = Enum_RouterAlert.Datagram_contains_a_Multicast_Listener_Discovery_message, # pylint: disable=line-too-long
|
1352
|
+
alert_default: 'Optional[int]' = None,
|
1353
|
+
alert_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
1354
|
+
alert_reversed: 'bool' = False,
|
1355
|
+
**kwargs: 'Any') -> 'Schema_RouterAlertOption':
|
1356
|
+
"""Make HOPOPT router alert option.
|
1357
|
+
|
1358
|
+
Args:
|
1359
|
+
code: option type value
|
1360
|
+
opt: option data
|
1361
|
+
alert: router alert value
|
1362
|
+
alert_default: default value of router alert
|
1363
|
+
alert_namespace: namespace of router alert
|
1364
|
+
alert_reversed: reversed flag of router alert
|
1365
|
+
**kwargs: arbitrary keyword arguments
|
1366
|
+
|
1367
|
+
Returns:
|
1368
|
+
Constructured option schema.
|
1369
|
+
|
1370
|
+
"""
|
1371
|
+
if opt is not None:
|
1372
|
+
value = opt.value
|
1373
|
+
else:
|
1374
|
+
value = self._make_index(alert, alert_default, namespace=alert_namespace, # type: ignore[assignment]
|
1375
|
+
reversed=alert_reversed, pack=False)
|
1376
|
+
|
1377
|
+
return Schema_RouterAlertOption(
|
1378
|
+
type=code,
|
1379
|
+
len=2,
|
1380
|
+
alert=value,
|
1381
|
+
)
|
1382
|
+
|
1383
|
+
def _make_opt_calipso(self, code: 'Enum_Option', opt: 'Optional[Data_CALIPSOOption]' = None, *,
|
1384
|
+
domain: 'int' = 0,
|
1385
|
+
level: 'int' = 0,
|
1386
|
+
checksum: 'bytes' = b'\x00\x00',
|
1387
|
+
bitmap: 'Optional[bytes]' = None,
|
1388
|
+
**kwargs: 'Any') -> 'Schema_CALIPSOOption':
|
1389
|
+
"""Make HOPOPT calipso option.
|
1390
|
+
|
1391
|
+
Args:
|
1392
|
+
code: option type value
|
1393
|
+
opt: option data
|
1394
|
+
domain: CALIPSO domain of interpretation
|
1395
|
+
level: sensitivity level
|
1396
|
+
checksum: checksum of the option
|
1397
|
+
bitmap: compartment bitmap
|
1398
|
+
**kwargs: arbitrary keyword arguments
|
1399
|
+
|
1400
|
+
Returns:
|
1401
|
+
Constructured option schema.
|
1402
|
+
|
1403
|
+
"""
|
1404
|
+
if opt is not None:
|
1405
|
+
domain = opt.domain
|
1406
|
+
cmpt_len = len(opt.cmpt_bitmap) if hasattr(opt, 'cmpt_bitmap') else 0
|
1407
|
+
level = opt.level
|
1408
|
+
checksum = opt.checksum
|
1409
|
+
bitmap = opt.cmpt_bitmap if hasattr(opt, 'cmpt_bitmap') else None
|
1410
|
+
|
1411
|
+
return Schema_CALIPSOOption(
|
1412
|
+
type=code,
|
1413
|
+
len=8 + cmpt_len,
|
1414
|
+
domain=domain,
|
1415
|
+
cmpt_len=cmpt_len,
|
1416
|
+
level=level,
|
1417
|
+
checksum=checksum,
|
1418
|
+
bitmap=bitmap,
|
1419
|
+
)
|
1420
|
+
|
1421
|
+
def _make_opt_smf_dpd(self, code: 'Enum_Option', opt: 'Optional[Data_SMFIdentificationBasedDPDOption | Data_SMFHashBasedDPDOption]' = None, *,
|
1422
|
+
mode: 'Enum_SMFDPDMode | StdlibEnum | AenumEnum | str | int' = Enum_SMFDPDMode.I_DPD,
|
1423
|
+
mode_default: 'Optional[int]' = None,
|
1424
|
+
mode_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
1425
|
+
mode_reversed: 'bool' = False,
|
1426
|
+
tid: 'Optional[bytes | IPv4Address | IPv6Address]' = None,
|
1427
|
+
id: 'bytes' = b'',
|
1428
|
+
hav: 'bytes' = b'',
|
1429
|
+
**kwargs: 'Any') -> 'Schema_SMFDPDOption':
|
1430
|
+
"""Make HOPOPT SMF DPD option.
|
1431
|
+
|
1432
|
+
Args:
|
1433
|
+
code: option type value
|
1434
|
+
opt: option data
|
1435
|
+
mode: DPD mode
|
1436
|
+
mode_default: default value of DPD mode
|
1437
|
+
mode_namespace: namespace of DPD mode
|
1438
|
+
mode_reversed: reversed flag of DPD mode
|
1439
|
+
tid: Tagger ID
|
1440
|
+
id: identifier
|
1441
|
+
hav: hash assist value (HAV)
|
1442
|
+
**kwargs: arbitrary keyword arguments
|
1443
|
+
|
1444
|
+
Returns:
|
1445
|
+
Constructured option schema.
|
1446
|
+
|
1447
|
+
"""
|
1448
|
+
if opt is not None:
|
1449
|
+
dpd_type = opt.dpd_type
|
1450
|
+
tid = getattr(opt, 'tid', None)
|
1451
|
+
id = getattr(opt, 'id', b'')
|
1452
|
+
hav = getattr(opt, 'hav', b'')
|
1453
|
+
|
1454
|
+
dpd_type = self._make_index(mode, mode_default, namespace=mode_namespace, # type: ignore[assignment]
|
1455
|
+
reversed=mode_reversed, pack=False)
|
1456
|
+
|
1457
|
+
if dpd_type == Enum_SMFDPDMode.I_DPD:
|
1458
|
+
if tid is None:
|
1459
|
+
schema = Schema_SMFIdentificationBasedDPDOption(
|
1460
|
+
type=code,
|
1461
|
+
len=1 + len(id),
|
1462
|
+
info={
|
1463
|
+
'mode': 0,
|
1464
|
+
'type': Enum_TaggerID.NULL,
|
1465
|
+
'len': 0,
|
1466
|
+
},
|
1467
|
+
tid=None,
|
1468
|
+
id=id,
|
1469
|
+
) # type: Schema_SMFDPDOption
|
1470
|
+
elif isinstance(tid, bytes):
|
1471
|
+
tid_len = len(tid)
|
1472
|
+
if tid_len == 0:
|
1473
|
+
tid_type = Enum_TaggerID.NULL
|
1474
|
+
else:
|
1475
|
+
try:
|
1476
|
+
tid_ip_ver = ipaddress.ip_address(tid).version
|
1477
|
+
if tid_ip_ver == 4:
|
1478
|
+
tid_type = Enum_TaggerID.IPv4
|
1479
|
+
elif tid_ip_ver == 6:
|
1480
|
+
tid_type = Enum_TaggerID.IPv6
|
1481
|
+
else:
|
1482
|
+
tid_type = Enum_TaggerID.DEFAULT # type: ignore[unreachable]
|
1483
|
+
except ValueError:
|
1484
|
+
tid_type = Enum_TaggerID.DEFAULT
|
1485
|
+
|
1486
|
+
schema = Schema_SMFIdentificationBasedDPDOption(
|
1487
|
+
type=code,
|
1488
|
+
len=1 + tid_len + len(id),
|
1489
|
+
info={
|
1490
|
+
'mode': 0,
|
1491
|
+
'type': tid_type,
|
1492
|
+
'len': tid_len - 1,
|
1493
|
+
},
|
1494
|
+
tid=tid,
|
1495
|
+
id=id,
|
1496
|
+
)
|
1497
|
+
else:
|
1498
|
+
tid_ver = tid.version
|
1499
|
+
if tid_ver == 4:
|
1500
|
+
tid_type = Enum_TaggerID.IPv4
|
1501
|
+
tid_len = 4
|
1502
|
+
elif tid_ver == 6:
|
1503
|
+
tid_type = Enum_TaggerID.IPv6
|
1504
|
+
tid_len = 16
|
1505
|
+
else:
|
1506
|
+
raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid TaggerID version: {tid_ver}')
|
1507
|
+
|
1508
|
+
schema = Schema_SMFIdentificationBasedDPDOption(
|
1509
|
+
type=code,
|
1510
|
+
len=1 + tid_len + len(id),
|
1511
|
+
info={
|
1512
|
+
'mode': 0,
|
1513
|
+
'type': tid_type,
|
1514
|
+
'len': tid_len - 1,
|
1515
|
+
},
|
1516
|
+
tid=tid.packed,
|
1517
|
+
id=id,
|
1518
|
+
)
|
1519
|
+
elif dpd_type == Enum_SMFDPDMode.H_DPD:
|
1520
|
+
hav_ba = bytearray(hav)
|
1521
|
+
hav_ba[0] = hav[0] | 0x80
|
1522
|
+
|
1523
|
+
schema = Schema_SMFHashBasedDPDOption(
|
1524
|
+
type=code,
|
1525
|
+
len=len(hav),
|
1526
|
+
hav=bytes(hav_ba),
|
1527
|
+
)
|
1528
|
+
else:
|
1529
|
+
raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid DPD type: {dpd_type}')
|
1530
|
+
return schema
|
1531
|
+
|
1532
|
+
def _make_opt_pdm(self, code: 'Enum_Option', opt: 'Optional[Data_PDMOption]' = None, *,
|
1533
|
+
psntp: 'int' = 0,
|
1534
|
+
psnlr: 'int' = 0,
|
1535
|
+
deltatlr: 'int' = 0,
|
1536
|
+
deltatls: 'int' = 0,
|
1537
|
+
**kwargs: 'Any') -> 'Schema_PDMOption':
|
1538
|
+
"""Make HOPOPT PDM option.
|
1539
|
+
|
1540
|
+
Args:
|
1541
|
+
code: option type value
|
1542
|
+
opt: option data
|
1543
|
+
psntp: packet sequence number (PSN) this packet
|
1544
|
+
psnlr: packet sequence number (PSN) last received
|
1545
|
+
deltatlr: delta time last received (in attoseconds)
|
1546
|
+
deltatls: delta time last sent (in attoseconds)
|
1547
|
+
**kwargs: arbitrary keyword arguments
|
1548
|
+
|
1549
|
+
Returns:
|
1550
|
+
Constructured option schema.
|
1551
|
+
|
1552
|
+
"""
|
1553
|
+
if opt is not None:
|
1554
|
+
psntp = opt.psntp
|
1555
|
+
psnlr = opt.psnlr
|
1556
|
+
deltatlr = opt.deltatlr
|
1557
|
+
deltatls = opt.deltatls
|
1558
|
+
|
1559
|
+
dtlr_bl = deltatlr.bit_length()
|
1560
|
+
scale_dtlr = dtlr_bl - 16 if dtlr_bl > 16 else 0
|
1561
|
+
if scale_dtlr > 255:
|
1562
|
+
warn(f'{self.alias}: [OptNo {code}] too large delta time last received: {deltatlr} (scaled: {scale_dtlr})',
|
1563
|
+
ProtocolWarning)
|
1564
|
+
|
1565
|
+
dtls_bl = deltatls.bit_length()
|
1566
|
+
scale_dtls = dtls_bl - 16 if dtls_bl > 16 else 0
|
1567
|
+
if scale_dtls > 255:
|
1568
|
+
warn(f'{self.alias}: [OptNo {code}] too large delta time last sent: {deltatls} (scaled: {scale_dtls})',
|
1569
|
+
ProtocolWarning)
|
1570
|
+
|
1571
|
+
return Schema_PDMOption(
|
1572
|
+
type=code,
|
1573
|
+
len=10,
|
1574
|
+
scaledtlr=scale_dtlr,
|
1575
|
+
scaledtls=scale_dtls,
|
1576
|
+
psntp=psntp,
|
1577
|
+
psnlr=psnlr,
|
1578
|
+
deltatlr=deltatlr >> scale_dtlr,
|
1579
|
+
deltatls=deltatls >> scale_dtls,
|
1580
|
+
)
|
1581
|
+
|
1582
|
+
def _make_opt_qs(self, code: 'Enum_Option', opt: 'Optional[Data_QuickStartOption]' = None, *,
|
1583
|
+
func: 'Enum_QSFunction | StdlibEnum | AenumEnum | str | int' = Enum_QSFunction.Quick_Start_Request,
|
1584
|
+
func_default: 'Optional[int]' = None,
|
1585
|
+
func_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
1586
|
+
func_reversed: 'bool' = False,
|
1587
|
+
rate: 'int' = 0,
|
1588
|
+
ttl: 'timedelta | int' = 0,
|
1589
|
+
nonce: 'int' = 0,
|
1590
|
+
**kwargs: 'Any') -> 'Schema_QuickStartOption':
|
1591
|
+
"""Make HOPOPT QS option.
|
1592
|
+
|
1593
|
+
Args:
|
1594
|
+
code: option type value
|
1595
|
+
opt: option data
|
1596
|
+
func: QS function type
|
1597
|
+
func_default: default value for QS function type
|
1598
|
+
func_namespace: namespace for QS function type
|
1599
|
+
func_reversed: reversed flag for QS function type
|
1600
|
+
rate: rate (in kbps)
|
1601
|
+
ttl: time to live (in seconds)
|
1602
|
+
nonce: nonce value
|
1603
|
+
**kwargs: arbitrary keyword arguments
|
1604
|
+
|
1605
|
+
Returns:
|
1606
|
+
Constructured option schema.
|
1607
|
+
|
1608
|
+
"""
|
1609
|
+
if opt is not None:
|
1610
|
+
func_enum = opt.func
|
1611
|
+
rate = opt.rate
|
1612
|
+
ttl = getattr(opt, 'ttl', 0)
|
1613
|
+
nonce = getattr(opt, 'nonce', 0)
|
1614
|
+
else:
|
1615
|
+
func_enum = self._make_index(func, func_default, namespace=func_namespace, # type: ignore[assignment]
|
1616
|
+
reversed=func_reversed, pack=False)
|
1617
|
+
rate_val = math.floor(math.log2(rate * 1000 / 40000)) if rate > 0 else 0
|
1618
|
+
|
1619
|
+
if func_enum == Enum_QSFunction.Quick_Start_Request:
|
1620
|
+
ttl_value = ttl if isinstance(ttl, int) else math.floor(ttl.total_seconds())
|
1621
|
+
|
1622
|
+
return Schema_QuickStartRequestOption(
|
1623
|
+
type=code,
|
1624
|
+
len=6,
|
1625
|
+
flags={
|
1626
|
+
'func': func_enum,
|
1627
|
+
'rate': rate_val,
|
1628
|
+
},
|
1629
|
+
ttl=ttl_value,
|
1630
|
+
nonce={
|
1631
|
+
'nonce': nonce,
|
1632
|
+
},
|
1633
|
+
)
|
1634
|
+
if func_enum == Enum_QSFunction.Report_of_Approved_Rate:
|
1635
|
+
return Schema_QuickStartReportOption(
|
1636
|
+
type=code,
|
1637
|
+
len=6,
|
1638
|
+
flags={
|
1639
|
+
'func': func_enum,
|
1640
|
+
'rate': rate_val,
|
1641
|
+
},
|
1642
|
+
nonce={
|
1643
|
+
'nonce': nonce,
|
1644
|
+
},
|
1645
|
+
)
|
1646
|
+
raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid QS function: {func_enum}')
|
1647
|
+
|
1648
|
+
def _make_opt_rpl(self, code: 'Enum_Option', opt: 'Optional[Data_RPLOption]' = None, *,
|
1649
|
+
down: 'bool' = False,
|
1650
|
+
rank_err: 'bool' = False,
|
1651
|
+
fwd_err: 'bool' = False,
|
1652
|
+
id: 'int' = 0,
|
1653
|
+
rank: 'int' = 0,
|
1654
|
+
**kwargs: 'Any') -> 'Schema_RPLOption':
|
1655
|
+
"""Make HOPOPT RPL option.
|
1656
|
+
|
1657
|
+
Args:
|
1658
|
+
code: option type value
|
1659
|
+
opt: option data
|
1660
|
+
down: down flag
|
1661
|
+
rank_err: rank error flag
|
1662
|
+
fwd_err: forwarding error flag
|
1663
|
+
id: RPL instance ID
|
1664
|
+
rank: sender rank
|
1665
|
+
**kwargs: arbitrary keyword arguments
|
1666
|
+
|
1667
|
+
Returns:
|
1668
|
+
Constructured option schema.
|
1669
|
+
|
1670
|
+
"""
|
1671
|
+
if opt is not None:
|
1672
|
+
down = opt.flags.down
|
1673
|
+
rank_err = opt.flags.rank_err
|
1674
|
+
fwd_err = opt.flags.fwd_err
|
1675
|
+
id = opt.id
|
1676
|
+
rank = opt.rank
|
1677
|
+
|
1678
|
+
return Schema_RPLOption(
|
1679
|
+
type=code,
|
1680
|
+
len=4,
|
1681
|
+
flags={
|
1682
|
+
'down': down,
|
1683
|
+
'rank_err': rank_err,
|
1684
|
+
'fwd_err': fwd_err,
|
1685
|
+
},
|
1686
|
+
id=id,
|
1687
|
+
rank=rank,
|
1688
|
+
)
|
1689
|
+
|
1690
|
+
def _make_opt_mpl(self, code: 'Enum_Option', opt: 'Optional[Data_MPLOption]' = None, *,
|
1691
|
+
max: 'bool' = False,
|
1692
|
+
drop: 'bool' = False,
|
1693
|
+
seq: 'int' = 0,
|
1694
|
+
seed: 'Optional[int]' = None,
|
1695
|
+
**kwargs: 'Any') -> 'Schema_MPLOption':
|
1696
|
+
"""Make HOPOPT MPL option.
|
1697
|
+
|
1698
|
+
Args:
|
1699
|
+
code: option type value
|
1700
|
+
opt: option data
|
1701
|
+
max: maximum sequence number flag
|
1702
|
+
drop: drop packet flag
|
1703
|
+
seq: MPL sequence number
|
1704
|
+
seed: MPL seed ID
|
1705
|
+
**kwargs: arbitrary keyword arguments
|
1706
|
+
|
1707
|
+
Returns:
|
1708
|
+
Constructured option schema.
|
1709
|
+
|
1710
|
+
"""
|
1711
|
+
if opt is not None:
|
1712
|
+
max = opt.flags.max
|
1713
|
+
drop = opt.flags.drop
|
1714
|
+
seq = opt.seq
|
1715
|
+
seed = opt.seed_id
|
1716
|
+
|
1717
|
+
if seed is None:
|
1718
|
+
kind = Enum_SeedID.IPV6_SOURCE_ADDRESS
|
1719
|
+
clen = 2
|
1720
|
+
else:
|
1721
|
+
seed_bl = seed.bit_length()
|
1722
|
+
if seed_bl <= 16:
|
1723
|
+
kind = Enum_SeedID.SEEDID_16_BIT_UNSIGNED_INTEGER
|
1724
|
+
clen = 4
|
1725
|
+
elif seed_bl <= 64:
|
1726
|
+
kind = Enum_SeedID.SEEDID_64_BIT_UNSIGNED_INTEGER
|
1727
|
+
clen = 10
|
1728
|
+
elif seed_bl <= 128:
|
1729
|
+
kind = Enum_SeedID.SEEDID_128_BIT_UNSIGNED_INTEGER
|
1730
|
+
clen = 18
|
1731
|
+
else:
|
1732
|
+
raise ProtocolError(f'{self.alias}: [OptNo {code}] too large MPL seed ID: {seed}')
|
1733
|
+
|
1734
|
+
return Schema_MPLOption(
|
1735
|
+
type=code,
|
1736
|
+
len=clen,
|
1737
|
+
flags={
|
1738
|
+
'type': kind,
|
1739
|
+
'max': max,
|
1740
|
+
'drop': drop,
|
1741
|
+
},
|
1742
|
+
seq=seq,
|
1743
|
+
seed=seed,
|
1744
|
+
)
|
1745
|
+
|
1746
|
+
def _make_opt_ilnp(self, code: 'Enum_Option', opt: 'Optional[Data_ILNPOption]' = None, *,
|
1747
|
+
nonce: 'int' = 0,
|
1748
|
+
**kwargs: 'Any') -> 'Schema_ILNPOption':
|
1749
|
+
"""Make HOPOPT ILNP option.
|
1750
|
+
|
1751
|
+
Args:
|
1752
|
+
code: option type value
|
1753
|
+
opt: option data
|
1754
|
+
nonce: ILNP nonce value
|
1755
|
+
**kwargs: arbitrary keyword arguments
|
1756
|
+
|
1757
|
+
Returns:
|
1758
|
+
Constructured option schema.
|
1759
|
+
|
1760
|
+
"""
|
1761
|
+
if opt is not None:
|
1762
|
+
nonce = opt.nonce
|
1763
|
+
|
1764
|
+
return Schema_ILNPOption(
|
1765
|
+
type=code,
|
1766
|
+
len=math.ceil(nonce.bit_length() // 8),
|
1767
|
+
nonce=nonce,
|
1768
|
+
)
|
1769
|
+
|
1770
|
+
def _make_opt_lio(self, code: 'Enum_Option', opt: 'Optional[Data_LineIdentificationOption]' = None, *,
|
1771
|
+
id: 'bytes' = b'',
|
1772
|
+
**kwargs: 'Any') -> 'Schema_LineIdentificationOption':
|
1773
|
+
"""Make HOPOPT LIO option.
|
1774
|
+
|
1775
|
+
Args:
|
1776
|
+
code: option type value
|
1777
|
+
opt: option data
|
1778
|
+
id: line ID value
|
1779
|
+
**kwargs: arbitrary keyword arguments
|
1780
|
+
|
1781
|
+
Returns:
|
1782
|
+
Constructured option schema.
|
1783
|
+
|
1784
|
+
"""
|
1785
|
+
if opt is not None:
|
1786
|
+
id = opt.line_id
|
1787
|
+
|
1788
|
+
return Schema_LineIdentificationOption(
|
1789
|
+
type=code,
|
1790
|
+
len=len(id) + 1,
|
1791
|
+
id_len=len(id),
|
1792
|
+
id=id,
|
1793
|
+
)
|
1794
|
+
|
1795
|
+
def _make_opt_jumbo(self, code: 'Enum_Option', opt: 'Optional[Data_JumboPayloadOption]' = None, *,
|
1796
|
+
len: 'int' = 0,
|
1797
|
+
**kwargs: 'Any') -> 'Schema_JumboPayloadOption':
|
1798
|
+
"""Make HOPOPT Jumbo Payload option.
|
1799
|
+
|
1800
|
+
Args:
|
1801
|
+
code: option type value
|
1802
|
+
opt: option data
|
1803
|
+
len: jumbo payload length
|
1804
|
+
**kwargs: arbitrary keyword arguments
|
1805
|
+
|
1806
|
+
Returns:
|
1807
|
+
Constructured option schema.
|
1808
|
+
|
1809
|
+
"""
|
1810
|
+
if opt is not None:
|
1811
|
+
len = opt.jumbo_len
|
1812
|
+
|
1813
|
+
return Schema_JumboPayloadOption(
|
1814
|
+
type=code,
|
1815
|
+
len=4,
|
1816
|
+
jumbo_len=len,
|
1817
|
+
)
|
1818
|
+
|
1819
|
+
def _make_opt_home(self, code: 'Enum_Option', opt: 'Optional[Data_HomeAddressOption]' = None, *,
|
1820
|
+
addr: 'IPv6Address | str | bytes | int' = '::',
|
1821
|
+
**kwargs: 'Any') -> 'Schema_HomeAddressOption':
|
1822
|
+
"""Make HOPOPT Home Address option.
|
1823
|
+
|
1824
|
+
Args:
|
1825
|
+
code: option type value
|
1826
|
+
opt: option data
|
1827
|
+
addr: home address value
|
1828
|
+
**kwargs: arbitrary keyword arguments
|
1829
|
+
|
1830
|
+
Returns:
|
1831
|
+
Constructured option schema.
|
1832
|
+
|
1833
|
+
"""
|
1834
|
+
if opt is not None:
|
1835
|
+
addr = opt.address
|
1836
|
+
|
1837
|
+
return Schema_HomeAddressOption(
|
1838
|
+
type=code,
|
1839
|
+
len=16,
|
1840
|
+
addr=addr,
|
1841
|
+
)
|
1842
|
+
|
1843
|
+
def _make_opt_ip_dff(self, code: 'Enum_Option', opt: 'Optional[Data_IPDFFOption]' = None, *,
|
1844
|
+
version: 'int' = 0,
|
1845
|
+
dup: 'bool' = False,
|
1846
|
+
ret: 'bool' = False,
|
1847
|
+
seq: 'int' = 0,
|
1848
|
+
**kwargs: 'Any') -> 'Schema_IPDFFOption':
|
1849
|
+
"""Make HOPOPT IP DFF option.
|
1850
|
+
|
1851
|
+
Args:
|
1852
|
+
code: option type value
|
1853
|
+
opt: option data
|
1854
|
+
version: DFF version
|
1855
|
+
dup: duplicate packet flag
|
1856
|
+
ret: return packet flag
|
1857
|
+
seq: DFF sequence number
|
1858
|
+
**kwargs: arbitrary keyword arguments
|
1859
|
+
|
1860
|
+
Returns:
|
1861
|
+
Constructured option schema.
|
1862
|
+
|
1863
|
+
"""
|
1864
|
+
if opt is not None:
|
1865
|
+
version = opt.version
|
1866
|
+
dup = opt.flags.dup
|
1867
|
+
ret = opt.flags.ret
|
1868
|
+
seq = opt.seq
|
1869
|
+
|
1870
|
+
return Schema_IPDFFOption(
|
1871
|
+
type=code,
|
1872
|
+
len=2,
|
1873
|
+
flags={
|
1874
|
+
'ver': version,
|
1875
|
+
'dup': dup,
|
1876
|
+
'ret': ret,
|
1877
|
+
},
|
1878
|
+
seq=seq,
|
1879
|
+
)
|