Bladeren bron

connecting dots

V2Ray 10 jaren geleden
bovenliggende
commit
0a96b8fb1d
13 gewijzigde bestanden met toevoegingen van 501 en 48 verwijderingen
  1. 27 0
      io/aes.go
  2. 18 3
      io/socks/socks.go
  3. 24 4
      io/vmess/vmess.go
  4. 7 6
      net/freedom/freedom.go
  5. 46 1
      net/socks/socks.go
  6. 12 0
      net/socks/socksfactory.go
  7. 60 0
      net/vdest.go
  8. 3 15
      net/vmess/vmess.go
  9. 119 0
      net/vmess/vmessin.go
  10. 133 0
      net/vmess/vmessout.go
  11. 6 2
      vconfig.go
  12. 39 7
      vpoint.go
  13. 7 10
      vray.go

+ 27 - 0
io/aes.go

@@ -0,0 +1,27 @@
+package io
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"io"
+)
+
+func NewAesDecryptReader(key []byte, iv []byte, reader io.Reader) (io.Reader, error) {
+	aesBlock, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	aesMode := cipher.NewCBCDecrypter(aesBlock, iv)
+	return NewCryptionReader(aesMode, reader), nil
+}
+
+func NewAesEncryptWriter(key []byte, iv []byte, writer io.Writer) (io.Writer, error) {
+	aesBlock, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	aesMode := cipher.NewCBCEncrypter(aesBlock, iv)
+	return NewCryptionWriter(aesMode, writer), nil
+}

+ 18 - 3
io/socks/socks.go

