Merge pull request #1 from v2ray/master

Pull
pull/861/head
Ariselia 2018-02-11 18:05:21 +08:00 committed by GitHub
commit 693c9bda49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
130 changed files with 4323 additions and 2182 deletions

View File

@ -1,7 +1,7 @@
sudo: required sudo: required
language: go language: go
go: go:
- 1.9.2 - 1.9.4
go_import_path: v2ray.com/core go_import_path: v2ray.com/core
git: git:
depth: 5 depth: 5

View File

@ -1,4 +0,0 @@
package api
type ApiServer struct {
}

View File

@ -1,9 +0,0 @@
package api
import (
"v2ray.com/core/common/net"
)
type Config struct {
DirectPort net.Port
}

View File

@ -1,3 +1 @@
package app package app
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg app -path App

View File

@ -0,0 +1,95 @@
package commander
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg commander -path App,Commander
import (
"context"
"net"
"sync"
"google.golang.org/grpc"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/common/signal"
)
type Commander struct {
sync.Mutex
server *grpc.Server
config Config
v *core.Instance
ohm core.OutboundHandlerManager
}
func NewCommander(ctx context.Context, config *Config) (*Commander, error) {
v := core.FromContext(ctx)
if v == nil {
return nil, newError("V is not in context.")
}
c := &Commander{
config: *config,
ohm: v.OutboundHandlerManager(),
v: v,
}
if err := v.RegisterFeature((*core.Commander)(nil), c); err != nil {
return nil, err
}
return c, nil
}
func (c *Commander) Start() error {
c.Lock()
c.server = grpc.NewServer()
for _, rawConfig := range c.config.Service {
config, err := rawConfig.GetInstance()
if err != nil {
return err
}
rawService, err := c.v.CreateObject(config)
if err != nil {
return err
}
service, ok := rawService.(Service)
if !ok {
return newError("not a Service.")
}
service.Register(c.server)
}
c.Unlock()
listener := &OutboundListener{
buffer: make(chan net.Conn, 4),
done: signal.NewDone(),
}
go func() {
if err := c.server.Serve(listener); err != nil {
newError("failed to start grpc server").Base(err).AtError().WriteToLog()
}
}()
c.ohm.RemoveHandler(context.Background(), c.config.Tag)
c.ohm.AddHandler(context.Background(), &CommanderOutbound{
tag: c.config.Tag,
listener: listener,
})
return nil
}
func (c *Commander) Close() error {
c.Lock()
defer c.Unlock()
if c.server != nil {
c.server.Stop()
c.server = nil
}
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
return NewCommander(ctx, cfg.(*Config))
}))
}

View File

