|  | @@ -27,14 +27,14 @@ type VNextServer struct {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  type VMessOutboundHandler struct {
 | 
	
		
			
				|  |  |  	vPoint    *core.Point
 | 
	
		
			
				|  |  | -	dest      v2net.Destination
 | 
	
		
			
				|  |  | +	packet    v2net.Packet
 | 
	
		
			
				|  |  |  	vNextList []VNextServer
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func NewVMessOutboundHandler(vp *core.Point, vNextList []VNextServer, dest v2net.Destination) *VMessOutboundHandler {
 | 
	
		
			
				|  |  | +func NewVMessOutboundHandler(vp *core.Point, vNextList []VNextServer, firstPacket v2net.Packet) *VMessOutboundHandler {
 | 
	
		
			
				|  |  |  	return &VMessOutboundHandler{
 | 
	
		
			
				|  |  |  		vPoint:    vp,
 | 
	
		
			
				|  |  | -		dest:      dest,
 | 
	
		
			
				|  |  | +		packet:    firstPacket,
 | 
	
		
			
				|  |  |  		vNextList: vNextList,
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -66,37 +66,50 @@ func (handler *VMessOutboundHandler) Start(ray core.OutboundRay) error {
 | 
	
		
			
				|  |  |  	vNextAddress, vNextUser := handler.pickVNext()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	command := protocol.CmdTCP
 | 
	
		
			
				|  |  | -	if handler.dest.IsUDP() {
 | 
	
		
			
				|  |  | +	if handler.packet.Destination().IsUDP() {
 | 
	
		
			
				|  |  |  		command = protocol.CmdUDP
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	request := &protocol.VMessRequest{
 | 
	
		
			
				|  |  |  		Version: protocol.Version,
 | 
	
		
			
				|  |  |  		UserId:  vNextUser.Id,
 | 
	
		
			
				|  |  |  		Command: command,
 | 
	
		
			
				|  |  | -		Address: handler.dest.Address(),
 | 
	
		
			
				|  |  | +		Address: handler.packet.Destination().Address(),
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	rand.Read(request.RequestIV[:])
 | 
	
		
			
				|  |  |  	rand.Read(request.RequestKey[:])
 | 
	
		
			
				|  |  |  	rand.Read(request.ResponseHeader[:])
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	go startCommunicate(request, vNextAddress, ray)
 | 
	
		
			
				|  |  | +	go startCommunicate(request, vNextAddress, ray, handler.packet)
 | 
	
		
			
				|  |  |  	return nil
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray core.OutboundRay) error {
 | 
	
		
			
				|  |  | -	input := ray.OutboundInput()
 | 
	
		
			
				|  |  | -	output := ray.OutboundOutput()
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +func startCommunicate(request *protocol.VMessRequest, dest v2net.Destination, ray core.OutboundRay, firstPacket v2net.Packet) error {
 | 
	
		
			
				|  |  |  	conn, err := net.DialTCP(dest.Network(), nil, &net.TCPAddr{dest.Address().IP(), int(dest.Address().Port()), ""})
 | 
	
		
			
				|  |  |  	if err != nil {
 | 
	
		
			
				|  |  |  		log.Error("Failed to open tcp (%s): %v", dest.String(), err)
 | 
	
		
			
				|  |  | -		close(output)
 | 
	
		
			
				|  |  | +		if ray != nil {
 | 
	
		
			
				|  |  | +			close(ray.OutboundOutput())
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  |  		return err
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	log.Info("VMessOut: Tunneling request for %s", request.Address.String())
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	defer conn.Close()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +	if chunk := firstPacket.Chunk(); chunk != nil {
 | 
	
		
			
				|  |  | +		conn.Write(chunk)
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if !firstPacket.MoreChunks() {
 | 
	
		
			
				|  |  | +		if ray != nil {
 | 
	
		
			
				|  |  | +			close(ray.OutboundOutput())
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		return nil
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	input := ray.OutboundInput()
 | 
	
		
			
				|  |  | +	output := ray.OutboundOutput()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  	requestFinish := make(chan bool)
 | 
	
		
			
				|  |  |  	responseFinish := make(chan bool)
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -171,7 +184,7 @@ func handleResponse(conn *net.TCPConn, request *protocol.VMessRequest, output ch
 | 
	
		
			
				|  |  |  type VMessOutboundHandlerFactory struct {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (factory *VMessOutboundHandlerFactory) Create(vp *core.Point, rawConfig []byte, destination v2net.Destination) (core.OutboundConnectionHandler, error) {
 | 
	
		
			
				|  |  | +func (factory *VMessOutboundHandlerFactory) Create(vp *core.Point, rawConfig []byte, firstPacket v2net.Packet) (core.OutboundConnectionHandler, error) {
 | 
	
		
			
				|  |  |  	config, err := loadOutboundConfig(rawConfig)
 | 
	
		
			
				|  |  |  	if err != nil {
 | 
	
		
			
				|  |  |  		panic(log.Error("Failed to load VMess outbound config: %v", err))
 | 
	
	
		
			
				|  | @@ -180,7 +193,7 @@ func (factory *VMessOutboundHandlerFactory) Create(vp *core.Point, rawConfig []b
 | 
	
		
			
				|  |  |  	for _, server := range config.VNextList {
 | 
	
		
			
				|  |  |  		servers = append(servers, server.ToVNextServer())
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	return NewVMessOutboundHandler(vp, servers, destination), nil
 | 
	
		
			
				|  |  | +	return NewVMessOutboundHandler(vp, servers, firstPacket), nil
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  func init() {
 |