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