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

split listening settings from inbound proxies and apply context

This commit is contained in:
Darien Raymond 2017-01-26 20:46:44 +01:00
parent 3bbdf2a065
commit ca721230e1
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
73 changed files with 2086 additions and 2957 deletions

View File

@ -1,14 +1,15 @@
package dispatcher package dispatcher
import ( import (
"context"
"v2ray.com/core/app" "v2ray.com/core/app"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
) )
// Interface dispatch a packet and possibly further network payload to its destination. // Interface dispatch a packet and possibly further network payload to its destination.
type Interface interface { type Interface interface {
DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay DispatchToOutbound(ctx context.Context) ray.InboundRay
} }
func FromSpace(space app.Space) Interface { func FromSpace(space app.Space) Interface {

View File

@ -12,7 +12,6 @@ import (
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
) )
@ -43,12 +42,15 @@ func (DefaultDispatcher) Interface() interface{} {
return (*dispatcher.Interface)(nil) return (*dispatcher.Interface)(nil)
} }
func (v *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay { func (v *DefaultDispatcher) DispatchToOutbound(ctx context.Context) ray.InboundRay {
dispatcher := v.ohm.GetDefaultHandler() dispatcher := v.ohm.GetDefaultHandler()
destination := session.Destination destination := proxy.DestinationFromContext(ctx)
if !destination.IsValid() {
panic("Dispatcher: Invalid destination.")
}
if v.router != nil { if v.router != nil {
if tag, err := v.router.TakeDetour(session); err == nil { if tag, err := v.router.TakeDetour(ctx); err == nil {
if handler := v.ohm.GetHandler(tag); handler != nil { if handler := v.ohm.GetHandler(tag); handler != nil {
log.Info("DefaultDispatcher: Taking detour [", tag, "] for [", destination, "].") log.Info("DefaultDispatcher: Taking detour [", tag, "] for [", destination, "].")
dispatcher = handler dispatcher = handler
@ -60,9 +62,9 @@ func (v *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.I
} }
} }
direct := ray.NewRay() direct := ray.NewRay(ctx)
var waitFunc func() error var waitFunc func() error
if session.Inbound != nil && session.Inbound.AllowPassiveConnection { if allowPassiveConnection, ok := proxy.AllowPassiveConnectionFromContext(ctx); ok && allowPassiveConnection {
waitFunc = noOpWait() waitFunc = noOpWait()
} else { } else {
wdi := &waitDataInspector{ wdi := &waitDataInspector{
@ -72,12 +74,12 @@ func (v *DefaultDispatcher) DispatchToOutbound(session *proxy.SessionInfo) ray.I
waitFunc = waitForData(wdi) waitFunc = waitForData(wdi)
} }
go v.waitAndDispatch(waitFunc, destination, direct, dispatcher) go v.waitAndDispatch(ctx, waitFunc, direct, dispatcher)
return direct return direct
} }
func (v *DefaultDispatcher) waitAndDispatch(wait func() error, destination net.Destination, link ray.OutboundRay, dispatcher proxy.OutboundHandler) { func (v *DefaultDispatcher) waitAndDispatch(ctx context.Context, wait func() error, link ray.OutboundRay, dispatcher proxyman.OutboundHandler) {
if err := wait(); err != nil { if err := wait(); err != nil {
log.Info("DefaultDispatcher: Failed precondition: ", err) log.Info("DefaultDispatcher: Failed precondition: ", err)
link.OutboundInput().CloseError() link.OutboundInput().CloseError()
@ -85,7 +87,7 @@ func (v *DefaultDispatcher) waitAndDispatch(wait func() error, destination net.D
return return
} }
dispatcher.Dispatch(destination, link) dispatcher.Dispatch(ctx, link)
} }
func init() { func init() {

View File

@ -1,19 +1,18 @@
package server package server
import ( import (
"context"
"net" "net"
"sync" "sync"
"time" "time"
"github.com/miekg/dns"
"v2ray.com/core/app/dispatcher" "v2ray.com/core/app/dispatcher"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/dice" "v2ray.com/core/common/dice"
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet/udp" "v2ray.com/core/transport/internet/udp"
"github.com/miekg/dns"
) )
const ( const (
@ -101,7 +100,7 @@ func (v *UDPNameServer) AssignUnusedID(response chan<- *ARecord) uint16 {
} }
// Private: Visible for testing. // Private: Visible for testing.
func (v *UDPNameServer) HandleResponse(dest v2net.Destination, payload *buf.Buffer) { func (v *UDPNameServer) HandleResponse(payload *buf.Buffer) {
msg := new(dns.Msg) msg := new(dns.Msg)
err := msg.Unpack(payload.Bytes()) err := msg.Unpack(payload.Bytes())
if err != nil { if err != nil {
@ -165,15 +164,12 @@ func (v *UDPNameServer) BuildQueryA(domain string, id uint16) *buf.Buffer {
return buffer return buffer
} }
func (v *UDPNameServer) DispatchQuery(payload *buf.Buffer) {
v.udpServer.Dispatch(&proxy.SessionInfo{Source: pseudoDestination, Destination: v.address}, payload, v.HandleResponse)
}
func (v *UDPNameServer) QueryA(domain string) <-chan *ARecord { func (v *UDPNameServer) QueryA(domain string) <-chan *ARecord {
response := make(chan *ARecord, 1) response := make(chan *ARecord, 1)
id := v.AssignUnusedID(response) id := v.AssignUnusedID(response)
v.DispatchQuery(v.BuildQueryA(domain, id)) ctx, cancel := context.WithTimeout(context.Background(), time.Second*8)
v.udpServer.Dispatch(ctx, v.address, v.BuildQueryA(domain, id), v.HandleResponse)
go func() { go func() {
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
@ -182,11 +178,12 @@ func (v *UDPNameServer) QueryA(domain string) <-chan *ARecord {
_, found := v.requests[id] _, found := v.requests[id]
v.Unlock() v.Unlock()
if found { if found {
v.DispatchQuery(v.BuildQueryA(domain, id)) v.udpServer.Dispatch(ctx, v.address, v.BuildQueryA(domain, id), v.HandleResponse)
} else { } else {
break break
} }
} }
cancel()
}() }()
return response return response

View File

@ -1,42 +0,0 @@
package proxy
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Config struct {
}
func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.app.proxy.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/app/proxy/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 128 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x52, 0x2d, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0x2c, 0x28, 0xd0, 0x2f,
0x28, 0xca, 0xaf, 0xa8, 0xd4, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f,
0xc9, 0x17, 0x12, 0x81, 0x29, 0x2b, 0x4a, 0xd5, 0x4b, 0x2c, 0x28, 0xd0, 0x03, 0x2b, 0x51, 0xe2,
0xe0, 0x62, 0x73, 0x06, 0xab, 0x72, 0x72, 0xe5, 0x92, 0x48, 0xce, 0xcf, 0xd5, 0xc3, 0xa6, 0xca,
0x89, 0x1b, 0xa2, 0x26, 0x00, 0x64, 0x50, 0x14, 0x2b, 0x58, 0x6c, 0x15, 0x93, 0x48, 0x98, 0x51,
0x50, 0x62, 0xa5, 0x9e, 0x33, 0x48, 0xa9, 0x63, 0x41, 0x81, 0x5e, 0x00, 0x48, 0x38, 0x89, 0x0d,
0x6c, 0x9b, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x16, 0xbe, 0x54, 0x50, 0x96, 0x00, 0x00, 0x00,
}

View File

@ -1,10 +0,0 @@
syntax = "proto3";
package v2ray.core.app.proxy;
option csharp_namespace = "V2Ray.Core.App.Proxy";
option go_package = "proxy";
option java_package = "com.v2ray.core.app.proxy";
option java_outer_classname = "ConfigProto";
message Config {
}

View File

@ -1,156 +0,0 @@
package proxy
import (
"io"
"net"
"time"
"context"
"v2ray.com/core/app"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/ray"
)
type OutboundProxy struct {
outboundManager proxyman.OutboundHandlerManager
}
func NewOutboundProxy(ctx context.Context, config *Config) (*OutboundProxy, error) {
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, errors.New("OutboundProxy: No space in context.")
}
proxy := new(OutboundProxy)
space.OnInitialize(func() error {
proxy.outboundManager = proxyman.OutboundHandlerManagerFromSpace(space)
if proxy.outboundManager == nil {
return errors.New("Proxy: Outbound handler manager not found in space.")
}
return nil
})
return proxy, nil
}
func (OutboundProxy) Interface() interface{} {
return (*OutboundProxy)(nil)
}
func (v *OutboundProxy) RegisterDialer() {
internet.ProxyDialer = v.Dial
}
// Dial implements internet.Dialer.
func (v *OutboundProxy) Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) {
handler := v.outboundManager.GetHandler(options.Proxy.Tag)
if handler == nil {
log.Warning("Proxy: Failed to get outbound handler with tag: ", options.Proxy.Tag)
return internet.Dial(src, dest, internet.DialerOptions{
Stream: options.Stream,
})
}
log.Info("Proxy: Dialing to ", dest)
stream := ray.NewRay()
go handler.Dispatch(dest, stream)
return NewConnection(src, dest, stream), nil
}
type Connection struct {
stream ray.Ray
closed bool
localAddr net.Addr
remoteAddr net.Addr
reader *buf.BufferToBytesReader
writer *buf.BytesToBufferWriter
}
func NewConnection(src v2net.Address, dest v2net.Destination, stream ray.Ray) *Connection {
return &Connection{
stream: stream,
localAddr: &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
},
remoteAddr: &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
},
reader: buf.NewBytesReader(stream.InboundOutput()),
writer: buf.NewBytesWriter(stream.InboundInput()),
}
}
// Read implements net.Conn.Read().
func (v *Connection) Read(b []byte) (int, error) {
if v.closed {
return 0, io.EOF
}
return v.reader.Read(b)
}
// Write implements net.Conn.Write().
func (v *Connection) Write(b []byte) (int, error) {
if v.closed {
return 0, io.ErrClosedPipe
}
return v.writer.Write(b)
}
// Close implements net.Conn.Close().
func (v *Connection) Close() error {
v.closed = true
v.stream.InboundInput().Close()
v.stream.InboundOutput().CloseError()
return nil
}
// LocalAddr implements net.Conn.LocalAddr().
func (v *Connection) LocalAddr() net.Addr {
return v.localAddr
}
// RemoteAddr implements net.Conn.RemoteAddr().
func (v *Connection) RemoteAddr() net.Addr {
return v.remoteAddr
}
func (v *Connection) SetDeadline(t time.Time) error {
return nil
}
func (v *Connection) SetReadDeadline(t time.Time) error {
return nil
}
func (v *Connection) SetWriteDeadline(t time.Time) error {
return nil
}
func (v *Connection) Reusable() bool {
return false
}
func (v *Connection) SetReusable(bool) {
}
func OutboundProxyFromSpace(space app.Space) *OutboundProxy {
app := space.GetApplication((*OutboundProxy)(nil))
if app == nil {
return nil
}
return app.(*OutboundProxy)
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewOutboundProxy(ctx, config.(*Config))
}))
}

View File

@ -1,74 +0,0 @@
package proxy_test
import (
"context"
"testing"
"v2ray.com/core/app"
. "v2ray.com/core/app/proxy"
"v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/proxy/freedom"
"v2ray.com/core/testing/assert"
"v2ray.com/core/testing/servers/tcp"
"v2ray.com/core/transport/internet"
_ "v2ray.com/core/transport/internet/tcp"
)
func TestProxyDial(t *testing.T) {
assert := assert.On(t)
space := app.NewSpace()
ctx := app.ContextWithSpace(context.Background(), space)
assert.Error(app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))).IsNil()
outboundManager := proxyman.OutboundHandlerManagerFromSpace(space)
freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
Tag: "tag",
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
},
}), &freedom.Config{})
assert.Error(err).IsNil()
common.Must(outboundManager.SetHandler("tag", freedom))
assert.Error(app.AddApplicationToSpace(ctx, new(Config))).IsNil()
proxy := OutboundProxyFromSpace(space)
assert.Error(space.Initialize()).IsNil()
xor := func(b []byte) []byte {
for idx, x := range b {
b[idx] = x ^ 'c'
}
return b
}
tcpServer := &tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
assert.Error(err).IsNil()
conn, err := proxy.Dial(net.LocalHostIP, dest, internet.DialerOptions{
Stream: &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
},
Proxy: &internet.ProxyConfig{
Tag: "tag",
},
})
assert.Error(err).IsNil()
_, err = conn.Write([]byte{'a', 'b', 'c', 'd'})
assert.Error(err).IsNil()
b := make([]byte, 10)
nBytes, err := conn.Read(b)
assert.Error(err).IsNil()
assert.Bytes(xor(b[:nBytes])).Equals([]byte{'a', 'b', 'c', 'd'})
common.Must(conn.Close())
tcpServer.Close()
}

View File

