From 1ad87cfec928fb69036cba7004e566fc797a1239 Mon Sep 17 00:00:00 2001 From: adlyq Date: Fri, 3 Jun 2022 13:31:56 +0800 Subject: [PATCH 1/9] =?UTF-8?q?chore:=20=E9=80=89=E6=8B=A9fallback?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=BD=93=E8=8A=82=E7=82=B9=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E7=94=A8=E6=97=B6=E8=A7=A6=E5=8F=91urltest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adapter/outboundgroup/fallback.go | 23 +++++++++++++++++++---- adapter/outboundgroup/groupbase.go | 4 ++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index cd09b747..ef237c64 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -8,11 +8,13 @@ import ( "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" + "time" ) type Fallback struct { *GroupBase disableUDP bool + testUrl string selected string } @@ -90,15 +92,27 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy { return al } -func (f *Fallback) Set(name string) error { +func (f *Fallback) Set(name string) (err error) { + var p C.Proxy for _, proxy := range f.GetProxies(false) { if proxy.Name() == name { - f.selected = name - return nil + p = proxy + break } } - return errors.New("proxy not exist") + if p == nil { + return errors.New("proxy not exist") + } + + f.selected = name + if !p.Alive() { + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(5000)) + defer cancel() + _, _ = p.URLTest(ctx, f.testUrl) + } + + return nil } func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback { @@ -114,5 +128,6 @@ func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) providers, }), disableUDP: option.DisableUDP, + testUrl: option.URL, } } diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 4aa290c0..707e1a6a 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -146,14 +146,14 @@ func (gb *GroupBase) onDialFailed() { gb.failedTimes++ if gb.failedTimes == 1 { - log.Warnln("ProxyGroup: %s first failed", gb.Name()) + log.Debugln("ProxyGroup: %s first failed", gb.Name()) gb.failedTime = time.Now() } else { if time.Since(gb.failedTime) > gb.failedTimeoutInterval() { return } - log.Warnln("ProxyGroup: %s failed count: %d", gb.Name(), gb.failedTimes) + log.Debugln("ProxyGroup: %s failed count: %d", gb.Name(), gb.failedTimes) if gb.failedTimes >= gb.maxFailedTimes() { gb.failedTesting.Store(true) log.Warnln("because %s failed multiple times, active health check", gb.Name()) From 6e84f685ce61d96db28c5eb1457828735b3f70ed Mon Sep 17 00:00:00 2001 From: adlyq Date: Fri, 3 Jun 2022 16:50:05 +0800 Subject: [PATCH 2/9] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0geox=E6=97=B6?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E5=86=85=E5=AD=98=E5=AD=98=E5=82=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adapter/outboundgroup/fallback.go | 2 +- component/geodata/geodata.go | 4 +- component/geodata/geodataproto.go | 6 +- component/geodata/memconservative/memc.go | 13 ++- component/geodata/standard/standard.go | 40 ++++--- config/updateGeo.go | 124 +++++++++++----------- 6 files changed, 103 insertions(+), 86 deletions(-) diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index ef237c64..8f5f539b 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -92,7 +92,7 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy { return al } -func (f *Fallback) Set(name string) (err error) { +func (f *Fallback) Set(name string) error { var p C.Proxy for _, proxy := range f.GetProxies(false) { if proxy.Name() == name { diff --git a/component/geodata/geodata.go b/component/geodata/geodata.go index c23d0b52..ac0f820e 100644 --- a/component/geodata/geodata.go +++ b/component/geodata/geodata.go @@ -30,7 +30,7 @@ func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*route return nil, fmt.Errorf("empty listname in rule: %s", siteWithAttr) } - domains, err := l.LoadSite(file, list) + domains, err := l.LoadSiteByPath(file, list) if err != nil { return nil, err } @@ -59,7 +59,7 @@ func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*route } func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) { - return l.LoadIP(C.GeoipName, country) + return l.LoadIPByPath(C.GeoipName, country) } var loaders map[string]func() LoaderImplementation diff --git a/component/geodata/geodataproto.go b/component/geodata/geodataproto.go index a63b25bc..ffefc484 100644 --- a/component/geodata/geodataproto.go +++ b/component/geodata/geodataproto.go @@ -5,8 +5,10 @@ import ( ) type LoaderImplementation interface { - LoadSite(filename, list string) ([]*router.Domain, error) - LoadIP(filename, country string) ([]*router.CIDR, error) + LoadSiteByPath(filename, list string) ([]*router.Domain, error) + LoadSiteByBytes(geositeBytes []byte, list string) ([]*router.Domain, error) + LoadIPByPath(filename, country string) ([]*router.CIDR, error) + LoadIPByBytes(geoipBytes []byte, country string) ([]*router.CIDR, error) } type Loader interface { diff --git a/component/geodata/memconservative/memc.go b/component/geodata/memconservative/memc.go index 2961f6eb..88d3b4e5 100644 --- a/component/geodata/memconservative/memc.go +++ b/component/geodata/memconservative/memc.go @@ -1,6 +1,7 @@ package memconservative import ( + "errors" "fmt" "runtime" @@ -13,7 +14,7 @@ type memConservativeLoader struct { geositecache GeoSiteCache } -func (m *memConservativeLoader) LoadIP(filename, country string) ([]*router.CIDR, error) { +func (m *memConservativeLoader) LoadIPByPath(filename, country string) ([]*router.CIDR, error) { defer runtime.GC() geoip, err := m.geoipcache.Unmarshal(filename, country) if err != nil { @@ -22,7 +23,11 @@ func (m *memConservativeLoader) LoadIP(filename, country string) ([]*router.CIDR return geoip.Cidr, nil } -func (m *memConservativeLoader) LoadSite(filename, list string) ([]*router.Domain, error) { +func (m *memConservativeLoader) LoadIPByBytes(geoipBytes []byte, country string) ([]*router.CIDR, error) { + return nil, errors.New("memConservative do not support LoadIPByBytes") +} + +func (m *memConservativeLoader) LoadSiteByPath(filename, list string) ([]*router.Domain, error) { defer runtime.GC() geosite, err := m.geositecache.Unmarshal(filename, list) if err != nil { @@ -31,6 +36,10 @@ func (m *memConservativeLoader) LoadSite(filename, list string) ([]*router.Domai return geosite.Domain, nil } +func (m *memConservativeLoader) LoadSiteByBytes(geositeBytes []byte, list string) ([]*router.Domain, error) { + return nil, errors.New("memConservative do not support LoadSiteByBytes") +} + func newMemConservativeLoader() geodata.LoaderImplementation { return &memConservativeLoader{make(map[string]*router.GeoIP), make(map[string]*router.GeoSite)} } diff --git a/component/geodata/standard/standard.go b/component/geodata/standard/standard.go index 0febbc08..355cbf34 100644 --- a/component/geodata/standard/standard.go +++ b/component/geodata/standard/standard.go @@ -29,11 +29,7 @@ func ReadAsset(file string) ([]byte, error) { return ReadFile(C.Path.GetAssetLocation(file)) } -func loadIP(filename, country string) ([]*router.CIDR, error) { - geoipBytes, err := ReadAsset(filename) - if err != nil { - return nil, fmt.Errorf("failed to open file: %s, base error: %s", filename, err.Error()) - } +func loadIP(geoipBytes []byte, country string) ([]*router.CIDR, error) { var geoipList router.GeoIPList if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil { return nil, err @@ -45,14 +41,10 @@ func loadIP(filename, country string) ([]*router.CIDR, error) { } } - return nil, fmt.Errorf("country not found in %s%s%s", filename, ": ", country) + return nil, fmt.Errorf("country %s not found", country) } -func loadSite(filename, list string) ([]*router.Domain, error) { - geositeBytes, err := ReadAsset(filename) - if err != nil { - return nil, fmt.Errorf("failed to open file: %s, base error: %s", filename, err.Error()) - } +func loadSite(geositeBytes []byte, list string) ([]*router.Domain, error) { var geositeList router.GeoSiteList if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil { return nil, err @@ -64,17 +56,33 @@ func loadSite(filename, list string) ([]*router.Domain, error) { } } - return nil, fmt.Errorf("list not found in %s%s%s", filename, ": ", list) + return nil, fmt.Errorf("list %s not found", list) } type standardLoader struct{} -func (d standardLoader) LoadSite(filename, list string) ([]*router.Domain, error) { - return loadSite(filename, list) +func (d standardLoader) LoadSiteByPath(filename, list string) ([]*router.Domain, error) { + geositeBytes, err := ReadAsset(filename) + if err != nil { + return nil, fmt.Errorf("failed to open file: %s, base error: %s", filename, err.Error()) + } + return loadSite(geositeBytes, list) } -func (d standardLoader) LoadIP(filename, country string) ([]*router.CIDR, error) { - return loadIP(filename, country) +func (d standardLoader) LoadSiteByBytes(geositeBytes []byte, list string) ([]*router.Domain, error) { + return loadSite(geositeBytes, list) +} + +func (d standardLoader) LoadIPByPath(filename, country string) ([]*router.CIDR, error) { + geoipBytes, err := ReadAsset(filename) + if err != nil { + return nil, fmt.Errorf("failed to open file: %s, base error: %s", filename, err.Error()) + } + return loadIP(geoipBytes, country) +} + +func (d standardLoader) LoadIPByBytes(geoipBytes []byte, country string) ([]*router.CIDR, error) { + return loadIP(geoipBytes, country) } func init() { diff --git a/config/updateGeo.go b/config/updateGeo.go index a78a0320..e865f807 100644 --- a/config/updateGeo.go +++ b/config/updateGeo.go @@ -6,77 +6,75 @@ import ( _ "github.com/Dreamacro/clash/component/geodata/standard" C "github.com/Dreamacro/clash/constant" "github.com/oschwald/geoip2-golang" - "os" + "io/ioutil" + "net/http" "runtime" ) func UpdateGeoDatabases() error { - var ( - tmpMMDB = C.Path.Resolve("temp_country.mmdb") - tmpGepIP = C.Path.Resolve("temp_geoip.dat") - tmpGeoSite = C.Path.Resolve("temp_geosite.dat") - ) - - if C.GeodataMode { - if err := downloadGeoIP(tmpGepIP); err != nil { - return fmt.Errorf("can't download GeoIP database file: %w", err) - } - - if err := verifyGeoSite("temp_geoip.dat"); err != nil { - _ = os.Remove(tmpGepIP) - return fmt.Errorf("invalid GeoIP database file: %s", err) - } - - if err := os.Rename(tmpGepIP, C.Path.GeoIP()); err != nil { - return fmt.Errorf("can't rename MMDB database file: %w", err) - } - - } else { - if err := downloadMMDB(tmpMMDB); err != nil { - return fmt.Errorf("can't download MMDB database file: %w", err) - } - - if err := verifyMMDB("temp_country.mmdb"); err != nil { - _ = os.Remove(tmpMMDB) - return fmt.Errorf("invalid MMDB database file: %s", err) - } - - if err := os.Rename(tmpMMDB, C.Path.MMDB()); err != nil { - return fmt.Errorf("can't rename MMDB database file: %w", err) - } - } - - if err := downloadGeoSite(tmpGeoSite); err != nil { - return fmt.Errorf("can't download GeoSite database file: %w", err) - } - - if err := verifyGeoSite("temp_geosite.dat"); err != nil { - _ = os.Remove(tmpGeoSite) - return fmt.Errorf("invalid GeoSite database file: %s", err) - } - - if err := os.Rename(tmpGeoSite, C.Path.GeoSite()); err != nil { - return fmt.Errorf("can't rename GeoSite database file: %w", err) - } - runtime.GC() - return nil -} - -func verifyMMDB(path string) error { - instance, err := geoip2.Open(path) - if err == nil { - _ = instance.Close() - } - return err -} - -func verifyGeoSite(path string) error { + defer runtime.GC() geoLoader, err := geodata.GetGeoDataLoader("standard") if err != nil { return err } - _, err = geoLoader.LoadSite(path, "cn") + if C.GeodataMode { + data, err := downloadForBytes(C.GeoIpUrl) + if err != nil { + return fmt.Errorf("can't download GeoIP database file: %w", err) + } - return err + if _, err = geoLoader.LoadIPByBytes(data, "cn"); err != nil { + return fmt.Errorf("invalid GeoIP database file: %s", err) + } + + if saveFile(data, C.Path.GeoIP()) != nil { + return fmt.Errorf("can't save GeoIP database file: %w", err) + } + + } else { + data, err := downloadForBytes(C.MmdbUrl) + if err != nil { + return fmt.Errorf("can't download MMDB database file: %w", err) + } + + instance, err := geoip2.FromBytes(data) + if err != nil { + return fmt.Errorf("invalid MMDB database file: %s", err) + } + _ = instance.Close() + + if saveFile(data, C.Path.MMDB()) != nil { + return fmt.Errorf("can't save MMDB database file: %w", err) + } + } + + data, err := downloadForBytes(C.GeoSiteUrl) + if err != nil { + return fmt.Errorf("can't download GeoSite database file: %w", err) + } + + if _, err = geoLoader.LoadSiteByBytes(data, "cn"); err != nil { + return fmt.Errorf("invalid GeoSite database file: %s", err) + } + + if saveFile(data, C.Path.GeoSite()) != nil { + return fmt.Errorf("can't save GeoSite database file: %w", err) + } + + return nil +} + +func downloadForBytes(url string) ([]byte, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return ioutil.ReadAll(resp.Body) +} + +func saveFile(bytes []byte, path string) error { + return ioutil.WriteFile(path, bytes, 0o644) } From 1298d2f8b6f5557eec764fa5cb82eeae5974cb45 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 3 Jun 2022 18:09:08 +0800 Subject: [PATCH 3/9] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0tag=20no=5Fdoq?= =?UTF-8?q?=20=E7=BC=96=E8=AF=91=E4=B8=8D=E5=90=ABdoq=E7=89=88=E6=9C=AC,?= =?UTF-8?q?=20=E4=BB=85=E5=87=8F=E5=B0=911.5MB(macOS-arm64)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dns/doq.go | 2 ++ dns/no_doq.go | 10 ++++++++++ 2 files changed, 12 insertions(+) create mode 100644 dns/no_doq.go diff --git a/dns/doq.go b/dns/doq.go index 7682a21e..7baeb700 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -1,3 +1,5 @@ +//go:build !no_doq + package dns import ( diff --git a/dns/no_doq.go b/dns/no_doq.go new file mode 100644 index 00000000..b1d0a485 --- /dev/null +++ b/dns/no_doq.go @@ -0,0 +1,10 @@ +//go:build no_doq + +package dns + +import "github.com/Dreamacro/clash/log" + +func newDOQ(r *Resolver, addr, proxyAdapter string) dnsClient { + log.Fatalln("unsupported feature on the build") + return nil +} From ed9b9ce3c5e0abc60b6c6440f9297dee4f84f7a3 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 3 Jun 2022 20:07:30 +0800 Subject: [PATCH 4/9] =?UTF-8?q?refactor:=20=E6=B7=BB=E5=8A=A0no=5Fgvisor?= =?UTF-8?q?=20=E7=BC=96=E8=AF=91tag,=20=E5=89=94=E9=99=A4gvisor=20stack?= =?UTF-8?q?=E6=94=AF=E6=8C=81,=20=E6=96=B9=E4=BE=BF=E5=9C=A8arm=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E4=B8=8Adebug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dns/doq.go | 2 -- dns/no_doq.go | 10 ------ listener/tun/device/device.go | 2 ++ listener/tun/device/device_no_gvisor.go | 29 ++++++++++++++++ listener/tun/device/fdbased/fd_unix.go | 11 ------ listener/tun/device/fdbased/fd_unix_gvisor.go | 17 ++++++++++ .../tun/device/fdbased/fd_unix_no_gvisor.go | 14 ++++++++ listener/tun/device/fdbased/open_others.go | 8 +---- .../tun/device/fdbased/open_others_gvisor.go | 19 +++++++++++ .../device/fdbased/open_others_no_gvisor.go | 11 ++++++ listener/tun/device/iobased/endpoint.go | 2 ++ listener/tun/device/iobased/iobased.go | 1 + listener/tun/device/tun/tun_wireguard.go | 25 ++------------ .../tun/device/tun/tun_wireguard_gvisor.go | 34 +++++++++++++++++++ .../tun/device/tun/tun_wireguard_no_gvisor.go | 24 +++++++++++++ .../tun/ipstack/gvisor/adapter/adapter.go | 2 ++ .../tun/ipstack/gvisor/adapter/handler.go | 2 ++ listener/tun/ipstack/gvisor/handler.go | 2 ++ listener/tun/ipstack/gvisor/nic.go | 2 ++ listener/tun/ipstack/gvisor/option/option.go | 2 ++ listener/tun/ipstack/gvisor/route.go | 2 ++ listener/tun/ipstack/gvisor/stack.go | 7 ++-- .../tun/ipstack/gvisor/stack_no_gvisor.go | 19 +++++++++++ listener/tun/ipstack/gvisor/tcp.go | 2 ++ listener/tun/ipstack/gvisor/udp.go | 2 ++ listener/tun/tun_adapter.go | 3 +- 26 files changed, 197 insertions(+), 57 deletions(-) delete mode 100644 dns/no_doq.go create mode 100644 listener/tun/device/device_no_gvisor.go create mode 100644 listener/tun/device/fdbased/fd_unix_gvisor.go create mode 100644 listener/tun/device/fdbased/fd_unix_no_gvisor.go create mode 100644 listener/tun/device/fdbased/open_others_gvisor.go create mode 100644 listener/tun/device/fdbased/open_others_no_gvisor.go create mode 100644 listener/tun/device/iobased/iobased.go create mode 100644 listener/tun/device/tun/tun_wireguard_gvisor.go create mode 100644 listener/tun/device/tun/tun_wireguard_no_gvisor.go create mode 100644 listener/tun/ipstack/gvisor/stack_no_gvisor.go diff --git a/dns/doq.go b/dns/doq.go index 7baeb700..7682a21e 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -1,5 +1,3 @@ -//go:build !no_doq - package dns import ( diff --git a/dns/no_doq.go b/dns/no_doq.go deleted file mode 100644 index b1d0a485..00000000 --- a/dns/no_doq.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build no_doq - -package dns - -import "github.com/Dreamacro/clash/log" - -func newDOQ(r *Resolver, addr, proxyAdapter string) dnsClient { - log.Fatalln("unsupported feature on the build") - return nil -} diff --git a/listener/tun/device/device.go b/listener/tun/device/device.go index 70115cbd..f7c3552a 100644 --- a/listener/tun/device/device.go +++ b/listener/tun/device/device.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package device import ( diff --git a/listener/tun/device/device_no_gvisor.go b/listener/tun/device/device_no_gvisor.go new file mode 100644 index 00000000..b2d7225d --- /dev/null +++ b/listener/tun/device/device_no_gvisor.go @@ -0,0 +1,29 @@ +//go:build no_gvisor + +package device + +// Device is the interface that implemented by network layer devices (e.g. tun), +// and easy to use as stack.LinkEndpoint. +type Device interface { + + // Name returns the current name of the device. + Name() string + + // Type returns the driver type of the device. + Type() string + + // Read packets from tun device + Read(packet []byte) (int, error) + + // Write packets to tun device + Write(packet []byte) (int, error) + + // Close stops and closes the device. + Close() error + + // UseEndpoint work for gVisor stack + UseEndpoint() error + + // UseIOBased work for other ip stack + UseIOBased() error +} diff --git a/listener/tun/device/fdbased/fd_unix.go b/listener/tun/device/fdbased/fd_unix.go index 23474a5a..63f6e839 100644 --- a/listener/tun/device/fdbased/fd_unix.go +++ b/listener/tun/device/fdbased/fd_unix.go @@ -4,24 +4,13 @@ package fdbased import ( "fmt" - "os" "strconv" "github.com/Dreamacro/clash/listener/tun/device" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/tcpip/stack" ) -type FD struct { - stack.LinkEndpoint - - fd int - mtu uint32 - - file *os.File -} - func Open(name string, mtu uint32) (device.Device, error) { fd, err := strconv.Atoi(name) if err != nil { diff --git a/listener/tun/device/fdbased/fd_unix_gvisor.go b/listener/tun/device/fdbased/fd_unix_gvisor.go new file mode 100644 index 00000000..cc327c77 --- /dev/null +++ b/listener/tun/device/fdbased/fd_unix_gvisor.go @@ -0,0 +1,17 @@ +//go:build !no_gvisor + +package fdbased + +import ( + "gvisor.dev/gvisor/pkg/tcpip/stack" + "os" +) + +type FD struct { + stack.LinkEndpoint + + fd int + mtu uint32 + + file *os.File +} diff --git a/listener/tun/device/fdbased/fd_unix_no_gvisor.go b/listener/tun/device/fdbased/fd_unix_no_gvisor.go new file mode 100644 index 00000000..a4ecf8b9 --- /dev/null +++ b/listener/tun/device/fdbased/fd_unix_no_gvisor.go @@ -0,0 +1,14 @@ +//go:build no_gvisor + +package fdbased + +import ( + "os" +) + +type FD struct { + fd int + mtu uint32 + + file *os.File +} diff --git a/listener/tun/device/fdbased/open_others.go b/listener/tun/device/fdbased/open_others.go index 57ad2c1a..a4d4687a 100644 --- a/listener/tun/device/fdbased/open_others.go +++ b/listener/tun/device/fdbased/open_others.go @@ -7,7 +7,6 @@ import ( "os" "github.com/Dreamacro/clash/listener/tun/device" - "github.com/Dreamacro/clash/listener/tun/device/iobased" ) func open(fd int, mtu uint32) (device.Device, error) { @@ -17,12 +16,7 @@ func open(fd int, mtu uint32) (device.Device, error) { } func (f *FD) useEndpoint() error { - ep, err := iobased.New(os.NewFile(uintptr(f.fd), f.Name()), f.mtu, 0) - if err != nil { - return fmt.Errorf("create endpoint: %w", err) - } - f.LinkEndpoint = ep - return nil + return newEp(f) } func (f *FD) useIOBased() error { diff --git a/listener/tun/device/fdbased/open_others_gvisor.go b/listener/tun/device/fdbased/open_others_gvisor.go new file mode 100644 index 00000000..7f7249eb --- /dev/null +++ b/listener/tun/device/fdbased/open_others_gvisor.go @@ -0,0 +1,19 @@ +//go:build !no_gvisor && !linux && !windows + +package fdbased + +import ( + "fmt" + "os" + + "github.com/Dreamacro/clash/listener/tun/device/iobased" +) + +func newEp(f *FD) error { + ep, err := iobased.New(os.NewFile(uintptr(f.fd), f.Name()), f.mtu, 0) + if err != nil { + return fmt.Errorf("create endpoint: %w", err) + } + f.LinkEndpoint = ep + return nil +} diff --git a/listener/tun/device/fdbased/open_others_no_gvisor.go b/listener/tun/device/fdbased/open_others_no_gvisor.go new file mode 100644 index 00000000..559881b4 --- /dev/null +++ b/listener/tun/device/fdbased/open_others_no_gvisor.go @@ -0,0 +1,11 @@ +//go:build no_gvisor && !linux && !windows + +package fdbased + +import ( + "fmt" +) + +func newEp(f *FD) error { + return fmt.Errorf("unsupported gvisor on the build") +} diff --git a/listener/tun/device/iobased/endpoint.go b/listener/tun/device/iobased/endpoint.go index e0a4583a..90871ee0 100644 --- a/listener/tun/device/iobased/endpoint.go +++ b/listener/tun/device/iobased/endpoint.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + // Package iobased provides the implementation of io.ReadWriter // based data-link layer endpoints. package iobased diff --git a/listener/tun/device/iobased/iobased.go b/listener/tun/device/iobased/iobased.go new file mode 100644 index 00000000..c16ee55c --- /dev/null +++ b/listener/tun/device/iobased/iobased.go @@ -0,0 +1 @@ +package iobased diff --git a/listener/tun/device/tun/tun_wireguard.go b/listener/tun/device/tun/tun_wireguard.go index 1aafae54..828dd56d 100644 --- a/listener/tun/device/tun/tun_wireguard.go +++ b/listener/tun/device/tun/tun_wireguard.go @@ -8,22 +8,10 @@ import ( "runtime" "github.com/Dreamacro/clash/listener/tun/device" - "github.com/Dreamacro/clash/listener/tun/device/iobased" "golang.zx2c4.com/wireguard/tun" ) -type TUN struct { - *iobased.Endpoint - - nt *tun.NativeTun - mtu uint32 - name string - offset int - - cache []byte -} - func Open(name string, mtu uint32) (_ device.Device, err error) { defer func() { if r := recover(); r != nil { @@ -91,11 +79,7 @@ func (t *TUN) Write(packet []byte) (int, error) { } func (t *TUN) Close() error { - defer func(ep *iobased.Endpoint) { - if ep != nil { - ep.Close() - } - }(t.Endpoint) + defer closeIO(t) return t.nt.Close() } @@ -105,12 +89,7 @@ func (t *TUN) Name() string { } func (t *TUN) UseEndpoint() error { - ep, err := iobased.New(t, t.mtu, t.offset) - if err != nil { - return fmt.Errorf("create endpoint: %w", err) - } - t.Endpoint = ep - return nil + return newEq(t) } func (t *TUN) UseIOBased() error { diff --git a/listener/tun/device/tun/tun_wireguard_gvisor.go b/listener/tun/device/tun/tun_wireguard_gvisor.go new file mode 100644 index 00000000..400b4219 --- /dev/null +++ b/listener/tun/device/tun/tun_wireguard_gvisor.go @@ -0,0 +1,34 @@ +//go:build !linux && !no_gvisor + +package tun + +import ( + "fmt" + "github.com/Dreamacro/clash/listener/tun/device/iobased" + "golang.zx2c4.com/wireguard/tun" +) + +type TUN struct { + *iobased.Endpoint + nt *tun.NativeTun + mtu uint32 + name string + offset int + + cache []byte +} + +func closeIO(t *TUN) { + if t.Endpoint != nil { + t.Endpoint.Close() + } +} + +func newEq(t *TUN) error { + ep, err := iobased.New(t, t.mtu, t.offset) + if err != nil { + return fmt.Errorf("create endpoint: %w", err) + } + t.Endpoint = ep + return nil +} diff --git a/listener/tun/device/tun/tun_wireguard_no_gvisor.go b/listener/tun/device/tun/tun_wireguard_no_gvisor.go new file mode 100644 index 00000000..c55487c7 --- /dev/null +++ b/listener/tun/device/tun/tun_wireguard_no_gvisor.go @@ -0,0 +1,24 @@ +//go:build !linux && no_gvisor + +package tun + +import ( + "golang.zx2c4.com/wireguard/tun" +) + +type TUN struct { + nt *tun.NativeTun + mtu uint32 + name string + offset int + + cache []byte +} + +func closeIO(t *TUN) { + +} + +func newEq(t *TUN) error { + return nil +} diff --git a/listener/tun/ipstack/gvisor/adapter/adapter.go b/listener/tun/ipstack/gvisor/adapter/adapter.go index 9a5649ef..08d0e780 100644 --- a/listener/tun/ipstack/gvisor/adapter/adapter.go +++ b/listener/tun/ipstack/gvisor/adapter/adapter.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package adapter import ( diff --git a/listener/tun/ipstack/gvisor/adapter/handler.go b/listener/tun/ipstack/gvisor/adapter/handler.go index 715f6636..913922d6 100644 --- a/listener/tun/ipstack/gvisor/adapter/handler.go +++ b/listener/tun/ipstack/gvisor/adapter/handler.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package adapter // Handler is a TCP/UDP connection handler that implements diff --git a/listener/tun/ipstack/gvisor/handler.go b/listener/tun/ipstack/gvisor/handler.go index 2e4ac9ff..ed119fc3 100644 --- a/listener/tun/ipstack/gvisor/handler.go +++ b/listener/tun/ipstack/gvisor/handler.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package gvisor import ( diff --git a/listener/tun/ipstack/gvisor/nic.go b/listener/tun/ipstack/gvisor/nic.go index 0ca96778..77a1a349 100644 --- a/listener/tun/ipstack/gvisor/nic.go +++ b/listener/tun/ipstack/gvisor/nic.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package gvisor import ( diff --git a/listener/tun/ipstack/gvisor/option/option.go b/listener/tun/ipstack/gvisor/option/option.go index 2076fd58..a2fb2851 100644 --- a/listener/tun/ipstack/gvisor/option/option.go +++ b/listener/tun/ipstack/gvisor/option/option.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package option import ( diff --git a/listener/tun/ipstack/gvisor/route.go b/listener/tun/ipstack/gvisor/route.go index 5a3d3bf4..8e1ae94e 100644 --- a/listener/tun/ipstack/gvisor/route.go +++ b/listener/tun/ipstack/gvisor/route.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package gvisor import ( diff --git a/listener/tun/ipstack/gvisor/stack.go b/listener/tun/ipstack/gvisor/stack.go index 1307bc71..c79bd0df 100644 --- a/listener/tun/ipstack/gvisor/stack.go +++ b/listener/tun/ipstack/gvisor/stack.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + // Package gvisor provides a thin wrapper around a gVisor's stack. package gvisor @@ -64,8 +66,9 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref // Generate unique NIC id. nicID := tcpip.NICID(s.Stack.UniqueID()) - - opts = append(opts, + defaultOpts := []option.Option{option.WithDefault()} + defaultOpts = append(defaultOpts, opts...) + opts = append(defaultOpts, // Create stack NIC and then bind link endpoint to it. withCreatingNIC(nicID, device), diff --git a/listener/tun/ipstack/gvisor/stack_no_gvisor.go b/listener/tun/ipstack/gvisor/stack_no_gvisor.go new file mode 100644 index 00000000..7a424e74 --- /dev/null +++ b/listener/tun/ipstack/gvisor/stack_no_gvisor.go @@ -0,0 +1,19 @@ +//go:build no_gvisor + +package gvisor + +import ( + "fmt" + "github.com/Dreamacro/clash/adapter/inbound" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/listener/tun/device" + "github.com/Dreamacro/clash/listener/tun/ipstack" + "github.com/Dreamacro/clash/log" + "net/netip" +) + +// New allocates a new *gvStack with given options. +func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Prefix, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) { + log.Fatalln("unsupported gvisor stack on the build") + return nil, fmt.Errorf("unsupported gvisor stack on the build") +} diff --git a/listener/tun/ipstack/gvisor/tcp.go b/listener/tun/ipstack/gvisor/tcp.go index a045d056..660912cb 100644 --- a/listener/tun/ipstack/gvisor/tcp.go +++ b/listener/tun/ipstack/gvisor/tcp.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package gvisor import ( diff --git a/listener/tun/ipstack/gvisor/udp.go b/listener/tun/ipstack/gvisor/udp.go index 502e3a9c..f010ed8a 100644 --- a/listener/tun/ipstack/gvisor/udp.go +++ b/listener/tun/ipstack/gvisor/udp.go @@ -1,3 +1,5 @@ +//go:build !no_gvisor + package gvisor import ( diff --git a/listener/tun/tun_adapter.go b/listener/tun/tun_adapter.go index 9d0cad1b..7b69c5f3 100644 --- a/listener/tun/tun_adapter.go +++ b/listener/tun/tun_adapter.go @@ -13,7 +13,6 @@ import ( "github.com/Dreamacro/clash/listener/tun/ipstack" "github.com/Dreamacro/clash/listener/tun/ipstack/commons" "github.com/Dreamacro/clash/listener/tun/ipstack/gvisor" - "github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option" "github.com/Dreamacro/clash/listener/tun/ipstack/system" "github.com/Dreamacro/clash/log" "net/netip" @@ -63,7 +62,7 @@ func New(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound. return nil, fmt.Errorf("can't attach endpoint to tun: %w", err) } - tunStack, err = gvisor.New(tunDevice, tunConf.DNSHijack, tunAddress, tcpIn, udpIn, option.WithDefault()) + tunStack, err = gvisor.New(tunDevice, tunConf.DNSHijack, tunAddress, tcpIn, udpIn) if err != nil { _ = tunDevice.Close() From 298ca42369366cff797f5fd3ab085b9e4825b43a Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 3 Jun 2022 20:23:53 +0800 Subject: [PATCH 5/9] =?UTF-8?q?chore:=20=E5=90=AF=E5=8A=A8=E5=8F=82?= =?UTF-8?q?=E6=95=B0v=EF=BC=8C=E6=9F=A5=E7=9C=8B=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E6=89=93=E5=8D=B0=E4=BD=BF=E7=94=A8=E7=9A=84?= =?UTF-8?q?tags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- constant/features/no_doq.go | 7 +++++++ constant/features/no_gvisor.go | 7 +++++++ constant/features/tags.go | 3 +++ main.go | 6 +++++- 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 constant/features/no_doq.go create mode 100644 constant/features/no_gvisor.go create mode 100644 constant/features/tags.go diff --git a/constant/features/no_doq.go b/constant/features/no_doq.go new file mode 100644 index 00000000..c915272f --- /dev/null +++ b/constant/features/no_doq.go @@ -0,0 +1,7 @@ +//go:build no_doq + +package features + +func init() { + TAGS = append(TAGS, "no_doq") +} diff --git a/constant/features/no_gvisor.go b/constant/features/no_gvisor.go new file mode 100644 index 00000000..d0d5391a --- /dev/null +++ b/constant/features/no_gvisor.go @@ -0,0 +1,7 @@ +//go:build no_gvisor + +package features + +func init() { + TAGS = append(TAGS, "no_gvisor") +} diff --git a/constant/features/tags.go b/constant/features/tags.go new file mode 100644 index 00000000..c81f6d4e --- /dev/null +++ b/constant/features/tags.go @@ -0,0 +1,3 @@ +package features + +var TAGS = make([]string, 0, 0) diff --git a/main.go b/main.go index 10f4307b..7b128e2d 100644 --- a/main.go +++ b/main.go @@ -3,10 +3,12 @@ package main import ( "flag" "fmt" + "github.com/Dreamacro/clash/constant/features" "os" "os/signal" "path/filepath" "runtime" + "strings" "syscall" "github.com/Dreamacro/clash/config" @@ -50,7 +52,9 @@ func init() { func main() { _, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {})) if version { - fmt.Printf("Clash Meta %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime) + fmt.Printf("Clash Meta %s %s %s with %s %s\n", + C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime) + fmt.Printf("Use tags: %s\n", strings.Join(features.TAGS, ", ")) return } From 8e959bd2455963dc84e97dcc51ac5ddca6d23854 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 3 Jun 2022 21:00:45 +0800 Subject: [PATCH 6/9] =?UTF-8?q?chore:=20=E5=BD=93=E6=97=A0tag=E6=97=B6?= =?UTF-8?q?=E4=B8=8D=E8=BE=93=E5=87=BA=E6=97=A0=E6=95=88=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 7b128e2d..e13b8dc8 100644 --- a/main.go +++ b/main.go @@ -54,7 +54,10 @@ func main() { if version { fmt.Printf("Clash Meta %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime) - fmt.Printf("Use tags: %s\n", strings.Join(features.TAGS, ", ")) + if len(features.TAGS) != 0 { + fmt.Printf("Use tags: %s\n", strings.Join(features.TAGS, ", ")) + } + return } From c52e689d0d8e056a56e81f96ba0422bcb3d9b28a Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 4 Jun 2022 19:12:50 +0800 Subject: [PATCH 7/9] =?UTF-8?q?fix:=20classical=20rule-set=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=9C=AA=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rule/provider/classical_strategy.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rule/provider/classical_strategy.go b/rule/provider/classical_strategy.go index 4ce69389..297ad32f 100644 --- a/rule/provider/classical_strategy.go +++ b/rule/provider/classical_strategy.go @@ -30,20 +30,24 @@ func (c *classicalStrategy) ShouldResolveIP() bool { } func (c *classicalStrategy) OnUpdate(rules []string) { + var classicalRules []C.Rule + shouldResolveIP := false for _, rawRule := range rules { ruleType, rule, params := ruleParse(rawRule) r, err := parseRule(ruleType, rule, "", params) if err != nil { log.Warnln("parse rule error:[%s]", err.Error()) } else { - if !c.shouldResolveIP { - c.shouldResolveIP = r.ShouldResolveIP() + if !shouldResolveIP { + shouldResolveIP = r.ShouldResolveIP() } - c.rules = append(c.rules, r) - c.count++ + classicalRules = append(classicalRules, r) } } + + c.rules = classicalRules + c.count = len(classicalRules) } func NewClassicalStrategy() *classicalStrategy { From 3827e00b548575544af541e572cc56ea3a27ca20 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 4 Jun 2022 19:14:39 +0800 Subject: [PATCH 8/9] =?UTF-8?q?refactor:=20=E6=8A=BD=E7=A6=BBhttp=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adapter/provider/vehicle.go | 46 ++------------------------ common/net/http.go | 5 --- component/http/http.go | 64 +++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 48 deletions(-) delete mode 100644 common/net/http.go create mode 100644 component/http/http.go diff --git a/adapter/provider/vehicle.go b/adapter/provider/vehicle.go index 289ab3a0..1eb5df83 100644 --- a/adapter/provider/vehicle.go +++ b/adapter/provider/vehicle.go @@ -2,16 +2,12 @@ package provider import ( "context" - "github.com/Dreamacro/clash/listener/inner" + netHttp "github.com/Dreamacro/clash/component/http" + types "github.com/Dreamacro/clash/constant/provider" "io" - "net" "net/http" - "net/url" "os" "time" - - netHttp "github.com/Dreamacro/clash/common/net" - types "github.com/Dreamacro/clash/constant/provider" ) type FileVehicle struct { @@ -50,52 +46,16 @@ func (h *HTTPVehicle) Path() string { func (h *HTTPVehicle) Read() ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) defer cancel() - - uri, err := url.Parse(h.url) + resp, err := netHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil) if err != nil { return nil, err } - req, err := http.NewRequest(http.MethodGet, uri.String(), nil) - req.Header.Set("User-Agent", netHttp.UA) - - if err != nil { - return nil, err - } - - if user := uri.User; user != nil { - password, _ := user.Password() - req.SetBasicAuth(user.Username(), password) - } - - req = req.WithContext(ctx) - - transport := &http.Transport{ - // from http.DefaultTransport - MaxIdleConns: 100, - IdleConnTimeout: 30 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - conn := inner.HandleTcp(address, uri.Hostname()) - return conn, nil - }, - } - - client := http.Client{Transport: transport} - resp, err := client.Do(req) - if err != nil { - if err != nil { - return nil, err - } - } defer resp.Body.Close() - buf, err := io.ReadAll(resp.Body) if err != nil { return nil, err } - return buf, nil } diff --git a/common/net/http.go b/common/net/http.go deleted file mode 100644 index ae10f7fc..00000000 --- a/common/net/http.go +++ /dev/null @@ -1,5 +0,0 @@ -package net - -const ( - UA = "Clash" -) diff --git a/component/http/http.go b/component/http/http.go new file mode 100644 index 00000000..c534b2ee --- /dev/null +++ b/component/http/http.go @@ -0,0 +1,64 @@ +package http + +import ( + "context" + "github.com/Dreamacro/clash/listener/inner" + "github.com/Dreamacro/clash/log" + "io" + "net" + "net/http" + URL "net/url" + "strings" + "time" +) + +const ( + UA = "Clash" +) + +func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { + method = strings.ToUpper(method) + urlRes, err := URL.Parse(url) + if err != nil { + return nil, err + } + + req, err := http.NewRequest(method, urlRes.String(), body) + for k, v := range header { + for _, v := range v { + req.Header.Add(k, v) + } + } + + if _, ok := header["User-Agent"]; !ok { + req.Header.Set("User-Agent", UA) + } + + if err != nil { + return nil, err + } + + if user := urlRes.User; user != nil { + password, _ := user.Password() + req.SetBasicAuth(user.Username(), password) + } + + req = req.WithContext(ctx) + + transport := &http.Transport{ + // from http.DefaultTransport + MaxIdleConns: 100, + IdleConnTimeout: 30 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { + log.Infoln(urlRes.String()) + conn := inner.HandleTcp(address, urlRes.Hostname()) + return conn, nil + }, + } + + client := http.Client{Transport: transport} + return client.Do(req) + +} From 8ff7e180a490ec31b53293df27fa12622f31fa45 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 4 Jun 2022 19:15:30 +0800 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=E5=BD=93=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E6=97=B6=EF=BC=8C=E5=AE=9A=E6=97=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adapter/provider/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 1a3850a6..4fc30a64 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -75,7 +75,7 @@ func (pp *proxySetProvider) Initial() error { pp.onUpdate(elm) if pp.healthCheck.auto() { - go pp.healthCheck.process() + defer func() { go pp.healthCheck.process() }() } return nil