mirror of
https://github.com/qdm12/gluetun.git
synced 2026-05-07 04:20:12 +02:00
feat(pmtud/tcp): generate MTU test data to mimic TLS if possible to avoid being blocked
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -72,10 +73,10 @@ func createPacket(src, dst netip.AddrPort,
|
|||||||
tcpHeader := makeTCPHeader(src.Port(), dst.Port(), seq, ack, flags)
|
tcpHeader := makeTCPHeader(src.Port(), dst.Port(), seq, ack, flags)
|
||||||
|
|
||||||
// data is just zeroes
|
// data is just zeroes
|
||||||
dataLength := int(payloadLength) - int(constants.BaseTCPHeaderLength)
|
dataLength := int(payloadLength - constants.BaseTCPHeaderLength)
|
||||||
var data []byte
|
var data []byte
|
||||||
if dataLength > 0 {
|
if dataLength > 0 {
|
||||||
data = make([]byte, dataLength)
|
data = generatePayload(uint16(dataLength)) //nolint:gosec
|
||||||
}
|
}
|
||||||
checksum := tcpChecksum(ipHeader, tcpHeader, data)
|
checksum := tcpChecksum(ipHeader, tcpHeader, data)
|
||||||
tcpHeader[16] = byte(checksum >> 8) //nolint:mnd
|
tcpHeader[16] = byte(checksum >> 8) //nolint:mnd
|
||||||
@@ -87,3 +88,70 @@ func createPacket(src, dst netip.AddrPort,
|
|||||||
copy(packet[len(ipHeader)+int(constants.BaseTCPHeaderLength):], data)
|
copy(packet[len(ipHeader)+int(constants.BaseTCPHeaderLength):], data)
|
||||||
return packet
|
return packet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generatePayload creates a byte slice of 'length' size.
|
||||||
|
// For lengths below 88B, it returns pseudo random data.
|
||||||
|
// For lengths above, it returns a structured TLS Client Hello with padding,
|
||||||
|
// which is more likely to be accepted by servers and not trigger RST replies.
|
||||||
|
//
|
||||||
|
//nolint:mnd
|
||||||
|
func generatePayload(length uint16) []byte {
|
||||||
|
const minTLSClientHelloSize = 5 + // TLS record
|
||||||
|
4 + // handshake header
|
||||||
|
67 + // client hello
|
||||||
|
4 + // cipher suites
|
||||||
|
2 + // compression methods
|
||||||
|
2 + // extensions length
|
||||||
|
4 // padding extension header
|
||||||
|
if length < minTLSClientHelloSize {
|
||||||
|
data := make([]byte, length)
|
||||||
|
makeRandom(data)
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := make([]byte, length)
|
||||||
|
|
||||||
|
// --- TLS Record Layer ---
|
||||||
|
payload[0] = 0x16 // Handshake
|
||||||
|
payload[1] = 0x03 // Version 3.1
|
||||||
|
payload[2] = 0x01
|
||||||
|
binary.BigEndian.PutUint16(payload[3:5], length-5)
|
||||||
|
|
||||||
|
// --- Handshake Header ---
|
||||||
|
payload[5] = 0x01 // Client Hello
|
||||||
|
handshakeLength := make([]byte, 4)
|
||||||
|
// TLS Handshake length is 24-bit.
|
||||||
|
// We use a 4-byte buffer and copy the trailing 3 bytes.
|
||||||
|
binary.BigEndian.PutUint32(handshakeLength, uint32(length-9))
|
||||||
|
copy(payload[6:9], handshakeLength[1:])
|
||||||
|
|
||||||
|
// --- Client Hello Body ---
|
||||||
|
payload[9] = 0x03 // Version 3.3 (TLS 1.2)
|
||||||
|
payload[10] = 0x03
|
||||||
|
makeRandom(payload[11:43]) // 32 bytes of random
|
||||||
|
payload[43] = 32 // Session ID length
|
||||||
|
|
||||||
|
// Cipher Suites (Length: 2, Data: 2)
|
||||||
|
binary.BigEndian.PutUint16(payload[44:46], 2)
|
||||||
|
binary.BigEndian.PutUint16(payload[46:48], 0x009c) // TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||||
|
|
||||||
|
payload[48] = 0x01 // Compression length
|
||||||
|
payload[49] = 0x00 // Null compression
|
||||||
|
|
||||||
|
// --- Extensions ---
|
||||||
|
binary.BigEndian.PutUint16(payload[50:52], length-52) // extension length
|
||||||
|
|
||||||
|
// --- Padding Extension (Type 21) ---
|
||||||
|
binary.BigEndian.PutUint16(payload[52:54], 21)
|
||||||
|
const bytesUsedSoFar = 88
|
||||||
|
paddingDataLength := length - bytesUsedSoFar
|
||||||
|
binary.BigEndian.PutUint16(payload[54:56], paddingDataLength)
|
||||||
|
|
||||||
|
return payload
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeRandom(b []byte) {
|
||||||
|
for i := range b {
|
||||||
|
b[i] = byte(rand.Uint32()) //nolint:gosec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user