Explorar el Código

Merge pull request #16 from dolonet/sync-upstream-handshake-grease

Sync upstream: handshake timeout, GREASE cipher fix, no-default TLS cipher
pull/455/head
dolonet hace 4 semanas
padre
commit
bd5ad0aaf8
No account linked to committer's email address

+ 1
- 3
example.config.toml Ver fichero

220
 # means a timeout on pumping data between sockset when nothing is
220
 # means a timeout on pumping data between sockset when nothing is
221
 # happening.
221
 # happening.
222
 #
222
 #
223
-# please be noticed that handshakes have no timeouts intentionally. You can
224
-# find a reasoning here:
225
-# https://www.ndss-symposium.org/wp-content/uploads/2020/02/23087-paper.pdf
226
 [network.timeout]
223
 [network.timeout]
227
 tcp = "5s"
224
 tcp = "5s"
228
 http = "10s"
225
 http = "10s"
229
 idle = "5m"
226
 idle = "5m"
227
+handshake = "10s"
230
 
228
 
231
 # mtg has to mimic real websites. It does not mean domain fronting, it also
229
 # mtg has to mimic real websites. It does not mean domain fronting, it also
232
 # means that traffic characteristics should be similar to real world traffic.
230
 # means that traffic characteristics should be similar to real world traffic.

+ 1
- 0
internal/cli/run_proxy.go Ver fichero

264
 		AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false),
264
 		AllowFallbackOnUnknownDC: conf.AllowFallbackOnUnknownDC.Get(false),
265
 		TolerateTimeSkewness:     conf.TolerateTimeSkewness.Value,
265
 		TolerateTimeSkewness:     conf.TolerateTimeSkewness.Value,
266
 		IdleTimeout:              conf.Network.Timeout.Idle.Get(mtglib.DefaultIdleTimeout),
266
 		IdleTimeout:              conf.Network.Timeout.Idle.Get(mtglib.DefaultIdleTimeout),
267
+		HandshakeTimeout:         conf.Network.Timeout.Handshake.Get(mtglib.DefaultHandshakeTimeout),
267
 
268
 
268
 		DoppelGangerURLs:    doppelGangerURLs,
269
 		DoppelGangerURLs:    doppelGangerURLs,
269
 		DoppelGangerPerRaid: conf.Defense.Doppelganger.Repeats.Get(mtglib.DoppelGangerPerRaid),
270
 		DoppelGangerPerRaid: conf.Defense.Doppelganger.Repeats.Get(mtglib.DoppelGangerPerRaid),

+ 4
- 3
internal/config/config.go Ver fichero

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

+ 4
- 3
internal/config/parse.go Ver fichero

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

+ 4
- 0
mtglib/init.go Ver fichero

81
 	// avoid racing with MTProto ping_delay_disconnect (~60s interval).
81
 	// avoid racing with MTProto ping_delay_disconnect (~60s interval).
82
 	DefaultIdleTimeout = 5 * time.Minute
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
 	// DefaultTolerateTimeSkewness is a default timeout for time skewness on a
88
 	// DefaultTolerateTimeSkewness is a default timeout for time skewness on a
85
 	// faketls timeout verification.
89
 	// faketls timeout verification.
86
 	DefaultTolerateTimeSkewness = 3 * time.Second
90
 	DefaultTolerateTimeSkewness = 3 * time.Second

+ 27
- 13
mtglib/internal/tls/fake/client_side.go Ver fichero

6
 	"crypto/sha256"
6
 	"crypto/sha256"
7
 	"crypto/subtle"
7
 	"crypto/subtle"
8
 	"encoding/binary"
8
 	"encoding/binary"
9
+	"errors"
9
 	"fmt"
10
 	"fmt"
10
 	"io"
11
 	"io"
11
 	"net"
12
 	"net"
20
 	// record_type(1) + version(2) + size(2) + handshake_type(1) + uint24_length(3) + client_version(2)
21
 	// record_type(1) + version(2) + size(2) + handshake_type(1) + uint24_length(3) + client_version(2)
21
 	RandomOffset = 1 + 2 + 2 + 1 + 3 + 2
22
 	RandomOffset = 1 + 2 + 2 + 1 + 3 + 2
22
 
23
 
24
+	// https://datatracker.ietf.org/doc/html/rfc8701#name-grease-values
25
+	// https://medium.com/asecuritysite-when-bob-met-alice/in-cybersecurity-what-is-grease-9f8850558dea
26
+	GreaseMask      = 0x0f0f
27
+	GreaseValueType = 0x0a0a
28
+
23
 	sniDNSNamesListType = 0
