| 
					
				 | 
			
			
				@@ -16,6 +16,7 @@ import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	v2net "github.com/v2ray/v2ray-core/common/net" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/v2ray/v2ray-core/proxy" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/v2ray/v2ray-core/proxy/internal" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	vmessio "github.com/v2ray/v2ray-core/proxy/vmess/io" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/v2ray/v2ray-core/proxy/vmess/protocol" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"github.com/v2ray/v2ray-core/transport/ray" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -38,6 +39,9 @@ func (this *VMessOutboundHandler) Dispatch(firstPacket v2net.Packet, ray ray.Out 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Address: firstPacket.Destination().Address(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Port:    firstPacket.Destination().Port(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if command == protocol.CmdUDP { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		request.Option |= protocol.OptionChunk 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	buffer := alloc.NewSmallBuffer() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	defer buffer.Release()                      // Buffer is released after communication finishes. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -83,7 +87,7 @@ func (this *VMessOutboundHandler) startCommunicate(request *protocol.VMessReques 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	responseFinish.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	go this.handleRequest(conn, request, firstPacket, input, &requestFinish) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	go this.handleResponse(conn, request, dest, output, &responseFinish, (request.Command == protocol.CmdUDP)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	go this.handleResponse(conn, request, dest, output, &responseFinish) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	requestFinish.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	conn.CloseWrite() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -121,6 +125,10 @@ func (this *VMessOutboundHandler) handleRequest(conn net.Conn, request *protocol 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if request.IsChunkStream() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		vmessio.Authenticate(firstChunk) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	aesStream.XORKeyStream(firstChunk.Value, firstChunk.Value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	buffer.Append(firstChunk.Value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	firstChunk.Release() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -132,7 +140,12 @@ func (this *VMessOutboundHandler) handleRequest(conn net.Conn, request *protocol 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if moreChunks { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		v2io.ChanToWriter(encryptRequestWriter, input) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		var streamWriter v2io.Writer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		streamWriter = v2io.NewAdaptiveWriter(encryptRequestWriter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if request.IsChunkStream() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			streamWriter = vmessio.NewAuthChunkWriter(streamWriter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		v2io.ChanToWriter(streamWriter, input) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -141,7 +154,7 @@ func headerMatch(request *protocol.VMessRequest, responseHeader byte) bool { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return request.ResponseHeader == responseHeader 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (this *VMessOutboundHandler) handleResponse(conn net.Conn, request *protocol.VMessRequest, dest v2net.Destination, output chan<- *alloc.Buffer, finish *sync.Mutex, isUDP bool) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (this *VMessOutboundHandler) handleResponse(conn net.Conn, request *protocol.VMessRequest, dest v2net.Destination, output chan<- *alloc.Buffer, finish *sync.Mutex) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	defer finish.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	defer close(output) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	responseKey := md5.Sum(request.RequestKey[:]) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -154,39 +167,40 @@ func (this *VMessOutboundHandler) handleResponse(conn net.Conn, request *protoco 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	decryptResponseReader := v2crypto.NewCryptionReader(aesStream, conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	buffer, err := v2io.ReadFrom(decryptResponseReader, nil) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	buffer := alloc.NewSmallBuffer() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	defer buffer.Release() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	_, err = io.ReadFull(decryptResponseReader, buffer.Value[:4]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		log.Error("VMessOut: Failed to read VMess response (", buffer.Len(), " bytes): ", err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		buffer.Release() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if buffer.Len() < 4 || !headerMatch(request, buffer.Value[0]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if !headerMatch(request, buffer.Value[0]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		log.Warning("VMessOut: unexepcted response header. The connection is probably hijacked.") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	log.Info("VMessOut received ", buffer.Len()-4, " bytes from ", conn.RemoteAddr()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	responseBegin := 4 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if buffer.Value[2] != 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		command := buffer.Value[2] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		dataLen := int(buffer.Value[3]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if buffer.Len() < dataLen+4 { // Rare case 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			diffBuffer := make([]byte, dataLen+4-buffer.Len()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			io.ReadFull(decryptResponseReader, diffBuffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			buffer.Append(diffBuffer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		_, err := io.ReadFull(decryptResponseReader, buffer.Value[:dataLen]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if err != nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			log.Error("VMessOut: Failed to read response command: ", err) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		command := buffer.Value[2] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		data := buffer.Value[4 : 4+dataLen] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		data := buffer.Value[:dataLen] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		go this.handleCommand(dest, command, data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		responseBegin = 4 + dataLen 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	buffer.SliceFrom(responseBegin) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	output <- buffer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if !isUDP { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		v2io.RawReaderToChan(output, decryptResponseReader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var reader v2io.Reader 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if request.IsChunkStream() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		reader = vmessio.NewAuthChunkReader(decryptResponseReader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		reader = v2io.NewAdaptiveReader(decryptResponseReader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	v2io.ReaderToChan(output, reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |