github.com/xraypb/Xray-core@v1.8.1/proxy/vless/encoding/encoding.go (about) 1 package encoding 2 3 //go:generate go run github.com/xraypb/Xray-core/common/errors/errorgen 4 5 import ( 6 "bytes" 7 "context" 8 "crypto/rand" 9 "io" 10 "math/big" 11 "runtime" 12 "strconv" 13 "syscall" 14 "time" 15 16 "github.com/xraypb/Xray-core/common/buf" 17 "github.com/xraypb/Xray-core/common/errors" 18 "github.com/xraypb/Xray-core/common/net" 19 "github.com/xraypb/Xray-core/common/protocol" 20 "github.com/xraypb/Xray-core/common/session" 21 "github.com/xraypb/Xray-core/common/signal" 22 "github.com/xraypb/Xray-core/features/stats" 23 "github.com/xraypb/Xray-core/proxy/vless" 24 "github.com/xraypb/Xray-core/transport/internet/stat" 25 "github.com/xraypb/Xray-core/transport/internet/tls" 26 ) 27 28 const ( 29 Version = byte(0) 30 ) 31 32 var ( 33 tls13SupportedVersions = []byte{0x00, 0x2b, 0x00, 0x02, 0x03, 0x04} 34 tlsClientHandShakeStart = []byte{0x16, 0x03} 35 tlsServerHandShakeStart = []byte{0x16, 0x03, 0x03} 36 tlsApplicationDataStart = []byte{0x17, 0x03, 0x03} 37 38 Tls13CipherSuiteDic = map[uint16]string{ 39 0x1301: "TLS_AES_128_GCM_SHA256", 40 0x1302: "TLS_AES_256_GCM_SHA384", 41 0x1303: "TLS_CHACHA20_POLY1305_SHA256", 42 0x1304: "TLS_AES_128_CCM_SHA256", 43 0x1305: "TLS_AES_128_CCM_8_SHA256", 44 } 45 ) 46 47 const ( 48 tlsHandshakeTypeClientHello byte = 0x01 49 tlsHandshakeTypeServerHello byte = 0x02 50 51 CommandPaddingContinue byte = 0x00 52 CommandPaddingEnd byte = 0x01 53 CommandPaddingDirect byte = 0x02 54 ) 55 56 var addrParser = protocol.NewAddressParser( 57 protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv4), net.AddressFamilyIPv4), 58 protocol.AddressFamilyByte(byte(protocol.AddressTypeDomain), net.AddressFamilyDomain), 59 protocol.AddressFamilyByte(byte(protocol.AddressTypeIPv6), net.AddressFamilyIPv6), 60 protocol.PortThenAddress(), 61 ) 62 63 // EncodeRequestHeader writes encoded request header into the given writer. 64 func EncodeRequestHeader(writer io.Writer, request *protocol.RequestHeader, requestAddons *Addons) error { 65 buffer := buf.StackNew() 66 defer buffer.Release() 67 68 if err := buffer.WriteByte(request.Version); err != nil { 69 return newError("failed to write request version").Base(err) 70 } 71 72 if _, err := buffer.Write(request.User.Account.(*vless.MemoryAccount).ID.Bytes()); err != nil { 73 return newError("failed to write request user id").Base(err) 74 } 75 76 if err := EncodeHeaderAddons(&buffer, requestAddons); err != nil { 77 return newError("failed to encode request header addons").Base(err) 78 } 79 80 if err := buffer.WriteByte(byte(request.Command)); err != nil { 81 return newError("failed to write request command").Base(err) 82 } 83 84 if request.Command != protocol.RequestCommandMux { 85 if err := addrParser.WriteAddressPort(&buffer, request.Address, request.Port); err != nil { 86 return newError("failed to write request address and port").Base(err) 87 } 88 } 89 90 if _, err := writer.Write(buffer.Bytes()); err != nil { 91 return newError("failed to write request header").Base(err) 92 } 93 94 return nil 95 } 96 97 // DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream. 98 func DecodeRequestHeader(isfb bool, first *buf.Buffer, reader io.Reader, validator *vless.Validator) (*protocol.RequestHeader, *Addons, bool, error) { 99 buffer := buf.StackNew() 100 defer buffer.Release() 101 102 request := new(protocol.RequestHeader) 103 104 if isfb { 105 request.Version = first.Byte(0) 106 } else { 107 if _, err := buffer.ReadFullFrom(reader, 1); err != nil { 108 return nil, nil, false, newError("failed to read request version").Base(err) 109 } 110 request.Version = buffer.Byte(0) 111 } 112 113 switch request.Version { 114 case 0: 115 116 var id [16]byte 117 118 if isfb { 119 copy(id[:], first.BytesRange(1, 17)) 120 } else { 121 buffer.Clear() 122 if _, err := buffer.ReadFullFrom(reader, 16); err != nil { 123 return nil, nil, false, newError("failed to read request user id").Base(err) 124 } 125 copy(id[:], buffer.Bytes()) 126 } 127 128 if request.User = validator.Get(id); request.User == nil { 129 return nil, nil, isfb, newError("invalid request user id") 130 } 131 132 if isfb { 133 first.Advance(17) 134 } 135 136 requestAddons, err := DecodeHeaderAddons(&buffer, reader) 137 if err != nil { 138 return nil, nil, false, newError("failed to decode request header addons").Base(err) 139 } 140 141 buffer.Clear() 142 if _, err := buffer.ReadFullFrom(reader, 1); err != nil { 143 return nil, nil, false, newError("failed to read request command").Base(err) 144 } 145 146 request.Command = protocol.RequestCommand(buffer.Byte(0)) 147 switch request.Command { 148 case protocol.RequestCommandMux: 149 request.Address = net.DomainAddress("v1.mux.cool") 150 request.Port = 0 151 case protocol.RequestCommandTCP, protocol.RequestCommandUDP: 152 if addr, port, err := addrParser.ReadAddressPort(&buffer, reader); err == nil { 153 request.Address = addr 154 request.Port = port 155 } 156 } 157 if request.Address == nil { 158 return nil, nil, false, newError("invalid request address") 159 } 160 return request, requestAddons, false, nil 161 default: 162 return nil, nil, isfb, newError("invalid request version") 163 } 164 } 165 166 // EncodeResponseHeader writes encoded response header into the given writer. 167 func EncodeResponseHeader(writer io.Writer, request *protocol.RequestHeader, responseAddons *Addons) error { 168 buffer := buf.StackNew() 169 defer buffer.Release() 170 171 if err := buffer.WriteByte(request.Version); err != nil { 172 return newError("failed to write response version").Base(err) 173 } 174 175 if err := EncodeHeaderAddons(&buffer, responseAddons); err != nil { 176 return newError("failed to encode response header addons").Base(err) 177 } 178 179 if _, err := writer.Write(buffer.Bytes()); err != nil { 180 return newError("failed to write response header").Base(err) 181 } 182 183 return nil 184 } 185 186 // DecodeResponseHeader decodes and returns (if successful) a ResponseHeader from an input stream. 187 func DecodeResponseHeader(reader io.Reader, request *protocol.RequestHeader) (*Addons, error) { 188 buffer := buf.StackNew() 189 defer buffer.Release() 190 191 if _, err := buffer.ReadFullFrom(reader, 1); err != nil { 192 return nil, newError("failed to read response version").Base(err) 193 } 194 195 if buffer.Byte(0) != request.Version { 196 return nil, newError("unexpected response version. Expecting ", int(request.Version), " but actually ", int(buffer.Byte(0))) 197 } 198 199 responseAddons, err := DecodeHeaderAddons(&buffer, reader) 200 if err != nil { 201 return nil, newError("failed to decode response header addons").Base(err) 202 } 203 204 return responseAddons, nil 205 } 206 207 // XtlsRead filter and read xtls protocol 208 func XtlsRead(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, rawConn syscall.RawConn, 209 input *bytes.Reader, rawInput *bytes.Buffer, 210 counter stats.Counter, ctx context.Context, userUUID []byte, numberOfPacketToFilter *int, enableXtls *bool, 211 isTLS12orAbove *bool, isTLS *bool, cipher *uint16, remainingServerHello *int32, 212 ) error { 213 err := func() error { 214 var ct stats.Counter 215 withinPaddingBuffers := true 216 shouldSwitchToDirectCopy := false 217 var remainingContent int32 = -1 218 var remainingPadding int32 = -1 219 currentCommand := 0 220 for { 221 if shouldSwitchToDirectCopy { 222 shouldSwitchToDirectCopy = false 223 if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Conn != nil && (runtime.GOOS == "linux" || runtime.GOOS == "android") { 224 if _, ok := inbound.User.Account.(*vless.MemoryAccount); inbound.User.Account == nil || ok { 225 iConn := inbound.Conn 226 statConn, ok := iConn.(*stat.CounterConnection) 227 if ok { 228 iConn = statConn.Connection 229 } 230 if xc, ok := iConn.(*tls.Conn); ok { 231 iConn = xc.NetConn() 232 } 233 if tc, ok := iConn.(*net.TCPConn); ok { 234 newError("XtlsRead splice").WriteToLog(session.ExportIDToError(ctx)) 235 runtime.Gosched() // necessary 236 w, err := tc.ReadFrom(conn) 237 if counter != nil { 238 counter.Add(w) 239 } 240 if statConn != nil && statConn.WriteCounter != nil { 241 statConn.WriteCounter.Add(w) 242 } 243 return err 244 } 245 } 246 } 247 reader = buf.NewReadVReader(conn, rawConn, nil) 248 ct = counter 249 newError("XtlsRead readV").WriteToLog(session.ExportIDToError(ctx)) 250 } 251 buffer, err := reader.ReadMultiBuffer() 252 if !buffer.IsEmpty() { 253 if withinPaddingBuffers || *numberOfPacketToFilter > 0 { 254 buffer = XtlsUnpadding(ctx, buffer, userUUID, &remainingContent, &remainingPadding, ¤tCommand) 255 if remainingContent == 0 && remainingPadding == 0 { 256 if currentCommand == 1 { 257 withinPaddingBuffers = false 258 remainingContent = -1 259 remainingPadding = -1 // set to initial state to parse the next padding 260 } else if currentCommand == 2 { 261 withinPaddingBuffers = false 262 shouldSwitchToDirectCopy = true 263 // XTLS Vision processes struct TLS Conn's input and rawInput 264 if inputBuffer, err := buf.ReadFrom(input); err == nil { 265 if !inputBuffer.IsEmpty() { 266 buffer, _ = buf.MergeMulti(buffer, inputBuffer) 267 } 268 } 269 if rawInputBuffer, err := buf.ReadFrom(rawInput); err == nil { 270 if !rawInputBuffer.IsEmpty() { 271 buffer, _ = buf.MergeMulti(buffer, rawInputBuffer) 272 } 273 } 274 } else if currentCommand == 0 { 275 withinPaddingBuffers = true 276 } else { 277 newError("XtlsRead unknown command ", currentCommand, buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) 278 } 279 } else if remainingContent > 0 || remainingPadding > 0 { 280 withinPaddingBuffers = true 281 } else { 282 withinPaddingBuffers = false 283 } 284 } 285 if *numberOfPacketToFilter > 0 { 286 XtlsFilterTls(buffer, numberOfPacketToFilter, enableXtls, isTLS12orAbove, isTLS, cipher, remainingServerHello, ctx) 287 } 288 if ct != nil { 289 ct.Add(int64(buffer.Len())) 290 } 291 timer.Update() 292 if werr := writer.WriteMultiBuffer(buffer); werr != nil { 293 return werr 294 } 295 } 296 if err != nil { 297 return err 298 } 299 } 300 }() 301 if err != nil && errors.Cause(err) != io.EOF { 302 return err 303 } 304 return nil 305 } 306 307 // XtlsWrite filter and write xtls protocol 308 func XtlsWrite(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn net.Conn, counter stats.Counter, 309 ctx context.Context, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool, 310 cipher *uint16, remainingServerHello *int32, 311 ) error { 312 err := func() error { 313 var ct stats.Counter 314 isPadding := true 315 shouldSwitchToDirectCopy := false 316 for { 317 buffer, err := reader.ReadMultiBuffer() 318 if !buffer.IsEmpty() { 319 if *numberOfPacketToFilter > 0 { 320 XtlsFilterTls(buffer, numberOfPacketToFilter, enableXtls, isTLS12orAbove, isTLS, cipher, remainingServerHello, ctx) 321 } 322 if isPadding { 323 buffer = ReshapeMultiBuffer(ctx, buffer) 324 var xtlsSpecIndex int 325 for i, b := range buffer { 326 if *isTLS && b.Len() >= 6 && bytes.Equal(tlsApplicationDataStart, b.BytesTo(3)) { 327 var command byte = CommandPaddingEnd 328 if *enableXtls { 329 shouldSwitchToDirectCopy = true 330 xtlsSpecIndex = i 331 command = CommandPaddingDirect 332 } 333 isPadding = false 334 buffer[i] = XtlsPadding(b, command, nil, *isTLS, ctx) 335 break 336 } else if !*isTLS12orAbove && *numberOfPacketToFilter <= 1 { // For compatibility with earlier vision receiver, we finish padding 1 packet early 337 isPadding = false 338 buffer[i] = XtlsPadding(b, CommandPaddingEnd, nil, *isTLS, ctx) 339 break 340 } 341 buffer[i] = XtlsPadding(b, CommandPaddingContinue, nil, *isTLS, ctx) 342 } 343 if shouldSwitchToDirectCopy { 344 encryptBuffer, directBuffer := buf.SplitMulti(buffer, xtlsSpecIndex+1) 345 length := encryptBuffer.Len() 346 if !encryptBuffer.IsEmpty() { 347 timer.Update() 348 if werr := writer.WriteMultiBuffer(encryptBuffer); werr != nil { 349 return werr 350 } 351 } 352 buffer = directBuffer 353 writer = buf.NewWriter(conn) 354 ct = counter 355 newError("XtlsWrite writeV ", xtlsSpecIndex, " ", length, " ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) 356 time.Sleep(5 * time.Millisecond) // for some device, the first xtls direct packet fails without this delay 357 } 358 } 359 if !buffer.IsEmpty() { 360 if ct != nil { 361 ct.Add(int64(buffer.Len())) 362 } 363 timer.Update() 364 if werr := writer.WriteMultiBuffer(buffer); werr != nil { 365 return werr 366 } 367 } 368 } 369 if err != nil { 370 return err 371 } 372 } 373 }() 374 if err != nil && errors.Cause(err) != io.EOF { 375 return err 376 } 377 return nil 378 } 379 380 // XtlsFilterTls filter and recognize tls 1.3 and other info 381 func XtlsFilterTls(buffer buf.MultiBuffer, numberOfPacketToFilter *int, enableXtls *bool, isTLS12orAbove *bool, isTLS *bool, 382 cipher *uint16, remainingServerHello *int32, ctx context.Context, 383 ) { 384 for _, b := range buffer { 385 *numberOfPacketToFilter-- 386 if b.Len() >= 6 { 387 startsBytes := b.BytesTo(6) 388 if bytes.Equal(tlsServerHandShakeStart, startsBytes[:3]) && startsBytes[5] == tlsHandshakeTypeServerHello { 389 *remainingServerHello = (int32(startsBytes[3])<<8 | int32(startsBytes[4])) + 5 390 *isTLS12orAbove = true 391 *isTLS = true 392 if b.Len() >= 79 && *remainingServerHello >= 79 { 393 sessionIdLen := int32(b.Byte(43)) 394 cipherSuite := b.BytesRange(43+sessionIdLen+1, 43+sessionIdLen+3) 395 *cipher = uint16(cipherSuite[0])<<8 | uint16(cipherSuite[1]) 396 } else { 397 newError("XtlsFilterTls short server hello, tls 1.2 or older? ", b.Len(), " ", *remainingServerHello).WriteToLog(session.ExportIDToError(ctx)) 398 } 399 } else if bytes.Equal(tlsClientHandShakeStart, startsBytes[:2]) && startsBytes[5] == tlsHandshakeTypeClientHello { 400 *isTLS = true 401 newError("XtlsFilterTls found tls client hello! ", buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) 402 } 403 } 404 if *remainingServerHello > 0 { 405 end := *remainingServerHello 406 if end > b.Len() { 407 end = b.Len() 408 } 409 *remainingServerHello -= b.Len() 410 if bytes.Contains(b.BytesTo(end), tls13SupportedVersions) { 411 v, ok := Tls13CipherSuiteDic[*cipher] 412 if !ok { 413 v = "Old cipher: " + strconv.FormatUint(uint64(*cipher), 16) 414 } else if v != "TLS_AES_128_CCM_8_SHA256" { 415 *enableXtls = true 416 } 417 newError("XtlsFilterTls found tls 1.3! ", b.Len(), " ", v).WriteToLog(session.ExportIDToError(ctx)) 418 *numberOfPacketToFilter = 0 419 return 420 } else if *remainingServerHello <= 0 { 421 newError("XtlsFilterTls found tls 1.2! ", b.Len()).WriteToLog(session.ExportIDToError(ctx)) 422 *numberOfPacketToFilter = 0 423 return 424 } 425 newError("XtlsFilterTls inconclusive server hello ", b.Len(), " ", *remainingServerHello).WriteToLog(session.ExportIDToError(ctx)) 426 } 427 if *numberOfPacketToFilter <= 0 { 428 newError("XtlsFilterTls stop filtering", buffer.Len()).WriteToLog(session.ExportIDToError(ctx)) 429 } 430 } 431 } 432 433 // ReshapeMultiBuffer prepare multi buffer for padding stucture (max 21 bytes) 434 func ReshapeMultiBuffer(ctx context.Context, buffer buf.MultiBuffer) buf.MultiBuffer { 435 needReshape := 0 436 for _, b := range buffer { 437 if b.Len() >= buf.Size-21 { 438 needReshape += 1 439 } 440 } 441 if needReshape == 0 { 442 return buffer 443 } 444 mb2 := make(buf.MultiBuffer, 0, len(buffer)+needReshape) 445 toPrint := "" 446 for i, buffer1 := range buffer { 447 if buffer1.Len() >= buf.Size-21 { 448 index := int32(bytes.LastIndex(buffer1.Bytes(), tlsApplicationDataStart)) 449 if index <= 0 || index > buf.Size-21 { 450 index = buf.Size / 2 451 } 452 buffer2 := buf.New() 453 buffer2.Write(buffer1.BytesFrom(index)) 454 buffer1.Resize(0, index) 455 mb2 = append(mb2, buffer1, buffer2) 456 toPrint += " " + strconv.Itoa(int(buffer1.Len())) + " " + strconv.Itoa(int(buffer2.Len())) 457 } else { 458 mb2 = append(mb2, buffer1) 459 toPrint += " " + strconv.Itoa(int(buffer1.Len())) 460 } 461 buffer[i] = nil 462 } 463 buffer = buffer[:0] 464 newError("ReshapeMultiBuffer ", toPrint).WriteToLog(session.ExportIDToError(ctx)) 465 return mb2 466 } 467 468 // XtlsPadding add padding to eliminate length siganature during tls handshake 469 func XtlsPadding(b *buf.Buffer, command byte, userUUID *[]byte, longPadding bool, ctx context.Context) *buf.Buffer { 470 var contentLen int32 = 0 471 var paddingLen int32 = 0 472 if b != nil { 473 contentLen = b.Len() 474 } 475 if contentLen < 900 && longPadding { 476 l, err := rand.Int(rand.Reader, big.NewInt(500)) 477 if err != nil { 478 newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx)) 479 } 480 paddingLen = int32(l.Int64()) + 900 - contentLen 481 } else { 482 l, err := rand.Int(rand.Reader, big.NewInt(256)) 483 if err != nil { 484 newError("failed to generate padding").Base(err).WriteToLog(session.ExportIDToError(ctx)) 485 } 486 paddingLen = int32(l.Int64()) 487 } 488 if paddingLen > buf.Size-21-contentLen { 489 paddingLen = buf.Size - 21 - contentLen 490 } 491 newbuffer := buf.New() 492 if userUUID != nil { 493 newbuffer.Write(*userUUID) 494 *userUUID = nil 495 } 496 newbuffer.Write([]byte{command, byte(contentLen >> 8), byte(contentLen), byte(paddingLen >> 8), byte(paddingLen)}) 497 if b != nil { 498 newbuffer.Write(b.Bytes()) 499 b.Release() 500 b = nil 501 } 502 newbuffer.Extend(paddingLen) 503 newError("XtlsPadding ", contentLen, " ", paddingLen, " ", command).WriteToLog(session.ExportIDToError(ctx)) 504 return newbuffer 505 } 506 507 // XtlsUnpadding remove padding and parse command 508 func XtlsUnpadding(ctx context.Context, buffer buf.MultiBuffer, userUUID []byte, remainingContent *int32, remainingPadding *int32, currentCommand *int) buf.MultiBuffer { 509 posindex := 0 510 var posByte int32 = 0 511 if *remainingContent == -1 && *remainingPadding == -1 { 512 for i, b := range buffer { 513 if b.Len() >= 21 && bytes.Equal(userUUID, b.BytesTo(16)) { 514 posindex = i 515 posByte = 16 516 *remainingContent = 0 517 *remainingPadding = 0 518 *currentCommand = 0 519 break 520 } 521 } 522 } 523 if *remainingContent == -1 && *remainingPadding == -1 { 524 return buffer 525 } 526 mb2 := make(buf.MultiBuffer, 0, len(buffer)) 527 for i := 0; i < posindex; i++ { 528 newbuffer := buf.New() 529 newbuffer.Write(buffer[i].Bytes()) 530 mb2 = append(mb2, newbuffer) 531 } 532 for i := posindex; i < len(buffer); i++ { 533 b := buffer[i] 534 for posByte < b.Len() { 535 if *remainingContent <= 0 && *remainingPadding <= 0 { 536 if *currentCommand == 1 { // possible buffer after padding, no need to worry about xtls (command 2) 537 len := b.Len() - posByte 538 newbuffer := buf.New() 539 newbuffer.Write(b.BytesRange(posByte, posByte+len)) 540 mb2 = append(mb2, newbuffer) 541 posByte += len 542 } else { 543 paddingInfo := b.BytesRange(posByte, posByte+5) 544 *currentCommand = int(paddingInfo[0]) 545 *remainingContent = int32(paddingInfo[1])<<8 | int32(paddingInfo[2]) 546 *remainingPadding = int32(paddingInfo[3])<<8 | int32(paddingInfo[4]) 547 newError("Xtls Unpadding new block", i, " ", posByte, " content ", *remainingContent, " padding ", *remainingPadding, " ", paddingInfo[0]).WriteToLog(session.ExportIDToError(ctx)) 548 posByte += 5 549 } 550 } else if *remainingContent > 0 { 551 len := *remainingContent 552 if b.Len() < posByte+*remainingContent { 553 len = b.Len() - posByte 554 } 555 newbuffer := buf.New() 556 newbuffer.Write(b.BytesRange(posByte, posByte+len)) 557 mb2 = append(mb2, newbuffer) 558 *remainingContent -= len 559 posByte += len 560 } else { // remainingPadding > 0 561 len := *remainingPadding 562 if b.Len() < posByte+*remainingPadding { 563 len = b.Len() - posByte 564 } 565 *remainingPadding -= len 566 posByte += len 567 } 568 if posByte == b.Len() { 569 posByte = 0 570 break 571 } 572 } 573 } 574 buf.ReleaseMulti(buffer) 575 return mb2 576 }