diff --git a/component/geodata/router/condition.go b/component/geodata/router/condition.go index 6b3f8b86..3f620f64 100644 --- a/component/geodata/router/condition.go +++ b/component/geodata/router/condition.go @@ -1,8 +1,10 @@ package router import ( + "encoding/binary" "fmt" "net" + "sort" "strings" "github.com/Dreamacro/clash/component/geodata/strmatcher" @@ -71,6 +73,241 @@ func (m *DomainMatcher) ApplyDomain(domain string) bool { return len(m.matchers.Match(strings.ToLower(domain))) > 0 } +// CIDRList is an alias of []*CIDR to provide sort.Interface. +type CIDRList []*CIDR + +// Len implements sort.Interface. +func (l *CIDRList) Len() int { + return len(*l) +} + +// Less implements sort.Interface. +func (l *CIDRList) Less(i int, j int) bool { + ci := (*l)[i] + cj := (*l)[j] + + if len(ci.Ip) < len(cj.Ip) { + return true + } + + if len(ci.Ip) > len(cj.Ip) { + return false + } + + for k := 0; k < len(ci.Ip); k++ { + if ci.Ip[k] < cj.Ip[k] { + return true + } + + if ci.Ip[k] > cj.Ip[k] { + return false + } + } + + return ci.Prefix < cj.Prefix +} + +// Swap implements sort.Interface. +func (l *CIDRList) Swap(i int, j int) { + (*l)[i], (*l)[j] = (*l)[j], (*l)[i] +} + +type ipv6 struct { + a uint64 + b uint64 +} + +type GeoIPMatcher struct { + countryCode string + reverseMatch bool + ip4 []uint32 + prefix4 []uint8 + ip6 []ipv6 + prefix6 []uint8 +} + +func normalize4(ip uint32, prefix uint8) uint32 { + return (ip >> (32 - prefix)) << (32 - prefix) +} + +func normalize6(ip ipv6, prefix uint8) ipv6 { + if prefix <= 64 { + ip.a = (ip.a >> (64 - prefix)) << (64 - prefix) + ip.b = 0 + } else { + ip.b = (ip.b >> (128 - prefix)) << (128 - prefix) + } + return ip +} + +func (m *GeoIPMatcher) Init(cidrs []*CIDR) error { + ip4Count := 0 + ip6Count := 0 + + for _, cidr := range cidrs { + ip := cidr.Ip + switch len(ip) { + case 4: + ip4Count++ + case 16: + ip6Count++ + default: + return fmt.Errorf("unexpect ip length: %d", len(ip)) + } + } + + cidrList := CIDRList(cidrs) + sort.Sort(&cidrList) + + m.ip4 = make([]uint32, 0, ip4Count) + m.prefix4 = make([]uint8, 0, ip4Count) + m.ip6 = make([]ipv6, 0, ip6Count) + m.prefix6 = make([]uint8, 0, ip6Count) + + for _, cidr := range cidrs { + ip := cidr.Ip + prefix := uint8(cidr.Prefix) + switch len(ip) { + case 4: + m.ip4 = append(m.ip4, normalize4(binary.BigEndian.Uint32(ip), prefix)) + m.prefix4 = append(m.prefix4, prefix) + case 16: + ip6 := ipv6{ + a: binary.BigEndian.Uint64(ip[0:8]), + b: binary.BigEndian.Uint64(ip[8:16]), + } + ip6 = normalize6(ip6, prefix) + + m.ip6 = append(m.ip6, ip6) + m.prefix6 = append(m.prefix6, prefix) + } + } + + return nil +} + +func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) { + m.reverseMatch = isReverseMatch +} + +func (m *GeoIPMatcher) match4(ip uint32) bool { + if len(m.ip4) == 0 { + return false + } + + if ip < m.ip4[0] { + return false + } + + size := uint32(len(m.ip4)) + l := uint32(0) + r := size + for l < r { + x := ((l + r) >> 1) + if ip < m.ip4[x] { + r = x + continue + } + + nip := normalize4(ip, m.prefix4[x]) + if nip == m.ip4[x] { + return true + } + + l = x + 1 + } + + return l > 0 && normalize4(ip, m.prefix4[l-1]) == m.ip4[l-1] +} + +func less6(a ipv6, b ipv6) bool { + return a.a < b.a || (a.a == b.a && a.b < b.b) +} + +func (m *GeoIPMatcher) match6(ip ipv6) bool { + if len(m.ip6) == 0 { + return false + } + + if less6(ip, m.ip6[0]) { + return false + } + + size := uint32(len(m.ip6)) + l := uint32(0) + r := size + for l < r { + x := (l + r) / 2 + if less6(ip, m.ip6[x]) { + r = x + continue + } + + if normalize6(ip, m.prefix6[x]) == m.ip6[x] { + return true + } + + l = x + 1 + } + + return l > 0 && normalize6(ip, m.prefix6[l-1]) == m.ip6[l-1] +} + +// Match returns true if the given ip is included by the GeoIP. +func (m *GeoIPMatcher) Match(ip net.IP) bool { + switch len(ip) { + case 4: + if m.reverseMatch { + return !m.match4(binary.BigEndian.Uint32(ip)) + } + return m.match4(binary.BigEndian.Uint32(ip)) + case 16: + if m.reverseMatch { + return !m.match6(ipv6{ + a: binary.BigEndian.Uint64(ip[0:8]), + b: binary.BigEndian.Uint64(ip[8:16]), + }) + } + return m.match6(ipv6{ + a: binary.BigEndian.Uint64(ip[0:8]), + b: binary.BigEndian.Uint64(ip[8:16]), + }) + default: + return false + } +} + +// GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code. +type GeoIPMatcherContainer struct { + matchers []*GeoIPMatcher +} + +// Add adds a new GeoIP set into the container. +// If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one. +func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) { + if len(geoip.CountryCode) > 0 { + for _, m := range c.matchers { + if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch { + return m, nil + } + } + } + + m := &GeoIPMatcher{ + countryCode: geoip.CountryCode, + reverseMatch: geoip.ReverseMatch, + } + if err := m.Init(geoip.Cidr); err != nil { + return nil, err + } + if len(geoip.CountryCode) > 0 { + c.matchers = append(c.matchers, m) + } + return m, nil +} + +var globalGeoIPContainer GeoIPMatcherContainer + type MultiGeoIPMatcher struct { matchers []*GeoIPMatcher } diff --git a/component/process/process_linux.go b/component/process/process_linux.go index d70a2922..7a160395 100644 --- a/component/process/process_linux.go +++ b/component/process/process_linux.go @@ -108,7 +108,7 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int3 return 0, 0, fmt.Errorf("invalid uid(%d) or inode(%d)", uid, inode) } - return uid, inode, nil + return inode, uid, nil } func packSocketDiagRequest(family, protocol byte, source net.IP, sourcePort uint16) []byte { diff --git a/config/config.go b/config/config.go index 894a91b1..902686f9 100644 --- a/config/config.go +++ b/config/config.go @@ -237,15 +237,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { DNSHijack: []string{"198.18.0.2:53"}, // default hijack all dns query AutoRoute: true, }, - Proxy: []map[string]any{}, - ProxyGroup: []map[string]any{}, - Tun: RawTun{ - Enable: false, - Device: "", - Stack: C.TunGvisor, - DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query - AutoRoute: true, - }, DNS: RawDNS{ Enable: false, UseHosts: true, @@ -589,7 +580,7 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin payload = strings.Join(rule[1:l-1], ",") } else { if l < 2 { - return nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line) + return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line) } if l < 4 { rule = append(rule, make([]string, 4-l)...) @@ -603,7 +594,6 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin } target = rule[l-1] params = rule[l:] - } } if _, ok := proxies[target]; mode != T.Script && !ok { diff --git a/go.mod b/go.mod index 3816dfcf..eda06d5d 100644 --- a/go.mod +++ b/go.mod @@ -11,21 +11,19 @@ require ( github.com/gofrs/uuid v4.2.0+incompatible github.com/gorilla/websocket v1.5.0 github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd + github.com/lucas-clemente/quic-go v0.25.0 github.com/miekg/dns v1.1.47 github.com/oschwald/geoip2-golang v1.6.1 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.1 github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 go.etcd.io/bbolt v1.3.6 - github.com/lucas-clemente/quic-go v0.25.0 go.uber.org/atomic v1.9.0 go.uber.org/automaxprocs v1.4.0 golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd golang.org/x/net v0.0.0-20220225172249-27dd8689420f golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 - golang.zx2c4.com/wireguard/windows v0.5.1 - golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86 golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 golang.zx2c4.com/wireguard v0.0.0-20220310012736-ae6bc4dd64e1 golang.zx2c4.com/wireguard/windows v0.5.3 @@ -41,8 +39,6 @@ require ( github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/google/btree v1.0.1 // indirect github.com/kr/pretty v0.2.1 // indirect - github.com/oschwald/maxminddb-golang v1.8.0 // indirect - github.com/kr/pretty v0.2.1 // indirect github.com/marten-seemann/qtls-go1-16 v0.1.4 // indirect github.com/marten-seemann/qtls-go1-17 v0.1.0 // indirect github.com/marten-seemann/qtls-go1-18 v0.1.0 // indirect @@ -50,18 +46,12 @@ require ( github.com/onsi/ginkgo v1.16.5 // indirect github.com/oschwald/maxminddb-golang v1.8.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect - golang.org/x/mod v0.5.1 // indirect - golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab // indirect - golang.org/x/tools v0.1.9 // indirect github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect - golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect + golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab // indirect golang.org/x/tools v0.1.10 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect - golang.zx2c4.com/go118/netip v0.0.0-20211106132939-9d41d90554dd // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/go.sum b/go.sum index dd4e55ee..ab30b06c 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99 h1:dkEFEnGUg2z/FAPywWr4yfR/sWDQK76qn3J4Y5H2hJs= -github.com/kr328/tun2socket v0.0.0-20210412191540-3d56c47e2d99/go.mod h1:FWfSixjrLgtK+dHkDoN6lHMNhvER24gnjUZd/wt8Z9o= github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc= github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= @@ -196,8 +194,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME= @@ -323,8 +322,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y= -golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= +golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab h1:eHo2TTVBaAPw9lDGK2Gb9GyPMXT6g7O63W6sx3ylbzU= +golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= @@ -352,12 +351,12 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.zx2c4.com/go118/netip v0.0.0-20211106132939-9d41d90554dd h1:gUHae7sCd+tFJLcCximWeBFD2b6Jg3O7UaNaPvjIJHc= -golang.zx2c4.com/go118/netip v0.0.0-20211106132939-9d41d90554dd/go.mod h1:5yyfuiqVIJ7t+3MqrpTQ+QqRkMWiESiyDvPNvKYCecg= -golang.zx2c4.com/wireguard/windows v0.5.1 h1:OnYw96PF+CsIMrqWo5QP3Q59q5hY1rFErk/yN3cS+JQ= -golang.zx2c4.com/wireguard/windows v0.5.1/go.mod h1:EApyTk/ZNrkbZjurHL1nleDYnsPpJYBO7LZEBCyDAHk= -golang.zx2c4.com/wireguard/windows v0.5.2 h1:C3kUahG6QPhXUYSMesW0t1mDo1XCwls2c8Bz16umS44= -golang.zx2c4.com/wireguard/windows v0.5.2/go.mod h1:KptYG5fXTsP1sHafw0BnWHxobtR6QZHWY6SVWq5R0PM= +golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= +golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard v0.0.0-20220310012736-ae6bc4dd64e1 h1:iuQdvJn3LrXxz3Iony1qBGVS7kEy2uHYnnjHsVbzq/s= +golang.zx2c4.com/wireguard v0.0.0-20220310012736-ae6bc4dd64e1/go.mod h1:TjUWrnD5ATh7bFvmm/ALEJZQ4ivKbETb6pmyj1vUoNI= +golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= +golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -400,8 +399,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= -gvisor.dev/gvisor v0.0.0-20220129032118-ed00636ef990 h1:fTgWAYpliP19U3FX8+tI2TZGXnnk45g18frOuZxKay4= -gvisor.dev/gvisor v0.0.0-20220129032118-ed00636ef990/go.mod h1:vmN0Pug/s8TJmpnt30DvrEfZ5vDl52psGLU04tFuK2U= +gvisor.dev/gvisor v0.0.0-20220315202956-f1399ecf1672 h1:aXIFpjZYl3zv2rQyr4rSit5Uq0k7BVXC8lJaDa4Cg7M= +gvisor.dev/gvisor v0.0.0-20220315202956-f1399ecf1672/go.mod h1:V4WNP2Uwtx69eOhvLDSQ734EaTJTaBI3P8KgRAlROsg= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 7297b270..4a1cc749 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -7,7 +7,6 @@ import ( "os" "runtime" "strconv" - "strings" "sync" "github.com/Dreamacro/clash/listener/tproxy" @@ -28,7 +27,6 @@ import ( "github.com/Dreamacro/clash/dns" P "github.com/Dreamacro/clash/listener" authStore "github.com/Dreamacro/clash/listener/auth" - "github.com/Dreamacro/clash/listener/tproxy" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/tunnel" ) @@ -83,9 +81,9 @@ func ApplyConfig(cfg *config.Config, force bool) { updateGeneral(cfg.General, cfg.Tun, force) updateProxies(cfg.Proxies, cfg.Providers) updateRules(cfg.Rules, cfg.RuleProviders) - updateIPTables(cfg.DNS, cfg.General, cfg.Tun) + updateIPTables(cfg.DNS, cfg.General.TProxyPort, cfg.General.Interface, cfg.Tun.Enable) updateDNS(cfg.DNS, cfg.Tun) - updateTun(cfg.Tun) + updateTun(cfg.Tun, cfg.DNS.FakeIPRange.IPNet().String()) updateExperimental(cfg) loadProvider(cfg.RuleProviders, cfg.Providers) updateProfile(cfg) diff --git a/hub/route/configs.go b/hub/route/configs.go index 6ec86963..3e36c054 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -78,10 +78,6 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn) P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn) - if general.Tun != nil { - P.ReCreateTun(*general.Tun, tcpIn, udpIn) - } - if general.Mode != nil { tunnel.SetMode(*general.Mode) } diff --git a/listener/listener.go b/listener/listener.go index 286d04d5..6df92e2d 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -5,7 +5,6 @@ import ( "github.com/Dreamacro/clash/listener/inner" "net" "os" - "runtime" "strconv" "sync" diff --git a/listener/tun/dev/dev_windows_extra.go b/listener/tun/dev/dev_windows_extra.go deleted file mode 100644 index e4b1193f..00000000 --- a/listener/tun/dev/dev_windows_extra.go +++ /dev/null @@ -1,398 +0,0 @@ -//go:build windows -// +build windows - -package dev - -import ( - "bytes" - "errors" - "fmt" - "net" - "sort" - "sync" - "sync/atomic" - "time" - - "github.com/Dreamacro/clash/listener/tun/dev/wintun" - "github.com/Dreamacro/clash/log" - - "golang.org/x/sys/windows" - "golang.zx2c4.com/wireguard/windows/tunnel/winipcfg" -) - -const messageTransportHeaderSize = 0 // size of data preceding content in transport message - -type tunWindows struct { - wt *wintun.Adapter - handle windows.Handle - close int32 - running sync.WaitGroup - forcedMTU int - rate rateJuggler - session wintun.Session - readWait windows.Handle - closeOnce sync.Once - - url string - name string - tunAddress string - autoRoute bool -} - -// OpenTunDevice return a TunDevice according a URL -func OpenTunDevice(tunAddress string, autoRoute bool) (TunDevice, error) { - - requestedGUID, err := windows.GUIDFromString("{330EAEF8-7578-5DF2-D97B-8DADC0EA85CB}") - if err == nil { - WintunStaticRequestedGUID = &requestedGUID - log.Debugln("Generate GUID: %s", WintunStaticRequestedGUID.String()) - } else { - log.Warnln("Error parese GUID from string: %v", err) - } - - interfaceName := "Meta Tunnel" - mtu := 9000 - - tun, err := CreateTUN(interfaceName, mtu, tunAddress, autoRoute) - if err != nil { - return nil, err - } - - return tun, nil -} - -// -// CreateTUN creates a Wintun interface with the given name. Should a Wintun -// interface with the same name exist, it is reused. -// -func CreateTUN(ifname string, mtu int, tunAddress string, autoRoute bool) (TunDevice, error) { - return CreateTUNWithRequestedGUID(ifname, WintunStaticRequestedGUID, mtu, tunAddress, autoRoute) -} - -// -// CreateTUNWithRequestedGUID creates a Wintun interface with the given name and -// a requested GUID. Should a Wintun interface with the same name exist, it is reused. -// -func CreateTUNWithRequestedGUID(ifname string, requestedGUID *windows.GUID, mtu int, tunAddress string, autoRoute bool) (TunDevice, error) { - wt, err := wintun.CreateAdapter(ifname, WintunTunnelType, requestedGUID) - if err != nil { - return nil, fmt.Errorf("Error creating interface: %w", err) - } - - forcedMTU := 1420 - if mtu > 0 { - forcedMTU = mtu - } - - tun := &tunWindows{ - name: ifname, - wt: wt, - handle: windows.InvalidHandle, - forcedMTU: forcedMTU, - tunAddress: tunAddress, - autoRoute: autoRoute, - } - - // config tun ip - err = tun.configureInterface() - if err != nil { - tun.wt.Close() - return nil, fmt.Errorf("error configure interface: %w", err) - } - - tun.session, err = wt.StartSession(0x800000) // Ring capacity, 8 MiB - if err != nil { - tun.wt.Close() - return nil, fmt.Errorf("error starting session: %w", err) - } - tun.readWait = tun.session.ReadWaitEvent() - return tun, nil -} - -func (tun *tunWindows) Name() string { - return tun.name -} - -func (tun *tunWindows) IsClose() bool { - return atomic.LoadInt32(&tun.close) == 1 -} - -func (tun *tunWindows) Read(buff []byte) (int, error) { - return tun.Read0(buff, messageTransportHeaderSize) -} - -func (tun *tunWindows) Write(buff []byte) (int, error) { - return tun.Write0(buff, messageTransportHeaderSize) -} - -func (tun *tunWindows) URL() string { - return fmt.Sprintf("dev://%s", tun.Name()) -} - -func (tun *tunWindows) configureInterface() error { - retryOnFailure := wintun.StartedAtBoot() - tryTimes := 0 -startOver: - var err error - if tryTimes > 0 { - log.Infoln("Retrying interface configuration after failure because system just booted (T+%v): %v", windows.DurationSinceBoot(), err) - time.Sleep(time.Second) - retryOnFailure = retryOnFailure && tryTimes < 15 - } - tryTimes++ - - luid := winipcfg.LUID(tun.LUID()) - log.Infoln("[wintun]: tun adapter LUID: %d", luid) - mtu, err := tun.MTU() - - if err != nil { - return errors.New("unable to get device mtu") - } - - family := winipcfg.AddressFamily(windows.AF_INET) - familyV6 := winipcfg.AddressFamily(windows.AF_INET6) - - tunAddress := wintun.ParseIPCidr(tun.tunAddress + "/16") - - addresses := []net.IPNet{tunAddress.IPNet()} - - err = luid.FlushIPAddresses(familyV6) - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return err - } - err = luid.FlushDNS(family) - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return err - } - err = luid.FlushDNS(familyV6) - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return err - } - err = luid.FlushRoutes(familyV6) - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return err - } - - foundDefault4 := false - foundDefault6 := false - - if tun.autoRoute { - allowedIPs := []*wintun.IPCidr{ - //wintun.ParseIPCidr("0.0.0.0/0"), - wintun.ParseIPCidr("1.0.0.0/8"), - wintun.ParseIPCidr("2.0.0.0/7"), - wintun.ParseIPCidr("4.0.0.0/6"), - wintun.ParseIPCidr("8.0.0.0/5"), - wintun.ParseIPCidr("16.0.0.0/4"), - wintun.ParseIPCidr("32.0.0.0/3"), - wintun.ParseIPCidr("64.0.0.0/2"), - wintun.ParseIPCidr("128.0.0.0/1"), - wintun.ParseIPCidr("224.0.0.0/4"), - wintun.ParseIPCidr("255.255.255.255/32"), - } - - estimatedRouteCount := len(allowedIPs) - routes := make([]winipcfg.RouteData, 0, estimatedRouteCount) - var haveV4Address, haveV6Address bool = true, false - - for _, allowedip := range allowedIPs { - allowedip.MaskSelf() - if (allowedip.Bits() == 32 && !haveV4Address) || (allowedip.Bits() == 128 && !haveV6Address) { - continue - } - route := winipcfg.RouteData{ - Destination: allowedip.IPNet(), - Metric: 0, - } - if allowedip.Bits() == 32 { - if allowedip.Cidr == 0 { - foundDefault4 = true - } - route.NextHop = net.IPv4zero - } else if allowedip.Bits() == 128 { - if allowedip.Cidr == 0 { - foundDefault6 = true - } - route.NextHop = net.IPv6zero - } - routes = append(routes, route) - } - - deduplicatedRoutes := make([]*winipcfg.RouteData, 0, len(routes)) - sort.Slice(routes, func(i, j int) bool { - if routes[i].Metric != routes[j].Metric { - return routes[i].Metric < routes[j].Metric - } - if c := bytes.Compare(routes[i].NextHop, routes[j].NextHop); c != 0 { - return c < 0 - } - if c := bytes.Compare(routes[i].Destination.IP, routes[j].Destination.IP); c != 0 { - return c < 0 - } - if c := bytes.Compare(routes[i].Destination.Mask, routes[j].Destination.Mask); c != 0 { - return c < 0 - } - return false - }) - for i := 0; i < len(routes); i++ { - if i > 0 && routes[i].Metric == routes[i-1].Metric && - bytes.Equal(routes[i].NextHop, routes[i-1].NextHop) && - bytes.Equal(routes[i].Destination.IP, routes[i-1].Destination.IP) && - bytes.Equal(routes[i].Destination.Mask, routes[i-1].Destination.Mask) { - continue - } - deduplicatedRoutes = append(deduplicatedRoutes, &routes[i]) - } - - err = luid.SetRoutesForFamily(family, deduplicatedRoutes) - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return fmt.Errorf("unable to set routes: %w", err) - } - } - - err = luid.SetIPAddressesForFamily(family, addresses) - if err == windows.ERROR_OBJECT_ALREADY_EXISTS { - cleanupAddressesOnDisconnectedInterfaces(family, addresses) - err = luid.SetIPAddressesForFamily(family, addresses) - } - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return fmt.Errorf("unable to set ips: %w", err) - } - - var ipif *winipcfg.MibIPInterfaceRow - ipif, err = luid.IPInterface(family) - if err != nil { - return err - } - ipif.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled - ipif.DadTransmits = 0 - ipif.ManagedAddressConfigurationSupported = false - ipif.OtherStatefulConfigurationSupported = false - if mtu > 0 { - ipif.NLMTU = uint32(mtu) - } - if (family == windows.AF_INET && foundDefault4) || (family == windows.AF_INET6 && foundDefault6) { - ipif.UseAutomaticMetric = false - ipif.Metric = 0 - } - err = ipif.Set() - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return fmt.Errorf("unable to set metric and MTU: %w", err) - } - - var ipif6 *winipcfg.MibIPInterfaceRow - ipif6, err = luid.IPInterface(familyV6) - if err != nil { - return err - } - ipif6.RouterDiscoveryBehavior = winipcfg.RouterDiscoveryDisabled - ipif6.DadTransmits = 0 - ipif6.ManagedAddressConfigurationSupported = false - ipif6.OtherStatefulConfigurationSupported = false - - err = ipif6.Set() - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return fmt.Errorf("unable to set v6 metric and MTU: %w", err) - } - - err = luid.SetDNS(family, []net.IP{net.ParseIP("198.18.0.2")}, nil) - if err == windows.ERROR_NOT_FOUND && retryOnFailure { - goto startOver - } else if err != nil { - return fmt.Errorf("unable to set DNS %s %s: %w", "198.18.0.2", "nil", err) - } - return nil -} - -func cleanupAddressesOnDisconnectedInterfaces(family winipcfg.AddressFamily, addresses []net.IPNet) { - if len(addresses) == 0 { - return - } - addrToStr := func(ip *net.IP) string { - if ip4 := ip.To4(); ip4 != nil { - return string(ip4) - } - return string(*ip) - } - addrHash := make(map[string]bool, len(addresses)) - for i := range addresses { - addrHash[addrToStr(&addresses[i].IP)] = true - } - interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagDefault) - if err != nil { - return - } - for _, iface := range interfaces { - if iface.OperStatus == winipcfg.IfOperStatusUp { - continue - } - for address := iface.FirstUnicastAddress; address != nil; address = address.Next { - ip := address.Address.IP() - if addrHash[addrToStr(&ip)] { - ipnet := net.IPNet{IP: ip, Mask: net.CIDRMask(int(address.OnLinkPrefixLength), 8*len(ip))} - log.Infoln("Cleaning up stale address %s from interface ā€˜%sā€™", ipnet.String(), iface.FriendlyName()) - iface.LUID.DeleteIPAddress(ipnet) - } - } - } -} - -// GetAutoDetectInterface get ethernet interface -func GetAutoDetectInterface() (string, error) { - ifname, err := getAutoDetectInterfaceByFamily(winipcfg.AddressFamily(windows.AF_INET)) - if err == nil { - return ifname, err - } - - return getAutoDetectInterfaceByFamily(winipcfg.AddressFamily(windows.AF_INET6)) -} - -func getAutoDetectInterfaceByFamily(family winipcfg.AddressFamily) (string, error) { - interfaces, err := winipcfg.GetAdaptersAddresses(family, winipcfg.GAAFlagIncludeGateways) - if err != nil { - return "", fmt.Errorf("get ethernet interface failure. %w", err) - } - for _, iface := range interfaces { - if iface.OperStatus != winipcfg.IfOperStatusUp { - continue - } - - ifname := iface.FriendlyName() - if ifname == "Clash" { - continue - } - - for gatewayAddress := iface.FirstGatewayAddress; gatewayAddress != nil; gatewayAddress = gatewayAddress.Next { - nextHop := gatewayAddress.Address.IP() - - var ipnet net.IPNet - if family == windows.AF_INET { - ipnet = net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)} - } else { - ipnet = net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)} - } - - if _, err = iface.LUID.Route(ipnet, nextHop); err == nil { - return ifname, nil - } - } - } - - return "", errors.New("ethernet interface not found") -} diff --git a/listener/tun/dev/wintun/boot.go b/listener/tun/dev/wintun/boot.go deleted file mode 100644 index d66d3cdc..00000000 --- a/listener/tun/dev/wintun/boot.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build windows -// +build windows - -/* SPDX-License-Identifier: MIT - * - * Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved. - */ - -package wintun - -import ( - "errors" - "log" - "sync" - "time" - - "golang.org/x/sys/windows" - "golang.org/x/sys/windows/svc" -) - -var ( - startedAtBoot bool - startedAtBootOnce sync.Once -) - -func StartedAtBoot() bool { - startedAtBootOnce.Do(func() { - if isService, err := svc.IsWindowsService(); err == nil && !isService { - return - } - if reason, err := svc.DynamicStartReason(); err == nil { - startedAtBoot = (reason&svc.StartReasonAuto) != 0 || (reason&svc.StartReasonDelayedAuto) != 0 - } else if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) { - // TODO: Below this line is Windows 7 compatibility code, which hopefully we can delete at some point. - startedAtBoot = windows.DurationSinceBoot() < time.Minute*10 - } else { - log.Printf("Unable to determine service start reason: %v", err) - } - }) - return startedAtBoot -} diff --git a/listener/tun/dev/wintun/embed_dll/amd64/wintun.dll b/listener/tun/dev/wintun/embed_dll/amd64/wintun.dll deleted file mode 100755 index aee04e77..00000000 Binary files a/listener/tun/dev/wintun/embed_dll/amd64/wintun.dll and /dev/null differ diff --git a/listener/tun/dev/wintun/embed_dll/arm/wintun.dll b/listener/tun/dev/wintun/embed_dll/arm/wintun.dll deleted file mode 100755 index 0017794f..00000000 Binary files a/listener/tun/dev/wintun/embed_dll/arm/wintun.dll and /dev/null differ diff --git a/listener/tun/dev/wintun/embed_dll/arm64/wintun.dll b/listener/tun/dev/wintun/embed_dll/arm64/wintun.dll deleted file mode 100755 index dc4e4aee..00000000 Binary files a/listener/tun/dev/wintun/embed_dll/arm64/wintun.dll and /dev/null differ diff --git a/listener/tun/dev/wintun/embed_dll/windows_386.go b/listener/tun/dev/wintun/embed_dll/windows_386.go deleted file mode 100644 index 05fab743..00000000 --- a/listener/tun/dev/wintun/embed_dll/windows_386.go +++ /dev/null @@ -1,21 +0,0 @@ -package embed_dll - -// Copyright 2020 MeshStep Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -import ( - _ "embed" -) - -//go:embed x86/wintun.dll -var DDlContent []byte diff --git a/listener/tun/dev/wintun/embed_dll/windows_amd64.go b/listener/tun/dev/wintun/embed_dll/windows_amd64.go deleted file mode 100644 index 2ee9f791..00000000 --- a/listener/tun/dev/wintun/embed_dll/windows_amd64.go +++ /dev/null @@ -1,21 +0,0 @@ -package embed_dll - -// Copyright 2020 MeshStep Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -import ( - _ "embed" -) - -//go:embed amd64/wintun.dll -var DDlContent []byte diff --git a/listener/tun/dev/wintun/embed_dll/windows_arm.go b/listener/tun/dev/wintun/embed_dll/windows_arm.go deleted file mode 100644 index 0636f21b..00000000 --- a/listener/tun/dev/wintun/embed_dll/windows_arm.go +++ /dev/null @@ -1,21 +0,0 @@ -package embed_dll - -// Copyright 2020 MeshStep Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -import ( - _ "embed" -) - -//go:embed arm/wintun.dll -var DDlContent []byte diff --git a/listener/tun/dev/wintun/embed_dll/windows_arm64.go b/listener/tun/dev/wintun/embed_dll/windows_arm64.go deleted file mode 100644 index 1e5d605d..00000000 --- a/listener/tun/dev/wintun/embed_dll/windows_arm64.go +++ /dev/null @@ -1,21 +0,0 @@ -package embed_dll - -// Copyright 2020 MeshStep Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// See the License for the specific language governing permissions and -// limitations under the License. - -import ( - _ "embed" -) - -//go:embed arm64/wintun.dll -var DDlContent []byte diff --git a/listener/tun/dev/wintun/embed_dll/x86/wintun.dll b/listener/tun/dev/wintun/embed_dll/x86/wintun.dll deleted file mode 100755 index 2ab97dba..00000000 Binary files a/listener/tun/dev/wintun/embed_dll/x86/wintun.dll and /dev/null differ diff --git a/listener/tun/tun_adapter.go b/listener/tun/tun_adapter.go index b60ae583..f30456f5 100644 --- a/listener/tun/tun_adapter.go +++ b/listener/tun/tun_adapter.go @@ -53,7 +53,7 @@ func New(tunConf *config.Tun, tunAddressPrefix string, tcpIn chan<- C.ConnContex if err != nil { for i := 1; i < 3; i++ { time.Sleep(time.Second * 1) - device, err = dev.OpenTunDevice(tunAddress, autoRoute) + tunDevice, err = parseDevice(devName, uint32(mtu)) if err == nil { break } diff --git a/rule/common/base.go b/rule/common/base.go index d858a7d6..d95c3d34 100644 --- a/rule/common/base.go +++ b/rule/common/base.go @@ -30,6 +30,10 @@ func (b *Base) ShouldFindProcess() bool { return false } +func (b *Base) ShouldResolveIP() bool { + return false +} + func HasNoResolve(params []string) bool { for _, p := range params { if p == noResolve { diff --git a/rule/common/domain.go b/rule/common/domain.go index 5082edbf..f52f1f23 100644 --- a/rule/common/domain.go +++ b/rule/common/domain.go @@ -31,14 +31,6 @@ func (d *Domain) Payload() string { return d.domain } -func (d *Domain) ShouldResolveIP() bool { - return false -} - -func (d *Domain) ShouldFindProcess() bool { - return false -} - func NewDomain(domain string, adapter string) *Domain { return &Domain{ Base: &Base{}, diff --git a/rule/common/domain_keyword.go b/rule/common/domain_keyword.go index 7d6930a0..ea9f5703 100644 --- a/rule/common/domain_keyword.go +++ b/rule/common/domain_keyword.go @@ -32,14 +32,6 @@ func (dk *DomainKeyword) Payload() string { return dk.keyword } -func (dk *DomainKeyword) ShouldResolveIP() bool { - return false -} - -func (dk *DomainKeyword) ShouldFindProcess() bool { - return false -} - func NewDomainKeyword(keyword string, adapter string) *DomainKeyword { return &DomainKeyword{ Base: &Base{}, diff --git a/rule/common/domain_suffix.go b/rule/common/domain_suffix.go index d963ffe2..dd350983 100644 --- a/rule/common/domain_suffix.go +++ b/rule/common/domain_suffix.go @@ -32,14 +32,6 @@ func (ds *DomainSuffix) Payload() string { return ds.suffix } -func (ds *DomainSuffix) ShouldResolveIP() bool { - return false -} - -func (ds *DomainSuffix) ShouldFindProcess() bool { - return false -} - func NewDomainSuffix(suffix string, adapter string) *DomainSuffix { return &DomainSuffix{ Base: &Base{}, diff --git a/rule/common/final.go b/rule/common/final.go index b2c1bbe0..e42baf92 100644 --- a/rule/common/final.go +++ b/rule/common/final.go @@ -25,14 +25,6 @@ func (f *Match) Payload() string { return "" } -func (f *Match) ShouldResolveIP() bool { - return false -} - -func (f *Match) ShouldFindProcess() bool { - return false -} - func NewMatch(adapter string) *Match { return &Match{ Base: &Base{}, diff --git a/rule/common/geoip.go b/rule/common/geoip.go index 3823fbaa..fd32a471 100644 --- a/rule/common/geoip.go +++ b/rule/common/geoip.go @@ -14,16 +14,12 @@ import ( type GEOIP struct { *Base - country string - adapter string - noResolveIP bool + country string + adapter string + noResolveIP bool geoIPMatcher *router.GeoIPMatcher } -func (g *GEOIP) ShouldFindProcess() bool { - return false -} - func (g *GEOIP) RuleType() C.RuleType { return C.GEOIP } @@ -87,7 +83,7 @@ func NewGEOIP(country string, adapter string, noResolveIP bool) (*GEOIP, error) log.Infoln("Start initial GeoIP rule %s => %s, records: %d", country, adapter, recordsCount) geoip := &GEOIP{ - Base: &Base{}, + Base: &Base{}, country: country, adapter: adapter, noResolveIP: noResolveIP, diff --git a/rule/common/geosite.go b/rule/common/geosite.go index 574671b9..8087403b 100644 --- a/rule/common/geosite.go +++ b/rule/common/geosite.go @@ -40,19 +40,11 @@ func (gs *GEOSITE) Payload() string { return gs.country } -func (gs *GEOSITE) ShouldResolveIP() bool { - return false -} - -func (gs *GEOSITE) ShouldFindProcess() bool { - return false -} - func (gs *GEOSITE) GetDomainMatcher() *router.DomainMatcher { return gs.matcher } -func NewGEOSITE(country string, adapter string, ruleExtra *C.RuleExtra) (*GEOSITE, error) { +func NewGEOSITE(country string, adapter string) (*GEOSITE, error) { matcher, recordsCount, err := geodata.LoadGeoSiteMatcher(country) if err != nil { return nil, fmt.Errorf("load GeoSite data error, %s", err.Error()) diff --git a/rule/common/ipcidr.go b/rule/common/ipcidr.go index 06119d9a..a831965a 100644 --- a/rule/common/ipcidr.go +++ b/rule/common/ipcidr.go @@ -55,10 +55,6 @@ func (i *IPCIDR) ShouldResolveIP() bool { return !i.noResolveIP } -func (i *IPCIDR) ShouldFindProcess() bool { - return false -} - func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error) { _, ipnet, err := net.ParseCIDR(s) if err != nil { diff --git a/rule/common/network_type.go b/rule/common/network_type.go index 10729110..f10d9a37 100644 --- a/rule/common/network_type.go +++ b/rule/common/network_type.go @@ -7,14 +7,11 @@ import ( ) type NetworkType struct { + *Base network C.NetWork adapter string } -func (n *NetworkType) ShouldFindProcess() bool { - return false -} - func NewNetworkType(network, adapter string) (*NetworkType, error) { ntType := new(NetworkType) ntType.adapter = adapter @@ -47,11 +44,3 @@ func (n *NetworkType) Adapter() string { func (n *NetworkType) Payload() string { return n.network.String() } - -func (n *NetworkType) ShouldResolveIP() bool { - return false -} - -func (n *NetworkType) RuleExtra() *C.RuleExtra { - return nil -} diff --git a/rule/common/port.go b/rule/common/port.go index 2d665a1a..0e46649b 100644 --- a/rule/common/port.go +++ b/rule/common/port.go @@ -21,10 +21,6 @@ type Port struct { portList []portReal } -func (p *Port) ShouldFindProcess() bool { - return false -} - func (p *Port) RuleType() C.RuleType { if p.isSource { return C.SrcPort @@ -47,10 +43,6 @@ func (p *Port) Payload() string { return p.port } -func (p *Port) ShouldResolveIP() bool { - return false -} - func (p *Port) matchPortReal(portRef string) bool { port, _ := strconv.Atoi(portRef) var rs bool diff --git a/rule/common/process.go b/rule/common/process.go index eeced31a..67a5fad2 100644 --- a/rule/common/process.go +++ b/rule/common/process.go @@ -14,14 +14,10 @@ import ( var processCache = cache.NewLRUCache(cache.WithAge(2), cache.WithSize(64)) type Process struct { - adapter string - process string - nameOnly bool - ruleExtra *C.RuleExtra -} - -func (ps *Process) ShouldFindProcess() bool { - return false + *Base + adapter string + process string + nameOnly bool } func (ps *Process) RuleType() C.RuleType { @@ -67,19 +63,11 @@ func (ps *Process) Payload() string { return ps.process } -func (ps *Process) ShouldResolveIP() bool { - return false -} - -func (ps *Process) RuleExtra() *C.RuleExtra { - return ps.ruleExtra -} - -func NewProcess(process string, adapter string, nameOnly bool, ruleExtra *C.RuleExtra) (*Process, error) { +func NewProcess(process string, adapter string, nameOnly bool) (*Process, error) { return &Process{ - adapter: adapter, - process: process, - nameOnly: nameOnly, - ruleExtra: ruleExtra, + Base: &Base{}, + adapter: adapter, + process: process, + nameOnly: nameOnly, }, nil } diff --git a/rule/logic/and.go b/rule/logic/and.go index 7c1d0b48..91197b8a 100644 --- a/rule/logic/and.go +++ b/rule/logic/and.go @@ -1,8 +1,12 @@ package logic -import C "github.com/Dreamacro/clash/constant" +import ( + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/rule/common" +) type AND struct { + common.Base rules []C.Rule payload string adapter string @@ -56,7 +60,3 @@ func (A *AND) Payload() string { func (A *AND) ShouldResolveIP() bool { return A.needIP } - -func (A *AND) RuleExtra() *C.RuleExtra { - return nil -} diff --git a/rule/logic/common.go b/rule/logic/common.go index 4b2879ca..9cc2bd9a 100644 --- a/rule/logic/common.go +++ b/rule/logic/common.go @@ -74,31 +74,31 @@ func parseRule(tp, payload string, params []string) (C.Rule, error) { switch tp { case "DOMAIN": - parsed = RC.NewDomain(payload, "", nil) + parsed = RC.NewDomain(payload, "") case "DOMAIN-SUFFIX": - parsed = RC.NewDomainSuffix(payload, "", nil) + parsed = RC.NewDomainSuffix(payload, "") case "DOMAIN-KEYWORD": - parsed = RC.NewDomainKeyword(payload, "", nil) + parsed = RC.NewDomainKeyword(payload, "") case "GEOSITE": - parsed, parseErr = RC.NewGEOSITE(payload, "", nil) + parsed, parseErr = RC.NewGEOSITE(payload, "") case "GEOIP": noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewGEOIP(payload, "", noResolve, nil) + parsed, parseErr = RC.NewGEOIP(payload, "", noResolve) case "IP-CIDR", "IP-CIDR6": noResolve := RC.HasNoResolve(params) parsed, parseErr = RC.NewIPCIDR(payload, "", nil, RC.WithIPCIDRNoResolve(noResolve)) case "SRC-IP-CIDR": parsed, parseErr = RC.NewIPCIDR(payload, "", nil, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true)) case "SRC-PORT": - parsed, parseErr = RC.NewPort(payload, "", true, nil) + parsed, parseErr = RC.NewPort(payload, "", true) case "DST-PORT": - parsed, parseErr = RC.NewPort(payload, "", false, nil) + parsed, parseErr = RC.NewPort(payload, "", false) case "PROCESS-NAME": - parsed, parseErr = RC.NewProcess(payload, "", true, nil) + parsed, parseErr = RC.NewProcess(payload, "", true) case "PROCESS-PATH": - parsed, parseErr = RC.NewProcess(payload, "", false, nil) + parsed, parseErr = RC.NewProcess(payload, "", false) case "RULE-SET": - parsed, parseErr = provider.NewRuleSet(payload, "", nil) + parsed, parseErr = provider.NewRuleSet(payload, "") case "NOT": parsed, parseErr = NewNOT(payload, "") case "AND": diff --git a/rule/logic/not.go b/rule/logic/not.go index c42e6fab..0c85d2dd 100644 --- a/rule/logic/not.go +++ b/rule/logic/not.go @@ -3,9 +3,11 @@ package logic import ( "fmt" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/rule/common" ) type NOT struct { + common.Base rule C.Rule payload string adapter string @@ -49,7 +51,3 @@ func (not *NOT) Payload() string { func (not *NOT) ShouldResolveIP() bool { return not.rule.ShouldResolveIP() } - -func (not *NOT) RuleExtra() *C.RuleExtra { - return nil -} diff --git a/rule/logic/or.go b/rule/logic/or.go index e3b0f48c..7aeb27b3 100644 --- a/rule/logic/or.go +++ b/rule/logic/or.go @@ -1,8 +1,12 @@ package logic -import C "github.com/Dreamacro/clash/constant" +import ( + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/rule/common" +) type OR struct { + common.Base rules []C.Rule payload string adapter string @@ -39,10 +43,6 @@ func (or *OR) ShouldResolveIP() bool { return or.needIP } -func (or *OR) RuleExtra() *C.RuleExtra { - return nil -} - func NewOR(payload string, adapter string) (*OR, error) { or := &OR{payload: payload, adapter: adapter} rules, err := parseRuleByPayload(payload) diff --git a/rule/provider/parse.go b/rule/provider/parse.go index ec08f121..8d07f469 100644 --- a/rule/provider/parse.go +++ b/rule/provider/parse.go @@ -57,39 +57,38 @@ func parseRule(tp, payload, target string, params []string) (C.Rule, error) { parsed C.Rule ) + switch tp { + case "DOMAIN": + parsed = RC.NewDomain(payload, target) + case "DOMAIN-SUFFIX": + parsed = RC.NewDomainSuffix(payload, target) + case "DOMAIN-KEYWORD": + parsed = RC.NewDomainKeyword(payload, target) + case "GEOSITE": + parsed, parseErr = RC.NewGEOSITE(payload, target) + case "IP-CIDR", "IP-CIDR6": + noResolve := RC.HasNoResolve(params) + parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRNoResolve(noResolve)) + case "SRC-IP-CIDR": + parsed, parseErr = RC.NewIPCIDR(payload, target, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true)) + case "SRC-PORT": + parsed, parseErr = RC.NewPort(payload, target, true) + case "DST-PORT": + parsed, parseErr = RC.NewPort(payload, target, false) + case "PROCESS-NAME": + parsed, parseErr = RC.NewProcess(payload, target, true) + case "PROCESS-PATH": + parsed, parseErr = RC.NewProcess(payload, target, false) + case "GEOIP": + noResolve := RC.HasNoResolve(params) + parsed, parseErr = RC.NewGEOIP(payload, target, noResolve) + default: + parseErr = fmt.Errorf("unsupported rule type %s", tp) + } ruleExtra := &C.RuleExtra{ Network: RC.FindNetwork(params), SourceIPs: RC.FindSourceIPs(params), } - - switch tp { - case "DOMAIN": - parsed = RC.NewDomain(payload, target, ruleExtra) - case "DOMAIN-SUFFIX": - parsed = RC.NewDomainSuffix(payload, target, ruleExtra) - case "DOMAIN-KEYWORD": - parsed = RC.NewDomainKeyword(payload, target, ruleExtra) - case "GEOSITE": - parsed, parseErr = RC.NewGEOSITE(payload, target, ruleExtra) - case "IP-CIDR", "IP-CIDR6": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewIPCIDR(payload, target, ruleExtra, RC.WithIPCIDRNoResolve(noResolve)) - case "SRC-IP-CIDR": - parsed, parseErr = RC.NewIPCIDR(payload, target, ruleExtra, RC.WithIPCIDRSourceIP(true), RC.WithIPCIDRNoResolve(true)) - case "SRC-PORT": - parsed, parseErr = RC.NewPort(payload, target, true, ruleExtra) - case "DST-PORT": - parsed, parseErr = RC.NewPort(payload, target, false, ruleExtra) - case "PROCESS-NAME": - parsed, parseErr = RC.NewProcess(payload, target, true, ruleExtra) - case "PROCESS-PATH": - parsed, parseErr = RC.NewProcess(payload, target, false, ruleExtra) - case "GEOIP": - noResolve := RC.HasNoResolve(params) - parsed, parseErr = RC.NewGEOIP(payload, target, noResolve, ruleExtra) - default: - parseErr = fmt.Errorf("unsupported rule type %s", tp) - } - + parsed.SetRuleExtra(ruleExtra) return parsed, parseErr } diff --git a/rule/provider/rule_set.go b/rule/provider/rule_set.go index 92c5151a..386e838e 100644 --- a/rule/provider/rule_set.go +++ b/rule/provider/rule_set.go @@ -4,13 +4,14 @@ import ( "fmt" C "github.com/Dreamacro/clash/constant" P "github.com/Dreamacro/clash/constant/provider" + "github.com/Dreamacro/clash/rule/common" ) type RuleSet struct { + common.Base ruleProviderName string adapter string ruleProvider P.RuleProvider - ruleExtra *C.RuleExtra } func (rs *RuleSet) ShouldFindProcess() bool { @@ -45,11 +46,7 @@ func (rs *RuleSet) getProviders() P.RuleProvider { return rs.ruleProvider } -func (rs *RuleSet) RuleExtra() *C.RuleExtra { - return nil -} - -func NewRuleSet(ruleProviderName string, adapter string, ruleExtra *C.RuleExtra) (*RuleSet, error) { +func NewRuleSet(ruleProviderName string, adapter string) (*RuleSet, error) { rp, ok := RuleProviders()[ruleProviderName] if !ok { return nil, fmt.Errorf("rule set %s not found", ruleProviderName) @@ -58,6 +55,5 @@ func NewRuleSet(ruleProviderName string, adapter string, ruleExtra *C.RuleExtra) ruleProviderName: ruleProviderName, adapter: adapter, ruleProvider: rp, - ruleExtra: ruleExtra, }, nil } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index df964b0b..643595df 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -3,7 +3,6 @@ package tunnel import ( "context" "fmt" - R "github.com/Dreamacro/clash/rule/common" "net" "path/filepath" "runtime" @@ -343,7 +342,6 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { defer configMux.RUnlock() var resolved bool - var processFound bool if node := resolver.DefaultHosts.Search(metadata.Host); node != nil { ip := node.Data.(net.IP)