1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 09:36:34 -05: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
import (
"context"
"v2ray.com/core/app"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/ray"
)
// Interface dispatch a packet and possibly further network payload to its destination.
type Interface interface {
DispatchToOutbound(session *proxy.SessionInfo) ray.InboundRay
DispatchToOutbound(ctx context.Context) ray.InboundRay
}
func FromSpace(space app.Space) Interface {

View File

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

View File

@ -1,19 +1,18 @@
package server
import (
"context"
"net"
"sync"
"time"
"github.com/miekg/dns"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/common/buf"
"v2ray.com/core/common/dice"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet/udp"
"github.com/miekg/dns"
)
const (
@ -101,7 +100,7 @@ func (v *UDPNameServer) AssignUnusedID(response chan<- *ARecord) uint16 {
}
// 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)
err := msg.Unpack(payload.Bytes())
if err != nil {
@ -165,15 +164,12 @@ func (v *UDPNameServer) BuildQueryA(domain string, id uint16) *buf.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 {
response := make(chan *ARecord, 1)
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() {
for i := 0; i < 2; i++ {
@ -182,11 +178,12 @@ func (v *UDPNameServer) QueryA(domain string) <-chan *ARecord {
_, found := v.requests[id]
v.Unlock()
if found {
v.DispatchQuery(v.BuildQueryA(domain, id))
v.udpServer.Dispatch(ctx, v.address, v.BuildQueryA(domain, id), v.HandleResponse)
} else {
break
}
}
cancel()
}()
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
}
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"`
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"`
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 *StreamReceiverConfig) String() string { return proto.CompactTextString(m) }
func (*StreamReceiverConfig) ProtoMessage() {}
func (*StreamReceiverConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *ReceiverConfig) Reset() { *m = ReceiverConfig{} }
func (m *ReceiverConfig) String() string { return proto.CompactTextString(m) }
func (*ReceiverConfig) ProtoMessage() {}
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 {
return m.PortRange
}
return nil
}
func (m *StreamReceiverConfig) GetListen() *v2ray_core_common_net.IPOrDomain {
func (m *ReceiverConfig) GetListen() *v2ray_core_common_net.IPOrDomain {
if m != nil {
return m.Listen
}
return nil
}
func (m *StreamReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
func (m *ReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
if m != nil {
return m.AllocationStrategy
}
return nil
}
func (m *StreamReceiverConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
func (m *ReceiverConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
if m != nil {
return m.StreamSettings
}
return nil
}
type DatagramReceiverConfig struct {
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"`
AllocationStrategy *AllocationStrategy `protobuf:"bytes,3,opt,name=allocation_strategy,json=allocationStrategy" json:"allocation_strategy,omitempty"`
}
func (m *DatagramReceiverConfig) Reset() { *m = DatagramReceiverConfig{} }
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 {
func (m *ReceiverConfig) GetReceiveOriginalDestination() bool {
if m != nil {
return m.PortRange
return m.ReceiveOriginalDestination
}
return nil
return false
}
func (m *DatagramReceiverConfig) GetListen() *v2ray_core_common_net.IPOrDomain {
func (m *ReceiverConfig) GetAllowPassiveConnection() bool {
if m != nil {
return m.Listen
return m.AllowPassiveConnection
}
return nil
}
func (m *DatagramReceiverConfig) GetAllocationStrategy() *AllocationStrategy {
if m != nil {
return m.AllocationStrategy
}
return nil
return false
}
type InboundHandlerConfig struct {
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"`
}
func (m *InboundHandlerConfig) Reset() { *m = InboundHandlerConfig{} }
func (m *InboundHandlerConfig) String() string { return proto.CompactTextString(m) }
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 {
if m != nil {
@ -224,7 +208,7 @@ func (m *InboundHandlerConfig) GetTag() string {
return ""
}
func (m *InboundHandlerConfig) GetReceiverSettings() []*v2ray_core_common_serial.TypedMessage {
func (m *InboundHandlerConfig) GetReceiverSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.ReceiverSettings
}
@ -244,60 +228,35 @@ type OutboundConfig struct {
func (m *OutboundConfig) Reset() { *m = OutboundConfig{} }
func (m *OutboundConfig) String() string { return proto.CompactTextString(m) }
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.
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"`
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 *StreamSenderConfig) String() string { return proto.CompactTextString(m) }
func (*StreamSenderConfig) ProtoMessage() {}
func (*StreamSenderConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *SenderConfig) Reset() { *m = SenderConfig{} }
func (m *SenderConfig) String() string { return proto.CompactTextString(m) }
func (*SenderConfig) ProtoMessage() {}
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 {
return m.Via
}
return nil
}
func (m *StreamSenderConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
func (m *SenderConfig) GetStreamSettings() *v2ray_core_transport_internet.StreamConfig {
if m != nil {
return m.StreamSettings
}
return nil
}
func (m *StreamSenderConfig) 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 {
func (m *SenderConfig) GetProxySettings() *v2ray_core_transport_internet.ProxyConfig {
if m != nil {
return m.ProxySettings
}
@ -306,14 +265,16 @@ func (m *DatagramSenderConfig) GetProxySettings() *v2ray_core_transport_internet
type OutboundHandlerConfig struct {
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"`
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) String() string { return proto.CompactTextString(m) }
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 {
if m != nil {
@ -322,7 +283,7 @@ func (m *OutboundHandlerConfig) GetTag() string {
return ""
}
func (m *OutboundHandlerConfig) GetSenderSettings() []*v2ray_core_common_serial.TypedMessage {
func (m *OutboundHandlerConfig) GetSenderSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.SenderSettings
}
@ -336,17 +297,29 @@ func (m *OutboundHandlerConfig) GetProxySettings() *v2ray_core_common_serial.Typ
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() {
proto.RegisterType((*InboundConfig)(nil), "v2ray.core.app.proxyman.InboundConfig")
proto.RegisterType((*AllocationStrategy)(nil), "v2ray.core.app.proxyman.AllocationStrategy")
proto.RegisterType((*AllocationStrategy_AllocationStrategyConcurrency)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency")
proto.RegisterType((*AllocationStrategy_AllocationStrategyRefresh)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh")
proto.RegisterType((*StreamReceiverConfig)(nil), "v2ray.core.app.proxyman.StreamReceiverConfig")
proto.RegisterType((*DatagramReceiverConfig)(nil), "v2ray.core.app.proxyman.DatagramReceiverConfig")
proto.RegisterType((*ReceiverConfig)(nil), "v2ray.core.app.proxyman.ReceiverConfig")
proto.RegisterType((*InboundHandlerConfig)(nil), "v2ray.core.app.proxyman.InboundHandlerConfig")
proto.RegisterType((*OutboundConfig)(nil), "v2ray.core.app.proxyman.OutboundConfig")
proto.RegisterType((*StreamSenderConfig)(nil), "v2ray.core.app.proxyman.StreamSenderConfig")
proto.RegisterType((*DatagramSenderConfig)(nil), "v2ray.core.app.proxyman.DatagramSenderConfig")
proto.RegisterType((*SenderConfig)(nil), "v2ray.core.app.proxyman.SenderConfig")
proto.RegisterType((*OutboundHandlerConfig)(nil), "v2ray.core.app.proxyman.OutboundHandlerConfig")
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) }
var fileDescriptor0 = []byte{
// 683 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe4, 0x55, 0xdd, 0x6e, 0xd3, 0x30,
0x18, 0x25, 0xe9, 0x18, 0xdb, 0x57, 0xd6, 0x15, 0x53, 0x58, 0x29, 0x42, 0x2a, 0x15, 0x82, 0x0a,
0x50, 0x32, 0x3a, 0x71, 0xc1, 0x15, 0xda, 0x9f, 0xc4, 0x2e, 0xc6, 0x8a, 0x3b, 0x71, 0x81, 0x90,
0x2a, 0x2f, 0xf1, 0x42, 0x44, 0x62, 0x47, 0xb6, 0x5b, 0x96, 0x97, 0xe1, 0x01, 0x78, 0x0a, 0xae,
0x90, 0x90, 0x78, 0x9a, 0x3d, 0x01, 0x72, 0x9c, 0x74, 0xd5, 0xda, 0xb2, 0x8d, 0x8a, 0x2b, 0xee,
0x5c, 0xf7, 0x3b, 0xc7, 0x3e, 0xe7, 0x7c, 0xfe, 0x02, 0xed, 0x61, 0x47, 0x90, 0xd4, 0xf1, 0x78,
0xec, 0x7a, 0x5c, 0x50, 0x97, 0x24, 0x89, 0x9b, 0x08, 0x7e, 0x92, 0xc6, 0x84, 0xb9, 0x1e, 0x67,
0xc7, 0x61, 0xe0, 0x24, 0x82, 0x2b, 0x8e, 0xd6, 0x8a, 0x4a, 0x41, 0x1d, 0x92, 0x24, 0x4e, 0x51,
0xd5, 0x58, 0x3f, 0x47, 0xe1, 0xf1, 0x38, 0xe6, 0xcc, 0x95, 0x54, 0x84, 0x24, 0x72, 0x55, 0x9a,
0x50, 0xbf, 0x1f, 0x53, 0x29, 0x49, 0x40, 0x0d, 0x55, 0xe3, 0xc9, 0x74, 0x04, 0xa3, 0xca, 0x25,
0xbe, 0x2f, 0xa8, 0x94, 0x79, 0xe1, 0xa3, 0xd9, 0x85, 0x09, 0x17, 0x2a, 0xaf, 0x72, 0xce, 0x55,
0x29, 0x41, 0x98, 0xd4, 0xff, 0xbb, 0x21, 0x53, 0x54, 0xe8, 0xea, 0x71, 0x25, 0xad, 0x55, 0x58,
0xd9, 0x63, 0x47, 0x7c, 0xc0, 0xfc, 0xed, 0x6c, 0xbb, 0xf5, 0xbd, 0x04, 0x68, 0x33, 0x8a, 0xb8,
0x47, 0x54, 0xc8, 0x59, 0x4f, 0x09, 0xa2, 0x68, 0x90, 0xa2, 0x1d, 0x58, 0xd0, 0xb7, 0xaf, 0x5b,
0x4d, 0xab, 0x5d, 0xe9, 0xac, 0x3b, 0x33, 0x0c, 0x70, 0x26, 0xa1, 0xce, 0x61, 0x9a, 0x50, 0x9c,
0xa1, 0xd1, 0x67, 0x28, 0x7b, 0x9c, 0x79, 0x03, 0x21, 0x28, 0xf3, 0xd2, 0xba, 0xdd, 0xb4, 0xda,
0xe5, 0xce, 0xde, 0x55, 0xc8, 0x26, 0xb7, 0xb6, 0xcf, 0x08, 0xf1, 0x38, 0x3b, 0xea, 0xc3, 0x0d,
0x41, 0x8f, 0x05, 0x95, 0x9f, 0xea, 0xa5, 0xec, 0xa0, 0xdd, 0xf9, 0x0e, 0xc2, 0x86, 0x0c, 0x17,
0xac, 0x8d, 0x97, 0xf0, 0xe0, 0x8f, 0xd7, 0x41, 0x35, 0xb8, 0x3e, 0x24, 0xd1, 0xc0, 0xb8, 0xb6,
0x82, 0xcd, 0x8f, 0xc6, 0x0b, 0xb8, 0x37, 0x93, 0x7c, 0x3a, 0xa4, 0xf5, 0x1c, 0x16, 0xb4, 0x8b,
0x08, 0x60, 0x71, 0x33, 0xfa, 0x42, 0x52, 0x59, 0xbd, 0xa6, 0xd7, 0x98, 0x30, 0x9f, 0xc7, 0x55,
0x0b, 0xdd, 0x84, 0xa5, 0xdd, 0x13, 0x1d, 0x2f, 0x89, 0xaa, 0x76, 0xeb, 0x87, 0x0d, 0xb5, 0x9e,
0x12, 0x94, 0xc4, 0x98, 0x7a, 0x34, 0x1c, 0x52, 0x61, 0xb2, 0x45, 0xaf, 0x01, 0x74, 0x2b, 0xf4,
0x05, 0x61, 0x81, 0x39, 0xa1, 0xdc, 0x69, 0x8e, 0x9b, 0x62, 0x7a, 0xca, 0x61, 0x54, 0x39, 0x5d,
0x2e, 0x14, 0xd6, 0x75, 0x78, 0x39, 0x29, 0x96, 0xe8, 0x15, 0x2c, 0x46, 0xa1, 0x54, 0x94, 0xe5,
0xd1, 0x3d, 0x9c, 0x01, 0xde, 0xeb, 0x1e, 0x88, 0x1d, 0x1e, 0x93, 0x90, 0xe1, 0x1c, 0x80, 0x3e,
0xc2, 0x6d, 0x32, 0x52, 0xdd, 0x97, 0xb9, 0xec, 0x3c, 0x99, 0x67, 0x57, 0x48, 0x06, 0x23, 0x32,
0xd9, 0x9e, 0x87, 0xb0, 0x2a, 0x33, 0xc5, 0x7d, 0x49, 0x95, 0x0a, 0x59, 0x20, 0xeb, 0x0b, 0x93,
0xcc, 0xa3, 0xc7, 0xe0, 0x14, 0x8f, 0xc1, 0x31, 0x3e, 0x19, 0x7f, 0x70, 0xc5, 0x70, 0xf4, 0x72,
0x8a, 0xd6, 0xa9, 0x05, 0x77, 0x77, 0x88, 0x22, 0x81, 0xf8, 0x7f, 0xac, 0x6c, 0xfd, 0xb2, 0xa0,
0x96, 0x8f, 0x84, 0x37, 0x84, 0xf9, 0xd1, 0x48, 0x72, 0x15, 0x4a, 0x8a, 0x04, 0x99, 0xd6, 0x65,
0xac, 0x97, 0xa8, 0x07, 0xb7, 0x44, 0x6e, 0xcb, 0x99, 0xef, 0x76, 0xb3, 0xd4, 0x2e, 0x77, 0x1e,
0x4f, 0x91, 0x63, 0xa6, 0x60, 0x36, 0x0f, 0xfc, 0x7d, 0x33, 0x04, 0x71, 0xb5, 0x20, 0x28, 0x4c,
0x47, 0xfb, 0x50, 0xc9, 0xae, 0x7c, 0xc6, 0x68, 0x84, 0x5d, 0x96, 0x71, 0x25, 0x43, 0x8f, 0x32,
0xac, 0x42, 0xe5, 0x60, 0xa0, 0xc6, 0x27, 0xdc, 0xa9, 0x05, 0xa8, 0x97, 0x07, 0xcd, 0xfc, 0x91,
0xbc, 0x0d, 0x28, 0x0d, 0x43, 0x92, 0x47, 0x79, 0x89, 0x34, 0x74, 0xf5, 0xb4, 0xbe, 0xb3, 0xe7,
0xee, 0x3b, 0xf4, 0x6e, 0x86, 0x05, 0x4f, 0x2f, 0x20, 0xed, 0x6a, 0x50, 0xce, 0x79, 0xce, 0x86,
0xaf, 0x16, 0xd4, 0x8a, 0x56, 0x9e, 0x5f, 0xf6, 0xe4, 0x05, 0xed, 0x79, 0x2f, 0xf8, 0xd3, 0x82,
0x3b, 0x45, 0x50, 0x17, 0xf5, 0xdd, 0x01, 0xac, 0xca, 0x4c, 0xc3, 0xdf, 0x76, 0x5d, 0xc5, 0xc0,
0xff, 0x51, 0xcf, 0x6d, 0xbd, 0x85, 0xfb, 0x1e, 0x8f, 0x67, 0x3d, 0xc4, 0xad, 0xb2, 0x11, 0xd6,
0xd5, 0x1f, 0xe0, 0x0f, 0x4b, 0xc5, 0xf6, 0x37, 0x7b, 0xed, 0x7d, 0x07, 0x93, 0xd4, 0xd9, 0xd6,
0x80, 0xcd, 0x24, 0x31, 0x6e, 0xc5, 0x84, 0x1d, 0x2d, 0x66, 0xdf, 0xea, 0x8d, 0xdf, 0x01, 0x00,
0x00, 0xff, 0xff, 0x18, 0xce, 0x1c, 0x24, 0xa1, 0x08, 0x00, 0x00,
// 737 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x55, 0xd1, 0x6e, 0xdb, 0x36,
0x14, 0x9d, 0xec, 0xc4, 0x49, 0xae, 0x13, 0xc7, 0xe3, 0xb2, 0xc4, 0xf3, 0x36, 0xc0, 0x33, 0x86,
0xcd, 0xd8, 0x06, 0x29, 0x73, 0x30, 0x60, 0x7b, 0xda, 0x12, 0x27, 0xc0, 0xf2, 0x90, 0xd9, 0xa3,
0x83, 0x3e, 0x14, 0x05, 0x04, 0x46, 0x62, 0x5c, 0xa1, 0x12, 0x29, 0x90, 0xb4, 0x13, 0xfd, 0x52,
0xbf, 0xa1, 0x0f, 0xfd, 0x80, 0x7e, 0x4a, 0xff, 0xa0, 0x2f, 0x05, 0x49, 0xc9, 0x36, 0x62, 0xbb,
0x69, 0x1a, 0xf4, 0x4d, 0x24, 0xcf, 0x39, 0xe4, 0x3d, 0x87, 0x97, 0x82, 0xce, 0xa4, 0x2b, 0x48,
0xe6, 0x06, 0x3c, 0xf1, 0x02, 0x2e, 0xa8, 0x47, 0xd2, 0xd4, 0x4b, 0x05, 0xbf, 0xcd, 0x12, 0xc2,
0xbc, 0x80, 0xb3, 0xeb, 0x68, 0xe4, 0xa6, 0x82, 0x2b, 0x8e, 0x0e, 0x0a, 0xa4, 0xa0, 0x2e, 0x49,
0x53, 0xb7, 0x40, 0x35, 0x0f, 0xef, 0x48, 0x04, 0x3c, 0x49, 0x38, 0xf3, 0x24, 0x15, 0x11, 0x89,
0x3d, 0x95, 0xa5, 0x34, 0xf4, 0x13, 0x2a, 0x25, 0x19, 0x51, 0x2b, 0xd5, 0xfc, 0x79, 0x39, 0x83,
0x51, 0xe5, 0x91, 0x30, 0x14, 0x54, 0xca, 0x1c, 0xf8, 0xe3, 0x6a, 0x60, 0xca, 0x85, 0xca, 0x51,
0xee, 0x1d, 0x94, 0x12, 0x84, 0x49, 0xbd, 0xee, 0x45, 0x4c, 0x51, 0xa1, 0xd1, 0xf3, 0x95, 0xb4,
0x77, 0x61, 0xe7, 0x9c, 0x5d, 0xf1, 0x31, 0x0b, 0x7b, 0x66, 0xba, 0xfd, 0xba, 0x0c, 0xe8, 0x38,
0x8e, 0x79, 0x40, 0x54, 0xc4, 0xd9, 0x50, 0x09, 0xa2, 0xe8, 0x28, 0x43, 0xa7, 0xb0, 0xa6, 0x4f,
0xdf, 0x70, 0x5a, 0x4e, 0xa7, 0xd6, 0x3d, 0x74, 0x57, 0x18, 0xe0, 0x2e, 0x52, 0xdd, 0xcb, 0x2c,
0xa5, 0xd8, 0xb0, 0xd1, 0x0b, 0xa8, 0x06, 0x9c, 0x05, 0x63, 0x21, 0x28, 0x0b, 0xb2, 0x46, 0xa9,
0xe5, 0x74, 0xaa, 0xdd, 0xf3, 0x87, 0x88, 0x2d, 0x4e, 0xf5, 0x66, 0x82, 0x78, 0x5e, 0x1d, 0xf9,
0xb0, 0x21, 0xe8, 0xb5, 0xa0, 0xf2, 0x79, 0xa3, 0x6c, 0x36, 0x3a, 0x7b, 0xdc, 0x46, 0xd8, 0x8a,
0xe1, 0x42, 0xb5, 0xf9, 0x07, 0x7c, 0xff, 0xc1, 0xe3, 0xa0, 0x3d, 0x58, 0x9f, 0x90, 0x78, 0x6c,
0x5d, 0xdb, 0xc1, 0x76, 0xd0, 0xfc, 0x1d, 0xbe, 0x59, 0x29, 0xbe, 0x9c, 0xd2, 0xfe, 0x0d, 0xd6,
0xb4, 0x8b, 0x08, 0xa0, 0x72, 0x1c, 0xdf, 0x90, 0x4c, 0xd6, 0xbf, 0xd0, 0xdf, 0x98, 0xb0, 0x90,
0x27, 0x75, 0x07, 0x6d, 0xc3, 0xe6, 0xd9, 0xad, 0x8e, 0x97, 0xc4, 0xf5, 0x52, 0xfb, 0x55, 0x19,
0x6a, 0x98, 0x06, 0x34, 0x9a, 0x50, 0x61, 0x53, 0x45, 0x7f, 0x03, 0xe8, 0x4b, 0xe0, 0x0b, 0xc2,
0x46, 0x56, 0xbb, 0xda, 0x6d, 0xcd, 0xdb, 0x61, 0x6f, 0x93, 0xcb, 0xa8, 0x72, 0x07, 0x5c, 0x28,
0xac, 0x71, 0x78, 0x2b, 0x2d, 0x3e, 0xd1, 0x5f, 0x50, 0x89, 0x23, 0xa9, 0x28, 0xcb, 0x43, 0xfb,
0x61, 0x05, 0xf9, 0x7c, 0xd0, 0x17, 0xa7, 0x3c, 0x21, 0x11, 0xc3, 0x39, 0x01, 0x3d, 0x83, 0xaf,
0xc8, 0xb4, 0x5e, 0x5f, 0xe6, 0x05, 0xe7, 0x99, 0xfc, 0xfa, 0x80, 0x4c, 0x30, 0x22, 0x8b, 0x17,
0xf3, 0x12, 0x76, 0xa5, 0x12, 0x94, 0x24, 0xbe, 0xa4, 0x4a, 0x45, 0x6c, 0x24, 0x1b, 0x6b, 0x8b,
0xca, 0xd3, 0x36, 0x70, 0x8b, 0x36, 0x70, 0x87, 0x86, 0x65, 0xfd, 0xc1, 0x35, 0xab, 0x31, 0xcc,
0x25, 0xd0, 0x3f, 0xf0, 0x9d, 0xb0, 0x0e, 0xfa, 0x5c, 0x44, 0xa3, 0x88, 0x91, 0xd8, 0x0f, 0xa9,
0x54, 0x11, 0x33, 0xbb, 0x37, 0xd6, 0x5b, 0x4e, 0x67, 0x13, 0x37, 0x73, 0x4c, 0x3f, 0x87, 0x9c,
0xce, 0x10, 0xe8, 0x4f, 0x68, 0xe8, 0xd3, 0xde, 0xf8, 0x29, 0x91, 0x52, 0xeb, 0x04, 0x9c, 0x31,
0x1a, 0x18, 0x76, 0xc5, 0xb0, 0xf7, 0xcd, 0xfa, 0xc0, 0x2e, 0xf7, 0xa6, 0xab, 0xed, 0x37, 0x0e,
0xec, 0xe5, 0x3d, 0xf9, 0x2f, 0x61, 0x61, 0x3c, 0x0d, 0xb1, 0x0e, 0x65, 0x45, 0x46, 0x26, 0xbd,
0x2d, 0xac, 0x3f, 0xd1, 0x10, 0xbe, 0xcc, 0x8f, 0x20, 0x66, 0xe5, 0xdb, 0x80, 0x7e, 0x5a, 0x12,
0x90, 0x7d, 0x86, 0x4c, 0x43, 0x86, 0x17, 0xf6, 0x15, 0xc2, 0xf5, 0x42, 0x60, 0x5a, 0xfb, 0x05,
0xd4, 0x4c, 0x08, 0x33, 0xc5, 0xf2, 0x83, 0x14, 0x77, 0x0c, 0xbb, 0x90, 0x6b, 0xd7, 0xa1, 0xd6,
0x1f, 0xab, 0xf9, 0x27, 0xe6, 0xad, 0x03, 0xdb, 0x43, 0xca, 0xc2, 0x69, 0x61, 0x47, 0x50, 0x9e,
0x44, 0x24, 0xbf, 0x96, 0x1f, 0x71, 0xb3, 0x34, 0x7a, 0x59, 0xf0, 0xa5, 0xc7, 0x07, 0xff, 0xff,
0x8a, 0xe2, 0x7f, 0xb9, 0x47, 0x74, 0xa0, 0x49, 0xb9, 0xe6, 0x1d, 0x03, 0xde, 0x39, 0xf0, 0x75,
0xe1, 0xc0, 0x7d, 0x81, 0xf6, 0x61, 0x57, 0x1a, 0x67, 0x3e, 0x35, 0xce, 0x9a, 0xa5, 0x7f, 0xa6,
0x30, 0xd1, 0x3e, 0x54, 0xe8, 0x6d, 0x1a, 0x09, 0x6a, 0x9a, 0xac, 0x8c, 0xf3, 0x11, 0x6a, 0xc0,
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;
}
message StreamReceiverConfig {
message ReceiverConfig {
v2ray.core.common.net.PortRange port_range = 1;
v2ray.core.common.net.IPOrDomain listen = 2;
AllocationStrategy allocation_strategy = 3;
v2ray.core.transport.internet.StreamConfig stream_settings = 4;
}
message DatagramReceiverConfig {
v2ray.core.common.net.PortRange port_range = 1;
v2ray.core.common.net.IPOrDomain listen = 2;
AllocationStrategy allocation_strategy = 3;
bool receive_original_destination = 5;
bool allow_passive_connection = 6;
}
message InboundHandlerConfig {
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;
}
@ -69,21 +65,17 @@ message OutboundConfig {
}
message StreamSenderConfig {
message SenderConfig {
// Send traffic through the given IP. Only IP is allowed.
v2ray.core.common.net.IPOrDomain via = 1;
v2ray.core.transport.internet.StreamConfig stream_settings = 2;
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 {
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;
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 (
"context"
"errors"
"io"
"net"
"time"
"v2ray.com/core/app"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"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/ray"
)
type Handler struct {
config *proxyman.OutboundHandlerConfig
streamSettings *proxyman.StreamSenderConfig
datagramSettings *proxyman.DatagramSenderConfig
senderSettings *proxyman.SenderConfig
proxy proxy.OutboundHandler
outboundManager proxyman.OutboundHandlerManager
}
func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*Handler, error) {
h := &Handler{
config: config,
}
for _, rawSettings := range config.SenderSettings {
settings, err := rawSettings.GetInstance()
space := app.SpaceFromContext(ctx)
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 {
return nil, err
}
switch ts := settings.(type) {
case *proxyman.StreamSenderConfig:
h.streamSettings = ts
case *proxyman.DatagramSenderConfig:
h.datagramSettings = ts
switch s := senderSettings.(type) {
case *proxyman.SenderConfig:
h.senderSettings = s
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))
if err != nil {
return nil, err
@ -44,38 +63,114 @@ func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*H
return h, nil
}
func (h *Handler) Dial(ctx context.Context, destination net.Destination) (internet.Connection, error) {
switch destination.Network {
case net.Network_TCP:
return h.dialStream(ctx, destination)
case net.Network_UDP:
return h.dialDatagram(ctx, destination)
default:
panic("Proxyman|DefaultOutboundHandler: unexpected network.")
func (h *Handler) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) {
ctx = proxy.ContextWithDialer(ctx, h)
h.proxy.Process(ctx, outboundRay)
}
func (h *Handler) Dial(ctx context.Context, dest v2net.Destination) (internet.Connection, error) {
if h.senderSettings != nil {
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)
}
}
func (h *Handler) dialStream(ctx context.Context, destination net.Destination) (internet.Connection, error) {
var src net.Address
if h.streamSettings != nil {
src = h.streamSettings.Via.AsAddress()
}
var options internet.DialerOptions
if h.streamSettings != nil {
options.Proxy = h.streamSettings.ProxySettings
options.Stream = h.streamSettings.StreamSettings
}
return internet.Dial(src, destination, options)
return internet.Dial(ctx, dest)
}
func (h *Handler) dialDatagram(ctx context.Context, destination net.Destination) (internet.Connection, error) {
var src net.Address
if h.datagramSettings != nil {
src = h.datagramSettings.Via.AsAddress()
type Connection struct {
stream ray.Ray
closed bool
localAddr net.Addr
remoteAddr net.Addr
reader *buf.BufferToBytesReader
writer *buf.BytesToBufferWriter
}
var options internet.DialerOptions
if h.datagramSettings != nil {
options.Proxy = h.datagramSettings.ProxySettings
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()),
}
return internet.Dial(src, destination, options)
}
// 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) {
}

View File

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

View File

@ -11,21 +11,28 @@ import (
)
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 {
Start() error
Close()
// For migration
GetRandomInboundProxy() (proxy.InboundHandler, net.Port, int)
}
type OutboundHandlerManager interface {
GetHandler(tag string) proxy.OutboundHandler
GetDefaultHandler() proxy.OutboundHandler
SetDefaultHandler(handler proxy.OutboundHandler) error
SetHandler(tag string, handler proxy.OutboundHandler) error
GetHandler(tag string) OutboundHandler
GetDefaultHandler() OutboundHandler
AddHandler(ctx context.Context, config *OutboundHandlerConfig) error
}
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 {

View File

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

View File

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

View File

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

View File

@ -41,7 +41,8 @@ func TestSimpleRouter(t *testing.T) {
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.String(tag).Equals("test")
}

View File

@ -48,6 +48,10 @@ func (v Destination) String() string {
return v.Network.URLPrefix() + ":" + v.NetAddr()
}
func (v Destination) IsValid() bool {
return v.Network != Network_Unknown
}
func (v *Endpoint) AsDestination() Destination {
return Destination{
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)
creator, found := typeCreatorRegistry[configType]
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)
}

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 fmt "fmt"
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_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_transport_internet "v2ray.com/core/transport/internet"
import v2ray_core_transport "v2ray.com/core/transport"
// Reference imports to suppress errors if they are not otherwise used.
@ -43,225 +41,11 @@ func (x ConfigFormat) String() string {
}
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 {
// 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 []*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"`
// App configuration. Must be one in the app directory.
App []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,4,rep,name=app" json:"app,omitempty"`
@ -271,16 +55,16 @@ 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{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 {
return m.Inbound
}
return nil
}
func (m *Config) GetOutbound() []*OutboundConnectionConfig {
func (m *Config) GetOutbound() []*v2ray_core_app_proxyman.OutboundHandlerConfig {
if m != nil {
return m.Outbound
}
@ -309,65 +93,34 @@ func (m *Config) GetTransport() *v2ray_core_transport.Config {
}
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.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) }
var fileDescriptor0 = []byte{
// 745 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x95, 0xd1, 0x6e, 0xd3, 0x3a,
0x1c, 0xc6, 0x97, 0xb6, 0xeb, 0xda, 0x7f, 0xb7, 0x9e, 0xca, 0xe7, 0xe8, 0x9c, 0x9c, 0xc1, 0x50,
0x29, 0xdb, 0x28, 0x03, 0xa5, 0xa3, 0x08, 0x31, 0x21, 0xc1, 0xd8, 0x3a, 0x90, 0x06, 0x82, 0x16,
0x77, 0xe2, 0x82, 0x9b, 0xc8, 0x4b, 0xbd, 0x2c, 0x52, 0x62, 0x47, 0xb6, 0xbb, 0x2d, 0x8f, 0xc0,
0xab, 0x70, 0xc5, 0xab, 0xf0, 0x04, 0xbc, 0x0a, 0x72, 0x92, 0xa6, 0x1d, 0x6d, 0xb7, 0x49, 0x88,
0xbb, 0x34, 0xf9, 0x7e, 0x9f, 0x9d, 0xef, 0xfb, 0xc7, 0x85, 0x5b, 0x67, 0x6d, 0x41, 0x22, 0xcb,
0xe1, 0x41, 0xcb, 0xe1, 0x82, 0xb6, 0x1c, 0xce, 0x4e, 0x3c, 0xd7, 0x0a, 0x05, 0x57, 0x1c, 0xc1,
0xe8, 0xa1, 0xa0, 0xab, 0xdb, 0x53, 0xc2, 0x20, 0xe0, 0xac, 0x25, 0xa9, 0xf0, 0x88, 0xdf, 0x52,
0x51, 0x48, 0x07, 0x76, 0x40, 0xa5, 0x24, 0x2e, 0x4d, 0xe8, 0xd5, 0xf5, 0xd9, 0x04, 0xa3, 0xaa,
0x15, 0x72, 0xa1, 0x52, 0xd5, 0xfd, 0xf9, 0x2a, 0x32, 0x18, 0x08, 0x2a, 0x65, 0x2a, 0xdc, 0x9c,
0x2d, 0xf4, 0xb9, 0x7b, 0x69, 0xd3, 0xab, 0xd6, 0x2f, 0x3a, 0x25, 0x08, 0x93, 0x7a, 0xc1, 0x96,
0xc7, 0x14, 0x15, 0xda, 0xf8, 0x92, 0x7e, 0x63, 0xae, 0x7e, 0x52, 0xd6, 0x78, 0x0a, 0x6b, 0x7b,
0xbe, 0xcf, 0x1d, 0xa2, 0x3c, 0xce, 0xfa, 0x4a, 0x10, 0x45, 0xdd, 0xa8, 0xc3, 0x99, 0x33, 0x14,
0x82, 0x32, 0x27, 0x42, 0xff, 0xc0, 0xe2, 0x19, 0xf1, 0x87, 0xd4, 0x34, 0xea, 0x46, 0x73, 0x05,
0x27, 0x3f, 0x1a, 0x8f, 0xe1, 0xff, 0x69, 0x0c, 0xd3, 0x13, 0x41, 0xe5, 0xe9, 0x1c, 0xe4, 0x4b,
0x0e, 0xd0, 0x34, 0x83, 0x9e, 0x41, 0x41, 0xa7, 0x1c, 0x6b, 0xab, 0xed, 0x7b, 0xd6, 0xb8, 0x1b,
0x6b, 0x5a, 0x6d, 0x1d, 0x45, 0x21, 0xc5, 0x31, 0x80, 0xde, 0x41, 0xc5, 0x19, 0xef, 0xd3, 0xcc,
0xd5, 0x8d, 0x66, 0xa5, 0xfd, 0xe0, 0x6a, 0x7e, 0xe2, 0xc5, 0xf0, 0x24, 0x8d, 0x76, 0x61, 0x49,
0x24, 0xbb, 0x37, 0xf3, 0xb1, 0xd1, 0xc6, 0xd5, 0x46, 0xe9, 0xab, 0xe2, 0x11, 0xd5, 0x78, 0x04,
0x05, 0xbd, 0x37, 0x04, 0x50, 0xdc, 0xf3, 0xcf, 0x49, 0x24, 0x6b, 0x0b, 0xfa, 0x1a, 0x13, 0x36,
0xe0, 0x41, 0xcd, 0x40, 0xcb, 0x50, 0x7a, 0x7d, 0xa1, 0x7b, 0x22, 0x7e, 0x2d, 0xd7, 0xf8, 0x9e,
0x87, 0xff, 0x0e, 0xd9, 0x31, 0x1f, 0xb2, 0x41, 0x87, 0x33, 0x46, 0x1d, 0xed, 0xdd, 0x89, 0x7b,
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,
// 338 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x91, 0xdf, 0x4a, 0x02, 0x41,
0x14, 0xc6, 0xd3, 0x35, 0xb3, 0xa3, 0x84, 0xcc, 0xd5, 0x62, 0x05, 0x12, 0x24, 0x12, 0x34, 0x2b,
0xdb, 0x4d, 0x74, 0xa9, 0xd0, 0x1f, 0xa1, 0x0c, 0x8b, 0x2e, 0xba, 0x89, 0x71, 0x1d, 0x17, 0x61,
0x67, 0xce, 0x30, 0xbb, 0x46, 0xfb, 0x4a, 0x3d, 0x47, 0x0f, 0x16, 0x3b, 0xe3, 0xaa, 0x6b, 0x76,
0x7b, 0xe6, 0xfb, 0xfd, 0x0e, 0xe7, 0x1b, 0x38, 0xfe, 0xf4, 0x35, 0x4b, 0x69, 0x80, 0xc2, 0x0b,
0x50, 0x73, 0x2f, 0x40, 0x39, 0x9b, 0x87, 0x54, 0x69, 0x4c, 0x90, 0x40, 0xfe, 0xa8, 0x79, 0xab,
0xbb, 0x15, 0x64, 0x4a, 0x79, 0x4a, 0xe3, 0x57, 0x2a, 0x98, 0x2c, 0x50, 0xad, 0xde, 0x1f, 0xa5,
0x10, 0x28, 0xbd, 0x98, 0xeb, 0x39, 0x8b, 0xbc, 0x24, 0x55, 0x7c, 0xfa, 0x21, 0x78, 0x1c, 0xb3,
0x90, 0x2f, 0x89, 0xce, 0x6e, 0x22, 0xc2, 0xb0, 0x68, 0x3e, 0xdf, 0xca, 0x25, 0x9a, 0xc9, 0x58,
0xa1, 0x4e, 0x0a, 0xb1, 0xb3, 0x9f, 0x32, 0x54, 0x07, 0x66, 0x40, 0xee, 0xe0, 0x60, 0x2e, 0x27,
0xb8, 0x90, 0x53, 0xb7, 0xd4, 0x76, 0xba, 0x75, 0xff, 0x92, 0xae, 0x6f, 0xa2, 0x4c, 0x29, 0x9a,
0xdf, 0x40, 0x1f, 0x6c, 0xee, 0x9e, 0xc9, 0x69, 0xc4, 0xb5, 0xe5, 0xc7, 0x39, 0x4d, 0x86, 0x50,
0xc3, 0x45, 0x62, 0x4d, 0x65, 0x63, 0xa2, 0xff, 0x9a, 0x46, 0xcb, 0x60, 0x51, 0xb5, 0xe2, 0x89,
0x07, 0x4e, 0x84, 0xa1, 0xeb, 0xb4, 0x4b, 0xdd, 0xba, 0x7f, 0xba, 0xa9, 0xb1, 0x87, 0xd3, 0x08,
0x43, 0xba, 0xa4, 0xb2, 0x24, 0xb9, 0x06, 0x87, 0x29, 0xe5, 0x56, 0xcc, 0xde, 0xce, 0x0e, 0xc0,
0x76, 0x4b, 0x5f, 0xb3, 0x6e, 0x1f, 0x6d, 0xb5, 0xe3, 0x0c, 0x21, 0x37, 0x70, 0xb8, 0x2a, 0xc9,
0xdd, 0x37, 0x0b, 0x4f, 0x36, 0xf9, 0xd5, 0x63, 0xbe, 0x6f, 0x1d, 0xbf, 0xe8, 0x40, 0xc3, 0x0e,
0x6f, 0x51, 0x0b, 0x96, 0x90, 0x06, 0xd4, 0x9e, 0xb3, 0x7e, 0x27, 0x8b, 0x59, 0x73, 0x8f, 0xd4,
0xa0, 0x32, 0x7c, 0x19, 0x3d, 0x35, 0x4b, 0xfd, 0x1e, 0x1c, 0x05, 0x28, 0x36, 0xac, 0xfd, 0xba,
0xe5, 0x4c, 0xfa, 0xbd, 0x92, 0x8d, 0xbe, 0xcb, 0xf0, 0xe6, 0x8f, 0x59, 0x4a, 0x07, 0xa8, 0xf9,
0xa4, 0x6a, 0xfe, 0xe9, 0xea, 0x37, 0x00, 0x00, 0xff, 0xff, 0xa7, 0x35, 0x52, 0xbd, 0x7d, 0x02,
0x00, 0x00,
}

View File

@ -6,11 +6,9 @@ option go_package = "core";
option java_package = "com.v2ray.core";
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/net/port.proto";
import "v2ray.com/core/common/net/address.proto";
import "v2ray.com/core/common/log/config.proto";
import "v2ray.com/core/transport/internet/config.proto";
import "v2ray.com/core/transport/config.proto";
// Configuration serialization format.
@ -19,75 +17,13 @@ enum ConfigFormat {
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 {
// 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.
repeated OutboundConnectionConfig outbound = 2;
repeated v2ray.core.app.proxyman.OutboundHandlerConfig outbound = 2;
v2ray.core.common.log.Config log = 3;
// App configuration. Must be one in the app directory.

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.
_ "v2ray.com/core/app/dispatcher/impl"
_ "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/router"

View File

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

View File

@ -2,40 +2,24 @@ package proxy
import (
"context"
"v2ray.com/core/common/net"
)
type key int
const (
inboundMetaKey key = iota
outboundMetaKey
dialerKey
dialerKey key = iota
sourceKey
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 {
return context.WithValue(ctx, dialerKey, dialer)
}
@ -47,3 +31,93 @@ func DialerFromContext(ctx context.Context) 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 (
"context"
"sync"
"v2ray.com/core/app"
"v2ray.com/core/app/dispatcher"
@ -14,21 +13,13 @@ import (
"v2ray.com/core/common/signal"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/udp"
)
type DokodemoDoor struct {
tcpMutex sync.RWMutex
udpMutex sync.RWMutex
config *Config
accepting bool
address net.Address
port net.Port
packetDispatcher dispatcher.Interface
tcpListener *internet.TCPHub
udpHub *udp.Hub
udpServer *udp.Server
meta *proxy.InboundHandlerMeta
}
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 {
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 {
return nil, errors.New("DokodemoDoor: No network specified.")
}
@ -47,7 +34,6 @@ func New(ctx context.Context, config *Config) (*DokodemoDoor, error) {
config: config,
address: config.GetPredefinedAddress(),
port: net.Port(config.Port),
meta: meta,
}
space.OnInitialize(func() error {
d.packetDispatcher = dispatcher.FromSpace(space)
@ -59,140 +45,28 @@ func New(ctx context.Context, config *Config) (*DokodemoDoor, error) {
return d, nil
}
func (v *DokodemoDoor) Port() net.Port {
return v.meta.Port
func (d *DokodemoDoor) Network() net.NetworkList {
return *(d.config.NetworkList)
}
func (v *DokodemoDoor) Close() {
v.accepting = false
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()
func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn internet.Connection) error {
log.Debug("Dokodemo: processing connection from: ", conn.RemoteAddr())
conn.SetReusable(false)
var dest net.Destination
if v.config.FollowRedirect {
originalDest := GetOriginalDestination(conn)
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,
ctx = proxy.ContextWithDestination(ctx, net.Destination{
Network: network,
Address: d.address,
Port: d.port,
})
reader := net.NewTimeOutReader(v.config.Timeout, conn)
inboundRay := d.packetDispatcher.DispatchToOutbound(ctx)
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 {
log.Info("Dokodemo: Failed to transport all TCP request: ", err)
if err := buf.PipeUntilEOF(chunkReader, inboundRay.InboundInput()); err != nil {
log.Info("Dokodemo: Failed to transport request: ", err)
return err
}
@ -202,18 +76,21 @@ func (v *DokodemoDoor) HandleTCPConnection(conn internet.Connection) {
responseDone := signal.ExecuteAsync(func() error {
v2writer := buf.NewWriter(conn)
if err := buf.PipeUntilEOF(ray.InboundOutput(), v2writer); err != nil {
log.Info("Dokodemo: Failed to transport all TCP response: ", err)
if err := buf.PipeUntilEOF(inboundRay.InboundOutput(), v2writer); err != nil {
log.Info("Dokodemo: Failed to transport response: ", err)
return err
}
return nil
})
if err := signal.ErrorOrFinish2(requestDone, responseDone); err != nil {
ray.InboundInput().CloseError()
ray.InboundOutput().CloseError()
inboundRay.InboundInput().CloseError()
inboundRay.InboundOutput().CloseError()
log.Info("Dokodemo: Connection ends with ", err)
return err
}
return nil
}
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
timeout uint32
dns dns.Server
meta *proxy.OutboundHandlerMeta
}
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 {
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{
domainStrategy: config.DomainStrategy,
timeout: config.Timeout,
meta: meta,
}
space.OnInitialize(func() error {
if config.DomainStrategy == Config_USE_IP {
@ -75,18 +69,21 @@ func (v *Handler) ResolveIP(destination net.Destination) net.Destination {
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)
input := ray.OutboundInput()
output := ray.OutboundOutput()
input := outboundRay.OutboundInput()
output := outboundRay.OutboundOutput()
var conn internet.Connection
if v.domainStrategy == Config_USE_IP && destination.Address.Family().IsDomain() {
destination = v.ResolveIP(destination)
}
dialer := proxy.DialerFromContext(ctx)
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 {
return err
}
@ -95,7 +92,7 @@ func (v *Handler) Dispatch(destination net.Destination, ray ray.OutboundRay) {
})
if err != nil {
log.Warning("Freedom: Failed to open connection to ", destination, ": ", err)
return
return err
}
defer conn.Close()
@ -133,7 +130,10 @@ func (v *Handler) Dispatch(destination net.Destination, ray ray.OutboundRay) {
log.Info("Freedom: Connection ending with ", err)
input.CloseError()
output.CloseError()
return err
}
return nil
}
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.
type Server struct {
sync.Mutex
accepting bool
packetDispatcher dispatcher.Interface
config *ServerConfig
tcpListener *internet.TCPHub
meta *proxy.InboundHandlerMeta
}
// NewServer creates a new HTTP inbound handler.
@ -38,13 +35,8 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if space == nil {
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{
config: config,
meta: meta,
}
space.OnInitialize(func() error {
s.packetDispatcher = dispatcher.FromSpace(space)
@ -56,46 +48,12 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
return s, nil
}
// Port implements InboundHandler.Port().
func (v *Server) Port() v2net.Port {
return v.meta.Port
}
func (v *Server) Network() v2net.NetworkList {
func (*Server) Network() v2net.NetworkList {
return v2net.NetworkList{
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) {
port := defaultPort
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
}
func (v *Server) handleConnection(conn internet.Connection) {
defer conn.Close()
func (s *Server) Process(ctx context.Context, network v2net.Network, conn internet.Connection) error {
conn.SetReusable(false)
timedReader := v2net.NewTimeOutReader(v.config.Timeout, conn)
timedReader := v2net.NewTimeOutReader(s.config.Timeout, conn)
reader := bufio.OriginalReaderSize(timedReader, 2048)
request, err := http.ReadRequest(reader)
@ -131,7 +88,7 @@ func (v *Server) handleConnection(conn internet.Connection) {
if errors.Cause(err) != io.EOF {
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, "]")
defaultPort := v2net.Port(80)
@ -145,22 +102,18 @@ func (v *Server) handleConnection(conn internet.Connection) {
dest, err := parseHost(host, defaultPort)
if err != nil {
log.Warning("HTTP: Malformed proxy host (", host, "): ", err)
return
return err
}
log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "")
session := &proxy.SessionInfo{
Source: v2net.DestinationFromAddr(conn.RemoteAddr()),
Destination: dest,
Inbound: v.meta,
}
ctx = proxy.ContextWithDestination(ctx, dest)
if strings.ToUpper(request.Method) == "CONNECT" {
v.handleConnect(request, session, reader, conn)
return s.handleConnect(ctx, request, reader, conn)
} 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{
Status: "200 OK",
StatusCode: 200,
@ -174,10 +127,10 @@ func (v *Server) handleConnect(request *http.Request, session *proxy.SessionInfo
}
if err := response.Write(writer); err != nil {
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 {
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)
ray.InboundInput().CloseError()
ray.InboundOutput().CloseError()
return err
}
return nil
}
// @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.Set("Connection", "close")
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 {
response := v.GenerateResponse(400, "Bad Request")
response.Write(writer)
return
response := generateResponse(400, "Bad Request")
return response.Write(writer)
}
request.Host = request.URL.Host
StripHopByHopHeaders(request)
ray := v.packetDispatcher.DispatchToOutbound(session)
ray := s.packetDispatcher.DispatchToOutbound(ctx)
input := ray.InboundInput()
output := ray.InboundOutput()
@ -279,7 +233,7 @@ func (v *Server) handlePlainHTTP(request *http.Request, session *proxy.SessionIn
response, err := http.ReadResponse(responseReader, request)
if err != nil {
log.Warning("HTTP: Failed to read response: ", err)
response = v.GenerateResponse(503, "Service Unavailable")
response = generateResponse(503, "Service Unavailable")
}
responseWriter := bufio.NewWriter(writer)
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)
input.CloseError()
output.CloseError()
return err
}
return nil
}
func init() {

View File

@ -5,63 +5,20 @@ import (
"context"
"v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/transport/internet"
"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.
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
Process(context.Context, net.Network, internet.Connection) error
}
// An OutboundHandler handles outbound network connection for V2Ray.
type OutboundHandler interface {
// Dispatch sends one or more Packets to its destination.
Dispatch(destination net.Destination, ray ray.OutboundRay)
Process(context.Context, ray.OutboundRay) error
}
// Dialer is used by OutboundHandler for creating outbound connections.

View File

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

View File

@ -23,10 +23,6 @@ type Server struct {
config *ServerConfig
user *protocol.User
account *ShadowsocksAccount
meta *proxy.InboundHandlerMeta
accepting bool
tcpHub *internet.TCPHub
udpHub *udp.Hub
udpServer *udp.Server
}
@ -35,10 +31,6 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if space == nil {
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 {
return nil, protocol.ErrUserMissing
}
@ -51,7 +43,6 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
s := &Server{
config: config,
meta: meta,
user: config.GetUser(),
account: account,
}
@ -67,88 +58,63 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
return s, nil
}
func (v *Server) Network() net.NetworkList {
func (s *Server) Network() net.NetworkList {
list := net.NetworkList{
Network: []net.Network{net.Network_TCP},
}
if v.config.UdpEnabled {
if s.config.UdpEnabled {
list.Network = append(list.Network, net.Network_UDP)
}
return list
}
func (v *Server) Port() net.Port {
return v.meta.Port
}
func (v *Server) Close() {
v.accepting = false
// TODO: synchronization
if v.tcpHub != nil {
v.tcpHub.Close()
v.tcpHub = nil
}
if v.udpHub != nil {
v.udpHub.Close()
v.udpHub = nil
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection) error {
switch network {
case net.Network_TCP:
return s.handleConnection(ctx, conn)
case net.Network_UDP:
return s.handlerUDPPayload(ctx, conn)
default:
return errors.New("Shadowsocks|Server: Unknown network: ", network)
}
}
func (v *Server) Start() error {
if v.accepting {
return nil
}
func (v *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection) error {
source := proxy.SourceFromContext(ctx)
tcpHub, err := internet.ListenTCP(v.meta.Address, v.meta.Port, v.handleConnection, v.meta.StreamSettings)
reader := buf.NewReader(conn)
for {
payload, err := reader.Read()
if err != nil {
log.Error("Shadowsocks: Failed to listen TCP on ", v.meta.Address, ":", v.meta.Port, ": ", err)
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 {
log.Error("Shadowsocks: Failed to listen UDP on ", v.meta.Address, ":", v.meta.Port, ": ", err)
return err
}
v.udpHub = udpHub
break
}
v.accepting = true
return nil
}
func (v *Server) handlerUDPPayload(payload *buf.Buffer, session *proxy.SessionInfo) {
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
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()
return
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()
return
continue
}
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) {
ctx = protocol.ContextWithUser(ctx, request.User)
v.udpServer.Dispatch(ctx, dest, data, func(payload *buf.Buffer) {
defer payload.Release()
data, err := EncodeUDPPacket(request, payload)
@ -158,38 +124,37 @@ func (v *Server) handlerUDPPayload(payload *buf.Buffer, session *proxy.SessionIn
}
defer data.Release()
v.udpHub.WriteTo(data.Bytes(), source)
conn.Write(data.Bytes())
})
}
func (v *Server) handleConnection(conn internet.Connection) {
defer conn.Close()
return nil
}
func (s *Server) handleConnection(ctx context.Context, conn internet.Connection) error {
conn.SetReusable(false)
timedReader := net.NewTimeOutReader(16, conn)
bufferedReader := bufio.NewReader(timedReader)
request, bodyReader, err := ReadTCPSession(v.user, bufferedReader)
request, bodyReader, err := ReadTCPSession(s.user, bufferedReader)
if err != nil {
log.Access(conn.RemoteAddr(), "", log.AccessRejected, err)
log.Info("Shadowsocks|Server: Failed to create request from: ", conn.RemoteAddr(), ": ", err)
return
return err
}
bufferedReader.SetBuffered(false)
userSettings := v.user.GetSettings()
userSettings := s.user.GetSettings()
timedReader.SetTimeOut(userSettings.PayloadReadTimeout)
dest := request.Destination()
log.Access(conn.RemoteAddr(), dest, log.AccessAccepted, "")
log.Info("Shadowsocks|Server: Tunnelling request to ", dest)
ray := v.packetDispatcher.DispatchToOutbound(&proxy.SessionInfo{
Source: net.DestinationFromAddr(conn.RemoteAddr()),
Destination: dest,
User: request.User,
Inbound: v.meta,
})
ctx = proxy.ContextWithDestination(ctx, dest)
ctx = protocol.ContextWithUser(ctx, request.User)
ray := s.packetDispatcher.DispatchToOutbound(ctx)
requestDone := signal.ExecuteAsync(func() error {
bufferedWriter := bufio.NewWriter(conn)
@ -234,7 +199,10 @@ func (v *Server) handleConnection(conn internet.Connection) {
log.Info("Shadowsocks|Server: Connection ends with ", err)
ray.InboundInput().CloseError()
ray.InboundOutput().CloseError()
return err
}
return nil
}
func init() {

View File

@ -2,7 +2,6 @@ package socks
import (
"context"
"errors"
"v2ray.com/core/common"
"v2ray.com/core/common/buf"
@ -18,34 +17,31 @@ import (
type Client struct {
serverPicker protocol.ServerPicker
meta *proxy.OutboundHandlerMeta
}
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()
for _, rec := range config.Server {
serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
}
client := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
meta: meta,
}
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 conn internet.Connection
dialer := proxy.DialerFromContext(ctx)
err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer()
dest := server.Destination()
rawConn, err := internet.Dial(c.meta.Address, dest, c.meta.GetDialerOptions())
rawConn, err := dialer.Dial(ctx, dest)
if err != nil {
return err
}
@ -56,7 +52,7 @@ func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
if err != nil {
log.Warning("Socks|Client: Failed to find an available destination.")
return
return err
}
defer conn.Close()
@ -80,7 +76,7 @@ func (c *Client) Dispatch(destination net.Destination, ray ray.OutboundRay) {
udpRequest, err := ClientHandshake(request, conn, conn)
if err != nil {
log.Warning("Socks|Client: Failed to establish connection to server: ", err)
return
return err
}
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())
}
} 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 {
log.Info("Socks|Client: Failed to create UDP connection: ", err)
return
return err
}
defer udpConn.Close()
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)
ray.OutboundInput().CloseError()
ray.OutboundOutput().CloseError()
return err
}
return nil
}
func init() {

View File

@ -8,7 +8,6 @@ import (
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy"
)
const (
@ -37,7 +36,7 @@ const (
type ServerSession struct {
config *ServerConfig
meta *proxy.InboundHandlerMeta
port v2net.Port
}
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
}
responseAddress = addr
responsePort = s.meta.Port
responsePort = s.port
}
if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {
return nil, err

View File

@ -3,7 +3,6 @@ package socks
import (
"context"
"io"
"sync"
"time"
"v2ray.com/core/app"
@ -23,16 +22,9 @@ import (
// Server is a SOCKS 5 proxy server
type Server struct {
tcpMutex sync.RWMutex
udpMutex sync.RWMutex
accepting bool
packetDispatcher dispatcher.Interface
config *ServerConfig
tcpListener *internet.TCPHub
udpHub *udp.Hub
udpAddress net.Destination
udpServer *udp.Server
meta *proxy.InboundHandlerMeta
}
// NewServer creates a new Server object.
@ -41,135 +33,89 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
if space == nil {
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{
config: config,
meta: meta,
}
space.OnInitialize(func() error {
s.packetDispatcher = dispatcher.FromSpace(space)
if s.packetDispatcher == nil {
return errors.New("Socks|Server: Dispatcher is not found in the space.")
}
s.udpServer = udp.NewServer(s.packetDispatcher)
return nil
})
return s, nil
}
func (v *Server) Network() net.NetworkList {
func (s *Server) Network() net.NetworkList {
list := net.NetworkList{
Network: []net.Network{net.Network_TCP},
}
if v.config.UdpEnabled {
if s.config.UdpEnabled {
list.Network = append(list.Network, net.Network_UDP)
}
return list
}
// Port implements InboundHandler.Port().
func (v *Server) Port() net.Port {
return v.meta.Port
}
// Close implements InboundHandler.Close().
func (v *Server) Close() {
v.accepting = false
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 (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection) error {
switch network {
case net.Network_TCP:
return s.processTCP(ctx, conn)
case net.Network_UDP:
return s.handleUDPPayload(ctx, conn)
default:
return errors.New("Socks|Server: Unknown network: ", network)
}
}
// Start implements InboundHandler.Start().
func (v *Server) Start() error {
if v.accepting {
return nil
}
func (s *Server) processTCP(ctx context.Context, conn internet.Connection) error {
conn.SetReusable(false)
listener, err := internet.ListenTCP(
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)
timedReader := net.NewTimeOutReader(16 /* seconds, for handshake */, conn)
reader := bufio.NewReader(timedReader)
inboundDest := proxy.InboundDestinationFromContext(ctx)
session := &ServerSession{
config: v.config,
meta: v.meta,
config: s.config,
port: inboundDest.Port,
}
clientAddr := net.DestinationFromAddr(connection.RemoteAddr())
request, err := session.Handshake(reader, connection)
source := proxy.SourceFromContext(ctx)
request, err := session.Handshake(reader, conn)
if err != nil {
log.Access(clientAddr, "", log.AccessRejected, err)
log.Access(source, "", log.AccessRejected, err)
log.Info("Socks|Server: Failed to read request: ", err)
return
return err
}
if request.Command == protocol.RequestCommandTCP {
dest := request.Destination()
session := &proxy.SessionInfo{
Source: clientAddr,
Destination: dest,
Inbound: v.meta,
}
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)
v.transport(reader, connection, session)
return
timedReader.SetTimeOut(s.config.Timeout)
ctx = proxy.ContextWithDestination(ctx, dest)
return s.transport(ctx, reader, conn)
}
if request.Command == protocol.RequestCommandUDP {
v.handleUDP()
return
}
return s.handleUDP()
}
func (v *Server) handleUDP() {
return nil
}
func (*Server) handleUDP() error {
// The TCP connection closes after v method returns. We need to wait until
// the client closes it.
// TODO: get notified from UDP part
<-time.After(5 * time.Minute)
return nil
}
func (v *Server) transport(reader io.Reader, writer io.Writer, session *proxy.SessionInfo) {
ray := v.packetDispatcher.DispatchToOutbound(session)
func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer) error {
ray := v.packetDispatcher.DispatchToOutbound(ctx)
input := ray.InboundInput()
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)
input.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
clients protocol.UserValidator
usersByEmail *userByEmail
accepting bool
listener *internet.TCPHub
detours *DetourConfig
meta *proxy.InboundHandlerMeta
}
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 {
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)
for _, user := range config.User {
@ -102,7 +95,6 @@ func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) {
clients: allowedClients,
detours: config.Detour,
usersByEmail: NewUserByEmail(config.User, config.GetDefaultValue()),
meta: meta,
}
space.OnInitialize(func() error {
@ -120,36 +112,16 @@ func New(ctx context.Context, config *Config) (*VMessInboundHandler, error) {
return handler, nil
}
func (v *VMessInboundHandler) Network() net.NetworkList {
func (*VMessInboundHandler) Network() net.NetworkList {
return net.NetworkList{
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 {
v.RLock()
defer v.RUnlock()
if !v.accepting {
return nil
}
user, existing := v.usersByEmail.Get(email)
if !existing {
v.clients.Add(user)
@ -157,23 +129,6 @@ func (v *VMessInboundHandler) GetUser(email string) *protocol.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 {
defer output.Close()
@ -219,23 +174,12 @@ func transferResponse(session *encoding.ServerSession, request *protocol.Request
return nil
}
func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) {
defer connection.Close()
if !v.accepting {
return
}
func (v *VMessInboundHandler) Process(ctx context.Context, network net.Network, connection internet.Connection) error {
connReader := net.NewTimeOutReader(8, connection)
reader := bufio.NewReader(connReader)
v.RLock()
if !v.accepting {
v.RUnlock()
return
}
session := encoding.NewServerSession(v.clients)
request, err := session.DecodeRequestHeader(reader)
v.RUnlock()
if err != nil {
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)
}
connection.SetReusable(false)
return
return err
}
log.Access(connection.RemoteAddr(), request.Destination(), log.AccessAccepted, "")
log.Info("VMess|Inbound: Received request for ", request.Destination())
connection.SetReusable(request.Option.Has(protocol.RequestOptionConnectionReuse))
ray := v.packetDispatcher.DispatchToOutbound(&proxy.SessionInfo{
Source: net.DestinationFromAddr(connection.RemoteAddr()),
Destination: request.Destination(),
User: request.User,
Inbound: v.meta,
})
ctx = proxy.ContextWithDestination(ctx, request.Destination())
ctx = protocol.ContextWithUser(ctx, request.User)
ray := v.packetDispatcher.DispatchToOutbound(ctx)
input := ray.InboundInput()
output := ray.InboundOutput()
@ -269,7 +211,7 @@ func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) {
writer := bufio.NewWriter(connection)
response := &protocol.ResponseHeader{
Command: v.generateCommand(request),
Command: v.generateCommand(ctx, request),
}
if connection.Reusable() {
@ -285,14 +227,52 @@ func (v *VMessInboundHandler) HandleConnection(connection internet.Connection) {
connection.SetReusable(false)
input.CloseError()
output.CloseError()
return
return err
}
if err := writer.Flush(); err != nil {
log.Info("VMess|Inbound: Failed to flush remain data: ", err)
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() {

View File

@ -25,7 +25,6 @@ import (
type VMessOutboundHandler struct {
serverList *protocol.ServerList
serverPicker protocol.ServerPicker
meta *proxy.OutboundHandlerMeta
}
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 {
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()
for _, rec := range config.Receiver {
@ -45,20 +40,20 @@ func New(ctx context.Context, config *Config) (*VMessOutboundHandler, error) {
handler := &VMessOutboundHandler{
serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
meta: meta,
}
return handler, nil
}
// 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 conn internet.Connection
dialer := proxy.DialerFromContext(ctx)
err := retry.ExponentialBackoff(5, 100).On(func() error {
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 {
return err
}
@ -68,8 +63,11 @@ func (v *VMessOutboundHandler) Dispatch(target net.Destination, outboundRay ray.
})
if err != nil {
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())
command := protocol.RequestCommandTCP
@ -88,12 +86,11 @@ func (v *VMessOutboundHandler) Dispatch(target net.Destination, outboundRay ray.
rawAccount, err := request.User.GetTypedAccount()
if err != nil {
log.Warning("VMess|Outbound: Failed to get user account: ", err)
return err
}
account := rawAccount.(*vmess.InternalAccount)
request.Security = account.Security
defer conn.Close()
conn.SetReusable(true)
if conn.Reusable() { // Conn reuse may be disabled on transportation layer
request.Option.Set(protocol.RequestOptionConnectionReuse)
@ -160,9 +157,10 @@ func (v *VMessOutboundHandler) Dispatch(target net.Destination, outboundRay ray.
conn.SetReusable(false)
input.CloseError()
output.CloseError()
return err
}
return
return nil
}
func init() {

View File

@ -5,6 +5,7 @@ import (
"testing"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
@ -32,11 +33,13 @@ func TestDokodemoTCP(t *testing.T) {
userID := protocol.NewID(uuid.New())
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
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())
clientPortRange := uint32(5)
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange},
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -129,11 +134,13 @@ func TestDokodemoUDP(t *testing.T) {
userID := protocol.NewID(uuid.New())
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
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())
clientPortRange := uint32(5)
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange},
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),

View File

@ -5,6 +5,7 @@ import (
"testing"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/router"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
@ -34,12 +35,14 @@ func TestPassiveConnection(t *testing.T) {
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
AllowPassiveConnection: true,
Settings: serial.ToTypedMessage(&dokodemo.Config{
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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())
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
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())
proxyPort := pickPort()
proxyConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(proxyPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
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()
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(clientPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -182,13 +191,15 @@ func TestProxy(t *testing.T) {
},
},
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
ProxySettings: &internet.ProxyConfig{
Tag: "proxy",
},
}),
},
{
Tag: "proxy",
Settings: serial.ToTypedMessage(&outbound.Config{
ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -244,11 +255,16 @@ func TestProxyOverKCP(t *testing.T) {
serverUserID := protocol.NewID(uuid.New())
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
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{
{
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())
proxyPort := pickPort()
proxyConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(proxyPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
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{}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
},
}),
},
},
}
clientPort := pickPort()
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(clientPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -329,16 +348,18 @@ func TestProxyOverKCP(t *testing.T) {
},
},
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
ProxySettings: &internet.ProxyConfig{
Tag: "proxy",
},
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
},
}),
},
{
Tag: "proxy",
Settings: serial.ToTypedMessage(&outbound.Config{
ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -401,11 +422,13 @@ func TestBlackhole(t *testing.T) {
serverPort := pickPort()
serverPort2 := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
NetworkList: &v2net.NetworkList{
@ -414,9 +437,11 @@ func TestBlackhole(t *testing.T) {
}),
},
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort2),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest2.Address),
Port: uint32(dest2.Port),
NetworkList: &v2net.NetworkList{
@ -425,14 +450,14 @@ func TestBlackhole(t *testing.T) {
}),
},
},
Outbound: []*core.OutboundConnectionConfig{
Outbound: []*proxyman.OutboundHandlerConfig{
{
Tag: "direct",
Settings: serial.ToTypedMessage(&freedom.Config{}),
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
{
Tag: "blocked",
Settings: serial.ToTypedMessage(&blackhole.Config{}),
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
},
},
App: []*serial.TypedMessage{

View File

@ -7,6 +7,7 @@ import (
xproxy "golang.org/x/net/proxy"
socks4 "h12.me/socks"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
@ -30,11 +31,13 @@ func TestSocksBridgeTCP(t *testing.T) {
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&socks.ServerConfig{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_PASSWORD,
Accounts: map[string]string{
"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()
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(clientPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -123,11 +128,13 @@ func TestSocksBridageUDP(t *testing.T) {
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&socks.ServerConfig{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_PASSWORD,
Accounts: map[string]string{
"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()
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(clientPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -217,11 +226,13 @@ func TestSocksConformance(t *testing.T) {
authPort := pickPort()
noAuthPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(authPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&socks.ServerConfig{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_PASSWORD,
Accounts: map[string]string{
"Test Account": "Test Password",
@ -231,9 +242,11 @@ func TestSocksConformance(t *testing.T) {
}),
},
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(noAuthPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&socks.ServerConfig{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&socks.ServerConfig{
AuthType: socks.AuthType_NO_AUTH,
Accounts: map[string]string{
"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"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
@ -35,19 +36,11 @@ func TestSimpleTLSConnection(t *testing.T) {
userID := protocol.NewID(uuid.New())
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
@ -56,22 +49,34 @@ func TestSimpleTLSConnection(t *testing.T) {
}),
},
},
},
},
Outbound: []*core.OutboundConnectionConfig{
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Settings: serial.ToTypedMessage(&freedom.Config{}),
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
},
},
Outbound: []*proxyman.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := pickPort()
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(clientPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -97,6 +102,7 @@ func TestSimpleTLSConnection(t *testing.T) {
},
},
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
@ -105,6 +111,7 @@ func TestSimpleTLSConnection(t *testing.T) {
}),
},
},
}),
},
},
}
@ -143,19 +150,11 @@ func TestTLSOverKCP(t *testing.T) {
userID := protocol.NewID(uuid.New())
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
SecurityType: serial.GetMessageType(&tls.Config{}),
@ -165,22 +164,34 @@ func TestTLSOverKCP(t *testing.T) {
}),
},
},
},
},
Outbound: []*core.OutboundConnectionConfig{
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Settings: serial.ToTypedMessage(&freedom.Config{}),
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
},
},
Outbound: []*proxyman.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := pickPort()
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(clientPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -206,6 +217,7 @@ func TestTLSOverKCP(t *testing.T) {
},
},
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
Protocol: internet.TransportProtocol_MKCP,
SecurityType: serial.GetMessageType(&tls.Config{}),
@ -215,6 +227,7 @@ func TestTLSOverKCP(t *testing.T) {
}),
},
},
}),
},
},
}
@ -253,19 +266,11 @@ func TestTLSConnectionReuse(t *testing.T) {
userID := protocol.NewID(uuid.New())
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
@ -274,22 +279,34 @@ func TestTLSConnectionReuse(t *testing.T) {
}),
},
},
},
},
Outbound: []*core.OutboundConnectionConfig{
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Settings: serial.ToTypedMessage(&freedom.Config{}),
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
},
},
Outbound: []*proxyman.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := pickPort()
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(clientPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -315,6 +332,7 @@ func TestTLSConnectionReuse(t *testing.T) {
},
},
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
@ -323,6 +341,7 @@ func TestTLSConnectionReuse(t *testing.T) {
}),
},
},
}),
},
},
}

View File

@ -6,6 +6,7 @@ import (
"time"
"v2ray.com/core"
"v2ray.com/core/app/proxyman"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
@ -35,19 +36,11 @@ func TestNoOpConnectionHeader(t *testing.T) {
userID := protocol.NewID(uuid.New())
serverPort := pickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(serverPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
TransportSettings: []*internet.TransportConfig{
{
@ -58,22 +51,34 @@ func TestNoOpConnectionHeader(t *testing.T) {
},
},
},
},
},
Outbound: []*core.OutboundConnectionConfig{
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Settings: serial.ToTypedMessage(&freedom.Config{}),
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
},
},
Outbound: []*proxyman.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
clientPort := pickPort()
clientConfig := &core.Config{
Inbound: []*core.InboundConnectionConfig{
Inbound: []*proxyman.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: v2net.SinglePortRange(clientPort),
ListenOn: v2net.NewIPOrDomain(v2net.LocalHostIP),
Settings: serial.ToTypedMessage(&dokodemo.Config{
Listen: v2net.NewIPOrDomain(v2net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: v2net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
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{
{
Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
@ -99,6 +104,7 @@ func TestNoOpConnectionHeader(t *testing.T) {
},
},
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
TransportSettings: []*internet.TransportConfig{
{
@ -109,6 +115,7 @@ func TestNoOpConnectionHeader(t *testing.T) {
},
},
},
}),
},
},
}

View File

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

View File

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

View File

@ -56,6 +56,24 @@ func (v *StreamConfig) GetEffectiveTransportSettings() (interface{}, error) {
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) {
for _, settings := range v.SecuritySettings {
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
import (
"context"
"net"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
)
type DialerOptions struct {
Stream *StreamConfig
Proxy *ProxyConfig
}
type Dialer func(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error)
type Dialer func(ctx context.Context, dest v2net.Destination) (Connection, error)
var (
transportDialerCache = make(map[TransportProtocol]Dialer)
ProxyDialer Dialer
)
func RegisterTransportDialer(protocol TransportProtocol, dialer Dialer) error {
@ -29,26 +22,34 @@ func RegisterTransportDialer(protocol TransportProtocol, dialer Dialer) error {
return nil
}
func Dial(src v2net.Address, dest v2net.Destination, options DialerOptions) (Connection, error) {
if options.Proxy.HasTag() && ProxyDialer != nil {
log.Info("Internet: Proxying outbound connection through: ", options.Proxy.Tag)
return ProxyDialer(src, dest, options)
}
func Dial(ctx context.Context, dest v2net.Destination) (Connection, error) {
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]
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]
if udpDialer == nil {
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.

View File

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

View File

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

View File

@ -13,7 +13,6 @@ import (
"v2ray.com/core/common/errors"
"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/internal"
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
}
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()
src := session.Source
segments := v.reader.Read(payload.Bytes())
if len(segments) == 0 {
log.Info("KCP|Listener: discarding invalid payload from ", src)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
package udp
import (
"context"
"v2ray.com/core/common"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/transport/internet"
@ -9,7 +11,8 @@ import (
func init() {
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)
if err != nil {
return nil, err

View File

@ -9,18 +9,18 @@ import (
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/common/signal"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/internet/internal"
)
// Payload represents a single UDP payload.
type Payload struct {
payload *buf.Buffer
session *proxy.SessionInfo
source v2net.Destination
originalDest v2net.Destination
}
// 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.
type PayloadQueue struct {
@ -59,7 +59,7 @@ func (v *PayloadQueue) Enqueue(payload Payload) {
func (v *PayloadQueue) Dequeue(queue <-chan Payload) {
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 {
return nil, err
}
log.Info("UDP|Hub: Listening on ", address, ":", port)
if option.ReceiveOriginalDest {
fd, err := internal.GetSysFd(udpConn)
if err != nil {
@ -155,15 +156,14 @@ func (v *Hub) start() {
continue
}
session := new(proxy.SessionInfo)
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 := Payload{
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
import (
"context"
"sync"
"time"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/common/buf"
@ -12,95 +12,17 @@ import (
"v2ray.com/core/transport/ray"
)
type ResponseCallback func(destination v2net.Destination, 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 ResponseCallback func(payload *buf.Buffer)
type Server struct {
sync.RWMutex
conns map[string]*TimedInboundRay
conns map[string]ray.InboundRay
packetDispatcher dispatcher.Interface
}
func NewServer(packetDispatcher dispatcher.Interface) *Server {
return &Server{
conns: make(map[string]*TimedInboundRay),
conns: make(map[string]ray.InboundRay),
packetDispatcher: packetDispatcher,
}
}
@ -108,69 +30,53 @@ func NewServer(packetDispatcher dispatcher.Interface) *Server {
func (v *Server) RemoveRay(name string) {
v.Lock()
defer v.Unlock()
if conn, found := v.conns[name]; found {
conn.InboundInput().Close()
conn.InboundOutput().Close()
delete(v.conns, name)
}
func (v *Server) locateExistingAndDispatch(name string, payload *buf.Buffer) bool {
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()
defer v.Unlock()
if entry, found := v.conns[dest]; found {
if entry, found := v.conns[destString]; found {
return entry, true
}
log.Info("UDP|Server: establishing new connection for ", dest)
inboundRay := v.packetDispatcher.DispatchToOutbound(session)
return NewTimedInboundRay(dest, inboundRay, v), false
ctx = proxy.ContextWithDestination(ctx, dest)
return v.packetDispatcher.DispatchToOutbound(ctx), false
}
func (v *Server) Dispatch(session *proxy.SessionInfo, payload *buf.Buffer, callback ResponseCallback) {
source := session.Source
destination := session.Destination
func (v *Server) Dispatch(ctx context.Context, destination v2net.Destination, payload *buf.Buffer, callback ResponseCallback) {
// TODO: Add user to destString
destString := source.String() + "-" + destination.String()
destString := destination.String()
log.Debug("UDP|Server: Dispatch request: ", destString)
inboundRay, existing := v.getInboundRay(destString, session)
inboundRay, existing := v.getInboundRay(ctx, destination)
outputStream := inboundRay.InboundInput()
if outputStream != nil {
outputStream.Write(payload)
if err := outputStream.Write(payload); err != nil {
v.RemoveRay(destString)
}
}
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 {
inputStream := inboundRay.InboundOutput()
if inputStream == nil {
break
}
data, err := inputStream.Read()
data, err := input.Read()
if err != nil {
break
}
callback(source, data)
callback(data)
}
inboundRay.Release()
}

View File

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

View File

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

View File

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

View File

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

103
v2ray.go
View File

@ -6,22 +6,13 @@ import (
"v2ray.com/core/app"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/dns"
proxydialer "v2ray.com/core/app/proxy"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/log"
v2net "v2ray.com/core/common/net"
"v2ray.com/core/proxy"
)
// Point shell of V2Ray.
type Point struct {
inboundHandlers []InboundDetourHandler
taggedInboundHandlers map[string]InboundDetourHandler
outboundHandlers []proxy.OutboundHandler
taggedOutboundHandlers map[string]proxy.OutboundHandler
space app.Space
}
@ -42,7 +33,6 @@ func NewPoint(pConfig *Config) (*Point, error) {
ctx := app.ContextWithSpace(context.Background(), space)
vpoint.space = space
vpoint.space.AddApplication(vpoint)
outboundHandlerManager := proxyman.OutboundHandlerManagerFromSpace(space)
if outboundHandlerManager == nil {
@ -54,16 +44,15 @@ func NewPoint(pConfig *Config) (*Point, error) {
outboundHandlerManager = o.(proxyman.OutboundHandlerManager)
}
proxyDialer := proxydialer.OutboundProxyFromSpace(space)
if proxyDialer == nil {
p, err := app.CreateAppFromConfig(ctx, new(proxydialer.Config))
inboundHandlerManager := proxyman.InboundHandlerManagerFromSpace(space)
if inboundHandlerManager == nil {
o, err := app.CreateAppFromConfig(ctx, new(proxyman.InboundConfig))
if err != nil {
return nil, err
}
space.AddApplication(p)
proxyDialer = p.(*proxydialer.OutboundProxy)
space.AddApplication(o)
inboundHandlerManager = o.(proxyman.InboundHandlerManager)
}
proxyDialer.RegisterDialer()
for _, appSettings := range pConfig.App {
settings, err := appSettings.GetInstance()
@ -104,62 +93,16 @@ func NewPoint(pConfig *Config) (*Point, error) {
disp = d.(dispatcher.Interface)
}
vpoint.inboundHandlers = make([]InboundDetourHandler, 0, 8)
vpoint.taggedInboundHandlers = make(map[string]InboundDetourHandler)
for _, inbound := range pConfig.Inbound {
allocConfig := inbound.GetAllocationStrategyValue()
var inboundHandler InboundDetourHandler
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
if err := inboundHandlerManager.AddHandler(ctx, inbound); err != nil {
return nil, err
}
}
vpoint.outboundHandlers = make([]proxy.OutboundHandler, 0, 8)
vpoint.taggedOutboundHandlers = make(map[string]proxy.OutboundHandler)
for idx, outbound := range pConfig.Outbound {
outboundSettings, err := outbound.GetTypedSettings()
if err != nil {
for _, outbound := range pConfig.Outbound {
if err := outboundHandlerManager.AddHandler(ctx, outbound); err != nil {
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 {
@ -169,39 +112,19 @@ func NewPoint(pConfig *Config) (*Point, error) {
return vpoint, nil
}
func (Point) Interface() interface{} {
return (*proxyman.InboundHandlerManager)(nil)
}
func (v *Point) Close() {
for _, inbound := range v.inboundHandlers {
inbound.Close()
}
ihm := proxyman.InboundHandlerManagerFromSpace(v.space)
ihm.Close()
}
// 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.
func (v *Point) Start() error {
for _, inbound := range v.inboundHandlers {
err := inbound.Start()
if err != nil {
ihm := proxyman.InboundHandlerManagerFromSpace(v.space)
if err := ihm.Start(); err != nil {
return err
}
}
log.Warning("V2Ray started.")
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() {
}