Prechádzať zdrojové kódy

handle inbound detour in vmess inbound

v2ray 9 rokov pred
rodič
commit
b0adb24003

+ 23 - 9
proxy/dokodemo/dokodemo.go

@@ -10,18 +10,20 @@ import (
 	"github.com/v2ray/v2ray-core/common/log"
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/common/retry"
+	"github.com/v2ray/v2ray-core/proxy"
 )
 
 type DokodemoDoor struct {
-	tcpMutex    sync.RWMutex
-	udpMutex    sync.RWMutex
-	config      *Config
-	accepting   bool
-	address     v2net.Address
-	port        v2net.Port
-	space       app.Space
-	tcpListener *net.TCPListener
-	udpConn     *net.UDPConn
+	tcpMutex      sync.RWMutex
+	udpMutex      sync.RWMutex
+	config        *Config
+	accepting     bool
+	address       v2net.Address
+	port          v2net.Port
+	space         app.Space
+	tcpListener   *net.TCPListener
+	udpConn       *net.UDPConn
+	listeningPort v2net.Port
 }
 
 func NewDokodemoDoor(space app.Space, config *Config) *DokodemoDoor {
@@ -33,6 +35,10 @@ func NewDokodemoDoor(space app.Space, config *Config) *DokodemoDoor {
 	}
 }
 
+func (this *DokodemoDoor) Port() v2net.Port {
+	return this.listeningPort
+}
+
 func (this *DokodemoDoor) Close() {
 	this.accepting = false
 	if this.tcpListener != nil {
@@ -50,6 +56,14 @@ func (this *DokodemoDoor) Close() {
 }
 
 func (this *DokodemoDoor) Listen(port v2net.Port) error {
+	if this.accepting {
+		if this.listeningPort == port {
+			return nil
+		} else {
+			return proxy.ErrorAlreadyListening
+		}
+	}
+	this.listeningPort = port
 	this.accepting = true
 
 	if this.config.Network.HasNetwork(v2net.TCPNetwork) {

+ 1 - 0
proxy/errors.go

@@ -7,4 +7,5 @@ import (
 var (
 	InvalidAuthentication  = errors.New("Invalid authentication.")
 	InvalidProtocolVersion = errors.New("Invalid protocol version.")
+	ErrorAlreadyListening  = errors.New("Already listening on another port.")
 )

+ 19 - 4
proxy/http/http.go

@@ -15,15 +15,17 @@ import (
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/common/retry"
 	"github.com/v2ray/v2ray-core/common/serial"
+	"github.com/v2ray/v2ray-core/proxy"
 	"github.com/v2ray/v2ray-core/transport/ray"
 )
 
 type HttpProxyServer struct {
 	sync.Mutex
-	accepting   bool
-	space       app.Space
-	config      *Config
-	tcpListener *net.TCPListener
+	accepting     bool
+	space         app.Space
+	config        *Config
+	tcpListener   *net.TCPListener
+	listeningPort v2net.Port
 }
 
 func NewHttpProxyServer(space app.Space, config *Config) *HttpProxyServer {
@@ -33,6 +35,10 @@ func NewHttpProxyServer(space app.Space, config *Config) *HttpProxyServer {
 	}
 }
 
+func (this *HttpProxyServer) Port() v2net.Port {
+	return this.listeningPort
+}
+
 func (this *HttpProxyServer) Close() {
 	this.accepting = false
 	if this.tcpListener != nil {
@@ -44,6 +50,15 @@ func (this *HttpProxyServer) Close() {
 }
 
 func (this *HttpProxyServer) Listen(port v2net.Port) error {
+	if this.accepting {
+		if this.listeningPort == port {
+			return nil
+		} else {
+			return proxy.ErrorAlreadyListening
+		}
+	}
+	this.listeningPort = port
+
 	tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{
 		Port: int(port.Value()),
 		IP:   []byte{0, 0, 0, 0},

+ 2 - 0
proxy/proxy.go

@@ -13,6 +13,8 @@ type InboundConnectionHandler interface {
 	Listen(port v2net.Port) error
 	// Close stops the handler to accepting anymore inbound connections.
 	Close()
+	// Port returns the port that the handler is listening on.
+	Port() v2net.Port
 }
 
 // An OutboundConnectionHandler handles outbound network connection for V2Ray.

+ 22 - 8
proxy/socks/socks.go

@@ -23,14 +23,15 @@ var (
 
 // SocksServer is a SOCKS 5 proxy server
 type SocksServer struct {
-	tcpMutex    sync.RWMutex
-	udpMutex    sync.RWMutex
-	accepting   bool
-	space       app.Space
-	config      *Config
-	tcpListener *net.TCPListener
-	udpConn     *net.UDPConn
-	udpAddress  v2net.Destination
+	tcpMutex      sync.RWMutex
+	udpMutex      sync.RWMutex
+	accepting     bool
+	space         app.Space
+	config        *Config
+	tcpListener   *net.TCPListener
+	udpConn       *net.UDPConn
+	udpAddress    v2net.Destination
+	listeningPort v2net.Port
 }
 
 func NewSocksServer(space app.Space, config *Config) *SocksServer {
@@ -40,6 +41,10 @@ func NewSocksServer(space app.Space, config *Config) *SocksServer {
 	}
 }
 
+func (this *SocksServer) Port() v2net.Port {
+	return this.listeningPort
+}
+
 func (this *SocksServer) Close() {
 	this.accepting = false
 	if this.tcpListener != nil {
@@ -57,6 +62,15 @@ func (this *SocksServer) Close() {
 }
 
 func (this *SocksServer) Listen(port v2net.Port) error {
+	if this.accepting {
+		if this.listeningPort == port {
+			return nil
+		} else {
+			return proxy.ErrorAlreadyListening
+		}
+	}
+	this.listeningPort = port
+
 	listener, err := net.ListenTCP("tcp", &net.TCPAddr{
 		IP:   []byte{0, 0, 0, 0},
 		Port: int(port),

+ 6 - 2
proxy/testing/mocks/inboundhandler.go

@@ -9,17 +9,21 @@ import (
 )
 
 type InboundConnectionHandler struct {
-	Port       v2net.Port
+	port       v2net.Port
 	Space      app.Space
 	ConnInput  io.Reader
 	ConnOutput io.Writer
 }
 
 func (this *InboundConnectionHandler) Listen(port v2net.Port) error {
-	this.Port = port
+	this.port = port
 	return nil
 }
 
+func (this *InboundConnectionHandler) Port() v2net.Port {
+	return this.port
+}
+
 func (this *InboundConnectionHandler) Close() {
 
 }

+ 9 - 21
proxy/vmess/command/accounts.go

@@ -2,7 +2,6 @@ package command
 
 import (
 	"io"
-	"time"
 
 	v2net "github.com/v2ray/v2ray-core/common/net"
 	"github.com/v2ray/v2ray-core/common/serial"
@@ -22,44 +21,33 @@ func init() {
 // 2 bytes: alterid
 // 8 bytes: time
 type SwitchAccount struct {
-	Host       v2net.Address
-	Port       v2net.Port
-	ID         *uuid.UUID
-	AlterIds   serial.Uint16Literal
-	ValidUntil time.Time
+	Host     v2net.Address
+	Port     v2net.Port
+	ID       *uuid.UUID
+	AlterIds serial.Uint16Literal
+	ValidSec serial.Uint16Literal
 }
 
-func (this *SwitchAccount) Marshal(writer io.Writer) (int, error) {
-	outBytes := 0
+func (this *SwitchAccount) Marshal(writer io.Writer) {
 	hostStr := ""
 	if this.Host != nil {
 		hostStr = this.Host.String()
 	}
 	writer.Write([]byte{byte(len(hostStr))})
-	outBytes++
 
 	if len(hostStr) > 0 {
 		writer.Write([]byte(hostStr))
-		outBytes += len(hostStr)
 	}
 
 	writer.Write(this.Port.Bytes())
-	outBytes += 2
 
 	idBytes := this.ID.Bytes()
 	writer.Write(idBytes)
-	outBytes += len(idBytes)
 
 	writer.Write(this.AlterIds.Bytes())
-	outBytes += 2
-
-	timestamp := this.ValidUntil.Unix()
-	timeBytes := serial.Int64Literal(timestamp).Bytes()
 
+	timeBytes := this.ValidSec.Bytes()
 	writer.Write(timeBytes)
-	outBytes += len(timeBytes)
-
-	return outBytes, nil
 }
 
 func (this *SwitchAccount) Unmarshal(data []byte) error {
@@ -84,9 +72,9 @@ func (this *SwitchAccount) Unmarshal(data []byte) error {
 	}
 	this.AlterIds = serial.ParseUint16(data[alterIdStart : alterIdStart+2])
 	timeStart := alterIdStart + 2
-	if len(data) < timeStart+8 {
+	if len(data) < timeStart+2 {
 		return transport.CorruptedPacket
 	}
-	this.ValidUntil = time.Unix(serial.BytesLiteral(data[timeStart:timeStart+8]).Int64Value(), 0)
+	this.ValidSec = serial.ParseUint16(data[timeStart : timeStart+2])
 	return nil
 }

+ 6 - 9
proxy/vmess/command/accounts_test.go

@@ -3,7 +3,6 @@ package command_test
 import (
 	"bytes"
 	"testing"
-	"time"
 
 	netassert "github.com/v2ray/v2ray-core/common/net/testing/assert"
 	"github.com/v2ray/v2ray-core/common/uuid"
@@ -16,19 +15,17 @@ func TestSwitchAccount(t *testing.T) {
 	v2testing.Current(t)
 
 	sa := &SwitchAccount{
-		Port:       1234,
-		ID:         uuid.New(),
-		AlterIds:   1024,
-		ValidUntil: time.Now(),
+		Port:     1234,
+		ID:       uuid.New(),
+		AlterIds: 1024,
+		ValidSec: 8080,
 	}
 
 	cmd, err := CreateResponseCommand(1)
 	assert.Error(err).IsNil()
 
 	buffer := bytes.NewBuffer(make([]byte, 0, 1024))
-	nBytes, err := sa.Marshal(buffer)
-	assert.Error(err).IsNil()
-	assert.Int(nBytes).Equals(buffer.Len())
+	sa.Marshal(buffer)
 
 	cmd.Unmarshal(buffer.Bytes())
 	sa2, ok := cmd.(*SwitchAccount)
@@ -36,5 +33,5 @@ func TestSwitchAccount(t *testing.T) {
 	netassert.Port(sa.Port).Equals(sa2.Port)
 	assert.String(sa.ID).Equals(sa2.ID.String())
 	assert.Uint16(sa.AlterIds.Value()).Equals(sa2.AlterIds.Value())
-	assert.Int64(sa.ValidUntil.Unix()).Equals(sa2.ValidUntil.Unix())
+	assert.Uint16(sa.ValidSec.Value()).Equals(sa2.ValidSec.Value())
 }

+ 1 - 1
proxy/vmess/command/command.go

@@ -10,7 +10,7 @@ var (
 )
 
 type Command interface {
-	Marshal(io.Writer) (int, error)
+	Marshal(io.Writer)
 	Unmarshal([]byte) error
 }
 

+ 1 - 5
proxy/vmess/command/dns.go

@@ -26,20 +26,16 @@ type CacheDns struct {
 	Address v2net.Address
 }
 
-func (this *CacheDns) Marshal(writer io.Writer) (int, error) {
+func (this *CacheDns) Marshal(writer io.Writer) {
 	if this.Address.IsIPv4() {
 		writer.Write([]byte{typeIPv4})
 		writer.Write(this.Address.IP())
-		return 5, nil
 	}
 
 	if this.Address.IsIPv6() {
 		writer.Write([]byte{typeIPv6})
 		writer.Write(this.Address.IP())
-		return 17, nil
 	}
-
-	return 0, ErrDomainAddress
 }
 
 func (this *CacheDns) Unmarshal(data []byte) error {

+ 2 - 4
proxy/vmess/command/dns_test.go

@@ -21,12 +21,10 @@ func TestCacheDnsIPv4(t *testing.T) {
 	buffer := alloc.NewBuffer().Clear()
 	defer buffer.Release()
 
-	nBytes, err := cd.Marshal(buffer)
-	assert.Error(err).IsNil()
-	assert.Int(nBytes).Equals(buffer.Len())
+	cd.Marshal(buffer)
 
 	cd2 := &CacheDns{}
-	err = cd2.Unmarshal(buffer.Value)
+	err := cd2.Unmarshal(buffer.Value)
 	assert.Error(err).IsNil()
 	netassert.Address(cd.Address).Equals(cd2.Address)
 }

+ 45 - 0
proxy/vmess/inbound/command.go

@@ -0,0 +1,45 @@
+package inbound
+
+import (
+	"github.com/v2ray/v2ray-core/common/alloc"
+	"github.com/v2ray/v2ray-core/common/serial"
+	"github.com/v2ray/v2ray-core/proxy/vmess/command"
+)
+
+func (this *VMessInboundHandler) generateCommand(buffer *alloc.Buffer) {
+	cmd := byte(0)
+	commandBytes := alloc.NewSmallBuffer().Clear()
+	defer commandBytes.Release()
+
+	if this.features != nil && this.features.Detour != nil {
+		tag := this.features.Detour.ToTag
+		if this.space.HasInboundHandlerManager() {
+			handlerManager := this.space.InboundHandlerManager()
+			handler, availableSec := handlerManager.GetHandler(tag)
+			inboundHandler, ok := handler.(*VMessInboundHandler)
+			if ok {
+				user := inboundHandler.GetUser()
+				availableSecUint16 := uint16(65535)
+				if availableSec < 65535 {
+					availableSecUint16 = uint16(availableSec)
+				}
+
+				saCmd := &command.SwitchAccount{
+					Port:     inboundHandler.Port(),
+					ID:       user.ID.UUID(),
+					AlterIds: serial.Uint16Literal(len(user.AlterIDs)),
+					ValidSec: serial.Uint16Literal(availableSecUint16),
+				}
+				saCmd.Marshal(commandBytes)
+			}
+
+		}
+	}
+
+	if commandBytes.Len() > 256 {
+		buffer.AppendBytes(byte(0), byte(0))
+	} else {
+		buffer.AppendBytes(cmd, byte(commandBytes.Len()))
+		buffer.Append(commandBytes.Value)
+	}
+}

+ 26 - 12
proxy/vmess/inbound/inbound.go

@@ -22,17 +22,17 @@ import (
 // Inbound connection handler that handles messages in VMess format.
 type VMessInboundHandler struct {
 	sync.Mutex
-	space     app.Space
-	clients   protocol.UserSet
-	accepting bool
-	listener  *net.TCPListener
+	space         app.Space
+	clients       protocol.UserSet
+	user          *vmess.User
+	accepting     bool
+	listener      *net.TCPListener
+	features      *FeaturesConfig
+	listeningPort v2net.Port
 }
 
-func NewVMessInboundHandler(space app.Space, clients protocol.UserSet) *VMessInboundHandler {
-	return &VMessInboundHandler{
-		space:   space,
-		clients: clients,
-	}
+func (this *VMessInboundHandler) Port() v2net.Port {
+	return this.listeningPort
 }
 
 func (this *VMessInboundHandler) Close() {
@@ -45,11 +45,20 @@ func (this *VMessInboundHandler) Close() {
 	}
 }
 
-func (this *VMessInboundHandler) AddUser(user vmess.User) {
-
+func (this *VMessInboundHandler) GetUser() *vmess.User {
+	return this.user
 }
 
 func (this *VMessInboundHandler) Listen(port v2net.Port) error {
+	if this.accepting {
+		if this.listeningPort == port {
+			return nil
+		} else {
+			return proxy.ErrorAlreadyListening
+		}
+	}
+	this.listeningPort = port
+
 	listener, err := net.ListenTCP("tcp", &net.TCPAddr{
 		IP:   []byte{0, 0, 0, 0},
 		Port: int(port),
@@ -175,6 +184,11 @@ func init() {
 				allowedClients.AddUser(user)
 			}
 
-			return NewVMessInboundHandler(space, allowedClients), nil
+			return &VMessInboundHandler{
+				space:    space,
+				clients:  allowedClients,
+				features: config.Features,
+				user:     config.AllowedUsers[0],
+			}, nil
 		})
 }