mirror of https://github.com/v2ray/v2ray-core
				
				
				
			socks client
							parent
							
								
									b00ee67369
								
							
						
					
					
						commit
						f2e9d8a4e0
					
				| 
						 | 
				
			
			@ -97,7 +97,14 @@ func (v *ServerSpec) AddUser(user *User) {
 | 
			
		|||
 | 
			
		||||
func (v *ServerSpec) PickUser() *User {
 | 
			
		||||
	userCount := len(v.users)
 | 
			
		||||
	return v.users[dice.Roll(userCount)]
 | 
			
		||||
	switch userCount {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return nil
 | 
			
		||||
	case 1:
 | 
			
		||||
		return v.users[0]
 | 
			
		||||
	default:
 | 
			
		||||
		return v.users[dice.Roll(userCount)]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *ServerSpec) IsValid() bool {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -166,13 +166,13 @@ func (v *Client) Dispatch(destination v2net.Destination, ray ray.OutboundRay) {
 | 
			
		|||
type ClientFactory struct{}
 | 
			
		||||
 | 
			
		||||
// StreamCapability implements OutboundHandlerFactory.StreamCapability().
 | 
			
		||||
func (v *ClientFactory) StreamCapability() v2net.NetworkList {
 | 
			
		||||
func (ClientFactory) StreamCapability() v2net.NetworkList {
 | 
			
		||||
	return v2net.NetworkList{
 | 
			
		||||
		Network: []v2net.Network{v2net.Network_TCP},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Create implements OutboundHandlerFactory.Create().
 | 
			
		||||
func (v *ClientFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
 | 
			
		||||
func (ClientFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
 | 
			
		||||
	return NewClient(rawConfig.(*ClientConfig), space, meta)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,125 @@
 | 
			
		|||
package socks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"v2ray.com/core/app"
 | 
			
		||||
	"v2ray.com/core/common/buf"
 | 
			
		||||
	"v2ray.com/core/common/log"
 | 
			
		||||
	"v2ray.com/core/common/net"
 | 
			
		||||
	"v2ray.com/core/common/protocol"
 | 
			
		||||
	"v2ray.com/core/common/retry"
 | 
			
		||||
	"v2ray.com/core/common/signal"
 | 
			
		||||
	"v2ray.com/core/proxy"
 | 
			
		||||
	"v2ray.com/core/transport/internet"
 | 
			
		||||
	"v2ray.com/core/transport/ray"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Client struct {
 | 
			
		||||
	serverPicker protocol.ServerPicker
 | 
			
		||||
	meta         *proxy.OutboundHandlerMeta
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewClient(config *ClientConfig, space app.Space, meta *proxy.OutboundHandlerMeta) (*Client, error) {
 | 
			
		||||
	serverList := protocol.NewServerList()
 | 
			
		||||
	for _, rec := range config.Server {
 | 
			
		||||
		serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
 | 
			
		||||
	}
 | 
			
		||||
	client := &Client{
 | 
			
		||||
		serverPicker: protocol.NewRoundRobinServerPicker(serverList),
 | 
			
		||||
		meta:         meta,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return client, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
 | 
			
		||||
	var server *protocol.ServerSpec
 | 
			
		||||
	var conn internet.Connection
 | 
			
		||||
 | 
			
		||||
	err := retry.ExponentialBackoff(5, 100).On(func() error {
 | 
			
		||||
		server = c.serverPicker.PickServer()
 | 
			
		||||
		dest := server.Destination()
 | 
			
		||||
		rawConn, err := internet.Dial(c.meta.Address, dest, c.meta.GetDialerOptions())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		conn = rawConn
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warning("Socks|Client: Failed to find an available destination.")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer conn.Close()
 | 
			
		||||
	conn.SetReusable(false)
 | 
			
		||||
 | 
			
		||||
	request := &protocol.RequestHeader{
 | 
			
		||||
		Version: socks5Version,
 | 
			
		||||
		Command: protocol.RequestCommandTCP,
 | 
			
		||||
		Address: destination.Address,
 | 
			
		||||
		Port:    destination.Port,
 | 
			
		||||
	}
 | 
			
		||||
	if destination.Network == net.Network_UDP {
 | 
			
		||||
		request.Command = protocol.RequestCommandUDP
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user := server.PickUser()
 | 
			
		||||
	if user != nil {
 | 
			
		||||
		request.User = user
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	udpRequest, err := ClientHandshake(request, conn, conn)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Warning("Socks|Client: Failed to establish connection to server: ", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var requestFunc func() error
 | 
			
		||||
	var responseFunc func() error
 | 
			
		||||
	if request.Command == protocol.RequestCommandTCP {
 | 
			
		||||
		requestFunc = func() error {
 | 
			
		||||
			defer ray.OutboundInput().ForceClose()
 | 
			
		||||
			return buf.PipeUntilEOF(ray.OutboundInput(), buf.NewWriter(conn))
 | 
			
		||||
		}
 | 
			
		||||
		responseFunc = func() error {
 | 
			
		||||
			defer ray.OutboundOutput().Close()
 | 
			
		||||
			return buf.PipeUntilEOF(buf.NewReader(conn), ray.OutboundOutput())
 | 
			
		||||
		}
 | 
			
		||||
	} else if request.Command == protocol.RequestCommandUDP {
 | 
			
		||||
		udpConn, err := internet.Dial(c.meta.Address, udpRequest.Destination(), c.meta.GetDialerOptions())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Info("Socks|Client: Failed to create UDP connection: ", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		defer udpConn.Close()
 | 
			
		||||
		requestFunc = func() error {
 | 
			
		||||
			defer ray.OutboundInput().ForceClose()
 | 
			
		||||
			return buf.PipeUntilEOF(ray.OutboundInput(), &UDPWriter{request: request, writer: udpConn})
 | 
			
		||||
		}
 | 
			
		||||
		responseFunc = func() error {
 | 
			
		||||
			defer ray.OutboundOutput().Close()
 | 
			
		||||
			reader := &UDPReader{reader: net.NewTimeOutReader(16, udpConn)}
 | 
			
		||||
			return buf.PipeUntilEOF(reader, ray.OutboundOutput())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	requestDone := signal.ExecuteAsync(requestFunc)
 | 
			
		||||
	responseDone := signal.ExecuteAsync(responseFunc)
 | 
			
		||||
	if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil {
 | 
			
		||||
		log.Info("Socks|Client: Connection ends with ", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ClientFactory struct{}
 | 
			
		||||
 | 
			
		||||
func (ClientFactory) StreamCapability() net.NetworkList {
 | 
			
		||||
	return net.NetworkList{
 | 
			
		||||
		Network: []net.Network{net.Network_TCP},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ClientFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.OutboundHandlerMeta) (proxy.OutboundHandler, error) {
 | 
			
		||||
	return NewClient(rawConfig.(*ClientConfig), space, meta)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3,6 +3,8 @@ package socks
 | 
			
		|||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"v2ray.com/core/common/buf"
 | 
			
		||||
	"v2ray.com/core/common/errors"
 | 
			
		||||
	v2net "v2ray.com/core/common/net"
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +92,7 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
 | 
			
		|||
		}
 | 
			
		||||
 | 
			
		||||
		var expectedAuth byte = authNotRequired
 | 
			
		||||
		if len(s.config.Accounts) > 0 {
 | 
			
		||||
		if s.config.AuthType == AuthType_PASSWORD {
 | 
			
		||||
			expectedAuth = authPassword
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,21 +101,27 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
 | 
			
		|||
			return nil, errors.New("Socks|Server: No matching auth method.")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := writeSocks5AuthenticationResponse(writer, expectedAuth); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fmt.Println("s a")
 | 
			
		||||
		if expectedAuth == authPassword {
 | 
			
		||||
			username, password, err := readUsernamePassword(reader)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, errors.Base(err).Message("Socks|Server: Failed to read username or password.")
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Println("s b")
 | 
			
		||||
			if !s.config.HasAccount(username, password) {
 | 
			
		||||
				writeSocks5AuthenticationResponse(writer, 0xFF)
 | 
			
		||||
				return nil, errors.Base(err).Message("Socks|Server: Invalid username or password.")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := writeSocks5AuthenticationResponse(writer, 0x00); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
			if err := writeSocks5AuthenticationResponse(writer, 0x00); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fmt.Println("s c")
 | 
			
		||||
		buffer.Clear()
 | 
			
		||||
		if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 4)); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -194,21 +202,27 @@ func readUsernamePassword(reader io.Reader) (string, string, error) {
 | 
			
		|||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
	nUsername := int(buffer.Byte(1))
 | 
			
		||||
	fmt.Println("s username", nUsername)
 | 
			
		||||
 | 
			
		||||
	buffer.Clear()
 | 
			
		||||
	if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, nUsername)); err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
	username := buffer.String()
 | 
			
		||||
	fmt.Println("s username", username)
 | 
			
		||||
	buffer.Clear()
 | 
			
		||||
 | 
			
		||||
	if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 1)); err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
	nPassword := int(buffer.Byte(0))
 | 
			
		||||
	fmt.Println("s pwd", nPassword)
 | 
			
		||||
	buffer.Clear()
 | 
			
		||||
	if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, nPassword)); err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
	password := buffer.String()
 | 
			
		||||
	fmt.Println("s pwd", password)
 | 
			
		||||
	return username, password, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -244,9 +258,7 @@ func writeSocks5AuthenticationResponse(writer io.Writer, auth byte) error {
 | 
			
		|||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeSocks5Response(writer io.Writer, errCode byte, address v2net.Address, port v2net.Port) error {
 | 
			
		||||
	buffer := buf.NewLocal(64)
 | 
			
		||||
	buffer.AppendBytes(socks5Version, errCode, 0x00 /* reserved */)
 | 
			
		||||
func appendAddress(buffer *buf.Buffer, address v2net.Address, port v2net.Port) {
 | 
			
		||||
	switch address.Family() {
 | 
			
		||||
	case v2net.AddressFamilyIPv4:
 | 
			
		||||
		buffer.AppendBytes(0x01)
 | 
			
		||||
| 
						 | 
				
			
			@ -259,6 +271,12 @@ func writeSocks5Response(writer io.Writer, errCode byte, address v2net.Address,
 | 
			
		|||
		buffer.AppendSupplier(serial.WriteString(address.Domain()))
 | 
			
		||||
	}
 | 
			
		||||
	buffer.AppendSupplier(serial.WriteUint16(port.Value()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeSocks5Response(writer io.Writer, errCode byte, address v2net.Address, port v2net.Port) error {
 | 
			
		||||
	buffer := buf.NewLocal(64)
 | 
			
		||||
	buffer.AppendBytes(socks5Version, errCode, 0x00 /* reserved */)
 | 
			
		||||
	appendAddress(buffer, address, port)
 | 
			
		||||
 | 
			
		||||
	_, err := writer.Write(buffer.Bytes())
 | 
			
		||||
	return err
 | 
			
		||||
| 
						 | 
				
			
			@ -326,18 +344,162 @@ func DecodeUDPPacket(packet []byte) (*protocol.RequestHeader, []byte, error) {
 | 
			
		|||
func EncodeUDPPacket(request *protocol.RequestHeader, data []byte) *buf.Buffer {
 | 
			
		||||
	b := buf.NewSmall()
 | 
			
		||||
	b.AppendBytes(0, 0, 0 /* Fragment */)
 | 
			
		||||
	switch request.Address.Family() {
 | 
			
		||||
	case v2net.AddressFamilyIPv4:
 | 
			
		||||
		b.AppendBytes(addrTypeIPv4)
 | 
			
		||||
		b.Append(request.Address.IP())
 | 
			
		||||
	case v2net.AddressFamilyIPv6:
 | 
			
		||||
		b.AppendBytes(addrTypeIPv6)
 | 
			
		||||
		b.Append(request.Address.IP())
 | 
			
		||||
	case v2net.AddressFamilyDomain:
 | 
			
		||||
		b.AppendBytes(addrTypeDomain, byte(len(request.Address.Domain())))
 | 
			
		||||
		b.AppendSupplier(serial.WriteString(request.Address.Domain()))
 | 
			
		||||
	}
 | 
			
		||||
	b.AppendSupplier(serial.WriteUint16(request.Port.Value()))
 | 
			
		||||
	appendAddress(b, request.Address, request.Port)
 | 
			
		||||
	b.Append(data)
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UDPReader struct {
 | 
			
		||||
	reader io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *UDPReader) Read() (*buf.Buffer, error) {
 | 
			
		||||
	b := buf.NewSmall()
 | 
			
		||||
	if err := b.AppendSupplier(buf.ReadFrom(r.reader)); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	_, data, err := DecodeUDPPacket(b.Bytes())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	b.Clear()
 | 
			
		||||
	b.Append(data)
 | 
			
		||||
	return b, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UDPWriter struct {
 | 
			
		||||
	request *protocol.RequestHeader
 | 
			
		||||
	writer  io.Writer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *UDPWriter) Write(b *buf.Buffer) error {
 | 
			
		||||
	eb := EncodeUDPPacket(w.request, b.Bytes())
 | 
			
		||||
	b.Release()
 | 
			
		||||
	defer eb.Release()
 | 
			
		||||
	if _, err := w.writer.Write(eb.Bytes()); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
 | 
			
		||||
	authByte := byte(authNotRequired)
 | 
			
		||||
	if request.User != nil {
 | 
			
		||||
		authByte = byte(authPassword)
 | 
			
		||||
	}
 | 
			
		||||
	authRequest := []byte{socks5Version, 0x01, authByte}
 | 
			
		||||
	if _, err := writer.Write(authRequest); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b := buf.NewLocal(64)
 | 
			
		||||
	if err := b.AppendSupplier(buf.ReadFullFrom(reader, 2)); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b.Byte(0) != socks5Version {
 | 
			
		||||
		return nil, errors.New("Socks|Client: Unexpected server version: ", b.Byte(0))
 | 
			
		||||
	}
 | 
			
		||||
	if b.Byte(1) != authByte {
 | 
			
		||||
		return nil, errors.New("Socks|Client: auth method not supported.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if authByte == authPassword {
 | 
			
		||||
		rawAccount, err := request.User.GetTypedAccount()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		account := rawAccount.(*Account)
 | 
			
		||||
 | 
			
		||||
		fmt.Println("c username", account.Username)
 | 
			
		||||
		fmt.Println("c pwd", account.Password)
 | 
			
		||||
		b.Clear()
 | 
			
		||||
		b.AppendBytes(socks5Version, byte(len(account.Username)))
 | 
			
		||||
		b.Append([]byte(account.Username))
 | 
			
		||||
		b.AppendBytes(byte(len(account.Password)))
 | 
			
		||||
		b.Append([]byte(account.Password))
 | 
			
		||||
		fmt.Println("c a")
 | 
			
		||||
		if _, err := writer.Write(b.Bytes()); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("c b")
 | 
			
		||||
		b.Clear()
 | 
			
		||||
		if err := b.AppendSupplier(buf.ReadFullFrom(reader, 2)); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("c c")
 | 
			
		||||
		if b.Byte(1) != 0x00 {
 | 
			
		||||
			return nil, errors.New("Socks|Client: Server rejects account: ", b.Byte(1))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Clear()
 | 
			
		||||
 | 
			
		||||
	command := byte(cmdTCPConnect)
 | 
			
		||||
	if request.Command == protocol.RequestCommandUDP {
 | 
			
		||||
		command = byte(cmdUDPPort)
 | 
			
		||||
	}
 | 
			
		||||
	b.AppendBytes(socks5Version, command, 0x00 /* reserved */)
 | 
			
		||||
	appendAddress(b, request.Address, request.Port)
 | 
			
		||||
	fmt.Println("c e")
 | 
			
		||||
	if _, err := writer.Write(b.Bytes()); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.Clear()
 | 
			
		||||
	fmt.Println("c f")
 | 
			
		||||
	if err := b.AppendSupplier(buf.ReadFullFrom(reader, 4)); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp := b.Byte(1)
 | 
			
		||||
	if resp != 0x00 {
 | 
			
		||||
		return nil, errors.New("Socks|Client: Server rejects request: ", resp)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	addrType := b.Byte(3)
 | 
			
		||||
 | 
			
		||||
	b.Clear()
 | 
			
		||||
 | 
			
		||||
	var address v2net.Address
 | 
			
		||||
	switch addrType {
 | 
			
		||||
	case addrTypeIPv4:
 | 
			
		||||
		if err := b.AppendSupplier(buf.ReadFullFrom(reader, 4)); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		address = v2net.IPAddress(b.Bytes())
 | 
			
		||||
	case addrTypeIPv6:
 | 
			
		||||
		if err := b.AppendSupplier(buf.ReadFullFrom(reader, 16)); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		address = v2net.IPAddress(b.Bytes())
 | 
			
		||||
	case addrTypeDomain:
 | 
			
		||||
		if err := b.AppendSupplier(buf.ReadFullFrom(reader, 1)); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		domainLength := int(b.Byte(0))
 | 
			
		||||
		if err := b.AppendSupplier(buf.ReadFullFrom(reader, domainLength)); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		address = v2net.DomainAddress(string(b.BytesFrom(-domainLength)))
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errors.New("Socks|Server: Unknown address type: ", addrType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := b.AppendSupplier(buf.ReadFullFrom(reader, 2)); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	port := v2net.PortFromBytes(b.BytesFrom(-2))
 | 
			
		||||
 | 
			
		||||
	if request.Command == protocol.RequestCommandUDP {
 | 
			
		||||
		udpRequest := &protocol.RequestHeader{
 | 
			
		||||
			Version: socks5Version,
 | 
			
		||||
			Command: protocol.RequestCommandUDP,
 | 
			
		||||
			Address: address,
 | 
			
		||||
			Port:    port,
 | 
			
		||||
		}
 | 
			
		||||
		return udpRequest, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,14 +7,12 @@ import (
 | 
			
		|||
 | 
			
		||||
	"v2ray.com/core/app"
 | 
			
		||||
	"v2ray.com/core/app/dispatcher"
 | 
			
		||||
	"v2ray.com/core/common"
 | 
			
		||||
	"v2ray.com/core/common/buf"
 | 
			
		||||
	"v2ray.com/core/common/bufio"
 | 
			
		||||
	"v2ray.com/core/common/errors"
 | 
			
		||||
	"v2ray.com/core/common/log"
 | 
			
		||||
	v2net "v2ray.com/core/common/net"
 | 
			
		||||
	"v2ray.com/core/common/protocol"
 | 
			
		||||
	"v2ray.com/core/common/serial"
 | 
			
		||||
	"v2ray.com/core/common/signal"
 | 
			
		||||
	"v2ray.com/core/proxy"
 | 
			
		||||
	"v2ray.com/core/transport/internet"
 | 
			
		||||
| 
						 | 
				
			
			@ -193,7 +191,3 @@ func (v *ServerFactory) StreamCapability() v2net.NetworkList {
 | 
			
		|||
func (v *ServerFactory) Create(space app.Space, rawConfig interface{}, meta *proxy.InboundHandlerMeta) (proxy.InboundHandler, error) {
 | 
			
		||||
	return NewServer(rawConfig.(*ServerConfig), space, meta), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType(new(ServerConfig)), new(ServerFactory)))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,12 @@
 | 
			
		|||
package socks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"v2ray.com/core/common"
 | 
			
		||||
	"v2ray.com/core/common/serial"
 | 
			
		||||
	"v2ray.com/core/proxy"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	common.Must(proxy.RegisterOutboundHandlerCreator(serial.GetMessageType((*ClientConfig)(nil)), new(ClientFactory)))
 | 
			
		||||
	common.Must(proxy.RegisterInboundHandlerCreator(serial.GetMessageType((*ServerConfig)(nil)), new(ServerFactory)))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,254 @@
 | 
			
		|||
package scenarios
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	socks1 "h12.me/socks"
 | 
			
		||||
	"v2ray.com/core"
 | 
			
		||||
	v2net "v2ray.com/core/common/net"
 | 
			
		||||
	"v2ray.com/core/common/protocol"
 | 
			
		||||
	"v2ray.com/core/common/serial"
 | 
			
		||||
	"v2ray.com/core/proxy/dokodemo"
 | 
			
		||||
	"v2ray.com/core/proxy/freedom"
 | 
			
		||||
	"v2ray.com/core/proxy/socks"
 | 
			
		||||
	"v2ray.com/core/testing/assert"
 | 
			
		||||
	"v2ray.com/core/testing/servers/tcp"
 | 
			
		||||
	"v2ray.com/core/testing/servers/udp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestSocksBridgeTCP(t *testing.T) {
 | 
			
		||||
	assert := assert.On(t)
 | 
			
		||||
 | 
			
		||||
	tcpServer := tcp.Server{
 | 
			
		||||
		MsgProcessor: xor,
 | 
			
		||||
	}
 | 
			
		||||
	dest, err := tcpServer.Start()
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	defer tcpServer.Close()
 | 
			
		||||
 | 
			
		||||
	serverPort := pickPort()
 | 
			
		||||
	serverConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				PortRange: v2net.SinglePortRange(serverPort),
 | 
			
		||||
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
				Settings: serial.ToTypedMessage(&socks.ServerConfig{
 | 
			
		||||
					AuthType: socks.AuthType_PASSWORD,
 | 
			
		||||
					Accounts: map[string]string{
 | 
			
		||||
						"Test Account": "Test Password",
 | 
			
		||||
					},
 | 
			
		||||
					Address:    v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
					UdpEnabled: false,
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				Settings: serial.ToTypedMessage(&freedom.Config{}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientPort := pickPort()
 | 
			
		||||
	clientConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				PortRange: v2net.SinglePortRange(clientPort),
 | 
			
		||||
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
				Settings: serial.ToTypedMessage(&dokodemo.Config{
 | 
			
		||||
					Address: v2net.NewIPOrDomain(dest.Address),
 | 
			
		||||
					Port:    uint32(dest.Port),
 | 
			
		||||
					NetworkList: &v2net.NetworkList{
 | 
			
		||||
						Network: []v2net.Network{v2net.Network_TCP},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				Settings: serial.ToTypedMessage(&socks.ClientConfig{
 | 
			
		||||
					Server: []*protocol.ServerEndpoint{
 | 
			
		||||
						{
 | 
			
		||||
							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
							Port:    uint32(serverPort),
 | 
			
		||||
							User: []*protocol.User{
 | 
			
		||||
								{
 | 
			
		||||
									Account: serial.ToTypedMessage(&socks.Account{
 | 
			
		||||
										Username: "Test Account",
 | 
			
		||||
										Password: "Test Password",
 | 
			
		||||
									}),
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
 | 
			
		||||
	assert.Error(InitializeServerConfig(clientConfig)).IsNil()
 | 
			
		||||
 | 
			
		||||
	conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
 | 
			
		||||
		IP:   []byte{127, 0, 0, 1},
 | 
			
		||||
		Port: int(clientPort),
 | 
			
		||||
	})
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
 | 
			
		||||
	payload := "test payload"
 | 
			
		||||
	nBytes, err := conn.Write([]byte(payload))
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	assert.Int(nBytes).Equals(len(payload))
 | 
			
		||||
 | 
			
		||||
	response := make([]byte, 1024)
 | 
			
		||||
	nBytes, err = conn.Read(response)
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	assert.Bytes(response[:nBytes]).Equals(xor([]byte(payload)))
 | 
			
		||||
	assert.Error(conn.Close()).IsNil()
 | 
			
		||||
 | 
			
		||||
	CloseAllServers()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSocks4(t *testing.T) {
 | 
			
		||||
	assert := assert.On(t)
 | 
			
		||||
 | 
			
		||||
	tcpServer := tcp.Server{
 | 
			
		||||
		MsgProcessor: xor,
 | 
			
		||||
	}
 | 
			
		||||
	dest, err := tcpServer.Start()
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	defer tcpServer.Close()
 | 
			
		||||
 | 
			
		||||
	serverPort := pickPort()
 | 
			
		||||
	serverConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				PortRange: v2net.SinglePortRange(serverPort),
 | 
			
		||||
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
				Settings: serial.ToTypedMessage(&socks.ServerConfig{
 | 
			
		||||
					AuthType:   socks.AuthType_NO_AUTH,
 | 
			
		||||
					Address:    v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
					UdpEnabled: false,
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				Settings: serial.ToTypedMessage(&freedom.Config{}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
 | 
			
		||||
 | 
			
		||||
	dialer := socks1.DialSocksProxy(socks1.SOCKS4, v2net.TCPDestination(v2net.LocalHostIP, serverPort).NetAddr())
 | 
			
		||||
	conn, err := dialer("tcp", dest.NetAddr())
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
 | 
			
		||||
	payload := "test payload"
 | 
			
		||||
	nBytes, err := conn.Write([]byte(payload))
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	assert.Int(nBytes).Equals(len(payload))
 | 
			
		||||
 | 
			
		||||
	response := make([]byte, 1024)
 | 
			
		||||
	nBytes, err = conn.Read(response)
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	assert.Bytes(response[:nBytes]).Equals(xor([]byte(payload)))
 | 
			
		||||
	assert.Error(conn.Close()).IsNil()
 | 
			
		||||
 | 
			
		||||
	CloseAllServers()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSocksBridageUDP(t *testing.T) {
 | 
			
		||||
	assert := assert.On(t)
 | 
			
		||||
 | 
			
		||||
	udpServer := udp.Server{
 | 
			
		||||
		MsgProcessor: xor,
 | 
			
		||||
	}
 | 
			
		||||
	dest, err := udpServer.Start()
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	defer udpServer.Close()
 | 
			
		||||
 | 
			
		||||
	serverPort := pickPort()
 | 
			
		||||
	serverConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				PortRange: v2net.SinglePortRange(serverPort),
 | 
			
		||||
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
				Settings: serial.ToTypedMessage(&socks.ServerConfig{
 | 
			
		||||
					AuthType: socks.AuthType_PASSWORD,
 | 
			
		||||
					Accounts: map[string]string{
 | 
			
		||||
						"Test Account": "Test Password",
 | 
			
		||||
					},
 | 
			
		||||
					Address:    v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
					UdpEnabled: true,
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				Settings: serial.ToTypedMessage(&freedom.Config{}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientPort := pickPort()
 | 
			
		||||
	clientConfig := &core.Config{
 | 
			
		||||
		Inbound: []*core.InboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				PortRange: v2net.SinglePortRange(clientPort),
 | 
			
		||||
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
				Settings: serial.ToTypedMessage(&dokodemo.Config{
 | 
			
		||||
					Address: v2net.NewIPOrDomain(dest.Address),
 | 
			
		||||
					Port:    uint32(dest.Port),
 | 
			
		||||
					NetworkList: &v2net.NetworkList{
 | 
			
		||||
						Network: []v2net.Network{v2net.Network_TCP, v2net.Network_UDP},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundConnectionConfig{
 | 
			
		||||
			{
 | 
			
		||||
				Settings: serial.ToTypedMessage(&socks.ClientConfig{
 | 
			
		||||
					Server: []*protocol.ServerEndpoint{
 | 
			
		||||
						{
 | 
			
		||||
							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
 | 
			
		||||
							Port:    uint32(serverPort),
 | 
			
		||||
							User: []*protocol.User{
 | 
			
		||||
								{
 | 
			
		||||
									Account: serial.ToTypedMessage(&socks.Account{
 | 
			
		||||
										Username: "Test Account",
 | 
			
		||||
										Password: "Test Password",
 | 
			
		||||
									}),
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
 | 
			
		||||
	assert.Error(InitializeServerConfig(clientConfig)).IsNil()
 | 
			
		||||
 | 
			
		||||
	conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
 | 
			
		||||
		IP:   []byte{127, 0, 0, 1},
 | 
			
		||||
		Port: int(clientPort),
 | 
			
		||||
	})
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
 | 
			
		||||
	payload := "dokodemo request."
 | 
			
		||||
	nBytes, err := conn.Write([]byte(payload))
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	assert.Int(nBytes).Equals(len(payload))
 | 
			
		||||
 | 
			
		||||
	response := make([]byte, 1024)
 | 
			
		||||
	nBytes, err = conn.Read(response)
 | 
			
		||||
	assert.Error(err).IsNil()
 | 
			
		||||
	assert.Bytes(response[:nBytes]).Equals(xor([]byte(payload)))
 | 
			
		||||
	assert.Error(conn.Close()).IsNil()
 | 
			
		||||
 | 
			
		||||
	CloseAllServers()
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue