mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-22 12:49:20 +02:00
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:
parent
55dc26f228
commit
2d898480be
|
@ -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, ¤tCommand)
|
buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, ¤tCommand)
|
||||||
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",
|
|
||||||
}
|
|
||||||
|
|
|
@ -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, encoding.CommandPaddingContinue, &userUUID, isTLS, ctx)
|
||||||
multiBuffer[i] = encoding.XtlsPadding(b, 0x00, &userUUID, 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue