1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-06-10 09:50:43 +00:00

connecting dots

This commit is contained in:
V2Ray 2015-09-11 00:24:18 +02:00
parent 1c618e93b1
commit 0a96b8fb1d
13 changed files with 501 additions and 48 deletions

27
io/aes.go Normal file
View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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
net/socks/socksfactory.go Normal file
View File

@ -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
net/vdest.go Normal file
View File

@ -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))
}

View File

@ -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
net/vmess/vmessin.go Normal file
View File

@ -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
net/vmess/vmessout.go Normal file
View File

@ -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)
}

View File

@ -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.

View File

@ -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
}

17
vray.go
View File

@ -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
}