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