@ -0,0 +1,68 @@
package commander
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import v2ray_core_common_serial "v2ray.com/core/common/serial"
// 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
// Config is the settings for Commander.
type Config struct {
// Tag of the outbound handler that handles grpc connections.
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
// Services that supported by this server. All services must implement Service interface.
Service []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,rep,name=service" json:"service,omitempty"`
}
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 (m *Config) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *Config) GetService() []*v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.Service
}
return nil
}
func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.app.commander.Config")
}
func init() { proto.RegisterFile("v2ray.com/core/app/commander/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 212 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2c, 0x33, 0x2a, 0x4a,
0xac, 0xd4, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0x2c, 0x28, 0xd0, 0x4f,
0xce, 0xcf, 0xcd, 0x4d, 0xcc, 0x4b, 0x49, 0x2d, 0xd2, 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7,
0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x80, 0x29, 0x2d, 0x4a, 0xd5, 0x4b, 0x2c, 0x28, 0xd0,
0x83, 0x2b, 0x93, 0x32, 0x40, 0x33, 0x04, 0x24, 0x93, 0x9f, 0xa7, 0x5f, 0x9c, 0x5a, 0x94, 0x99,
0x98, 0xa3, 0x5f, 0x52, 0x59, 0x90, 0x9a, 0x12, 0x9f, 0x9b, 0x5a, 0x5c, 0x9c, 0x98, 0x9e, 0x0a,
0x31, 0x4b, 0x29, 0x86, 0x8b, 0xcd, 0x19, 0x6c, 0xb6, 0x90, 0x00, 0x17, 0x73, 0x49, 0x62, 0xba,
0x04, 0xa3, 0x02, 0xa3, 0x06, 0x67, 0x10, 0x88, 0x29, 0xe4, 0xc0, 0xc5, 0x5e, 0x9c, 0x5a, 0x54,
0x96, 0x99, 0x9c, 0x2a, 0xc1, 0xa4, 0xc0, 0xac, 0xc1, 0x6d, 0xa4, 0xa6, 0x87, 0x64, 0x33, 0xc4,
0x6c, 0x3d, 0x88, 0xd9, 0x7a, 0x21, 0x20, 0xb3, 0x7d, 0x21, 0x46, 0x07, 0xc1, 0xb4, 0x39, 0xb9,
0x71, 0xc9, 0x24, 0xe7, 0xe7, 0xea, 0xe1, 0x72, 0x6f, 0x00, 0x63, 0x14, 0x27, 0x9c, 0xb3, 0x8a,
0x49, 0x22, 0xcc, 0x28, 0x28, 0xb1, 0x52, 0xcf, 0x19, 0xa4, 0xce, 0xb1, 0xa0, 0x40, 0xcf, 0x19,
0x26, 0x95, 0xc4, 0x06, 0x76, 0xac, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x29, 0x02, 0xa6, 0x19,
0x25, 0x01, 0x00, 0x00,
}

View File

@ -0,0 +1,17 @@
syntax = "proto3";
package v2ray.core.app.commander;
option csharp_namespace = "V2Ray.Core.App.Commander";
option go_package = "commander";
option java_package = "com.v2ray.core.app.commander";
option java_multiple_files = true;
import "v2ray.com/core/common/serial/typed_message.proto";
// Config is the settings for Commander.
message Config {
// Tag of the outbound handler that handles grpc connections.
string tag = 1;
// Services that supported by this server. All services must implement Service interface.
repeated v2ray.core.common.serial.TypedMessage service = 2;
}

View File

@ -1,7 +1,7 @@
package impl package commander
import "v2ray.com/core/common/errors" import "v2ray.com/core/common/errors"
func newError(values ...interface{}) *errors.Error { func newError(values ...interface{}) *errors.Error {
return errors.New(values...).Path("App", "Dispatcher", "Default") return errors.New(values...).Path("App", "Commander")
} }

101
app/commander/outbound.go Normal file
View File

@ -0,0 +1,101 @@
package commander
import (
"context"
"net"
"sync"
"v2ray.com/core/common/signal"
"v2ray.com/core/transport/ray"
)
type OutboundListener struct {
buffer chan net.Conn
done *signal.Done
}
func (l *OutboundListener) add(conn net.Conn) {
select {
case l.buffer <- conn:
case <-l.done.C():
conn.Close()
default:
conn.Close()
}
}
func (l *OutboundListener) Accept() (net.Conn, error) {
select {
case <-l.done.C():
return nil, newError("listern closed")
case c := <-l.buffer:
return c, nil
}
}
func (l *OutboundListener) Close() error {
l.done.Close()
L:
for {
select {
case c := <-l.buffer:
c.Close()
default:
break L
}
}
return nil
}
func (l *OutboundListener) Addr() net.Addr {
return &net.TCPAddr{
IP: net.IP{0, 0, 0, 0},
Port: 0,
}
}
type CommanderOutbound struct {
tag string
listener *OutboundListener
access sync.RWMutex
closed bool
}
func (co *CommanderOutbound) Dispatch(ctx context.Context, r ray.OutboundRay) {
co.access.RLock()
if co.closed {
r.OutboundInput().CloseError()
r.OutboundOutput().CloseError()
co.access.RUnlock()
return
}
closeSignal := signal.NewNotifier()
c := ray.NewConnection(r.OutboundInput(), r.OutboundOutput(), ray.ConnCloseSignal(closeSignal))
co.listener.add(c)
co.access.RUnlock()
<-closeSignal.Wait()
return
}
func (co *CommanderOutbound) Tag() string {
return co.tag
}
func (co *CommanderOutbound) Start() error {
co.access.Lock()
co.closed = false
co.access.Unlock()
return nil
}
func (co *CommanderOutbound) Close() error {
co.access.Lock()
co.closed = true
co.listener.Close()
co.access.Unlock()
return nil
}

9
app/commander/service.go Normal file
View File

@ -0,0 +1,9 @@
package commander
import (
"google.golang.org/grpc"
)
type Service interface {
Register(*grpc.Server)
}

View File

@ -1,4 +1,4 @@
package impl package dispatcher
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg impl -path App,Dispatcher,Default //go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg impl -path App,Dispatcher,Default
@ -6,10 +6,8 @@ import (
"context" "context"
"time" "time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/app/router"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
@ -21,31 +19,27 @@ var (
errSniffingTimeout = newError("timeout on sniffing") errSniffingTimeout = newError("timeout on sniffing")
) )
var (
_ app.Application = (*DefaultDispatcher)(nil)
)
// DefaultDispatcher is a default implementation of Dispatcher. // DefaultDispatcher is a default implementation of Dispatcher.
type DefaultDispatcher struct { type DefaultDispatcher struct {
ohm proxyman.OutboundHandlerManager ohm core.OutboundHandlerManager
router *router.Router router core.Router
} }
// NewDefaultDispatcher create a new DefaultDispatcher. // NewDefaultDispatcher create a new DefaultDispatcher.
func NewDefaultDispatcher(ctx context.Context, config *dispatcher.Config) (*DefaultDispatcher, error) { func NewDefaultDispatcher(ctx context.Context, config *Config) (*DefaultDispatcher, error) {
space := app.SpaceFromContext(ctx) v := core.FromContext(ctx)
if space == nil { if v == nil {
return nil, newError("no space in context") return nil, newError("V is not in context.")
}
d := &DefaultDispatcher{
ohm: v.OutboundHandlerManager(),
router: v.Router(),
}
if err := v.RegisterFeature((*core.Dispatcher)(nil), d); err != nil {
return nil, newError("unable to register Dispatcher")
} }
d := &DefaultDispatcher{}
space.On(app.SpaceInitializing, func(interface{}) error {
d.ohm = proxyman.OutboundHandlerManagerFromSpace(space)
if d.ohm == nil {
return newError("OutboundHandlerManager is not found in the space")
}
d.router = router.FromSpace(space)
return nil
})
return d, nil return d, nil
} }
@ -55,14 +49,9 @@ func (*DefaultDispatcher) Start() error {
} }
// Close implements app.Application. // Close implements app.Application.
func (*DefaultDispatcher) Close() {} func (*DefaultDispatcher) Close() error { return nil }
// Interface implements app.Application. // Dispatch implements core.Dispatcher.
func (*DefaultDispatcher) Interface() interface{} {
return (*dispatcher.Interface)(nil)
}
// Dispatch implements Dispatcher.Interface.
func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (ray.InboundRay, error) { func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (ray.InboundRay, error) {
if !destination.IsValid() { if !destination.IsValid() {
panic("Dispatcher: Invalid destination.") panic("Dispatcher: Invalid destination.")
@ -120,7 +109,7 @@ func snifer(ctx context.Context, sniferList []proxyman.KnownProtocols, outbound
func (d *DefaultDispatcher) routedDispatch(ctx context.Context, outbound ray.OutboundRay, destination net.Destination) { func (d *DefaultDispatcher) routedDispatch(ctx context.Context, outbound ray.OutboundRay, destination net.Destination) {
dispatcher := d.ohm.GetDefaultHandler() dispatcher := d.ohm.GetDefaultHandler()
if d.router != nil { if d.router != nil {
if tag, err := d.router.TakeDetour(ctx); err == nil { if tag, err := d.router.PickRoute(ctx); err == nil {
if handler := d.ohm.GetHandler(tag); handler != nil { if handler := d.ohm.GetHandler(tag); handler != nil {
newError("taking detour [", tag, "] for [", destination, "]").WriteToLog() newError("taking detour [", tag, "] for [", destination, "]").WriteToLog()
dispatcher = handler dispatcher = handler
@ -135,7 +124,7 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, outbound ray.Out
} }
func init() { func init() {
common.Must(common.RegisterConfig((*dispatcher.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewDefaultDispatcher(ctx, config.(*dispatcher.Config)) return NewDefaultDispatcher(ctx, config.(*Config))
})) }))
} }

View File

@ -1,21 +1,3 @@
package dispatcher package dispatcher
import ( //go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg dispatcher -path App,Dispatcher
"context"
"v2ray.com/core/app"
"v2ray.com/core/common/net"
"v2ray.com/core/transport/ray"
)
// Interface dispatch a packet and possibly further network payload to its destination.
type Interface interface {
Dispatch(ctx context.Context, dest net.Destination) (ray.InboundRay, error)
}
func FromSpace(space app.Space) Interface {
if app := space.GetApplication((*Interface)(nil)); app != nil {
return app.(Interface)
}
return nil
}

View File

@ -0,0 +1,7 @@
package dispatcher
import "v2ray.com/core/common/errors"
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).Path("App", "Dispatcher")
}

View File

@ -1,4 +1,4 @@
package impl package dispatcher
import ( import (
"bytes" "bytes"

View File

@ -1,11 +1,10 @@
package impl_test package dispatcher_test
import ( import (
"testing" "testing"
. "v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
. "v2ray.com/core/app/dispatcher/impl"
. "v2ray.com/ext/assert" . "v2ray.com/ext/assert"
) )

View File

@ -6,7 +6,7 @@ import (
"time" "time"
"github.com/miekg/dns" "github.com/miekg/dns"
"v2ray.com/core/app/dispatcher" "v2ray.com/core"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/dice" "v2ray.com/core/common/dice"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
@ -48,7 +48,7 @@ type UDPNameServer struct {
nextCleanup time.Time nextCleanup time.Time
} }
func NewUDPNameServer(address net.Destination, dispatcher dispatcher.Interface) *UDPNameServer { func NewUDPNameServer(address net.Destination, dispatcher core.Dispatcher) *UDPNameServer {
s := &UDPNameServer{ s := &UDPNameServer{
address: address, address: address,
requests: make(map[uint16]*PendingRequest), requests: make(map[uint16]*PendingRequest),
@ -216,8 +216,7 @@ func (*LocalNameServer) QueryA(domain string) <-chan *ARecord {
go func() { go func() {
defer close(response) defer close(response)
resolver := net.SystemIPResolver() ips, err := net.LookupIP(domain)
ips, err := resolver.LookupIP(domain)
if err != nil { if err != nil {
newError("failed to lookup IPs for domain ", domain).Base(err).AtWarning().WriteToLog() newError("failed to lookup IPs for domain ", domain).Base(err).AtWarning().WriteToLog()
return return

View File

@ -1,6 +1,6 @@
package dns package dns
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg server -path App,DNS,Server //go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg dns -path App,DNS
import ( import (
"context" "context"
@ -8,10 +8,10 @@ import (
"time" "time"
dnsmsg "github.com/miekg/dns" dnsmsg "github.com/miekg/dns"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/signal"
) )
const ( const (
@ -38,56 +38,60 @@ type Server struct {
hosts map[string]net.IP hosts map[string]net.IP
records map[string]*DomainRecord records map[string]*DomainRecord
servers []NameServer servers []NameServer
task *signal.PeriodicTask
} }
func New(ctx context.Context, config *Config) (*Server, error) { func New(ctx context.Context, config *Config) (*Server, error) {
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, newError("no space in context")
}
server := &Server{ server := &Server{
records: make(map[string]*DomainRecord), records: make(map[string]*DomainRecord),
servers: make([]NameServer, len(config.NameServers)), servers: make([]NameServer, len(config.NameServers)),
hosts: config.GetInternalHosts(), hosts: config.GetInternalHosts(),
} }
space.On(app.SpaceInitializing, func(interface{}) error { server.task = &signal.PeriodicTask{
disp := dispatcher.FromSpace(space) Interval: time.Minute * 10,
if disp == nil { Execute: func() error {
return newError("dispatcher is not found in the space") server.cleanup()
} return nil
for idx, destPB := range config.NameServers { },
address := destPB.Address.AsAddress() }
if address.Family().IsDomain() && address.Domain() == "localhost" { v := core.FromContext(ctx)
server.servers[idx] = &LocalNameServer{} if v == nil {
} else { return nil, newError("V is not in context.")
dest := destPB.AsDestination() }
if dest.Network == net.Network_Unknown {
dest.Network = net.Network_UDP if err := v.RegisterFeature((*core.DNSClient)(nil), server); err != nil {
} return nil, newError("unable to register DNSClient.").Base(err)
if dest.Network == net.Network_UDP { }
server.servers[idx] = NewUDPNameServer(dest, disp)
} for idx, destPB := range config.NameServers {
address := destPB.Address.AsAddress()
if address.Family().IsDomain() && address.Domain() == "localhost" {
server.servers[idx] = &LocalNameServer{}
} else {
dest := destPB.AsDestination()
if dest.Network == net.Network_Unknown {
dest.Network = net.Network_UDP
}
if dest.Network == net.Network_UDP {
server.servers[idx] = NewUDPNameServer(dest, v.Dispatcher())
} }
} }
if len(config.NameServers) == 0 { }
server.servers = append(server.servers, &LocalNameServer{}) if len(config.NameServers) == 0 {
} server.servers = append(server.servers, &LocalNameServer{})
return nil }
})
return server, nil return server, nil
} }
func (*Server) Interface() interface{} { // Start implements common.Runnable.
return (*Server)(nil)
}
func (s *Server) Start() error { func (s *Server) Start() error {
net.RegisterIPResolver(s) return s.task.Start()
return nil
} }
func (*Server) Close() { // Close implements common.Runnable.
net.RegisterIPResolver(net.SystemIPResolver()) func (s *Server) Close() error {
return s.task.Close()
} }
func (s *Server) GetCached(domain string) []net.IP { func (s *Server) GetCached(domain string) []net.IP {
@ -101,18 +105,12 @@ func (s *Server) GetCached(domain string) []net.IP {
return nil return nil
} }
func (s *Server) tryCleanup() { func (s *Server) cleanup() {
s.Lock() s.Lock()
defer s.Unlock() defer s.Unlock()
if len(s.records) > 256 { for d, r := range s.records {
domains := make([]string, 0, 256) if r.Expired() {
for d, r := range s.records {
if r.Expired() {
domains = append(domains, d)
}
}
for _, d := range domains {
delete(s.records, d) delete(s.records, d)
} }
} }
@ -129,8 +127,6 @@ func (s *Server) LookupIP(domain string) ([]net.IP, error) {
return ips, nil return ips, nil
} }
s.tryCleanup()
for _, server := range s.servers { for _, server := range s.servers {
response := server.QueryA(domain) response := server.QueryA(domain)
select { select {

View File

@ -1,18 +1,14 @@
package dns_test package dns_test
import ( import (
"context"
"testing" "testing"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher" "v2ray.com/core/app/dispatcher"
_ "v2ray.com/core/app/dispatcher/impl"
. "v2ray.com/core/app/dns" . "v2ray.com/core/app/dns"
"v2ray.com/core/app/policy" "v2ray.com/core/app/policy"
_ "v2ray.com/core/app/policy/manager"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/outbound" _ "v2ray.com/core/app/proxyman/outbound"
"v2ray.com/core/common"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
"v2ray.com/core/proxy/freedom" "v2ray.com/core/proxy/freedom"
@ -54,50 +50,50 @@ func TestUDPServer(t *testing.T) {
go dnsServer.ListenAndServe() go dnsServer.ListenAndServe()
config := &Config{ config := &core.Config{
NameServers: []*net.Endpoint{ App: []*serial.TypedMessage{
{ serial.ToTypedMessage(&Config{
Network: net.Network_UDP, NameServers: []*net.Endpoint{
Address: &net.IPOrDomain{ {
Address: &net.IPOrDomain_Ip{ Network: net.Network_UDP,
Ip: []byte{127, 0, 0, 1}, Address: &net.IPOrDomain{
Address: &net.IPOrDomain_Ip{
Ip: []byte{127, 0, 0, 1},
},
},
Port: uint32(port),
}, },
}, },
Port: uint32(port), }),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
serial.ToTypedMessage(&policy.Config{}),
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
}, },
} }
ctx := context.Background() v, err := core.New(config)
space := app.NewSpace() assert(err, IsNil)
ctx = app.ContextWithSpace(ctx, space) client := v.DNSClient()
common.Must(app.AddApplicationToSpace(ctx, config))
common.Must(app.AddApplicationToSpace(ctx, &dispatcher.Config{}))
common.Must(app.AddApplicationToSpace(ctx, &proxyman.OutboundConfig{}))
common.Must(app.AddApplicationToSpace(ctx, &policy.Config{}))
om := proxyman.OutboundHandlerManagerFromSpace(space) ips, err := client.LookupIP("google.com")
om.AddHandler(ctx, &proxyman.OutboundHandlerConfig{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
})
common.Must(space.Initialize())
common.Must(space.Start())
ips, err := net.LookupIP("google.com")
assert(err, IsNil) assert(err, IsNil)
assert(len(ips), Equals, 1) assert(len(ips), Equals, 1)
assert([]byte(ips[0]), Equals, []byte{8, 8, 8, 8}) assert([]byte(ips[0]), Equals, []byte{8, 8, 8, 8})
ips, err = net.LookupIP("facebook.com") ips, err = client.LookupIP("facebook.com")
assert(err, IsNil) assert(err, IsNil)
assert(len(ips), Equals, 1) assert(len(ips), Equals, 1)
assert([]byte(ips[0]), Equals, []byte{9, 9, 9, 9}) assert([]byte(ips[0]), Equals, []byte{9, 9, 9, 9})
dnsServer.Shutdown() dnsServer.Shutdown()
ips, err = net.LookupIP("google.com") ips, err = client.LookupIP("google.com")
assert(err, IsNil) assert(err, IsNil)
assert(len(ips), Equals, 1) assert(len(ips), Equals, 1)
assert([]byte(ips[0]), Equals, []byte{8, 8, 8, 8}) assert([]byte(ips[0]), Equals, []byte{8, 8, 8, 8})

View File

@ -37,11 +37,6 @@ func New(ctx context.Context, config *Config) (*Instance, error) {
return g, nil return g, nil
} }
// Interface implements app.Application.Interface().
func (*Instance) Interface() interface{} {
return (*Instance)(nil)
}
func (g *Instance) initAccessLogger() error { func (g *Instance) initAccessLogger() error {
switch g.config.AccessLogType { switch g.config.AccessLogType {
case LogType_File: case LogType_File:
@ -108,11 +103,13 @@ func (g *Instance) Handle(msg log.Message) {
} }
// Close implement app.Application.Close(). // Close implement app.Application.Close().
func (g *Instance) Close() { func (g *Instance) Close() error {
g.Lock() g.Lock()
defer g.Unlock() defer g.Unlock()
g.active = false g.active = false
return nil
} }
func init() { func init() {

View File

@ -2,10 +2,15 @@ package policy
import ( import (
"time" "time"
"v2ray.com/core"
) )
// Duration converts Second to time.Duration. // Duration converts Second to time.Duration.
func (s *Second) Duration() time.Duration { func (s *Second) Duration() time.Duration {
if s == nil {
return 0
}
return time.Second * time.Duration(s.Value) return time.Second * time.Duration(s.Value)
} }
@ -26,3 +31,14 @@ func (p *Policy) OverrideWith(another *Policy) {
} }
} }
} }
func (p *Policy) ToCorePolicy() core.Policy {
var cp core.Policy
if p.Timeout != nil {
cp.Timeouts.ConnectionIdle = p.Timeout.ConnectionIdle.Duration()
cp.Timeouts.Handshake = p.Timeout.Handshake.Duration()
cp.Timeouts.DownlinkOnly = p.Timeout.DownlinkOnly.Duration()
cp.Timeouts.UplinkOnly = p.Timeout.UplinkOnly.Duration()
}
return cp
}

View File

@ -1,5 +1,5 @@
package app package policy
import "v2ray.com/core/common/errors" import "v2ray.com/core/common/errors"
func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("App") } func newError(values ...interface{}) *errors.Error { return errors.New(values...).Path("App", "Policy") }

62
app/policy/manager.go Normal file
View File

@ -0,0 +1,62 @@
package policy
import (
"context"
"v2ray.com/core"
"v2ray.com/core/common"
)
// Instance is an instance of Policy manager.
type Instance struct {
levels map[uint32]core.Policy
}
// New creates new Policy manager instance.
func New(ctx context.Context, config *Config) (*Instance, error) {
m := &Instance{
levels: make(map[uint32]core.Policy),
}
if len(config.Level) > 0 {
for lv, p := range config.Level {
dp := core.DefaultPolicy()
dp.OverrideWith(p.ToCorePolicy())
m.levels[lv] = dp
}
}
v := core.FromContext(ctx)
if v == nil {
return nil, newError("V is not in context.")
}
if err := v.RegisterFeature((*core.PolicyManager)(nil), m); err != nil {
return nil, newError("unable to register PolicyManager in core").Base(err).AtError()
}
return m, nil
}
// ForLevel implements core.PolicyManager.
func (m *Instance) ForLevel(level uint32) core.Policy {
if p, ok := m.levels[level]; ok {
return p
}
return core.DefaultPolicy()
}
// Start implements app.Application.Start().
func (m *Instance) Start() error {
return nil
}
// Close implements app.Application.Close().
func (m *Instance) Close() error {
return nil
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*Config))
}))
}

View File

@ -1,68 +0,0 @@
package manager
import (
"context"
"v2ray.com/core/app/policy"
"v2ray.com/core/common"
)
// Instance is an instance of Policy manager.
type Instance struct {
levels map[uint32]*policy.Policy
}
// New creates new Policy manager instance.
func New(ctx context.Context, config *policy.Config) (*Instance, error) {
levels := config.Level
if levels == nil {
levels = make(map[uint32]*policy.Policy)
}
for _, p := range levels {
g := global()
g.OverrideWith(p)
*p = g
}
return &Instance{
levels: levels,
}, nil
}
func global() policy.Policy {
return policy.Policy{
Timeout: &policy.Policy_Timeout{
Handshake: &policy.Second{Value: 4},
ConnectionIdle: &policy.Second{Value: 300},
UplinkOnly: &policy.Second{Value: 5},
DownlinkOnly: &policy.Second{Value: 30},
},
}
}
// GetPolicy implements policy.Manager.
func (m *Instance) GetPolicy(level uint32) policy.Policy {
if p, ok := m.levels[level]; ok {
return *p
}
return global()
}
// Start implements app.Application.Start().
func (m *Instance) Start() error {
return nil
}
// Close implements app.Application.Close().
func (m *Instance) Close() {
}
// Interface implement app.Application.Interface().
func (m *Instance) Interface() interface{} {
return (*policy.Manager)(nil)
}
func init() {
common.Must(common.RegisterConfig((*policy.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*policy.Config))
}))
}

View File

@ -1,20 +1,3 @@
package policy package policy
import ( //go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg policy -path App,Policy
"v2ray.com/core/app"
)
// Manager is an utility to manage policy per user level.
type Manager interface {
// GetPolicy returns the Policy for the given user level.
GetPolicy(level uint32) Policy
}
// FromSpace returns the policy.Manager in a space.
func FromSpace(space app.Space) Manager {
app := space.GetApplication((*Manager)(nil))
if app == nil {
return nil
}
return app.(Manager)
}

View File

@ -0,0 +1,148 @@
package command
import (
"context"
grpc "google.golang.org/grpc"
"v2ray.com/core"
"v2ray.com/core/common"
"v2ray.com/core/proxy"
)
// InboundOperation is the interface for operations that applies to inbound handlers.
type InboundOperation interface {
// ApplyInbound appliess this operation to the given inbound handler.
ApplyInbound(context.Context, core.InboundHandler) error
}
// OutboundOperation is the interface for operations that applies to outbound handlers.
type OutboundOperation interface {
// ApplyOutbound applies this operation to the given outbound handler.
ApplyOutbound(context.Context, core.OutboundHandler) error
}
func getInbound(handler core.InboundHandler) (proxy.Inbound, error) {
gi, ok := handler.(proxy.GetInbound)
if !ok {
return nil, newError("can't get inbound proxy from handler.")
}
return gi.GetInbound(), nil
}
// ApplyInbound implements InboundOperation.
func (op *AddUserOperation) ApplyInbound(ctx context.Context, handler core.InboundHandler) error {
p, err := getInbound(handler)
if err != nil {
return err
}
um, ok := p.(proxy.UserManager)
if !ok {
return newError("proxy is not an UserManager")
}
return um.AddUser(ctx, op.User)
}
// ApplyInbound implements InboundOperation.
func (op *RemoveUserOperation) ApplyInbound(ctx context.Context, handler core.InboundHandler) error {
p, err := getInbound(handler)
if err != nil {
return err
}
um, ok := p.(proxy.UserManager)
if !ok {
return newError("proxy is not an UserManager")
}
return um.RemoveUser(ctx, op.Email)
}
type handlerServer struct {
s *core.Instance
ihm core.InboundHandlerManager
ohm core.OutboundHandlerManager
}
func (s *handlerServer) AddInbound(ctx context.Context, request *AddInboundRequest) (*AddInboundResponse, error) {
rawHandler, err := s.s.CreateObject(request.Inbound)
if err != nil {
return nil, err
}
handler, ok := rawHandler.(core.InboundHandler)
if !ok {
return nil, newError("not an InboundHandler.")
}
return &AddInboundResponse{}, s.ihm.AddHandler(ctx, handler)
}
func (s *handlerServer) RemoveInbound(ctx context.Context, request *RemoveInboundRequest) (*RemoveInboundResponse, error) {
return &RemoveInboundResponse{}, s.ihm.RemoveHandler(ctx, request.Tag)
}
func (s *handlerServer) AlterInbound(ctx context.Context, request *AlterInboundRequest) (*AlterInboundResponse, error) {
rawOperation, err := request.Operation.GetInstance()
if err != nil {
return nil, newError("unknown operation").Base(err)
}
operation, ok := rawOperation.(InboundOperation)
if !ok {
return nil, newError("not an inbound operation")
}
handler, err := s.ihm.GetHandler(ctx, request.Tag)
if err != nil {
return nil, newError("failed to get handler: ", request.Tag).Base(err)
}
return &AlterInboundResponse{}, operation.ApplyInbound(ctx, handler)
}
func (s *handlerServer) AddOutbound(ctx context.Context, request *AddOutboundRequest) (*AddOutboundResponse, error) {
rawHandler, err := s.s.CreateObject(request.Outbound)
if err != nil {
return nil, err
}
handler, ok := rawHandler.(core.OutboundHandler)
if !ok {
return nil, newError("not an OutboundHandler.")
}
return &AddOutboundResponse{}, s.ohm.AddHandler(ctx, handler)
}
func (s *handlerServer) RemoveOutbound(ctx context.Context, request *RemoveOutboundRequest) (*RemoveOutboundResponse, error) {
return &RemoveOutboundResponse{}, s.ohm.RemoveHandler(ctx, request.Tag)
}
func (s *handlerServer) AlterOutbound(ctx context.Context, request *AlterOutboundRequest) (*AlterOutboundResponse, error) {
rawOperation, err := request.Operation.GetInstance()
if err != nil {
return nil, newError("unknown operation").Base(err)
}
operation, ok := rawOperation.(OutboundOperation)
if !ok {
return nil, newError("not an outbound operation")
}
handler := s.ohm.GetHandler(request.Tag)
return &AlterOutboundResponse{}, operation.ApplyOutbound(ctx, handler)
}
type service struct {
v *core.Instance
}
func (s *service) Register(server *grpc.Server) {
RegisterHandlerServiceServer(server, &handlerServer{
s: s.v,
ihm: s.v.InboundHandlerManager(),
ohm: s.v.OutboundHandlerManager(),
})
}
func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, cfg interface{}) (interface{}, error) {
s := core.FromContext(ctx)
if s == nil {
return nil, newError("V is not in context.")
}
return &service{v: s}, nil
}))
}

View File

@ -0,0 +1,520 @@
package command
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import v2ray_core_common_protocol "v2ray.com/core/common/protocol"
import v2ray_core_common_serial "v2ray.com/core/common/serial"
import v2ray_core "v2ray.com/core"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// 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 AddUserOperation struct {
User *v2ray_core_common_protocol.User `protobuf:"bytes,1,opt,name=user" json:"user,omitempty"`
}
func (m *AddUserOperation) Reset() { *m = AddUserOperation{} }
func (m *AddUserOperation) String() string { return proto.CompactTextString(m) }
func (*AddUserOperation) ProtoMessage() {}
func (*AddUserOperation) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *AddUserOperation) GetUser() *v2ray_core_common_protocol.User {
if m != nil {
return m.User
}
return nil
}
type RemoveUserOperation struct {
Email string `protobuf:"bytes,1,opt,name=email" json:"email,omitempty"`
}
func (m *RemoveUserOperation) Reset() { *m = RemoveUserOperation{} }
func (m *RemoveUserOperation) String() string { return proto.CompactTextString(m) }
func (*RemoveUserOperation) ProtoMessage() {}
func (*RemoveUserOperation) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *RemoveUserOperation) GetEmail() string {
if m != nil {
return m.Email
}
return ""
}
type AddInboundRequest struct {
Inbound *v2ray_core.InboundHandlerConfig `protobuf:"bytes,1,opt,name=inbound" json:"inbound,omitempty"`
}
func (m *AddInboundRequest) Reset() { *m = AddInboundRequest{} }
func (m *AddInboundRequest) String() string { return proto.CompactTextString(m) }
func (*AddInboundRequest) ProtoMessage() {}
func (*AddInboundRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *AddInboundRequest) GetInbound() *v2ray_core.InboundHandlerConfig {
if m != nil {
return m.Inbound
}
return nil
}
type AddInboundResponse struct {
}
func (m *AddInboundResponse) Reset() { *m = AddInboundResponse{} }
func (m *AddInboundResponse) String() string { return proto.CompactTextString(m) }
func (*AddInboundResponse) ProtoMessage() {}
func (*AddInboundResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
type RemoveInboundRequest struct {
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
}
func (m *RemoveInboundRequest) Reset() { *m = RemoveInboundRequest{} }
func (m *RemoveInboundRequest) String() string { return proto.CompactTextString(m) }
func (*RemoveInboundRequest) ProtoMessage() {}
func (*RemoveInboundRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *RemoveInboundRequest) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
type RemoveInboundResponse struct {
}
func (m *RemoveInboundResponse) Reset() { *m = RemoveInboundResponse{} }
func (m *RemoveInboundResponse) String() string { return proto.CompactTextString(m) }
func (*RemoveInboundResponse) ProtoMessage() {}
func (*RemoveInboundResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
type AlterInboundRequest struct {
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
Operation *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,opt,name=operation" json:"operation,omitempty"`
}
func (m *AlterInboundRequest) Reset() { *m = AlterInboundRequest{} }
func (m *AlterInboundRequest) String() string { return proto.CompactTextString(m) }
func (*AlterInboundRequest) ProtoMessage() {}
func (*AlterInboundRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
func (m *AlterInboundRequest) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *AlterInboundRequest) GetOperation() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.Operation
}
return nil
}
type AlterInboundResponse struct {
}
func (m *AlterInboundResponse) Reset() { *m = AlterInboundResponse{} }
func (m *AlterInboundResponse) String() string { return proto.CompactTextString(m) }
func (*AlterInboundResponse) ProtoMessage() {}
func (*AlterInboundResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
type AddOutboundRequest struct {
Outbound *v2ray_core.OutboundHandlerConfig `protobuf:"bytes,1,opt,name=outbound" json:"outbound,omitempty"`
}
func (m *AddOutboundRequest) Reset() { *m = AddOutboundRequest{} }
func (m *AddOutboundRequest) String() string { return proto.CompactTextString(m) }
func (*AddOutboundRequest) ProtoMessage() {}
func (*AddOutboundRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *AddOutboundRequest) GetOutbound() *v2ray_core.OutboundHandlerConfig {
if m != nil {
return m.Outbound
}
return nil
}
type AddOutboundResponse struct {
}
func (m *AddOutboundResponse) Reset() { *m = AddOutboundResponse{} }
func (m *AddOutboundResponse) String() string { return proto.CompactTextString(m) }
func (*AddOutboundResponse) ProtoMessage() {}
func (*AddOutboundResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
type RemoveOutboundRequest struct {
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
}
func (m *RemoveOutboundRequest) Reset() { *m = RemoveOutboundRequest{} }
func (m *RemoveOutboundRequest) String() string { return proto.CompactTextString(m) }
func (*RemoveOutboundRequest) ProtoMessage() {}
func (*RemoveOutboundRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
func (m *RemoveOutboundRequest) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
type RemoveOutboundResponse struct {
}
func (m *RemoveOutboundResponse) Reset() { *m = RemoveOutboundResponse{} }
func (m *RemoveOutboundResponse) String() string { return proto.CompactTextString(m) }
func (*RemoveOutboundResponse) ProtoMessage() {}
func (*RemoveOutboundResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
type AlterOutboundRequest struct {
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
Operation *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,opt,name=operation" json:"operation,omitempty"`
}
func (m *AlterOutboundRequest) Reset() { *m = AlterOutboundRequest{} }
func (m *AlterOutboundRequest) String() string { return proto.CompactTextString(m) }
func (*AlterOutboundRequest) ProtoMessage() {}
func (*AlterOutboundRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
func (m *AlterOutboundRequest) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *AlterOutboundRequest) GetOperation() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.Operation
}
return nil
}
type AlterOutboundResponse struct {
}
func (m *AlterOutboundResponse) Reset() { *m = AlterOutboundResponse{} }
func (m *AlterOutboundResponse) String() string { return proto.CompactTextString(m) }
func (*AlterOutboundResponse) ProtoMessage() {}
func (*AlterOutboundResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
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{14} }
func init() {
proto.RegisterType((*AddUserOperation)(nil), "v2ray.core.app.proxyman.command.AddUserOperation")
proto.RegisterType((*RemoveUserOperation)(nil), "v2ray.core.app.proxyman.command.RemoveUserOperation")
proto.RegisterType((*AddInboundRequest)(nil), "v2ray.core.app.proxyman.command.AddInboundRequest")
proto.RegisterType((*AddInboundResponse)(nil), "v2ray.core.app.proxyman.command.AddInboundResponse")
proto.RegisterType((*RemoveInboundRequest)(nil), "v2ray.core.app.proxyman.command.RemoveInboundRequest")
proto.RegisterType((*RemoveInboundResponse)(nil), "v2ray.core.app.proxyman.command.RemoveInboundResponse")
proto.RegisterType((*AlterInboundRequest)(nil), "v2ray.core.app.proxyman.command.AlterInboundRequest")
proto.RegisterType((*AlterInboundResponse)(nil), "v2ray.core.app.proxyman.command.AlterInboundResponse")
proto.RegisterType((*AddOutboundRequest)(nil), "v2ray.core.app.proxyman.command.AddOutboundRequest")
proto.RegisterType((*AddOutboundResponse)(nil), "v2ray.core.app.proxyman.command.AddOutboundResponse")
proto.RegisterType((*RemoveOutboundRequest)(nil), "v2ray.core.app.proxyman.command.RemoveOutboundRequest")
proto.RegisterType((*RemoveOutboundResponse)(nil), "v2ray.core.app.proxyman.command.RemoveOutboundResponse")
proto.RegisterType((*AlterOutboundRequest)(nil), "v2ray.core.app.proxyman.command.AlterOutboundRequest")
proto.RegisterType((*AlterOutboundResponse)(nil), "v2ray.core.app.proxyman.command.AlterOutboundResponse")
proto.RegisterType((*Config)(nil), "v2ray.core.app.proxyman.command.Config")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for HandlerService service
type HandlerServiceClient interface {
AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error)
RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error)
AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error)
AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error)
RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error)
AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error)
}
type handlerServiceClient struct {
cc *grpc.ClientConn
}
func NewHandlerServiceClient(cc *grpc.ClientConn) HandlerServiceClient {
return &handlerServiceClient{cc}
}
func (c *handlerServiceClient) AddInbound(ctx context.Context, in *AddInboundRequest, opts ...grpc.CallOption) (*AddInboundResponse, error) {
out := new(AddInboundResponse)
err := grpc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/AddInbound", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) RemoveInbound(ctx context.Context, in *RemoveInboundRequest, opts ...grpc.CallOption) (*RemoveInboundResponse, error) {
out := new(RemoveInboundResponse)
err := grpc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/RemoveInbound", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) AlterInbound(ctx context.Context, in *AlterInboundRequest, opts ...grpc.CallOption) (*AlterInboundResponse, error) {
out := new(AlterInboundResponse)
err := grpc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/AlterInbound", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) AddOutbound(ctx context.Context, in *AddOutboundRequest, opts ...grpc.CallOption) (*AddOutboundResponse, error) {
out := new(AddOutboundResponse)
err := grpc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/AddOutbound", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) RemoveOutbound(ctx context.Context, in *RemoveOutboundRequest, opts ...grpc.CallOption) (*RemoveOutboundResponse, error) {
out := new(RemoveOutboundResponse)
err := grpc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/RemoveOutbound", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *handlerServiceClient) AlterOutbound(ctx context.Context, in *AlterOutboundRequest, opts ...grpc.CallOption) (*AlterOutboundResponse, error) {
out := new(AlterOutboundResponse)
err := grpc.Invoke(ctx, "/v2ray.core.app.proxyman.command.HandlerService/AlterOutbound", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for HandlerService service
type HandlerServiceServer interface {
AddInbound(context.Context, *AddInboundRequest) (*AddInboundResponse, error)
RemoveInbound(context.Context, *RemoveInboundRequest) (*RemoveInboundResponse, error)
AlterInbound(context.Context, *AlterInboundRequest) (*AlterInboundResponse, error)
AddOutbound(context.Context, *AddOutboundRequest) (*AddOutboundResponse, error)
RemoveOutbound(context.Context, *RemoveOutboundRequest) (*RemoveOutboundResponse, error)
AlterOutbound(context.Context, *AlterOutboundRequest) (*AlterOutboundResponse, error)
}
func RegisterHandlerServiceServer(s *grpc.Server, srv HandlerServiceServer) {
s.RegisterService(&_HandlerService_serviceDesc, srv)
}
func _HandlerService_AddInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddInboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).AddInbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/AddInbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AddInbound(ctx, req.(*AddInboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_RemoveInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RemoveInboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).RemoveInbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/RemoveInbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).RemoveInbound(ctx, req.(*RemoveInboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_AlterInbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AlterInboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).AlterInbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/AlterInbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AlterInbound(ctx, req.(*AlterInboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_AddOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddOutboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).AddOutbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/AddOutbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AddOutbound(ctx, req.(*AddOutboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_RemoveOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RemoveOutboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).RemoveOutbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/RemoveOutbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).RemoveOutbound(ctx, req.(*RemoveOutboundRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HandlerService_AlterOutbound_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AlterOutboundRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HandlerServiceServer).AlterOutbound(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/v2ray.core.app.proxyman.command.HandlerService/AlterOutbound",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HandlerServiceServer).AlterOutbound(ctx, req.(*AlterOutboundRequest))
}
return interceptor(ctx, in, info, handler)
}
var _HandlerService_serviceDesc = grpc.ServiceDesc{
ServiceName: "v2ray.core.app.proxyman.command.HandlerService",
HandlerType: (*HandlerServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "AddInbound",
Handler: _HandlerService_AddInbound_Handler,
},
{
MethodName: "RemoveInbound",
Handler: _HandlerService_RemoveInbound_Handler,
},
{
MethodName: "AlterInbound",
Handler: _HandlerService_AlterInbound_Handler,
},
{
MethodName: "AddOutbound",
Handler: _HandlerService_AddOutbound_Handler,
},
{
MethodName: "RemoveOutbound",
Handler: _HandlerService_RemoveOutbound_Handler,
},
{
MethodName: "AlterOutbound",
Handler: _HandlerService_AlterOutbound_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "v2ray.com/core/app/proxyman/command/command.proto",
}
func init() { proto.RegisterFile("v2ray.com/core/app/proxyman/command/command.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 557 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xdf, 0x6b, 0xd3, 0x40,
0x1c, 0xb7, 0x53, 0xbb, 0xed, 0x3b, 0x1d, 0xf3, 0xda, 0x6e, 0x25, 0x3e, 0x6c, 0x46, 0x90, 0x0d,
0xe1, 0xa2, 0x59, 0x37, 0x41, 0xf0, 0xa1, 0xd6, 0x87, 0xf9, 0x20, 0x1d, 0x99, 0xfa, 0xe0, 0x8b,
0xdc, 0x92, 0xb3, 0x04, 0x92, 0xbb, 0xf3, 0x92, 0x56, 0x2b, 0x08, 0x82, 0xff, 0x80, 0x7f, 0x87,
0x7f, 0xa5, 0x24, 0x77, 0xd7, 0x25, 0x69, 0x21, 0x0d, 0xf8, 0xd4, 0xf4, 0xfa, 0xf9, 0xf5, 0xfd,
0xde, 0x27, 0x14, 0x9e, 0xcf, 0x5c, 0x49, 0xe6, 0xd8, 0xe7, 0xb1, 0xe3, 0x73, 0x49, 0x1d, 0x22,
0x84, 0x23, 0x24, 0xff, 0x3e, 0x8f, 0x09, 0x73, 0x7c, 0x1e, 0xc7, 0x84, 0x05, 0xe6, 0x13, 0x0b,
0xc9, 0x53, 0x8e, 0x0e, 0x0d, 0x45, 0x52, 0x4c, 0x84, 0xc0, 0x06, 0x8e, 0x35, 0xcc, 0x3a, 0xa9,
0x68, 0x66, 0xe7, 0x9c, 0x39, 0x39, 0xdb, 0xe7, 0x91, 0x33, 0x4d, 0xa8, 0x54, 0x5a, 0xd6, 0xb3,
0xd5, 0xd0, 0x84, 0xca, 0x90, 0x44, 0x4e, 0x3a, 0x17, 0x34, 0xf8, 0x1c, 0xd3, 0x24, 0x21, 0x13,
0xaa, 0x19, 0x0f, 0x97, 0x18, 0xec, 0x4b, 0x38, 0x51, 0x3f, 0xda, 0x17, 0xb0, 0x37, 0x0c, 0x82,
0x0f, 0x09, 0x95, 0x63, 0x41, 0x25, 0x49, 0x43, 0xce, 0xd0, 0x00, 0xee, 0x64, 0x86, 0xfd, 0xd6,
0x51, 0xeb, 0x78, 0xc7, 0x3d, 0xc2, 0x85, 0xf4, 0xca, 0x0d, 0x9b, 0x60, 0x38, 0x23, 0x7a, 0x39,
0xda, 0x7e, 0x0a, 0x1d, 0x8f, 0xc6, 0x7c, 0x46, 0xcb, 0x62, 0x5d, 0xb8, 0x4b, 0x63, 0x12, 0x46,
0xb9, 0xda, 0xb6, 0xa7, 0xbe, 0xd8, 0x63, 0x78, 0x30, 0x0c, 0x82, 0xb7, 0xec, 0x9a, 0x4f, 0x59,
0xe0, 0xd1, 0xaf, 0x53, 0x9a, 0xa4, 0xe8, 0x25, 0x6c, 0x86, 0xea, 0x64, 0x95, 0xb5, 0x06, 0x5f,
0x10, 0x16, 0x44, 0x54, 0x8e, 0xf2, 0x21, 0x3c, 0x43, 0xb0, 0xbb, 0x80, 0x8a, 0x82, 0x89, 0xe0,
0x2c, 0xa1, 0xf6, 0x31, 0x74, 0x55, 0xa6, 0x8a, 0xd3, 0x1e, 0xdc, 0x4e, 0xc9, 0x44, 0x47, 0xca,
0x1e, 0xed, 0x03, 0xe8, 0x55, 0x90, 0x5a, 0x22, 0x86, 0xce, 0x30, 0x4a, 0xa9, 0xac, 0x53, 0x40,
0x6f, 0x60, 0x9b, 0x9b, 0xa9, 0xfb, 0x1b, 0x79, 0xfe, 0x27, 0x2b, 0x56, 0xa7, 0x2e, 0x0a, 0xbf,
0xcf, 0x2e, 0xea, 0x9d, 0xba, 0x27, 0xef, 0x86, 0x68, 0xef, 0x43, 0xb7, 0x6c, 0xa7, 0x63, 0x5c,
0xe5, 0xf3, 0x8d, 0xa7, 0x69, 0x29, 0xc5, 0x2b, 0xd8, 0xe2, 0xfa, 0x48, 0xaf, 0xec, 0x51, 0xd1,
0xd2, 0xc0, 0xcb, 0x3b, 0x5b, 0x50, 0xec, 0x1e, 0x74, 0x4a, 0xa2, 0xda, 0xeb, 0xc4, 0xec, 0xa2,
0x6a, 0xb7, 0xbc, 0xb6, 0x3e, 0xec, 0x57, 0xa1, 0x5a, 0x84, 0xe9, 0x41, 0x6a, 0x35, 0xfe, 0xd3,
0xe2, 0x0e, 0xa0, 0x57, 0xf1, 0xd3, 0x41, 0xb6, 0xa0, 0xad, 0x06, 0x77, 0xff, 0xb4, 0x61, 0x57,
0xaf, 0xe2, 0x8a, 0xca, 0x59, 0xe8, 0x53, 0xf4, 0x0d, 0xe0, 0xa6, 0x36, 0xc8, 0xc5, 0x35, 0x2f,
0x2a, 0x5e, 0x2a, 0xad, 0x75, 0xda, 0x88, 0xa3, 0x33, 0xdd, 0x42, 0xbf, 0x5a, 0x70, 0xbf, 0x54,
0x38, 0x74, 0x56, 0x2b, 0xb4, 0xaa, 0xca, 0xd6, 0x79, 0x53, 0xda, 0x22, 0xc2, 0x4f, 0xb8, 0x57,
0xac, 0x1a, 0x1a, 0xd4, 0x4f, 0xb2, 0xfc, 0x22, 0x58, 0x67, 0x0d, 0x59, 0x0b, 0xfb, 0x1f, 0xb0,
0x53, 0x28, 0x1f, 0x5a, 0x6b, 0x8f, 0x95, 0x32, 0x59, 0x83, 0x66, 0xa4, 0x85, 0xf7, 0xef, 0x16,
0xec, 0x96, 0x7b, 0x8b, 0xd6, 0xdd, 0x63, 0x35, 0xc2, 0x8b, 0xc6, 0xbc, 0x52, 0x07, 0x4a, 0x9d,
0x45, 0x6b, 0x2e, 0xb3, 0x9a, 0xe1, 0xbc, 0x29, 0xcd, 0x44, 0x78, 0xed, 0xc1, 0x63, 0x9f, 0xc7,
0x75, 0xf4, 0xcb, 0xd6, 0xa7, 0x4d, 0xfd, 0xf8, 0x77, 0xe3, 0xf0, 0xa3, 0xeb, 0x91, 0x39, 0x1e,
0x65, 0xe0, 0xa1, 0x10, 0xf8, 0xd2, 0x80, 0x47, 0x0a, 0x71, 0xdd, 0xce, 0xff, 0x1d, 0x4e, 0xff,
0x05, 0x00, 0x00, 0xff, 0xff, 0x2f, 0x05, 0xaa, 0x44, 0x29, 0x07, 0x00, 0x00,
}

View File

@ -0,0 +1,80 @@
syntax = "proto3";
package v2ray.core.app.proxyman.command;
option csharp_namespace = "V2Ray.Core.App.Proxyman.Command";
option go_package = "command";
option java_package = "com.v2ray.core.app.proxyman.command";
option java_multiple_files = true;
import "v2ray.com/core/common/protocol/user.proto";
import "v2ray.com/core/common/serial/typed_message.proto";
import "v2ray.com/core/config.proto";
message AddUserOperation {
v2ray.core.common.protocol.User user = 1;
}
message RemoveUserOperation {
string email = 1;
}
message AddInboundRequest {
core.InboundHandlerConfig inbound = 1;
}
message AddInboundResponse{
}
message RemoveInboundRequest {
string tag = 1;
}
message RemoveInboundResponse {}
message AlterInboundRequest {
string tag = 1;
v2ray.core.common.serial.TypedMessage operation = 2;
}
message AlterInboundResponse {
}
message AddOutboundRequest {
core.OutboundHandlerConfig outbound = 1;
}
message AddOutboundResponse {
}
message RemoveOutboundRequest {
string tag = 1;
}
message RemoveOutboundResponse {
}
message AlterOutboundRequest {
string tag = 1;
v2ray.core.common.serial.TypedMessage operation = 2;
}
message AlterOutboundResponse {
}
service HandlerService {
rpc AddInbound(AddInboundRequest) returns (AddInboundResponse) {}
rpc RemoveInbound(RemoveInboundRequest) returns (RemoveInboundResponse) {}
rpc AlterInbound(AlterInboundRequest) returns (AlterInboundResponse) {}
rpc AddOutbound(AddOutboundRequest) returns (AddOutboundResponse) {}
rpc RemoveOutbound(RemoveOutboundRequest) returns (RemoveOutboundResponse) {}
rpc AlterOutbound(AlterOutboundRequest) returns (AlterOutboundResponse) {}
}
message Config {}

View File

@ -0,0 +1,3 @@
package command
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg command -path App,Proxyman,Command

View File

@ -0,0 +1,7 @@
package command
import "v2ray.com/core/common/errors"
func newError(values ...interface{}) *errors.Error {
return errors.New(values...).Path("App", "Proxyman", "Command")
}

View File

@ -1,11 +1,5 @@
package proxyman package proxyman
import (
"context"
"v2ray.com/core/proxy"
)
func (s *AllocationStrategy) GetConcurrencyValue() uint32 { func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
if s == nil || s.Concurrency == nil { if s == nil || s.Concurrency == nil {
return 3 return 3
@ -19,14 +13,3 @@ func (s *AllocationStrategy) GetRefreshValue() uint32 {
} }
return s.Refresh.Value return s.Refresh.Value
} }
func (c *OutboundHandlerConfig) GetProxyHandler(ctx context.Context) (proxy.Outbound, error) {
if c == nil {
return nil, newError("OutboundHandlerConfig is nil")
}
config, err := c.ProxySettings.GetInstance()
if err != nil {
return nil, err
}
return proxy.CreateOutboundHandler(ctx, config)
}

View File

@ -3,7 +3,6 @@ package proxyman
import proto "github.com/golang/protobuf/proto" import proto "github.com/golang/protobuf/proto"
import fmt "fmt" import fmt "fmt"
import math "math" import math "math"
import v2ray_core_common_serial "v2ray.com/core/common/serial"
import v2ray_core_common_net "v2ray.com/core/common/net" import v2ray_core_common_net "v2ray.com/core/common/net"
import v2ray_core_common_net1 "v2ray.com/core/common/net" import v2ray_core_common_net1 "v2ray.com/core/common/net"
import v2ray_core_transport_internet "v2ray.com/core/transport/internet" import v2ray_core_transport_internet "v2ray.com/core/transport/internet"
@ -211,45 +210,13 @@ func (m *ReceiverConfig) GetDomainOverride() []KnownProtocols {
return nil return nil
} }
type InboundHandlerConfig struct {
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,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{3} }
func (m *InboundHandlerConfig) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *InboundHandlerConfig) GetReceiverSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.ReceiverSettings
}
return nil
}
func (m *InboundHandlerConfig) GetProxySettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.ProxySettings
}
return nil
}
type OutboundConfig struct { type OutboundConfig struct {
} }
func (m *OutboundConfig) Reset() { *m = OutboundConfig{} } func (m *OutboundConfig) Reset() { *m = OutboundConfig{} }
func (m *OutboundConfig) String() string { return proto.CompactTextString(m) } func (m *OutboundConfig) String() string { return proto.CompactTextString(m) }
func (*OutboundConfig) ProtoMessage() {} func (*OutboundConfig) ProtoMessage() {}
func (*OutboundConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } func (*OutboundConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
type SenderConfig struct { type SenderConfig struct {
// Send traffic through the given IP. Only IP is allowed. // Send traffic through the given IP. Only IP is allowed.
@ -262,7 +229,7 @@ type SenderConfig struct {
func (m *SenderConfig) Reset() { *m = SenderConfig{} } func (m *SenderConfig) Reset() { *m = SenderConfig{} }
func (m *SenderConfig) String() string { return proto.CompactTextString(m) } func (m *SenderConfig) String() string { return proto.CompactTextString(m) }
func (*SenderConfig) ProtoMessage() {} func (*SenderConfig) ProtoMessage() {}
func (*SenderConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } func (*SenderConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *SenderConfig) GetVia() *v2ray_core_common_net.IPOrDomain { func (m *SenderConfig) GetVia() *v2ray_core_common_net.IPOrDomain {
if m != nil { if m != nil {
@ -292,54 +259,6 @@ func (m *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
return nil return nil
} }
type OutboundHandlerConfig struct {
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,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{6} }
func (m *OutboundHandlerConfig) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *OutboundHandlerConfig) GetSenderSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.SenderSettings
}
return nil
}
func (m *OutboundHandlerConfig) GetProxySettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.ProxySettings
}
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 ""
}
type MultiplexingConfig struct { type MultiplexingConfig struct {
// Whether or not Mux is enabled. // Whether or not Mux is enabled.
Enabled bool `protobuf:"varint,1,opt,name=enabled" json:"enabled,omitempty"` Enabled bool `protobuf:"varint,1,opt,name=enabled" json:"enabled,omitempty"`
@ -350,7 +269,7 @@ type MultiplexingConfig struct {
func (m *MultiplexingConfig) Reset() { *m = MultiplexingConfig{} } func (m *MultiplexingConfig) Reset() { *m = MultiplexingConfig{} }
func (m *MultiplexingConfig) String() string { return proto.CompactTextString(m) } func (m *MultiplexingConfig) String() string { return proto.CompactTextString(m) }
func (*MultiplexingConfig) ProtoMessage() {} func (*MultiplexingConfig) ProtoMessage() {}
func (*MultiplexingConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } func (*MultiplexingConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *MultiplexingConfig) GetEnabled() bool { func (m *MultiplexingConfig) GetEnabled() bool {
if m != nil { if m != nil {
@ -372,10 +291,8 @@ func init() {
proto.RegisterType((*AllocationStrategy_AllocationStrategyConcurrency)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency") proto.RegisterType((*AllocationStrategy_AllocationStrategyConcurrency)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency")
proto.RegisterType((*AllocationStrategy_AllocationStrategyRefresh)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh") proto.RegisterType((*AllocationStrategy_AllocationStrategyRefresh)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh")
proto.RegisterType((*ReceiverConfig)(nil), "v2ray.core.app.proxyman.ReceiverConfig") 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((*OutboundConfig)(nil), "v2ray.core.app.proxyman.OutboundConfig")
proto.RegisterType((*SenderConfig)(nil), "v2ray.core.app.proxyman.SenderConfig") proto.RegisterType((*SenderConfig)(nil), "v2ray.core.app.proxyman.SenderConfig")
proto.RegisterType((*OutboundHandlerConfig)(nil), "v2ray.core.app.proxyman.OutboundHandlerConfig")
proto.RegisterType((*MultiplexingConfig)(nil), "v2ray.core.app.proxyman.MultiplexingConfig") proto.RegisterType((*MultiplexingConfig)(nil), "v2ray.core.app.proxyman.MultiplexingConfig")
proto.RegisterEnum("v2ray.core.app.proxyman.KnownProtocols", KnownProtocols_name, KnownProtocols_value) proto.RegisterEnum("v2ray.core.app.proxyman.KnownProtocols", KnownProtocols_name, KnownProtocols_value)
proto.RegisterEnum("v2ray.core.app.proxyman.AllocationStrategy_Type", AllocationStrategy_Type_name, AllocationStrategy_Type_value) proto.RegisterEnum("v2ray.core.app.proxyman.AllocationStrategy_Type", AllocationStrategy_Type_name, AllocationStrategy_Type_value)
@ -384,57 +301,49 @@ func init() {
func init() { proto.RegisterFile("v2ray.com/core/app/proxyman/config.proto", fileDescriptor0) } func init() { proto.RegisterFile("v2ray.com/core/app/proxyman/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 822 bytes of a gzipped FileDescriptorProto // 691 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xd1, 0x8e, 0xdb, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x5d, 0x6f, 0xd3, 0x3a,
0x14, 0xad, 0xe3, 0x34, 0xc9, 0xde, 0xed, 0x7a, 0xdd, 0xa1, 0xd0, 0x10, 0x40, 0x0a, 0x01, 0xd1, 0x1c, 0xc6, 0x97, 0xb6, 0x6b, 0x7b, 0xfe, 0x5b, 0xb3, 0x1c, 0x9f, 0x23, 0x2d, 0xa7, 0x07, 0xa4,
0xa8, 0x20, 0xa7, 0xa4, 0xe2, 0x81, 0x27, 0x58, 0x76, 0x2b, 0x75, 0x81, 0x55, 0xcc, 0x24, 0xe2, 0x52, 0x90, 0x56, 0x0d, 0x94, 0x40, 0x27, 0x2e, 0xb8, 0x82, 0xd1, 0x4d, 0x62, 0xbc, 0xa8, 0xc1,
0xa1, 0x42, 0xb2, 0x66, 0xed, 0xa9, 0x19, 0x61, 0xcf, 0x58, 0x33, 0x93, 0x74, 0xfd, 0x4b, 0x7c, 0xad, 0xb8, 0x98, 0x90, 0x22, 0x2f, 0xf1, 0x8a, 0x45, 0x62, 0x47, 0x8e, 0xdb, 0x2d, 0x5f, 0x89,
0x05, 0x8f, 0x3c, 0xf0, 0x05, 0xfc, 0x0a, 0x2f, 0xc8, 0x9e, 0x71, 0x76, 0xb7, 0x49, 0x5a, 0x96, 0x4f, 0xc1, 0x25, 0x9f, 0x81, 0x4f, 0x83, 0xf2, 0xd6, 0x75, 0xeb, 0x3a, 0x98, 0x76, 0xe7, 0xa6,
0xaa, 0x6f, 0x33, 0xc9, 0x39, 0xc7, 0x73, 0xcf, 0x3d, 0x77, 0x06, 0xc6, 0xab, 0xa9, 0x24, 0x65, 0xcf, 0xf3, 0xb3, 0xfd, 0x3c, 0xb6, 0xa1, 0x37, 0xeb, 0x4b, 0x92, 0x58, 0x9e, 0x08, 0x6d, 0x4f,
0x10, 0x8b, 0x7c, 0x12, 0x0b, 0x49, 0x27, 0xa4, 0x28, 0x26, 0x85, 0x14, 0x17, 0x65, 0x4e, 0xf8, 0x48, 0x6a, 0x93, 0x28, 0xb2, 0x23, 0x29, 0xce, 0x93, 0x90, 0x70, 0xdb, 0x13, 0xfc, 0x94, 0x4d,
0x24, 0x16, 0xfc, 0x39, 0x4b, 0x83, 0x42, 0x0a, 0x2d, 0xd0, 0xfd, 0x06, 0x29, 0x69, 0x40, 0x8a, 0xac, 0x48, 0x0a, 0x25, 0xd0, 0x76, 0xa9, 0x94, 0xd4, 0x22, 0x51, 0x64, 0x95, 0xaa, 0xf6, 0xce,
0x22, 0x68, 0x50, 0x83, 0x47, 0x2f, 0x49, 0xc4, 0x22, 0xcf, 0x05, 0x9f, 0x28, 0x2a, 0x19, 0xc9, 0x15, 0x84, 0x27, 0xc2, 0x50, 0x70, 0x9b, 0x53, 0x65, 0x13, 0xdf, 0x97, 0x34, 0x8e, 0x73, 0x42,
0x26, 0xba, 0x2c, 0x68, 0x12, 0xe5, 0x54, 0x29, 0x92, 0x52, 0x23, 0x35, 0x78, 0xb0, 0x9d, 0xc1, 0xfb, 0xd1, 0x6a, 0x61, 0x24, 0xa4, 0x2a, 0x54, 0xd6, 0x15, 0x95, 0x92, 0x84, 0xc7, 0xe9, 0xff,
0xa9, 0x9e, 0x90, 0x24, 0x91, 0x54, 0x29, 0x0b, 0xfc, 0x74, 0x37, 0xb0, 0x10, 0x52, 0x5b, 0x54, 0x36, 0xe3, 0x8a, 0xca, 0x54, 0xbd, 0xb8, 0xae, 0xee, 0x16, 0xb4, 0x8e, 0xf8, 0x89, 0x98, 0x72,
0xf0, 0x12, 0x4a, 0x4b, 0xc2, 0x55, 0xf5, 0xff, 0x84, 0x71, 0x4d, 0x65, 0x85, 0xbe, 0x5a, 0xc9, 0x7f, 0x90, 0x7d, 0xee, 0x7e, 0xaf, 0x02, 0xda, 0x0f, 0x02, 0xe1, 0x11, 0xc5, 0x04, 0x1f, 0x29,
0xe8, 0x10, 0x0e, 0x4e, 0xf9, 0xb9, 0x58, 0xf2, 0xe4, 0xb8, 0xfe, 0x79, 0xf4, 0x87, 0x0b, 0xe8, 0x49, 0x14, 0x9d, 0x24, 0xe8, 0x00, 0x6a, 0x2a, 0x89, 0xa8, 0xa9, 0x75, 0xb4, 0x9e, 0xde, 0x7f,
0x28, 0xcb, 0x44, 0x4c, 0x34, 0x13, 0x7c, 0xae, 0x25, 0xd1, 0x34, 0x2d, 0xd1, 0x09, 0xb4, 0xab, 0x6a, 0xad, 0xd8, 0x8e, 0xb5, 0x6c, 0xb5, 0xc6, 0x49, 0x44, 0x71, 0xe6, 0x46, 0x5f, 0x61, 0xc3,
0xd3, 0xf7, 0x9d, 0xa1, 0x33, 0xf6, 0xa6, 0x8f, 0x82, 0x1d, 0x06, 0x04, 0x9b, 0xd4, 0x60, 0x51, 0x13, 0xdc, 0x9b, 0x4a, 0x49, 0xb9, 0x97, 0x98, 0x95, 0x8e, 0xd6, 0xdb, 0xe8, 0x1f, 0xdd, 0x06,
0x16, 0x14, 0xd7, 0x6c, 0xf4, 0x1b, 0xec, 0xc7, 0x82, 0xc7, 0x4b, 0x29, 0x29, 0x8f, 0xcb, 0x7e, 0xb6, 0xfc, 0x69, 0x70, 0x01, 0xc4, 0x8b, 0x74, 0xe4, 0x42, 0x43, 0xd2, 0x53, 0x49, 0xe3, 0x2f,
0x6b, 0xe8, 0x8c, 0xf7, 0xa7, 0xa7, 0x37, 0x11, 0xdb, 0xfc, 0xe9, 0xf8, 0x52, 0x10, 0x5f, 0x55, 0x66, 0x35, 0x9b, 0xe8, 0xf0, 0x6e, 0x13, 0xe1, 0x1c, 0x86, 0x4b, 0x6a, 0xfb, 0x39, 0xdc, 0xbf,
0x47, 0x11, 0x74, 0x25, 0x7d, 0x2e, 0xa9, 0xfa, 0xb5, 0xef, 0xd6, 0x1f, 0x7a, 0xf2, 0x66, 0x1f, 0x71, 0x39, 0xe8, 0x5f, 0x58, 0x9f, 0x91, 0x60, 0x9a, 0xa7, 0xd6, 0xc2, 0xf9, 0x8f, 0xf6, 0x33,
0xc2, 0x46, 0x0c, 0x37, 0xaa, 0x83, 0xaf, 0xe0, 0xa3, 0x57, 0x1e, 0x07, 0xdd, 0x83, 0xdb, 0x2b, 0xf8, 0x6f, 0x25, 0xfc, 0x7a, 0x4b, 0xf7, 0x09, 0xd4, 0xd2, 0x14, 0x11, 0x40, 0x7d, 0x3f, 0x38,
0x92, 0x2d, 0x8d, 0x6b, 0x07, 0xd8, 0x6c, 0x06, 0x5f, 0xc2, 0xfb, 0x3b, 0xc5, 0xb7, 0x53, 0x46, 0x23, 0x49, 0x6c, 0xac, 0xa5, 0x63, 0x4c, 0xb8, 0x2f, 0x42, 0x43, 0x43, 0x9b, 0xd0, 0x3c, 0x3c,
0x5f, 0x40, 0xbb, 0x72, 0x11, 0x01, 0x74, 0x8e, 0xb2, 0x17, 0xa4, 0x54, 0xfe, 0xad, 0x6a, 0x8d, 0x4f, 0xeb, 0x25, 0x81, 0x51, 0xe9, 0xfe, 0xac, 0x82, 0x8e, 0xa9, 0x47, 0xd9, 0x8c, 0xca, 0xbc,
0x09, 0x4f, 0x44, 0xee, 0x3b, 0xe8, 0x0e, 0xf4, 0x9e, 0x5c, 0x54, 0xed, 0x25, 0x99, 0xdf, 0x1a, 0x55, 0xf4, 0x12, 0x20, 0x3d, 0x04, 0xae, 0x24, 0x7c, 0x92, 0xb3, 0x37, 0xfa, 0x9d, 0xc5, 0x38,
0xfd, 0xed, 0x82, 0x87, 0x69, 0x4c, 0xd9, 0x8a, 0x4a, 0xd3, 0x55, 0xf4, 0x0d, 0x40, 0x15, 0x82, 0xf2, 0xd3, 0x64, 0x71, 0xaa, 0x2c, 0x47, 0x48, 0x85, 0x53, 0x1d, 0xfe, 0x2b, 0x2a, 0x87, 0xe8,
0x48, 0x12, 0x9e, 0x1a, 0xed, 0xfd, 0xe9, 0xf0, 0xaa, 0x1d, 0x26, 0x4d, 0x01, 0xa7, 0x3a, 0x08, 0x05, 0xd4, 0x03, 0x16, 0x2b, 0xca, 0x8b, 0xd2, 0x1e, 0xac, 0x30, 0x1f, 0x39, 0x43, 0x79, 0x20,
0x85, 0xd4, 0xb8, 0xc2, 0xe1, 0xbd, 0xa2, 0x59, 0xa2, 0xaf, 0xa1, 0x93, 0x31, 0xa5, 0x29, 0xb7, 0x42, 0xc2, 0x38, 0x2e, 0x0c, 0xe8, 0x33, 0xfc, 0x43, 0xe6, 0xfb, 0x75, 0xe3, 0x62, 0xc3, 0x45,
0x4d, 0xfb, 0x78, 0x07, 0xf9, 0x34, 0x9c, 0xc9, 0x13, 0x91, 0x13, 0xc6, 0xb1, 0x25, 0xa0, 0x5f, 0x27, 0x8f, 0x6f, 0xd1, 0x09, 0x46, 0x64, 0xf9, 0x60, 0x8e, 0x61, 0x2b, 0x56, 0x92, 0x92, 0xd0,
0xe0, 0x1d, 0xb2, 0xae, 0x37, 0x52, 0xb6, 0x60, 0xdb, 0x93, 0xcf, 0x6f, 0xd0, 0x13, 0x8c, 0xc8, 0x8d, 0xa9, 0x52, 0x8c, 0x4f, 0x62, 0xb3, 0xb6, 0x4c, 0x9e, 0x5f, 0x03, 0xab, 0xbc, 0x06, 0xd6,
0x66, 0x30, 0x17, 0x70, 0xa8, 0xb4, 0xa4, 0x24, 0x8f, 0x14, 0xd5, 0x9a, 0xf1, 0x54, 0xf5, 0xdb, 0x28, 0x73, 0xe5, 0xf9, 0x60, 0x3d, 0x67, 0x8c, 0x0a, 0x04, 0x7a, 0x05, 0xf7, 0x64, 0x9e, 0xa0,
0x9b, 0xca, 0xeb, 0x31, 0x08, 0x9a, 0x31, 0x08, 0xe6, 0x35, 0xcb, 0xf8, 0x83, 0x3d, 0xa3, 0x31, 0x2b, 0x24, 0x9b, 0x30, 0x4e, 0x02, 0xd7, 0xa7, 0xb1, 0x62, 0x3c, 0x9b, 0xdd, 0x5c, 0xef, 0x68,
0xb7, 0x12, 0xe8, 0x5b, 0xf8, 0x50, 0x1a, 0x07, 0x23, 0x21, 0x59, 0xca, 0x38, 0xc9, 0xa2, 0x84, 0xbd, 0x26, 0x6e, 0x17, 0x9a, 0x61, 0x21, 0x39, 0xb8, 0x50, 0x20, 0x07, 0xb6, 0xfc, 0x2c, 0x07,
0x2a, 0xcd, 0x78, 0xfd, 0xf5, 0xfe, 0xed, 0xa1, 0x33, 0xee, 0xe1, 0x81, 0xc5, 0xcc, 0x2c, 0xe4, 0x57, 0xcc, 0xa8, 0x94, 0xcc, 0xa7, 0x66, 0xa3, 0x53, 0xed, 0xe9, 0xfd, 0x9d, 0x95, 0x3b, 0x7e,
0xe4, 0x12, 0x81, 0x42, 0x38, 0x4c, 0x6a, 0x1f, 0x22, 0xb1, 0xa2, 0x52, 0xb2, 0x84, 0xf6, 0xbb, 0xc7, 0xc5, 0x19, 0x77, 0xd2, 0x6b, 0xe9, 0x89, 0x20, 0xc6, 0x7a, 0xee, 0x1f, 0x16, 0xf6, 0xb7,
0x43, 0x77, 0xec, 0x4d, 0x1f, 0xec, 0xac, 0xf8, 0x07, 0x2e, 0x5e, 0xf0, 0xb0, 0x1a, 0xcb, 0x58, 0xb5, 0x66, 0xdd, 0x68, 0x74, 0x0d, 0xd0, 0x87, 0x53, 0xb5, 0x78, 0x63, 0x7f, 0x54, 0x60, 0x73,
0x64, 0x0a, 0x7b, 0x86, 0x3f, 0xb3, 0xf4, 0xef, 0xdb, 0xbd, 0x8e, 0xdf, 0x1d, 0xfd, 0xe5, 0xc0, 0x44, 0xb9, 0x3f, 0x2f, 0x7b, 0x0f, 0xaa, 0x33, 0x46, 0x8a, 0x96, 0xff, 0xa0, 0xa8, 0x54, 0x7d,
0x3d, 0x3b, 0xb1, 0x4f, 0x09, 0x4f, 0xb2, 0x75, 0x8b, 0x7d, 0x70, 0x35, 0x49, 0xeb, 0xde, 0xee, 0x5d, 0x8e, 0x95, 0xbb, 0xe7, 0xf8, 0x11, 0xf4, 0x6c, 0x7b, 0x17, 0xd0, 0xbc, 0xf6, 0xdd, 0xdf,
0xe1, 0x6a, 0x89, 0xe6, 0x70, 0xd7, 0x1e, 0x50, 0x5e, 0x9a, 0x63, 0xda, 0xf7, 0xd9, 0x96, 0xf6, 0x40, 0x9d, 0xd4, 0x54, 0x30, 0x5b, 0x19, 0x61, 0x8e, 0x3c, 0x06, 0x14, 0x4e, 0x03, 0xc5, 0xa2,
0x99, 0x4b, 0xaa, 0x1e, 0xd7, 0xe4, 0xcc, 0xdc, 0x51, 0xd8, 0x6f, 0x04, 0xd6, 0xce, 0x9c, 0x81, 0x80, 0x9e, 0xdf, 0xd8, 0xf9, 0xa5, 0x6c, 0x3f, 0x94, 0x16, 0xc6, 0x27, 0x05, 0xf7, 0xef, 0x39,
0x57, 0x1f, 0xf8, 0x52, 0xd1, 0xbd, 0x91, 0xe2, 0x41, 0xcd, 0x6e, 0xe4, 0x46, 0x3e, 0x78, 0xb3, 0xa6, 0x64, 0x77, 0x1d, 0x40, 0xcb, 0x42, 0x64, 0x42, 0x83, 0x72, 0x72, 0x12, 0x50, 0x3f, 0xcb,
0xa5, 0xbe, 0x7a, 0x01, 0xfd, 0xd9, 0x82, 0x3b, 0x73, 0xca, 0x93, 0x75, 0x61, 0x8f, 0xc1, 0x5d, 0xb4, 0x89, 0xcb, 0x9f, 0xa8, 0xb3, 0xfc, 0x9e, 0xb5, 0x2e, 0x3d, 0x42, 0xbb, 0x0f, 0x41, 0xbf,
0x31, 0x62, 0x43, 0xfb, 0x1f, 0x72, 0x57, 0xa1, 0xb7, 0xc5, 0xa2, 0xf5, 0xe6, 0xb1, 0xf8, 0x69, 0x5c, 0x2b, 0x6a, 0x42, 0xed, 0xcd, 0x78, 0xec, 0x18, 0x6b, 0xa8, 0x01, 0xd5, 0xf1, 0xfb, 0x91,
0x47, 0xf1, 0x0f, 0x5f, 0x23, 0x1a, 0x56, 0x24, 0xab, 0x79, 0xdd, 0x00, 0xf4, 0x0c, 0x50, 0xbe, 0xa1, 0xbd, 0x1e, 0xc0, 0xff, 0x9e, 0x08, 0x57, 0xad, 0xdd, 0xd1, 0x8e, 0x9b, 0xe5, 0xf8, 0x5b,
0xcc, 0x34, 0x2b, 0x32, 0x7a, 0xf1, 0xca, 0x08, 0x5f, 0x8b, 0xca, 0x59, 0x43, 0x61, 0x3c, 0xb5, 0x65, 0xfb, 0x53, 0x1f, 0x93, 0xc4, 0x1a, 0xa4, 0xaa, 0xfd, 0x28, 0xca, 0x93, 0x0a, 0x09, 0x3f,
0xba, 0x77, 0xd7, 0x32, 0x6b, 0x73, 0xff, 0x71, 0xe0, 0xdd, 0xc6, 0xdd, 0xd7, 0x85, 0x65, 0x06, 0xa9, 0x67, 0x0f, 0xfa, 0xde, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x77, 0x7f, 0xdc, 0x8e, 0x94,
0x87, 0xaa, 0x76, 0xfd, 0xff, 0x46, 0xc5, 0x33, 0xf4, 0xb7, 0x14, 0x14, 0xf4, 0x1e, 0x74, 0xe8, 0x06, 0x00, 0x00,
0x45, 0xc1, 0x24, 0xad, 0xbd, 0x71, 0xb1, 0xdd, 0xa1, 0x3e, 0x74, 0x2b, 0x11, 0xca, 0x75, 0x3d,
0x94, 0x7b, 0xb8, 0xd9, 0x8e, 0x42, 0x40, 0x9b, 0x36, 0x55, 0x78, 0xca, 0xc9, 0x79, 0x46, 0x93,
0xba, 0xfa, 0x1e, 0x6e, 0xb6, 0x68, 0xb8, 0xf9, 0x38, 0x1d, 0x5c, 0x7b, 0x51, 0x1e, 0x7e, 0x02,
0xde, 0xf5, 0x19, 0x45, 0x3d, 0x68, 0x3f, 0x5d, 0x2c, 0x42, 0xff, 0x16, 0xea, 0x82, 0xbb, 0xf8,
0x71, 0xee, 0x3b, 0xdf, 0x1d, 0xc3, 0x07, 0xb1, 0xc8, 0x77, 0x75, 0x2e, 0x74, 0x9e, 0xf5, 0x9a,
0xf5, 0xef, 0xad, 0xfb, 0x3f, 0x4f, 0x31, 0x29, 0x83, 0xe3, 0x0a, 0x75, 0x54, 0x14, 0x26, 0x27,
0x39, 0xe1, 0xe7, 0x9d, 0xfa, 0x75, 0x7e, 0xfc, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x25, 0xdf,
0x6a, 0xb2, 0x93, 0x08, 0x00, 0x00,
} }

View File

@ -6,7 +6,6 @@ option go_package = "proxyman";
option java_package = "com.v2ray.core.app.proxyman"; option java_package = "com.v2ray.core.app.proxyman";
option java_multiple_files = true; option java_multiple_files = true;
import "v2ray.com/core/common/serial/typed_message.proto";
import "v2ray.com/core/common/net/address.proto"; import "v2ray.com/core/common/net/address.proto";
import "v2ray.com/core/common/net/port.proto"; import "v2ray.com/core/common/net/port.proto";
import "v2ray.com/core/transport/internet/config.proto"; import "v2ray.com/core/transport/internet/config.proto";
@ -61,15 +60,6 @@ message ReceiverConfig {
repeated KnownProtocols domain_override = 7; repeated KnownProtocols domain_override = 7;
} }
message InboundHandlerConfig {
// Tag of the inbound handler.
string tag = 1;
// Settings for how this inbound proxy is handled. Must be ReceiverConfig above.
v2ray.core.common.serial.TypedMessage receiver_settings = 2;
// Settings for inbound proxy. Must be one of the inbound proxies.
v2ray.core.common.serial.TypedMessage proxy_settings = 3;
}
message OutboundConfig { message OutboundConfig {
} }
@ -82,19 +72,6 @@ message SenderConfig {
MultiplexingConfig multiplex_settings = 4; MultiplexingConfig multiplex_settings = 4;
} }
message OutboundHandlerConfig {
// Tag of this outbound handler.
string tag = 1;
// Settings for how to dial connection for this outbound handler. Must be SenderConfig above.
v2ray.core.common.serial.TypedMessage sender_settings = 2;
// Settings for this outbound proxy. Must be one of the outbound proxies.
v2ray.core.common.serial.TypedMessage proxy_settings = 3;
// If not zero, this outbound will be expired in seconds. Not used for now.
int64 expire = 4;
// Comment of this outbound handler. Not used for now.
string comment = 5;
}
message MultiplexingConfig { message MultiplexingConfig {
// Whether or not Mux is enabled. // Whether or not Mux is enabled.
bool enabled = 1; bool enabled = 1;

View File

@ -5,6 +5,7 @@ import (
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/app/proxyman/mux" "v2ray.com/core/app/proxyman/mux"
"v2ray.com/core/common"
"v2ray.com/core/common/dice" "v2ray.com/core/common/dice"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
@ -14,17 +15,23 @@ type AlwaysOnInboundHandler struct {
proxy proxy.Inbound proxy proxy.Inbound
workers []worker workers []worker
mux *mux.Server mux *mux.Server
tag string
} }
func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) { func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*AlwaysOnInboundHandler, error) {
p, err := proxy.CreateInboundHandler(ctx, proxyConfig) rawProxy, err := common.CreateObject(ctx, proxyConfig)
if err != nil { if err != nil {
return nil, err return nil, err
} }
p, ok := rawProxy.(proxy.Inbound)
if !ok {
return nil, newError("not an inbound proxy.")
}
h := &AlwaysOnInboundHandler{ h := &AlwaysOnInboundHandler{
proxy: p, proxy: p,
mux: mux.NewServer(ctx), mux: mux.NewServer(ctx),
tag: tag,
} }
nl := p.Network() nl := p.Network()
@ -74,16 +81,26 @@ func (h *AlwaysOnInboundHandler) Start() error {
return nil return nil
} }
func (h *AlwaysOnInboundHandler) Close() { func (h *AlwaysOnInboundHandler) Close() error {
for _, worker := range h.workers { for _, worker := range h.workers {
worker.Close() worker.Close()
} }
h.mux.Close()
return nil
} }
func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (proxy.Inbound, net.Port, int) { func (h *AlwaysOnInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
if len(h.workers) == 0 { if len(h.workers) == 0 {
return nil, 0, 0 return nil, 0, 0
} }
w := h.workers[dice.Roll(len(h.workers))] w := h.workers[dice.Roll(len(h.workers))]
return w.Proxy(), w.Port(), 9999 return w.Proxy(), w.Port(), 9999
} }
func (h *AlwaysOnInboundHandler) Tag() string {
return h.tag
}
func (h *AlwaysOnInboundHandler) GetInbound() proxy.Inbound {
return h.proxy
}

View File

@ -5,17 +5,18 @@ import (
"sync" "sync"
"time" "time"
"v2ray.com/core"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/app/proxyman/mux" "v2ray.com/core/app/proxyman/mux"
"v2ray.com/core/common/dice" "v2ray.com/core/common/dice"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/signal"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
) )
type DynamicInboundHandler struct { type DynamicInboundHandler struct {
tag string tag string
ctx context.Context v *core.Instance
cancel context.CancelFunc
proxyConfig interface{} proxyConfig interface{}
receiverConfig *proxyman.ReceiverConfig receiverConfig *proxyman.ReceiverConfig
portMutex sync.Mutex portMutex sync.Mutex
@ -24,18 +25,26 @@ type DynamicInboundHandler struct {
worker []worker worker []worker
lastRefresh time.Time lastRefresh time.Time
mux *mux.Server mux *mux.Server
task *signal.PeriodicTask
} }
func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) { func NewDynamicInboundHandler(ctx context.Context, tag string, receiverConfig *proxyman.ReceiverConfig, proxyConfig interface{}) (*DynamicInboundHandler, error) {
ctx, cancel := context.WithCancel(ctx) v := core.FromContext(ctx)
if v == nil {
return nil, newError("V is not in context.")
}
h := &DynamicInboundHandler{ h := &DynamicInboundHandler{
ctx: ctx,
tag: tag, tag: tag,
cancel: cancel,
proxyConfig: proxyConfig, proxyConfig: proxyConfig,
receiverConfig: receiverConfig, receiverConfig: receiverConfig,
portsInUse: make(map[net.Port]bool), portsInUse: make(map[net.Port]bool),
mux: mux.NewServer(ctx), mux: mux.NewServer(ctx),
v: v,
}
h.task = &signal.PeriodicTask{
Interval: time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()),
Execute: h.refresh,
} }
return h, nil return h, nil
@ -59,9 +68,7 @@ func (h *DynamicInboundHandler) allocatePort() net.Port {
} }
} }
func (h *DynamicInboundHandler) waitAnyCloseWorkers(ctx context.Context, cancel context.CancelFunc, workers []worker, duration time.Duration) { func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
time.Sleep(duration)
cancel()
ports2Del := make([]net.Port, len(workers)) ports2Del := make([]net.Port, len(workers))
for idx, worker := range workers { for idx, worker := range workers {
ports2Del[idx] = worker.Port() ports2Del[idx] = worker.Port()
@ -80,7 +87,6 @@ func (h *DynamicInboundHandler) refresh() error {
timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2 timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue() concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
ctx, cancel := context.WithTimeout(h.ctx, timeout)
workers := make([]worker, 0, concurrency) workers := make([]worker, 0, concurrency)
address := h.receiverConfig.Listen.AsAddress() address := h.receiverConfig.Listen.AsAddress()
@ -89,11 +95,12 @@ func (h *DynamicInboundHandler) refresh() error {
} }
for i := uint32(0); i < concurrency; i++ { for i := uint32(0); i < concurrency; i++ {
port := h.allocatePort() port := h.allocatePort()
p, err := proxy.CreateInboundHandler(ctx, h.proxyConfig) rawProxy, err := h.v.CreateObject(h.proxyConfig)
if err != nil { if err != nil {
newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog() newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog()
continue continue
} }
p := rawProxy.(proxy.Inbound)
nl := p.Network() nl := p.Network()
if nl.HasNetwork(net.Network_TCP) { if nl.HasNetwork(net.Network_TCP) {
worker := &tcpWorker{ worker := &tcpWorker{
@ -134,36 +141,22 @@ func (h *DynamicInboundHandler) refresh() error {
h.worker = workers h.worker = workers
h.workerMutex.Unlock() h.workerMutex.Unlock()
go h.waitAnyCloseWorkers(ctx, cancel, workers, timeout) time.AfterFunc(timeout, func() {
h.closeWorkers(workers)
})
return nil return nil
} }
func (h *DynamicInboundHandler) monitor() {
timer := time.NewTicker(time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()))
defer timer.Stop()
for {
select {
case <-h.ctx.Done():
return
case <-timer.C:
h.refresh()
}
}
}
func (h *DynamicInboundHandler) Start() error { func (h *DynamicInboundHandler) Start() error {
err := h.refresh() return h.task.Start()
go h.monitor()
return err
} }
func (h *DynamicInboundHandler) Close() { func (h *DynamicInboundHandler) Close() error {
h.cancel() return h.task.Close()
} }
func (h *DynamicInboundHandler) GetRandomInboundProxy() (proxy.Inbound, net.Port, int) { func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
h.workerMutex.RLock() h.workerMutex.RLock()
defer h.workerMutex.RUnlock() defer h.workerMutex.RUnlock()
@ -174,3 +167,7 @@ func (h *DynamicInboundHandler) GetRandomInboundProxy() (proxy.Inbound, net.Port
expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute) expire := h.receiverConfig.AllocationStrategy.GetRefreshValue() - uint32(time.Since(h.lastRefresh)/time.Minute)
return w.Proxy(), w.Port(), int(expire) return w.Proxy(), w.Port(), int(expire)
} }
func (h *DynamicInboundHandler) Tag() string {
return h.tag
}

View File

@ -4,65 +4,60 @@ package inbound
import ( import (
"context" "context"
"sync"
"v2ray.com/core"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/common" "v2ray.com/core/common"
) )
// Manager is to manage all inbound handlers. // Manager is to manage all inbound handlers.
type Manager struct { type Manager struct {
handlers []proxyman.InboundHandler access sync.RWMutex
taggedHandlers map[string]proxyman.InboundHandler untaggedHandler []core.InboundHandler
taggedHandlers map[string]core.InboundHandler
running bool
} }
// New returns a new Manager for inbound handlers.
func New(ctx context.Context, config *proxyman.InboundConfig) (*Manager, error) { func New(ctx context.Context, config *proxyman.InboundConfig) (*Manager, error) {
return &Manager{ m := &Manager{
taggedHandlers: make(map[string]proxyman.InboundHandler), taggedHandlers: make(map[string]core.InboundHandler),
}, nil }
v := core.FromContext(ctx)
if v == nil {
return nil, newError("V is not in context")
}
if err := v.RegisterFeature((*core.InboundHandlerManager)(nil), m); err != nil {
return nil, newError("unable to register InboundHandlerManager").Base(err)
}
return m, nil
} }
func (m *Manager) AddHandler(ctx context.Context, config *proxyman.InboundHandlerConfig) error { // AddHandler implements core.InboundHandlerManager.
rawReceiverSettings, err := config.ReceiverSettings.GetInstance() func (m *Manager) AddHandler(ctx context.Context, handler core.InboundHandler) error {
if err != nil { m.access.Lock()
return err defer m.access.Unlock()
}
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
if !ok {
return newError("not a ReceiverConfig").AtError()
}
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 { tag := handler.Tag()
return newError("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
}
m.handlers = append(m.handlers, handler)
if len(tag) > 0 { if len(tag) > 0 {
m.taggedHandlers[tag] = handler m.taggedHandlers[tag] = handler
} else {
m.untaggedHandler = append(m.untaggedHandler, handler)
} }
if m.running {
return handler.Start()
}
return nil return nil
} }
func (m *Manager) GetHandler(ctx context.Context, tag string) (proxyman.InboundHandler, error) { // GetHandler returns core.InboundHandlerManager.
func (m *Manager) GetHandler(ctx context.Context, tag string) (core.InboundHandler, error) {
m.access.RLock()
defer m.access.RUnlock()
handler, found := m.taggedHandlers[tag] handler, found := m.taggedHandlers[tag]
if !found { if !found {
return nil, newError("handler not found: ", tag) return nil, newError("handler not found: ", tag)
@ -70,8 +65,36 @@ func (m *Manager) GetHandler(ctx context.Context, tag string) (proxyman.InboundH
return handler, nil return handler, nil
} }
func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
if len(tag) == 0 {
return core.ErrNoClue
}
m.access.Lock()
defer m.access.Unlock()
if handler, found := m.taggedHandlers[tag]; found {
handler.Close()
delete(m.taggedHandlers, tag)
return nil
}
return core.ErrNoClue
}
func (m *Manager) Start() error { func (m *Manager) Start() error {
for _, handler := range m.handlers { m.access.Lock()
defer m.access.Unlock()
m.running = true
for _, handler := range m.taggedHandlers {
if err := handler.Start(); err != nil {
return err
}
}
for _, handler := range m.untaggedHandler {
if err := handler.Start(); err != nil { if err := handler.Start(); err != nil {
return err return err
} }
@ -79,18 +102,52 @@ func (m *Manager) Start() error {
return nil return nil
} }
func (m *Manager) Close() { func (m *Manager) Close() error {
for _, handler := range m.handlers { m.access.Lock()
defer m.access.Unlock()
m.running = false
for _, handler := range m.taggedHandlers {
handler.Close() handler.Close()
} }
for _, handler := range m.untaggedHandler {
handler.Close()
}
return nil
} }
func (m *Manager) Interface() interface{} { func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (core.InboundHandler, error) {
return (*proxyman.InboundHandlerManager)(nil) rawReceiverSettings, err := config.ReceiverSettings.GetInstance()
if err != nil {
return nil, err
}
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
if !ok {
return nil, newError("not a ReceiverConfig").AtError()
}
proxySettings, err := config.ProxySettings.GetInstance()
if err != nil {
return nil, err
}
tag := config.Tag
allocStrategy := receiverSettings.AllocationStrategy
if allocStrategy == nil || allocStrategy.Type == proxyman.AllocationStrategy_Always {
return NewAlwaysOnInboundHandler(ctx, tag, receiverSettings, proxySettings)
}
if allocStrategy.Type == proxyman.AllocationStrategy_Random {
return NewDynamicInboundHandler(ctx, tag, receiverSettings, proxySettings)
}
return nil, newError("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
} }
func init() { func init() {
common.Must(common.RegisterConfig((*proxyman.InboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*proxyman.InboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*proxyman.InboundConfig)) return New(ctx, config.(*proxyman.InboundConfig))
})) }))
common.Must(common.RegisterConfig((*core.InboundHandlerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewHandler(ctx, config.(*core.InboundHandlerConfig))
}))
} }

View File

@ -7,10 +7,12 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"v2ray.com/core/app/dispatcher" "v2ray.com/core"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/signal"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/internet/tcp" "v2ray.com/core/transport/internet/tcp"
@ -19,7 +21,7 @@ import (
type worker interface { type worker interface {
Start() error Start() error
Close() Close() error
Port() net.Port Port() net.Port
Proxy() proxy.Inbound Proxy() proxy.Inbound
} }
@ -31,16 +33,14 @@ type tcpWorker struct {
stream *internet.StreamConfig stream *internet.StreamConfig
recvOrigDest bool recvOrigDest bool
tag string tag string
dispatcher dispatcher.Interface dispatcher core.Dispatcher
sniffers []proxyman.KnownProtocols sniffers []proxyman.KnownProtocols
ctx context.Context hub internet.Listener
cancel context.CancelFunc
hub internet.Listener
} }
func (w *tcpWorker) callback(conn internet.Connection) { func (w *tcpWorker) callback(conn internet.Connection) {
ctx, cancel := context.WithCancel(w.ctx) ctx, cancel := context.WithCancel(context.Background())
if w.recvOrigDest { if w.recvOrigDest {
dest, err := tcp.GetOriginalDestination(conn) dest, err := tcp.GetOriginalDestination(conn)
if err != nil { if err != nil {
@ -70,45 +70,24 @@ func (w *tcpWorker) Proxy() proxy.Inbound {
} }
func (w *tcpWorker) Start() error { func (w *tcpWorker) Start() error {
ctx, cancel := context.WithCancel(context.Background()) ctx := internet.ContextWithStreamSettings(context.Background(), w.stream)
w.ctx = ctx hub, err := internet.ListenTCP(ctx, w.address, w.port, func(conn internet.Connection) {
w.cancel = cancel go w.callback(conn)
ctx = internet.ContextWithStreamSettings(ctx, w.stream) })
conns := make(chan internet.Connection, 16)
hub, err := internet.ListenTCP(ctx, w.address, w.port, conns)
if err != nil { if err != nil {
return newError("failed to listen TCP on ", w.port).AtWarning().Base(err) return newError("failed to listen TCP on ", w.port).AtWarning().Base(err)
} }
go w.handleConnections(conns)
w.hub = hub w.hub = hub
return nil return nil
} }
func (w *tcpWorker) handleConnections(conns <-chan internet.Connection) { func (w *tcpWorker) Close() error {
for {
select {
case <-w.ctx.Done():
w.hub.Close()
L:
for {
select {
case conn := <-conns:
conn.Close()
default:
break L
}
}
return
case conn := <-conns:
go w.callback(conn)
}
}
}
func (w *tcpWorker) Close() {
if w.hub != nil { if w.hub != nil {
w.cancel() common.Close(w.hub)
common.Close(w.proxy)
} }
return nil
} }
func (w *tcpWorker) Port() net.Port { func (w *tcpWorker) Port() net.Port {
@ -121,7 +100,7 @@ type udpConn struct {
output func([]byte) (int, error) output func([]byte) (int, error)
remote net.Addr remote net.Addr
local net.Addr local net.Addr
cancel context.CancelFunc done *signal.Done
} }
func (c *udpConn) updateActivity() { func (c *udpConn) updateActivity() {
@ -129,13 +108,14 @@ func (c *udpConn) updateActivity() {
} }
func (c *udpConn) Read(buf []byte) (int, error) { func (c *udpConn) Read(buf []byte) (int, error) {
in, open := <-c.input select {
if !open { case in := <-c.input:
defer in.Release()
c.updateActivity()
return copy(buf, in.Bytes()), nil
case <-c.done.C():
return 0, io.EOF return 0, io.EOF
} }
defer in.Release()
c.updateActivity()
return copy(buf, in.Bytes()), nil
} }
// Write implements io.Writer. // Write implements io.Writer.
@ -148,6 +128,7 @@ func (c *udpConn) Write(buf []byte) (int, error) {
} }
func (c *udpConn) Close() error { func (c *udpConn) Close() error {
common.Close(c.done)
return nil return nil
} }
@ -171,7 +152,7 @@ func (*udpConn) SetWriteDeadline(time.Time) error {
return nil return nil
} }
type connId struct { type connID struct {
src net.Destination src net.Destination
dest net.Destination dest net.Destination
} }
@ -185,14 +166,13 @@ type udpWorker struct {
port net.Port port net.Port
recvOrigDest bool recvOrigDest bool
tag string tag string
dispatcher dispatcher.Interface dispatcher core.Dispatcher
ctx context.Context done *signal.Done
cancel context.CancelFunc activeConn map[connID]*udpConn
activeConn map[connId]*udpConn
} }
func (w *udpWorker) getConnection(id connId) (*udpConn, bool) { func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
w.Lock() w.Lock()
defer w.Unlock() defer w.Unlock()
@ -213,6 +193,7 @@ func (w *udpWorker) getConnection(id connId) (*udpConn, bool) {
IP: w.address.IP(), IP: w.address.IP(),
Port: int(w.port), Port: int(w.port),
}, },
done: signal.NewDone(),
} }
w.activeConn[id] = conn w.activeConn[id] = conn
@ -221,22 +202,22 @@ func (w *udpWorker) getConnection(id connId) (*udpConn, bool) {
} }
func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest net.Destination) { func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest net.Destination) {
id := connId{ id := connID{
src: source, src: source,
dest: originalDest, dest: originalDest,
} }
conn, existing := w.getConnection(id) conn, existing := w.getConnection(id)
select { select {
case conn.input <- b: case conn.input <- b:
case <-conn.done.C():
b.Release()
default: default:
b.Release() b.Release()
} }
if !existing { if !existing {
go func() { go func() {
ctx := w.ctx ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
conn.cancel = cancel
if originalDest.IsValid() { if originalDest.IsValid() {
ctx = proxy.ContextWithOriginalTarget(ctx, originalDest) ctx = proxy.ContextWithOriginalTarget(ctx, originalDest)
} }
@ -248,23 +229,21 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil { if err := w.proxy.Process(ctx, net.Network_UDP, conn, w.dispatcher); err != nil {
newError("connection ends").Base(err).WriteToLog() newError("connection ends").Base(err).WriteToLog()
} }
conn.Close()
w.removeConn(id) w.removeConn(id)
cancel()
}() }()
} }
} }
func (w *udpWorker) removeConn(id connId) { func (w *udpWorker) removeConn(id connID) {
w.Lock() w.Lock()
delete(w.activeConn, id) delete(w.activeConn, id)
w.Unlock() w.Unlock()
} }
func (w *udpWorker) Start() error { func (w *udpWorker) Start() error {
w.activeConn = make(map[connId]*udpConn, 16) w.activeConn = make(map[connID]*udpConn, 16)
ctx, cancel := context.WithCancel(context.Background()) w.done = signal.NewDone()
w.ctx = ctx
w.cancel = cancel
h, err := udp.ListenUDP(w.address, w.port, udp.ListenOption{ h, err := udp.ListenUDP(w.address, w.port, udp.ListenOption{
Callback: w.callback, Callback: w.callback,
ReceiveOriginalDest: w.recvOrigDest, ReceiveOriginalDest: w.recvOrigDest,
@ -277,11 +256,13 @@ func (w *udpWorker) Start() error {
return nil return nil
} }
func (w *udpWorker) Close() { func (w *udpWorker) Close() error {
if w.hub != nil { if w.hub != nil {
w.hub.Close() w.hub.Close()
w.cancel() w.done.Close()
common.Close(w.proxy)
} }
return nil
} }
func (w *udpWorker) monitor() { func (w *udpWorker) monitor() {
@ -290,7 +271,7 @@ func (w *udpWorker) monitor() {
for { for {
select { select {
case <-w.ctx.Done(): case <-w.done.C():
return return
case <-timer.C: case <-timer.C:
nowSec := time.Now().Unix() nowSec := time.Now().Unix()
@ -298,7 +279,7 @@ func (w *udpWorker) monitor() {
for addr, conn := range w.activeConn { for addr, conn := range w.activeConn {
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 { if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 {
delete(w.activeConn, addr) delete(w.activeConn, addr)
conn.cancel() conn.Close()
} }
} }
w.Unlock() w.Unlock()

View File

@ -8,13 +8,13 @@ import (
"sync" "sync"
"time" "time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/signal"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
) )
@ -75,8 +75,7 @@ func (m *ClientManager) onClientFinish() {
type Client struct { type Client struct {
sessionManager *SessionManager sessionManager *SessionManager
inboundRay ray.InboundRay inboundRay ray.InboundRay
ctx context.Context done *signal.Done
cancel context.CancelFunc
manager *ClientManager manager *ClientManager
concurrency uint32 concurrency uint32
} }
@ -86,26 +85,26 @@ var muxCoolPort = net.Port(9527)
// NewClient creates a new mux.Client. // NewClient creates a new mux.Client.
func NewClient(p proxy.Outbound, dialer proxy.Dialer, m *ClientManager) (*Client, error) { func NewClient(p proxy.Outbound, dialer proxy.Dialer, m *ClientManager) (*Client, error) {
ctx, cancel := context.WithCancel(context.Background()) ctx := proxy.ContextWithTarget(context.Background(), net.TCPDestination(muxCoolAddress, muxCoolPort))
ctx = proxy.ContextWithTarget(ctx, net.TCPDestination(muxCoolAddress, muxCoolPort)) ctx, cancel := context.WithCancel(ctx)
pipe := ray.NewRay(ctx) pipe := ray.NewRay(ctx)
go func() {
if err := p.Process(ctx, pipe, dialer); err != nil {
cancel()
errors.New("failed to handler mux client connection").Base(err).WriteToLog()
}
}()
c := &Client{ c := &Client{
sessionManager: NewSessionManager(), sessionManager: NewSessionManager(),
inboundRay: pipe, inboundRay: pipe,
ctx: ctx, done: signal.NewDone(),
cancel: cancel,
manager: m, manager: m,
concurrency: m.config.Concurrency, concurrency: m.config.Concurrency,
} }
go func() {
if err := p.Process(ctx, pipe, dialer); err != nil {
errors.New("failed to handler mux client connection").Base(err).WriteToLog()
}
c.done.Close()
cancel()
}()
go c.fetchOutput() go c.fetchOutput()
go c.monitor() go c.monitor()
return c, nil return c, nil
@ -113,12 +112,7 @@ func NewClient(p proxy.Outbound, dialer proxy.Dialer, m *ClientManager) (*Client
// Closed returns true if this Client is closed. // Closed returns true if this Client is closed.
func (m *Client) Closed() bool { func (m *Client) Closed() bool {
select { return m.done.Done()
case <-m.ctx.Done():
return true
default:
return false
}
} }
func (m *Client) monitor() { func (m *Client) monitor() {
@ -129,7 +123,7 @@ func (m *Client) monitor() {
for { for {
select { select {
case <-m.ctx.Done(): case <-m.done.C():
m.sessionManager.Close() m.sessionManager.Close()
m.inboundRay.InboundInput().Close() m.inboundRay.InboundInput().Close()
m.inboundRay.InboundOutput().CloseError() m.inboundRay.InboundOutput().CloseError()
@ -137,7 +131,8 @@ func (m *Client) monitor() {
case <-timer.C: case <-timer.C:
size := m.sessionManager.Size() size := m.sessionManager.Size()
if size == 0 && m.sessionManager.CloseIfNoSession() { if size == 0 && m.sessionManager.CloseIfNoSession() {
m.cancel() m.done.Close()
return
} }
} }
} }
@ -171,10 +166,8 @@ func (m *Client) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) bool
return false return false
} }
select { if m.done.Done() {
case <-m.ctx.Done():
return false return false
default:
} }
s := sm.Allocate() s := sm.Allocate()
@ -227,7 +220,7 @@ func (m *Client) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader
} }
func (m *Client) fetchOutput() { func (m *Client) fetchOutput() {
defer m.cancel() defer m.done.Close()
reader := buf.NewBufferedReader(m.inboundRay.InboundOutput()) reader := buf.NewBufferedReader(m.inboundRay.InboundOutput())
@ -262,21 +255,14 @@ func (m *Client) fetchOutput() {
} }
type Server struct { type Server struct {
dispatcher dispatcher.Interface dispatcher core.Dispatcher
} }
// NewServer creates a new mux.Server. // NewServer creates a new mux.Server.
func NewServer(ctx context.Context) *Server { func NewServer(ctx context.Context) *Server {
s := &Server{} s := &Server{
space := app.SpaceFromContext(ctx) dispatcher: core.FromContext(ctx).Dispatcher(),
space.On(app.SpaceInitializing, func(interface{}) error { }
d := dispatcher.FromSpace(space)
if d == nil {
return newError("no dispatcher in space")
}
s.dispatcher = d
return nil
})
return s return s
} }
@ -295,8 +281,16 @@ func (s *Server) Dispatch(ctx context.Context, dest net.Destination) (ray.Inboun
return ray, nil return ray, nil
} }
func (s *Server) Start() error {
return nil
}
func (s *Server) Close() error {
return nil
}
type ServerWorker struct { type ServerWorker struct {
dispatcher dispatcher.Interface dispatcher core.Dispatcher
outboundRay ray.OutboundRay outboundRay ray.OutboundRay
sessionManager *SessionManager sessionManager *SessionManager
} }

View File

@ -103,12 +103,12 @@ func (m *SessionManager) CloseIfNoSession() bool {
return true return true
} }
func (m *SessionManager) Close() { func (m *SessionManager) Close() error {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
if m.closed { if m.closed {
return return nil
} }
m.closed = true m.closed = true
@ -119,6 +119,7 @@ func (m *SessionManager) Close() {
} }
m.sessions = nil m.sessions = nil
return nil
} }
// Session represents a client connection in a Mux connection. // Session represents a client connection in a Mux connection.
@ -131,10 +132,11 @@ type Session struct {
} }
// Close closes all resources associated with this session. // Close closes all resources associated with this session.
func (s *Session) Close() { func (s *Session) Close() error {
s.output.Close() s.output.Close()
s.input.Close() s.input.Close()
s.parent.Remove(s.ID) s.parent.Remove(s.ID)
return nil
} }
// NewReader creates a buf.Reader based on the transfer type of this Session. // NewReader creates a buf.Reader based on the transfer type of this Session.

View File

@ -100,7 +100,7 @@ func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {
return nil return nil
} }
func (w *Writer) Close() { func (w *Writer) Close() error {
meta := FrameMetadata{ meta := FrameMetadata{
SessionID: w.id, SessionID: w.id,
SessionStatus: SessionStatusEnd, SessionStatus: SessionStatusEnd,
@ -110,4 +110,5 @@ func (w *Writer) Close() {
common.Must(frame.Reset(meta.AsSupplier())) common.Must(frame.Reset(meta.AsSupplier()))
w.writer.WriteMultiBuffer(buf.NewMultiBufferValue(frame)) w.writer.WriteMultiBuffer(buf.NewMultiBufferValue(frame))
return nil
} }

View File

@ -3,12 +3,11 @@ package outbound
import ( import (
"context" "context"
"io" "io"
"time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/app/proxyman/mux" "v2ray.com/core/app/proxyman/mux"
"v2ray.com/core/common/buf" "v2ray.com/core/common"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
@ -17,29 +16,22 @@ import (
) )
type Handler struct { type Handler struct {
config *proxyman.OutboundHandlerConfig config *core.OutboundHandlerConfig
senderSettings *proxyman.SenderConfig senderSettings *proxyman.SenderConfig
proxy proxy.Outbound proxy proxy.Outbound
outboundManager proxyman.OutboundHandlerManager outboundManager core.OutboundHandlerManager
mux *mux.ClientManager mux *mux.ClientManager
} }
func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*Handler, error) { func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (*Handler, error) {
v := core.FromContext(ctx)
if v == nil {
return nil, newError("V is not in context")
}
h := &Handler{ h := &Handler{
config: config, config: config,
outboundManager: v.OutboundHandlerManager(),
} }
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, newError("no space in context")
}
space.On(app.SpaceInitializing, func(interface{}) error {
ohm := proxyman.OutboundHandlerManagerFromSpace(space)
if ohm == nil {
return newError("no OutboundManager in space")
}
h.outboundManager = ohm
return nil
})
if config.SenderSettings != nil { if config.SenderSettings != nil {
senderSettings, err := config.SenderSettings.GetInstance() senderSettings, err := config.SenderSettings.GetInstance()
@ -54,11 +46,21 @@ func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*H
} }
} }
proxyHandler, err := config.GetProxyHandler(ctx) proxyConfig, err := config.ProxySettings.GetInstance()
if err != nil { if err != nil {
return nil, err return nil, err
} }
rawProxyHandler, err := common.CreateObject(ctx, proxyConfig)
if err != nil {
return nil, err
}
proxyHandler, ok := rawProxyHandler.(proxy.Outbound)
if !ok {
return nil, newError("not an outbound handler")
}
if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil && h.senderSettings.MultiplexSettings.Enabled { if h.senderSettings != nil && h.senderSettings.MultiplexSettings != nil && h.senderSettings.MultiplexSettings.Enabled {
config := h.senderSettings.MultiplexSettings config := h.senderSettings.MultiplexSettings
if config.Concurrency < 1 || config.Concurrency > 1024 { if config.Concurrency < 1 || config.Concurrency > 1024 {
@ -71,6 +73,11 @@ func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*H
return h, nil return h, nil
} }
// Tag implements core.OutboundHandler.
func (h *Handler) Tag() string {
return h.config.Tag
}
// Dispatch implements proxy.Outbound.Dispatch. // Dispatch implements proxy.Outbound.Dispatch.
func (h *Handler) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) { func (h *Handler) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) {
if h.mux != nil { if h.mux != nil {
@ -103,7 +110,7 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (internet.Conn
ctx = proxy.ContextWithTarget(ctx, dest) ctx = proxy.ContextWithTarget(ctx, dest)
stream := ray.NewRay(ctx) stream := ray.NewRay(ctx)
go handler.Dispatch(ctx, stream) go handler.Dispatch(ctx, stream)
return NewConnection(stream), nil return ray.NewConnection(stream.InboundOutput(), stream.InboundInput()), nil
} }
newError("failed to get outbound handler with tag: ", tag).AtWarning().WriteToLog() newError("failed to get outbound handler with tag: ", tag).AtWarning().WriteToLog()
@ -121,98 +128,18 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (internet.Conn
return internet.Dial(ctx, dest) return internet.Dial(ctx, dest)
} }
var ( // GetOutbound implements proxy.GetOutbound.
_ buf.Reader = (*Connection)(nil) func (h *Handler) GetOutbound() proxy.Outbound {
_ buf.Writer = (*Connection)(nil) return h.proxy
)
type Connection struct {
stream ray.Ray
closed bool
localAddr net.Addr
remoteAddr net.Addr
reader *buf.BufferedReader
writer buf.Writer
} }
func NewConnection(stream ray.Ray) *Connection { // Start implements common.Runnable.
return &Connection{ func (h *Handler) Start() error {
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.NewBufferedReader(stream.InboundOutput()),
writer: 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)
}
func (v *Connection) ReadMultiBuffer() (buf.MultiBuffer, error) {
return v.reader.ReadMultiBuffer()
}
// Write implements net.Conn.Write().
func (v *Connection) Write(b []byte) (int, error) {
if v.closed {
return 0, io.ErrClosedPipe
}
l := len(b)
mb := buf.NewMultiBufferCap(l/buf.Size + 1)
mb.Write(b)
return l, v.writer.WriteMultiBuffer(mb)
}
func (v *Connection) WriteMultiBuffer(mb buf.MultiBuffer) error {
if v.closed {
return io.ErrClosedPipe
}
return v.writer.WriteMultiBuffer(mb)
}
// Close implements net.Conn.Close().
func (v *Connection) Close() error {
v.closed = true
v.stream.InboundInput().Close()
v.stream.InboundOutput().CloseError()
return nil return nil
} }
// LocalAddr implements net.Conn.LocalAddr(). // Close implements common.Runnable.
func (v *Connection) LocalAddr() net.Addr { func (h *Handler) Close() error {
return v.localAddr common.Close(h.mux)
}
// RemoteAddr implements net.Conn.RemoteAddr().
func (v *Connection) RemoteAddr() net.Addr {
return v.remoteAddr
}
// SetDeadline implements net.Conn.SetDeadline().
func (v *Connection) SetDeadline(t time.Time) error {
return nil
}
// SetReadDeadline implements net.Conn.SetReadDeadline().
func (v *Connection) SetReadDeadline(t time.Time) error {
return nil
}
// SetWriteDeadline implement net.Conn.SetWriteDeadline().
func (v *Connection) SetWriteDeadline(t time.Time) error {
return nil return nil
} }

View File

@ -0,0 +1,16 @@
package outbound_test
import (
"testing"
"v2ray.com/core"
. "v2ray.com/core/app/proxyman/outbound"
. "v2ray.com/ext/assert"
)
func TestInterfaces(t *testing.T) {
assert := With(t)
assert((*Handler)(nil), Implements, (*core.OutboundHandler)(nil))
assert((*Manager)(nil), Implements, (*core.OutboundHandlerManager)(nil))
}

View File

@ -6,67 +6,130 @@ import (
"context" "context"
"sync" "sync"
"v2ray.com/core"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
"v2ray.com/core/common" "v2ray.com/core/common"
) )
// Manager is to manage all outbound handlers. // Manager is to manage all outbound handlers.
type Manager struct { type Manager struct {
sync.RWMutex access sync.RWMutex
defaultHandler *Handler defaultHandler core.OutboundHandler
taggedHandler map[string]*Handler taggedHandler map[string]core.OutboundHandler
untaggedHandlers []core.OutboundHandler
running bool
} }
// New creates a new Manager. // New creates a new Manager.
func New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error) { func New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error) {
return &Manager{ m := &Manager{
taggedHandler: make(map[string]*Handler), taggedHandler: make(map[string]core.OutboundHandler),
}, nil }
v := core.FromContext(ctx)
if v == nil {
return nil, newError("V is not in context")
}
if err := v.RegisterFeature((*core.OutboundHandlerManager)(nil), m); err != nil {
return nil, newError("unable to register OutboundHandlerManager").Base(err)
}
return m, nil
} }
// Interface implements Application.Interface. // Start implements core.Feature
func (*Manager) Interface() interface{} { func (m *Manager) Start() error {
return (*proxyman.OutboundHandlerManager)(nil) m.access.Lock()
defer m.access.Unlock()
m.running = true
for _, h := range m.taggedHandler {
if err := h.Start(); err != nil {
return err
}
}
for _, h := range m.untaggedHandlers {
if err := h.Start(); err != nil {
return err
}
}
return nil
} }
// Start implements Application.Start // Close implements core.Feature
func (*Manager) Start() error { return nil } func (m *Manager) Close() error {
m.access.Lock()
defer m.access.Unlock()
// Close implements Application.Close m.running = false
func (*Manager) Close() {}
for _, h := range m.taggedHandler {
h.Close()
}
for _, h := range m.untaggedHandlers {
h.Close()
}
return nil
}
// GetDefaultHandler implements core.OutboundHandlerManager.
func (m *Manager) GetDefaultHandler() core.OutboundHandler {
m.access.RLock()
defer m.access.RUnlock()
func (m *Manager) GetDefaultHandler() proxyman.OutboundHandler {
m.RLock()
defer m.RUnlock()
if m.defaultHandler == nil { if m.defaultHandler == nil {
return nil return nil
} }
return m.defaultHandler return m.defaultHandler
} }
func (m *Manager) GetHandler(tag string) proxyman.OutboundHandler { // GetHandler implements core.OutboundHandlerManager.
m.RLock() func (m *Manager) GetHandler(tag string) core.OutboundHandler {
defer m.RUnlock() m.access.RLock()
defer m.access.RUnlock()
if handler, found := m.taggedHandler[tag]; found { if handler, found := m.taggedHandler[tag]; found {
return handler return handler
} }
return nil return nil
} }
func (m *Manager) AddHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) error { // AddHandler implements core.OutboundHandlerManager.
m.Lock() func (m *Manager) AddHandler(ctx context.Context, handler core.OutboundHandler) error {
defer m.Unlock() m.access.Lock()
defer m.access.Unlock()
handler, err := NewHandler(ctx, config)
if err != nil {
return err
}
if m.defaultHandler == nil { if m.defaultHandler == nil {
m.defaultHandler = handler m.defaultHandler = handler
} }
if len(config.Tag) > 0 { tag := handler.Tag()
m.taggedHandler[config.Tag] = handler if len(tag) > 0 {
m.taggedHandler[tag] = handler
} else {
m.untaggedHandlers = append(m.untaggedHandlers, handler)
}
if m.running {
return handler.Start()
}
return nil
}
// RemoveHandler implements core.OutboundHandlerManager.
func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
if len(tag) == 0 {
return core.ErrNoClue
}
m.access.Lock()
defer m.access.Unlock()
delete(m.taggedHandler, tag)
if m.defaultHandler.Tag() == tag {
m.defaultHandler = nil
} }
return nil return nil
@ -76,4 +139,7 @@ func init() {
common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*proxyman.OutboundConfig)) return New(ctx, config.(*proxyman.OutboundConfig))
})) }))
common.Must(common.RegisterConfig((*core.OutboundHandlerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return NewHandler(ctx, config.(*core.OutboundHandlerConfig))
}))
} }

View File

@ -5,52 +5,8 @@ package proxyman
import ( import (
"context" "context"
"v2ray.com/core/app"
"v2ray.com/core/common/net"
"v2ray.com/core/proxy"
"v2ray.com/core/transport/ray"
) )
type InboundHandlerManager interface {
GetHandler(ctx context.Context, tag string) (InboundHandler, error)
AddHandler(ctx context.Context, config *InboundHandlerConfig) error
}
type InboundHandler interface {
Start() error
Close()
// For migration
GetRandomInboundProxy() (proxy.Inbound, net.Port, int)
}
type OutboundHandlerManager interface {
GetHandler(tag string) OutboundHandler
GetDefaultHandler() OutboundHandler
AddHandler(ctx context.Context, config *OutboundHandlerConfig) error
}
type OutboundHandler interface {
Dispatch(ctx context.Context, outboundRay ray.OutboundRay)
}
func InboundHandlerManagerFromSpace(space app.Space) InboundHandlerManager {
app := space.GetApplication((*InboundHandlerManager)(nil))
if app == nil {
return nil
}
return app.(InboundHandlerManager)
}
func OutboundHandlerManagerFromSpace(space app.Space) OutboundHandlerManager {
app := space.GetApplication((*OutboundHandlerManager)(nil))
if app == nil {
return nil
}
return app.(OutboundHandlerManager)
}
type key int type key int
const ( const (

View File

@ -5,46 +5,47 @@ package router
import ( import (
"context" "context"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
) )
var (
ErrNoRuleApplicable = newError("No rule applicable")
)
type Router struct { type Router struct {
domainStrategy Config_DomainStrategy domainStrategy Config_DomainStrategy
rules []Rule rules []Rule
dns core.DNSClient
} }
func NewRouter(ctx context.Context, config *Config) (*Router, error) { func NewRouter(ctx context.Context, config *Config) (*Router, error) {
space := app.SpaceFromContext(ctx) v := core.FromContext(ctx)
if space == nil { if v == nil {
return nil, newError("no space in context") return nil, newError("V is not in context")
} }
r := &Router{ r := &Router{
domainStrategy: config.DomainStrategy, domainStrategy: config.DomainStrategy,
rules: make([]Rule, len(config.Rule)), rules: make([]Rule, len(config.Rule)),
dns: v.DNSClient(),
} }
space.On(app.SpaceInitializing, func(interface{}) error { for idx, rule := range config.Rule {
for idx, rule := range config.Rule { r.rules[idx].Tag = rule.Tag
r.rules[idx].Tag = rule.Tag cond, err := rule.BuildCondition()
cond, err := rule.BuildCondition() if err != nil {
if err != nil { return nil, err
return err
}
r.rules[idx].Condition = cond
} }
return nil r.rules[idx].Condition = cond
}) }
if err := v.RegisterFeature((*core.Router)(nil), r); err != nil {
return nil, newError("unable to register Router").Base(err)
}
return r, nil return r, nil
} }
type ipResolver struct { type ipResolver struct {
dns core.DNSClient
ip []net.Address ip []net.Address
domain string domain string
resolved bool resolved bool
@ -57,7 +58,7 @@ func (r *ipResolver) Resolve() []net.Address {
newError("looking for IP for domain: ", r.domain).WriteToLog() newError("looking for IP for domain: ", r.domain).WriteToLog()
r.resolved = true r.resolved = true
ips, err := net.LookupIP(r.domain) ips, err := r.dns.LookupIP(r.domain)
if err != nil { if err != nil {
newError("failed to get IP address").Base(err).WriteToLog() newError("failed to get IP address").Base(err).WriteToLog()
} }
@ -71,8 +72,10 @@ func (r *ipResolver) Resolve() []net.Address {
return r.ip return r.ip
} }
func (r *Router) TakeDetour(ctx context.Context) (string, error) { func (r *Router) PickRoute(ctx context.Context) (string, error) {
resolver := &ipResolver{} resolver := &ipResolver{
dns: r.dns,
}
if r.domainStrategy == Config_IpOnDemand { if r.domainStrategy == Config_IpOnDemand {
if dest, ok := proxy.TargetFromContext(ctx); ok && dest.Address.Family().IsDomain() { if dest, ok := proxy.TargetFromContext(ctx); ok && dest.Address.Family().IsDomain() {
resolver.domain = dest.Address.Domain() resolver.domain = dest.Address.Domain()
@ -88,7 +91,7 @@ func (r *Router) TakeDetour(ctx context.Context) (string, error) {
dest, ok := proxy.TargetFromContext(ctx) dest, ok := proxy.TargetFromContext(ctx)
if !ok { if !ok {
return "", ErrNoRuleApplicable return "", core.ErrNoClue
} }
if r.domainStrategy == Config_IpIfNonMatch && dest.Address.Family().IsDomain() { if r.domainStrategy == Config_IpIfNonMatch && dest.Address.Family().IsDomain() {
@ -104,25 +107,15 @@ func (r *Router) TakeDetour(ctx context.Context) (string, error) {
} }
} }
return "", ErrNoRuleApplicable return "", core.ErrNoClue
}
func (*Router) Interface() interface{} {
return (*Router)(nil)
} }
func (*Router) Start() error { func (*Router) Start() error {
return nil return nil
} }
func (*Router) Close() {} func (*Router) Close() error {
return nil
func FromSpace(space app.Space) *Router {
app := space.GetApplication((*Router)(nil))
if app == nil {
return nil
}
return app.(*Router)
} }
func init() { func init() {

View File

@ -4,13 +4,14 @@ import (
"context" "context"
"testing" "testing"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher" "v2ray.com/core/app/dispatcher"
_ "v2ray.com/core/app/dispatcher/impl"
"v2ray.com/core/app/proxyman" "v2ray.com/core/app/proxyman"
_ "v2ray.com/core/app/proxyman/outbound" _ "v2ray.com/core/app/proxyman/outbound"
. "v2ray.com/core/app/router" . "v2ray.com/core/app/router"
"v2ray.com/core/common"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy" "v2ray.com/core/proxy"
. "v2ray.com/ext/assert" . "v2ray.com/ext/assert"
) )
@ -18,28 +19,30 @@ import (
func TestSimpleRouter(t *testing.T) { func TestSimpleRouter(t *testing.T) {
assert := With(t) assert := With(t)
config := &Config{ config := &core.Config{
Rule: []*RoutingRule{ App: []*serial.TypedMessage{
{ serial.ToTypedMessage(&Config{
Tag: "test", Rule: []*RoutingRule{
NetworkList: &net.NetworkList{ {
Network: []net.Network{net.Network_TCP}, Tag: "test",
NetworkList: &net.NetworkList{
Network: []net.Network{net.Network_TCP},
},
},
}, },
}, }),
serial.ToTypedMessage(&dispatcher.Config{}),
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
}, },
} }
space := app.NewSpace() v, err := core.New(config)
ctx := app.ContextWithSpace(context.Background(), space) common.Must(err)
assert(app.AddApplicationToSpace(ctx, new(dispatcher.Config)), IsNil)
assert(app.AddApplicationToSpace(ctx, new(proxyman.OutboundConfig)), IsNil)
assert(app.AddApplicationToSpace(ctx, config), IsNil)
assert(space.Initialize(), IsNil)
r := FromSpace(space) r := v.Router()
ctx = proxy.ContextWithTarget(ctx, net.TCPDestination(net.DomainAddress("v2ray.com"), 80)) ctx := proxy.ContextWithTarget(context.Background(), net.TCPDestination(net.DomainAddress("v2ray.com"), 80))
tag, err := r.TakeDetour(ctx) tag, err := r.PickRoute(ctx)
assert(err, IsNil) assert(err, IsNil)
assert(tag, Equals, "test") assert(tag, Equals, "test")
} }

View File

@ -1,132 +0,0 @@
package app
import (
"context"
"reflect"
"v2ray.com/core/common"
"v2ray.com/core/common/event"
)
// Application is a component that runs in Space.
type Application interface {
Interface() interface{}
Start() error
Close()
}
// CreateAppFromConfig creates an Application based on its config. Application must have been registered.
func CreateAppFromConfig(ctx context.Context, config interface{}) (Application, error) {
application, err := common.CreateObject(ctx, config)
if err != nil {
return nil, err
}
switch a := application.(type) {
case Application:
return a, nil
default:
return nil, newError("not an application")
}
}
// A Space contains all apps that may be available in a V2Ray runtime.
type Space interface {
event.Registry
GetApplication(appInterface interface{}) Application
AddApplication(application Application) error
Initialize() error
Start() error
Close()
}
const (
// SpaceInitializing is an event to be fired when Space is being initialized.
SpaceInitializing event.Event = iota
)
type spaceImpl struct {
event.Listener
cache map[reflect.Type]Application
initialized bool
}
// NewSpace creates a new Space.
func NewSpace() Space {
return &spaceImpl{
cache: make(map[reflect.Type]Application),
}
}
func (s *spaceImpl) On(e event.Event, h event.Handler) {
if e == SpaceInitializing && s.initialized {
_ = h(nil) // Ignore error
return
}
s.Listener.On(e, h)
}
func (s *spaceImpl) Initialize() error {
if s.initialized {
return nil
}
s.initialized = true
return s.Fire(SpaceInitializing, nil)
}
func (s *spaceImpl) GetApplication(appInterface interface{}) Application {
if s == nil {
return nil
}
appType := reflect.TypeOf(appInterface)
return s.cache[appType]
}
func (s *spaceImpl) AddApplication(app Application) error {
if s == nil {
return newError("nil space").AtError()
}
appType := reflect.TypeOf(app.Interface())
s.cache[appType] = app
return nil
}
func (s *spaceImpl) Start() error {
for _, app := range s.cache {
if err := app.Start(); err != nil {
return err
}
}
return nil
}
func (s *spaceImpl) Close() {
for _, app := range s.cache {
app.Close()
}
}
type contextKey int
const (
spaceKey = contextKey(0)
)
func AddApplicationToSpace(ctx context.Context, appConfig interface{}) error {
space := SpaceFromContext(ctx)
if space == nil {
return newError("no space in context").AtError()
}
application, err := CreateAppFromConfig(ctx, appConfig)
if err != nil {
return err
}
return space.AddApplication(application)
}
func SpaceFromContext(ctx context.Context) Space {
return ctx.Value(spaceKey).(Space)
}
func ContextWithSpace(ctx context.Context, space Space) context.Context {
return context.WithValue(ctx, spaceKey, space)
}

59
clock.go Normal file
View File

@ -0,0 +1,59 @@
package core
import (
"sync"
"time"
)
// Clock is a V2Ray feature that returns current time.
type Clock interface {
Feature
// Now returns current time.
Now() time.Time
}
type syncClock struct {
sync.RWMutex
Clock
}
func (c *syncClock) Now() time.Time {
c.RLock()
defer c.RUnlock()
if c.Clock == nil {
return time.Now()
}
return c.Clock.Now()
}
func (c *syncClock) Start() error {
c.RLock()
defer c.RUnlock()
if c.Clock == nil {
return nil
}
return c.Clock.Start()
}
func (c *syncClock) Close() error {
c.RLock()
defer c.RUnlock()
if c.Clock == nil {
return nil
}
return c.Clock.Close()
}
func (c *syncClock) Set(clock Clock) {
c.Lock()
defer c.Unlock()
c.Clock = clock
}

44
commander.go Normal file
View File

@ -0,0 +1,44 @@
package core
import (
"sync"
)
// Commander is a feature that accepts commands from external source.
type Commander interface {
Feature
}
type syncCommander struct {
sync.RWMutex
Commander
}
func (c *syncCommander) Start() error {
c.RLock()
defer c.RUnlock()
if c.Commander == nil {
return nil
}
return c.Commander.Start()
}
func (c *syncCommander) Close() error {
c.RLock()
defer c.RUnlock()
if c.Commander == nil {
return nil
}
return c.Commander.Close()
}
func (c *syncCommander) Set(commander Commander) {
c.Lock()
defer c.Unlock()
c.Commander = commander
}

View File

@ -1,46 +0,0 @@
package event
import "sync"
type Event uint16
type Handler func(data interface{}) error
type Registry interface {
On(Event, Handler)
}
type Listener struct {
sync.RWMutex
events map[Event][]Handler
}
func (l *Listener) On(e Event, h Handler) {
l.Lock()
defer l.Unlock()
if l.events == nil {
l.events = make(map[Event][]Handler)
}
handlers := l.events[e]
handlers = append(handlers, h)
l.events[e] = handlers
}
func (l *Listener) Fire(e Event, data interface{}) error {
l.RLock()
defer l.RUnlock()
if l.events == nil {
return nil
}
for _, h := range l.events[e] {
if err := h(data); err != nil {
return err
}
}
return nil
}

23
common/interfaces.go Normal file
View File

@ -0,0 +1,23 @@
package common
// Closable is the interface for objects that can release its resources.
type Closable interface {
// Close release all resources used by this object, including goroutines.
Close() error
}
// Close closes the obj if it is a Closable.
func Close(obj interface{}) error {
if c, ok := obj.(Closable); ok {
return c.Close()
}
return nil
}
// Runnable is the interface for objects that can start to work and stop on demand.
type Runnable interface {
// Start starts the runnable object. Upon the method returning nil, the object begins to function properly.
Start() error
Closable
}

View File

@ -1,8 +1,7 @@
package log package log
import ( import (
"sync/atomic" "sync"
"unsafe"
"v2ray.com/core/common/serial" "v2ray.com/core/common/serial"
) )
@ -30,12 +29,11 @@ func (m *GeneralMessage) String() string {
// Record writes a message into log stream. // Record writes a message into log stream.
func Record(msg Message) { func Record(msg Message) {
h := (*Handler)(atomic.LoadPointer(&logHandler)) logHandler.Handle(msg)
(*h).Handle(msg)
} }
var ( var (
logHandler unsafe.Pointer logHandler syncHandler
) )
// RegisterHandler register a new handler as current log handler. Previous registered handler will be discarded. // RegisterHandler register a new handler as current log handler. Previous registered handler will be discarded.
@ -43,5 +41,26 @@ func RegisterHandler(handler Handler) {
if handler == nil { if handler == nil {
panic("Log handler is nil") panic("Log handler is nil")
} }
atomic.StorePointer(&logHandler, unsafe.Pointer(&handler)) logHandler.Set(handler)
}
type syncHandler struct {
sync.RWMutex
Handler
}
func (h *syncHandler) Handle(msg Message) {
h.RLock()
defer h.RUnlock()
if h.Handler != nil {
h.Handler.Handle(msg)
}
}
func (h *syncHandler) Set(handler Handler) {
h.Lock()
defer h.Unlock()
h.Handler = handler
} }

View File

@ -1,44 +0,0 @@
package net
import (
"net"
"sync/atomic"
"unsafe"
)
// IPResolver is the interface to resolve host name to IPs.
type IPResolver interface {
LookupIP(host string) ([]net.IP, error)
}
type systemIPResolver int
func (s systemIPResolver) LookupIP(host string) ([]net.IP, error) {
return net.LookupIP(host)
}
const (
systemIPResolverInstance = systemIPResolver(0)
)
// SystemIPResolver returns an IPResolver that resolves IP through underlying system.
func SystemIPResolver() IPResolver {
return systemIPResolverInstance
}
var (
ipResolver unsafe.Pointer
)
func LookupIP(host string) ([]net.IP, error) {
r := (*IPResolver)(atomic.LoadPointer(&ipResolver))
return (*r).LookupIP(host)
}
func RegisterIPResolver(resolver IPResolver) {
atomic.StorePointer(&ipResolver, unsafe.Pointer(&resolver))
}
func init() {
RegisterIPResolver(systemIPResolverInstance)
}

View File

@ -11,6 +11,8 @@ var Listen = net.Listen
var ListenTCP = net.ListenTCP var ListenTCP = net.ListenTCP
var ListenUDP = net.ListenUDP var ListenUDP = net.ListenUDP
var LookupIP = net.LookupIP
var FileConn = net.FileConn var FileConn = net.FileConn
var ParseIP = net.ParseIP var ParseIP = net.ParseIP

View File

@ -18,11 +18,14 @@ const (
) )
func (c RequestCommand) TransferType() TransferType { func (c RequestCommand) TransferType() TransferType {
if c == RequestCommandTCP { switch c {
case RequestCommandTCP, RequestCommandMux:
return TransferTypeStream
case RequestCommandUDP:
return TransferTypePacket
default:
return TransferTypeStream return TransferTypeStream
} }
return TransferTypePacket
} }
const ( const (
@ -79,7 +82,7 @@ type ResponseHeader struct {
type CommandSwitchAccount struct { type CommandSwitchAccount struct {
Host net.Address Host net.Address
Port net.Port Port net.Port
ID *uuid.UUID ID uuid.UUID
Level uint32 Level uint32
AlterIds uint16 AlterIds uint16
ValidMin byte ValidMin byte

View File

@ -21,13 +21,13 @@ func DefaultIDHash(key []byte) hash.Hash {
// The ID of en entity, in the form of an UUID. // The ID of en entity, in the form of an UUID.
type ID struct { type ID struct {
uuid *uuid.UUID uuid uuid.UUID
cmdKey [IDBytesLen]byte cmdKey [IDBytesLen]byte
} }
// Equals returns true if this ID equals to the other one. // Equals returns true if this ID equals to the other one.
func (id *ID) Equals(another *ID) bool { func (id *ID) Equals(another *ID) bool {
return id.uuid.Equals(another.uuid) return id.uuid.Equals(&(another.uuid))
} }
func (id *ID) Bytes() []byte { func (id *ID) Bytes() []byte {
@ -38,7 +38,7 @@ func (id *ID) String() string {
return id.uuid.String() return id.uuid.String()
} }
func (id *ID) UUID() *uuid.UUID { func (id *ID) UUID() uuid.UUID {
return id.uuid return id.uuid
} }
@ -47,7 +47,7 @@ func (id ID) CmdKey() []byte {
} }
// NewID returns an ID with given UUID. // NewID returns an ID with given UUID.
func NewID(uuid *uuid.UUID) *ID { func NewID(uuid uuid.UUID) *ID {
id := &ID{uuid: uuid} id := &ID{uuid: uuid}
md5hash := md5.New() md5hash := md5.New()
common.Must2(md5hash.Write(uuid.Bytes())) common.Must2(md5hash.Write(uuid.Bytes()))

View File

@ -14,7 +14,7 @@ var _ = math.Inf
type User struct { type User struct {
Level uint32 `protobuf:"varint,1,opt,name=level" json:"level,omitempty"` Level uint32 `protobuf:"varint,1,opt,name=level" json:"level,omitempty"`
Email string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"` Email string `protobuf:"bytes,2,opt,name=email" json:"email,omitempty"`
// Protocol specific account information. // Protocol specific account information. Must be the account proto in one of the proxies.
Account *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,3,opt,name=account" json:"account,omitempty"` Account *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,3,opt,name=account" json:"account,omitempty"`
} }

View File

@ -3,4 +3,5 @@ package protocol
type UserValidator interface { type UserValidator interface {
Add(user *User) error Add(user *User) error
Get(timeHash []byte) (*User, Timestamp, bool) Get(timeHash []byte) (*User, Timestamp, bool)
Remove(email string) bool
} }

View File

@ -0,0 +1,12 @@
package router
import (
"context"
"v2ray.com/core/common/net"
"v2ray.com/core/transport/ray"
)
type Dispatcher interface {
Dispatch(ctx context.Context, dest net.Destination) (ray.InboundRay, error)
}

53
common/router/router.go Normal file
View File

@ -0,0 +1,53 @@
package router
import (
"context"
"sync"
)
type Router interface {
Pick(ctx context.Context) (string, bool)
}
type defaultRouter byte
func (defaultRouter) Pick(ctx context.Context) (string, bool) {
return "", false
}
type syncRouter struct {
sync.RWMutex
Router
}
func (r *syncRouter) Pick(ctx context.Context) (string, bool) {
r.RLock()
defer r.RUnlock()
return r.Router.Pick(ctx)
}
func (r *syncRouter) Set(router Router) {
r.Lock()
defer r.Unlock()
r.Router = router
}
var (
routerInstance = &syncRouter{
Router: defaultRouter(0),
}
)
func RegisterRouter(router Router) {
if router == nil {
panic("Router is nil.")
}
routerInstance.Set(router)
}
func Pick(ctx context.Context) (string, bool) {
return routerInstance.Router.Pick(ctx)
}

48
common/signal/done.go Normal file
View File

@ -0,0 +1,48 @@
package signal
import (
"sync"
)
type Done struct {
access sync.Mutex
c chan struct{}
closed bool
}
func NewDone() *Done {
return &Done{
c: make(chan struct{}),
}
}
func (d *Done) Done() bool {
select {
case <-d.c:
return true
default:
return false
}
}
func (d *Done) C() chan struct{} {
return d.c
}
func (d *Done) Wait() {
<-d.c
}
func (d *Done) Close() error {
d.access.Lock()
defer d.access.Unlock()
if d.closed {
return nil
}
d.closed = true
close(d.c)
return nil
}

View File

@ -1,22 +1,22 @@
package signal package signal
type Notifier struct { type Notifier struct {
c chan bool c chan struct{}
} }
func NewNotifier() *Notifier { func NewNotifier() *Notifier {
return &Notifier{ return &Notifier{
c: make(chan bool, 1), c: make(chan struct{}, 1),
} }
} }
func (n *Notifier) Signal() { func (n *Notifier) Signal() {
select { select {
case n.c <- true: case n.c <- struct{}{}:
default: default:
} }
} }
func (n *Notifier) Wait() <-chan bool { func (n *Notifier) Wait() <-chan struct{} {
return n.c return n.c
} }

View File

@ -1,23 +1,23 @@
package signal package signal
type Semaphore struct { type Semaphore struct {
token chan bool token chan struct{}
} }
func NewSemaphore(n int) *Semaphore { func NewSemaphore(n int) *Semaphore {
s := &Semaphore{ s := &Semaphore{
token: make(chan bool, n), token: make(chan struct{}, n),
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
s.token <- true s.token <- struct{}{}
} }
return s return s
} }
func (s *Semaphore) Wait() <-chan bool { func (s *Semaphore) Wait() <-chan struct{} {
return s.token return s.token
} }
func (s *Semaphore) Signal() { func (s *Semaphore) Signal() {
s.token <- true s.token <- struct{}{}
} }

60
common/signal/task.go Normal file
View File

@ -0,0 +1,60 @@
package signal
import (
"sync"
"time"
)
type PeriodicTask struct {
Interval time.Duration
Execute func() error
access sync.Mutex
timer *time.Timer
closed bool
}
func (t *PeriodicTask) checkedExecute() error {
t.access.Lock()
defer t.access.Unlock()
if t.closed {
return nil
}
if err := t.Execute(); err != nil {
return err
}
t.timer = time.AfterFunc(t.Interval, func() {
t.checkedExecute()
})
return nil
}
func (t *PeriodicTask) Start() error {
t.access.Lock()
t.closed = false
t.access.Unlock()
if err := t.checkedExecute(); err != nil {
t.closed = true
return err
}
return nil
}
func (t *PeriodicTask) Close() error {
t.access.Lock()
defer t.access.Unlock()
t.closed = true
if t.timer != nil {
t.timer.Stop()
t.timer = nil
}
return nil
}

View File

@ -0,0 +1,29 @@
package signal_test
import (
"testing"
"time"
"v2ray.com/core/common"
. "v2ray.com/core/common/signal"
. "v2ray.com/ext/assert"
)
func TestPeriodicTaskStop(t *testing.T) {
assert := With(t)
value := 0
task := &PeriodicTask{
Interval: time.Second * 2,
Execute: func() error {
value++
return nil
},
}
common.Must(task.Start())
time.Sleep(time.Second * 5)
common.Must(task.Close())
assert(value, Equals, 3)
time.Sleep(time.Second * 4)
assert(value, Equals, 3)
}

View File

@ -10,23 +10,30 @@ type ActivityUpdater interface {
} }
type ActivityTimer struct { type ActivityTimer struct {
updated chan bool updated chan struct{}
timeout chan time.Duration timeout chan time.Duration
closing chan struct{}
} }
func (t *ActivityTimer) Update() { func (t *ActivityTimer) Update() {
select { select {
case t.updated <- true: case t.updated <- struct{}{}:
default: default:
} }
} }
func (t *ActivityTimer) SetTimeout(timeout time.Duration) { func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
t.timeout <- timeout select {
case <-t.closing:
case t.timeout <- timeout:
}
} }
func (t *ActivityTimer) run(ctx context.Context, cancel context.CancelFunc) { func (t *ActivityTimer) run(ctx context.Context, cancel context.CancelFunc) {
defer cancel() defer func() {
cancel()
close(t.closing)
}()
timeout := <-t.timeout timeout := <-t.timeout
if timeout == 0 { if timeout == 0 {
@ -65,7 +72,8 @@ func (t *ActivityTimer) run(ctx context.Context, cancel context.CancelFunc) {
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer { func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {
timer := &ActivityTimer{ timer := &ActivityTimer{
timeout: make(chan time.Duration, 1), timeout: make(chan time.Duration, 1),
updated: make(chan bool, 1), updated: make(chan struct{}, 1),
closing: make(chan struct{}),
} }
timer.timeout <- timeout timer.timeout <- timeout
go timer.run(ctx, cancel) go timer.run(ctx, cancel)

View File

@ -32,3 +32,15 @@ func TestActivityTimerUpdate(t *testing.T) {
assert(ctx.Err(), IsNotNil) assert(ctx.Err(), IsNotNil)
runtime.KeepAlive(timer) runtime.KeepAlive(timer)
} }
func TestActivityTimerNonBlocking(t *testing.T) {
assert := With(t)
ctx, cancel := context.WithCancel(context.Background())
timer := CancelAfterInactivity(ctx, cancel, 0)
time.Sleep(time.Second * 1)
assert(ctx, HasDone)
timer.SetTimeout(0)
timer.SetTimeout(1)
timer.SetTimeout(2)
}

View File

@ -6,6 +6,7 @@ import (
"crypto/rand" "crypto/rand"
"encoding/hex" "encoding/hex"
"v2ray.com/core/common"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
) )
@ -46,11 +47,11 @@ func (u *UUID) Equals(another *UUID) bool {
} }
// Next generates a deterministic random UUID based on this UUID. // Next generates a deterministic random UUID based on this UUID.
func (u *UUID) Next() *UUID { func (u *UUID) Next() UUID {
md5hash := md5.New() md5hash := md5.New()
md5hash.Write(u.Bytes()) md5hash.Write(u.Bytes())
md5hash.Write([]byte("16167dc8-16b6-4e6d-b8bb-65dd68113a81")) md5hash.Write([]byte("16167dc8-16b6-4e6d-b8bb-65dd68113a81"))
newid := new(UUID) var newid UUID
for { for {
md5hash.Sum(newid[:0]) md5hash.Sum(newid[:0])
if !newid.Equals(u) { if !newid.Equals(u) {
@ -61,30 +62,31 @@ func (u *UUID) Next() *UUID {
} }
// New creates an UUID with random value. // New creates an UUID with random value.
func New() *UUID { func New() UUID {
uuid := new(UUID) var uuid UUID
rand.Read(uuid.Bytes()) common.Must2(rand.Read(uuid.Bytes()))
return uuid return uuid
} }
// ParseBytes converts an UUID in byte form to object. // ParseBytes converts an UUID in byte form to object.
func ParseBytes(b []byte) (*UUID, error) { func ParseBytes(b []byte) (UUID, error) {
var uuid UUID
if len(b) != 16 { if len(b) != 16 {
return nil, errors.New("invalid UUID: ", b) return uuid, errors.New("invalid UUID: ", b)
} }
uuid := new(UUID)
copy(uuid[:], b) copy(uuid[:], b)
return uuid, nil return uuid, nil
} }
// ParseString converts an UUID in string form to object. // ParseString converts an UUID in string form to object.
func ParseString(str string) (*UUID, error) { func ParseString(str string) (UUID, error) {
var uuid UUID
text := []byte(str) text := []byte(str)
if len(text) < 32 { if len(text) < 32 {
return nil, errors.New("invalid UUID: ", str) return uuid, errors.New("invalid UUID: ", str)
} }
uuid := new(UUID)
b := uuid.Bytes() b := uuid.Bytes()
for _, byteGroup := range byteGroups { for _, byteGroup := range byteGroups {
@ -95,7 +97,7 @@ func ParseString(str string) (*UUID, error) {
_, err := hex.Decode(b[:byteGroup/2], text[:byteGroup]) _, err := hex.Decode(b[:byteGroup/2], text[:byteGroup])
if err != nil { if err != nil {
return nil, err return uuid, err
} }
text = text[byteGroup:] text = text[byteGroup:]

View File

@ -65,7 +65,9 @@ func TestEquals(t *testing.T) {
var uuid *UUID = nil var uuid *UUID = nil
var uuid2 *UUID = nil var uuid2 *UUID = nil
assert(uuid.Equals(uuid2), IsTrue) assert(uuid.Equals(uuid2), IsTrue)
assert(uuid.Equals(New()), IsFalse)
uuid3 := New()
assert(uuid.Equals(&uuid3), IsFalse)
} }
func TestNext(t *testing.T) { func TestNext(t *testing.T) {
@ -73,5 +75,5 @@ func TestNext(t *testing.T) {
uuid := New() uuid := New()
uuid2 := uuid.Next() uuid2 := uuid.Next()
assert(uuid.Equals(uuid2), IsFalse) assert(uuid.Equals(&uuid2), IsFalse)
} }

View File

@ -3,7 +3,6 @@ package core
import proto "github.com/golang/protobuf/proto" import proto "github.com/golang/protobuf/proto"
import fmt "fmt" import fmt "fmt"
import math "math" import math "math"
import v2ray_core_app_proxyman "v2ray.com/core/app/proxyman"
import v2ray_core_common_serial "v2ray.com/core/common/serial" import v2ray_core_common_serial "v2ray.com/core/common/serial"
import v2ray_core_transport "v2ray.com/core/transport" import v2ray_core_transport "v2ray.com/core/transport"
@ -40,12 +39,12 @@ func (x ConfigFormat) String() string {
} }
func (ConfigFormat) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (ConfigFormat) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
// Master config of V2Ray. V2Ray Core takes this config as input and functions accordingly. // Master config of V2Ray. V2Ray takes this config as input and functions accordingly.
type Config struct { type Config struct {
// Inbound handler configurations. Must have at least one item. // Inbound handler configurations. Must have at least one item.
Inbound []*v2ray_core_app_proxyman.InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbound" json:"inbound,omitempty"` Inbound []*InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbound" json:"inbound,omitempty"`
// Outbound handler configurations. Must have at least one item. The first item is used as default for routing. // Outbound handler configurations. Must have at least one item. The first item is used as default for routing.
Outbound []*v2ray_core_app_proxyman.OutboundHandlerConfig `protobuf:"bytes,2,rep,name=outbound" json:"outbound,omitempty"` Outbound []*OutboundHandlerConfig `protobuf:"bytes,2,rep,name=outbound" json:"outbound,omitempty"`
// App configuration. Must be one in the app directory. // App configuration. Must be one in the app directory.
App []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,4,rep,name=app" json:"app,omitempty"` App []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,4,rep,name=app" json:"app,omitempty"`
// Transport settings. // Transport settings.
@ -60,14 +59,14 @@ func (m *Config) String() string { return proto.CompactTextString(m)
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *Config) GetInbound() []*v2ray_core_app_proxyman.InboundHandlerConfig { func (m *Config) GetInbound() []*InboundHandlerConfig {
if m != nil { if m != nil {
return m.Inbound return m.Inbound
} }
return nil return nil
} }
func (m *Config) GetOutbound() []*v2ray_core_app_proxyman.OutboundHandlerConfig { func (m *Config) GetOutbound() []*OutboundHandlerConfig {
if m != nil { if m != nil {
return m.Outbound return m.Outbound
} }
@ -95,34 +94,131 @@ func (m *Config) GetExtension() []*v2ray_core_common_serial.TypedMessage {
return nil return nil
} }
type InboundHandlerConfig struct {
// Tag of the inbound handler.
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
// Settings for how this inbound proxy is handled. Must be ReceiverConfig above.
ReceiverSettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,opt,name=receiver_settings,json=receiverSettings" json:"receiver_settings,omitempty"`
// Settings for inbound proxy. Must be one of the inbound proxies.
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{1} }
func (m *InboundHandlerConfig) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *InboundHandlerConfig) GetReceiverSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.ReceiverSettings
}
return nil
}
func (m *InboundHandlerConfig) GetProxySettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.ProxySettings
}
return nil
}
type OutboundHandlerConfig struct {
// Tag of this outbound handler.
Tag string `protobuf:"bytes,1,opt,name=tag" json:"tag,omitempty"`
// Settings for how to dial connection for this outbound handler. Must be SenderConfig above.
SenderSettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,2,opt,name=sender_settings,json=senderSettings" json:"sender_settings,omitempty"`
// Settings for this outbound proxy. Must be one of the outbound proxies.
ProxySettings *v2ray_core_common_serial.TypedMessage `protobuf:"bytes,3,opt,name=proxy_settings,json=proxySettings" json:"proxy_settings,omitempty"`
// If not zero, this outbound will be expired in seconds. Not used for now.
Expire int64 `protobuf:"varint,4,opt,name=expire" json:"expire,omitempty"`
// Comment of this outbound handler. Not used for now.
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{2} }
func (m *OutboundHandlerConfig) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *OutboundHandlerConfig) GetSenderSettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.SenderSettings
}
return nil
}
func (m *OutboundHandlerConfig) GetProxySettings() *v2ray_core_common_serial.TypedMessage {
if m != nil {
return m.ProxySettings
}
return nil
}
func (m *OutboundHandlerConfig) GetExpire() int64 {
if m != nil {
return m.Expire
}
return 0
}
func (m *OutboundHandlerConfig) GetComment() string {
if m != nil {
return m.Comment
}
return ""
}
func init() { func init() {
proto.RegisterType((*Config)(nil), "v2ray.core.Config") proto.RegisterType((*Config)(nil), "v2ray.core.Config")
proto.RegisterType((*InboundHandlerConfig)(nil), "v2ray.core.InboundHandlerConfig")
proto.RegisterType((*OutboundHandlerConfig)(nil), "v2ray.core.OutboundHandlerConfig")
proto.RegisterEnum("v2ray.core.ConfigFormat", ConfigFormat_name, ConfigFormat_value) proto.RegisterEnum("v2ray.core.ConfigFormat", ConfigFormat_name, ConfigFormat_value)
} }
func init() { proto.RegisterFile("v2ray.com/core/config.proto", fileDescriptor0) } func init() { proto.RegisterFile("v2ray.com/core/config.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 336 bytes of a gzipped FileDescriptorProto // 436 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x91, 0xcd, 0x4a, 0xf3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0x41, 0x6f, 0xd3, 0x30,
0x18, 0x85, 0xbf, 0xb4, 0xf9, 0x6a, 0xfa, 0xb6, 0x48, 0x99, 0x55, 0xa8, 0x2e, 0x8a, 0xd0, 0x52, 0x14, 0xc7, 0x71, 0x13, 0xba, 0xf6, 0x6d, 0x94, 0x60, 0x01, 0xb2, 0x06, 0x87, 0x50, 0x69, 0x53,
0x04, 0x27, 0x12, 0x37, 0xe2, 0xd2, 0x8a, 0x3f, 0x05, 0x6d, 0xa9, 0xe2, 0xc2, 0x8d, 0x4c, 0xd3, 0xc5, 0xc1, 0x45, 0xe5, 0x82, 0x26, 0x71, 0x61, 0x08, 0xc1, 0xa4, 0xd1, 0x29, 0x45, 0x1c, 0xb8,
0x69, 0x09, 0x74, 0xe6, 0x1d, 0x26, 0x53, 0x69, 0x6e, 0xc9, 0x9b, 0xf2, 0x56, 0x24, 0x99, 0xfe, 0x4c, 0x6e, 0xfa, 0x56, 0x45, 0x5a, 0xec, 0xc8, 0x76, 0xa7, 0xe6, 0x2b, 0xf1, 0x3d, 0xb8, 0xf1,
0xa5, 0xe2, 0xc2, 0x55, 0x20, 0x73, 0x9e, 0xe7, 0x4c, 0x4e, 0xe0, 0xe8, 0x23, 0xd4, 0x2c, 0xa5, 0x8d, 0xb8, 0xa0, 0xc4, 0x49, 0x93, 0x41, 0x0f, 0x14, 0x69, 0xa7, 0xc4, 0x79, 0xfe, 0xfd, 0xdf,
0x11, 0x8a, 0x20, 0x42, 0xcd, 0x83, 0x08, 0xe5, 0x34, 0x9e, 0x51, 0xa5, 0xd1, 0x20, 0x81, 0xf5, 0xfb, 0x25, 0x31, 0x3c, 0xbb, 0x99, 0x68, 0x91, 0xf3, 0x58, 0xa5, 0xe3, 0x58, 0x69, 0x1c, 0xc7,
0xa1, 0xe6, 0xcd, 0xee, 0x5e, 0x90, 0x29, 0x15, 0x28, 0x8d, 0xcb, 0x54, 0x30, 0x59, 0xa0, 0x9a, 0x4a, 0x5e, 0x25, 0x4b, 0x9e, 0x69, 0x65, 0x15, 0x85, 0xba, 0xa8, 0xf1, 0xf0, 0xd5, 0x5f, 0x1b,
0xe7, 0x3f, 0x94, 0x42, 0xa0, 0x0c, 0x12, 0xae, 0x63, 0x36, 0x0f, 0x4c, 0xaa, 0xf8, 0xe4, 0x5d, 0xd3, 0x54, 0xc9, 0xb1, 0x41, 0x9d, 0x88, 0xeb, 0xb1, 0xcd, 0x33, 0x5c, 0x5c, 0xa6, 0x68, 0x8c,
0xf0, 0x24, 0x61, 0x33, 0xbe, 0x22, 0xda, 0x7b, 0x84, 0xd1, 0x4c, 0x26, 0x0a, 0xb5, 0x29, 0x88, 0x58, 0xa2, 0xa3, 0x0f, 0x8f, 0xfe, 0x20, 0xac, 0x16, 0xd2, 0x64, 0x4a, 0xdb, 0x5b, 0x4d, 0x86,
0x4f, 0xbe, 0x4a, 0x50, 0xe9, 0xe5, 0x2f, 0xc8, 0x1d, 0x1c, 0xc4, 0x72, 0x8c, 0x0b, 0x39, 0xf1, 0x3f, 0x3a, 0xd0, 0x3d, 0x2d, 0x1f, 0xd0, 0x13, 0xd8, 0x4b, 0xe4, 0x5c, 0xad, 0xe4, 0x82, 0x91,
0x9d, 0x56, 0xb9, 0x5b, 0x0b, 0xcf, 0xe8, 0xf6, 0xae, 0x94, 0x29, 0x45, 0xd7, 0x77, 0xa3, 0x0f, 0xd0, 0x1b, 0xed, 0x4f, 0x42, 0xde, 0x4c, 0xc0, 0x3f, 0xb9, 0xd2, 0x47, 0x21, 0x17, 0xd7, 0xa8,
0x36, 0x77, 0xcf, 0xe4, 0x64, 0xce, 0xb5, 0xe5, 0x47, 0x6b, 0x9a, 0xf4, 0xc1, 0xc3, 0x85, 0xb1, 0x1d, 0x12, 0xd5, 0x00, 0x7d, 0x0b, 0x3d, 0xb5, 0xb2, 0x0e, 0xee, 0x94, 0xf0, 0x8b, 0x36, 0x3c,
0xa6, 0x52, 0x6e, 0xa2, 0xbf, 0x9a, 0x06, 0xab, 0x60, 0x51, 0xb5, 0xe1, 0xc9, 0x25, 0x94, 0x99, 0xad, 0x6a, 0xb7, 0xe9, 0x0d, 0x42, 0xdf, 0x80, 0x27, 0xb2, 0x8c, 0xf9, 0x25, 0x79, 0xdc, 0x26,
0x52, 0xbe, 0x9b, 0x6b, 0x3a, 0xbb, 0x1a, 0x3b, 0x01, 0xb5, 0x13, 0xd0, 0x97, 0x6c, 0x82, 0x47, 0x9d, 0x28, 0x77, 0xa2, 0xfc, 0x4b, 0x21, 0x7a, 0xee, 0x3c, 0xa3, 0x02, 0xa1, 0x27, 0xd0, 0xdf,
0xbb, 0xc0, 0x28, 0x43, 0xc8, 0x15, 0x54, 0x37, 0xdf, 0xec, 0xff, 0x6f, 0x39, 0xdd, 0x5a, 0x78, 0x98, 0xb1, 0xfb, 0x21, 0x19, 0xed, 0x4f, 0x9e, 0xb7, 0xf9, 0x4d, 0x91, 0x57, 0x4d, 0x9b, 0xed,
0xbc, 0xcb, 0x6f, 0x0e, 0xe9, 0xaa, 0x74, 0x1b, 0x27, 0x37, 0x50, 0xe5, 0x4b, 0xc3, 0x65, 0x12, 0xf4, 0x3d, 0xf4, 0x71, 0x6d, 0x51, 0x9a, 0x44, 0x49, 0xd6, 0xdd, 0xa9, 0x77, 0x03, 0x9e, 0xf9,
0xa3, 0xf4, 0x2b, 0x7f, 0xea, 0xde, 0x82, 0x7d, 0xd7, 0x2b, 0x37, 0xdc, 0xd3, 0x0e, 0xd4, 0x6d, 0x3d, 0x2f, 0xf0, 0x87, 0x3f, 0x09, 0x3c, 0xde, 0xf6, 0x8a, 0x68, 0x00, 0x9e, 0x15, 0x4b, 0x46,
0xc1, 0x2d, 0x6a, 0xc1, 0x0c, 0xa9, 0x83, 0x37, 0xcc, 0xa6, 0x1f, 0x2f, 0xa6, 0x8d, 0x7f, 0xc4, 0x42, 0x32, 0xea, 0x47, 0xc5, 0x2d, 0x9d, 0xc1, 0x23, 0x8d, 0x31, 0x26, 0x37, 0xa8, 0x2f, 0x0d,
0x03, 0xb7, 0xff, 0x3c, 0x78, 0x6a, 0x38, 0xd7, 0x6d, 0x38, 0x8c, 0x50, 0xec, 0xb4, 0x0c, 0x9d, 0x5a, 0x9b, 0xc8, 0xa5, 0x61, 0x9d, 0x72, 0xf4, 0x7f, 0x6d, 0x1f, 0xd4, 0x01, 0xb3, 0x8a, 0xa7,
0x37, 0x37, 0x7b, 0x7e, 0x96, 0xe0, 0x35, 0x1c, 0xb1, 0x94, 0xf6, 0x50, 0xf3, 0x71, 0x25, 0xff, 0xe7, 0x30, 0xc8, 0xb4, 0x5a, 0xe7, 0x4d, 0xa2, 0xb7, 0x53, 0xe2, 0x83, 0x92, 0xae, 0xe3, 0x86,
0x6f, 0x17, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x62, 0x93, 0x6d, 0x78, 0x65, 0x02, 0x00, 0x00, 0xbf, 0x08, 0x3c, 0xd9, 0xfa, 0xd1, 0xb6, 0xf8, 0x4c, 0xe1, 0xa1, 0x41, 0xb9, 0xf8, 0x7f, 0x9b,
0x81, 0xc3, 0xef, 0xc8, 0x85, 0x3e, 0x85, 0x2e, 0xae, 0xb3, 0x44, 0x23, 0xf3, 0x43, 0x32, 0xf2,
0xa2, 0x6a, 0x45, 0x19, 0xec, 0x15, 0x21, 0x28, 0xdd, 0x8f, 0xd3, 0x8f, 0xea, 0xe5, 0xcb, 0x63,
0x38, 0x70, 0xb6, 0x1f, 0x94, 0x4e, 0x85, 0xa5, 0x07, 0xd0, 0xbb, 0x28, 0x4e, 0xcb, 0x7c, 0x75,
0x15, 0xdc, 0xa3, 0x3d, 0xf0, 0xcf, 0x66, 0xd3, 0xcf, 0x01, 0x79, 0x77, 0x04, 0x83, 0x58, 0xa5,
0xad, 0xa9, 0x2e, 0xc8, 0x37, 0xbf, 0xb8, 0x7e, 0xef, 0xc0, 0xd7, 0x49, 0x24, 0x72, 0x7e, 0xaa,
0x34, 0xce, 0xbb, 0xe5, 0x51, 0x7b, 0xfd, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 0x59, 0x1b,
0xee, 0x03, 0x00, 0x00,
} }

View File

@ -6,7 +6,6 @@ option go_package = "core";
option java_package = "com.v2ray.core"; option java_package = "com.v2ray.core";
option java_multiple_files = true; option java_multiple_files = true;
import "v2ray.com/core/app/proxyman/config.proto";
import "v2ray.com/core/common/serial/typed_message.proto"; import "v2ray.com/core/common/serial/typed_message.proto";
import "v2ray.com/core/transport/config.proto"; import "v2ray.com/core/transport/config.proto";
@ -19,10 +18,10 @@ enum ConfigFormat {
// Master config of V2Ray. V2Ray takes this config as input and functions accordingly. // Master config of V2Ray. V2Ray takes this config as input and functions accordingly.
message Config { message Config {
// Inbound handler configurations. Must have at least one item. // Inbound handler configurations. Must have at least one item.
repeated v2ray.core.app.proxyman.InboundHandlerConfig inbound = 1; repeated InboundHandlerConfig inbound = 1;
// Outbound handler configurations. Must have at least one item. The first item is used as default for routing. // Outbound handler configurations. Must have at least one item. The first item is used as default for routing.
repeated v2ray.core.app.proxyman.OutboundHandlerConfig outbound = 2; repeated OutboundHandlerConfig outbound = 2;
reserved 3; reserved 3;
@ -36,3 +35,25 @@ message Config {
// V2Ray will ignore such config during initialization. // V2Ray will ignore such config during initialization.
repeated v2ray.core.common.serial.TypedMessage extension = 6; repeated v2ray.core.common.serial.TypedMessage extension = 6;
} }
message InboundHandlerConfig {
// Tag of the inbound handler.
string tag = 1;
// Settings for how this inbound proxy is handled. Must be ReceiverConfig above.
v2ray.core.common.serial.TypedMessage receiver_settings = 2;
// Settings for inbound proxy. Must be one of the inbound proxies.
v2ray.core.common.serial.TypedMessage proxy_settings = 3;
}
message OutboundHandlerConfig {
// Tag of this outbound handler.
string tag = 1;
// Settings for how to dial connection for this outbound handler. Must be SenderConfig above.
v2ray.core.common.serial.TypedMessage sender_settings = 2;
// Settings for this outbound proxy. Must be one of the outbound proxies.
v2ray.core.common.serial.TypedMessage proxy_settings = 3;
// If not zero, this outbound will be expired in seconds. Not used for now.
int64 expire = 4;
// Comment of this outbound handler. Not used for now.
string comment = 5;
}

17
context.go Normal file
View File

@ -0,0 +1,17 @@
package core
import (
"context"
)
type key int
const v2rayKey key = 1
// FromContext returns a Instance from the given context, or nil if the context doesn't contain one.
func FromContext(ctx context.Context) *Instance {
if s, ok := ctx.Value(v2rayKey).(*Instance); ok {
return s
}
return nil
}

View File

@ -18,7 +18,7 @@ import (
) )
var ( var (
version = "3.6" version = "3.8"
build = "Custom" build = "Custom"
codename = "die Commanderin" codename = "die Commanderin"
intro = "An unified platform for anti-censorship." intro = "An unified platform for anti-censorship."

20
dial.go Normal file
View File

@ -0,0 +1,20 @@
package core
import (
"context"
"v2ray.com/core/common/net"
"v2ray.com/core/transport/ray"
)
// Dial provides an easy way for upstream caller to create net.Conn through V2Ray.
// It dispatches the request to the given destination by the given V2Ray instance.
// Since it is under a proxy context, the LocalAddr() and RemoteAddr() in returned net.Conn
// will not show real addresses being used for communication.
func Dial(ctx context.Context, v *Instance, dest net.Destination) (net.Conn, error) {
r, err := v.Dispatcher().Dispatch(ctx, dest)
if err != nil {
return nil, err
}
return ray.NewConnection(r.InboundOutput(), r.InboundInput()), nil
}

59
dns.go Normal file
View File

@ -0,0 +1,59 @@
package core
import (
"net"
"sync"
"v2ray.com/core/common"
)
// DNSClient is a V2Ray feature for querying DNS information.
type DNSClient interface {
Feature
LookupIP(host string) ([]net.IP, error)
}
type syncDNSClient struct {
sync.RWMutex
DNSClient
}
func (d *syncDNSClient) LookupIP(host string) ([]net.IP, error) {
d.RLock()
defer d.RUnlock()
if d.DNSClient == nil {
return net.LookupIP(host)
}
return d.DNSClient.LookupIP(host)
}
func (d *syncDNSClient) Start() error {
d.RLock()
defer d.RUnlock()
if d.DNSClient == nil {
return nil
}
return d.DNSClient.Start()
}
func (d *syncDNSClient) Close() error {
d.RLock()
defer d.RUnlock()
return common.Close(d.DNSClient)
}
func (d *syncDNSClient) Set(client DNSClient) {
if client == nil {
return
}
d.Lock()
defer d.Unlock()
d.DNSClient = client
}

View File

@ -2,10 +2,12 @@ package all
import ( import (
// The following are necessary as they register handlers in their init functions. // The following are necessary as they register handlers in their init functions.
_ "v2ray.com/core/app/dispatcher/impl" _ "v2ray.com/core/app/commander"
_ "v2ray.com/core/app/dispatcher"
_ "v2ray.com/core/app/dns" _ "v2ray.com/core/app/dns"
_ "v2ray.com/core/app/log" _ "v2ray.com/core/app/log"
_ "v2ray.com/core/app/policy/manager" _ "v2ray.com/core/app/policy"
_ "v2ray.com/core/app/proxyman/command"
_ "v2ray.com/core/app/proxyman/inbound" _ "v2ray.com/core/app/proxyman/inbound"
_ "v2ray.com/core/app/proxyman/outbound" _ "v2ray.com/core/app/proxyman/outbound"
_ "v2ray.com/core/app/router" _ "v2ray.com/core/app/router"

168
network.go Normal file
View File

@ -0,0 +1,168 @@
package core
import (
"context"
"sync"
"v2ray.com/core/common"
"v2ray.com/core/common/net"
"v2ray.com/core/transport/ray"
)
// InboundHandler is the interface for handlers that process inbound connections.
type InboundHandler interface {
common.Runnable
// The tag of this handler.
Tag() string
// Deprecated. Do not use in new code.
GetRandomInboundProxy() (interface{}, net.Port, int)
}
// OutboundHandler is the interface for handlers that process outbound connections.
type OutboundHandler interface {
common.Runnable
Tag() string
Dispatch(ctx context.Context, outboundRay ray.OutboundRay)
}
// InboundHandlerManager is a feature that managers InboundHandlers.
type InboundHandlerManager interface {
Feature
// GetHandlers returns an InboundHandler for the given tag.
GetHandler(ctx context.Context, tag string) (InboundHandler, error)
// AddHandler adds the given handler into this InboundHandlerManager.
AddHandler(ctx context.Context, handler InboundHandler) error
// RemoveHandler removes a handler from InboundHandlerManager.
RemoveHandler(ctx context.Context, tag string) error
}
type syncInboundHandlerManager struct {
sync.RWMutex
InboundHandlerManager
}
func (m *syncInboundHandlerManager) GetHandler(ctx context.Context, tag string) (InboundHandler, error) {
m.RLock()
defer m.RUnlock()
if m.InboundHandlerManager == nil {
return nil, newError("InboundHandlerManager not set.").AtError()
}
return m.InboundHandlerManager.GetHandler(ctx, tag)
}
func (m *syncInboundHandlerManager) AddHandler(ctx context.Context, handler InboundHandler) error {
m.RLock()
defer m.RUnlock()
if m.InboundHandlerManager == nil {
return newError("InboundHandlerManager not set.").AtError()
}
return m.InboundHandlerManager.AddHandler(ctx, handler)
}
func (m *syncInboundHandlerManager) Start() error {
m.RLock()
defer m.RUnlock()
if m.InboundHandlerManager == nil {
return newError("InboundHandlerManager not set.").AtError()
}
return m.InboundHandlerManager.Start()
}
func (m *syncInboundHandlerManager) Close() error {
m.RLock()
defer m.RUnlock()
return common.Close(m.InboundHandlerManager)
}
func (m *syncInboundHandlerManager) Set(manager InboundHandlerManager) {
m.Lock()
defer m.Unlock()
m.InboundHandlerManager = manager
}
// OutboundHandlerManager is a feature that manages OutboundHandlers.
type OutboundHandlerManager interface {
Feature
// GetHandler returns an OutboundHandler will given tag.
GetHandler(tag string) OutboundHandler
// GetDefaultHandler returns the default OutboundHandler. It is usually the first OutboundHandler specified in the configuration.
GetDefaultHandler() OutboundHandler
// AddHandler adds a handler into this OutboundHandlerManager.
AddHandler(ctx context.Context, handler OutboundHandler) error
// RemoveHandler removes a handler from OutboundHandlerManager.
RemoveHandler(ctx context.Context, tag string) error
}
type syncOutboundHandlerManager struct {
sync.RWMutex
OutboundHandlerManager
}
func (m *syncOutboundHandlerManager) GetHandler(tag string) OutboundHandler {
m.RLock()
defer m.RUnlock()
if m.OutboundHandlerManager == nil {
return nil
}
return m.OutboundHandlerManager.GetHandler(tag)
}
func (m *syncOutboundHandlerManager) GetDefaultHandler() OutboundHandler {
m.RLock()
defer m.RUnlock()
if m.OutboundHandlerManager == nil {
return nil
}
return m.OutboundHandlerManager.GetDefaultHandler()
}
func (m *syncOutboundHandlerManager) AddHandler(ctx context.Context, handler OutboundHandler) error {
m.RLock()
defer m.RUnlock()
if m.OutboundHandlerManager == nil {
return newError("OutboundHandlerManager not set.").AtError()
}
return m.OutboundHandlerManager.AddHandler(ctx, handler)
}
func (m *syncOutboundHandlerManager) Start() error {
m.RLock()
defer m.RUnlock()
if m.OutboundHandlerManager == nil {
return newError("OutboundHandlerManager not set.").AtError()
}
return m.OutboundHandlerManager.Start()
}
func (m *syncOutboundHandlerManager) Close() error {
m.RLock()
defer m.RUnlock()
return common.Close(m.OutboundHandlerManager)
}
func (m *syncOutboundHandlerManager) Set(manager OutboundHandlerManager) {
m.Lock()
defer m.Unlock()
m.OutboundHandlerManager = manager
}

117
policy.go Normal file
View File

@ -0,0 +1,117 @@
package core
import (
"sync"
"time"
"v2ray.com/core/common"
)
// TimeoutPolicy contains limits for connection timeout.
type TimeoutPolicy struct {
// Timeout for handshake phase in a connection.
Handshake time.Duration
// Timeout for connection being idle, i.e., there is no egress or ingress traffic in this connection.
ConnectionIdle time.Duration
// Timeout for an uplink only connection, i.e., the downlink of the connection has ben closed.
UplinkOnly time.Duration
// Timeout for an downlink only connection, i.e., the uplink of the connection has ben closed.
DownlinkOnly time.Duration
}
// OverrideWith overrides the current TimeoutPolicy with another one. All timeouts with zero value will be overridden with the new value.
func (p TimeoutPolicy) OverrideWith(another TimeoutPolicy) TimeoutPolicy {
if p.Handshake == 0 {
p.Handshake = another.Handshake
}
if p.ConnectionIdle == 0 {
p.ConnectionIdle = another.ConnectionIdle
}
if p.UplinkOnly == 0 {
p.UplinkOnly = another.UplinkOnly
}
if p.DownlinkOnly == 0 {
p.DownlinkOnly = another.DownlinkOnly
}
return p
}
// Policy is session based settings for controlling V2Ray requests. It contains various settings (or limits) that may differ for different users in the context.
type Policy struct {
Timeouts TimeoutPolicy // Timeout settings
}
// OverrideWith overrides the current Policy with another one. All values with default value will be overridden.
func (p Policy) OverrideWith(another Policy) Policy {
p.Timeouts.OverrideWith(another.Timeouts)
return p
}
// PolicyManager is a feature that provides Policy for the given user by its id or level.
type PolicyManager interface {
Feature
// ForLevel returns the Policy for the given user level.
ForLevel(level uint32) Policy
}
// DefaultPolicy returns the Policy when user is not specified.
func DefaultPolicy() Policy {
return Policy{
Timeouts: TimeoutPolicy{
Handshake: time.Second * 4,
ConnectionIdle: time.Second * 300,
UplinkOnly: time.Second * 5,
DownlinkOnly: time.Second * 30,
},
}
}
type syncPolicyManager struct {
sync.RWMutex
PolicyManager
}
func (m *syncPolicyManager) ForLevel(level uint32) Policy {
m.RLock()
defer m.RUnlock()
if m.PolicyManager == nil {
p := DefaultPolicy()
if level == 1 {
p.Timeouts.ConnectionIdle = time.Second * 600
}
return p
}
return m.PolicyManager.ForLevel(level)
}
func (m *syncPolicyManager) Start() error {
m.RLock()
defer m.RUnlock()
if m.PolicyManager == nil {
return nil
}
return m.PolicyManager.Start()
}
func (m *syncPolicyManager) Close() error {
m.RLock()
defer m.RUnlock()
return common.Close(m.PolicyManager)
}
func (m *syncPolicyManager) Set(manager PolicyManager) {
if manager == nil {
return
}
m.Lock()
defer m.Unlock()
m.PolicyManager = manager
}

View File

@ -4,10 +4,9 @@ package dokodemo
import ( import (
"context" "context"
"time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/policy"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
@ -18,36 +17,29 @@ import (
) )
type DokodemoDoor struct { type DokodemoDoor struct {
config *Config policyManager core.PolicyManager
address net.Address config *Config
port net.Port address net.Address
policy policy.Policy port net.Port
v *core.Instance
} }
func New(ctx context.Context, config *Config) (*DokodemoDoor, error) { func New(ctx context.Context, config *Config) (*DokodemoDoor, error) {
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, newError("no space in context")
}
if config.NetworkList == nil || config.NetworkList.Size() == 0 { if config.NetworkList == nil || config.NetworkList.Size() == 0 {
return nil, newError("no network specified") return nil, newError("no network specified")
} }
d := &DokodemoDoor{ v := core.FromContext(ctx)
config: config, if v == nil {
address: config.GetPredefinedAddress(), return nil, newError("V is not in context.")
port: net.Port(config.Port),
} }
space.On(app.SpaceInitializing, func(interface{}) error {
pm := policy.FromSpace(space) d := &DokodemoDoor{
if pm == nil { config: config,
return newError("Policy not found in space.") address: config.GetPredefinedAddress(),
} port: net.Port(config.Port),
d.policy = pm.GetPolicy(config.UserLevel) policyManager: v.PolicyManager(),
if config.Timeout > 0 && config.UserLevel == 0 { }
d.policy.Timeout.ConnectionIdle.Value = config.Timeout
}
return nil
})
return d, nil return d, nil
} }
@ -55,7 +47,16 @@ func (d *DokodemoDoor) Network() net.NetworkList {
return *(d.config.NetworkList) return *(d.config.NetworkList)
} }
func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error { func (d *DokodemoDoor) policy() core.Policy {
config := d.config
p := d.policyManager.ForLevel(config.UserLevel)
if config.Timeout > 0 && config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
}
return p
}
func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher core.Dispatcher) error {
newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog() newError("processing connection from: ", conn.RemoteAddr()).AtDebug().WriteToLog()
dest := net.Destination{ dest := net.Destination{
Network: network, Network: network,
@ -72,7 +73,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
} }
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, d.policy.Timeout.ConnectionIdle.Duration()) timer := signal.CancelAfterInactivity(ctx, cancel, d.policy().Timeouts.ConnectionIdle)
inboundRay, err := dispatcher.Dispatch(ctx, dest) inboundRay, err := dispatcher.Dispatch(ctx, dest)
if err != nil { if err != nil {
@ -88,7 +89,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
return newError("failed to transport request").Base(err) return newError("failed to transport request").Base(err)
} }
timer.SetTimeout(d.policy.Timeout.DownlinkOnly.Duration()) timer.SetTimeout(d.policy().Timeouts.DownlinkOnly)
return nil return nil
}) })
@ -115,7 +116,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
return newError("failed to transport response").Base(err) return newError("failed to transport response").Base(err)
} }
timer.SetTimeout(d.policy.Timeout.UplinkOnly.Duration()) timer.SetTimeout(d.policy().Timeouts.UplinkOnly)
return nil return nil
}) })

View File

@ -4,9 +4,9 @@ package freedom
import ( import (
"context" "context"
"time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/policy"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/dice" "v2ray.com/core/common/dice"
@ -20,37 +20,35 @@ import (
// Handler handles Freedom connections. // Handler handles Freedom connections.
type Handler struct { type Handler struct {
domainStrategy Config_DomainStrategy policyManager core.PolicyManager
timeout uint32 dns core.DNSClient
destOverride *DestinationOverride config Config
policy policy.Policy
} }
// New creates a new Freedom handler. // New creates a new Freedom handler.
func New(ctx context.Context, config *Config) (*Handler, error) { func New(ctx context.Context, config *Config) (*Handler, error) {
space := app.SpaceFromContext(ctx) v := core.FromContext(ctx)
if space == nil { if v == nil {
return nil, newError("no space in context") return nil, newError("V is not found in context.")
} }
f := &Handler{ f := &Handler{
domainStrategy: config.DomainStrategy, config: *config,
timeout: config.Timeout, policyManager: v.PolicyManager(),
destOverride: config.DestinationOverride, dns: v.DNSClient(),
} }
space.On(app.SpaceInitializing, func(interface{}) error {
pm := policy.FromSpace(space)
if pm == nil {
return newError("Policy not found in space.")
}
f.policy = pm.GetPolicy(config.UserLevel)
if config.Timeout > 0 && config.UserLevel == 0 {
f.policy.Timeout.ConnectionIdle.Value = config.Timeout
}
return nil
})
return f, nil return f, nil
} }
func (h *Handler) policy() core.Policy {
p := h.policyManager.ForLevel(h.config.UserLevel)
if h.config.Timeout > 0 && h.config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(h.config.Timeout) * time.Second
}
return p
}
func (h *Handler) resolveIP(ctx context.Context, domain string) net.Address { func (h *Handler) resolveIP(ctx context.Context, domain string) net.Address {
if resolver, ok := proxy.ResolvedIPsFromContext(ctx); ok { if resolver, ok := proxy.ResolvedIPsFromContext(ctx); ok {
ips := resolver.Resolve() ips := resolver.Resolve()
@ -60,7 +58,7 @@ func (h *Handler) resolveIP(ctx context.Context, domain string) net.Address {
return ips[dice.Roll(len(ips))] return ips[dice.Roll(len(ips))]
} }
ips, err := net.LookupIP(domain) ips, err := h.dns.LookupIP(domain)
if err != nil { if err != nil {
newError("failed to get IP address for domain ", domain).Base(err).WriteToLog() newError("failed to get IP address for domain ", domain).Base(err).WriteToLog()
} }
@ -73,8 +71,8 @@ func (h *Handler) resolveIP(ctx context.Context, domain string) net.Address {
// Process implements proxy.Outbound. // Process implements proxy.Outbound.
func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dialer proxy.Dialer) error { func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dialer proxy.Dialer) error {
destination, _ := proxy.TargetFromContext(ctx) destination, _ := proxy.TargetFromContext(ctx)
if h.destOverride != nil { if h.config.DestinationOverride != nil {
server := h.destOverride.Server server := h.config.DestinationOverride.Server
destination = net.Destination{ destination = net.Destination{
Network: destination.Network, Network: destination.Network,
Address: server.Address.AsAddress(), Address: server.Address.AsAddress(),
@ -86,7 +84,7 @@ func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
input := outboundRay.OutboundInput() input := outboundRay.OutboundInput()
output := outboundRay.OutboundOutput() output := outboundRay.OutboundOutput()
if h.domainStrategy == Config_USE_IP && destination.Address.Family().IsDomain() { if h.config.DomainStrategy == Config_USE_IP && destination.Address.Family().IsDomain() {
ip := h.resolveIP(ctx, destination.Address.Domain()) ip := h.resolveIP(ctx, destination.Address.Domain())
if ip != nil { if ip != nil {
destination = net.Destination{ destination = net.Destination{
@ -113,7 +111,7 @@ func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
defer conn.Close() defer conn.Close()
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, h.policy.Timeout.ConnectionIdle.Duration()) timer := signal.CancelAfterInactivity(ctx, cancel, h.policy().Timeouts.ConnectionIdle)
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
var writer buf.Writer var writer buf.Writer
@ -125,7 +123,7 @@ func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(input, writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to process request").Base(err) return newError("failed to process request").Base(err)
} }
timer.SetTimeout(h.policy.Timeout.DownlinkOnly.Duration()) timer.SetTimeout(h.policy().Timeouts.DownlinkOnly)
return nil return nil
}) })
@ -136,7 +134,7 @@ func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
if err := buf.Copy(v2reader, output, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(v2reader, output, buf.UpdateActivity(timer)); err != nil {
return newError("failed to process response").Base(err) return newError("failed to process response").Base(err)
} }
timer.SetTimeout(h.policy.Timeout.UplinkOnly.Duration()) timer.SetTimeout(h.policy().Timeouts.UplinkOnly)
return nil return nil
}) })

View File

@ -1,33 +0,0 @@
package proxy
import (
"context"
"v2ray.com/core/common"
)
func CreateInboundHandler(ctx context.Context, config interface{}) (Inbound, error) {
handler, err := common.CreateObject(ctx, config)
if err != nil {
return nil, newError("failed to create inbound handler").Base(err)
}
switch h := handler.(type) {
case Inbound:
return h, nil
default:
return nil, newError("not a InboundHandler")
}
}
func CreateOutboundHandler(ctx context.Context, config interface{}) (Outbound, error) {
handler, err := common.CreateObject(ctx, config)
if err != nil {
return nil, newError("failed to create outbound handler").Base(err)
}
switch h := handler.(type) {
case Outbound:
return h, nil
default:
return nil, newError("not a OutboundHandler")
}
}

View File

@ -10,9 +10,7 @@ import (
"strings" "strings"
"time" "time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/policy"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
@ -26,32 +24,31 @@ import (
// Server is a HTTP proxy server. // Server is a HTTP proxy server.
type Server struct { type Server struct {
config *ServerConfig config *ServerConfig
policy policy.Policy v *core.Instance
} }
// NewServer creates a new HTTP inbound handler. // NewServer creates a new HTTP inbound handler.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, newError("no space in context.")
}
s := &Server{ s := &Server{
config: config, config: config,
v: core.FromContext(ctx),
} }
space.On(app.SpaceInitializing, func(interface{}) error { if s.v == nil {
pm := policy.FromSpace(space) return nil, newError("V is not in context.")
if pm == nil { }
return newError("Policy not found in space.")
}
s.policy = pm.GetPolicy(config.UserLevel)
if config.Timeout > 0 && config.UserLevel == 0 {
s.policy.Timeout.ConnectionIdle.Value = config.Timeout
}
return nil
})
return s, nil return s, nil
} }
func (s *Server) policy() core.Policy {
config := s.config
p := s.v.PolicyManager().ForLevel(config.UserLevel)
if config.Timeout > 0 && config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
}
return p
}
func (*Server) Network() net.NetworkList { func (*Server) Network() net.NetworkList {
return net.NetworkList{ return net.NetworkList{
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
@ -104,11 +101,11 @@ type readerOnly struct {
io.Reader io.Reader
} }
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error { func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher core.Dispatcher) error {
reader := bufio.NewReaderSize(readerOnly{conn}, buf.Size) reader := bufio.NewReaderSize(readerOnly{conn}, buf.Size)
Start: Start:
conn.SetReadDeadline(time.Now().Add(s.policy.Timeout.Handshake.Duration())) conn.SetReadDeadline(time.Now().Add(s.policy().Timeouts.Handshake))
request, err := http.ReadRequest(reader) request, err := http.ReadRequest(reader)
if err != nil { if err != nil {
@ -165,14 +162,14 @@ Start:
return err return err
} }
func (s *Server) handleConnect(ctx context.Context, request *http.Request, reader *bufio.Reader, conn internet.Connection, dest net.Destination, dispatcher dispatcher.Interface) error { func (s *Server) handleConnect(ctx context.Context, request *http.Request, reader *bufio.Reader, conn internet.Connection, dest net.Destination, dispatcher core.Dispatcher) error {
_, err := conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n")) _, err := conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
if err != nil { if err != nil {
return newError("failed to write back OK response").Base(err) return newError("failed to write back OK response").Base(err)
} }
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, s.policy.Timeout.ConnectionIdle.Duration()) timer := signal.CancelAfterInactivity(ctx, cancel, s.policy().Timeouts.ConnectionIdle)
ray, err := dispatcher.Dispatch(ctx, dest) ray, err := dispatcher.Dispatch(ctx, dest)
if err != nil { if err != nil {
return err return err
@ -191,7 +188,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
defer ray.InboundInput().Close() defer ray.InboundInput().Close()
defer timer.SetTimeout(s.policy.Timeout.DownlinkOnly.Duration()) defer timer.SetTimeout(s.policy().Timeouts.DownlinkOnly)
v2reader := buf.NewReader(conn) v2reader := buf.NewReader(conn)
return buf.Copy(v2reader, ray.InboundInput(), buf.UpdateActivity(timer)) return buf.Copy(v2reader, ray.InboundInput(), buf.UpdateActivity(timer))
@ -202,7 +199,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
if err := buf.Copy(ray.InboundOutput(), v2writer, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(ray.InboundOutput(), v2writer, buf.UpdateActivity(timer)); err != nil {
return err return err
} }
timer.SetTimeout(s.policy.Timeout.UplinkOnly.Duration()) timer.SetTimeout(s.policy().Timeouts.UplinkOnly)
return nil return nil
}) })
@ -217,7 +214,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
var errWaitAnother = newError("keep alive") var errWaitAnother = newError("keep alive")
func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error { func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, writer io.Writer, dest net.Destination, dispatcher core.Dispatcher) error {
if !s.config.AllowTransparent && len(request.URL.Host) <= 0 { if !s.config.AllowTransparent && len(request.URL.Host) <= 0 {
// RFC 2068 (HTTP/1.1) requires URL to be absolute URL in HTTP proxy. // RFC 2068 (HTTP/1.1) requires URL to be absolute URL in HTTP proxy.
response := &http.Response{ response := &http.Response{

View File

@ -10,8 +10,9 @@ package proxy
import ( import (
"context" "context"
"v2ray.com/core/app/dispatcher" "v2ray.com/core"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/protocol"
"v2ray.com/core/transport/internet" "v2ray.com/core/transport/internet"
"v2ray.com/core/transport/ray" "v2ray.com/core/transport/ray"
) )
@ -22,7 +23,7 @@ type Inbound interface {
Network() net.NetworkList Network() net.NetworkList
// Process processes a connection of given network. If necessary, the Inbound can dispatch the connection to an Outbound. // Process processes a connection of given network. If necessary, the Inbound can dispatch the connection to an Outbound.
Process(context.Context, net.Network, internet.Connection, dispatcher.Interface) error Process(context.Context, net.Network, internet.Connection, core.Dispatcher) error
} }
// An Outbound process outbound connections. // An Outbound process outbound connections.
@ -36,3 +37,20 @@ type Dialer interface {
// Dial dials a system connection to the given destination. // Dial dials a system connection to the given destination.
Dial(ctx context.Context, destination net.Destination) (internet.Connection, error) Dial(ctx context.Context, destination net.Destination) (internet.Connection, error)
} }
// UserManager is the interface for Inbounds and Outbounds that can manage their users.
type UserManager interface {
// AddUser adds a new user.
AddUser(context.Context, *protocol.User) error
// RemoveUser removes an user by email.
RemoveUser(context.Context, string) error
}
type GetInbound interface {
GetInbound() Inbound
}
type GetOutbound interface {
GetOutbound() Outbound
}

View File

@ -3,8 +3,7 @@ package shadowsocks
import ( import (
"context" "context"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/policy"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
@ -18,8 +17,8 @@ import (
// Client is a inbound handler for Shadowsocks protocol // Client is a inbound handler for Shadowsocks protocol
type Client struct { type Client struct {
serverPicker protocol.ServerPicker serverPicker protocol.ServerPicker
policyManager policy.Manager v *core.Instance
} }
// NewClient create a new Shadowsocks client. // NewClient create a new Shadowsocks client.
@ -33,19 +32,11 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
} }
client := &Client{ client := &Client{
serverPicker: protocol.NewRoundRobinServerPicker(serverList), serverPicker: protocol.NewRoundRobinServerPicker(serverList),
v: core.FromContext(ctx),
} }
space := app.SpaceFromContext(ctx) if client.v == nil {
if space == nil { return nil, newError("V is not in context.")
return nil, newError("Space not found.")
} }
space.On(app.SpaceInitializing, func(interface{}) error {
pm := policy.FromSpace(space)
if pm == nil {
return newError("Policy not found in space.")
}
client.policyManager = pm
return nil
})
return client, nil return client, nil
} }
@ -103,9 +94,9 @@ func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, diale
request.Option |= RequestOptionOneTimeAuth request.Option |= RequestOptionOneTimeAuth
} }
sessionPolicy := v.policyManager.GetPolicy(user.Level) sessionPolicy := v.v.PolicyManager().ForLevel(user.Level)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeout.ConnectionIdle.Duration()) timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
if request.Command == protocol.RequestCommandTCP { if request.Command == protocol.RequestCommandTCP {
bufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn)) bufferedWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
@ -119,13 +110,13 @@ func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, diale
} }
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
defer timer.SetTimeout(sessionPolicy.Timeout.DownlinkOnly.Duration()) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
return buf.Copy(outboundRay.OutboundInput(), bodyWriter, buf.UpdateActivity(timer)) return buf.Copy(outboundRay.OutboundInput(), bodyWriter, buf.UpdateActivity(timer))
}) })
responseDone := signal.ExecuteAsync(func() error { responseDone := signal.ExecuteAsync(func() error {
defer outboundRay.OutboundOutput().Close() defer outboundRay.OutboundOutput().Close()
defer timer.SetTimeout(sessionPolicy.Timeout.UplinkOnly.Duration()) defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
responseReader, err := ReadTCPResponse(user, conn) responseReader, err := ReadTCPResponse(user, conn)
if err != nil { if err != nil {
@ -164,7 +155,7 @@ func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, diale
User: user, User: user,
} }
if err := buf.Copy(reader, outboundRay.OutboundOutput(), buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(reader, outboundRay.OutboundOutput(), buf.UpdateActivity(timer), buf.IgnoreReaderError()); err != nil {
return newError("failed to transport all UDP response").Base(err) return newError("failed to transport all UDP response").Base(err)
} }
return nil return nil

View File

@ -140,6 +140,9 @@ func (v *AesCfb) EncodePacket(key []byte, b *buf.Buffer) error {
} }
func (v *AesCfb) DecodePacket(key []byte, b *buf.Buffer) error { func (v *AesCfb) DecodePacket(key []byte, b *buf.Buffer) error {
if b.Len() <= v.IVSize() {
return newError("insufficient data: ", b.Len())
}
iv := b.BytesTo(v.IVSize()) iv := b.BytesTo(v.IVSize())
stream := crypto.NewAesDecryptionStream(key, iv) stream := crypto.NewAesDecryptionStream(key, iv)
stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize())) stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
@ -203,6 +206,9 @@ func (c *AEADCipher) EncodePacket(key []byte, b *buf.Buffer) error {
} }
func (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error { func (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error {
if b.Len() <= c.IVSize() {
return newError("insufficient data: ", b.Len())
}
ivLen := c.IVSize() ivLen := c.IVSize()
payloadLen := b.Len() payloadLen := b.Len()
auth := c.createAuthenticator(key, b.BytesTo(ivLen)) auth := c.createAuthenticator(key, b.BytesTo(ivLen))
@ -253,6 +259,9 @@ func (v *ChaCha20) EncodePacket(key []byte, b *buf.Buffer) error {
} }
func (v *ChaCha20) DecodePacket(key []byte, b *buf.Buffer) error { func (v *ChaCha20) DecodePacket(key []byte, b *buf.Buffer) error {
if b.Len() <= v.IVSize() {
return newError("insufficient data: ", b.Len())
}
iv := b.BytesTo(v.IVSize()) iv := b.BytesTo(v.IVSize())
stream := crypto.NewChaCha20Stream(key, iv) stream := crypto.NewChaCha20Stream(key, iv)
stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize())) stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))

View File

@ -4,9 +4,7 @@ import (
"context" "context"
"time" "time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/policy"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
@ -19,18 +17,14 @@ import (
) )
type Server struct { type Server struct {
config *ServerConfig config *ServerConfig
user *protocol.User user *protocol.User
account *MemoryAccount account *MemoryAccount
policyManager policy.Manager v *core.Instance
} }
// NewServer create a new Shadowsocks server. // NewServer create a new Shadowsocks server.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, newError("no space in context")
}
if config.GetUser() == nil { if config.GetUser() == nil {
return nil, newError("user is not specified") return nil, newError("user is not specified")
} }
@ -45,16 +39,12 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
config: config, config: config,
user: config.GetUser(), user: config.GetUser(),
account: account, account: account,
v: core.FromContext(ctx),
} }
space.On(app.SpaceInitializing, func(interface{}) error { if s.v == nil {
pm := policy.FromSpace(space) return nil, newError("V is not in context.")
if pm == nil { }
return newError("Policy not found in space.")
}
s.policyManager = pm
return nil
})
return s, nil return s, nil
} }
@ -69,7 +59,7 @@ func (s *Server) Network() net.NetworkList {
return list return list
} }
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error { func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher core.Dispatcher) error {
switch network { switch network {
case net.Network_TCP: case net.Network_TCP:
return s.handleConnection(ctx, conn, dispatcher) return s.handleConnection(ctx, conn, dispatcher)
@ -80,7 +70,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
} }
} }
func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher dispatcher.Interface) error { func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection, dispatcher core.Dispatcher) error {
udpServer := udp.NewDispatcher(dispatcher) udpServer := udp.NewDispatcher(dispatcher)
reader := buf.NewReader(conn) reader := buf.NewReader(conn)
@ -148,9 +138,9 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
return nil return nil
} }
func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher dispatcher.Interface) error { func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher core.Dispatcher) error {
sessionPolicy := s.policyManager.GetPolicy(s.user.Level) sessionPolicy := s.v.PolicyManager().ForLevel(s.user.Level)
conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeout.Handshake.Duration())) conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake))
bufferedReader := buf.NewBufferedReader(buf.NewReader(conn)) bufferedReader := buf.NewBufferedReader(buf.NewReader(conn))
request, bodyReader, err := ReadTCPSession(s.user, bufferedReader) request, bodyReader, err := ReadTCPSession(s.user, bufferedReader)
if err != nil { if err != nil {
@ -178,7 +168,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
ctx = protocol.ContextWithUser(ctx, request.User) ctx = protocol.ContextWithUser(ctx, request.User)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeout.ConnectionIdle.Duration()) timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ray, err := dispatcher.Dispatch(ctx, dest) ray, err := dispatcher.Dispatch(ctx, dest)
if err != nil { if err != nil {
return err return err
@ -208,7 +198,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
return newError("failed to transport all TCP response").Base(err) return newError("failed to transport all TCP response").Base(err)
} }
timer.SetTimeout(sessionPolicy.Timeout.UplinkOnly.Duration()) timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
return nil return nil
}) })
@ -219,7 +209,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
if err := buf.Copy(bodyReader, ray.InboundInput(), buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(bodyReader, ray.InboundInput(), buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all TCP request").Base(err) return newError("failed to transport all TCP request").Base(err)
} }
timer.SetTimeout(sessionPolicy.Timeout.DownlinkOnly.Duration()) timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
return nil return nil
}) })

View File

@ -5,9 +5,7 @@ import (
"io" "io"
"time" "time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/policy"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
@ -22,32 +20,30 @@ import (
// Server is a SOCKS 5 proxy server // Server is a SOCKS 5 proxy server
type Server struct { type Server struct {
config *ServerConfig config *ServerConfig
policy policy.Policy v *core.Instance
} }
// NewServer creates a new Server object. // NewServer creates a new Server object.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) { func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, newError("no space in context").AtWarning()
}
s := &Server{ s := &Server{
config: config, config: config,
v: core.FromContext(ctx),
}
if s.v == nil {
return nil, newError("V is not in context.")
} }
space.On(app.SpaceInitializing, func(interface{}) error {
pm := policy.FromSpace(space)
if pm == nil {
return newError("Policy not found in space.")
}
s.policy = pm.GetPolicy(config.UserLevel)
if config.Timeout > 0 && config.UserLevel == 0 {
s.policy.Timeout.ConnectionIdle.Value = config.Timeout
}
return nil
})
return s, nil return s, nil
} }
func (s *Server) policy() core.Policy {
config := s.config
p := s.v.PolicyManager().ForLevel(config.UserLevel)
if config.Timeout > 0 && config.UserLevel == 0 {
p.Timeouts.ConnectionIdle = time.Duration(config.Timeout) * time.Second
}
return p
}
func (s *Server) Network() net.NetworkList { func (s *Server) Network() net.NetworkList {
list := net.NetworkList{ list := net.NetworkList{
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
@ -58,7 +54,7 @@ func (s *Server) Network() net.NetworkList {
return list return list
} }
func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error { func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher core.Dispatcher) error {
switch network { switch network {
case net.Network_TCP: case net.Network_TCP:
return s.processTCP(ctx, conn, dispatcher) return s.processTCP(ctx, conn, dispatcher)
@ -69,8 +65,8 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
} }
} }
func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispatcher dispatcher.Interface) error { func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispatcher core.Dispatcher) error {
conn.SetReadDeadline(time.Now().Add(s.policy.Timeout.Handshake.Duration())) conn.SetReadDeadline(time.Now().Add(s.policy().Timeouts.Handshake))
reader := buf.NewBufferedReader(buf.NewReader(conn)) reader := buf.NewBufferedReader(buf.NewReader(conn))
inboundDest, ok := proxy.InboundEntryPointFromContext(ctx) inboundDest, ok := proxy.InboundEntryPointFromContext(ctx)
@ -125,9 +121,9 @@ func (*Server) handleUDP(c net.Conn) error {
return err return err
} }
func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error { func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher core.Dispatcher) error {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, v.policy.Timeout.ConnectionIdle.Duration()) timer := signal.CancelAfterInactivity(ctx, cancel, v.policy().Timeouts.ConnectionIdle)
ray, err := dispatcher.Dispatch(ctx, dest) ray, err := dispatcher.Dispatch(ctx, dest)
if err != nil { if err != nil {
@ -144,7 +140,7 @@ func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
if err := buf.Copy(v2reader, input, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(v2reader, input, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all TCP request").Base(err) return newError("failed to transport all TCP request").Base(err)
} }
timer.SetTimeout(v.policy.Timeout.DownlinkOnly.Duration()) timer.SetTimeout(v.policy().Timeouts.DownlinkOnly)
return nil return nil
}) })
@ -153,7 +149,7 @@ func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
if err := buf.Copy(output, v2writer, buf.UpdateActivity(timer)); err != nil { if err := buf.Copy(output, v2writer, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transport all TCP response").Base(err) return newError("failed to transport all TCP response").Base(err)
} }
timer.SetTimeout(v.policy.Timeout.UplinkOnly.Duration()) timer.SetTimeout(v.policy().Timeouts.UplinkOnly)
return nil return nil
}) })
@ -166,7 +162,7 @@ func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
return nil return nil
} }
func (v *Server) handleUDPPayload(ctx context.Context, conn internet.Connection, dispatcher dispatcher.Interface) error { func (v *Server) handleUDPPayload(ctx context.Context, conn internet.Connection, dispatcher core.Dispatcher) error {
udpServer := udp.NewDispatcher(dispatcher) udpServer := udp.NewDispatcher(dispatcher)
if source, ok := proxy.SourceFromContext(ctx); ok { if source, ok := proxy.SourceFromContext(ctx); ok {

View File

@ -31,8 +31,7 @@ func (a *InternalAccount) Equals(account protocol.Account) bool {
func (a *Account) AsAccount() (protocol.Account, error) { func (a *Account) AsAccount() (protocol.Account, error) {
id, err := uuid.ParseString(a.Id) id, err := uuid.ParseString(a.Id)
if err != nil { if err != nil {
newError("failed to parse ID").Base(err).AtError().WriteToLog() return nil, newError("failed to parse ID").Base(err).AtError()
return nil, err
} }
protoID := protocol.NewID(id) protoID := protocol.NewID(id)
return &InternalAccount{ return &InternalAccount{

View File

@ -131,7 +131,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
} }
if request.Security.Is(protocol.SecurityType_NONE) { if request.Security.Is(protocol.SecurityType_NONE) {
if request.Option.Has(protocol.RequestOptionChunkStream) { if request.Option.Has(protocol.RequestOptionChunkStream) {
if request.Command == protocol.RequestCommandTCP { if request.Command.TransferType() == protocol.TransferTypeStream {
return crypto.NewChunkStreamWriter(sizeParser, writer) return crypto.NewChunkStreamWriter(sizeParser, writer)
} }
auth := &crypto.AEADAuthenticator{ auth := &crypto.AEADAuthenticator{
@ -236,7 +236,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
} }
if request.Security.Is(protocol.SecurityType_NONE) { if request.Security.Is(protocol.SecurityType_NONE) {
if request.Option.Has(protocol.RequestOptionChunkStream) { if request.Option.Has(protocol.RequestOptionChunkStream) {
if request.Command == protocol.RequestCommandTCP { if request.Command.TransferType() == protocol.TransferTypeStream {
return crypto.NewChunkStreamReader(sizeParser, reader) return crypto.NewChunkStreamReader(sizeParser, reader)
} }

View File

@ -1,7 +1,6 @@
package encoding_test package encoding_test
import ( import (
"context"
"testing" "testing"
"v2ray.com/core/common" "v2ray.com/core/common"
@ -22,8 +21,9 @@ func TestRequestSerialization(t *testing.T) {
Level: 0, Level: 0,
Email: "test@v2ray.com", Email: "test@v2ray.com",
} }
id := uuid.New()
account := &vmess.Account{ account := &vmess.Account{
Id: uuid.New().String(), Id: id.String(),
AlterId: 0, AlterId: 0,
} }
user.Account = serial.ToTypedMessage(account) user.Account = serial.ToTypedMessage(account)
@ -44,11 +44,12 @@ func TestRequestSerialization(t *testing.T) {
buffer2 := buf.New() buffer2 := buf.New()
buffer2.Append(buffer.Bytes()) buffer2.Append(buffer.Bytes())
ctx, cancel := context.WithCancel(context.Background()) sessionHistory := NewSessionHistory()
sessionHistory := NewSessionHistory(ctx) defer common.Close(sessionHistory)
userValidator := vmess.NewTimedUserValidator(ctx, protocol.DefaultIDHash) userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
userValidator.Add(user) userValidator.Add(user)
defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory) server := NewServerSession(userValidator, sessionHistory)
actualRequest, err := server.DecodeRequestHeader(buffer) actualRequest, err := server.DecodeRequestHeader(buffer)
@ -64,6 +65,91 @@ func TestRequestSerialization(t *testing.T) {
_, err = server.DecodeRequestHeader(buffer2) _, err = server.DecodeRequestHeader(buffer2)
// anti replay attack // anti replay attack
assert(err, IsNotNil) assert(err, IsNotNil)
}
cancel()
func TestInvalidRequest(t *testing.T) {
assert := With(t)
user := &protocol.User{
Level: 0,
Email: "test@v2ray.com",
}
id := uuid.New()
account := &vmess.Account{
Id: id.String(),
AlterId: 0,
}
user.Account = serial.ToTypedMessage(account)
expectedRequest := &protocol.RequestHeader{
Version: 1,
User: user,
Command: protocol.RequestCommand(100),
Address: net.DomainAddress("www.v2ray.com"),
Port: net.Port(443),
Security: protocol.Security(protocol.SecurityType_AES128_GCM),
}
buffer := buf.New()
client := NewClientSession(protocol.DefaultIDHash)
common.Must(client.EncodeRequestHeader(expectedRequest, buffer))
buffer2 := buf.New()
buffer2.Append(buffer.Bytes())
sessionHistory := NewSessionHistory()
defer common.Close(sessionHistory)
userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
userValidator.Add(user)
defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory)
_, err := server.DecodeRequestHeader(buffer)
assert(err, IsNotNil)
}
func TestMuxRequest(t *testing.T) {
assert := With(t)
user := &protocol.User{
Level: 0,
Email: "test@v2ray.com",
}
id := uuid.New()
account := &vmess.Account{
Id: id.String(),
AlterId: 0,
}
user.Account = serial.ToTypedMessage(account)
expectedRequest := &protocol.RequestHeader{
Version: 1,
User: user,
Command: protocol.RequestCommandMux,
Security: protocol.Security(protocol.SecurityType_AES128_GCM),
}
buffer := buf.New()
client := NewClientSession(protocol.DefaultIDHash)
common.Must(client.EncodeRequestHeader(expectedRequest, buffer))
buffer2 := buf.New()
buffer2.Append(buffer.Bytes())
sessionHistory := NewSessionHistory()
defer common.Close(sessionHistory)
userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
userValidator.Add(user)
defer common.Close(userValidator)
server := NewServerSession(userValidator, sessionHistory)
actualRequest, err := server.DecodeRequestHeader(buffer)
assert(err, IsNil)
assert(expectedRequest.Version, Equals, actualRequest.Version)
assert(byte(expectedRequest.Command), Equals, byte(actualRequest.Command))
assert(byte(expectedRequest.Option), Equals, byte(actualRequest.Option))
assert(byte(expectedRequest.Security), Equals, byte(actualRequest.Security))
} }

View File

@ -1,7 +1,6 @@
package encoding package encoding
import ( import (
"context"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/md5" "crypto/md5"
@ -10,6 +9,8 @@ import (
"sync" "sync"
"time" "time"
"v2ray.com/core/common/dice"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/bitmask" "v2ray.com/core/common/bitmask"
@ -31,29 +32,34 @@ type sessionId struct {
type SessionHistory struct { type SessionHistory struct {
sync.RWMutex sync.RWMutex
cache map[sessionId]time.Time cache map[sessionId]time.Time
token *signal.Semaphore task *signal.PeriodicTask
ctx context.Context
} }
func NewSessionHistory(ctx context.Context) *SessionHistory { func NewSessionHistory() *SessionHistory {
h := &SessionHistory{ h := &SessionHistory{
cache: make(map[sessionId]time.Time, 128), cache: make(map[sessionId]time.Time, 128),
token: signal.NewSemaphore(1),
ctx: ctx,
} }
h.task = &signal.PeriodicTask{
Interval: time.Second * 30,
Execute: func() error {
h.removeExpiredEntries()
return nil
},
}
common.Must(h.task.Start())
return h return h
} }
// Close implements common.Closable.
func (h *SessionHistory) Close() error {
return h.task.Close()
}
func (h *SessionHistory) add(session sessionId) { func (h *SessionHistory) add(session sessionId) {
h.Lock() h.Lock()
h.cache[session] = time.Now().Add(time.Minute * 3) defer h.Unlock()
h.Unlock()
select { h.cache[session] = time.Now().Add(time.Minute * 3)
case <-h.token.Wait():
go h.run()
default:
}
} }
func (h *SessionHistory) has(session sessionId) bool { func (h *SessionHistory) has(session sessionId) bool {
@ -66,31 +72,16 @@ func (h *SessionHistory) has(session sessionId) bool {
return false return false
} }
func (h *SessionHistory) run() { func (h *SessionHistory) removeExpiredEntries() {
defer h.token.Signal() now := time.Now()
for { h.Lock()
select { defer h.Unlock()
case <-h.ctx.Done():
return for session, expire := range h.cache {
case <-time.After(time.Second * 30): if expire.Before(now) {
}
session2Remove := make([]sessionId, 0, 16)
now := time.Now()
h.Lock()
if len(h.cache) == 0 {
h.Unlock()
return
}
for session, expire := range h.cache {
if expire.Before(now) {
session2Remove = append(session2Remove, session)
}
}
for _, session := range session2Remove {
delete(h.cache, session) delete(h.cache, session)
} }
h.Unlock()
} }
} }
@ -114,6 +105,44 @@ func NewServerSession(validator protocol.UserValidator, sessionHistory *SessionH
} }
} }
func readAddress(buffer *buf.Buffer, reader io.Reader) (net.Address, net.Port, error) {
var address net.Address
var port net.Port
if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 3)); err != nil {
return address, port, newError("failed to read port and address type").Base(err)
}
port = net.PortFromBytes(buffer.BytesRange(-3, -1))
addressType := protocol.AddressType(buffer.Byte(buffer.Len() - 1))
switch addressType {
case protocol.AddressTypeIPv4:
if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 4)); err != nil {
return address, port, newError("failed to read IPv4 address").Base(err)
}
address = net.IPAddress(buffer.BytesFrom(-4))
case protocol.AddressTypeIPv6:
if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 16)); err != nil {
return address, port, newError("failed to read IPv6 address").Base(err)
}
address = net.IPAddress(buffer.BytesFrom(-16))
case protocol.AddressTypeDomain:
if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, 1)); err != nil {
return address, port, newError("failed to read domain address").Base(err)
}
domainLength := int(buffer.Byte(buffer.Len() - 1))
if domainLength == 0 {
return address, port, newError("zero length domain")
}
if err := buffer.AppendSupplier(buf.ReadFullFrom(reader, domainLength)); err != nil {
return address, port, newError("failed to read domain address").Base(err)
}
address = net.DomainAddress(string(buffer.BytesFrom(-domainLength)))
default:
return address, port, newError("invalid address type", addressType)
}
return address, port, nil
}
func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.RequestHeader, error) { func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.RequestHeader, error) {
buffer := buf.New() buffer := buf.New()
defer buffer.Release() defer buffer.Release()
@ -139,7 +168,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
aesStream := crypto.NewAesDecryptionStream(vmessAccount.ID.CmdKey(), iv) aesStream := crypto.NewAesDecryptionStream(vmessAccount.ID.CmdKey(), iv)
decryptor := crypto.NewCryptionReader(aesStream, reader) decryptor := crypto.NewCryptionReader(aesStream, reader)
if err := buffer.Reset(buf.ReadFullFrom(decryptor, 41)); err != nil { if err := buffer.Reset(buf.ReadFullFrom(decryptor, 38)); err != nil {
return nil, newError("failed to read request header").Base(err) return nil, newError("failed to read request header").Base(err)
} }
@ -148,10 +177,6 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
Version: buffer.Byte(0), Version: buffer.Byte(0),
} }
if request.Version != Version {
return nil, newError("invalid protocol version ", request.Version)
}
s.requestBodyIV = append([]byte(nil), buffer.BytesRange(1, 17)...) // 16 bytes s.requestBodyIV = append([]byte(nil), buffer.BytesRange(1, 17)...) // 16 bytes
s.requestBodyKey = append([]byte(nil), buffer.BytesRange(17, 33)...) // 16 bytes s.requestBodyKey = append([]byte(nil), buffer.BytesRange(17, 33)...) // 16 bytes
var sid sessionId var sid sessionId
@ -170,33 +195,28 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
// 1 bytes reserved // 1 bytes reserved
request.Command = protocol.RequestCommand(buffer.Byte(37)) request.Command = protocol.RequestCommand(buffer.Byte(37))
if request.Command != protocol.RequestCommandMux { invalidRequest := false
request.Port = net.PortFromBytes(buffer.BytesRange(38, 40)) switch request.Command {
case protocol.RequestCommandMux:
switch protocol.AddressType(buffer.Byte(40)) { request.Address = net.DomainAddress("v1.mux.cool")
case protocol.AddressTypeIPv4: request.Port = 0
if err := buffer.AppendSupplier(buf.ReadFullFrom(decryptor, 4)); err != nil { case protocol.RequestCommandTCP, protocol.RequestCommandUDP:
return nil, newError("failed to read IPv4 address").Base(err) if addr, port, err := readAddress(buffer, decryptor); err == nil {
} request.Address = addr
request.Address = net.IPAddress(buffer.BytesFrom(-4)) request.Port = port
case protocol.AddressTypeIPv6: } else {
if err := buffer.AppendSupplier(buf.ReadFullFrom(decryptor, 16)); err != nil { invalidRequest = true
return nil, newError("failed to read IPv6 address").Base(err) newError("failed to read address").Base(err).WriteToLog()
}
request.Address = net.IPAddress(buffer.BytesFrom(-16))
case protocol.AddressTypeDomain:
if err := buffer.AppendSupplier(buf.ReadFullFrom(decryptor, 1)); err != nil {
return nil, newError("failed to read domain address").Base(err)
}
domainLength := int(buffer.Byte(buffer.Len() - 1))
if domainLength == 0 {
return nil, newError("zero length domain").Base(err)
}
if err := buffer.AppendSupplier(buf.ReadFullFrom(decryptor, domainLength)); err != nil {
return nil, newError("failed to read domain address").Base(err)
}
request.Address = net.DomainAddress(string(buffer.BytesFrom(-domainLength)))
} }
default:
invalidRequest = true
}
if invalidRequest {
randomLen := dice.Roll(32) + 1
// Read random number of bytes for prevent detection.
buffer.AppendSupplier(buf.ReadFullFrom(decryptor, randomLen))
return nil, newError("invalid request")
} }
if padingLen > 0 { if padingLen > 0 {
@ -232,7 +252,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
} }
if request.Security.Is(protocol.SecurityType_NONE) { if request.Security.Is(protocol.SecurityType_NONE) {
if request.Option.Has(protocol.RequestOptionChunkStream) { if request.Option.Has(protocol.RequestOptionChunkStream) {
if request.Command == protocol.RequestCommandTCP { if request.Command.TransferType() == protocol.TransferTypeStream {
return crypto.NewChunkStreamReader(sizeParser, reader) return crypto.NewChunkStreamReader(sizeParser, reader)
} }
@ -318,7 +338,7 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ
} }
if request.Security.Is(protocol.SecurityType_NONE) { if request.Security.Is(protocol.SecurityType_NONE) {
if request.Option.Has(protocol.RequestOptionChunkStream) { if request.Option.Has(protocol.RequestOptionChunkStream) {
if request.Command == protocol.RequestCommandTCP { if request.Command.TransferType() == protocol.TransferTypeStream {
return crypto.NewChunkStreamWriter(sizeParser, writer) return crypto.NewChunkStreamWriter(sizeParser, writer)
} }

View File

@ -5,13 +5,11 @@ package inbound
import ( import (
"context" "context"
"io" "io"
"strings"
"sync" "sync"
"time" "time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/policy"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/errors" "v2ray.com/core/common/errors"
@ -28,96 +26,116 @@ import (
) )
type userByEmail struct { type userByEmail struct {
sync.RWMutex sync.Mutex
cache map[string]*protocol.User cache map[string]*protocol.User
defaultLevel uint32 defaultLevel uint32
defaultAlterIDs uint16 defaultAlterIDs uint16
} }
func newUserByEmail(users []*protocol.User, config *DefaultConfig) *userByEmail { func newUserByEmail(config *DefaultConfig) *userByEmail {
cache := make(map[string]*protocol.User)
for _, user := range users {
cache[user.Email] = user
}
return &userByEmail{ return &userByEmail{
cache: cache, cache: make(map[string]*protocol.User),
defaultLevel: config.Level, defaultLevel: config.Level,
defaultAlterIDs: uint16(config.AlterId), defaultAlterIDs: uint16(config.AlterId),
} }
} }
func (v *userByEmail) addNoLock(u *protocol.User) bool {
email := strings.ToLower(u.Email)
user, found := v.cache[email]
if found {
return false
}
v.cache[email] = user
return true
}
func (v *userByEmail) Add(u *protocol.User) bool {
v.Lock()
defer v.Unlock()
return v.addNoLock(u)
}
func (v *userByEmail) Get(email string) (*protocol.User, bool) { func (v *userByEmail) Get(email string) (*protocol.User, bool) {
var user *protocol.User email = strings.ToLower(email)
var found bool
v.RLock() v.Lock()
user, found = v.cache[email] defer v.Unlock()
v.RUnlock()
user, found := v.cache[email]
if !found { if !found {
v.Lock() id := uuid.New()
user, found = v.cache[email] account := &vmess.Account{
if !found { Id: id.String(),
account := &vmess.Account{ AlterId: uint32(v.defaultAlterIDs),
Id: uuid.New().String(),
AlterId: uint32(v.defaultAlterIDs),
}
user = &protocol.User{
Level: v.defaultLevel,
Email: email,
Account: serial.ToTypedMessage(account),
}
v.cache[email] = user
} }
v.Unlock() user = &protocol.User{
Level: v.defaultLevel,
Email: email,
Account: serial.ToTypedMessage(account),
}
v.cache[email] = user
} }
return user, found return user, found
} }
func (v *userByEmail) Remove(email string) bool {
email = strings.ToLower(email)
v.Lock()
defer v.Unlock()
if _, found := v.cache[email]; !found {
return false
}
delete(v.cache, email)
return true
}
// Handler is an inbound connection handler that handles messages in VMess protocol. // Handler is an inbound connection handler that handles messages in VMess protocol.
type Handler struct { type Handler struct {
inboundHandlerManager proxyman.InboundHandlerManager policyManager core.PolicyManager
inboundHandlerManager core.InboundHandlerManager
clients protocol.UserValidator clients protocol.UserValidator
usersByEmail *userByEmail usersByEmail *userByEmail
detours *DetourConfig detours *DetourConfig
sessionHistory *encoding.SessionHistory sessionHistory *encoding.SessionHistory
policyManager policy.Manager
} }
// New creates a new VMess inbound handler. // New creates a new VMess inbound handler.
func New(ctx context.Context, config *Config) (*Handler, error) { func New(ctx context.Context, config *Config) (*Handler, error) {
space := app.SpaceFromContext(ctx) v := core.FromContext(ctx)
if space == nil { if v == nil {
return nil, newError("no space in context") return nil, newError("V is not in context.")
}
handler := &Handler{
policyManager: v.PolicyManager(),
inboundHandlerManager: v.InboundHandlerManager(),
clients: vmess.NewTimedUserValidator(protocol.DefaultIDHash),
detours: config.Detour,
usersByEmail: newUserByEmail(config.GetDefaultValue()),
sessionHistory: encoding.NewSessionHistory(),
} }
allowedClients := vmess.NewTimedUserValidator(ctx, protocol.DefaultIDHash)
for _, user := range config.User { for _, user := range config.User {
if err := allowedClients.Add(user); err != nil { if err := handler.AddUser(ctx, user); err != nil {
return nil, newError("failed to initiate user").Base(err) return nil, newError("failed to initiate user").Base(err)
} }
} }
handler := &Handler{
clients: allowedClients,
detours: config.Detour,
usersByEmail: newUserByEmail(config.User, config.GetDefaultValue()),
sessionHistory: encoding.NewSessionHistory(ctx),
}
space.On(app.SpaceInitializing, func(interface{}) error {
handler.inboundHandlerManager = proxyman.InboundHandlerManagerFromSpace(space)
if handler.inboundHandlerManager == nil {
return newError("InboundHandlerManager is not found is space.")
}
handler.policyManager = policy.FromSpace(space)
if handler.policyManager == nil {
return newError("Policy is not found in space.")
}
return nil
})
return handler, nil return handler, nil
} }
// Close implements common.Closable.
func (h *Handler) Close() error {
common.Close(h.clients)
common.Close(h.sessionHistory)
common.Close(h.usersByEmail)
return nil
}
// Network implements proxy.Inbound.Network(). // Network implements proxy.Inbound.Network().
func (*Handler) Network() net.NetworkList { func (*Handler) Network() net.NetworkList {
return net.NetworkList{ return net.NetworkList{
@ -133,6 +151,24 @@ func (h *Handler) GetUser(email string) *protocol.User {
return user return user
} }
func (h *Handler) AddUser(ctx context.Context, user *protocol.User) error {
if len(user.Email) > 0 && !h.usersByEmail.Add(user) {
return newError("User ", user.Email, " already exists.")
}
return h.clients.Add(user)
}
func (h *Handler) RemoveUser(ctx context.Context, email string) error {
if len(email) == 0 {
return newError("Email must not be empty.")
}
if !h.usersByEmail.Remove(email) {
return newError("User ", email, " not found.")
}
h.clients.Remove(email)
return nil
}
func transferRequest(timer signal.ActivityUpdater, session *encoding.ServerSession, request *protocol.RequestHeader, input io.Reader, output ray.OutputStream) error { func transferRequest(timer signal.ActivityUpdater, session *encoding.ServerSession, request *protocol.RequestHeader, input io.Reader, output ray.OutputStream) error {
defer output.Close() defer output.Close()
@ -179,9 +215,9 @@ func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSess
} }
// Process implements proxy.Inbound.Process(). // Process implements proxy.Inbound.Process().
func (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher dispatcher.Interface) error { func (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher core.Dispatcher) error {
sessionPolicy := h.policyManager.GetPolicy(0) sessionPolicy := h.policyManager.ForLevel(0)
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeout.Handshake.Duration())); err != nil { if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
return newError("unable to set read deadline").Base(err).AtWarning() return newError("unable to set read deadline").Base(err).AtWarning()
} }
@ -198,16 +234,11 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
Status: log.AccessRejected, Status: log.AccessRejected,
Reason: err, Reason: err,
}) })
newError("invalid request from ", connection.RemoteAddr(), ": ", err).AtInfo().WriteToLog() err = newError("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
} }
return err return err
} }
if request.Command == protocol.RequestCommandMux {
request.Address = net.DomainAddress("v1.mux.com")
request.Port = net.Port(0)
}
log.Record(&log.AccessMessage{ log.Record(&log.AccessMessage{
From: connection.RemoteAddr(), From: connection.RemoteAddr(),
To: request.Destination(), To: request.Destination(),
@ -221,11 +252,11 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
newError("unable to set back read deadline").Base(err).WriteToLog() newError("unable to set back read deadline").Base(err).WriteToLog()
} }
sessionPolicy = h.policyManager.GetPolicy(request.User.Level) sessionPolicy = h.policyManager.ForLevel(request.User.Level)
ctx = protocol.ContextWithUser(ctx, request.User) ctx = protocol.ContextWithUser(ctx, request.User)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeout.ConnectionIdle.Duration()) timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
ray, err := dispatcher.Dispatch(ctx, request.Destination()) ray, err := dispatcher.Dispatch(ctx, request.Destination())
if err != nil { if err != nil {
return newError("failed to dispatch request to ", request.Destination()).Base(err) return newError("failed to dispatch request to ", request.Destination()).Base(err)
@ -235,14 +266,14 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
output := ray.InboundOutput() output := ray.InboundOutput()
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
defer timer.SetTimeout(sessionPolicy.Timeout.DownlinkOnly.Duration()) defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
return transferRequest(timer, session, request, reader, input) return transferRequest(timer, session, request, reader, input)
}) })
responseDone := signal.ExecuteAsync(func() error { responseDone := signal.ExecuteAsync(func() error {
writer := buf.NewBufferedWriter(buf.NewWriter(connection)) writer := buf.NewBufferedWriter(buf.NewWriter(connection))
defer writer.Flush() defer writer.Flush()
defer timer.SetTimeout(sessionPolicy.Timeout.UplinkOnly.Duration()) defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
response := &protocol.ResponseHeader{ response := &protocol.ResponseHeader{
Command: h.generateCommand(ctx, request), Command: h.generateCommand(ctx, request),
@ -265,7 +296,7 @@ func (h *Handler) generateCommand(ctx context.Context, request *protocol.Request
if h.inboundHandlerManager != nil { if h.inboundHandlerManager != nil {
handler, err := h.inboundHandlerManager.GetHandler(ctx, tag) handler, err := h.inboundHandlerManager.GetHandler(ctx, tag)
if err != nil { if err != nil {
newError("failed to get detour handler: ", tag, err).AtWarning().WriteToLog() newError("failed to get detour handler: ", tag).Base(err).AtWarning().WriteToLog()
return nil return nil
} }
proxyHandler, port, availableMin := handler.GetRandomInboundProxy() proxyHandler, port, availableMin := handler.GetRandomInboundProxy()

View File

@ -6,8 +6,7 @@ import (
"context" "context"
"time" "time"
"v2ray.com/core/app" "v2ray.com/core"
"v2ray.com/core/app/policy"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/buf" "v2ray.com/core/common/buf"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
@ -23,17 +22,12 @@ import (
// Handler is an outbound connection handler for VMess protocol. // Handler is an outbound connection handler for VMess protocol.
type Handler struct { type Handler struct {
serverList *protocol.ServerList serverList *protocol.ServerList
serverPicker protocol.ServerPicker serverPicker protocol.ServerPicker
policyManager policy.Manager v *core.Instance
} }
func New(ctx context.Context, config *Config) (*Handler, error) { func New(ctx context.Context, config *Config) (*Handler, error) {
space := app.SpaceFromContext(ctx)
if space == nil {
return nil, newError("no space in context.")
}
serverList := protocol.NewServerList() serverList := protocol.NewServerList()
for _, rec := range config.Receiver { for _, rec := range config.Receiver {
serverList.AddServer(protocol.NewServerSpecFromPB(*rec)) serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
@ -41,16 +35,12 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
handler := &Handler{ handler := &Handler{
serverList: serverList, serverList: serverList,
serverPicker: protocol.NewRoundRobinServerPicker(serverList), serverPicker: protocol.NewRoundRobinServerPicker(serverList),
v: core.FromContext(ctx),
} }
space.On(app.SpaceInitializing, func(interface{}) error { if handler.v == nil {
pm := policy.FromSpace(space) return nil, newError("V is not in context.")
if pm == nil { }
return newError("Policy is not found in space.")
}
handler.policyManager = pm
return nil
})
return handler, nil return handler, nil
} }
@ -85,9 +75,9 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
if target.Network == net.Network_UDP { if target.Network == net.Network_UDP {
command = protocol.RequestCommandUDP command = protocol.RequestCommandUDP
} }
if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.com" { //if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
command = protocol.RequestCommandMux // command = protocol.RequestCommandMux
} //}
request := &protocol.RequestHeader{ request := &protocol.RequestHeader{
Version: encoding.Version, Version: encoding.Version,
User: rec.PickUser(), User: rec.PickUser(),
@ -112,10 +102,10 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
output := outboundRay.OutboundOutput() output := outboundRay.OutboundOutput()
session := encoding.NewClientSession(protocol.DefaultIDHash) session := encoding.NewClientSession(protocol.DefaultIDHash)
sessionPolicy := v.policyManager.GetPolicy(request.User.Level) sessionPolicy := v.v.PolicyManager().ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeout.ConnectionIdle.Duration()) timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
requestDone := signal.ExecuteAsync(func() error { requestDone := signal.ExecuteAsync(func() error {
writer := buf.NewBufferedWriter(buf.NewWriter(conn)) writer := buf.NewBufferedWriter(buf.NewWriter(conn))
@ -148,13 +138,13 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
return err return err
} }
} }
timer.SetTimeout(sessionPolicy.Timeout.DownlinkOnly.Duration()) timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
return nil return nil
}) })
responseDone := signal.ExecuteAsync(func() error { responseDone := signal.ExecuteAsync(func() error {
defer output.Close() defer output.Close()
defer timer.SetTimeout(sessionPolicy.Timeout.UplinkOnly.Duration()) defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
reader := buf.NewBufferedReader(buf.NewReader(conn)) reader := buf.NewBufferedReader(buf.NewReader(conn))
header, err := session.DecodeResponseHeader(reader) header, err := session.DecodeResponseHeader(reader)

View File

@ -8,99 +8,110 @@ package vmess
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg vmess -path Proxy,VMess //go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg vmess -path Proxy,VMess
import ( import (
"context" "strings"
"sync" "sync"
"time" "time"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/protocol" "v2ray.com/core/common/protocol"
"v2ray.com/core/common/signal"
) )
const ( const (
updateIntervalSec = 10 updateInterval = 10 * time.Second
cacheDurationSec = 120 cacheDurationSec = 120
) )
type idEntry struct { type user struct {
id *protocol.ID user *protocol.User
userIdx int account *InternalAccount
lastSec protocol.Timestamp lastSec protocol.Timestamp
lastSecRemoval protocol.Timestamp
} }
type TimedUserValidator struct { type TimedUserValidator struct {
sync.RWMutex sync.RWMutex
validUsers []*protocol.User users []*user
userHash map[[16]byte]indexTimePair userHash map[[16]byte]indexTimePair
ids []*idEntry hasher protocol.IDHash
hasher protocol.IDHash baseTime protocol.Timestamp
baseTime protocol.Timestamp task *signal.PeriodicTask
} }
type indexTimePair struct { type indexTimePair struct {
index int user *user
timeInc uint32 timeInc uint32
} }
func NewTimedUserValidator(ctx context.Context, hasher protocol.IDHash) protocol.UserValidator { func NewTimedUserValidator(hasher protocol.IDHash) protocol.UserValidator {
tus := &TimedUserValidator{ tuv := &TimedUserValidator{
validUsers: make([]*protocol.User, 0, 16), users: make([]*user, 0, 16),
userHash: make(map[[16]byte]indexTimePair, 512), userHash: make(map[[16]byte]indexTimePair, 1024),
ids: make([]*idEntry, 0, 512), hasher: hasher,
hasher: hasher, baseTime: protocol.Timestamp(time.Now().Unix() - cacheDurationSec*3),
baseTime: protocol.Timestamp(time.Now().Unix() - cacheDurationSec*3),
} }
go tus.updateUserHash(ctx, updateIntervalSec*time.Second) tuv.task = &signal.PeriodicTask{
return tus Interval: updateInterval,
Execute: func() error {
tuv.updateUserHash()
return nil
},
}
tuv.task.Start()
return tuv
} }
func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, idx int, entry *idEntry) { func (v *TimedUserValidator) generateNewHashes(nowSec protocol.Timestamp, user *user) {
var hashValue [16]byte var hashValue [16]byte
var hashValueRemoval [16]byte genHashForID := func(id *protocol.ID) {
idHash := v.hasher(entry.id.Bytes()) idHash := v.hasher(id.Bytes())
for entry.lastSec <= nowSec { for ts := user.lastSec; ts <= nowSec; ts++ {
common.Must2(idHash.Write(entry.lastSec.Bytes(nil))) common.Must2(idHash.Write(ts.Bytes(nil)))
idHash.Sum(hashValue[:0]) idHash.Sum(hashValue[:0])
idHash.Reset() idHash.Reset()
common.Must2(idHash.Write(entry.lastSecRemoval.Bytes(nil))) v.userHash[hashValue] = indexTimePair{
idHash.Sum(hashValueRemoval[:0]) user: user,
idHash.Reset() timeInc: uint32(ts - v.baseTime),
delete(v.userHash, hashValueRemoval)
v.userHash[hashValue] = indexTimePair{
index: idx,
timeInc: uint32(entry.lastSec - v.baseTime),
}
entry.lastSec++
entry.lastSecRemoval++
}
}
func (v *TimedUserValidator) updateUserHash(ctx context.Context, interval time.Duration) {
for {
select {
case now := <-time.After(interval):
nowSec := protocol.Timestamp(now.Unix() + cacheDurationSec)
v.Lock()
for _, entry := range v.ids {
v.generateNewHashes(nowSec, entry.userIdx, entry)
} }
v.Unlock() }
case <-ctx.Done(): }
return
genHashForID(user.account.ID)
for _, id := range user.account.AlterIDs {
genHashForID(id)
}
user.lastSec = nowSec
}
func (v *TimedUserValidator) removeExpiredHashes(expire uint32) {
for key, pair := range v.userHash {
if pair.timeInc < expire {
delete(v.userHash, key)
} }
} }
} }
func (v *TimedUserValidator) Add(user *protocol.User) error { func (v *TimedUserValidator) updateUserHash() {
now := time.Now()
nowSec := protocol.Timestamp(now.Unix() + cacheDurationSec)
v.Lock() v.Lock()
defer v.Unlock() defer v.Unlock()
idx := len(v.validUsers) for _, user := range v.users {
v.validUsers = append(v.validUsers, user) v.generateNewHashes(nowSec, user)
rawAccount, err := user.GetTypedAccount() }
expire := protocol.Timestamp(now.Unix() - cacheDurationSec*3)
if expire > v.baseTime {
v.removeExpiredHashes(uint32(expire - v.baseTime))
}
}
func (v *TimedUserValidator) Add(u *protocol.User) error {
v.Lock()
defer v.Unlock()
rawAccount, err := u.GetTypedAccount()
if err != nil { if err != nil {
return err return err
} }
@ -108,24 +119,13 @@ func (v *TimedUserValidator) Add(user *protocol.User) error {
nowSec := time.Now().Unix() nowSec := time.Now().Unix()
entry := &idEntry{ uu := &user{
id: account.ID, user: u,
userIdx: idx, account: account,
lastSec: protocol.Timestamp(nowSec - cacheDurationSec), lastSec: protocol.Timestamp(nowSec - cacheDurationSec),
lastSecRemoval: protocol.Timestamp(nowSec - cacheDurationSec*3),
}
v.generateNewHashes(protocol.Timestamp(nowSec+cacheDurationSec), idx, entry)
v.ids = append(v.ids, entry)
for _, alterid := range account.AlterIDs {
entry := &idEntry{
id: alterid,
userIdx: idx,
lastSec: protocol.Timestamp(nowSec - cacheDurationSec),
lastSecRemoval: protocol.Timestamp(nowSec - cacheDurationSec*3),
}
v.generateNewHashes(protocol.Timestamp(nowSec+cacheDurationSec), idx, entry)
v.ids = append(v.ids, entry)
} }
v.users = append(v.users, uu)
v.generateNewHashes(protocol.Timestamp(nowSec+cacheDurationSec), uu)
return nil return nil
} }
@ -138,7 +138,36 @@ func (v *TimedUserValidator) Get(userHash []byte) (*protocol.User, protocol.Time
copy(fixedSizeHash[:], userHash) copy(fixedSizeHash[:], userHash)
pair, found := v.userHash[fixedSizeHash] pair, found := v.userHash[fixedSizeHash]
if found { if found {
return v.validUsers[pair.index], protocol.Timestamp(pair.timeInc) + v.baseTime, true return pair.user.user, protocol.Timestamp(pair.timeInc) + v.baseTime, true
} }
return nil, 0, false return nil, 0, false
} }
func (v *TimedUserValidator) Remove(email string) bool {
v.Lock()
defer v.Unlock()
email = strings.ToLower(email)
idx := -1
for i, u := range v.users {
if strings.ToLower(u.user.Email) == email {
idx = i
break
}
}
if idx == -1 {
return false
}
ulen := len(v.users)
if idx < len(v.users) {
v.users[idx] = v.users[ulen-1]
v.users[ulen-1] = nil
v.users = v.users[:ulen-1]
}
return true
}
// Close implements common.Closable.
func (v *TimedUserValidator) Close() error {
return v.task.Close()
}

58
proxy/vmess/vmess_test.go Normal file
View File

@ -0,0 +1,58 @@
package vmess_test
import (
"testing"
"time"
"v2ray.com/core/common"
"v2ray.com/core/common/serial"
"v2ray.com/core/common/uuid"
"v2ray.com/core/common/protocol"
. "v2ray.com/core/proxy/vmess"
. "v2ray.com/ext/assert"
)
func TestUserValidator(t *testing.T) {
assert := With(t)
hasher := protocol.DefaultIDHash
v := NewTimedUserValidator(hasher)
defer common.Close(v)
id := uuid.New()
user := &protocol.User{
Email: "test",
Account: serial.ToTypedMessage(&Account{
Id: id.String(),
AlterId: 8,
}),
}
common.Must(v.Add(user))
{
ts := protocol.Timestamp(time.Now().Unix())
idHash := hasher(id.Bytes())
idHash.Write(ts.Bytes(nil))
userHash := idHash.Sum(nil)
euser, ets, found := v.Get(userHash)
assert(found, IsTrue)
assert(euser.Email, Equals, user.Email)
assert(int64(ets), Equals, int64(ts))
}
{
ts := protocol.Timestamp(time.Now().Add(time.Second * 500).Unix())
idHash := hasher(id.Bytes())
idHash.Write(ts.Bytes(nil))
userHash := idHash.Sum(nil)
euser, _, found := v.Get(userHash)
assert(found, IsFalse)
assert(euser, IsNil)
}
assert(v.Remove(user.Email), IsTrue)
assert(v.Remove(user.Email), IsFalse)
}

View File

@ -25,7 +25,7 @@ echo ${SIGN_KEY_PASS} | gpg --passphrase-fd 0 --batch --import /v2ray/build/sign
curl -L -o /v2ray/build/releases https://api.github.com/repos/v2ray/v2ray-core/releases curl -L -o /v2ray/build/releases https://api.github.com/repos/v2ray/v2ray-core/releases
GO_INSTALL=golang.tar.gz GO_INSTALL=golang.tar.gz
curl -L -o ${GO_INSTALL} https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz curl -L -o ${GO_INSTALL} https://storage.googleapis.com/golang/go1.9.4.linux-amd64.tar.gz
tar -C /usr/local -xzf ${GO_INSTALL} tar -C /usr/local -xzf ${GO_INSTALL}
export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:/usr/local/go/bin
@ -65,7 +65,7 @@ $GOPATH/bin/vbuild --os=openbsd --arch=amd64 --zip --sign #--encrypt
RELBODY="https://www.v2ray.com/chapter_00/01_versions.html" RELBODY="https://www.v2ray.com/chapter_00/01_versions.html"
JSON_DATA=$(echo "{}" | jq -c ".tag_name=\"${RELEASE_TAG}\"") JSON_DATA=$(echo "{}" | jq -c ".tag_name=\"${RELEASE_TAG}\"")
JSON_DATA=$(echo ${JSON_DATA} | jq -c ".prerelease=${PRERELEASE}") JSON_DATA=$(echo ${JSON_DATA} | jq -c ".prerelease=${PRERELEASE}")
JSON_DATA=$(echo ${JSON_DATA} | jq -c ".body=${RELBODY}") JSON_DATA=$(echo ${JSON_DATA} | jq -c ".body=\"${RELBODY}\"")
RELEASE_ID=$(curl --data "${JSON_DATA}" -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/v2ray/v2ray-core/releases | jq ".id") RELEASE_ID=$(curl --data "${JSON_DATA}" -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/v2ray/v2ray-core/releases | jq ".id")
function upload() { function upload() {

115
router.go Normal file
View File

@ -0,0 +1,115 @@
package core
import (
"context"
"sync"
"v2ray.com/core/common"
"v2ray.com/core/common/errors"
"v2ray.com/core/common/net"
"v2ray.com/core/transport/ray"
)
// Dispatcher is a feature that dispatches inbound requests to outbound handlers based on rules.
// Dispatcher is required to be registered in a V2Ray instance to make V2Ray function properly.
type Dispatcher interface {
Feature
// Dispatch returns a Ray for transporting data for the given request.
Dispatch(ctx context.Context, dest net.Destination) (ray.InboundRay, error)
}
type syncDispatcher struct {
sync.RWMutex
Dispatcher
}
func (d *syncDispatcher) Dispatch(ctx context.Context, dest net.Destination) (ray.InboundRay, error) {
d.RLock()
defer d.RUnlock()
if d.Dispatcher == nil {
return nil, newError("Dispatcher not set.").AtError()
}
return d.Dispatcher.Dispatch(ctx, dest)
}
func (d *syncDispatcher) Start() error {
d.RLock()
defer d.RUnlock()
if d.Dispatcher == nil {
return newError("Dispatcher not set.").AtError()
}
return d.Dispatcher.Start()
}
func (d *syncDispatcher) Close() error {
d.RLock()
defer d.RUnlock()
return common.Close(d.Dispatcher)
}
func (d *syncDispatcher) Set(disp Dispatcher) {
d.Lock()
defer d.Unlock()
d.Dispatcher = disp
}
var (
// ErrNoClue is for the situation that existing information is not enough to make a decision. For example, Router may return this error when there is no suitable route.
ErrNoClue = errors.New("not enough information for making a decision")
)
// Router is a feature to choose a outbound tag for the given request.
type Router interface {
Feature
// PickRoute returns a tag of an OutboundHandler based on the given context.
PickRoute(ctx context.Context) (string, error)
}
type syncRouter struct {
sync.RWMutex
Router
}
func (r *syncRouter) PickRoute(ctx context.Context) (string, error) {
r.RLock()
defer r.RUnlock()
if r.Router == nil {
return "", ErrNoClue
}
return r.Router.PickRoute(ctx)
}
func (r *syncRouter) Start() error {
r.RLock()
defer r.RUnlock()
if r.Router == nil {
return nil
}
return r.Router.Start()
}
func (r *syncRouter) Close() error {
r.RLock()
defer r.RUnlock()
return common.Close(r.Router)
}
func (r *syncRouter) Set(router Router) {
r.Lock()
defer r.Unlock()
r.Router = router
}

View File

@ -0,0 +1,130 @@
package scenarios
import (
"context"
"fmt"
"testing"
"google.golang.org/grpc"
"v2ray.com/core"
"v2ray.com/core/app/commander"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/app/proxyman/command"
"v2ray.com/core/app/router"
"v2ray.com/core/common/net"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/dokodemo"
"v2ray.com/core/proxy/freedom"
"v2ray.com/core/testing/servers/tcp"
. "v2ray.com/ext/assert"
)
func TestCommanderRemoveHandler(t *testing.T) {
assert := With(t)
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
assert(err, IsNil)
defer tcpServer.Close()
clientPort := pickPort()
cmdPort := pickPort()
clientConfig := &core.Config{
App: []*serial.TypedMessage{
serial.ToTypedMessage(&commander.Config{
Tag: "api",
Service: []*serial.TypedMessage{
serial.ToTypedMessage(&command.Config{}),
},
}),
serial.ToTypedMessage(&router.Config{
Rule: []*router.RoutingRule{
{
InboundTag: []string{"api"},
Tag: "api",
},
},
}),
},
Inbound: []*core.InboundHandlerConfig{
{
Tag: "d",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(clientPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
NetworkList: &net.NetworkList{
Network: []net.Network{net.Network_TCP},
},
}),
},
{
Tag: "api",
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(cmdPort),
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
NetworkList: &net.NetworkList{
Network: []net.Network{net.Network_TCP},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
Tag: "default-outbound",
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}
servers, err := InitializeServerConfigs(clientConfig)
assert(err, IsNil)
{
conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
IP: []byte{127, 0, 0, 1},
Port: int(clientPort),
})
assert(err, IsNil)
payload := "commander request."
nBytes, err := conn.Write([]byte(payload))
assert(err, IsNil)
assert(nBytes, Equals, len(payload))
response := make([]byte, 1024)
nBytes, err = conn.Read(response)
assert(err, IsNil)
assert(response[:nBytes], Equals, xor([]byte(payload)))
assert(conn.Close(), IsNil)
}
cmdConn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", cmdPort), grpc.WithInsecure())
assert(err, IsNil)
hsClient := command.NewHandlerServiceClient(cmdConn)
resp, err := hsClient.RemoveInbound(context.Background(), &command.RemoveInboundRequest{
Tag: "d",
})
assert(err, IsNil)
assert(resp, IsNotNil)
{
_, err := net.DialTCP("tcp", nil, &net.TCPAddr{
IP: []byte{127, 0, 0, 1},
Port: int(clientPort),
})
assert(err, IsNotNil)
}
CloseAllServers(servers)
}

View File

@ -13,14 +13,17 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"v2ray.com/core" "v2ray.com/core"
"v2ray.com/core/app/dispatcher"
"v2ray.com/core/app/proxyman"
"v2ray.com/core/common" "v2ray.com/core/common"
"v2ray.com/core/common/log" "v2ray.com/core/common/log"
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/retry" "v2ray.com/core/common/retry"
"v2ray.com/core/common/serial"
) )
func pickPort() net.Port { func pickPort() net.Port {
listener, err := net.Listen("tcp4", ":0") listener, err := net.Listen("tcp4", "127.0.0.1:0")
common.Must(err) common.Must(err)
defer listener.Close() defer listener.Close()
@ -70,6 +73,7 @@ func InitializeServerConfig(config *core.Config) (*exec.Cmd, error) {
return nil, err return nil, err
} }
config = withDefaultApps(config)
configBytes, err := proto.Marshal(config) configBytes, err := proto.Marshal(config)
if err != nil { if err != nil {
return nil, err return nil, err
@ -128,3 +132,10 @@ func CloseAllServers(servers []*exec.Cmd) {
Content: "All server closed.", Content: "All server closed.",
}) })
} }
func withDefaultApps(config *core.Config) *core.Config {
config.App = append(config.App, serial.ToTypedMessage(&dispatcher.Config{}))
config.App = append(config.App, serial.ToTypedMessage(&proxyman.InboundConfig{}))
config.App = append(config.App, serial.ToTypedMessage(&proxyman.OutboundConfig{}))
return config
}

View File

@ -51,7 +51,7 @@ func TestResolveIP(t *testing.T) {
}, },
}), }),
}, },
Inbound: []*proxyman.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortRange: net.SinglePortRange(serverPort),
@ -67,7 +67,7 @@ func TestResolveIP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*proxyman.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}), ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
}, },

View File

@ -40,7 +40,7 @@ func TestDokodemoTCP(t *testing.T) {
ErrorLogType: log.LogType_Console, ErrorLogType: log.LogType_Console,
}), }),
}, },
Inbound: []*proxyman.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortRange: net.SinglePortRange(serverPort),
@ -57,7 +57,7 @@ func TestDokodemoTCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*proxyman.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
@ -73,7 +73,7 @@ func TestDokodemoTCP(t *testing.T) {
ErrorLogType: log.LogType_Console, ErrorLogType: log.LogType_Console,
}), }),
}, },
Inbound: []*proxyman.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &net.PortRange{From: clientPort, To: clientPort + clientPortRange}, PortRange: &net.PortRange{From: clientPort, To: clientPort + clientPortRange},
@ -88,7 +88,7 @@ func TestDokodemoTCP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*proxyman.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{
@ -147,7 +147,7 @@ func TestDokodemoUDP(t *testing.T) {
userID := protocol.NewID(uuid.New()) userID := protocol.NewID(uuid.New())
serverPort := pickPort() serverPort := pickPort()
serverConfig := &core.Config{ serverConfig := &core.Config{
Inbound: []*proxyman.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: net.SinglePortRange(serverPort), PortRange: net.SinglePortRange(serverPort),
@ -164,7 +164,7 @@ func TestDokodemoUDP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*proxyman.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&freedom.Config{}), ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
}, },
@ -174,7 +174,7 @@ func TestDokodemoUDP(t *testing.T) {
clientPort := uint32(pickPort()) clientPort := uint32(pickPort())
clientPortRange := uint32(5) clientPortRange := uint32(5)
clientConfig := &core.Config{ clientConfig := &core.Config{
Inbound: []*proxyman.InboundHandlerConfig{ Inbound: []*core.InboundHandlerConfig{
{ {
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{ ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortRange: &net.PortRange{From: clientPort, To: clientPort + clientPortRange}, PortRange: &net.PortRange{From: clientPort, To: clientPort + clientPortRange},
@ -189,7 +189,7 @@ func TestDokodemoUDP(t *testing.T) {
}), }),
}, },
}, },
Outbound: []*proxyman.OutboundHandlerConfig{ Outbound: []*core.OutboundHandlerConfig{
{ {
ProxySettings: serial.ToTypedMessage(&outbound.Config{ ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{ Receiver: []*protocol.ServerEndpoint{

Some files were not shown because too many files have changed in this diff Show More