pypcapkit 1.3.5.post6__pp310-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (466) hide show
  1. pcapkit/__init__.py +124 -0
  2. pcapkit/__main__.py +138 -0
  3. pcapkit/all.py +136 -0
  4. pcapkit/const/__init__.py +81 -0
  5. pcapkit/const/arp/__init__.py +25 -0
  6. pcapkit/const/arp/hardware.py +181 -0
  7. pcapkit/const/arp/operation.py +131 -0
  8. pcapkit/const/ftp/__init__.py +25 -0
  9. pcapkit/const/ftp/command.py +309 -0
  10. pcapkit/const/ftp/return_code.py +304 -0
  11. pcapkit/const/hip/__init__.py +94 -0
  12. pcapkit/const/hip/certificate.py +77 -0
  13. pcapkit/const/hip/cipher.py +65 -0
  14. pcapkit/const/hip/di.py +59 -0
  15. pcapkit/const/hip/ecdsa_curve.py +59 -0
  16. pcapkit/const/hip/ecdsa_low_curve.py +56 -0
  17. pcapkit/const/hip/eddsa_curve.py +65 -0
  18. pcapkit/const/hip/esp_transform_suite.py +98 -0
  19. pcapkit/const/hip/group.py +86 -0
  20. pcapkit/const/hip/hi_algorithm.py +86 -0
  21. pcapkit/const/hip/hit_suite.py +68 -0
  22. pcapkit/const/hip/nat_traversal.py +62 -0
  23. pcapkit/const/hip/notify_message.py +200 -0
  24. pcapkit/const/hip/packet.py +89 -0
  25. pcapkit/const/hip/parameter.py +377 -0
  26. pcapkit/const/hip/registration.py +68 -0
  27. pcapkit/const/hip/registration_failure.py +84 -0
  28. pcapkit/const/hip/suite.py +71 -0
  29. pcapkit/const/hip/transport.py +59 -0
  30. pcapkit/const/http/__init__.py +39 -0
  31. pcapkit/const/http/error_code.py +95 -0
  32. pcapkit/const/http/frame.py +95 -0
  33. pcapkit/const/http/method.py +184 -0
  34. pcapkit/const/http/setting.py +96 -0
  35. pcapkit/const/http/status_code.py +298 -0
  36. pcapkit/const/ipv4/__init__.py +57 -0
  37. pcapkit/const/ipv4/classification_level.py +64 -0
  38. pcapkit/const/ipv4/option_class.py +55 -0
  39. pcapkit/const/ipv4/option_number.py +137 -0
  40. pcapkit/const/ipv4/protection_authority.py +63 -0
  41. pcapkit/const/ipv4/qs_function.py +51 -0
  42. pcapkit/const/ipv4/router_alert.py +251 -0
  43. pcapkit/const/ipv4/tos_del.py +51 -0
  44. pcapkit/const/ipv4/tos_ecn.py +55 -0
  45. pcapkit/const/ipv4/tos_pre.py +63 -0
  46. pcapkit/const/ipv4/tos_rel.py +51 -0
  47. pcapkit/const/ipv4/tos_thr.py +51 -0
  48. pcapkit/const/ipv4/ts_flag.py +53 -0
  49. pcapkit/const/ipv6/__init__.py +53 -0
  50. pcapkit/const/ipv6/extension_header.py +69 -0
  51. pcapkit/const/ipv6/option.py +137 -0
  52. pcapkit/const/ipv6/option_action.py +55 -0
  53. pcapkit/const/ipv6/qs_function.py +51 -0
  54. pcapkit/const/ipv6/router_alert.py +266 -0
  55. pcapkit/const/ipv6/routing.py +80 -0
  56. pcapkit/const/ipv6/seed_id.py +55 -0
  57. pcapkit/const/ipv6/smf_dpd_mode.py +51 -0
  58. pcapkit/const/ipv6/tagger_id.py +62 -0
  59. pcapkit/const/ipx/__init__.py +27 -0
  60. pcapkit/const/ipx/packet.py +72 -0
  61. pcapkit/const/ipx/socket.py +104 -0
  62. pcapkit/const/l2tp/__init__.py +21 -0
  63. pcapkit/const/l2tp/type.py +51 -0
  64. pcapkit/const/mh/__init__.py +204 -0
  65. pcapkit/const/mh/access_type.py +92 -0
  66. pcapkit/const/mh/ack_status_code.py +71 -0
  67. pcapkit/const/mh/ani_suboption.py +74 -0
  68. pcapkit/const/mh/auth_subtype.py +53 -0
  69. pcapkit/const/mh/binding_ack_flag.py +66 -0
  70. pcapkit/const/mh/binding_error.py +51 -0
  71. pcapkit/const/mh/binding_revocation.py +59 -0
  72. pcapkit/const/mh/binding_update_flag.py +81 -0
  73. pcapkit/const/mh/cga_extension.py +66 -0
  74. pcapkit/const/mh/cga_sec.py +57 -0
  75. pcapkit/const/mh/cga_type.py +68 -0
  76. pcapkit/const/mh/dhcp_support_mode.py +53 -0
  77. pcapkit/const/mh/dns_status_code.py +65 -0
  78. pcapkit/const/mh/dsmip6_tls_packet.py +62 -0
  79. pcapkit/const/mh/dsmipv6_home_address.py +74 -0
  80. pcapkit/const/mh/enumerating_algorithm.py +56 -0
  81. pcapkit/const/mh/fb_ack_status.py +62 -0
  82. pcapkit/const/mh/fb_action.py +71 -0
  83. pcapkit/const/mh/fb_indication_trigger.py +65 -0
  84. pcapkit/const/mh/fb_type.py +59 -0
  85. pcapkit/const/mh/flow_id_status.py +77 -0
  86. pcapkit/const/mh/flow_id_suboption.py +71 -0
  87. pcapkit/const/mh/handoff_type.py +71 -0
  88. pcapkit/const/mh/handover_ack_flag.py +54 -0
  89. pcapkit/const/mh/handover_ack_status.py +92 -0
  90. pcapkit/const/mh/handover_initiate_flag.py +57 -0
  91. pcapkit/const/mh/handover_initiate_status.py +62 -0
  92. pcapkit/const/mh/home_address_reply.py +71 -0
  93. pcapkit/const/mh/lla_code.py +63 -0
  94. pcapkit/const/mh/lma_mag_suboption.py +59 -0
  95. pcapkit/const/mh/mn_group_id.py +59 -0
  96. pcapkit/const/mh/mn_id_subtype.py +77 -0
  97. pcapkit/const/mh/operator_id.py +63 -0
  98. pcapkit/const/mh/option.py +260 -0
  99. pcapkit/const/mh/packet.py +119 -0
  100. pcapkit/const/mh/qos_attribute.py +89 -0
  101. pcapkit/const/mh/revocation_status_code.py +83 -0
  102. pcapkit/const/mh/revocation_trigger.py +86 -0
  103. pcapkit/const/mh/status_code.py +232 -0
  104. pcapkit/const/mh/traffic_selector.py +62 -0
  105. pcapkit/const/mh/upa_status.py +71 -0
  106. pcapkit/const/mh/upn_reason.py +80 -0
  107. pcapkit/const/ospf/__init__.py +27 -0
  108. pcapkit/const/ospf/authentication.py +65 -0
  109. pcapkit/const/ospf/packet.py +71 -0
  110. pcapkit/const/pcapng/__init__.py +51 -0
  111. pcapkit/const/pcapng/block_type.py +152 -0
  112. pcapkit/const/pcapng/filter_type.py +48 -0
  113. pcapkit/const/pcapng/hash_algorithm.py +59 -0
  114. pcapkit/const/pcapng/option_type.py +233 -0
  115. pcapkit/const/pcapng/record_type.py +57 -0
  116. pcapkit/const/pcapng/secrets_type.py +56 -0
  117. pcapkit/const/pcapng/verdict_type.py +53 -0
  118. pcapkit/const/reg/__init__.py +34 -0
  119. pcapkit/const/reg/apptype.py +32728 -0
  120. pcapkit/const/reg/ethertype.py +714 -0
  121. pcapkit/const/reg/linktype.py +890 -0
  122. pcapkit/const/reg/transtype.py +526 -0
  123. pcapkit/const/tcp/__init__.py +35 -0
  124. pcapkit/const/tcp/checksum.py +55 -0
  125. pcapkit/const/tcp/flags.py +73 -0
  126. pcapkit/const/tcp/mp_tcp_option.py +80 -0
  127. pcapkit/const/tcp/option.py +198 -0
  128. pcapkit/const/vlan/__init__.py +23 -0
  129. pcapkit/const/vlan/priority_level.py +71 -0
  130. pcapkit/corekit/__init__.py +59 -0
  131. pcapkit/corekit/fields/__init__.py +45 -0
  132. pcapkit/corekit/fields/collections.py +282 -0
  133. pcapkit/corekit/fields/field.py +269 -0
  134. pcapkit/corekit/fields/ipaddress.py +274 -0
  135. pcapkit/corekit/fields/misc.py +722 -0
  136. pcapkit/corekit/fields/numbers.py +375 -0
  137. pcapkit/corekit/fields/strings.py +245 -0
  138. pcapkit/corekit/infoclass.py +394 -0
  139. pcapkit/corekit/io.py +506 -0
  140. pcapkit/corekit/module.py +39 -0
  141. pcapkit/corekit/multidict.py +626 -0
  142. pcapkit/corekit/protochain.py +263 -0
  143. pcapkit/corekit/version.py +33 -0
  144. pcapkit/dumpkit/__init__.py +15 -0
  145. pcapkit/dumpkit/common.py +199 -0
  146. pcapkit/dumpkit/null.py +77 -0
  147. pcapkit/dumpkit/pcap.py +144 -0
  148. pcapkit/foundation/__init__.py +45 -0
  149. pcapkit/foundation/engines/__init__.py +36 -0
  150. pcapkit/foundation/engines/dpkt.py +230 -0
  151. pcapkit/foundation/engines/engine.py +194 -0
  152. pcapkit/foundation/engines/pcap.py +188 -0
  153. pcapkit/foundation/engines/pcapng.py +310 -0
  154. pcapkit/foundation/engines/pyshark.py +166 -0
  155. pcapkit/foundation/engines/scapy.py +161 -0
  156. pcapkit/foundation/extraction.py +915 -0
  157. pcapkit/foundation/reassembly/__init__.py +49 -0
  158. pcapkit/foundation/reassembly/data/__init__.py +48 -0
  159. pcapkit/foundation/reassembly/data/ip.py +117 -0
  160. pcapkit/foundation/reassembly/data/tcp.py +145 -0
  161. pcapkit/foundation/reassembly/ip.py +192 -0
  162. pcapkit/foundation/reassembly/ipv4.py +50 -0
  163. pcapkit/foundation/reassembly/ipv6.py +50 -0
  164. pcapkit/foundation/reassembly/reassembly.py +389 -0
  165. pcapkit/foundation/reassembly/tcp.py +249 -0
  166. pcapkit/foundation/registry/__init__.py +41 -0
  167. pcapkit/foundation/registry/foundation.py +327 -0
  168. pcapkit/foundation/registry/protocols.py +885 -0
  169. pcapkit/foundation/traceflow/__init__.py +44 -0
  170. pcapkit/foundation/traceflow/data/__init__.py +30 -0
  171. pcapkit/foundation/traceflow/data/tcp.py +105 -0
  172. pcapkit/foundation/traceflow/tcp.py +159 -0
  173. pcapkit/foundation/traceflow/traceflow.py +390 -0
  174. pcapkit/interface/__init__.py +22 -0
  175. pcapkit/interface/core.py +185 -0
  176. pcapkit/interface/misc.py +120 -0
  177. pcapkit/protocols/__init__.py +85 -0
  178. pcapkit/protocols/application/NotImplemented/bgp.py +0 -0
  179. pcapkit/protocols/application/NotImplemented/dhcp.py +0 -0
  180. pcapkit/protocols/application/NotImplemented/dhcpv6.py +0 -0
  181. pcapkit/protocols/application/NotImplemented/dns.py +0 -0
  182. pcapkit/protocols/application/NotImplemented/imap.py +0 -0
  183. pcapkit/protocols/application/NotImplemented/ldap.py +0 -0
  184. pcapkit/protocols/application/NotImplemented/mqtt.py +0 -0
  185. pcapkit/protocols/application/NotImplemented/nntp.py +0 -0
  186. pcapkit/protocols/application/NotImplemented/ntp.py +0 -0
  187. pcapkit/protocols/application/NotImplemented/onc_rpc.py +0 -0
  188. pcapkit/protocols/application/NotImplemented/pop.py +0 -0
  189. pcapkit/protocols/application/NotImplemented/rip.py +0 -0
  190. pcapkit/protocols/application/NotImplemented/rtp.py +0 -0
  191. pcapkit/protocols/application/NotImplemented/sip.py +0 -0
  192. pcapkit/protocols/application/NotImplemented/smtp.py +0 -0
  193. pcapkit/protocols/application/NotImplemented/snmp.py +0 -0
  194. pcapkit/protocols/application/NotImplemented/ssh.py +0 -0
  195. pcapkit/protocols/application/NotImplemented/telnet.py +0 -0
  196. pcapkit/protocols/application/NotImplemented/tls.py +0 -0
  197. pcapkit/protocols/application/NotImplemented/xmpp.py +0 -0
  198. pcapkit/protocols/application/__init__.py +34 -0
  199. pcapkit/protocols/application/application.py +114 -0
  200. pcapkit/protocols/application/ftp.py +206 -0
  201. pcapkit/protocols/application/http.py +176 -0
  202. pcapkit/protocols/application/httpv1.py +320 -0
  203. pcapkit/protocols/application/httpv2.py +1255 -0
  204. pcapkit/protocols/data/__init__.py +192 -0
  205. pcapkit/protocols/data/application/__init__.py +57 -0
  206. pcapkit/protocols/data/application/ftp.py +59 -0
  207. pcapkit/protocols/data/application/httpv1.py +79 -0
  208. pcapkit/protocols/data/application/httpv2.py +293 -0
  209. pcapkit/protocols/data/data.py +25 -0
  210. pcapkit/protocols/data/internet/__init__.py +298 -0
  211. pcapkit/protocols/data/internet/ah.py +31 -0
  212. pcapkit/protocols/data/internet/hip.py +804 -0
  213. pcapkit/protocols/data/internet/hopopt.py +351 -0
  214. pcapkit/protocols/data/internet/ipv4.py +369 -0
  215. pcapkit/protocols/data/internet/ipv6.py +67 -0
  216. pcapkit/protocols/data/internet/ipv6_frag.py +29 -0
  217. pcapkit/protocols/data/internet/ipv6_opts.py +368 -0
  218. pcapkit/protocols/data/internet/ipv6_route.py +86 -0
  219. pcapkit/protocols/data/internet/ipx.py +56 -0
  220. pcapkit/protocols/data/internet/mh.py +509 -0
  221. pcapkit/protocols/data/link/__init__.py +33 -0
  222. pcapkit/protocols/data/link/arp.py +74 -0
  223. pcapkit/protocols/data/link/ethernet.py +28 -0
  224. pcapkit/protocols/data/link/l2tp.py +63 -0
  225. pcapkit/protocols/data/link/ospf.py +58 -0
  226. pcapkit/protocols/data/link/vlan.py +42 -0
  227. pcapkit/protocols/data/misc/__init__.py +109 -0
  228. pcapkit/protocols/data/misc/null.py +18 -0
  229. pcapkit/protocols/data/misc/pcap/__init__.py +18 -0
  230. pcapkit/protocols/data/misc/pcap/frame.py +56 -0
  231. pcapkit/protocols/data/misc/pcap/header.py +53 -0
  232. pcapkit/protocols/data/misc/pcapng.py +925 -0
  233. pcapkit/protocols/data/misc/raw.py +25 -0
  234. pcapkit/protocols/data/protocol.py +32 -0
  235. pcapkit/protocols/data/transport/__init__.py +71 -0
  236. pcapkit/protocols/data/transport/tcp.py +555 -0
  237. pcapkit/protocols/data/transport/udp.py +29 -0
  238. pcapkit/protocols/internet/NotImplemented/ecn.py +0 -0
  239. pcapkit/protocols/internet/NotImplemented/esp.py +97 -0
  240. pcapkit/protocols/internet/NotImplemented/icmp.py +0 -0
  241. pcapkit/protocols/internet/NotImplemented/icmpv6.py +0 -0
  242. pcapkit/protocols/internet/NotImplemented/igmp.py +0 -0
  243. pcapkit/protocols/internet/NotImplemented/shim6.py +0 -0
  244. pcapkit/protocols/internet/__init__.py +43 -0
  245. pcapkit/protocols/internet/ah.py +275 -0
  246. pcapkit/protocols/internet/hip.py +4727 -0
  247. pcapkit/protocols/internet/hopopt.py +1879 -0
  248. pcapkit/protocols/internet/internet.py +249 -0
  249. pcapkit/protocols/internet/ip.py +51 -0
  250. pcapkit/protocols/internet/ipsec.py +50 -0
  251. pcapkit/protocols/internet/ipv4.py +1782 -0
  252. pcapkit/protocols/internet/ipv6.py +412 -0
  253. pcapkit/protocols/internet/ipv6_frag.py +258 -0
  254. pcapkit/protocols/internet/ipv6_opts.py +1890 -0
  255. pcapkit/protocols/internet/ipv6_route.py +708 -0
  256. pcapkit/protocols/internet/ipx.py +230 -0
  257. pcapkit/protocols/internet/mh.py +2764 -0
  258. pcapkit/protocols/link/NotImplemented/dsl.py +0 -0
  259. pcapkit/protocols/link/NotImplemented/eapol.py +1 -0
  260. pcapkit/protocols/link/NotImplemented/fddi.py +0 -0
  261. pcapkit/protocols/link/NotImplemented/isdn.py +0 -0
  262. pcapkit/protocols/link/NotImplemented/ndp.py +0 -0
  263. pcapkit/protocols/link/NotImplemented/ppp.py +0 -0
  264. pcapkit/protocols/link/__init__.py +35 -0
  265. pcapkit/protocols/link/arp.py +421 -0
  266. pcapkit/protocols/link/ethernet.py +248 -0
  267. pcapkit/protocols/link/l2tp.py +267 -0
  268. pcapkit/protocols/link/link.py +140 -0
  269. pcapkit/protocols/link/ospf.py +342 -0
  270. pcapkit/protocols/link/rarp.py +82 -0
  271. pcapkit/protocols/link/vlan.py +225 -0
  272. pcapkit/protocols/misc/__init__.py +37 -0
  273. pcapkit/protocols/misc/null.py +129 -0
  274. pcapkit/protocols/misc/pcap/__init__.py +17 -0
  275. pcapkit/protocols/misc/pcap/frame.py +478 -0
  276. pcapkit/protocols/misc/pcap/header.py +358 -0
  277. pcapkit/protocols/misc/pcapng.py +5520 -0
  278. pcapkit/protocols/misc/raw.py +180 -0
  279. pcapkit/protocols/protocol.py +1216 -0
  280. pcapkit/protocols/schema/__init__.py +140 -0
  281. pcapkit/protocols/schema/application/__init__.py +40 -0
  282. pcapkit/protocols/schema/application/ftp.py +21 -0
  283. pcapkit/protocols/schema/application/httpv1.py +21 -0
  284. pcapkit/protocols/schema/application/httpv2.py +384 -0
  285. pcapkit/protocols/schema/internet/__init__.py +294 -0
  286. pcapkit/protocols/schema/internet/ah.py +40 -0
  287. pcapkit/protocols/schema/internet/hip.py +1184 -0
  288. pcapkit/protocols/schema/internet/hopopt.py +679 -0
  289. pcapkit/protocols/schema/internet/ipv4.py +576 -0
  290. pcapkit/protocols/schema/internet/ipv6.py +63 -0
  291. pcapkit/protocols/schema/internet/ipv6_frag.py +48 -0
  292. pcapkit/protocols/schema/internet/ipv6_opts.py +680 -0
  293. pcapkit/protocols/schema/internet/ipv6_route.py +197 -0
  294. pcapkit/protocols/schema/internet/ipx.py +40 -0
  295. pcapkit/protocols/schema/internet/mh.py +718 -0
  296. pcapkit/protocols/schema/link/__init__.py +19 -0
  297. pcapkit/protocols/schema/link/arp.py +39 -0
  298. pcapkit/protocols/schema/link/ethernet.py +51 -0
  299. pcapkit/protocols/schema/link/l2tp.py +88 -0
  300. pcapkit/protocols/schema/link/ospf.py +90 -0
  301. pcapkit/protocols/schema/link/vlan.py +69 -0
  302. pcapkit/protocols/schema/misc/__init__.py +108 -0
  303. pcapkit/protocols/schema/misc/null.py +18 -0
  304. pcapkit/protocols/schema/misc/pcap/__init__.py +10 -0
  305. pcapkit/protocols/schema/misc/pcap/frame.py +51 -0
  306. pcapkit/protocols/schema/misc/pcap/header.py +63 -0
  307. pcapkit/protocols/schema/misc/pcapng.py +1689 -0
  308. pcapkit/protocols/schema/misc/raw.py +24 -0
  309. pcapkit/protocols/schema/schema.py +809 -0
  310. pcapkit/protocols/schema/transport/__init__.py +69 -0
  311. pcapkit/protocols/schema/transport/tcp.py +928 -0
  312. pcapkit/protocols/schema/transport/udp.py +90 -0
  313. pcapkit/protocols/transport/NotImplemented/dccp.py +0 -0
  314. pcapkit/protocols/transport/NotImplemented/rsvp.py +0 -0
  315. pcapkit/protocols/transport/NotImplemented/sctp.py +0 -0
  316. pcapkit/protocols/transport/__init__.py +27 -0
  317. pcapkit/protocols/transport/tcp.py +3025 -0
  318. pcapkit/protocols/transport/transport.py +158 -0
  319. pcapkit/protocols/transport/udp.py +214 -0
  320. pcapkit/py.typed +0 -0
  321. pcapkit/toolkit/__init__.py +57 -0
  322. pcapkit/toolkit/dpkt.py +306 -0
  323. pcapkit/toolkit/pcap.py +212 -0
  324. pcapkit/toolkit/pcapng.py +251 -0
  325. pcapkit/toolkit/pyshark.py +99 -0
  326. pcapkit/toolkit/scapy.py +297 -0
  327. pcapkit/utilities/__init__.py +20 -0
  328. pcapkit/utilities/compat.py +196 -0
  329. pcapkit/utilities/decorators.py +197 -0
  330. pcapkit/utilities/exceptions.py +365 -0
  331. pcapkit/utilities/logging.py +55 -0
  332. pcapkit/utilities/warnings.py +185 -0
  333. pcapkit/vendor/__init__.py +105 -0
  334. pcapkit/vendor/__main__.py +92 -0
  335. pcapkit/vendor/arp/__init__.py +27 -0
  336. pcapkit/vendor/arp/hardware.py +29 -0
  337. pcapkit/vendor/arp/operation.py +29 -0
  338. pcapkit/vendor/default.py +474 -0
  339. pcapkit/vendor/ftp/__init__.py +27 -0
  340. pcapkit/vendor/ftp/command.py +244 -0
  341. pcapkit/vendor/ftp/return_code.py +256 -0
  342. pcapkit/vendor/hip/__init__.py +94 -0
  343. pcapkit/vendor/hip/certificate.py +29 -0
  344. pcapkit/vendor/hip/cipher.py +29 -0
  345. pcapkit/vendor/hip/di.py +29 -0
  346. pcapkit/vendor/hip/ecdsa_curve.py +29 -0
  347. pcapkit/vendor/hip/ecdsa_low_curve.py +29 -0
  348. pcapkit/vendor/hip/eddsa_curve.py +85 -0
  349. pcapkit/vendor/hip/esp_transform_suite.py +29 -0
  350. pcapkit/vendor/hip/group.py +87 -0
  351. pcapkit/vendor/hip/hi_algorithm.py +29 -0
  352. pcapkit/vendor/hip/hit_suite.py +29 -0
  353. pcapkit/vendor/hip/nat_traversal.py +29 -0
  354. pcapkit/vendor/hip/notify_message.py +29 -0
  355. pcapkit/vendor/hip/packet.py +88 -0
  356. pcapkit/vendor/hip/parameter.py +88 -0
  357. pcapkit/vendor/hip/registration.py +29 -0
  358. pcapkit/vendor/hip/registration_failure.py +29 -0
  359. pcapkit/vendor/hip/suite.py +29 -0
  360. pcapkit/vendor/hip/transport.py +29 -0
  361. pcapkit/vendor/http/__init__.py +39 -0
  362. pcapkit/vendor/http/error_code.py +95 -0
  363. pcapkit/vendor/http/frame.py +91 -0
  364. pcapkit/vendor/http/method.py +167 -0
  365. pcapkit/vendor/http/setting.py +93 -0
  366. pcapkit/vendor/http/status_code.py +185 -0
  367. pcapkit/vendor/ipv4/__init__.py +57 -0
  368. pcapkit/vendor/ipv4/classification_level.py +91 -0
  369. pcapkit/vendor/ipv4/option_class.py +80 -0
  370. pcapkit/vendor/ipv4/option_number.py +105 -0
  371. pcapkit/vendor/ipv4/protection_authority.py +84 -0
  372. pcapkit/vendor/ipv4/qs_function.py +78 -0
  373. pcapkit/vendor/ipv4/router_alert.py +93 -0
  374. pcapkit/vendor/ipv4/tos_del.py +78 -0
  375. pcapkit/vendor/ipv4/tos_ecn.py +95 -0
  376. pcapkit/vendor/ipv4/tos_pre.py +84 -0
  377. pcapkit/vendor/ipv4/tos_rel.py +78 -0
  378. pcapkit/vendor/ipv4/tos_thr.py +77 -0
  379. pcapkit/vendor/ipv4/ts_flag.py +79 -0
  380. pcapkit/vendor/ipv6/__init__.py +53 -0
  381. pcapkit/vendor/ipv6/extension_header.py +171 -0
  382. pcapkit/vendor/ipv6/option.py +104 -0
  383. pcapkit/vendor/ipv6/option_action.py +90 -0
  384. pcapkit/vendor/ipv6/qs_function.py +78 -0
  385. pcapkit/vendor/ipv6/router_alert.py +93 -0
  386. pcapkit/vendor/ipv6/routing.py +87 -0
  387. pcapkit/vendor/ipv6/seed_id.py +81 -0
  388. pcapkit/vendor/ipv6/smf_dpd_mode.py +78 -0
  389. pcapkit/vendor/ipv6/tagger_id.py +81 -0
  390. pcapkit/vendor/ipx/__init__.py +37 -0
  391. pcapkit/vendor/ipx/packet.py +123 -0
  392. pcapkit/vendor/ipx/socket.py +125 -0
  393. pcapkit/vendor/l2tp/__init__.py +21 -0
  394. pcapkit/vendor/l2tp/type.py +78 -0
  395. pcapkit/vendor/mh/__init__.py +204 -0
  396. pcapkit/vendor/mh/access_type.py +87 -0
  397. pcapkit/vendor/mh/ack_status_code.py +88 -0
  398. pcapkit/vendor/mh/ani_suboption.py +88 -0
  399. pcapkit/vendor/mh/auth_subtype.py +83 -0
  400. pcapkit/vendor/mh/binding_ack_flag.py +148 -0
  401. pcapkit/vendor/mh/binding_error.py +78 -0
  402. pcapkit/vendor/mh/binding_revocation.py +87 -0
  403. pcapkit/vendor/mh/binding_update_flag.py +147 -0
  404. pcapkit/vendor/mh/cga_extension.py +91 -0
  405. pcapkit/vendor/mh/cga_sec.py +91 -0
  406. pcapkit/vendor/mh/cga_type.py +74 -0
  407. pcapkit/vendor/mh/dhcp_support_mode.py +77 -0
  408. pcapkit/vendor/mh/dns_status_code.py +87 -0
  409. pcapkit/vendor/mh/dsmip6_tls_packet.py +87 -0
  410. pcapkit/vendor/mh/dsmipv6_home_address.py +87 -0
  411. pcapkit/vendor/mh/enumerating_algorithm.py +82 -0
  412. pcapkit/vendor/mh/fb_ack_status.py +87 -0
  413. pcapkit/vendor/mh/fb_action.py +88 -0
  414. pcapkit/vendor/mh/fb_indication_trigger.py +87 -0
  415. pcapkit/vendor/mh/fb_type.py +88 -0
  416. pcapkit/vendor/mh/flow_id_status.py +87 -0
  417. pcapkit/vendor/mh/flow_id_suboption.py +87 -0
  418. pcapkit/vendor/mh/handoff_type.py +87 -0
  419. pcapkit/vendor/mh/handover_ack_flag.py +143 -0
  420. pcapkit/vendor/mh/handover_ack_status.py +87 -0
  421. pcapkit/vendor/mh/handover_initiate_flag.py +143 -0
  422. pcapkit/vendor/mh/handover_initiate_status.py +87 -0
  423. pcapkit/vendor/mh/home_address_reply.py +87 -0
  424. pcapkit/vendor/mh/lla_code.py +97 -0
  425. pcapkit/vendor/mh/lma_mag_suboption.py +88 -0
  426. pcapkit/vendor/mh/mn_group_id.py +87 -0
  427. pcapkit/vendor/mh/mn_id_subtype.py +87 -0
  428. pcapkit/vendor/mh/operator_id.py +87 -0
  429. pcapkit/vendor/mh/option.py +83 -0
  430. pcapkit/vendor/mh/packet.py +82 -0
  431. pcapkit/vendor/mh/qos_attribute.py +87 -0
  432. pcapkit/vendor/mh/revocation_status_code.py +87 -0
  433. pcapkit/vendor/mh/revocation_trigger.py +87 -0
  434. pcapkit/vendor/mh/status_code.py +91 -0
  435. pcapkit/vendor/mh/traffic_selector.py +87 -0
  436. pcapkit/vendor/mh/upa_status.py +87 -0
  437. pcapkit/vendor/mh/upn_reason.py +87 -0
  438. pcapkit/vendor/ospf/__init__.py +27 -0
  439. pcapkit/vendor/ospf/authentication.py +29 -0
  440. pcapkit/vendor/ospf/packet.py +29 -0
  441. pcapkit/vendor/pcapng/__init__.py +51 -0
  442. pcapkit/vendor/pcapng/block_type.py +94 -0
  443. pcapkit/vendor/pcapng/filter_type.py +77 -0
  444. pcapkit/vendor/pcapng/hash_algorithm.py +82 -0
  445. pcapkit/vendor/pcapng/option_type.py +287 -0
  446. pcapkit/vendor/pcapng/record_type.py +81 -0
  447. pcapkit/vendor/pcapng/secrets_type.py +81 -0
  448. pcapkit/vendor/pcapng/verdict_type.py +79 -0
  449. pcapkit/vendor/reg/__init__.py +34 -0
  450. pcapkit/vendor/reg/apptype.py +338 -0
  451. pcapkit/vendor/reg/ethertype.py +121 -0
  452. pcapkit/vendor/reg/linktype.py +110 -0
  453. pcapkit/vendor/reg/transtype.py +111 -0
  454. pcapkit/vendor/tcp/__init__.py +35 -0
  455. pcapkit/vendor/tcp/checksum.py +80 -0
  456. pcapkit/vendor/tcp/flags.py +149 -0
  457. pcapkit/vendor/tcp/mp_tcp_option.py +90 -0
  458. pcapkit/vendor/tcp/option.py +103 -0
  459. pcapkit/vendor/vlan/__init__.py +23 -0
  460. pcapkit/vendor/vlan/priority_level.py +97 -0
  461. pypcapkit-1.3.5.post6.dist-info/LICENSE +29 -0
  462. pypcapkit-1.3.5.post6.dist-info/METADATA +238 -0
  463. pypcapkit-1.3.5.post6.dist-info/RECORD +466 -0
  464. pypcapkit-1.3.5.post6.dist-info/WHEEL +5 -0
  465. pypcapkit-1.3.5.post6.dist-info/entry_points.txt +3 -0
  466. pypcapkit-1.3.5.post6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,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
+ )