From b6aef3d293d6347fb0e2c23d79ab0ab3c03131f8 Mon Sep 17 00:00:00 2001 From: Petr Zhizhin Date: Wed, 13 Nov 2024 02:22:25 +0100 Subject: [PATCH] review fixes --- x/configurl/doc.go | 7 ++++--- x/disorder/stream_dialer.go | 14 +++++++------- x/disorder/writer.go | 18 ++++++++++-------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/x/configurl/doc.go b/x/configurl/doc.go index 29c7aa70..cea90498 100644 --- a/x/configurl/doc.go +++ b/x/configurl/doc.go @@ -103,7 +103,7 @@ For more details, refer to [github.com/Jigsaw-Code/outline-sdk/transport/tlsfrag tlsfrag:[LENGTH] -Disorder transport (streams only, package [github.com/Jigsaw-Code/outline-sdk/x/disorder]) +Packet reordering (streams only, package [github.com/Jigsaw-Code/outline-sdk/x/disorder]) The disorder strategy sends TCP packets out of order by manipulating the socket's Time To Live (TTL) or Hop Limit. It temporarily sets the TTL to a low @@ -126,11 +126,12 @@ Packet splitting - To split outgoing streams on bytes 2 and 123, you can use: split:2|split:123 -Disorder transport - Send some of the packets out of order +Disorder transport - Send some of the packets out of order: disorder:0|split:123 -Split at position 123, then send packet 0 of 123 bytes (from splitting) out of order. The network filter will first receive packet 1, only then packet 0. +Split at position 123, then send packet 0 of 123 bytes (from splitting) out of order. The network filter will first receive packet 1, only then packet 0. This +is done by setting the hop limit for the write to 1, and then restoring it. It will be sent with its original hop limit on retransmission. Evading DNS and SNI blocking - You can use Cloudflare's DNS-over-HTTPS to protect against DNS disruption. The DoH resolver cloudflare-dns.com is accessible from any cloudflare.net IP, so you can specify the address to avoid blocking diff --git a/x/disorder/stream_dialer.go b/x/disorder/stream_dialer.go index a280ee60..8bd55a36 100644 --- a/x/disorder/stream_dialer.go +++ b/x/disorder/stream_dialer.go @@ -32,13 +32,13 @@ type disorderDialer struct { var _ transport.StreamDialer = (*disorderDialer)(nil) // NewStreamDialer creates a [transport.StreamDialer] -// It work almost the same as the other split dialer, however, it also manipulates socket TTL: -// * Before sending the first prefixBytes TTL is set to 1 -// * This packet is dropped somewhere in the network and never reaches the server -// * TTL is restored -// * The next part of data is sent normally -// * Server notices the lost fragment and requests re-transmission -// Currently this only works with Linux kernel (for Windows/Mac a different implementation is required) +// It work like this: +// * Wait for disorderPacketN'th call to Write. All Write requests before and after the target packet are written normally. +// * Send the disorderPacketN'th packet with TTL == 1. +// * This packet is dropped somewhere in the network and never reaches the server. +// * TTL is restored. +// * The next part of data is sent normally. +// * Server notices the lost fragment and requests re-transmission of lost packet. func NewStreamDialer(dialer transport.StreamDialer, disorderPacketN int) (transport.StreamDialer, error) { if dialer == nil { return nil, errors.New("argument dialer must not be nil") diff --git a/x/disorder/writer.go b/x/disorder/writer.go index b6dc1d4c..0abe4250 100644 --- a/x/disorder/writer.go +++ b/x/disorder/writer.go @@ -29,7 +29,7 @@ type disorderWriter struct { var _ io.Writer = (*disorderWriter)(nil) -// Setting number of hops to 1 will lead to data to get lost on host +// Setting number of hops to 1 will lead to data to get lost on host. var disorderHopN = 1 func NewWriter(conn io.Writer, tcpOptions sockopt.TCPOptions, runAtPacketN int) io.Writer { @@ -54,11 +54,11 @@ func (w *disorderWriter) Write(data []byte) (written int, err error) { } defer func() { - // The packet with low hop limit was sent - // Make next calls send data normally + // The packet with low hop limit was sent. + // Make next calls send data normally. // - // The packet with the low hop limit will get resent by the kernel later - // The network filters will receive data out of order + // The packet with the low hop limit will get resent by the kernel later. + // The network filters will receive data out of order. err = w.tcpOptions.SetHopLimit(defaultHopLimit) if err != nil { err = fmt.Errorf("failed to set the hop limit error %d: %w", defaultHopLimit, err) @@ -66,11 +66,13 @@ func (w *disorderWriter) Write(data []byte) (written int, err error) { }() } - // The packet will get lost at the first send, since the hop limit is too low + // The packet will get lost at the first send, since the hop limit is too low. n, err := w.conn.Write(data) - // TODO: Wait for queued data to be sent by the kernel to the socket + // TODO: Wait for queued data to be sent by the kernel to the socket. - w.writesToDisorder -= 1 + if w.writesToDisorder > -1 { + w.writesToDisorder -= 1 + } return n, err }