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,3025 @@
1
+ # -*- coding: utf-8 -*-
2
+ # mypy: disable-error-code=dict-item
3
+ """TCP - Transmission Control Protocol
4
+ =========================================
5
+
6
+ .. module:: pcapkit.protocols.transport.tcp
7
+
8
+ :mod:`pcapkit.protocols.transport.tcp` contains
9
+ :class:`~pcapkit.protocols.transport.tcp.TCP` only,
10
+ which implements extractor for Transmission Control
11
+ Protocol (TCP) [*]_, whose structure is described as
12
+ below:
13
+
14
+ ======= ========= ========================= =======================================
15
+ Octets Bits Name Description
16
+ ======= ========= ========================= =======================================
17
+ 0 0 ``tcp.srcport`` Source Port
18
+ 2 16 ``tcp.dstport`` Destination Port
19
+ 4 32 ``tcp.seq`` Sequence Number
20
+ 8 64 ``tcp.ack`` Acknowledgement Number (if ACK set)
21
+ 12 96 ``tcp.hdr_len`` Data Offset
22
+ 12 100 Reserved (must be ``\\x00``)
23
+ 12 103 ``tcp.flags.ns`` ECN Concealment Protection (NS)
24
+ 13 104 ``tcp.flags.cwr`` Congestion Window Reduced (CWR)
25
+ 13 105 ``tcp.flags.ece`` ECN-Echo (ECE)
26
+ 13 106 ``tcp.flags.urg`` Urgent (URG)
27
+ 13 107 ``tcp.flags.ack`` Acknowledgement (ACK)
28
+ 13 108 ``tcp.flags.psh`` Push Function (PSH)
29
+ 13 109 ``tcp.flags.rst`` Reset Connection (RST)
30
+ 13 110 ``tcp.flags.syn`` Synchronize Sequence Numbers (SYN)
31
+ 13 111 ``tcp.flags.fin`` Last Packet from Sender (FIN)
32
+ 14 112 ``tcp.window_size`` Size of Receive Window
33
+ 16 128 ``tcp.checksum`` Checksum
34
+ 18 144 ``tcp.urgent_pointer`` Urgent Pointer (if URG set)
35
+ 20 160 ``tcp.opt`` TCP Options (if data offset > 5)
36
+ ======= ========= ========================= =======================================
37
+
38
+ .. [*] https://en.wikipedia.org/wiki/Transmission_Control_Protocol
39
+
40
+ """
41
+ import collections
42
+ import datetime
43
+ import ipaddress
44
+ import math
45
+ from typing import TYPE_CHECKING, cast
46
+
47
+ from pcapkit.const.reg.transtype import TransType
48
+ from pcapkit.const.tcp.checksum import Checksum as Enum_Checksum
49
+ from pcapkit.const.tcp.flags import Flags as Enum_Flags
50
+ from pcapkit.const.tcp.mp_tcp_option import MPTCPOption as Enum_MPTCPOption
51
+ from pcapkit.const.tcp.option import Option as Enum_Option
52
+ from pcapkit.corekit.module import ModuleDescriptor
53
+ from pcapkit.corekit.multidict import OrderedMultiDict
54
+ from pcapkit.protocols.data.transport.tcp import CC as Data_CC
55
+ from pcapkit.protocols.data.transport.tcp import MPTCPDSS as Data_MPTCPDSS
56
+ from pcapkit.protocols.data.transport.tcp import SACK as Data_SACK
57
+ from pcapkit.protocols.data.transport.tcp import TCP as Data_TCP
58
+ from pcapkit.protocols.data.transport.tcp import AlternateChecksumData as Data_AlternateChecksumData
59
+ from pcapkit.protocols.data.transport.tcp import \
60
+ AlternateChecksumRequest as Data_AlternateChecksumRequest
61
+ from pcapkit.protocols.data.transport.tcp import Authentication as Data_Authentication
62
+ from pcapkit.protocols.data.transport.tcp import CCEcho as Data_CCEcho
63
+ from pcapkit.protocols.data.transport.tcp import CCNew as Data_CCNew
64
+ from pcapkit.protocols.data.transport.tcp import Echo as Data_Echo
65
+ from pcapkit.protocols.data.transport.tcp import EchoReply as Data_EchoReply
66
+ from pcapkit.protocols.data.transport.tcp import EndOfOptionList as Data_EndOfOptionList
67
+ from pcapkit.protocols.data.transport.tcp import FastOpenCookie as Data_FastOpenCookie
68
+ from pcapkit.protocols.data.transport.tcp import Flags as Data_Flags
69
+ from pcapkit.protocols.data.transport.tcp import MaximumSegmentSize as Data_MaximumSegmentSize
70
+ from pcapkit.protocols.data.transport.tcp import MD5Signature as Data_MD5Signature
71
+ from pcapkit.protocols.data.transport.tcp import MPTCPAddAddress as Data_MPTCPAddAddress
72
+ from pcapkit.protocols.data.transport.tcp import MPTCPCapable as Data_MPTCPCapable
73
+ from pcapkit.protocols.data.transport.tcp import MPTCPCapableFlag as Data_MPTCPCapableFlag
74
+ from pcapkit.protocols.data.transport.tcp import MPTCPFallback as Data_MPTCPFallback
75
+ from pcapkit.protocols.data.transport.tcp import MPTCPFastclose as Data_MPTCPFastclose
76
+ from pcapkit.protocols.data.transport.tcp import MPTCPJoinACK as Data_MPTCPJoinACK
77
+ from pcapkit.protocols.data.transport.tcp import MPTCPJoinSYN as Data_MPTCPJoinSYN
78
+ from pcapkit.protocols.data.transport.tcp import MPTCPJoinSYNACK as Data_MPTCPJoinSYNACK
79
+ from pcapkit.protocols.data.transport.tcp import MPTCPPriority as Data_MPTCPPriority
80
+ from pcapkit.protocols.data.transport.tcp import MPTCPRemoveAddress as Data_MPTCPRemoveAddress
81
+ from pcapkit.protocols.data.transport.tcp import MPTCPUnknown as Data_MPTCPUnknown
82
+ from pcapkit.protocols.data.transport.tcp import NoOperation as Data_NoOperation
83
+ from pcapkit.protocols.data.transport.tcp import \
84
+ PartialOrderConnectionPermitted as Data_PartialOrderConnectionPermitted
85
+ from pcapkit.protocols.data.transport.tcp import \
86
+ PartialOrderServiceProfile as Data_PartialOrderServiceProfile
87
+ from pcapkit.protocols.data.transport.tcp import QuickStartResponse as Data_QuickStartResponse
88
+ from pcapkit.protocols.data.transport.tcp import SACKBlock as Data_SACKBlock
89
+ from pcapkit.protocols.data.transport.tcp import SACKPermitted as Data_SACKPermitted
90
+ from pcapkit.protocols.data.transport.tcp import Timestamps as Data_Timestamps
91
+ from pcapkit.protocols.data.transport.tcp import UnassignedOption as Data_UnassignedOption
92
+ from pcapkit.protocols.data.transport.tcp import UserTimeout as Data_UserTimeout
93
+ from pcapkit.protocols.data.transport.tcp import WindowScale as Data_WindowScale
94
+ from pcapkit.protocols.schema.transport.tcp import CC as Schema_CC
95
+ from pcapkit.protocols.schema.transport.tcp import MPTCPDSS as Schema_MPTCPDSS
96
+ from pcapkit.protocols.schema.transport.tcp import SACK as Schema_SACK
97
+ from pcapkit.protocols.schema.transport.tcp import TCP as Schema_TCP
98
+ from pcapkit.protocols.schema.transport.tcp import \
99
+ AlternateChecksumData as Schema_AlternateChecksumData
100
+ from pcapkit.protocols.schema.transport.tcp import \
101
+ AlternateChecksumRequest as Schema_AlternateChecksumRequest
102
+ from pcapkit.protocols.schema.transport.tcp import Authentication as Schema_Authentication
103
+ from pcapkit.protocols.schema.transport.tcp import CCEcho as Schema_CCEcho
104
+ from pcapkit.protocols.schema.transport.tcp import CCNew as Schema_CCNew
105
+ from pcapkit.protocols.schema.transport.tcp import Echo as Schema_Echo
106
+ from pcapkit.protocols.schema.transport.tcp import EchoReply as Schema_EchoReply
107
+ from pcapkit.protocols.schema.transport.tcp import EndOfOptionList as Schema_EndOfOptionList
108
+ from pcapkit.protocols.schema.transport.tcp import FastOpenCookie as Schema_FastOpenCookie
109
+ from pcapkit.protocols.schema.transport.tcp import MaximumSegmentSize as Schema_MaximumSegmentSize
110
+ from pcapkit.protocols.schema.transport.tcp import MD5Signature as Schema_MD5Signature
111
+ from pcapkit.protocols.schema.transport.tcp import MPTCPAddAddress as Schema_MPTCPAddAddress
112
+ from pcapkit.protocols.schema.transport.tcp import MPTCPCapable as Schema_MPTCPCapable
113
+ from pcapkit.protocols.schema.transport.tcp import MPTCPFallback as Schema_MPTCPFallback
114
+ from pcapkit.protocols.schema.transport.tcp import MPTCPFastclose as Schema_MPTCPFastclose
115
+ from pcapkit.protocols.schema.transport.tcp import MPTCPJoinACK as Schema_MPTCPJoinACK
116
+ from pcapkit.protocols.schema.transport.tcp import MPTCPJoinSYN as Schema_MPTCPJoinSYN
117
+ from pcapkit.protocols.schema.transport.tcp import MPTCPJoinSYNACK as Schema_MPTCPJoinSYNACK
118
+ from pcapkit.protocols.schema.transport.tcp import MPTCPPriority as Schema_MPTCPPriority
119
+ from pcapkit.protocols.schema.transport.tcp import MPTCPRemoveAddress as Schema_MPTCPRemoveAddress
120
+ from pcapkit.protocols.schema.transport.tcp import MPTCPUnknown as Schema_MPTCPUnknown
121
+ from pcapkit.protocols.schema.transport.tcp import NoOperation as Schema_NoOperation
122
+ from pcapkit.protocols.schema.transport.tcp import \
123
+ PartialOrderConnectionPermitted as Schema_PartialOrderConnectionPermitted
124
+ from pcapkit.protocols.schema.transport.tcp import \
125
+ PartialOrderServiceProfile as Schema_PartialOrderServiceProfile
126
+ from pcapkit.protocols.schema.transport.tcp import QuickStartResponse as Schema_QuickStartResponse
127
+ from pcapkit.protocols.schema.transport.tcp import SACKBlock as Schema_SACKBlock
128
+ from pcapkit.protocols.schema.transport.tcp import SACKPermitted as Schema_SACKPermitted
129
+ from pcapkit.protocols.schema.transport.tcp import Timestamps as Schema_Timestamps
130
+ from pcapkit.protocols.schema.transport.tcp import UnassignedOption as Schema_UnassignedOption
131
+ from pcapkit.protocols.schema.transport.tcp import UserTimeout as Schema_UserTimeout
132
+ from pcapkit.protocols.schema.transport.tcp import WindowScale as Schema_WindowScale
133
+ from pcapkit.protocols.transport.transport import Transport
134
+ from pcapkit.utilities.exceptions import ProtocolError
135
+ from pcapkit.utilities.warnings import RegistryWarning, warn
136
+
137
+ if TYPE_CHECKING:
138
+ from datetime import timedelta
139
+ from enum import IntEnum as StdlibEnum
140
+ from ipaddress import IPv4Address, IPv6Address
141
+ from typing import Any, Callable, DefaultDict, Optional, Type
142
+
143
+ from aenum import IntEnum as AenumEnum
144
+ from mypy_extensions import DefaultArg, KwArg, NamedArg
145
+ from typing_extensions import Literal
146
+
147
+ from pcapkit.const.reg.apptype import AppType as Enum_AppType
148
+ from pcapkit.protocols.data.transport.tcp import MPTCP as Data_MPTCP
149
+ from pcapkit.protocols.data.transport.tcp import MPTCPJoin as Data_MPTCPJoin
150
+ from pcapkit.protocols.data.transport.tcp import Option as Data_Option
151
+ from pcapkit.protocols.protocol import ProtocolBase as Protocol
152
+ from pcapkit.protocols.schema.schema import Schema
153
+ from pcapkit.protocols.schema.transport.tcp import MPTCP as Schema_MPTCP
154
+ from pcapkit.protocols.schema.transport.tcp import Flags as Schema_Flags
155
+ from pcapkit.protocols.schema.transport.tcp import MPTCPJoin as Schema_MPTCPJoin
156
+ from pcapkit.protocols.schema.transport.tcp import Option as Schema_Option
157
+
158
+ Option = OrderedMultiDict[Enum_Option, Data_Option]
159
+ OptionParser = Callable[[Schema_Option, NamedArg(Option, 'options')], Data_Option]
160
+ MPOptionParser = Callable[[Schema_MPTCP, NamedArg(Option, 'options')], Data_MPTCP]
161
+ OptionConstructor = Callable[[Enum_Option, DefaultArg(Optional[Data_Option]),
162
+ KwArg(Any)], Schema_Option]
163
+ MPOptionConstructor = Callable[[Enum_MPTCPOption, DefaultArg(Optional[Data_MPTCP]),
164
+ KwArg(Any)], Schema_MPTCP]
165
+
166
+ __all__ = ['TCP']
167
+
168
+
169
+ class TCP(Transport[Data_TCP, Schema_TCP],
170
+ schema=Schema_TCP, data=Data_TCP):
171
+ """This class implements Transmission Control Protocol.
172
+
173
+ This class currently supports parsing of the following protocols, which are
174
+ registered in the :attr:`self.__proto__ <pcapkit.protocols.transport.tcp.TCP.__proto__>`
175
+ attribute:
176
+
177
+ .. list-table::
178
+ :header-rows: 1
179
+
180
+ * - Port Number
181
+ - Protocol
182
+ * - 21
183
+ - :class:`pcapkit.protocols.application.ftp.FTP`
184
+ * - 80
185
+ - :class:`pcapkit.protocols.application.http.HTTP`
186
+
187
+ This class currently supports parsing of the following TCP options,
188
+ which are directly mapped to the :class:`pcapkit.const.tcp.option.Option`
189
+ enumeration:
190
+
191
+ .. list-table::
192
+ :header-rows: 1
193
+
194
+ * - Option Code
195
+ - Option Parser
196
+ - Option Constructor
197
+ * - :attr:`~pcapkit.const.tcp.option.Option.End_of_Option_List`
198
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_eool`
199
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_eool`
200
+ * - :attr:`~pcapkit.const.tcp.option.Option.No_Operation`
201
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_nop`
202
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_nop`
203
+ * - :attr:`~pcapkit.const.tcp.option.Option.Maximum_Segment_Size`
204
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_mss`
205
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_mss`
206
+ * - :attr:`~pcapkit.const.tcp.option.Option.Window_Scale`
207
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_ws`
208
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_ws`
209
+ * - :attr:`~pcapkit.const.tcp.option.Option.SACK_Permitted`
210
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_sackpmt`
211
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_sackpmt`
212
+ * - :attr:`~pcapkit.const.tcp.option.Option.SACK`
213
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_sack`
214
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_sack`
215
+ * - :attr:`~pcapkit.const.tcp.option.Option.Echo`
216
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_echo`
217
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_echo`
218
+ * - :attr:`~pcapkit.const.tcp.option.Option.Echo_Reply`
219
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_echore`
220
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_echore`
221
+ * - :attr:`~pcapkit.const.tcp.option.Option.Timestamps`
222
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_ts`
223
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_ts`
224
+ * - :attr:`~pcapkit.const.tcp.option.Option.Partial_Order_Connection_Permitted`
225
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_poc`
226
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_poc`
227
+ * - :attr:`~pcapkit.const.tcp.option.Option.Partial_Order_Service_Profile`
228
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_pocsp`
229
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_pocsp`
230
+ * - :attr:`~pcapkit.const.tcp.option.Option.CC`
231
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_cc`
232
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_cc`
233
+ * - :attr:`~pcapkit.const.tcp.option.Option.CC_NEW`
234
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_ccnew`
235
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_ccnew`
236
+ * - :attr:`~pcapkit.const.tcp.option.Option.CC_ECHO`
237
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_ccecho`
238
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_ccecho`
239
+ * - :attr:`~pcapkit.const.tcp.option.Option.TCP_Alternate_Checksum_Request`
240
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_chkreq`
241
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_chkreq`
242
+ * - :attr:`~pcapkit.const.tcp.option.Option.TCP_Alternate_Checksum_Data`
243
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_chksum`
244
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_chksum`
245
+ * - :attr:`~pcapkit.const.tcp.option.Option.MD5_Signature_Option`
246
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_sig`
247
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_sig`
248
+ * - :attr:`~pcapkit.const.tcp.option.Option.Quick_Start_Response`
249
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_qs`
250
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_qs`
251
+ * - :attr:`~pcapkit.const.tcp.option.Option.User_Timeout_Option`
252
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_timeout`
253
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_timeout`
254
+ * - :attr:`~pcapkit.const.tcp.option.Option.TCP_Authentication_Option`
255
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_ao`
256
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_ao`
257
+ * - :attr:`~pcapkit.const.tcp.option.Option.Multipath_TCP`
258
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_mp`
259
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_mp`
260
+ * - :attr:`~pcapkit.const.tcp.option.Option.TCP_Fast_Open_Cookie`
261
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mode_fastopen`
262
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mode_fastopen`
263
+
264
+ This class currently supports parsing of the following Multipath TCP options,
265
+ which are directly mapped to the :class:`pcapkit.const.tcp.mp_tcp_option.MPTCPOption`
266
+ enumeration:
267
+
268
+ .. list-table::
269
+ :header-rows: 1
270
+
271
+ * - Option Code
272
+ - Option Parser
273
+ - Option Constructor
274
+ * - :attr:`~pcapkit.const.tcp.mp_tcp_option.MPTCPOption.MP_CAPABLE`
275
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mptcp_capable`
276
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mptcp_capable`
277
+ * - :attr:`~pcapkit.const.tcp.mp_tcp_option.MPTCPOption.MP_JOIN`
278
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mptcp_join`
279
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mptcp_join`
280
+ * - :attr:`~pcapkit.const.tcp.mp_tcp_option.MPTCPOption.DSS`
281
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mptcp_dss`
282
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mptcp_dss`
283
+ * - :attr:`~pcapkit.const.tcp.mp_tcp_option.MPTCPOption.ADD_ADDR`
284
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mptcp_addaddr`
285
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mptcp_addaddr`
286
+ * - :attr:`~pcapkit.const.tcp.mp_tcp_option.MPTCPOption.REMOVE_ADDR`
287
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mptcp_remove`
288
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mptcp_remove`
289
+ * - :attr:`~pcapkit.const.tcp.mp_tcp_option.MPTCPOption.MP_PRIO`
290
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mptcp_prio`
291
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mptcp_prio`
292
+ * - :attr:`~pcapkit.const.tcp.mp_tcp_option.MPTCPOption.MP_FAIL`
293
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mptcp_fail`
294
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mptcp_fail`
295
+ * - :attr:`~pcapkit.const.tcp.mp_tcp_option.MPTCPOption.MP_FASTCLOSE`
296
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._read_mptcp_fastclose`
297
+ - :meth:`~pcapkit.protocols.transport.tcp.TCP._make_mptcp_fastclose`
298
+
299
+ """
300
+
301
+ ##########################################################################
302
+ # Defaults.
303
+ ##########################################################################
304
+
305
+ #: DefaultDict[int, ModuleDescriptor[Protocol] | Type[Protocol]]: Protocol
306
+ #: index mapping for decoding next layer, c.f.
307
+ #: :meth:`self._decode_next_layer <pcapkit.protocols.transport.transport.Transport._decode_next_layer>`
308
+ #: & :meth:`self._import_next_layer <pcapkit.protocols.protocol.Protocol._import_next_layer>`.
309
+ __proto__ = collections.defaultdict(
310
+ lambda: ModuleDescriptor('pcapkit.protocols.misc.raw', 'Raw'),
311
+ {
312
+ 21: ModuleDescriptor('pcapkit.protocols.application.ftp', 'FTP'), # FTP
313
+ 80: ModuleDescriptor('pcapkit.protocols.application.httpv1', 'HTTP'), # HTTP/1.*
314
+ },
315
+ )
316
+
317
+ #: DefaultDict[Enum_Option, str | tuple[OptionParser, OptionConstructor]]: Option
318
+ #: code to method mapping, c.f. :meth:`_read_tcp_options` and
319
+ #: :meth:`_make_tcp_options`. Method names are expected to be referred to
320
+ #: the class by ``_read_mode_${name}`` and ``_make_mode_${name}``, and if
321
+ #: such name not found, the value should then be a method that can parse
322
+ #: the option by itself.
323
+ __option__ = collections.defaultdict(
324
+ lambda: 'donone',
325
+ {
326
+ Enum_Option.End_of_Option_List: 'eool', # [RFC 793] End of Option List
327
+ Enum_Option.No_Operation: 'nop', # [RFC 793] No-Operation
328
+ Enum_Option.Maximum_Segment_Size: 'mss', # [RFC 793] Maximum Segment Size
329
+ Enum_Option.Window_Scale: 'ws', # [RFC 7323] Window Scale
330
+ Enum_Option.SACK_Permitted: 'sackpmt', # [RFC 2018] SACK Permitted
331
+ Enum_Option.SACK: 'sack', # [RFC 2018] SACK
332
+ Enum_Option.Echo: 'echo', # [RFC 1072] Echo
333
+ Enum_Option.Echo_Reply: 'echore', # [RFC 1072] Echo Reply
334
+ Enum_Option.Timestamps: 'ts', # [RFC 7323] Timestamps
335
+ Enum_Option.Partial_Order_Connection_Permitted: 'poc', # [RFC 1693] POC Permitted
336
+ Enum_Option.Partial_Order_Service_Profile: 'pocsp', # [RFC 1693] POC-Serv Profile
337
+ Enum_Option.CC: 'cc', # [RFC 1644] Connection Count
338
+ Enum_Option.CC_NEW: 'ccnew', # [RFC 1644] CC.NEW
339
+ Enum_Option.CC_ECHO: 'ccecho', # [RFC 1644] CC.ECHO
340
+ Enum_Option.TCP_Alternate_Checksum_Request: 'chkreq', # [RFC 1146] Alt-Chksum Request
341
+ Enum_Option.TCP_Alternate_Checksum_Data: 'chksum', # [RFC 1146] Alt-Chksum Data
342
+ Enum_Option.MD5_Signature_Option: 'sig', # [RFC 2385] MD5 Signature Option
343
+ Enum_Option.Quick_Start_Response: 'qs', # [RFC 4782] Quick-Start Response
344
+ Enum_Option.User_Timeout_Option: 'timeout', # [RFC 5482] User Timeout Option
345
+ Enum_Option.TCP_Authentication_Option: 'ao', # [RFC 5925] TCP Authentication Option
346
+ Enum_Option.Multipath_TCP: 'mp', # [RFC 6824] Multipath TCP
347
+ Enum_Option.TCP_Fast_Open_Cookie: 'fastopen', # [RFC 7413] Fast Open
348
+ },
349
+ ) # type: DefaultDict[int, str | tuple[OptionParser, OptionConstructor]]
350
+
351
+ #: DefaultDict[Enum_MPTCPOption, str | tuple[MPOptionParser, MPOptionConstructor]]: Option
352
+ #: code to method mapping, c.f. :meth:`_read_mode_mp` and :meth:`_make_mode_mp`.
353
+ #: Method names are expected to be referred to the class by ``_read_mptcp_${name}``
354
+ #: and ``_make_mptcp_${name}``, and if such name not found, the value should
355
+ #: then be a method that can parse the option by itself.
356
+ __mp_option__ = collections.defaultdict(
357
+ lambda: 'unknown',
358
+ {
359
+ Enum_MPTCPOption.MP_CAPABLE: 'capable',
360
+ Enum_MPTCPOption.MP_JOIN: 'join',
361
+ Enum_MPTCPOption.DSS: 'dss',
362
+ Enum_MPTCPOption.ADD_ADDR: 'addaddr',
363
+ Enum_MPTCPOption.REMOVE_ADDR: 'removeaddr',
364
+ Enum_MPTCPOption.MP_PRIO: 'prio',
365
+ Enum_MPTCPOption.MP_FAIL: 'fail',
366
+ Enum_MPTCPOption.MP_FASTCLOSE: 'fastclose',
367
+ },
368
+ ) # type: DefaultDict[int, str | tuple[MPOptionParser, MPOptionConstructor]]
369
+
370
+ ##########################################################################
371
+ # Properties.
372
+ ##########################################################################
373
+
374
+ @property
375
+ def name(self) -> 'Literal["Transmission Control Protocol"]':
376
+ """Name of current protocol."""
377
+ return 'Transmission Control Protocol'
378
+
379
+ @property
380
+ def length(self) -> 'int':
381
+ """Header length of current protocol."""
382
+ return self._info.hdr_len
383
+
384
+ @property
385
+ def src(self) -> 'Enum_AppType':
386
+ """Source port."""
387
+ return self._info.srcport
388
+
389
+ @property
390
+ def dst(self) -> 'Enum_AppType':
391
+ """Destination port."""
392
+ return self._info.dstport
393
+
394
+ @property
395
+ def connection(self) -> 'Enum_Flags':
396
+ """Connection flags."""
397
+ return self._flags
398
+
399
+ ##########################################################################
400
+ # Methods.
401
+ ##########################################################################
402
+
403
+ def read(self, length: 'Optional[int]' = None, **kwargs: 'Any') -> 'Data_TCP': # pylint: disable=unused-argument
404
+ """Read Transmission Control Protocol (TCP).
405
+
406
+ Structure of TCP header [:rfc:`793`]::
407
+
408
+ 0 1 2 3
409
+ 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
410
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411
+ | Source Port | Destination Port |
412
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
413
+ | Sequence Number |
414
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
415
+ | Acknowledgement Number |
416
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
417
+ | Data | |U|A|P|R|S|F| |
418
+ | Offset| Reserved |R|C|S|S|Y|I| Window |
419
+ | | |G|K|H|T|N|N| |
420
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
421
+ | Checksum | Urgent Pointer |
422
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
423
+ | Options | Padding |
424
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
425
+ | data |
426
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427
+
428
+ Args:
429
+ length: Length of packet data.
430
+ **kwargs: Arbitrary keyword arguments.
431
+
432
+ Returns:
433
+ Parsed packet data.
434
+
435
+ """
436
+ if length is None:
437
+ length = len(self)
438
+ schema = self.__header__
439
+
440
+ tcp = Data_TCP(
441
+ srcport=schema.srcport,
442
+ dstport=schema.dstport,
443
+ seq=schema.seq,
444
+ ack=schema.ack,
445
+ hdr_len=schema.offset['offset'] * 4,
446
+ flags=Data_Flags(
447
+ #ns=bool(schema.offset['ns']),
448
+ cwr=bool(schema.flags['cwr']),
449
+ ece=bool(schema.flags['ece']),
450
+ urg=bool(schema.flags['urg']),
451
+ ack=bool(schema.flags['ack']),
452
+ psh=bool(schema.flags['psh']),
453
+ rst=bool(schema.flags['rst']),
454
+ syn=bool(schema.flags['syn']),
455
+ fin=bool(schema.flags['fin']),
456
+ ),
457
+ window_size=schema.window,
458
+ checksum=schema.checksum,
459
+ urgent_pointer=schema.urgent,
460
+ )
461
+
462
+ # connection control flags
463
+ _flag = cast('Enum_Flags', 0)
464
+ for key, val in schema.flags.items():
465
+ if val == 1:
466
+ _flag |= Enum_Flags.get(key.upper())
467
+ self._flags = _flag
468
+
469
+ tcp.__update__({
470
+ 'connection': self._flags,
471
+ })
472
+
473
+ _optl = tcp.hdr_len - 20
474
+ if _optl:
475
+ tcp.__update__({
476
+ 'options': self._read_tcp_options(_optl),
477
+ })
478
+
479
+ return self._decode_next_layer(tcp, (tcp.srcport.port, tcp.dstport.port), length - tcp.hdr_len)
480
+
481
+ def make(self,
482
+ srcport: 'Enum_AppType | int' = 0,
483
+ dstport: 'Enum_AppType | int' = 0,
484
+ seq_no: 'int' = 0,
485
+ ack_no: 'int' = 0,
486
+ ns: 'bool' = False,
487
+ cwr: 'bool' = False,
488
+ ece: 'bool' = False,
489
+ urg: 'bool' = False,
490
+ ack: 'bool' = False,
491
+ psh: 'bool' = False,
492
+ rst: 'bool' = False,
493
+ syn: 'bool' = False,
494
+ fin: 'bool' = False,
495
+ window: 'int' = 65535, # reasonable default value
496
+ checksum: 'bytes' = b'\x00\x00',
497
+ urgent: 'int' = 0,
498
+ options: 'Optional[list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes] | Option]' = None, # pylint: disable=line-too-long
499
+ payload: 'bytes | Protocol | Schema' = b'',
500
+ **kwargs: 'Any') -> 'Schema_TCP':
501
+ """Make (construct) packet data.
502
+
503
+ Args:
504
+ srcport: Source port.
505
+ dstport: Destination port.
506
+ seq_no: Sequence number.
507
+ ack_no: Acknowledgement number.
508
+ ns: ECN-nonce concealment protection.
509
+ cwr: Congestion window reduced.
510
+ ece: ECN-Echo.
511
+ urg: Urgent.
512
+ ack: Acknowledgement.
513
+ psh: Push function.
514
+ rst: Reset connection.
515
+ syn: Synchronize sequence numbers.
516
+ fin: Last packet from sender.
517
+ window: Window size.
518
+ checksum: Checksum.
519
+ urgent: Urgent pointer.
520
+ options: TCP options.
521
+ payload: Payload of the packet.
522
+ **kwargs: Arbitrary keyword arguments.
523
+
524
+ Returns:
525
+ Constructed packet data.
526
+
527
+ """
528
+ if options is not None:
529
+ options_value, total_length = self._make_tcp_options(options)
530
+ else:
531
+ options_value, total_length = [], 0
532
+
533
+ offset = math.ceil((20 + total_length) / 4)
534
+ flags = {
535
+ 'cwr': int(cwr),
536
+ 'ece': int(ece),
537
+ 'urg': int(urg),
538
+ 'ack': int(ack),
539
+ 'psh': int(psh),
540
+ 'rst': int(rst),
541
+ 'syn': int(syn),
542
+ 'fin': int(fin),
543
+ } # type: Schema_Flags
544
+
545
+ _flag = cast('Enum_Flags', 0)
546
+ for key, val in flags.items():
547
+ if val == 1:
548
+ _flag |= Enum_Flags.get(key.upper())
549
+ self._flags = _flag
550
+
551
+ return Schema_TCP(
552
+ srcport=srcport,
553
+ dstport=dstport,
554
+ seq=seq_no,
555
+ ack=ack_no,
556
+ offset={
557
+ 'offset': offset,
558
+ 'ns': int(ns),
559
+ },
560
+ flags=flags,
561
+ window=window,
562
+ checksum=checksum,
563
+ urgent=urgent,
564
+ options=options_value,
565
+ payload=payload,
566
+ )
567
+
568
+ @classmethod
569
+ def register_option(cls, code: 'Enum_Option', meth: 'str | tuple[OptionParser, OptionConstructor]') -> 'None':
570
+ """Register an option parser.
571
+
572
+ Args:
573
+ code: TCP option code.
574
+ meth: Method name or callable to parse and/or construct the option.
575
+
576
+ """
577
+ if code in cls.__option__:
578
+ warn(f'option {code} already registered, overwriting', RegistryWarning)
579
+ cls.__option__[code] = meth
580
+
581
+ @classmethod
582
+ def register_mp_option(cls, code: 'Enum_MPTCPOption', meth: 'str | tuple[MPOptionParser, MPOptionConstructor]') -> 'None':
583
+ """Register an MPTCP option parser.
584
+
585
+ Args:
586
+ code: MPTCP option code.
587
+ meth: Method name or callable to parse and/or construct the option.
588
+
589
+ """
590
+ if code in cls.__mp_option__:
591
+ warn(f'option {code} already registered, overwriting', RegistryWarning)
592
+ cls.__mp_option__[code] = meth
593
+
594
+ ##########################################################################
595
+ # Data models.
596
+ ##########################################################################
597
+
598
+ def __length_hint__(self) -> 'Literal[20]':
599
+ """Return an estimated length for the object."""
600
+ return 20
601
+
602
+ @classmethod
603
+ def __index__(cls) -> 'TransType': # pylint: disable=invalid-index-returned
604
+ """Numeral registry index of the protocol.
605
+
606
+ Returns:
607
+ Numeral registry index of the protocol in `IANA`_.
608
+
609
+ .. _IANA: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
610
+
611
+ """
612
+ return TransType.TCP # type: ignore[return-value]
613
+
614
+ ##########################################################################
615
+ # Utilities.
616
+ ##########################################################################
617
+
618
+ @classmethod
619
+ def _make_data(cls, data: 'Data_TCP') -> 'dict[str, Any]': # type: ignore[override]
620
+ """Create key-value pairs from ``data`` for protocol construction.
621
+
622
+ Args:
623
+ data: protocol data
624
+
625
+ Returns:
626
+ Key-value pairs for protocol construction.
627
+
628
+ """
629
+ return {
630
+ 'srcport': data.srcport,
631
+ 'dstport': data.dstport,
632
+ 'seq_no': data.seq,
633
+ 'ack_no': data.ack,
634
+ #'ns': data.flags.ns,
635
+ 'cwr': data.flags.cwr,
636
+ 'ece': data.flags.ece,
637
+ 'urg': data.flags.urg,
638
+ 'ack': data.flags.ack,
639
+ 'psh': data.flags.psh,
640
+ 'rst': data.flags.rst,
641
+ 'syn': data.flags.syn,
642
+ 'fin': data.flags.fin,
643
+ 'window': data.window_size,
644
+ 'checksum': data.checksum,
645
+ 'urgent': data.urgent_pointer,
646
+ 'options': getattr(data, 'options', None),
647
+ 'payload': cls._make_payload(data),
648
+ }
649
+
650
+ def _read_tcp_options(self, size: 'int') -> 'Option':
651
+ """Read TCP option list.
652
+
653
+ Arguments:
654
+ size: length of option list
655
+
656
+ Returns:
657
+ Extracted TCP options.
658
+
659
+ Raises:
660
+ ProtocolError: If the threshold is **NOT** matching.
661
+
662
+ """
663
+ counter = 0 # length of read option list
664
+ options = OrderedMultiDict() # type: Option
665
+
666
+ for schema in self.__header__.options:
667
+ kind = schema.kind
668
+ name = self.__option__[kind]
669
+
670
+ if isinstance(name, str):
671
+ meth_name = f'_read_mode_{name}'
672
+ meth = cast('OptionParser',
673
+ getattr(self, meth_name, self._read_mode_donone))
674
+ else:
675
+ meth = name[0]
676
+ data = meth(schema, options=options)
677
+
678
+ # record option data
679
+ options.add(kind, data)
680
+ counter += len(schema)
681
+
682
+ # break when End of Option List (EOOL) triggered
683
+ if kind == Enum_Option.End_of_Option_List:
684
+ break
685
+
686
+ # check threshold
687
+ if counter > size:
688
+ raise ProtocolError('TCP: invalid format')
689
+ return options
690
+
691
+ def _read_mode_donone(self, schema: 'Schema_UnassignedOption', *, options: 'Option') -> 'Data_UnassignedOption': # pylint: disable=unused-argument
692
+ """Read options request no process.
693
+
694
+ Arguments:
695
+ schema: parsed option schema
696
+ options: extracted TCP options
697
+
698
+ Returns:
699
+ Parsed option data.
700
+
701
+ """
702
+ option = Data_UnassignedOption(
703
+ kind=schema.kind,
704
+ length=schema.length,
705
+ data=schema.data,
706
+ )
707
+ return option
708
+
709
+ def _read_mode_eool(self, schema: 'Schema_EndOfOptionList', *, options: 'Option') -> 'Data_EndOfOptionList': # pylint: disable=unused-argument
710
+ """Read TCP End of Option List option.
711
+
712
+ Structure of TCP end of option list option [:rfc:`793`]:
713
+
714
+ .. code-block:: text
715
+
716
+ +--------+
717
+ |00000000|
718
+ +--------+
719
+ Kind=0
720
+
721
+ Arguments:
722
+ schema: parsed option schema
723
+ options: extracted TCP options
724
+
725
+ Returns:
726
+ Parsed option data.
727
+
728
+ """
729
+ return Data_EndOfOptionList(
730
+ kind=schema.kind,
731
+ length=1,
732
+ )
733
+
734
+ def _read_mode_nop(self, schema: 'Schema_NoOperation', *, options: 'Option') -> 'Data_NoOperation': # pylint: disable=unused-argument
735
+ """Read TCP No Operation option.
736
+
737
+ Structure of TCP maximum segment size option [:rfc:`793`]:
738
+
739
+ .. code-block:: text
740
+
741
+ +--------+
742
+ |00000001|
743
+ +--------+
744
+ Kind=1
745
+
746
+ Arguments:
747
+ schema: parsed option schema
748
+ options: extracted TCP options
749
+
750
+ Returns:
751
+ Parsed option data.
752
+
753
+ """
754
+ return Data_NoOperation(
755
+ kind=schema.kind,
756
+ length=1,
757
+ )
758
+
759
+ def _read_mode_mss(self, schema: 'Schema_MaximumSegmentSize', *, options: 'Option') -> 'Data_MaximumSegmentSize': # pylint: disable=unused-argument
760
+ """Read TCP max segment size option.
761
+
762
+ Structure of TCP maximum segment size option [:rfc:`793`]:
763
+
764
+ .. code-block:: text
765
+
766
+ +--------+--------+---------+--------+
767
+ |00000010|00000100| max seg size |
768
+ +--------+--------+---------+--------+
769
+ Kind=2 Length=4
770
+
771
+ Arguments:
772
+ schema: parsed option schema
773
+ options: extracted TCP options
774
+
775
+ Returns:
776
+ Parsed option data.
777
+
778
+ Raises:
779
+ ProtocolError: If length is **NOT** ``4``.
780
+
781
+ """
782
+ if schema.length != 4:
783
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
784
+
785
+ data = Data_MaximumSegmentSize(
786
+ kind=schema.kind,
787
+ length=schema.length,
788
+ mss=schema.mss,
789
+ )
790
+ return data
791
+
792
+ def _read_mode_ws(self, schema: 'Schema_WindowScale', *, options: 'Option') -> 'Data_WindowScale': # pylint: disable=unused-argument
793
+ """Read TCP windows scale option.
794
+
795
+ Structure of TCP window scale option [:rfc:`7323`]:
796
+
797
+ .. code-block:: text
798
+
799
+ +---------+---------+---------+
800
+ | Kind=3 |Length=3 |shift.cnt|
801
+ +---------+---------+---------+
802
+ 1 1 1
803
+
804
+ Arguments:
805
+ schema: parsed option schema
806
+ options: extracted TCP options
807
+
808
+ Returns:
809
+ Parsed option data.
810
+
811
+ Raises:
812
+ ProtocolError: If length is **NOT** ``3``.
813
+
814
+ """
815
+ if schema.length != 3:
816
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
817
+
818
+ data = Data_WindowScale(
819
+ kind=schema.kind,
820
+ length=schema.length,
821
+ shift=schema.shift,
822
+ )
823
+ return data
824
+
825
+ def _read_mode_sackpmt(self, schema: 'Schema_SACKPermitted', *, options: 'Option') -> 'Data_SACKPermitted': # pylint: disable=unused-argument
826
+ """Read TCP SACK permitted option.
827
+
828
+ Structure of TCP SACK permitted option [:rfc:`2018`]:
829
+
830
+ .. code-block:: text
831
+
832
+ +---------+---------+
833
+ | Kind=4 | Length=2|
834
+ +---------+---------+
835
+
836
+ Arguments:
837
+ schema: parsed option schema
838
+ options: extracted TCP options
839
+
840
+ Returns:
841
+ Parsed option data.
842
+
843
+ Raises:
844
+ ProtocolError: If length is **NOT** ``2``.
845
+
846
+ """
847
+ if schema.length != 2:
848
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
849
+
850
+ return Data_SACKPermitted(
851
+ kind=schema.kind,
852
+ length=schema.length,
853
+ )
854
+
855
+ def _read_mode_sack(self, schema: 'Schema_SACK', *, options: 'Option') -> 'Data_SACK': # pylint: disable=unused-argument
856
+ """Read TCP SACK option.
857
+
858
+ Structure of TCP SACK option [:rfc:`2018`]:
859
+
860
+ .. code-block:: text
861
+
862
+ +--------+--------+
863
+ | Kind=5 | Length |
864
+ +--------+--------+--------+--------+
865
+ | Left Edge of 1st Block |
866
+ +--------+--------+--------+--------+
867
+ | Right Edge of 1st Block |
868
+ +--------+--------+--------+--------+
869
+ | |
870
+ / . . . /
871
+ | |
872
+ +--------+--------+--------+--------+
873
+ | Left Edge of nth Block |
874
+ +--------+--------+--------+--------+
875
+ | Right Edge of nth Block |
876
+ +--------+--------+--------+--------+
877
+
878
+ Arguments:
879
+ schema: parsed option schema
880
+ options: extracted TCP options
881
+
882
+ Returns:
883
+ Parsed option data.
884
+
885
+ Raises:
886
+ ProtocolError: If length is **NOT** multiply of ``8`` plus ``2``.
887
+
888
+ """
889
+ data = Data_SACK(
890
+ kind=schema.kind,
891
+ length=schema.length,
892
+ sack=tuple(
893
+ Data_SACKBlock(
894
+ left=block.left,
895
+ right=block.right,
896
+ ) for block in schema.sack
897
+ ),
898
+ )
899
+ return data
900
+
901
+ def _read_mode_echo(self, schema: 'Schema_Echo', *, options: 'Option') -> 'Data_Echo': # pylint: disable=unused-argument
902
+ """Read TCP echo option.
903
+
904
+ Structure of TCP echo option [:rfc:`1072`]:
905
+
906
+ .. code-block:: text
907
+
908
+ +--------+--------+--------+--------+--------+--------+
909
+ | Kind=6 | Length | 4 bytes of info to be echoed |
910
+ +--------+--------+--------+--------+--------+--------+
911
+
912
+ Arguments:
913
+ schema: parsed option schema
914
+ options: extracted TCP options
915
+
916
+ Returns:
917
+ Parsed option data.
918
+
919
+ Raises:
920
+ ProtocolError: If length is **NOT** ``6``.
921
+
922
+ """
923
+ if schema.length != 6:
924
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
925
+
926
+ data = Data_Echo(
927
+ kind=schema.kind,
928
+ length=schema.length,
929
+ data=schema.data,
930
+ )
931
+ return data
932
+
933
+ def _read_mode_echore(self, schema: 'Schema_EchoReply', *, options: 'Option') -> 'Data_EchoReply': # pylint: disable=unused-argument
934
+ """Read TCP echo reply option.
935
+
936
+ Structure of TCP echo reply option [:rfc:`1072`]:
937
+
938
+ .. code-block:: text
939
+
940
+ +--------+--------+--------+--------+--------+--------+
941
+ | Kind=7 | Length | 4 bytes of echoed info |
942
+ +--------+--------+--------+--------+--------+--------+
943
+
944
+ Arguments:
945
+ schema: parsed option schema
946
+ options: extracted TCP options
947
+
948
+ Returns:
949
+ Parsed option data.
950
+
951
+ Raises:
952
+ ProtocolError: If length is **NOT** ``6``.
953
+
954
+ """
955
+ if schema.length != 6:
956
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
957
+
958
+ data = Data_EchoReply(
959
+ kind=schema.kind,
960
+ length=schema.length,
961
+ data=schema.data,
962
+ )
963
+ return data
964
+
965
+ def _read_mode_ts(self, schema: 'Schema_Timestamps', *, options: 'Option') -> 'Data_Timestamps': # pylint: disable=unused-argument
966
+ """Read TCP timestamps option.
967
+
968
+ Structure of TCP timestamp option [:rfc:`7323`]:
969
+
970
+ .. code-block:: text
971
+
972
+ +-------+-------+---------------------+---------------------+
973
+ |Kind=8 | 10 | TS Value (TSval) |TS Echo Reply (TSecr)|
974
+ +-------+-------+---------------------+---------------------+
975
+ 1 1 4 4
976
+
977
+ Arguments:
978
+ schema: parsed option schema
979
+ options: extracted TCP options
980
+
981
+ Returns:
982
+ Parsed option data.
983
+
984
+ Raises:
985
+ ProtocolError: If length is **NOT** ``10``.
986
+
987
+ """
988
+ if schema.length != 10:
989
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
990
+
991
+ data = Data_Timestamps(
992
+ kind=schema.kind,
993
+ length=schema.length,
994
+ timestamp=schema.value,
995
+ echo=schema.reply,
996
+ )
997
+ return data
998
+
999
+ def _read_mode_poc(self, schema: 'Schema_PartialOrderConnectionPermitted', *, options: 'Option') -> 'Data_PartialOrderConnectionPermitted': # pylint: disable=unused-argument
1000
+ """Read TCP partial order connection service profile option.
1001
+
1002
+ Structure of TCP ``POC-Permitted`` option [:rfc:`1693`][:rfc:`6247`]:
1003
+
1004
+ .. code-block:: text
1005
+
1006
+ +-----------+-------------+
1007
+ | Kind=9 | Length=2 |
1008
+ +-----------+-------------+
1009
+
1010
+ Arguments:
1011
+ schema: parsed option schema
1012
+ options: extracted TCP options
1013
+
1014
+ Returns:
1015
+ Parsed option data.
1016
+
1017
+ Raises:
1018
+ ProtocolError: If length is **NOT** ``2``.
1019
+
1020
+ """
1021
+ if schema.length != 2:
1022
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1023
+
1024
+ return Data_PartialOrderConnectionPermitted(
1025
+ kind=schema.kind,
1026
+ length=schema.length,
1027
+ )
1028
+
1029
+ def _read_mode_pocsp(self, schema: 'Schema_PartialOrderServiceProfile', *, options: 'Option') -> 'Data_PartialOrderServiceProfile': # pylint: disable=unused-argument
1030
+ """Read TCP partial order connection service profile option.
1031
+
1032
+ Structure of TCP ``POC-SP`` option [:rfc:`1693`][:rfc:`6247`]:
1033
+
1034
+ .. code-block:: text
1035
+
1036
+ 1 bit 1 bit 6 bits
1037
+ +----------+----------+------------+----------+--------+
1038
+ | Kind=10 | Length=3 | Start_flag | End_flag | Filler |
1039
+ +----------+----------+------------+----------+--------+
1040
+
1041
+ Arguments:
1042
+ schema: parsed option schema
1043
+ options: extracted TCP options
1044
+
1045
+ Returns:
1046
+ Parsed option data.
1047
+
1048
+ Raises:
1049
+ ProtocolError: If length is **NOT** ``3``.
1050
+
1051
+ """
1052
+ if schema.length != 3:
1053
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1054
+
1055
+ data = Data_PartialOrderServiceProfile(
1056
+ kind=schema.kind,
1057
+ length=schema.length,
1058
+ start=bool(schema.profile['start']),
1059
+ end=bool(schema.profile['end']),
1060
+ )
1061
+ return data
1062
+
1063
+ def _read_mode_cc(self, schema: 'Schema_CC', *, options: 'Option') -> 'Data_CC': # pylint: disable=unused-argument
1064
+ """Read TCP connection count option.
1065
+
1066
+ Structure of TCP ``CC`` option [:rfc:`1644`]:
1067
+
1068
+ .. code-block:: text
1069
+
1070
+ +--------+--------+--------+--------+--------+--------+
1071
+ |00001011|00000110| Connection Count: SEG.CC |
1072
+ +--------+--------+--------+--------+--------+--------+
1073
+ Kind=11 Length=6
1074
+
1075
+ Arguments:
1076
+ schema: parsed option schema
1077
+ options: extracted TCP options
1078
+
1079
+ Returns:
1080
+ Parsed option data.
1081
+
1082
+ Raises:
1083
+ ProtocolError: If length is **NOT** ``6``.
1084
+
1085
+ """
1086
+ if schema.length != 6:
1087
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1088
+
1089
+ data = Data_CC(
1090
+ kind=schema.kind,
1091
+ length=schema.length,
1092
+ cc=schema.count,
1093
+ )
1094
+ return data
1095
+
1096
+ def _read_mode_ccnew(self, schema: 'Schema_CCNew', *, options: 'Option') -> 'Data_CCNew': # pylint: disable=unused-argument
1097
+ """Read TCP connection count (new) option.
1098
+
1099
+ Structure of TCP ``CC.NEW`` option [:rfc:`1644`]:
1100
+
1101
+ .. code-block:: text
1102
+
1103
+ +--------+--------+--------+--------+--------+--------+
1104
+ |00001100|00000110| Connection Count: SEG.CC |
1105
+ +--------+--------+--------+--------+--------+--------+
1106
+ Kind=12 Length=6
1107
+
1108
+ Arguments:
1109
+ schema: parsed option schema
1110
+ options: extracted TCP options
1111
+
1112
+ Returns:
1113
+ Parsed option data.
1114
+
1115
+ Raises:
1116
+ ProtocolError: If length is **NOT** ``6``.
1117
+
1118
+ """
1119
+ if schema.length != 6:
1120
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1121
+
1122
+ data = Data_CCNew(
1123
+ kind=schema.kind,
1124
+ length=schema.length,
1125
+ cc=schema.count,
1126
+ )
1127
+ return data
1128
+
1129
+ def _read_mode_ccecho(self, schema: 'Schema_CCEcho', *, options: 'Option') -> 'Data_CCEcho': # pylint: disable=unused-argument
1130
+ """Read TCP connection count (echo) option.
1131
+
1132
+ Structure of TCP ``CC.ECHO`` option [:rfc:`1644`]:
1133
+
1134
+ .. code-block:: text
1135
+
1136
+ +--------+--------+--------+--------+--------+--------+
1137
+ |00001101|00000110| Connection Count: SEG.CC |
1138
+ +--------+--------+--------+--------+--------+--------+
1139
+ Kind=13 Length=6
1140
+
1141
+ Arguments:
1142
+ schema: parsed option schema
1143
+ options: extracted TCP options
1144
+
1145
+ Returns:
1146
+ Parsed option data.
1147
+
1148
+ Raises:
1149
+ ProtocolError: If length is **NOT** ``6``.
1150
+
1151
+ """
1152
+ if schema.length != 6:
1153
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1154
+
1155
+ data = Data_CCEcho(
1156
+ kind=schema.kind,
1157
+ length=schema.length,
1158
+ cc=schema.count,
1159
+ )
1160
+ return data
1161
+
1162
+ def _read_mode_chkreq(self, schema: 'Schema_AlternateChecksumRequest', *, options: 'Option') -> 'Data_AlternateChecksumRequest': # pylint: disable=unused-argument
1163
+ """Read TCP Alternate Checksum Request option.
1164
+
1165
+ Structure of TCP ``CHKSUM-REQ`` [:rfc:`1146`][:rfc:`6247`]:
1166
+
1167
+ .. code-block:: text
1168
+
1169
+ +----------+----------+----------+
1170
+ | Kind=14 | Length=3 | chksum |
1171
+ +----------+----------+----------+
1172
+
1173
+ Arguments:
1174
+ schema: parsed option schema
1175
+ options: extracted TCP options
1176
+
1177
+ Returns:
1178
+ Parsed option data.
1179
+
1180
+ Raises:
1181
+ ProtocolError: If length is **NOT** ``3``.
1182
+
1183
+ """
1184
+ if schema.length != 3:
1185
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1186
+
1187
+ data = Data_AlternateChecksumRequest(
1188
+ kind=schema.kind,
1189
+ length=schema.length,
1190
+ chksum=schema.algorithm,
1191
+ )
1192
+ return data
1193
+
1194
+ def _read_mode_chksum(self, schema: 'Schema_AlternateChecksumData', *, options: 'Option') -> 'Data_AlternateChecksumData': # pylint: disable=unused-argument
1195
+ """Read Alternate Checksum Data option.
1196
+
1197
+ Structure of TCP ``CHKSUM`` [:rfc:`1146`][:rfc:`6247`]:
1198
+
1199
+ .. code-block:: text
1200
+
1201
+ +---------+---------+---------+ +---------+
1202
+ | Kind=15 |Length=N | data | ... | data |
1203
+ +---------+---------+---------+ +---------+
1204
+
1205
+ Arguments:
1206
+ schema: parsed option schema
1207
+ options: extracted TCP options
1208
+
1209
+ Returns:
1210
+ Parsed option data.
1211
+
1212
+ """
1213
+ data = Data_AlternateChecksumData(
1214
+ kind=schema.kind,
1215
+ length=schema.length,
1216
+ data=schema.data,
1217
+ )
1218
+ return data
1219
+
1220
+ def _read_mode_sig(self, schema: 'Schema_MD5Signature', *, options: 'Option') -> 'Data_MD5Signature': # pylint: disable=unused-argument
1221
+ """Read MD5 Signature option.
1222
+
1223
+ Structure of TCP ``SIG`` option [:rfc:`2385`]:
1224
+
1225
+ .. code-block:: text
1226
+
1227
+ +---------+---------+-------------------+
1228
+ | Kind=19 |Length=18| MD5 digest... |
1229
+ +---------+---------+-------------------+
1230
+ | |
1231
+ +---------------------------------------+
1232
+ | |
1233
+ +---------------------------------------+
1234
+ | |
1235
+ +-------------------+-------------------+
1236
+ | |
1237
+ +-------------------+
1238
+
1239
+ Arguments:
1240
+ schema: parsed option schema
1241
+ options: extracted TCP options
1242
+
1243
+ Returns:
1244
+ Parsed option data.
1245
+
1246
+ Raises:
1247
+ ProtocolError: If length is **NOT** ``18``.
1248
+
1249
+ """
1250
+ if schema.length != 18:
1251
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1252
+
1253
+ data = Data_MD5Signature(
1254
+ kind=schema.kind,
1255
+ length=schema.length,
1256
+ digest=schema.digest,
1257
+ )
1258
+ return data
1259
+
1260
+ def _read_mode_qs(self, schema: 'Schema_QuickStartResponse', *, options: 'Option') -> 'Data_QuickStartResponse': # pylint: disable=unused-argument
1261
+ """Read Quick-Start Response option.
1262
+
1263
+ Structure of TCP ``QSopt`` [:rfc:`4782`]:
1264
+
1265
+ .. code-block:: text
1266
+
1267
+ 0 1 2 3
1268
+ 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
1269
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1270
+ | Kind | Length=8 | Resv. | Rate | TTL Diff |
1271
+ | | | |Request| |
1272
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1273
+ | QS Nonce | R |
1274
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1275
+
1276
+ Arguments:
1277
+ schema: parsed option schema
1278
+ options: extracted TCP options
1279
+
1280
+ Returns:
1281
+ Parsed option data.
1282
+
1283
+ Raises:
1284
+ ProtocolError: If length is **NOT** ``8``.
1285
+
1286
+ """
1287
+ size = self._read_unpack(1)
1288
+ if schema.length != 8:
1289
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1290
+
1291
+ rate = schema.flags['rate']
1292
+ data = Data_QuickStartResponse(
1293
+ kind=schema.kind,
1294
+ length=schema.length,
1295
+ req_rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
1296
+ ttl_diff=schema.diff,
1297
+ nonce=schema.nonce['nonce'],
1298
+ )
1299
+ return data
1300
+
1301
+ def _read_mode_timeout(self, schema: 'Schema_UserTimeout', *, options: 'Option') -> 'Data_UserTimeout': # pylint: disable=unused-argument
1302
+ """Read User Timeout option.
1303
+
1304
+ Structure of TCP ``TIMEOUT`` [:rfc:`5482`]:
1305
+
1306
+ .. code-block:: text
1307
+
1308
+ 0 1 2 3
1309
+ 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
1310
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1311
+ | Kind = 28 | Length = 4 |G| User Timeout |
1312
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1313
+
1314
+ Arguments:
1315
+ schema: parsed option schema
1316
+ options: extracted TCP options
1317
+
1318
+ Returns:
1319
+ Parsed option data.
1320
+
1321
+ Raises:
1322
+ ProtocolError: If length is **NOT** ``4``.
1323
+
1324
+ """
1325
+ if schema.length != 4:
1326
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1327
+
1328
+ if schema.info['granularity'] == 1:
1329
+ time = datetime.timedelta(minutes=schema.info['timeout'])
1330
+ else:
1331
+ time = datetime.timedelta(seconds=schema.info['timeout'])
1332
+
1333
+ data = Data_UserTimeout(
1334
+ kind=schema.kind,
1335
+ length=schema.length,
1336
+ timeout=time,
1337
+ )
1338
+ return data
1339
+
1340
+ def _read_mode_ao(self, schema: 'Schema_Authentication', *, options: 'Option') -> 'Data_Authentication': # pylint: disable=unused-argument
1341
+ """Read Authentication option.
1342
+
1343
+ Structure of TCP ``AOopt`` [:rfc:`5925`]:
1344
+
1345
+ .. code-block:: text
1346
+
1347
+ +------------+------------+------------+------------+
1348
+ | Kind=29 | Length | KeyID | RNextKeyID |
1349
+ +------------+------------+------------+------------+
1350
+ | MAC ...
1351
+ +-----------------------------------...
1352
+
1353
+ ...-----------------+
1354
+ ... MAC (con't) |
1355
+ ...-----------------+
1356
+
1357
+ Arguments:
1358
+ schema: parsed option schema
1359
+ options: extracted TCP options
1360
+
1361
+ Returns:
1362
+ Parsed option data.
1363
+
1364
+ Raises:
1365
+ ProtocolError: If length is **NOT** larger than or equal to ``4``.
1366
+
1367
+ """
1368
+ if schema.length < 4:
1369
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1370
+
1371
+ data = Data_Authentication(
1372
+ kind=schema.kind,
1373
+ length=schema.length,
1374
+ key_id=schema.key_id,
1375
+ next_key_id=schema.next_key_id,
1376
+ mac=schema.mac,
1377
+ )
1378
+ return data
1379
+
1380
+ def _read_mode_mp(self, schema: 'Schema_MPTCP', *, options: 'Option') -> 'Data_MPTCP': # pylint: disable=unused-argument
1381
+ """Read Multipath TCP option.
1382
+
1383
+ Structure of ``MP-TCP`` [:rfc:`6824`]:
1384
+
1385
+ .. code-block:: text
1386
+
1387
+ 1 2 3
1388
+ 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
1389
+ +---------------+---------------+-------+-----------------------+
1390
+ | Kind | Length |Subtype| |
1391
+ +---------------+---------------+-------+ |
1392
+ | Subtype-specific data |
1393
+ | (variable length) |
1394
+ +---------------------------------------------------------------+
1395
+
1396
+ Arguments:
1397
+ schema: parsed option schema
1398
+ options: extracted TCP options
1399
+
1400
+ Returns:
1401
+ Parsed option data.
1402
+
1403
+ """
1404
+ subtype = schema.subtype
1405
+ name = self.__mp_option__[subtype]
1406
+
1407
+ if isinstance(name, str):
1408
+ meth_name = f'_read_mptcp_{name}'
1409
+ meth = cast('MPOptionParser',
1410
+ getattr(self, meth_name, self._read_mptcp_unknown))
1411
+ else:
1412
+ meth = name[0]
1413
+
1414
+ data = meth(schema, options=options)
1415
+ return data
1416
+
1417
+ def _read_mptcp_unknown(self, schema: 'Schema_MPTCPUnknown', *, options: 'Option') -> 'Data_MPTCPUnknown': # pylint: disable=unused-argument
1418
+ """Read unknown MPTCP subtype.
1419
+
1420
+ Arguments:
1421
+ schema: parsed option schema
1422
+ options: extracted TCP options
1423
+
1424
+ Returns:
1425
+ Parsed option data.
1426
+
1427
+ """
1428
+ data = Data_MPTCPUnknown(
1429
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1430
+ length=schema.length,
1431
+ subtype=schema.subtype,
1432
+ data=schema.test['data'].to_bytes(1, 'big', signed=False) + schema.data,
1433
+ )
1434
+ return data
1435
+
1436
+ def _read_mptcp_capable(self, schema: 'Schema_MPTCPCapable', *, options: 'Option') -> 'Data_MPTCPCapable': # pylint: disable=unused-argument
1437
+ """Read Multipath Capable option.
1438
+
1439
+ Structure of ``MP_CAPABLE`` [:rfc:`6824`]:
1440
+
1441
+ .. code-block:: text
1442
+
1443
+ 1 2 3
1444
+ 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
1445
+ +---------------+---------------+-------+-------+---------------+
1446
+ | Kind | Length |Subtype|Version|A|B|C|D|E|F|G|H|
1447
+ +---------------+---------------+-------+-------+---------------+
1448
+ | Option Sender's Key (64 bits) |
1449
+ | |
1450
+ | |
1451
+ +---------------------------------------------------------------+
1452
+ | Option Receiver's Key (64 bits) |
1453
+ | (if option Length == 20) |
1454
+ | |
1455
+ +---------------------------------------------------------------+
1456
+
1457
+ Arguments:
1458
+ schema: parsed option schema
1459
+ options: extracted TCP options
1460
+
1461
+ Returns:
1462
+ Parsed option data.
1463
+
1464
+ Raises:
1465
+ ProtocolError: If length is **NOT** ``20`` or ``32``.
1466
+
1467
+ """
1468
+ if schema.length not in (20, 32):
1469
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1470
+
1471
+ data = Data_MPTCPCapable(
1472
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1473
+ length=schema.length,
1474
+ subtype=schema.subtype,
1475
+ version=schema.test['version'],
1476
+ flags=Data_MPTCPCapableFlag(
1477
+ req=bool(schema.flags['req']),
1478
+ ext=bool(schema.flags['ext']),
1479
+ hsa=bool(schema.flags['hsa']),
1480
+ ),
1481
+ skey=schema.skey,
1482
+ rkey=schema.rkey if schema.length == 32 else None,
1483
+ )
1484
+ return data
1485
+
1486
+ def _read_mptcp_join(self, schema: 'Schema_MPTCPJoin', *, options: 'Option') -> 'Data_MPTCPJoin':
1487
+ """Read Join Connection option.
1488
+
1489
+ Arguments:
1490
+ schema: parsed option schema
1491
+ options: extracted TCP options
1492
+
1493
+ Returns:
1494
+ Parsed option data.
1495
+
1496
+ Raises:
1497
+ ProtocolError: If the option is not given on a valid SYN/ACK packet.
1498
+
1499
+ """
1500
+ if Enum_Flags.SYN in self._flags and Enum_Flags.ACK not in self._flags: # MP_JOIN-SYN
1501
+ return self._read_join_syn(schema, options=options) # type: ignore[arg-type]
1502
+ if Enum_Flags.SYN in self._flags and Enum_Flags.ACK in self._flags: # MP_JOIN-SYN/ACK
1503
+ return self._read_join_synack(schema, options=options) # type: ignore[arg-type]
1504
+ if Enum_Flags.SYN not in self._flags and Enum_Flags.ACK in self._flags: # MP_JOIN-ACK
1505
+ return self._read_join_ack(schema, options=options) # type: ignore[arg-type]
1506
+ raise ProtocolError(f'{self.alias}: : [OptNo {schema.kind}] {schema.subtype}: invalid flags combination')
1507
+
1508
+ def _read_join_syn(self, schema: 'Schema_MPTCPJoinSYN', *, options: 'Option') -> 'Data_MPTCPJoinSYN': # pylint: disable=unused-argument
1509
+ """Read Join Connection option for Initial SYN.
1510
+
1511
+ Structure of ``MP_JOIN-SYN`` [:rfc:`6824`]:
1512
+
1513
+ .. code-block:: text
1514
+
1515
+ 1 2 3
1516
+ 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
1517
+ +---------------+---------------+-------+-----+-+---------------+
1518
+ | Kind | Length = 12 |Subtype| |B| Address ID |
1519
+ +---------------+---------------+-------+-----+-+---------------+
1520
+ | Receiver's Token (32 bits) |
1521
+ +---------------------------------------------------------------+
1522
+ | Sender's Random Number (32 bits) |
1523
+ +---------------------------------------------------------------+
1524
+
1525
+ Arguments:
1526
+ schema: parsed option schema
1527
+ options: extracted TCP options
1528
+
1529
+ Returns:
1530
+ Parsed option data.
1531
+
1532
+ Raises:
1533
+ ProtocolError: If length is **NOT** ``12``.
1534
+
1535
+ """
1536
+ if schema.length != 12:
1537
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1538
+
1539
+ data = Data_MPTCPJoinSYN(
1540
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1541
+ length=schema.length,
1542
+ subtype=schema.subtype,
1543
+ connection=Enum_Flags.SYN, # type: ignore[arg-type]
1544
+ backup=bool(schema.test['backup']),
1545
+ addr_id=schema.addr_id,
1546
+ token=schema.token,
1547
+ nonce=schema.nonce,
1548
+ )
1549
+ return data
1550
+
1551
+ def _read_join_synack(self, schema: 'Schema_MPTCPJoinSYNACK', options: 'Option') -> 'Data_MPTCPJoinSYNACK': # pylint: disable=unused-argument
1552
+ """Read Join Connection option for Responding SYN/ACK.
1553
+
1554
+ Structure of ``MP_JOIN-SYN/ACK`` [:rfc:`6824`]:
1555
+
1556
+ .. code-block:: text
1557
+
1558
+ 1 2 3
1559
+ 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
1560
+ +---------------+---------------+-------+-----+-+---------------+
1561
+ | Kind | Length = 16 |Subtype| |B| Address ID |
1562
+ +---------------+---------------+-------+-----+-+---------------+
1563
+ | |
1564
+ | Sender's Truncated HMAC (64 bits) |
1565
+ | |
1566
+ +---------------------------------------------------------------+
1567
+ | Sender's Random Number (32 bits) |
1568
+ +---------------------------------------------------------------+
1569
+
1570
+ Arguments:
1571
+ schema: parsed option schema
1572
+ options: extracted TCP options
1573
+
1574
+ Returns:
1575
+ Parsed option data.
1576
+
1577
+ Raises:
1578
+ ProtocolError: If length is **NOT** ``20``.
1579
+
1580
+ """
1581
+ if schema.length != 20:
1582
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1583
+
1584
+ data = Data_MPTCPJoinSYNACK(
1585
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1586
+ length=schema.length,
1587
+ subtype=schema.subtype,
1588
+ connection=Enum_Flags.SYN | Enum_Flags.ACK, # type: ignore[arg-type]
1589
+ backup=bool(schema.test['backup']),
1590
+ addr_id=schema.addr_id,
1591
+ hmac=schema.hmac,
1592
+ nonce=schema.nonce,
1593
+ )
1594
+ return data
1595
+
1596
+ def _read_join_ack(self, schema: 'Schema_MPTCPJoinACK', *, options: 'Option') -> 'Data_MPTCPJoinACK': # pylint: disable=unused-argument
1597
+ """Read Join Connection option for Third ACK.
1598
+
1599
+ Structure of ``MP_JOIN-ACK`` [:rfc:`6824`]:
1600
+
1601
+ .. code-block:: text
1602
+
1603
+ 1 2 3
1604
+ 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
1605
+ +---------------+---------------+-------+-----------------------+
1606
+ | Kind | Length = 24 |Subtype| (reserved) |
1607
+ +---------------+---------------+-------+-----------------------+
1608
+ | |
1609
+ | |
1610
+ | Sender's HMAC (160 bits) |
1611
+ | |
1612
+ | |
1613
+ +---------------------------------------------------------------+
1614
+
1615
+ Arguments:
1616
+ schema: parsed option schema
1617
+ options: extracted TCP options
1618
+
1619
+ Returns:
1620
+ Parsed option data.
1621
+
1622
+ Raises:
1623
+ ProtocolError: If length is **NOT** ``24``.
1624
+
1625
+ """
1626
+ if schema.length != 24:
1627
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1628
+
1629
+ data = Data_MPTCPJoinACK(
1630
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1631
+ length=schema.length,
1632
+ subtype=schema.subtype,
1633
+ connection=Enum_Flags.ACK, # type: ignore[arg-type]
1634
+ hmac=schema.hmac,
1635
+ )
1636
+ return data
1637
+
1638
+ def _read_mptcp_dss(self, schema: 'Schema_MPTCPDSS', *, options: 'Option') -> 'Data_MPTCPDSS': # pylint: disable=unused-argument
1639
+ """Read Data Sequence Signal (Data ACK and Data Sequence Mapping) option.
1640
+
1641
+ Structure of ``DSS`` [:rfc:`6824`]:
1642
+
1643
+ .. code-block:: text
1644
+
1645
+ 1 2 3
1646
+ 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
1647
+ +---------------+---------------+-------+----------------------+
1648
+ | Kind | Length |Subtype| (reserved) |F|m|M|a|A|
1649
+ +---------------+---------------+-------+----------------------+
1650
+ | |
1651
+ | Data ACK (4 or 8 octets, depending on flags) |
1652
+ | |
1653
+ +--------------------------------------------------------------+
1654
+ | |
1655
+ | Data sequence number (4 or 8 octets, depending on flags) |
1656
+ | |
1657
+ +--------------------------------------------------------------+
1658
+ | Subflow Sequence Number (4 octets) |
1659
+ +-------------------------------+------------------------------+
1660
+ | Data-Level Length (2 octets) | Checksum (2 octets) |
1661
+ +-------------------------------+------------------------------+
1662
+
1663
+ Arguments:
1664
+ schema: parsed option schema
1665
+ options: extracted TCP options
1666
+
1667
+ Returns:
1668
+ Parsed option data.
1669
+
1670
+ """
1671
+ data = Data_MPTCPDSS(
1672
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1673
+ length=schema.length,
1674
+ subtype=schema.subtype,
1675
+ data_fin=bool(schema.flags['F']),
1676
+ ack=schema.ack,
1677
+ dsn=schema.dsn,
1678
+ ssn=schema.ssn,
1679
+ dl_len=schema.dl_len,
1680
+ checksum=schema.checksum,
1681
+ )
1682
+ return data
1683
+
1684
+ def _read_mptcp_addaddr(self, schema: 'Schema_MPTCPAddAddress', *, options: 'Option') -> 'Data_MPTCPAddAddress': # pylint: disable=unused-argument
1685
+ """Read Add Address option.
1686
+
1687
+ Structure of ``ADD_ADDR`` [:rfc:`6824`]:
1688
+
1689
+ .. code-block:: text
1690
+
1691
+ 1 2 3
1692
+ 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
1693
+ +---------------+---------------+-------+-------+---------------+
1694
+ | Kind | Length |Subtype| IPVer | Address ID |
1695
+ +---------------+---------------+-------+-------+---------------+
1696
+ | Address (TCP - 4 octets / IPv6 - 16 octets) |
1697
+ +-------------------------------+-------------------------------+
1698
+ | Port (2 octets, optional) |
1699
+ +-------------------------------+
1700
+
1701
+ Arguments:
1702
+ schema: parsed option schema
1703
+ options: extracted TCP options
1704
+
1705
+ Returns:
1706
+ Parsed option data.
1707
+
1708
+ Raises:
1709
+ ProtocolError: Invalid IP version and/or addresses.
1710
+
1711
+ """
1712
+ if schema.test['version'] not in (4, 6):
1713
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid IP version')
1714
+
1715
+ data = Data_MPTCPAddAddress(
1716
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1717
+ length=schema.length,
1718
+ subtype=schema.subtype,
1719
+ version=schema.test['version'],
1720
+ addr_id=schema.addr_id,
1721
+ addr=schema.address,
1722
+ port=schema.port,
1723
+ )
1724
+ return data
1725
+
1726
+ def _read_mptcp_remove(self, schema: 'Schema_MPTCPRemoveAddress', *, options: 'Option') -> 'Data_MPTCPRemoveAddress': # pylint: disable=unused-argument
1727
+ """Read Remove Address option.
1728
+
1729
+ Structure of ``REMOVE_ADDR`` [:rfc:`6824`]:
1730
+
1731
+ .. code-block:: text
1732
+
1733
+ 1 2 3
1734
+ 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
1735
+ +---------------+---------------+-------+-------+---------------+
1736
+ | Kind | Length = 3+n |Subtype|(resvd)| Address ID | ...
1737
+ +---------------+---------------+-------+-------+---------------+
1738
+ (followed by n-1 Address IDs, if required)
1739
+
1740
+ Arguments:
1741
+ schema: parsed option schema
1742
+ options: extracted TCP options
1743
+
1744
+ Returns:
1745
+ Parsed option data.
1746
+
1747
+ Raises:
1748
+ ProtocolError: If the length is smaller than **3**.
1749
+
1750
+ """
1751
+ if schema.length < 3:
1752
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1753
+
1754
+ data = Data_MPTCPRemoveAddress(
1755
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1756
+ length=schema.length,
1757
+ subtype=schema.subtype,
1758
+ addr_id=tuple(schema.addr_id),
1759
+ )
1760
+
1761
+ return data
1762
+
1763
+ def _read_mptcp_prio(self, schema: 'Schema_MPTCPPriority', *, options: 'Option') -> 'Data_MPTCPPriority': # pylint: disable=unused-argument
1764
+ """Read Change Subflow Priority option.
1765
+
1766
+ Structure of ``MP_PRIO`` [RFC 6824]:
1767
+
1768
+ .. code-block:: text
1769
+
1770
+ 1 2 3
1771
+ 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
1772
+ +---------------+---------------+-------+-----+-+--------------+
1773
+ | Kind | Length |Subtype| |B| AddrID (opt) |
1774
+ +---------------+---------------+-------+-----+-+--------------+
1775
+
1776
+ Arguments:
1777
+ schema: parsed option schema
1778
+ options: extracted TCP options
1779
+
1780
+ Returns:
1781
+ Parsed option data.
1782
+
1783
+ Raises:
1784
+ ProtocolError: If the length is smaller than **3**.
1785
+
1786
+ """
1787
+ if schema.length not in (3, 4):
1788
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1789
+
1790
+ data = Data_MPTCPPriority(
1791
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1792
+ length=schema.length,
1793
+ subtype=schema.subtype,
1794
+ backup=bool(schema.test['backup']),
1795
+ addr_id=schema.addr_id,
1796
+ )
1797
+
1798
+ return data
1799
+
1800
+ def _read_mptcp_fail(self, schema: 'Schema_MPTCPFallback', *, options: 'Option') -> 'Data_MPTCPFallback': # pylint: disable=unused-argument
1801
+ """Read Fallback option.
1802
+
1803
+ Structure of ``MP_FAIL`` [:rfc:`6824`]:
1804
+
1805
+ .. code-block:: text
1806
+
1807
+ 1 2 3
1808
+ 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
1809
+ +---------------+---------------+-------+----------------------+
1810
+ | Kind | Length=12 |Subtype| (reserved) |
1811
+ +---------------+---------------+-------+----------------------+
1812
+ | |
1813
+ | Data Sequence Number (8 octets) |
1814
+ | |
1815
+ +--------------------------------------------------------------+
1816
+
1817
+ Arguments:
1818
+ schema: parsed option schema
1819
+ options: extracted TCP options
1820
+
1821
+ Returns:
1822
+ Parsed option data.
1823
+
1824
+ Raises:
1825
+ ProtocolError: If the length is **NOT** 12.
1826
+
1827
+ """
1828
+ if schema.length != 12:
1829
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1830
+
1831
+ data = Data_MPTCPFallback(
1832
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1833
+ length=schema.length,
1834
+ subtype=schema.subtype,
1835
+ dsn=schema.dsn,
1836
+ )
1837
+ return data
1838
+
1839
+ def _read_mptcp_fastclose(self, schema: 'Schema_MPTCPFastclose', options: 'Option') -> 'Data_MPTCPFastclose': # pylint: disable=unused-argument
1840
+ """Read Fast Close option.
1841
+
1842
+ Structure of ``MP_FASTCLOSE`` [RFC 6824]:
1843
+
1844
+ .. code-block:: text
1845
+
1846
+ 1 2 3
1847
+ 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
1848
+ +---------------+---------------+-------+-----------------------+
1849
+ | Kind | Length |Subtype| (reserved) |
1850
+ +---------------+---------------+-------+-----------------------+
1851
+ | Option Receiver's Key |
1852
+ | (64 bits) |
1853
+ | |
1854
+ +---------------------------------------------------------------+
1855
+
1856
+ Arguments:
1857
+ schema: parsed option schema
1858
+ options: extracted TCP options
1859
+
1860
+ Returns:
1861
+ Parsed option data.
1862
+
1863
+ Raises:
1864
+ ProtocolError: If the length is **NOT** 16.
1865
+
1866
+ """
1867
+ if schema.length != 16:
1868
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1869
+
1870
+ data = Data_MPTCPFastclose(
1871
+ kind=Enum_Option.Multipath_TCP, # type: ignore[arg-type]
1872
+ length=schema.length,
1873
+ subtype=schema.subtype,
1874
+ rkey=schema.key,
1875
+ )
1876
+ return data
1877
+
1878
+ def _read_mode_fastopen(self, schema: 'Schema_FastOpenCookie', *, options: 'Option') -> 'Data_FastOpenCookie': # pylint: disable=unused-argument
1879
+ """Read Fast Open option.
1880
+
1881
+ Structure of TCP ``FASTOPEN`` [:rfc:`7413`]:
1882
+
1883
+ .. code-block:: text
1884
+
1885
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1886
+ | Kind | Length |
1887
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1888
+ | |
1889
+ ~ Cookie ~
1890
+ | |
1891
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1892
+
1893
+ Arguments:
1894
+ schema: parsed option schema
1895
+ options: extracted TCP options
1896
+
1897
+ Returns:
1898
+ Parsed option data.
1899
+
1900
+ Raises:
1901
+ ProtocolError: If length is **NOT** valid.
1902
+
1903
+ """
1904
+ if not (6 <= schema.length <= 18 or schema.length == 2) and schema.length % 2 != 0:
1905
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.kind}] invalid format')
1906
+
1907
+ data = Data_FastOpenCookie(
1908
+ kind=schema.kind,
1909
+ length=schema.length,
1910
+ cookie=schema.cookie,
1911
+ )
1912
+ return data
1913
+
1914
+ def _make_tcp_options(self, options: 'list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes] | Option') -> 'tuple[list[Schema_Option | bytes], int]':
1915
+ """Make options for TCP.
1916
+
1917
+ Args:
1918
+ options: TCP options
1919
+
1920
+ Returns:
1921
+ Tuple of options and total length of options.
1922
+
1923
+ """
1924
+ total_length = 0
1925
+ if isinstance(options, list):
1926
+ options_list = [] # type: list[Schema_Option | bytes]
1927
+ for schema in options:
1928
+ if isinstance(schema, bytes):
1929
+ code = Enum_Option.get(schema[0])
1930
+ if code in (Enum_Option.No_Operation, Enum_Option.End_of_Option_List): # ignore padding options by default
1931
+ continue
1932
+
1933
+ data = schema # type: Schema_Option | bytes
1934
+ data_len = len(data)
1935
+ elif isinstance(schema, Schema):
1936
+ code = schema.type
1937
+ if code in (Enum_Option.No_Operation, Enum_Option.End_of_Option_List): # ignore padding options by default
1938
+ continue
1939
+
1940
+ data = schema
1941
+ data_len = len(schema.pack())
1942
+ else:
1943
+ code, args = cast('tuple[Enum_Option, dict[str, Any]]', schema)
1944
+ if code in (Enum_Option.No_Operation, Enum_Option.End_of_Option_List): # ignore padding options by default
1945
+ continue
1946
+
1947
+ name = self.__option__[code]
1948
+ if isinstance(name, str):
1949
+ meth_name = f'_make_mode_{name}'
1950
+ meth = cast('OptionConstructor',
1951
+ getattr(self, meth_name, self._make_mode_donone))
1952
+ else:
1953
+ meth = name[1]
1954
+
1955
+ data = meth(code, **args)
1956
+ data_len = len(data.pack())
1957
+
1958
+ options_list.append(data)
1959
+ total_length += data_len
1960
+
1961
+ # force alignment to 32-bit boundary
1962
+ if data_len % 4:
1963
+ pad_len = 4 - (data_len % 4)
1964
+ pad_opt = self._make_mode_nop(Enum_Option.No_Operation) # type: ignore[arg-type]
1965
+ total_length += pad_len
1966
+
1967
+ for _ in range(pad_len - 1):
1968
+ options_list.append(pad_opt)
1969
+ options_list.append(self._make_mode_eool(Enum_Option.End_of_Option_List)) # type: ignore[arg-type]
1970
+ return options_list, total_length
1971
+
1972
+ options_list = []
1973
+ for code, option in options.items(multi=True):
1974
+ # ignore padding options by default
1975
+ if code in (Enum_Option.No_Operation, Enum_Option.End_of_Option_List):
1976
+ continue
1977
+
1978
+ name = self.__option__[code]
1979
+ if isinstance(name, str):
1980
+ meth_name = f'_make_mode_{name}'
1981
+ meth = cast('OptionConstructor',
1982
+ getattr(self, meth_name, self._make_mode_donone))
1983
+ else:
1984
+ meth = name[1]
1985
+
1986
+ data = meth(code, option)
1987
+ data_len = len(data.pack())
1988
+
1989
+ options_list.append(data)
1990
+ total_length += data_len
1991
+
1992
+ # force alignment to 32-bit boundary
1993
+ if data_len % 4:
1994
+ pad_len = 4 - (data_len % 4)
1995
+ pad_opt = self._make_mode_nop(Enum_Option.No_Operation) # type: ignore[arg-type]
1996
+ total_length += pad_len
1997
+
1998
+ for _ in range(pad_len - 1):
1999
+ options_list.append(pad_opt)
2000
+ options_list.append(self._make_mode_eool(Enum_Option.End_of_Option_List)) # type: ignore[arg-type]
2001
+ return options_list, total_length
2002
+
2003
+ def _make_mode_donone(self, code: 'Enum_Option', opt: 'Optional[Data_UnassignedOption]' = None, *,
2004
+ data: 'bytes' = b'',
2005
+ **kwargs: 'Any') -> 'Schema_UnassignedOption':
2006
+ """Make TCP unassigned option.
2007
+
2008
+ Args:
2009
+ code: option code
2010
+ opt: option data
2011
+ data: option payload in :obj:`bytes`
2012
+ **kwargs: arbitrary keyword arguments
2013
+
2014
+ Returns:
2015
+ Constructed option schema.
2016
+
2017
+ """
2018
+ if opt is not None:
2019
+ data = opt.data
2020
+
2021
+ return Schema_UnassignedOption(
2022
+ kind=code,
2023
+ length=len(data) + 2,
2024
+ data=data,
2025
+ )
2026
+
2027
+ def _make_mode_eool(self, code: 'Enum_Option', opt: 'Optional[Data_EndOfOptionList]' = None, **kwargs: 'Any') -> 'Schema_EndOfOptionList':
2028
+ """Make TCP End of Option List option.
2029
+
2030
+ Args:
2031
+ code: option code
2032
+ opt: option data
2033
+ **kwargs: arbitrary keyword arguments
2034
+
2035
+ Returns:
2036
+ Constructed option schema.
2037
+
2038
+ """
2039
+ return Schema_EndOfOptionList(
2040
+ kind=code,
2041
+ length=1,
2042
+ )
2043
+
2044
+ def _make_mode_nop(self, code: 'Enum_Option', opt: 'Optional[Data_NoOperation]' = None, **kwargs: 'Any') -> 'Schema_NoOperation':
2045
+ """Make TCP NoOperation option.
2046
+
2047
+ Args:
2048
+ code: option code
2049
+ opt: option data
2050
+ **kwargs: arbitrary keyword arguments
2051
+
2052
+ Returns:
2053
+ Constructed option schema.
2054
+
2055
+ """
2056
+ return Schema_NoOperation(
2057
+ kind=code,
2058
+ length=1,
2059
+ )
2060
+
2061
+ def _make_mode_mss(self, code: 'Enum_Option', opt: 'Optional[Data_MaximumSegmentSize]' = None, *,
2062
+ mss: 'int' = 65535, # reasonable default value
2063
+ **kwargs: 'Any') -> 'Schema_MaximumSegmentSize':
2064
+ """Make TCP maximum segment size option.
2065
+
2066
+ Args:
2067
+ code: option code
2068
+ opt: option data
2069
+ mss: maximum segment size
2070
+ **kwargs: arbitrary keyword arguments
2071
+
2072
+ Returns:
2073
+ Constructed option schema.
2074
+
2075
+ """
2076
+ if opt is not None:
2077
+ mss = opt.mss
2078
+
2079
+ return Schema_MaximumSegmentSize(
2080
+ kind=code,
2081
+ length=4,
2082
+ mss=mss,
2083
+ )
2084
+
2085
+ def _make_mode_ws(self, code: 'Enum_Option', opt: 'Optional[Data_WindowScale]' = None, *,
2086
+ shift: 'int' = 0, # reasonable default value
2087
+ **kwargs: 'Any') -> 'Schema_WindowScale':
2088
+ """Make TCP window scale option.
2089
+
2090
+ Args:
2091
+ code: option code
2092
+ opt: option data
2093
+ shift: window scale shift count
2094
+ **kwargs: arbitrary keyword arguments
2095
+
2096
+ Returns:
2097
+ Constructed option schema.
2098
+
2099
+ """
2100
+ if opt is not None:
2101
+ shift = opt.shift
2102
+
2103
+ return Schema_WindowScale(
2104
+ kind=code,
2105
+ length=3,
2106
+ scale=shift,
2107
+ )
2108
+
2109
+ def _make_mode_sackpmt(self, code: 'Enum_Option', opt: 'Optional[Data_SACKPermitted]' = None,
2110
+ **kwargs: 'Any') -> 'Schema_SACKPermitted':
2111
+ """Make TCP SACK permitted option.
2112
+
2113
+ Args:
2114
+ code: option code
2115
+ opt: option data
2116
+ **kwargs: arbitrary keyword arguments
2117
+
2118
+ Returns:
2119
+ Constructed option schema.
2120
+
2121
+ """
2122
+ return Schema_SACKPermitted(
2123
+ kind=code,
2124
+ length=2,
2125
+ )
2126
+
2127
+ def _make_mode_sack(self, code: 'Enum_Option', opt: 'Optional[Data_SACK]' = None, *,
2128
+ sack: 'Optional[list[tuple[int, int]]]' = None,
2129
+ **kwargs: 'Any') -> 'Schema_SACK':
2130
+ """Make TCP SACK option.
2131
+
2132
+ Args:
2133
+ code: option code
2134
+ opt: option data
2135
+ sack: SACK blocks
2136
+ **kwargs: arbitrary keyword arguments
2137
+
2138
+ Returns:
2139
+ Constructed option schema.
2140
+
2141
+ """
2142
+ if opt is not None:
2143
+ sack_val = [Schema_SACKBlock(
2144
+ left=block.left,
2145
+ right=block.right,
2146
+ ) for block in opt.sack]
2147
+ else:
2148
+ sack_val = []
2149
+
2150
+ if sack is not None:
2151
+ for left, right in sack:
2152
+ sack_val.append(Schema_SACKBlock(
2153
+ left=left,
2154
+ right=right,
2155
+ ))
2156
+
2157
+ return Schema_SACK(
2158
+ kind=code,
2159
+ length=2 + (len(sack_val) * 8),
2160
+ sack=sack_val,
2161
+ )
2162
+
2163
+ def _make_mode_echo(self, code: 'Enum_Option', opt: 'Optional[Data_Echo]' = None, *,
2164
+ data: 'bytes' = b'\x00\x00\x00\x00',
2165
+ **kwargs: 'Any') -> 'Schema_Echo':
2166
+ """Make TCP echo option.
2167
+
2168
+ Args:
2169
+ code: option code
2170
+ opt: option data
2171
+ data: 4 bytes of info to be echoed
2172
+ **kwargs: arbitrary keyword arguments
2173
+
2174
+ Returns:
2175
+ Constructed option schema.
2176
+
2177
+ """
2178
+ if opt is not None:
2179
+ data = opt.data
2180
+
2181
+ return Schema_Echo(
2182
+ kind=code,
2183
+ length=6,
2184
+ data=data,
2185
+ )
2186
+
2187
+ def _make_mode_echore(self, code: 'Enum_Option', opt: 'Optional[Data_EchoReply]' = None, *,
2188
+ data: 'bytes' = b'\x00\x00\x00\x00',
2189
+ **kwargs: 'Any') -> 'Schema_EchoReply':
2190
+ """Make TCP echo reply option.
2191
+
2192
+ Args:
2193
+ code: option code
2194
+ opt: option data
2195
+ data: 4 bytes of echoed info
2196
+ **kwargs: arbitrary keyword arguments
2197
+
2198
+ Returns:
2199
+ Constructed option schema.
2200
+
2201
+ """
2202
+ if opt is not None:
2203
+ data = opt.data
2204
+
2205
+ return Schema_EchoReply(
2206
+ kind=code,
2207
+ length=6,
2208
+ data=data,
2209
+ )
2210
+
2211
+ def _make_mode_ts(self, code: 'Enum_Option', opt: 'Optional[Data_Timestamps]' = None, *,
2212
+ tsval: 'int' = 0,
2213
+ tsecr: 'int' = 0,
2214
+ **kwargs: 'Any') -> 'Schema_Timestamps':
2215
+ """Make TCP timestamps option.
2216
+
2217
+ Args:
2218
+ code: option code
2219
+ opt: option data
2220
+ tsval: timestamp value
2221
+ tsecr: timestamp echo reply
2222
+ **kwargs: arbitrary keyword arguments
2223
+
2224
+ Returns:
2225
+ Constructed option schema.
2226
+
2227
+ """
2228
+ if opt is not None:
2229
+ tsval = opt.timestamp
2230
+ tsecr = opt.echo
2231
+
2232
+ return Schema_Timestamps(
2233
+ kind=code,
2234
+ length=10,
2235
+ value=tsval,
2236
+ reply=tsecr,
2237
+ )
2238
+
2239
+ def _make_mode_poc(self, code: 'Enum_Option', opt: 'Optional[Data_PartialOrderConnectionPermitted]' = None,
2240
+ **kwargs: 'Any') -> 'Schema_PartialOrderConnectionPermitted':
2241
+ """Make TCP partial order connection option.
2242
+
2243
+ Args:
2244
+ code: option code
2245
+ opt: option data
2246
+ **kwargs: arbitrary keyword arguments
2247
+
2248
+ Returns:
2249
+ Constructed option schema.
2250
+
2251
+ """
2252
+ return Schema_PartialOrderConnectionPermitted(
2253
+ kind=code,
2254
+ length=2,
2255
+ )
2256
+
2257
+ def _make_mode_pocsp(self, code: 'Enum_Option', opt: 'Optional[Data_PartialOrderServiceProfile]' = None, *,
2258
+ start: 'bool' = False,
2259
+ end: 'bool' = False,
2260
+ **kwargs: 'Any') -> 'Schema_PartialOrderServiceProfile':
2261
+ """Make TCP partial order connection service profile option.
2262
+
2263
+ Args:
2264
+ code: option code
2265
+ opt: option data
2266
+ start: start partial order connection
2267
+ end: end partial order connection
2268
+ **kwargs: arbitrary keyword arguments
2269
+
2270
+ Returns:
2271
+ Constructed option schema.
2272
+
2273
+ """
2274
+ if opt is not None:
2275
+ start = opt.start
2276
+ end = opt.end
2277
+
2278
+ return Schema_PartialOrderServiceProfile(
2279
+ kind=code,
2280
+ length=3,
2281
+ profile={
2282
+ 'start': start,
2283
+ 'end': end,
2284
+ },
2285
+ )
2286
+
2287
+ def _make_mode_cc(self, code: 'Enum_Option', opt: 'Optional[Data_CC]' = None, *,
2288
+ count: 'int' = 0,
2289
+ **kwargs: 'Any') -> 'Schema_CC':
2290
+ """Make TCP connection count option.
2291
+
2292
+ Args:
2293
+ code: option code
2294
+ opt: option data
2295
+ count: connection count
2296
+ **kwargs: arbitrary keyword arguments
2297
+
2298
+ Returns:
2299
+ Constructed option schema.
2300
+
2301
+ """
2302
+ if opt is not None:
2303
+ count = opt.cc
2304
+
2305
+ return Schema_CC(
2306
+ kind=code,
2307
+ length=6,
2308
+ count=count,
2309
+ )
2310
+
2311
+ def _make_mode_ccnew(self, code: 'Enum_Option', opt: 'Optional[Data_CCNew]' = None, *,
2312
+ count: 'int' = 0,
2313
+ **kwargs: 'Any') -> 'Schema_CCNew':
2314
+ """Make TCP connection count new option.
2315
+
2316
+ Args:
2317
+ code: option code
2318
+ opt: option data
2319
+ count: connection count
2320
+ **kwargs: arbitrary keyword arguments
2321
+
2322
+ Returns:
2323
+ Constructed option schema.
2324
+
2325
+ """
2326
+ if opt is not None:
2327
+ count = opt.cc
2328
+
2329
+ return Schema_CCNew(
2330
+ kind=code,
2331
+ length=6,
2332
+ count=count,
2333
+ )
2334
+
2335
+ def _make_mode_ccecho(self, code: 'Enum_Option', opt: 'Optional[Data_CCEcho]' = None, *,
2336
+ count: 'int' = 0,
2337
+ **kwargs: 'Any') -> 'Schema_CCEcho':
2338
+ """Make TCP connection count echo option.
2339
+
2340
+ Args:
2341
+ code: option code
2342
+ opt: option data
2343
+ count: connection count
2344
+ **kwargs: arbitrary keyword arguments
2345
+
2346
+ Returns:
2347
+ Constructed option schema.
2348
+
2349
+ """
2350
+ if opt is not None:
2351
+ count = opt.cc
2352
+
2353
+ return Schema_CCEcho(
2354
+ kind=code,
2355
+ length=6,
2356
+ count=count,
2357
+ )
2358
+
2359
+ def _make_mode_chkreq(self, code: 'Enum_Option', opt: 'Optional[Data_AlternateChecksumRequest]' = None, *,
2360
+ algorithm: 'Enum_Checksum | StdlibEnum | AenumEnum | int | str' = Enum_Checksum.TCP_checksum,
2361
+ algorithm_default: 'Optional[int]' = None,
2362
+ algorithm_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
2363
+ algorithm_reversed: 'bool' = False,
2364
+ **kwargs: 'Any') -> 'Schema_AlternateChecksumRequest':
2365
+ """Make TCP alternate checksum request option.
2366
+
2367
+ Args:
2368
+ code: option code
2369
+ opt: option data
2370
+ algorithm: checksum algorithm
2371
+ algorithm_default: default value for checksum algorithm
2372
+ algorithm_namespace: namespace for checksum algorithm
2373
+ algorithm_reversed: reversed flag for checksum algorithm
2374
+ **kwargs: arbitrary keyword arguments
2375
+
2376
+ Returns:
2377
+ Constructed option schema.
2378
+
2379
+ """
2380
+ if opt is not None:
2381
+ algorithm_val = opt.chksum
2382
+ else:
2383
+ algorithm_val = self._make_index(algorithm, algorithm_default, namespace=algorithm_namespace, # type: ignore[assignment]
2384
+ reversed=algorithm_reversed, pack=False)
2385
+
2386
+ return Schema_AlternateChecksumRequest(
2387
+ kind=code,
2388
+ length=3,
2389
+ algorithm=algorithm_val,
2390
+ )
2391
+
2392
+ def _make_mode_chksum(self, code: 'Enum_Option', opt: 'Optional[Data_AlternateChecksumData]' = None, *,
2393
+ data: 'bytes' = b'',
2394
+ **kwargs: 'Any') -> 'Schema_AlternateChecksumData':
2395
+ """Make TCP alternate checksum data option.
2396
+
2397
+ Args:
2398
+ code: option code
2399
+ opt: option data
2400
+ data: checksum data
2401
+ **kwargs: arbitrary keyword arguments
2402
+
2403
+ Returns:
2404
+ Constructed option schema.
2405
+
2406
+ """
2407
+ if opt is not None:
2408
+ data = opt.data
2409
+
2410
+ return Schema_AlternateChecksumData(
2411
+ kind=code,
2412
+ length=2 + len(data),
2413
+ data=data,
2414
+ )
2415
+
2416
+ def _make_mode_sig(self, code: 'Enum_Option', opt: 'Optional[Data_MD5Signature]' = None, *,
2417
+ digest: 'bytes' = bytes(16),
2418
+ **kwargs: 'Any') -> 'Schema_MD5Signature':
2419
+ """Make TCP MD5 signature option.
2420
+
2421
+ Args:
2422
+ code: option code
2423
+ opt: option data
2424
+ digest: digest
2425
+ **kwargs: arbitrary keyword arguments
2426
+
2427
+ Returns:
2428
+ Constructed option schema.
2429
+
2430
+ """
2431
+ if opt is not None:
2432
+ digest = opt.digest
2433
+
2434
+ return Schema_MD5Signature(
2435
+ kind=code,
2436
+ length=18,
2437
+ digest=digest,
2438
+ )
2439
+
2440
+ def _make_mode_qs(self, code: 'Enum_Option', opt: 'Optional[Data_QuickStartResponse]' = None, *,
2441
+ rate: 'int' = 0,
2442
+ diff: 'timedelta | int' = 0,
2443
+ nonce: 'int' = 0,
2444
+ **kwargs: 'Any') -> 'Schema_QuickStartResponse':
2445
+ """Make TCP quick start response option.
2446
+
2447
+ Args:
2448
+ code: option code
2449
+ opt: option data
2450
+ rate: rate (in kbps)
2451
+ diff: time to live (in seconds) difference
2452
+ nonce: nonce value
2453
+ **kwargs: arbitrary keyword arguments
2454
+
2455
+ Returns:
2456
+ Constructed option schema.
2457
+
2458
+ """
2459
+ if opt is not None:
2460
+ rate = opt.req_rate
2461
+ diff = opt.ttl_diff
2462
+ nonce = opt.nonce
2463
+
2464
+ rate_val = math.floor(math.log2(rate * 1000 / 40000)) if rate > 0 else 0
2465
+ diff_val = diff if isinstance(diff, int) else math.floor(diff.total_seconds())
2466
+
2467
+ return Schema_QuickStartResponse(
2468
+ kind=code,
2469
+ length=8,
2470
+ flags={
2471
+ 'rate': rate_val,
2472
+ },
2473
+ diff=diff_val,
2474
+ nonce={
2475
+ 'nonce': nonce,
2476
+ },
2477
+ )
2478
+
2479
+ def _make_mode_timeout(self, code: 'Enum_Option', opt: 'Optional[Data_UserTimeout]' = None, *,
2480
+ timeout: 'timedelta | int' = 0,
2481
+ **kwargs: 'Any') -> 'Schema_UserTimeout':
2482
+ """Make TCP user timeout option.
2483
+
2484
+ Args:
2485
+ code: option code
2486
+ opt: option data
2487
+ timeout: timeout value
2488
+ **kwargs: arbitrary keyword arguments
2489
+
2490
+ Returns:
2491
+ Constructed option schema.
2492
+
2493
+ """
2494
+ if opt is not None:
2495
+ timeout_val = math.floor(opt.timeout.total_seconds())
2496
+ else:
2497
+ timeout_val = timeout if isinstance(timeout, int) else math.floor(timeout.total_seconds())
2498
+
2499
+ granularity = timeout_val.bit_length() > 15
2500
+ timeout_val = math.floor(timeout_val / 60) if granularity else timeout_val
2501
+
2502
+ if timeout_val.bit_length() > 15:
2503
+ raise ProtocolError(f'TCP: [OptNo {code}] timeout value too large: {timeout}')
2504
+
2505
+ return Schema_UserTimeout(
2506
+ kind=code,
2507
+ length=3,
2508
+ info={
2509
+ 'granularity': granularity,
2510
+ 'timeout': timeout_val,
2511
+ },
2512
+ )
2513
+
2514
+ def _make_mode_ao(self, code: 'Enum_Option', opt: 'Optional[Data_Authentication]' = None, *,
2515
+ key_id: 'int' = 0,
2516
+ next_key_id: 'int' = 0,
2517
+ mac: 'bytes' = b'',
2518
+ **kwargs: 'Any') -> 'Schema_Authentication':
2519
+ """Make TCP authentication option.
2520
+
2521
+ Args:
2522
+ code: option code
2523
+ opt: option data
2524
+ key_id: key ID
2525
+ next_key_id: next key ID
2526
+ mac: MAC value
2527
+ **kwargs: arbitrary keyword arguments
2528
+
2529
+ Returns:
2530
+ Constructed option schema.
2531
+
2532
+ """
2533
+ if opt is not None:
2534
+ key_id = opt.key_id
2535
+ next_key_id = opt.next_key_id
2536
+ mac = opt.mac
2537
+
2538
+ return Schema_Authentication(
2539
+ kind=code,
2540
+ length=4 + len(mac),
2541
+ key_id=key_id,
2542
+ next_key_id=next_key_id,
2543
+ mac=mac,
2544
+ )
2545
+
2546
+ def _make_mode_mp(self, code: 'Enum_Option', opt: 'Optional[Data_MPTCP]' = None, *,
2547
+ subtype: 'Enum_MPTCPOption | StdlibEnum | AenumEnum | int | str' = Enum_MPTCPOption.MP_CAPABLE,
2548
+ subtype_default: 'Optional[int]' = None,
2549
+ subtype_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
2550
+ subtype_reversed: 'bool' = False,
2551
+ **kwargs: 'Any') -> 'Schema_MPTCP':
2552
+ """Make multipath TCP option.
2553
+
2554
+ Args:
2555
+ code: option code
2556
+ opt: option data
2557
+ subtype: MPTCP subtype
2558
+ subtype_default: default value for MPTCP subtype
2559
+ subtype_namespace: namespace for MPTCP subtype
2560
+ subtype_reversed: reversed flag for MPTCP subtype
2561
+ **kwargs: arbitrary keyword arguments
2562
+
2563
+ Returns:
2564
+ Constructed option schema.
2565
+
2566
+ """
2567
+ if opt is not None:
2568
+ subtype_val = opt.subtype
2569
+ else:
2570
+ subtype_val = self._make_index(subtype, subtype_default, namespace=subtype_namespace, # type: ignore[assignment]
2571
+ reversed=subtype_reversed, pack=False)
2572
+
2573
+ name = self.__mp_option__[subtype_val]
2574
+ if isinstance(name, str):
2575
+ meth_name = f'_make_mptcp_{name}'
2576
+ meth = cast('MPOptionConstructor',
2577
+ getattr(self, meth_name, self._make_mptcp_unknown))
2578
+ else:
2579
+ meth = name[1]
2580
+
2581
+ schema = meth(subtype_val, opt, **kwargs)
2582
+ return schema
2583
+
2584
+ def _make_mptcp_unknown(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPUnknown]' = None, *,
2585
+ data: 'bytes' = b'\x00',
2586
+ **kwargs: 'Any') -> 'Schema_MPTCPUnknown':
2587
+ """Make unknown multipath TCP option.
2588
+
2589
+ Args:
2590
+ subtype: MPTCP subtype
2591
+ opt: option data
2592
+ data: option payload data
2593
+ **kwargs: arbitrary keyword arguments
2594
+
2595
+ Returns:
2596
+ Constructed option schema.
2597
+
2598
+ """
2599
+ if opt is not None:
2600
+ data = opt.data
2601
+
2602
+ return Schema_MPTCPUnknown(
2603
+ kind=Enum_Option.MPTCP,
2604
+ length=2 + len(data),
2605
+ test={
2606
+ 'subtype': subtype.value,
2607
+ 'data': data[0] & 0x0F if data else 0,
2608
+ },
2609
+ data=data[1:],
2610
+ )
2611
+
2612
+ def _make_mptcp_capable(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPCapable]' = None, *,
2613
+ version: 'int' = 0,
2614
+ flag_req: 'bool' = False,
2615
+ flag_ext: 'bool' = False,
2616
+ flag_hsa: 'bool' = False,
2617
+ skey: 'int' = 0,
2618
+ rkey: 'Optional[int]' = 0,
2619
+ **kwargs: 'Any') -> 'Schema_MPTCPCapable':
2620
+ """Make multipath TCP capable option.
2621
+
2622
+ Args:
2623
+ subtype: MPTCP subtype
2624
+ opt: option data
2625
+ version: MPTCP version
2626
+ flag_req: checksum required flag
2627
+ flag_ext: extensability flag
2628
+ flag_hsa: use of HMAC-SHA1 flag
2629
+ skey: option sender's key
2630
+ rkey: option receiver's key
2631
+ **kwargs: arbitrary keyword arguments
2632
+
2633
+ Returns:
2634
+ Constructed option schema.
2635
+
2636
+ """
2637
+ if opt is not None:
2638
+ version = opt.version
2639
+ flag_req = opt.flags.req
2640
+ flag_ext = opt.flags.ext
2641
+ flag_hsa = opt.flags.hsa
2642
+ skey = opt.skey
2643
+ rkey = opt.rkey
2644
+
2645
+ return Schema_MPTCPCapable(
2646
+ kind=Enum_Option.MPTCP,
2647
+ length=20 if rkey is None else 32,
2648
+ test={
2649
+ 'subtype': subtype.value,
2650
+ 'version': version,
2651
+ },
2652
+ flags={
2653
+ 'req': flag_req,
2654
+ 'ext': flag_ext,
2655
+ 'hsa': flag_hsa,
2656
+ },
2657
+ skey=skey,
2658
+ rkey=rkey,
2659
+ )
2660
+
2661
+ def _make_mptcp_join(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPJoin]' = None, **kwargs: 'Any') -> 'Schema_MPTCPJoin':
2662
+ """Make multipath TCP join option.
2663
+
2664
+ Args:
2665
+ subtype: MPTCP subtype
2666
+ opt: option data
2667
+ **kwargs: arbitrary keyword arguments
2668
+
2669
+ Returns:
2670
+ Constructed option schema.
2671
+
2672
+ """
2673
+ if Enum_Flags.SYN in self._flags and Enum_Flags.ACK not in self._flags: # MP_JOIN-SYN
2674
+ return self._make_join_syn(subtype, opt, **kwargs) # type: ignore[arg-type]
2675
+ if Enum_Flags.SYN in self._flags and Enum_Flags.ACK in self._flags: # MP_JOIN-SYN/ACK
2676
+ return self._make_join_synack(subtype, opt, **kwargs) # type: ignore[arg-type]
2677
+ if Enum_Flags.SYN not in self._flags and Enum_Flags.ACK in self._flags: # MP_JOIN-ACK
2678
+ return self._make_join_ack(subtype, opt, **kwargs) # type: ignore[arg-type]
2679
+ raise ProtocolError(f'{self.alias}: : [OptNo {Enum_Option.Multipath_TCP}] {subtype}: invalid flags combination')
2680
+
2681
+ def _make_join_syn(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPJoinSYN]' = None, *,
2682
+ backup: 'bool' = False,
2683
+ addr_id: 'int' = 0,
2684
+ token: 'int' = 0,
2685
+ nonce: 'int' = 0,
2686
+ **kwargs: 'Any') -> 'Schema_MPTCPJoinSYN':
2687
+ """Make multipath TCP join SYN option.
2688
+
2689
+ Args:
2690
+ subtype: MPTCP subtype
2691
+ opt: option data
2692
+ backup: backup flag
2693
+ addr_id: address ID
2694
+ token: receiver's token
2695
+ nonce: sender's random number
2696
+ **kwargs: arbitrary keyword arguments
2697
+
2698
+ Returns:
2699
+ Constructed option schema.
2700
+
2701
+ """
2702
+ if opt is not None:
2703
+ backup = opt.backup
2704
+ addr_id = opt.addr_id
2705
+ token = opt.token
2706
+ nonce = opt.nonce
2707
+
2708
+ return Schema_MPTCPJoinSYN(
2709
+ kind=Enum_Option.MPTCP,
2710
+ length=12,
2711
+ test={
2712
+ 'subtype': subtype.value,
2713
+ 'backup': backup,
2714
+ },
2715
+ addr_id=addr_id,
2716
+ token=token,
2717
+ nonce=nonce,
2718
+ )
2719
+
2720
+ def _make_join_synack(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPJoinSYNACK]' = None, *,
2721
+ backup: 'bool' = False,
2722
+ addr_id: 'int' = 0,
2723
+ hmac: 'bytes' = bytes(8),
2724
+ nonce: 'int' = 0,
2725
+ **kwargs: 'Any') -> 'Schema_MPTCPJoinSYNACK':
2726
+ """Make multipath TCP join SYN/ACK option.
2727
+
2728
+ Args:
2729
+ subtype: MPTCP subtype
2730
+ opt: option data
2731
+ backup: backup flag
2732
+ addr_id: address ID
2733
+ hmac: sender's truncated HMAC
2734
+ nonce: sender's random number
2735
+ **kwargs: arbitrary keyword arguments
2736
+
2737
+ Returns:
2738
+ Constructed option schema.
2739
+
2740
+ """
2741
+ if opt is not None:
2742
+ backup = opt.backup
2743
+ addr_id = opt.addr_id
2744
+ nonce = opt.nonce
2745
+ nonce = opt.nonce
2746
+
2747
+ return Schema_MPTCPJoinSYNACK(
2748
+ kind=Enum_Option.MPTCP,
2749
+ length=12,
2750
+ test={
2751
+ 'subtype': subtype.value,
2752
+ 'backup': backup,
2753
+ },
2754
+ addr_id=addr_id,
2755
+ hmac=hmac,
2756
+ nonce=nonce,
2757
+ )
2758
+
2759
+ def _make_join_ack(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPJoinACK]' = None, *,
2760
+ hmac: 'bytes' = bytes(20),
2761
+ **kwargs: 'Any') -> 'Schema_MPTCPJoinACK':
2762
+ """Make multipath TCP join ACK option.
2763
+
2764
+ Args:
2765
+ subtype: MPTCP subtype
2766
+ opt: option data
2767
+ hmac: sender's HMAC
2768
+ **kwargs: arbitrary keyword arguments
2769
+
2770
+ Returns:
2771
+ Constructed option schema.
2772
+
2773
+ """
2774
+ if opt is not None:
2775
+ hmac = opt.hmac
2776
+
2777
+ return Schema_MPTCPJoinACK(
2778
+ kind=Enum_Option.MPTCP,
2779
+ length=8,
2780
+ test={
2781
+ 'subtype': subtype.value,
2782
+ },
2783
+ hmac=hmac,
2784
+ )
2785
+
2786
+ def _make_mptcp_dss(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPDSS]' = None, *,
2787
+ data_fin: 'bool' = False,
2788
+ ack: 'Optional[int]' = None,
2789
+ dsn: 'Optional[int]' = None,
2790
+ ssn: 'Optional[int]' = None,
2791
+ dl_len: 'Optional[int]' = None,
2792
+ checksum: 'Optional[bytes]' = None,
2793
+ **kwargs: 'Any') -> 'Schema_MPTCPDSS':
2794
+ """Make multipath TCP DSS option.
2795
+
2796
+ Args:
2797
+ subtype: MPTCP subtype
2798
+ opt: option data
2799
+ data_fin: ``DATA_FIN`` flag
2800
+ ack: Data ACK
2801
+ dsn: data sequence number
2802
+ ssn: subflow sequence number
2803
+ dl_len: data-level length
2804
+ checksum: checksum
2805
+ **kwargs: arbitrary keyword arguments
2806
+
2807
+ Returns:
2808
+ Constructed option schema.
2809
+
2810
+ """
2811
+ if opt is not None:
2812
+ data_fin = opt.data_fin
2813
+ ack = opt.ack
2814
+ dsn = opt.dsn
2815
+ ssn = opt.ssn
2816
+ dl_len = opt.dl_len
2817
+ checksum = opt.checksum
2818
+
2819
+ flag_A = ack is not None
2820
+ flag_a = cast('int', ack).bit_length() > 32 if flag_A else False
2821
+
2822
+ flag_M = dsn is not None
2823
+ flag_m = cast('int', dsn).bit_length() > 32 if flag_M else False
2824
+
2825
+ if flag_M and (ssn is None or dl_len is None or checksum is None):
2826
+ raise ProtocolError(f'{self.alias}: : [OptNo {Enum_Option.Multipath_TCP}] {subtype}: missing required fields')
2827
+ if not flag_M and (ssn is not None or dl_len is not None or checksum is not None):
2828
+ raise ProtocolError(f'{self.alias}: : [OptNo {Enum_Option.Multipath_TCP}] {subtype}: missing required fields')
2829
+
2830
+ return Schema_MPTCPDSS(
2831
+ kind=Enum_Option.MPTCP,
2832
+ length=4 + (4 if flag_A else 0) + (4 if flag_a else 0) + (12 if flag_M else 0) + (4 if flag_m else 0),
2833
+ test={
2834
+ 'subtype': subtype.value,
2835
+ },
2836
+ flags={
2837
+ 'F': data_fin,
2838
+ 'A': flag_A,
2839
+ 'm': flag_m,
2840
+ 'M': flag_M,
2841
+ 'a': flag_a,
2842
+ 'A': flag_A,
2843
+ },
2844
+ ack=ack,
2845
+ dsn=dsn,
2846
+ ssn=ssn,
2847
+ dl_len=dl_len,
2848
+ checksum=checksum,
2849
+ )
2850
+
2851
+ def _make_mptcp_addaddr(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPAddAddress]' = None, *,
2852
+ addr_id: 'int' = 0,
2853
+ addr: 'IPv4Address | IPv6Address | int | bytes | str' = '0.0.0.0', # nosec: B104
2854
+ port: 'Optional[int]' = None,
2855
+ **kwargs: 'Any') -> 'Schema_MPTCPAddAddress':
2856
+ """Make multipath TCP add address option.
2857
+
2858
+ Args:
2859
+ subtype: MPTCP subtype
2860
+ opt: option data
2861
+ addr_id: address ID
2862
+ addr: address
2863
+ port: port number
2864
+ **kwargs: arbitrary keyword arguments
2865
+
2866
+ Returns:
2867
+ Constructed option schema.
2868
+
2869
+ """
2870
+ if opt is not None:
2871
+ addr_id = opt.addr_id
2872
+ addr_val = opt.addr
2873
+ port = opt.port
2874
+ else:
2875
+ addr_val = ipaddress.ip_address(addr)
2876
+ version = addr_val.version
2877
+
2878
+ return Schema_MPTCPAddAddress(
2879
+ kind=Enum_Option.MPTCP,
2880
+ length=4 + (4 if version == 4 else 16) + (2 if port is not None else 0),
2881
+ test={
2882
+ 'subtype': subtype.value,
2883
+ 'version': version,
2884
+ },
2885
+ addr_id=addr_id,
2886
+ address=addr_val,
2887
+ port=port,
2888
+ )
2889
+
2890
+ def _make_mptcp_remove(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPRemoveAddress]' = None, *,
2891
+ addr_id: 'Optional[list[int]]' = None,
2892
+ **kwargs: 'Any') -> 'Schema_MPTCPRemoveAddress':
2893
+ """Make multipath TCP remove address option.
2894
+
2895
+ Args:
2896
+ subtype: MPTCP subtype
2897
+ opt: option data
2898
+ addr_id: address ID list
2899
+ **kwargs: arbitrary keyword arguments
2900
+
2901
+ Returns:
2902
+ Constructed option schema.
2903
+
2904
+ """
2905
+ if opt is not None:
2906
+ addr_id_list = cast('list[int]', opt.addr_id)
2907
+ else:
2908
+ addr_id_list = addr_id if addr_id is not None else []
2909
+
2910
+ return Schema_MPTCPRemoveAddress(
2911
+ kind=Enum_Option.MPTCP,
2912
+ length=4,
2913
+ test={
2914
+ 'subtype': subtype.value,
2915
+ },
2916
+ addr_id=addr_id_list,
2917
+ )
2918
+
2919
+ def _make_mptcp_prio(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPPriority]' = None, *,
2920
+ backup: 'bool' = False,
2921
+ addr_id: 'Optional[int]' = None,
2922
+ **kwargs: 'Any') -> 'Schema_MPTCPPriority':
2923
+ """Make multipath TCP priority option.
2924
+
2925
+ Args:
2926
+ subtype: MPTCP subtype
2927
+ opt: option data
2928
+ backup: backup flag
2929
+ addr_id: address ID
2930
+ **kwargs: arbitrary keyword arguments
2931
+
2932
+ Returns:
2933
+ Constructed option schema.
2934
+
2935
+ """
2936
+ if opt is not None:
2937
+ addr_id = opt.addr_id
2938
+
2939
+ return Schema_MPTCPPriority(
2940
+ kind=Enum_Option.MPTCP,
2941
+ length=4,
2942
+ test={
2943
+ 'subtype': subtype.value,
2944
+ 'backup': backup,
2945
+ },
2946
+ addr_id=addr_id,
2947
+ )
2948
+
2949
+ def _make_mptcp_fail(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPFallback]' = None, *,
2950
+ dsn: 'int' = 0,
2951
+ **kwargs: 'Any') -> 'Schema_MPTCPFallback':
2952
+ """Make multipath TCP fail option.
2953
+
2954
+ Args:
2955
+ subtype: MPTCP subtype
2956
+ opt: option data
2957
+ dsn: data sequence number
2958
+ **kwargs: arbitrary keyword arguments
2959
+
2960
+ Returns:
2961
+ Constructed option schema.
2962
+
2963
+ """
2964
+ if opt is not None:
2965
+ dsn = opt.dsn
2966
+
2967
+ return Schema_MPTCPFallback(
2968
+ kind=Enum_Option.MPTCP,
2969
+ length=12,
2970
+ test={
2971
+ 'subtype': subtype.value,
2972
+ },
2973
+ dsn=dsn,
2974
+ )
2975
+
2976
+ def _make_mptcp_fastclose(self, subtype: 'Enum_MPTCPOption', opt: 'Optional[Data_MPTCPFastclose]' = None, *,
2977
+ key: 'int' = 0,
2978
+ **kwargs: 'Any') -> 'Schema_MPTCPFastclose':
2979
+ """Make multipath TCP fastclose option.
2980
+
2981
+ Args:
2982
+ subtype: MPTCP subtype
2983
+ opt: option data
2984
+ key: option receiver's key
2985
+ **kwargs: arbitrary keyword arguments
2986
+
2987
+ Returns:
2988
+ Constructed option schema.
2989
+
2990
+ """
2991
+ if opt is not None:
2992
+ key = opt.rkey
2993
+
2994
+ return Schema_MPTCPFastclose(
2995
+ kind=Enum_Option.MPTCP,
2996
+ length=12,
2997
+ test={
2998
+ 'subtype': subtype.value,
2999
+ },
3000
+ key=key,
3001
+ )
3002
+
3003
+ def _make_mode_fastopen(self, code: 'Enum_Option', opt: 'Optional[Data_FastOpenCookie]' = None, *,
3004
+ cookie: 'Optional[bytes]' = None,
3005
+ **kwargs: 'Any') -> 'Schema_FastOpenCookie':
3006
+ """Make TCP Fast Open option.
3007
+
3008
+ Args:
3009
+ code: option code
3010
+ opt: option data
3011
+ cookie: fast open cookie
3012
+ **kwargs: arbitrary keyword arguments
3013
+
3014
+ Returns:
3015
+ Constructed option schema.
3016
+
3017
+ """
3018
+ if opt is not None:
3019
+ cookie = opt.cookie
3020
+
3021
+ return Schema_FastOpenCookie(
3022
+ kind=code,
3023
+ length=2 + (len(cookie) if cookie is not None else 0),
3024
+ cookie=cookie,
3025
+ )