Просмотр исходного кода

Validate hostname if it was found in SNI

tags/v2.0.0-rc1
9seconds 5 лет назад
Родитель
Сommit
5eca6ecb05

+ 1
- 1
example.config.toml Просмотреть файл

@@ -13,7 +13,7 @@
13 13
 # Debug starts application in debug mode. It starts to be quite verbose
14 14
 # in output. Actually, the idea is that you run it in debug mode only if
15 15
 # you have any issue.
16
-debug = false
16
+debug = true
17 17
 
18 18
 # A secret. Please remember that mtg supports only FakeTLS mode, legacy
19 19
 # simple and secured mode are prohibited. For you it means that secret

+ 48
- 1
mtglib/internal/faketls/client_hello.go Просмотреть файл

@@ -14,6 +14,7 @@ type ClientHello struct {
14 14
 	Time        time.Time
15 15
 	Random      [RandomLen]byte
16 16
 	SessionID   []byte
17
+	Host        string
17 18
 	CipherSuite uint16
18 19
 }
19 20
 
@@ -28,6 +29,15 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
28 29
 		return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
29 30
 	}
30 31
 
32
+	handshakeSizeBytes := [4]byte{0, handshake[1], handshake[2], handshake[3]}
33
+	handshakeLength := binary.BigEndian.Uint32(handshakeSizeBytes[:])
34
+
35
+	if len(handshake)-4 != int(handshakeLength) {
36
+		return hello,
37
+			fmt.Errorf("incorrect handshake size. manifested=%d, real=%d",
38
+				handshakeLength, len(handshake)-4) // nolint: gomnd
39
+	}
40
+
31 41
 	copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
32 42
 
33 43
 	for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
@@ -61,11 +71,48 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
61 71
 	timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
62 72
 	hello.Time = time.Unix(timestamp, 0)
63 73
 
74
+	parseSessionID(&hello, handshake)
75
+	parseCipherSuite(&hello, handshake)
76
+	parseSNI(&hello, handshake)
77
+
78
+	return hello, nil
79
+}
80
+
81
+func parseSessionID(hello *ClientHello, handshake []byte) {
64 82
 	hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
65 83
 	copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
84
+}
66 85
 
86
+func parseCipherSuite(hello *ClientHello, handshake []byte) {
67 87
 	cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 // nolint: gomnd
68 88
 	hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
89
+}
69 90
 
70
-	return hello, nil
91
+func parseSNI(hello *ClientHello, handshake []byte) {
92
+	cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 1
93
+	handshake = handshake[cipherSuiteOffset:]
94
+
95
+	cipherSuiteLength := binary.BigEndian.Uint16(handshake[:2])
96
+	handshake = handshake[2+cipherSuiteLength:]
97
+
98
+	compressionMethodsLength := int(handshake[0])
99
+	handshake = handshake[1+compressionMethodsLength:]
100
+
101
+	extensionsLength := binary.BigEndian.Uint16(handshake[:2])
102
+	handshake = handshake[2 : 2+extensionsLength]
103
+
104
+	for len(handshake) > 0 {
105
+		if binary.BigEndian.Uint16(handshake[:2]) != ExtensionSNI {
106
+			extensionsLength := binary.BigEndian.Uint16(handshake[2:4])
107
+			handshake = handshake[4+extensionsLength:]
108
+
109
+			continue
110
+		}
111
+
112
+		hostnameLength := binary.BigEndian.Uint16(handshake[7:9])
113
+		handshake = handshake[9:]
114
+		hello.Host = string(handshake[:int(hostnameLength)])
115
+
116
+		return
117
+	}
71 118
 }

+ 3
- 1
mtglib/internal/faketls/init.go Просмотреть файл

@@ -7,7 +7,7 @@ const (
7 7
 
8 8
 	ClientHelloRandomOffset    = 6
9 9
 	ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
10
-	ClientHelloMinLen          = ClientHelloSessionIDOffset + 1
10
+	ClientHelloMinLen          = 4
11 11
 
12 12
 	WelcomePacketRandomOffset = 11
13 13
 
@@ -15,6 +15,8 @@ const (
15 15
 	HandshakeTypeServer = 0x02
16 16
 
17 17
 	ChangeCipherValue = 0x01
18
+
19
+	ExtensionSNI = 0x00
18 20
 )
19 21
 
20 22
 var (

+ 1
- 1
mtglib/internal/telegram/init.go Просмотреть файл

@@ -36,7 +36,7 @@ var (
36 36
 			{network: "tcp4", address: "149.154.167.91:443"},
37 37
 		},
38 38
 		{
39
-            {network: "tcp4", address: "149.154.171.5:443"},
39
+			{network: "tcp4", address: "149.154.171.5:443"},
40 40
 		},
41 41
 	}
42 42
 	v6Addresses = [5]tgAddr{

+ 7
- 0
mtglib/proxy.go Просмотреть файл

@@ -144,6 +144,13 @@ func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) bool {
144 144
 		return false
145 145
 	}
146 146
 
147
+	if hello.Host != "" && hello.Host != p.secret.Host {
148
+		p.logger.BindStr("hostname", hello.Host).Info("incorrect domain was found in SNI")
149
+		p.doDomainFronting(ctx, rewind)
150
+
151
+		return false
152
+	}
153
+
147 154
 	if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
148 155
 		p.logger.InfoError("invalid faketls time", err)
149 156
 		p.doDomainFronting(ctx, rewind)

Загрузка…
Отмена
Сохранить