mirror of
https://github.com/v2fly/v2ray-core.git
synced 2024-12-22 01:57:12 -05:00
commit
693c9bda49
@ -1,7 +1,7 @@
|
||||
sudo: required
|
||||
language: go
|
||||
go:
|
||||
- 1.9.2
|
||||
- 1.9.4
|
||||
go_import_path: v2ray.com/core
|
||||
git:
|
||||
depth: 5
|
||||
|
@ -1,4 +0,0 @@
|
||||
package api
|
||||
|
||||
type ApiServer struct {
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"v2ray.com/core/common/net"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
DirectPort net.Port
|
||||
}
|
@ -1,3 +1 @@
|
||||
package app
|
||||
|
||||
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg app -path App
|
||||
|
95
app/commander/commander.go
Normal file
95
app/commander/commander.go
Normal 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))
|
||||
}))
|
||||
}
|
68
app/commander/config.pb.go
Normal file
68
app/commander/config.pb.go
Normal 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,
|
||||
}
|
17
app/commander/config.proto
Normal file
17
app/commander/config.proto
Normal 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;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package impl
|
||||
package commander
|
||||
|
||||
import "v2ray.com/core/common/errors"
|
||||
|
||||
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
101
app/commander/outbound.go
Normal 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
9
app/commander/service.go
Normal file
@ -0,0 +1,9 @@
|
||||
package commander
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
Register(*grpc.Server)
|
||||
}
|
@ -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
|
||||
|
||||
@ -6,10 +6,8 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/app/router"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/net"
|
||||
@ -21,31 +19,27 @@ var (
|
||||
errSniffingTimeout = newError("timeout on sniffing")
|
||||
)
|
||||
|
||||
var (
|
||||
_ app.Application = (*DefaultDispatcher)(nil)
|
||||
)
|
||||
|
||||
// DefaultDispatcher is a default implementation of Dispatcher.
|
||||
type DefaultDispatcher struct {
|
||||
ohm proxyman.OutboundHandlerManager
|
||||
router *router.Router
|
||||
ohm core.OutboundHandlerManager
|
||||
router core.Router
|
||||
}
|
||||
|
||||
// NewDefaultDispatcher create a new DefaultDispatcher.
|
||||
func NewDefaultDispatcher(ctx context.Context, config *dispatcher.Config) (*DefaultDispatcher, error) {
|
||||
space := app.SpaceFromContext(ctx)
|
||||
if space == nil {
|
||||
return nil, newError("no space in context")
|
||||
func NewDefaultDispatcher(ctx context.Context, config *Config) (*DefaultDispatcher, error) {
|
||||
v := core.FromContext(ctx)
|
||||
if v == nil {
|
||||
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
|
||||
}
|
||||
|
||||
@ -55,14 +49,9 @@ func (*DefaultDispatcher) Start() error {
|
||||
}
|
||||
|
||||
// Close implements app.Application.
|
||||
func (*DefaultDispatcher) Close() {}
|
||||
func (*DefaultDispatcher) Close() error { return nil }
|
||||
|
||||
// Interface implements app.Application.
|
||||
func (*DefaultDispatcher) Interface() interface{} {
|
||||
return (*dispatcher.Interface)(nil)
|
||||
}
|
||||
|
||||
// Dispatch implements Dispatcher.Interface.
|
||||
// Dispatch implements core.Dispatcher.
|
||||
func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (ray.InboundRay, error) {
|
||||
if !destination.IsValid() {
|
||||
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) {
|
||||
dispatcher := d.ohm.GetDefaultHandler()
|
||||
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 {
|
||||
newError("taking detour [", tag, "] for [", destination, "]").WriteToLog()
|
||||
dispatcher = handler
|
||||
@ -135,7 +124,7 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, outbound ray.Out
|
||||
}
|
||||
|
||||
func init() {
|
||||
common.Must(common.RegisterConfig((*dispatcher.Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
return NewDefaultDispatcher(ctx, config.(*dispatcher.Config))
|
||||
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
return NewDefaultDispatcher(ctx, config.(*Config))
|
||||
}))
|
||||
}
|
@ -1,21 +1,3 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"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
|
||||
}
|
||||
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg dispatcher -path App,Dispatcher
|
||||
|
7
app/dispatcher/errors.generated.go
Normal file
7
app/dispatcher/errors.generated.go
Normal 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")
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package impl
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"bytes"
|
@ -1,11 +1,10 @@
|
||||
package impl_test
|
||||
package dispatcher_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
|
||||
. "v2ray.com/core/app/dispatcher/impl"
|
||||
. "v2ray.com/ext/assert"
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/dice"
|
||||
"v2ray.com/core/common/net"
|
||||
@ -48,7 +48,7 @@ type UDPNameServer struct {
|
||||
nextCleanup time.Time
|
||||
}
|
||||
|
||||
func NewUDPNameServer(address net.Destination, dispatcher dispatcher.Interface) *UDPNameServer {
|
||||
func NewUDPNameServer(address net.Destination, dispatcher core.Dispatcher) *UDPNameServer {
|
||||
s := &UDPNameServer{
|
||||
address: address,
|
||||
requests: make(map[uint16]*PendingRequest),
|
||||
@ -216,8 +216,7 @@ func (*LocalNameServer) QueryA(domain string) <-chan *ARecord {
|
||||
go func() {
|
||||
defer close(response)
|
||||
|
||||
resolver := net.SystemIPResolver()
|
||||
ips, err := resolver.LookupIP(domain)
|
||||
ips, err := net.LookupIP(domain)
|
||||
if err != nil {
|
||||
newError("failed to lookup IPs for domain ", domain).Base(err).AtWarning().WriteToLog()
|
||||
return
|
||||
|
@ -1,6 +1,6 @@
|
||||
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 (
|
||||
"context"
|
||||
@ -8,10 +8,10 @@ import (
|
||||
"time"
|
||||
|
||||
dnsmsg "github.com/miekg/dns"
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/signal"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -38,56 +38,60 @@ type Server struct {
|
||||
hosts map[string]net.IP
|
||||
records map[string]*DomainRecord
|
||||
servers []NameServer
|
||||
task *signal.PeriodicTask
|
||||
}
|
||||
|
||||
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{
|
||||
records: make(map[string]*DomainRecord),
|
||||
servers: make([]NameServer, len(config.NameServers)),
|
||||
hosts: config.GetInternalHosts(),
|
||||
}
|
||||
space.On(app.SpaceInitializing, func(interface{}) error {
|
||||
disp := dispatcher.FromSpace(space)
|
||||
if disp == nil {
|
||||
return newError("dispatcher is not found in the space")
|
||||
}
|
||||
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, disp)
|
||||
}
|
||||
server.task = &signal.PeriodicTask{
|
||||
Interval: time.Minute * 10,
|
||||
Execute: func() error {
|
||||
server.cleanup()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
v := core.FromContext(ctx)
|
||||
if v == nil {
|
||||
return nil, newError("V is not in context.")
|
||||
}
|
||||
|
||||
if err := v.RegisterFeature((*core.DNSClient)(nil), server); err != nil {
|
||||
return nil, newError("unable to register DNSClient.").Base(err)
|
||||
}
|
||||
|
||||
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{})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if len(config.NameServers) == 0 {
|
||||
server.servers = append(server.servers, &LocalNameServer{})
|
||||
}
|
||||
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func (*Server) Interface() interface{} {
|
||||
return (*Server)(nil)
|
||||
}
|
||||
|
||||
// Start implements common.Runnable.
|
||||
func (s *Server) Start() error {
|
||||
net.RegisterIPResolver(s)
|
||||
return nil
|
||||
return s.task.Start()
|
||||
}
|
||||
|
||||
func (*Server) Close() {
|
||||
net.RegisterIPResolver(net.SystemIPResolver())
|
||||
// Close implements common.Runnable.
|
||||
func (s *Server) Close() error {
|
||||
return s.task.Close()
|
||||
}
|
||||
|
||||
func (s *Server) GetCached(domain string) []net.IP {
|
||||
@ -101,18 +105,12 @@ func (s *Server) GetCached(domain string) []net.IP {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) tryCleanup() {
|
||||
func (s *Server) cleanup() {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if len(s.records) > 256 {
|
||||
domains := make([]string, 0, 256)
|
||||
for d, r := range s.records {
|
||||
if r.Expired() {
|
||||
domains = append(domains, d)
|
||||
}
|
||||
}
|
||||
for _, d := range domains {
|
||||
for d, r := range s.records {
|
||||
if r.Expired() {
|
||||
delete(s.records, d)
|
||||
}
|
||||
}
|
||||
@ -129,8 +127,6 @@ func (s *Server) LookupIP(domain string) ([]net.IP, error) {
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
s.tryCleanup()
|
||||
|
||||
for _, server := range s.servers {
|
||||
response := server.QueryA(domain)
|
||||
select {
|
||||
|
@ -1,18 +1,14 @@
|
||||
package dns_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
_ "v2ray.com/core/app/dispatcher/impl"
|
||||
. "v2ray.com/core/app/dns"
|
||||
"v2ray.com/core/app/policy"
|
||||
_ "v2ray.com/core/app/policy/manager"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
_ "v2ray.com/core/app/proxyman/outbound"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/serial"
|
||||
"v2ray.com/core/proxy/freedom"
|
||||
@ -54,50 +50,50 @@ func TestUDPServer(t *testing.T) {
|
||||
|
||||
go dnsServer.ListenAndServe()
|
||||
|
||||
config := &Config{
|
||||
NameServers: []*net.Endpoint{
|
||||
{
|
||||
Network: net.Network_UDP,
|
||||
Address: &net.IPOrDomain{
|
||||
Address: &net.IPOrDomain_Ip{
|
||||
Ip: []byte{127, 0, 0, 1},
|
||||
config := &core.Config{
|
||||
App: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&Config{
|
||||
NameServers: []*net.Endpoint{
|
||||
{
|
||||
Network: net.Network_UDP,
|
||||
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()
|
||||
space := app.NewSpace()
|
||||
v, err := core.New(config)
|
||||
assert(err, IsNil)
|
||||
|
||||
ctx = app.ContextWithSpace(ctx, space)
|
||||
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{}))
|
||||
client := v.DNSClient()
|
||||
|
||||
om := proxyman.OutboundHandlerManagerFromSpace(space)
|
||||
om.AddHandler(ctx, &proxyman.OutboundHandlerConfig{
|
||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||
})
|
||||
|
||||
common.Must(space.Initialize())
|
||||
common.Must(space.Start())
|
||||
|
||||
ips, err := net.LookupIP("google.com")
|
||||
ips, err := client.LookupIP("google.com")
|
||||
assert(err, IsNil)
|
||||
assert(len(ips), Equals, 1)
|
||||
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(len(ips), Equals, 1)
|
||||
assert([]byte(ips[0]), Equals, []byte{9, 9, 9, 9})
|
||||
|
||||
dnsServer.Shutdown()
|
||||
|
||||
ips, err = net.LookupIP("google.com")
|
||||
ips, err = client.LookupIP("google.com")
|
||||
assert(err, IsNil)
|
||||
assert(len(ips), Equals, 1)
|
||||
assert([]byte(ips[0]), Equals, []byte{8, 8, 8, 8})
|
||||
|
@ -37,11 +37,6 @@ func New(ctx context.Context, config *Config) (*Instance, error) {
|
||||
return g, nil
|
||||
}
|
||||
|
||||
// Interface implements app.Application.Interface().
|
||||
func (*Instance) Interface() interface{} {
|
||||
return (*Instance)(nil)
|
||||
}
|
||||
|
||||
func (g *Instance) initAccessLogger() error {
|
||||
switch g.config.AccessLogType {
|
||||
case LogType_File:
|
||||
@ -108,11 +103,13 @@ func (g *Instance) Handle(msg log.Message) {
|
||||
}
|
||||
|
||||
// Close implement app.Application.Close().
|
||||
func (g *Instance) Close() {
|
||||
func (g *Instance) Close() error {
|
||||
g.Lock()
|
||||
defer g.Unlock()
|
||||
|
||||
g.active = false
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -2,10 +2,15 @@ package policy
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"v2ray.com/core"
|
||||
)
|
||||
|
||||
// Duration converts Second to time.Duration.
|
||||
func (s *Second) Duration() time.Duration {
|
||||
if s == nil {
|
||||
return 0
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
package app
|
||||
package policy
|
||||
|
||||
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
62
app/policy/manager.go
Normal 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))
|
||||
}))
|
||||
}
|
@ -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))
|
||||
}))
|
||||
}
|
@ -1,20 +1,3 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"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)
|
||||
}
|
||||
//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg policy -path App,Policy
|
||||
|
148
app/proxyman/command/command.go
Normal file
148
app/proxyman/command/command.go
Normal 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
|
||||
}))
|
||||
}
|
520
app/proxyman/command/command.pb.go
Normal file
520
app/proxyman/command/command.pb.go
Normal 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,
|
||||
}
|
80
app/proxyman/command/command.proto
Normal file
80
app/proxyman/command/command.proto
Normal 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 {}
|
3
app/proxyman/command/doc.go
Normal file
3
app/proxyman/command/doc.go
Normal 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
|
7
app/proxyman/command/errors.generated.go
Normal file
7
app/proxyman/command/errors.generated.go
Normal 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")
|
||||
}
|
@ -1,11 +1,5 @@
|
||||
package proxyman
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"v2ray.com/core/proxy"
|
||||
)
|
||||
|
||||
func (s *AllocationStrategy) GetConcurrencyValue() uint32 {
|
||||
if s == nil || s.Concurrency == nil {
|
||||
return 3
|
||||
@ -19,14 +13,3 @@ func (s *AllocationStrategy) GetRefreshValue() uint32 {
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package proxyman
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
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_net1 "v2ray.com/core/common/net"
|
||||
import v2ray_core_transport_internet "v2ray.com/core/transport/internet"
|
||||
@ -211,45 +210,13 @@ func (m *ReceiverConfig) GetDomainOverride() []KnownProtocols {
|
||||
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 {
|
||||
}
|
||||
|
||||
func (m *OutboundConfig) Reset() { *m = OutboundConfig{} }
|
||||
func (m *OutboundConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*OutboundConfig) ProtoMessage() {}
|
||||
func (*OutboundConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
|
||||
func (*OutboundConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||
|
||||
type SenderConfig struct {
|
||||
// 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) String() string { return proto.CompactTextString(m) }
|
||||
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 {
|
||||
if m != nil {
|
||||
@ -292,54 +259,6 @@ func (m *SenderConfig) GetMultiplexSettings() *MultiplexingConfig {
|
||||
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 {
|
||||
// Whether or not Mux is enabled.
|
||||
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) String() string { return proto.CompactTextString(m) }
|
||||
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 {
|
||||
if m != nil {
|
||||
@ -372,10 +291,8 @@ func init() {
|
||||
proto.RegisterType((*AllocationStrategy_AllocationStrategyConcurrency)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyConcurrency")
|
||||
proto.RegisterType((*AllocationStrategy_AllocationStrategyRefresh)(nil), "v2ray.core.app.proxyman.AllocationStrategy.AllocationStrategyRefresh")
|
||||
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((*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.RegisterEnum("v2ray.core.app.proxyman.KnownProtocols", KnownProtocols_name, KnownProtocols_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) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 822 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xd1, 0x8e, 0xdb, 0x44,
|
||||
0x14, 0xad, 0xe3, 0x34, 0xc9, 0xde, 0xed, 0x7a, 0xdd, 0xa1, 0xd0, 0x10, 0x40, 0x0a, 0x01, 0xd1,
|
||||
0xa8, 0x20, 0xa7, 0xa4, 0xe2, 0x81, 0x27, 0x58, 0x76, 0x2b, 0x75, 0x81, 0x55, 0xcc, 0x24, 0xe2,
|
||||
0xa1, 0x42, 0xb2, 0x66, 0xed, 0xa9, 0x19, 0x61, 0xcf, 0x58, 0x33, 0x93, 0x74, 0xfd, 0x4b, 0x7c,
|
||||
0x05, 0x8f, 0x3c, 0xf0, 0x05, 0xfc, 0x0a, 0x2f, 0xc8, 0x9e, 0x71, 0x76, 0xb7, 0x49, 0x5a, 0x96,
|
||||
0xaa, 0x6f, 0x33, 0xc9, 0x39, 0xc7, 0x73, 0xcf, 0x3d, 0x77, 0x06, 0xc6, 0xab, 0xa9, 0x24, 0x65,
|
||||
0x10, 0x8b, 0x7c, 0x12, 0x0b, 0x49, 0x27, 0xa4, 0x28, 0x26, 0x85, 0x14, 0x17, 0x65, 0x4e, 0xf8,
|
||||
0x24, 0x16, 0xfc, 0x39, 0x4b, 0x83, 0x42, 0x0a, 0x2d, 0xd0, 0xfd, 0x06, 0x29, 0x69, 0x40, 0x8a,
|
||||
0x22, 0x68, 0x50, 0x83, 0x47, 0x2f, 0x49, 0xc4, 0x22, 0xcf, 0x05, 0x9f, 0x28, 0x2a, 0x19, 0xc9,
|
||||
0x26, 0xba, 0x2c, 0x68, 0x12, 0xe5, 0x54, 0x29, 0x92, 0x52, 0x23, 0x35, 0x78, 0xb0, 0x9d, 0xc1,
|
||||
0xa9, 0x9e, 0x90, 0x24, 0x91, 0x54, 0x29, 0x0b, 0xfc, 0x74, 0x37, 0xb0, 0x10, 0x52, 0x5b, 0x54,
|
||||
0xf0, 0x12, 0x4a, 0x4b, 0xc2, 0x55, 0xf5, 0xff, 0x84, 0x71, 0x4d, 0x65, 0x85, 0xbe, 0x5a, 0xc9,
|
||||
0xe8, 0x10, 0x0e, 0x4e, 0xf9, 0xb9, 0x58, 0xf2, 0xe4, 0xb8, 0xfe, 0x79, 0xf4, 0x87, 0x0b, 0xe8,
|
||||
0x28, 0xcb, 0x44, 0x4c, 0x34, 0x13, 0x7c, 0xae, 0x25, 0xd1, 0x34, 0x2d, 0xd1, 0x09, 0xb4, 0xab,
|
||||
0xd3, 0xf7, 0x9d, 0xa1, 0x33, 0xf6, 0xa6, 0x8f, 0x82, 0x1d, 0x06, 0x04, 0x9b, 0xd4, 0x60, 0x51,
|
||||
0x16, 0x14, 0xd7, 0x6c, 0xf4, 0x1b, 0xec, 0xc7, 0x82, 0xc7, 0x4b, 0x29, 0x29, 0x8f, 0xcb, 0x7e,
|
||||
0x6b, 0xe8, 0x8c, 0xf7, 0xa7, 0xa7, 0x37, 0x11, 0xdb, 0xfc, 0xe9, 0xf8, 0x52, 0x10, 0x5f, 0x55,
|
||||
0x47, 0x11, 0x74, 0x25, 0x7d, 0x2e, 0xa9, 0xfa, 0xb5, 0xef, 0xd6, 0x1f, 0x7a, 0xf2, 0x66, 0x1f,
|
||||
0xc2, 0x46, 0x0c, 0x37, 0xaa, 0x83, 0xaf, 0xe0, 0xa3, 0x57, 0x1e, 0x07, 0xdd, 0x83, 0xdb, 0x2b,
|
||||
0x92, 0x2d, 0x8d, 0x6b, 0x07, 0xd8, 0x6c, 0x06, 0x5f, 0xc2, 0xfb, 0x3b, 0xc5, 0xb7, 0x53, 0x46,
|
||||
0x5f, 0x40, 0xbb, 0x72, 0x11, 0x01, 0x74, 0x8e, 0xb2, 0x17, 0xa4, 0x54, 0xfe, 0xad, 0x6a, 0x8d,
|
||||
0x09, 0x4f, 0x44, 0xee, 0x3b, 0xe8, 0x0e, 0xf4, 0x9e, 0x5c, 0x54, 0xed, 0x25, 0x99, 0xdf, 0x1a,
|
||||
0xfd, 0xed, 0x82, 0x87, 0x69, 0x4c, 0xd9, 0x8a, 0x4a, 0xd3, 0x55, 0xf4, 0x0d, 0x40, 0x15, 0x82,
|
||||
0x48, 0x12, 0x9e, 0x1a, 0xed, 0xfd, 0xe9, 0xf0, 0xaa, 0x1d, 0x26, 0x4d, 0x01, 0xa7, 0x3a, 0x08,
|
||||
0x85, 0xd4, 0xb8, 0xc2, 0xe1, 0xbd, 0xa2, 0x59, 0xa2, 0xaf, 0xa1, 0x93, 0x31, 0xa5, 0x29, 0xb7,
|
||||
0x4d, 0xfb, 0x78, 0x07, 0xf9, 0x34, 0x9c, 0xc9, 0x13, 0x91, 0x13, 0xc6, 0xb1, 0x25, 0xa0, 0x5f,
|
||||
0xe0, 0x1d, 0xb2, 0xae, 0x37, 0x52, 0xb6, 0x60, 0xdb, 0x93, 0xcf, 0x6f, 0xd0, 0x13, 0x8c, 0xc8,
|
||||
0x66, 0x30, 0x17, 0x70, 0xa8, 0xb4, 0xa4, 0x24, 0x8f, 0x14, 0xd5, 0x9a, 0xf1, 0x54, 0xf5, 0xdb,
|
||||
0x9b, 0xca, 0xeb, 0x31, 0x08, 0x9a, 0x31, 0x08, 0xe6, 0x35, 0xcb, 0xf8, 0x83, 0x3d, 0xa3, 0x31,
|
||||
0xb7, 0x12, 0xe8, 0x5b, 0xf8, 0x50, 0x1a, 0x07, 0x23, 0x21, 0x59, 0xca, 0x38, 0xc9, 0xa2, 0x84,
|
||||
0x2a, 0xcd, 0x78, 0xfd, 0xf5, 0xfe, 0xed, 0xa1, 0x33, 0xee, 0xe1, 0x81, 0xc5, 0xcc, 0x2c, 0xe4,
|
||||
0xe4, 0x12, 0x81, 0x42, 0x38, 0x4c, 0x6a, 0x1f, 0x22, 0xb1, 0xa2, 0x52, 0xb2, 0x84, 0xf6, 0xbb,
|
||||
0x43, 0x77, 0xec, 0x4d, 0x1f, 0xec, 0xac, 0xf8, 0x07, 0x2e, 0x5e, 0xf0, 0xb0, 0x1a, 0xcb, 0x58,
|
||||
0x64, 0x0a, 0x7b, 0x86, 0x3f, 0xb3, 0xf4, 0xef, 0xdb, 0xbd, 0x8e, 0xdf, 0x1d, 0xfd, 0xe5, 0xc0,
|
||||
0x3d, 0x3b, 0xb1, 0x4f, 0x09, 0x4f, 0xb2, 0x75, 0x8b, 0x7d, 0x70, 0x35, 0x49, 0xeb, 0xde, 0xee,
|
||||
0xe1, 0x6a, 0x89, 0xe6, 0x70, 0xd7, 0x1e, 0x50, 0x5e, 0x9a, 0x63, 0xda, 0xf7, 0xd9, 0x96, 0xf6,
|
||||
0x99, 0x4b, 0xaa, 0x1e, 0xd7, 0xe4, 0xcc, 0xdc, 0x51, 0xd8, 0x6f, 0x04, 0xd6, 0xce, 0x9c, 0x81,
|
||||
0x57, 0x1f, 0xf8, 0x52, 0xd1, 0xbd, 0x91, 0xe2, 0x41, 0xcd, 0x6e, 0xe4, 0x46, 0x3e, 0x78, 0xb3,
|
||||
0xa5, 0xbe, 0x7a, 0x01, 0xfd, 0xd9, 0x82, 0x3b, 0x73, 0xca, 0x93, 0x75, 0x61, 0x8f, 0xc1, 0x5d,
|
||||
0x31, 0x62, 0x43, 0xfb, 0x1f, 0x72, 0x57, 0xa1, 0xb7, 0xc5, 0xa2, 0xf5, 0xe6, 0xb1, 0xf8, 0x69,
|
||||
0x47, 0xf1, 0x0f, 0x5f, 0x23, 0x1a, 0x56, 0x24, 0xab, 0x79, 0xdd, 0x00, 0xf4, 0x0c, 0x50, 0xbe,
|
||||
0xcc, 0x34, 0x2b, 0x32, 0x7a, 0xf1, 0xca, 0x08, 0x5f, 0x8b, 0xca, 0x59, 0x43, 0x61, 0x3c, 0xb5,
|
||||
0xba, 0x77, 0xd7, 0x32, 0x6b, 0x73, 0xff, 0x71, 0xe0, 0xdd, 0xc6, 0xdd, 0xd7, 0x85, 0x65, 0x06,
|
||||
0x87, 0xaa, 0x76, 0xfd, 0xff, 0x46, 0xc5, 0x33, 0xf4, 0xb7, 0x14, 0x14, 0xf4, 0x1e, 0x74, 0xe8,
|
||||
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,
|
||||
// 691 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x5d, 0x6f, 0xd3, 0x3a,
|
||||
0x1c, 0xc6, 0x97, 0xb6, 0x6b, 0x7b, 0xfe, 0x5b, 0xb3, 0x1c, 0x9f, 0x23, 0x2d, 0xa7, 0x07, 0xa4,
|
||||
0x52, 0x90, 0x56, 0x0d, 0x94, 0x40, 0x27, 0x2e, 0xb8, 0x82, 0xd1, 0x4d, 0x62, 0xbc, 0xa8, 0xc1,
|
||||
0xad, 0xb8, 0x98, 0x90, 0x22, 0x2f, 0xf1, 0x8a, 0x45, 0x62, 0x47, 0x8e, 0xdb, 0x2d, 0x5f, 0x89,
|
||||
0x4f, 0xc1, 0x25, 0x9f, 0x81, 0x4f, 0x83, 0xf2, 0xd6, 0x75, 0xeb, 0x3a, 0x98, 0x76, 0xe7, 0xa6,
|
||||
0xcf, 0xf3, 0xb3, 0xfd, 0x3c, 0xb6, 0xa1, 0x37, 0xeb, 0x4b, 0x92, 0x58, 0x9e, 0x08, 0x6d, 0x4f,
|
||||
0x48, 0x6a, 0x93, 0x28, 0xb2, 0x23, 0x29, 0xce, 0x93, 0x90, 0x70, 0xdb, 0x13, 0xfc, 0x94, 0x4d,
|
||||
0xac, 0x48, 0x0a, 0x25, 0xd0, 0x76, 0xa9, 0x94, 0xd4, 0x22, 0x51, 0x64, 0x95, 0xaa, 0xf6, 0xce,
|
||||
0x15, 0x84, 0x27, 0xc2, 0x50, 0x70, 0x9b, 0x53, 0x65, 0x13, 0xdf, 0x97, 0x34, 0x8e, 0x73, 0x42,
|
||||
0xfb, 0xd1, 0x6a, 0x61, 0x24, 0xa4, 0x2a, 0x54, 0xd6, 0x15, 0x95, 0x92, 0x84, 0xc7, 0xe9, 0xff,
|
||||
0x36, 0xe3, 0x8a, 0xca, 0x54, 0xbd, 0xb8, 0xae, 0xee, 0x16, 0xb4, 0x8e, 0xf8, 0x89, 0x98, 0x72,
|
||||
0x7f, 0x90, 0x7d, 0xee, 0x7e, 0xaf, 0x02, 0xda, 0x0f, 0x02, 0xe1, 0x11, 0xc5, 0x04, 0x1f, 0x29,
|
||||
0x49, 0x14, 0x9d, 0x24, 0xe8, 0x00, 0x6a, 0x2a, 0x89, 0xa8, 0xa9, 0x75, 0xb4, 0x9e, 0xde, 0x7f,
|
||||
0x6a, 0xad, 0xd8, 0x8e, 0xb5, 0x6c, 0xb5, 0xc6, 0x49, 0x44, 0x71, 0xe6, 0x46, 0x5f, 0x61, 0xc3,
|
||||
0x13, 0xdc, 0x9b, 0x4a, 0x49, 0xb9, 0x97, 0x98, 0x95, 0x8e, 0xd6, 0xdb, 0xe8, 0x1f, 0xdd, 0x06,
|
||||
0xb6, 0xfc, 0x69, 0x70, 0x01, 0xc4, 0x8b, 0x74, 0xe4, 0x42, 0x43, 0xd2, 0x53, 0x49, 0xe3, 0x2f,
|
||||
0x66, 0x35, 0x9b, 0xe8, 0xf0, 0x6e, 0x13, 0xe1, 0x1c, 0x86, 0x4b, 0x6a, 0xfb, 0x39, 0xdc, 0xbf,
|
||||
0x71, 0x39, 0xe8, 0x5f, 0x58, 0x9f, 0x91, 0x60, 0x9a, 0xa7, 0xd6, 0xc2, 0xf9, 0x8f, 0xf6, 0x33,
|
||||
0xf8, 0x6f, 0x25, 0xfc, 0x7a, 0x4b, 0xf7, 0x09, 0xd4, 0xd2, 0x14, 0x11, 0x40, 0x7d, 0x3f, 0x38,
|
||||
0x23, 0x49, 0x6c, 0xac, 0xa5, 0x63, 0x4c, 0xb8, 0x2f, 0x42, 0x43, 0x43, 0x9b, 0xd0, 0x3c, 0x3c,
|
||||
0x4f, 0xeb, 0x25, 0x81, 0x51, 0xe9, 0xfe, 0xac, 0x82, 0x8e, 0xa9, 0x47, 0xd9, 0x8c, 0xca, 0xbc,
|
||||
0x55, 0xf4, 0x12, 0x20, 0x3d, 0x04, 0xae, 0x24, 0x7c, 0x92, 0xb3, 0x37, 0xfa, 0x9d, 0xc5, 0x38,
|
||||
0xf2, 0xd3, 0x64, 0x71, 0xaa, 0x2c, 0x47, 0x48, 0x85, 0x53, 0x1d, 0xfe, 0x2b, 0x2a, 0x87, 0xe8,
|
||||
0x05, 0xd4, 0x03, 0x16, 0x2b, 0xca, 0x8b, 0xd2, 0x1e, 0xac, 0x30, 0x1f, 0x39, 0x43, 0x79, 0x20,
|
||||
0x42, 0xc2, 0x38, 0x2e, 0x0c, 0xe8, 0x33, 0xfc, 0x43, 0xe6, 0xfb, 0x75, 0xe3, 0x62, 0xc3, 0x45,
|
||||
0x27, 0x8f, 0x6f, 0xd1, 0x09, 0x46, 0x64, 0xf9, 0x60, 0x8e, 0x61, 0x2b, 0x56, 0x92, 0x92, 0xd0,
|
||||
0x8d, 0xa9, 0x52, 0x8c, 0x4f, 0x62, 0xb3, 0xb6, 0x4c, 0x9e, 0x5f, 0x03, 0xab, 0xbc, 0x06, 0xd6,
|
||||
0x28, 0x73, 0xe5, 0xf9, 0x60, 0x3d, 0x67, 0x8c, 0x0a, 0x04, 0x7a, 0x05, 0xf7, 0x64, 0x9e, 0xa0,
|
||||
0x2b, 0x24, 0x9b, 0x30, 0x4e, 0x02, 0xd7, 0xa7, 0xb1, 0x62, 0x3c, 0x9b, 0xdd, 0x5c, 0xef, 0x68,
|
||||
0xbd, 0x26, 0x6e, 0x17, 0x9a, 0x61, 0x21, 0x39, 0xb8, 0x50, 0x20, 0x07, 0xb6, 0xfc, 0x2c, 0x07,
|
||||
0x57, 0xcc, 0xa8, 0x94, 0xcc, 0xa7, 0x66, 0xa3, 0x53, 0xed, 0xe9, 0xfd, 0x9d, 0x95, 0x3b, 0x7e,
|
||||
0xc7, 0xc5, 0x19, 0x77, 0xd2, 0x6b, 0xe9, 0x89, 0x20, 0xc6, 0x7a, 0xee, 0x1f, 0x16, 0xf6, 0xb7,
|
||||
0xb5, 0x66, 0xdd, 0x68, 0x74, 0x0d, 0xd0, 0x87, 0x53, 0xb5, 0x78, 0x63, 0x7f, 0x54, 0x60, 0x73,
|
||||
0x44, 0xb9, 0x3f, 0x2f, 0x7b, 0x0f, 0xaa, 0x33, 0x46, 0x8a, 0x96, 0xff, 0xa0, 0xa8, 0x54, 0x7d,
|
||||
0x5d, 0x8e, 0x95, 0xbb, 0xe7, 0xf8, 0x11, 0xf4, 0x6c, 0x7b, 0x17, 0xd0, 0xbc, 0xf6, 0xdd, 0xdf,
|
||||
0x40, 0x9d, 0xd4, 0x54, 0x30, 0x5b, 0x19, 0x61, 0x8e, 0x3c, 0x06, 0x14, 0x4e, 0x03, 0xc5, 0xa2,
|
||||
0x80, 0x9e, 0xdf, 0xd8, 0xf9, 0xa5, 0x6c, 0x3f, 0x94, 0x16, 0xc6, 0x27, 0x05, 0xf7, 0xef, 0x39,
|
||||
0xa6, 0x64, 0x77, 0x1d, 0x40, 0xcb, 0x42, 0x64, 0x42, 0x83, 0x72, 0x72, 0x12, 0x50, 0x3f, 0xcb,
|
||||
0xb4, 0x89, 0xcb, 0x9f, 0xa8, 0xb3, 0xfc, 0x9e, 0xb5, 0x2e, 0x3d, 0x42, 0xbb, 0x0f, 0x41, 0xbf,
|
||||
0x5c, 0x2b, 0x6a, 0x42, 0xed, 0xcd, 0x78, 0xec, 0x18, 0x6b, 0xa8, 0x01, 0xd5, 0xf1, 0xfb, 0x91,
|
||||
0xa1, 0xbd, 0x1e, 0xc0, 0xff, 0x9e, 0x08, 0x57, 0xad, 0xdd, 0xd1, 0x8e, 0x9b, 0xe5, 0xf8, 0x5b,
|
||||
0x65, 0xfb, 0x53, 0x1f, 0x93, 0xc4, 0x1a, 0xa4, 0xaa, 0xfd, 0x28, 0xca, 0x93, 0x0a, 0x09, 0x3f,
|
||||
0xa9, 0x67, 0x0f, 0xfa, 0xde, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x77, 0x7f, 0xdc, 0x8e, 0x94,
|
||||
0x06, 0x00, 0x00,
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ option go_package = "proxyman";
|
||||
option java_package = "com.v2ray.core.app.proxyman";
|
||||
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/port.proto";
|
||||
import "v2ray.com/core/transport/internet/config.proto";
|
||||
@ -61,15 +60,6 @@ message ReceiverConfig {
|
||||
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 {
|
||||
|
||||
}
|
||||
@ -82,19 +72,6 @@ message SenderConfig {
|
||||
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 {
|
||||
// Whether or not Mux is enabled.
|
||||
bool enabled = 1;
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/app/proxyman/mux"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/dice"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
@ -14,17 +15,23 @@ type AlwaysOnInboundHandler struct {
|
||||
proxy proxy.Inbound
|
||||
workers []worker
|
||||
mux *mux.Server
|
||||
tag string
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
p, ok := rawProxy.(proxy.Inbound)
|
||||
if !ok {
|
||||
return nil, newError("not an inbound proxy.")
|
||||
}
|
||||
|
||||
h := &AlwaysOnInboundHandler{
|
||||
proxy: p,
|
||||
mux: mux.NewServer(ctx),
|
||||
tag: tag,
|
||||
}
|
||||
|
||||
nl := p.Network()
|
||||
@ -74,16 +81,26 @@ func (h *AlwaysOnInboundHandler) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *AlwaysOnInboundHandler) Close() {
|
||||
func (h *AlwaysOnInboundHandler) Close() error {
|
||||
for _, worker := range h.workers {
|
||||
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 {
|
||||
return nil, 0, 0
|
||||
}
|
||||
w := h.workers[dice.Roll(len(h.workers))]
|
||||
return w.Proxy(), w.Port(), 9999
|
||||
}
|
||||
|
||||
func (h *AlwaysOnInboundHandler) Tag() string {
|
||||
return h.tag
|
||||
}
|
||||
|
||||
func (h *AlwaysOnInboundHandler) GetInbound() proxy.Inbound {
|
||||
return h.proxy
|
||||
}
|
||||
|
@ -5,17 +5,18 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/app/proxyman/mux"
|
||||
"v2ray.com/core/common/dice"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/signal"
|
||||
"v2ray.com/core/proxy"
|
||||
)
|
||||
|
||||
type DynamicInboundHandler struct {
|
||||
tag string
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
v *core.Instance
|
||||
proxyConfig interface{}
|
||||
receiverConfig *proxyman.ReceiverConfig
|
||||
portMutex sync.Mutex
|
||||
@ -24,18 +25,26 @@ type DynamicInboundHandler struct {
|
||||
worker []worker
|
||||
lastRefresh time.Time
|
||||
mux *mux.Server
|
||||
task *signal.PeriodicTask
|
||||
}
|
||||
|
||||
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{
|
||||
ctx: ctx,
|
||||
tag: tag,
|
||||
cancel: cancel,
|
||||
proxyConfig: proxyConfig,
|
||||
receiverConfig: receiverConfig,
|
||||
portsInUse: make(map[net.Port]bool),
|
||||
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
|
||||
@ -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) {
|
||||
time.Sleep(duration)
|
||||
cancel()
|
||||
func (h *DynamicInboundHandler) closeWorkers(workers []worker) {
|
||||
ports2Del := make([]net.Port, len(workers))
|
||||
for idx, worker := range workers {
|
||||
ports2Del[idx] = worker.Port()
|
||||
@ -80,7 +87,6 @@ func (h *DynamicInboundHandler) refresh() error {
|
||||
|
||||
timeout := time.Minute * time.Duration(h.receiverConfig.AllocationStrategy.GetRefreshValue()) * 2
|
||||
concurrency := h.receiverConfig.AllocationStrategy.GetConcurrencyValue()
|
||||
ctx, cancel := context.WithTimeout(h.ctx, timeout)
|
||||
workers := make([]worker, 0, concurrency)
|
||||
|
||||
address := h.receiverConfig.Listen.AsAddress()
|
||||
@ -89,11 +95,12 @@ func (h *DynamicInboundHandler) refresh() error {
|
||||
}
|
||||
for i := uint32(0); i < concurrency; i++ {
|
||||
port := h.allocatePort()
|
||||
p, err := proxy.CreateInboundHandler(ctx, h.proxyConfig)
|
||||
rawProxy, err := h.v.CreateObject(h.proxyConfig)
|
||||
if err != nil {
|
||||
newError("failed to create proxy instance").Base(err).AtWarning().WriteToLog()
|
||||
continue
|
||||
}
|
||||
p := rawProxy.(proxy.Inbound)
|
||||
nl := p.Network()
|
||||
if nl.HasNetwork(net.Network_TCP) {
|
||||
worker := &tcpWorker{
|
||||
@ -134,36 +141,22 @@ func (h *DynamicInboundHandler) refresh() error {
|
||||
h.worker = workers
|
||||
h.workerMutex.Unlock()
|
||||
|
||||
go h.waitAnyCloseWorkers(ctx, cancel, workers, timeout)
|
||||
time.AfterFunc(timeout, func() {
|
||||
h.closeWorkers(workers)
|
||||
})
|
||||
|
||||
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 {
|
||||
err := h.refresh()
|
||||
go h.monitor()
|
||||
return err
|
||||
return h.task.Start()
|
||||
}
|
||||
|
||||
func (h *DynamicInboundHandler) Close() {
|
||||
h.cancel()
|
||||
func (h *DynamicInboundHandler) Close() error {
|
||||
return h.task.Close()
|
||||
}
|
||||
|
||||
func (h *DynamicInboundHandler) GetRandomInboundProxy() (proxy.Inbound, net.Port, int) {
|
||||
func (h *DynamicInboundHandler) GetRandomInboundProxy() (interface{}, net.Port, int) {
|
||||
h.workerMutex.RLock()
|
||||
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)
|
||||
return w.Proxy(), w.Port(), int(expire)
|
||||
}
|
||||
|
||||
func (h *DynamicInboundHandler) Tag() string {
|
||||
return h.tag
|
||||
}
|
||||
|
@ -4,65 +4,60 @@ package inbound
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/common"
|
||||
)
|
||||
|
||||
// Manager is to manage all inbound handlers.
|
||||
type Manager struct {
|
||||
handlers []proxyman.InboundHandler
|
||||
taggedHandlers map[string]proxyman.InboundHandler
|
||||
access sync.RWMutex
|
||||
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) {
|
||||
return &Manager{
|
||||
taggedHandlers: make(map[string]proxyman.InboundHandler),
|
||||
}, nil
|
||||
m := &Manager{
|
||||
taggedHandlers: make(map[string]core.InboundHandler),
|
||||
}
|
||||
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 {
|
||||
rawReceiverSettings, err := config.ReceiverSettings.GetInstance()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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
|
||||
}
|
||||
// AddHandler implements core.InboundHandlerManager.
|
||||
func (m *Manager) AddHandler(ctx context.Context, handler core.InboundHandler) error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
|
||||
if handler == nil {
|
||||
return newError("unknown allocation strategy: ", receiverSettings.AllocationStrategy.Type).AtError()
|
||||
}
|
||||
|
||||
m.handlers = append(m.handlers, handler)
|
||||
tag := handler.Tag()
|
||||
if len(tag) > 0 {
|
||||
m.taggedHandlers[tag] = handler
|
||||
} else {
|
||||
m.untaggedHandler = append(m.untaggedHandler, handler)
|
||||
}
|
||||
|
||||
if m.running {
|
||||
return handler.Start()
|
||||
}
|
||||
|
||||
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]
|
||||
if !found {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -79,18 +102,52 @@ func (m *Manager) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() {
|
||||
for _, handler := range m.handlers {
|
||||
func (m *Manager) Close() error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
|
||||
m.running = false
|
||||
|
||||
for _, handler := range m.taggedHandlers {
|
||||
handler.Close()
|
||||
}
|
||||
for _, handler := range m.untaggedHandler {
|
||||
handler.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Interface() interface{} {
|
||||
return (*proxyman.InboundHandlerManager)(nil)
|
||||
func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (core.InboundHandler, error) {
|
||||
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() {
|
||||
common.Must(common.RegisterConfig((*proxyman.InboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
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))
|
||||
}))
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/signal"
|
||||
"v2ray.com/core/proxy"
|
||||
"v2ray.com/core/transport/internet"
|
||||
"v2ray.com/core/transport/internet/tcp"
|
||||
@ -19,7 +21,7 @@ import (
|
||||
|
||||
type worker interface {
|
||||
Start() error
|
||||
Close()
|
||||
Close() error
|
||||
Port() net.Port
|
||||
Proxy() proxy.Inbound
|
||||
}
|
||||
@ -31,16 +33,14 @@ type tcpWorker struct {
|
||||
stream *internet.StreamConfig
|
||||
recvOrigDest bool
|
||||
tag string
|
||||
dispatcher dispatcher.Interface
|
||||
dispatcher core.Dispatcher
|
||||
sniffers []proxyman.KnownProtocols
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
hub internet.Listener
|
||||
hub internet.Listener
|
||||
}
|
||||
|
||||
func (w *tcpWorker) callback(conn internet.Connection) {
|
||||
ctx, cancel := context.WithCancel(w.ctx)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
if w.recvOrigDest {
|
||||
dest, err := tcp.GetOriginalDestination(conn)
|
||||
if err != nil {
|
||||
@ -70,45 +70,24 @@ func (w *tcpWorker) Proxy() proxy.Inbound {
|
||||
}
|
||||
|
||||
func (w *tcpWorker) Start() error {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
w.ctx = ctx
|
||||
w.cancel = cancel
|
||||
ctx = internet.ContextWithStreamSettings(ctx, w.stream)
|
||||
conns := make(chan internet.Connection, 16)
|
||||
hub, err := internet.ListenTCP(ctx, w.address, w.port, conns)
|
||||
ctx := internet.ContextWithStreamSettings(context.Background(), w.stream)
|
||||
hub, err := internet.ListenTCP(ctx, w.address, w.port, func(conn internet.Connection) {
|
||||
go w.callback(conn)
|
||||
})
|
||||
if err != nil {
|
||||
return newError("failed to listen TCP on ", w.port).AtWarning().Base(err)
|
||||
}
|
||||
go w.handleConnections(conns)
|
||||
w.hub = hub
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *tcpWorker) handleConnections(conns <-chan internet.Connection) {
|
||||
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() {
|
||||
func (w *tcpWorker) Close() error {
|
||||
if w.hub != nil {
|
||||
w.cancel()
|
||||
common.Close(w.hub)
|
||||
common.Close(w.proxy)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *tcpWorker) Port() net.Port {
|
||||
@ -121,7 +100,7 @@ type udpConn struct {
|
||||
output func([]byte) (int, error)
|
||||
remote net.Addr
|
||||
local net.Addr
|
||||
cancel context.CancelFunc
|
||||
done *signal.Done
|
||||
}
|
||||
|
||||
func (c *udpConn) updateActivity() {
|
||||
@ -129,13 +108,14 @@ func (c *udpConn) updateActivity() {
|
||||
}
|
||||
|
||||
func (c *udpConn) Read(buf []byte) (int, error) {
|
||||
in, open := <-c.input
|
||||
if !open {
|
||||
select {
|
||||
case in := <-c.input:
|
||||
defer in.Release()
|
||||
c.updateActivity()
|
||||
return copy(buf, in.Bytes()), nil
|
||||
case <-c.done.C():
|
||||
return 0, io.EOF
|
||||
}
|
||||
defer in.Release()
|
||||
c.updateActivity()
|
||||
return copy(buf, in.Bytes()), nil
|
||||
}
|
||||
|
||||
// Write implements io.Writer.
|
||||
@ -148,6 +128,7 @@ func (c *udpConn) Write(buf []byte) (int, error) {
|
||||
}
|
||||
|
||||
func (c *udpConn) Close() error {
|
||||
common.Close(c.done)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -171,7 +152,7 @@ func (*udpConn) SetWriteDeadline(time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type connId struct {
|
||||
type connID struct {
|
||||
src net.Destination
|
||||
dest net.Destination
|
||||
}
|
||||
@ -185,14 +166,13 @@ type udpWorker struct {
|
||||
port net.Port
|
||||
recvOrigDest bool
|
||||
tag string
|
||||
dispatcher dispatcher.Interface
|
||||
dispatcher core.Dispatcher
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
activeConn map[connId]*udpConn
|
||||
done *signal.Done
|
||||
activeConn map[connID]*udpConn
|
||||
}
|
||||
|
||||
func (w *udpWorker) getConnection(id connId) (*udpConn, bool) {
|
||||
func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
|
||||
w.Lock()
|
||||
defer w.Unlock()
|
||||
|
||||
@ -213,6 +193,7 @@ func (w *udpWorker) getConnection(id connId) (*udpConn, bool) {
|
||||
IP: w.address.IP(),
|
||||
Port: int(w.port),
|
||||
},
|
||||
done: signal.NewDone(),
|
||||
}
|
||||
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) {
|
||||
id := connId{
|
||||
id := connID{
|
||||
src: source,
|
||||
dest: originalDest,
|
||||
}
|
||||
conn, existing := w.getConnection(id)
|
||||
select {
|
||||
case conn.input <- b:
|
||||
case <-conn.done.C():
|
||||
b.Release()
|
||||
default:
|
||||
b.Release()
|
||||
}
|
||||
|
||||
if !existing {
|
||||
go func() {
|
||||
ctx := w.ctx
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
conn.cancel = cancel
|
||||
ctx := context.Background()
|
||||
if originalDest.IsValid() {
|
||||
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 {
|
||||
newError("connection ends").Base(err).WriteToLog()
|
||||
}
|
||||
conn.Close()
|
||||
w.removeConn(id)
|
||||
cancel()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (w *udpWorker) removeConn(id connId) {
|
||||
func (w *udpWorker) removeConn(id connID) {
|
||||
w.Lock()
|
||||
delete(w.activeConn, id)
|
||||
w.Unlock()
|
||||
}
|
||||
|
||||
func (w *udpWorker) Start() error {
|
||||
w.activeConn = make(map[connId]*udpConn, 16)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
w.ctx = ctx
|
||||
w.cancel = cancel
|
||||
w.activeConn = make(map[connID]*udpConn, 16)
|
||||
w.done = signal.NewDone()
|
||||
h, err := udp.ListenUDP(w.address, w.port, udp.ListenOption{
|
||||
Callback: w.callback,
|
||||
ReceiveOriginalDest: w.recvOrigDest,
|
||||
@ -277,11 +256,13 @@ func (w *udpWorker) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *udpWorker) Close() {
|
||||
func (w *udpWorker) Close() error {
|
||||
if w.hub != nil {
|
||||
w.hub.Close()
|
||||
w.cancel()
|
||||
w.done.Close()
|
||||
common.Close(w.proxy)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *udpWorker) monitor() {
|
||||
@ -290,7 +271,7 @@ func (w *udpWorker) monitor() {
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-w.ctx.Done():
|
||||
case <-w.done.C():
|
||||
return
|
||||
case <-timer.C:
|
||||
nowSec := time.Now().Unix()
|
||||
@ -298,7 +279,7 @@ func (w *udpWorker) monitor() {
|
||||
for addr, conn := range w.activeConn {
|
||||
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 {
|
||||
delete(w.activeConn, addr)
|
||||
conn.cancel()
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
w.Unlock()
|
||||
|
@ -8,13 +8,13 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/errors"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/protocol"
|
||||
"v2ray.com/core/common/signal"
|
||||
"v2ray.com/core/proxy"
|
||||
"v2ray.com/core/transport/ray"
|
||||
)
|
||||
@ -75,8 +75,7 @@ func (m *ClientManager) onClientFinish() {
|
||||
type Client struct {
|
||||
sessionManager *SessionManager
|
||||
inboundRay ray.InboundRay
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
done *signal.Done
|
||||
manager *ClientManager
|
||||
concurrency uint32
|
||||
}
|
||||
@ -86,26 +85,26 @@ var muxCoolPort = net.Port(9527)
|
||||
|
||||
// NewClient creates a new mux.Client.
|
||||
func NewClient(p proxy.Outbound, dialer proxy.Dialer, m *ClientManager) (*Client, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx = proxy.ContextWithTarget(ctx, net.TCPDestination(muxCoolAddress, muxCoolPort))
|
||||
ctx := proxy.ContextWithTarget(context.Background(), net.TCPDestination(muxCoolAddress, muxCoolPort))
|
||||
ctx, cancel := context.WithCancel(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{
|
||||
sessionManager: NewSessionManager(),
|
||||
inboundRay: pipe,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
done: signal.NewDone(),
|
||||
manager: m,
|
||||
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.monitor()
|
||||
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.
|
||||
func (m *Client) Closed() bool {
|
||||
select {
|
||||
case <-m.ctx.Done():
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return m.done.Done()
|
||||
}
|
||||
|
||||
func (m *Client) monitor() {
|
||||
@ -129,7 +123,7 @@ func (m *Client) monitor() {
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-m.ctx.Done():
|
||||
case <-m.done.C():
|
||||
m.sessionManager.Close()
|
||||
m.inboundRay.InboundInput().Close()
|
||||
m.inboundRay.InboundOutput().CloseError()
|
||||
@ -137,7 +131,8 @@ func (m *Client) monitor() {
|
||||
case <-timer.C:
|
||||
size := m.sessionManager.Size()
|
||||
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
|
||||
}
|
||||
|
||||
select {
|
||||
case <-m.ctx.Done():
|
||||
if m.done.Done() {
|
||||
return false
|
||||
default:
|
||||
}
|
||||
|
||||
s := sm.Allocate()
|
||||
@ -227,7 +220,7 @@ func (m *Client) handleStatusEnd(meta *FrameMetadata, reader *buf.BufferedReader
|
||||
}
|
||||
|
||||
func (m *Client) fetchOutput() {
|
||||
defer m.cancel()
|
||||
defer m.done.Close()
|
||||
|
||||
reader := buf.NewBufferedReader(m.inboundRay.InboundOutput())
|
||||
|
||||
@ -262,21 +255,14 @@ func (m *Client) fetchOutput() {
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
dispatcher dispatcher.Interface
|
||||
dispatcher core.Dispatcher
|
||||
}
|
||||
|
||||
// NewServer creates a new mux.Server.
|
||||
func NewServer(ctx context.Context) *Server {
|
||||
s := &Server{}
|
||||
space := app.SpaceFromContext(ctx)
|
||||
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
|
||||
})
|
||||
s := &Server{
|
||||
dispatcher: core.FromContext(ctx).Dispatcher(),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@ -295,8 +281,16 @@ func (s *Server) Dispatch(ctx context.Context, dest net.Destination) (ray.Inboun
|
||||
return ray, nil
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServerWorker struct {
|
||||
dispatcher dispatcher.Interface
|
||||
dispatcher core.Dispatcher
|
||||
outboundRay ray.OutboundRay
|
||||
sessionManager *SessionManager
|
||||
}
|
||||
|
@ -103,12 +103,12 @@ func (m *SessionManager) CloseIfNoSession() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *SessionManager) Close() {
|
||||
func (m *SessionManager) Close() error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if m.closed {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
m.closed = true
|
||||
@ -119,6 +119,7 @@ func (m *SessionManager) Close() {
|
||||
}
|
||||
|
||||
m.sessions = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Session represents a client connection in a Mux connection.
|
||||
@ -131,10 +132,11 @@ type Session struct {
|
||||
}
|
||||
|
||||
// Close closes all resources associated with this session.
|
||||
func (s *Session) Close() {
|
||||
func (s *Session) Close() error {
|
||||
s.output.Close()
|
||||
s.input.Close()
|
||||
s.parent.Remove(s.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewReader creates a buf.Reader based on the transfer type of this Session.
|
||||
|
@ -100,7 +100,7 @@ func (w *Writer) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Writer) Close() {
|
||||
func (w *Writer) Close() error {
|
||||
meta := FrameMetadata{
|
||||
SessionID: w.id,
|
||||
SessionStatus: SessionStatusEnd,
|
||||
@ -110,4 +110,5 @@ func (w *Writer) Close() {
|
||||
common.Must(frame.Reset(meta.AsSupplier()))
|
||||
|
||||
w.writer.WriteMultiBuffer(buf.NewMultiBufferValue(frame))
|
||||
return nil
|
||||
}
|
||||
|
@ -3,12 +3,11 @@ package outbound
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/app/proxyman/mux"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/errors"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
@ -17,29 +16,22 @@ import (
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
config *proxyman.OutboundHandlerConfig
|
||||
config *core.OutboundHandlerConfig
|
||||
senderSettings *proxyman.SenderConfig
|
||||
proxy proxy.Outbound
|
||||
outboundManager proxyman.OutboundHandlerManager
|
||||
outboundManager core.OutboundHandlerManager
|
||||
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{
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
config := h.senderSettings.MultiplexSettings
|
||||
if config.Concurrency < 1 || config.Concurrency > 1024 {
|
||||
@ -71,6 +73,11 @@ func NewHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) (*H
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// Tag implements core.OutboundHandler.
|
||||
func (h *Handler) Tag() string {
|
||||
return h.config.Tag
|
||||
}
|
||||
|
||||
// Dispatch implements proxy.Outbound.Dispatch.
|
||||
func (h *Handler) Dispatch(ctx context.Context, outboundRay ray.OutboundRay) {
|
||||
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)
|
||||
stream := ray.NewRay(ctx)
|
||||
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()
|
||||
@ -121,98 +128,18 @@ func (h *Handler) Dial(ctx context.Context, dest net.Destination) (internet.Conn
|
||||
return internet.Dial(ctx, dest)
|
||||
}
|
||||
|
||||
var (
|
||||
_ buf.Reader = (*Connection)(nil)
|
||||
_ buf.Writer = (*Connection)(nil)
|
||||
)
|
||||
|
||||
type Connection struct {
|
||||
stream ray.Ray
|
||||
closed bool
|
||||
localAddr net.Addr
|
||||
remoteAddr net.Addr
|
||||
|
||||
reader *buf.BufferedReader
|
||||
writer buf.Writer
|
||||
// GetOutbound implements proxy.GetOutbound.
|
||||
func (h *Handler) GetOutbound() proxy.Outbound {
|
||||
return h.proxy
|
||||
}
|
||||
|
||||
func NewConnection(stream ray.Ray) *Connection {
|
||||
return &Connection{
|
||||
stream: stream,
|
||||
localAddr: &net.TCPAddr{
|
||||
IP: []byte{0, 0, 0, 0},
|
||||
Port: 0,
|
||||
},
|
||||
remoteAddr: &net.TCPAddr{
|
||||
IP: []byte{0, 0, 0, 0},
|
||||
Port: 0,
|
||||
},
|
||||
reader: buf.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()
|
||||
// Start implements common.Runnable.
|
||||
func (h *Handler) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// LocalAddr implements net.Conn.LocalAddr().
|
||||
func (v *Connection) LocalAddr() net.Addr {
|
||||
return v.localAddr
|
||||
}
|
||||
|
||||
// RemoteAddr implements net.Conn.RemoteAddr().
|
||||
func (v *Connection) RemoteAddr() net.Addr {
|
||||
return v.remoteAddr
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// Close implements common.Runnable.
|
||||
func (h *Handler) Close() error {
|
||||
common.Close(h.mux)
|
||||
return nil
|
||||
}
|
||||
|
16
app/proxyman/outbound/handler_test.go
Normal file
16
app/proxyman/outbound/handler_test.go
Normal 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))
|
||||
}
|
@ -6,67 +6,130 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/common"
|
||||
)
|
||||
|
||||
// Manager is to manage all outbound handlers.
|
||||
type Manager struct {
|
||||
sync.RWMutex
|
||||
defaultHandler *Handler
|
||||
taggedHandler map[string]*Handler
|
||||
access sync.RWMutex
|
||||
defaultHandler core.OutboundHandler
|
||||
taggedHandler map[string]core.OutboundHandler
|
||||
untaggedHandlers []core.OutboundHandler
|
||||
running bool
|
||||
}
|
||||
|
||||
// New creates a new Manager.
|
||||
func New(ctx context.Context, config *proxyman.OutboundConfig) (*Manager, error) {
|
||||
return &Manager{
|
||||
taggedHandler: make(map[string]*Handler),
|
||||
}, nil
|
||||
m := &Manager{
|
||||
taggedHandler: make(map[string]core.OutboundHandler),
|
||||
}
|
||||
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.
|
||||
func (*Manager) Interface() interface{} {
|
||||
return (*proxyman.OutboundHandlerManager)(nil)
|
||||
// Start implements core.Feature
|
||||
func (m *Manager) Start() error {
|
||||
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
|
||||
func (*Manager) Start() error { return nil }
|
||||
// Close implements core.Feature
|
||||
func (m *Manager) Close() error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
|
||||
// Close implements Application.Close
|
||||
func (*Manager) Close() {}
|
||||
m.running = false
|
||||
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
return m.defaultHandler
|
||||
}
|
||||
|
||||
func (m *Manager) GetHandler(tag string) proxyman.OutboundHandler {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
// GetHandler implements core.OutboundHandlerManager.
|
||||
func (m *Manager) GetHandler(tag string) core.OutboundHandler {
|
||||
m.access.RLock()
|
||||
defer m.access.RUnlock()
|
||||
if handler, found := m.taggedHandler[tag]; found {
|
||||
return handler
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) AddHandler(ctx context.Context, config *proxyman.OutboundHandlerConfig) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
// AddHandler implements core.OutboundHandlerManager.
|
||||
func (m *Manager) AddHandler(ctx context.Context, handler core.OutboundHandler) error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
|
||||
handler, err := NewHandler(ctx, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m.defaultHandler == nil {
|
||||
m.defaultHandler = handler
|
||||
}
|
||||
|
||||
if len(config.Tag) > 0 {
|
||||
m.taggedHandler[config.Tag] = handler
|
||||
tag := handler.Tag()
|
||||
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
|
||||
@ -76,4 +139,7 @@ func init() {
|
||||
common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||
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))
|
||||
}))
|
||||
}
|
||||
|
@ -5,52 +5,8 @@ package proxyman
|
||||
|
||||
import (
|
||||
"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
|
||||
|
||||
const (
|
||||
|
@ -5,46 +5,47 @@ package router
|
||||
import (
|
||||
"context"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/proxy"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoRuleApplicable = newError("No rule applicable")
|
||||
)
|
||||
|
||||
type Router struct {
|
||||
domainStrategy Config_DomainStrategy
|
||||
rules []Rule
|
||||
dns core.DNSClient
|
||||
}
|
||||
|
||||
func NewRouter(ctx context.Context, config *Config) (*Router, error) {
|
||||
space := app.SpaceFromContext(ctx)
|
||||
if space == nil {
|
||||
return nil, newError("no space in context")
|
||||
v := core.FromContext(ctx)
|
||||
if v == nil {
|
||||
return nil, newError("V is not in context")
|
||||
}
|
||||
|
||||
r := &Router{
|
||||
domainStrategy: config.DomainStrategy,
|
||||
rules: make([]Rule, len(config.Rule)),
|
||||
dns: v.DNSClient(),
|
||||
}
|
||||
|
||||
space.On(app.SpaceInitializing, func(interface{}) error {
|
||||
for idx, rule := range config.Rule {
|
||||
r.rules[idx].Tag = rule.Tag
|
||||
cond, err := rule.BuildCondition()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.rules[idx].Condition = cond
|
||||
for idx, rule := range config.Rule {
|
||||
r.rules[idx].Tag = rule.Tag
|
||||
cond, err := rule.BuildCondition()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
type ipResolver struct {
|
||||
dns core.DNSClient
|
||||
ip []net.Address
|
||||
domain string
|
||||
resolved bool
|
||||
@ -57,7 +58,7 @@ func (r *ipResolver) Resolve() []net.Address {
|
||||
|
||||
newError("looking for IP for domain: ", r.domain).WriteToLog()
|
||||
r.resolved = true
|
||||
ips, err := net.LookupIP(r.domain)
|
||||
ips, err := r.dns.LookupIP(r.domain)
|
||||
if err != nil {
|
||||
newError("failed to get IP address").Base(err).WriteToLog()
|
||||
}
|
||||
@ -71,8 +72,10 @@ func (r *ipResolver) Resolve() []net.Address {
|
||||
return r.ip
|
||||
}
|
||||
|
||||
func (r *Router) TakeDetour(ctx context.Context) (string, error) {
|
||||
resolver := &ipResolver{}
|
||||
func (r *Router) PickRoute(ctx context.Context) (string, error) {
|
||||
resolver := &ipResolver{
|
||||
dns: r.dns,
|
||||
}
|
||||
if r.domainStrategy == Config_IpOnDemand {
|
||||
if dest, ok := proxy.TargetFromContext(ctx); ok && dest.Address.Family().IsDomain() {
|
||||
resolver.domain = dest.Address.Domain()
|
||||
@ -88,7 +91,7 @@ func (r *Router) TakeDetour(ctx context.Context) (string, error) {
|
||||
|
||||
dest, ok := proxy.TargetFromContext(ctx)
|
||||
if !ok {
|
||||
return "", ErrNoRuleApplicable
|
||||
return "", core.ErrNoClue
|
||||
}
|
||||
|
||||
if r.domainStrategy == Config_IpIfNonMatch && dest.Address.Family().IsDomain() {
|
||||
@ -104,25 +107,15 @@ func (r *Router) TakeDetour(ctx context.Context) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return "", ErrNoRuleApplicable
|
||||
}
|
||||
|
||||
func (*Router) Interface() interface{} {
|
||||
return (*Router)(nil)
|
||||
return "", core.ErrNoClue
|
||||
}
|
||||
|
||||
func (*Router) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*Router) Close() {}
|
||||
|
||||
func FromSpace(space app.Space) *Router {
|
||||
app := space.GetApplication((*Router)(nil))
|
||||
if app == nil {
|
||||
return nil
|
||||
}
|
||||
return app.(*Router)
|
||||
func (*Router) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -4,13 +4,14 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
_ "v2ray.com/core/app/dispatcher/impl"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
_ "v2ray.com/core/app/proxyman/outbound"
|
||||
. "v2ray.com/core/app/router"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/serial"
|
||||
"v2ray.com/core/proxy"
|
||||
. "v2ray.com/ext/assert"
|
||||
)
|
||||
@ -18,28 +19,30 @@ import (
|
||||
func TestSimpleRouter(t *testing.T) {
|
||||
assert := With(t)
|
||||
|
||||
config := &Config{
|
||||
Rule: []*RoutingRule{
|
||||
{
|
||||
Tag: "test",
|
||||
NetworkList: &net.NetworkList{
|
||||
Network: []net.Network{net.Network_TCP},
|
||||
config := &core.Config{
|
||||
App: []*serial.TypedMessage{
|
||||
serial.ToTypedMessage(&Config{
|
||||
Rule: []*RoutingRule{
|
||||
{
|
||||
Tag: "test",
|
||||
NetworkList: &net.NetworkList{
|
||||
Network: []net.Network{net.Network_TCP},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
serial.ToTypedMessage(&dispatcher.Config{}),
|
||||
serial.ToTypedMessage(&proxyman.OutboundConfig{}),
|
||||
},
|
||||
}
|
||||
|
||||
space := app.NewSpace()
|
||||
ctx := app.ContextWithSpace(context.Background(), space)
|
||||
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)
|
||||
v, err := core.New(config)
|
||||
common.Must(err)
|
||||
|
||||
r := FromSpace(space)
|
||||
r := v.Router()
|
||||
|
||||
ctx = proxy.ContextWithTarget(ctx, net.TCPDestination(net.DomainAddress("v2ray.com"), 80))
|
||||
tag, err := r.TakeDetour(ctx)
|
||||
ctx := proxy.ContextWithTarget(context.Background(), net.TCPDestination(net.DomainAddress("v2ray.com"), 80))
|
||||
tag, err := r.PickRoute(ctx)
|
||||
assert(err, IsNil)
|
||||
assert(tag, Equals, "test")
|
||||
}
|
||||
|
132
app/space.go
132
app/space.go
@ -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
59
clock.go
Normal 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
44
commander.go
Normal 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
|
||||
}
|
@ -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
23
common/interfaces.go
Normal 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
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
"sync"
|
||||
|
||||
"v2ray.com/core/common/serial"
|
||||
)
|
||||
@ -30,12 +29,11 @@ func (m *GeneralMessage) String() string {
|
||||
|
||||
// Record writes a message into log stream.
|
||||
func Record(msg Message) {
|
||||
h := (*Handler)(atomic.LoadPointer(&logHandler))
|
||||
(*h).Handle(msg)
|
||||
logHandler.Handle(msg)
|
||||
}
|
||||
|
||||
var (
|
||||
logHandler unsafe.Pointer
|
||||
logHandler syncHandler
|
||||
)
|
||||
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -11,6 +11,8 @@ var Listen = net.Listen
|
||||
var ListenTCP = net.ListenTCP
|
||||
var ListenUDP = net.ListenUDP
|
||||
|
||||
var LookupIP = net.LookupIP
|
||||
|
||||
var FileConn = net.FileConn
|
||||
|
||||
var ParseIP = net.ParseIP
|
||||
|
@ -18,11 +18,14 @@ const (
|
||||
)
|
||||
|
||||
func (c RequestCommand) TransferType() TransferType {
|
||||
if c == RequestCommandTCP {
|
||||
switch c {
|
||||
case RequestCommandTCP, RequestCommandMux:
|
||||
return TransferTypeStream
|
||||
case RequestCommandUDP:
|
||||
return TransferTypePacket
|
||||
default:
|
||||
return TransferTypeStream
|
||||
}
|
||||
|
||||
return TransferTypePacket
|
||||
}
|
||||
|
||||
const (
|
||||
@ -79,7 +82,7 @@ type ResponseHeader struct {
|
||||
type CommandSwitchAccount struct {
|
||||
Host net.Address
|
||||
Port net.Port
|
||||
ID *uuid.UUID
|
||||
ID uuid.UUID
|
||||
Level uint32
|
||||
AlterIds uint16
|
||||
ValidMin byte
|
||||
|
@ -21,13 +21,13 @@ func DefaultIDHash(key []byte) hash.Hash {
|
||||
|
||||
// The ID of en entity, in the form of an UUID.
|
||||
type ID struct {
|
||||
uuid *uuid.UUID
|
||||
uuid uuid.UUID
|
||||
cmdKey [IDBytesLen]byte
|
||||
}
|
||||
|
||||
// Equals returns true if this ID equals to the other one.
|
||||
func (id *ID) Equals(another *ID) bool {
|
||||
return id.uuid.Equals(another.uuid)
|
||||
return id.uuid.Equals(&(another.uuid))
|
||||
}
|
||||
|
||||
func (id *ID) Bytes() []byte {
|
||||
@ -38,7 +38,7 @@ func (id *ID) String() string {
|
||||
return id.uuid.String()
|
||||
}
|
||||
|
||||
func (id *ID) UUID() *uuid.UUID {
|
||||
func (id *ID) UUID() uuid.UUID {
|
||||
return id.uuid
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ func (id ID) CmdKey() []byte {
|
||||
}
|
||||
|
||||
// NewID returns an ID with given UUID.
|
||||
func NewID(uuid *uuid.UUID) *ID {
|
||||
func NewID(uuid uuid.UUID) *ID {
|
||||
id := &ID{uuid: uuid}
|
||||
md5hash := md5.New()
|
||||
common.Must2(md5hash.Write(uuid.Bytes()))
|
||||
|
@ -14,7 +14,7 @@ var _ = math.Inf
|
||||
type User struct {
|
||||
Level uint32 `protobuf:"varint,1,opt,name=level" json:"level,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"`
|
||||
}
|
||||
|
||||
|
@ -3,4 +3,5 @@ package protocol
|
||||
type UserValidator interface {
|
||||
Add(user *User) error
|
||||
Get(timeHash []byte) (*User, Timestamp, bool)
|
||||
Remove(email string) bool
|
||||
}
|
||||
|
12
common/router/dispatcher.go
Normal file
12
common/router/dispatcher.go
Normal 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
53
common/router/router.go
Normal 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
48
common/signal/done.go
Normal 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
|
||||
}
|
@ -1,22 +1,22 @@
|
||||
package signal
|
||||
|
||||
type Notifier struct {
|
||||
c chan bool
|
||||
c chan struct{}
|
||||
}
|
||||
|
||||
func NewNotifier() *Notifier {
|
||||
return &Notifier{
|
||||
c: make(chan bool, 1),
|
||||
c: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) Signal() {
|
||||
select {
|
||||
case n.c <- true:
|
||||
case n.c <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notifier) Wait() <-chan bool {
|
||||
func (n *Notifier) Wait() <-chan struct{} {
|
||||
return n.c
|
||||
}
|
||||
|
@ -1,23 +1,23 @@
|
||||
package signal
|
||||
|
||||
type Semaphore struct {
|
||||
token chan bool
|
||||
token chan struct{}
|
||||
}
|
||||
|
||||
func NewSemaphore(n int) *Semaphore {
|
||||
s := &Semaphore{
|
||||
token: make(chan bool, n),
|
||||
token: make(chan struct{}, n),
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
s.token <- true
|
||||
s.token <- struct{}{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Semaphore) Wait() <-chan bool {
|
||||
func (s *Semaphore) Wait() <-chan struct{} {
|
||||
return s.token
|
||||
}
|
||||
|
||||
func (s *Semaphore) Signal() {
|
||||
s.token <- true
|
||||
s.token <- struct{}{}
|
||||
}
|
||||
|
60
common/signal/task.go
Normal file
60
common/signal/task.go
Normal 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
|
||||
}
|
29
common/signal/task_test.go
Normal file
29
common/signal/task_test.go
Normal 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)
|
||||
}
|
@ -10,23 +10,30 @@ type ActivityUpdater interface {
|
||||
}
|
||||
|
||||
type ActivityTimer struct {
|
||||
updated chan bool
|
||||
updated chan struct{}
|
||||
timeout chan time.Duration
|
||||
closing chan struct{}
|
||||
}
|
||||
|
||||
func (t *ActivityTimer) Update() {
|
||||
select {
|
||||
case t.updated <- true:
|
||||
case t.updated <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
defer cancel()
|
||||
defer func() {
|
||||
cancel()
|
||||
close(t.closing)
|
||||
}()
|
||||
|
||||
timeout := <-t.timeout
|
||||
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 {
|
||||
timer := &ActivityTimer{
|
||||
timeout: make(chan time.Duration, 1),
|
||||
updated: make(chan bool, 1),
|
||||
updated: make(chan struct{}, 1),
|
||||
closing: make(chan struct{}),
|
||||
}
|
||||
timer.timeout <- timeout
|
||||
go timer.run(ctx, cancel)
|
||||
|
@ -32,3 +32,15 @@ func TestActivityTimerUpdate(t *testing.T) {
|
||||
assert(ctx.Err(), IsNotNil)
|
||||
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)
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"v2ray.com/core/common"
|
||||
"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.
|
||||
func (u *UUID) Next() *UUID {
|
||||
func (u *UUID) Next() UUID {
|
||||
md5hash := md5.New()
|
||||
md5hash.Write(u.Bytes())
|
||||
md5hash.Write([]byte("16167dc8-16b6-4e6d-b8bb-65dd68113a81"))
|
||||
newid := new(UUID)
|
||||
var newid UUID
|
||||
for {
|
||||
md5hash.Sum(newid[:0])
|
||||
if !newid.Equals(u) {
|
||||
@ -61,30 +62,31 @@ func (u *UUID) Next() *UUID {
|
||||
}
|
||||
|
||||
// New creates an UUID with random value.
|
||||
func New() *UUID {
|
||||
uuid := new(UUID)
|
||||
rand.Read(uuid.Bytes())
|
||||
func New() UUID {
|
||||
var uuid UUID
|
||||
common.Must2(rand.Read(uuid.Bytes()))
|
||||
return uuid
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil, errors.New("invalid UUID: ", b)
|
||||
return uuid, errors.New("invalid UUID: ", b)
|
||||
}
|
||||
uuid := new(UUID)
|
||||
copy(uuid[:], b)
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if len(text) < 32 {
|
||||
return nil, errors.New("invalid UUID: ", str)
|
||||
return uuid, errors.New("invalid UUID: ", str)
|
||||
}
|
||||
|
||||
uuid := new(UUID)
|
||||
b := uuid.Bytes()
|
||||
|
||||
for _, byteGroup := range byteGroups {
|
||||
@ -95,7 +97,7 @@ func ParseString(str string) (*UUID, error) {
|
||||
_, err := hex.Decode(b[:byteGroup/2], text[:byteGroup])
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
text = text[byteGroup:]
|
||||
|
@ -65,7 +65,9 @@ func TestEquals(t *testing.T) {
|
||||
var uuid *UUID = nil
|
||||
var uuid2 *UUID = nil
|
||||
assert(uuid.Equals(uuid2), IsTrue)
|
||||
assert(uuid.Equals(New()), IsFalse)
|
||||
|
||||
uuid3 := New()
|
||||
assert(uuid.Equals(&uuid3), IsFalse)
|
||||
}
|
||||
|
||||
func TestNext(t *testing.T) {
|
||||
@ -73,5 +75,5 @@ func TestNext(t *testing.T) {
|
||||
|
||||
uuid := New()
|
||||
uuid2 := uuid.Next()
|
||||
assert(uuid.Equals(uuid2), IsFalse)
|
||||
assert(uuid.Equals(&uuid2), IsFalse)
|
||||
}
|
||||
|
152
config.pb.go
152
config.pb.go
@ -3,7 +3,6 @@ package core
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import v2ray_core_app_proxyman "v2ray.com/core/app/proxyman"
|
||||
import v2ray_core_common_serial "v2ray.com/core/common/serial"
|
||||
import v2ray_core_transport "v2ray.com/core/transport"
|
||||
|
||||
@ -40,12 +39,12 @@ func (x ConfigFormat) String() string {
|
||||
}
|
||||
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 {
|
||||
// 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 []*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 []*v2ray_core_common_serial.TypedMessage `protobuf:"bytes,4,rep,name=app" json:"app,omitempty"`
|
||||
// Transport settings.
|
||||
@ -60,14 +59,14 @@ func (m *Config) String() string { return proto.CompactTextString(m)
|
||||
func (*Config) ProtoMessage() {}
|
||||
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 {
|
||||
return m.Inbound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Config) GetOutbound() []*v2ray_core_app_proxyman.OutboundHandlerConfig {
|
||||
func (m *Config) GetOutbound() []*OutboundHandlerConfig {
|
||||
if m != nil {
|
||||
return m.Outbound
|
||||
}
|
||||
@ -95,34 +94,131 @@ func (m *Config) GetExtension() []*v2ray_core_common_serial.TypedMessage {
|
||||
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() {
|
||||
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)
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("v2ray.com/core/config.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 336 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x91, 0xcd, 0x4a, 0xf3, 0x40,
|
||||
0x18, 0x85, 0xbf, 0xb4, 0xf9, 0x6a, 0xfa, 0xb6, 0x48, 0x99, 0x55, 0xa8, 0x2e, 0x8a, 0xd0, 0x52,
|
||||
0x04, 0x27, 0x12, 0x37, 0xe2, 0xd2, 0x8a, 0x3f, 0x05, 0x6d, 0xa9, 0xe2, 0xc2, 0x8d, 0x4c, 0xd3,
|
||||
0x69, 0x09, 0x74, 0xe6, 0x1d, 0x26, 0x53, 0x69, 0x6e, 0xc9, 0x9b, 0xf2, 0x56, 0x24, 0x99, 0xfe,
|
||||
0xa5, 0xe2, 0xc2, 0x55, 0x20, 0x73, 0x9e, 0xe7, 0x4c, 0x4e, 0xe0, 0xe8, 0x23, 0xd4, 0x2c, 0xa5,
|
||||
0x11, 0x8a, 0x20, 0x42, 0xcd, 0x83, 0x08, 0xe5, 0x34, 0x9e, 0x51, 0xa5, 0xd1, 0x20, 0x81, 0xf5,
|
||||
0xa1, 0xe6, 0xcd, 0xee, 0x5e, 0x90, 0x29, 0x15, 0x28, 0x8d, 0xcb, 0x54, 0x30, 0x59, 0xa0, 0x9a,
|
||||
0xe7, 0x3f, 0x94, 0x42, 0xa0, 0x0c, 0x12, 0xae, 0x63, 0x36, 0x0f, 0x4c, 0xaa, 0xf8, 0xe4, 0x5d,
|
||||
0xf0, 0x24, 0x61, 0x33, 0xbe, 0x22, 0xda, 0x7b, 0x84, 0xd1, 0x4c, 0x26, 0x0a, 0xb5, 0x29, 0x88,
|
||||
0x4f, 0xbe, 0x4a, 0x50, 0xe9, 0xe5, 0x2f, 0xc8, 0x1d, 0x1c, 0xc4, 0x72, 0x8c, 0x0b, 0x39, 0xf1,
|
||||
0x9d, 0x56, 0xb9, 0x5b, 0x0b, 0xcf, 0xe8, 0xf6, 0xae, 0x94, 0x29, 0x45, 0xd7, 0x77, 0xa3, 0x0f,
|
||||
0x36, 0x77, 0xcf, 0xe4, 0x64, 0xce, 0xb5, 0xe5, 0x47, 0x6b, 0x9a, 0xf4, 0xc1, 0xc3, 0x85, 0xb1,
|
||||
0xa6, 0x52, 0x6e, 0xa2, 0xbf, 0x9a, 0x06, 0xab, 0x60, 0x51, 0xb5, 0xe1, 0xc9, 0x25, 0x94, 0x99,
|
||||
0x52, 0xbe, 0x9b, 0x6b, 0x3a, 0xbb, 0x1a, 0x3b, 0x01, 0xb5, 0x13, 0xd0, 0x97, 0x6c, 0x82, 0x47,
|
||||
0xbb, 0xc0, 0x28, 0x43, 0xc8, 0x15, 0x54, 0x37, 0xdf, 0xec, 0xff, 0x6f, 0x39, 0xdd, 0x5a, 0x78,
|
||||
0xbc, 0xcb, 0x6f, 0x0e, 0xe9, 0xaa, 0x74, 0x1b, 0x27, 0x37, 0x50, 0xe5, 0x4b, 0xc3, 0x65, 0x12,
|
||||
0xa3, 0xf4, 0x2b, 0x7f, 0xea, 0xde, 0x82, 0x7d, 0xd7, 0x2b, 0x37, 0xdc, 0xd3, 0x0e, 0xd4, 0x6d,
|
||||
0xc1, 0x2d, 0x6a, 0xc1, 0x0c, 0xa9, 0x83, 0x37, 0xcc, 0xa6, 0x1f, 0x2f, 0xa6, 0x8d, 0x7f, 0xc4,
|
||||
0x03, 0xb7, 0xff, 0x3c, 0x78, 0x6a, 0x38, 0xd7, 0x6d, 0x38, 0x8c, 0x50, 0xec, 0xb4, 0x0c, 0x9d,
|
||||
0x37, 0x37, 0x7b, 0x7e, 0x96, 0xe0, 0x35, 0x1c, 0xb1, 0x94, 0xf6, 0x50, 0xf3, 0x71, 0x25, 0xff,
|
||||
0x6f, 0x17, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x62, 0x93, 0x6d, 0x78, 0x65, 0x02, 0x00, 0x00,
|
||||
// 436 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0x41, 0x6f, 0xd3, 0x30,
|
||||
0x14, 0xc7, 0x71, 0x13, 0xba, 0xf6, 0x6d, 0x94, 0x60, 0x01, 0xb2, 0x06, 0x87, 0x50, 0x69, 0x53,
|
||||
0xc5, 0xc1, 0x45, 0xe5, 0x82, 0x26, 0x71, 0x61, 0x08, 0xc1, 0xa4, 0xd1, 0x29, 0x45, 0x1c, 0xb8,
|
||||
0x4c, 0x6e, 0xfa, 0x56, 0x45, 0x5a, 0xec, 0xc8, 0x76, 0xa7, 0xe6, 0x2b, 0xf1, 0x3d, 0xb8, 0xf1,
|
||||
0x8d, 0xb8, 0xa0, 0xc4, 0x49, 0x93, 0x41, 0x0f, 0x14, 0x69, 0xa7, 0xc4, 0x79, 0xfe, 0xfd, 0xdf,
|
||||
0xfb, 0x25, 0x31, 0x3c, 0xbb, 0x99, 0x68, 0x91, 0xf3, 0x58, 0xa5, 0xe3, 0x58, 0x69, 0x1c, 0xc7,
|
||||
0x4a, 0x5e, 0x25, 0x4b, 0x9e, 0x69, 0x65, 0x15, 0x85, 0xba, 0xa8, 0xf1, 0xf0, 0xd5, 0x5f, 0x1b,
|
||||
0xd3, 0x54, 0xc9, 0xb1, 0x41, 0x9d, 0x88, 0xeb, 0xb1, 0xcd, 0x33, 0x5c, 0x5c, 0xa6, 0x68, 0x8c,
|
||||
0x58, 0xa2, 0xa3, 0x0f, 0x8f, 0xfe, 0x20, 0xac, 0x16, 0xd2, 0x64, 0x4a, 0xdb, 0x5b, 0x4d, 0x86,
|
||||
0x3f, 0x3a, 0xd0, 0x3d, 0x2d, 0x1f, 0xd0, 0x13, 0xd8, 0x4b, 0xe4, 0x5c, 0xad, 0xe4, 0x82, 0x91,
|
||||
0xd0, 0x1b, 0xed, 0x4f, 0x42, 0xde, 0x4c, 0xc0, 0x3f, 0xb9, 0xd2, 0x47, 0x21, 0x17, 0xd7, 0xa8,
|
||||
0x1d, 0x12, 0xd5, 0x00, 0x7d, 0x0b, 0x3d, 0xb5, 0xb2, 0x0e, 0xee, 0x94, 0xf0, 0x8b, 0x36, 0x3c,
|
||||
0xad, 0x6a, 0xb7, 0xe9, 0x0d, 0x42, 0xdf, 0x80, 0x27, 0xb2, 0x8c, 0xf9, 0x25, 0x79, 0xdc, 0x26,
|
||||
0x9d, 0x28, 0x77, 0xa2, 0xfc, 0x4b, 0x21, 0x7a, 0xee, 0x3c, 0xa3, 0x02, 0xa1, 0x27, 0xd0, 0xdf,
|
||||
0x98, 0xb1, 0xfb, 0x21, 0x19, 0xed, 0x4f, 0x9e, 0xb7, 0xf9, 0x4d, 0x91, 0x57, 0x4d, 0x9b, 0xed,
|
||||
0xf4, 0x3d, 0xf4, 0x71, 0x6d, 0x51, 0x9a, 0x44, 0x49, 0xd6, 0xdd, 0xa9, 0x77, 0x03, 0x9e, 0xf9,
|
||||
0x3d, 0x2f, 0xf0, 0x87, 0x3f, 0x09, 0x3c, 0xde, 0xf6, 0x8a, 0x68, 0x00, 0x9e, 0x15, 0x4b, 0x46,
|
||||
0x42, 0x32, 0xea, 0x47, 0xc5, 0x2d, 0x9d, 0xc1, 0x23, 0x8d, 0x31, 0x26, 0x37, 0xa8, 0x2f, 0x0d,
|
||||
0x5a, 0x9b, 0xc8, 0xa5, 0x61, 0x9d, 0x72, 0xf4, 0x7f, 0x6d, 0x1f, 0xd4, 0x01, 0xb3, 0x8a, 0xa7,
|
||||
0xe7, 0x30, 0xc8, 0xb4, 0x5a, 0xe7, 0x4d, 0xa2, 0xb7, 0x53, 0xe2, 0x83, 0x92, 0xae, 0xe3, 0x86,
|
||||
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,
|
||||
}
|
||||
|
27
config.proto
27
config.proto
@ -6,7 +6,6 @@ option go_package = "core";
|
||||
option java_package = "com.v2ray.core";
|
||||
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/transport/config.proto";
|
||||
|
||||
@ -19,10 +18,10 @@ enum ConfigFormat {
|
||||
// Master config of V2Ray. V2Ray takes this config as input and functions accordingly.
|
||||
message Config {
|
||||
// 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.
|
||||
repeated v2ray.core.app.proxyman.OutboundHandlerConfig outbound = 2;
|
||||
repeated OutboundHandlerConfig outbound = 2;
|
||||
|
||||
reserved 3;
|
||||
|
||||
@ -36,3 +35,25 @@ message Config {
|
||||
// V2Ray will ignore such config during initialization.
|
||||
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
17
context.go
Normal 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
|
||||
}
|
2
core.go
2
core.go
@ -18,7 +18,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
version = "3.6"
|
||||
version = "3.8"
|
||||
build = "Custom"
|
||||
codename = "die Commanderin"
|
||||
intro = "An unified platform for anti-censorship."
|
||||
|
20
dial.go
Normal file
20
dial.go
Normal 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
59
dns.go
Normal 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
|
||||
}
|
@ -2,10 +2,12 @@ package all
|
||||
|
||||
import (
|
||||
// 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/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/outbound"
|
||||
_ "v2ray.com/core/app/router"
|
||||
|
168
network.go
Normal file
168
network.go
Normal 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
117
policy.go
Normal 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
|
||||
}
|
@ -4,10 +4,9 @@ package dokodemo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core/app/policy"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/net"
|
||||
@ -18,36 +17,29 @@ import (
|
||||
)
|
||||
|
||||
type DokodemoDoor struct {
|
||||
config *Config
|
||||
address net.Address
|
||||
port net.Port
|
||||
policy policy.Policy
|
||||
policyManager core.PolicyManager
|
||||
config *Config
|
||||
address net.Address
|
||||
port net.Port
|
||||
v *core.Instance
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, newError("no network specified")
|
||||
}
|
||||
d := &DokodemoDoor{
|
||||
config: config,
|
||||
address: config.GetPredefinedAddress(),
|
||||
port: net.Port(config.Port),
|
||||
v := core.FromContext(ctx)
|
||||
if 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.")
|
||||
}
|
||||
d.policy = pm.GetPolicy(config.UserLevel)
|
||||
if config.Timeout > 0 && config.UserLevel == 0 {
|
||||
d.policy.Timeout.ConnectionIdle.Value = config.Timeout
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
d := &DokodemoDoor{
|
||||
config: config,
|
||||
address: config.GetPredefinedAddress(),
|
||||
port: net.Port(config.Port),
|
||||
policyManager: v.PolicyManager(),
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
@ -55,7 +47,16 @@ func (d *DokodemoDoor) Network() net.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()
|
||||
dest := net.Destination{
|
||||
Network: network,
|
||||
@ -72,7 +73,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
}
|
||||
|
||||
timer.SetTimeout(d.policy.Timeout.DownlinkOnly.Duration())
|
||||
timer.SetTimeout(d.policy().Timeouts.DownlinkOnly)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
timer.SetTimeout(d.policy.Timeout.UplinkOnly.Duration())
|
||||
timer.SetTimeout(d.policy().Timeouts.UplinkOnly)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
@ -4,9 +4,9 @@ package freedom
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/policy"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/dice"
|
||||
@ -20,37 +20,35 @@ import (
|
||||
|
||||
// Handler handles Freedom connections.
|
||||
type Handler struct {
|
||||
domainStrategy Config_DomainStrategy
|
||||
timeout uint32
|
||||
destOverride *DestinationOverride
|
||||
policy policy.Policy
|
||||
policyManager core.PolicyManager
|
||||
dns core.DNSClient
|
||||
config Config
|
||||
}
|
||||
|
||||
// New creates a new Freedom handler.
|
||||
func New(ctx context.Context, config *Config) (*Handler, error) {
|
||||
space := app.SpaceFromContext(ctx)
|
||||
if space == nil {
|
||||
return nil, newError("no space in context")
|
||||
v := core.FromContext(ctx)
|
||||
if v == nil {
|
||||
return nil, newError("V is not found in context.")
|
||||
}
|
||||
|
||||
f := &Handler{
|
||||
domainStrategy: config.DomainStrategy,
|
||||
timeout: config.Timeout,
|
||||
destOverride: config.DestinationOverride,
|
||||
config: *config,
|
||||
policyManager: v.PolicyManager(),
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
if resolver, ok := proxy.ResolvedIPsFromContext(ctx); ok {
|
||||
ips := resolver.Resolve()
|
||||
@ -60,7 +58,7 @@ func (h *Handler) resolveIP(ctx context.Context, domain string) net.Address {
|
||||
return ips[dice.Roll(len(ips))]
|
||||
}
|
||||
|
||||
ips, err := net.LookupIP(domain)
|
||||
ips, err := h.dns.LookupIP(domain)
|
||||
if err != nil {
|
||||
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.
|
||||
func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dialer proxy.Dialer) error {
|
||||
destination, _ := proxy.TargetFromContext(ctx)
|
||||
if h.destOverride != nil {
|
||||
server := h.destOverride.Server
|
||||
if h.config.DestinationOverride != nil {
|
||||
server := h.config.DestinationOverride.Server
|
||||
destination = net.Destination{
|
||||
Network: destination.Network,
|
||||
Address: server.Address.AsAddress(),
|
||||
@ -86,7 +84,7 @@ func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
|
||||
input := outboundRay.OutboundInput()
|
||||
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())
|
||||
if ip != nil {
|
||||
destination = net.Destination{
|
||||
@ -113,7 +111,7 @@ func (h *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
|
||||
defer conn.Close()
|
||||
|
||||
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 {
|
||||
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 {
|
||||
return newError("failed to process request").Base(err)
|
||||
}
|
||||
timer.SetTimeout(h.policy.Timeout.DownlinkOnly.Duration())
|
||||
timer.SetTimeout(h.policy().Timeouts.DownlinkOnly)
|
||||
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 {
|
||||
return newError("failed to process response").Base(err)
|
||||
}
|
||||
timer.SetTimeout(h.policy.Timeout.UplinkOnly.Duration())
|
||||
timer.SetTimeout(h.policy().Timeouts.UplinkOnly)
|
||||
return nil
|
||||
})
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
@ -10,9 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core/app/policy"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/errors"
|
||||
@ -26,32 +24,31 @@ import (
|
||||
// Server is a HTTP proxy server.
|
||||
type Server struct {
|
||||
config *ServerConfig
|
||||
policy policy.Policy
|
||||
v *core.Instance
|
||||
}
|
||||
|
||||
// NewServer creates a new HTTP inbound handler.
|
||||
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{
|
||||
config: config,
|
||||
v: core.FromContext(ctx),
|
||||
}
|
||||
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
|
||||
})
|
||||
if s.v == nil {
|
||||
return nil, newError("V is not in context.")
|
||||
}
|
||||
|
||||
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 {
|
||||
return net.NetworkList{
|
||||
Network: []net.Network{net.Network_TCP},
|
||||
@ -104,11 +101,11 @@ type readerOnly struct {
|
||||
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)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
@ -165,14 +162,14 @@ Start:
|
||||
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"))
|
||||
if err != nil {
|
||||
return newError("failed to write back OK response").Base(err)
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -191,7 +188,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
|
||||
|
||||
requestDone := signal.ExecuteAsync(func() error {
|
||||
defer ray.InboundInput().Close()
|
||||
defer timer.SetTimeout(s.policy.Timeout.DownlinkOnly.Duration())
|
||||
defer timer.SetTimeout(s.policy().Timeouts.DownlinkOnly)
|
||||
|
||||
v2reader := buf.NewReader(conn)
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
timer.SetTimeout(s.policy.Timeout.UplinkOnly.Duration())
|
||||
timer.SetTimeout(s.policy().Timeouts.UplinkOnly)
|
||||
return nil
|
||||
})
|
||||
|
||||
@ -217,7 +214,7 @@ func (s *Server) handleConnect(ctx context.Context, request *http.Request, reade
|
||||
|
||||
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 {
|
||||
// RFC 2068 (HTTP/1.1) requires URL to be absolute URL in HTTP proxy.
|
||||
response := &http.Response{
|
||||
|
@ -10,8 +10,9 @@ package proxy
|
||||
import (
|
||||
"context"
|
||||
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/protocol"
|
||||
"v2ray.com/core/transport/internet"
|
||||
"v2ray.com/core/transport/ray"
|
||||
)
|
||||
@ -22,7 +23,7 @@ type Inbound interface {
|
||||
Network() net.NetworkList
|
||||
|
||||
// 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.
|
||||
@ -36,3 +37,20 @@ type Dialer interface {
|
||||
// Dial dials a system connection to the given destination.
|
||||
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
|
||||
}
|
||||
|
@ -3,8 +3,7 @@ package shadowsocks
|
||||
import (
|
||||
"context"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/policy"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/net"
|
||||
@ -18,8 +17,8 @@ import (
|
||||
|
||||
// Client is a inbound handler for Shadowsocks protocol
|
||||
type Client struct {
|
||||
serverPicker protocol.ServerPicker
|
||||
policyManager policy.Manager
|
||||
serverPicker protocol.ServerPicker
|
||||
v *core.Instance
|
||||
}
|
||||
|
||||
// NewClient create a new Shadowsocks client.
|
||||
@ -33,19 +32,11 @@ func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
||||
}
|
||||
client := &Client{
|
||||
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
|
||||
v: core.FromContext(ctx),
|
||||
}
|
||||
space := app.SpaceFromContext(ctx)
|
||||
if space == nil {
|
||||
return nil, newError("Space not found.")
|
||||
if client.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.")
|
||||
}
|
||||
client.policyManager = pm
|
||||
return nil
|
||||
})
|
||||
|
||||
return client, nil
|
||||
}
|
||||
@ -103,9 +94,9 @@ func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, diale
|
||||
request.Option |= RequestOptionOneTimeAuth
|
||||
}
|
||||
|
||||
sessionPolicy := v.policyManager.GetPolicy(user.Level)
|
||||
sessionPolicy := v.v.PolicyManager().ForLevel(user.Level)
|
||||
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 {
|
||||
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 {
|
||||
defer timer.SetTimeout(sessionPolicy.Timeout.DownlinkOnly.Duration())
|
||||
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||
return buf.Copy(outboundRay.OutboundInput(), bodyWriter, buf.UpdateActivity(timer))
|
||||
})
|
||||
|
||||
responseDone := signal.ExecuteAsync(func() error {
|
||||
defer outboundRay.OutboundOutput().Close()
|
||||
defer timer.SetTimeout(sessionPolicy.Timeout.UplinkOnly.Duration())
|
||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||
|
||||
responseReader, err := ReadTCPResponse(user, conn)
|
||||
if err != nil {
|
||||
@ -164,7 +155,7 @@ func (v *Client) Process(ctx context.Context, outboundRay ray.OutboundRay, diale
|
||||
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 nil
|
||||
|
@ -140,6 +140,9 @@ func (v *AesCfb) EncodePacket(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())
|
||||
stream := crypto.NewAesDecryptionStream(key, iv)
|
||||
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 {
|
||||
if b.Len() <= c.IVSize() {
|
||||
return newError("insufficient data: ", b.Len())
|
||||
}
|
||||
ivLen := c.IVSize()
|
||||
payloadLen := b.Len()
|
||||
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 {
|
||||
if b.Len() <= v.IVSize() {
|
||||
return newError("insufficient data: ", b.Len())
|
||||
}
|
||||
iv := b.BytesTo(v.IVSize())
|
||||
stream := crypto.NewChaCha20Stream(key, iv)
|
||||
stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
|
||||
|
@ -4,9 +4,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core/app/policy"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/log"
|
||||
@ -19,18 +17,14 @@ import (
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
config *ServerConfig
|
||||
user *protocol.User
|
||||
account *MemoryAccount
|
||||
policyManager policy.Manager
|
||||
config *ServerConfig
|
||||
user *protocol.User
|
||||
account *MemoryAccount
|
||||
v *core.Instance
|
||||
}
|
||||
|
||||
// NewServer create a new Shadowsocks server.
|
||||
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 {
|
||||
return nil, newError("user is not specified")
|
||||
}
|
||||
@ -45,16 +39,12 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
||||
config: config,
|
||||
user: config.GetUser(),
|
||||
account: account,
|
||||
v: core.FromContext(ctx),
|
||||
}
|
||||
|
||||
space.On(app.SpaceInitializing, func(interface{}) error {
|
||||
pm := policy.FromSpace(space)
|
||||
if pm == nil {
|
||||
return newError("Policy not found in space.")
|
||||
}
|
||||
s.policyManager = pm
|
||||
return nil
|
||||
})
|
||||
if s.v == nil {
|
||||
return nil, newError("V is not in context.")
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
@ -69,7 +59,7 @@ func (s *Server) Network() net.NetworkList {
|
||||
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 {
|
||||
case net.Network_TCP:
|
||||
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)
|
||||
|
||||
reader := buf.NewReader(conn)
|
||||
@ -148,9 +138,9 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher dispatcher.Interface) error {
|
||||
sessionPolicy := s.policyManager.GetPolicy(s.user.Level)
|
||||
conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeout.Handshake.Duration()))
|
||||
func (s *Server) handleConnection(ctx context.Context, conn internet.Connection, dispatcher core.Dispatcher) error {
|
||||
sessionPolicy := s.v.PolicyManager().ForLevel(s.user.Level)
|
||||
conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake))
|
||||
bufferedReader := buf.NewBufferedReader(buf.NewReader(conn))
|
||||
request, bodyReader, err := ReadTCPSession(s.user, bufferedReader)
|
||||
if err != nil {
|
||||
@ -178,7 +168,7 @@ func (s *Server) handleConnection(ctx context.Context, conn internet.Connection,
|
||||
ctx = protocol.ContextWithUser(ctx, request.User)
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
timer.SetTimeout(sessionPolicy.Timeout.UplinkOnly.Duration())
|
||||
timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||
|
||||
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 {
|
||||
return newError("failed to transport all TCP request").Base(err)
|
||||
}
|
||||
timer.SetTimeout(sessionPolicy.Timeout.DownlinkOnly.Duration())
|
||||
timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||
return nil
|
||||
})
|
||||
|
||||
|
@ -5,9 +5,7 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core/app/policy"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/log"
|
||||
@ -22,32 +20,30 @@ import (
|
||||
// Server is a SOCKS 5 proxy server
|
||||
type Server struct {
|
||||
config *ServerConfig
|
||||
policy policy.Policy
|
||||
v *core.Instance
|
||||
}
|
||||
|
||||
// NewServer creates a new Server object.
|
||||
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{
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
list := net.NetworkList{
|
||||
Network: []net.Network{net.Network_TCP},
|
||||
@ -58,7 +54,7 @@ func (s *Server) Network() net.NetworkList {
|
||||
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 {
|
||||
case net.Network_TCP:
|
||||
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 {
|
||||
conn.SetReadDeadline(time.Now().Add(s.policy.Timeout.Handshake.Duration()))
|
||||
func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispatcher core.Dispatcher) error {
|
||||
conn.SetReadDeadline(time.Now().Add(s.policy().Timeouts.Handshake))
|
||||
reader := buf.NewBufferedReader(buf.NewReader(conn))
|
||||
|
||||
inboundDest, ok := proxy.InboundEntryPointFromContext(ctx)
|
||||
@ -125,9 +121,9 @@ func (*Server) handleUDP(c net.Conn) error {
|
||||
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)
|
||||
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)
|
||||
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 {
|
||||
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
|
||||
})
|
||||
|
||||
@ -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 {
|
||||
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
|
||||
})
|
||||
|
||||
@ -166,7 +162,7 @@ func (v *Server) transport(ctx context.Context, reader io.Reader, writer io.Writ
|
||||
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)
|
||||
|
||||
if source, ok := proxy.SourceFromContext(ctx); ok {
|
||||
|
@ -31,8 +31,7 @@ func (a *InternalAccount) Equals(account protocol.Account) bool {
|
||||
func (a *Account) AsAccount() (protocol.Account, error) {
|
||||
id, err := uuid.ParseString(a.Id)
|
||||
if err != nil {
|
||||
newError("failed to parse ID").Base(err).AtError().WriteToLog()
|
||||
return nil, err
|
||||
return nil, newError("failed to parse ID").Base(err).AtError()
|
||||
}
|
||||
protoID := protocol.NewID(id)
|
||||
return &InternalAccount{
|
||||
|
@ -131,7 +131,7 @@ func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
|
||||
}
|
||||
if request.Security.Is(protocol.SecurityType_NONE) {
|
||||
if request.Option.Has(protocol.RequestOptionChunkStream) {
|
||||
if request.Command == protocol.RequestCommandTCP {
|
||||
if request.Command.TransferType() == protocol.TransferTypeStream {
|
||||
return crypto.NewChunkStreamWriter(sizeParser, writer)
|
||||
}
|
||||
auth := &crypto.AEADAuthenticator{
|
||||
@ -236,7 +236,7 @@ func (c *ClientSession) DecodeResponseBody(request *protocol.RequestHeader, read
|
||||
}
|
||||
if request.Security.Is(protocol.SecurityType_NONE) {
|
||||
if request.Option.Has(protocol.RequestOptionChunkStream) {
|
||||
if request.Command == protocol.RequestCommandTCP {
|
||||
if request.Command.TransferType() == protocol.TransferTypeStream {
|
||||
return crypto.NewChunkStreamReader(sizeParser, reader)
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package encoding_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"v2ray.com/core/common"
|
||||
@ -22,8 +21,9 @@ func TestRequestSerialization(t *testing.T) {
|
||||
Level: 0,
|
||||
Email: "test@v2ray.com",
|
||||
}
|
||||
id := uuid.New()
|
||||
account := &vmess.Account{
|
||||
Id: uuid.New().String(),
|
||||
Id: id.String(),
|
||||
AlterId: 0,
|
||||
}
|
||||
user.Account = serial.ToTypedMessage(account)
|
||||
@ -44,11 +44,12 @@ func TestRequestSerialization(t *testing.T) {
|
||||
buffer2 := buf.New()
|
||||
buffer2.Append(buffer.Bytes())
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
sessionHistory := NewSessionHistory(ctx)
|
||||
sessionHistory := NewSessionHistory()
|
||||
defer common.Close(sessionHistory)
|
||||
|
||||
userValidator := vmess.NewTimedUserValidator(ctx, protocol.DefaultIDHash)
|
||||
userValidator := vmess.NewTimedUserValidator(protocol.DefaultIDHash)
|
||||
userValidator.Add(user)
|
||||
defer common.Close(userValidator)
|
||||
|
||||
server := NewServerSession(userValidator, sessionHistory)
|
||||
actualRequest, err := server.DecodeRequestHeader(buffer)
|
||||
@ -64,6 +65,91 @@ func TestRequestSerialization(t *testing.T) {
|
||||
_, err = server.DecodeRequestHeader(buffer2)
|
||||
// anti replay attack
|
||||
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))
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package encoding
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
@ -10,6 +9,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/common/dice"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/bitmask"
|
||||
@ -31,29 +32,34 @@ type sessionId struct {
|
||||
type SessionHistory struct {
|
||||
sync.RWMutex
|
||||
cache map[sessionId]time.Time
|
||||
token *signal.Semaphore
|
||||
ctx context.Context
|
||||
task *signal.PeriodicTask
|
||||
}
|
||||
|
||||
func NewSessionHistory(ctx context.Context) *SessionHistory {
|
||||
func NewSessionHistory() *SessionHistory {
|
||||
h := &SessionHistory{
|
||||
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
|
||||
}
|
||||
|
||||
// Close implements common.Closable.
|
||||
func (h *SessionHistory) Close() error {
|
||||
return h.task.Close()
|
||||
}
|
||||
|
||||
func (h *SessionHistory) add(session sessionId) {
|
||||
h.Lock()
|
||||
h.cache[session] = time.Now().Add(time.Minute * 3)
|
||||
h.Unlock()
|
||||
defer h.Unlock()
|
||||
|
||||
select {
|
||||
case <-h.token.Wait():
|
||||
go h.run()
|
||||
default:
|
||||
}
|
||||
h.cache[session] = time.Now().Add(time.Minute * 3)
|
||||
}
|
||||
|
||||
func (h *SessionHistory) has(session sessionId) bool {
|
||||
@ -66,31 +72,16 @@ func (h *SessionHistory) has(session sessionId) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *SessionHistory) run() {
|
||||
defer h.token.Signal()
|
||||
func (h *SessionHistory) removeExpiredEntries() {
|
||||
now := time.Now()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-h.ctx.Done():
|
||||
return
|
||||
case <-time.After(time.Second * 30):
|
||||
}
|
||||
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 {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
|
||||
for session, expire := range h.cache {
|
||||
if expire.Before(now) {
|
||||
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) {
|
||||
buffer := buf.New()
|
||||
defer buffer.Release()
|
||||
@ -139,7 +168,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
|
||||
aesStream := crypto.NewAesDecryptionStream(vmessAccount.ID.CmdKey(), iv)
|
||||
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)
|
||||
}
|
||||
|
||||
@ -148,10 +177,6 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
|
||||
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.requestBodyKey = append([]byte(nil), buffer.BytesRange(17, 33)...) // 16 bytes
|
||||
var sid sessionId
|
||||
@ -170,33 +195,28 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request
|
||||
// 1 bytes reserved
|
||||
request.Command = protocol.RequestCommand(buffer.Byte(37))
|
||||
|
||||
if request.Command != protocol.RequestCommandMux {
|
||||
request.Port = net.PortFromBytes(buffer.BytesRange(38, 40))
|
||||
|
||||
switch protocol.AddressType(buffer.Byte(40)) {
|
||||
case protocol.AddressTypeIPv4:
|
||||
if err := buffer.AppendSupplier(buf.ReadFullFrom(decryptor, 4)); err != nil {
|
||||
return nil, newError("failed to read IPv4 address").Base(err)
|
||||
}
|
||||
request.Address = net.IPAddress(buffer.BytesFrom(-4))
|
||||
case protocol.AddressTypeIPv6:
|
||||
if err := buffer.AppendSupplier(buf.ReadFullFrom(decryptor, 16)); err != nil {
|
||||
return nil, newError("failed to read IPv6 address").Base(err)
|
||||
}
|
||||
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)))
|
||||
invalidRequest := false
|
||||
switch request.Command {
|
||||
case protocol.RequestCommandMux:
|
||||
request.Address = net.DomainAddress("v1.mux.cool")
|
||||
request.Port = 0
|
||||
case protocol.RequestCommandTCP, protocol.RequestCommandUDP:
|
||||
if addr, port, err := readAddress(buffer, decryptor); err == nil {
|
||||
request.Address = addr
|
||||
request.Port = port
|
||||
} else {
|
||||
invalidRequest = true
|
||||
newError("failed to read address").Base(err).WriteToLog()
|
||||
}
|
||||
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 {
|
||||
@ -232,7 +252,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade
|
||||
}
|
||||
if request.Security.Is(protocol.SecurityType_NONE) {
|
||||
if request.Option.Has(protocol.RequestOptionChunkStream) {
|
||||
if request.Command == protocol.RequestCommandTCP {
|
||||
if request.Command.TransferType() == protocol.TransferTypeStream {
|
||||
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.Option.Has(protocol.RequestOptionChunkStream) {
|
||||
if request.Command == protocol.RequestCommandTCP {
|
||||
if request.Command.TransferType() == protocol.TransferTypeStream {
|
||||
return crypto.NewChunkStreamWriter(sizeParser, writer)
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,11 @@ package inbound
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core/app/policy"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/errors"
|
||||
@ -28,96 +26,116 @@ import (
|
||||
)
|
||||
|
||||
type userByEmail struct {
|
||||
sync.RWMutex
|
||||
sync.Mutex
|
||||
cache map[string]*protocol.User
|
||||
defaultLevel uint32
|
||||
defaultAlterIDs uint16
|
||||
}
|
||||
|
||||
func newUserByEmail(users []*protocol.User, config *DefaultConfig) *userByEmail {
|
||||
cache := make(map[string]*protocol.User)
|
||||
for _, user := range users {
|
||||
cache[user.Email] = user
|
||||
}
|
||||
func newUserByEmail(config *DefaultConfig) *userByEmail {
|
||||
return &userByEmail{
|
||||
cache: cache,
|
||||
cache: make(map[string]*protocol.User),
|
||||
defaultLevel: config.Level,
|
||||
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) {
|
||||
var user *protocol.User
|
||||
var found bool
|
||||
v.RLock()
|
||||
user, found = v.cache[email]
|
||||
v.RUnlock()
|
||||
email = strings.ToLower(email)
|
||||
|
||||
v.Lock()
|
||||
defer v.Unlock()
|
||||
|
||||
user, found := v.cache[email]
|
||||
if !found {
|
||||
v.Lock()
|
||||
user, found = v.cache[email]
|
||||
if !found {
|
||||
account := &vmess.Account{
|
||||
Id: uuid.New().String(),
|
||||
AlterId: uint32(v.defaultAlterIDs),
|
||||
}
|
||||
user = &protocol.User{
|
||||
Level: v.defaultLevel,
|
||||
Email: email,
|
||||
Account: serial.ToTypedMessage(account),
|
||||
}
|
||||
v.cache[email] = user
|
||||
id := uuid.New()
|
||||
account := &vmess.Account{
|
||||
Id: id.String(),
|
||||
AlterId: uint32(v.defaultAlterIDs),
|
||||
}
|
||||
v.Unlock()
|
||||
user = &protocol.User{
|
||||
Level: v.defaultLevel,
|
||||
Email: email,
|
||||
Account: serial.ToTypedMessage(account),
|
||||
}
|
||||
v.cache[email] = user
|
||||
}
|
||||
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.
|
||||
type Handler struct {
|
||||
inboundHandlerManager proxyman.InboundHandlerManager
|
||||
policyManager core.PolicyManager
|
||||
inboundHandlerManager core.InboundHandlerManager
|
||||
clients protocol.UserValidator
|
||||
usersByEmail *userByEmail
|
||||
detours *DetourConfig
|
||||
sessionHistory *encoding.SessionHistory
|
||||
policyManager policy.Manager
|
||||
}
|
||||
|
||||
// New creates a new VMess inbound handler.
|
||||
func New(ctx context.Context, config *Config) (*Handler, error) {
|
||||
space := app.SpaceFromContext(ctx)
|
||||
if space == nil {
|
||||
return nil, newError("no space in context")
|
||||
v := core.FromContext(ctx)
|
||||
if v == nil {
|
||||
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 {
|
||||
if err := allowedClients.Add(user); err != nil {
|
||||
if err := handler.AddUser(ctx, user); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
// 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().
|
||||
func (*Handler) Network() net.NetworkList {
|
||||
return net.NetworkList{
|
||||
@ -133,6 +151,24 @@ func (h *Handler) GetUser(email string) *protocol.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 {
|
||||
defer output.Close()
|
||||
|
||||
@ -179,9 +215,9 @@ func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSess
|
||||
}
|
||||
|
||||
// Process implements proxy.Inbound.Process().
|
||||
func (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher dispatcher.Interface) error {
|
||||
sessionPolicy := h.policyManager.GetPolicy(0)
|
||||
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeout.Handshake.Duration())); err != nil {
|
||||
func (h *Handler) Process(ctx context.Context, network net.Network, connection internet.Connection, dispatcher core.Dispatcher) error {
|
||||
sessionPolicy := h.policyManager.ForLevel(0)
|
||||
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||
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,
|
||||
Reason: err,
|
||||
})
|
||||
newError("invalid request from ", connection.RemoteAddr(), ": ", err).AtInfo().WriteToLog()
|
||||
err = newError("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if request.Command == protocol.RequestCommandMux {
|
||||
request.Address = net.DomainAddress("v1.mux.com")
|
||||
request.Port = net.Port(0)
|
||||
}
|
||||
|
||||
log.Record(&log.AccessMessage{
|
||||
From: connection.RemoteAddr(),
|
||||
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()
|
||||
}
|
||||
|
||||
sessionPolicy = h.policyManager.GetPolicy(request.User.Level)
|
||||
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
|
||||
ctx = protocol.ContextWithUser(ctx, request.User)
|
||||
|
||||
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())
|
||||
if err != nil {
|
||||
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()
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
responseDone := signal.ExecuteAsync(func() error {
|
||||
writer := buf.NewBufferedWriter(buf.NewWriter(connection))
|
||||
defer writer.Flush()
|
||||
defer timer.SetTimeout(sessionPolicy.Timeout.UplinkOnly.Duration())
|
||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||
|
||||
response := &protocol.ResponseHeader{
|
||||
Command: h.generateCommand(ctx, request),
|
||||
@ -265,7 +296,7 @@ func (h *Handler) generateCommand(ctx context.Context, request *protocol.Request
|
||||
if h.inboundHandlerManager != nil {
|
||||
handler, err := h.inboundHandlerManager.GetHandler(ctx, tag)
|
||||
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
|
||||
}
|
||||
proxyHandler, port, availableMin := handler.GetRandomInboundProxy()
|
||||
|
@ -6,8 +6,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/app"
|
||||
"v2ray.com/core/app/policy"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/buf"
|
||||
"v2ray.com/core/common/net"
|
||||
@ -23,17 +22,12 @@ import (
|
||||
|
||||
// Handler is an outbound connection handler for VMess protocol.
|
||||
type Handler struct {
|
||||
serverList *protocol.ServerList
|
||||
serverPicker protocol.ServerPicker
|
||||
policyManager policy.Manager
|
||||
serverList *protocol.ServerList
|
||||
serverPicker protocol.ServerPicker
|
||||
v *core.Instance
|
||||
}
|
||||
|
||||
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()
|
||||
for _, rec := range config.Receiver {
|
||||
serverList.AddServer(protocol.NewServerSpecFromPB(*rec))
|
||||
@ -41,16 +35,12 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
||||
handler := &Handler{
|
||||
serverList: serverList,
|
||||
serverPicker: protocol.NewRoundRobinServerPicker(serverList),
|
||||
v: core.FromContext(ctx),
|
||||
}
|
||||
|
||||
space.On(app.SpaceInitializing, func(interface{}) error {
|
||||
pm := policy.FromSpace(space)
|
||||
if pm == nil {
|
||||
return newError("Policy is not found in space.")
|
||||
}
|
||||
handler.policyManager = pm
|
||||
return nil
|
||||
})
|
||||
if handler.v == nil {
|
||||
return nil, newError("V is not in context.")
|
||||
}
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
@ -85,9 +75,9 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
|
||||
if target.Network == net.Network_UDP {
|
||||
command = protocol.RequestCommandUDP
|
||||
}
|
||||
if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.com" {
|
||||
command = protocol.RequestCommandMux
|
||||
}
|
||||
//if target.Address.Family().IsDomain() && target.Address.Domain() == "v1.mux.cool" {
|
||||
// command = protocol.RequestCommandMux
|
||||
//}
|
||||
request := &protocol.RequestHeader{
|
||||
Version: encoding.Version,
|
||||
User: rec.PickUser(),
|
||||
@ -112,10 +102,10 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
|
||||
output := outboundRay.OutboundOutput()
|
||||
|
||||
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)
|
||||
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeout.ConnectionIdle.Duration())
|
||||
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)
|
||||
|
||||
requestDone := signal.ExecuteAsync(func() error {
|
||||
writer := buf.NewBufferedWriter(buf.NewWriter(conn))
|
||||
@ -148,13 +138,13 @@ func (v *Handler) Process(ctx context.Context, outboundRay ray.OutboundRay, dial
|
||||
return err
|
||||
}
|
||||
}
|
||||
timer.SetTimeout(sessionPolicy.Timeout.DownlinkOnly.Duration())
|
||||
timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
||||
return nil
|
||||
})
|
||||
|
||||
responseDone := signal.ExecuteAsync(func() error {
|
||||
defer output.Close()
|
||||
defer timer.SetTimeout(sessionPolicy.Timeout.UplinkOnly.Duration())
|
||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||
|
||||
reader := buf.NewBufferedReader(buf.NewReader(conn))
|
||||
header, err := session.DecodeResponseHeader(reader)
|
||||
|
@ -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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/protocol"
|
||||
"v2ray.com/core/common/signal"
|
||||
)
|
||||
|
||||
const (
|
||||
updateIntervalSec = 10
|
||||
cacheDurationSec = 120
|
||||
updateInterval = 10 * time.Second
|
||||
cacheDurationSec = 120
|
||||
)
|
||||
|
||||
type idEntry struct {
|
||||
id *protocol.ID
|
||||
userIdx int
|
||||
lastSec protocol.Timestamp
|
||||
lastSecRemoval protocol.Timestamp
|
||||
type user struct {
|
||||
user *protocol.User
|
||||
account *InternalAccount
|
||||
lastSec protocol.Timestamp
|
||||
}
|
||||
|
||||
type TimedUserValidator struct {
|
||||
sync.RWMutex
|
||||
validUsers []*protocol.User
|
||||
userHash map[[16]byte]indexTimePair
|
||||
ids []*idEntry
|
||||
hasher protocol.IDHash
|
||||
baseTime protocol.Timestamp
|
||||
users []*user
|
||||
userHash map[[16]byte]indexTimePair
|
||||
hasher protocol.IDHash
|
||||
baseTime protocol.Timestamp
|
||||
task *signal.PeriodicTask
|
||||
}
|
||||
|
||||
type indexTimePair struct {
|
||||
index int
|
||||
user *user
|
||||
timeInc uint32
|
||||
}
|
||||
|
||||
func NewTimedUserValidator(ctx context.Context, hasher protocol.IDHash) protocol.UserValidator {
|
||||
tus := &TimedUserValidator{
|
||||
validUsers: make([]*protocol.User, 0, 16),
|
||||
userHash: make(map[[16]byte]indexTimePair, 512),
|
||||
ids: make([]*idEntry, 0, 512),
|
||||
hasher: hasher,
|
||||
baseTime: protocol.Timestamp(time.Now().Unix() - cacheDurationSec*3),
|
||||
func NewTimedUserValidator(hasher protocol.IDHash) protocol.UserValidator {
|
||||
tuv := &TimedUserValidator{
|
||||
users: make([]*user, 0, 16),
|
||||
userHash: make(map[[16]byte]indexTimePair, 1024),
|
||||
hasher: hasher,
|
||||
baseTime: protocol.Timestamp(time.Now().Unix() - cacheDurationSec*3),
|
||||
}
|
||||
go tus.updateUserHash(ctx, updateIntervalSec*time.Second)
|
||||
return tus
|
||||
tuv.task = &signal.PeriodicTask{
|
||||
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 hashValueRemoval [16]byte
|
||||
idHash := v.hasher(entry.id.Bytes())
|
||||
for entry.lastSec <= nowSec {
|
||||
common.Must2(idHash.Write(entry.lastSec.Bytes(nil)))
|
||||
idHash.Sum(hashValue[:0])
|
||||
idHash.Reset()
|
||||
genHashForID := func(id *protocol.ID) {
|
||||
idHash := v.hasher(id.Bytes())
|
||||
for ts := user.lastSec; ts <= nowSec; ts++ {
|
||||
common.Must2(idHash.Write(ts.Bytes(nil)))
|
||||
idHash.Sum(hashValue[:0])
|
||||
idHash.Reset()
|
||||
|
||||
common.Must2(idHash.Write(entry.lastSecRemoval.Bytes(nil)))
|
||||
idHash.Sum(hashValueRemoval[:0])
|
||||
idHash.Reset()
|
||||
|
||||
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.userHash[hashValue] = indexTimePair{
|
||||
user: user,
|
||||
timeInc: uint32(ts - v.baseTime),
|
||||
}
|
||||
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()
|
||||
defer v.Unlock()
|
||||
|
||||
idx := len(v.validUsers)
|
||||
v.validUsers = append(v.validUsers, user)
|
||||
rawAccount, err := user.GetTypedAccount()
|
||||
for _, user := range v.users {
|
||||
v.generateNewHashes(nowSec, user)
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -108,24 +119,13 @@ func (v *TimedUserValidator) Add(user *protocol.User) error {
|
||||
|
||||
nowSec := time.Now().Unix()
|
||||
|
||||
entry := &idEntry{
|
||||
id: account.ID,
|
||||
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)
|
||||
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)
|
||||
uu := &user{
|
||||
user: u,
|
||||
account: account,
|
||||
lastSec: protocol.Timestamp(nowSec - cacheDurationSec),
|
||||
}
|
||||
v.users = append(v.users, uu)
|
||||
v.generateNewHashes(protocol.Timestamp(nowSec+cacheDurationSec), uu)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -138,7 +138,36 @@ func (v *TimedUserValidator) Get(userHash []byte) (*protocol.User, protocol.Time
|
||||
copy(fixedSizeHash[:], userHash)
|
||||
pair, found := v.userHash[fixedSizeHash]
|
||||
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
|
||||
}
|
||||
|
||||
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
58
proxy/vmess/vmess_test.go
Normal 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)
|
||||
}
|
@ -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
|
||||
|
||||
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}
|
||||
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"
|
||||
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 ".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")
|
||||
|
||||
function upload() {
|
||||
|
115
router.go
Normal file
115
router.go
Normal 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
|
||||
}
|
130
testing/scenarios/command_test.go
Normal file
130
testing/scenarios/command_test.go
Normal 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)
|
||||
}
|
@ -13,14 +13,17 @@ import (
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"v2ray.com/core"
|
||||
"v2ray.com/core/app/dispatcher"
|
||||
"v2ray.com/core/app/proxyman"
|
||||
"v2ray.com/core/common"
|
||||
"v2ray.com/core/common/log"
|
||||
"v2ray.com/core/common/net"
|
||||
"v2ray.com/core/common/retry"
|
||||
"v2ray.com/core/common/serial"
|
||||
)
|
||||
|
||||
func pickPort() net.Port {
|
||||
listener, err := net.Listen("tcp4", ":0")
|
||||
listener, err := net.Listen("tcp4", "127.0.0.1:0")
|
||||
common.Must(err)
|
||||
defer listener.Close()
|
||||
|
||||
@ -70,6 +73,7 @@ func InitializeServerConfig(config *core.Config) (*exec.Cmd, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config = withDefaultApps(config)
|
||||
configBytes, err := proto.Marshal(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -128,3 +132,10 @@ func CloseAllServers(servers []*exec.Cmd) {
|
||||
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
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ func TestResolveIP(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
},
|
||||
Inbound: []*proxyman.InboundHandlerConfig{
|
||||
Inbound: []*core.InboundHandlerConfig{
|
||||
{
|
||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||
PortRange: net.SinglePortRange(serverPort),
|
||||
@ -67,7 +67,7 @@ func TestResolveIP(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
Outbound: []*proxyman.OutboundHandlerConfig{
|
||||
Outbound: []*core.OutboundHandlerConfig{
|
||||
{
|
||||
ProxySettings: serial.ToTypedMessage(&blackhole.Config{}),
|
||||
},
|
||||
|
@ -40,7 +40,7 @@ func TestDokodemoTCP(t *testing.T) {
|
||||
ErrorLogType: log.LogType_Console,
|
||||
}),
|
||||
},
|
||||
Inbound: []*proxyman.InboundHandlerConfig{
|
||||
Inbound: []*core.InboundHandlerConfig{
|
||||
{
|
||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||
PortRange: net.SinglePortRange(serverPort),
|
||||
@ -57,7 +57,7 @@ func TestDokodemoTCP(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
Outbound: []*proxyman.OutboundHandlerConfig{
|
||||
Outbound: []*core.OutboundHandlerConfig{
|
||||
{
|
||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||
},
|
||||
@ -73,7 +73,7 @@ func TestDokodemoTCP(t *testing.T) {
|
||||
ErrorLogType: log.LogType_Console,
|
||||
}),
|
||||
},
|
||||
Inbound: []*proxyman.InboundHandlerConfig{
|
||||
Inbound: []*core.InboundHandlerConfig{
|
||||
{
|
||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||
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{
|
||||
Receiver: []*protocol.ServerEndpoint{
|
||||
@ -147,7 +147,7 @@ func TestDokodemoUDP(t *testing.T) {
|
||||
userID := protocol.NewID(uuid.New())
|
||||
serverPort := pickPort()
|
||||
serverConfig := &core.Config{
|
||||
Inbound: []*proxyman.InboundHandlerConfig{
|
||||
Inbound: []*core.InboundHandlerConfig{
|
||||
{
|
||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||
PortRange: net.SinglePortRange(serverPort),
|
||||
@ -164,7 +164,7 @@ func TestDokodemoUDP(t *testing.T) {
|
||||
}),
|
||||
},
|
||||
},
|
||||
Outbound: []*proxyman.OutboundHandlerConfig{
|
||||
Outbound: []*core.OutboundHandlerConfig{
|
||||
{
|
||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
|
||||
},
|
||||
@ -174,7 +174,7 @@ func TestDokodemoUDP(t *testing.T) {
|
||||
clientPort := uint32(pickPort())
|
||||
clientPortRange := uint32(5)
|
||||
clientConfig := &core.Config{
|
||||
Inbound: []*proxyman.InboundHandlerConfig{
|
||||
Inbound: []*core.InboundHandlerConfig{
|
||||
{
|
||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
||||
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{
|
||||
Receiver: []*protocol.ServerEndpoint{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user