@@ -5,6 +5,8 @@ import (
 	"encoding/binary"
 	"fmt"
 	"io"
+
+	v2net "github.com/v2ray/v2ray-core/net"
 )
 
 const (
@@ -128,7 +130,7 @@ func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
 	// buffer[2] is a reserved field
 	request.AddrType = buffer[3]
 	switch request.AddrType {
-	case 0x01:
+	case AddrTypeIPv4:
 		nBytes, err = reader.Read(request.IPv4[:])
 		if err != nil {
 			return
@@ -137,7 +139,7 @@ func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
 			err = fmt.Errorf("Unable to read IPv4 address.")
 			return
 		}
-	case 0x03:
+	case AddrTypeDomain:
 		buffer = make([]byte, 257)
 		nBytes, err = reader.Read(buffer)
 		if err != nil {
@@ -149,7 +151,7 @@ func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
 			return
 		}
 		request.Domain = string(buffer[1 : domainLength+1])
-	case 0x04:
+	case AddrTypeIPv6:
 		nBytes, err = reader.Read(request.IPv6[:])
 		if err != nil {
 			return
@@ -177,6 +179,19 @@ func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
 	return
 }
 
+func (request *Socks5Request) Destination() v2net.VAddress {
+	switch request.AddrType {
+	case AddrTypeIPv4:
+		return v2net.IPAddress(request.IPv4[:], request.Port)
+	case AddrTypeIPv6:
+		return v2net.IPAddress(request.IPv6[:], request.Port)
+	case AddrTypeDomain:
+		return v2net.DomainAddress(request.Domain, request.Port)
+	default:
+		panic("Unknown address type")
+	}
+}
+
 const (
 	ErrorSuccess                 = byte(0x00)
 	ErrorGeneralFailure          = byte(0x01)

+ 24 - 4
io/vmess/vmess.go

@@ -15,6 +15,7 @@ import (
 
 	"github.com/v2ray/v2ray-core"
 	v2io "github.com/v2ray/v2ray-core/io"
+	v2net "github.com/v2ray/v2ray-core/net"
 )
 
 const (
@@ -22,7 +23,7 @@ const (
 	addrTypeIPv6   = byte(0x03)
 	addrTypeDomain = byte(0x02)
 
-	vMessVersion = byte(0x01)
+	Version = byte(0x01)
 )
 
 var (
@@ -95,12 +96,25 @@ func (r *VMessRequest) targetAddressType() byte {
 	return r[56]
 }
 
+func (r *VMessRequest) Destination() v2net.VAddress {
+	switch r.targetAddressType() {
+	case addrTypeIPv4:
+		fallthrough
+	case addrTypeIPv6:
+		return v2net.IPAddress(r.targetAddressBytes(), r.Port())
+	case addrTypeDomain:
+		return v2net.DomainAddress(r.TargetAddress(), r.Port())
+	default:
+		panic("Unpexected address type")
+	}
+}
+
 func (r *VMessRequest) TargetAddress() string {
 	switch r.targetAddressType() {
 	case addrTypeIPv4:
-		return string(net.IPv4(r[57], r[58], r[59], r[60]))
+		return net.IP(r[57:61]).String()
 	case addrTypeIPv6:
-		return string(net.IP(r[57:73]))
+		return net.IP(r[57:73]).String()
 	case addrTypeDomain:
 		domainLength := int(r[57])
 		return string(r[58 : 58+domainLength])
@@ -326,4 +340,10 @@ func (w *VMessRequestWriter) Write(writer io.Writer, request *VMessRequest) erro
 	return nil
 }
 
-type VMessOutput [4]byte
+type VMessResponse [4]byte
+
+func NewVMessResponse(request *VMessRequest) *VMessResponse {
+	response := new(VMessResponse)
+	copy(response[:], request.ResponseHeader())
+	return response
+}

+ 7 - 6
net/freedom/freedom.go

@@ -5,24 +5,25 @@ import (
 	"net"
 
 	"github.com/v2ray/v2ray-core"
+	v2net "github.com/v2ray/v2ray-core/net"
 )
 
 type VFreeConnection struct {
-	network string
-	address string
+	vPoint *core.VPoint
+	dest   v2net.VAddress
 }
 
-func NewVFreeConnection(network string, address string) *VFreeConnection {
+func NewVFreeConnection(vp *core.VPoint, dest v2net.VAddress) *VFreeConnection {
 	conn := new(VFreeConnection)
-	conn.network = network
-	conn.address = address
+	conn.vPoint = vp
+	conn.dest = dest
 	return conn
 }
 
 func (vconn *VFreeConnection) Start(vRay core.OutboundVRay) error {
 	input := vRay.OutboundInput()
 	output := vRay.OutboundOutput()
-	conn, err := net.Dial(vconn.network, vconn.address)
+	conn, err := net.Dial("tcp", vconn.dest.String())
 	if err != nil {
 		return err
 	}

+ 46 - 1
net/socks/socks.go

@@ -2,8 +2,10 @@ package socks
 
 import (
 	"errors"
+	"io"
 	"net"
 
+	"github.com/v2ray/v2ray-core"
 	socksio "github.com/v2ray/v2ray-core/io/socks"
 )
 
@@ -15,6 +17,13 @@ var (
 // SocksServer is a SOCKS 5 proxy server
 type SocksServer struct {
 	accepting bool
+	vPoint    *core.VPoint
+}
+
+func NewSocksServer(vp *core.VPoint) *SocksServer {
+	server := new(SocksServer)
+	server.vPoint = vp
+	return server
 }
 
 func (server *SocksServer) Listen(port uint8) error {
@@ -65,7 +74,43 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
 		return ErrorCommandNotSupported
 	}
 
-	// TODO: establish connection with VNext
+	ray := server.vPoint.NewInboundConnectionAccepted(request.Destination())
+	input := ray.InboundInput()
+	output := ray.InboundOutput()
+	finish := make(chan bool, 2)
+
+	go server.dumpInput(connection, input, finish)
+	go server.dumpOutput(connection, output, finish)
+	server.waitForFinish(finish)
 
 	return nil
 }
+
+func (server *SocksServer) dumpInput(conn net.Conn, input chan<- []byte, finish chan<- bool) {
+	for {
+		buffer := make([]byte, 256)
+		nBytes, err := conn.Read(buffer)
+		if err == io.EOF {
+			finish <- true
+			break
+		}
+		input <- buffer[:nBytes]
+	}
+}
+
+func (server *SocksServer) dumpOutput(conn net.Conn, output <-chan []byte, finish chan<- bool) {
+	for {
+		buffer, open := <-output
+		if !open {
+			finish <- true
+			break
+		}
+		conn.Write(buffer)
+	}
+}
+
+func (server *SocksServer) waitForFinish(finish <-chan bool) {
+	for i := 0; i < 2; i++ {
+		<-finish
+	}
+}

+ 12 - 0
net/socks/socksfactory.go

@@ -0,0 +1,12 @@
+package socks
+
+import (
+	"github.com/v2ray/v2ray-core"
+)
+
+type SocksServerFactory struct {
+}
+
+func (factory *SocksServerFactory) Create(vp *core.VPoint) *SocksServer {
+	return NewSocksServer(vp)
+}

+ 60 - 0
net/vdest.go

@@ -0,0 +1,60 @@
+package core
+
+import (
+	"net"
+	"strconv"
+)
+
+const (
+	AddrTypeIP     = byte(0x01)
+	AddrTypeDomain = byte(0x03)
+)
+
+type VAddress struct {
+	Type   byte
+	IP     net.IP
+	Domain string
+	Port   uint16
+}
+
+func IPAddress(ip []byte, port uint16) VAddress {
+	// TODO: check IP length
+	return VAddress{
+		AddrTypeIP,
+		net.IP(ip),
+		"",
+		port}
+}
+
+func DomainAddress(domain string, port uint16) VAddress {
+	return VAddress{
+		AddrTypeDomain,
+		nil,
+		domain,
+		port}
+}
+
+func (addr VAddress) IsIPv4() bool {
+	return addr.Type == AddrTypeIP && len(addr.IP) == net.IPv4len
+}
+
+func (addr VAddress) IsIPv6() bool {
+	return addr.Type == AddrTypeIP && len(addr.IP) == net.IPv6len
+}
+
+func (addr VAddress) IsDomain() bool {
+	return addr.Type == AddrTypeDomain
+}
+
+func (addr VAddress) String() string {
+	var host string
+	switch addr.Type {
+	case AddrTypeIP:
+		host = addr.IP.String()
+	case AddrTypeDomain:
+		host = addr.Domain
+	default:
+		panic("Unknown Address Type " + strconv.Itoa(int(addr.Type)))
+	}
+	return host + ":" + strconv.Itoa(int(addr.Port))
+}

+ 3 - 15
net/vmess/vmess.go

@@ -1,17 +1,5 @@
-package vemss
+package vmess
 
-import (
-	"net"
+const (
+	BufferSize = 256
 )
-
-type VMessHandler struct {
-}
-
-func (*VMessHandler) Listen(port uint8) error {
-	_, err := net.Listen("tcp", ":"+string(port))
-	if err != nil {
-		return err
-	}
-
-	return nil
-}

+ 119 - 0
net/vmess/vmessin.go

@@ -0,0 +1,119 @@
+package vmess
+
+import (
+	"crypto/md5"
+	"io"
+	"net"
+
+	"github.com/v2ray/v2ray-core"
+	v2io "github.com/v2ray/v2ray-core/io"
+	vmessio "github.com/v2ray/v2ray-core/io/vmess"
+)
+
+type VMessInboundHandler struct {
+	vPoint    *core.VPoint
+	accepting bool
+}
+
+func NewVMessInboundHandler(vp *core.VPoint) *VMessInboundHandler {
+	handler := new(VMessInboundHandler)
+	handler.vPoint = vp
+	return handler
+}
+
+func (handler *VMessInboundHandler) Listen(port uint8) error {
+	listener, err := net.Listen("tcp", ":"+string(port))
+	if err != nil {
+		return err
+	}
+	handler.accepting = true
+	go handler.AcceptConnections(listener)
+
+	return nil
+}
+
+func (handler *VMessInboundHandler) AcceptConnections(listener net.Listener) error {
+	for handler.accepting {
+		connection, err := listener.Accept()
+		if err != nil {
+			return err
+		}
+		go handler.HandleConnection(connection)
+	}
+	return nil
+}
+
+func (handler *VMessInboundHandler) HandleConnection(connection net.Conn) error {
+	defer connection.Close()
+	reader := vmessio.NewVMessRequestReader(handler.vPoint.UserSet)
+
+	request, err := reader.Read(connection)
+	if err != nil {
+		return err
+	}
+
+	response := vmessio.NewVMessResponse(request)
+	connection.Write(response[:])
+
+	requestKey := request.RequestKey()
+	requestIV := request.RequestIV()
+	responseKey := md5.Sum(requestKey)
+	responseIV := md5.Sum(requestIV)
+
+	requestReader, err := v2io.NewAesDecryptReader(requestKey, requestIV, connection)
+	if err != nil {
+		return err
+	}
+
+	responseWriter, err := v2io.NewAesEncryptWriter(responseKey[:], responseIV[:], connection)
+	if err != nil {
+		return err
+	}
+
+	ray := handler.vPoint.NewInboundConnectionAccepted(request.Destination())
+	input := ray.InboundInput()
+	output := ray.InboundOutput()
+	finish := make(chan bool, 2)
+
+	go handler.dumpInput(requestReader, input, finish)
+	go handler.dumpOutput(responseWriter, output, finish)
+	handler.waitForFinish(finish)
+
+	return nil
+}
+
+func (handler *VMessInboundHandler) dumpInput(reader io.Reader, input chan<- []byte, finish chan<- bool) {
+	for {
+		buffer := make([]byte, BufferSize)
+		nBytes, err := reader.Read(buffer)
+		if err == io.EOF {
+			finish <- true
+			break
+		}
+		input <- buffer[:nBytes]
+	}
+}
+
+func (handler *VMessInboundHandler) dumpOutput(writer io.Writer, output <-chan []byte, finish chan<- bool) {
+	for {
+		buffer, open := <-output
+		if !open {
+			finish <- true
+			break
+		}
+		writer.Write(buffer)
+	}
+}
+
+func (handler *VMessInboundHandler) waitForFinish(finish <-chan bool) {
+	for i := 0; i < 2; i++ {
+		<-finish
+	}
+}
+
+type VMessInboundHandlerFactory struct {
+}
+
+func (factory *VMessInboundHandlerFactory) Create(vp *core.VPoint) *VMessInboundHandler {
+	return NewVMessInboundHandler(vp)
+}

+ 133 - 0
net/vmess/vmessout.go

@@ -0,0 +1,133 @@
+package vmess
+
+import (
+	"crypto/md5"
+	"crypto/rand"
+	"io"
+	mrand "math/rand"
+	"net"
+
+	"github.com/v2ray/v2ray-core"
+	v2io "github.com/v2ray/v2ray-core/io"
+	vmessio "github.com/v2ray/v2ray-core/io/vmess"
+	v2net "github.com/v2ray/v2ray-core/net"
+)
+
+type VMessOutboundHandler struct {
+	vPoint *core.VPoint
+	dest   v2net.VAddress
+}
+
+func NewVMessOutboundHandler(vp *core.VPoint, dest v2net.VAddress) *VMessOutboundHandler {
+	handler := new(VMessOutboundHandler)
+	handler.vPoint = vp
+	handler.dest = dest
+	return handler
+}
+
+func (handler *VMessOutboundHandler) pickVNext() (v2net.VAddress, core.VUser) {
+	vNextLen := len(handler.vPoint.Config.VNextList)
+	if vNextLen == 0 {
+		panic("Zero vNext is configured.")
+	}
+	vNextIndex := mrand.Intn(vNextLen)
+	vNext := handler.vPoint.Config.VNextList[vNextIndex]
+	vNextUserLen := len(vNext.Users)
+	if vNextUserLen == 0 {
+		panic("Zero User account.")
+	}
+	vNextUserIndex := mrand.Intn(vNextUserLen)
+	vNextUser := vNext.Users[vNextUserIndex]
+	return vNext.Address, vNextUser
+}
+
+func (handler *VMessOutboundHandler) Start(ray core.OutboundVRay) error {
+	vNextAddress, vNextUser := handler.pickVNext()
+
+	request := new(vmessio.VMessRequest)
+	request.SetVersion(vmessio.Version)
+	copy(request.UserHash(), vNextUser.Id.Hash([]byte("ASK")))
+	rand.Read(request.RequestIV())
+	rand.Read(request.RequestKey())
+	rand.Read(request.ResponseHeader())
+	request.SetCommand(byte(0x01))
+	request.SetPort(handler.dest.Port)
+
+	address := handler.dest
+	switch {
+	case address.IsIPv4():
+		request.SetIPv4(address.IP)
+	case address.IsIPv6():
+		request.SetIPv6(address.IP)
+	case address.IsDomain():
+		request.SetDomain(address.Domain)
+	}
+
+	conn, err := net.Dial("tcp", vNextAddress.String())
+	if err != nil {
+		return err
+	}
+	defer conn.Close()
+
+	requestWriter := vmessio.NewVMessRequestWriter(handler.vPoint.UserSet)
+	requestWriter.Write(conn, request)
+
+	requestKey := request.RequestKey()
+	requestIV := request.RequestIV()
+	responseKey := md5.Sum(requestKey)
+	responseIV := md5.Sum(requestIV)
+
+	encryptRequestWriter, err := v2io.NewAesEncryptWriter(requestKey, requestIV, conn)
+	if err != nil {
+		return err
+	}
+	responseReader, err := v2io.NewAesDecryptReader(responseKey[:], responseIV[:], conn)
+	if err != nil {
+		return err
+	}
+
+	input := ray.OutboundInput()
+	output := ray.OutboundOutput()
+	finish := make(chan bool, 2)
+
+	go handler.dumpInput(encryptRequestWriter, input, finish)
+	go handler.dumpOutput(responseReader, output, finish)
+	handler.waitForFinish(finish)
+	return nil
+}
+
+func (handler *VMessOutboundHandler) dumpOutput(reader io.Reader, output chan<- []byte, finish chan<- bool) {
+	for {
+		buffer := make([]byte, BufferSize)
+		nBytes, err := reader.Read(buffer)
+		if err == io.EOF {
+			finish <- true
+			break
+		}
+		output <- buffer[:nBytes]
+	}
+}
+
+func (handler *VMessOutboundHandler) dumpInput(writer io.Writer, input <-chan []byte, finish chan<- bool) {
+	for {
+		buffer, open := <-input
+		if !open {
+			finish <- true
+			break
+		}
+		writer.Write(buffer)
+	}
+}
+
+func (handler *VMessOutboundHandler) waitForFinish(finish <-chan bool) {
+	for i := 0; i < 2; i++ {
+		<-finish
+	}
+}
+
+type VMessOutboundHandlerFactory struct {
+}
+
+func (factory *VMessOutboundHandlerFactory) Create(vp *core.VPoint, destination v2net.VAddress) *VMessOutboundHandler {
+	return NewVMessOutboundHandler(vp, destination)
+}

+ 6 - 2
vconfig.go

@@ -1,5 +1,9 @@
 package core
 
+import (
+	v2net "github.com/v2ray/v2ray-core/net"
+)
+
 // VUser is the user account that is used for connection to a VPoint
 type VUser struct {
 	Id VID // The ID of this VUser.
@@ -7,8 +11,8 @@ type VUser struct {
 
 // VNext is the next VPoint server in the connection chain.
 type VNext struct {
-	ServerAddress string  // Address of VNext server, in the form of "IP:Port"
-	User          []VUser // User accounts for accessing VNext.
+	Address v2net.VAddress // Address of VNext server
+	Users   []VUser        // User accounts for accessing VNext.
 }
 
 // VConfig is the config for VPoint server.

+ 39 - 7
vpoint.go

@@ -2,11 +2,14 @@ package core
 
 import (
 	"fmt"
+
+	v2net "github.com/v2ray/v2ray-core/net"
 )
 
 // VPoint is an single server in V2Ray system.
 type VPoint struct {
-	config     VConfig
+	Config     VConfig
+	UserSet    *VUserSet
 	ichFactory InboundConnectionHandlerFactory
 	ochFactory OutboundConnectionHandlerFactory
 }
@@ -15,7 +18,13 @@ type VPoint struct {
 // The server is not started at this point.
 func NewVPoint(config *VConfig) (*VPoint, error) {
 	var vpoint = new(VPoint)
-	vpoint.config = *config
+	vpoint.Config = *config
+	vpoint.UserSet = NewVUserSet()
+
+	for _, user := range vpoint.Config.AllowedClients {
+		vpoint.UserSet.AddUser(user)
+	}
+
 	return vpoint, nil
 }
 
@@ -28,23 +37,46 @@ type InboundConnectionHandler interface {
 }
 
 type OutboundConnectionHandlerFactory interface {
-	Create(vPoint *VPoint) (OutboundConnectionHandler, error)
+	Create(vPoint *VPoint, dest v2net.VAddress) (OutboundConnectionHandler, error)
 }
 
 type OutboundConnectionHandler interface {
-	Start(vray *OutboundVRay) error
+	Start(vray OutboundVRay) error
 }
 
 // Start starts the VPoint server, and return any error during the process.
 // In the case of any errors, the state of the server is unpredicatable.
 func (vp *VPoint) Start() error {
-	if vp.config.Port <= 0 {
-		return fmt.Errorf("Invalid port %d", vp.config.Port)
+	if vp.Config.Port <= 0 {
+		return fmt.Errorf("Invalid port %d", vp.Config.Port)
 	}
 	inboundConnectionHandler, err := vp.ichFactory.Create(vp)
 	if err != nil {
 		return err
 	}
-	err = inboundConnectionHandler.Listen(vp.config.Port)
+	err = inboundConnectionHandler.Listen(vp.Config.Port)
 	return nil
 }
+
+func (vp *VPoint) NewInboundConnectionAccepted(destination v2net.VAddress) InboundVRay {
+	/*
+	  vNextLen := len(vp.Config.VNextList)
+	  if vNextLen > 0 {
+	    vNextIndex := rand.Intn(vNextLen)
+	    vNext := vp.Config.VNextList[vNextIndex]
+	    vNextUser := dest.User
+	    vNextUserLen := len(vNext.Users)
+	    if vNextUserLen > 0 {
+	      vNextUserIndex = rand.Intn(vNextUserLen)
+	      vNextUser = vNext.Users[vNextUserIndex]
+	    }
+	    newDest := VDestination{"tcp", vNext.ServerAddress, vNextUser}
+	    dest = newDest
+	  }*/
+
+	ray := NewVRay()
+	// TODO: handle error
+	och, _ := vp.ochFactory.Create(vp, destination)
+	_ = och.Start(ray)
+	return ray
+}

+ 7 - 10
vray.go

@@ -5,11 +5,8 @@ type VRay struct {
 	Output chan []byte
 }
 
-func NewVRay() *VRay {
-	ray := new(VRay)
-	ray.Input = make(chan []byte, 128)
-	ray.Output = make(chan []byte, 128)
-	return ray
+func NewVRay() VRay {
+	return VRay{make(chan []byte, 128), make(chan []byte, 128)}
 }
 
 type OutboundVRay interface {
@@ -19,21 +16,21 @@ type OutboundVRay interface {
 
 type InboundVRay interface {
 	InboundInput() chan<- []byte
-	OutboundOutput() <-chan []byte
+	InboundOutput() <-chan []byte
 }
 
-func (ray *VRay) OutboundInput() <-chan []byte {
+func (ray VRay) OutboundInput() <-chan []byte {
 	return ray.Input
 }
 
-func (ray *VRay) OutboundOutput() chan<- []byte {
+func (ray VRay) OutboundOutput() chan<- []byte {
 	return ray.Output
 }
 
-func (ray *VRay) InboundInput() chan<- []byte {
+func (ray VRay) InboundInput() chan<- []byte {
 	return ray.Input
 }
 
-func (ray *VRay) InboundOutput() <-chan []byte {
+func (ray VRay) InboundOutput() <-chan []byte {
 	return ray.Output
 }