Pārlūkot izejas kodu

Add separate handshake timeout

This PR adds a new setting to the config: `network.timeout`. This setting
defines a time period during which all handshake procedures and
ceremonies must be completed. If not - connection is aborted. This
should help in situations when connection is established but client
cannot continue for some reason (for example, RST sent by some middle box).
tags/v2.2.8^2^2
9seconds 4 nedēļas atpakaļ
vecāks
revīzija
eb564936c7

+ 1
- 3
example.config.toml Parādīt failu

@@ -205,13 +205,11 @@ proxies = [
205 205
 # means a timeout on pumping data between sockset when nothing is
206 206
 # happening.
207 207
 #
208
-# please be noticed that handshakes have no timeouts intentionally. You can
209
-# find a reasoning here:
210
-# https://www.ndss-symposium.org/wp-content/uploads/2020/02/23087-paper.pdf
211 208
 [network.timeout]
212 209
 tcp = "5s"
213 210
 http = "10s"
214 211
 idle = "5m"
212
+handshake = "10s"
215 213
 
216 214
 # mtg has to mimic real websites. It does not mean domain fronting, it also
217 215
 # means that traffic characteristics should be similar to real world traffic.

+ 1
- 0
internal/cli/run_proxy.go Parādīt failu

@@ -263,6 +263,7 @@ func runProxy(conf *config.Config, version string) error { //nolint: funlen
263 263
 		AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false),
264 264
 		TolerateTimeSkewness:     conf.TolerateTimeSkewness.Value,
265 265
 		IdleTimeout:              conf.Network.Timeout.Idle.Get(mtglib.DefaultIdleTimeout),
266
+		HandshakeTimeout:         conf.Network.Timeout.Handshake.Get(mtglib.DefaultHandshakeTimeout),
266 267
 
267 268
 		DoppelGangerURLs:    doppelGangerURLs,
268 269
 		DoppelGangerPerRaid: conf.Defense.Doppelganger.Repeats.Get(mtglib.DoppelGangerPerRaid),

+ 4
- 3
internal/config/config.go Parādīt failu

@@ -60,9 +60,10 @@ type Config struct {
60 60
 	} `json:"defense"`
61 61
 	Network struct {
62 62
 		Timeout struct {
63
-			TCP  TypeDuration `json:"tcp"`
64
-			HTTP TypeDuration `json:"http"`
65
-			Idle TypeDuration `json:"idle"`
63
+			TCP       TypeDuration `json:"tcp"`
64
+			HTTP      TypeDuration `json:"http"`
65
+			Idle      TypeDuration `json:"idle"`
66
+			Handshake TypeDuration `json:"handshake"`
66 67
 		} `json:"timeout"`
67 68
 		DOHIP   TypeIP         `json:"dohIp"`
68 69
 		DNS     TypeDNSURI     `json:"dns"`

+ 4
- 3
internal/config/parse.go Parādīt failu

@@ -55,9 +55,10 @@ type tomlConfig struct {
55 55
 	} `toml:"defense" json:"defense,omitempty"`
56 56
 	Network struct {
57 57
 		Timeout struct {
58
-			TCP  string `toml:"tcp" json:"tcp,omitempty"`
59
-			HTTP string `toml:"http" json:"http,omitempty"`
60
-			Idle string `toml:"idle" json:"idle,omitempty"`
58
+			TCP       string `toml:"tcp" json:"tcp,omitempty"`
59
+			HTTP      string `toml:"http" json:"http,omitempty"`
60
+			Idle      string `toml:"idle" json:"idle,omitempty"`
61
+			Handshake string `toml:"handshake" json:"handshake,omitempty"`
61 62
 		} `toml:"timeout" json:"timeout,omitempty"`
62 63
 		DOHIP   string   `toml:"doh-ip" json:"dohIp,omitempty"`
63 64
 		DNS     string   `toml:"dns" json:"dns,omitempty"`

+ 4
- 0
mtglib/init.go Parādīt failu

@@ -81,6 +81,10 @@ const (
81 81
 	// avoid racing with MTProto ping_delay_disconnect (~60s interval).
82 82
 	DefaultIdleTimeout = 5 * time.Minute
83 83
 
84
+	// DefaultHandshakeTimeout defines a time period during which the
85
+	// all handshake ceremonies must be completed.
86
+	DefaultHandshakeTimeout = 10 * time.Second
87
+
84 88
 	// DefaultTolerateTimeSkewness is a default timeout for time skewness on a
85 89
 	// faketls timeout verification.
86 90
 	DefaultTolerateTimeSkewness = 3 * time.Second

+ 0
- 5
mtglib/internal/tls/fake/client_side.go Parādīt failu

@@ -40,11 +40,6 @@ func ReadClientHello(
40 40
 	hostname string,
41 41
 	tolerateTimeSkewness time.Duration,
42 42
 ) (*ClientHello, error) {
43
-	if err := conn.SetReadDeadline(time.Now().Add(ClientHelloReadTimeout)); err != nil {
44
-		return nil, fmt.Errorf("cannot set read deadline: %w", err)
45
-	}
46
-	defer conn.SetReadDeadline(resetDeadline) //nolint: errcheck
47
-
48 43
 	// This is how FakeTLS is organized:
49 44
 	//  1. We create sha256 HMAC with a given secret
50 45
 	//  2. We dump there a whole TLS frame except of the fact that random

+ 0
- 6
mtglib/internal/tls/fake/client_side_snapshot_test.go Parādīt failu

@@ -12,7 +12,6 @@ import (
12 12
 	"github.com/9seconds/mtg/v2/mtglib"
13 13
 	"github.com/9seconds/mtg/v2/mtglib/internal/tls/fake"
14 14
 	"github.com/stretchr/testify/assert"
15
-	"github.com/stretchr/testify/mock"
16 15
 	"github.com/stretchr/testify/require"
17 16
 	"github.com/stretchr/testify/suite"
18 17
 )
@@ -71,11 +70,6 @@ func (suite *ParseClientHelloSnapshotTestSuite) makeConn(data []byte) *parseClie
71 70
 		readBuf: readBuf,
72 71
 	}
73 72
 
74
-	connMock.
75
-		On("SetReadDeadline", mock.AnythingOfType("time.Time")).
76
-		Twice().
77
-		Return(nil)
78
-
79 73
 	return connMock
80 74
 }
81 75
 

+ 1
- 25
mtglib/internal/tls/fake/client_side_test.go Parādīt failu

@@ -4,7 +4,6 @@ import (
4 4
 	"bytes"
5 5
 	"encoding/binary"
6 6
 	"encoding/json"
7
-	"errors"
8 7
 	"io"
9 8
 	"os"
10 9
 	"testing"
@@ -14,7 +13,6 @@ import (
14 13
 	"github.com/9seconds/mtg/v2/mtglib"
15 14
 	"github.com/9seconds/mtg/v2/mtglib/internal/tls"
16 15
 	"github.com/9seconds/mtg/v2/mtglib/internal/tls/fake"
17
-	"github.com/stretchr/testify/mock"
18 16
 	"github.com/stretchr/testify/require"
19 17
 	"github.com/stretchr/testify/suite"
20 18
 )
@@ -53,11 +51,6 @@ func (suite *ParseClientHelloTestSuite) SetupTest() {
53 51
 	suite.connMock = &parseClientHelloConnMock{
54 52
 		readBuf: suite.readBuf,
55 53
 	}
56
-
57
-	suite.connMock.
58
-		On("SetReadDeadline", mock.AnythingOfType("time.Time")).
59
-		Twice().
60
-		Return(nil)
61 54
 }
62 55
 
63 56
 func (suite *ParseClientHelloTestSuite) TearDownTest() {
@@ -69,23 +62,11 @@ type ParseClientHello_TLSHeaderTestSuite struct {
69 62
 }
70 63
 
71 64
 func (suite *ParseClientHello_TLSHeaderTestSuite) TestEmpty() {
72
-	suite.connMock.ExpectedCalls = []*mock.Call{}
73
-	suite.connMock.
74
-		On("SetReadDeadline", mock.AnythingOfType("time.Time")).
75
-		Once().
76
-		Return(errors.New("fail"))
77
-
78 65
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
79
-	suite.ErrorContains(err, "fail")
66
+	suite.ErrorContains(err, "cannot read client hello")
80 67
 }
81 68
 
82 69
 func (suite *ParseClientHello_TLSHeaderTestSuite) TestNothing() {
83
-	suite.connMock.ExpectedCalls = []*mock.Call{}
84
-	suite.connMock.
85
-		On("SetReadDeadline", mock.AnythingOfType("time.Time")).
86
-		Twice().
87
-		Return(nil)
88
-
89 70
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
90 71
 	suite.ErrorIs(err, io.EOF)
91 72
 }
@@ -478,11 +459,6 @@ func (s *ParseClientHelloFragmentedTestSuite) makeConn(data []byte) *parseClient
478 459
 		readBuf: readBuf,
479 460
 	}
480 461
 
481
-	connMock.
482
-		On("SetReadDeadline", mock.AnythingOfType("time.Time")).
483
-		Twice().
484
-		Return(nil)
485
-
486 462
 	return connMock
487 463
 }
488 464
 

+ 1
- 10
mtglib/internal/tls/fake/init.go Parādīt failu

@@ -2,15 +2,6 @@ package fake
2 2
 
3 3
 import (
4 4
 	"errors"
5
-	"time"
6 5
 )
7 6
 
8
-const (
9
-	ClientHelloReadTimeout = 5 * time.Second
10
-)
11
-
12
-var (
13
-	resetDeadline time.Time
14
-
15
-	ErrBadDigest = errors.New("incorrect client random")
16
-)
7
+var ErrBadDigest = errors.New("incorrect client random")

+ 12
- 0
mtglib/proxy.go Parādīt failu

@@ -28,6 +28,7 @@ type Proxy struct {
28 28
 	allowFallbackOnUnknownDC    bool
29 29
 	tolerateTimeSkewness        time.Duration
30 30
 	idleTimeout                 time.Duration
31
+	handshakeTimeout            time.Duration
31 32
 	domainFrontingPort          int
32 33
 	domainFrontingIP            string
33 34
 	domainFrontingProxyProtocol bool
@@ -66,6 +67,11 @@ func (p *Proxy) ServeConn(conn essentials.Conn) {
66 67
 	ctx := newStreamContext(p.ctx, p.logger, conn)
67 68
 	defer ctx.Close()
68 69
 
70
+	if err := ctx.clientConn.SetDeadline(time.Now().Add(p.handshakeTimeout)); err != nil {
71
+		ctx.logger.WarningError("cannot set handshake timeout", err)
72
+		return
73
+	}
74
+
69 75
 	stop := context.AfterFunc(ctx, func() {
70 76
 		ctx.Close()
71 77
 	})
@@ -97,6 +103,11 @@ func (p *Proxy) ServeConn(conn essentials.Conn) {
97 103
 		return
98 104
 	}
99 105
 
106
+	if err := ctx.clientConn.SetDeadline(time.Time{}); err != nil {
107
+		ctx.logger.WarningError("cannot set deadline", err)
108
+		return
109
+	}
110
+
100 111
 	if err := p.doTelegramCall(ctx); err != nil {
101 112
 		ctx.logger.WarningError("cannot dial to telegram", err)
102 113
 		return
@@ -346,6 +357,7 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) {
346 357
 		domainFrontingIP:         opts.DomainFrontingIP,
347 358
 		tolerateTimeSkewness:     opts.getTolerateTimeSkewness(),
348 359
 		idleTimeout:              opts.getIdleTimeout(),
360
+		handshakeTimeout:         opts.getHandshakeTimeout(),
349 361
 		allowFallbackOnUnknownDC: opts.AllowFallbackOnUnknownDC,
350 362
 		telegram:                 tg,
351 363
 		doppelGanger: doppel.NewGanger(

+ 14
- 0
mtglib/proxy_opts.go Parādīt failu

@@ -70,6 +70,12 @@ type ProxyOpts struct {
70 70
 	// This is an optional setting.
71 71
 	IdleTimeout time.Duration
72 72
 
73
+	// HandshakeTimeout is a timeout during which all handshake ceremonies must
74
+	// be completed, otherwise this process will be aborted
75
+	//
76
+	// This is an optional setting.
77
+	HandshakeTimeout time.Duration
78
+
73 79
 	// TolerateTimeSkewness is a time boundary that defines a time range where
74 80
 	// faketls timestamp is acceptable.
75 81
 	//
@@ -215,6 +221,14 @@ func (p ProxyOpts) getPreferIP() string {
215 221
 	return p.PreferIP
216 222
 }
217 223
 
224
+func (p ProxyOpts) getHandshakeTimeout() time.Duration {
225
+	if p.HandshakeTimeout == 0 {
226
+		return DefaultHandshakeTimeout
227
+	}
228
+
229
+	return p.HandshakeTimeout
230
+}
231
+
218 232
 func (p ProxyOpts) getIdleTimeout() time.Duration {
219 233
 	if p.IdleTimeout == 0 {
220 234
 		return DefaultIdleTimeout

Notiek ielāde…
Atcelt
Saglabāt