-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmusctp_draft.txt
More file actions
8045 lines (6530 loc) · 441 KB
/
Copy pathmusctp_draft.txt
File metadata and controls
8045 lines (6530 loc) · 441 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
!!! ЧЕРНОВИК !!!
muSCTP: Multiflow Unsymmetric Sessionful Concise Tunneled Protocol
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Универсальный транспортный протокол, предоставляющий прикладному коду сервис,
аналогичный TCP или SCTP, то есть надежную доставку данных, при этом могущий
работать по нескольким транспортным путям одновременно (как failover, так и
повышение производительности), и поддерживающий мультиплексирование в одном
соединении (ассоциации) сразу несколько байтовых TCP-потоков или передачи
разграниченных блоков данных, как в SCTP или Win32 CreateNamedPipe() в
режиме PIPE_TYPE_MESSAGE. Ключевой особенностью протокола является расчет
на работу в средах с очень малым размером пакета и с несимметричностью
сторон соединения - когда сервер в состоянии только отвечать на пакеты
клиента, но не посылать их самостоятельно, например, поверх ICMP-запросов и
ответов (однако если самостоятельные пакеты от сервера иногда возможны,
поддерживается и это).
A siginficant adavantage of muSCTP over QUIC is multipath: e.g. a mobile host
with both EDGE and Wi-Fi connectivity can not only rapidly switch from one
to another (as in QUIC, in cases like network change/failure/NAT rebinding),
but use both Wi-Fi and EDGE links simultaneously, increasing bandwidth.
1. Введение.
Application-layer framing or application-level framing (ALF) is a method of allowing an application to use its semantics for the design of its network protocols.
This procedure was first proposed by D. D. Clark and David L. Tennenhouse.[1] It works as follows:
* The application splits the data into useful segments.
* These segments are called ADUs (application data units).
* The ADUs can be processed in any order.
* The lower layers keep the ADU borders.
TODO 30.11.24 describe that L4 knowing how many bytes app wants to transmit is
beneficial for things like scheduling over multipath and e.g. Section 6.3.1 of
RFC 9049 describes why Quick-Start should be for bulk flows
- 25.01.25 https://arxiv.org/pdf/2210.00714 about Homa has a good list of TCP
problems in this respect, e.g. scheduling Shortest Remaining Processing Time
for "task to completion" - may be additional attribute to message here?
[QUIC-APPLICABILITY]:
in comparison to QUIC, muSCTP does not need fallback protocol, tunnels are for this
QUIC problems: increased deadlock probabilty,
Once stream limits are reached, no more streams can be opened,
which prevents applications using QUIC from making further progress
QUIC does not provide any mechanism for graceful connection termination;
QUIC DATAGRAM extension [RFC 9221] does not allow ordering inside streams or
window control, while muSCTP allows this,and time, for unordedered chunks
RFC 8546 wire image:
is that all
observable parts of a protocol's wire image will eventually be used
by devices on path. Consequently, changes or future extensions that
affect the observable part of the wire image become difficult or
impossible to deploy.
4.1: Integrity protection of the wire image may
itself help protect against accidental invariance, because read-only
wire images invite less meddling than path-writable wire images. The
techniques discussed in [USE-IT] may also be useful in further
preventing accidental invariance and ossification.
for example, QUIC's spin bit (an ugly kludge for measuring RTT
by on-path observers) is easily replaced by unencrypted (but authenticated)
packets with HEARTBEAT, ECHO, ECNE_CWR and LINK_INFO options, while all other
packets could remain encrypted
"Let's simplify user interface features" paradigm is bad and wrong, as seen on example
of TCP-3 [IEN21] this leads to problems in strategic perspective; [RFC 9170]
also states about bad assumptions in the protocol design about performance constraints
(read: variable-length fields)
due to Unix Time is bad in long scale, Leap Seconds and other problems, this
protocol version MUST NOT be used in XXII century (recommended method will be
e.g. Julian Days or CCSDS DAY SEGMENTED TIME CODE), so, for this version,
tv_sec is simply limited to 32 bits (unsigned) and that's it.
https://apenwarr.ca/log/20170810 describes problems of WiFi repeaters and LTE
due to bridging - which can be solved by changing from 4-tuple, that is,
Connection Tag of muSCTP (TBD may be have it longer by variable-length bits?)
RFC 6830 LISP January 2013
Address Family Identifier (AFI): AFI is a term used to describe an
address encoding in a packet. An address family currently
pertains to an IPv4 or IPv6 address. See [AFI] and [RFC3232] for
details. An AFI value of 0 used in this specification indicates
an unspecified encoded address where the length of the address is
0 octets following the 16-bit AFI value of 0.
RFC 8376:
The DNS query/answer protocol as a precursor to other communication
within the Time-To-Live (TTL) of a DNS answer is clearly problematic
in an LPWAN, say where only one round-trip per hour can be used, and
with a TTL that is less than 3600 seconds. It is currently unclear
whether and how DNS-like functionality might be provided in LPWANs.
-- muSCTP could be used directly with DNS as sockaddr?
https://ipj.dreamhosters.com/wp-content/uploads/2023/01/253-ipj.pdf :
THE INTERNET PROTOCOL JOURNAL
11
RPC Support
IP hosts commonly support just two transport services, UDP and
TCP. UDP is a simple datagram-delivery service. Data encapsulated
using UDP have no assured delivery. TCP, as we have seen, is a reli-
able streaming service. The TCP protocol repairs any packet loss or
changes to the delivered packet sequence.
Another model, namely the Remote Procedure Call (RPC) model,
emulates the functionality of procedure calls, and rather than the byte-
stream model of TCP or the datagram model of UDP, the RPC model
is a reliable request/reply model, where the reply is uniquely associated
with the request. Perhaps the most well-known example today of an
RPC framework is gRPC[8]. gRPC is based on an HTTP/2 platform,
implying that the framework is susceptible to head-of-line blocking as
with any other TCP-based substrate.
The issue here is that a reliable byte stream is not the right abstrac-
tion for RPC, as the core of RPC is a request/reply paradigm, which
is more aligned to a reliable messaging paradigm, with all that such
a paradigm entails. A capable RPC framework needs to handle lost,
mis-ordered, and duplicated messages, with an identifier space that
can match requests and responses. The underlying message transport
needs to handle messages of arbitrary size, which entails packetization
adaptation within the transport.
The bidirectional stream framework is a reasonable match to the RPC
communications model where each RPC can be matched against an
individual stream. The stream is reliable and sequenced. The data
framing is not contained in QUIC, and it is still an application task to
add a record structure to an RPC stream, if that is what is required.
The invocation overhead is low in that the encrypted end-to-end con-
nection is already established.
It certainly appears that HTTPS behaves much more like RPC than
a reliable byte stream. That can benefit applications that run over
HTTP(S), such as gRPC, and a set of Representational State Transfer
(REST)ful APIs.
Load-Balancing QUIC
In today’s world of managing scale, it is very common to place a front-
end load balancer across many servers. The load balancer in the TCP
world typically categorizes packets as being in the same TCP session
because of a common 5-tuple value of protocol, IP addresses, and port
numbers, with the confident assurance that this value is stable for the
life of the TCP session.
QUIC offers no such assurances. The 5-tuple load-balancing approach
can work, but if the client is behind a NAT that performs what could be
called “aggressive” rebinding, then any such load-balancing approach
will be thrown. The reason why is that UDP does not provide session
signalling to a NAT, so there is no a priori assurance that the NAT
bindings (and the presented source address and port) will remain con-
stant for the entire QUIC session.
THE INTERNET PROTOCOL JOURNAL
12
Now in theory IPv6 could invoke the Flow-ID to provide a proxy
persistent field that remains constant for a flow, but the Flow-ID is of
limited size and has no assurances of uniqueness, as well as evidence
of highly variable treatment by IPv6 network infrastructure and end
hosts.
This topic touches upon a major assumption in today’s high-capacity
server infrastructure on the public Internet. Data streams use TCP and
the DNS uses UDP. Using UDP to carry sustained high-volume streams
may not match the internal optimisations used in server content-deliv-
ery networks.
DDoS Defence
The next issue here is exposure to Distributed Denial-of-Service
(DDoS) attacks. An attacker can send a large volume of packets to
the server and cause the server to perform work to attempt to decrypt
the packet. For this capability to be successful in TLS over TCP the
attacker must make a reasonable guess of the TCP sequence number
and window size for the packet to be accepted and passed to the TLS
decoder. QUIC has no lightweight packet filter before the decoder is
invoked.
On the other hand, the session encryption uses symmetric crypto
algorithms, which are less of a load on the receiver to decode than
asymmetric encryption. Is this difference enough to allow large-scale
QUIC platforms that are DDoS resistant to be constructed? I’m unsure
if there are clear answers here, but it seems that it’s part of the cost of
having a more complete encryption framework, which in itself appears
to be sorely needed on the public Internet.
Private QUIC
For private contexts, can QUIC negotiate a “null” TLS encryp-
tion algorithm? There is a bigger world out there beyond the public
Internet, and in many private data centre environments the overheads
of encrypting and decrypting packets may appear to be unnecessary.
While QUIC can present some clear advantages in terms of suitability
to complex application behaviours in the data centre that can lever-
age QUIC’s multi-stream capability, the cost of encryption may be too
high.
Of course, there is nothing stopping an implementation using a null
encryption algorithm, but such an implementation could talk only
to other implementations of itself. Strictly speaking, if you remove
encryption, then it’s no longer QUIC and it won’t interoperate with
anything else that is QUIC.
QUIC and OpenSSL
It useful to ask that if QUIC has such clear advantages over TCP, then
why hasn’t the adoption of QUIC been rapid? Metrics of QUIC use
tend to point to a use rate of some 30% of web sessions (such as
Cloudflare’s Radar report[9]).
QUIC and TCP continued
THE INTERNET PROTOCOL JOURNAL
13
However, if you alter the measurement to measure the extent to which
browsers on end systems are capable of supporting a QUIC session,
then the measurement jumps to 60%[10].
There are a couple of reasons why QUIC use is far lower than QUIC
capability. The first is that the Chrome browser still relies on the con-
tent-level switch to QUIC, so the client has to visit the site for the first
time using HTTP/2 (TCP/TLS) and thereby receive an indication if the
server can support QUIC, and then on the second visit the client may
use QUIC. It’s not quite as simple as this, as HTTP/2 uses persistent
connection, so if the second visit is sufficiently close in time to the first,
then the HTTP/2 session will remain open and still be used. The Safari
browser is capable of using QUIC on first use because it is triggered by
the Service Binding (SVCB) record in the DNS, but the market share
of Safari is relatively small in comparison to QUIC.
The second reason lies in the web server environment. Many servers
rely on the OpenSSL TLS library[11], and so far, (November 2022)
OpenSSL does not include support for QUIC. QUIC is supported in
BoringSSL[12], but as the notes for BoringSSL state, BoringSSL is a
fork of OpenSSL that is designed to meet Google’s needs, and while
it works for Google, it may not work for everyone else. Google does
not recommend that third parties depend on BoringSSL. There is also
QuicTLS, a fork of OpenSSL that Akamai and Google support[13].
This fragmentation of OpenSSL is not exactly helpful, and the result
is that many server environments are waiting for OpenSSL to incorpo-
rate a QUIC library. This effort was delayed by the work on OpenSSL
release 3.0.0, and then the OpenSSL folks announced their intention
to provide a fully functional QUIC implementation, and this develop-
ment of a new QUIC protocol stack may further delay QUIC support
in OpenSSL by months, if not years.
TBD 18.04.25 incorporate some features of gRPC
TBD 28.07.25 look at paths with attributes from https://www.openconfig.net/docs/gnmi/gnmi-specification/ like `/a/b[name=b1]/c/d` (is it from YANG or independent?) and updating them like union_replace merge
1.1. Общий обзор.
Ranging protocols (boundaries really are somewhat blurred) by upper scale:
Very . Low end . Middle . Higher . Very . Ultra High
constrained . . (today) . end . Highload . (future)
. . . . .
IoT/Embedded . older hw . casual . low-end . Big DC .
. and sw, . user's . servers, . servers, .
. future . desktop . VMs . HPC clus- .
. embedded . . . ters .
. . . . .
< 1 Mbps, . 10-100 Mbps . 1 Gbps, . 10 Gbps, . 40-800 Gbps . > 8 Tbps
MTU 60-128 . IPv4 . IPv4/IPv6 . IPv4/6 . IPv6/custom .
Bytes \__ MTU 576-1500 Bytes __/ \_ MTU 1500-9000 Bytes _/
. . . . .
|<------ CoAP ------>| . . . .
. . . . .
|<----------------------- TCP ----------------------->|
. . . . .
|<------------------------ muSCTP ------------------------>|
. . . . .
. |<--------------------- SCTP --------------------->|
. . . . .
. |<--------------------- DCCP --------------------->|
. . . . .
. |<-------------------- QUIC -------------------->|
. . . . .
|<-------x-----x--- custom protocols per task / field ---x--------x------->|
In what SCTP is better performing than muSCTP:
* up to 65536 theoretical streams instead of 256
* same 32 bits for TSN, but chunk size is 2048 bytes maximum in muSCTP and
65536 in SCTP so possible max speed is 32 times more (this requires,
however, adding Window Scale INIT parameter like in TCP)
* unlimited message size, compared to 1 Gb of muSCTP - and unlimited message
is conceptually the same as opening and closing bytestream in QUIC
* multiple peers in one socket, though this is API feature, not of protocol
itself
In all other respects muSCTP is better and have more features than SCTP
(and, of course, TCP). And as QUIC is in fact 61-bit protocol with
non-circular number space - it must be stopped on reaching this limit - it
is also limited and not final word in protocols developing to match hardware
speed.
Базируется в основном на SCTP (RFC 4960) и некоторых идеях из CoAP (RFC 7252).
Кроме того, поддерживается прозрачное для пользователя шифрование, подобное
TLS/SSL (или же IPsec, если смотреть с точки зрения транспортов).
Другой ключевой особенностью протокола является не самостоятельная работа
напрямую поверх IP или UDP, но поверх некоторого другого, более простого
туннельного протокола, обеспечивающего контроль целостности чексуммами
(например, поверх UDP), но не гарантирующего доставки данных, и являющегося
клиент-серверным модели "запрос-ответ" вплоть до 1 пакета, как в ICMP. С точки
зрения пользователя muSCTP, т.е. кода приложения:
+-------------+
OSI Layer 7 | application |
+-------------+
|
+-------------+
OSI Layer 5 | Session/QoS |
+-------------+
OSI Layer 4 | muSCTP |
+-------------+
| | |
.-------' | `---,
| | |
backends ===|=========|=========|===[ шифрование и проверка целостности ]===
| | |
+-----+ +------+ +-----------+
Layer 3 | UDP | | ICMP | | HTTP+CoAP |
+-----+ +------+ +-----------+
С точки зрения реальной модели OSI, конечно, сами транспорты ("бэкенды")
находятся на Layer 7.
Поскольку транспорты возможны очень разные, и единственное, что их объединяет,
это "отражение" сервером в ответе на запрос клиенту некоторого количества
идентифицирующих байт, то собственно шифрование вынесено на уровень
транспортных бэкендов, и даже сам пакет muSCTP, таким образом, состоит из
более чем одной части: собственно тела, и повторяемая идентифицирующая часть:
Client Server
| |
| +---------------------+ |
| | client packet body | request |
| +---------------------+--, +------------------+ by protocol |
| >-| transport packet |-------------->|
| +---------------------+--' +------------------+ of transport |
| | uniq. identificator | |
| +---------------------+ |
| +---------------------+ |
| response | server packet body | |
| by protocol +------------------+ .-+---------------------+ |
|<---------------| transport packet |-< |
| of transport +------------------+ `-+----------------------+ |
| | same identificator | |
| +----------------------+ |
| |
Как именно эти части упаковываются в протокол конкретного транспорта, дело
сугубо бэкенда этого транспорта. Концептуально, это может происходить как
как непосредственными вызовами функций с аргументами (комбинированная
реализация типична для клиента), так и разными процессами, возможно, на
разных физических машинах, в случае сервера (соответственно с
промежуточными мини-протокола) - в случае сервера, для обеспечения
Highload, высоконагруженной системы на большое количество клиентов. В
действительности, идентификатор состоит из отдельных частей:
+---------------+ +---------+ +-------------+ +-------+
| Server number | | Counter | | Key number | | Nonce |
+---------------+ +---------+ +-------------+ +-------+
Проблема короткоопакетных протоколов - малое количество байт на
идентификатор соединения. Тогда как в полноценном TCP/IP есть еще:
* номер порта клиента, 16 бит
* номер порта сервера, 16 бит
В итоге высока вероятность коллизий, при большом количестве клиентов за
одним IP-адресом (типично при NAT), что ведет к обрыву соединений. При
этом в SCTP/IP не достаточно и этого, потому что соединение (ассоциация)
может идти по нескольким маршрутам - так что добавлены еще дополнительные:
* Client Verification Tag, 32 бита
* Server Verification Tag, 32 бита
Причем они разные для сервера и клиента из соображений безопасности. Мы
обеспечиваем безопасность и шифрование, так что повторяем эту схему, но
на неё нет места в идентификаторе пакета, поэтому теги уходят в тело, а
в идентификаторе остается другая важная часть - "номер сервера". Это аналог
tcp-порта на сервере, но он применяется не как порт как таковой, а как
средство распределения нагрузки:
* при установке соединения клиент посылает на нулевой номер сервера
* ему приходит ответ, с каким номером сервера дальше будет работа
* далее клиент посылает запросы уже на этот номер сервера
Так достигается балансировка нагрузки на сервер (эти номера могут быть,
например, на разных физических машинах).
К сожалению, из повтора сервером, Nonce не в полной мере оправдывает свое
название, эта проблема будет решена другим путем.
TBD переименовать Verification, разобраться с Nfewnce, clarify "вместо портов"
TBD a host-to-host problem - SCTP has ports:
o SCTP association: A protocol relationship between SCTP endpoints,
composed of the two SCTP endpoints and protocol state information
including Verification Tags and the currently active set of
Transmission Sequence Numbers (TSNs), etc. An association can be
uniquely identified by the transport addresses used by the
endpoints in the association. Two SCTP endpoints MUST NOT have
more than one SCTP association between them at any given time.
B) "Z" shall respond immediately with an INIT ACK chunk. The
destination IP address of the INIT ACK MUST be set to the source
IP address of the INIT to which this INIT ACK is responding. In
the response, besides filling in other parameters, "Z" must set
the Verification Tag field to Tag_A, and also provide its own
Verification Tag (Tag_Z) in the Initiate Tag field.
so what to do when no ports?
TBD reflection problem for Key ID
Номер ключа представляет собой аналог SPI из IPsec, то есть индекс
использованных параметров шифрования - помимо собственно строки байт ключа,
ключ данного номера имеет прикрепленную информацию в виде срока действия,
алгоритмов; так же разные транспорты могут использовать разные байтовые
подстроки ключа для уменьшения вероятности взлома других направлений при
проблемах с одним из них. Сам muSCTP не занимается непосредственно
шифрованием, это делают бэкенды, но занимается согласованием этих параметров
и самих ключей, ротацию ключей, загрузку их в бэкенды. Ключи с очень низкими
номерами зарезервированы (не ротируются, вшиты), в частности, ключ номер 0
"пустой", означает отсутствие шифрования.
Наконец, счетчик представляет из себя просто инкрементирующийся с каждым
пакетом номер, служащий в основном цели уникальности пакета за некоторый
период времени (исключением является только установление соединения). Это
решает проблему наивных решений, когда счетчик есть непосредственно номер
блока, причем общим для клиента и сервера, что создавало проблемы при
закрытом окне и большом расхождении блоков на клиенте и сервере друг от
друга. Кроме того, оно также ограничивало количество возможных ретрансмиссий
для блока (Rand-битами), каковой проблемы не имеют обычные протоколы, и
соответствено серьезно ограничивало применимость алгоритма Fast Retransmit.
Внутри "контейнера" под идентификатором протокол майнтейнит свои номера,
имитируя полноценный неограниченный схемой "запрос-ответ" протокол, и в
случае поддерживающего такое транспорта сервер даже может отправить клиенту
несколько пакетов с одинаковым идентификатором, но разным содержимым
внутри.
1.2. Пути, потоки и блоки: удобство программной модели.
Прежде всего, с точки зрения администратора, muSCTP может одновременно
работать по нескольким путям, т.е. адресам.
Рассмотрим обыкновенный классический TCP:
_____________ _____________
| TCP User | | TCP User |
| Application | | Application |
|-------------| address 1 data address 2 |-------------|
| TCP |<---------------------------------->| TCP |
| Transport | port 1 byte stream port 2 | Transport |
| Service | | Service |
|_____________| |_____________|
В обычном TCP всё просто - у каждого конца только один адрес и порт. Данные
представляют собой неструктурированный поток байт - сколько записали,
столько в итоге прочитает получатель, но вовсе не факт, что такими же
порциями. Поэтому в ряде прикладных протоколов программистам приходится
самостоятельно каким-либо способом размечать (делить) поток на записи,
часто указанием какой-либо длины.
Если соединение в TCP порвалось, то... оно порвалось, ничего сделать нельзя,
только установить новое (если получится).
А в muSCTP возможна параллельная работа:
_____________ _____________
| muSCTP User | | muSCTP User |
| Application | | Application |
|-------------| address 1 data address 4 |-------------|
| muSCTP |<---------------------------------->| muSCTP |
| Transport | | Transport |
| Service | | Service |
|-------------| address 2 data address 5 |-------------|
| |<---------------------------------->| |
| Transport | \/ | Transport |
| backends | address 3 /\ address 6 | backends |
|_____________|<---------------------------------->|_____________|
fail
muSCTP Node A muSCTP Node B
То есть, в одно "соединение" - теперь оно называется "ассоциация" - внизу
вовлекается несколько реальных соединений по разным адресам. И данные
бегают по всем из них сразу, параллельно, вероятно, повышая скорость
работы. Теперь, если одно из нижележащих "соединений" обрывается - это
обнаруживается, и muSCTP переотправляет данные по другим путям. И в целом
соединение (ассоциация) не рвётся - что, как минимум, удобно при
интерактивной работе (шелл).
Так, например, изначально ассоциация muSCTP могла быть установлена на адрес
UDP-сервера, затем тот сообщил клиенту - "у меня есть еще ICMP-туннель", и
клиент добавляет ICMP-адрес, и данные начинают ходить по обоим сразу. Далее,
скажем, клиент может сообщить серверу "у меня получился коннект в HTTP",
и они с сервером получают еще один канал для связи в той же ассоциации. При
этом для пользователя, который уже, например, мог установить шелл-коннект
через эту ассоциацию, всё происходит прозрачно - ничего не рвётся, всё
работает, заново переустанавливать шелл-коннект на ставшее доступным более
быстрое соединение вручную не надо. Всё автоматически.
Это первейшее с точки зрения администратора, но есть более интересные вещи.
Если соединение в TCP "застряло", то возникает более интересная ситуация.
Допустим, программист делил на блоки и передавал по одному соединению данные
параллельно - разные запросы, файлы и т.п. Когда временная ошибка, и поток
застрял, тормозятся ВСЕ они - потому что TCP ничего не знает о структуре
потока. Это называется head of line blocking, и для решения этой проблемы
(то есть ускорения работы при одиночных ошибках) часто изобретают
велосипеды, например, Google c протоколом QUIC по UDP. В них разделяют, что
застрянет только один "поток" (HTTP-запрос), в котором произошла временная
ошибка (потеря пакета), все остальные не затормозятся.
muSCTP предоставляет возможность такого деления - поверх одной ассоциации
может ходить несколько "логических" соединений - потоков. Например, по
одному может быть шелл-коннект, по другому передача файла, по третьему
SOCKS5 - это может и просто ssh, но ssh работает по tcp, и при обрыве или
затыке заткнется всё. А в muSCTP только тот из потоков, который затронуло.
И поскольку они имеют общие параметры, с точки зрения пользователя тут
возможна и ПРИОРИТЕЗАЦИЯ - например, чтобы передача файла не забивала собой
канал, как в старом решении, чтобы шеллу давался приоритет.
stream messages
+---+---+---+ entry
| 0/0 |-, to common "pipe" .-> stream 0
+---+---+---+ | \\ // |
| ## +---+---+---+---+---+---+---+---+---+ ## |
+---+---+---+ '-> ## |2/0|1/2|0/0|2/0|1/1|0/0|2/0|1/0|0/0| ##-'
|1/2|1/1|1/0|---> ## |---|---|---|---|---|---|---|---|---| ##---> stream 1
+---+---+---+ .-> ## | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ##-,
| ## +---+---+---+---+---+---+---+---+---+ ## |
+---+---+---+ | // fragmenting messages to packets \\ |
| 2/0 |-' exit `-> stream 2
+---+---+---+ from common "pipe"
+-------+
+-------+ |SID/SSN|
|SID/SSN| <- numbers mean -> |-------|
+-------+ | TSN |
+-------+
Для программиста же muSCTP предоставляет еще одно удобство - деление данных
в потоках на блоки. То есть, отправка и чтение в каждый поток происходят с
сохранением границ блоков - до 1 Гб. Получатель получит запись размера,
который задал отправитель. Блоки отправляются и принимаются последовательно,
каждый имеет номер, который увеличивается до максимума и снова начинает с
нуля. Но есть и возможность отправить "внеочередной", unordered, блок, по
потоку, не имеющий номера. Самый простой пример - послать Control-C в шелл
или иные данные "сбоку". Итого как бы 16 пайпов с PIPE_TYPE_MESSAGE и
еще 16 с типом по выбору, если говорить в терминах Win32 API.
Ввиду специфики среды и малых пакетов, muSCTP поддерживает максимум 16
потоков в одной ассоциации. Для удобства любой из них может быть переведен
в "байтовый" режим, чтобы проще было передавать tcp-данные типа SOCKS5, а
потом выведен. В байтовом режиме возможность посылать unordered-блоки
сохраняется. Также для удобства при открытии байтового потока / в любой
другой момент потоку может быть назначен произвольный DWORD, самим muSCTP
не интерпретируемый, но к примеру, получатель может по нему понять, какой
хэндлер открываемому потоку назначить, т.е. удобство протоколов поверх
(аналог PPID в SCTP передается в каждом блоке, но здесь пакеты слишком
короткие, чтобы тратить 4 байта на каждый блок, а вот время от времени можно).
Some LPWAN technologies provide quasi-bidirectional connectivity,
whereby a Downlink transmission from the Network Infrastructure can
only take place right after an Uplink transmission by the Dev.
1.3. Philosophical background and values.
attacks such as ALPACA
mixing layers
or disabling compression for individual messages - something simply not
possible with byte streams:
Some packet compression methods are known to be susceptible to
attacks, such as BREACH and CRIME. The attack involves injecting
arbitrary data into the packet and observing the resulting compressed
packet size. The observed size potentially reflects correlation
between the arbitrary data and some content that was meant to remain
secret, such as a security token, thereby allowing the attacker to
get at the secret.
Section 2.6 of [RFC7457]
2. Общий формат пакетов, идентификаторов и структур адресов.
Здесь рассматриваются как пакет самого muSCTP внутри "контейнера" бэкенда
транспортного протокола, так и минимально необходимых сопутствующих
протоколов.
2.1. Идентификаторы.
С точки зрения кода, идентификаторы представляют собой просто аргументы
вызовов API, и как таковые не имеют формата, в частности endianness. В
зависимости от туннеля, они могут иметь переменный размер
Таким образом, размеры идентификаторов получаются:
* Packet Counter - 4..19 бит
* Sever instance Number - 6 бит
* Shared Key Id - 6..8 бит
* Random Nonce - битовая строка
* Nfewnce - битовая строка, может отсутствовать
TODO
2.2. Структура адреса.
Как внутри самого muSCTP при переконфигурациях дополнительных путей связи,
так и во вспомогательных мини-протоколах, применяется структура адреса,
представляющая по сути (без align) сериализованный стандартный
struct sockaddr {
uint8_t sa_len; /* total length */
uint8_t sa_family; /* address family */
char sa_data[126]; /* to sockaddr_storage max size */
};
RFC 3493
То есть, 1 байт полной длины (включая саму длину), 1 байт типа адреса, и
собственно данные адреса, зависящие от его типа. В отличие от низкоуровневой
struct sockaddr, в muSCTP в основном применяются более высокоуровневые типы.
TBD CBOR for address #6.9426([ protocol_name: tstr / bstr, address: any, * params: any ])
and UDP port 9426 for tunnel "UDP-Example"
- this must be a range ports to solve INIT/ACK problem
- how many enough, to 9444?
- 11264 seems longer available range and 0x2c00 easier for debug
TBD djbernstein's MinimaLT https://cr.yp.to/tcpip/minimalt-20131031.pdf :
* allows data in first packet given client's ephemeral public key in it and server key in DNS, so may be put a key into CBOR tagged address?
* add puzzle as option to cookie?
* MinimaLT rekeying is indistinguishable from new connection
TBD better name than "tunnel" ?
- "bearer" from TIPC ? "carrier" ?
TBD there is AFI first appeared in RIPv2
<http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml>
do we need to suport it?
- there will be cases when AFI would be NULL, e.g. when address is "http://domain/url"
- probably may be paired with protocol number, to be able to have
not only [1, "UDP", address...]
but also e.g. [[1, 2], "UDP", address...] for both IPv4 and IPv6 ?
- no, not array, coz v4 and v6 will have different addresses
TODO описать дерево в атомах, где их номера
2.3. Мини-протоколы инкапусуляции muSCTP.
Для целей балансировки и поддержки высокой нагрузки как собственно сервер
может состоять из ряда процессов, возможно, расположенных на разных
физических машинах, так и транспортные бэкенды могут работать на разных
машинах, вынося нагрузку по шифровке-расшифровке с сервера:
tunnel mini-protocol
protocols +----------------+ +-------------------+
.----> | UDP backend 1 |------------>| Server Instance 1 |
/ +----------------+-. +-------------------+
/ \
/ +----------------+ \______ +-------------------+
/ __,--> | UDP backend 2 |----------`=>| Server Instance 2 |
| / +----------------+-. ,-->+-------------------+
| | \ /
v v +----------------+ \ / +-------------------+
clients <---> | ICMP backend 1 |----`=/=====>| Server Instance 3 |
^ ^ +----------------+\ / +-------------------+
| \ \ /
\ \ +----------------+__\/ +-------------------+
\ `---> | ICMP backend 2 |---\-=======>| Server Instance 4 |
\ +----------------+ X +-------------------+
\ / \
\ +----------------+ -' \ +-------------------+
`---> | CoAP backend 1 |-------`====>| Server Instance 5 |
+----------------+ +-------------------+
Это требует сохранения информации о том, от какого удаленного клиента был
пакет, т.е. кому в итоге отвечать бэкенду. Кроме того, для балансировки
бэкендам нужно знать загруженность каждого серверного процесса, не упал
ли он, а также серверу загружать в бэкенды новые ключи.
Это общение происходит по UDP, или, если выяснится, что на UDP большие потери
либо необходимо шифрование этих данных из-за физически разнесенных площадок,
по TCP с простым префиксом:
TBD как выполняется балансировка? не мало ли 8 байт Nonce max.? может
выделить отдельный OpType для инита, чтобы расширить Nonce до 16 байт?
- нет, не нужно, пусть бэкенды реальным Nonce дополняют, а этот будет Nfewnce
TODO
2.4. Общий формат тела пакета muSCTP.
Пакет-"тело" внутри "контейнера", основная часть протокола, состоит из
фикисированного заголовка, затем опций переменной длины, и, опционально,
из дополнительных данных, который выполняют роль дополнительного
payload, либо padding для криптографии (либо того и другого вместе).
Особый случай - пакет установления соединения, в нём нет опций, см. ниже.
Опции смоделированы из протокола CoAp, но на самом деле они не заголовки,
как там, а аналог chunk в SCTP.
Фиксированный заголовок на самом деле не совсем фиксированный, а может
быть от 4 до 8 байт. Итого, пакет muSCTP в общем виде:
0 1 2 3
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|TSL|M| Connection Verification Tag |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
. 0/1/2/4 bytes - Transmission Sequence Number (TSN) Base .
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1 1 1 1 1 1 1 1| Padding (if any) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Здесь в фиксированном заголовке:
* TSL - сколько байт поля TSN base реально присутствует в пакете:
00 - 0 байт
01 - 1 байт
10 - 2 байта
11 - 4 байта
* Connection Verification Tag, 30 бит - свой для каждой стороны
соединения, идентификатор соединения и проверка корректности,
из него 1 бит R зарезервирован (и ДОЛЖЕН быть равен 0) на случай
возможного внедрения мультикаста/групповых коммуникаций в будущем
* Transmission Sequence Number (TSN) Base - базовое значение TSN для
дальнейших опций.
protocol is built so that - except optional cryptographic part - only 32-bit
arithmetics is required from underlying hardware, and, in some cases, 64-bit
values in only logical/masking operations, effectively on subfileds, so that
e.g. 64 bits of Message ID split into 32 bits of time in second, 20 bits of
milliseconds, 10 bits stream and 2 bit flags - this could be parsed by
processing two 32-bit words
TBD 7 is too much for constrained, 6 max is enough, and only in c2s direction
TBD combine with M so M=1100 and above?
- then need change SRTLn in ABORT also
TFLL SocketID | non-constrained | constrained
0000 zero | 4 bytes, indicate INIT packet
0000 non-zero | 4 bytes | no CompressRule, as is
0001 any | 5 bytes | CompressRule=1
0010 any | 6 bytes | CompressRule=2
0011 any | 7 bytes | CompressRule=3
0100 zero | Prohibited due to E / zero compression to T23
0100 non-zero | 8 bytes | CompressRule=4
0101 any | 10 bytes | CompressRule=5
0110 any | 12 bytes | CompressRule=6
0111 any | 14 bytes | CompressRule=7
1000 non-zero | 16 bytes | CompressRule=8
1000 zero | 4 bytes, indicate error flag (ABORT packet)
1001 any | 20 bytes | CompressRule=9
1010 any | Reserved | CompressRule=10
1011 any | Reserved | CompressRule=11
11xx any | Reserved for Multicast / Group Communications
TBD what to do with E / zero compression to T23 ? Reserve for another packet
type or just prohibit?..
TBD move tag len to tunnel format so 11 compression rules could be used?
rule does not need CBAR but can be simple CBOR: uint=copy N bytes from pkt,
bstr=add literal bytes, negative int for bits?
TBD full BPF for bit fields? but this is not simple for constrained devices...
- [Aug 2024] well, we target entire spectrum sizing from very constrained to
very highload, so just offer several options: constrained could use
something like GHC/LZF, more capable could accept BPF64 - so this should
be one of BPF64 design goals
TBD split Connection Tag to separate Host ID, if IPnh provides us with it
- and for constrained sizes even Host IDs Sum instead of full pair
- 17.09.24 also add IPnh tunnel addresses, either in INIT or backends?
- 18.09.24 see fragmentation issues (for this day), so if ever ConnectionTag
considered to be longer than 4 bytes, only alternatives are 8 and 12 bytes
Поле TSN имеет то же значение, что и в SCTP - номер блока данных при передаче
данных с подтверждением, имеет полный "виртуальный" размер 32 бита, и
подчиняется тем же правилам арифметики по модулю 32, что и в TCP и в SCTP.
Однако, поскольку тратить 4 байта на TSN в каждом чанке расточительно при
очень малых размерах пакета, если опции с TSN вообще есть в пакете, то
передается базовое TSN, а в самих опциях - только короткая дельта (они не
могут быть опущены последовательной нумерации из-за ретрансмиссий при
потерянныъ пакетах, т.е. "дырках").
И кроме того, в ряде случаев 32-битный TSN Base подвергается дополнительной
компрессии по методу, похожему на DCCP и протокол QUIC от Google.
2.4.1. TSN Base and it's compression.
TBD от сервера младшие биты про packet stamp:
00 - fresh and timely answer to this packet id
01 - packet stamp seen first time, but ACK delayed
10 - ??? packet id non-first time, retransmitted
11 - packet id reused for server next data
TBD вынести их в TSL? но тогда
TBD после смены адреса сервер шлёт меньше - защита от спуфа/DDoS
TBD Ack Delay в SACK ?
TBD Stateless Reset Token?
https://datatracker.ietf.org/doc/html/draft-trammell-plus-statefulness-04 :
4.3.1. Authenticated Stop Signaling
Additionally, the stop and stop confirmation signals could be
designed to authenticate themselves. Each endpoint could reveal a
stop hash during the initial association, which is the result of a
chosen cryptographic hash function applied to a stop token which that
endpoint keeps secret. An endpoint wishing to end the association
then reveals the stop token, which can be verified both by the far
endpoint and devices on path which have cached the stop hash to be
authentic.
HEARTBEAT MUST be at least twice per tv_sec bitwitdth interval - coz clock
drift
В случае относительно низкой скорости (в пакетах) передачи данных, на низких
MTU используется компрессия Transmission Sequence Number (TSN) Base -
передача только одного или двух его младших байт из полных четырех. В отличие
от QUIC, где номер пакета только монотонно растёт с нуля до 2^62 and don't
wraps, у нас, в виду отсутствия места, классическая схема со всего лишь 32
битами и их переиспользованием, поэтому соответствующий алгоритм компресии
номера из QUIC не может быть применён в чистом виде. Для этого приходится
применять вспомогательное средство из заголовка пакета, причем, поскольку
передача данных может вестись одновременно по нескольким путям, а TSN are
общие на всю ассоциацию, то Packet Counter не может быть использован,
а только лишь Packet Stamp.
Пусть "tick" - гранулярность Packet Stamp, предоставляемая тунгейтом
(например, 1 миллисекунда или 125 мс), а Cumulative TSN Ack есть номер,
ниже которого все TSN получены (возможны только дупликаты). Тогда, поскольку
нет никакого вреда в том, чтобы передать TSN Base длиннее теоретически
требовавшегося (кроме уменьшение доступного места в пакете), отправитель и
получатель следуют нижеизложенным правилам.
Отправитель:
S1) все TSN с номерами, близкими к концу или началу на размер более меньшего
участка + cwnd, передаются увеличенными. Например, TSN с 0x00000000 по
0x00010001 и c 0xfffeffff по 0xffffffff передаются всегда как 4 байта, а
все TSN c 0xhhhh0000 по 0xhhhh0101 и с 0xhhhhfeff по 0xhhhhffff - не менее
чем 2 байта, если cwnd на соответствующие моменты составлял 1;
S2) при каждом увеличении на следующий тик, первый пакет с ним (по каждому из
путей) всегда передается с полным 4-байтным TSN;
S3) в случае, если это ретрансмит какого-либо пакета не "как есть",
а пересборкой из нескольких чанков, всегда MUST применяется 4-байтный TSN;
S4) каждое определенное число пакетов с уменьшенным TSN Base передается на
один размерный шаг больше: оно составляет каждый пакет из 16 для
1-байтных TSN Base и каждые 1024 для 2-байтных - for simplicity,
implementations MAY test if TSN divisble by 16 for 2-byte and by 1024
for 4-byte [Rationale: packet loss ~3% дает примерно каждый 32-й пакет, на
случай, если потеряны именно они, увеличим число];
S5) наконец, применяется алгоритм из QUIC: из TSN Base готовящегося к отправке
пакета вычитается текущий Cumulative TSN Ack получателя, и число байт
TSN Base должно вмещать более чем два этих числа. Note that comparison
here is strict: difference 127 is still 1 byte, but 128 raises 2 bytes.
Получатель же, в случае получения неполного TSN Base, применяет
модифицированную процедуру из DCCP с псевдокодом:
procedure Extend_Sequence_Number(S, REF, width)
/* S is a width-bit (8 or 16) sequence number from the packet header.
* REF is the relevant full 32-bit reference sequence number
*/
Set REF_low := low width bits of REF
Set REF_hi := high (32-width) bits of REF
If REF_low (<) S /* circular comparison mod 2^width */
and S |<| REF_low, /* conventional, non-circular comparison */
Return (( (REF_hi + 1) mod 2^(32-width) ) << width) | S
Otherwise, if S (<) REF_low and REF_low |<| S,
Return (( (REF_hi - 1) mod 2^(32-width) ) << width) | S
Otherwise,
Return (REF_hi << width) | S
Основной проблемой здесь является нахождение полного 32-битного REF, на
основе которого вычисляется полный TSN Base текущего пакета. DCCP and QUIC
используют в качестве него номер самого последнего полученного пакета.
В DCCP проблема маловероятна к достижимости в реальном мире ввиду широкого
размера номера: 2^23 пакетов стандартного Ethernet MTU размера 1500 байт
потребуют 100 Gbit/s, что является труднодостижимым размером cwnd даже
спустя 15 лет после опубликования спецификации DCCP. QUIC же has design flaw
и игнорирует проблему, неявным образом полагаясь на TLS в части replay
attacks and out-of-order packets - в случае ошибочного определения номера
пакета, используемого для IV/nonce [RFC 9001, Section 5.3, 5.5], будет получен
неверный AEAD и пакет будет отброшен, но с криптографическими затратами. Это
не подходит для протокола, который, ввиду поддержки ограниченный устройств,
имеет режим работы без шифрования, а также производит шифрование пакетов на
более низком уровне, не зависящем от TSN Base.
Суть проблемы: предположим, что мы получаем пакет из прошлого с 1-байтным
TSN Base, который вполне укладывается в окно с соседним "свежим" 1-байтным
TSN Base. В этом случае он будет декодирован в неверный номер, и произойдет
повреждение потока данных. Вариант включения полного TSN Base в подпись
передаваемого пакета (без передачи его самого) позволил бы избежать проблемы
способом QUIC, но потребовал бы криптографических затрат, что неприемлемо
для ограниченных устройств (можно приравнивать к DoS-атаке).
Предположим, для простоты рассуждений, что мы имеем только сокращенные
в 8 бит и полные в 16 бит, считая каждое полученное 16-битной значение
референсным. Тогда процедура Extend_Sequence_Number будет давать корректные
результаты для значений в интервале [-128..+127] от референсного. Тогда нам
необходимо отсеять значения от -128 и ниже. Отсюда вытекает, как минимум,
что кратность передачи референсных значений должна быть делителем 128, т.е.
составлять 64 или менее. Далее, правило S5 гарантирует нам, что уменьшенных
TSN Base будет отправлено менее 128 от нашего Cumulative TSN Ack, поэтому
можно отсекать все пакеты с таймштампом строго меньшим, чем был у пакета
с TSN, равным текущему Cumulative TSN Ack, но здесь возникает subtle
problem: как быть, если пакет из прошлого приходит с тем же самым tick, что
у Cumulative TSN Ack, вследствие плохой гранулярности таймштампов?
Рассмотрим гипотетическую ситуацию в сети, возникшую на линке с 3 битами на
доли секунды, т.е. таймером 8 Гц, в стабильных до того момента условиях при
cwnd=254:
Sender Receiver
| |
| S=123 from tick 0, will also dup ------> | decode OK,
-- tick 1/8 ----+ | Nagle timer
| S=124 -- will also dup ----------------> | started
| S=125..128 ----------------------------> |
| S=125 -- DUP IN NET ---, .------- | send ACK
| S=126 -- DUP IN NET ---.\ / |
| S=127 -- DUP IN NET -----\ / |
| S=128 now Cumul Ack <-----\--' |
| S=129 ----. \ |
-- tick 2/8 ----+ \ \ |
| S=130..253 \ \ |
| cwnd allows >-- (X) LOST! \ |
| sending / \ |
| \ |
| TSN=254 Reference ---------------\-----> | OK, Nagle
| S=255 last allowed by S5 --------\----> | decode OK
| (T3-rtx fires, cwnd halves, stop) `---> | ???
Пусть на рисунке отправитель имел последний подтвержденный TSN=128, и окно
позволило отправить ему пакеты с номерами по 255 включительно, из которых
TSN=254 имел полную ширину и был референсным, а пакеты со 129 по 253 были
потеряны. Теперь, вследствие проблем в сети или действий атакующего, после
пакетов 254 и 255 получателю прибывают дубликаты пакетов с TSN=123 по
TSN=127. Пакет с TSN=123 был из другого тика, 0, меньше, чем тик=1
последнего подтвержденного пакета с TSN=128, и был отброшен. Применим
процедуру Extend_Sequence_Number(S, 254, 8) для S=124..127.
Имеем REF_hi=0, REF_low = 254, для аргументов следует:
S=124: REF_low (<) S: true
S |<| REF_low: true
---> return ((0+1)<<8) | 124 => TSN=380
S=125: REF_low (<) S:true
S |<| REF_low: true
---> return ((0+1)<<8) | 125 => TSN=381
S=126: REF_low (<) S: false
S (<) REF_low: false
---> return ( (0) <<8) | 126 => TSN=126
S=127: REF_low (<) S: false
S (<) REF_low: true
REF_low |<| S: false
---> return ( (0) <<8) | 127 => TSN=127
На этом примере мы видим, что, если пакеты c S=124 и S=125 отправлялись
в тот же тик, они не будут отброшены сравнением строгого неравенства по
времени, в отличие от S=123. Не помогло бы и сравнение "меньше или равно"
с TSN=128, поскольку, как мы видим, если S=129 отправляется в тот же тик, он
вполне ожидаем и валиден. Правило S2 позволило бы исключить из этого списка
пакет с TSN=124 как первый в тик (он был бы передан референсным), но всё еще
остается проблема со 125-м. Нельзя здесь и иметь ожидания по поводу размера
окна: в TSN=128 отправитель мог передать LINK_INFO с большим cwnd, так что
вполне ожидаемы TSN вплоть до 382.
Из других полей имеем решение: получателю сохранять так же и Packet Counter
пакета, на который отправлялся Cumulative TSN Ack, и сравнивать с ним пакеты
в том же тике, что и Cumulative TSN Ack - тогда более старые могут быть
отброшены. Здесь следует подчеркнуть, что Packet Counter является отдельным
счетчиком для каждого линка, а не глобальным, поэтому, будучи вполне
применимым в случае единственного пути, вызывает вопросы. Однако эта
проблема вполне разрешима, если считать, что дубликаты пакетов в сети могут
появиться только по тому же самому пути/паре адресов, на которой они
изначально были переданы. Отсюда, в том числе, и вытекает правило S3: если
ретрансмиты происходят по другому пути, в них должен быть полный TSN, и
Packet Counter другого пути будет в данном случае неважен.
Note: it's HALF of Packet Counter per tick permitted! as circular comparison
Receiver Path 1 Sender Receiver Path 2
| ... | |
| |---- S=10 --------------> |
|--- SACK=10 ------------> | |
ms=125 -+ | +- tick 1/8
| <-------------- TSN=11 --| |
| <-------------- TSN=12 --| |
| |---- S=13 --------------> |
|--- SACK=12 ------------> | |
| | <------------- SACK=13 --|
ms=126 -+ | |
| <-------------- TSN=14 --| |
| <-------------- TSN=15 --| |
| |---- S=16 --. |
|--- SACK=15 ------------> | \ |
| | \ |