mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-08 14:13:22 +00:00
https://github.com/XTLS/Xray-core/issues/4422#issuecomment-3533007890 Breaking changes https://github.com/XTLS/Xray-core/pull/5569 Reverts https://github.com/XTLS/Xray-core/pull/5505 Closes https://github.com/XTLS/Xray-core/pull/643
166 lines
3.9 KiB
Go
166 lines
3.9 KiB
Go
package router
|
|
|
|
import (
|
|
"context"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/xtls/xray-core/common/errors"
|
|
"github.com/xtls/xray-core/features/outbound"
|
|
"github.com/xtls/xray-core/features/routing"
|
|
)
|
|
|
|
type Rule struct {
|
|
Tag string
|
|
RuleTag string
|
|
Balancer *Balancer
|
|
Condition Condition
|
|
Webhook *WebhookNotifier
|
|
}
|
|
|
|
func (r *Rule) GetTag() (string, error) {
|
|
if r.Balancer != nil {
|
|
return r.Balancer.PickOutbound()
|
|
}
|
|
return r.Tag, nil
|
|
}
|
|
|
|
// Apply checks rule matching of current routing context.
|
|
func (r *Rule) Apply(ctx routing.Context) bool {
|
|
return r.Condition.Apply(ctx)
|
|
}
|
|
|
|
func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
|
conds := NewConditionChan()
|
|
|
|
if len(rr.InboundTag) > 0 {
|
|
conds.Add(NewInboundTagMatcher(rr.InboundTag))
|
|
}
|
|
|
|
if len(rr.Networks) > 0 {
|
|
conds.Add(NewNetworkMatcher(rr.Networks))
|
|
}
|
|
|
|
if len(rr.Protocol) > 0 {
|
|
conds.Add(NewProtocolMatcher(rr.Protocol))
|
|
}
|
|
|
|
if rr.PortList != nil {
|
|
conds.Add(NewPortMatcher(rr.PortList, MatcherAsType_Target))
|
|
}
|
|
|
|
if rr.SourcePortList != nil {
|
|
conds.Add(NewPortMatcher(rr.SourcePortList, MatcherAsType_Source))
|
|
}
|
|
|
|
if rr.LocalPortList != nil {
|
|
conds.Add(NewPortMatcher(rr.LocalPortList, MatcherAsType_Local))
|
|
}
|
|
|
|
if rr.VlessRouteList != nil {
|
|
conds.Add(NewPortMatcher(rr.VlessRouteList, MatcherAsType_VlessRoute))
|
|
}
|
|
|
|
if len(rr.UserEmail) > 0 {
|
|
conds.Add(NewUserMatcher(rr.UserEmail))
|
|
}
|
|
|
|
if len(rr.Attributes) > 0 {
|
|
configuredKeys := make(map[string]*regexp.Regexp)
|
|
for key, value := range rr.Attributes {
|
|
configuredKeys[strings.ToLower(key)] = regexp.MustCompile(value)
|
|
}
|
|
conds.Add(&AttributeMatcher{configuredKeys})
|
|
}
|
|
|
|
if len(rr.Ip) > 0 {
|
|
cond, err := NewIPMatcher(rr.Ip, MatcherAsType_Target)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
conds.Add(cond)
|
|
}
|
|
|
|
if len(rr.SourceIp) > 0 {
|
|
cond, err := NewIPMatcher(rr.SourceIp, MatcherAsType_Source)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
conds.Add(cond)
|
|
}
|
|
|
|
if len(rr.LocalIp) > 0 {
|
|
cond, err := NewIPMatcher(rr.LocalIp, MatcherAsType_Local)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
conds.Add(cond)
|
|
errors.LogWarning(context.Background(), "Due to some limitations, in UDP connections, localIP is always equal to listen interface IP, so \"localIP\" rule condition does not work properly on UDP inbound connections that listen on all interfaces")
|
|
}
|
|
|
|
if len(rr.Domain) > 0 {
|
|
cond, err := NewDomainMatcher(rr.Domain)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
conds.Add(cond)
|
|
}
|
|
|
|
if len(rr.Process) > 0 {
|
|
conds.Add(NewProcessNameMatcher(rr.Process))
|
|
}
|
|
|
|
if conds.Len() == 0 {
|
|
return nil, errors.New("this rule has no effective fields").AtWarning()
|
|
}
|
|
|
|
return conds, nil
|
|
}
|
|
|
|
// Build builds the balancing rule
|
|
func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatcher) (*Balancer, error) {
|
|
switch strings.ToLower(br.Strategy) {
|
|
case "leastping":
|
|
return &Balancer{
|
|
selectors: br.OutboundSelector,
|
|
strategy: &LeastPingStrategy{},
|
|
fallbackTag: br.FallbackTag,
|
|
ohm: ohm,
|
|
}, nil
|
|
case "roundrobin":
|
|
return &Balancer{
|
|
selectors: br.OutboundSelector,
|
|
strategy: &RoundRobinStrategy{FallbackTag: br.FallbackTag},
|
|
fallbackTag: br.FallbackTag,
|
|
ohm: ohm,
|
|
}, nil
|
|
case "leastload":
|
|
i, err := br.StrategySettings.GetInstance()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s, ok := i.(*StrategyLeastLoadConfig)
|
|
if !ok {
|
|
return nil, errors.New("not a StrategyLeastLoadConfig").AtError()
|
|
}
|
|
leastLoadStrategy := NewLeastLoadStrategy(s)
|
|
return &Balancer{
|
|
selectors: br.OutboundSelector,
|
|
ohm: ohm,
|
|
fallbackTag: br.FallbackTag,
|
|
strategy: leastLoadStrategy,
|
|
}, nil
|
|
case "random":
|
|
fallthrough
|
|
case "":
|
|
return &Balancer{
|
|
selectors: br.OutboundSelector,
|
|
ohm: ohm,
|
|
fallbackTag: br.FallbackTag,
|
|
strategy: &RandomStrategy{FallbackTag: br.FallbackTag},
|
|
}, nil
|
|
default:
|
|
return nil, errors.New("unrecognized balancer type")
|
|
}
|
|
}
|