@ -134,88 +134,72 @@ func (m *AllocationStrategy_AllocationStrategyRefresh) GetValue() uint32 {
return 0 return 0
} }
type StreamReceiverConfig struct { type ReceiverConfig struct {
PortRange *v2ray_core_common_net1.PortRange `protobuf:"bytes,1,opt,name=port_range,json=portRange" json:"port_range,omitempty"` PortRange *v2ray_core_common_net1.PortRange `protobuf:"bytes,1,opt,name=port_range,json=portRange" json:"port_range,omitempty"`
Listen *v2ray_core_common_net.IPOrDomain `protobuf:"bytes,2,opt,name=listen" json:"listen,omitempty"` Listen *v2ray_core_common_net.IPOrDomain `protobuf:"bytes,2,opt,name=listen" json:"listen,omitempty"`
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy" json:"allocation_strategy,omitempty"` AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy" json:"allocation_strategy,omitempty"`
StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"` StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,4,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
ReceiveOriginalDestination bool `protobuf:"varint,5,opt,name=receive_original_destination,json=receiveOriginalDestination" json:"receive_original_destination,omitempty"`
AllowPassiveConnection bool `protobuf:"varint,6,opt,name=allow_passive_connection,json=allowPassiveConnection" json:"allow_passive_connection,omitempty"`
} }
func (m *StreamReceiverConfig) Reset() { *m = StreamReceiverConfig{} } func (m *ReceiverConfig) Reset() { *m = ReceiverConfig{} }
func (m *StreamReceiverConfig) String() string { return proto.CompactTextString(m) } func (m *ReceiverConfig) String() string { return proto.CompactTextString(m) }
func (*StreamReceiverConfig) ProtoMessage() {} func (*ReceiverConfig) ProtoMessage() {}
func (*StreamReceiverConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } func (*ReceiverConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *StreamReceiverConfig) GetPortRange() *v2ray_core_common_net1.PortRange { func (m *ReceiverConfig) GetPortRange() *v2ray_core_common_net1.PortRange {
if m != nil { if m != nil {
return m.PortRange return m.PortRange
} }
return nil return nil
} }
func (m *StreamReceiverConfig) GetListen() *v2ray_core_common_net.IPOrDomain { func (m *ReceiverConfig) GetListen() *v2ray_core_common_net.IPOrDomain {
if m != nil { if m != nil {
return m.Listen return m.Listen
} }
return nil return nil
} }
func (m *StreamReceiverConfig) GetAllocationStrategy() *AllocationStrategy { func (m *ReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
if m != nil { if m != nil {
return m.AllocationStrategy return m.AllocationStrategy
} }
return nil return nil
} }
func (m *StreamReceiverConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig { func (m *ReceiverConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
if m != nil { if m != nil {
return m.StreamSettings return m.StreamSettings
} }
return nil return nil
} }
type DatagramReceiverConfig struct { func (m *ReceiverConfig) GetReceiveOriginalDestination() bool {
PortRange *v2ray_core_common_net1.PortRange `protobuf:"bytes,1,opt,name=port_range,json=portRange" json:"port_range,omitempty"` if m != nil {
Listen *v2ray_core_common_net.IPOrDomain `protobuf:"bytes,2,opt,name=listen" json:"listen,omitempty"` return m.ReceiveOriginalDestination
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy" json:"allocation_strategy,omitempty"` }
return false
} }
func (m *DatagramReceiverConfig) Reset() { *m = DatagramReceiverConfig{} } func (m *ReceiverConfig) GetAllowPassiveConnection() bool {
func (m *DatagramReceiverConfig) String() string { return proto.CompactTextString(m) }
func (*DatagramReceiverConfig) ProtoMessage() {}
func (*DatagramReceiverConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *DatagramReceiverConfig) GetPortRange() *v2ray_core_common_net1.PortRange {
if m != nil { if m != nil {
return m.PortRange return m.AllowPassiveConnection
} }
return nil return false
}
func (m *DatagramReceiverConfig) GetListen() *v2ray_core_common_net.IPOrDomain {
if m != nil {
return m.Listen
}
return nil
}
func (m *DatagramReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
if m != nil {
return m.AllocationStrategy
}
return nil
} }
type InboundHandlerConfig struct { type InboundHandlerConfig struct {
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"` Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
ReceiverSettings []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,rep,name=receiver_settings,json=receiverSettings" json:"receiver_settings,omitempty"` ReceiverSettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,opt,name=receiver_settings,json=receiverSettings" json:"receiver_settings,omitempty"`
ProxySettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"` ProxySettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"`
} }
func (m *InboundHandlerConfig) Reset() { *m = InboundHandlerConfig{} } func (m *InboundHandlerConfig) Reset() { *m = InboundHandlerConfig{} }
func (m *InboundHandlerConfig) String() string { return proto.CompactTextString(m) } func (m *InboundHandlerConfig) String() string { return proto.CompactTextString(m) }
func (*InboundHandlerConfig) ProtoMessage() {} func (*InboundHandlerConfig) ProtoMessage() {}
func (*InboundHandlerConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (*InboundHandlerConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *InboundHandlerConfig) GetTag() string { func (m *InboundHandlerConfig) GetTag() string {
if m != nil { if m != nil {
@ -224,7 +208,7 @@ func (m *InboundHandlerConfig) GetTag() string {
return "" return ""
} }
func (m *InboundHandlerConfig) GetReceiverSettings() []*v2ray_core_common_serial.TypedMessage { func (m *InboundHandlerConfig) GetReceiverSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil { if m != nil {
return m.ReceiverSettings return m.ReceiverSettings
} }
@ -244,60 +228,35 @@ type OutboundConfig struct {
func (m *OutboundConfig) Reset() { *m = OutboundConfig{} } func (m *OutboundConfig) Reset() { *m = OutboundConfig{} }
func (m *OutboundConfig) String() string { return proto.CompactTextString(m) } func (m *OutboundConfig) String() string { return proto.CompactTextString(m) }
func (*OutboundConfig) ProtoMessage() {} func (*OutboundConfig) ProtoMessage() {}
func (*OutboundConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (*OutboundConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
type StreamSenderConfig struct { type SenderConfig struct {
// Send traffic through the given IP. Only IP is allowed. // Send traffic through the given IP. Only IP is allowed.
Via *v2ray_core_common_net.IPOrDomain `protobuf:"bytes,1,opt,name=via" json:"via,omitempty"` Via *v2ray_core_common_net.IPOrDomain `protobuf:"bytes,1,opt,name=via" json:"via,omitempty"`
StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"` StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,2,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
ProxySettings *v2ray_core_transport_internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"` ProxySettings *v2ray_core_transport_internet.ProxyConfig `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"`
} }
func (m *StreamSenderConfig) Reset() { *m = StreamSenderConfig{} } func (m *SenderConfig) Reset() { *m = SenderConfig{} }
func (m *StreamSenderConfig) String() string { return proto.CompactTextString(m) } func (m *SenderConfig) String() string { return proto.CompactTextString(m) }
func (*StreamSenderConfig) ProtoMessage() {} func (*SenderConfig) ProtoMessage() {}
func (*StreamSenderConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } func (*SenderConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *StreamSenderConfig) GetVia() *v2ray_core_common_net.IPOrDomain { func (m *SenderConfig) GetVia() *v2ray_core_common_net.IPOrDomain {
if m != nil { if m != nil {
return m.Via return m.Via
} }
return nil return nil
} }
func (m *StreamSenderConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig { func (m *SenderConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
if m != nil { if m != nil {
return m.StreamSettings return m.StreamSettings
} }
return nil return nil
} }
func (m *StreamSenderConfig) GetProxySettings() *v2ray_core_transport_internet.ProxyConfig { func (m *SenderConfig) GetProxySettings() *v2ray_core_transport_internet.ProxyConfig {
if m != nil {
return m.ProxySettings
}
return nil
}
type DatagramSenderConfig struct {
// Send traffic through the given IP. Only IP is allowed.
Via *v2ray_core_common_net.IPOrDomain `protobuf:"bytes,1,opt,name=via" json:"via,omitempty"`
ProxySettings *v2ray_core_transport_internet.ProxyConfig `protobuf:"bytes,2,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"`
}
func (m *DatagramSenderConfig) Reset() { *m = DatagramSenderConfig{} }
func (m *DatagramSenderConfig) String() string { return proto.CompactTextString(m) }
func (*DatagramSenderConfig) ProtoMessage() {}
func (*DatagramSenderConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
func (m *DatagramSenderConfig) GetVia() *v2ray_core_common_net.IPOrDomain {
if m != nil {
return m.Via
}
return nil
}
func (m *DatagramSenderConfig) GetProxySettings() *v2ray_core_transport_internet.ProxyConfig {
if m != nil { if m != nil {
return m.ProxySettings return m.ProxySettings
} }
@ -305,15 +264,17 @@ func (m *DatagramSenderConfig) GetProxySettings() *v2ray_core_transport_internet
} }
type OutboundHandlerConfig struct { type OutboundHandlerConfig struct {
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"` Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
SenderSettings []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,rep,name=sender_settings,json=senderSettings" json:"sender_settings,omitempty"` SenderSettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,opt,name=sender_settings,json=senderSettings" json:"sender_settings,omitempty"`
ProxySettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"` ProxySettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"`
Expire int64 `protobuf:"varint,4,opt,name=expire" json:"expire,omitempty"`
Comment string `protobuf:"bytes,5,opt,name=comment" json:"comment,omitempty"`
} }
func (m *OutboundHandlerConfig) Reset() { *m = OutboundHandlerConfig{} } func (m *OutboundHandlerConfig) Reset() { *m = OutboundHandlerConfig{} }
func (m *OutboundHandlerConfig) String() string { return proto.CompactTextString(m) } func (m *OutboundHandlerConfig) String() string { return proto.CompactTextString(m) }
func (*OutboundHandlerConfig) ProtoMessage() {} func (*OutboundHandlerConfig) ProtoMessage() {}
func (*OutboundHandlerConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } func (*OutboundHandlerConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *OutboundHandlerConfig) GetTag() string { func (m *OutboundHandlerConfig) GetTag() string {
if m != nil { if m != nil {
@ -322,7 +283,7 @@ func (m *OutboundHandlerConfig) GetTag() string {
return "" return ""
} }
func (m *OutboundHandlerConfig) GetSenderSettings() []*v2ray_core_common_serial.TypedMessage { func (m *OutboundHandlerConfig) GetSenderSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil { if m != nil {
return m.SenderSettings return m.SenderSettings
} }
@ -336,17 +297,29 @@ func (m *OutboundHandlerConfig) GetProxySettings() *v2ray_core_common_serial.Typ
return nil return nil
} }
func (m *OutboundHandlerConfig) GetExpire() int64 {
if m != nil {
return m.Expire
}
return 0
}
func (m *OutboundHandlerConfig) GetComment() string {
if m != nil {
return m.Comment
}
return ""
}
func init() { func init() {
proto.RegisterType((*InboundConfig)(nil), "v2ray.core.app.proxyman.InboundConfig") proto.RegisterType((*InboundConfig)(nil), "v2ray.core.app.proxyman.InboundConfig")
proto.RegisterType((*AllocationStrategy)(nil), "v2ray.core.app.proxyman.AllocationStrategy") proto.RegisterType((*AllocationStrategy)(nil), "v2ray.core.app.proxyman.AllocationStrategy")
proto.RegisterType((*AllocationStrategy_AllocationStrategyConcurrency)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency") proto.RegisterType((*AllocationStrategy_AllocationStrategyConcurrency)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency")
proto.RegisterType((*AllocationStrategy_AllocationStrategyRefresh)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh") proto.RegisterType((*AllocationStrategy_AllocationStrategyRefresh)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh")
proto.RegisterType((*StreamReceiverConfig)(nil), "v2ray.core.app.proxyman.StreamReceiverConfig") proto.RegisterType((*ReceiverConfig)(nil), "v2ray.core.app.proxyman.ReceiverConfig")
proto.RegisterType((*DatagramReceiverConfig)(nil), "v2ray.core.app.proxyman.DatagramReceiverConfig")
proto.RegisterType((*InboundHandlerConfig)(nil), "v2ray.core.app.proxyman.InboundHandlerConfig") proto.RegisterType((*InboundHandlerConfig)(nil), "v2ray.core.app.proxyman.InboundHandlerConfig")
proto.RegisterType((*OutboundConfig)(nil), "v2ray.core.app.proxyman.OutboundConfig") proto.RegisterType((*OutboundConfig)(nil), "v2ray.core.app.proxyman.OutboundConfig")
proto.RegisterType((*StreamSenderConfig)(nil), "v2ray.core.app.proxyman.StreamSenderConfig") proto.RegisterType((*SenderConfig)(nil), "v2ray.core.app.proxyman.SenderConfig")
proto.RegisterType((*DatagramSenderConfig)(nil), "v2ray.core.app.proxyman.DatagramSenderConfig")
proto.RegisterType((*OutboundHandlerConfig)(nil), "v2ray.core.app.proxyman.OutboundHandlerConfig") proto.RegisterType((*OutboundHandlerConfig)(nil), "v2ray.core.app.proxyman.OutboundHandlerConfig")
proto.RegisterEnum("v2ray.core.app.proxyman.AllocationStrategy_Type", AllocationStrategy_Type_name, AllocationStrategy_Type_value) proto.RegisterEnum("v2ray.core.app.proxyman.AllocationStrategy_Type", AllocationStrategy_Type_name, AllocationStrategy_Type_value)
} }
@ -354,48 +327,52 @@ func init() {
func init() { proto.RegisterFile("v2ray.com/core/app/proxyman/config.proto", fileDescriptor0) } func init() { proto.RegisterFile("v2ray.com/core/app/proxyman/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 683 bytes of a gzipped FileDescriptorProto // 737 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe4, 0x55, 0xdd, 0x6e, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x55, 0xd1, 0x6e, 0xdb, 0x36,
0x18, 0x25, 0xe9, 0x18, 0xdb, 0x57, 0xd6, 0x15, 0x53, 0x58, 0x29, 0x42, 0x2a, 0x15, 0x82, 0x0a, 0x14, 0x9d, 0xec, 0xc4, 0x49, 0xae, 0x13, 0xc7, 0xe3, 0xb2, 0xc4, 0xf3, 0x36, 0xc0, 0x33, 0x86,
0x50, 0x32, 0x3a, 0x71, 0xc1, 0x15, 0xda, 0x9f, 0xc4, 0x2e, 0xc6, 0x8a, 0x3b, 0x71, 0x81, 0x90, 0xcd, 0xd8, 0x06, 0x29, 0x73, 0x30, 0x60, 0x7b, 0xda, 0x12, 0x27, 0xc0, 0xf2, 0x90, 0xd9, 0xa3,
0x2a, 0x2f, 0xf1, 0x42, 0x44, 0x62, 0x47, 0xb6, 0x5b, 0x96, 0x97, 0xe1, 0x01, 0x78, 0x0a, 0xae, 0x83, 0x3e, 0x14, 0x05, 0x04, 0x46, 0x62, 0x5c, 0xa1, 0x12, 0x29, 0x90, 0xb4, 0x13, 0xfd, 0x52,
0x90, 0x90, 0x78, 0x9a, 0x3d, 0x01, 0x72, 0x9c, 0x74, 0xd5, 0xda, 0xb2, 0x8d, 0x8a, 0x2b, 0xee, 0xbf, 0xa1, 0x0f, 0xfd, 0x80, 0x7e, 0x4a, 0xff, 0xa0, 0x2f, 0x05, 0x49, 0xc9, 0x36, 0x62, 0xbb,
0x5c, 0xf7, 0x3b, 0xc7, 0x3e, 0xe7, 0x7c, 0xfe, 0x02, 0xed, 0x61, 0x47, 0x90, 0xd4, 0xf1, 0x78, 0x69, 0x1a, 0xf4, 0x4d, 0x24, 0xcf, 0x39, 0xe4, 0x3d, 0x87, 0x97, 0x82, 0xce, 0xa4, 0x2b, 0x48,
0xec, 0x7a, 0x5c, 0x50, 0x97, 0x24, 0x89, 0x9b, 0x08, 0x7e, 0x92, 0xc6, 0x84, 0xb9, 0x1e, 0x67, 0xe6, 0x06, 0x3c, 0xf1, 0x02, 0x2e, 0xa8, 0x47, 0xd2, 0xd4, 0x4b, 0x05, 0xbf, 0xcd, 0x12, 0xc2,
0xc7, 0x61, 0xe0, 0x24, 0x82, 0x2b, 0x8e, 0xd6, 0x8a, 0x4a, 0x41, 0x1d, 0x92, 0x24, 0x4e, 0x51, 0xbc, 0x80, 0xb3, 0xeb, 0x68, 0xe4, 0xa6, 0x82, 0x2b, 0x8e, 0x0e, 0x0a, 0xa4, 0xa0, 0x2e, 0x49,
0xd5, 0x58, 0x3f, 0x47, 0xe1, 0xf1, 0x38, 0xe6, 0xcc, 0x95, 0x54, 0x84, 0x24, 0x72, 0x55, 0x9a, 0x53, 0xb7, 0x40, 0x35, 0x0f, 0xef, 0x48, 0x04, 0x3c, 0x49, 0x38, 0xf3, 0x24, 0x15, 0x11, 0x89,
0x50, 0xbf, 0x1f, 0x53, 0x29, 0x49, 0x40, 0x0d, 0x55, 0xe3, 0xc9, 0x74, 0x04, 0xa3, 0xca, 0x25, 0x3d, 0x95, 0xa5, 0x34, 0xf4, 0x13, 0x2a, 0x25, 0x19, 0x51, 0x2b, 0xd5, 0xfc, 0x79, 0x39, 0x83,
0xbe, 0x2f, 0xa8, 0x94, 0x79, 0xe1, 0xa3, 0xd9, 0x85, 0x09, 0x17, 0x2a, 0xaf, 0x72, 0xce, 0x55, 0x51, 0xe5, 0x91, 0x30, 0x14, 0x54, 0xca, 0x1c, 0xf8, 0xe3, 0x6a, 0x60, 0xca, 0x85, 0xca, 0x51,
0x29, 0x41, 0x98, 0xd4, 0xff, 0xbb, 0x21, 0x53, 0x54, 0xe8, 0xea, 0x71, 0x25, 0xad, 0x55, 0x58, 0xee, 0x1d, 0x94, 0x12, 0x84, 0x49, 0xbd, 0xee, 0x45, 0x4c, 0x51, 0xa1, 0xd1, 0xf3, 0x95, 0xb4,
0xd9, 0x63, 0x47, 0x7c, 0xc0, 0xfc, 0xed, 0x6c, 0xbb, 0xf5, 0xbd, 0x04, 0x68, 0x33, 0x8a, 0xb8, 0x77, 0x61, 0xe7, 0x9c, 0x5d, 0xf1, 0x31, 0x0b, 0x7b, 0x66, 0xba, 0xfd, 0xba, 0x0c, 0xe8, 0x38,
0x47, 0x54, 0xc8, 0x59, 0x4f, 0x09, 0xa2, 0x68, 0x90, 0xa2, 0x1d, 0x58, 0xd0, 0xb7, 0xaf, 0x5b, 0x8e, 0x79, 0x40, 0x54, 0xc4, 0xd9, 0x50, 0x09, 0xa2, 0xe8, 0x28, 0x43, 0xa7, 0xb0, 0xa6, 0x4f,
0x4d, 0xab, 0x5d, 0xe9, 0xac, 0x3b, 0x33, 0x0c, 0x70, 0x26, 0xa1, 0xce, 0x61, 0x9a, 0x50, 0x9c, 0xdf, 0x70, 0x5a, 0x4e, 0xa7, 0xd6, 0x3d, 0x74, 0x57, 0x18, 0xe0, 0x2e, 0x52, 0xdd, 0xcb, 0x2c,
0xa1, 0xd1, 0x67, 0x28, 0x7b, 0x9c, 0x79, 0x03, 0x21, 0x28, 0xf3, 0xd2, 0xba, 0xdd, 0xb4, 0xda, 0xa5, 0xd8, 0xb0, 0xd1, 0x0b, 0xa8, 0x06, 0x9c, 0x05, 0x63, 0x21, 0x28, 0x0b, 0xb2, 0x46, 0xa9,
0xe5, 0xce, 0xde, 0x55, 0xc8, 0x26, 0xb7, 0xb6, 0xcf, 0x08, 0xf1, 0x38, 0x3b, 0xea, 0xc3, 0x0d, 0xe5, 0x74, 0xaa, 0xdd, 0xf3, 0x87, 0x88, 0x2d, 0x4e, 0xf5, 0x66, 0x82, 0x78, 0x5e, 0x1d, 0xf9,
0x41, 0x8f, 0x05, 0x95, 0x9f, 0xea, 0xa5, 0xec, 0xa0, 0xdd, 0xf9, 0x0e, 0xc2, 0x86, 0x0c, 0x17, 0xb0, 0x21, 0xe8, 0xb5, 0xa0, 0xf2, 0x79, 0xa3, 0x6c, 0x36, 0x3a, 0x7b, 0xdc, 0x46, 0xd8, 0x8a,
0xac, 0x8d, 0x97, 0xf0, 0xe0, 0x8f, 0xd7, 0x41, 0x35, 0xb8, 0x3e, 0x24, 0xd1, 0xc0, 0xb8, 0xb6, 0xe1, 0x42, 0xb5, 0xf9, 0x07, 0x7c, 0xff, 0xc1, 0xe3, 0xa0, 0x3d, 0x58, 0x9f, 0x90, 0x78, 0x6c,
0x82, 0xcd, 0x8f, 0xc6, 0x0b, 0xb8, 0x37, 0x93, 0x7c, 0x3a, 0xa4, 0xf5, 0x1c, 0x16, 0xb4, 0x8b, 0x5d, 0xdb, 0xc1, 0x76, 0xd0, 0xfc, 0x1d, 0xbe, 0x59, 0x29, 0xbe, 0x9c, 0xd2, 0xfe, 0x0d, 0xd6,
0x08, 0x60, 0x71, 0x33, 0xfa, 0x42, 0x52, 0x59, 0xbd, 0xa6, 0xd7, 0x98, 0x30, 0x9f, 0xc7, 0x55, 0xb4, 0x8b, 0x08, 0xa0, 0x72, 0x1c, 0xdf, 0x90, 0x4c, 0xd6, 0xbf, 0xd0, 0xdf, 0x98, 0xb0, 0x90,
0x0b, 0xdd, 0x84, 0xa5, 0xdd, 0x13, 0x1d, 0x2f, 0x89, 0xaa, 0x76, 0xeb, 0x87, 0x0d, 0xb5, 0x9e, 0x27, 0x75, 0x07, 0x6d, 0xc3, 0xe6, 0xd9, 0xad, 0x8e, 0x97, 0xc4, 0xf5, 0x52, 0xfb, 0x55, 0x19,
0x12, 0x94, 0xc4, 0x98, 0x7a, 0x34, 0x1c, 0x52, 0x61, 0xb2, 0x45, 0xaf, 0x01, 0x74, 0x2b, 0xf4, 0x6a, 0x98, 0x06, 0x34, 0x9a, 0x50, 0x61, 0x53, 0x45, 0x7f, 0x03, 0xe8, 0x4b, 0xe0, 0x0b, 0xc2,
0x05, 0x61, 0x81, 0x39, 0xa1, 0xdc, 0x69, 0x8e, 0x9b, 0x62, 0x7a, 0xca, 0x61, 0x54, 0x39, 0x5d, 0x46, 0x56, 0xbb, 0xda, 0x6d, 0xcd, 0xdb, 0x61, 0x6f, 0x93, 0xcb, 0xa8, 0x72, 0x07, 0x5c, 0x28,
0x2e, 0x14, 0xd6, 0x75, 0x78, 0x39, 0x29, 0x96, 0xe8, 0x15, 0x2c, 0x46, 0xa1, 0x54, 0x94, 0xe5, 0xac, 0x71, 0x78, 0x2b, 0x2d, 0x3e, 0xd1, 0x5f, 0x50, 0x89, 0x23, 0xa9, 0x28, 0xcb, 0x43, 0xfb,
0xd1, 0x3d, 0x9c, 0x01, 0xde, 0xeb, 0x1e, 0x88, 0x1d, 0x1e, 0x93, 0x90, 0xe1, 0x1c, 0x80, 0x3e, 0x61, 0x05, 0xf9, 0x7c, 0xd0, 0x17, 0xa7, 0x3c, 0x21, 0x11, 0xc3, 0x39, 0x01, 0x3d, 0x83, 0xaf,
0xc2, 0x6d, 0x32, 0x52, 0xdd, 0x97, 0xb9, 0xec, 0x3c, 0x99, 0x67, 0x57, 0x48, 0x06, 0x23, 0x32, 0xc8, 0xb4, 0x5e, 0x5f, 0xe6, 0x05, 0xe7, 0x99, 0xfc, 0xfa, 0x80, 0x4c, 0x30, 0x22, 0x8b, 0x17,
0xd9, 0x9e, 0x87, 0xb0, 0x2a, 0x33, 0xc5, 0x7d, 0x49, 0x95, 0x0a, 0x59, 0x20, 0xeb, 0x0b, 0x93, 0xf3, 0x12, 0x76, 0xa5, 0x12, 0x94, 0x24, 0xbe, 0xa4, 0x4a, 0x45, 0x6c, 0x24, 0x1b, 0x6b, 0x8b,
0xcc, 0xa3, 0xc7, 0xe0, 0x14, 0x8f, 0xc1, 0x31, 0x3e, 0x19, 0x7f, 0x70, 0xc5, 0x70, 0xf4, 0x72, 0xca, 0xd3, 0x36, 0x70, 0x8b, 0x36, 0x70, 0x87, 0x86, 0x65, 0xfd, 0xc1, 0x35, 0xab, 0x31, 0xcc,
0x8a, 0xd6, 0xa9, 0x05, 0x77, 0x77, 0x88, 0x22, 0x81, 0xf8, 0x7f, 0xac, 0x6c, 0xfd, 0xb2, 0xa0, 0x25, 0xd0, 0x3f, 0xf0, 0x9d, 0xb0, 0x0e, 0xfa, 0x5c, 0x44, 0xa3, 0x88, 0x91, 0xd8, 0x0f, 0xa9,
0x96, 0x8f, 0x84, 0x37, 0x84, 0xf9, 0xd1, 0x48, 0x72, 0x15, 0x4a, 0x8a, 0x04, 0x99, 0xd6, 0x65, 0x54, 0x11, 0x33, 0xbb, 0x37, 0xd6, 0x5b, 0x4e, 0x67, 0x13, 0x37, 0x73, 0x4c, 0x3f, 0x87, 0x9c,
0xac, 0x97, 0xa8, 0x07, 0xb7, 0x44, 0x6e, 0xcb, 0x99, 0xef, 0x76, 0xb3, 0xd4, 0x2e, 0x77, 0x1e, 0xce, 0x10, 0xe8, 0x4f, 0x68, 0xe8, 0xd3, 0xde, 0xf8, 0x29, 0x91, 0x52, 0xeb, 0x04, 0x9c, 0x31,
0x4f, 0x91, 0x63, 0xa6, 0x60, 0x36, 0x0f, 0xfc, 0x7d, 0x33, 0x04, 0x71, 0xb5, 0x20, 0x28, 0x4c, 0x1a, 0x18, 0x76, 0xc5, 0xb0, 0xf7, 0xcd, 0xfa, 0xc0, 0x2e, 0xf7, 0xa6, 0xab, 0xed, 0x37, 0x0e,
0x47, 0xfb, 0x50, 0xc9, 0xae, 0x7c, 0xc6, 0x68, 0x84, 0x5d, 0x96, 0x71, 0x25, 0x43, 0x8f, 0x32, 0xec, 0xe5, 0x3d, 0xf9, 0x2f, 0x61, 0x61, 0x3c, 0x0d, 0xb1, 0x0e, 0x65, 0x45, 0x46, 0x26, 0xbd,
0xac, 0x42, 0xe5, 0x60, 0xa0, 0xc6, 0x27, 0xdc, 0xa9, 0x05, 0xa8, 0x97, 0x07, 0xcd, 0xfc, 0x91, 0x2d, 0xac, 0x3f, 0xd1, 0x10, 0xbe, 0xcc, 0x8f, 0x20, 0x66, 0xe5, 0xdb, 0x80, 0x7e, 0x5a, 0x12,
0xbc, 0x0d, 0x28, 0x0d, 0x43, 0x92, 0x47, 0x79, 0x89, 0x34, 0x74, 0xf5, 0xb4, 0xbe, 0xb3, 0xe7, 0x90, 0x7d, 0x86, 0x4c, 0x43, 0x86, 0x17, 0xf6, 0x15, 0xc2, 0xf5, 0x42, 0x60, 0x5a, 0xfb, 0x05,
0xee, 0x3b, 0xf4, 0x6e, 0x86, 0x05, 0x4f, 0x2f, 0x20, 0xed, 0x6a, 0x50, 0xce, 0x79, 0xce, 0x86, 0xd4, 0x4c, 0x08, 0x33, 0xc5, 0xf2, 0x83, 0x14, 0x77, 0x0c, 0xbb, 0x90, 0x6b, 0xd7, 0xa1, 0xd6,
0xaf, 0x16, 0xd4, 0x8a, 0x56, 0x9e, 0x5f, 0xf6, 0xe4, 0x05, 0xed, 0x79, 0x2f, 0xf8, 0xd3, 0x82, 0x1f, 0xab, 0xf9, 0x27, 0xe6, 0xad, 0x03, 0xdb, 0x43, 0xca, 0xc2, 0x69, 0x61, 0x47, 0x50, 0x9e,
0x3b, 0x45, 0x50, 0x17, 0xf5, 0xdd, 0x01, 0xac, 0xca, 0x4c, 0xc3, 0xdf, 0x76, 0x5d, 0xc5, 0xc0, 0x44, 0x24, 0xbf, 0x96, 0x1f, 0x71, 0xb3, 0x34, 0x7a, 0x59, 0xf0, 0xa5, 0xc7, 0x07, 0xff, 0xff,
0xff, 0x51, 0xcf, 0x6d, 0xbd, 0x85, 0xfb, 0x1e, 0x8f, 0x67, 0x3d, 0xc4, 0xad, 0xb2, 0x11, 0xd6, 0x8a, 0xe2, 0x7f, 0xb9, 0x47, 0x74, 0xa0, 0x49, 0xb9, 0xe6, 0x1d, 0x03, 0xde, 0x39, 0xf0, 0x75,
0xd5, 0x1f, 0xe0, 0x0f, 0x4b, 0xc5, 0xf6, 0x37, 0x7b, 0xed, 0x7d, 0x07, 0x93, 0xd4, 0xd9, 0xd6, 0xe1, 0xc0, 0x7d, 0x81, 0xf6, 0x61, 0x57, 0x1a, 0x67, 0x3e, 0x35, 0xce, 0x9a, 0xa5, 0x7f, 0xa6,
0x80, 0xcd, 0x24, 0x31, 0x6e, 0xc5, 0x84, 0x1d, 0x2d, 0x66, 0xdf, 0xea, 0x8d, 0xdf, 0x01, 0x00, 0x30, 0xd1, 0x3e, 0x54, 0xe8, 0x6d, 0x1a, 0x09, 0x6a, 0x9a, 0xac, 0x8c, 0xf3, 0x11, 0x6a, 0xc0,
0x00, 0xff, 0xff, 0x18, 0xce, 0x1c, 0x24, 0xa1, 0x08, 0x00, 0x00, 0x86, 0x16, 0xa1, 0x4c, 0x99, 0xd6, 0xd8, 0xc2, 0xc5, 0xf0, 0xe4, 0x3f, 0xf8, 0x36, 0xe0, 0xc9,
0xaa, 0x2e, 0x3f, 0xa9, 0x5a, 0x2b, 0x06, 0xfa, 0x67, 0xf4, 0x74, 0xb3, 0x98, 0x7e, 0x59, 0x3a,
0x78, 0xd2, 0xc5, 0x24, 0x73, 0x7b, 0x9a, 0x70, 0x9c, 0xa6, 0xd6, 0xdf, 0x84, 0xb0, 0xab, 0x8a,
0xf9, 0x6f, 0x1d, 0xbd, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x26, 0xa3, 0xe8, 0x2c, 0xad, 0x07, 0x00,
0x00,
} }

View File

@ -46,22 +46,18 @@ message AllocationStrategy {
AllocationStrategyRefresh refresh = 3; AllocationStrategyRefresh refresh = 3;
} }
message StreamReceiverConfig { message ReceiverConfig {
v2ray.core.common.net.PortRange port_range = 1; v2ray.core.common.net.PortRange port_range = 1;
v2ray.core.common.net.IPOrDomain listen = 2; v2ray.core.common.net.IPOrDomain listen = 2;
AllocationStrategy allocation_strategy = 3; AllocationStrategy allocation_strategy = 3;
v2ray.core.transport.internet.StreamConfig stream_settings = 4; v2ray.core.transport.internet.StreamConfig stream_settings = 4;
} bool receive_original_destination = 5;
bool allow_passive_connection = 6;
message DatagramReceiverConfig {
v2ray.core.common.net.PortRange port_range = 1;
v2ray.core.common.net.IPOrDomain listen = 2;
AllocationStrategy allocation_strategy = 3;
} }
message InboundHandlerConfig { message InboundHandlerConfig {
string tag = 1; string tag = 1;
repeated v2ray.core.common.serial.TypedMessage receiver_settings = 2; v2ray.core.common.serial.TypedMessage receiver_settings = 2;
v2ray.core.common.serial.TypedMessage proxy_settings = 3; v2ray.core.common.serial.TypedMessage proxy_settings = 3;
} }
@ -69,21 +65,17 @@ message OutboundConfig {
} }
message StreamSenderConfig { message SenderConfig {
// Send traffic through the given IP. Only IP is allowed. // Send traffic through the given IP. Only IP is allowed.
v2ray.core.common.net.IPOrDomain via = 1; v2ray.core.common.net.IPOrDomain via = 1;
v2ray.core.transport.internet.StreamConfig stream_settings = 2; v2ray.core.transport.internet.StreamConfig stream_settings = 2;
v2ray.core.transport.internet.ProxyConfig proxy_settings = 3; v2ray.core.transport.internet.ProxyConfig proxy_settings = 3;
} }
message DatagramSenderConfig {
// Send traffic through the given IP. Only IP is allowed.
v2ray.core.common.net.IPOrDomain via = 1;
v2ray.core.transport.internet.ProxyConfig proxy_settings = 2;
}
message OutboundHandlerConfig { message OutboundHandlerConfig {
string tag = 1; string tag = 1;
repeated v2ray.core.common.serial.TypedMessage sender_settings = 2; v2ray.core.common.serial.TypedMessage sender_settings = 2;
v2ray.core.common.serial.TypedMessage proxy_settings = 3; v2ray.core.common.serial.TypedMessage proxy_settings = 3;
int64 expire = 4;
string comment = 5;
} }

View File

@ -0,0 +1,78 @@
package inbound
import (
"context"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/proxy"
)
type AlwaysOnInboundHandler struct {
proxy proxy.InboundHandler
workers []worker
}
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
p, err := proxy.CreateInboundHandler(ctx, proxyConfig)
if err != nil {
return nil, err
}
h := &AlwaysOnInboundHandler{
proxy: p,
}
nl := p.Network()
pr := receiverConfig.PortRange
for port := pr.From; port <= pr.To; port++ {
if nl.HasNetwork(net.Network_TCP) {
log.Debug("Proxyman|DefaultInboundHandler: creating tcp worker on ", receiverConfig.Listen.AsAddress(), ":", port)
worker := &tcpWorker{
address: receiverConfig.Listen.AsAddress(),
port: net.Port(port),
proxy: p,
stream: receiverConfig.StreamSettings,
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
tag: tag,
allowPassiveConn: receiverConfig.AllowPassiveConnection,
}
h.workers = append(h.workers, worker)
}
if nl.HasNetwork(net.Network_UDP) {
worker := &udpWorker{
tag: tag,
proxy: p,
address: receiverConfig.Listen.AsAddress(),
port: net.Port(port),
recvOrigDest: receiverConfig.ReceiveOriginalDestination,
}
h.workers = append(h.workers, worker)
}
}
return h, nil
}
func (h *AlwaysOnInboundHandler) Start() error {
for _, worker := range h.workers {
if err := worker.Start(); err != nil {
return err
}
}
return nil
}
func (h *AlwaysOnInboundHandler) Close() {
for _, worker := range h.workers {
worker.Close()
}
}
func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (proxy.InboundHandler, net.Port, int) {
w := h.workers[dice.Roll(len(h.workers))]
return w.Proxy(), w.Port(), 9999
}

View File

@ -0,0 +1,143 @@
package inbound
import (
"context"
"sync"
"time"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
)
type DynamicInboundHandler struct {
sync.Mutex
tag string
ctx context.Context
cancel context.CancelFunc
proxyConfig interface{}
receiverConfig *proxyman.ReceiverConfig
portsInUse map[v2net.Port]bool
worker []worker
worker2Recycle []worker
lastRefresh time.Time
}
func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
ctx, cancel := context.WithCancel(ctx)
h := &DynamicInboundHandler{
ctx: ctx,
tag: tag,
cancel: cancel,
proxyConfig: proxyConfig,
receiverConfig: receiverConfig,
portsInUse: make(map[v2net.Port]bool),
}
return h, nil
}
func (h *DynamicInboundHandler) allocatePort() v2net.Port {
from := int(h.receiverConfig.PortRange.From)
delta := int(h.receiverConfig.PortRange.To) - from + 1
h.Lock()
defer h.Unlock()
for {
r := dice.Roll(delta)
port := v2net.Port(from + r)
_, used := h.portsInUse[port]
if !used {
h.portsInUse[port] = true
return port
}
}
}
func (h *DynamicInboundHandler) refresh() error {
h.lastRefresh = time.Now()
ports2Del := make([]v2net.Port, 0, 16)
for _, worker := range h.worker2Recycle {
worker.Close()
ports2Del = append(ports2Del, worker.Port())
}
h.Lock()
for _, port := range ports2Del {
delete(h.portsInUse, port)
}
h.Unlock()
h.worker2Recycle, h.worker = h.worker, h.worker2Recycle[:0]
for i := uint32(0); i < h.receiverConfig.AllocationStrategy.GetConcurrencyValue(); i++ {
port := h.allocatePort()
p, err := proxy.CreateInboundHandler(h.ctx, h.proxyConfig)
if err != nil {
log.Warning("Proxyman|DefaultInboundHandler: Failed to create proxy instance: ", err)
continue
}
nl := p.Network()
if nl.HasNetwork(v2net.Network_TCP) {
worker := &tcpWorker{
tag: h.tag,
address: h.receiverConfig.Listen.AsAddress(),
port: port,
proxy: p,
stream: h.receiverConfig.StreamSettings,
recvOrigDest: h.receiverConfig.ReceiveOriginalDestination,
allowPassiveConn: h.receiverConfig.AllowPassiveConnection,
}
if err := worker.Start(); err != nil {
return err
}
h.worker = append(h.worker, worker)
}
if nl.HasNetwork(v2net.Network_UDP) {
worker := &udpWorker{
tag: h.tag,
proxy: p,
address: h.receiverConfig.Listen.AsAddress(),
port: port,
recvOrigDest: h.receiverConfig.ReceiveOriginalDestination,
}
if err := worker.Start(); err != nil {
return err
}
h.worker = append(h.worker, worker)
}
}
return nil
}
func (h *DynamicInboundHandler) monitor() {
for {
select {
case <-h.ctx.Done():
return
case <-time.After(time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue())):
h.refresh()
}
}
}
func (h *DynamicInboundHandler) Start() error {
err := h.refresh()
go h.monitor()
return err
}
func (h *DynamicInboundHandler) Close() {
h.cancel()
}
func (h *DynamicInboundHandler) GetRandomInboundProxy() (proxy.InboundHandler, v2net.Port, int) {
w := h.worker[dice.Roll(len(h.worker))]
expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)
return w.Proxy(), w.Port(), int(expire)
}

View File

@ -0,0 +1,94 @@
package inbound
import (
"context"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
)
type DefaultInboundHandlerManager struct {
handlers []proxyman.InboundHandler
taggedHandlers map[string]proxyman.InboundHandler
}
func New(ctx context.Context, config *proxyman.InboundConfig) (*DefaultInboundHandlerManager, error) {
return &DefaultInboundHandlerManager{
taggedHandlers: make(map[string]proxyman.InboundHandler),
}, nil
}
func (m *DefaultInboundHandlerManager) AddHandler(ctx context.Context, config *proxyman.InboundHandlerConfig) error {
rawReceiverSettings, err := config.ReceiverSettings.GetInstance()
if err != nil {
return err
}
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
if !ok {
return errors.New("Proxyman|DefaultInboundHandlerManager: Not a ReceiverConfig.")
}
proxySettings, err := config.ProxySettings.GetInstance()
if err != nil {
return err
}
var handler proxyman.InboundHandler
tag := config.Tag
allocStrategy := receiverSettings.AllocationStrategy
if allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {
h, err := NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
if err != nil {
return err
}
handler = h
} else if allocStrategy.Type == proxyman.AllocationStrategy_Random {
h, err := NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
if err != nil {
return err
}
handler = h
}
if handler == nil {
return errors.New("Proxyman|DefaultInboundHandlerManager: Unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type)
}
m.handlers = append(m.handlers, handler)
if len(tag) > 0 {
m.taggedHandlers[tag] = handler
}
return nil
}
func (m *DefaultInboundHandlerManager) GetHandler(ctx context.Context, tag string) (proxyman.InboundHandler, error) {
handler, found := m.taggedHandlers[tag]
if !found {
return nil, errors.New("Proxymand|DefaultInboundHandlerManager: Handler not found: ", tag)
}
return handler, nil
}
func (m *DefaultInboundHandlerManager) Start() error {
for _, handler := range m.handlers {
if err := handler.Start(); err != nil {
return err
}
}
return nil
}
func (m *DefaultInboundHandlerManager) Close() {
for _, handler := range m.handlers {
handler.Close()
}
}
func (m *DefaultInboundHandlerManager) Interface() interface{} {
return (*proxyman.InboundHandlerManager)(nil)
}
func init() {
common.Must(common.RegisterConfig((*proxyman.InboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*proxyman.InboundConfig))
}))
}

View File

@ -0,0 +1,269 @@
package inbound
import (
"context"
"io"
"net"
"sync"
"sync/atomic"
"time"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/internet/udp"
)
type worker interface {
Start() error
Close()
Port() v2net.Port
Proxy() proxy.InboundHandler
}
type tcpWorker struct {
address v2net.Address
port v2net.Port
proxy proxy.InboundHandler
stream *internet.StreamConfig
recvOrigDest bool
tag string
allowPassiveConn bool
ctx context.Context
cancel context.CancelFunc
hub *internet.TCPHub
}
func (w *tcpWorker) callback(conn internet.Connection) {
ctx, cancel := context.WithCancel(w.ctx)
if w.recvOrigDest {
dest := tcp.GetOriginalDestination(conn)
if dest.IsValid() {
ctx = proxy.ContextWithOriginalDestination(ctx, dest)
}
}
if len(w.tag) > 0 {
ctx = proxy.ContextWithInboundTag(ctx, w.tag)
}
ctx = proxy.ContextWithAllowPassiveConnection(ctx, w.allowPassiveConn)
ctx = proxy.ContextWithInboundDestination(ctx, v2net.TCPDestination(w.address, w.port))
w.proxy.Process(ctx, v2net.Network_TCP, conn)
cancel()
conn.Close()
}
func (w *tcpWorker) Proxy() proxy.InboundHandler {
return w.proxy
}
func (w *tcpWorker) Start() error {
ctx, cancel := context.WithCancel(context.Background())
w.ctx = ctx
w.cancel = cancel
hub, err := internet.ListenTCP(w.address, w.port, w.callback, w.stream)
if err != nil {
return err
}
w.hub = hub
return nil
}
func (w *tcpWorker) Close() {
log.Debug("Proxyman|TCPWorker: Closed. ", w.port)
w.hub.Close()
w.cancel()
}
func (w *tcpWorker) Port() v2net.Port {
return w.port
}
type udpConn struct {
cancel context.CancelFunc
lastActivityTime int64 // in seconds
input chan []byte
output func([]byte) (int, error)
closer func() error
remote net.Addr
local net.Addr
}
func (c *udpConn) updateActivity() {
atomic.StoreInt64(&c.lastActivityTime, time.Now().Unix())
}
func (c *udpConn) Read(buf []byte) (int, error) {
in, open := <-c.input
if !open {
return 0, io.EOF
}
c.updateActivity()
return copy(buf, in), nil
}
func (c *udpConn) Write(buf []byte) (int, error) {
n, err := c.output(buf)
if err == nil {
c.updateActivity()
}
return n, err
}
func (c *udpConn) Close() error {
close(c.input)
c.cancel()
return nil
}
func (c *udpConn) RemoteAddr() net.Addr {
return c.remote
}
func (c *udpConn) LocalAddr() net.Addr {
return c.remote
}
func (*udpConn) SetDeadline(time.Time) error {
return nil
}
func (*udpConn) SetReadDeadline(time.Time) error {
return nil
}
func (*udpConn) SetWriteDeadline(time.Time) error {
return nil
}
func (*udpConn) Reusable() bool {
return false
}
func (*udpConn) SetReusable(bool) {}
type udpWorker struct {
sync.RWMutex
proxy proxy.InboundHandler
hub *udp.Hub
address v2net.Address
port v2net.Port
recvOrigDest bool
tag string
ctx context.Context
cancel context.CancelFunc
activeConn map[v2net.Destination]*udpConn
}
func (w *udpWorker) getConnection(src v2net.Destination) (*udpConn, bool) {
w.Lock()
defer w.Unlock()
if conn, found := w.activeConn[src]; found {
return conn, true
}
conn := &udpConn{
input: make(chan []byte, 32),
output: func(b []byte) (int, error) {
return w.hub.WriteTo(b, src)
},
closer: func() error {
w.Lock()
delete(w.activeConn, src)
w.Unlock()
return nil
},
remote: &net.UDPAddr{
IP: src.Address.IP(),
Port: int(src.Port),
},
local: &net.UDPAddr{
IP: w.address.IP(),
Port: int(w.port),
},
}
conn.updateActivity()
return conn, false
}
func (w *udpWorker) callback(b *buf.Buffer, source v2net.Destination, originalDest v2net.Destination) {
conn, existing := w.getConnection(source)
conn.input <- b.Bytes()
if !existing {
go func() {
ctx := w.ctx
ctx, cancel := context.WithCancel(ctx)
conn.cancel = cancel
if originalDest.IsValid() {
ctx = proxy.ContextWithOriginalDestination(ctx, originalDest)
}
if len(w.tag) > 0 {
ctx = proxy.ContextWithInboundTag(ctx, w.tag)
}
ctx = proxy.ContextWithSource(ctx, source)
ctx = proxy.ContextWithInboundDestination(ctx, v2net.UDPDestination(w.address, w.port))
w.proxy.Process(ctx, v2net.Network_UDP, conn)
conn.cancel()
}()
}
}
func (w *udpWorker) removeConn(src v2net.Destination) {
w.Lock()
delete(w.activeConn, src)
w.Unlock()
}
func (w *udpWorker) Start() error {
ctx, cancel := context.WithCancel(context.Background())
w.ctx = ctx
w.cancel = cancel
h, err := udp.ListenUDP(w.address, w.port, udp.ListenOption{
Callback: w.callback,
ReceiveOriginalDest: w.recvOrigDest,
})
if err != nil {
return err
}
w.hub = h
return nil
}
func (w *udpWorker) Close() {
w.hub.Close()
w.cancel()
}
func (w *udpWorker) monitor() {
for {
select {
case <-w.ctx.Done():
return
case <-time.After(time.Second * 16):
nowSec := time.Now().Unix()
w.Lock()
for addr, conn := range w.activeConn {
if nowSec-conn.lastActivityTime > 8 {
w.removeConn(addr)
conn.Close()
}
}
}
}
}
func (w *udpWorker) Port() v2net.Port {
return w.port
}
func (w *udpWorker) Proxy() proxy.InboundHandler {
return w.proxy
}

View File

@ -2,39 +2,58 @@ package outbound
import ( import (
"context" "context"
"errors"
"io"
"net"
"time"
"v2ray.com/core/app"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/common/errors" "v2ray.com/core/common/buf"
"v2ray.com/core/common/net" "v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/ray"
) )
type Handler struct { type Handler struct {
config *proxyman.OutboundHandlerConfig config *proxyman.OutboundHandlerConfig
streamSettings *proxyman.StreamSenderConfig senderSettings *proxyman.SenderConfig
datagramSettings *proxyman.DatagramSenderConfig proxy proxy.OutboundHandler
proxy proxy.OutboundHandler outboundManager proxyman.OutboundHandlerManager
} }
func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*Handler, error) { func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*Handler, error) {
h := &Handler{ h := &Handler{
config: config, config: config,
} }
for _, rawSettings := range config.SenderSettings { space := app.SpaceFromContext(ctx)
settings, err := rawSettings.GetInstance() if space == nil {
return nil, errors.New("Proxyman|OutboundHandler: No space in context.")
}
space.OnInitialize(func() error {
ohm := proxyman.OutboundHandlerManagerFromSpace(space)
if ohm == nil {
return errors.New("Proxyman|OutboundHandler: No OutboundManager in space.")
}
h.outboundManager = ohm
return nil
})
if config.SenderSettings != nil {
senderSettings, err := config.SenderSettings.GetInstance()
if err != nil { if err != nil {
return nil, err return nil, err
} }
switch ts := settings.(type) { switch s := senderSettings.(type) {
case *proxyman.StreamSenderConfig: case *proxyman.SenderConfig:
h.streamSettings = ts h.senderSettings = s
case *proxyman.DatagramSenderConfig:
h.datagramSettings = ts
default: default:
return nil, errors.New("Proxyman|DefaultOutboundHandler: Unknown sender settings: ", rawSettings.Type) return nil, errors.New("Proxyman|DefaultOutboundHandler: settings is not SenderConfig.")
} }
} }
proxyHandler, err := config.GetProxyHandler(proxy.ContextWithDialer(ctx, h)) proxyHandler, err := config.GetProxyHandler(proxy.ContextWithDialer(ctx, h))
if err != nil { if err != nil {
return nil, err return nil, err
@ -44,38 +63,114 @@ func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*H
return h, nil return h, nil
} }
func (h *Handler) Dial(ctx context.Context, destination net.Destination) (internet.Connection, error) { func (h *Handler) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) {
switch destination.Network { ctx = proxy.ContextWithDialer(ctx, h)
case net.Network_TCP: h.proxy.Process(ctx, outboundRay)
return h.dialStream(ctx, destination) }
case net.Network_UDP:
return h.dialDatagram(ctx, destination) func (h *Handler) Dial(ctx context.Context, dest v2net.Destination) (internet.Connection, error) {
default: if h.senderSettings != nil {
panic("Proxyman|DefaultOutboundHandler: unexpected network.") if h.senderSettings.ProxySettings.HasTag() {
tag := h.senderSettings.ProxySettings.Tag
handler := h.outboundManager.GetHandler(tag)
if handler != nil {
log.Info("Proxyman|OutboundHandler: Proxying to ", dest)
ctx = proxy.ContextWithDestination(ctx, dest)
stream := ray.NewRay(ctx)
go handler.Dispatch(ctx, stream)
return NewConnection(stream), nil
}
log.Warning("Proxyman|OutboundHandler: Failed to get outbound handler with tag: ", tag)
}
if h.senderSettings.Via != nil {
ctx = internet.ContextWithDialerSource(ctx, h.senderSettings.Via.AsAddress())
}
if h.senderSettings != nil {
ctx = internet.ContextWithStreamSettings(ctx, h.senderSettings.StreamSettings)
}
}
return internet.Dial(ctx, dest)
}
type Connection struct {
stream ray.Ray
closed bool
localAddr net.Addr
remoteAddr net.Addr
reader *buf.BufferToBytesReader
writer *buf.BytesToBufferWriter
}
func NewConnection(stream ray.Ray) *Connection {
return &Connection{
stream: stream,
localAddr: &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
},
remoteAddr: &net.TCPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
},
reader: buf.NewBytesReader(stream.InboundOutput()),
writer: buf.NewBytesWriter(stream.InboundInput()),
} }
} }
func (h *Handler) dialStream(ctx context.Context, destination net.Destination) (internet.Connection, error) { // Read implements net.Conn.Read().
var src net.Address func (v *Connection) Read(b []byte) (int, error) {
if h.streamSettings != nil { if v.closed {
src = h.streamSettings.Via.AsAddress() return 0, io.EOF
} }
var options internet.DialerOptions return v.reader.Read(b)
if h.streamSettings != nil {
options.Proxy = h.streamSettings.ProxySettings
options.Stream = h.streamSettings.StreamSettings
}
return internet.Dial(src, destination, options)
} }
func (h *Handler) dialDatagram(ctx context.Context, destination net.Destination) (internet.Connection, error) { // Write implements net.Conn.Write().
var src net.Address func (v *Connection) Write(b []byte) (int, error) {
if h.datagramSettings != nil { if v.closed {
src = h.datagramSettings.Via.AsAddress() return 0, io.ErrClosedPipe
} }
var options internet.DialerOptions return v.writer.Write(b)
if h.datagramSettings != nil { }
options.Proxy = h.datagramSettings.ProxySettings
} // Close implements net.Conn.Close().
return internet.Dial(src, destination, options) func (v *Connection) Close() error {
v.closed = true
v.stream.InboundInput().Close()
v.stream.InboundOutput().CloseError()
return nil
}
// LocalAddr implements net.Conn.LocalAddr().
func (v *Connection) LocalAddr() net.Addr {
return v.localAddr
}
// RemoteAddr implements net.Conn.RemoteAddr().
func (v *Connection) RemoteAddr() net.Addr {
return v.remoteAddr
}
func (v *Connection) SetDeadline(t time.Time) error {
return nil
}
func (v *Connection) SetReadDeadline(t time.Time) error {
return nil
}
func (v *Connection) SetWriteDeadline(t time.Time) error {
return nil
}
func (v *Connection) Reusable() bool {
return false
}
func (v *Connection) SetReusable(bool) {
} }

View File

@ -6,18 +6,17 @@ import (
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/proxy"
) )
type DefaultOutboundHandlerManager struct { type DefaultOutboundHandlerManager struct {
sync.RWMutex sync.RWMutex
defaultHandler proxy.OutboundHandler defaultHandler *Handler
taggedHandler map[string]proxy.OutboundHandler taggedHandler map[string]*Handler
} }
func New(ctx context.Context, config *proxyman.OutboundConfig) (*DefaultOutboundHandlerManager, error) { func New(ctx context.Context, config *proxyman.OutboundConfig) (*DefaultOutboundHandlerManager, error) {
return &DefaultOutboundHandlerManager{ return &DefaultOutboundHandlerManager{
taggedHandler: make(map[string]proxy.OutboundHandler), taggedHandler: make(map[string]*Handler),
}, nil }, nil
} }
@ -25,7 +24,7 @@ func (DefaultOutboundHandlerManager) Interface() interface{} {
return (*proxyman.OutboundHandlerManager)(nil) return (*proxyman.OutboundHandlerManager)(nil)
} }
func (v *DefaultOutboundHandlerManager) GetDefaultHandler() proxy.OutboundHandler { func (v *DefaultOutboundHandlerManager) GetDefaultHandler() proxyman.OutboundHandler {
v.RLock() v.RLock()
defer v.RUnlock() defer v.RUnlock()
if v.defaultHandler == nil { if v.defaultHandler == nil {
@ -34,14 +33,7 @@ func (v *DefaultOutboundHandlerManager) GetDefaultHandler() proxy.OutboundHandle
return v.defaultHandler return v.defaultHandler
} }
func (v *DefaultOutboundHandlerManager) SetDefaultHandler(handler proxy.OutboundHandler) error { func (v *DefaultOutboundHandlerManager) GetHandler(tag string) proxyman.OutboundHandler {
v.Lock()
defer v.Unlock()
v.defaultHandler = handler
return nil
}
func (v *DefaultOutboundHandlerManager) GetHandler(tag string) proxy.OutboundHandler {
v.RLock() v.RLock()
defer v.RUnlock() defer v.RUnlock()
if handler, found := v.taggedHandler[tag]; found { if handler, found := v.taggedHandler[tag]; found {
@ -50,11 +42,22 @@ func (v *DefaultOutboundHandlerManager) GetHandler(tag string) proxy.OutboundHan
return nil return nil
} }
func (v *DefaultOutboundHandlerManager) SetHandler(tag string, handler proxy.OutboundHandler) error { func (v *DefaultOutboundHandlerManager) AddHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) error {
v.Lock() v.Lock()
defer v.Unlock() defer v.Unlock()
v.taggedHandler[tag] = handler handler, err := NewHandler(ctx, config)
if err != nil {
return err
}
if v.defaultHandler == nil {
v.defaultHandler = handler
}
if len(config.Tag) > 0 {
v.taggedHandler[config.Tag] = handler
}
return nil return nil
} }

View File

@ -11,21 +11,28 @@ import (
) )
type InboundHandlerManager interface { type InboundHandlerManager interface {
GetHandler(tag string) (proxy.InboundHandler, int) GetHandler(ctx context.Context, tag string) (InboundHandler, error)
AddHandler(ctx context.Context, config *InboundHandlerConfig) error
Start() error
Close()
} }
type InboundHandler interface { type InboundHandler interface {
Start() error
Close()
// For migration
GetRandomInboundProxy() (proxy.InboundHandler, net.Port, int)
} }
type OutboundHandlerManager interface { type OutboundHandlerManager interface {
GetHandler(tag string) proxy.OutboundHandler GetHandler(tag string) OutboundHandler
GetDefaultHandler() proxy.OutboundHandler GetDefaultHandler() OutboundHandler
SetDefaultHandler(handler proxy.OutboundHandler) error AddHandler(ctx context.Context, config *OutboundHandlerConfig) error
SetHandler(tag string, handler proxy.OutboundHandler) error
} }
type OutboundHandler interface { type OutboundHandler interface {
Dispatch(ctx context.Context, destination net.Destination, outboundRay ray.OutboundRay) Dispatch(ctx context.Context, outboundRay ray.OutboundRay)
} }
func InboundHandlerManagerFromSpace(space app.Space) InboundHandlerManager { func InboundHandlerManagerFromSpace(space app.Space) InboundHandlerManager {

View File

@ -1,16 +1,18 @@
package router package router
import ( import (
"context"
"net" "net"
"regexp" "regexp"
"strings" "strings"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
) )
type Condition interface { type Condition interface {
Apply(session *proxy.SessionInfo) bool Apply(ctx context.Context) bool
} }
type ConditionChan []Condition type ConditionChan []Condition
@ -25,9 +27,9 @@ func (v *ConditionChan) Add(cond Condition) *ConditionChan {
return v return v
} }
func (v *ConditionChan) Apply(session *proxy.SessionInfo) bool { func (v *ConditionChan) Apply(ctx context.Context) bool {
for _, cond := range *v { for _, cond := range *v {
if !cond.Apply(session) { if !cond.Apply(ctx) {
return false return false
} }
} }
@ -50,9 +52,9 @@ func (v *AnyCondition) Add(cond Condition) *AnyCondition {
return v return v
} }
func (v *AnyCondition) Apply(session *proxy.SessionInfo) bool { func (v *AnyCondition) Apply(ctx context.Context) bool {
for _, cond := range *v { for _, cond := range *v {
if cond.Apply(session) { if cond.Apply(ctx) {
return true return true
} }
} }
@ -73,8 +75,8 @@ func NewPlainDomainMatcher(pattern string) *PlainDomainMatcher {
} }
} }
func (v *PlainDomainMatcher) Apply(session *proxy.SessionInfo) bool { func (v *PlainDomainMatcher) Apply(ctx context.Context) bool {
dest := session.Destination dest := proxy.DestinationFromContext(ctx)
if !dest.Address.Family().IsDomain() { if !dest.Address.Family().IsDomain() {
return false return false
} }
@ -96,8 +98,8 @@ func NewRegexpDomainMatcher(pattern string) (*RegexpDomainMatcher, error) {
}, nil }, nil
} }
func (v *RegexpDomainMatcher) Apply(session *proxy.SessionInfo) bool { func (v *RegexpDomainMatcher) Apply(ctx context.Context) bool {
dest := session.Destination dest := proxy.DestinationFromContext(ctx)
if !dest.Address.Family().IsDomain() { if !dest.Address.Family().IsDomain() {
return false return false
} }
@ -121,15 +123,31 @@ func NewCIDRMatcher(ip []byte, mask uint32, onSource bool) (*CIDRMatcher, error)
}, nil }, nil
} }
func (v *CIDRMatcher) Apply(session *proxy.SessionInfo) bool { func (v *CIDRMatcher) Apply(ctx context.Context) bool {
dest := session.Destination var dest v2net.Destination
if v.onSource { if v.onSource {
dest = session.Source dest = proxy.SourceFromContext(ctx)
} else {
dest = proxy.DestinationFromContext(ctx)
} }
if !dest.Address.Family().Either(v2net.AddressFamilyIPv4, v2net.AddressFamilyIPv6) { if !dest.Address.Family().Either(v2net.AddressFamilyIPv4, v2net.AddressFamilyIPv6) {
return false return false
} }
return v.cidr.Contains(dest.Address.IP())
ips := []net.IP{dest.Address.IP()}
if resolveIPs, ok := proxy.ResolvedIPsFromContext(ctx); ok {
for _, rip := range resolveIPs {
ips = append(ips, rip.IP())
}
}
for _, ip := range ips {
if v.cidr.Contains(ip) {
return true
}
}
return false
} }
type IPv4Matcher struct { type IPv4Matcher struct {
@ -144,15 +162,30 @@ func NewIPv4Matcher(ipnet *v2net.IPNet, onSource bool) *IPv4Matcher {
} }
} }
func (v *IPv4Matcher) Apply(session *proxy.SessionInfo) bool { func (v *IPv4Matcher) Apply(ctx context.Context) bool {
dest := session.Destination var dest v2net.Destination
if v.onSource { if v.onSource {
dest = session.Source dest = proxy.SourceFromContext(ctx)
} else {
dest = proxy.DestinationFromContext(ctx)
} }
if !dest.Address.Family().Either(v2net.AddressFamilyIPv4) { if !dest.Address.Family().Either(v2net.AddressFamilyIPv4) {
return false return false
} }
return v.ipv4net.Contains(dest.Address.IP())
ips := []net.IP{dest.Address.IP()}
if resolvedIPs, ok := proxy.ResolvedIPsFromContext(ctx); ok {
for _, rip := range resolvedIPs {
ips = append(ips, rip.IP())
}
}
for _, ip := range ips {
if v.ipv4net.Contains(ip) {
return true
}
}
return false
} }
type PortMatcher struct { type PortMatcher struct {
@ -165,8 +198,9 @@ func NewPortMatcher(portRange v2net.PortRange) *PortMatcher {
} }
} }
func (v *PortMatcher) Apply(session *proxy.SessionInfo) bool { func (v *PortMatcher) Apply(ctx context.Context) bool {
return v.port.Contains(session.Destination.Port) dest := proxy.DestinationFromContext(ctx)
return v.port.Contains(dest.Port)
} }
type NetworkMatcher struct { type NetworkMatcher struct {
@ -179,8 +213,9 @@ func NewNetworkMatcher(network *v2net.NetworkList) *NetworkMatcher {
} }
} }
func (v *NetworkMatcher) Apply(session *proxy.SessionInfo) bool { func (v *NetworkMatcher) Apply(ctx context.Context) bool {
return v.network.HasNetwork(session.Destination.Network) dest := proxy.DestinationFromContext(ctx)
return v.network.HasNetwork(dest.Network)
} }
type UserMatcher struct { type UserMatcher struct {
@ -193,12 +228,13 @@ func NewUserMatcher(users []string) *UserMatcher {
} }
} }
func (v *UserMatcher) Apply(session *proxy.SessionInfo) bool { func (v *UserMatcher) Apply(ctx context.Context) bool {
if session.User == nil { user := protocol.UserFromContext(ctx)
if user == nil {
return false return false
} }
for _, u := range v.user { for _, u := range v.user {
if u == session.User.Email { if u == user.Email {
return true return true
} }
} }
@ -215,13 +251,14 @@ func NewInboundTagMatcher(tags []string) *InboundTagMatcher {
} }
} }
func (v *InboundTagMatcher) Apply(session *proxy.SessionInfo) bool { func (v *InboundTagMatcher) Apply(ctx context.Context) bool {
if session.Inbound == nil || len(session.Inbound.Tag) == 0 { tag := proxy.InboundTagFromContext(ctx)
if len(tag) == 0 {
return false return false
} }
for _, t := range v.tags { for _, t := range v.tags {
if t == session.Inbound.Tag { if t == tag {
return true return true
} }
} }

View File

@ -1,11 +1,11 @@
package router package router
import ( import (
"context"
"net" "net"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
) )
type Rule struct { type Rule struct {
@ -13,8 +13,8 @@ type Rule struct {
Condition Condition Condition Condition
} }
func (v *Rule) Apply(session *proxy.SessionInfo) bool { func (v *Rule) Apply(ctx context.Context) bool {
return v.Condition.Apply(session) return v.Condition.Apply(ctx)
} }
func (v *RoutingRule) BuildCondition() (Condition, error) { func (v *RoutingRule) BuildCondition() (Condition, error) {

View File

@ -55,43 +55,34 @@ func NewRouter(ctx context.Context, config *Config) (*Router, error) {
} }
// Private: Visible for testing. // Private: Visible for testing.
func (v *Router) ResolveIP(dest net.Destination) []net.Destination { func (v *Router) ResolveIP(dest net.Destination) []net.Address {
ips := v.dnsServer.Get(dest.Address.Domain()) ips := v.dnsServer.Get(dest.Address.Domain())
if len(ips) == 0 { if len(ips) == 0 {
return nil return nil
} }
dests := make([]net.Destination, len(ips)) dests := make([]net.Address, len(ips))
for idx, ip := range ips { for idx, ip := range ips {
if dest.Network == net.Network_TCP { dests[idx] = net.IPAddress(ip)
dests[idx] = net.TCPDestination(net.IPAddress(ip), dest.Port)
} else {
dests[idx] = net.UDPDestination(net.IPAddress(ip), dest.Port)
}
} }
return dests return dests
} }
func (v *Router) takeDetourWithoutCache(session *proxy.SessionInfo) (string, error) { func (v *Router) takeDetourWithoutCache(ctx context.Context) (string, error) {
for _, rule := range v.rules { for _, rule := range v.rules {
if rule.Apply(session) { if rule.Apply(ctx) {
return rule.Tag, nil return rule.Tag, nil
} }
} }
dest := session.Destination
dest := proxy.DestinationFromContext(ctx)
if v.domainStrategy == Config_IpIfNonMatch && dest.Address.Family().IsDomain() { if v.domainStrategy == Config_IpIfNonMatch && dest.Address.Family().IsDomain() {
log.Info("Router: Looking up IP for ", dest) log.Info("Router: Looking up IP for ", dest)
ipDests := v.ResolveIP(dest) ipDests := v.ResolveIP(dest)
if ipDests != nil { if ipDests != nil {
for _, ipDest := range ipDests { ctx = proxy.ContextWithResolveIPs(ctx, ipDests)
log.Info("Router: Trying IP ", ipDest) for _, rule := range v.rules {
for _, rule := range v.rules { if rule.Apply(ctx) {
if rule.Apply(&proxy.SessionInfo{ return rule.Tag, nil
Source: session.Source,
Destination: ipDest,
User: session.User,
}) {
return rule.Tag, nil
}
} }
} }
} }
@ -100,11 +91,11 @@ func (v *Router) takeDetourWithoutCache(session *proxy.SessionInfo) (string, err
return "", ErrNoRuleApplicable return "", ErrNoRuleApplicable
} }
func (v *Router) TakeDetour(session *proxy.SessionInfo) (string, error) { func (v *Router) TakeDetour(ctx context.Context) (string, error) {
//destStr := dest.String() //destStr := dest.String()
//found, tag, err := v.cache.Get(destStr) //found, tag, err := v.cache.Get(destStr)
//if !found { //if !found {
tag, err := v.takeDetourWithoutCache(session) tag, err := v.takeDetourWithoutCache(ctx)
//v.cache.Set(destStr, tag, err) //v.cache.Set(destStr, tag, err)
return tag, err return tag, err
//} //}

View File

@ -41,7 +41,8 @@ func TestSimpleRouter(t *testing.T) {
r := FromSpace(space) r := FromSpace(space)
tag, err := r.TakeDetour(&proxy.SessionInfo{Destination: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)}) ctx = proxy.ContextWithDestination(ctx, net.TCPDestination(net.DomainAddress("v2ray.com"), 80))
tag, err := r.TakeDetour(ctx)
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.String(tag).Equals("test") assert.String(tag).Equals("test")
} }

View File

@ -48,6 +48,10 @@ func (v Destination) String() string {
return v.Network.URLPrefix() + ":" + v.NetAddr() return v.Network.URLPrefix() + ":" + v.NetAddr()
} }
func (v Destination) IsValid() bool {
return v.Network != Network_Unknown
}
func (v *Endpoint) AsDestination() Destination { func (v *Endpoint) AsDestination() Destination {
return Destination{ return Destination{
Network: v.Network, Network: v.Network,

View File

@ -0,0 +1,23 @@
package protocol
import (
"context"
)
type key int
const (
userKey key = iota
)
func ContextWithUser(ctx context.Context, user *User) context.Context {
return context.WithValue(ctx, userKey, user)
}
func UserFromContext(ctx context.Context) *User {
v := ctx.Value(userKey)
if v == nil {
return nil
}
return v.(*User)
}

View File

@ -25,7 +25,7 @@ func CreateObject(ctx context.Context, config interface{}) (interface{}, error)
configType := reflect.TypeOf(config) configType := reflect.TypeOf(config)
creator, found := typeCreatorRegistry[configType] creator, found := typeCreatorRegistry[configType]
if !found { if !found {
return nil, errors.New("Common: " + configType.Name() + " is not registered.") return nil, errors.New("Common: " + configType.String() + " is not registered.")
} }
return creator(ctx, config) return creator(ctx, config)
} }

View File

@ -1,55 +0,0 @@
package core
import (
"v2ray.com/core/common"
"v2ray.com/core/common/net"
)
func (v *AllocationStrategy) GetConcurrencyValue() uint32 {
if v == nil || v.Concurrency == nil {
return 3
}
return v.Concurrency.Value
}
func (v *AllocationStrategy) GetRefreshValue() uint32 {
if v == nil || v.Refresh == nil {
return 5
}
return v.Refresh.Value
}
func (v *InboundConnectionConfig) GetAllocationStrategyValue() *AllocationStrategy {
if v.AllocationStrategy == nil {
return &AllocationStrategy{}
}
return v.AllocationStrategy
}
func (v *InboundConnectionConfig) GetListenOnValue() net.Address {
if v.GetListenOn() == nil {
return net.AnyIP
}
return v.ListenOn.AsAddress()
}
func (v *InboundConnectionConfig) GetTypedSettings() (interface{}, error) {
if v.GetSettings() == nil {
return nil, common.ErrBadConfiguration
}
return v.GetSettings().GetInstance()
}
func (v *OutboundConnectionConfig) GetTypedSettings() (interface{}, error) {
if v.GetSettings() == nil {
return nil, common.ErrBadConfiguration
}
return v.GetSettings().GetInstance()
}
func (v *OutboundConnectionConfig) GetSendThroughValue() net.Address {
if v.GetSendThrough() == nil {
return net.AnyIP
}
return v.SendThrough.AsAddress()
}

View File

@ -3,11 +3,9 @@ package core
import proto "github.com/golang/protobuf/proto" import proto "github.com/golang/protobuf/proto"
import fmt "fmt" import fmt "fmt"
import math "math" import math "math"
import v2ray_core_app_proxyman "v2ray.com/core/app/proxyman"
import v2ray_core_common_serial "v2ray.com/core/common/serial" import v2ray_core_common_serial "v2ray.com/core/common/serial"
import v2ray_core_common_net "v2ray.com/core/common/net"
import v2ray_core_common_net1 "v2ray.com/core/common/net"
import v2ray_core_common_log "v2ray.com/core/common/log" import v2ray_core_common_log "v2ray.com/core/common/log"
import v2ray_core_transport_internet "v2ray.com/core/transport/internet"
import v2ray_core_transport "v2ray.com/core/transport" import v2ray_core_transport "v2ray.com/core/transport"
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
@ -43,226 +41,12 @@ func (x ConfigFormat) String() string {
} }
func (ConfigFormat) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (ConfigFormat) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type AllocationStrategy_Type int32
const (
// Always allocate all connection handlers.
AllocationStrategy_Always AllocationStrategy_Type = 0
// Randomly allocate specific range of handlers.
AllocationStrategy_Random AllocationStrategy_Type = 1
// External. Not supported yet.
AllocationStrategy_External AllocationStrategy_Type = 2
)
var AllocationStrategy_Type_name = map[int32]string{
0: "Always",
1: "Random",
2: "External",
}
var AllocationStrategy_Type_value = map[string]int32{
"Always": 0,
"Random": 1,
"External": 2,
}
func (x AllocationStrategy_Type) String() string {
return proto.EnumName(AllocationStrategy_Type_name, int32(x))
}
func (AllocationStrategy_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2, 0} }
type AllocationStrategyConcurrency struct {
Value uint32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
}
func (m *AllocationStrategyConcurrency) Reset() { *m = AllocationStrategyConcurrency{} }
func (m *AllocationStrategyConcurrency) String() string { return proto.CompactTextString(m) }
func (*AllocationStrategyConcurrency) ProtoMessage() {}
func (*AllocationStrategyConcurrency) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *AllocationStrategyConcurrency) GetValue() uint32 {
if m != nil {
return m.Value
}
return 0
}
type AllocationStrategyRefresh struct {
Value uint32 `protobuf:"varint,1,opt,name=value" json:"value,omitempty"`
}
func (m *AllocationStrategyRefresh) Reset() { *m = AllocationStrategyRefresh{} }
func (m *AllocationStrategyRefresh) String() string { return proto.CompactTextString(m) }
func (*AllocationStrategyRefresh) ProtoMessage() {}
func (*AllocationStrategyRefresh) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *AllocationStrategyRefresh) GetValue() uint32 {
if m != nil {
return m.Value
}
return 0
}
type AllocationStrategy struct {
Type AllocationStrategy_Type `protobuf:"varint,1,opt,name=type,enum=v2ray.core.AllocationStrategy_Type" json:"type,omitempty"`
// Number of handlers (ports) running in parallel.
// Default value is 3 if unset.
Concurrency *AllocationStrategyConcurrency `protobuf:"bytes,2,opt,name=concurrency" json:"concurrency,omitempty"`
// Number of minutes before a handler is regenerated.
// Default value is 5 if unset.
Refresh *AllocationStrategyRefresh `protobuf:"bytes,3,opt,name=refresh" json:"refresh,omitempty"`
}
func (m *AllocationStrategy) Reset() { *m = AllocationStrategy{} }
func (m *AllocationStrategy) String() string { return proto.CompactTextString(m) }
func (*AllocationStrategy) ProtoMessage() {}
func (*AllocationStrategy) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *AllocationStrategy) GetType() AllocationStrategy_Type {
if m != nil {
return m.Type
}
return AllocationStrategy_Always
}
func (m *AllocationStrategy) GetConcurrency() *AllocationStrategyConcurrency {
if m != nil {
return m.Concurrency
}
return nil
}
func (m *AllocationStrategy) GetRefresh() *AllocationStrategyRefresh {
if m != nil {
return m.Refresh
}
return nil
}
// Config for an inbound connection handler.
type InboundConnectionConfig struct {
// Protocol specific settings. Must be one of the supported protocols.
Settings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,1,opt,name=settings" json:"settings,omitempty"`
// Range of port number to run on. Both inclusive.
PortRange *v2ray_core_common_net.PortRange `protobuf:"bytes,2,opt,name=port_range,json=portRange" json:"port_range,omitempty"`
// IP address to listen on. 0.0.0.0 if unset.
ListenOn *v2ray_core_common_net1.IPOrDomain `protobuf:"bytes,3,opt,name=listen_on,json=listenOn" json:"listen_on,omitempty"`
// Tag of this handler.
Tag string `protobuf:"bytes,4,opt,name=tag" json:"tag,omitempty"`
AllocationStrategy *AllocationStrategy `protobuf:"bytes,5,opt,name=allocation_strategy,json=allocationStrategy" json:"allocation_strategy,omitempty"`
StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,6,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
AllowPassiveConnection bool `protobuf:"varint,7,opt,name=allow_passive_connection,json=allowPassiveConnection" json:"allow_passive_connection,omitempty"`
}
func (m *InboundConnectionConfig) Reset() { *m = InboundConnectionConfig{} }
func (m *InboundConnectionConfig) String() string { return proto.CompactTextString(m) }
func (*InboundConnectionConfig) ProtoMessage() {}
func (*InboundConnectionConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *InboundConnectionConfig) GetSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.Settings
}
return nil
}
func (m *InboundConnectionConfig) GetPortRange() *v2ray_core_common_net.PortRange {
if m != nil {
return m.PortRange
}
return nil
}
func (m *InboundConnectionConfig) GetListenOn() *v2ray_core_common_net1.IPOrDomain {
if m != nil {
return m.ListenOn
}
return nil
}
func (m *InboundConnectionConfig) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *InboundConnectionConfig) GetAllocationStrategy() *AllocationStrategy {
if m != nil {
return m.AllocationStrategy
}
return nil
}
func (m *InboundConnectionConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
if m != nil {
return m.StreamSettings
}
return nil
}
func (m *InboundConnectionConfig) GetAllowPassiveConnection() bool {
if m != nil {
return m.AllowPassiveConnection
}
return false
}
// Config for an outbound connection handler.
type OutboundConnectionConfig struct {
Settings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,1,opt,name=settings" json:"settings,omitempty"`
// IP address to send data through. 0.0.0.0 if unset.
SendThrough *v2ray_core_common_net1.IPOrDomain `protobuf:"bytes,2,opt,name=send_through,json=sendThrough" json:"send_through,omitempty"`
StreamSettings *v2ray_core_transport_internet.StreamConfig `protobuf:"bytes,3,opt,name=stream_settings,json=streamSettings" json:"stream_settings,omitempty"`
ProxySettings *v2ray_core_transport_internet.ProxyConfig `protobuf:"bytes,5,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"`
Tag string `protobuf:"bytes,4,opt,name=tag" json:"tag,omitempty"`
}
func (m *OutboundConnectionConfig) Reset() { *m = OutboundConnectionConfig{} }
func (m *OutboundConnectionConfig) String() string { return proto.CompactTextString(m) }
func (*OutboundConnectionConfig) ProtoMessage() {}
func (*OutboundConnectionConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *OutboundConnectionConfig) GetSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.Settings
}
return nil
}
func (m *OutboundConnectionConfig) GetSendThrough() *v2ray_core_common_net1.IPOrDomain {
if m != nil {
return m.SendThrough
}
return nil
}
func (m *OutboundConnectionConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
if m != nil {
return m.StreamSettings
}
return nil
}
func (m *OutboundConnectionConfig) GetProxySettings() *v2ray_core_transport_internet.ProxyConfig {
if m != nil {
return m.ProxySettings
}
return nil
}
func (m *OutboundConnectionConfig) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
type Config struct { type Config struct {
// Inbound handler configurations. Must have at least one item. // Inbound handler configurations. Must have at least one item.
Inbound []*InboundConnectionConfig `protobuf:"bytes,1,rep,name=inbound" json:"inbound,omitempty"` Inbound []*v2ray_core_app_proxyman.InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbound" json:"inbound,omitempty"`
// Outbound handler configurations. Must have at least one item. The first item is used as default for routing. // Outbound handler configurations. Must have at least one item. The first item is used as default for routing.
Outbound []*OutboundConnectionConfig `protobuf:"bytes,2,rep,name=outbound" json:"outbound,omitempty"` Outbound []*v2ray_core_app_proxyman.OutboundHandlerConfig `protobuf:"bytes,2,rep,name=outbound" json:"outbound,omitempty"`
Log *v2ray_core_common_log.Config `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"` Log *v2ray_core_common_log.Config `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"`
// App configuration. Must be one in the app directory. // App configuration. Must be one in the app directory.
App []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,4,rep,name=app" json:"app,omitempty"` App []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,4,rep,name=app" json:"app,omitempty"`
Transport *v2ray_core_transport.Config `protobuf:"bytes,5,opt,name=transport" json:"transport,omitempty"` Transport *v2ray_core_transport.Config `protobuf:"bytes,5,opt,name=transport" json:"transport,omitempty"`
@ -271,16 +55,16 @@ type Config struct {
func (m *Config) Reset() { *m = Config{} } func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) } func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Config) GetInbound() []*InboundConnectionConfig { func (m *Config) GetInbound() []*v2ray_core_app_proxyman.InboundHandlerConfig {
if m != nil { if m != nil {
return m.Inbound return m.Inbound
} }
return nil return nil
} }
func (m *Config) GetOutbound() []*OutboundConnectionConfig { func (m *Config) GetOutbound() []*v2ray_core_app_proxyman.OutboundHandlerConfig {
if m != nil { if m != nil {
return m.Outbound return m.Outbound
} }
@ -309,65 +93,34 @@ func (m *Config) GetTransport() *v2ray_core_transport.Config {
} }
func init() { func init() {
proto.RegisterType((*AllocationStrategyConcurrency)(nil), "v2ray.core.AllocationStrategyConcurrency")
proto.RegisterType((*AllocationStrategyRefresh)(nil), "v2ray.core.AllocationStrategyRefresh")
proto.RegisterType((*AllocationStrategy)(nil), "v2ray.core.AllocationStrategy")
proto.RegisterType((*InboundConnectionConfig)(nil), "v2ray.core.InboundConnectionConfig")
proto.RegisterType((*OutboundConnectionConfig)(nil), "v2ray.core.OutboundConnectionConfig")
proto.RegisterType((*Config)(nil), "v2ray.core.Config") proto.RegisterType((*Config)(nil), "v2ray.core.Config")
proto.RegisterEnum("v2ray.core.ConfigFormat", ConfigFormat_name, ConfigFormat_value) proto.RegisterEnum("v2ray.core.ConfigFormat", ConfigFormat_name, ConfigFormat_value)
proto.RegisterEnum("v2ray.core.AllocationStrategy_Type", AllocationStrategy_Type_name, AllocationStrategy_Type_value)
} }
func init() { proto.RegisterFile("v2ray.com/core/config.proto", fileDescriptor0) } func init() { proto.RegisterFile("v2ray.com/core/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 745 bytes of a gzipped FileDescriptorProto // 338 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x95, 0xd1, 0x6e, 0xd3, 0x3a, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x91, 0xdf, 0x4a, 0x02, 0x41,
0x1c, 0xc6, 0x97, 0xb6, 0xeb, 0xda, 0x7f, 0xb7, 0x9e, 0xca, 0xe7, 0xe8, 0x9c, 0x9c, 0xc1, 0x50, 0x14, 0xc6, 0xd3, 0x35, 0xb3, 0xa3, 0x84, 0xcc, 0xd5, 0x62, 0x05, 0x12, 0x24, 0x12, 0x34, 0x2b,
0x29, 0xdb, 0x28, 0x03, 0xa5, 0xa3, 0x08, 0x31, 0x21, 0xc1, 0xd8, 0x3a, 0x90, 0x06, 0x82, 0x16, 0xdb, 0x4d, 0x74, 0xa9, 0xd0, 0x1f, 0xa1, 0x0c, 0x8b, 0x2e, 0xba, 0x89, 0x71, 0x1d, 0x17, 0x61,
0x77, 0xe2, 0x82, 0x9b, 0xc8, 0x4b, 0xbd, 0x2c, 0x52, 0x62, 0x47, 0xb6, 0xbb, 0x2d, 0x8f, 0xc0, 0x67, 0xce, 0x30, 0xbb, 0x46, 0xfb, 0x4a, 0x3d, 0x47, 0x0f, 0x16, 0x3b, 0xe3, 0xaa, 0x6b, 0x76,
0xab, 0x70, 0xc5, 0xab, 0xf0, 0x04, 0xbc, 0x0a, 0x72, 0x92, 0xa6, 0x1d, 0x6d, 0xb7, 0x49, 0x88, 0x7b, 0xe6, 0xfb, 0xfd, 0x0e, 0xe7, 0x1b, 0x38, 0xfe, 0xf4, 0x35, 0x4b, 0x69, 0x80, 0xc2, 0x0b,
0xbb, 0x34, 0xf9, 0x7e, 0x9f, 0x9d, 0xef, 0xfb, 0xc7, 0x85, 0x5b, 0x67, 0x6d, 0x41, 0x22, 0xcb, 0x50, 0x73, 0x2f, 0x40, 0x39, 0x9b, 0x87, 0x54, 0x69, 0x4c, 0x90, 0x40, 0xfe, 0xa8, 0x79, 0xab,
0xe1, 0x41, 0xcb, 0xe1, 0x82, 0xb6, 0x1c, 0xce, 0x4e, 0x3c, 0xd7, 0x0a, 0x05, 0x57, 0x1c, 0xc1, 0xbb, 0x15, 0x64, 0x4a, 0x79, 0x4a, 0xe3, 0x57, 0x2a, 0x98, 0x2c, 0x50, 0xad, 0xde, 0x1f, 0xa5,
0xe8, 0xa1, 0xa0, 0xab, 0xdb, 0x53, 0xc2, 0x20, 0xe0, 0xac, 0x25, 0xa9, 0xf0, 0x88, 0xdf, 0x52, 0x10, 0x28, 0xbd, 0x98, 0xeb, 0x39, 0x8b, 0xbc, 0x24, 0x55, 0x7c, 0xfa, 0x21, 0x78, 0x1c, 0xb3,
0x51, 0x48, 0x07, 0x76, 0x40, 0xa5, 0x24, 0x2e, 0x4d, 0xe8, 0xd5, 0xf5, 0xd9, 0x04, 0xa3, 0xaa, 0x90, 0x2f, 0x89, 0xce, 0x6e, 0x22, 0xc2, 0xb0, 0x68, 0x3e, 0xdf, 0xca, 0x25, 0x9a, 0xc9, 0x58,
0x15, 0x72, 0xa1, 0x52, 0xd5, 0xfd, 0xf9, 0x2a, 0x32, 0x18, 0x08, 0x2a, 0x65, 0x2a, 0xdc, 0x9c, 0xa1, 0x4e, 0x0a, 0xb1, 0xb3, 0x9f, 0x32, 0x54, 0x07, 0x66, 0x40, 0xee, 0xe0, 0x60, 0x2e, 0x27,
0x2d, 0xf4, 0xb9, 0x7b, 0x69, 0xd3, 0xab, 0xd6, 0x2f, 0x3a, 0x25, 0x08, 0x93, 0x7a, 0xc1, 0x96, 0xb8, 0x90, 0x53, 0xb7, 0xd4, 0x76, 0xba, 0x75, 0xff, 0x92, 0xae, 0x6f, 0xa2, 0x4c, 0x29, 0x9a,
0xc7, 0x14, 0x15, 0xda, 0xf8, 0x92, 0x7e, 0x63, 0xae, 0x7e, 0x52, 0xd6, 0x78, 0x0a, 0x6b, 0x7b, 0xdf, 0x40, 0x1f, 0x6c, 0xee, 0x9e, 0xc9, 0x69, 0xc4, 0xb5, 0xe5, 0xc7, 0x39, 0x4d, 0x86, 0x50,
0xbe, 0xcf, 0x1d, 0xa2, 0x3c, 0xce, 0xfa, 0x4a, 0x10, 0x45, 0xdd, 0xa8, 0xc3, 0x99, 0x33, 0x14, 0xc3, 0x45, 0x62, 0x4d, 0x65, 0x63, 0xa2, 0xff, 0x9a, 0x46, 0xcb, 0x60, 0x51, 0xb5, 0xe2, 0x89,
0x82, 0x32, 0x27, 0x42, 0xff, 0xc0, 0xe2, 0x19, 0xf1, 0x87, 0xd4, 0x34, 0xea, 0x46, 0x73, 0x05, 0x07, 0x4e, 0x84, 0xa1, 0xeb, 0xb4, 0x4b, 0xdd, 0xba, 0x7f, 0xba, 0xa9, 0xb1, 0x87, 0xd3, 0x08,
0x27, 0x3f, 0x1a, 0x8f, 0xe1, 0xff, 0x69, 0x0c, 0xd3, 0x13, 0x41, 0xe5, 0xe9, 0x1c, 0xe4, 0x4b, 0x43, 0xba, 0xa4, 0xb2, 0x24, 0xb9, 0x06, 0x87, 0x29, 0xe5, 0x56, 0xcc, 0xde, 0xce, 0x0e, 0xc0,
0x0e, 0xd0, 0x34, 0x83, 0x9e, 0x41, 0x41, 0xa7, 0x1c, 0x6b, 0xab, 0xed, 0x7b, 0xd6, 0xb8, 0x1b, 0x76, 0x4b, 0x5f, 0xb3, 0x6e, 0x1f, 0x6d, 0xb5, 0xe3, 0x0c, 0x21, 0x37, 0x70, 0xb8, 0x2a, 0xc9,
0x6b, 0x5a, 0x6d, 0x1d, 0x45, 0x21, 0xc5, 0x31, 0x80, 0xde, 0x41, 0xc5, 0x19, 0xef, 0xd3, 0xcc, 0xdd, 0x37, 0x0b, 0x4f, 0x36, 0xf9, 0xd5, 0x63, 0xbe, 0x6f, 0x1d, 0xbf, 0xe8, 0x40, 0xc3, 0x0e,
0xd5, 0x8d, 0x66, 0xa5, 0xfd, 0xe0, 0x6a, 0x7e, 0xe2, 0xc5, 0xf0, 0x24, 0x8d, 0x76, 0x61, 0x49, 0x6f, 0x51, 0x0b, 0x96, 0x90, 0x06, 0xd4, 0x9e, 0xb3, 0x7e, 0x27, 0x8b, 0x59, 0x73, 0x8f, 0xd4,
0x24, 0xbb, 0x37, 0xf3, 0xb1, 0xd1, 0xc6, 0xd5, 0x46, 0xe9, 0xab, 0xe2, 0x11, 0xd5, 0x78, 0x04, 0xa0, 0x32, 0x7c, 0x19, 0x3d, 0x35, 0x4b, 0xfd, 0x1e, 0x1c, 0x05, 0x28, 0x36, 0xac, 0xfd, 0xba,
0x05, 0xbd, 0x37, 0x04, 0x50, 0xdc, 0xf3, 0xcf, 0x49, 0x24, 0x6b, 0x0b, 0xfa, 0x1a, 0x13, 0x36, 0xe5, 0x4c, 0xfa, 0xbd, 0x92, 0x8d, 0xbe, 0xcb, 0xf0, 0xe6, 0x8f, 0x59, 0x4a, 0x07, 0xa8, 0xf9,
0xe0, 0x41, 0xcd, 0x40, 0xcb, 0x50, 0x7a, 0x7d, 0xa1, 0x7b, 0x22, 0x7e, 0x2d, 0xd7, 0xf8, 0x9e, 0xa4, 0x6a, 0xfe, 0xe9, 0xea, 0x37, 0x00, 0x00, 0xff, 0xff, 0xa7, 0x35, 0x52, 0xbd, 0x7d, 0x02,
0x87, 0xff, 0x0e, 0xd9, 0x31, 0x1f, 0xb2, 0x41, 0x87, 0x33, 0x46, 0x1d, 0xed, 0xdd, 0x89, 0x7b, 0x00, 0x00,
0x41, 0xfb, 0x50, 0x92, 0x54, 0x29, 0x8f, 0xb9, 0x32, 0x0e, 0xa5, 0xd2, 0xde, 0x9c, 0xdc, 0x4b,
0x32, 0x1f, 0x56, 0x32, 0xa0, 0x71, 0x1e, 0x83, 0xf7, 0xc9, 0x7c, 0xe2, 0x8c, 0x43, 0xbb, 0x00,
0xba, 0x6a, 0x5b, 0x10, 0xe6, 0xd2, 0x34, 0x9a, 0xfa, 0x0c, 0x17, 0x46, 0x95, 0xd5, 0xe3, 0x42,
0x61, 0xad, 0xc3, 0xe5, 0x70, 0x74, 0x89, 0x5e, 0x42, 0xd9, 0xf7, 0xa4, 0xa2, 0xcc, 0xe6, 0x2c,
0x4d, 0xe4, 0xee, 0x1c, 0xfe, 0xb0, 0xd7, 0x15, 0x07, 0x3c, 0x20, 0x1e, 0xc3, 0xa5, 0x84, 0xe9,
0x32, 0x54, 0x83, 0xbc, 0x22, 0xae, 0x59, 0xa8, 0x1b, 0xcd, 0x32, 0xd6, 0x97, 0xa8, 0x0b, 0x7f,
0x93, 0x2c, 0x46, 0x5b, 0xa6, 0x39, 0x9a, 0x8b, 0xb1, 0xf7, 0x9d, 0x6b, 0xd2, 0x46, 0x64, 0x7a,
0x70, 0x8e, 0xe0, 0x2f, 0xa9, 0x04, 0x25, 0x81, 0x9d, 0xc5, 0x55, 0x8c, 0xcd, 0x1e, 0x4e, 0x9a,
0x65, 0x63, 0x6f, 0x8d, 0x3e, 0x13, 0xab, 0x1f, 0x53, 0x49, 0xda, 0xb8, 0x9a, 0x78, 0xf4, 0x47,
0xc9, 0xed, 0x80, 0xa9, 0xd7, 0x3a, 0xb7, 0x43, 0x22, 0xa5, 0x77, 0x46, 0x6d, 0x27, 0xeb, 0xc7,
0x5c, 0xaa, 0x1b, 0xcd, 0x12, 0xfe, 0x37, 0x7e, 0xde, 0x4b, 0x1e, 0x8f, 0xdb, 0x6b, 0xfc, 0xc8,
0x81, 0xd9, 0x1d, 0xaa, 0x3f, 0x57, 0xea, 0x01, 0x2c, 0x4b, 0xca, 0x06, 0xb6, 0x3a, 0x15, 0x7c,
0xe8, 0x9e, 0xa6, 0xb5, 0xde, 0xa0, 0x96, 0x8a, 0xc6, 0x8e, 0x12, 0x6a, 0x56, 0x6c, 0xf9, 0xdf,
0x8f, 0xed, 0x23, 0x54, 0x43, 0xc1, 0x2f, 0xa2, 0xb1, 0x69, 0x52, 0xec, 0xd6, 0x35, 0xa6, 0x3d,
0x0d, 0xa5, 0x9e, 0x2b, 0xb1, 0x43, 0x66, 0x39, 0x35, 0x42, 0x8d, 0x6f, 0x39, 0x28, 0xa6, 0x79,
0xbe, 0x80, 0x25, 0x2f, 0xf9, 0x7e, 0x4c, 0xa3, 0x9e, 0x6f, 0x56, 0x2e, 0x1f, 0x1c, 0x73, 0x3e,
0x2d, 0x3c, 0x62, 0xd0, 0x2b, 0x28, 0xf1, 0xb4, 0x2a, 0x33, 0x17, 0xf3, 0xeb, 0x93, 0xfc, 0xbc,
0x1a, 0x71, 0x46, 0xa1, 0x16, 0xe4, 0x7d, 0xee, 0xa6, 0xd1, 0xad, 0xcd, 0xe8, 0xc0, 0xe7, 0xae,
0x95, 0x52, 0x5a, 0x89, 0x76, 0x20, 0x4f, 0xc2, 0xd0, 0x2c, 0xc4, 0xab, 0xdd, 0xb4, 0x7c, 0x8d,
0xa0, 0xe7, 0x50, 0xce, 0x92, 0x4b, 0x63, 0xbd, 0x3d, 0x3b, 0xd6, 0x74, 0xbd, 0xb1, 0x7c, 0x6b,
0x13, 0x96, 0x93, 0x9b, 0x6f, 0xb8, 0x08, 0x88, 0xd2, 0xc7, 0x50, 0x4f, 0x9f, 0xfb, 0xc7, 0xc3,
0x93, 0xda, 0x02, 0x2a, 0x41, 0xe1, 0x6d, 0xbf, 0xfb, 0xa1, 0x66, 0xec, 0x6f, 0x43, 0xd5, 0xe1,
0xc1, 0x84, 0xeb, 0x7e, 0x25, 0xe1, 0x62, 0xf5, 0xe7, 0x82, 0xbe, 0xf5, 0x35, 0x07, 0x9f, 0xda,
0x98, 0x44, 0x56, 0x87, 0x0b, 0x7a, 0x5c, 0x8c, 0xff, 0x3f, 0x9e, 0xfc, 0x0c, 0x00, 0x00, 0xff,
0xff, 0xff, 0x44, 0xf3, 0xc8, 0x6a, 0x07, 0x00, 0x00,
} }

View File

@ -6,11 +6,9 @@ option go_package = "core";
option java_package = "com.v2ray.core"; option java_package = "com.v2ray.core";
option java_outer_classname = "ConfigProto"; option java_outer_classname = "ConfigProto";
import "v2ray.com/core/app/proxyman/config.proto";
import "v2ray.com/core/common/serial/typed_message.proto"; import "v2ray.com/core/common/serial/typed_message.proto";
import "v2ray.com/core/common/net/port.proto";
import "v2ray.com/core/common/net/address.proto";
import "v2ray.com/core/common/log/config.proto"; import "v2ray.com/core/common/log/config.proto";
import "v2ray.com/core/transport/internet/config.proto";
import "v2ray.com/core/transport/config.proto"; import "v2ray.com/core/transport/config.proto";
// Configuration serialization format. // Configuration serialization format.
@ -19,78 +17,16 @@ enum ConfigFormat {
JSON = 1; JSON = 1;
} }
message AllocationStrategyConcurrency {
uint32 value = 1;
}
message AllocationStrategyRefresh {
uint32 value = 1;
}
message AllocationStrategy {
enum Type {
// Always allocate all connection handlers.
Always = 0;
// Randomly allocate specific range of handlers.
Random = 1;
// External. Not supported yet.
External = 2;
}
Type type = 1;
// Number of handlers (ports) running in parallel.
// Default value is 3 if unset.
AllocationStrategyConcurrency concurrency = 2;
// Number of minutes before a handler is regenerated.
// Default value is 5 if unset.
AllocationStrategyRefresh refresh = 3;
}
// Config for an inbound connection handler.
message InboundConnectionConfig {
// Protocol specific settings. Must be one of the supported protocols.
v2ray.core.common.serial.TypedMessage settings = 1;
// Range of port number to run on. Both inclusive.
v2ray.core.common.net.PortRange port_range = 2;
// IP address to listen on. 0.0.0.0 if unset.
v2ray.core.common.net.IPOrDomain listen_on = 3;
// Tag of this handler.
string tag = 4;
AllocationStrategy allocation_strategy = 5;
v2ray.core.transport.internet.StreamConfig stream_settings = 6;
bool allow_passive_connection = 7;
}
// Config for an outbound connection handler.
message OutboundConnectionConfig {
v2ray.core.common.serial.TypedMessage settings = 1;
// IP address to send data through. 0.0.0.0 if unset.
v2ray.core.common.net.IPOrDomain send_through = 2;
v2ray.core.transport.internet.StreamConfig stream_settings = 3;
v2ray.core.transport.internet.ProxyConfig proxy_settings = 5;
string tag = 4;
}
message Config { message Config {
// Inbound handler configurations. Must have at least one item. // Inbound handler configurations. Must have at least one item.
repeated InboundConnectionConfig inbound = 1; repeated v2ray.core.app.proxyman.InboundHandlerConfig inbound = 1;
// Outbound handler configurations. Must have at least one item. The first item is used as default for routing. // Outbound handler configurations. Must have at least one item. The first item is used as default for routing.
repeated OutboundConnectionConfig outbound = 2; repeated v2ray.core.app.proxyman.OutboundHandlerConfig outbound = 2;
v2ray.core.common.log.Config log = 3; v2ray.core.common.log.Config log = 3;
// App configuration. Must be one in the app directory. // App configuration. Must be one in the app directory.
repeated v2ray.core.common.serial.TypedMessage app = 4; repeated v2ray.core.common.serial.TypedMessage app = 4;
v2ray.core.transport.Config transport = 5; v2ray.core.transport.Config transport = 5;
} }

View File

@ -1,11 +0,0 @@
package core
import (
"v2ray.com/core/proxy"
)
type InboundDetourHandler interface {
Start() error
Close()
GetConnectionHandler() (proxy.InboundHandler, int)
}

View File

@ -1,77 +0,0 @@
package core
import (
"context"
"v2ray.com/core/app"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/log"
"v2ray.com/core/common/retry"
"v2ray.com/core/proxy"
)
// InboundDetourHandlerAlways is a handler for inbound detour connections.
type InboundDetourHandlerAlways struct {
space app.Space
config *InboundConnectionConfig
ich []proxy.InboundHandler
}
func NewInboundDetourHandlerAlways(ctx context.Context, config *InboundConnectionConfig) (*InboundDetourHandlerAlways, error) {
space := app.SpaceFromContext(ctx)
handler := &InboundDetourHandlerAlways{
space: space,
config: config,
}
ports := config.PortRange
handler.ich = make([]proxy.InboundHandler, 0, ports.To-ports.From+1)
for i := ports.FromPort(); i <= ports.ToPort(); i++ {
ichConfig, err := config.GetTypedSettings()
if err != nil {
return nil, err
}
ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{
Address: config.GetListenOnValue(),
Port: i,
Tag: config.Tag,
StreamSettings: config.StreamSettings,
AllowPassiveConnection: config.AllowPassiveConnection,
}), ichConfig)
if err != nil {
log.Error("Failed to create inbound connection handler: ", err)
return nil, err
}
handler.ich = append(handler.ich, ich)
}
return handler, nil
}
func (v *InboundDetourHandlerAlways) GetConnectionHandler() (proxy.InboundHandler, int) {
ich := v.ich[dice.Roll(len(v.ich))]
return ich, int(v.config.GetAllocationStrategyValue().GetRefreshValue())
}
func (v *InboundDetourHandlerAlways) Close() {
for _, ich := range v.ich {
ich.Close()
}
}
// Start starts the inbound connection handler.
func (v *InboundDetourHandlerAlways) Start() error {
for _, ich := range v.ich {
err := retry.ExponentialBackoff(10 /* times */, 200 /* ms */).On(func() error {
err := ich.Start()
if err != nil {
log.Error("Failed to start inbound detour:", err)
return err
}
return nil
})
if err != nil {
return err
}
}
return nil
}

View File

@ -1,164 +0,0 @@
package core
import (
"context"
"sync"
"time"
"v2ray.com/core/app"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/common/retry"
"v2ray.com/core/proxy"
)
type InboundDetourHandlerDynamic struct {
sync.RWMutex
space app.Space
config *InboundConnectionConfig
portsInUse map[net.Port]bool
ichs []proxy.InboundHandler
ich2Recyle []proxy.InboundHandler
lastRefresh time.Time
ctx context.Context
}
func NewInboundDetourHandlerDynamic(ctx context.Context, config *InboundConnectionConfig) (*InboundDetourHandlerDynamic, error) {
space := app.SpaceFromContext(ctx)
handler := &InboundDetourHandlerDynamic{
space: space,
config: config,
portsInUse: make(map[net.Port]bool),
ctx: ctx,
}
handler.ichs = make([]proxy.InboundHandler, config.GetAllocationStrategyValue().GetConcurrencyValue())
// To test configuration
ichConfig, err := config.GetTypedSettings()
if err != nil {
return nil, err
}
ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{
Address: config.GetListenOnValue(),
Port: 0,
Tag: config.Tag,
StreamSettings: config.StreamSettings,
AllowPassiveConnection: config.AllowPassiveConnection,
}), ichConfig)
if err != nil {
log.Error("Point: Failed to create inbound connection handler: ", err)
return nil, err
}
ich.Close()
return handler, nil
}
func (v *InboundDetourHandlerDynamic) pickUnusedPort() net.Port {
delta := int(v.config.PortRange.To) - int(v.config.PortRange.From) + 1
for {
r := dice.Roll(delta)
port := v.config.PortRange.FromPort() + net.Port(r)
_, used := v.portsInUse[port]
if !used {
return port
}
}
}
func (v *InboundDetourHandlerDynamic) GetConnectionHandler() (proxy.InboundHandler, int) {
v.RLock()
defer v.RUnlock()
ich := v.ichs[dice.Roll(len(v.ichs))]
until := int(v.config.GetAllocationStrategyValue().GetRefreshValue()) - int((time.Now().Unix()-v.lastRefresh.Unix())/60/1000)
if until < 0 {
until = 0
}
return ich, int(until)
}
func (v *InboundDetourHandlerDynamic) Close() {
v.Lock()
defer v.Unlock()
for _, ich := range v.ichs {
ich.Close()
}
}
func (v *InboundDetourHandlerDynamic) RecyleHandles() {
if v.ich2Recyle != nil {
for _, ich := range v.ich2Recyle {
if ich == nil {
continue
}
port := ich.Port()
ich.Close()
delete(v.portsInUse, port)
}
v.ich2Recyle = nil
}
}
func (v *InboundDetourHandlerDynamic) refresh() error {
v.lastRefresh = time.Now()
config := v.config
v.ich2Recyle = v.ichs
newIchs := make([]proxy.InboundHandler, config.GetAllocationStrategyValue().GetConcurrencyValue())
for idx := range newIchs {
err := retry.Timed(5, 100).On(func() error {
port := v.pickUnusedPort()
ichConfig, _ := config.GetTypedSettings()
ich, err := proxy.CreateInboundHandler(proxy.ContextWithInboundMeta(v.ctx, &proxy.InboundHandlerMeta{
Address: config.GetListenOnValue(),
Port: port, Tag: config.Tag,
StreamSettings: config.StreamSettings}), ichConfig)
if err != nil {
delete(v.portsInUse, port)
return err
}
err = ich.Start()
if err != nil {
delete(v.portsInUse, port)
return err
}
v.portsInUse[port] = true
newIchs[idx] = ich
return nil
})
if err != nil {
log.Error("Point: Failed to create inbound connection handler: ", err)
return err
}
}
v.Lock()
v.ichs = newIchs
v.Unlock()
return nil
}
func (v *InboundDetourHandlerDynamic) Start() error {
err := v.refresh()
if err != nil {
log.Error("Point: Failed to refresh dynamic allocations: ", err)
return err
}
go func() {
for {
time.Sleep(time.Duration(v.config.GetAllocationStrategyValue().GetRefreshValue())*time.Minute - 1)
v.RecyleHandles()
err := v.refresh()
if err != nil {
log.Error("Point: Failed to refresh dynamic allocations: ", err)
}
time.Sleep(time.Minute)
}
}()
return nil
}

View File

@ -4,7 +4,7 @@ import (
// The following are necessary as they register handlers in their init functions. // The following are necessary as they register handlers in their init functions.
_ "v2ray.com/core/app/dispatcher/impl" _ "v2ray.com/core/app/dispatcher/impl"
_ "v2ray.com/core/app/dns/server" _ "v2ray.com/core/app/dns/server"
_ "v2ray.com/core/app/proxy" _ "v2ray.com/core/app/proxyman/inbound"
_ "v2ray.com/core/app/proxyman/outbound" _ "v2ray.com/core/app/proxyman/outbound"
_ "v2ray.com/core/app/router" _ "v2ray.com/core/app/router"

View File

@ -6,7 +6,6 @@ import (
"time" "time"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
) )
@ -27,13 +26,14 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
} }
// Dispatch implements OutboundHandler.Dispatch(). // Dispatch implements OutboundHandler.Dispatch().
func (v *Handler) Dispatch(destination net.Destination, ray ray.OutboundRay) { func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay) error {
v.response.WriteTo(ray.OutboundOutput()) v.response.WriteTo(outboundRay.OutboundOutput())
// CloseError() will immediately close the connection. // CloseError() will immediately close the connection.
// Sleep a little here to make sure the response is sent to client. // Sleep a little here to make sure the response is sent to client.
time.Sleep(time.Millisecond * 500) time.Sleep(time.Millisecond * 500)
ray.OutboundInput().CloseError() outboundRay.OutboundInput().CloseError()
ray.OutboundOutput().CloseError() outboundRay.OutboundOutput().CloseError()
return nil
} }
func init() { func init() {

View File

@ -2,40 +2,24 @@ package proxy
import ( import (
"context" "context"
"v2ray.com/core/common/net"
) )
type key int type key int
const ( const (
inboundMetaKey key = iota dialerKey key = iota
outboundMetaKey sourceKey
dialerKey destinationKey
originalDestinationKey
inboundDestinationKey
inboundTagKey
outboundTagKey
resolvedIPsKey
allowPassiveConnKey
) )
func ContextWithInboundMeta(ctx context.Context, meta *InboundHandlerMeta) context.Context {
return context.WithValue(ctx, inboundMetaKey, meta)
}
func InboundMetaFromContext(ctx context.Context) *InboundHandlerMeta {
v := ctx.Value(inboundMetaKey)
if v == nil {
return nil
}
return v.(*InboundHandlerMeta)
}
func ContextWithOutboundMeta(ctx context.Context, meta *OutboundHandlerMeta) context.Context {
return context.WithValue(ctx, outboundMetaKey, meta)
}
func OutboundMetaFromContext(ctx context.Context) *OutboundHandlerMeta {
v := ctx.Value(outboundMetaKey)
if v == nil {
return nil
}
return v.(*OutboundHandlerMeta)
}
func ContextWithDialer(ctx context.Context, dialer Dialer) context.Context { func ContextWithDialer(ctx context.Context, dialer Dialer) context.Context {
return context.WithValue(ctx, dialerKey, dialer) return context.WithValue(ctx, dialerKey, dialer)
} }
@ -47,3 +31,93 @@ func DialerFromContext(ctx context.Context) Dialer {
} }
return v.(Dialer) return v.(Dialer)
} }
func ContextWithSource(ctx context.Context, src net.Destination) context.Context {
return context.WithValue(ctx, sourceKey, src)
}
func SourceFromContext(ctx context.Context) net.Destination {
v := ctx.Value(sourceKey)
if v == nil {
return net.Destination{}
}
return v.(net.Destination)
}
func ContextWithOriginalDestination(ctx context.Context, dest net.Destination) context.Context {
return context.WithValue(ctx, originalDestinationKey, dest)
}
func OriginalDestinationFromContext(ctx context.Context) net.Destination {
v := ctx.Value(originalDestinationKey)
if v == nil {
return net.Destination{}
}
return v.(net.Destination)
}
func ContextWithDestination(ctx context.Context, dest net.Destination) context.Context {
return context.WithValue(ctx, destinationKey, dest)
}
func DestinationFromContext(ctx context.Context) net.Destination {
v := ctx.Value(destinationKey)
if v == nil {
return net.Destination{}
}
return v.(net.Destination)
}
func ContextWithInboundDestination(ctx context.Context, dest net.Destination) context.Context {
return context.WithValue(ctx, inboundDestinationKey, dest)
}
func InboundDestinationFromContext(ctx context.Context) net.Destination {
v := ctx.Value(inboundDestinationKey)
if v == nil {
return net.Destination{}
}
return v.(net.Destination)
}
func ContextWithInboundTag(ctx context.Context, tag string) context.Context {
return context.WithValue(ctx, inboundTagKey, tag)
}
func InboundTagFromContext(ctx context.Context) string {
v := ctx.Value(inboundTagKey)
if v == nil {
return ""
}
return v.(string)
}
func ContextWithOutboundTag(ctx context.Context, tag string) context.Context {
return context.WithValue(ctx, outboundTagKey, tag)
}
func OutboundTagFromContext(ctx context.Context) string {
v := ctx.Value(outboundTagKey)
if v == nil {
return ""
}
return v.(string)
}
func ContextWithResolveIPs(ctx context.Context, ips []net.Address) context.Context {
return context.WithValue(ctx, resolvedIPsKey, ips)
}
func ResolvedIPsFromContext(ctx context.Context) ([]net.Address, bool) {
ips, ok := ctx.Value(resolvedIPsKey).([]net.Address)
return ips, ok
}
func ContextWithAllowPassiveConnection(ctx context.Context, allowPassiveConnection bool) context.Context {
return context.WithValue(ctx, allowPassiveConnKey, allowPassiveConnection)
}
func AllowPassiveConnectionFromContext(ctx context.Context) (bool, bool) {
allow, ok := ctx.Value(allowPassiveConnKey).(bool)
return allow, ok
}

View File

@ -2,7 +2,6 @@ package dokodemo
import ( import (
"context" "context"
"sync"
"v2ray.com/core/app" "v2ray.com/core/app"
"v2ray.com/core/app/dispatcher" "v2ray.com/core/app/dispatcher"
@ -14,21 +13,13 @@ import (
"v2ray.com/core/common/signal" "v2ray.com/core/common/signal"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/udp"
) )
type DokodemoDoor struct { type DokodemoDoor struct {
tcpMutex sync.RWMutex
udpMutex sync.RWMutex
config *Config config *Config
accepting bool
address net.Address address net.Address
port net.Port port net.Port
packetDispatcher dispatcher.Interface packetDispatcher dispatcher.Interface
tcpListener *internet.TCPHub
udpHub *udp.Hub
udpServer *udp.Server
meta *proxy.InboundHandlerMeta
} }
func New(ctx context.Context, config *Config) (*DokodemoDoor, error) { func New(ctx context.Context, config *Config) (*DokodemoDoor, error) {
@ -36,10 +27,6 @@ func New(ctx context.Context, config *Config) (*DokodemoDoor, error) {
if space == nil { if space == nil {
return nil, errors.New("Dokodemo: No space in context.") return nil, errors.New("Dokodemo: No space in context.")
} }
meta := proxy.InboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("Dokodemo: No outbound meta in context.")
}
if config.NetworkList == nil || config.NetworkList.Size() == 0 { if config.NetworkList == nil || config.NetworkList.Size() == 0 {
return nil, errors.New("DokodemoDoor: No network specified.") return nil, errors.New("DokodemoDoor: No network specified.")
} }
@ -47,7 +34,6 @@ func New(ctx context.Context, config *Config) (*DokodemoDoor, error) {
config: config, config: config,
address: config.GetPredefinedAddress(), address: config.GetPredefinedAddress(),
port: net.Port(config.Port), port: net.Port(config.Port),
meta: meta,
} }
space.OnInitialize(func() error { space.OnInitialize(func() error {
d.packetDispatcher = dispatcher.FromSpace(space) d.packetDispatcher = dispatcher.FromSpace(space)
@ -59,140 +45,28 @@ func New(ctx context.Context, config *Config) (*DokodemoDoor, error) {
return d, nil return d, nil
} }
func (v *DokodemoDoor) Port() net.Port { func (d *DokodemoDoor) Network() net.NetworkList {
return v.meta.Port return *(d.config.NetworkList)
} }
func (v *DokodemoDoor) Close() { func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn internet.Connection) error {
v.accepting = false log.Debug("Dokodemo: processing connection from: ", conn.RemoteAddr())
if v.tcpListener != nil {
v.tcpMutex.Lock()
v.tcpListener.Close()
v.tcpListener = nil
v.tcpMutex.Unlock()
}
if v.udpHub != nil {
v.udpMutex.Lock()
v.udpHub.Close()
v.udpHub = nil
v.udpMutex.Unlock()
}
}
func (v *DokodemoDoor) Network() net.NetworkList {
return *(v.config.NetworkList)
}
func (v *DokodemoDoor) Start() error {
if v.accepting {
return nil
}
v.accepting = true
if v.config.NetworkList.HasNetwork(net.Network_TCP) {
err := v.ListenTCP()
if err != nil {
return err
}
}
if v.config.NetworkList.HasNetwork(net.Network_UDP) {
err := v.ListenUDP()
if err != nil {
return err
}
}
return nil
}
func (v *DokodemoDoor) ListenUDP() error {
v.udpServer = udp.NewServer(v.packetDispatcher)
udpHub, err := udp.ListenUDP(
v.meta.Address, v.meta.Port, udp.ListenOption{
Callback: v.handleUDPPackets,
ReceiveOriginalDest: v.config.FollowRedirect,
Concurrency: 2,
})
if err != nil {
log.Error("Dokodemo failed to listen on ", v.meta.Address, ":", v.meta.Port, ": ", err)
return err
}
v.udpMutex.Lock()
v.udpHub = udpHub
v.udpMutex.Unlock()
return nil
}
func (v *DokodemoDoor) handleUDPPackets(payload *buf.Buffer, session *proxy.SessionInfo) {
if session.Destination.Network == net.Network_Unknown && v.address != nil && v.port > 0 {
session.Destination = net.UDPDestination(v.address, v.port)
}
if session.Destination.Network == net.Network_Unknown {
log.Info("Dokodemo: Unknown destination, stop forwarding...")
return
}
session.Inbound = v.meta
v.udpServer.Dispatch(session, payload, v.handleUDPResponse)
}
func (v *DokodemoDoor) handleUDPResponse(dest net.Destination, payload *buf.Buffer) {
defer payload.Release()
v.udpMutex.RLock()
defer v.udpMutex.RUnlock()
if !v.accepting {
return
}
v.udpHub.WriteTo(payload.Bytes(), dest)
}
func (v *DokodemoDoor) ListenTCP() error {
tcpListener, err := internet.ListenTCP(v.meta.Address, v.meta.Port, v.HandleTCPConnection, v.meta.StreamSettings)
if err != nil {
log.Error("Dokodemo: Failed to listen on ", v.meta.Address, ":", v.meta.Port, ": ", err)
return err
}
v.tcpMutex.Lock()
v.tcpListener = tcpListener
v.tcpMutex.Unlock()
return nil
}
func (v *DokodemoDoor) HandleTCPConnection(conn internet.Connection) {
defer conn.Close()
conn.SetReusable(false) conn.SetReusable(false)
ctx = proxy.ContextWithDestination(ctx, net.Destination{
var dest net.Destination Network: network,
if v.config.FollowRedirect { Address: d.address,
originalDest := GetOriginalDestination(conn) Port: d.port,
if originalDest.Network != net.Network_Unknown {
log.Info("Dokodemo: Following redirect to: ", originalDest)
dest = originalDest
}
}
if dest.Network == net.Network_Unknown && v.address != nil && v.port > net.Port(0) {
dest = net.TCPDestination(v.address, v.port)
}
if dest.Network == net.Network_Unknown {
log.Info("Dokodemo: Unknown destination, stop forwarding...")
return
}
log.Info("Dokodemo: Handling request to ", dest)
ray := v.packetDispatcher.DispatchToOutbound(&proxy.SessionInfo{
Source: net.DestinationFromAddr(conn.RemoteAddr()),
Destination: dest,
Inbound: v.meta,
}) })
inboundRay := d.packetDispatcher.DispatchToOutbound(ctx)
reader := net.NewTimeOutReader(v.config.Timeout, conn)
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
defer ray.InboundInput().Close() defer inboundRay.InboundInput().Close()
v2reader := buf.NewReader(reader) timedReader := net.NewTimeOutReader(d.config.Timeout, conn)
chunkReader := buf.NewReader(timedReader)
if err := buf.PipeUntilEOF(v2reader, ray.InboundInput()); err != nil { if err := buf.PipeUntilEOF(chunkReader, inboundRay.InboundInput()); err != nil {
log.Info("Dokodemo: Failed to transport all TCP request: ", err) log.Info("Dokodemo: Failed to transport request: ", err)
return err return err
} }
@ -202,18 +76,21 @@ func (v *DokodemoDoor) HandleTCPConnection(conn internet.Connection) {
responseDone := signal.ExecuteAsync(func() error { responseDone := signal.ExecuteAsync(func() error {
v2writer := buf.NewWriter(conn) v2writer := buf.NewWriter(conn)
if err := buf.PipeUntilEOF(ray.InboundOutput(), v2writer); err != nil { if err := buf.PipeUntilEOF(inboundRay.InboundOutput(), v2writer); err != nil {
log.Info("Dokodemo: Failed to transport all TCP response: ", err) log.Info("Dokodemo: Failed to transport response: ", err)
return err return err
} }
return nil return nil
}) })
if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil { if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil {
ray.InboundInput().CloseError() inboundRay.InboundInput().CloseError()
ray.InboundOutput().CloseError() inboundRay.InboundOutput().CloseError()
log.Info("Dokodemo: Connection ends with ", err) log.Info("Dokodemo: Connection ends with ", err)
return err
} }
return nil
} }
func init() { func init() {

View File

@ -1,173 +0,0 @@
package dokodemo_test
import (
"net"
"testing"
"context"
"v2ray.com/core/app"
"v2ray.com/core/app/dispatcher"
_ "v2ray.com/core/app/dispatcher/impl"
"v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/common/dice"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
. "v2ray.com/core/proxy/dokodemo"
"v2ray.com/core/proxy/freedom"
"v2ray.com/core/testing/assert"
"v2ray.com/core/testing/servers/tcp"
"v2ray.com/core/testing/servers/udp"
"v2ray.com/core/transport/internet"
_ "v2ray.com/core/transport/internet/tcp"
)
func TestDokodemoTCP(t *testing.T) {
assert := assert.On(t)
tcpServer := &tcp.Server{
MsgProcessor: func(data []byte) []byte {
buffer := make([]byte, 0, 2048)
buffer = append(buffer, []byte("Processed: ")...)
buffer = append(buffer, data...)
return buffer
},
}
_, err := tcpServer.Start()
assert.Error(err).IsNil()
defer tcpServer.Close()
space := app.NewSpace()
ctx := app.ContextWithSpace(context.Background(), space)
app.AddApplicationToSpace(ctx, new(dispatcher.Config))
app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))
ohm := proxyman.OutboundHandlerManagerFromSpace(space)
freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
Address: v2net.LocalHostIP,
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
},
}), &freedom.Config{})
assert.Error(err).IsNil()
ohm.SetDefaultHandler(freedom)
data2Send := "Data to be sent to remote."
port := v2net.Port(dice.Roll(20000) + 10000)
ctx = proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{
Address: v2net.LocalHostIP,
Port: port,
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
}})
dokodemo, err := New(ctx, &Config{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
Port: uint32(tcpServer.Port),
NetworkList: v2net.Network_TCP.AsList(),
Timeout: 600,
})
assert.Error(err).IsNil()
defer dokodemo.Close()
assert.Error(space.Initialize()).IsNil()
err = dokodemo.Start()
assert.Error(err).IsNil()
assert.Port(port).Equals(dokodemo.Port())
tcpClient, err := net.DialTCP("tcp", nil, &net.TCPAddr{
IP: []byte{127, 0, 0, 1},
Port: int(port),
Zone: "",
})
assert.Error(err).IsNil()
tcpClient.Write([]byte(data2Send))
tcpClient.CloseWrite()
response := make([]byte, 1024)
nBytes, err := tcpClient.Read(response)
assert.Error(err).IsNil()
tcpClient.Close()
assert.String("Processed: " + data2Send).Equals(string(response[:nBytes]))
}
func TestDokodemoUDP(t *testing.T) {
assert := assert.On(t)
udpServer := &udp.Server{
MsgProcessor: func(data []byte) []byte {
buffer := make([]byte, 0, 2048)
buffer = append(buffer, []byte("Processed: ")...)
buffer = append(buffer, data...)
return buffer
},
}
_, err := udpServer.Start()
assert.Error(err).IsNil()
defer udpServer.Close()
space := app.NewSpace()
ctx := app.ContextWithSpace(context.Background(), space)
app.AddApplicationToSpace(ctx, new(dispatcher.Config))
app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))
ohm := proxyman.OutboundHandlerManagerFromSpace(space)
freedom, err := freedom.New(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
Address: v2net.AnyIP,
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
},
}), &freedom.Config{})
assert.Error(err).IsNil()
ohm.SetDefaultHandler(freedom)
data2Send := "Data to be sent to remote."
port := v2net.Port(dice.Roll(20000) + 10000)
ctx = proxy.ContextWithInboundMeta(ctx, &proxy.InboundHandlerMeta{
Address: v2net.LocalHostIP,
Port: port,
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
}})
dokodemo, err := New(ctx, &Config{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
Port: uint32(udpServer.Port),
NetworkList: v2net.Network_UDP.AsList(),
Timeout: 600,
})
assert.Error(err).IsNil()
defer dokodemo.Close()
assert.Error(space.Initialize()).IsNil()
err = dokodemo.Start()
assert.Error(err).IsNil()
assert.Port(port).Equals(dokodemo.Port())
udpClient, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: []byte{127, 0, 0, 1},
Port: int(port),
Zone: "",
})
assert.Error(err).IsNil()
defer udpClient.Close()
udpClient.Write([]byte(data2Send))
response := make([]byte, 1024)
nBytes, addr, err := udpClient.ReadFromUDP(response)
assert.Error(err).IsNil()
assert.IP(addr.IP).Equals(v2net.LocalHostIP.IP())
assert.Bytes(response[:nBytes]).Equals([]byte("Processed: " + data2Send))
}

View File

@ -23,7 +23,6 @@ type Handler struct {
domainStrategy Config_DomainStrategy domainStrategy Config_DomainStrategy
timeout uint32 timeout uint32
dns dns.Server dns dns.Server
meta *proxy.OutboundHandlerMeta
} }
func New(ctx context.Context, config *Config) (*Handler, error) { func New(ctx context.Context, config *Config) (*Handler, error) {
@ -31,14 +30,9 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
if space == nil { if space == nil {
return nil, errors.New("Freedom: No space in context.") return nil, errors.New("Freedom: No space in context.")
} }
meta := proxy.OutboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("Freedom: No outbound meta in context.")
}
f := &Handler{ f := &Handler{
domainStrategy: config.DomainStrategy, domainStrategy: config.DomainStrategy,
timeout: config.Timeout, timeout: config.Timeout,
meta: meta,
} }
space.OnInitialize(func() error { space.OnInitialize(func() error {
if config.DomainStrategy == Config_USE_IP { if config.DomainStrategy == Config_USE_IP {
@ -75,18 +69,21 @@ func (v *Handler) ResolveIP(destination net.Destination) net.Destination {
return newDest return newDest
} }
func (v *Handler) Dispatch(destination net.Destination, ray ray.OutboundRay) { func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay) error {
destination := proxy.DestinationFromContext(ctx)
log.Info("Freedom: Opening connection to ", destination) log.Info("Freedom: Opening connection to ", destination)
input := ray.OutboundInput() input := outboundRay.OutboundInput()
output := ray.OutboundOutput() output := outboundRay.OutboundOutput()
var conn internet.Connection var conn internet.Connection
if v.domainStrategy == Config_USE_IP && destination.Address.Family().IsDomain() { if v.domainStrategy == Config_USE_IP && destination.Address.Family().IsDomain() {
destination = v.ResolveIP(destination) destination = v.ResolveIP(destination)
} }
dialer := proxy.DialerFromContext(ctx)
err := retry.ExponentialBackoff(5, 100).On(func() error { err := retry.ExponentialBackoff(5, 100).On(func() error {
rawConn, err := internet.Dial(v.meta.Address, destination, v.meta.GetDialerOptions()) rawConn, err := dialer.Dial(ctx, destination)
if err != nil { if err != nil {
return err return err
} }
@ -95,7 +92,7 @@ func (v *Handler) Dispatch(destination net.Destination, ray ray.OutboundRay) {
}) })
if err != nil { if err != nil {
log.Warning("Freedom: Failed to open connection to ", destination, ": ", err) log.Warning("Freedom: Failed to open connection to ", destination, ": ", err)
return return err
} }
defer conn.Close() defer conn.Close()
@ -133,7 +130,10 @@ func (v *Handler) Dispatch(destination net.Destination, ray ray.OutboundRay) {
log.Info("Freedom: Connection ending with ", err) log.Info("Freedom: Connection ending with ", err)
input.CloseError() input.CloseError()
output.CloseError() output.CloseError()
return err
} }
return nil
} }
func init() { func init() {

View File

@ -1,97 +0,0 @@
package freedom_test
import (
"testing"
"context"
"v2ray.com/core/app"
"v2ray.com/core/app/dispatcher"
_ "v2ray.com/core/app/dispatcher/impl"
"v2ray.com/core/app/dns"
_ "v2ray.com/core/app/dns/server"
"v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/app/router"
"v2ray.com/core/common/buf"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
. "v2ray.com/core/proxy/freedom"
"v2ray.com/core/testing/assert"
"v2ray.com/core/testing/servers/tcp"
"v2ray.com/core/transport/internet"
_ "v2ray.com/core/transport/internet/tcp"
"v2ray.com/core/transport/ray"
)
func TestSinglePacket(t *testing.T) {
assert := assert.On(t)
tcpServer := &tcp.Server{
MsgProcessor: func(data []byte) []byte {
buffer := make([]byte, 0, 2048)
buffer = append(buffer, []byte("Processed: ")...)
buffer = append(buffer, data...)
return buffer
},
}
tcpServerAddr, err := tcpServer.Start()
assert.Error(err).IsNil()
space := app.NewSpace()
ctx := app.ContextWithSpace(context.Background(), space)
ctx = proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
Address: v2net.AnyIP,
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
},
})
freedom, err := New(ctx, &Config{})
assert.Error(err).IsNil()
assert.Error(space.Initialize()).IsNil()
traffic := ray.NewRay()
data2Send := "Data to be sent to remote"
payload := buf.NewLocal(2048)
payload.Append([]byte(data2Send))
traffic.InboundInput().Write(payload)
go freedom.Dispatch(tcpServerAddr, traffic)
traffic.InboundInput().Close()
respPayload, err := traffic.InboundOutput().Read()
assert.Error(err).IsNil()
assert.String(respPayload.String()).Equals("Processed: Data to be sent to remote")
tcpServer.Close()
}
func TestIPResolution(t *testing.T) {
assert := assert.On(t)
space := app.NewSpace()
ctx := app.ContextWithSpace(context.Background(), space)
assert.Error(app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig))).IsNil()
assert.Error(app.AddApplicationToSpace(ctx, new(dispatcher.Config))).IsNil()
assert.Error(app.AddApplicationToSpace(ctx, new(router.Config))).IsNil()
assert.Error(app.AddApplicationToSpace(ctx, &dns.Config{
Hosts: map[string]*v2net.IPOrDomain{
"v2ray.com": v2net.NewIPOrDomain(v2net.LocalHostIP),
},
})).IsNil()
ctx = proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
Address: v2net.AnyIP,
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_TCP,
},
})
freedom, err := New(ctx, &Config{DomainStrategy: Config_USE_IP})
assert.Error(err).IsNil()
assert.Error(space.Initialize()).IsNil()
ipDest := freedom.ResolveIP(v2net.TCPDestination(v2net.DomainAddress("v2ray.com"), v2net.Port(80)))
assert.Destination(ipDest).IsTCP()
assert.Address(ipDest.Address).Equals(v2net.LocalHostIP)
}

View File

@ -25,11 +25,8 @@ import (
// Server is a HTTP proxy server. // Server is a HTTP proxy server.
type Server struct { type Server struct {
sync.Mutex sync.Mutex
accepting bool
packetDispatcher dispatcher.Interface packetDispatcher dispatcher.Interface
config *ServerConfig config *ServerConfig
tcpListener *internet.TCPHub
meta *proxy.InboundHandlerMeta
} }
// NewServer creates a new HTTP inbound handler. // NewServer creates a new HTTP inbound handler.
@ -38,13 +35,8 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if space == nil { if space == nil {
return nil, errors.New("HTTP|Server: No space in context.") return nil, errors.New("HTTP|Server: No space in context.")
} }
meta := proxy.InboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("HTTP|Server: No inbound meta from context.")
}
s := &Server{ s := &Server{
config: config, config: config,
meta: meta,
} }
space.OnInitialize(func() error { space.OnInitialize(func() error {
s.packetDispatcher = dispatcher.FromSpace(space) s.packetDispatcher = dispatcher.FromSpace(space)
@ -56,46 +48,12 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
return s, nil return s, nil
} }
// Port implements InboundHandler.Port(). func (*Server) Network() v2net.NetworkList {
func (v *Server) Port() v2net.Port {
return v.meta.Port
}
func (v *Server) Network() v2net.NetworkList {
return v2net.NetworkList{ return v2net.NetworkList{
Network: []v2net.Network{v2net.Network_TCP}, Network: []v2net.Network{v2net.Network_TCP},
} }
} }
// Close implements InboundHandler.Close().
func (v *Server) Close() {
v.accepting = false
if v.tcpListener != nil {
v.Lock()
v.tcpListener.Close()
v.tcpListener = nil
v.Unlock()
}
}
// Start implements InboundHandler.Start().
func (v *Server) Start() error {
if v.accepting {
return nil
}
tcpListener, err := internet.ListenTCP(v.meta.Address, v.meta.Port, v.handleConnection, v.meta.StreamSettings)
if err != nil {
log.Error("HTTP: Failed listen on ", v.meta.Address, ":", v.meta.Port, ": ", err)
return err
}
v.Lock()
v.tcpListener = tcpListener
v.Unlock()
v.accepting = true
return nil
}
func parseHost(rawHost string, defaultPort v2net.Port) (v2net.Destination, error) { func parseHost(rawHost string, defaultPort v2net.Port) (v2net.Destination, error) {
port := defaultPort port := defaultPort
host, rawPort, err := net.SplitHostPort(rawHost) host, rawPort, err := net.SplitHostPort(rawHost)
@ -119,11 +77,10 @@ func parseHost(rawHost string, defaultPort v2net.Port) (v2net.Destination, error
return v2net.TCPDestination(v2net.DomainAddress(host), port), nil return v2net.TCPDestination(v2net.DomainAddress(host), port), nil
} }
func (v *Server) handleConnection(conn internet.Connection) { func (s *Server) Process(ctx context.Context, network v2net.Network, conn internet.Connection) error {
defer conn.Close()
conn.SetReusable(false) conn.SetReusable(false)
timedReader := v2net.NewTimeOutReader(v.config.Timeout, conn) timedReader := v2net.NewTimeOutReader(s.config.Timeout, conn)
reader := bufio.OriginalReaderSize(timedReader, 2048) reader := bufio.OriginalReaderSize(timedReader, 2048)
request, err := http.ReadRequest(reader) request, err := http.ReadRequest(reader)
@ -131,7 +88,7 @@ func (v *Server) handleConnection(conn internet.Connection) {
if errors.Cause(err) != io.EOF { if errors.Cause(err) != io.EOF {
log.Warning("HTTP: Failed to read http request: ", err) log.Warning("HTTP: Failed to read http request: ", err)
} }
return return err
} }
log.Info("HTTP: Request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]") log.Info("HTTP: Request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]")
defaultPort := v2net.Port(80) defaultPort := v2net.Port(80)
@ -145,22 +102,18 @@ func (v *Server) handleConnection(conn internet.Connection) {
dest, err := parseHost(host, defaultPort) dest, err := parseHost(host, defaultPort)
if err != nil { if err != nil {
log.Warning("HTTP: Malformed proxy host (", host, "): ", err) log.Warning("HTTP: Malformed proxy host (", host, "): ", err)
return return err
} }
log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "") log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "")
session := &proxy.SessionInfo{ ctx = proxy.ContextWithDestination(ctx, dest)
Source: v2net.DestinationFromAddr(conn.RemoteAddr()),
Destination: dest,
Inbound: v.meta,
}
if strings.ToUpper(request.Method) == "CONNECT" { if strings.ToUpper(request.Method) == "CONNECT" {
v.handleConnect(request, session, reader, conn) return s.handleConnect(ctx, request, reader, conn)
} else { } else {
v.handlePlainHTTP(request, session, reader, conn) return s.handlePlainHTTP(ctx, request, reader, conn)
} }
} }
func (v *Server) handleConnect(request *http.Request, session *proxy.SessionInfo, reader io.Reader, writer io.Writer) { func (s *Server) handleConnect(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer) error {
response := &http.Response{ response := &http.Response{
Status: "200 OK", Status: "200 OK",
StatusCode: 200, StatusCode: 200,
@ -174,10 +127,10 @@ func (v *Server) handleConnect(request *http.Request, session *proxy.SessionInfo
} }
if err := response.Write(writer); err != nil { if err := response.Write(writer); err != nil {
log.Warning("HTTP|Server: failed to write back OK response: ", err) log.Warning("HTTP|Server: failed to write back OK response: ", err)
return return err
} }
ray := v.packetDispatcher.DispatchToOutbound(session) ray := s.packetDispatcher.DispatchToOutbound(ctx)
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
defer ray.InboundInput().Close() defer ray.InboundInput().Close()
@ -201,7 +154,10 @@ func (v *Server) handleConnect(request *http.Request, session *proxy.SessionInfo
log.Info("HTTP|Server: Connection ends with: ", err) log.Info("HTTP|Server: Connection ends with: ", err)
ray.InboundInput().CloseError() ray.InboundInput().CloseError()
ray.InboundOutput().CloseError() ray.InboundOutput().CloseError()
return err
} }
return nil
} }
// @VisibleForTesting // @VisibleForTesting
@ -229,7 +185,7 @@ func StripHopByHopHeaders(request *http.Request) {
} }
} }
func (v *Server) GenerateResponse(statusCode int, status string) *http.Response { func generateResponse(statusCode int, status string) *http.Response {
hdr := http.Header(make(map[string][]string)) hdr := http.Header(make(map[string][]string))
hdr.Set("Connection", "close") hdr.Set("Connection", "close")
return &http.Response{ return &http.Response{
@ -245,18 +201,16 @@ func (v *Server) GenerateResponse(statusCode int, status string) *http.Response
} }
} }
func (v *Server) handlePlainHTTP(request *http.Request, session *proxy.SessionInfo, reader io.Reader, writer io.Writer) { func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer) error {
if len(request.URL.Host) <= 0 { if len(request.URL.Host) <= 0 {
response := v.GenerateResponse(400, "Bad Request") response := generateResponse(400, "Bad Request")
response.Write(writer) return response.Write(writer)
return
} }
request.Host = request.URL.Host request.Host = request.URL.Host
StripHopByHopHeaders(request) StripHopByHopHeaders(request)
ray := v.packetDispatcher.DispatchToOutbound(session) ray := s.packetDispatcher.DispatchToOutbound(ctx)
input := ray.InboundInput() input := ray.InboundInput()
output := ray.InboundOutput() output := ray.InboundOutput()
@ -279,7 +233,7 @@ func (v *Server) handlePlainHTTP(request *http.Request, session *proxy.SessionIn
response, err := http.ReadResponse(responseReader, request) response, err := http.ReadResponse(responseReader, request)
if err != nil { if err != nil {
log.Warning("HTTP: Failed to read response: ", err) log.Warning("HTTP: Failed to read response: ", err)
response = v.GenerateResponse(503, "Service Unavailable") response = generateResponse(503, "Service Unavailable")
} }
responseWriter := bufio.NewWriter(writer) responseWriter := bufio.NewWriter(writer)
if err := response.Write(responseWriter); err != nil { if err := response.Write(responseWriter); err != nil {
@ -296,7 +250,10 @@ func (v *Server) handlePlainHTTP(request *http.Request, session *proxy.SessionIn
log.Info("HTTP|Server: Connecton ending with ", err) log.Info("HTTP|Server: Connecton ending with ", err)
input.CloseError() input.CloseError()
output.CloseError() output.CloseError()
return err
} }
return nil
} }
func init() { func init() {

View File

@ -5,63 +5,20 @@ import (
"context" "context"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
) )
type HandlerState int
const (
HandlerStateStopped = HandlerState(0)
HandlerStateRunning = HandlerState(1)
)
type SessionInfo struct {
Source net.Destination
Destination net.Destination
User *protocol.User
Inbound *InboundHandlerMeta
}
type InboundHandlerMeta struct {
Tag string
Address net.Address
Port net.Port
AllowPassiveConnection bool
StreamSettings *internet.StreamConfig
}
type OutboundHandlerMeta struct {
Tag string
Address net.Address
StreamSettings *internet.StreamConfig
ProxySettings *internet.ProxyConfig
}
func (v *OutboundHandlerMeta) GetDialerOptions() internet.DialerOptions {
return internet.DialerOptions{
Stream: v.StreamSettings,
Proxy: v.ProxySettings,
}
}
// An InboundHandler handles inbound network connections to V2Ray. // An InboundHandler handles inbound network connections to V2Ray.
type InboundHandler interface { type InboundHandler interface {
// Listen starts a InboundHandler.
Start() error
// Close stops the handler to accepting anymore inbound connections.
Close()
// Port returns the port that the handler is listening on.
Port() net.Port
Network() net.NetworkList Network() net.NetworkList
Process(context.Context, net.Network, internet.Connection) error
} }
// An OutboundHandler handles outbound network connection for V2Ray. // An OutboundHandler handles outbound network connection for V2Ray.
type OutboundHandler interface { type OutboundHandler interface {
// Dispatch sends one or more Packets to its destination. Process(context.Context, ray.OutboundRay) error
Dispatch(destination net.Destination, ray ray.OutboundRay)
} }
// Dialer is used by OutboundHandler for creating outbound connections. // Dialer is used by OutboundHandler for creating outbound connections.

View File

@ -2,7 +2,6 @@ package shadowsocks
import ( import (
"context" "context"
"errors"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
@ -20,39 +19,35 @@ import (
// Client is a inbound handler for Shadowsocks protocol // Client is a inbound handler for Shadowsocks protocol
type Client struct { type Client struct {
serverPicker protocol.ServerPicker serverPicker protocol.ServerPicker
meta *proxy.OutboundHandlerMeta
} }
// NewClient create a new Shadowsocks client. // NewClient create a new Shadowsocks client.
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
meta := proxy.OutboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("Shadowsocks|Client: No outbound meta in context.")
}
serverList := protocol.NewServerList() serverList := protocol.NewServerList()
for _, rec := range config.Server { for _, rec := range config.Server {
serverList.AddServer(protocol.NewServerSpecFromPB(*rec)) serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
} }
client := &Client{ client := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList), serverPicker: protocol.NewRoundRobinServerPicker(serverList),
meta: meta,
} }
return client, nil return client, nil
} }
// Dispatch implements OutboundHandler.Dispatch(). // Process implements OutboundHandler.Process().
func (v *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) { func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay) error {
destination := proxy.DestinationFromContext(ctx)
network := destination.Network network := destination.Network
var server *protocol.ServerSpec var server *protocol.ServerSpec
var conn internet.Connection var conn internet.Connection
dialer := proxy.DialerFromContext(ctx)
err := retry.ExponentialBackoff(5, 100).On(func() error { err := retry.ExponentialBackoff(5, 100).On(func() error {
server = v.serverPicker.PickServer() server = v.serverPicker.PickServer()
dest := server.Destination() dest := server.Destination()
dest.Network = network dest.Network = network
rawConn, err := internet.Dial(v.meta.Address, dest, v.meta.GetDialerOptions()) rawConn, err := dialer.Dial(ctx, dest)
if err != nil { if err != nil {
return err return err
} }
@ -62,7 +57,7 @@ func (v *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
}) })
if err != nil { if err != nil {
log.Warning("Shadowsocks|Client: Failed to find an available destination:", err) log.Warning("Shadowsocks|Client: Failed to find an available destination:", err)
return return err
} }
log.Info("Shadowsocks|Client: Tunneling request to ", destination, " via ", server.Destination()) log.Info("Shadowsocks|Client: Tunneling request to ", destination, " via ", server.Destination())
@ -83,7 +78,7 @@ func (v *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
rawAccount, err := user.GetTypedAccount() rawAccount, err := user.GetTypedAccount()
if err != nil { if err != nil {
log.Warning("Shadowsocks|Client: Failed to get a valid user account: ", err) log.Warning("Shadowsocks|Client: Failed to get a valid user account: ", err)
return return err
} }
account := rawAccount.(*ShadowsocksAccount) account := rawAccount.(*ShadowsocksAccount)
request.User = user request.User = user
@ -97,27 +92,27 @@ func (v *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
bodyWriter, err := WriteTCPRequest(request, bufferedWriter) bodyWriter, err := WriteTCPRequest(request, bufferedWriter)
if err != nil { if err != nil {
log.Info("Shadowsocks|Client: Failed to write request: ", err) log.Info("Shadowsocks|Client: Failed to write request: ", err)
return return err
} }
bufferedWriter.SetBuffered(false) bufferedWriter.SetBuffered(false)
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
if err := buf.PipeUntilEOF(ray.OutboundInput(), bodyWriter); err != nil { if err := buf.PipeUntilEOF(outboundRay.OutboundInput(), bodyWriter); err != nil {
return err return err
} }
return nil return nil
}) })
responseDone := signal.ExecuteAsync(func() error { responseDone := signal.ExecuteAsync(func() error {
defer ray.OutboundOutput().Close() defer outboundRay.OutboundOutput().Close()
responseReader, err := ReadTCPResponse(user, conn) responseReader, err := ReadTCPResponse(user, conn)
if err != nil { if err != nil {
return err return err
} }
if err := buf.PipeUntilEOF(responseReader, ray.OutboundOutput()); err != nil { if err := buf.PipeUntilEOF(responseReader, outboundRay.OutboundOutput()); err != nil {
return err return err
} }
@ -126,9 +121,12 @@ func (v *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil { if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil {
log.Info("Shadowsocks|Client: Connection ends with ", err) log.Info("Shadowsocks|Client: Connection ends with ", err)
ray.OutboundInput().CloseError() outboundRay.OutboundInput().CloseError()
ray.OutboundOutput().CloseError() outboundRay.OutboundOutput().CloseError()
return err
} }
return nil
} }
if request.Command == protocol.RequestCommandUDP { if request.Command == protocol.RequestCommandUDP {
@ -139,7 +137,7 @@ func (v *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
} }
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
if err := buf.PipeUntilEOF(ray.OutboundInput(), writer); err != nil { if err := buf.PipeUntilEOF(outboundRay.OutboundInput(), writer); err != nil {
log.Info("Shadowsocks|Client: Failed to transport all UDP request: ", err) log.Info("Shadowsocks|Client: Failed to transport all UDP request: ", err)
return err return err
} }
@ -149,14 +147,14 @@ func (v *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
timedReader := net.NewTimeOutReader(16, conn) timedReader := net.NewTimeOutReader(16, conn)
responseDone := signal.ExecuteAsync(func() error { responseDone := signal.ExecuteAsync(func() error {
defer ray.OutboundOutput().Close() defer outboundRay.OutboundOutput().Close()
reader := &UDPReader{ reader := &UDPReader{
Reader: timedReader, Reader: timedReader,
User: user, User: user,
} }
if err := buf.PipeUntilEOF(reader, ray.OutboundOutput()); err != nil { if err := buf.PipeUntilEOF(reader, outboundRay.OutboundOutput()); err != nil {
log.Info("Shadowsocks|Client: Failed to transport all UDP response: ", err) log.Info("Shadowsocks|Client: Failed to transport all UDP response: ", err)
return err return err
} }
@ -165,10 +163,15 @@ func (v *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil { if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil {
log.Info("Shadowsocks|Client: Connection ends with ", err) log.Info("Shadowsocks|Client: Connection ends with ", err)
ray.OutboundInput().CloseError() outboundRay.OutboundInput().CloseError()
ray.OutboundOutput().CloseError() outboundRay.OutboundOutput().CloseError()
return err
} }
return nil
} }
return nil
} }
func init() { func init() {

View File

@ -23,10 +23,6 @@ type Server struct {
config *ServerConfig config *ServerConfig
user *protocol.User user *protocol.User
account *ShadowsocksAccount account *ShadowsocksAccount
meta *proxy.InboundHandlerMeta
accepting bool
tcpHub *internet.TCPHub
udpHub *udp.Hub
udpServer *udp.Server udpServer *udp.Server
} }
@ -35,10 +31,6 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if space == nil { if space == nil {
return nil, errors.New("Shadowsocks|Server: No space in context.") return nil, errors.New("Shadowsocks|Server: No space in context.")
} }
meta := proxy.InboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("Shadowsocks|Server: No inbound meta in context.")
}
if config.GetUser() == nil { if config.GetUser() == nil {
return nil, protocol.ErrUserMissing return nil, protocol.ErrUserMissing
} }
@ -51,7 +43,6 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
s := &Server{ s := &Server{
config: config, config: config,
meta: meta,
user: config.GetUser(), user: config.GetUser(),
account: account, account: account,
} }
@ -67,129 +58,103 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
return s, nil return s, nil
} }
func (v *Server) Network() net.NetworkList { func (s *Server) Network() net.NetworkList {
list := net.NetworkList{ list := net.NetworkList{
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
} }
if v.config.UdpEnabled { if s.config.UdpEnabled {
list.Network = append(list.Network, net.Network_UDP) list.Network = append(list.Network, net.Network_UDP)
} }
return list return list
} }
func (v *Server) Port() net.Port { func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection) error {
return v.meta.Port switch network {
} case net.Network_TCP:
return s.handleConnection(ctx, conn)
func (v *Server) Close() { case net.Network_UDP:
v.accepting = false return s.handlerUDPPayload(ctx, conn)
// TODO: synchronization default:
if v.tcpHub != nil { return errors.New("Shadowsocks|Server: Unknown network: ", network)
v.tcpHub.Close()
v.tcpHub = nil
}
if v.udpHub != nil {
v.udpHub.Close()
v.udpHub = nil
} }
} }
func (v *Server) Start() error { func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection) error {
if v.accepting { source := proxy.SourceFromContext(ctx)
return nil
}
tcpHub, err := internet.ListenTCP(v.meta.Address, v.meta.Port, v.handleConnection, v.meta.StreamSettings) reader := buf.NewReader(conn)
if err != nil { for {
log.Error("Shadowsocks: Failed to listen TCP on ", v.meta.Address, ":", v.meta.Port, ": ", err) payload, err := reader.Read()
return err
}
v.tcpHub = tcpHub
if v.config.UdpEnabled {
v.udpServer = udp.NewServer(v.packetDispatcher)
udpHub, err := udp.ListenUDP(v.meta.Address, v.meta.Port, udp.ListenOption{Callback: v.handlerUDPPayload})
if err != nil { if err != nil {
log.Error("Shadowsocks: Failed to listen UDP on ", v.meta.Address, ":", v.meta.Port, ": ", err) break
return err
} }
v.udpHub = udpHub
}
v.accepting = true request, data, err := DecodeUDPPacket(v.user, payload)
if err != nil {
log.Info("Shadowsocks|Server: Skipping invalid UDP packet from: ", source, ": ", err)
log.Access(source, "", log.AccessRejected, err)
payload.Release()
continue
}
if request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Disabled {
log.Info("Shadowsocks|Server: Client payload enables OTA but server doesn't allow it.")
payload.Release()
continue
}
if !request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Enabled {
log.Info("Shadowsocks|Server: Client payload disables OTA but server forces it.")
payload.Release()
continue
}
dest := request.Destination()
log.Access(source, dest, log.AccessAccepted, "")
log.Info("Shadowsocks|Server: Tunnelling request to ", dest)
ctx = protocol.ContextWithUser(ctx, request.User)
v.udpServer.Dispatch(ctx, dest, data, func(payload *buf.Buffer) {
defer payload.Release()
data, err := EncodeUDPPacket(request, payload)
if err != nil {
log.Warning("Shadowsocks|Server: Failed to encode UDP packet: ", err)
return
}
defer data.Release()
conn.Write(data.Bytes())
})
}
return nil return nil
} }
func (v *Server) handlerUDPPayload(payload *buf.Buffer, session *proxy.SessionInfo) { func (s *Server) handleConnection(ctx context.Context, conn internet.Connection) error {
source := session.Source
request, data, err := DecodeUDPPacket(v.user, payload)
if err != nil {
log.Info("Shadowsocks|Server: Skipping invalid UDP packet from: ", source, ": ", err)
log.Access(source, "", log.AccessRejected, err)
payload.Release()
return
}
if request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Disabled {
log.Info("Shadowsocks|Server: Client payload enables OTA but server doesn't allow it.")
payload.Release()
return
}
if !request.Option.Has(RequestOptionOneTimeAuth) && v.account.OneTimeAuth == Account_Enabled {
log.Info("Shadowsocks|Server: Client payload disables OTA but server forces it.")
payload.Release()
return
}
dest := request.Destination()
log.Access(source, dest, log.AccessAccepted, "")
log.Info("Shadowsocks|Server: Tunnelling request to ", dest)
v.udpServer.Dispatch(&proxy.SessionInfo{Source: source, Destination: dest, User: request.User, Inbound: v.meta}, data, func(destination net.Destination, payload *buf.Buffer) {
defer payload.Release()
data, err := EncodeUDPPacket(request, payload)
if err != nil {
log.Warning("Shadowsocks|Server: Failed to encode UDP packet: ", err)
return
}
defer data.Release()
v.udpHub.WriteTo(data.Bytes(), source)
})
}
func (v *Server) handleConnection(conn internet.Connection) {
defer conn.Close()
conn.SetReusable(false) conn.SetReusable(false)
timedReader := net.NewTimeOutReader(16, conn) timedReader := net.NewTimeOutReader(16, conn)
bufferedReader := bufio.NewReader(timedReader) bufferedReader := bufio.NewReader(timedReader)
request, bodyReader, err := ReadTCPSession(v.user, bufferedReader) request, bodyReader, err := ReadTCPSession(s.user, bufferedReader)
if err != nil { if err != nil {
log.Access(conn.RemoteAddr(), "", log.AccessRejected, err) log.Access(conn.RemoteAddr(), "", log.AccessRejected, err)
log.Info("Shadowsocks|Server: Failed to create request from: ", conn.RemoteAddr(), ": ", err) log.Info("Shadowsocks|Server: Failed to create request from: ", conn.RemoteAddr(), ": ", err)
return return err
} }
bufferedReader.SetBuffered(false) bufferedReader.SetBuffered(false)
userSettings := v.user.GetSettings() userSettings := s.user.GetSettings()
timedReader.SetTimeOut(userSettings.PayloadReadTimeout) timedReader.SetTimeOut(userSettings.PayloadReadTimeout)
dest := request.Destination() dest := request.Destination()
log.Access(conn.RemoteAddr(), dest, log.AccessAccepted, "") log.Access(conn.RemoteAddr(), dest, log.AccessAccepted, "")
log.Info("Shadowsocks|Server: Tunnelling request to ", dest) log.Info("Shadowsocks|Server: Tunnelling request to ", dest)
ray := v.packetDispatcher.DispatchToOutbound(&proxy.SessionInfo{ ctx = proxy.ContextWithDestination(ctx, dest)
Source: net.DestinationFromAddr(conn.RemoteAddr()), ctx = protocol.ContextWithUser(ctx, request.User)
Destination: dest, ray := s.packetDispatcher.DispatchToOutbound(ctx)
User: request.User,
Inbound: v.meta,
})
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
bufferedWriter := bufio.NewWriter(conn) bufferedWriter := bufio.NewWriter(conn)
@ -234,7 +199,10 @@ func (v *Server) handleConnection(conn internet.Connection) {
log.Info("Shadowsocks|Server: Connection ends with ", err) log.Info("Shadowsocks|Server: Connection ends with ", err)
ray.InboundInput().CloseError() ray.InboundInput().CloseError()
ray.InboundOutput().CloseError() ray.InboundOutput().CloseError()
return err
} }
return nil
} }
func init() { func init() {

View File

@ -2,7 +2,6 @@ package socks
import ( import (
"context" "context"
"errors"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
@ -18,34 +17,31 @@ import (
type Client struct { type Client struct {
serverPicker protocol.ServerPicker serverPicker protocol.ServerPicker
meta *proxy.OutboundHandlerMeta
} }
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) { func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
meta := proxy.OutboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("Socks|Client: No outbound meta in context.")
}
serverList := protocol.NewServerList() serverList := protocol.NewServerList()
for _, rec := range config.Server { for _, rec := range config.Server {
serverList.AddServer(protocol.NewServerSpecFromPB(*rec)) serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
} }
client := &Client{ client := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList), serverPicker: protocol.NewRoundRobinServerPicker(serverList),
meta: meta,
} }
return client, nil return client, nil
} }
func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) { func (c *Client) Process(ctx context.Context, ray ray.OutboundRay) error {
destination := proxy.DestinationFromContext(ctx)
var server *protocol.ServerSpec var server *protocol.ServerSpec
var conn internet.Connection var conn internet.Connection
dialer := proxy.DialerFromContext(ctx)
err := retry.ExponentialBackoff(5, 100).On(func() error { err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer() server = c.serverPicker.PickServer()
dest := server.Destination() dest := server.Destination()
rawConn, err := internet.Dial(c.meta.Address, dest, c.meta.GetDialerOptions()) rawConn, err := dialer.Dial(ctx, dest)
if err != nil { if err != nil {
return err return err
} }
@ -56,7 +52,7 @@ func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
if err != nil { if err != nil {
log.Warning("Socks|Client: Failed to find an available destination.") log.Warning("Socks|Client: Failed to find an available destination.")
return return err
} }
defer conn.Close() defer conn.Close()
@ -80,7 +76,7 @@ func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
udpRequest, err := ClientHandshake(request, conn, conn) udpRequest, err := ClientHandshake(request, conn, conn)
if err != nil { if err != nil {
log.Warning("Socks|Client: Failed to establish connection to server: ", err) log.Warning("Socks|Client: Failed to establish connection to server: ", err)
return return err
} }
var requestFunc func() error var requestFunc func() error
@ -94,10 +90,10 @@ func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
return buf.PipeUntilEOF(buf.NewReader(conn), ray.OutboundOutput()) return buf.PipeUntilEOF(buf.NewReader(conn), ray.OutboundOutput())
} }
} else if request.Command == protocol.RequestCommandUDP { } else if request.Command == protocol.RequestCommandUDP {
udpConn, err := internet.Dial(c.meta.Address, udpRequest.Destination(), c.meta.GetDialerOptions()) udpConn, err := dialer.Dial(ctx, udpRequest.Destination())
if err != nil { if err != nil {
log.Info("Socks|Client: Failed to create UDP connection: ", err) log.Info("Socks|Client: Failed to create UDP connection: ", err)
return return err
} }
defer udpConn.Close() defer udpConn.Close()
requestFunc = func() error { requestFunc = func() error {
@ -116,7 +112,10 @@ func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
log.Info("Socks|Client: Connection ends with ", err) log.Info("Socks|Client: Connection ends with ", err)
ray.OutboundInput().CloseError() ray.OutboundInput().CloseError()
ray.OutboundOutput().CloseError() ray.OutboundOutput().CloseError()
return err
} }
return nil
} }
func init() { func init() {

View File

@ -8,7 +8,6 @@ import (
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
"v2ray.com/core/proxy"
) )
const ( const (
@ -37,7 +36,7 @@ const (
type ServerSession struct { type ServerSession struct {
config *ServerConfig config *ServerConfig
meta *proxy.InboundHandlerMeta port v2net.Port
} }
func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) { func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
@ -178,7 +177,7 @@ func (s *ServerSession) Handshake(reader io.Reader, writer io.Writer) (*protocol
addr = v2net.LocalHostIP addr = v2net.LocalHostIP
} }
responseAddress = addr responseAddress = addr
responsePort = s.meta.Port responsePort = s.port
} }
if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil { if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {
return nil, err return nil, err

View File

@ -3,7 +3,6 @@ package socks
import ( import (
"context" "context"
"io" "io"
"sync"
"time" "time"
"v2ray.com/core/app" "v2ray.com/core/app"
@ -23,16 +22,9 @@ import (
// Server is a SOCKS 5 proxy server // Server is a SOCKS 5 proxy server
type Server struct { type Server struct {
tcpMutex sync.RWMutex
udpMutex sync.RWMutex
accepting bool
packetDispatcher dispatcher.Interface packetDispatcher dispatcher.Interface
config *ServerConfig config *ServerConfig
tcpListener *internet.TCPHub
udpHub *udp.Hub
udpAddress net.Destination
udpServer *udp.Server udpServer *udp.Server
meta *proxy.InboundHandlerMeta
} }
// NewServer creates a new Server object. // NewServer creates a new Server object.
@ -41,135 +33,89 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if space == nil { if space == nil {
return nil, errors.New("Socks|Server: No space in context.") return nil, errors.New("Socks|Server: No space in context.")
} }
meta := proxy.InboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("Socks|Server: No inbound meta in context.")
}
s := &Server{ s := &Server{
config: config, config: config,
meta: meta,
} }
space.OnInitialize(func() error { space.OnInitialize(func() error {
s.packetDispatcher = dispatcher.FromSpace(space) s.packetDispatcher = dispatcher.FromSpace(space)
if s.packetDispatcher == nil { if s.packetDispatcher == nil {
return errors.New("Socks|Server: Dispatcher is not found in the space.") return errors.New("Socks|Server: Dispatcher is not found in the space.")
} }
s.udpServer = udp.NewServer(s.packetDispatcher)
return nil return nil
}) })
return s, nil return s, nil
} }
func (v *Server) Network() net.NetworkList { func (s *Server) Network() net.NetworkList {
list := net.NetworkList{ list := net.NetworkList{
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
} }
if v.config.UdpEnabled { if s.config.UdpEnabled {
list.Network = append(list.Network, net.Network_UDP) list.Network = append(list.Network, net.Network_UDP)
} }
return list return list
} }
// Port implements InboundHandler.Port(). func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection) error {
func (v *Server) Port() net.Port { switch network {
return v.meta.Port case net.Network_TCP:
} return s.processTCP(ctx, conn)
case net.Network_UDP:
// Close implements InboundHandler.Close(). return s.handleUDPPayload(ctx, conn)
func (v *Server) Close() { default:
v.accepting = false return errors.New("Socks|Server: Unknown network: ", network)
if v.tcpListener != nil {
v.tcpMutex.Lock()
v.tcpListener.Close()
v.tcpListener = nil
v.tcpMutex.Unlock()
}
if v.udpHub != nil {
v.udpMutex.Lock()
v.udpHub.Close()
v.udpHub = nil
v.udpMutex.Unlock()
} }
} }
// Start implements InboundHandler.Start(). func (s *Server) processTCP(ctx context.Context, conn internet.Connection) error {
func (v *Server) Start() error { conn.SetReusable(false)
if v.accepting {
return nil
}
listener, err := internet.ListenTCP( timedReader := net.NewTimeOutReader(16 /* seconds, for handshake */, conn)
v.meta.Address,
v.meta.Port,
v.handleConnection,
v.meta.StreamSettings)
if err != nil {
log.Error("Socks: failed to listen on ", v.meta.Address, ":", v.meta.Port, ": ", err)
return err
}
v.accepting = true
v.tcpMutex.Lock()
v.tcpListener = listener
v.tcpMutex.Unlock()
if v.config.UdpEnabled {
if err := v.listenUDP(); err != nil {
return err
}
}
return nil
}
func (v *Server) handleConnection(connection internet.Connection) {
defer connection.Close()
connection.SetReusable(false)
timedReader := net.NewTimeOutReader(16 /* seconds, for handshake */, connection)
reader := bufio.NewReader(timedReader) reader := bufio.NewReader(timedReader)
inboundDest := proxy.InboundDestinationFromContext(ctx)
session := &ServerSession{ session := &ServerSession{
config: v.config, config: s.config,
meta: v.meta, port: inboundDest.Port,
} }
clientAddr := net.DestinationFromAddr(connection.RemoteAddr()) source := proxy.SourceFromContext(ctx)
request, err := session.Handshake(reader, conn)
request, err := session.Handshake(reader, connection)
if err != nil { if err != nil {
log.Access(clientAddr, "", log.AccessRejected, err) log.Access(source, "", log.AccessRejected, err)
log.Info("Socks|Server: Failed to read request: ", err) log.Info("Socks|Server: Failed to read request: ", err)
return return err
} }
if request.Command == protocol.RequestCommandTCP { if request.Command == protocol.RequestCommandTCP {
dest := request.Destination() dest := request.Destination()
session := &proxy.SessionInfo{
Source: clientAddr,
Destination: dest,
Inbound: v.meta,
}
log.Info("Socks|Server: TCP Connect request to ", dest) log.Info("Socks|Server: TCP Connect request to ", dest)
log.Access(clientAddr, dest, log.AccessAccepted, "") log.Access(source, dest, log.AccessAccepted, "")
timedReader.SetTimeOut(v.config.Timeout) timedReader.SetTimeOut(s.config.Timeout)
v.transport(reader, connection, session) ctx = proxy.ContextWithDestination(ctx, dest)
return return s.transport(ctx, reader, conn)
} }
if request.Command == protocol.RequestCommandUDP { if request.Command == protocol.RequestCommandUDP {
v.handleUDP() return s.handleUDP()
return
} }
return nil
} }
func (v *Server) handleUDP() { func (*Server) handleUDP() error {
// The TCP connection closes after v method returns. We need to wait until // The TCP connection closes after v method returns. We need to wait until
// the client closes it. // the client closes it.
// TODO: get notified from UDP part // TODO: get notified from UDP part
<-time.After(5 * time.Minute) <-time.After(5 * time.Minute)
return nil
} }
func (v *Server) transport(reader io.Reader, writer io.Writer, session *proxy.SessionInfo) { func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer) error {
ray := v.packetDispatcher.DispatchToOutbound(session) ray := v.packetDispatcher.DispatchToOutbound(ctx)
input := ray.InboundInput() input := ray.InboundInput()
output := ray.InboundOutput() output := ray.InboundOutput()
@ -198,6 +144,48 @@ func (v *Server) transport(reader io.Reader, writer io.Writer, session *proxy.Se
log.Info("Socks|Server: Connection ends with ", err) log.Info("Socks|Server: Connection ends with ", err)
input.CloseError() input.CloseError()
output.CloseError() output.CloseError()
return err
}
return nil
}
func (v *Server) handleUDPPayload(ctx context.Context, conn internet.Connection) error {
source := proxy.SourceFromContext(ctx)
log.Info("Socks|Server: Client UDP connection from ", source)
reader := buf.NewReader(conn)
for {
payload, err := reader.Read()
if err != nil {
return err
}
request, data, err := DecodeUDPPacket(payload.Bytes())
if err != nil {
log.Info("Socks|Server: Failed to parse UDP request: ", err)
continue
}
if len(data) == 0 {
continue
}
log.Info("Socks: Send packet to ", request.Destination(), " with ", len(data), " bytes")
log.Access(source, request.Destination, log.AccessAccepted, "")
dataBuf := buf.NewSmall()
dataBuf.Append(data)
v.udpServer.Dispatch(ctx, request.Destination(), dataBuf, func(payload *buf.Buffer) {
defer payload.Release()
log.Info("Socks|Server: Writing back UDP response with ", payload.Len(), " bytes")
udpMessage := EncodeUDPPacket(request, payload.Bytes())
defer udpMessage.Release()
conn.Write(udpMessage.Bytes())
})
} }
} }

View File

@ -1,66 +0,0 @@
package socks
import (
"v2ray.com/core/common/buf"
"v2ray.com/core/common/log"
"v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet/udp"
)
func (v *Server) listenUDP() error {
v.udpServer = udp.NewServer(v.packetDispatcher)
udpHub, err := udp.ListenUDP(v.meta.Address, v.meta.Port, udp.ListenOption{Callback: v.handleUDPPayload})
if err != nil {
log.Error("Socks: Failed to listen on udp (", v.meta.Address, ":", v.meta.Port, "): ", err)
return err
}
v.udpMutex.Lock()
v.udpAddress = net.UDPDestination(v.config.GetNetAddress(), v.meta.Port)
v.udpHub = udpHub
v.udpMutex.Unlock()
return nil
}
func (v *Server) handleUDPPayload(payload *buf.Buffer, session *proxy.SessionInfo) {
defer payload.Release()
source := session.Source
log.Info("Socks: Client UDP connection from ", source)
request, data, err := DecodeUDPPacket(payload.Bytes())
if err != nil {
log.Error("Socks|Server: Failed to parse UDP request: ", err)
return
}
if len(data) == 0 {
return
}
log.Info("Socks: Send packet to ", request.Destination(), " with ", len(data), " bytes")
log.Access(source, request.Destination, log.AccessAccepted, "")
dataBuf := buf.NewSmall()
dataBuf.Append(data)
v.udpServer.Dispatch(&proxy.SessionInfo{Source: source, Destination: request.Destination(), Inbound: v.meta}, dataBuf, func(destination net.Destination, payload *buf.Buffer) {
defer payload.Release()
log.Info("Socks: Writing back UDP response with ", payload.Len(), " bytes to ", destination)
udpMessage := EncodeUDPPacket(request, payload.Bytes())
defer udpMessage.Release()
v.udpMutex.RLock()
if !v.accepting {
v.udpMutex.RUnlock()
return
}
nBytes, err := v.udpHub.WriteTo(udpMessage.Bytes(), destination)
v.udpMutex.RUnlock()
if err != nil {
log.Warning("Socks: failed to write UDP message (", nBytes, " bytes) to ", destination, ": ", err)
}
})
}

View File

@ -1,38 +0,0 @@
package inbound
import (
"v2ray.com/core/common/log"
"v2ray.com/core/common/protocol"
"v2ray.com/core/proxy/vmess"
)
func (v *VMessInboundHandler) generateCommand(request *protocol.RequestHeader) protocol.ResponseCommand {
if v.detours != nil {
tag := v.detours.To
if v.inboundHandlerManager != nil {
handler, availableMin := v.inboundHandlerManager.GetHandler(tag)
inboundHandler, ok := handler.(*VMessInboundHandler)
if ok {
if availableMin > 255 {
availableMin = 255
}
log.Info("VMessIn: Pick detour handler for port ", inboundHandler.Port(), " for ", availableMin, " minutes.")
user := inboundHandler.GetUser(request.User.Email)
if user == nil {
return nil
}
account, _ := user.GetTypedAccount()
return &protocol.CommandSwitchAccount{
Port: inboundHandler.Port(),
ID: account.(*vmess.InternalAccount).ID.UUID(),
AlterIds: uint16(len(account.(*vmess.InternalAccount).AlterIDs)),
Level: user.Level,
ValidMin: byte(availableMin),
}
}
}
}
return nil
}

View File

@ -77,10 +77,7 @@ type VMessInboundHandler struct {
inboundHandlerManager proxyman.InboundHandlerManager inboundHandlerManager proxyman.InboundHandlerManager
clients protocol.UserValidator clients protocol.UserValidator
usersByEmail *userByEmail usersByEmail *userByEmail
accepting bool
listener *internet.TCPHub
detours *DetourConfig detours *DetourConfig
meta *proxy.InboundHandlerMeta
} }
func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) { func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) {
@ -88,10 +85,6 @@ func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) {
if space == nil { if space == nil {
return nil, errors.New("VMess|Inbound: No space in context.") return nil, errors.New("VMess|Inbound: No space in context.")
} }
meta := proxy.InboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("VMess|Inbound: No inbound meta in context.")
}
allowedClients := vmess.NewTimedUserValidator(protocol.DefaultIDHash) allowedClients := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
for _, user := range config.User { for _, user := range config.User {
@ -102,7 +95,6 @@ func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) {
clients: allowedClients, clients: allowedClients,
detours: config.Detour, detours: config.Detour,
usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()), usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()),
meta: meta,
} }
space.OnInitialize(func() error { space.OnInitialize(func() error {
@ -120,36 +112,16 @@ func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) {
return handler, nil return handler, nil
} }
func (v *VMessInboundHandler) Network() net.NetworkList { func (*VMessInboundHandler) Network() net.NetworkList {
return net.NetworkList{ return net.NetworkList{
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
} }
} }
func (v *VMessInboundHandler) Port() net.Port {
return v.meta.Port
}
func (v *VMessInboundHandler) Close() {
v.Lock()
v.accepting = false
if v.listener != nil {
v.listener.Close()
v.listener = nil
v.clients.Release()
v.clients = nil
}
v.Unlock()
}
func (v *VMessInboundHandler) GetUser(email string) *protocol.User { func (v *VMessInboundHandler) GetUser(email string) *protocol.User {
v.RLock() v.RLock()
defer v.RUnlock() defer v.RUnlock()
if !v.accepting {
return nil
}
user, existing := v.usersByEmail.Get(email) user, existing := v.usersByEmail.Get(email)
if !existing { if !existing {
v.clients.Add(user) v.clients.Add(user)
@ -157,23 +129,6 @@ func (v *VMessInboundHandler) GetUser(email string) *protocol.User {
return user return user
} }
func (v *VMessInboundHandler) Start() error {
if v.accepting {
return nil
}
tcpListener, err := internet.ListenTCP(v.meta.Address, v.meta.Port, v.HandleConnection, v.meta.StreamSettings)
if err != nil {
log.Error("VMess|Inbound: Unable to listen tcp ", v.meta.Address, ":", v.meta.Port, ": ", err)
return err
}
v.accepting = true
v.Lock()
v.listener = tcpListener
v.Unlock()
return nil
}
func transferRequest(session *encoding.ServerSession, request *protocol.RequestHeader, input io.Reader, output ray.OutputStream) error { func transferRequest(session *encoding.ServerSession, request *protocol.RequestHeader, input io.Reader, output ray.OutputStream) error {
defer output.Close() defer output.Close()
@ -219,23 +174,12 @@ func transferResponse(session *encoding.ServerSession, request *protocol.Request
return nil return nil
} }
func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) { func (v *VMessInboundHandler) Process(ctx context.Context, network net.Network, connection internet.Connection) error {
defer connection.Close()
if !v.accepting {
return
}
connReader := net.NewTimeOutReader(8, connection) connReader := net.NewTimeOutReader(8, connection)
reader := bufio.NewReader(connReader) reader := bufio.NewReader(connReader)
v.RLock()
if !v.accepting {
v.RUnlock()
return
}
session := encoding.NewServerSession(v.clients) session := encoding.NewServerSession(v.clients)
request, err := session.DecodeRequestHeader(reader) request, err := session.DecodeRequestHeader(reader)
v.RUnlock()
if err != nil { if err != nil {
if errors.Cause(err) != io.EOF { if errors.Cause(err) != io.EOF {
@ -243,19 +187,17 @@ func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) {
log.Info("VMess|Inbound: Invalid request from ", connection.RemoteAddr(), ": ", err) log.Info("VMess|Inbound: Invalid request from ", connection.RemoteAddr(), ": ", err)
} }
connection.SetReusable(false) connection.SetReusable(false)
return return err
} }
log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, "") log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, "")
log.Info("VMess|Inbound: Received request for ", request.Destination()) log.Info("VMess|Inbound: Received request for ", request.Destination())
connection.SetReusable(request.Option.Has(protocol.RequestOptionConnectionReuse)) connection.SetReusable(request.Option.Has(protocol.RequestOptionConnectionReuse))
ray := v.packetDispatcher.DispatchToOutbound(&proxy.SessionInfo{ ctx = proxy.ContextWithDestination(ctx, request.Destination())
Source: net.DestinationFromAddr(connection.RemoteAddr()), ctx = protocol.ContextWithUser(ctx, request.User)
Destination: request.Destination(), ray := v.packetDispatcher.DispatchToOutbound(ctx)
User: request.User,
Inbound: v.meta,
})
input := ray.InboundInput() input := ray.InboundInput()
output := ray.InboundOutput() output := ray.InboundOutput()
@ -269,7 +211,7 @@ func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) {
writer := bufio.NewWriter(connection) writer := bufio.NewWriter(connection)
response := &protocol.ResponseHeader{ response := &protocol.ResponseHeader{
Command: v.generateCommand(request), Command: v.generateCommand(ctx, request),
} }
if connection.Reusable() { if connection.Reusable() {
@ -285,14 +227,52 @@ func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) {
connection.SetReusable(false) connection.SetReusable(false)
input.CloseError() input.CloseError()
output.CloseError() output.CloseError()
return return err
} }
if err := writer.Flush(); err != nil { if err := writer.Flush(); err != nil {
log.Info("VMess|Inbound: Failed to flush remain data: ", err) log.Info("VMess|Inbound: Failed to flush remain data: ", err)
connection.SetReusable(false) connection.SetReusable(false)
return return err
} }
return nil
}
func (v *VMessInboundHandler) generateCommand(ctx context.Context, request *protocol.RequestHeader) protocol.ResponseCommand {
if v.detours != nil {
tag := v.detours.To
if v.inboundHandlerManager != nil {
handler, err := v.inboundHandlerManager.GetHandler(ctx, tag)
if err != nil {
log.Warning("VMess|Inbound: Failed to get detour handler: ", tag, err)
return nil
}
proxyHandler, port, availableMin := handler.GetRandomInboundProxy()
inboundHandler, ok := proxyHandler.(*VMessInboundHandler)
if ok {
if availableMin > 255 {
availableMin = 255
}
log.Info("VMessIn: Pick detour handler for port ", port, " for ", availableMin, " minutes.")
user := inboundHandler.GetUser(request.User.Email)
if user == nil {
return nil
}
account, _ := user.GetTypedAccount()
return &protocol.CommandSwitchAccount{
Port: port,
ID: account.(*vmess.InternalAccount).ID.UUID(),
AlterIds: uint16(len(account.(*vmess.InternalAccount).AlterIDs)),
Level: user.Level,
ValidMin: byte(availableMin),
}
}
}
}
return nil
} }
func init() { func init() {

View File

@ -25,7 +25,6 @@ import (
type VMessOutboundHandler struct { type VMessOutboundHandler struct {
serverList *protocol.ServerList serverList *protocol.ServerList
serverPicker protocol.ServerPicker serverPicker protocol.ServerPicker
meta *proxy.OutboundHandlerMeta
} }
func New(ctx context.Context, config *Config) (*VMessOutboundHandler, error) { func New(ctx context.Context, config *Config) (*VMessOutboundHandler, error) {
@ -33,10 +32,6 @@ func New(ctx context.Context, config *Config) (*VMessOutboundHandler, error) {
if space == nil { if space == nil {
return nil, errors.New("VMess|Outbound: No space in context.") return nil, errors.New("VMess|Outbound: No space in context.")
} }
meta := proxy.OutboundMetaFromContext(ctx)
if meta == nil {
return nil, errors.New("VMess|Outbound: No outbound meta in context.")
}
serverList := protocol.NewServerList() serverList := protocol.NewServerList()
for _, rec := range config.Receiver { for _, rec := range config.Receiver {
@ -45,20 +40,20 @@ func New(ctx context.Context, config *Config) (*VMessOutboundHandler, error) {
handler := &VMessOutboundHandler{ handler := &VMessOutboundHandler{
serverList: serverList, serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList), serverPicker: protocol.NewRoundRobinServerPicker(serverList),
meta: meta,
} }
return handler, nil return handler, nil
} }
// Dispatch implements OutboundHandler.Dispatch(). // Dispatch implements OutboundHandler.Dispatch().
func (v *VMessOutboundHandler) Dispatch(target net.Destination, outboundRay ray.OutboundRay) { func (v *VMessOutboundHandler) Process(ctx context.Context, outboundRay ray.OutboundRay) error {
var rec *protocol.ServerSpec var rec *protocol.ServerSpec
var conn internet.Connection var conn internet.Connection
dialer := proxy.DialerFromContext(ctx)
err := retry.ExponentialBackoff(5, 100).On(func() error { err := retry.ExponentialBackoff(5, 100).On(func() error {
rec = v.serverPicker.PickServer() rec = v.serverPicker.PickServer()
rawConn, err := internet.Dial(v.meta.Address, rec.Destination(), v.meta.GetDialerOptions()) rawConn, err := dialer.Dial(ctx, rec.Destination())
if err != nil { if err != nil {
return err return err
} }
@ -68,8 +63,11 @@ func (v *VMessOutboundHandler) Dispatch(target net.Destination, outboundRay ray.
}) })
if err != nil { if err != nil {
log.Warning("VMess|Outbound: Failed to find an available destination:", err) log.Warning("VMess|Outbound: Failed to find an available destination:", err)
return return err
} }
defer conn.Close()
target := proxy.DestinationFromContext(ctx)
log.Info("VMess|Outbound: Tunneling request to ", target, " via ", rec.Destination()) log.Info("VMess|Outbound: Tunneling request to ", target, " via ", rec.Destination())
command := protocol.RequestCommandTCP command := protocol.RequestCommandTCP
@ -88,12 +86,11 @@ func (v *VMessOutboundHandler) Dispatch(target net.Destination, outboundRay ray.
rawAccount, err := request.User.GetTypedAccount() rawAccount, err := request.User.GetTypedAccount()
if err != nil { if err != nil {
log.Warning("VMess|Outbound: Failed to get user account: ", err) log.Warning("VMess|Outbound: Failed to get user account: ", err)
return err
} }
account := rawAccount.(*vmess.InternalAccount) account := rawAccount.(*vmess.InternalAccount)
request.Security = account.Security request.Security = account.Security
defer conn.Close()
conn.SetReusable(true) conn.SetReusable(true)
if conn.Reusable() { // Conn reuse may be disabled on transportation layer if conn.Reusable() { // Conn reuse may be disabled on transportation layer
request.Option.Set(protocol.RequestOptionConnectionReuse) request.Option.Set(protocol.RequestOptionConnectionReuse)
@ -160,9 +157,10 @@ func (v *VMessOutboundHandler) Dispatch(target net.Destination, outboundRay ray.
conn.SetReusable(false) conn.SetReusable(false)
input.CloseError() input.CloseError()
output.CloseError() output.CloseError()
return err
} }
return return nil
} }
func init() { func init() {

View File

@ -5,6 +5,7 @@ import (
"testing" "testing"
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
@ -32,11 +33,13 @@ func TestDokodemoTCP(t *testing.T) {
userID := protocol.NewID(uuid.New()) userID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -47,9 +50,9 @@ func TestDokodemoTCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
@ -57,11 +60,13 @@ func TestDokodemoTCP(t *testing.T) {
clientPort := uint32(pickPort()) clientPort := uint32(pickPort())
clientPortRange := uint32(5) clientPortRange := uint32(5)
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange}, ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange},
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -70,9 +75,9 @@ func TestDokodemoTCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -129,11 +134,13 @@ func TestDokodemoUDP(t *testing.T) {
userID := protocol.NewID(uuid.New()) userID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -144,9 +151,9 @@ func TestDokodemoUDP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
@ -154,11 +161,13 @@ func TestDokodemoUDP(t *testing.T) {
clientPort := uint32(pickPort()) clientPort := uint32(pickPort())
clientPortRange := uint32(5) clientPortRange := uint32(5)
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange}, ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange},
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -167,9 +176,9 @@ func TestDokodemoUDP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),

View File

@ -5,6 +5,7 @@ import (
"testing" "testing"
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/router" "v2ray.com/core/app/router"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
@ -34,12 +35,14 @@ func TestPassiveConnection(t *testing.T) {
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
AllowPassiveConnection: true, Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{ AllowPassiveConnection: true,
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -48,9 +51,9 @@ func TestPassiveConnection(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
@ -103,11 +106,13 @@ func TestProxy(t *testing.T) {
serverUserID := protocol.NewID(uuid.New()) serverUserID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -118,9 +123,9 @@ func TestProxy(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
@ -128,11 +133,13 @@ func TestProxy(t *testing.T) {
proxyUserID := protocol.NewID(uuid.New()) proxyUserID := protocol.NewID(uuid.New())
proxyPort := pickPort() proxyPort := pickPort()
proxyConfig := &core.Config{ proxyConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(proxyPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(proxyPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -143,20 +150,22 @@ func TestProxy(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
clientPort := pickPort() clientPort := pickPort()
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(clientPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(clientPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -165,9 +174,9 @@ func TestProxy(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -182,13 +191,15 @@ func TestProxy(t *testing.T) {
}, },
}, },
}), }),
ProxySettings: &internet.ProxyConfig{ SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
Tag: "proxy", ProxySettings: &internet.ProxyConfig{
}, Tag: "proxy",
},
}),
}, },
{ {
Tag: "proxy", Tag: "proxy",
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -244,11 +255,16 @@ func TestProxyOverKCP(t *testing.T) {
serverUserID := protocol.NewID(uuid.New()) serverUserID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -257,14 +273,11 @@ func TestProxyOverKCP(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
},
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
@ -272,11 +285,13 @@ func TestProxyOverKCP(t *testing.T) {
proxyUserID := protocol.NewID(uuid.New()) proxyUserID := protocol.NewID(uuid.New())
proxyPort := pickPort() proxyPort := pickPort()
proxyConfig := &core.Config{ proxyConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(proxyPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(proxyPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -287,23 +302,27 @@ func TestProxyOverKCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
StreamSettings: &internet.StreamConfig{ SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
Protocol: internet.TransportProtocol_MKCP, StreamSettings: &internet.StreamConfig{
}, Protocol: internet.TransportProtocol_MKCP,
},
}),
}, },
}, },
} }
clientPort := pickPort() clientPort := pickPort()
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(clientPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(clientPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -312,9 +331,9 @@ func TestProxyOverKCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -329,16 +348,18 @@ func TestProxyOverKCP(t *testing.T) {
}, },
}, },
}), }),
ProxySettings: &internet.ProxyConfig{ SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
Tag: "proxy", ProxySettings: &internet.ProxyConfig{
}, Tag: "proxy",
StreamSettings: &internet.StreamConfig{ },
Protocol: internet.TransportProtocol_MKCP, StreamSettings: &internet.StreamConfig{
}, Protocol: internet.TransportProtocol_MKCP,
},
}),
}, },
{ {
Tag: "proxy", Tag: "proxy",
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -401,11 +422,13 @@ func TestBlackhole(t *testing.T) {
serverPort := pickPort() serverPort := pickPort()
serverPort2 := pickPort() serverPort2 := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -414,9 +437,11 @@ func TestBlackhole(t *testing.T) {
}), }),
}, },
{ {
PortRange: v2net.SinglePortRange(serverPort2), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort2),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest2.Address), Address: v2net.NewIPOrDomain(dest2.Address),
Port: uint32(dest2.Port), Port: uint32(dest2.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -425,14 +450,14 @@ func TestBlackhole(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Tag: "direct", Tag: "direct",
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
{ {
Tag: "blocked", Tag: "blocked",
Settings: serial.ToTypedMessage(&blackhole.Config{}), ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
}, },
}, },
App: []*serial.TypedMessage{ App: []*serial.TypedMessage{

View File

@ -7,6 +7,7 @@ import (
xproxy "golang.org/x/net/proxy" xproxy "golang.org/x/net/proxy"
socks4 "h12.me/socks" socks4 "h12.me/socks"
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
@ -30,11 +31,13 @@ func TestSocksBridgeTCP(t *testing.T) {
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&socks.ServerConfig{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_PASSWORD, AuthType: socks.AuthType_PASSWORD,
Accounts: map[string]string{ Accounts: map[string]string{
"Test Account": "Test Password", "Test Account": "Test Password",
@ -44,20 +47,22 @@ func TestSocksBridgeTCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
clientPort := pickPort() clientPort := pickPort()
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(clientPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(clientPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -66,9 +71,9 @@ func TestSocksBridgeTCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&socks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -123,11 +128,13 @@ func TestSocksBridageUDP(t *testing.T) {
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&socks.ServerConfig{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_PASSWORD, AuthType: socks.AuthType_PASSWORD,
Accounts: map[string]string{ Accounts: map[string]string{
"Test Account": "Test Password", "Test Account": "Test Password",
@ -137,20 +144,22 @@ func TestSocksBridageUDP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
clientPort := pickPort() clientPort := pickPort()
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(clientPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(clientPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -159,9 +168,9 @@ func TestSocksBridageUDP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&socks.ClientConfig{ ProxySettings: serial.ToTypedMessage(&socks.ClientConfig{
Server: []*protocol.ServerEndpoint{ Server: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -217,11 +226,13 @@ func TestSocksConformance(t *testing.T) {
authPort := pickPort() authPort := pickPort()
noAuthPort := pickPort() noAuthPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(authPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(authPort),
Settings: serial.ToTypedMessage(&socks.ServerConfig{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_PASSWORD, AuthType: socks.AuthType_PASSWORD,
Accounts: map[string]string{ Accounts: map[string]string{
"Test Account": "Test Password", "Test Account": "Test Password",
@ -231,9 +242,11 @@ func TestSocksConformance(t *testing.T) {
}), }),
}, },
{ {
PortRange: v2net.SinglePortRange(noAuthPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(noAuthPort),
Settings: serial.ToTypedMessage(&socks.ServerConfig{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_NO_AUTH, AuthType: socks.AuthType_NO_AUTH,
Accounts: map[string]string{ Accounts: map[string]string{
"Test Account": "Test Password", "Test Account": "Test Password",
@ -243,9 +256,9 @@ func TestSocksConformance(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
@ -35,11 +36,21 @@ func TestSimpleTLSConnection(t *testing.T) {
userID := protocol.NewID(uuid.New()) userID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
Certificate: []*tls.Certificate{tlsgen.GenerateCertificateForTest()},
}),
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -48,30 +59,24 @@ func TestSimpleTLSConnection(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
Certificate: []*tls.Certificate{tlsgen.GenerateCertificateForTest()},
}),
},
},
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
clientPort := pickPort() clientPort := pickPort()
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(clientPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(clientPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -80,9 +85,9 @@ func TestSimpleTLSConnection(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -97,14 +102,16 @@ func TestSimpleTLSConnection(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{ SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
SecurityType: serial.GetMessageType(&tls.Config{}), StreamSettings: &internet.StreamConfig{
SecuritySettings: []*serial.TypedMessage{ SecurityType: serial.GetMessageType(&tls.Config{}),
serial.ToTypedMessage(&tls.Config{ SecuritySettings: []*serial.TypedMessage{
AllowInsecure: true, serial.ToTypedMessage(&tls.Config{
}), AllowInsecure: true,
}),
},
}, },
}, }),
}, },
}, },
} }
@ -143,11 +150,22 @@ func TestTLSOverKCP(t *testing.T) {
userID := protocol.NewID(uuid.New()) userID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
Certificate: []*tls.Certificate{tlsgen.GenerateCertificateForTest()},
}),
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -156,31 +174,24 @@ func TestTLSOverKCP(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
Certificate: []*tls.Certificate{tlsgen.GenerateCertificateForTest()},
}),
},
},
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
clientPort := pickPort() clientPort := pickPort()
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(clientPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(clientPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -189,9 +200,9 @@ func TestTLSOverKCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -206,15 +217,17 @@ func TestTLSOverKCP(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{ SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
Protocol: internet.TransportProtocol_MKCP, StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}), Protocol: internet.TransportProtocol_MKCP,
SecuritySettings: []*serial.TypedMessage{ SecurityType: serial.GetMessageType(&tls.Config{}),
serial.ToTypedMessage(&tls.Config{ SecuritySettings: []*serial.TypedMessage{
AllowInsecure: true, serial.ToTypedMessage(&tls.Config{
}), AllowInsecure: true,
}),
},
}, },
}, }),
}, },
}, },
} }
@ -253,11 +266,21 @@ func TestTLSConnectionReuse(t *testing.T) {
userID := protocol.NewID(uuid.New()) userID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
Certificate: []*tls.Certificate{tlsgen.GenerateCertificateForTest()},
}),
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -266,30 +289,24 @@ func TestTLSConnectionReuse(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
Certificate: []*tls.Certificate{tlsgen.GenerateCertificateForTest()},
}),
},
},
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
clientPort := pickPort() clientPort := pickPort()
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(clientPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(clientPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -298,9 +315,9 @@ func TestTLSConnectionReuse(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -315,14 +332,16 @@ func TestTLSConnectionReuse(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{ SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
SecurityType: serial.GetMessageType(&tls.Config{}), StreamSettings: &internet.StreamConfig{
SecuritySettings: []*serial.TypedMessage{ SecurityType: serial.GetMessageType(&tls.Config{}),
serial.ToTypedMessage(&tls.Config{ SecuritySettings: []*serial.TypedMessage{
AllowInsecure: true, serial.ToTypedMessage(&tls.Config{
}), AllowInsecure: true,
}),
},
}, },
}, }),
}, },
}, },
} }

View File

@ -6,6 +6,7 @@ import (
"time" "time"
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
@ -35,11 +36,23 @@ func TestNoOpConnectionHeader(t *testing.T) {
userID := protocol.NewID(uuid.New()) userID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(serverPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(serverPort),
Settings: serial.ToTypedMessage(&inbound.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
TransportSettings: []*internet.TransportConfig{
{
Protocol: internet.TransportProtocol_TCP,
Settings: serial.ToTypedMessage(&tcptransport.Config{
HeaderSettings: serial.ToTypedMessage(&http.Config{}),
}),
},
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{ User: []*protocol.User{
{ {
Account: serial.ToTypedMessage(&vmess.Account{ Account: serial.ToTypedMessage(&vmess.Account{
@ -48,32 +61,24 @@ func TestNoOpConnectionHeader(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{
TransportSettings: []*internet.TransportConfig{
{
Protocol: internet.TransportProtocol_TCP,
Settings: serial.ToTypedMessage(&tcptransport.Config{
HeaderSettings: serial.ToTypedMessage(&http.Config{}),
}),
},
},
},
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
clientPort := pickPort() clientPort := pickPort()
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{ Inbound: []*proxyman.InboundHandlerConfig{
{ {
PortRange: v2net.SinglePortRange(clientPort), ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP), PortRange: v2net.SinglePortRange(clientPort),
Settings: serial.ToTypedMessage(&dokodemo.Config{ Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address), Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port), Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{ NetworkList: &v2net.NetworkList{
@ -82,9 +87,9 @@ func TestNoOpConnectionHeader(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*core.OutboundConnectionConfig{ Outbound: []*proxyman.OutboundHandlerConfig{
{ {
Settings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
{ {
Address: v2net.NewIPOrDomain(v2net.LocalHostIP), Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -99,16 +104,18 @@ func TestNoOpConnectionHeader(t *testing.T) {
}, },
}, },
}), }),
StreamSettings: &internet.StreamConfig{ SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
TransportSettings: []*internet.TransportConfig{ StreamSettings: &internet.StreamConfig{
{ TransportSettings: []*internet.TransportConfig{
Protocol: internet.TransportProtocol_TCP, {
Settings: serial.ToTypedMessage(&tcptransport.Config{ Protocol: internet.TransportProtocol_TCP,
HeaderSettings: serial.ToTypedMessage(&http.Config{}), Settings: serial.ToTypedMessage(&tcptransport.Config{
}), HeaderSettings: serial.ToTypedMessage(&http.Config{}),
}),
},
}, },
}, },
}, }),
}, },
}, },
} }

View File

@ -4,6 +4,8 @@ import (
"net" "net"
"testing" "testing"
"context"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/testing/assert" "v2ray.com/core/testing/assert"
@ -28,22 +30,12 @@ func TestChinaIPJson(t *testing.T) {
assert.String(rule.Tag).Equals("x") assert.String(rule.Tag).Equals("x")
cond, err := rule.BuildCondition() cond, err := rule.BuildCondition()
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("121.14.1.189"), 80)))).IsTrue() // sina.com.cn
Destination: v2net.TCPDestination(v2net.ParseAddress("121.14.1.189"), 80), assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("101.226.103.106"), 80)))).IsTrue() // qq.com
})).IsTrue() // sina.com.cn assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("115.239.210.36"), 80)))).IsTrue() // image.baidu.com
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("120.135.126.1"), 80)))).IsTrue()
Destination: v2net.TCPDestination(v2net.ParseAddress("101.226.103.106"), 80),
})).IsTrue() // qq.com
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.ParseAddress("115.239.210.36"), 80),
})).IsTrue() // image.baidu.com
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.ParseAddress("120.135.126.1"), 80),
})).IsTrue()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("8.8.8.8"), 80)))).IsFalse()
Destination: v2net.TCPDestination(v2net.ParseAddress("8.8.8.8"), 80),
})).IsFalse()
} }
func TestChinaSitesJson(t *testing.T) { func TestChinaSitesJson(t *testing.T) {
@ -56,22 +48,12 @@ func TestChinaSitesJson(t *testing.T) {
assert.String(rule.Tag).Equals("y") assert.String(rule.Tag).Equals("y")
cond, err := rule.BuildCondition() cond, err := rule.BuildCondition()
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("v.qq.com"), 80)))).IsTrue()
Destination: v2net.TCPDestination(v2net.ParseAddress("v.qq.com"), 80), assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.163.com"), 80)))).IsTrue()
})).IsTrue() assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("ngacn.cc"), 80)))).IsTrue()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("12306.cn"), 80)))).IsTrue()
Destination: v2net.TCPDestination(v2net.ParseAddress("www.163.com"), 80),
})).IsTrue()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.ParseAddress("ngacn.cc"), 80),
})).IsTrue()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.ParseAddress("12306.cn"), 80),
})).IsTrue()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("v2ray.com"), 80)))).IsFalse()
Destination: v2net.TCPDestination(v2net.ParseAddress("v2ray.com"), 80),
})).IsFalse()
} }
func TestDomainRule(t *testing.T) { func TestDomainRule(t *testing.T) {
@ -90,21 +72,11 @@ func TestDomainRule(t *testing.T) {
assert.Pointer(rule).IsNotNil() assert.Pointer(rule).IsNotNil()
cond, err := rule.BuildCondition() cond, err := rule.BuildCondition()
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.ooxx.com"), 80)))).IsTrue()
Destination: v2net.TCPDestination(v2net.ParseAddress("www.ooxx.com"), 80), assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.aabb.com"), 80)))).IsFalse()
})).IsTrue() assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.12306.cn"), 80)))).IsTrue()
Destination: v2net.TCPDestination(v2net.ParseAddress("www.aabb.com"), 80), assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.ParseAddress("www.acn.com"), 80)))).IsFalse()
})).IsFalse()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80),
})).IsFalse()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.ParseAddress("www.12306.cn"), 80),
})).IsTrue()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.ParseAddress("www.acn.com"), 80),
})).IsFalse()
} }
func TestIPRule(t *testing.T) { func TestIPRule(t *testing.T) {
@ -122,18 +94,10 @@ func TestIPRule(t *testing.T) {
assert.Pointer(rule).IsNotNil() assert.Pointer(rule).IsNotNil()
cond, err := rule.BuildCondition() cond, err := rule.BuildCondition()
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80)))).IsFalse()
Destination: v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80), assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80)))).IsTrue()
})).IsFalse() assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithDestination(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80)))).IsTrue()
Destination: v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80),
})).IsTrue()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80),
})).IsFalse()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Destination: v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80),
})).IsTrue()
} }
func TestSourceIPRule(t *testing.T) { func TestSourceIPRule(t *testing.T) {
@ -150,16 +114,8 @@ func TestSourceIPRule(t *testing.T) {
assert.Pointer(rule).IsNotNil() assert.Pointer(rule).IsNotNil()
cond, err := rule.BuildCondition() cond, err := rule.BuildCondition()
assert.Error(err).IsNil() assert.Error(err).IsNil()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80)))).IsFalse()
Source: v2net.TCPDestination(v2net.DomainAddress("www.ooxx.com"), 80), assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80)))).IsTrue()
})).IsFalse() assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80)))).IsFalse()
assert.Bool(cond.Apply(&proxy.SessionInfo{ assert.Bool(cond.Apply(proxy.ContextWithSource(context.Background(), v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80)))).IsTrue()
Source: v2net.TCPDestination(v2net.IPAddress([]byte{10, 0, 0, 1}), 80),
})).IsTrue()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Source: v2net.TCPDestination(v2net.IPAddress([]byte{127, 0, 0, 1}), 80),
})).IsFalse()
assert.Bool(cond.Apply(&proxy.SessionInfo{
Source: v2net.TCPDestination(v2net.IPAddress([]byte{192, 0, 0, 1}), 80),
})).IsTrue()
} }

View File

@ -6,6 +6,7 @@ import (
"strings" "strings"
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
@ -40,40 +41,45 @@ type InboundConnectionConfig struct {
Tag string `json:"tag"` Tag string `json:"tag"`
} }
func (v *InboundConnectionConfig) Build() (*core.InboundConnectionConfig, error) { func (v *InboundConnectionConfig) Build() (*proxyman.InboundHandlerConfig, error) {
config := new(core.InboundConnectionConfig) receiverConfig := &proxyman.ReceiverConfig{
config.PortRange = &v2net.PortRange{ PortRange: &v2net.PortRange{
From: uint32(v.Port), From: uint32(v.Port),
To: uint32(v.Port), To: uint32(v.Port),
},
AllowPassiveConnection: v.AllowPassive,
} }
if v.Listen != nil { if v.Listen != nil {
if v.Listen.Family().IsDomain() { if v.Listen.Family().IsDomain() {
return nil, errors.New("Point: Unable to listen on domain address: " + v.Listen.Domain()) return nil, errors.New("Point: Unable to listen on domain address: " + v.Listen.Domain())
} }
config.ListenOn = v.Listen.Build() receiverConfig.Listen = v.Listen.Build()
} }
if v.StreamSetting != nil { if v.StreamSetting != nil {
ts, err := v.StreamSetting.Build() ts, err := v.StreamSetting.Build()
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.StreamSettings = ts receiverConfig.StreamSettings = ts
} }
config.AllowPassiveConnection = v.AllowPassive
jsonConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol) jsonConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol)
if err != nil { if err != nil {
return nil, errors.Base(err).Message("Failed to load inbound config.") return nil, errors.Base(err).Message("Failed to load inbound config.")
} }
if dokodemoConfig, ok := jsonConfig.(*DokodemoConfig); ok {
receiverConfig.ReceiveOriginalDestination = dokodemoConfig.Redirect
}
ts, err := jsonConfig.(Buildable).Build() ts, err := jsonConfig.(Buildable).Build()
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Settings = ts
if len(v.Tag) > 0 { return &proxyman.InboundHandlerConfig{
config.Tag = v.Tag Tag: v.Tag,
} ReceiverSettings: serial.ToTypedMessage(receiverConfig),
return config, nil ProxySettings: ts,
}, nil
} }
type OutboundConnectionConfig struct { type OutboundConnectionConfig struct {
@ -85,8 +91,31 @@ type OutboundConnectionConfig struct {
Tag string `json:"tag"` Tag string `json:"tag"`
} }
func (v *OutboundConnectionConfig) Build() (*core.OutboundConnectionConfig, error) { func (v *OutboundConnectionConfig) Build() (*proxyman.OutboundHandlerConfig, error) {
config := new(core.OutboundConnectionConfig) senderSettings := &proxyman.SenderConfig{}
if v.SendThrough != nil {
address := v.SendThrough
if address.Family().IsDomain() {
return nil, errors.New("Invalid sendThrough address: " + address.String())
}
senderSettings.Via = address.Build()
}
if v.StreamSetting != nil {
ss, err := v.StreamSetting.Build()
if err != nil {
return nil, err
}
senderSettings.StreamSettings = ss
}
if v.ProxySettings != nil {
ps, err := v.ProxySettings.Build()
if err != nil {
return nil, errors.Base(err).Message("Invalid outbound proxy settings.")
}
senderSettings.ProxySettings = ps
}
rawConfig, err := outboundConfigLoader.LoadWithID(v.Settings, v.Protocol) rawConfig, err := outboundConfigLoader.LoadWithID(v.Settings, v.Protocol)
if err != nil { if err != nil {
return nil, errors.Base(err).Message("Failed to parse outbound config.") return nil, errors.Base(err).Message("Failed to parse outbound config.")
@ -95,33 +124,12 @@ func (v *OutboundConnectionConfig) Build() (*core.OutboundConnectionConfig, erro
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Settings = ts
if v.SendThrough != nil { return &proxyman.OutboundHandlerConfig{
address := v.SendThrough SenderSettings: serial.ToTypedMessage(senderSettings),
if address.Family().IsDomain() { ProxySettings: ts,
return nil, errors.New("Invalid sendThrough address: " + address.String()) Tag: v.Tag,
} }, nil
config.SendThrough = address.Build()
}
if v.StreamSetting != nil {
ss, err := v.StreamSetting.Build()
if err != nil {
return nil, err
}
config.StreamSettings = ss
}
if v.ProxySettings != nil {
ps, err := v.ProxySettings.Build()
if err != nil {
return nil, errors.Base(err).Message("Invalid outbound proxy settings.")
}
config.ProxySettings = ps
}
if len(v.Tag) > 0 {
config.Tag = v.Tag
}
return config, nil
} }
type InboundDetourAllocationConfig struct { type InboundDetourAllocationConfig struct {
@ -130,26 +138,26 @@ type InboundDetourAllocationConfig struct {
RefreshMin *uint32 `json:"refresh"` RefreshMin *uint32 `json:"refresh"`
} }
func (v *InboundDetourAllocationConfig) Build() (*core.AllocationStrategy, error) { func (v *InboundDetourAllocationConfig) Build() (*proxyman.AllocationStrategy, error) {
config := new(core.AllocationStrategy) config := new(proxyman.AllocationStrategy)
switch strings.ToLower(v.Strategy) { switch strings.ToLower(v.Strategy) {
case "always": case "always":
config.Type = core.AllocationStrategy_Always config.Type = proxyman.AllocationStrategy_Always
case "random": case "random":
config.Type = core.AllocationStrategy_Random config.Type = proxyman.AllocationStrategy_Random
case "external": case "external":
config.Type = core.AllocationStrategy_External config.Type = proxyman.AllocationStrategy_External
default: default:
return nil, errors.New("Unknown allocation strategy: ", v.Strategy) return nil, errors.New("Unknown allocation strategy: ", v.Strategy)
} }
if v.Concurrency != nil { if v.Concurrency != nil {
config.Concurrency = &core.AllocationStrategyConcurrency{ config.Concurrency = &proxyman.AllocationStrategy_AllocationStrategyConcurrency{
Value: *v.Concurrency, Value: *v.Concurrency,
} }
} }
if v.RefreshMin != nil { if v.RefreshMin != nil {
config.Refresh = &core.AllocationStrategyRefresh{ config.Refresh = &proxyman.AllocationStrategy_AllocationStrategyRefresh{
Value: *v.RefreshMin, Value: *v.RefreshMin,
} }
} }
@ -168,46 +176,54 @@ type InboundDetourConfig struct {
AllowPassive bool `json:"allowPassive"` AllowPassive bool `json:"allowPassive"`
} }
func (v *InboundDetourConfig) Build() (*core.InboundConnectionConfig, error) { func (v *InboundDetourConfig) Build() (*proxyman.InboundHandlerConfig, error) {
config := new(core.InboundConnectionConfig) receiverSettings := &proxyman.ReceiverConfig{
AllowPassiveConnection: v.AllowPassive,
}
if v.PortRange == nil { if v.PortRange == nil {
return nil, errors.New("Port range not specified in InboundDetour.") return nil, errors.New("Port range not specified in InboundDetour.")
} }
config.PortRange = v.PortRange.Build() receiverSettings.PortRange = v.PortRange.Build()
if v.ListenOn != nil { if v.ListenOn != nil {
if v.ListenOn.Family().IsDomain() { if v.ListenOn.Family().IsDomain() {
return nil, errors.New("Unable to listen on domain address: ", v.ListenOn.Domain()) return nil, errors.New("Unable to listen on domain address: ", v.ListenOn.Domain())
} }
config.ListenOn = v.ListenOn.Build() receiverSettings.Listen = v.ListenOn.Build()
} }
config.Tag = v.Tag
if v.Allocation != nil { if v.Allocation != nil {
as, err := v.Allocation.Build() as, err := v.Allocation.Build()
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.AllocationStrategy = as receiverSettings.AllocationStrategy = as
} }
if v.StreamSetting != nil { if v.StreamSetting != nil {
ss, err := v.StreamSetting.Build() ss, err := v.StreamSetting.Build()
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.StreamSettings = ss receiverSettings.StreamSettings = ss
} }
config.AllowPassiveConnection = v.AllowPassive
rawConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol) rawConfig, err := inboundConfigLoader.LoadWithID(v.Settings, v.Protocol)
if err != nil { if err != nil {
return nil, errors.Base(err).Message("Failed to load inbound detour config.") return nil, errors.Base(err).Message("Failed to load inbound detour config.")
} }
if dokodemoConfig, ok := rawConfig.(*DokodemoConfig); ok {
receiverSettings.ReceiveOriginalDestination = dokodemoConfig.Redirect
}
ts, err := rawConfig.(Buildable).Build() ts, err := rawConfig.(Buildable).Build()
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.Settings = ts
return config, nil return &proxyman.InboundHandlerConfig{
Tag: v.Tag,
ReceiverSettings: serial.ToTypedMessage(receiverSettings),
ProxySettings: ts,
}, nil
} }
type OutboundDetourConfig struct { type OutboundDetourConfig struct {
@ -219,16 +235,15 @@ type OutboundDetourConfig struct {
ProxySettings *ProxyConfig `json:"proxySettings"` ProxySettings *ProxyConfig `json:"proxySettings"`
} }
func (v *OutboundDetourConfig) Build() (*core.OutboundConnectionConfig, error) { func (v *OutboundDetourConfig) Build() (*proxyman.OutboundHandlerConfig, error) {
config := new(core.OutboundConnectionConfig) senderSettings := &proxyman.SenderConfig{}
config.Tag = v.Tag
if v.SendThrough != nil { if v.SendThrough != nil {
address := v.SendThrough address := v.SendThrough
if address.Family().IsDomain() { if address.Family().IsDomain() {
return nil, errors.New("Point: Unable to send through: " + address.String()) return nil, errors.New("Point: Unable to send through: " + address.String())
} }
config.SendThrough = address.Build() senderSettings.Via = address.Build()
} }
if v.StreamSetting != nil { if v.StreamSetting != nil {
@ -236,7 +251,15 @@ func (v *OutboundDetourConfig) Build() (*core.OutboundConnectionConfig, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
config.StreamSettings = ss senderSettings.StreamSettings = ss
}
if v.ProxySettings != nil {
ps, err := v.ProxySettings.Build()
if err != nil {
return nil, errors.Base(err).Message("Invalid outbound detour proxy settings.")
}
senderSettings.ProxySettings = ps
} }
rawConfig, err := outboundConfigLoader.LoadWithID(v.Settings, v.Protocol) rawConfig, err := outboundConfigLoader.LoadWithID(v.Settings, v.Protocol)
@ -248,15 +271,11 @@ func (v *OutboundDetourConfig) Build() (*core.OutboundConnectionConfig, error) {
return nil, err return nil, err
} }
if v.ProxySettings != nil { return &proxyman.OutboundHandlerConfig{
ps, err := v.ProxySettings.Build() SenderSettings: serial.ToTypedMessage(senderSettings),
if err != nil { Tag: v.Tag,
return nil, errors.Base(err).Message("Invalid outbound detour proxy settings.") ProxySettings: ts,
} }, nil
config.ProxySettings = ps
}
config.Settings = ts
return config, nil
} }
type Config struct { type Config struct {

View File

@ -56,6 +56,24 @@ func (v *StreamConfig) GetEffectiveTransportSettings() (interface{}, error) {
return CreateTransportConfig(protocol) return CreateTransportConfig(protocol)
} }
func (c *StreamConfig) GetTransportSettingsFor(protocol TransportProtocol) (interface{}, error) {
if c != nil {
for _, settings := range c.TransportSettings {
if settings.Protocol == protocol {
return settings.GetTypedSettings()
}
}
}
for _, settings := range globalTransportSettings {
if settings.Protocol == protocol {
return settings.GetTypedSettings()
}
}
return CreateTransportConfig(protocol)
}
func (v *StreamConfig) GetEffectiveSecuritySettings() (interface{}, error) { func (v *StreamConfig) GetEffectiveSecuritySettings() (interface{}, error) {
for _, settings := range v.SecuritySettings { for _, settings := range v.SecuritySettings {
if settings.Type == v.SecurityType { if settings.Type == v.SecurityType {

View File

@ -0,0 +1,52 @@
package internet
import (
"context"
"v2ray.com/core/common/net"
)
type key int
const (
streamSettingsKey key = iota
dialerSrcKey
transportSettingsKey
securitySettingsKey
)
func ContextWithStreamSettings(ctx context.Context, streamSettings *StreamConfig) context.Context {
return context.WithValue(ctx, streamSettingsKey, streamSettings)
}
func StreamSettingsFromContext(ctx context.Context) (*StreamConfig, bool) {
ss, ok := ctx.Value(streamSettingsKey).(*StreamConfig)
return ss, ok
}
func ContextWithDialerSource(ctx context.Context, addr net.Address) context.Context {
return context.WithValue(ctx, dialerSrcKey, addr)
}
func DialerSourceFromContext(ctx context.Context) net.Address {
if addr, ok := ctx.Value(dialerSrcKey).(net.Address); ok {
return addr
}
return net.AnyIP
}
func ContextWithTransportSettings(ctx context.Context, transportSettings interface{}) context.Context {
return context.WithValue(ctx, transportSettingsKey, transportSettings)
}
func TransportSettingsFromContext(ctx context.Context) interface{} {
return ctx.Value(transportSettingsKey)
}
func ContextWithSecuritySettings(ctx context.Context, securitySettings interface{}) context.Context {
return context.WithValue(ctx, securitySettingsKey, securitySettings)
}
func SecuritySettingsFromContext(ctx context.Context) interface{} {
return ctx.Value(securitySettingsKey)
}

View File

@ -1,24 +1,17 @@
package internet package internet
import ( import (
"context"
"net" "net"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
) )
type DialerOptions struct { type Dialer func(ctx context.Context, dest v2net.Destination) (Connection, error)
Stream *StreamConfig
Proxy *ProxyConfig
}
type Dialer func(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error)
var ( var (
transportDialerCache = make(map[TransportProtocol]Dialer) transportDialerCache = make(map[TransportProtocol]Dialer)
ProxyDialer Dialer
) )
func RegisterTransportDialer(protocol TransportProtocol, dialer Dialer) error { func RegisterTransportDialer(protocol TransportProtocol, dialer Dialer) error {
@ -29,26 +22,34 @@ func RegisterTransportDialer(protocol TransportProtocol, dialer Dialer) error {
return nil return nil
} }
func Dial(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error) { func Dial(ctx context.Context, dest v2net.Destination) (Connection, error) {
if options.Proxy.HasTag() && ProxyDialer != nil {
log.Info("Internet: Proxying outbound connection through: ", options.Proxy.Tag)
return ProxyDialer(src, dest, options)
}
if dest.Network == v2net.Network_TCP { if dest.Network == v2net.Network_TCP {
protocol := options.Stream.GetEffectiveProtocol() streamSettings, _ := StreamSettingsFromContext(ctx)
protocol := streamSettings.GetEffectiveProtocol()
transportSettings, err := streamSettings.GetEffectiveTransportSettings()
if err != nil {
return nil, err
}
ctx = ContextWithTransportSettings(ctx, transportSettings)
if streamSettings != nil && streamSettings.HasSecuritySettings() {
securitySettings, err := streamSettings.GetEffectiveSecuritySettings()
if err != nil {
return nil, err
}
ctx = ContextWithSecuritySettings(ctx, securitySettings)
}
dialer := transportDialerCache[protocol] dialer := transportDialerCache[protocol]
if dialer == nil { if dialer == nil {
return nil, errors.New("Internet|Dialer: ", options.Stream.Protocol, " dialer not registered.") return nil, errors.New("Internet|Dialer: ", protocol, " dialer not registered.")
} }
return dialer(src, dest, options) return dialer(ctx, dest)
} }
udpDialer := transportDialerCache[TransportProtocol_UDP] udpDialer := transportDialerCache[TransportProtocol_UDP]
if udpDialer == nil { if udpDialer == nil {
return nil, errors.New("Internet|Dialer: UDP dialer not registered.") return nil, errors.New("Internet|Dialer: UDP dialer not registered.")
} }
return udpDialer(src, dest, options) return udpDialer(ctx, dest)
} }
// DialSystem calls system dialer to create a network connection. // DialSystem calls system dialer to create a network connection.

View File

@ -1,6 +1,7 @@
package kcp package kcp
import ( import (
"context"
"crypto/cipher" "crypto/cipher"
"crypto/tls" "crypto/tls"
"net" "net"
@ -108,10 +109,11 @@ func (o *ClientConnection) Run() {
} }
} }
func DialKCP(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) { func DialKCP(ctx context.Context, dest v2net.Destination) (internet.Connection, error) {
dest.Network = v2net.Network_UDP dest.Network = v2net.Network_UDP
log.Info("KCP|Dialer: Dialing KCP to ", dest) log.Info("KCP|Dialer: Dialing KCP to ", dest)
src := internet.DialerSourceFromContext(ctx)
id := internal.NewConnectionID(src, dest) id := internal.NewConnectionID(src, dest)
conn := globalPool.Get(id) conn := globalPool.Get(id)
if conn == nil { if conn == nil {
@ -128,12 +130,7 @@ func DialKCP(src v2net.Address, dest v2net.Destination, options internet.DialerO
conn = c conn = c
} }
networkSettings, err := options.Stream.GetEffectiveTransportSettings() kcpSettings := internet.TransportSettingsFromContext(ctx).(*Config)
if err != nil {
log.Error("KCP|Dialer: Failed to get KCP settings: ", err)
return nil, err
}
kcpSettings := networkSettings.(*Config)
clientConn := conn.(*ClientConnection) clientConn := conn.(*ClientConnection)
header, err := kcpSettings.GetPackerHeader() header, err := kcpSettings.GetPackerHeader()
@ -151,12 +148,7 @@ func DialKCP(src v2net.Address, dest v2net.Destination, options internet.DialerO
var iConn internet.Connection var iConn internet.Connection
iConn = session iConn = session
if options.Stream != nil && options.Stream.HasSecuritySettings() { if securitySettings := internet.SecuritySettingsFromContext(ctx); securitySettings != nil {
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("KCP|Dialer: Failed to get security settings: ", err)
return nil, err
}
switch securitySettings := securitySettings.(type) { switch securitySettings := securitySettings.(type) {
case *v2tls.Config: case *v2tls.Config:
config := securitySettings.GetTLSConfig() config := securitySettings.GetTLSConfig()

View File

@ -1,6 +1,7 @@
package kcp_test package kcp_test
import ( import (
"context"
"crypto/rand" "crypto/rand"
"io" "io"
"net" "net"
@ -55,19 +56,10 @@ func TestDialAndListen(t *testing.T) {
} }
}() }()
ctx := internet.ContextWithTransportSettings(context.Background(), &Config{})
wg := new(sync.WaitGroup) wg := new(sync.WaitGroup)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
clientConn, err := DialKCP(v2net.LocalHostIP, v2net.UDPDestination(v2net.LocalHostIP, port), internet.DialerOptions{ clientConn, err := DialKCP(ctx, v2net.UDPDestination(v2net.LocalHostIP, port))
Stream: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
TransportSettings: []*internet.TransportConfig{
{
Protocol: internet.TransportProtocol_MKCP,
Settings: serial.ToTypedMessage(&Config{}),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
wg.Add(1) wg.Add(1)

View File

@ -13,7 +13,6 @@ import (
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/internal" "v2ray.com/core/transport/internet/internal"
v2tls "v2ray.com/core/transport/internet/tls" v2tls "v2ray.com/core/transport/internet/tls"
@ -140,11 +139,9 @@ func NewListener(address v2net.Address, port v2net.Port, options internet.Listen
return l, nil return l, nil
} }
func (v *Listener) OnReceive(payload *buf.Buffer, session *proxy.SessionInfo) { func (v *Listener) OnReceive(payload *buf.Buffer, src v2net.Destination, originalDest v2net.Destination) {
defer payload.Release() defer payload.Release()
src := session.Source
segments := v.reader.Read(payload.Bytes()) segments := v.reader.Read(payload.Bytes())
if len(segments) == 0 { if len(segments) == 0 {
log.Info("KCP|Listener: discarding invalid payload from ", src) log.Info("KCP|Listener: discarding invalid payload from ", src)

View File

@ -1,6 +1,7 @@
package tcp package tcp
import ( import (
"context"
"crypto/tls" "crypto/tls"
"net" "net"
@ -17,16 +18,11 @@ var (
globalCache = internal.NewConnectionPool() globalCache = internal.NewConnectionPool()
) )
func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) { func Dial(ctx context.Context, dest v2net.Destination) (internet.Connection, error) {
log.Info("Internet|TCP: Dailing TCP to ", dest) log.Info("Internet|TCP: Dailing TCP to ", dest)
if src == nil { src := internet.DialerSourceFromContext(ctx)
src = v2net.AnyIP
} tcpSettings := internet.TransportSettingsFromContext(ctx).(*Config)
networkSettings, err := options.Stream.GetEffectiveTransportSettings()
if err != nil {
return nil, err
}
tcpSettings := networkSettings.(*Config)
id := internal.NewConnectionID(src, dest) id := internal.NewConnectionID(src, dest)
var conn net.Conn var conn net.Conn
@ -39,12 +35,7 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
if err != nil { if err != nil {
return nil, err return nil, err
} }
if options.Stream != nil && options.Stream.HasSecuritySettings() { if securitySettings := internet.SecuritySettingsFromContext(ctx); securitySettings != nil {
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("TCP: Failed to get security settings: ", err)
return nil, err
}
tlsConfig, ok := securitySettings.(*v2tls.Config) tlsConfig, ok := securitySettings.(*v2tls.Config)
if ok { if ok {
config := tlsConfig.GetTLSConfig() config := tlsConfig.GetTLSConfig()

View File

@ -42,6 +42,7 @@ func ListenTCP(address v2net.Address, port v2net.Port, options internet.ListenOp
if err != nil { if err != nil {
return nil, err return nil, err
} }
log.Info("TCP|Listener: Listening on ", address, ":", port)
networkSettings, err := options.Stream.GetEffectiveTransportSettings() networkSettings, err := options.Stream.GetEffectiveTransportSettings()
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,6 +1,6 @@
// +build linux // +build linux
package dokodemo package tcp
import ( import (
"syscall" "syscall"

View File

@ -1,6 +1,6 @@
// +build !linux // +build !linux
package dokodemo package tcp
import ( import (
"v2ray.com/core/common/net" "v2ray.com/core/common/net"

View File

@ -24,7 +24,8 @@ func RegisterTransportListener(protocol TransportProtocol, listener ListenFunc)
type ListenFunc func(address v2net.Address, port v2net.Port, options ListenOptions) (Listener, error) type ListenFunc func(address v2net.Address, port v2net.Port, options ListenOptions) (Listener, error)
type ListenOptions struct { type ListenOptions struct {
Stream *StreamConfig Stream *StreamConfig
RecvOrigDest bool
} }
type Listener interface { type Listener interface {

View File

@ -1,6 +1,8 @@
package udp package udp
import ( import (
"context"
"v2ray.com/core/common" "v2ray.com/core/common"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
@ -9,7 +11,8 @@ import (
func init() { func init() {
common.Must(internet.RegisterTransportDialer(internet.TransportProtocol_UDP, common.Must(internet.RegisterTransportDialer(internet.TransportProtocol_UDP,
func(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) { func(ctx context.Context, dest v2net.Destination) (internet.Connection, error) {
src := internet.DialerSourceFromContext(ctx)
conn, err := internet.DialSystem(src, dest) conn, err := internet.DialSystem(src, dest)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -9,18 +9,18 @@ import (
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/signal" "v2ray.com/core/common/signal"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet/internal" "v2ray.com/core/transport/internet/internal"
) )
// Payload represents a single UDP payload. // Payload represents a single UDP payload.
type Payload struct { type Payload struct {
payload *buf.Buffer payload *buf.Buffer
session *proxy.SessionInfo source v2net.Destination
originalDest v2net.Destination
} }
// PayloadHandler is function to handle Payload. // PayloadHandler is function to handle Payload.
type PayloadHandler func(*buf.Buffer, *proxy.SessionInfo) type PayloadHandler func(payload *buf.Buffer, source v2net.Destination, originalDest v2net.Destination)
// PayloadQueue is a queue of Payload. // PayloadQueue is a queue of Payload.
type PayloadQueue struct { type PayloadQueue struct {
@ -59,7 +59,7 @@ func (v *PayloadQueue) Enqueue(payload Payload) {
func (v *PayloadQueue) Dequeue(queue <-chan Payload) { func (v *PayloadQueue) Dequeue(queue <-chan Payload) {
for payload := range queue { for payload := range queue {
v.callback(payload.payload, payload.session) v.callback(payload.payload, payload.source, payload.originalDest)
} }
} }
@ -94,6 +94,7 @@ func ListenUDP(address v2net.Address, port v2net.Port, option ListenOption) (*Hu
if err != nil { if err != nil {
return nil, err return nil, err
} }
log.Info("UDP|Hub: Listening on ", address, ":", port)
if option.ReceiveOriginalDest { if option.ReceiveOriginalDest {
fd, err := internal.GetSysFd(udpConn) fd, err := internal.GetSysFd(udpConn)
if err != nil { if err != nil {
@ -155,15 +156,14 @@ func (v *Hub) start() {
continue continue
} }
session := new(proxy.SessionInfo) payload := Payload{
session.Source = v2net.UDPDestination(v2net.IPAddress(addr.IP), v2net.Port(addr.Port))
if v.option.ReceiveOriginalDest && noob > 0 {
session.Destination = RetrieveOriginalDest(oobBytes[:noob])
}
v.queue.Enqueue(Payload{
payload: buffer, payload: buffer,
session: session, }
}) payload.source = v2net.UDPDestination(v2net.IPAddress(addr.IP), v2net.Port(addr.Port))
if v.option.ReceiveOriginalDest && noob > 0 {
payload.originalDest = RetrieveOriginalDest(oobBytes[:noob])
}
v.queue.Enqueue(payload)
} }
} }

View File

@ -1,8 +1,8 @@
package udp package udp
import ( import (
"context"
"sync" "sync"
"time"
"v2ray.com/core/app/dispatcher" "v2ray.com/core/app/dispatcher"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
@ -12,95 +12,17 @@ import (
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
) )
type ResponseCallback func(destination v2net.Destination, payload *buf.Buffer) type ResponseCallback func(payload *buf.Buffer)
type TimedInboundRay struct {
name string
inboundRay ray.InboundRay
accessed chan bool
server *Server
sync.RWMutex
}
func NewTimedInboundRay(name string, inboundRay ray.InboundRay, server *Server) *TimedInboundRay {
r := &TimedInboundRay{
name: name,
inboundRay: inboundRay,
accessed: make(chan bool, 1),
server: server,
}
go r.Monitor()
return r
}
func (v *TimedInboundRay) Monitor() {
for {
time.Sleep(time.Second * 16)
select {
case <-v.accessed:
default:
// Ray not accessed for a while, assuming communication is dead.
v.RLock()
if v.server == nil {
v.RUnlock()
return
}
v.server.RemoveRay(v.name)
v.RUnlock()
v.Release()
return
}
}
}
func (v *TimedInboundRay) InboundInput() ray.OutputStream {
v.RLock()
defer v.RUnlock()
if v.inboundRay == nil {
return nil
}
select {
case v.accessed <- true:
default:
}
return v.inboundRay.InboundInput()
}
func (v *TimedInboundRay) InboundOutput() ray.InputStream {
v.RLock()
defer v.RUnlock()
if v.inboundRay == nil {
return nil
}
select {
case v.accessed <- true:
default:
}
return v.inboundRay.InboundOutput()
}
func (v *TimedInboundRay) Release() {
log.Debug("UDP Server: Releasing TimedInboundRay: ", v.name)
v.Lock()
defer v.Unlock()
if v.server == nil {
return
}
v.server = nil
v.inboundRay.InboundInput().Close()
v.inboundRay.InboundOutput().CloseError()
v.inboundRay = nil
}
type Server struct { type Server struct {
sync.RWMutex sync.RWMutex
conns map[string]*TimedInboundRay conns map[string]ray.InboundRay
packetDispatcher dispatcher.Interface packetDispatcher dispatcher.Interface
} }
func NewServer(packetDispatcher dispatcher.Interface) *Server { func NewServer(packetDispatcher dispatcher.Interface) *Server {
return &Server{ return &Server{
conns: make(map[string]*TimedInboundRay), conns: make(map[string]ray.InboundRay),
packetDispatcher: packetDispatcher, packetDispatcher: packetDispatcher,
} }
} }
@ -108,69 +30,53 @@ func NewServer(packetDispatcher dispatcher.Interface) *Server {
func (v *Server) RemoveRay(name string) { func (v *Server) RemoveRay(name string) {
v.Lock() v.Lock()
defer v.Unlock() defer v.Unlock()
delete(v.conns, name) if conn, found := v.conns[name]; found {
} conn.InboundInput().Close()
conn.InboundOutput().Close()
func (v *Server) locateExistingAndDispatch(name string, payload *buf.Buffer) bool { delete(v.conns, name)
log.Debug("UDP Server: Locating existing connection for ", name)
v.RLock()
defer v.RUnlock()
if entry, found := v.conns[name]; found {
outputStream := entry.InboundInput()
if outputStream == nil {
return false
}
err := outputStream.Write(payload)
if err != nil {
go entry.Release()
return false
}
return true
} }
return false
} }
func (v *Server) getInboundRay(dest string, session *proxy.SessionInfo) (*TimedInboundRay, bool) { func (v *Server) getInboundRay(ctx context.Context, dest v2net.Destination) (ray.InboundRay, bool) {
destString := dest.String()
v.Lock() v.Lock()
defer v.Unlock() defer v.Unlock()
if entry, found := v.conns[dest]; found { if entry, found := v.conns[destString]; found {
return entry, true return entry, true
} }
log.Info("UDP|Server: establishing new connection for ", dest) log.Info("UDP|Server: establishing new connection for ", dest)
inboundRay := v.packetDispatcher.DispatchToOutbound(session) ctx = proxy.ContextWithDestination(ctx, dest)
return NewTimedInboundRay(dest, inboundRay, v), false return v.packetDispatcher.DispatchToOutbound(ctx), false
} }
func (v *Server) Dispatch(session *proxy.SessionInfo, payload *buf.Buffer, callback ResponseCallback) { func (v *Server) Dispatch(ctx context.Context, destination v2net.Destination, payload *buf.Buffer, callback ResponseCallback) {
source := session.Source
destination := session.Destination
// TODO: Add user to destString // TODO: Add user to destString
destString := source.String() + "-" + destination.String() destString := destination.String()
log.Debug("UDP|Server: Dispatch request: ", destString) log.Debug("UDP|Server: Dispatch request: ", destString)
inboundRay, existing := v.getInboundRay(destString, session)
inboundRay, existing := v.getInboundRay(ctx, destination)
outputStream := inboundRay.InboundInput() outputStream := inboundRay.InboundInput()
if outputStream != nil { if outputStream != nil {
outputStream.Write(payload) if err := outputStream.Write(payload); err != nil {
v.RemoveRay(destString)
}
} }
if !existing { if !existing {
go v.handleConnection(inboundRay, source, callback) go func() {
handleInput(inboundRay.InboundOutput(), callback)
v.RemoveRay(destString)
}()
} }
} }
func (v *Server) handleConnection(inboundRay *TimedInboundRay, source v2net.Destination, callback ResponseCallback) { func handleInput(input ray.InputStream, callback ResponseCallback) {
for { for {
inputStream := inboundRay.InboundOutput() data, err := input.Read()
if inputStream == nil {
break
}
data, err := inputStream.Read()
if err != nil { if err != nil {
break break
} }
callback(source, data) callback(data)
} }
inboundRay.Release()
} }

View File

@ -1,6 +1,7 @@
package websocket package websocket
import ( import (
"context"
"io/ioutil" "io/ioutil"
"net" "net"
@ -17,16 +18,10 @@ var (
globalCache = internal.NewConnectionPool() globalCache = internal.NewConnectionPool()
) )
func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (internet.Connection, error) { func Dial(ctx context.Context, dest v2net.Destination) (internet.Connection, error) {
log.Info("WebSocket|Dailer: Creating connection to ", dest) log.Info("WebSocket|Dialer: Creating connection to ", dest)
if src == nil { src := internet.DialerSourceFromContext(ctx)
src = v2net.AnyIP wsSettings := internet.TransportSettingsFromContext(ctx).(*Config)
}
networkSettings, err := options.Stream.GetEffectiveTransportSettings()
if err != nil {
return nil, err
}
wsSettings := networkSettings.(*Config)
id := internal.NewConnectionID(src, dest) id := internal.NewConnectionID(src, dest)
var conn *wsconn var conn *wsconn
@ -38,7 +33,7 @@ func Dial(src v2net.Address, dest v2net.Destination, options internet.DialerOpti
} }
if conn == nil { if conn == nil {
var err error var err error
conn, err = wsDial(src, dest, options) conn, err = wsDial(ctx, dest)
if err != nil { if err != nil {
log.Warning("WebSocket|Dialer: Dial failed: ", err) log.Warning("WebSocket|Dialer: Dial failed: ", err)
return nil, err return nil, err
@ -51,12 +46,9 @@ func init() {
common.Must(internet.RegisterTransportDialer(internet.TransportProtocol_WebSocket, Dial)) common.Must(internet.RegisterTransportDialer(internet.TransportProtocol_WebSocket, Dial))
} }
func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOptions) (*wsconn, error) { func wsDial(ctx context.Context, dest v2net.Destination) (*wsconn, error) {
networkSettings, err := options.Stream.GetEffectiveTransportSettings() src := internet.DialerSourceFromContext(ctx)
if err != nil { wsSettings := internet.TransportSettingsFromContext(ctx).(*Config)
return nil, err
}
wsSettings := networkSettings.(*Config)
commonDial := func(network, addr string) (net.Conn, error) { commonDial := func(network, addr string) (net.Conn, error) {
return internet.DialSystem(src, dest) return internet.DialSystem(src, dest)
@ -70,15 +62,10 @@ func wsDial(src v2net.Address, dest v2net.Destination, options internet.DialerOp
protocol := "ws" protocol := "ws"
if options.Stream != nil && options.Stream.HasSecuritySettings() { if securitySettings := internet.SecuritySettingsFromContext(ctx); securitySettings != nil {
protocol = "wss"
securitySettings, err := options.Stream.GetEffectiveSecuritySettings()
if err != nil {
log.Error("WebSocket: Failed to create security settings: ", err)
return nil, err
}
tlsConfig, ok := securitySettings.(*v2tls.Config) tlsConfig, ok := securitySettings.(*v2tls.Config)
if ok { if ok {
protocol = "wss"
dialer.TLSClientConfig = tlsConfig.GetTLSConfig() dialer.TLSClientConfig = tlsConfig.GetTLSConfig()
if dest.Address.Family().IsDomain() { if dest.Address.Family().IsDomain() {
dialer.TLSClientConfig.ServerName = dest.Address.Domain() dialer.TLSClientConfig.ServerName = dest.Address.Domain()

View File

@ -6,6 +6,8 @@ import (
"bytes" "bytes"
"context"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
"v2ray.com/core/testing/assert" "v2ray.com/core/testing/assert"
@ -54,19 +56,10 @@ func Test_listenWSAndDial(t *testing.T) {
}() }()
} }
}() }()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13146), internet.DialerOptions{
Stream: &internet.StreamConfig{ ctx := internet.ContextWithTransportSettings(context.Background(), &Config{Path: "ws"})
Protocol: internet.TransportProtocol_WebSocket, conn, err := Dial(ctx, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13146))
TransportSettings: []*internet.TransportConfig{
{
Protocol: internet.TransportProtocol_WebSocket,
Settings: serial.ToTypedMessage(&Config{
Path: "ws",
}),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
_, err = conn.Write([]byte("Test connection 1")) _, err = conn.Write([]byte("Test connection 1"))
assert.Error(err).IsNil() assert.Error(err).IsNil()
@ -78,19 +71,7 @@ func Test_listenWSAndDial(t *testing.T) {
assert.Error(conn.Close()).IsNil() assert.Error(conn.Close()).IsNil()
<-time.After(time.Second * 5) <-time.After(time.Second * 5)
conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13146), internet.DialerOptions{ conn, err = Dial(ctx, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13146))
Stream: &internet.StreamConfig{
Protocol: internet.TransportProtocol_WebSocket,
TransportSettings: []*internet.TransportConfig{
{
Protocol: internet.TransportProtocol_WebSocket,
Settings: serial.ToTypedMessage(&Config{
Path: "ws",
}),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
_, err = conn.Write([]byte("Test connection 2")) _, err = conn.Write([]byte("Test connection 2"))
assert.Error(err).IsNil() assert.Error(err).IsNil()
@ -99,19 +80,7 @@ func Test_listenWSAndDial(t *testing.T) {
assert.String(string(b[:n])).Equals("Response") assert.String(string(b[:n])).Equals("Response")
assert.Error(conn.Close()).IsNil() assert.Error(conn.Close()).IsNil()
<-time.After(time.Second * 15) <-time.After(time.Second * 15)
conn, err = Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13146), internet.DialerOptions{ conn, err = Dial(ctx, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13146))
Stream: &internet.StreamConfig{
Protocol: internet.TransportProtocol_WebSocket,
TransportSettings: []*internet.TransportConfig{
{
Protocol: internet.TransportProtocol_WebSocket,
Settings: serial.ToTypedMessage(&Config{
Path: "ws",
}),
},
},
},
})
assert.Error(err).IsNil() assert.Error(err).IsNil()
_, err = conn.Write([]byte("Test connection 3")) _, err = conn.Write([]byte("Test connection 3"))
assert.Error(err).IsNil() assert.Error(err).IsNil()
@ -157,26 +126,16 @@ func Test_listenWSAndDial_TLS(t *testing.T) {
conn.Close() conn.Close()
listen.Close() listen.Close()
}() }()
conn, err := Dial(v2net.AnyIP, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13143), internet.DialerOptions{ ctx := internet.ContextWithTransportSettings(context.Background(), &Config{
Stream: &internet.StreamConfig{ Path: "wss",
SecurityType: serial.GetMessageType(new(v2tls.Config)), ConnectionReuse: &ConnectionReuse{
SecuritySettings: []*serial.TypedMessage{serial.ToTypedMessage(&v2tls.Config{ Enable: true,
AllowInsecure: true,
})},
Protocol: internet.TransportProtocol_WebSocket,
TransportSettings: []*internet.TransportConfig{
{
Protocol: internet.TransportProtocol_WebSocket,
Settings: serial.ToTypedMessage(&Config{
Path: "wss",
ConnectionReuse: &ConnectionReuse{
Enable: true,
},
}),
},
},
}, },
}) })
ctx = internet.ContextWithSecuritySettings(ctx, &v2tls.Config{
AllowInsecure: true,
})
conn, err := Dial(ctx, v2net.TCPDestination(v2net.DomainAddress("localhost"), 13143))
assert.Error(err).IsNil() assert.Error(err).IsNil()
conn.Close() conn.Close()
} }

View File

@ -6,6 +6,8 @@ import (
"time" "time"
"context"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
) )
@ -16,10 +18,10 @@ const (
var ErrReadTimeout = errors.New("Ray: timeout.") var ErrReadTimeout = errors.New("Ray: timeout.")
// NewRay creates a new Ray for direct traffic transport. // NewRay creates a new Ray for direct traffic transport.
func NewRay() Ray { func NewRay(ctx context.Context) Ray {
return &directRay{ return &directRay{
Input: NewStream(), Input: NewStream(ctx),
Output: NewStream(), Output: NewStream(ctx),
} }
} }
@ -54,13 +56,15 @@ func (v *directRay) AddInspector(inspector Inspector) {
type Stream struct { type Stream struct {
buffer chan *buf.Buffer buffer chan *buf.Buffer
ctx context.Context
close chan bool close chan bool
err chan bool err chan bool
inspector *InspectorChain inspector *InspectorChain
} }
func NewStream() *Stream { func NewStream(ctx context.Context) *Stream {
return &Stream{ return &Stream{
ctx: ctx,
buffer: make(chan *buf.Buffer, bufferSize), buffer: make(chan *buf.Buffer, bufferSize),
close: make(chan bool), close: make(chan bool),
err: make(chan bool), err: make(chan bool),
@ -70,12 +74,16 @@ func NewStream() *Stream {
func (v *Stream) Read() (*buf.Buffer, error) { func (v *Stream) Read() (*buf.Buffer, error) {
select { select {
case <-v.ctx.Done():
return nil, io.ErrClosedPipe
case <-v.err: case <-v.err:
return nil, io.ErrClosedPipe return nil, io.ErrClosedPipe
case b := <-v.buffer: case b := <-v.buffer:
return b, nil return b, nil
default: default:
select { select {
case <-v.ctx.Done():
return nil, io.ErrClosedPipe
case b := <-v.buffer: case b := <-v.buffer:
return b, nil return b, nil
case <-v.close: case <-v.close:
@ -88,12 +96,16 @@ func (v *Stream) Read() (*buf.Buffer, error) {
func (v *Stream) ReadTimeout(timeout time.Duration) (*buf.Buffer, error) { func (v *Stream) ReadTimeout(timeout time.Duration) (*buf.Buffer, error) {
select { select {
case <-v.ctx.Done():
return nil, io.ErrClosedPipe
case <-v.err: case <-v.err:
return nil, io.ErrClosedPipe return nil, io.ErrClosedPipe
case b := <-v.buffer: case b := <-v.buffer:
return b, nil return b, nil
default: default:
select { select {
case <-v.ctx.Done():
return nil, io.ErrClosedPipe
case b := <-v.buffer: case b := <-v.buffer:
return b, nil return b, nil
case <-v.close: case <-v.close:
@ -112,12 +124,16 @@ func (v *Stream) Write(data *buf.Buffer) (err error) {
} }
select { select {
case <-v.ctx.Done():
return io.ErrClosedPipe
case <-v.err: case <-v.err:
return io.ErrClosedPipe return io.ErrClosedPipe
case <-v.close: case <-v.close:
return io.ErrClosedPipe return io.ErrClosedPipe
default: default:
select { select {
case <-v.ctx.Done():
return io.ErrClosedPipe
case <-v.err: case <-v.err:
return io.ErrClosedPipe return io.ErrClosedPipe
case <-v.close: case <-v.close:

View File

@ -4,6 +4,8 @@ import (
"io" "io"
"testing" "testing"
"context"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/testing/assert" "v2ray.com/core/testing/assert"
. "v2ray.com/core/transport/ray" . "v2ray.com/core/transport/ray"
@ -12,7 +14,7 @@ import (
func TestStreamIO(t *testing.T) { func TestStreamIO(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
stream := NewStream() stream := NewStream(context.Background())
b1 := buf.New() b1 := buf.New()
b1.AppendBytes('a') b1.AppendBytes('a')
assert.Error(stream.Write(b1)).IsNil() assert.Error(stream.Write(b1)).IsNil()
@ -33,7 +35,7 @@ func TestStreamIO(t *testing.T) {
func TestStreamClose(t *testing.T) { func TestStreamClose(t *testing.T) {
assert := assert.On(t) assert := assert.On(t)
stream := NewStream() stream := NewStream(context.Background())
b1 := buf.New() b1 := buf.New()
b1.AppendBytes('a') b1.AppendBytes('a')
assert.Error(stream.Write(b1)).IsNil() assert.Error(stream.Write(b1)).IsNil()

105
v2ray.go
View File

@ -6,22 +6,13 @@ import (
"v2ray.com/core/app" "v2ray.com/core/app"
"v2ray.com/core/app/dispatcher" "v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/dns" "v2ray.com/core/app/dns"
proxydialer "v2ray.com/core/app/proxy"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net" v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
) )
// Point shell of V2Ray. // Point shell of V2Ray.
type Point struct { type Point struct {
inboundHandlers []InboundDetourHandler
taggedInboundHandlers map[string]InboundDetourHandler
outboundHandlers []proxy.OutboundHandler
taggedOutboundHandlers map[string]proxy.OutboundHandler
space app.Space space app.Space
} }
@ -42,7 +33,6 @@ func NewPoint(pConfig *Config) (*Point, error) {
ctx := app.ContextWithSpace(context.Background(), space) ctx := app.ContextWithSpace(context.Background(), space)
vpoint.space = space vpoint.space = space
vpoint.space.AddApplication(vpoint)
outboundHandlerManager := proxyman.OutboundHandlerManagerFromSpace(space) outboundHandlerManager := proxyman.OutboundHandlerManagerFromSpace(space)
if outboundHandlerManager == nil { if outboundHandlerManager == nil {
@ -54,16 +44,15 @@ func NewPoint(pConfig *Config) (*Point, error) {
outboundHandlerManager = o.(proxyman.OutboundHandlerManager) outboundHandlerManager = o.(proxyman.OutboundHandlerManager)
} }
proxyDialer := proxydialer.OutboundProxyFromSpace(space) inboundHandlerManager := proxyman.InboundHandlerManagerFromSpace(space)
if proxyDialer == nil { if inboundHandlerManager == nil {
p, err := app.CreateAppFromConfig(ctx, new(proxydialer.Config)) o, err := app.CreateAppFromConfig(ctx, new(proxyman.InboundConfig))
if err != nil { if err != nil {
return nil, err return nil, err
} }
space.AddApplication(p) space.AddApplication(o)
proxyDialer = p.(*proxydialer.OutboundProxy) inboundHandlerManager = o.(proxyman.InboundHandlerManager)
} }
proxyDialer.RegisterDialer()
for _, appSettings := range pConfig.App { for _, appSettings := range pConfig.App {
settings, err := appSettings.GetInstance() settings, err := appSettings.GetInstance()
@ -104,62 +93,16 @@ func NewPoint(pConfig *Config) (*Point, error) {
disp = d.(dispatcher.Interface) disp = d.(dispatcher.Interface)
} }
vpoint.inboundHandlers = make([]InboundDetourHandler, 0, 8)
vpoint.taggedInboundHandlers = make(map[string]InboundDetourHandler)
for _, inbound := range pConfig.Inbound { for _, inbound := range pConfig.Inbound {
allocConfig := inbound.GetAllocationStrategyValue() if err := inboundHandlerManager.AddHandler(ctx, inbound); err != nil {
var inboundHandler InboundDetourHandler return nil, err
switch allocConfig.Type {
case AllocationStrategy_Always:
dh, err := NewInboundDetourHandlerAlways(ctx, inbound)
if err != nil {
log.Error("V2Ray: Failed to create detour handler: ", err)
return nil, common.ErrBadConfiguration
}
inboundHandler = dh
case AllocationStrategy_Random:
dh, err := NewInboundDetourHandlerDynamic(ctx, inbound)
if err != nil {
log.Error("V2Ray: Failed to create detour handler: ", err)
return nil, common.ErrBadConfiguration
}
inboundHandler = dh
default:
log.Error("V2Ray: Unknown allocation strategy: ", allocConfig.Type)
return nil, common.ErrBadConfiguration
}
vpoint.inboundHandlers = append(vpoint.inboundHandlers, inboundHandler)
if len(inbound.Tag) > 0 {
vpoint.taggedInboundHandlers[inbound.Tag] = inboundHandler
} }
} }
vpoint.outboundHandlers = make([]proxy.OutboundHandler, 0, 8) for _, outbound := range pConfig.Outbound {
vpoint.taggedOutboundHandlers = make(map[string]proxy.OutboundHandler) if err := outboundHandlerManager.AddHandler(ctx, outbound); err != nil {
for idx, outbound := range pConfig.Outbound {
outboundSettings, err := outbound.GetTypedSettings()
if err != nil {
return nil, err return nil, err
} }
outboundHandler, err := proxy.CreateOutboundHandler(proxy.ContextWithOutboundMeta(ctx, &proxy.OutboundHandlerMeta{
Tag: outbound.Tag,
Address: outbound.GetSendThroughValue(),
StreamSettings: outbound.StreamSettings,
ProxySettings: outbound.ProxySettings,
}), outboundSettings)
if err != nil {
log.Error("V2Ray: Failed to create detour outbound connection handler: ", err)
return nil, err
}
if idx == 0 {
outboundHandlerManager.SetDefaultHandler(outboundHandler)
}
if len(outbound.Tag) > 0 {
outboundHandlerManager.SetHandler(outbound.Tag, outboundHandler)
vpoint.taggedOutboundHandlers[outbound.Tag] = outboundHandler
}
vpoint.outboundHandlers = append(vpoint.outboundHandlers, outboundHandler)
} }
if err := vpoint.space.Initialize(); err != nil { if err := vpoint.space.Initialize(); err != nil {
@ -169,39 +112,19 @@ func NewPoint(pConfig *Config) (*Point, error) {
return vpoint, nil return vpoint, nil
} }
func (Point) Interface() interface{} {
return (*proxyman.InboundHandlerManager)(nil)
}
func (v *Point) Close() { func (v *Point) Close() {
for _, inbound := range v.inboundHandlers { ihm := proxyman.InboundHandlerManagerFromSpace(v.space)
inbound.Close() ihm.Close()
}
} }
// Start starts the Point server, and return any error during the process. // Start starts the Point 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 (v *Point) Start() error { func (v *Point) Start() error {
for _, inbound := range v.inboundHandlers { ihm := proxyman.InboundHandlerManagerFromSpace(v.space)
err := inbound.Start() if err := ihm.Start(); err != nil {
if err != nil { return err
return err
}
} }
log.Warning("V2Ray started.") log.Warning("V2Ray started.")
return nil return nil
} }
func (v *Point) GetHandler(tag string) (proxy.InboundHandler, int) {
handler, found := v.taggedInboundHandlers[tag]
if !found {
log.Warning("V2Ray: Unable to find an inbound handler with tag: ", tag)
return nil, 0
}
return handler.GetConnectionHandler()
}
func (v *Point) Release() {
}