|  | @@ -10,23 +10,17 @@ import (
 | 
											
												
													
														|  |  	"v2ray.com/core/common"
 |  |  	"v2ray.com/core/common"
 | 
											
												
													
														|  |  	"v2ray.com/core/common/buf"
 |  |  	"v2ray.com/core/common/buf"
 | 
											
												
													
														|  |  	"v2ray.com/core/common/bufio"
 |  |  	"v2ray.com/core/common/bufio"
 | 
											
												
													
														|  | -	"v2ray.com/core/common/crypto"
 |  | 
 | 
											
												
													
														|  |  	"v2ray.com/core/common/errors"
 |  |  	"v2ray.com/core/common/errors"
 | 
											
												
													
														|  |  	"v2ray.com/core/common/log"
 |  |  	"v2ray.com/core/common/log"
 | 
											
												
													
														|  |  	v2net "v2ray.com/core/common/net"
 |  |  	v2net "v2ray.com/core/common/net"
 | 
											
												
													
														|  | 
 |  | +	proto "v2ray.com/core/common/protocol"
 | 
											
												
													
														|  |  	"v2ray.com/core/common/serial"
 |  |  	"v2ray.com/core/common/serial"
 | 
											
												
													
														|  |  	"v2ray.com/core/common/signal"
 |  |  	"v2ray.com/core/common/signal"
 | 
											
												
													
														|  |  	"v2ray.com/core/proxy"
 |  |  	"v2ray.com/core/proxy"
 | 
											
												
													
														|  | -	"v2ray.com/core/proxy/socks/protocol"
 |  | 
 | 
											
												
													
														|  |  	"v2ray.com/core/transport/internet"
 |  |  	"v2ray.com/core/transport/internet"
 | 
											
												
													
														|  |  	"v2ray.com/core/transport/internet/udp"
 |  |  	"v2ray.com/core/transport/internet/udp"
 | 
											
												
													
														|  |  )
 |  |  )
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -var (
 |  | 
 | 
											
												
													
														|  | -	ErrUnsupportedSocksCommand = errors.New("Unsupported socks command.")
 |  | 
 | 
											
												
													
														|  | -	ErrUnsupportedAuthMethod   = errors.New("Unsupported auth method.")
 |  | 
 | 
											
												
													
														|  | -)
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |  // Server is a SOCKS 5 proxy server
 |  |  // Server is a SOCKS 5 proxy server
 | 
											
												
													
														|  |  type Server struct {
 |  |  type Server struct {
 | 
											
												
													
														|  |  	tcpMutex         sync.RWMutex
 |  |  	tcpMutex         sync.RWMutex
 | 
											
										
											
												
													
														|  | @@ -79,7 +73,7 @@ func (v *Server) Close() {
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -// Listen implements InboundHandler.Listen().
 |  | 
 | 
											
												
													
														|  | 
 |  | +// Start implements InboundHandler.Start().
 | 
											
												
													
														|  |  func (v *Server) Start() error {
 |  |  func (v *Server) Start() error {
 | 
											
												
													
														|  |  	if v.accepting {
 |  |  	if v.accepting {
 | 
											
												
													
														|  |  		return nil
 |  |  		return nil
 | 
											
										
											
												
													
														|  | @@ -113,153 +107,41 @@ func (v *Server) handleConnection(connection internet.Connection) {
 | 
											
												
													
														|  |  	reader := bufio.NewReader(timedReader)
 |  |  	reader := bufio.NewReader(timedReader)
 | 
											
												
													
														|  |  	defer reader.Release()
 |  |  	defer reader.Release()
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -	writer := bufio.NewWriter(connection)
 |  | 
 | 
											
												
													
														|  | -	defer writer.Release()
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	auth, auth4, err := protocol.ReadAuthentication(reader)
 |  | 
 | 
											
												
													
														|  | -	if err != nil && errors.Cause(err) != protocol.Socks4Downgrade {
 |  | 
 | 
											
												
													
														|  | -		if errors.Cause(err) != io.EOF {
 |  | 
 | 
											
												
													
														|  | -			log.Warning("Socks: failed to read authentication: ", err)
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		return
 |  | 
 | 
											
												
													
														|  | 
 |  | +	session := &ServerSession{
 | 
											
												
													
														|  | 
 |  | +		config: v.config,
 | 
											
												
													
														|  | 
 |  | +		meta:   v.meta,
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	clientAddr := v2net.DestinationFromAddr(connection.RemoteAddr())
 |  |  	clientAddr := v2net.DestinationFromAddr(connection.RemoteAddr())
 | 
											
												
													
														|  | -	if err != nil && err == protocol.Socks4Downgrade {
 |  | 
 | 
											
												
													
														|  | -		v.handleSocks4(clientAddr, reader, writer, auth4)
 |  | 
 | 
											
												
													
														|  | -	} else {
 |  | 
 | 
											
												
													
														|  | -		v.handleSocks5(clientAddr, reader, writer, auth)
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -func (v *Server) handleSocks5(clientAddr v2net.Destination, reader *bufio.BufferedReader, writer *bufio.BufferedWriter, auth protocol.Socks5AuthenticationRequest) error {
 |  | 
 | 
											
												
													
														|  | -	expectedAuthMethod := protocol.AuthNotRequired
 |  | 
 | 
											
												
													
														|  | -	if v.config.AuthType == AuthType_PASSWORD {
 |  | 
 | 
											
												
													
														|  | -		expectedAuthMethod = protocol.AuthUserPass
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if !auth.HasAuthMethod(expectedAuthMethod) {
 |  | 
 | 
											
												
													
														|  | -		authResponse := protocol.NewAuthenticationResponse(protocol.AuthNoMatchingMethod)
 |  | 
 | 
											
												
													
														|  | -		err := protocol.WriteAuthentication(writer, authResponse)
 |  | 
 | 
											
												
													
														|  | -		writer.Flush()
 |  | 
 | 
											
												
													
														|  | -		if err != nil {
 |  | 
 | 
											
												
													
														|  | -			log.Warning("Socks: failed to write authentication: ", err)
 |  | 
 | 
											
												
													
														|  | -			return err
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		log.Warning("Socks: client doesn't support any allowed auth methods.")
 |  | 
 | 
											
												
													
														|  | -		return ErrUnsupportedAuthMethod
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	authResponse := protocol.NewAuthenticationResponse(expectedAuthMethod)
 |  | 
 | 
											
												
													
														|  | -	protocol.WriteAuthentication(writer, authResponse)
 |  | 
 | 
											
												
													
														|  | -	err := writer.Flush()
 |  | 
 | 
											
												
													
														|  | -	if err != nil {
 |  | 
 | 
											
												
													
														|  | -		log.Error("Socks: failed to write authentication: ", err)
 |  | 
 | 
											
												
													
														|  | -		return err
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	if v.config.AuthType == AuthType_PASSWORD {
 |  | 
 | 
											
												
													
														|  | -		upRequest, err := protocol.ReadUserPassRequest(reader)
 |  | 
 | 
											
												
													
														|  | -		if err != nil {
 |  | 
 | 
											
												
													
														|  | -			log.Warning("Socks: failed to read username and password: ", err)
 |  | 
 | 
											
												
													
														|  | -			return err
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		status := byte(0)
 |  | 
 | 
											
												
													
														|  | -		if !v.config.HasAccount(upRequest.Username(), upRequest.Password()) {
 |  | 
 | 
											
												
													
														|  | -			status = byte(0xFF)
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		upResponse := protocol.NewSocks5UserPassResponse(status)
 |  | 
 | 
											
												
													
														|  | -		err = protocol.WriteUserPassResponse(writer, upResponse)
 |  | 
 | 
											
												
													
														|  | -		writer.Flush()
 |  | 
 | 
											
												
													
														|  | -		if err != nil {
 |  | 
 | 
											
												
													
														|  | -			log.Error("Socks: failed to write user pass response: ", err)
 |  | 
 | 
											
												
													
														|  | -			return err
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		if status != byte(0) {
 |  | 
 | 
											
												
													
														|  | -			log.Warning("Socks: Invalid user account: ", upRequest.AuthDetail())
 |  | 
 | 
											
												
													
														|  | -			log.Access(clientAddr, "", log.AccessRejected, crypto.ErrAuthenticationFailed)
 |  | 
 | 
											
												
													
														|  | -			return crypto.ErrAuthenticationFailed
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -	request, err := protocol.ReadRequest(reader)
 |  | 
 | 
											
												
													
														|  | 
 |  | +	request, err := session.Handshake(reader, connection)
 | 
											
												
													
														|  |  	if err != nil {
 |  |  	if err != nil {
 | 
											
												
													
														|  | -		log.Warning("Socks: failed to read request: ", err)
 |  | 
 | 
											
												
													
														|  | -		return err
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if request.Command == protocol.CmdUdpAssociate && v.config.UdpEnabled {
 |  | 
 | 
											
												
													
														|  | -		return v.handleUDP(reader, writer)
 |  | 
 | 
											
												
													
														|  | 
 |  | +		log.Access(clientAddr, "", log.AccessRejected, err)
 | 
											
												
													
														|  | 
 |  | +		log.Info("Socks|Server: Failed to read request: ", err)
 | 
											
												
													
														|  | 
 |  | +		return
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -	if request.Command == protocol.CmdBind || request.Command == protocol.CmdUdpAssociate {
 |  | 
 | 
											
												
													
														|  | -		response := protocol.NewSocks5Response()
 |  | 
 | 
											
												
													
														|  | -		response.Error = protocol.ErrorCommandNotSupported
 |  | 
 | 
											
												
													
														|  | -		response.Port = v2net.Port(0)
 |  | 
 | 
											
												
													
														|  | -		response.SetIPv4([]byte{0, 0, 0, 0})
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		response.Write(writer)
 |  | 
 | 
											
												
													
														|  | -		writer.Flush()
 |  | 
 | 
											
												
													
														|  | -		if err != nil {
 |  | 
 | 
											
												
													
														|  | -			log.Error("Socks: failed to write response: ", err)
 |  | 
 | 
											
												
													
														|  | -			return err
 |  | 
 | 
											
												
													
														|  | 
 |  | +	if request.Command == proto.RequestCommandTCP {
 | 
											
												
													
														|  | 
 |  | +		dest := request.Destination()
 | 
											
												
													
														|  | 
 |  | +		session := &proxy.SessionInfo{
 | 
											
												
													
														|  | 
 |  | +			Source:      clientAddr,
 | 
											
												
													
														|  | 
 |  | +			Destination: dest,
 | 
											
												
													
														|  | 
 |  | +			Inbound:     v.meta,
 | 
											
												
													
														|  |  		}
 |  |  		}
 | 
											
												
													
														|  | -		log.Warning("Socks: Unsupported socks command ", request.Command)
 |  | 
 | 
											
												
													
														|  | -		return ErrUnsupportedSocksCommand
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	response := protocol.NewSocks5Response()
 |  | 
 | 
											
												
													
														|  | -	response.Error = protocol.ErrorSuccess
 |  | 
 | 
											
												
													
														|  | 
 |  | +		log.Info("Socks|Server: TCP Connect request to ", dest)
 | 
											
												
													
														|  | 
 |  | +		log.Access(clientAddr, dest, log.AccessAccepted, "")
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -	// Some SOCKS software requires a value other than dest. Let's fake one:
 |  | 
 | 
											
												
													
														|  | -	response.Port = v2net.Port(1717)
 |  | 
 | 
											
												
													
														|  | -	response.SetIPv4([]byte{0, 0, 0, 0})
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	response.Write(writer)
 |  | 
 | 
											
												
													
														|  | -	if err != nil {
 |  | 
 | 
											
												
													
														|  | -		log.Error("Socks: failed to write response: ", err)
 |  | 
 | 
											
												
													
														|  | -		return err
 |  | 
 | 
											
												
													
														|  | 
 |  | +		v.transport(reader, connection, session)
 | 
											
												
													
														|  | 
 |  | +		return
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -	reader.SetBuffered(false)
 |  | 
 | 
											
												
													
														|  | -	writer.SetBuffered(false)
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	dest := request.Destination()
 |  | 
 | 
											
												
													
														|  | -	session := &proxy.SessionInfo{
 |  | 
 | 
											
												
													
														|  | -		Source:      clientAddr,
 |  | 
 | 
											
												
													
														|  | -		Destination: dest,
 |  | 
 | 
											
												
													
														|  | -		Inbound:     v.meta,
 |  | 
 | 
											
												
													
														|  | 
 |  | +	if request.Command == proto.RequestCommandUDP {
 | 
											
												
													
														|  | 
 |  | +		v.handleUDP()
 | 
											
												
													
														|  | 
 |  | +		return
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  | -	log.Info("Socks: TCP Connect request to ", dest)
 |  | 
 | 
											
												
													
														|  | -	log.Access(clientAddr, dest, log.AccessAccepted, "")
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	v.transport(reader, writer, session)
 |  | 
 | 
											
												
													
														|  | -	return nil
 |  | 
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -func (v *Server) handleUDP(reader io.Reader, writer *bufio.BufferedWriter) error {
 |  | 
 | 
											
												
													
														|  | -	response := protocol.NewSocks5Response()
 |  | 
 | 
											
												
													
														|  | -	response.Error = protocol.ErrorSuccess
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	udpAddr := v.udpAddress
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	response.Port = udpAddr.Port
 |  | 
 | 
											
												
													
														|  | -	switch udpAddr.Address.Family() {
 |  | 
 | 
											
												
													
														|  | -	case v2net.AddressFamilyIPv4:
 |  | 
 | 
											
												
													
														|  | -		response.SetIPv4(udpAddr.Address.IP())
 |  | 
 | 
											
												
													
														|  | -	case v2net.AddressFamilyIPv6:
 |  | 
 | 
											
												
													
														|  | -		response.SetIPv6(udpAddr.Address.IP())
 |  | 
 | 
											
												
													
														|  | -	case v2net.AddressFamilyDomain:
 |  | 
 | 
											
												
													
														|  | -		response.SetDomain(udpAddr.Address.Domain())
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	response.Write(writer)
 |  | 
 | 
											
												
													
														|  | -	err := writer.Flush()
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if err != nil {
 |  | 
 | 
											
												
													
														|  | -		log.Error("Socks: failed to write response: ", err)
 |  | 
 | 
											
												
													
														|  | -		return err
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | 
 |  | +func (v *Server) handleUDP() error {
 | 
											
												
													
														|  |  	// The TCP connection closes after v method returns. We need to wait until
 |  |  	// The TCP connection closes after v method returns. We need to wait until
 | 
											
												
													
														|  |  	// the client closes it.
 |  |  	// the client closes it.
 | 
											
												
													
														|  |  	// TODO: get notified from UDP part
 |  |  	// TODO: get notified from UDP part
 | 
											
										
											
												
													
														|  | @@ -268,35 +150,6 @@ func (v *Server) handleUDP(reader io.Reader, writer *bufio.BufferedWriter) error
 | 
											
												
													
														|  |  	return nil
 |  |  	return nil
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -func (v *Server) handleSocks4(clientAddr v2net.Destination, reader *bufio.BufferedReader, writer *bufio.BufferedWriter, auth protocol.Socks4AuthenticationRequest) error {
 |  | 
 | 
											
												
													
														|  | -	result := protocol.Socks4RequestGranted
 |  | 
 | 
											
												
													
														|  | -	if auth.Command == protocol.CmdBind {
 |  | 
 | 
											
												
													
														|  | -		result = protocol.Socks4RequestRejected
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	socks4Response := protocol.NewSocks4AuthenticationResponse(result, auth.Port, auth.IP[:])
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	socks4Response.Write(writer)
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if result == protocol.Socks4RequestRejected {
 |  | 
 | 
											
												
													
														|  | -		log.Warning("Socks: Unsupported socks 4 command ", auth.Command)
 |  | 
 | 
											
												
													
														|  | -		log.Access(clientAddr, "", log.AccessRejected, ErrUnsupportedSocksCommand)
 |  | 
 | 
											
												
													
														|  | -		return ErrUnsupportedSocksCommand
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	reader.SetBuffered(false)
 |  | 
 | 
											
												
													
														|  | -	writer.SetBuffered(false)
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	dest := v2net.TCPDestination(v2net.IPAddress(auth.IP[:]), auth.Port)
 |  | 
 | 
											
												
													
														|  | -	session := &proxy.SessionInfo{
 |  | 
 | 
											
												
													
														|  | -		Source:      clientAddr,
 |  | 
 | 
											
												
													
														|  | -		Destination: dest,
 |  | 
 | 
											
												
													
														|  | -		Inbound:     v.meta,
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	log.Access(clientAddr, dest, log.AccessAccepted, "")
 |  | 
 | 
											
												
													
														|  | -	v.transport(reader, writer, session)
 |  | 
 | 
											
												
													
														|  | -	return nil
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |  func (v *Server) transport(reader io.Reader, writer io.Writer, session *proxy.SessionInfo) {
 |  |  func (v *Server) transport(reader io.Reader, writer io.Writer, session *proxy.SessionInfo) {
 | 
											
												
													
														|  |  	ray := v.packetDispatcher.DispatchToOutbound(session)
 |  |  	ray := v.packetDispatcher.DispatchToOutbound(session)
 | 
											
												
													
														|  |  	input := ray.InboundInput()
 |  |  	input := ray.InboundInput()
 |