Refactor TLS record reading logic in probe.go to replace readOneTLSApplicationRecord with readNextTLS17Payload. The new function handles TLS 1.2-style records, improving error handling and skipping non-application data records. This change enhances the robustness of MTProxy decryption.
This commit is contained in:
+35
-17
@@ -154,7 +154,7 @@ func VerifyResPQ(ctx context.Context, conn net.Conn, enc, dec cipher.Stream, eeT
|
||||
var chunk []byte
|
||||
var rerr error
|
||||
if eeTLS {
|
||||
chunk, rerr = readOneTLSApplicationRecord(br)
|
||||
chunk, rerr = readNextTLS17Payload(br)
|
||||
} else {
|
||||
chunk, rerr = readAtMost(conn, 65536)
|
||||
}
|
||||
@@ -193,23 +193,41 @@ func VerifyResPQ(ctx context.Context, conn net.Conn, enc, dec cipher.Stream, eeT
|
||||
return ErrNoResPQ
|
||||
}
|
||||
|
||||
func readOneTLSApplicationRecord(br *bufio.Reader) ([]byte, error) {
|
||||
h := make([]byte, 5)
|
||||
if _, err := io.ReadFull(br, h); err != nil {
|
||||
return nil, err
|
||||
// readNextTLS17Payload reads TLS 1.2-style records from the wire (plaintext record headers).
|
||||
// Handshake (0x16) and ChangeCipherSpec (0x15) payloads are not MTProxy-CTR ciphertext — skip them.
|
||||
// Only application data (0x17) inner bytes are passed through the MTProxy decrypt stream (caller XORs).
|
||||
// Some proxies send extra handshake records after the fake ServerHello; clients skip them before MTProto.
|
||||
func readNextTLS17Payload(br *bufio.Reader) ([]byte, error) {
|
||||
const maxSkips = 128
|
||||
for range maxSkips {
|
||||
h := make([]byte, 5)
|
||||
if _, err := io.ReadFull(br, h); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ver := binary.BigEndian.Uint16(h[1:3])
|
||||
if ver != 0x0303 && ver != 0x0301 {
|
||||
return nil, fmt.Errorf("unexpected tls record version 0x%04x (type 0x%02x); if type is 0x48 ('H') the peer may be speaking HTTP on this socket", ver, h[0])
|
||||
}
|
||||
n := int(binary.BigEndian.Uint16(h[3:5]))
|
||||
if n <= 0 || n > 1<<20 {
|
||||
return nil, fmt.Errorf("invalid tls record length %d", n)
|
||||
}
|
||||
payload := make([]byte, n)
|
||||
if _, err := io.ReadFull(br, payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch h[0] {
|
||||
case 0x17: // application data — inner bytes are MTProxy-obfuscated
|
||||
return payload, nil
|
||||
case 0x16, 0x15: // more handshake / CCS after ServerHello — plaintext, do not advance CTR interpretation here
|
||||
continue
|
||||
case 0x14: // alert
|
||||
return nil, fmt.Errorf("tls alert record from proxy (len=%d)", n)
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected tls record type 0x%02x (len=%d); 0x48 often means cleartext HTTP if the stream is misaligned", h[0], n)
|
||||
}
|
||||
}
|
||||
if h[0] != 0x17 {
|
||||
return nil, fmt.Errorf("unexpected tls record type 0x%02x", h[0])
|
||||
}
|
||||
n := int(binary.BigEndian.Uint16(h[3:5]))
|
||||
if n <= 0 || n > 1<<20 {
|
||||
return nil, fmt.Errorf("invalid tls app length %d", n)
|
||||
}
|
||||
p := make([]byte, n)
|
||||
if _, err := io.ReadFull(br, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
return nil, fmt.Errorf("too many non-application tls records before 0x17")
|
||||
}
|
||||
|
||||
func readAtMost(conn net.Conn, max int) ([]byte, error) {
|
||||
|
||||
Reference in New Issue
Block a user