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

Validate hostname if it was found in SNI

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

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

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

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

14
 	Time        time.Time
14
 	Time        time.Time
15
 	Random      [RandomLen]byte
15
 	Random      [RandomLen]byte
16
 	SessionID   []byte
16
 	SessionID   []byte
17
+	Host        string
17
 	CipherSuite uint16
18
 	CipherSuite uint16
18
 }
19
 }
19
 
20
 
28
 		return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
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
 	copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
41
 	copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
32
 
42
 
33
 	for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
43
 	for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
61
 	timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
71
 	timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
62
 	hello.Time = time.Unix(timestamp, 0)
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
 	hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
82
 	hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
65
 	copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
83
 	copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
84
+}
66
 
85
 
86
+func parseCipherSuite(hello *ClientHello, handshake []byte) {
67
 	cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 // nolint: gomnd
87
 	cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 // nolint: gomnd
68
 	hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
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
 
8
 	ClientHelloRandomOffset    = 6
8
 	ClientHelloRandomOffset    = 6
9
 	ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
9
 	ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
10
-	ClientHelloMinLen          = ClientHelloSessionIDOffset + 1
10
+	ClientHelloMinLen          = 4
11
 
11
 
12
 	WelcomePacketRandomOffset = 11
12
 	WelcomePacketRandomOffset = 11
13
 
13
 
15
 	HandshakeTypeServer = 0x02
15
 	HandshakeTypeServer = 0x02
16
 
16
 
17
 	ChangeCipherValue = 0x01
17
 	ChangeCipherValue = 0x01
18
+
19
+	ExtensionSNI = 0x00
18
 )
20
 )
19
 
21
 
20
 var (
22
 var (

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

36
 			{network: "tcp4", address: "149.154.167.91:443"},
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
 	v6Addresses = [5]tgAddr{
42
 	v6Addresses = [5]tgAddr{

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

144
 		return false
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
 	if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
154
 	if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
148
 		p.logger.InfoError("invalid faketls time", err)
155
 		p.logger.InfoError("invalid faketls time", err)
149
 		p.doDomainFronting(ctx, rewind)
156
 		p.doDomainFronting(ctx, rewind)

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