From ca43efdaaaf5aa6629232b778f8757e32d8eda68 Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Sat, 20 Nov 2021 23:38:49 +0800 Subject: [PATCH 1/5] Feature: add filter on proxy provider (#1511) --- adapter/provider/parser.go | 4 ++- adapter/provider/provider.go | 66 ++++++++++++++++++++---------------- constant/adapters.go | 1 - 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 8a173966..bd393569 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -24,6 +24,7 @@ type proxyProviderSchema struct { Path string `provider:"path"` URL string `provider:"url,omitempty"` Interval int `provider:"interval,omitempty"` + Filter string `provider:"filter,omitempty"` HealthCheck healthCheckSchema `provider:"health-check,omitempty"` } @@ -58,5 +59,6 @@ func ParseProxyProvider(name string, mapping map[string]interface{}) (types.Prox } interval := time.Duration(uint(schema.Interval)) * time.Second - return NewProxySetProvider(name, interval, vehicle, hc), nil + filter := schema.Filter + return NewProxySetProvider(name, interval, filter, vehicle, hc), nil } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 32baaedd..c042b2de 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "regexp" "runtime" "time" @@ -82,33 +83,6 @@ func (pp *proxySetProvider) ProxiesWithTouch() []C.Proxy { return pp.Proxies() } -func proxiesParse(buf []byte) (interface{}, error) { - schema := &ProxySchema{} - - if err := yaml.Unmarshal(buf, schema); err != nil { - return nil, err - } - - if schema.Proxies == nil { - return nil, errors.New("file must have a `proxies` field") - } - - proxies := []C.Proxy{} - for idx, mapping := range schema.Proxies { - proxy, err := adapter.ParseProxy(mapping) - if err != nil { - return nil, fmt.Errorf("proxy %d error: %w", idx, err) - } - proxies = append(proxies, proxy) - } - - if len(proxies) == 0 { - return nil, errors.New("file doesn't have any valid proxy") - } - - return proxies, nil -} - func (pp *proxySetProvider) setProxies(proxies []C.Proxy) { pp.proxies = proxies pp.healthCheck.setProxy(proxies) @@ -122,7 +96,7 @@ func stopProxyProvider(pd *ProxySetProvider) { pd.fetcher.Destroy() } -func NewProxySetProvider(name string, interval time.Duration, vehicle types.Vehicle, hc *HealthCheck) *ProxySetProvider { +func NewProxySetProvider(name string, interval time.Duration, filter string, vehicle types.Vehicle, hc *HealthCheck) *ProxySetProvider { if hc.auto() { go hc.process() } @@ -137,7 +111,41 @@ func NewProxySetProvider(name string, interval time.Duration, vehicle types.Vehi pd.setProxies(ret) } - fetcher := newFetcher(name, interval, vehicle, proxiesParse, onUpdate) + proxiesParseAndFilter := func(buf []byte) (interface{}, error) { + schema := &ProxySchema{} + + if err := yaml.Unmarshal(buf, schema); err != nil { + return nil, err + } + + if schema.Proxies == nil { + return nil, errors.New("file must have a `proxies` field") + } + + proxies := []C.Proxy{} + filterReg := regexp.MustCompile(filter) + for idx, mapping := range schema.Proxies { + if name, ok := mapping["name"]; ok && len(filter) > 0 && !filterReg.MatchString(name.(string)) { + continue + } + proxy, err := adapter.ParseProxy(mapping) + if err != nil { + return nil, fmt.Errorf("proxy %d error: %w", idx, err) + } + proxies = append(proxies, proxy) + } + + if len(proxies) == 0 { + if len(filter) > 0 { + return nil, errors.New("doesn't match any proxy, please check your filter") + } + return nil, errors.New("file doesn't have any proxy") + } + + return proxies, nil + } + + fetcher := newFetcher(name, interval, vehicle, proxiesParseAndFilter, onUpdate) pd.fetcher = fetcher wrapper := &ProxySetProvider{pd} diff --git a/constant/adapters.go b/constant/adapters.go index 59fde960..136e48eb 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -93,7 +93,6 @@ type ProxyAdapter interface { // DialContext return a C.Conn with protocol which // contains multiplexing-related reuse logic (if any) DialContext(ctx context.Context, metadata *Metadata, opts ...dialer.Option) (Conn, error) - ListenPacketContext(ctx context.Context, metadata *Metadata, opts ...dialer.Option) (PacketConn, error) // Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract. From 76fe2b0bb8f413bf19b92d00667b695ef412bb11 Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Sun, 21 Nov 2021 17:44:03 +0800 Subject: [PATCH 2/5] Fix: provider filter potential panic --- adapter/provider/parser.go | 2 +- adapter/provider/provider.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index bd393569..d91aa4a1 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -60,5 +60,5 @@ func ParseProxyProvider(name string, mapping map[string]interface{}) (types.Prox interval := time.Duration(uint(schema.Interval)) * time.Second filter := schema.Filter - return NewProxySetProvider(name, interval, filter, vehicle, hc), nil + return NewProxySetProvider(name, interval, filter, vehicle, hc) } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index c042b2de..6a5e3052 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -96,7 +96,11 @@ func stopProxyProvider(pd *ProxySetProvider) { pd.fetcher.Destroy() } -func NewProxySetProvider(name string, interval time.Duration, filter string, vehicle types.Vehicle, hc *HealthCheck) *ProxySetProvider { +func NewProxySetProvider(name string, interval time.Duration, filter string, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) { + if _, err := regexp.Compile(filter); err != nil { + return nil, fmt.Errorf("invalid filter regex: %w", err) + } + if hc.auto() { go hc.process() } @@ -150,7 +154,7 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, veh wrapper := &ProxySetProvider{pd} runtime.SetFinalizer(wrapper, stopProxyProvider) - return wrapper + return wrapper, nil } // for auto gc From d5558aad2cc1b33be4cd61e6e9ebcd4b31ae45e1 Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Tue, 23 Nov 2021 22:01:49 +0800 Subject: [PATCH 3/5] Fix: fakeip pool cycle used --- component/fakeip/cachefile.go | 6 ++++++ component/fakeip/memory.go | 9 +++++++++ component/fakeip/pool.go | 4 ++++ component/fakeip/pool_test.go | 15 +++++++++++---- component/profile/cachefile/cache.go | 25 +++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/component/fakeip/cachefile.go b/component/fakeip/cachefile.go index 7ee88981..04bdc65c 100644 --- a/component/fakeip/cachefile.go +++ b/component/fakeip/cachefile.go @@ -38,6 +38,12 @@ func (c *cachefileStore) PutByIP(ip net.IP, host string) { c.cache.PutFakeip(ip.To4(), []byte(host)) } +// DelByIP implements store.DelByIP +func (c *cachefileStore) DelByIP(ip net.IP) { + ip = ip.To4() + c.cache.DelFakeipPair(ip, c.cache.GetFakeip(ip.To4())) +} + // Exist implements store.Exist func (c *cachefileStore) Exist(ip net.IP) bool { _, exist := c.GetByIP(ip) diff --git a/component/fakeip/memory.go b/component/fakeip/memory.go index 75d4a3b2..c6c6873d 100644 --- a/component/fakeip/memory.go +++ b/component/fakeip/memory.go @@ -46,6 +46,15 @@ func (m *memoryStore) PutByIP(ip net.IP, host string) { m.cache.Set(ipToUint(ip.To4()), host) } +// DelByIP implements store.DelByIP +func (m *memoryStore) DelByIP(ip net.IP) { + ipNum := ipToUint(ip.To4()) + if elm, exist := m.cache.Get(ipNum); exist { + m.cache.Delete(elm.(string)) + } + m.cache.Delete(ipNum) +} + // Exist implements store.Exist func (m *memoryStore) Exist(ip net.IP) bool { return m.cache.Exist(ipToUint(ip.To4())) diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index 180d5eb1..925882bb 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -15,6 +15,7 @@ type store interface { PutByHost(host string, ip net.IP) GetByIP(ip net.IP) (string, bool) PutByIP(ip net.IP, host string) + DelByIP(ip net.IP) Exist(ip net.IP) bool CloneTo(store) } @@ -97,6 +98,9 @@ func (p *Pool) get(host string) net.IP { p.offset = (p.offset + 1) % (p.max - p.min) // Avoid infinite loops if p.offset == current { + p.offset = (p.offset + 1) % (p.max - p.min) + ip := uintToIP(p.min + p.offset - 1) + p.store.DelByIP(ip) break } diff --git a/component/fakeip/pool_test.go b/component/fakeip/pool_test.go index bd4af4c9..bd034636 100644 --- a/component/fakeip/pool_test.go +++ b/component/fakeip/pool_test.go @@ -1,6 +1,7 @@ package fakeip import ( + "fmt" "net" "os" "testing" @@ -75,7 +76,7 @@ func TestPool_Basic(t *testing.T) { } func TestPool_CycleUsed(t *testing.T) { - _, ipnet, _ := net.ParseCIDR("192.168.0.1/30") + _, ipnet, _ := net.ParseCIDR("192.168.0.1/29") pools, tempfile, err := createPools(Options{ IPNet: ipnet, Size: 10, @@ -84,9 +85,15 @@ func TestPool_CycleUsed(t *testing.T) { defer os.Remove(tempfile) for _, pool := range pools { - first := pool.Lookup("foo.com") - same := pool.Lookup("baz.com") - assert.True(t, first.Equal(same)) + foo := pool.Lookup("foo.com") + bar := pool.Lookup("bar.com") + for i := 0; i < 3; i++ { + pool.Lookup(fmt.Sprintf("%d.com", i)) + } + baz := pool.Lookup("baz.com") + next := pool.Lookup("foo.com") + assert.True(t, foo.Equal(baz)) + assert.True(t, next.Equal(bar)) } } diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go index 1ef47493..214e729b 100644 --- a/component/profile/cachefile/cache.go +++ b/component/profile/cachefile/cache.go @@ -90,6 +90,31 @@ func (c *CacheFile) PutFakeip(key, value []byte) error { return err } +func (c *CacheFile) DelFakeipPair(ip, host []byte) error { + if c.DB == nil { + return nil + } + + err := c.DB.Batch(func(t *bbolt.Tx) error { + bucket, err := t.CreateBucketIfNotExists(bucketFakeip) + if err != nil { + return err + } + err = bucket.Delete(ip) + if len(host) > 0 { + if err := bucket.Delete(host); err != nil { + return err + } + } + return err + }) + if err != nil { + log.Warnln("[CacheFile] write cache to %s failed: %s", c.DB.Path(), err.Error()) + } + + return err +} + func (c *CacheFile) GetFakeip(key []byte) []byte { if c.DB == nil { return nil From 4fbb6d6fca14c819dab73e405a2621b18fd16426 Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Thu, 2 Dec 2021 21:12:45 +0800 Subject: [PATCH 4/5] Feature: add linux/arm/v6 for the container image (#1771) --- .github/workflows/docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 35083e51..f0ad1ea8 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -46,7 +46,7 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64,linux/arm/v7,linux/arm64 + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64 push: true tags: 'dreamacro/clash:dev,ghcr.io/dreamacro/clash:dev' @@ -71,6 +71,6 @@ jobs: uses: docker/build-push-action@v2 with: context: . - platforms: linux/amd64,linux/arm/v7,linux/arm64 + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64 push: true tags: ${{steps.tags.outputs.result}} From 4d8017574c492914e9d440e0a3c4e169a01fe15f Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Wed, 8 Dec 2021 13:38:25 +0800 Subject: [PATCH 5/5] Chore: builtin right mime of .js (#1808) --- constant/mime/mime.go | 16 ++++++++++++++++ hub/route/server.go | 1 + 2 files changed, 17 insertions(+) create mode 100644 constant/mime/mime.go diff --git a/constant/mime/mime.go b/constant/mime/mime.go new file mode 100644 index 00000000..431457be --- /dev/null +++ b/constant/mime/mime.go @@ -0,0 +1,16 @@ +package mime + +import ( + "mime" +) + +var consensusMimes = map[string]string{ + // rfc4329: text/javascript is obsolete, so we need to overwrite mime's builtin + ".js": "application/javascript; charset=utf-8", +} + +func init() { + for ext, typ := range consensusMimes { + mime.AddExtensionType(ext, typ) + } +} diff --git a/hub/route/server.go b/hub/route/server.go index e01696be..c38ca7e1 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -9,6 +9,7 @@ import ( "time" C "github.com/Dreamacro/clash/constant" + _ "github.com/Dreamacro/clash/constant/mime" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/tunnel/statistic"