mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-09-01 10:14:01 +03:00
Validate hostname if it was found in SNI
This commit is contained in:
+1
-1
@@ -13,7 +13,7 @@
|
|||||||
# Debug starts application in debug mode. It starts to be quite verbose
|
# Debug starts application in debug mode. It starts to be quite verbose
|
||||||
# in output. Actually, the idea is that you run it in debug mode only if
|
# in output. Actually, the idea is that you run it in debug mode only if
|
||||||
# you have any issue.
|
# you have any issue.
|
||||||
debug = false
|
debug = true
|
||||||
|
|
||||||
# A secret. Please remember that mtg supports only FakeTLS mode, legacy
|
# A secret. Please remember that mtg supports only FakeTLS mode, legacy
|
||||||
# simple and secured mode are prohibited. For you it means that secret
|
# simple and secured mode are prohibited. For you it means that secret
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type ClientHello struct {
|
|||||||
Time time.Time
|
Time time.Time
|
||||||
Random [RandomLen]byte
|
Random [RandomLen]byte
|
||||||
SessionID []byte
|
SessionID []byte
|
||||||
|
Host string
|
||||||
CipherSuite uint16
|
CipherSuite uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +29,15 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
|
|||||||
return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
|
return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handshakeSizeBytes := [4]byte{0, handshake[1], handshake[2], handshake[3]}
|
||||||
|
handshakeLength := binary.BigEndian.Uint32(handshakeSizeBytes[:])
|
||||||
|
|
||||||
|
if len(handshake)-4 != int(handshakeLength) {
|
||||||
|
return hello,
|
||||||
|
fmt.Errorf("incorrect handshake size. manifested=%d, real=%d",
|
||||||
|
handshakeLength, len(handshake)-4) // nolint: gomnd
|
||||||
|
}
|
||||||
|
|
||||||
copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
|
copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
|
||||||
|
|
||||||
for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
|
for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
|
||||||
@@ -61,11 +71,48 @@ func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
|
|||||||
timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
|
timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
|
||||||
hello.Time = time.Unix(timestamp, 0)
|
hello.Time = time.Unix(timestamp, 0)
|
||||||
|
|
||||||
hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
|
parseSessionID(&hello, handshake)
|
||||||
copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
|
parseCipherSuite(&hello, handshake)
|
||||||
|
parseSNI(&hello, handshake)
|
||||||
cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 // nolint: gomnd
|
|
||||||
hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
|
|
||||||
|
|
||||||
return hello, nil
|
return hello, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseSessionID(hello *ClientHello, handshake []byte) {
|
||||||
|
hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
|
||||||
|
copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCipherSuite(hello *ClientHello, handshake []byte) {
|
||||||
|
cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 // nolint: gomnd
|
||||||
|
hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSNI(hello *ClientHello, handshake []byte) {
|
||||||
|
cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 1
|
||||||
|
handshake = handshake[cipherSuiteOffset:]
|
||||||
|
|
||||||
|
cipherSuiteLength := binary.BigEndian.Uint16(handshake[:2])
|
||||||
|
handshake = handshake[2+cipherSuiteLength:]
|
||||||
|
|
||||||
|
compressionMethodsLength := int(handshake[0])
|
||||||
|
handshake = handshake[1+compressionMethodsLength:]
|
||||||
|
|
||||||
|
extensionsLength := binary.BigEndian.Uint16(handshake[:2])
|
||||||
|
handshake = handshake[2 : 2+extensionsLength]
|
||||||
|
|
||||||
|
for len(handshake) > 0 {
|
||||||
|
if binary.BigEndian.Uint16(handshake[:2]) != ExtensionSNI {
|
||||||
|
extensionsLength := binary.BigEndian.Uint16(handshake[2:4])
|
||||||
|
handshake = handshake[4+extensionsLength:]
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hostnameLength := binary.BigEndian.Uint16(handshake[7:9])
|
||||||
|
handshake = handshake[9:]
|
||||||
|
hello.Host = string(handshake[:int(hostnameLength)])
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const (
|
|||||||
|
|
||||||
ClientHelloRandomOffset = 6
|
ClientHelloRandomOffset = 6
|
||||||
ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
|
ClientHelloSessionIDOffset = ClientHelloRandomOffset + RandomLen
|
||||||
ClientHelloMinLen = ClientHelloSessionIDOffset + 1
|
ClientHelloMinLen = 4
|
||||||
|
|
||||||
WelcomePacketRandomOffset = 11
|
WelcomePacketRandomOffset = 11
|
||||||
|
|
||||||
@@ -15,6 +15,8 @@ const (
|
|||||||
HandshakeTypeServer = 0x02
|
HandshakeTypeServer = 0x02
|
||||||
|
|
||||||
ChangeCipherValue = 0x01
|
ChangeCipherValue = 0x01
|
||||||
|
|
||||||
|
ExtensionSNI = 0x00
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ var (
|
|||||||
{network: "tcp4", address: "149.154.167.91:443"},
|
{network: "tcp4", address: "149.154.167.91:443"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{network: "tcp4", address: "149.154.171.5:443"},
|
{network: "tcp4", address: "149.154.171.5:443"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
v6Addresses = [5]tgAddr{
|
v6Addresses = [5]tgAddr{
|
||||||
|
|||||||
@@ -144,6 +144,13 @@ func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hello.Host != "" && hello.Host != p.secret.Host {
|
||||||
|
p.logger.BindStr("hostname", hello.Host).Info("incorrect domain was found in SNI")
|
||||||
|
p.doDomainFronting(ctx, rewind)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
|
if err := p.timeAttackDetector.Valid(hello.Time); err != nil {
|
||||||
p.logger.InfoError("invalid faketls time", err)
|
p.logger.InfoError("invalid faketls time", err)
|
||||||
p.doDomainFronting(ctx, rewind)
|
p.doDomainFronting(ctx, rewind)
|
||||||
|
|||||||
Reference in New Issue
Block a user