github.com/xmplusdev/xray-core@v1.8.10/app/router/config.go (about) 1 package router 2 3 import ( 4 "regexp" 5 "strings" 6 7 "github.com/xmplusdev/xray-core/common/net" 8 "github.com/xmplusdev/xray-core/features/outbound" 9 "github.com/xmplusdev/xray-core/features/routing" 10 ) 11 12 type Rule struct { 13 Tag string 14 RuleTag string 15 Balancer *Balancer 16 Condition Condition 17 } 18 19 func (r *Rule) GetTag() (string, error) { 20 if r.Balancer != nil { 21 return r.Balancer.PickOutbound() 22 } 23 return r.Tag, nil 24 } 25 26 // Apply checks rule matching of current routing context. 27 func (r *Rule) Apply(ctx routing.Context) bool { 28 return r.Condition.Apply(ctx) 29 } 30 31 func (rr *RoutingRule) BuildCondition() (Condition, error) { 32 conds := NewConditionChan() 33 34 if len(rr.Domain) > 0 { 35 switch rr.DomainMatcher { 36 case "linear": 37 matcher, err := NewDomainMatcher(rr.Domain) 38 if err != nil { 39 return nil, newError("failed to build domain condition").Base(err) 40 } 41 conds.Add(matcher) 42 case "mph", "hybrid": 43 fallthrough 44 default: 45 matcher, err := NewMphMatcherGroup(rr.Domain) 46 if err != nil { 47 return nil, newError("failed to build domain condition with MphDomainMatcher").Base(err) 48 } 49 newError("MphDomainMatcher is enabled for ", len(rr.Domain), " domain rule(s)").AtDebug().WriteToLog() 50 conds.Add(matcher) 51 } 52 } 53 54 if len(rr.UserEmail) > 0 { 55 conds.Add(NewUserMatcher(rr.UserEmail)) 56 } 57 58 if len(rr.InboundTag) > 0 { 59 conds.Add(NewInboundTagMatcher(rr.InboundTag)) 60 } 61 62 if rr.PortList != nil { 63 conds.Add(NewPortMatcher(rr.PortList, false)) 64 } else if rr.PortRange != nil { 65 conds.Add(NewPortMatcher(&net.PortList{Range: []*net.PortRange{rr.PortRange}}, false)) 66 } 67 68 if rr.SourcePortList != nil { 69 conds.Add(NewPortMatcher(rr.SourcePortList, true)) 70 } 71 72 if len(rr.Networks) > 0 { 73 conds.Add(NewNetworkMatcher(rr.Networks)) 74 } else if rr.NetworkList != nil { 75 conds.Add(NewNetworkMatcher(rr.NetworkList.Network)) 76 } 77 78 if len(rr.Geoip) > 0 { 79 cond, err := NewMultiGeoIPMatcher(rr.Geoip, false) 80 if err != nil { 81 return nil, err 82 } 83 conds.Add(cond) 84 } else if len(rr.Cidr) > 0 { 85 cond, err := NewMultiGeoIPMatcher([]*GeoIP{{Cidr: rr.Cidr}}, false) 86 if err != nil { 87 return nil, err 88 } 89 conds.Add(cond) 90 } 91 92 if len(rr.SourceGeoip) > 0 { 93 cond, err := NewMultiGeoIPMatcher(rr.SourceGeoip, true) 94 if err != nil { 95 return nil, err 96 } 97 conds.Add(cond) 98 } else if len(rr.SourceCidr) > 0 { 99 cond, err := NewMultiGeoIPMatcher([]*GeoIP{{Cidr: rr.SourceCidr}}, true) 100 if err != nil { 101 return nil, err 102 } 103 conds.Add(cond) 104 } 105 106 if len(rr.Protocol) > 0 { 107 conds.Add(NewProtocolMatcher(rr.Protocol)) 108 } 109 110 if len(rr.Attributes) > 0 { 111 configuredKeys := make(map[string]*regexp.Regexp) 112 for key, value := range rr.Attributes { 113 configuredKeys[strings.ToLower(key)] = regexp.MustCompile(value) 114 } 115 conds.Add(&AttributeMatcher{configuredKeys}) 116 } 117 118 if conds.Len() == 0 { 119 return nil, newError("this rule has no effective fields").AtWarning() 120 } 121 122 return conds, nil 123 } 124 125 // Build builds the balancing rule 126 func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatcher) (*Balancer, error) { 127 switch strings.ToLower(br.Strategy) { 128 case "leastping": 129 return &Balancer{ 130 selectors: br.OutboundSelector, 131 strategy: &LeastPingStrategy{}, 132 fallbackTag: br.FallbackTag, 133 ohm: ohm, 134 }, nil 135 case "roundrobin": 136 return &Balancer{ 137 selectors: br.OutboundSelector, 138 strategy: &RoundRobinStrategy{}, 139 fallbackTag: br.FallbackTag, 140 ohm: ohm, 141 }, nil 142 case "leastload": 143 i, err := br.StrategySettings.GetInstance() 144 if err != nil { 145 return nil, err 146 } 147 s, ok := i.(*StrategyLeastLoadConfig) 148 if !ok { 149 return nil, newError("not a StrategyLeastLoadConfig").AtError() 150 } 151 leastLoadStrategy := NewLeastLoadStrategy(s) 152 return &Balancer{ 153 selectors: br.OutboundSelector, 154 ohm: ohm, 155 fallbackTag: br.FallbackTag, 156 strategy: leastLoadStrategy, 157 }, nil 158 case "random": 159 fallthrough 160 case "": 161 return &Balancer{ 162 selectors: br.OutboundSelector, 163 ohm: ohm, 164 fallbackTag: br.FallbackTag, 165 strategy: &RandomStrategy{}, 166 }, nil 167 default: 168 return nil, newError("unrecognized balancer type") 169 } 170 }