rule.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package rule
  2. import (
  3. "context"
  4. "encoding/json"
  5. "strconv"
  6. "strings"
  7. "github.com/v2fly/v2ray-core/v5/app/router"
  8. "github.com/v2fly/v2ray-core/v5/app/router/routercommon"
  9. "github.com/v2fly/v2ray-core/v5/common/net"
  10. "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon"
  11. )
  12. //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
  13. func parseDomainRule(ctx context.Context, domain string) ([]*routercommon.Domain, error) {
  14. cfgEnv := cfgcommon.GetConfigureLoadingEnvironment(ctx)
  15. geoLoader := cfgEnv.GetGeoLoader()
  16. if strings.HasPrefix(domain, "geosite:") {
  17. list := domain[8:]
  18. if len(list) == 0 {
  19. return nil, newError("empty listname in rule: ", domain)
  20. }
  21. domains, err := geoLoader.LoadGeoSite(list)
  22. if err != nil {
  23. return nil, newError("failed to load geosite: ", list).Base(err)
  24. }
  25. return domains, nil
  26. }
  27. isExtDatFile := 0
  28. {
  29. const prefix = "ext:"
  30. if strings.HasPrefix(domain, prefix) {
  31. isExtDatFile = len(prefix)
  32. }
  33. const prefixQualified = "ext-domain:"
  34. if strings.HasPrefix(domain, prefixQualified) {
  35. isExtDatFile = len(prefixQualified)
  36. }
  37. }
  38. if isExtDatFile != 0 {
  39. kv := strings.Split(domain[isExtDatFile:], ":")
  40. if len(kv) != 2 {
  41. return nil, newError("invalid external resource: ", domain)
  42. }
  43. filename := kv[0]
  44. list := kv[1]
  45. domains, err := geoLoader.LoadGeoSiteWithAttr(filename, list)
  46. if err != nil {
  47. return nil, newError("failed to load external geosite: ", list, " from ", filename).Base(err)
  48. }
  49. return domains, nil
  50. }
  51. domainRule := new(routercommon.Domain)
  52. switch {
  53. case strings.HasPrefix(domain, "regexp:"):
  54. regexpVal := domain[7:]
  55. if len(regexpVal) == 0 {
  56. return nil, newError("empty regexp type of rule: ", domain)
  57. }
  58. domainRule.Type = routercommon.Domain_Regex
  59. domainRule.Value = regexpVal
  60. case strings.HasPrefix(domain, "domain:"):
  61. domainName := domain[7:]
  62. if len(domainName) == 0 {
  63. return nil, newError("empty domain type of rule: ", domain)
  64. }
  65. domainRule.Type = routercommon.Domain_RootDomain
  66. domainRule.Value = domainName
  67. case strings.HasPrefix(domain, "full:"):
  68. fullVal := domain[5:]
  69. if len(fullVal) == 0 {
  70. return nil, newError("empty full domain type of rule: ", domain)
  71. }
  72. domainRule.Type = routercommon.Domain_Full
  73. domainRule.Value = fullVal
  74. case strings.HasPrefix(domain, "keyword:"):
  75. keywordVal := domain[8:]
  76. if len(keywordVal) == 0 {
  77. return nil, newError("empty keyword type of rule: ", domain)
  78. }
  79. domainRule.Type = routercommon.Domain_Plain
  80. domainRule.Value = keywordVal
  81. case strings.HasPrefix(domain, "dotless:"):
  82. domainRule.Type = routercommon.Domain_Regex
  83. switch substr := domain[8:]; {
  84. case substr == "":
  85. domainRule.Value = "^[^.]*$"
  86. case !strings.Contains(substr, "."):
  87. domainRule.Value = "^[^.]*" + substr + "[^.]*$"
  88. default:
  89. return nil, newError("substr in dotless rule should not contain a dot: ", substr)
  90. }
  91. default:
  92. domainRule.Type = routercommon.Domain_Plain
  93. domainRule.Value = domain
  94. }
  95. return []*routercommon.Domain{domainRule}, nil
  96. }
  97. func toCidrList(ctx context.Context, ips cfgcommon.StringList) ([]*routercommon.GeoIP, error) {
  98. cfgEnv := cfgcommon.GetConfigureLoadingEnvironment(ctx)
  99. geoLoader := cfgEnv.GetGeoLoader()
  100. var geoipList []*routercommon.GeoIP
  101. var customCidrs []*routercommon.CIDR
  102. for _, ip := range ips {
  103. if strings.HasPrefix(ip, "geoip:") {
  104. country := ip[6:]
  105. isReverseMatch := false
  106. if strings.HasPrefix(ip, "geoip:!") {
  107. country = ip[7:]
  108. isReverseMatch = true
  109. }
  110. if len(country) == 0 {
  111. return nil, newError("empty country name in rule")
  112. }
  113. geoip, err := geoLoader.LoadGeoIP(country)
  114. if err != nil {
  115. return nil, newError("failed to load geoip: ", country).Base(err)
  116. }
  117. geoipList = append(geoipList, &routercommon.GeoIP{
  118. CountryCode: strings.ToUpper(country),
  119. Cidr: geoip,
  120. InverseMatch: isReverseMatch,
  121. })
  122. continue
  123. }
  124. isExtDatFile := 0
  125. {
  126. const prefix = "ext:"
  127. if strings.HasPrefix(ip, prefix) {
  128. isExtDatFile = len(prefix)
  129. }
  130. const prefixQualified = "ext-ip:"
  131. if strings.HasPrefix(ip, prefixQualified) {
  132. isExtDatFile = len(prefixQualified)
  133. }
  134. }
  135. if isExtDatFile != 0 {
  136. kv := strings.Split(ip[isExtDatFile:], ":")
  137. if len(kv) != 2 {
  138. return nil, newError("invalid external resource: ", ip)
  139. }
  140. filename := kv[0]
  141. country := kv[1]
  142. if len(filename) == 0 || len(country) == 0 {
  143. return nil, newError("empty filename or empty country in rule")
  144. }
  145. isInverseMatch := false
  146. if strings.HasPrefix(country, "!") {
  147. country = country[1:]
  148. isInverseMatch = true
  149. }
  150. geoip, err := geoLoader.LoadIP(filename, country)
  151. if err != nil {
  152. return nil, newError("failed to load geoip: ", country, " from ", filename).Base(err)
  153. }
  154. geoipList = append(geoipList, &routercommon.GeoIP{
  155. CountryCode: strings.ToUpper(filename + "_" + country),
  156. Cidr: geoip,
  157. InverseMatch: isInverseMatch,
  158. })
  159. continue
  160. }
  161. ipRule, err := ParseIP(ip)
  162. if err != nil {
  163. return nil, newError("invalid IP: ", ip).Base(err)
  164. }
  165. customCidrs = append(customCidrs, ipRule)
  166. }
  167. if len(customCidrs) > 0 {
  168. geoipList = append(geoipList, &routercommon.GeoIP{
  169. Cidr: customCidrs,
  170. })
  171. }
  172. return geoipList, nil
  173. }
  174. func parseFieldRule(ctx context.Context, msg json.RawMessage) (*router.RoutingRule, error) {
  175. type RawFieldRule struct {
  176. RouterRule
  177. Domain *cfgcommon.StringList `json:"domain"`
  178. Domains *cfgcommon.StringList `json:"domains"`
  179. IP *cfgcommon.StringList `json:"ip"`
  180. Port *cfgcommon.PortList `json:"port"`
  181. Network *cfgcommon.NetworkList `json:"network"`
  182. SourceIP *cfgcommon.StringList `json:"source"`
  183. SourcePort *cfgcommon.PortList `json:"sourcePort"`
  184. User *cfgcommon.StringList `json:"user"`
  185. InboundTag *cfgcommon.StringList `json:"inboundTag"`
  186. Protocols *cfgcommon.StringList `json:"protocol"`
  187. Attributes string `json:"attrs"`
  188. }
  189. rawFieldRule := new(RawFieldRule)
  190. err := json.Unmarshal(msg, rawFieldRule)
  191. if err != nil {
  192. return nil, err
  193. }
  194. rule := new(router.RoutingRule)
  195. switch {
  196. case len(rawFieldRule.OutboundTag) > 0:
  197. rule.TargetTag = &router.RoutingRule_Tag{
  198. Tag: rawFieldRule.OutboundTag,
  199. }
  200. case len(rawFieldRule.BalancerTag) > 0:
  201. rule.TargetTag = &router.RoutingRule_BalancingTag{
  202. BalancingTag: rawFieldRule.BalancerTag,
  203. }
  204. default:
  205. return nil, newError("neither outboundTag nor balancerTag is specified in routing rule")
  206. }
  207. if rawFieldRule.DomainMatcher != "" {
  208. rule.DomainMatcher = rawFieldRule.DomainMatcher
  209. }
  210. if rawFieldRule.Domain != nil {
  211. for _, domain := range *rawFieldRule.Domain {
  212. rules, err := parseDomainRule(ctx, domain)
  213. if err != nil {
  214. return nil, newError("failed to parse domain rule: ", domain).Base(err)
  215. }
  216. rule.Domain = append(rule.Domain, rules...)
  217. }
  218. }
  219. if rawFieldRule.Domains != nil {
  220. for _, domain := range *rawFieldRule.Domains {
  221. rules, err := parseDomainRule(ctx, domain)
  222. if err != nil {
  223. return nil, newError("failed to parse domain rule: ", domain).Base(err)
  224. }
  225. rule.Domain = append(rule.Domain, rules...)
  226. }
  227. }
  228. if rawFieldRule.IP != nil {
  229. geoipList, err := toCidrList(ctx, *rawFieldRule.IP)
  230. if err != nil {
  231. return nil, err
  232. }
  233. rule.Geoip = geoipList
  234. }
  235. if rawFieldRule.Port != nil {
  236. rule.PortList = rawFieldRule.Port.Build()
  237. }
  238. if rawFieldRule.Network != nil {
  239. rule.Networks = rawFieldRule.Network.Build()
  240. }
  241. if rawFieldRule.SourceIP != nil {
  242. geoipList, err := toCidrList(ctx, *rawFieldRule.SourceIP)
  243. if err != nil {
  244. return nil, err
  245. }
  246. rule.SourceGeoip = geoipList
  247. }
  248. if rawFieldRule.SourcePort != nil {
  249. rule.SourcePortList = rawFieldRule.SourcePort.Build()
  250. }
  251. if rawFieldRule.User != nil {
  252. for _, s := range *rawFieldRule.User {
  253. rule.UserEmail = append(rule.UserEmail, s)
  254. }
  255. }
  256. if rawFieldRule.InboundTag != nil {
  257. for _, s := range *rawFieldRule.InboundTag {
  258. rule.InboundTag = append(rule.InboundTag, s)
  259. }
  260. }
  261. if rawFieldRule.Protocols != nil {
  262. for _, s := range *rawFieldRule.Protocols {
  263. rule.Protocol = append(rule.Protocol, s)
  264. }
  265. }
  266. if len(rawFieldRule.Attributes) > 0 {
  267. rule.Attributes = rawFieldRule.Attributes
  268. }
  269. return rule, nil
  270. }
  271. func ParseRule(ctx context.Context, msg json.RawMessage) (*router.RoutingRule, error) {
  272. rawRule := new(RouterRule)
  273. err := json.Unmarshal(msg, rawRule)
  274. if err != nil {
  275. return nil, newError("invalid router rule").Base(err)
  276. }
  277. if strings.EqualFold(rawRule.Type, "field") {
  278. fieldrule, err := parseFieldRule(ctx, msg)
  279. if err != nil {
  280. return nil, newError("invalid field rule").Base(err)
  281. }
  282. return fieldrule, nil
  283. }
  284. return nil, newError("unknown router rule type: ", rawRule.Type)
  285. }
  286. func ParseIP(s string) (*routercommon.CIDR, error) {
  287. var addr, mask string
  288. i := strings.Index(s, "/")
  289. if i < 0 {
  290. addr = s
  291. } else {
  292. addr = s[:i]
  293. mask = s[i+1:]
  294. }
  295. ip := net.ParseAddress(addr)
  296. switch ip.Family() {
  297. case net.AddressFamilyIPv4:
  298. bits := uint32(32)
  299. if len(mask) > 0 {
  300. bits64, err := strconv.ParseUint(mask, 10, 32)
  301. if err != nil {
  302. return nil, newError("invalid network mask for router: ", mask).Base(err)
  303. }
  304. bits = uint32(bits64)
  305. }
  306. if bits > 32 {
  307. return nil, newError("invalid network mask for router: ", bits)
  308. }
  309. return &routercommon.CIDR{
  310. Ip: []byte(ip.IP()),
  311. Prefix: bits,
  312. }, nil
  313. case net.AddressFamilyIPv6:
  314. bits := uint32(128)
  315. if len(mask) > 0 {
  316. bits64, err := strconv.ParseUint(mask, 10, 32)
  317. if err != nil {
  318. return nil, newError("invalid network mask for router: ", mask).Base(err)
  319. }
  320. bits = uint32(bits64)
  321. }
  322. if bits > 128 {
  323. return nil, newError("invalid network mask for router: ", bits)
  324. }
  325. return &routercommon.CIDR{
  326. Ip: []byte(ip.IP()),
  327. Prefix: bits,
  328. }, nil
  329. default:
  330. return nil, newError("unsupported address for router: ", s)
  331. }
  332. }
  333. func ParseDomainRule(ctx context.Context, domain string) ([]*routercommon.Domain, error) {
  334. return parseDomainRule(ctx, domain)
  335. }
  336. func ToCidrList(ctx context.Context, ips cfgcommon.StringList) ([]*routercommon.GeoIP, error) {
  337. return toCidrList(ctx, ips)
  338. }
  339. type RouterRule struct {
  340. Type string `json:"type"`
  341. OutboundTag string `json:"outboundTag"`
  342. BalancerTag string `json:"balancerTag"`
  343. DomainMatcher string `json:"domainMatcher"`
  344. }