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