mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-12-30 05:56:54 -05:00
connecting dots
This commit is contained in:
parent
1c618e93b1
commit
0a96b8fb1d
27
io/aes.go
Normal file
27
io/aes.go
Normal 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
|
||||||
|
}
|
@ -5,6 +5,8 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -128,7 +130,7 @@ func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
|
|||||||
// buffer[2] is a reserved field
|
// buffer[2] is a reserved field
|
||||||
request.AddrType = buffer[3]
|
request.AddrType = buffer[3]
|
||||||
switch request.AddrType {
|
switch request.AddrType {
|
||||||
case 0x01:
|
case AddrTypeIPv4:
|
||||||
nBytes, err = reader.Read(request.IPv4[:])
|
nBytes, err = reader.Read(request.IPv4[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -137,7 +139,7 @@ func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
|
|||||||
err = fmt.Errorf("Unable to read IPv4 address.")
|
err = fmt.Errorf("Unable to read IPv4 address.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 0x03:
|
case AddrTypeDomain:
|
||||||
buffer = make([]byte, 257)
|
buffer = make([]byte, 257)
|
||||||
nBytes, err = reader.Read(buffer)
|
nBytes, err = reader.Read(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -149,7 +151,7 @@ func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
request.Domain = string(buffer[1 : domainLength+1])
|
request.Domain = string(buffer[1 : domainLength+1])
|
||||||
case 0x04:
|
case AddrTypeIPv6:
|
||||||
nBytes, err = reader.Read(request.IPv6[:])
|
nBytes, err = reader.Read(request.IPv6[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -177,6 +179,19 @@ func ReadRequest(reader io.Reader) (request *Socks5Request, err error) {
|
|||||||
return
|
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 (
|
const (
|
||||||
ErrorSuccess = byte(0x00)
|
ErrorSuccess = byte(0x00)
|
||||||
ErrorGeneralFailure = byte(0x01)
|
ErrorGeneralFailure = byte(0x01)
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/v2ray/v2ray-core"
|
"github.com/v2ray/v2ray-core"
|
||||||
v2io "github.com/v2ray/v2ray-core/io"
|
v2io "github.com/v2ray/v2ray-core/io"
|
||||||
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -22,7 +23,7 @@ const (
|
|||||||
addrTypeIPv6 = byte(0x03)
|
addrTypeIPv6 = byte(0x03)
|
||||||
addrTypeDomain = byte(0x02)
|
addrTypeDomain = byte(0x02)
|
||||||
|
|
||||||
vMessVersion = byte(0x01)
|
Version = byte(0x01)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -95,12 +96,25 @@ func (r *VMessRequest) targetAddressType() byte {
|
|||||||
return r[56]
|
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 {
|
func (r *VMessRequest) TargetAddress() string {
|
||||||
switch r.targetAddressType() {
|
switch r.targetAddressType() {
|
||||||
case addrTypeIPv4:
|
case addrTypeIPv4:
|
||||||
return string(net.IPv4(r[57], r[58], r[59], r[60]))
|
return net.IP(r[57:61]).String()
|
||||||
case addrTypeIPv6:
|
case addrTypeIPv6:
|
||||||
return string(net.IP(r[57:73]))
|
return net.IP(r[57:73]).String()
|
||||||
case addrTypeDomain:
|
case addrTypeDomain:
|
||||||
domainLength := int(r[57])
|
domainLength := int(r[57])
|
||||||
return string(r[58 : 58+domainLength])
|
return string(r[58 : 58+domainLength])
|
||||||
@ -326,4 +340,10 @@ func (w *VMessRequestWriter) Write(writer io.Writer, request *VMessRequest) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type VMessOutput [4]byte
|
type VMessResponse [4]byte
|
||||||
|
|
||||||
|
func NewVMessResponse(request *VMessRequest) *VMessResponse {
|
||||||
|
response := new(VMessResponse)
|
||||||
|
copy(response[:], request.ResponseHeader())
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
@ -5,24 +5,25 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/v2ray/v2ray-core"
|
"github.com/v2ray/v2ray-core"
|
||||||
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VFreeConnection struct {
|
type VFreeConnection struct {
|
||||||
network string
|
vPoint *core.VPoint
|
||||||
address string
|
dest v2net.VAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVFreeConnection(network string, address string) *VFreeConnection {
|
func NewVFreeConnection(vp *core.VPoint, dest v2net.VAddress) *VFreeConnection {
|
||||||
conn := new(VFreeConnection)
|
conn := new(VFreeConnection)
|
||||||
conn.network = network
|
conn.vPoint = vp
|
||||||
conn.address = address
|
conn.dest = dest
|
||||||
return conn
|
return conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vconn *VFreeConnection) Start(vRay core.OutboundVRay) error {
|
func (vconn *VFreeConnection) Start(vRay core.OutboundVRay) error {
|
||||||
input := vRay.OutboundInput()
|
input := vRay.OutboundInput()
|
||||||
output := vRay.OutboundOutput()
|
output := vRay.OutboundOutput()
|
||||||
conn, err := net.Dial(vconn.network, vconn.address)
|
conn, err := net.Dial("tcp", vconn.dest.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@ package socks
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/v2ray/v2ray-core"
|
||||||
socksio "github.com/v2ray/v2ray-core/io/socks"
|
socksio "github.com/v2ray/v2ray-core/io/socks"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,6 +17,13 @@ var (
|
|||||||
// SocksServer is a SOCKS 5 proxy server
|
// SocksServer is a SOCKS 5 proxy server
|
||||||
type SocksServer struct {
|
type SocksServer struct {
|
||||||
accepting bool
|
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 {
|
func (server *SocksServer) Listen(port uint8) error {
|
||||||
@ -65,7 +74,43 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
|
|||||||
return ErrorCommandNotSupported
|
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
|
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
12
net/socks/socksfactory.go
Normal 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
60
net/vdest.go
Normal 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))
|
||||||
|
}
|
@ -1,17 +1,5 @@
|
|||||||
package vemss
|
package vmess
|
||||||
|
|
||||||
import (
|
const (
|
||||||
"net"
|
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
119
net/vmess/vmessin.go
Normal 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
133
net/vmess/vmessout.go
Normal 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)
|
||||||
|
}
|
@ -1,5 +1,9 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
|
)
|
||||||
|
|
||||||
// VUser is the user account that is used for connection to a VPoint
|
// VUser is the user account that is used for connection to a VPoint
|
||||||
type VUser struct {
|
type VUser struct {
|
||||||
Id VID // The ID of this VUser.
|
Id VID // The ID of this VUser.
|
||||||
@ -7,8 +11,8 @@ type VUser struct {
|
|||||||
|
|
||||||
// VNext is the next VPoint server in the connection chain.
|
// VNext is the next VPoint server in the connection chain.
|
||||||
type VNext struct {
|
type VNext struct {
|
||||||
ServerAddress string // Address of VNext server, in the form of "IP:Port"
|
Address v2net.VAddress // Address of VNext server
|
||||||
User []VUser // User accounts for accessing VNext.
|
Users []VUser // User accounts for accessing VNext.
|
||||||
}
|
}
|
||||||
|
|
||||||
// VConfig is the config for VPoint server.
|
// VConfig is the config for VPoint server.
|
||||||
|
46
vpoint.go
46
vpoint.go
@ -2,11 +2,14 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
v2net "github.com/v2ray/v2ray-core/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VPoint is an single server in V2Ray system.
|
// VPoint is an single server in V2Ray system.
|
||||||
type VPoint struct {
|
type VPoint struct {
|
||||||
config VConfig
|
Config VConfig
|
||||||
|
UserSet *VUserSet
|
||||||
ichFactory InboundConnectionHandlerFactory
|
ichFactory InboundConnectionHandlerFactory
|
||||||
ochFactory OutboundConnectionHandlerFactory
|
ochFactory OutboundConnectionHandlerFactory
|
||||||
}
|
}
|
||||||
@ -15,7 +18,13 @@ type VPoint struct {
|
|||||||
// The server is not started at this point.
|
// The server is not started at this point.
|
||||||
func NewVPoint(config *VConfig) (*VPoint, error) {
|
func NewVPoint(config *VConfig) (*VPoint, error) {
|
||||||
var vpoint = new(VPoint)
|
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
|
return vpoint, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,23 +37,46 @@ type InboundConnectionHandler interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OutboundConnectionHandlerFactory interface {
|
type OutboundConnectionHandlerFactory interface {
|
||||||
Create(vPoint *VPoint) (OutboundConnectionHandler, error)
|
Create(vPoint *VPoint, dest v2net.VAddress) (OutboundConnectionHandler, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutboundConnectionHandler interface {
|
type OutboundConnectionHandler interface {
|
||||||
Start(vray *OutboundVRay) error
|
Start(vray OutboundVRay) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the VPoint server, and return any error during the process.
|
// 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.
|
// In the case of any errors, the state of the server is unpredicatable.
|
||||||
func (vp *VPoint) Start() error {
|
func (vp *VPoint) Start() error {
|
||||||
if vp.config.Port <= 0 {
|
if vp.Config.Port <= 0 {
|
||||||
return fmt.Errorf("Invalid port %d", vp.config.Port)
|
return fmt.Errorf("Invalid port %d", vp.Config.Port)
|
||||||
}
|
}
|
||||||
inboundConnectionHandler, err := vp.ichFactory.Create(vp)
|
inboundConnectionHandler, err := vp.ichFactory.Create(vp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = inboundConnectionHandler.Listen(vp.config.Port)
|
err = inboundConnectionHandler.Listen(vp.Config.Port)
|
||||||
return nil
|
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
17
vray.go
@ -5,11 +5,8 @@ type VRay struct {
|
|||||||
Output chan []byte
|
Output chan []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVRay() *VRay {
|
func NewVRay() VRay {
|
||||||
ray := new(VRay)
|
return VRay{make(chan []byte, 128), make(chan []byte, 128)}
|
||||||
ray.Input = make(chan []byte, 128)
|
|
||||||
ray.Output = make(chan []byte, 128)
|
|
||||||
return ray
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutboundVRay interface {
|
type OutboundVRay interface {
|
||||||
@ -19,21 +16,21 @@ type OutboundVRay interface {
|
|||||||
|
|
||||||
type InboundVRay interface {
|
type InboundVRay interface {
|
||||||
InboundInput() chan<- []byte
|
InboundInput() chan<- []byte
|
||||||
OutboundOutput() <-chan []byte
|
InboundOutput() <-chan []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ray *VRay) OutboundInput() <-chan []byte {
|
func (ray VRay) OutboundInput() <-chan []byte {
|
||||||
return ray.Input
|
return ray.Input
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ray *VRay) OutboundOutput() chan<- []byte {
|
func (ray VRay) OutboundOutput() chan<- []byte {
|
||||||
return ray.Output
|
return ray.Output
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ray *VRay) InboundInput() chan<- []byte {
|
func (ray VRay) InboundInput() chan<- []byte {
|
||||||
return ray.Input
|
return ray.Input
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ray *VRay) InboundOutput() <-chan []byte {
|
func (ray VRay) InboundOutput() <-chan []byte {
|
||||||
return ray.Output
|
return ray.Output
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user