29
 	sniDNSNamesListType = 0
24
 )
30
 )
25
 
31
 
26
 var (
32
 var (
27
 	emptyRandom = [RandomLen]byte{}
33
 	emptyRandom = [RandomLen]byte{}
28
 	extTypeSNI  = [2]byte{}
34
 	extTypeSNI  = [2]byte{}
35
+
36
+	ErrCannotFindCipher = errors.New("cannot find a cipher")
29
 )
37
 )
30
 
38
 
31
 type ClientHello struct {
39
 type ClientHello struct {
64
 	hostname string,
72
 	hostname string,
65
 	tolerateTimeSkewness time.Duration,
73
 	tolerateTimeSkewness time.Duration,
66
 ) (*ReadClientHelloResult, error) {
74
 ) (*ReadClientHelloResult, error) {
67
-	if err := conn.SetReadDeadline(time.Now().Add(ClientHelloReadTimeout)); err != nil {
68
-		return nil, fmt.Errorf("cannot set read deadline: %w", err)
69
-	}
70
-	defer conn.SetReadDeadline(resetDeadline) //nolint: errcheck
71
-
72
 	clientHelloCopy, handshakeReader, err := parseClientHello(conn)
75
 	clientHelloCopy, handshakeReader, err := parseClientHello(conn)
73
 	if err != nil {
76
 	if err != nil {
74
 		return nil, fmt.Errorf("cannot read client hello: %w", err)
77
 		return nil, fmt.Errorf("cannot read client hello: %w", err)
155
 
158
 
156
 	cipherSuiteLen := int64(binary.BigEndian.Uint16(header[:]))
159
 	cipherSuiteLen := int64(binary.BigEndian.Uint16(header[:]))
157
 
160
 
158
-	// we do not care about picking up any cipher. we pick the first one,
159
-	// so it is always should be present.
160
-	if _, err := io.ReadFull(r, header[:]); err != nil {
161
-		return nil, fmt.Errorf("cannot read first cipher suite: %w", err)
162
-	}
161
+	// Pick the first non-GREASE cipher suite from the list.
162
+	// Real TLS servers never select GREASE values (RFC 8701, pattern 0x?a?a),
163
+	// so echoing them back is a trivial DPI fingerprint.
164
+	// cipherSuiteLen is in bytes; each cipher suite is 2 bytes.
165
+	for range cipherSuiteLen / 2 {
166
+		if _, err := io.ReadFull(r, header[:]); err != nil {
167
+			return nil, fmt.Errorf("cannot read cipher suite: %w", err)
168
+		}
169
+
170
+		if hello.CipherSuite != 0 {
171
+			// do not forget we have to scan until the end
172
+			continue
173
+		}
163
 
174
 
164
-	hello.CipherSuite = binary.BigEndian.Uint16(header[:])
175
+		if cs := binary.BigEndian.Uint16(header[:]); cs&GreaseMask != GreaseValueType {
176
+			hello.CipherSuite = cs
177
+		}
178
+	}
165
 
179
 
166
-	if _, err := io.CopyN(io.Discard, r, cipherSuiteLen-2); err != nil {
167
-		return nil, fmt.Errorf("cannot skip remaining cipher suites: %w", err)
180
+	if hello.CipherSuite == 0 {
181
+		return nil, ErrCannotFindCipher
168
 	}
182
 	}
169
 
183
 
170
 	if _, err := io.ReadFull(r, header[:1]); err != nil {
184
 	if _, err := io.ReadFull(r, header[:1]); err != nil {

+ 0
- 6
mtglib/internal/tls/fake/client_side_snapshot_test.go Ver fichero

12
 	"github.com/dolonet/mtg-multi/mtglib"
12
 	"github.com/dolonet/mtg-multi/mtglib"
13
 	"github.com/dolonet/mtg-multi/mtglib/internal/tls/fake"
13
 	"github.com/dolonet/mtg-multi/mtglib/internal/tls/fake"
14
 	"github.com/stretchr/testify/assert"
14
 	"github.com/stretchr/testify/assert"
15
-	"github.com/stretchr/testify/mock"
16
 	"github.com/stretchr/testify/require"
15
 	"github.com/stretchr/testify/require"
17
 	"github.com/stretchr/testify/suite"
16
 	"github.com/stretchr/testify/suite"
18
 )
17
 )
71
 		readBuf: readBuf,
70
 		readBuf: readBuf,
72
 	}
71
 	}
73
 
72
 
74
-	connMock.
75
-		On("SetReadDeadline", mock.AnythingOfType("time.Time")).
76
-		Twice().
77
-		Return(nil)
78
-
79
 	return connMock
73
 	return connMock
80
 }
74
 }
