1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-12-21 17:46:58 -05:00

prototype for balancing rules

This commit is contained in:
Darien Raymond 2018-11-07 21:08:20 +01:00
parent 874fc87498
commit 73d3be424b
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
8 changed files with 363 additions and 70 deletions

View File

@ -4,6 +4,7 @@ package outbound
import ( import (
"context" "context"
"strings"
"sync" "sync"
"v2ray.com/core" "v2ray.com/core"
@ -134,6 +135,28 @@ func (m *Manager) RemoveHandler(ctx context.Context, tag string) error {
return nil return nil
} }
func (m *Manager) Select(selectors []string) []string {
m.access.RLock()
defer m.access.RUnlock()
tags := make([]string, 0, len(selectors))
for tag := range m.taggedHandler {
match := false
for _, selector := range selectors {
if strings.HasPrefix(tag, selector) {
match = true
break
}
}
if match {
tags = append(tags, tag)
}
}
return tags
}
func init() { func init() {
common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*proxyman.OutboundConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
return New(ctx, config.(*proxyman.OutboundConfig)) return New(ctx, config.(*proxyman.OutboundConfig))

44
app/router/balancing.go Normal file
View File

@ -0,0 +1,44 @@
package router
import (
"v2ray.com/core/common/dice"
"v2ray.com/core/features/outbound"
)
type BalancingStrategy interface {
PickOutbound([]string) string
}
type RandomStrategy struct {
}
func (s *RandomStrategy) PickOutbound(tags []string) string {
n := len(tags)
if n == 0 {
panic("0 tags")
}
return tags[dice.Roll(n)]
}
type Balancer struct {
selectors []string
strategy BalancingStrategy
ohm outbound.Manager
}
func (b *Balancer) PickOutbound() (string, error) {
hs, ok := b.ohm.(outbound.HandlerSelector)
if !ok {
return "", newError("outbound.Manager is not a HandlerSelector")
}
tags := hs.Select(b.selectors)
if len(tags) == 0 {
return "", newError("no available outbounds selected")
}
tag := b.strategy.PickOutbound(tags)
if len(tag) == 0 {
return "", newError("balancing strategy returns empty tag")
}
return tag, nil
}

View File

@ -2,6 +2,8 @@ package router
import ( import (
"context" "context"
"v2ray.com/core/features/outbound"
) )
// CIDRList is an alias of []*CIDR to provide sort.Interface. // CIDRList is an alias of []*CIDR to provide sort.Interface.
@ -45,9 +47,17 @@ func (l *CIDRList) Swap(i int, j int) {
type Rule struct { type Rule struct {
Tag string Tag string
Balancer *Balancer
Condition Condition Condition Condition
} }
func (r *Rule) GetTag() (string, error) {
if r.Balancer != nil {
return r.Balancer.PickOutbound()
}
return r.Tag, nil
}
func (r *Rule) Apply(ctx context.Context) bool { func (r *Rule) Apply(ctx context.Context) bool {
return r.Condition.Apply(ctx) return r.Condition.Apply(ctx)
} }
@ -117,3 +127,10 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
return conds, nil return conds, nil
} }
func (br *BalancingRule) Build(ohm outbound.Manager) (*Balancer, error) {
return &Balancer{
selectors: br.OutboundSelector,
strategy: &RandomStrategy{},
}, nil
}

View File

@ -86,7 +86,7 @@ func (x Config_DomainStrategy) String() string {
} }
func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) { func (Config_DomainStrategy) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_6b1608360690c5fc, []int{7, 0} return fileDescriptor_6b1608360690c5fc, []int{8, 0}
} }
// Domain for routing decision. // Domain for routing decision.
@ -362,8 +362,10 @@ func (m *GeoSiteList) GetEntry() []*GeoSite {
} }
type RoutingRule struct { type RoutingRule struct {
// Tag of outbound that this rule is pointing to. // Types that are valid to be assigned to TargetTag:
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` // *RoutingRule_Tag
// *RoutingRule_BalancingTag
TargetTag isRoutingRule_TargetTag `protobuf_oneof:"target_tag"`
// List of domains for target domain matching. // List of domains for target domain matching.
Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"` Domain []*Domain `protobuf:"bytes,2,rep,name=domain,proto3" json:"domain,omitempty"`
// List of CIDRs for target IP address matching. // List of CIDRs for target IP address matching.
@ -412,9 +414,39 @@ func (m *RoutingRule) XXX_DiscardUnknown() {
var xxx_messageInfo_RoutingRule proto.InternalMessageInfo var xxx_messageInfo_RoutingRule proto.InternalMessageInfo
func (m *RoutingRule) GetTag() string { type isRoutingRule_TargetTag interface {
isRoutingRule_TargetTag()
}
type RoutingRule_Tag struct {
Tag string `protobuf:"bytes,1,opt,name=tag,proto3,oneof"`
}
type RoutingRule_BalancingTag struct {
BalancingTag string `protobuf:"bytes,12,opt,name=balancing_tag,json=balancingTag,proto3,oneof"`
}
func (*RoutingRule_Tag) isRoutingRule_TargetTag() {}
func (*RoutingRule_BalancingTag) isRoutingRule_TargetTag() {}
func (m *RoutingRule) GetTargetTag() isRoutingRule_TargetTag {
if m != nil { if m != nil {
return m.Tag return m.TargetTag
}
return nil
}
func (m *RoutingRule) GetTag() string {
if x, ok := m.GetTargetTag().(*RoutingRule_Tag); ok {
return x.Tag
}
return ""
}
func (m *RoutingRule) GetBalancingTag() string {
if x, ok := m.GetTargetTag().(*RoutingRule_BalancingTag); ok {
return x.BalancingTag
} }
return "" return ""
} }
@ -491,9 +523,123 @@ func (m *RoutingRule) GetProtocol() []string {
return nil return nil
} }
// XXX_OneofFuncs is for the internal use of the proto package.
func (*RoutingRule) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _RoutingRule_OneofMarshaler, _RoutingRule_OneofUnmarshaler, _RoutingRule_OneofSizer, []interface{}{
(*RoutingRule_Tag)(nil),
(*RoutingRule_BalancingTag)(nil),
}
}
func _RoutingRule_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*RoutingRule)
// target_tag
switch x := m.TargetTag.(type) {
case *RoutingRule_Tag:
b.EncodeVarint(1<<3 | proto.WireBytes)
b.EncodeStringBytes(x.Tag)
case *RoutingRule_BalancingTag:
b.EncodeVarint(12<<3 | proto.WireBytes)
b.EncodeStringBytes(x.BalancingTag)
case nil:
default:
return fmt.Errorf("RoutingRule.TargetTag has unexpected type %T", x)
}
return nil
}
func _RoutingRule_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*RoutingRule)
switch tag {
case 1: // target_tag.tag
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeStringBytes()
m.TargetTag = &RoutingRule_Tag{x}
return true, err
case 12: // target_tag.balancing_tag
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
x, err := b.DecodeStringBytes()
m.TargetTag = &RoutingRule_BalancingTag{x}
return true, err
default:
return false, nil
}
}
func _RoutingRule_OneofSizer(msg proto.Message) (n int) {
m := msg.(*RoutingRule)
// target_tag
switch x := m.TargetTag.(type) {
case *RoutingRule_Tag:
n += 1 // tag and wire
n += proto.SizeVarint(uint64(len(x.Tag)))
n += len(x.Tag)
case *RoutingRule_BalancingTag:
n += 1 // tag and wire
n += proto.SizeVarint(uint64(len(x.BalancingTag)))
n += len(x.BalancingTag)
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
type BalancingRule struct {
Tag string `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
OutboundSelector []string `protobuf:"bytes,2,rep,name=outbound_selector,json=outboundSelector,proto3" json:"outbound_selector,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BalancingRule) Reset() { *m = BalancingRule{} }
func (m *BalancingRule) String() string { return proto.CompactTextString(m) }
func (*BalancingRule) ProtoMessage() {}
func (*BalancingRule) Descriptor() ([]byte, []int) {
return fileDescriptor_6b1608360690c5fc, []int{7}
}
func (m *BalancingRule) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BalancingRule.Unmarshal(m, b)
}
func (m *BalancingRule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BalancingRule.Marshal(b, m, deterministic)
}
func (m *BalancingRule) XXX_Merge(src proto.Message) {
xxx_messageInfo_BalancingRule.Merge(m, src)
}
func (m *BalancingRule) XXX_Size() int {
return xxx_messageInfo_BalancingRule.Size(m)
}
func (m *BalancingRule) XXX_DiscardUnknown() {
xxx_messageInfo_BalancingRule.DiscardUnknown(m)
}
var xxx_messageInfo_BalancingRule proto.InternalMessageInfo
func (m *BalancingRule) GetTag() string {
if m != nil {
return m.Tag
}
return ""
}
func (m *BalancingRule) GetOutboundSelector() []string {
if m != nil {
return m.OutboundSelector
}
return nil
}
type Config struct { type Config struct {
DomainStrategy Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=v2ray.core.app.router.Config_DomainStrategy" json:"domain_strategy,omitempty"` DomainStrategy Config_DomainStrategy `protobuf:"varint,1,opt,name=domain_strategy,json=domainStrategy,proto3,enum=v2ray.core.app.router.Config_DomainStrategy" json:"domain_strategy,omitempty"`
Rule []*RoutingRule `protobuf:"bytes,2,rep,name=rule,proto3" json:"rule,omitempty"` Rule []*RoutingRule `protobuf:"bytes,2,rep,name=rule,proto3" json:"rule,omitempty"`
BalancingRule []*BalancingRule `protobuf:"bytes,3,rep,name=balancing_rule,json=balancingRule,proto3" json:"balancing_rule,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -503,7 +649,7 @@ func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) } func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {} func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) { func (*Config) Descriptor() ([]byte, []int) {
return fileDescriptor_6b1608360690c5fc, []int{7} return fileDescriptor_6b1608360690c5fc, []int{8}
} }
func (m *Config) XXX_Unmarshal(b []byte) error { func (m *Config) XXX_Unmarshal(b []byte) error {
@ -538,6 +684,13 @@ func (m *Config) GetRule() []*RoutingRule {
return nil return nil
} }
func (m *Config) GetBalancingRule() []*BalancingRule {
if m != nil {
return m.BalancingRule
}
return nil
}
func init() { func init() {
proto.RegisterEnum("v2ray.core.app.router.Domain_Type", Domain_Type_name, Domain_Type_value) proto.RegisterEnum("v2ray.core.app.router.Domain_Type", Domain_Type_name, Domain_Type_value)
proto.RegisterEnum("v2ray.core.app.router.Config_DomainStrategy", Config_DomainStrategy_name, Config_DomainStrategy_value) proto.RegisterEnum("v2ray.core.app.router.Config_DomainStrategy", Config_DomainStrategy_name, Config_DomainStrategy_value)
@ -548,6 +701,7 @@ func init() {
proto.RegisterType((*GeoSite)(nil), "v2ray.core.app.router.GeoSite") proto.RegisterType((*GeoSite)(nil), "v2ray.core.app.router.GeoSite")
proto.RegisterType((*GeoSiteList)(nil), "v2ray.core.app.router.GeoSiteList") proto.RegisterType((*GeoSiteList)(nil), "v2ray.core.app.router.GeoSiteList")
proto.RegisterType((*RoutingRule)(nil), "v2ray.core.app.router.RoutingRule") proto.RegisterType((*RoutingRule)(nil), "v2ray.core.app.router.RoutingRule")
proto.RegisterType((*BalancingRule)(nil), "v2ray.core.app.router.BalancingRule")
proto.RegisterType((*Config)(nil), "v2ray.core.app.router.Config") proto.RegisterType((*Config)(nil), "v2ray.core.app.router.Config")
} }
@ -556,49 +710,54 @@ func init() {
} }
var fileDescriptor_6b1608360690c5fc = []byte{ var fileDescriptor_6b1608360690c5fc = []byte{
// 691 bytes of a gzipped FileDescriptorProto // 776 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xdd, 0x6e, 0xd3, 0x4c, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xdd, 0x6e, 0xeb, 0x44,
0x10, 0xfd, 0xec, 0xfc, 0xb4, 0x1e, 0xe7, 0x0b, 0xd6, 0x8a, 0x22, 0x53, 0x28, 0x04, 0x0b, 0x41, 0x10, 0x3e, 0x76, 0x7e, 0x4e, 0x3d, 0x76, 0x83, 0x59, 0x71, 0x90, 0x29, 0x14, 0x82, 0x55, 0x20,
0x2e, 0x90, 0x23, 0xa5, 0xc0, 0x1d, 0x2a, 0x6d, 0x5a, 0xa2, 0x48, 0x50, 0xa2, 0x6d, 0xcb, 0x05, 0x12, 0xc8, 0x91, 0x52, 0xe0, 0x0e, 0x95, 0x26, 0x2d, 0x21, 0x02, 0x4a, 0xb4, 0x6d, 0xb9, 0x80,
0x5c, 0x44, 0xae, 0xb3, 0x35, 0x16, 0xce, 0xee, 0x6a, 0xbd, 0x2e, 0xcd, 0x2b, 0xf0, 0x20, 0x5c, 0x8b, 0x68, 0xeb, 0x6c, 0x8d, 0x85, 0xb3, 0xbb, 0x5a, 0xaf, 0x4b, 0xf3, 0x0a, 0x3c, 0x0a, 0x12,
0xf0, 0x54, 0x3c, 0x0a, 0xda, 0x9f, 0x40, 0x8b, 0x1a, 0x88, 0xb8, 0xdb, 0x59, 0x9f, 0x33, 0x73, 0x8f, 0xc4, 0xbb, 0xa0, 0xdd, 0x75, 0xda, 0x06, 0xd5, 0x10, 0x9d, 0xbb, 0x9d, 0xd9, 0x6f, 0x66,
0xe6, 0x78, 0x76, 0xe0, 0xd1, 0x79, 0x5f, 0x24, 0xf3, 0x38, 0x65, 0xb3, 0x5e, 0xca, 0x04, 0xe9, 0xbe, 0xf9, 0x85, 0x8f, 0xef, 0x46, 0x92, 0xac, 0x93, 0x94, 0xaf, 0x86, 0x29, 0x97, 0x74, 0x48,
0x25, 0x9c, 0xf7, 0x04, 0xab, 0x24, 0x11, 0xbd, 0x94, 0xd1, 0xb3, 0x3c, 0x8b, 0xb9, 0x60, 0x92, 0x84, 0x18, 0x4a, 0x5e, 0x29, 0x2a, 0x87, 0x29, 0x67, 0xb7, 0x79, 0x96, 0x08, 0xc9, 0x15, 0x47,
0xa1, 0x8d, 0x05, 0x4e, 0x90, 0x38, 0xe1, 0x3c, 0x36, 0x98, 0xcd, 0x87, 0xbf, 0xd1, 0x53, 0x36, 0xaf, 0x36, 0x38, 0x49, 0x13, 0x22, 0x44, 0x62, 0x31, 0x07, 0x47, 0xff, 0x32, 0x4f, 0xf9, 0x6a,
0x9b, 0x31, 0xda, 0xa3, 0x44, 0xf6, 0x38, 0x13, 0xd2, 0x90, 0x37, 0x1f, 0x2f, 0x47, 0x51, 0x22, 0xc5, 0xd9, 0x90, 0x51, 0x35, 0x14, 0x5c, 0x2a, 0x6b, 0x7c, 0xf0, 0x49, 0x33, 0x8a, 0x51, 0xf5,
0x3f, 0x33, 0xf1, 0xc9, 0x00, 0xa3, 0x2f, 0x0e, 0x34, 0xf7, 0xd9, 0x2c, 0xc9, 0x29, 0x7a, 0x0e, 0x3b, 0x97, 0xbf, 0x59, 0x60, 0xfc, 0x87, 0x03, 0xdd, 0x33, 0xbe, 0x22, 0x39, 0x43, 0x5f, 0x42,
0x75, 0x39, 0xe7, 0x24, 0x74, 0x3a, 0x4e, 0xb7, 0xdd, 0x8f, 0xe2, 0x6b, 0xeb, 0xc7, 0x06, 0x1c, 0x5b, 0xad, 0x05, 0x8d, 0x9c, 0xbe, 0x33, 0xe8, 0x8d, 0xe2, 0xe4, 0xd9, 0xf8, 0x89, 0x05, 0x27,
0x1f, 0xcf, 0x39, 0xc1, 0x1a, 0x8f, 0x6e, 0x42, 0xe3, 0x3c, 0x29, 0x2a, 0x12, 0xba, 0x1d, 0xa7, 0x57, 0x6b, 0x41, 0xb1, 0xc1, 0xa3, 0xb7, 0xa0, 0x73, 0x47, 0x8a, 0x8a, 0x46, 0x6e, 0xdf, 0x19,
0xeb, 0x61, 0x13, 0x44, 0x7d, 0xa8, 0x2b, 0x0c, 0xf2, 0xa0, 0x31, 0x2e, 0x92, 0x9c, 0x06, 0xff, 0x78, 0xd8, 0x0a, 0xf1, 0x08, 0xda, 0x1a, 0x83, 0x3c, 0xe8, 0xcc, 0x0b, 0x92, 0xb3, 0xf0, 0x85,
0xa9, 0x23, 0x26, 0x19, 0xb9, 0x08, 0x1c, 0x04, 0x8b, 0xaa, 0x81, 0x8b, 0xd6, 0xa1, 0xfe, 0xaa, 0x7e, 0x62, 0x9a, 0xd1, 0xfb, 0xd0, 0x41, 0xb0, 0x89, 0x1a, 0xba, 0x68, 0x0f, 0xda, 0xdf, 0x54,
0x2a, 0x8a, 0xa0, 0x16, 0xc5, 0x50, 0x1f, 0x8c, 0xf6, 0x31, 0x6a, 0x83, 0x9b, 0x73, 0xad, 0xa3, 0x45, 0x11, 0xb6, 0xe2, 0x04, 0xda, 0x93, 0xd9, 0x19, 0x46, 0x3d, 0x70, 0x73, 0x61, 0x78, 0x04,
0x85, 0xdd, 0x9c, 0xa3, 0x5b, 0xd0, 0xe4, 0x82, 0x9c, 0xe5, 0x17, 0xba, 0xc4, 0xff, 0xd8, 0x46, 0xd8, 0xcd, 0x05, 0x7a, 0x1b, 0xba, 0x42, 0xd2, 0xdb, 0xfc, 0xde, 0x84, 0xd8, 0xc7, 0xb5, 0x14,
0xd1, 0x07, 0x68, 0x0c, 0x09, 0x1b, 0x8d, 0xd1, 0x03, 0x68, 0xa5, 0xac, 0xa2, 0x52, 0xcc, 0x27, 0xff, 0x02, 0x9d, 0x29, 0xe5, 0xb3, 0x39, 0xfa, 0x10, 0x82, 0x94, 0x57, 0x4c, 0xc9, 0xf5, 0x22,
0x29, 0x9b, 0x9a, 0x16, 0x3c, 0xec, 0xdb, 0xbb, 0x01, 0x9b, 0x12, 0xd4, 0x83, 0x7a, 0x9a, 0x4f, 0xe5, 0x4b, 0x9b, 0x82, 0x87, 0xfd, 0x5a, 0x37, 0xe1, 0x4b, 0x8a, 0x86, 0xd0, 0x4e, 0xf3, 0xa5,
0x45, 0xe8, 0x76, 0x6a, 0x5d, 0xbf, 0x7f, 0x67, 0x49, 0x77, 0xaa, 0x3c, 0xd6, 0xc0, 0x68, 0x07, 0x8c, 0xdc, 0x7e, 0x6b, 0xe0, 0x8f, 0xde, 0x6d, 0xc8, 0x4e, 0x87, 0xc7, 0x06, 0x18, 0x9f, 0x80,
0x3c, 0x9d, 0xfc, 0x75, 0x5e, 0x4a, 0xd4, 0x87, 0x06, 0x51, 0xa9, 0x42, 0x47, 0xd3, 0xef, 0x2e, 0x67, 0x9c, 0x7f, 0x9f, 0x97, 0x0a, 0x8d, 0xa0, 0x43, 0xb5, 0xab, 0xc8, 0x31, 0xe6, 0xef, 0x35,
0xa1, 0x6b, 0x02, 0x36, 0xd0, 0x28, 0x85, 0xb5, 0x21, 0x61, 0x47, 0xb9, 0x24, 0xab, 0xe8, 0x7b, 0x98, 0x1b, 0x03, 0x6c, 0xa1, 0x71, 0x0a, 0x2f, 0xa7, 0x94, 0x5f, 0xe6, 0x8a, 0xee, 0xc2, 0xef,
0x06, 0xcd, 0xa9, 0x76, 0xc4, 0x2a, 0xdc, 0xfa, 0xa3, 0xff, 0xd8, 0x82, 0xa3, 0x01, 0xf8, 0xb6, 0x0b, 0xe8, 0x2e, 0x4d, 0x45, 0x6a, 0x86, 0x87, 0xff, 0x59, 0x7f, 0x5c, 0x83, 0xe3, 0x09, 0xf8,
0x88, 0xd6, 0xf9, 0xf4, 0xaa, 0xce, 0x7b, 0xcb, 0x75, 0x2a, 0xca, 0x42, 0xe9, 0xd7, 0x3a, 0xf8, 0x75, 0x10, 0xc3, 0xf3, 0xf3, 0x6d, 0x9e, 0xef, 0x37, 0xf3, 0xd4, 0x26, 0x1b, 0xa6, 0x7f, 0xb7,
0x98, 0x55, 0x32, 0xa7, 0x19, 0xae, 0x0a, 0x82, 0x02, 0xa8, 0xc9, 0x24, 0xb3, 0x2a, 0xd5, 0xf1, 0xc1, 0xc7, 0xbc, 0x52, 0x39, 0xcb, 0x70, 0x55, 0x50, 0x84, 0xa0, 0xa5, 0x48, 0x66, 0x59, 0x7e,
0x1f, 0xd5, 0xa1, 0x6d, 0x6b, 0x7a, 0xed, 0xaf, 0xa6, 0xef, 0xb9, 0xa1, 0x63, 0x8c, 0x57, 0x5e, 0xfb, 0x02, 0x6b, 0x01, 0x7d, 0x04, 0xfb, 0x37, 0xa4, 0x20, 0x2c, 0xcd, 0x59, 0xb6, 0xd0, 0xbf,
0x67, 0x84, 0xe5, 0x3c, 0x84, 0x55, 0xbc, 0xd6, 0x50, 0xb4, 0x03, 0xa0, 0xa6, 0x7f, 0x22, 0x12, 0x41, 0xfd, 0x1b, 0x3c, 0xa8, 0xaf, 0x48, 0xf6, 0x9a, 0x69, 0xa0, 0xe3, 0xba, 0x3b, 0xad, 0xff,
0x9a, 0x91, 0xb0, 0xde, 0x71, 0xba, 0x7e, 0xbf, 0x73, 0x99, 0x68, 0x1e, 0x40, 0x4c, 0x89, 0x8c, 0xed, 0xce, 0xd8, 0x8d, 0x1c, 0xdb, 0x21, 0xdd, 0x94, 0x8c, 0xf2, 0x5c, 0x44, 0xb0, 0x4b, 0x53,
0xc7, 0x4c, 0x48, 0xac, 0x70, 0xd8, 0xe3, 0x8b, 0x23, 0x3a, 0x80, 0x96, 0x7d, 0x18, 0x93, 0x22, 0x0c, 0x14, 0x9d, 0x00, 0xe8, 0x35, 0x59, 0x48, 0xc2, 0x32, 0x1a, 0xb5, 0xfb, 0xce, 0xc0, 0x1f,
0x2f, 0x65, 0xd8, 0xd0, 0x29, 0xa2, 0x25, 0x29, 0x0e, 0x0d, 0x54, 0x59, 0x8e, 0x7d, 0xfa, 0x2b, 0xf5, 0x9f, 0x1a, 0xda, 0x4d, 0x49, 0x18, 0x55, 0xc9, 0x9c, 0x4b, 0x85, 0x35, 0x0e, 0x7b, 0x62,
0x40, 0x2f, 0xc1, 0x2f, 0x59, 0x25, 0x52, 0x32, 0xd1, 0x7d, 0x37, 0x57, 0xeb, 0x1b, 0x0c, 0x67, 0xf3, 0x44, 0xe7, 0x10, 0xd4, 0x1b, 0xb4, 0x28, 0xf2, 0x52, 0x45, 0x1d, 0xe3, 0x22, 0x6e, 0x70,
0xa0, 0xba, 0xdf, 0x81, 0x96, 0xcd, 0x60, 0x4c, 0xf0, 0x57, 0x30, 0xc1, 0xd6, 0x1c, 0x6a, 0x2b, 0x71, 0x61, 0xa1, 0xba, 0x37, 0xd8, 0x67, 0x8f, 0x02, 0xfa, 0x1a, 0xfc, 0x92, 0x57, 0x32, 0xa5,
0xb6, 0x00, 0xaa, 0x92, 0x88, 0x09, 0x99, 0x25, 0x79, 0x11, 0xae, 0x75, 0x6a, 0x5d, 0x0f, 0x7b, 0x0b, 0x93, 0x77, 0x77, 0xb7, 0xbc, 0xc1, 0xda, 0x4c, 0x74, 0xf6, 0x27, 0x10, 0xd4, 0x1e, 0x6c,
0xea, 0xe6, 0x40, 0x5d, 0xa0, 0xfb, 0xe0, 0xe7, 0xf4, 0x94, 0x55, 0x74, 0x3a, 0x51, 0xff, 0x78, 0x11, 0xfc, 0x1d, 0x8a, 0x50, 0xc7, 0x9c, 0x9a, 0x52, 0x1c, 0x02, 0x54, 0x25, 0x95, 0x0b, 0xba,
0x5d, 0x7f, 0x07, 0x7b, 0x75, 0x9c, 0x64, 0x68, 0x13, 0xd6, 0xf5, 0x6a, 0x48, 0x59, 0x11, 0x7a, 0x22, 0x79, 0x11, 0xbd, 0xec, 0xb7, 0x06, 0x1e, 0xf6, 0xb4, 0xe6, 0x5c, 0x2b, 0xd0, 0x07, 0xe0,
0xfa, 0xeb, 0xcf, 0x38, 0xfa, 0xee, 0x40, 0x73, 0xa0, 0x97, 0x14, 0x3a, 0x81, 0x1b, 0xe6, 0x27, 0xe7, 0xec, 0x86, 0x57, 0x6c, 0x69, 0xda, 0xbd, 0x67, 0xfe, 0xa1, 0x56, 0xe9, 0x56, 0x1f, 0xc0,
0x4f, 0x4a, 0x29, 0x12, 0x49, 0xb2, 0xb9, 0x5d, 0x1c, 0x4f, 0x96, 0x75, 0x6b, 0x96, 0x9b, 0x99, 0x9e, 0xb9, 0x21, 0x29, 0x2f, 0x22, 0xcf, 0xfc, 0x3e, 0xc8, 0xe3, 0x00, 0x40, 0x11, 0x99, 0x51,
0x90, 0x23, 0xcb, 0xc1, 0xed, 0xe9, 0x95, 0x58, 0x2d, 0x21, 0x51, 0x15, 0xc4, 0x8e, 0xd9, 0xb2, 0xa5, 0x6d, 0xe3, 0x0b, 0xd8, 0x1f, 0x6f, 0x86, 0xc4, 0x0c, 0x58, 0xf8, 0x64, 0xc0, 0xec, 0x78,
0x25, 0x74, 0x69, 0x58, 0xb1, 0xc6, 0x47, 0x43, 0x68, 0x5f, 0xcd, 0xac, 0xd6, 0xca, 0x6e, 0x39, 0x7d, 0x0a, 0x6f, 0xf2, 0x4a, 0xd9, 0x70, 0x25, 0x2d, 0x68, 0xaa, 0xb8, 0xdd, 0x55, 0x0f, 0x87,
0x2a, 0xcd, 0xde, 0x39, 0x29, 0xc9, 0x88, 0x07, 0x0e, 0x0a, 0xa0, 0x35, 0xe2, 0xa3, 0xb3, 0x43, 0x9b, 0x8f, 0xcb, 0x5a, 0x1f, 0xff, 0xe5, 0x42, 0x77, 0x62, 0x6e, 0x25, 0xba, 0x86, 0x37, 0xec,
0x46, 0xdf, 0x24, 0x32, 0xfd, 0x18, 0xb8, 0xa8, 0x0d, 0x30, 0xe2, 0x6f, 0xe9, 0x3e, 0x99, 0x25, 0x08, 0x2d, 0x4a, 0x25, 0x89, 0xa2, 0xd9, 0xba, 0xbe, 0x5f, 0x9f, 0x35, 0xd5, 0xd2, 0xde, 0x58,
0x74, 0x1a, 0xd4, 0xf6, 0x5e, 0xc0, 0xed, 0x94, 0xcd, 0xae, 0xaf, 0x3b, 0x76, 0xde, 0x37, 0xcd, 0x3b, 0x7f, 0x97, 0xb5, 0x0d, 0xee, 0x2d, 0xb7, 0x64, 0x7d, 0x0b, 0x65, 0x55, 0xd0, 0x7a, 0x88,
0xe9, 0x9b, 0xbb, 0xf1, 0xae, 0x8f, 0x93, 0x79, 0x3c, 0x50, 0x88, 0x5d, 0xce, 0xb5, 0x24, 0x22, 0x9b, 0x6e, 0xe1, 0x93, 0x9d, 0xc1, 0x06, 0x8f, 0xbe, 0x83, 0xde, 0xe3, 0x96, 0x18, 0x0f, 0x76,
0x4e, 0x9b, 0xda, 0xab, 0xed, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x42, 0x5b, 0xf4, 0x78, 0xe6, 0xa2, 0x8f, 0x1a, 0x3c, 0x6c, 0x95, 0x05, 0x3f, 0x6e, 0x98, 0x16, 0xe3, 0x29, 0xf4, 0xb6, 0x69,
0x05, 0x00, 0x00, 0xea, 0x53, 0x79, 0x5a, 0xce, 0x4a, 0x7b, 0x4b, 0xaf, 0x4b, 0x3a, 0x13, 0xa1, 0x83, 0x42, 0x08,
0x66, 0x62, 0x76, 0x7b, 0xc1, 0xd9, 0x0f, 0x44, 0xa5, 0xbf, 0x86, 0x2e, 0xea, 0x01, 0xcc, 0xc4,
0x8f, 0xec, 0x8c, 0xae, 0x08, 0x5b, 0x86, 0xad, 0xf1, 0x57, 0xf0, 0x4e, 0xca, 0x57, 0xcf, 0x53,
0x98, 0x3b, 0x3f, 0x77, 0xed, 0xeb, 0x4f, 0xf7, 0xd5, 0x4f, 0x23, 0x4c, 0xd6, 0xc9, 0x44, 0x23,
0x4e, 0x85, 0x30, 0xf9, 0x51, 0x79, 0xd3, 0x35, 0x6d, 0x3d, 0xfe, 0x27, 0x00, 0x00, 0xff, 0xff,
0x7c, 0x01, 0x52, 0xfa, 0xba, 0x06, 0x00, 0x00,
} }

View File

@ -58,8 +58,14 @@ message GeoSiteList{
} }
message RoutingRule { message RoutingRule {
// Tag of outbound that this rule is pointing to. oneof target_tag {
string tag = 1; // Tag of outbound that this rule is pointing to.
string tag = 1;
// Tag of routing balancer.
string balancing_tag = 12;
}
// List of domains for target domain matching. // List of domains for target domain matching.
repeated Domain domain = 2; repeated Domain domain = 2;
@ -87,6 +93,11 @@ message RoutingRule {
repeated string protocol = 9; repeated string protocol = 9;
} }
message BalancingRule {
string tag = 1;
repeated string outbound_selector = 2;
}
message Config { message Config {
enum DomainStrategy { enum DomainStrategy {
// Use domain as is. // Use domain as is.
@ -103,4 +114,5 @@ message Config {
} }
DomainStrategy domain_strategy = 1; DomainStrategy domain_strategy = 1;
repeated RoutingRule rule = 2; repeated RoutingRule rule = 2;
repeated BalancingRule balancing_rule = 3;
} }

View File

@ -10,6 +10,7 @@ import (
"v2ray.com/core/common/net" "v2ray.com/core/common/net"
"v2ray.com/core/common/session" "v2ray.com/core/common/session"
"v2ray.com/core/features/dns" "v2ray.com/core/features/dns"
"v2ray.com/core/features/outbound"
"v2ray.com/core/features/routing" "v2ray.com/core/features/routing"
) )
@ -35,8 +36,8 @@ func ResolvedIPsFromContext(ctx context.Context) (IPResolver, bool) {
func init() { func init() {
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) { common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
r := new(Router) r := new(Router)
if err := core.RequireFeatures(ctx, func(d dns.Client) error { if err := core.RequireFeatures(ctx, func(d dns.Client, ohm outbound.Manager) error {
return r.Init(config.(*Config), d) return r.Init(config.(*Config), d, ohm)
}); err != nil { }); err != nil {
return nil, err return nil, err
} }
@ -47,23 +48,44 @@ func init() {
// Router is an implementation of routing.Router. // Router is an implementation of routing.Router.
type Router struct { type Router struct {
domainStrategy Config_DomainStrategy domainStrategy Config_DomainStrategy
rules []Rule rules []*Rule
balancers map[string]*Balancer
dns dns.Client dns dns.Client
} }
// Init initializes the Router. // Init initializes the Router.
func (r *Router) Init(config *Config, d dns.Client) error { func (r *Router) Init(config *Config, d dns.Client, ohm outbound.Manager) error {
r.domainStrategy = config.DomainStrategy r.domainStrategy = config.DomainStrategy
r.rules = make([]Rule, len(config.Rule))
r.dns = d r.dns = d
for idx, rule := range config.Rule { r.balancers = make(map[string]*Balancer, len(config.BalancingRule))
r.rules[idx].Tag = rule.Tag for _, rule := range config.BalancingRule {
balancer, err := rule.Build(ohm)
if err != nil {
return err
}
r.balancers[rule.Tag] = balancer
}
r.rules = make([]*Rule, 0, len(config.Rule))
for _, rule := range config.Rule {
cond, err := rule.BuildCondition() cond, err := rule.BuildCondition()
if err != nil { if err != nil {
return err return err
} }
r.rules[idx].Condition = cond rr := &Rule{
Condition: cond,
Tag: rule.GetTag(),
}
btag := rule.GetBalancingTag()
if len(btag) > 0 {
brule, found := r.balancers[btag]
if !found {
return newError("balancer ", btag, " not found")
}
rr.Balancer = brule
}
r.rules = append(r.rules, rr)
} }
return nil return nil
@ -97,8 +119,16 @@ func (r *ipResolver) Resolve() []net.Address {
return r.ip return r.ip
} }
// PickRoute implements routing.Router.
func (r *Router) PickRoute(ctx context.Context) (string, error) { func (r *Router) PickRoute(ctx context.Context) (string, error) {
rule, err := r.pickRouteInternal(ctx)
if err != nil {
return "", err
}
return rule.GetTag()
}
// PickRoute implements routing.Router.
func (r *Router) pickRouteInternal(ctx context.Context) (*Rule, error) {
resolver := &ipResolver{ resolver := &ipResolver{
dns: r.dns, dns: r.dns,
} }
@ -113,12 +143,12 @@ func (r *Router) PickRoute(ctx context.Context) (string, error) {
for _, rule := range r.rules { for _, rule := range r.rules {
if rule.Apply(ctx) { if rule.Apply(ctx) {
return rule.Tag, nil return rule, nil
} }
} }
if outbound == nil || !outbound.Target.IsValid() { if outbound == nil || !outbound.Target.IsValid() {
return "", common.ErrNoClue return nil, common.ErrNoClue
} }
dest := outbound.Target dest := outbound.Target
@ -129,13 +159,13 @@ func (r *Router) PickRoute(ctx context.Context) (string, error) {
ctx = ContextWithResolveIPs(ctx, resolver) ctx = ContextWithResolveIPs(ctx, resolver)
for _, rule := range r.rules { for _, rule := range r.rules {
if rule.Apply(ctx) { if rule.Apply(ctx) {
return rule.Tag, nil return rule, nil
} }
} }
} }
} }
return "", common.ErrNoClue return nil, common.ErrNoClue
} }
// Start implements common.Runnable. // Start implements common.Runnable.

View File

@ -15,7 +15,9 @@ func TestSimpleRouter(t *testing.T) {
config := &Config{ config := &Config{
Rule: []*RoutingRule{ Rule: []*RoutingRule{
{ {
Tag: "test", TargetTag: &RoutingRule_Tag{
Tag: "test",
},
NetworkList: &net.NetworkList{ NetworkList: &net.NetworkList{
Network: []net.Network{net.Network_TCP}, Network: []net.Network{net.Network_TCP},
}, },
@ -29,7 +31,7 @@ func TestSimpleRouter(t *testing.T) {
mockDns := mocks.NewDNSClient(mockCtl) mockDns := mocks.NewDNSClient(mockCtl)
r := new(Router) r := new(Router)
common.Must(r.Init(config, mockDns)) common.Must(r.Init(config, mockDns, nil))
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)}) ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)})
tag, err := r.PickRoute(ctx) tag, err := r.PickRoute(ctx)
@ -44,7 +46,9 @@ func TestIPOnDemand(t *testing.T) {
DomainStrategy: Config_IpOnDemand, DomainStrategy: Config_IpOnDemand,
Rule: []*RoutingRule{ Rule: []*RoutingRule{
{ {
Tag: "test", TargetTag: &RoutingRule_Tag{
Tag: "test",
},
Cidr: []*CIDR{ Cidr: []*CIDR{
{ {
Ip: []byte{192, 168, 0, 0}, Ip: []byte{192, 168, 0, 0},
@ -62,7 +66,7 @@ func TestIPOnDemand(t *testing.T) {
mockDns.EXPECT().LookupIP(gomock.Eq("v2ray.com")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes() mockDns.EXPECT().LookupIP(gomock.Eq("v2ray.com")).Return([]net.IP{{192, 168, 0, 1}}, nil).AnyTimes()
r := new(Router) r := new(Router)
common.Must(r.Init(config, mockDns)) common.Must(r.Init(config, mockDns, nil))
ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)}) ctx := withOutbound(&session.Outbound{Target: net.TCPDestination(net.DomainAddress("v2ray.com"), 80)})
tag, err := r.PickRoute(ctx) tag, err := r.PickRoute(ctx)

View File

@ -15,6 +15,10 @@ type Handler interface {
Dispatch(ctx context.Context, link *transport.Link) Dispatch(ctx context.Context, link *transport.Link)
} }
type HandlerSelector interface {
Select([]string) []string
}
// Manager is a feature that manages outbound.Handlers. // Manager is a feature that manages outbound.Handlers.
type Manager interface { type Manager interface {
features.Feature features.Feature