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,1782 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""IPv4 - Internet Protocol version 4
|
3
|
+
========================================
|
4
|
+
|
5
|
+
.. module:: pcapkit.protocols.internet.ipv4
|
6
|
+
|
7
|
+
:mod:`pcapkit.protocols.internet.ipv4` contains
|
8
|
+
:class:`~pcapkit.protocols.internet.ipv4.IPv4` only,
|
9
|
+
which implements extractor for Internet Protocol
|
10
|
+
version 4 (IPv4) [*]_, whose structure is described
|
11
|
+
as below:
|
12
|
+
|
13
|
+
======= ========= ====================== =============================================
|
14
|
+
Octets Bits Name Description
|
15
|
+
======= ========= ====================== =============================================
|
16
|
+
0 0 ``ip.version`` Version (``4``)
|
17
|
+
0 4 ``ip.hdr_len`` Internal Header Length (IHL)
|
18
|
+
1 8 ``ip.dsfield.dscp`` Differentiated Services Code Point (DSCP)
|
19
|
+
1 14 ``ip.dsfield.ecn`` Explicit Congestion Notification (ECN)
|
20
|
+
2 16 ``ip.len`` Total Length
|
21
|
+
4 32 ``ip.id`` Identification
|
22
|
+
6 48 Reserved Bit (must be ``\\x00``)
|
23
|
+
6 49 ``ip.flags.df`` Don't Fragment (DF)
|
24
|
+
6 50 ``ip.flags.mf`` More Fragments (MF)
|
25
|
+
6 51 ``ip.frag_offset`` Fragment Offset
|
26
|
+
8 64 ``ip.ttl`` Time To Live (TTL)
|
27
|
+
9 72 ``ip.proto`` Protocol (Transport Layer)
|
28
|
+
10 80 ``ip.checksum`` Header Checksum
|
29
|
+
12 96 ``ip.src`` Source IP Address
|
30
|
+
16 128 ``ip.dst`` Destination IP Address
|
31
|
+
20 160 ``ip.options`` IP Options (if IHL > ``5``)
|
32
|
+
======= ========= ====================== =============================================
|
33
|
+
|
34
|
+
.. [*] https://en.wikipedia.org/wiki/IPv4
|
35
|
+
|
36
|
+
"""
|
37
|
+
import datetime
|
38
|
+
import ipaddress
|
39
|
+
import math
|
40
|
+
from typing import TYPE_CHECKING, cast
|
41
|
+
|
42
|
+
from pcapkit.const.ipv4.classification_level import ClassificationLevel as Enum_ClassificationLevel
|
43
|
+
from pcapkit.const.ipv4.option_class import OptionClass as Enum_OptionClass
|
44
|
+
from pcapkit.const.ipv4.option_number import OptionNumber as Enum_OptionNumber
|
45
|
+
from pcapkit.const.ipv4.protection_authority import ProtectionAuthority as Enum_ProtectionAuthority
|
46
|
+
from pcapkit.const.ipv4.qs_function import QSFunction as Enum_QSFunction
|
47
|
+
from pcapkit.const.ipv4.router_alert import RouterAlert as Enum_RouterAlert
|
48
|
+
from pcapkit.const.ipv4.tos_del import ToSDelay as Enum_ToSDelay
|
49
|
+
from pcapkit.const.ipv4.tos_ecn import ToSECN as Enum_ToSECN
|
50
|
+
from pcapkit.const.ipv4.tos_pre import ToSPrecedence as Enum_ToSPrecedence
|
51
|
+
from pcapkit.const.ipv4.tos_rel import ToSReliability as Enum_ToSReliability
|
52
|
+
from pcapkit.const.ipv4.tos_thr import ToSThroughput as Enum_ToSThroughput
|
53
|
+
from pcapkit.const.ipv4.ts_flag import TSFlag as Enum_TSFlag
|
54
|
+
from pcapkit.const.reg.transtype import TransType as Enum_TransType
|
55
|
+
from pcapkit.corekit.multidict import OrderedMultiDict
|
56
|
+
from pcapkit.protocols.data.internet.ipv4 import EOOLOption as Data_EOOLOption
|
57
|
+
from pcapkit.protocols.data.internet.ipv4 import ESECOption as Data_ESECOption
|
58
|
+
from pcapkit.protocols.data.internet.ipv4 import Flags as Data_Flags
|
59
|
+
from pcapkit.protocols.data.internet.ipv4 import IPv4 as Data_IPv4
|
60
|
+
from pcapkit.protocols.data.internet.ipv4 import LSROption as Data_LSROption
|
61
|
+
from pcapkit.protocols.data.internet.ipv4 import MTUPOption as Data_MTUPOption
|
62
|
+
from pcapkit.protocols.data.internet.ipv4 import MTUROption as Data_MTUROption
|
63
|
+
from pcapkit.protocols.data.internet.ipv4 import NOPOption as Data_NOPOption
|
64
|
+
from pcapkit.protocols.data.internet.ipv4 import OptionType as Data_OptionType
|
65
|
+
from pcapkit.protocols.data.internet.ipv4 import QSOption as Data_QSOption
|
66
|
+
from pcapkit.protocols.data.internet.ipv4 import \
|
67
|
+
QuickStartReportOption as Data_QuickStartReportOption
|
68
|
+
from pcapkit.protocols.data.internet.ipv4 import \
|
69
|
+
QuickStartRequestOption as Data_QuickStartRequestOption
|
70
|
+
from pcapkit.protocols.data.internet.ipv4 import RROption as Data_RROption
|
71
|
+
from pcapkit.protocols.data.internet.ipv4 import RTRALTOption as Data_RTRALTOption
|
72
|
+
from pcapkit.protocols.data.internet.ipv4 import SECOption as Data_SECOption
|
73
|
+
from pcapkit.protocols.data.internet.ipv4 import SIDOption as Data_SIDOption
|
74
|
+
from pcapkit.protocols.data.internet.ipv4 import SSROption as Data_SSROption
|
75
|
+
from pcapkit.protocols.data.internet.ipv4 import ToSField as Data_ToSField
|
76
|
+
from pcapkit.protocols.data.internet.ipv4 import TROption as Data_TROption
|
77
|
+
from pcapkit.protocols.data.internet.ipv4 import TSOption as Data_TSOption
|
78
|
+
from pcapkit.protocols.data.internet.ipv4 import UnassignedOption as Data_UnassignedOption
|
79
|
+
from pcapkit.protocols.internet.ip import IP
|
80
|
+
from pcapkit.protocols.schema.internet.ipv4 import EOOLOption as Schema_EOOLOption
|
81
|
+
from pcapkit.protocols.schema.internet.ipv4 import ESECOption as Schema_ESECOption
|
82
|
+
from pcapkit.protocols.schema.internet.ipv4 import IPv4 as Schema_IPv4
|
83
|
+
from pcapkit.protocols.schema.internet.ipv4 import LSROption as Schema_LSROption
|
84
|
+
from pcapkit.protocols.schema.internet.ipv4 import MTUPOption as Schema_MTUPOption
|
85
|
+
from pcapkit.protocols.schema.internet.ipv4 import MTUROption as Schema_MTUROption
|
86
|
+
from pcapkit.protocols.schema.internet.ipv4 import NOPOption as Schema_NOPOption
|
87
|
+
from pcapkit.protocols.schema.internet.ipv4 import QSOption as Schema_QSOption
|
88
|
+
from pcapkit.protocols.schema.internet.ipv4 import \
|
89
|
+
QuickStartReportOption as Schema_QuickStartReportOption
|
90
|
+
from pcapkit.protocols.schema.internet.ipv4 import \
|
91
|
+
QuickStartRequestOption as Schema_QuickStartRequestOption
|
92
|
+
from pcapkit.protocols.schema.internet.ipv4 import RROption as Schema_RROption
|
93
|
+
from pcapkit.protocols.schema.internet.ipv4 import RTRALTOption as Schema_RTRALTOption
|
94
|
+
from pcapkit.protocols.schema.internet.ipv4 import SECOption as Schema_SECOption
|
95
|
+
from pcapkit.protocols.schema.internet.ipv4 import SIDOption as Schema_SIDOption
|
96
|
+
from pcapkit.protocols.schema.internet.ipv4 import SSROption as Schema_SSROption
|
97
|
+
from pcapkit.protocols.schema.internet.ipv4 import TROption as Schema_TROption
|
98
|
+
from pcapkit.protocols.schema.internet.ipv4 import TSOption as Schema_TSOption
|
99
|
+
from pcapkit.protocols.schema.internet.ipv4 import UnassignedOption as Schema_UnassignedOption
|
100
|
+
from pcapkit.protocols.schema.schema import Schema
|
101
|
+
from pcapkit.utilities.exceptions import ProtocolError
|
102
|
+
from pcapkit.utilities.warnings import ProtocolWarning, RegistryWarning, warn
|
103
|
+
|
104
|
+
if TYPE_CHECKING:
|
105
|
+
from datetime import timedelta
|
106
|
+
from enum import IntEnum as StdlibEnum
|
107
|
+
from ipaddress import IPv4Address
|
108
|
+
from typing import Any, Callable, Optional, Type
|
109
|
+
|
110
|
+
from aenum import IntEnum as AenumEnum
|
111
|
+
from mypy_extensions import DefaultArg, KwArg, NamedArg
|
112
|
+
from typing_extensions import Literal
|
113
|
+
|
114
|
+
from pcapkit.protocols.data.internet.ipv4 import Option as Data_Option
|
115
|
+
from pcapkit.protocols.protocol import ProtocolBase as Protocol
|
116
|
+
from pcapkit.protocols.schema.internet.ipv4 import Option as Schema_Option
|
117
|
+
|
118
|
+
Option = OrderedMultiDict[Enum_OptionNumber, Data_Option]
|
119
|
+
OptionParser = Callable[[Schema_Option, NamedArg(Option, 'options')], Data_Option]
|
120
|
+
OptionConstructor = Callable[[Enum_OptionNumber, DefaultArg(Optional[Data_Option]),
|
121
|
+
KwArg(Any)], Schema_Option]
|
122
|
+
|
123
|
+
__all__ = ['IPv4']
|
124
|
+
|
125
|
+
|
126
|
+
class IPv4(IP[Data_IPv4, Schema_IPv4],
|
127
|
+
schema=Schema_IPv4, data=Data_IPv4):
|
128
|
+
"""This class implements Internet Protocol version 4.
|
129
|
+
|
130
|
+
This class currently supports parsing of the following IPv4 options,
|
131
|
+
which are directly mapped to the :class:`pcapkit.const.ipv4.option_number.OptionNumber`
|
132
|
+
enumeration:
|
133
|
+
|
134
|
+
.. list-table::
|
135
|
+
:header-rows: 1
|
136
|
+
|
137
|
+
* - Option Code
|
138
|
+
- Option Parser
|
139
|
+
- Option Constructor
|
140
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.EOOL`
|
141
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_eool`
|
142
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_eool`
|
143
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.NOP`
|
144
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_nop`
|
145
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_nop`
|
146
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.SEC`
|
147
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_sec`
|
148
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_sec`
|
149
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.LSR`
|
150
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_lsr`
|
151
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_lsr`
|
152
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.TS`
|
153
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_ts`
|
154
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_ts`
|
155
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.E_SEC`
|
156
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_e_sec`
|
157
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_e_sec`
|
158
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.RR`
|
159
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_rr`
|
160
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_rr`
|
161
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.SID`
|
162
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_sid`
|
163
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_sid`
|
164
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.SSR`
|
165
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_ssr`
|
166
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_ssr`
|
167
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.MTUP`
|
168
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_mtup`
|
169
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_mtup`
|
170
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.MTUR`
|
171
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_mtur`
|
172
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_mtur`
|
173
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.TR`
|
174
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_tr`
|
175
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_tr`
|
176
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.RTRALT`
|
177
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_rtralt`
|
178
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_rtralt`
|
179
|
+
* - :attr:`~pcapkit.const.ipv4.option_number.OptionNumber.QS`
|
180
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._read_opt_qs`
|
181
|
+
- :meth:`~pcapkit.protocols.internet.ipv4.IPv4._make_opt_qs`
|
182
|
+
|
183
|
+
"""
|
184
|
+
|
185
|
+
##########################################################################
|
186
|
+
# Properties.
|
187
|
+
##########################################################################
|
188
|
+
|
189
|
+
@property
|
190
|
+
def name(self) -> 'Literal["Internet Protocol version 4"]':
|
191
|
+
"""Name of corresponding protocol."""
|
192
|
+
return 'Internet Protocol version 4'
|
193
|
+
|
194
|
+
@property
|
195
|
+
def length(self) -> 'int':
|
196
|
+
"""Header length of corresponding protocol."""
|
197
|
+
return self._info.hdr_len
|
198
|
+
|
199
|
+
@property
|
200
|
+
def protocol(self) -> 'Enum_TransType':
|
201
|
+
"""Name of next layer protocol."""
|
202
|
+
return self._info.protocol
|
203
|
+
|
204
|
+
# source IP address
|
205
|
+
@property
|
206
|
+
def src(self) -> 'IPv4Address':
|
207
|
+
"""Source IP address."""
|
208
|
+
return self._info.src
|
209
|
+
|
210
|
+
# destination IP address
|
211
|
+
@property
|
212
|
+
def dst(self) -> 'IPv4Address':
|
213
|
+
"""Destination IP address."""
|
214
|
+
return self._info.dst
|
215
|
+
|
216
|
+
##########################################################################
|
217
|
+
# Methods.
|
218
|
+
##########################################################################
|
219
|
+
|
220
|
+
def read(self, length: 'Optional[int]' = None, **kwargs: 'Any') -> 'Data_IPv4': # pylint: disable=unused-argument
|
221
|
+
"""Read Internet Protocol version 4 (IPv4).
|
222
|
+
|
223
|
+
Structure of IPv4 header [:rfc:`791`]:
|
224
|
+
|
225
|
+
.. code-block:: text
|
226
|
+
|
227
|
+
0 1 2 3
|
228
|
+
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
|
229
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
230
|
+
|Version| IHL |Type of Service| Total Length |
|
231
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
232
|
+
| Identification |Flags| Fragment Offset |
|
233
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
234
|
+
| Time to Live | Protocol | Header Checksum |
|
235
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
236
|
+
| Source Address |
|
237
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
238
|
+
| Destination Address |
|
239
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
240
|
+
| Options | Padding |
|
241
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
242
|
+
|
243
|
+
Args:
|
244
|
+
length: Length of packet data.
|
245
|
+
**kwargs: Arbitrary keyword arguments.
|
246
|
+
|
247
|
+
Returns:
|
248
|
+
Parsed packet data.
|
249
|
+
|
250
|
+
"""
|
251
|
+
if length is None:
|
252
|
+
length = len(self)
|
253
|
+
schema = self.__header__
|
254
|
+
|
255
|
+
if schema.vihl['version'] != 4:
|
256
|
+
raise ProtocolError(f"[IPv4] invalid version: {schema.vihl['version']}")
|
257
|
+
|
258
|
+
ipv4 = Data_IPv4(
|
259
|
+
version=schema.vihl['version'], # type: ignore[arg-type]
|
260
|
+
hdr_len=schema.vihl['ihl'] * 4,
|
261
|
+
tos=Data_ToSField.from_dict({
|
262
|
+
'pre': Enum_ToSPrecedence.get(schema.tos['pre']),
|
263
|
+
'del': Enum_ToSDelay.get(schema.tos['del']),
|
264
|
+
'thr': Enum_ToSThroughput.get(schema.tos['thr']),
|
265
|
+
'rel': Enum_ToSReliability.get(schema.tos['rel']),
|
266
|
+
'ecn': Enum_ToSECN.get(schema.tos['ecn']),
|
267
|
+
}),
|
268
|
+
len=schema.length,
|
269
|
+
id=schema.id,
|
270
|
+
flags=Data_Flags(
|
271
|
+
df=bool(schema.flags['df']),
|
272
|
+
mf=bool(schema.flags['mf']),
|
273
|
+
),
|
274
|
+
offset=int(schema.flags['offset']) * 8,
|
275
|
+
ttl=datetime.timedelta(seconds=schema.ttl),
|
276
|
+
protocol=schema.proto,
|
277
|
+
checksum=schema.chksum,
|
278
|
+
src=schema.src,
|
279
|
+
dst=schema.dst,
|
280
|
+
)
|
281
|
+
|
282
|
+
_optl = ipv4.hdr_len - 20
|
283
|
+
if _optl:
|
284
|
+
ipv4.__update__([
|
285
|
+
('options', self._read_ipv4_options(_optl)),
|
286
|
+
])
|
287
|
+
|
288
|
+
return self._decode_next_layer(ipv4, ipv4.protocol, ipv4.len - ipv4.hdr_len)
|
289
|
+
|
290
|
+
def make(self,
|
291
|
+
tos_pre: 'Enum_ToSPrecedence | StdlibEnum | AenumEnum | int | str' = Enum_ToSPrecedence.Routine,
|
292
|
+
tos_pre_default: 'Optional[int]' = None,
|
293
|
+
tos_pre_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
294
|
+
tos_pre_reversed: 'bool' = False,
|
295
|
+
tos_del: 'Enum_ToSDelay | StdlibEnum | AenumEnum | int | str' = Enum_ToSDelay.NORMAL,
|
296
|
+
tos_del_default: 'Optional[int]' = None,
|
297
|
+
tos_del_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
298
|
+
tos_del_reversed: 'bool' = False,
|
299
|
+
tos_thr: 'Enum_ToSThroughput | StdlibEnum | AenumEnum | int | str' = Enum_ToSThroughput.NORMAL,
|
300
|
+
tos_thr_default: 'Optional[int]' = None,
|
301
|
+
tos_thr_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
302
|
+
tos_thr_reversed: 'bool' = False,
|
303
|
+
tos_rel: 'Enum_ToSReliability | StdlibEnum | AenumEnum | int | str' = Enum_ToSReliability.NORMAL,
|
304
|
+
tos_rel_default: 'Optional[int]' = None,
|
305
|
+
tos_rel_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
306
|
+
tos_rel_reversed: 'bool' = False,
|
307
|
+
tos_ecn: 'Enum_ToSECN | StdlibEnum | AenumEnum | int | str' = Enum_ToSECN.Not_ECT,
|
308
|
+
tos_ecn_default: 'Optional[int]' = None,
|
309
|
+
tos_ecn_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
310
|
+
tos_ecn_reversed: 'bool' = False,
|
311
|
+
id: 'int' = 0,
|
312
|
+
df: 'bool' = False,
|
313
|
+
mf: 'bool' = False,
|
314
|
+
offset: 'int' = 0,
|
315
|
+
ttl: 'timedelta | int' = 0,
|
316
|
+
protocol: 'Enum_TransType | StdlibEnum | AenumEnum | int | str' = Enum_TransType.UDP,
|
317
|
+
protocol_default: 'Optional[int]' = None,
|
318
|
+
protocol_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
319
|
+
protocol_reversed: 'bool' = False,
|
320
|
+
checksum: 'bytes' = b'\x00\x00',
|
321
|
+
src: 'IPv4Address | str | int | bytes' = '127.0.0.1',
|
322
|
+
dst: 'IPv4Address | str | int | bytes' = '0.0.0.0', # nosec: B104
|
323
|
+
options: 'Optional[list[Schema_Option | tuple[Enum_OptionNumber, dict[str, Any]] | bytes] | Option]' = None, # pylint: disable=line-too-long
|
324
|
+
payload: 'bytes | Protocol | Schema' = b'',
|
325
|
+
**kwargs: 'Any') -> 'Schema_IPv4':
|
326
|
+
"""Make (construct) packet data.
|
327
|
+
|
328
|
+
Args:
|
329
|
+
tos_pre: Precedence of the packet.
|
330
|
+
tos_pre_default: Default value of ``tos_pre``.
|
331
|
+
tos_pre_namespace: Namespace of ``tos_pre``.
|
332
|
+
tos_pre_reversed: If the namespace of ``tos_pre`` is reversed.
|
333
|
+
tos_del: Delay of the packet.
|
334
|
+
tos_del_default: Default value of ``tos_del``.
|
335
|
+
tos_del_namespace: Namespace of ``tos_del``.
|
336
|
+
tos_del_reversed: If the namespace of ``tos_del`` is reversed.
|
337
|
+
tos_thr: Throughput of the packet.
|
338
|
+
tos_thr_default: Default value of ``tos_thr``.
|
339
|
+
tos_thr_namespace: Namespace of ``tos_thr``.
|
340
|
+
tos_thr_reversed: If the namespace of ``tos_thr`` is reversed.
|
341
|
+
tos_rel: Reliability of the packet.
|
342
|
+
tos_rel_default: Default value of ``tos_rel``.
|
343
|
+
tos_rel_namespace: Namespace of ``tos_rel``.
|
344
|
+
tos_rel_reversed: If the namespace of ``tos_rel`` is reversed.
|
345
|
+
tos_ecn: ECN of the packet.
|
346
|
+
tos_ecn_default: Default value of ``tos_ecn``.
|
347
|
+
tos_ecn_namespace: Namespace of ``tos_ecn``.
|
348
|
+
tos_ecn_reversed: If the namespace of ``tos_ecn`` is reversed.
|
349
|
+
id: Identification of the packet.
|
350
|
+
df: Don't fragment flag.
|
351
|
+
mf: More fragments flag.
|
352
|
+
offset: Fragment offset.
|
353
|
+
ttl: Time to live of the packet.
|
354
|
+
protocol: Payload protocol of the packet.
|
355
|
+
protocol_default: Default value of ``protocol``.
|
356
|
+
protocol_namespace: Namespace of ``protocol``.
|
357
|
+
protocol_reversed: If the namespace of ``protocol`` is reversed.
|
358
|
+
checksum: Checksum of the packet.
|
359
|
+
src: Source address of the packet.
|
360
|
+
dst: Destination address of the packet.
|
361
|
+
options: Options of the packet.
|
362
|
+
payload: Payload of the packet.
|
363
|
+
**kwargs: Arbitrary keyword arguments.
|
364
|
+
|
365
|
+
Returns:
|
366
|
+
Constructed packet data.
|
367
|
+
|
368
|
+
"""
|
369
|
+
tos_pre_val = self._make_index(tos_pre, tos_pre_default, namespace=tos_pre_namespace,
|
370
|
+
reversed=tos_pre_reversed, pack=False)
|
371
|
+
tos_del_val = self._make_index(tos_del, tos_del_default, namespace=tos_del_namespace,
|
372
|
+
reversed=tos_del_reversed, pack=False)
|
373
|
+
tos_thr_val = self._make_index(tos_thr, tos_thr_default, namespace=tos_thr_namespace,
|
374
|
+
reversed=tos_thr_reversed, pack=False)
|
375
|
+
tos_rel_val = self._make_index(tos_rel, tos_rel_default, namespace=tos_rel_namespace,
|
376
|
+
reversed=tos_rel_reversed, pack=False)
|
377
|
+
tos_ecn_val = self._make_index(tos_ecn, tos_ecn_default, namespace=tos_ecn_namespace,
|
378
|
+
reversed=tos_ecn_reversed, pack=False)
|
379
|
+
|
380
|
+
proto = self._make_index(protocol, protocol_default, namespace=protocol_namespace,
|
381
|
+
reversed=protocol_reversed, pack=False)
|
382
|
+
ttl_val = ttl if isinstance(ttl, int) else math.ceil(ttl.total_seconds())
|
383
|
+
|
384
|
+
if options is not None:
|
385
|
+
options_value, total_length = self._make_ipv4_options(options)
|
386
|
+
else:
|
387
|
+
options_value, total_length = [], 0
|
388
|
+
|
389
|
+
ihl = 5 + math.ceil(total_length / 4)
|
390
|
+
len = ihl * 4 + len(payload)
|
391
|
+
|
392
|
+
return Schema_IPv4(
|
393
|
+
vihl={
|
394
|
+
'version': 4,
|
395
|
+
'ihl': ihl,
|
396
|
+
},
|
397
|
+
tos={
|
398
|
+
'pre': tos_pre_val,
|
399
|
+
'del': tos_del_val,
|
400
|
+
'thr': tos_thr_val,
|
401
|
+
'rel': tos_rel_val,
|
402
|
+
'ecn': tos_ecn_val,
|
403
|
+
},
|
404
|
+
length=len,
|
405
|
+
id=id,
|
406
|
+
flags={
|
407
|
+
'df': df,
|
408
|
+
'mf': mf,
|
409
|
+
'offset': offset,
|
410
|
+
},
|
411
|
+
ttl=ttl_val,
|
412
|
+
proto=proto, # type: ignore[arg-type]
|
413
|
+
chksum=checksum,
|
414
|
+
src=src,
|
415
|
+
dst=dst,
|
416
|
+
options=options_value,
|
417
|
+
payload=payload,
|
418
|
+
)
|
419
|
+
|
420
|
+
@classmethod
|
421
|
+
def id(cls) -> 'tuple[Literal["IPv4"]]': # type: ignore[override]
|
422
|
+
"""Index ID of the protocol.
|
423
|
+
|
424
|
+
Returns:
|
425
|
+
Index ID of the protocol.
|
426
|
+
|
427
|
+
"""
|
428
|
+
return ('IPv4',)
|
429
|
+
|
430
|
+
@classmethod
|
431
|
+
def register_option(cls, code: 'Enum_OptionNumber', meth: 'str | tuple[OptionParser, OptionConstructor]') -> 'None':
|
432
|
+
"""Register an option parser.
|
433
|
+
|
434
|
+
Args:
|
435
|
+
code: IPv4 option code.
|
436
|
+
meth: Method name or callable to parse and/or construct the option.
|
437
|
+
|
438
|
+
"""
|
439
|
+
name = code.name.lower()
|
440
|
+
if hasattr(cls, f'_read_opt_{name}'):
|
441
|
+
warn(f'option {code} already registered, overwriting', RegistryWarning)
|
442
|
+
|
443
|
+
if isinstance(meth, str):
|
444
|
+
meth = (getattr(cls, f'_read_opt_{meth}', cls._read_opt_unassigned), # type: ignore[arg-type]
|
445
|
+
getattr(cls, f'_make_opt_{meth}', cls._make_opt_unassigned)) # type: ignore[arg-type]
|
446
|
+
|
447
|
+
setattr(cls, f'_read_opt_{name}', meth[0])
|
448
|
+
setattr(cls, f'_make_opt_{name}', meth[1])
|
449
|
+
|
450
|
+
##########################################################################
|
451
|
+
# Data models.
|
452
|
+
##########################################################################
|
453
|
+
|
454
|
+
def __length_hint__(self) -> 'Literal[20]':
|
455
|
+
"""Return an estimated length for the object."""
|
456
|
+
return 20
|
457
|
+
|
458
|
+
@classmethod
|
459
|
+
def __index__(cls) -> 'Enum_TransType': # pylint: disable=invalid-index-returned
|
460
|
+
"""Numeral registry index of the protocol.
|
461
|
+
|
462
|
+
Returns:
|
463
|
+
Numeral registry index of the protocol in `IANA`_.
|
464
|
+
|
465
|
+
.. _IANA: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
466
|
+
|
467
|
+
"""
|
468
|
+
return Enum_TransType.IPv4 # type: ignore[return-value]
|
469
|
+
|
470
|
+
##########################################################################
|
471
|
+
# Utilities.
|
472
|
+
##########################################################################
|
473
|
+
|
474
|
+
@classmethod
|
475
|
+
def _make_data(cls, data: 'Data_IPv4') -> 'dict[str, Any]': # type: ignore[override]
|
476
|
+
"""Create key-value pairs from ``data`` for protocol construction.
|
477
|
+
|
478
|
+
Args:
|
479
|
+
data: protocol data
|
480
|
+
|
481
|
+
Returns:
|
482
|
+
Key-value pairs for protocol construction.
|
483
|
+
|
484
|
+
"""
|
485
|
+
return {
|
486
|
+
'tos_pre': data.tos.pre,
|
487
|
+
'tos_del': data.tos['del'],
|
488
|
+
'tos_thr': data.tos.thr,
|
489
|
+
'tos_rel': data.tos.rel,
|
490
|
+
'tos_ecn': data.tos.ecn,
|
491
|
+
'id': data.id,
|
492
|
+
'df': data.flags.df,
|
493
|
+
'mf': data.flags.mf,
|
494
|
+
'offset': data.offset,
|
495
|
+
'ttl': data.ttl,
|
496
|
+
'protocol': data.protocol,
|
497
|
+
'checksum': data.checksum,
|
498
|
+
'src': data.src,
|
499
|
+
'dst': data.dst,
|
500
|
+
'options': data.options,
|
501
|
+
'payload': cls._make_payload(data),
|
502
|
+
}
|
503
|
+
|
504
|
+
def _read_ipv4_addr(self) -> 'IPv4Address':
|
505
|
+
"""Read IP address.
|
506
|
+
|
507
|
+
Returns:
|
508
|
+
Parsed IP address.
|
509
|
+
|
510
|
+
"""
|
511
|
+
_byte = self._read_fileng(4)
|
512
|
+
# _addr = '.'.join([str(_) for _ in _byte])
|
513
|
+
# return _addr
|
514
|
+
return ipaddress.ip_address(_byte) # type: ignore[return-value]
|
515
|
+
|
516
|
+
def _read_ipv4_opt_type(self, code: 'int') -> 'Data_OptionType':
|
517
|
+
"""Read option type field.
|
518
|
+
|
519
|
+
Arguments:
|
520
|
+
code: option kind value
|
521
|
+
|
522
|
+
Returns:
|
523
|
+
Extracted IPv4 option type, as an object of the option flag (copied
|
524
|
+
flag), option class, and option number.
|
525
|
+
|
526
|
+
"""
|
527
|
+
oflg = bool(code >> 7)
|
528
|
+
ocls = Enum_OptionClass.get((code >> 5) & 0b11)
|
529
|
+
onum = code & 0b11111
|
530
|
+
|
531
|
+
return Data_OptionType.from_dict({
|
532
|
+
'change': oflg,
|
533
|
+
'class': ocls,
|
534
|
+
'number': onum,
|
535
|
+
})
|
536
|
+
|
537
|
+
def _read_ipv4_options(self, length: 'int') -> 'Option':
|
538
|
+
"""Read IPv4 option list.
|
539
|
+
|
540
|
+
Arguments:
|
541
|
+
length: length of options
|
542
|
+
|
543
|
+
Returns:
|
544
|
+
Extracted IPv4 options.
|
545
|
+
|
546
|
+
Raises:
|
547
|
+
ProtocolError: If the threshold is **NOT** matching.
|
548
|
+
|
549
|
+
"""
|
550
|
+
counter = 0 # length of read option list
|
551
|
+
options = OrderedMultiDict() # type: Option
|
552
|
+
|
553
|
+
for schema in self.__header__.options:
|
554
|
+
kind = schema.type
|
555
|
+
name = kind.name.lower()
|
556
|
+
|
557
|
+
meth_name = f'_read_opt_{name}'
|
558
|
+
meth = cast('OptionParser',
|
559
|
+
getattr(self, meth_name, self._read_opt_unassigned))
|
560
|
+
data = meth(schema, options=options)
|
561
|
+
|
562
|
+
# record option data
|
563
|
+
counter += data.length
|
564
|
+
options.add(kind, data)
|
565
|
+
|
566
|
+
# break when End of Option List (EOOL) triggered
|
567
|
+
if kind == Enum_OptionNumber.EOOL:
|
568
|
+
break
|
569
|
+
|
570
|
+
# check threshold
|
571
|
+
if counter > length:
|
572
|
+
raise ProtocolError(f'IPv4: invalid format')
|
573
|
+
return options
|
574
|
+
|
575
|
+
def _read_opt_unassigned(self, schema: 'Schema_UnassignedOption', *, options: 'Option') -> 'Data_UnassignedOption': # pylint: disable=unused-argument
|
576
|
+
"""Read IPv4 unassigned options.
|
577
|
+
|
578
|
+
Structure of IPv4 unassigned options [:rfc:`791`]:
|
579
|
+
|
580
|
+
.. code-block:: text
|
581
|
+
|
582
|
+
0 1 2 3
|
583
|
+
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
|
584
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
585
|
+
| type | length | option data ...
|
586
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
587
|
+
|
588
|
+
Arguments:
|
589
|
+
schema: parsed option schema
|
590
|
+
options: extracted IPv4 options
|
591
|
+
|
592
|
+
Returns:
|
593
|
+
Parsed option data.
|
594
|
+
|
595
|
+
Raises:
|
596
|
+
ProtocolError: If ``length`` is **LESS THAN** ``3``.
|
597
|
+
|
598
|
+
"""
|
599
|
+
if schema.length < 3:
|
600
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
601
|
+
|
602
|
+
opt = Data_UnassignedOption(
|
603
|
+
code=schema.type,
|
604
|
+
type=self._read_ipv4_opt_type(schema.type),
|
605
|
+
length=schema.length,
|
606
|
+
data=schema.data,
|
607
|
+
)
|
608
|
+
return opt
|
609
|
+
|
610
|
+
def _read_opt_eool(self, schema: 'Schema_EOOLOption', *, options: 'Option') -> 'Data_EOOLOption': # pylint: disable=unused-argument
|
611
|
+
"""Read IPv4 End of Option List (``EOOL``) option.
|
612
|
+
|
613
|
+
Structure of IPv4 End of Option List (``EOOL``) option [:rfc:`719`]:
|
614
|
+
|
615
|
+
.. code-block:: text
|
616
|
+
|
617
|
+
+--------+
|
618
|
+
|00000000|
|
619
|
+
+--------+
|
620
|
+
Type=0
|
621
|
+
|
622
|
+
Arguments:
|
623
|
+
schema: parsed option schema
|
624
|
+
options: extracted IPv4 options
|
625
|
+
|
626
|
+
Returns:
|
627
|
+
Parsed option data.
|
628
|
+
|
629
|
+
"""
|
630
|
+
opt = Data_EOOLOption(
|
631
|
+
code=schema.type,
|
632
|
+
type=self._read_ipv4_opt_type(schema.type),
|
633
|
+
length=1,
|
634
|
+
)
|
635
|
+
return opt
|
636
|
+
|
637
|
+
def _read_opt_nop(self, schema: 'Schema_NOPOption', *, options: 'Option') -> 'Data_NOPOption': # pylint: disable=unused-argument
|
638
|
+
"""Read IPv4 No Operation (``NOP``) option.
|
639
|
+
|
640
|
+
Structure of IPv4 No Operation (``NOP``) option [:rfc:`719`]:
|
641
|
+
|
642
|
+
.. code-block:: text
|
643
|
+
|
644
|
+
+--------+
|
645
|
+
|00000001|
|
646
|
+
+--------+
|
647
|
+
Type=1
|
648
|
+
|
649
|
+
Arguments:
|
650
|
+
schema: parsed option schema
|
651
|
+
options: extracted IPv4 options
|
652
|
+
|
653
|
+
Returns:
|
654
|
+
Parsed option data.
|
655
|
+
|
656
|
+
"""
|
657
|
+
opt = Data_NOPOption(
|
658
|
+
code=schema.type,
|
659
|
+
type=self._read_ipv4_opt_type(schema.type),
|
660
|
+
length=1,
|
661
|
+
)
|
662
|
+
return opt
|
663
|
+
|
664
|
+
def _read_opt_sec(self, schema: 'Schema_SECOption', *, options: 'Option') -> 'Data_SECOption': # pylint: disable=unused-argument
|
665
|
+
"""Read IPv4 Security (``SEC``) option.
|
666
|
+
|
667
|
+
Structure of IPv4 Security (``SEC``) option [:rfc:`1108`]:
|
668
|
+
|
669
|
+
.. code-block:: text
|
670
|
+
|
671
|
+
+------------+------------+------------+-------------//----------+
|
672
|
+
| 10000010 | XXXXXXXX | SSSSSSSS | AAAAAAA[1] AAAAAAA0 |
|
673
|
+
| | | | [0] |
|
674
|
+
+------------+------------+------------+-------------//----------+
|
675
|
+
TYPE = 130 LENGTH CLASSIFICATION PROTECTION
|
676
|
+
LEVEL AUTHORITY
|
677
|
+
FLAGS
|
678
|
+
|
679
|
+
Arguments:
|
680
|
+
schema: parsed option schema
|
681
|
+
options: extracted IPv4 options
|
682
|
+
|
683
|
+
Returns:
|
684
|
+
Parsed option data.
|
685
|
+
|
686
|
+
Raises:
|
687
|
+
ProtocolError: If ``length`` is **LESS THAN** ``3``.
|
688
|
+
|
689
|
+
"""
|
690
|
+
if schema.length < 3:
|
691
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
692
|
+
|
693
|
+
if schema.length > 3:
|
694
|
+
flags = [] # type: list[Enum_ProtectionAuthority]
|
695
|
+
for base, byte in enumerate(schema.data):
|
696
|
+
for bit in range(7):
|
697
|
+
authority = Enum_ProtectionAuthority.get(base * 8 + bit)
|
698
|
+
if byte & (0x80 >> bit):
|
699
|
+
if 'Unassigned' in authority.name:
|
700
|
+
warn(f'{self.alias}: [OptNo {schema.type}] invalid format: unknown protection authority: {authority}', ProtocolWarning)
|
701
|
+
flags.append(authority)
|
702
|
+
|
703
|
+
if byte & 0x01 == 1 and base < schema.length - 4:
|
704
|
+
#raise ProtocolError(f'{self.alias}: [OptNo {kind}] invalid format: remaining data')
|
705
|
+
warn(f'{self.alias}: [OptNo {schema.type}] invalid format: remaining data', ProtocolWarning)
|
706
|
+
|
707
|
+
if schema.data[-1] & 0x01 == 0:
|
708
|
+
warn(f'{self.alias}: [OptNo {schema.type}] invalid format: field termination indicator not set', ProtocolWarning)
|
709
|
+
else:
|
710
|
+
flags = []
|
711
|
+
|
712
|
+
opt = Data_SECOption(
|
713
|
+
code=schema.type,
|
714
|
+
type=self._read_ipv4_opt_type(schema.type),
|
715
|
+
length=schema.length,
|
716
|
+
level=schema.level,
|
717
|
+
flags=tuple(flags),
|
718
|
+
)
|
719
|
+
|
720
|
+
return opt
|
721
|
+
|
722
|
+
def _read_opt_lsr(self, schema: 'Schema_LSROption', *, options: 'Option') -> 'Data_LSROption': # pylint: disable=unused-argument
|
723
|
+
"""Read IPv4 Loose Source Route (``LSR``) option.
|
724
|
+
|
725
|
+
Structure of IPv4 Loose Source Route (``LSR``) option [:rfc:`791`]:
|
726
|
+
|
727
|
+
.. code-block:: text
|
728
|
+
|
729
|
+
+--------+--------+--------+---------//--------+
|
730
|
+
|10000011| length | pointer| route data |
|
731
|
+
+--------+--------+--------+---------//--------+
|
732
|
+
|
733
|
+
Arguments:
|
734
|
+
schema: parsed option schema
|
735
|
+
options: extracted IPv4 options
|
736
|
+
|
737
|
+
Returns:
|
738
|
+
Parsed option data.
|
739
|
+
|
740
|
+
Raises:
|
741
|
+
ProtocolError: If option is malformed.
|
742
|
+
|
743
|
+
"""
|
744
|
+
if schema.length < 3 or (schema.length - 3) % 4 != 0:
|
745
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
746
|
+
if schema.pointer < 4:
|
747
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format: pointer too small: {schema.pointer}')
|
748
|
+
|
749
|
+
opt = Data_LSROption(
|
750
|
+
code=schema.type,
|
751
|
+
type=self._read_ipv4_opt_type(schema.type),
|
752
|
+
length=schema.length,
|
753
|
+
pointer=schema.pointer,
|
754
|
+
route=tuple(schema.route),
|
755
|
+
)
|
756
|
+
return opt
|
757
|
+
|
758
|
+
def _read_opt_ts(self, schema: 'Schema_TSOption', *, options: 'Option') -> 'Data_TSOption': # pylint: disable=unused-argument
|
759
|
+
"""Read IPv4 Time Stamp (``TS``) option.
|
760
|
+
|
761
|
+
Structure of IPv4 Time Stamp (``TS``) option [:rfc:`791`]:
|
762
|
+
|
763
|
+
.. code-block:: text
|
764
|
+
|
765
|
+
+--------+--------+--------+--------+
|
766
|
+
|01000100| length | pointer|oflw|flg|
|
767
|
+
+--------+--------+--------+--------+
|
768
|
+
| internet address |
|
769
|
+
+--------+--------+--------+--------+
|
770
|
+
| timestamp |
|
771
|
+
+--------+--------+--------+--------+
|
772
|
+
| . |
|
773
|
+
.
|
774
|
+
.
|
775
|
+
|
776
|
+
Arguments:
|
777
|
+
schema: parsed option schema
|
778
|
+
options: extracted IPv4 options
|
779
|
+
|
780
|
+
Returns:
|
781
|
+
Parsed option data.
|
782
|
+
|
783
|
+
Raises:
|
784
|
+
ProtocolError: If the option is malformed.
|
785
|
+
|
786
|
+
"""
|
787
|
+
if schema.length > 40 or schema.length < 4:
|
788
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
789
|
+
if schema.pointer < 5:
|
790
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format: pointer too small: {schema.pointer}')
|
791
|
+
|
792
|
+
opt = Data_TSOption(
|
793
|
+
code=schema.type,
|
794
|
+
type=self._read_ipv4_opt_type(schema.type),
|
795
|
+
length=schema.length,
|
796
|
+
pointer=schema.pointer,
|
797
|
+
overflow=schema.flags['oflw'],
|
798
|
+
flag=schema.ts_flag,
|
799
|
+
timestamp=schema.timestamp,
|
800
|
+
)
|
801
|
+
return opt
|
802
|
+
|
803
|
+
def _read_opt_e_sec(self, schema: 'Schema_ESECOption', *, options: 'Option') -> 'Data_ESECOption': # pylint: disable=unused-argument
|
804
|
+
"""Read IPv4 Extended Security (``E-SEC``) option.
|
805
|
+
|
806
|
+
Structure of IPv4 Extended Security (``E-SEC``) option [:rfc:`1108`]:
|
807
|
+
|
808
|
+
.. code-block:: text
|
809
|
+
|
810
|
+
+------------+------------+------------+-------//-------+
|
811
|
+
| 10000101 | 000LLLLL | AAAAAAAA | add sec info |
|
812
|
+
+------------+------------+------------+-------//-------+
|
813
|
+
TYPE = 133 LENGTH ADDITIONAL ADDITIONAL
|
814
|
+
SECURITY INFO SECURITY
|
815
|
+
FORMAT CODE INFO
|
816
|
+
|
817
|
+
Arguments:
|
818
|
+
schema: parsed option schema
|
819
|
+
options: extracted IPv4 options
|
820
|
+
|
821
|
+
Returns:
|
822
|
+
Parsed option data.
|
823
|
+
|
824
|
+
Raises:
|
825
|
+
ProtocolError: If ``length`` is **LESS THAN** ``3``.
|
826
|
+
|
827
|
+
"""
|
828
|
+
if schema.length < 3:
|
829
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
830
|
+
|
831
|
+
opt = Data_ESECOption(
|
832
|
+
code=schema.type,
|
833
|
+
type=self._read_ipv4_opt_type(schema.type),
|
834
|
+
length=schema.length,
|
835
|
+
format=schema.format,
|
836
|
+
info=schema.info,
|
837
|
+
)
|
838
|
+
return opt
|
839
|
+
|
840
|
+
def _read_opt_rr(self, schema: 'Schema_RROption', *, options: 'Option') -> 'Data_RROption': # pylint: disable=unused-argument
|
841
|
+
"""Read IPv4 Record Route (``RR``) option.
|
842
|
+
|
843
|
+
Structure of IPv4 Record Route (``RR``) option [:rfc:`791`]:
|
844
|
+
|
845
|
+
.. code-block:: text
|
846
|
+
|
847
|
+
+--------+--------+--------+---------//--------+
|
848
|
+
|00000111| length | pointer| route data |
|
849
|
+
+--------+--------+--------+---------//--------+
|
850
|
+
Type=7
|
851
|
+
|
852
|
+
Arguments:
|
853
|
+
schema: parsed option schema
|
854
|
+
options: extracted IPv4 options
|
855
|
+
|
856
|
+
Returns:
|
857
|
+
Parsed option data.
|
858
|
+
|
859
|
+
Raises:
|
860
|
+
ProtocolError: If option is malformed.
|
861
|
+
|
862
|
+
"""
|
863
|
+
if schema.length < 3 or (schema.length - 3) % 4 != 0:
|
864
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
865
|
+
if schema.pointer < 4:
|
866
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format: pointer too small: {schema.pointer}')
|
867
|
+
|
868
|
+
opt = Data_RROption(
|
869
|
+
code=schema.type,
|
870
|
+
type=self._read_ipv4_opt_type(schema.type),
|
871
|
+
length=schema.length,
|
872
|
+
pointer=schema.pointer,
|
873
|
+
route=tuple(schema.route),
|
874
|
+
)
|
875
|
+
return opt
|
876
|
+
|
877
|
+
def _read_opt_sid(self, schema: 'Schema_SIDOption', *, options: 'Option') -> 'Data_SIDOption': # pylint: disable=unused-argument
|
878
|
+
"""Read IPv4 Stream ID (``SID``) option.
|
879
|
+
|
880
|
+
Structure of IPv4 Stream ID (``SID``) option [:rfc:`791`][:rfc:`6814`]:
|
881
|
+
|
882
|
+
.. code-block:: text
|
883
|
+
|
884
|
+
+--------+--------+--------+--------+
|
885
|
+
|10001000|00000010| Stream ID |
|
886
|
+
+--------+--------+--------+--------+
|
887
|
+
Type=136 Length=4
|
888
|
+
|
889
|
+
Arguments:
|
890
|
+
schema: parsed option schema
|
891
|
+
options: extracted IPv4 options
|
892
|
+
|
893
|
+
Returns:
|
894
|
+
Parsed option data.
|
895
|
+
|
896
|
+
Raises:
|
897
|
+
ProtocolError: If ``length`` is **NOT** ``4``.
|
898
|
+
|
899
|
+
"""
|
900
|
+
if schema.length != 4:
|
901
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
902
|
+
|
903
|
+
opt = Data_SIDOption(
|
904
|
+
code=schema.type,
|
905
|
+
type=self._read_ipv4_opt_type(schema.type),
|
906
|
+
length=schema.length,
|
907
|
+
sid=schema.sid,
|
908
|
+
)
|
909
|
+
return opt
|
910
|
+
|
911
|
+
def _read_opt_ssr(self, schema: 'Schema_SSROption', *, options: 'Option') -> 'Data_SSROption': # pylint: disable=unused-argument
|
912
|
+
"""Read IPv4 Strict Source Route (``SSR``) option.
|
913
|
+
|
914
|
+
Structure of IPv4 Strict Source Route (``SSR``) option [:rfc:`791`]:
|
915
|
+
|
916
|
+
.. code-block:: text
|
917
|
+
|
918
|
+
+--------+--------+--------+---------//--------+
|
919
|
+
|10001001| length | pointer| route data |
|
920
|
+
+--------+--------+--------+---------//--------+
|
921
|
+
Type=137
|
922
|
+
|
923
|
+
Arguments:
|
924
|
+
schema: parsed option schema
|
925
|
+
options: extracted IPv4 options
|
926
|
+
|
927
|
+
Returns:
|
928
|
+
Parsed option data.
|
929
|
+
|
930
|
+
Raises:
|
931
|
+
ProtocolError: If option is malformed.
|
932
|
+
|
933
|
+
"""
|
934
|
+
if schema.length < 3 or (schema.length - 3) % 4 != 0:
|
935
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
936
|
+
if schema.pointer < 4:
|
937
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format: pointer too small: {schema.pointer}')
|
938
|
+
|
939
|
+
opt = Data_SSROption(
|
940
|
+
code=schema.type,
|
941
|
+
type=self._read_ipv4_opt_type(schema.type),
|
942
|
+
length=schema.length,
|
943
|
+
pointer=schema.pointer,
|
944
|
+
route=tuple(schema.route),
|
945
|
+
)
|
946
|
+
return opt
|
947
|
+
|
948
|
+
def _read_opt_mtup(self, schema: 'Schema_MTUPOption', *, options: 'Option') -> 'Data_MTUPOption': # pylint: disable=unused-argument
|
949
|
+
"""Read IPv4 MTU Probe (``MTUP``) option.
|
950
|
+
|
951
|
+
Structure of IPv4 MTU Probe (``MTUP``) option [:rfc:`1063`][:rfc:`1191`]:
|
952
|
+
|
953
|
+
.. code-block:: text
|
954
|
+
|
955
|
+
+--------+--------+--------+--------+
|
956
|
+
|00001011|00000100| 2 octet value |
|
957
|
+
+--------+--------+--------+--------+
|
958
|
+
|
959
|
+
Arguments:
|
960
|
+
schema: parsed option schema
|
961
|
+
options: extracted IPv4 options
|
962
|
+
|
963
|
+
Returns:
|
964
|
+
Parsed option data.
|
965
|
+
|
966
|
+
Raises:
|
967
|
+
ProtocolError: If ``length`` is **NOT** ``4``.
|
968
|
+
|
969
|
+
"""
|
970
|
+
if schema.length != 4:
|
971
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
972
|
+
|
973
|
+
opt = Data_MTUPOption(
|
974
|
+
code=schema.type,
|
975
|
+
type=self._read_ipv4_opt_type(schema.type),
|
976
|
+
length=schema.length,
|
977
|
+
mtu=schema.mtu,
|
978
|
+
)
|
979
|
+
return opt
|
980
|
+
|
981
|
+
def _read_opt_mtur(self, schema: 'Schema_MTUROption', *, options: 'Option') -> 'Data_MTUROption': # pylint: disable=unused-argument
|
982
|
+
"""Read IPv4 MTU Reply (``MTUR``) option.
|
983
|
+
|
984
|
+
Structure of IPv4 MTU Reply (``MTUR``) option [:rfc:`1063`][:rfc:`1191`]:
|
985
|
+
|
986
|
+
.. code-block:: text
|
987
|
+
|
988
|
+
+--------+--------+--------+--------+
|
989
|
+
|00001100|00000100| 2 octet value |
|
990
|
+
+--------+--------+--------+--------+
|
991
|
+
|
992
|
+
Arguments:
|
993
|
+
schema: parsed option schema
|
994
|
+
options: extracted IPv4 options
|
995
|
+
|
996
|
+
Returns:
|
997
|
+
Parsed option data.
|
998
|
+
|
999
|
+
Raises:
|
1000
|
+
ProtocolError: If ``length`` is **NOT** ``4``.
|
1001
|
+
|
1002
|
+
"""
|
1003
|
+
if schema.length != 4:
|
1004
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
1005
|
+
|
1006
|
+
opt = Data_MTUROption(
|
1007
|
+
code=schema.type,
|
1008
|
+
type=self._read_ipv4_opt_type(schema.type),
|
1009
|
+
length=schema.length,
|
1010
|
+
mtu=schema.mtu,
|
1011
|
+
)
|
1012
|
+
return opt
|
1013
|
+
|
1014
|
+
def _read_opt_tr(self, schema: 'Schema_TROption', *, options: 'Option') -> 'Data_TROption': # pylint: disable=unused-argument
|
1015
|
+
"""Read IPv4 Traceroute (``TR``) option.
|
1016
|
+
|
1017
|
+
Structure of IPv4 Traceroute (``TR``) option [:rfc:`1393`][:rfc:`6814`]:
|
1018
|
+
|
1019
|
+
.. code-block:: text
|
1020
|
+
|
1021
|
+
0 8 16 24
|
1022
|
+
+-+-+-+-+-+-+-+-+---------------+---------------+---------------+
|
1023
|
+
|F| C | Number | Length | ID Number |
|
1024
|
+
+-+-+-+-+-+-+-+-+---------------+---------------+---------------+
|
1025
|
+
| Outbound Hop Count | Return Hop Count |
|
1026
|
+
+---------------+---------------+---------------+---------------+
|
1027
|
+
| Originator IP Address |
|
1028
|
+
+---------------+---------------+---------------+---------------+
|
1029
|
+
|
1030
|
+
Arguments:
|
1031
|
+
schema: parsed option schema
|
1032
|
+
options: extracted IPv4 options
|
1033
|
+
|
1034
|
+
Returns:
|
1035
|
+
Parsed option data.
|
1036
|
+
|
1037
|
+
Raises:
|
1038
|
+
ProtocolError: If ``length`` is **NOT** ``12``.
|
1039
|
+
|
1040
|
+
"""
|
1041
|
+
if schema.length != 12:
|
1042
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
1043
|
+
|
1044
|
+
opt = Data_TROption.from_dict({
|
1045
|
+
'code': schema.type,
|
1046
|
+
'type': self._read_ipv4_opt_type(schema.type),
|
1047
|
+
'length': schema.length,
|
1048
|
+
'id': schema.id,
|
1049
|
+
'outbound': schema.out,
|
1050
|
+
'return': schema.ret,
|
1051
|
+
'originator': schema.origin,
|
1052
|
+
})
|
1053
|
+
return opt
|
1054
|
+
|
1055
|
+
def _read_opt_rtralt(self, schema: 'Schema_RTRALTOption', *, options: 'Option') -> 'Data_RTRALTOption': # pylint: disable=unused-argument
|
1056
|
+
"""Read IPv4 Router Alert (``RTRALT``) option.
|
1057
|
+
|
1058
|
+
Structure of IPv4 Router Alert (``RTRALT``) option [:rfc:`2113`]:
|
1059
|
+
|
1060
|
+
.. code:: text
|
1061
|
+
|
1062
|
+
+--------+--------+--------+--------+
|
1063
|
+
|10010100|00000100| 2 octet value |
|
1064
|
+
+--------+--------+--------+--------+
|
1065
|
+
|
1066
|
+
Arguments:
|
1067
|
+
schema: parsed option schema
|
1068
|
+
options: extracted IPv4 options
|
1069
|
+
|
1070
|
+
Returns:
|
1071
|
+
Parsed option data.
|
1072
|
+
|
1073
|
+
Raises:
|
1074
|
+
ProtocolError: If ``length`` is **NOT** ``4``.
|
1075
|
+
|
1076
|
+
"""
|
1077
|
+
if schema.length != 4:
|
1078
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
1079
|
+
|
1080
|
+
opt = Data_RTRALTOption(
|
1081
|
+
code=schema.type,
|
1082
|
+
type=self._read_ipv4_opt_type(schema.type),
|
1083
|
+
length=schema.length,
|
1084
|
+
alert=schema.alert,
|
1085
|
+
)
|
1086
|
+
return opt
|
1087
|
+
|
1088
|
+
def _read_opt_qs(self, schema: 'Schema_QSOption', *, options: 'Option') -> 'Data_QSOption': # pylint: disable=unused-argument
|
1089
|
+
"""Read IPv4 Quick Start (``QS``) option.
|
1090
|
+
|
1091
|
+
Structure of IPv4 Quick Start (``QS``) option [:rfc:`4782`]:
|
1092
|
+
|
1093
|
+
* A Quick-Start Request
|
1094
|
+
|
1095
|
+
.. code-block:: text
|
1096
|
+
|
1097
|
+
0 1 2 3
|
1098
|
+
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
|
1099
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1100
|
+
| Option | Length=8 | Func. | Rate | QS TTL |
|
1101
|
+
| | | 0000 |Request| |
|
1102
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1103
|
+
| QS Nonce | R |
|
1104
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1105
|
+
|
1106
|
+
* Report of Approved Rate
|
1107
|
+
|
1108
|
+
.. code-block:: text
|
1109
|
+
|
1110
|
+
0 1 2 3
|
1111
|
+
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
|
1112
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1113
|
+
| Option | Length=8 | Func. | Rate | Not Used |
|
1114
|
+
| | | 1000 | Report| |
|
1115
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1116
|
+
| QS Nonce | R |
|
1117
|
+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1118
|
+
|
1119
|
+
Arguments:
|
1120
|
+
schema: parsed option schema
|
1121
|
+
options: extracted IPv4 options
|
1122
|
+
|
1123
|
+
Returns:
|
1124
|
+
Parsed option data.
|
1125
|
+
|
1126
|
+
Raises:
|
1127
|
+
ProtocolError: If the option is malformed.
|
1128
|
+
|
1129
|
+
"""
|
1130
|
+
if schema.length != 8:
|
1131
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
|
1132
|
+
|
1133
|
+
func = schema.func
|
1134
|
+
if func == Enum_QSFunction.Quick_Start_Request:
|
1135
|
+
schema_req = cast('Schema_QuickStartRequestOption', schema)
|
1136
|
+
|
1137
|
+
rate = schema_req.flags['rate']
|
1138
|
+
opt = Data_QuickStartRequestOption(
|
1139
|
+
code=schema.type,
|
1140
|
+
type=self._read_ipv4_opt_type(schema.type),
|
1141
|
+
length=schema_req.length,
|
1142
|
+
func=func,
|
1143
|
+
rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
|
1144
|
+
ttl=datetime.timedelta(seconds=schema_req.ttl),
|
1145
|
+
nonce=schema_req.nonce['nonce'],
|
1146
|
+
) # type: Data_QSOption
|
1147
|
+
elif func == Enum_QSFunction.Report_of_Approved_Rate:
|
1148
|
+
schema_rep = cast('Schema_QuickStartReportOption', schema)
|
1149
|
+
|
1150
|
+
rate = schema_rep.flags['rate']
|
1151
|
+
opt = Data_QuickStartReportOption(
|
1152
|
+
code=schema.type,
|
1153
|
+
type=self._read_ipv4_opt_type(schema.type),
|
1154
|
+
length=schema_rep.length,
|
1155
|
+
func=func,
|
1156
|
+
rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
|
1157
|
+
nonce=schema_rep.nonce['nonce'],
|
1158
|
+
)
|
1159
|
+
else:
|
1160
|
+
raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] unknown QS function: {func}')
|
1161
|
+
return opt
|
1162
|
+
|
1163
|
+
def _make_ipv4_options(self, options: 'list[Schema_Option | tuple[Enum_OptionNumber, dict[str, Any]] | bytes] | Option') -> 'tuple[list[Schema_Option | bytes], int]':
|
1164
|
+
"""Make options for IPv4.
|
1165
|
+
|
1166
|
+
Args:
|
1167
|
+
option: IPv4 options
|
1168
|
+
|
1169
|
+
Returns:
|
1170
|
+
Tuple of options and total length of options.
|
1171
|
+
|
1172
|
+
"""
|
1173
|
+
total_length = 0
|
1174
|
+
if isinstance(options, list):
|
1175
|
+
options_list = [] # type: list[Schema_Option | bytes]
|
1176
|
+
for schema in options:
|
1177
|
+
if isinstance(schema, bytes):
|
1178
|
+
code = Enum_OptionNumber.get(schema[0])
|
1179
|
+
if code in (Enum_OptionNumber.NOP, Enum_OptionNumber.EOOL): # ignore padding options by default
|
1180
|
+
continue
|
1181
|
+
|
1182
|
+
data = schema # type: Schema_Option | bytes
|
1183
|
+
data_len = len(data)
|
1184
|
+
elif isinstance(schema, Schema):
|
1185
|
+
code = schema.type
|
1186
|
+
if code in (Enum_OptionNumber.NOP, Enum_OptionNumber.EOOL): # ignore padding options by default
|
1187
|
+
continue
|
1188
|
+
|
1189
|
+
data = schema
|
1190
|
+
data_len = len(schema.pack())
|
1191
|
+
else:
|
1192
|
+
code, args = cast('tuple[Enum_OptionNumber, dict[str, Any]]', schema)
|
1193
|
+
if code in (Enum_OptionNumber.NOP, Enum_OptionNumber.EOOL): # ignore padding options by default
|
1194
|
+
continue
|
1195
|
+
|
1196
|
+
name = f'_make_opt_{code.name.lower()}'
|
1197
|
+
meth = cast('OptionConstructor',
|
1198
|
+
getattr(self, name, self._make_opt_unassigned))
|
1199
|
+
|
1200
|
+
data = meth(code, **args)
|
1201
|
+
data_len = len(data.pack())
|
1202
|
+
|
1203
|
+
options_list.append(data)
|
1204
|
+
total_length += data_len
|
1205
|
+
|
1206
|
+
# force alignment to 32-bit boundary
|
1207
|
+
if data_len % 4:
|
1208
|
+
pad_len = 4 - (data_len % 4)
|
1209
|
+
pad_opt = self._make_opt_nop(Enum_OptionNumber.NOP) # type: ignore[arg-type]
|
1210
|
+
total_length += pad_len
|
1211
|
+
|
1212
|
+
for _ in range(pad_len - 1):
|
1213
|
+
options_list.append(pad_opt)
|
1214
|
+
options_list.append(Enum_OptionNumber.EOOL) # type: ignore[arg-type]
|
1215
|
+
return options_list, total_length
|
1216
|
+
|
1217
|
+
options_list = []
|
1218
|
+
for code, option in options.items(multi=True):
|
1219
|
+
# ignore padding options by default
|
1220
|
+
if code in (Enum_OptionNumber.NOP, Enum_OptionNumber.EOOL):
|
1221
|
+
continue
|
1222
|
+
|
1223
|
+
name = f'_make_opt_{code.name.lower()}'
|
1224
|
+
meth = cast('OptionConstructor',
|
1225
|
+
getattr(self, name, self._make_opt_unassigned))
|
1226
|
+
|
1227
|
+
data = meth(code, option)
|
1228
|
+
data_len = len(data.pack())
|
1229
|
+
|
1230
|
+
options_list.append(data)
|
1231
|
+
total_length += data_len
|
1232
|
+
|
1233
|
+
# force alignment to 32-bit boundary
|
1234
|
+
if data_len % 4:
|
1235
|
+
pad_len = 4 - (data_len % 4)
|
1236
|
+
pad_opt = self._make_opt_nop(Enum_OptionNumber.NOP) # type: ignore[arg-type]
|
1237
|
+
total_length += pad_len
|
1238
|
+
|
1239
|
+
for _ in range(pad_len - 1):
|
1240
|
+
options_list.append(pad_opt)
|
1241
|
+
options_list.append(Enum_OptionNumber.EOOL) # type: ignore[arg-type]
|
1242
|
+
return options_list, total_length
|
1243
|
+
|
1244
|
+
def _make_opt_unassigned(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_UnassignedOption]' = None, *,
|
1245
|
+
data: 'bytes',
|
1246
|
+
**kwargs: 'Any') -> 'Schema_Option':
|
1247
|
+
"""Make IPv4 unassigned options.
|
1248
|
+
|
1249
|
+
Args:
|
1250
|
+
kind: option type code
|
1251
|
+
option: option data
|
1252
|
+
data: option payload
|
1253
|
+
**kwargs: arbitrary keyword arguments
|
1254
|
+
|
1255
|
+
Returns:
|
1256
|
+
Constructured option schema.
|
1257
|
+
|
1258
|
+
"""
|
1259
|
+
if option is not None:
|
1260
|
+
data = option.data
|
1261
|
+
|
1262
|
+
return Schema_UnassignedOption(
|
1263
|
+
type=kind,
|
1264
|
+
length=len(data),
|
1265
|
+
data=data,
|
1266
|
+
)
|
1267
|
+
|
1268
|
+
def _make_opt_eool(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_EOOLOption]' = None,
|
1269
|
+
**kwargs: 'Any') -> 'Schema_EOOLOption':
|
1270
|
+
"""Make IPv4 End of Option List (``EOOL``) option.
|
1271
|
+
|
1272
|
+
Args:
|
1273
|
+
kind: option type code
|
1274
|
+
option: option data
|
1275
|
+
**kwargs: arbitrary keyword arguments
|
1276
|
+
|
1277
|
+
Returns:
|
1278
|
+
Constructured option schema.
|
1279
|
+
|
1280
|
+
"""
|
1281
|
+
return Schema_EOOLOption(
|
1282
|
+
type=kind,
|
1283
|
+
length=1,
|
1284
|
+
)
|
1285
|
+
|
1286
|
+
def _make_opt_nop(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_NOPOption]' = None,
|
1287
|
+
**kwargs: 'Any') -> 'Schema_NOPOption':
|
1288
|
+
"""Make IPv4 No Operation (``NOP``) option.
|
1289
|
+
|
1290
|
+
Args:
|
1291
|
+
kind: option type code
|
1292
|
+
option: option data
|
1293
|
+
**kwargs: arbitrary keyword arguments
|
1294
|
+
|
1295
|
+
Returns:
|
1296
|
+
Constructured option schema.
|
1297
|
+
|
1298
|
+
"""
|
1299
|
+
return Schema_NOPOption(
|
1300
|
+
type=kind,
|
1301
|
+
length=1,
|
1302
|
+
)
|
1303
|
+
|
1304
|
+
def _make_opt_sec(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_SECOption]' = None, *,
|
1305
|
+
level: 'Enum_ClassificationLevel | StdlibEnum | AenumEnum | int | str' = Enum_ClassificationLevel.Unclassified,
|
1306
|
+
level_default: 'Optional[int]' = None,
|
1307
|
+
level_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
1308
|
+
level_reversed: 'bool' = False,
|
1309
|
+
authorities: 'Optional[list[Enum_ProtectionAuthority]]' = None,
|
1310
|
+
**kwargs: 'Any') -> 'Schema_SECOption':
|
1311
|
+
"""Make IPv4 Security (``SEC``) option.
|
1312
|
+
|
1313
|
+
Args:
|
1314
|
+
kind: option type code
|
1315
|
+
option: option data
|
1316
|
+
sec: security option
|
1317
|
+
**kwargs: arbitrary keyword arguments
|
1318
|
+
|
1319
|
+
Returns:
|
1320
|
+
Constructured option schema.
|
1321
|
+
|
1322
|
+
"""
|
1323
|
+
if option is not None:
|
1324
|
+
level_val = option.level
|
1325
|
+
authorities = cast('list[Enum_ProtectionAuthority]', option.flags)
|
1326
|
+
else:
|
1327
|
+
level_val = self._make_index(level, level_default, namespace=level_namespace, # type: ignore[assignment]
|
1328
|
+
reversed=level_reversed, pack=False)
|
1329
|
+
authorities = [] if authorities is None else authorities
|
1330
|
+
|
1331
|
+
if authorities:
|
1332
|
+
max_auth = max(authorities)
|
1333
|
+
int_len = math.ceil(max_auth / 8)
|
1334
|
+
|
1335
|
+
data_list = [b'0' for _ in range(int_len * 8)]
|
1336
|
+
for auth in authorities:
|
1337
|
+
data_list[auth] = b'1'
|
1338
|
+
data = int(b''.join(data_list), base=2).to_bytes(int_len, 'big', signed=False)
|
1339
|
+
else:
|
1340
|
+
data = b''
|
1341
|
+
|
1342
|
+
return Schema_SECOption(
|
1343
|
+
type=kind,
|
1344
|
+
length=3 + len(data),
|
1345
|
+
level=level_val,
|
1346
|
+
data=data,
|
1347
|
+
)
|
1348
|
+
|
1349
|
+
def _make_opt_lsr(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_LSROption]' = None, *,
|
1350
|
+
counts: 'int' = 10, # reasonable default
|
1351
|
+
route: 'Optional[list[IPv4Address | str | bytes | int]]' = None,
|
1352
|
+
**kwargs: 'Any') -> 'Schema_LSROption':
|
1353
|
+
"""Make IPv4 Loose Source and Record Route (``LSR``) option.
|
1354
|
+
|
1355
|
+
Args:
|
1356
|
+
kind: option type code
|
1357
|
+
option: option data
|
1358
|
+
counts: maximum number of addresses to record
|
1359
|
+
route: list of IPv4 addresses as recorded routes
|
1360
|
+
**kwargs: arbitrary keyword arguments
|
1361
|
+
|
1362
|
+
Returns:
|
1363
|
+
Constructured option schema.
|
1364
|
+
|
1365
|
+
"""
|
1366
|
+
if option is not None:
|
1367
|
+
route = cast('list[IPv4Address | str | bytes | int]', option.route)
|
1368
|
+
pointer = option.pointer
|
1369
|
+
length = option.length
|
1370
|
+
else:
|
1371
|
+
route = [] if route is None else route
|
1372
|
+
length = 3 + counts * 4
|
1373
|
+
pointer = 4 + min(len(route), counts) * 4
|
1374
|
+
|
1375
|
+
return Schema_LSROption(
|
1376
|
+
type=kind,
|
1377
|
+
length=length,
|
1378
|
+
pointer=pointer,
|
1379
|
+
route=route,
|
1380
|
+
)
|
1381
|
+
|
1382
|
+
def _make_opt_ts(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_TSOption]' = None, *,
|
1383
|
+
counts: 'int' = 5,
|
1384
|
+
overflow: 'int' = 0,
|
1385
|
+
timestamp: 'Optional[list[int | timedelta] | dict[IPv4Address, int | timedelta]]' = None,
|
1386
|
+
**kwargs: 'Any') -> 'Schema_TSOption':
|
1387
|
+
"""Make IPv4 Timestamp (``TS``) option.
|
1388
|
+
|
1389
|
+
Args:
|
1390
|
+
kind: option type code
|
1391
|
+
option: option data
|
1392
|
+
counts: maximum number of timestamps to record
|
1393
|
+
timestamp: list of timestamps
|
1394
|
+
**kwargs: arbitrary keyword arguments
|
1395
|
+
|
1396
|
+
Returns:
|
1397
|
+
Constructured option schema.
|
1398
|
+
|
1399
|
+
"""
|
1400
|
+
if option is not None:
|
1401
|
+
ts_list = [] # type: list[int]
|
1402
|
+
if isinstance(option.timestamp, tuple):
|
1403
|
+
for ts in option.timestamp:
|
1404
|
+
if not isinstance(ts, int):
|
1405
|
+
ts = math.floor(ts.total_seconds() * 1000)
|
1406
|
+
|
1407
|
+
if ts.bit_length() > 31:
|
1408
|
+
warn(f'{self.alias}: [OptNo {kind}] timestamp value is too large: {ts}', ProtocolWarning)
|
1409
|
+
ts = ts | 0x80000000
|
1410
|
+
ts_list.append(ts)
|
1411
|
+
else:
|
1412
|
+
for ip, ts in option.timestamp.items(True):
|
1413
|
+
ts_list.append(int(ip))
|
1414
|
+
if not isinstance(ts, int):
|
1415
|
+
ts = math.floor(ts.total_seconds() * 1000)
|
1416
|
+
|
1417
|
+
if ts.bit_length() > 31:
|
1418
|
+
warn(f'{self.alias}: [OptNo {kind}] timestamp value is too large: {ts}', ProtocolWarning)
|
1419
|
+
ts = ts | 0x80000000
|
1420
|
+
ts_list.append(ts)
|
1421
|
+
|
1422
|
+
length = option.length
|
1423
|
+
pointer = option.pointer
|
1424
|
+
overflow = option.overflow
|
1425
|
+
flag = option.flag
|
1426
|
+
else:
|
1427
|
+
ts_list = []
|
1428
|
+
if isinstance(timestamp, list):
|
1429
|
+
flag = Enum_TSFlag.Timestamp_Only # type: ignore[assignment]
|
1430
|
+
counts = min(9, counts) # 9 is the maximum number of timestamps
|
1431
|
+
length = 4 + counts * 4
|
1432
|
+
|
1433
|
+
for index, ts in enumerate(timestamp):
|
1434
|
+
if index >= counts:
|
1435
|
+
warn(f'{self.alias}: [OptNo {kind}] too many timestamps: {len(timestamp)}', ProtocolWarning)
|
1436
|
+
break
|
1437
|
+
|
1438
|
+
if not isinstance(ts, int):
|
1439
|
+
ts = math.floor(ts.total_seconds() * 1000)
|
1440
|
+
|
1441
|
+
if ts.bit_length() > 31:
|
1442
|
+
warn(f'{self.alias}: [OptNo {kind}] timestamp value is too large: {ts}', ProtocolWarning)
|
1443
|
+
ts = ts | 0x80000000
|
1444
|
+
ts_list.append(ts)
|
1445
|
+
elif isinstance(timestamp, dict):
|
1446
|
+
flag = Enum_TSFlag.IP_with_Timestamp # type: ignore[assignment]
|
1447
|
+
counts = min(4, counts) # 4 is the maximum number of timestamps
|
1448
|
+
length = 4 + counts * 8
|
1449
|
+
|
1450
|
+
for index, (ip, ts) in enumerate(timestamp.items()):
|
1451
|
+
if index >= counts:
|
1452
|
+
warn(f'{self.alias}: [OptNo {kind}] too many timestamps: {len(timestamp)}', ProtocolWarning)
|
1453
|
+
break
|
1454
|
+
|
1455
|
+
ts_list.append(int(ip))
|
1456
|
+
if not isinstance(ts, int):
|
1457
|
+
ts = math.floor(ts.total_seconds() * 1000)
|
1458
|
+
if ts == 0:
|
1459
|
+
flag = Enum_TSFlag.Prespecified_IP_with_Timestamp # type: ignore[assignment]
|
1460
|
+
|
1461
|
+
if ts.bit_length() > 31:
|
1462
|
+
warn(f'{self.alias}: [OptNo {kind}] timestamp value is too large: {ts}', ProtocolWarning)
|
1463
|
+
ts = ts | 0x80000000
|
1464
|
+
ts_list.append(ts)
|
1465
|
+
else:
|
1466
|
+
raise ProtocolError(f'{self.alias}: [OptNo {kind}] invalid timestamp value: {timestamp}')
|
1467
|
+
pointer = 5 + len(ts_list) * 4
|
1468
|
+
|
1469
|
+
return Schema_TSOption(
|
1470
|
+
type=kind,
|
1471
|
+
length=length,
|
1472
|
+
pointer=pointer,
|
1473
|
+
flags={
|
1474
|
+
'oflw': overflow,
|
1475
|
+
'flag': flag,
|
1476
|
+
},
|
1477
|
+
data=ts_list,
|
1478
|
+
)
|
1479
|
+
|
1480
|
+
def _make_opt_e_sec(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_ESECOption]' = None, *,
|
1481
|
+
format: 'int' = 0,
|
1482
|
+
info: 'Optional[bytes]' = None,
|
1483
|
+
**kwargs: 'Any') -> 'Schema_ESECOption':
|
1484
|
+
"""Make IPv4 Extended Security (``E-SEC``) option.
|
1485
|
+
|
1486
|
+
Args:
|
1487
|
+
kind: option type code
|
1488
|
+
option: option data
|
1489
|
+
format: additional security information format code
|
1490
|
+
info: additional security information
|
1491
|
+
**kwargs: arbitrary keyword arguments
|
1492
|
+
|
1493
|
+
Returns:
|
1494
|
+
Constructured option schema.
|
1495
|
+
|
1496
|
+
"""
|
1497
|
+
if option is not None:
|
1498
|
+
length = option.length
|
1499
|
+
format = option.format
|
1500
|
+
info = option.info
|
1501
|
+
else:
|
1502
|
+
length = (3 + len(info)) if info is not None else 3
|
1503
|
+
|
1504
|
+
return Schema_ESECOption(
|
1505
|
+
type=kind,
|
1506
|
+
length=length,
|
1507
|
+
format=format,
|
1508
|
+
info=info,
|
1509
|
+
)
|
1510
|
+
|
1511
|
+
def _make_opt_rr(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_RROption]' = None, *,
|
1512
|
+
counts: 'int' = 10, # reasonable default
|
1513
|
+
route: 'Optional[list[IPv4Address | str | bytes | int]]' = None,
|
1514
|
+
**kwargs: 'Any') -> 'Schema_RROption':
|
1515
|
+
"""Make IPv4 Record Route (``RR``) option.
|
1516
|
+
|
1517
|
+
Args:
|
1518
|
+
kind: option type code
|
1519
|
+
option: option data
|
1520
|
+
counts: maximum number of addresses to record
|
1521
|
+
route: list of IPv4 addresses as recorded routes
|
1522
|
+
**kwargs: arbitrary keyword arguments
|
1523
|
+
|
1524
|
+
Returns:
|
1525
|
+
Constructured option schema.
|
1526
|
+
|
1527
|
+
"""
|
1528
|
+
if option is not None:
|
1529
|
+
route = cast('list[IPv4Address | str | bytes | int]', option.route)
|
1530
|
+
pointer = option.pointer
|
1531
|
+
length = option.length
|
1532
|
+
else:
|
1533
|
+
route = [] if route is None else route
|
1534
|
+
length = 3 + counts * 4
|
1535
|
+
pointer = 4 + min(len(route), counts) * 4
|
1536
|
+
|
1537
|
+
return Schema_RROption(
|
1538
|
+
type=kind,
|
1539
|
+
length=length,
|
1540
|
+
pointer=pointer,
|
1541
|
+
route=route,
|
1542
|
+
)
|
1543
|
+
|
1544
|
+
def _make_opt_sid(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_SIDOption]' = None, *,
|
1545
|
+
sid: 'int' = 0,
|
1546
|
+
**kwargs: 'Any') -> 'Schema_SIDOption':
|
1547
|
+
"""Make IPv4 Stream ID (``SID``) option.
|
1548
|
+
|
1549
|
+
Args:
|
1550
|
+
kind: option type code
|
1551
|
+
option: option data
|
1552
|
+
sid: stream ID
|
1553
|
+
**kwargs: arbitrary keyword arguments
|
1554
|
+
|
1555
|
+
Returns:
|
1556
|
+
Constructured option schema.
|
1557
|
+
|
1558
|
+
"""
|
1559
|
+
if option is not None:
|
1560
|
+
sid = option.sid
|
1561
|
+
|
1562
|
+
return Schema_SIDOption(
|
1563
|
+
type=kind,
|
1564
|
+
length=4,
|
1565
|
+
sid=sid,
|
1566
|
+
)
|
1567
|
+
|
1568
|
+
def _make_opt_ssr(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_SSROption]' = None, *,
|
1569
|
+
counts: 'int' = 10, # reasonable default
|
1570
|
+
route: 'Optional[list[IPv4Address | str | bytes | int]]' = None,
|
1571
|
+
**kwargs: 'Any') -> 'Schema_SSROption':
|
1572
|
+
"""Make IPv4 Strict Source Route (``SSR``) option.
|
1573
|
+
|
1574
|
+
Args:
|
1575
|
+
kind: option type code
|
1576
|
+
option: option data
|
1577
|
+
counts: maximum number of addresses to record
|
1578
|
+
route: list of IPv4 addresses as recorded routes
|
1579
|
+
**kwargs: arbitrary keyword arguments
|
1580
|
+
|
1581
|
+
Returns:
|
1582
|
+
Constructured option schema.
|
1583
|
+
|
1584
|
+
"""
|
1585
|
+
if option is not None:
|
1586
|
+
route = cast('list[IPv4Address | str | bytes | int]', option.route)
|
1587
|
+
pointer = option.pointer
|
1588
|
+
length = option.length
|
1589
|
+
else:
|
1590
|
+
route = [] if route is None else route
|
1591
|
+
length = 3 + counts * 4
|
1592
|
+
pointer = 4 + min(len(route), counts) * 4
|
1593
|
+
|
1594
|
+
return Schema_SSROption(
|
1595
|
+
type=kind,
|
1596
|
+
length=length,
|
1597
|
+
pointer=pointer,
|
1598
|
+
route=route,
|
1599
|
+
)
|
1600
|
+
|
1601
|
+
def _make_opt_mtup(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_MTUPOption]' = None, *,
|
1602
|
+
mtu: 'int' = 0,
|
1603
|
+
**kwargs: 'Any') -> 'Schema_MTUPOption':
|
1604
|
+
"""Make IPv4 MTU Probe (``MTUP``) option.
|
1605
|
+
|
1606
|
+
Args:
|
1607
|
+
kind: option type code
|
1608
|
+
option: option data
|
1609
|
+
mtu: MTU value
|
1610
|
+
**kwargs: arbitrary keyword arguments
|
1611
|
+
|
1612
|
+
Returns:
|
1613
|
+
Constructured option schema.
|
1614
|
+
|
1615
|
+
"""
|
1616
|
+
if option is not None:
|
1617
|
+
mtu = option.mtu
|
1618
|
+
|
1619
|
+
return Schema_MTUPOption(
|
1620
|
+
type=kind,
|
1621
|
+
length=4,
|
1622
|
+
mtu=mtu,
|
1623
|
+
)
|
1624
|
+
|
1625
|
+
def _make_opt_mtur(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_MTUROption]' = None, *,
|
1626
|
+
mtu: 'int' = 0,
|
1627
|
+
**kwargs: 'Any') -> 'Schema_MTUROption':
|
1628
|
+
"""Make IPv4 MTU Reply (``MTUR``) option.
|
1629
|
+
|
1630
|
+
Args:
|
1631
|
+
kind: option type code
|
1632
|
+
option: option data
|
1633
|
+
mtu: MTU value
|
1634
|
+
**kwargs: arbitrary keyword arguments
|
1635
|
+
|
1636
|
+
Returns:
|
1637
|
+
Constructured option schema.
|
1638
|
+
|
1639
|
+
"""
|
1640
|
+
if option is not None:
|
1641
|
+
mtu = option.mtu
|
1642
|
+
|
1643
|
+
return Schema_MTUROption(
|
1644
|
+
type=kind,
|
1645
|
+
length=4,
|
1646
|
+
mtu=mtu,
|
1647
|
+
)
|
1648
|
+
|
1649
|
+
def _make_opt_tr(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_TROption]' = None, *,
|
1650
|
+
id: 'int' = 0,
|
1651
|
+
out: 'int' = 0,
|
1652
|
+
ret: 'int' = 0,
|
1653
|
+
origin: 'IPv4Address | str | bytes | int' = '127.0.0.1',
|
1654
|
+
**kwargs: 'Any') -> 'Schema_TROption':
|
1655
|
+
"""Make IPv4 Traceroute (``TR``) option.
|
1656
|
+
|
1657
|
+
Args:
|
1658
|
+
kind: option type code
|
1659
|
+
option: option data
|
1660
|
+
id: ID number
|
1661
|
+
out: outbound hop count
|
1662
|
+
ret: return hop count
|
1663
|
+
origin: originator IP address
|
1664
|
+
**kwargs: arbitrary keyword arguments
|
1665
|
+
|
1666
|
+
Returns:
|
1667
|
+
Constructured option schema.
|
1668
|
+
|
1669
|
+
"""
|
1670
|
+
if option is not None:
|
1671
|
+
id = option.id
|
1672
|
+
out = option.outbound
|
1673
|
+
ret = option['return']
|
1674
|
+
origin = option.originator
|
1675
|
+
|
1676
|
+
return Schema_TROption(
|
1677
|
+
type=kind,
|
1678
|
+
length=12,
|
1679
|
+
id=id,
|
1680
|
+
out=out,
|
1681
|
+
ret=ret,
|
1682
|
+
origin=origin,
|
1683
|
+
)
|
1684
|
+
|
1685
|
+
def _make_opt_rtralt(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_RTRALTOption]' = None, *,
|
1686
|
+
alert: 'Enum_RouterAlert | StdlibEnum | AenumEnum | int | str' = Enum_RouterAlert.Aggregated_Reservation_Nesting_Level_0,
|
1687
|
+
alert_default: 'Optional[int]' = None,
|
1688
|
+
alert_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
1689
|
+
alert_reversed: 'bool' = False,
|
1690
|
+
**kwargs: 'Any') -> 'Schema_RTRALTOption':
|
1691
|
+
"""Make IPv4 Router Alert (``RTRALT``) option.
|
1692
|
+
|
1693
|
+
Args:
|
1694
|
+
kind: option type code
|
1695
|
+
option: option data
|
1696
|
+
alert: router alert type
|
1697
|
+
alert_default: default value for router alert type
|
1698
|
+
alert_namespace: namespace for router alert type
|
1699
|
+
alert_reversed: whether router alert type is reversed
|
1700
|
+
**kwargs: arbitrary keyword arguments
|
1701
|
+
|
1702
|
+
Returns:
|
1703
|
+
Constructured option schema.
|
1704
|
+
|
1705
|
+
"""
|
1706
|
+
if option is not None:
|
1707
|
+
alert_val = option.alert
|
1708
|
+
else:
|
1709
|
+
alert_val = self._make_index(alert, alert_default, namespace=alert_namespace, # type: ignore[assignment]
|
1710
|
+
reversed=alert_reversed, pack=False)
|
1711
|
+
|
1712
|
+
return Schema_RTRALTOption(
|
1713
|
+
type=kind,
|
1714
|
+
length=4,
|
1715
|
+
alert=alert_val,
|
1716
|
+
)
|
1717
|
+
|
1718
|
+
def _make_opt_qs(self, kind: 'Enum_OptionNumber', option: 'Optional[Data_QuickStartRequestOption | Data_QuickStartReportOption]' = None, *,
|
1719
|
+
func: 'Enum_QSFunction | StdlibEnum | AenumEnum | str | int' = Enum_QSFunction.Quick_Start_Request,
|
1720
|
+
func_default: 'Optional[int]' = None,
|
1721
|
+
func_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
|
1722
|
+
func_reversed: 'bool' = False,
|
1723
|
+
rate: 'int' = 0,
|
1724
|
+
ttl: 'timedelta | int' = 0,
|
1725
|
+
nonce: 'int' = 0,
|
1726
|
+
**kwargs: 'Any') -> 'Schema_QSOption':
|
1727
|
+
"""Make IPv4 Quick-Start (``QS``) option.
|
1728
|
+
|
1729
|
+
Args:
|
1730
|
+
code: option type value
|
1731
|
+
opt: option data
|
1732
|
+
func: QS function type
|
1733
|
+
func_default: default value for QS function type
|
1734
|
+
func_namespace: namespace for QS function type
|
1735
|
+
func_reversed: reversed flag for QS function type
|
1736
|
+
rate: rate (in kbps)
|
1737
|
+
ttl: time to live (in seconds)
|
1738
|
+
nonce: nonce value
|
1739
|
+
**kwargs: arbitrary keyword arguments
|
1740
|
+
|
1741
|
+
Returns:
|
1742
|
+
Constructured option schema.
|
1743
|
+
|
1744
|
+
"""
|
1745
|
+
if option is not None:
|
1746
|
+
func_enum = option.func
|
1747
|
+
rate = option.rate
|
1748
|
+
ttl = getattr(option, 'ttl', 0)
|
1749
|
+
nonce = option.nonce
|
1750
|
+
else:
|
1751
|
+
func_enum = self._make_index(func, func_default, namespace=func_namespace, # type: ignore[assignment]
|
1752
|
+
reversed=func_reversed, pack=False)
|
1753
|
+
rate_val = math.floor(math.log2(rate * 1000 / 40000)) if rate > 0 else 0
|
1754
|
+
|
1755
|
+
if func_enum == Enum_QSFunction.Quick_Start_Request:
|
1756
|
+
ttl_value = ttl if isinstance(ttl, int) else math.floor(ttl.total_seconds())
|
1757
|
+
|
1758
|
+
return Schema_QuickStartRequestOption(
|
1759
|
+
type=kind,
|
1760
|
+
length=8,
|
1761
|
+
flags={
|
1762
|
+
'func': func_enum,
|
1763
|
+
'rate': rate_val,
|
1764
|
+
},
|
1765
|
+
ttl=ttl_value,
|
1766
|
+
nonce={
|
1767
|
+
'nonce': nonce,
|
1768
|
+
},
|
1769
|
+
)
|
1770
|
+
if func_enum == Enum_QSFunction.Report_of_Approved_Rate:
|
1771
|
+
return Schema_QuickStartReportOption(
|
1772
|
+
type=kind,
|
1773
|
+
length=8,
|
1774
|
+
flags={
|
1775
|
+
'func': func_enum,
|
1776
|
+
'rate': rate_val,
|
1777
|
+
},
|
1778
|
+
nonce={
|
1779
|
+
'nonce': nonce,
|
1780
|
+
},
|
1781
|
+
)
|
1782
|
+
raise ProtocolError(f'{self.alias}: [OptNo {kind}] invalid QS function: {func_enum}')
|