81
 
75
 

+ 23
- 28
mtglib/internal/tls/fake/client_side_test.go Ver fichero

2
 
2
 
3
 import (
3
 import (
4
 	"bytes"
4
 	"bytes"
5
+	cryptotls "crypto/tls"
5
 	"encoding/binary"
6
 	"encoding/binary"
6
 	"encoding/json"
7
 	"encoding/json"
7
-	"errors"
8
 	"io"
8
 	"io"
9
 	"os"
9
 	"os"
10
 	"testing"
10
 	"testing"
14
 	"github.com/dolonet/mtg-multi/mtglib"
14
 	"github.com/dolonet/mtg-multi/mtglib"
15
 	"github.com/dolonet/mtg-multi/mtglib/internal/tls"
15
 	"github.com/dolonet/mtg-multi/mtglib/internal/tls"
16
 	"github.com/dolonet/mtg-multi/mtglib/internal/tls/fake"
16
 	"github.com/dolonet/mtg-multi/mtglib/internal/tls/fake"
17
-	"github.com/stretchr/testify/mock"
18
 	"github.com/stretchr/testify/require"
17
 	"github.com/stretchr/testify/require"
19
 	"github.com/stretchr/testify/suite"
18
 	"github.com/stretchr/testify/suite"
20
 )
19
 )
53
 	suite.connMock = &parseClientHelloConnMock{
52
 	suite.connMock = &parseClientHelloConnMock{
54
 		readBuf: suite.readBuf,
53
 		readBuf: suite.readBuf,
55
 	}
54
 	}
56
-
57
-	suite.connMock.
58
-		On("SetReadDeadline", mock.AnythingOfType("time.Time")).
59
-		Twice().
60
-		Return(nil)
61
 }
55
 }
62
 
56
 
63
 func (suite *ParseClientHelloTestSuite) TearDownTest() {
57
 func (suite *ParseClientHelloTestSuite) TearDownTest() {
69
 }
63
 }
70
 
64
 
71
 func (suite *ParseClientHello_TLSHeaderTestSuite) TestEmpty() {
65
 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
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
66
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
79
-	suite.ErrorContains(err, "fail")
67
+	suite.ErrorContains(err, "cannot read client hello")
80
 }
68
 }
81
 
69
 
82
 func (suite *ParseClientHello_TLSHeaderTestSuite) TestNothing() {
70
 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
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
71
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
90
 	suite.ErrorIs(err, io.EOF)
72
 	suite.ErrorIs(err, io.EOF)
91
 }
73
 }
234
 }
216
 }
235
 
217
 
236
 func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadFirstCipherSuite() {
218
 func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadFirstCipherSuite() {
237
-	body := make([]byte, 2+fake.RandomLen+1+2)
219
+	body := make([]byte, 2+fake.RandomLen+1+2+1) // cipherSuiteLen=2 but only 1 byte available
220
+	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
238
 
221
 
239
 	suite.writeBody(body)
222
 	suite.writeBody(body)
240
 
223
 
241
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
224
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
242
-	suite.ErrorContains(err, "cannot read first cipher suite")
225
+	suite.ErrorContains(err, "cannot read cipher suite")
243
 }
226
 }
244
 
227
 
245
 func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipRemainingCipherSuites() {
228
 func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipRemainingCipherSuites() {
249
 	suite.writeBody(body)
232
 	suite.writeBody(body)
250
 
233
 
251
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
234
 	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
252
-	suite.ErrorContains(err, "cannot skip remaining cipher suites")
235
+	suite.ErrorContains(err, "cannot read cipher suite")
236
+}
237
+
238
+func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotFindCipher() {
239
+	// All cipher suites are GREASE values — must return ErrCannotFindCipher.
240
+	body := make([]byte, 2+fake.RandomLen+1+2+4+1)
241
+	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 4)
242
+	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1+2:], 0x0a0a)
243
+	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1+2+2:], 0x1a1a)
244
+	body[2+fake.RandomLen+1+2+4] = 1
245
+
246
+	suite.writeBody(body)
247
+
248
+	_, err := fake.ReadClientHello(suite.connMock, suite.secret.Key[:], suite.secret.Host, TolerateTime)
249
+	suite.ErrorIs(err, fake.ErrCannotFindCipher)
253
 }
250
 }
254
 
251
 
