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:
parent
3bbdf2a065
commit
ca721230e1
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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))
|
||||
}))
|
||||
}
|
@ -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()
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
78
app/proxyman/inbound/always.go
Normal file
78
app/proxyman/inbound/always.go
Normal 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
|
||||
}
|
143
app/proxyman/inbound/dynamic.go
Normal file
143
app/proxyman/inbound/dynamic.go
Normal 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)
|
||||
}
|
94
app/proxyman/inbound/inbound.go
Normal file
94
app/proxyman/inbound/inbound.go
Normal 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))
|
||||
}))
|
||||
}
|
269
app/proxyman/inbound/worker.go
Normal file
269
app/proxyman/inbound/worker.go
Normal 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
|
||||
}
|
@ -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) {
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
//}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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,
|
||||
|
23
common/protocol/context.go
Normal file
23
common/protocol/context.go
Normal 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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
55
config.go
55
config.go
@ -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()
|
||||
}
|
305
config.pb.go
305
config.pb.go
@ -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,
|
||||
}
|
||||
|
72
config.proto
72
config.proto
@ -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.
|
||||
|
@ -1,11 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"v2ray.com/core/proxy"
|
||||
)
|
||||
|
||||
type InboundDetourHandler interface {
|
||||
Start() error
|
||||
Close()
|
||||
GetConnectionHandler() (proxy.InboundHandler, int)
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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"
|
||||
|
||||
|
@ -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() {
|
||||
|
128
proxy/context.go
128
proxy/context.go
@ -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
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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))
|
||||
}
|
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
@ -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() {
|
||||
|
@ -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.
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
@ -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
|
||||
}
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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),
|
||||
|
@ -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{
|
||||
|
@ -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{}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -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) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -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) {
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
52
transport/internet/context.go
Normal file
52
transport/internet/context.go
Normal 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)
|
||||
}
|
@ -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.
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -1,6 +1,6 @@
|
||||
// +build linux
|
||||
|
||||
package dokodemo
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"syscall"
|
@ -1,6 +1,6 @@
|
||||
// +build !linux
|
||||
|
||||
package dokodemo
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"v2ray.com/core/common/net"
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
103
v2ray.go
@ -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() {
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user