github.com/sagernet/sing-box@v1.9.0-rc.20/route/rule_abstract.go (about) 1 package route 2 3 import ( 4 "io" 5 "strings" 6 7 "github.com/sagernet/sing-box/adapter" 8 C "github.com/sagernet/sing-box/constant" 9 "github.com/sagernet/sing/common" 10 F "github.com/sagernet/sing/common/format" 11 ) 12 13 type abstractDefaultRule struct { 14 items []RuleItem 15 sourceAddressItems []RuleItem 16 sourcePortItems []RuleItem 17 destinationAddressItems []RuleItem 18 destinationIPCIDRItems []RuleItem 19 destinationPortItems []RuleItem 20 allItems []RuleItem 21 ruleSetItem RuleItem 22 invert bool 23 outbound string 24 } 25 26 func (r *abstractDefaultRule) Type() string { 27 return C.RuleTypeDefault 28 } 29 30 func (r *abstractDefaultRule) Start() error { 31 for _, item := range r.allItems { 32 err := common.Start(item) 33 if err != nil { 34 return err 35 } 36 } 37 return nil 38 } 39 40 func (r *abstractDefaultRule) Close() error { 41 for _, item := range r.allItems { 42 err := common.Close(item) 43 if err != nil { 44 return err 45 } 46 } 47 return nil 48 } 49 50 func (r *abstractDefaultRule) UpdateGeosite() error { 51 for _, item := range r.allItems { 52 if geositeItem, isSite := item.(*GeositeItem); isSite { 53 err := geositeItem.Update() 54 if err != nil { 55 return err 56 } 57 } 58 } 59 return nil 60 } 61 62 func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool { 63 if len(r.allItems) == 0 { 64 return true 65 } 66 67 if len(r.sourceAddressItems) > 0 && !metadata.SourceAddressMatch { 68 metadata.DidMatch = true 69 for _, item := range r.sourceAddressItems { 70 if item.Match(metadata) { 71 metadata.SourceAddressMatch = true 72 break 73 } 74 } 75 } 76 77 if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch { 78 metadata.DidMatch = true 79 for _, item := range r.sourcePortItems { 80 if item.Match(metadata) { 81 metadata.SourcePortMatch = true 82 break 83 } 84 } 85 } 86 87 if len(r.destinationAddressItems) > 0 && !metadata.DestinationAddressMatch { 88 metadata.DidMatch = true 89 for _, item := range r.destinationAddressItems { 90 if item.Match(metadata) { 91 metadata.DestinationAddressMatch = true 92 break 93 } 94 } 95 } 96 97 if !metadata.IgnoreDestinationIPCIDRMatch && len(r.destinationIPCIDRItems) > 0 && !metadata.DestinationAddressMatch { 98 metadata.DidMatch = true 99 for _, item := range r.destinationIPCIDRItems { 100 if item.Match(metadata) { 101 metadata.DestinationAddressMatch = true 102 break 103 } 104 } 105 } 106 107 if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch { 108 metadata.DidMatch = true 109 for _, item := range r.destinationPortItems { 110 if item.Match(metadata) { 111 metadata.DestinationPortMatch = true 112 break 113 } 114 } 115 } 116 117 for _, item := range r.items { 118 if _, isRuleSet := item.(*RuleSetItem); !isRuleSet { 119 metadata.DidMatch = true 120 } 121 if !item.Match(metadata) { 122 return r.invert 123 } 124 } 125 126 if len(r.sourceAddressItems) > 0 && !metadata.SourceAddressMatch { 127 return r.invert 128 } 129 130 if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch { 131 return r.invert 132 } 133 134 if ((!metadata.IgnoreDestinationIPCIDRMatch && len(r.destinationIPCIDRItems) > 0) || len(r.destinationAddressItems) > 0) && !metadata.DestinationAddressMatch { 135 return r.invert 136 } 137 138 if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch { 139 return r.invert 140 } 141 142 if !metadata.DidMatch { 143 return true 144 } 145 146 return !r.invert 147 } 148 149 func (r *abstractDefaultRule) Outbound() string { 150 return r.outbound 151 } 152 153 func (r *abstractDefaultRule) String() string { 154 if !r.invert { 155 return strings.Join(F.MapToString(r.allItems), " ") 156 } else { 157 return "!(" + strings.Join(F.MapToString(r.allItems), " ") + ")" 158 } 159 } 160 161 type abstractLogicalRule struct { 162 rules []adapter.HeadlessRule 163 mode string 164 invert bool 165 outbound string 166 } 167 168 func (r *abstractLogicalRule) Type() string { 169 return C.RuleTypeLogical 170 } 171 172 func (r *abstractLogicalRule) UpdateGeosite() error { 173 for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (adapter.Rule, bool) { 174 rule, loaded := it.(adapter.Rule) 175 return rule, loaded 176 }) { 177 err := rule.UpdateGeosite() 178 if err != nil { 179 return err 180 } 181 } 182 return nil 183 } 184 185 func (r *abstractLogicalRule) Start() error { 186 for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (common.Starter, bool) { 187 rule, loaded := it.(common.Starter) 188 return rule, loaded 189 }) { 190 err := rule.Start() 191 if err != nil { 192 return err 193 } 194 } 195 return nil 196 } 197 198 func (r *abstractLogicalRule) Close() error { 199 for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (io.Closer, bool) { 200 rule, loaded := it.(io.Closer) 201 return rule, loaded 202 }) { 203 err := rule.Close() 204 if err != nil { 205 return err 206 } 207 } 208 return nil 209 } 210 211 func (r *abstractLogicalRule) Match(metadata *adapter.InboundContext) bool { 212 if r.mode == C.LogicalTypeAnd { 213 return common.All(r.rules, func(it adapter.HeadlessRule) bool { 214 metadata.ResetRuleCache() 215 return it.Match(metadata) 216 }) != r.invert 217 } else { 218 return common.Any(r.rules, func(it adapter.HeadlessRule) bool { 219 metadata.ResetRuleCache() 220 return it.Match(metadata) 221 }) != r.invert 222 } 223 } 224 225 func (r *abstractLogicalRule) Outbound() string { 226 return r.outbound 227 } 228 229 func (r *abstractLogicalRule) String() string { 230 var op string 231 switch r.mode { 232 case C.LogicalTypeAnd: 233 op = "&&" 234 case C.LogicalTypeOr: 235 op = "||" 236 } 237 if !r.invert { 238 return strings.Join(F.MapToString(r.rules), " "+op+" ") 239 } else { 240 return "!(" + strings.Join(F.MapToString(r.rules), " "+op+" ") + ")" 241 } 242 }