255
 func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadCompressionMethodsLength() {
252
 func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotReadCompressionMethodsLength() {
256
 	body := make([]byte, 2+fake.RandomLen+1+2+2)
253
 	body := make([]byte, 2+fake.RandomLen+1+2+2)
257
 	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
254
 	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
255
+	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1+2:], cryptotls.TLS_AES_128_GCM_SHA256)
258
 
256
 
259
 	suite.writeBody(body)
257
 	suite.writeBody(body)
260
 
258
 
265
 func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipCompressionMethods() {
263
 func (suite *ParseClientHelloHandshakeBodyTestSuite) TestCannotSkipCompressionMethods() {
266
 	body := make([]byte, 2+fake.RandomLen+1+2+2+1)
264
 	body := make([]byte, 2+fake.RandomLen+1+2+2+1)
267
 	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
265
 	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1:], 2)
266
+	binary.BigEndian.PutUint16(body[2+fake.RandomLen+1+2:], cryptotls.TLS_AES_128_GCM_SHA256)
268
 	body[2+fake.RandomLen+1+2+2] = 1
267
 	body[2+fake.RandomLen+1+2+2] = 1
269
 
268
 
270
 	suite.writeBody(body)
269
 	suite.writeBody(body)
300
 	// cipherSuite(2) + compressionLen(1) + compression(1) = 41
299
 	// cipherSuite(2) + compressionLen(1) + compression(1) = 41
301
 	body := make([]byte, 41)
300
 	body := make([]byte, 41)
302
 	binary.BigEndian.PutUint16(body[35:], 2)
301
 	binary.BigEndian.PutUint16(body[35:], 2)
302
+	binary.BigEndian.PutUint16(body[37:], cryptotls.TLS_AES_128_GCM_SHA256)
303
 	body[39] = 1
303
 	body[39] = 1
304
 
304
 
305
 	suite.readBuf.Write(body)
305
 	suite.readBuf.Write(body)
478
 		readBuf: readBuf,
478
 		readBuf: readBuf,
479
 	}
479
 	}
480
 
480
 
481
-	connMock.
482
-		On("SetReadDeadline", mock.AnythingOfType("time.Time")).
483
-		Twice().
484
-		Return(nil)
485
-
486
 	return connMock
481
 	return connMock
487
 }
482
 }
488
 
483
 

+ 2
- 13
mtglib/internal/tls/fake/init.go Ver fichero

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

+ 1
- 1
mtglib/internal/tls/fake/server_side_test.go Ver fichero

58
 	recordType, length, err := tls.ReadRecord(suite.buf, &rec)
58
 	recordType, length, err := tls.ReadRecord(suite.buf, &rec)
59
 	suite.NoError(err)
59
 	suite.NoError(err)
60
 	suite.Equal(byte(tls.TypeApplicationData), recordType)
60
 	suite.Equal(byte(tls.TypeApplicationData), recordType)
61
-	suite.Greater(length, int64(2500))
61
+	suite.GreaterOrEqual(length, int64(2500))
62
 
62
 
63
 	suite.Empty(suite.buf.Bytes())
63
 	suite.Empty(suite.buf.Bytes())
64
 }
64
 }

+ 8
- 0
mtglib/internal/tls/fake/testdata/client-hello-ok-grease-first.json Ver fichero

1
+{
2
+  "time": 1617181365,
3
+  "random": "w4TaDfYg/aUKdx1oi68vxMKvHJczRNvtRRppLETzeNE=",
4
+  "sessionId": "St2BZ2uHMFn3B2trD1jfdtpjoJOOg6JBeLhFcyCMCq4=",
5
+  "host": "storage.googleapis.com",
6
+  "cipherSuite": 4867,
7
+  "full": "FgMBAgIBAAH+AwPDhNoN9iD9pQp3HWiLry/Ewq8clzNE2+1FGmksRPN40SBK3YFna4cwWfcHa2sPWN922mOgk46DokF4uEVzIIwKrgA2WloTAxMBEwLALMArwCTAI8AKwAnMqcAwwC/AKMAnwBTAE8yoAJ0AnAA9ADwANQAvwAjAEgAKAQABf/8BAAEAAAAAGwAZAAAWc3RvcmFnZS5nb29nbGVhcGlzLmNvbQAXAAAADQAYABYEAwgEBAEFAwIDCAUIBQUBCAYGAQIBAAUABQEAAAAAM3QAAAASAAAAEAAwAC4CaDIFaDItMTYFaDItMTUFaDItMTQIc3BkeS8zLjEGc3BkeS8zCGh0dHAvMS4xAAsAAgEAADMAJgAkAB0AIAf+6C8fSRJSAC7CyUvdR9kDclNR9KLCsCFHpVZ3bC8iAC0AAgEBACsACQgDBAMDAwIDAQAKAAoACAAdABcAGAAZABUAoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
8
+}

