Vision padding upgrade (#1646)

* Vision server allow multiple blocks of padding

* Fix Vision client to support multiple possible padding blocks

* Vision padding upgrade

- Now we have two types of padding: long (pad to 900-1400) and traditional (0-256)
- Long padding is applied to tls handshakes and first (empty) packet
- Traditional padding is applied to all beginning (7) packets of the connection (counted two-way)
- Since receiver changed its way to unpad buffer in fd6973b3c6, we can freely extend padding packet length easily in the future
- Simplify code

* Adjust receiver withinPaddingBuffers

Now default withinPaddingBuffers = true to give it a chance to do unpadding

* Fix magic numbers for Vision
Thanks @H1JK

Thanks @RPRX for guidance
This commit is contained in:
yuhan6665 2023-02-27 22:14:37 -05:00 committed by GitHub
parent 55dc26f228
commit 2d898480be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 44 deletions

View file

@ -36,6 +36,23 @@ var (
tlsClientHandShakeStart = []byte{0x16, 0x03} tlsClientHandShakeStart = []byte{0x16, 0x03}
tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03} tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03}
tlsApplicationDataStart = []byte{0x17, 0x03, 0x03} tlsApplicationDataStart = []byte{0x17, 0x03, 0x03}
Tls13CipherSuiteDic = map[uint16]string{
0x1301: "TLS_AES_128_GCM_SHA256",
0x1302: "TLS_AES_256_GCM_SHA384",
0x1303: "TLS_CHACHA20_POLY1305_SHA256",
0x1304: "TLS_AES_128_CCM_SHA256",
0x1305: "TLS_AES_128_CCM_8_SHA256",
}
)
const (
tlsHandshakeTypeClientHello byte = 0x01
tlsHandshakeTypeServerHello byte = 0x02
CommandPaddingContinue byte = 0x00
CommandPaddingEnd byte = 0x01
CommandPaddingDirect byte = 0x02
) )
var addrParser = protocol.NewAddressParser( var addrParser = protocol.NewAddressParser(
@ -256,7 +273,7 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
) error { ) error {
err := func() error { err := func() error {
var ct stats.Counter var ct stats.Counter
filterUUID := true withinPaddingBuffers := true
shouldSwitchToDirectCopy := false shouldSwitchToDirectCopy := false
var remainingContent int32 = -1 var remainingContent int32 = -1
var remainingPadding int32 = -1 var remainingPadding int32 = -1
@ -294,13 +311,15 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
} }
buffer, err := reader.ReadMultiBuffer() buffer, err := reader.ReadMultiBuffer()
if !buffer.IsEmpty() { if !buffer.IsEmpty() {
if filterUUID && (*isTLS || *numberOfPacketToFilter > 0) { if withinPaddingBuffers || *numberOfPacketToFilter > 0 {
buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, &currentCommand) buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, &currentCommand)
if remainingContent == 0 && remainingPadding == 0 { if remainingContent == 0 && remainingPadding == 0 {
if currentCommand == 1 { if currentCommand == 1 {
filterUUID = false withinPaddingBuffers = false
remainingContent = -1
remainingPadding = -1 // set to initial state to parse the next padding
} else if currentCommand == 2 { } else if currentCommand == 2 {
filterUUID = false withinPaddingBuffers = false
shouldSwitchToDirectCopy = true shouldSwitchToDirectCopy = true
// XTLS Vision processes struct TLS Conn's input and rawInput // XTLS Vision processes struct TLS Conn's input and rawInput
if inputBuffer, err := buf.ReadFrom(input); err == nil { if inputBuffer, err := buf.ReadFrom(input); err == nil {
@ -313,9 +332,15 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
buffer, _ = buf.MergeMulti(buffer, rawInputBuffer) buffer, _ = buf.MergeMulti(buffer, rawInputBuffer)
} }
} }
} else if currentCommand != 0 { } else if currentCommand == 0 {
withinPaddingBuffers = true
} else {
newError("XtlsRead unknown command ", currentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) newError("XtlsRead unknown command ", currentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
} }
} else if remainingContent > 0 || remainingPadding > 0 {
withinPaddingBuffers = true
} else {
withinPaddingBuffers = false
} }
} }
if *numberOfPacketToFilter > 0 { if *numberOfPacketToFilter > 0 {
@ -342,12 +367,12 @@ func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater
// XtlsWrite filter and write xtls protocol // XtlsWrite filter and write xtls protocol
func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, counter stats.Counter, func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, counter stats.Counter,
ctx context.Context, userUUID *[]byte, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool, ctx context.Context, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool,
cipher *uint16, remainingServerHello *int32, cipher *uint16, remainingServerHello *int32,
) error { ) error {
err := func() error { err := func() error {
var ct stats.Counter var ct stats.Counter
filterTlsApplicationData := true isPadding := true
shouldSwitchToDirectCopy := false shouldSwitchToDirectCopy := false
for { for {
buffer, err := reader.ReadMultiBuffer() buffer, err := reader.ReadMultiBuffer()
@ -355,27 +380,26 @@ func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdate
if *numberOfPacketToFilter > 0 { if *numberOfPacketToFilter > 0 {
XtlsFilterTls(buffer, numberOfPacketToFilter, enableXtls, isTLS12orAbove, isTLS, cipher, remainingServerHello, ctx) XtlsFilterTls(buffer, numberOfPacketToFilter, enableXtls, isTLS12orAbove, isTLS, cipher, remainingServerHello, ctx)
} }
if filterTlsApplicationData && *isTLS { if isPadding {
buffer = ReshapeMultiBuffer(ctx, buffer) buffer = ReshapeMultiBuffer(ctx, buffer)
var xtlsSpecIndex int var xtlsSpecIndex int
for i, b := range buffer { for i, b := range buffer {
if b.Len() >= 6 && bytes.Equal(tlsApplicationDataStart, b.BytesTo(3)) { if *isTLS && b.Len() >= 6 && bytes.Equal(tlsApplicationDataStart, b.BytesTo(3)) {
var command byte = 0x01 var command byte = CommandPaddingEnd
if *enableXtls { if *enableXtls {
shouldSwitchToDirectCopy = true shouldSwitchToDirectCopy = true
xtlsSpecIndex = i xtlsSpecIndex = i
command = 0x02 command = CommandPaddingDirect
} }
filterTlsApplicationData = false isPadding = false
buffer[i] = XtlsPadding(b, command, userUUID, ctx) buffer[i] = XtlsPadding(b, command, nil, *isTLS, ctx)
break break
} else if !*isTLS12orAbove && *numberOfPacketToFilter <= 0 { } else if !*isTLS12orAbove && *numberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early
// maybe tls 1.1 or 1.0 isPadding = false
filterTlsApplicationData = false buffer[i] = XtlsPadding(b, CommandPaddingEnd, nil, *isTLS, ctx)
buffer[i] = XtlsPadding(b, 0x01, userUUID, ctx)
break break
} }
buffer[i] = XtlsPadding(b, 0x00, userUUID, ctx) buffer[i] = XtlsPadding(b, CommandPaddingContinue, nil, *isTLS, ctx)
} }
if shouldSwitchToDirectCopy { if shouldSwitchToDirectCopy {
encryptBuffer, directBuffer := buf.SplitMulti(buffer, xtlsSpecIndex+1) encryptBuffer, directBuffer := buf.SplitMulti(buffer, xtlsSpecIndex+1)
@ -422,7 +446,7 @@ func XtlsFilterTls(buffer buf.MultiBuffer, numberOfPacketToFilter *int, enableXt
*numberOfPacketToFilter-- *numberOfPacketToFilter--
if b.Len() >= 6 { if b.Len() >= 6 {
startsBytes := b.BytesTo(6) startsBytes := b.BytesTo(6)
if bytes.Equal(tlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == 0x02 { if bytes.Equal(tlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == tlsHandshakeTypeServerHello {
*remainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5 *remainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5
*isTLS12orAbove = true *isTLS12orAbove = true
*isTLS = true *isTLS = true
@ -433,7 +457,7 @@ func XtlsFilterTls(buffer buf.MultiBuffer, numberOfPacketToFilter *int, enableXt
} else { } else {
newError("XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", *remainingServerHello).WriteToLog(session.ExportIDToError(ctx)) newError("XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", *remainingServerHello).WriteToLog(session.ExportIDToError(ctx))
} }
} else if bytes.Equal(tlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == 0x01 { } else if bytes.Equal(tlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == tlsHandshakeTypeClientHello {
*isTLS = true *isTLS = true
newError("XtlsFilterTls found tls client hello! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) newError("XtlsFilterTls found tls client hello! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx))
} }
@ -483,7 +507,7 @@ func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBu
for i, buffer1 := range buffer { for i, buffer1 := range buffer {
if buffer1.Len() >= buf.Size-21 { if buffer1.Len() >= buf.Size-21 {
index := int32(bytes.LastIndex(buffer1.Bytes(), tlsApplicationDataStart)) index := int32(bytes.LastIndex(buffer1.Bytes(), tlsApplicationDataStart))
if index <= 0 { if index <= 0 || index > buf.Size-21 {
index = buf.Size / 2 index = buf.Size / 2
} }
buffer2 := buf.New() buffer2 := buf.New()
@ -503,23 +527,28 @@ func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBu
} }
// XtlsPadding add padding to eliminate length siganature during tls handshake // XtlsPadding add padding to eliminate length siganature during tls handshake
func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, ctx context.Context) *buf.Buffer { func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer {
var contantLen int32 = 0 var contantLen int32 = 0
var paddingLen int32 = 0 var paddingLen int32 = 0
if b != nil { if b != nil {
contantLen = b.Len() contantLen = b.Len()
} }
if contantLen < 900 { if contantLen < 900 && longPadding {
l, err := rand.Int(rand.Reader, big.NewInt(500)) l, err := rand.Int(rand.Reader, big.NewInt(500))
if err != nil { if err != nil {
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx)) newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
} }
paddingLen = int32(l.Int64()) + 900 - contantLen paddingLen = int32(l.Int64()) + 900 - contantLen
} else {
l, err := rand.Int(rand.Reader, big.NewInt(256))
if err != nil {
newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx))
}
paddingLen = int32(l.Int64())
} }
newbuffer := buf.New() newbuffer := buf.New()
if userUUID != nil { if userUUID != nil {
newbuffer.Write(*userUUID) newbuffer.Write(*userUUID)
*userUUID = nil
} }
newbuffer.Write([]byte{command, byte(contantLen >> 8), byte(contantLen), byte(paddingLen >> 8), byte(paddingLen)}) newbuffer.Write([]byte{command, byte(contantLen >> 8), byte(contantLen), byte(paddingLen >> 8), byte(paddingLen)})
if b != nil { if b != nil {
@ -543,6 +572,7 @@ func XtlsUnpadding(ctx context.Context, buffer buf.MultiBuffer, userUUID []byte,
posByte = 16 posByte = 16
*remainingContent = 0 *remainingContent = 0
*remainingPadding = 0 *remainingPadding = 0
*currentCommand = 0
break break
} }
} }
@ -601,11 +631,3 @@ func XtlsUnpadding(ctx context.Context, buffer buf.MultiBuffer, userUUID []byte,
buf.ReleaseMulti(buffer) buf.ReleaseMulti(buffer)
return mb2 return mb2
} }
var Tls13CipherSuiteDic = map[uint16]string{
0x1301: "TLS_AES_128_GCM_SHA256",
0x1302: "TLS_AES_256_GCM_SHA384",
0x1303: "TLS_CHACHA20_POLY1305_SHA256",
0x1304: "TLS_AES_128_CCM_SHA256",
0x1305: "TLS_AES_128_CCM_8_SHA256",
}

View file

@ -624,11 +624,9 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
} }
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx) encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx)
if isTLS {
multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer) multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer)
for i, b := range multiBuffer { for i, b := range multiBuffer {
multiBuffer[i] = encoding.XtlsPadding(b, 0x00, &userUUID, ctx) multiBuffer[i] = encoding.XtlsPadding(b, encoding.CommandPaddingContinue, &userUUID, isTLS, ctx)
}
} }
} }
if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil { if err := clientWriter.WriteMultiBuffer(multiBuffer); err != nil {
@ -645,7 +643,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
if statConn != nil { if statConn != nil {
counter = statConn.WriteCounter counter = statConn.WriteCounter
} }
err = encoding.XtlsWrite(serverReader, clientWriter, timer, netConn, counter, ctx, &userUUID, &numberOfPacketToFilter, err = encoding.XtlsWrite(serverReader, clientWriter, timer, netConn, counter, ctx, &numberOfPacketToFilter,
&enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
} else { } else {
// from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer // from serverReader.ReadMultiBuffer to clientWriter.WriteMultiBufer

View file

@ -243,10 +243,9 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if err1 == nil { if err1 == nil {
if requestAddons.Flow == vless.XRV { if requestAddons.Flow == vless.XRV {
encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx) encoding.XtlsFilterTls(multiBuffer, &numberOfPacketToFilter, &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello, ctx)
if isTLS { multiBuffer = encoding.ReshapeMultiBuffer(ctx, multiBuffer)
for i, b := range multiBuffer { for i, b := range multiBuffer {
multiBuffer[i] = encoding.XtlsPadding(b, 0x00, &userUUID, ctx) multiBuffer[i] = encoding.XtlsPadding(b, encoding.CommandPaddingContinue, &userUUID, isTLS, ctx)
}
} }
} }
if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil { if err := serverWriter.WriteMultiBuffer(multiBuffer); err != nil {
@ -256,7 +255,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
return err1 return err1
} else if requestAddons.Flow == vless.XRV { } else if requestAddons.Flow == vless.XRV {
mb := make(buf.MultiBuffer, 1) mb := make(buf.MultiBuffer, 1)
mb[0] = encoding.XtlsPadding(nil, 0x01, &userUUID, ctx) // it must not be tls so padding finish with it (command 1) mb[0] = encoding.XtlsPadding(nil, encoding.CommandPaddingContinue, &userUUID, true, ctx) // we do a long padding to hide vless header
newError("Insert padding with empty content to camouflage VLESS header ", mb.Len()).WriteToLog(session.ExportIDToError(ctx)) newError("Insert padding with empty content to camouflage VLESS header ", mb.Len()).WriteToLog(session.ExportIDToError(ctx))
if err := serverWriter.WriteMultiBuffer(mb); err != nil { if err := serverWriter.WriteMultiBuffer(mb); err != nil {
return err return err
@ -285,7 +284,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
if statConn != nil { if statConn != nil {
counter = statConn.WriteCounter counter = statConn.WriteCounter
} }
err = encoding.XtlsWrite(clientReader, serverWriter, timer, netConn, counter, ctx, &userUUID, &numberOfPacketToFilter, err = encoding.XtlsWrite(clientReader, serverWriter, timer, netConn, counter, ctx, &numberOfPacketToFilter,
&enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello) &enableXtls, &isTLS12orAbove, &isTLS, &cipher, &remainingServerHello)
} else { } else {
// from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer // from clientReader.ReadMultiBuffer to serverWriter.WriteMultiBufer