pypcapkit 1.3.5.post6__cp312-none-any.whl

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