+ 12
- 0
mtglib/proxy.go Ver fichero

29
 	allowFallbackOnUnknownDC    bool
29
 	allowFallbackOnUnknownDC    bool
30
 	tolerateTimeSkewness        time.Duration
30
 	tolerateTimeSkewness        time.Duration
31
 	idleTimeout                 time.Duration
31
 	idleTimeout                 time.Duration
32
+	handshakeTimeout            time.Duration
32
 	domainFrontingPort          int
33
 	domainFrontingPort          int
33
 	domainFrontingIP            string
34
 	domainFrontingIP            string
34
 	domainFrontingProxyProtocol bool
35
 	domainFrontingProxyProtocol bool
70
 	ctx := newStreamContext(p.ctx, p.logger, conn)
71
 	ctx := newStreamContext(p.ctx, p.logger, conn)
71
 	defer ctx.Close()
72
 	defer ctx.Close()
72
 
73
 
74
+	if err := ctx.clientConn.SetDeadline(time.Now().Add(p.handshakeTimeout)); err != nil {
75
+		ctx.logger.WarningError("cannot set handshake timeout", err)
76
+		return
77
+	}
78
+
73
 	stop := context.AfterFunc(ctx, func() {
79
 	stop := context.AfterFunc(ctx, func() {
74
 		ctx.Close()
80
 		ctx.Close()
75
 	})
81
 	})
113
 		return
119
 		return
114
 	}
120
 	}
115
 
121
 
122
+	if err := ctx.clientConn.SetDeadline(time.Time{}); err != nil {
123
+		ctx.logger.WarningError("cannot set deadline", err)
124
+		return
125
+	}
126
+
116
 	if err := p.doTelegramCall(ctx); err != nil {
127
 	if err := p.doTelegramCall(ctx); err != nil {
117
 		ctx.logger.WarningError("cannot dial to telegram", err)
128
 		ctx.logger.WarningError("cannot dial to telegram", err)
118
 		return
129
 		return
409
 		domainFrontingIP:         opts.DomainFrontingIP,
420
 		domainFrontingIP:         opts.DomainFrontingIP,
410
 		tolerateTimeSkewness:     opts.getTolerateTimeSkewness(),
421
 		tolerateTimeSkewness:     opts.getTolerateTimeSkewness(),
411
 		idleTimeout:              opts.getIdleTimeout(),
422
 		idleTimeout:              opts.getIdleTimeout(),
423
+		handshakeTimeout:         opts.getHandshakeTimeout(),
412
 		allowFallbackOnUnknownDC: opts.AllowFallbackOnUnknownDC,
424
 		allowFallbackOnUnknownDC: opts.AllowFallbackOnUnknownDC,
413
 		telegram:                 tg,
425
 		telegram:                 tg,
414
 		doppelGanger: doppel.NewGanger(
426
 		doppelGanger: doppel.NewGanger(

+ 14
- 0
mtglib/proxy_opts.go Ver fichero

79
 	// This is an optional setting.
79
 	// This is an optional setting.
80
 	IdleTimeout time.Duration
80
 	IdleTimeout time.Duration
81
 
81
 
82
+	// HandshakeTimeout is a timeout during which all handshake ceremonies must
83
+	// be completed, otherwise this process will be aborted
84
+	//
85
+	// This is an optional setting.
86
+	HandshakeTimeout time.Duration
87
+
82
 	// TolerateTimeSkewness is a time boundary that defines a time range where
88
 	// TolerateTimeSkewness is a time boundary that defines a time range where
83
 	// faketls timestamp is acceptable.
89
 	// faketls timestamp is acceptable.
84
 	//
90
 	//
275
 	return p.PreferIP
281
 	return p.PreferIP
276
 }
282
 }
277
 
283
 
284
+func (p ProxyOpts) getHandshakeTimeout() time.Duration {
285
+	if p.HandshakeTimeout == 0 {
286
+		return DefaultHandshakeTimeout
287
+	}
288
+
289
+	return p.HandshakeTimeout
290
+}
291
+
278
 func (p ProxyOpts) getIdleTimeout() time.Duration {
292
 func (p ProxyOpts) getIdleTimeout() time.Duration {
279
 	if p.IdleTimeout == 0 {
293
 	if p.IdleTimeout == 0 {
280
 		return DefaultIdleTimeout
294
 		return DefaultIdleTimeout

Loading…
Cancelar
Guardar