[SKIP CI]

Merge remote-tracking branch 'Pro-Plus/with-tun' into Alpha

# Conflicts:
#	README.md
#	hub/route/server.go
This commit is contained in:
MetaCubeX 2022-03-23 13:20:15 +08:00
commit 7a54d616c4
13 changed files with 142 additions and 8 deletions

View file

@ -144,7 +144,7 @@ all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST)
releases: $(gz_releases) $(zip_releases) releases: $(gz_releases) $(zip_releases)
vet: vet:
go vet ./... go test ./...
lint: lint:
golangci-lint run ./... golangci-lint run ./...

View file

@ -216,6 +216,15 @@ func (c *LruCache) deleteElement(le *list.Element) {
} }
} }
func (c *LruCache) Clear() error {
c.mu.Lock()
c.cache = make(map[any]*list.Element)
c.mu.Unlock()
return nil
}
type entry struct { type entry struct {
key any key any
value any value any

View file

@ -53,3 +53,8 @@ func (c *cachefileStore) Exist(ip net.IP) bool {
// CloneTo implements store.CloneTo // CloneTo implements store.CloneTo
// already persistence // already persistence
func (c *cachefileStore) CloneTo(store store) {} func (c *cachefileStore) CloneTo(store store) {}
// FlushFakeIP implements store.FlushFakeIP
func (c *cachefileStore) FlushFakeIP() error {
return c.cache.FlushFakeIP()
}

View file

@ -67,3 +67,8 @@ func (m *memoryStore) CloneTo(store store) {
m.cache.CloneTo(ms.cache) m.cache.CloneTo(ms.cache)
} }
} }
// FlushFakeIP implements store.FlushFakeIP
func (m *memoryStore) FlushFakeIP() error {
return m.cache.Clear()
}

View file

@ -18,6 +18,7 @@ type store interface {
DelByIP(ip net.IP) DelByIP(ip net.IP)
Exist(ip net.IP) bool Exist(ip net.IP) bool
CloneTo(store) CloneTo(store)
FlushFakeIP() error
} }
// Pool is a implementation about fake ip generator without storage // Pool is a implementation about fake ip generator without storage
@ -120,6 +121,10 @@ func (p *Pool) get(host string) net.IP {
return ip return ip
} }
func (p *Pool) FlushFakeIP() error {
return p.store.FlushFakeIP()
}
func ipToUint(ip net.IP) uint32 { func ipToUint(ip net.IP) uint32 {
v := uint32(ip[0]) << 24 v := uint32(ip[0]) << 24
v += uint32(ip[1]) << 16 v += uint32(ip[1]) << 16

View file

@ -193,3 +193,59 @@ func TestPool_Error(t *testing.T) {
assert.Error(t, err) assert.Error(t, err)
} }
func TestPool_FlushFileCache(t *testing.T) {
_, ipnet, _ := net.ParseCIDR("192.168.0.1/28")
pools, tempfile, err := createPools(Options{
IPNet: ipnet,
Size: 10,
})
assert.Nil(t, err)
defer os.Remove(tempfile)
for _, pool := range pools {
foo := pool.Lookup("foo.com")
bar := pool.Lookup("baz.com")
bax := pool.Lookup("baz.com")
fox := pool.Lookup("foo.com")
err = pool.FlushFakeIP()
assert.Nil(t, err)
baz := pool.Lookup("foo.com")
next := pool.Lookup("baz.com")
nero := pool.Lookup("foo.com")
assert.Equal(t, foo, fox)
assert.NotEqual(t, foo, baz)
assert.Equal(t, bar, bax)
assert.NotEqual(t, bar, next)
assert.Equal(t, baz, nero)
}
}
func TestPool_FlushMemoryCache(t *testing.T) {
_, ipnet, _ := net.ParseCIDR("192.168.0.1/28")
pool, _ := New(Options{
IPNet: ipnet,
Size: 10,
})
foo := pool.Lookup("foo.com")
bar := pool.Lookup("baz.com")
bax := pool.Lookup("baz.com")
fox := pool.Lookup("foo.com")
err := pool.FlushFakeIP()
assert.Nil(t, err)
baz := pool.Lookup("foo.com")
next := pool.Lookup("baz.com")
nero := pool.Lookup("foo.com")
assert.Equal(t, foo, fox)
assert.NotEqual(t, foo, baz)
assert.Equal(t, bar, bax)
assert.NotEqual(t, bar, next)
assert.Equal(t, baz, nero)
}

View file

@ -132,6 +132,17 @@ func (c *CacheFile) GetFakeip(key []byte) []byte {
return bucket.Get(key) return bucket.Get(key)
} }
func (c *CacheFile) FlushFakeIP() error {
err := c.DB.Batch(func(t *bbolt.Tx) error {
bucket := t.Bucket(bucketFakeip)
if bucket == nil {
return nil
}
return t.DeleteBucket(bucketFakeip)
})
return err
}
func (c *CacheFile) Close() error { func (c *CacheFile) Close() error {
return c.DB.Close() return c.DB.Close()
} }

View file

@ -13,6 +13,7 @@ type Enhancer interface {
IsFakeBroadcastIP(net.IP) bool IsFakeBroadcastIP(net.IP) bool
IsExistFakeIP(net.IP) bool IsExistFakeIP(net.IP) bool
FindHostByIP(net.IP) (string, bool) FindHostByIP(net.IP) (string, bool)
FlushFakeIP() error
} }
func FakeIPEnabled() bool { func FakeIPEnabled() bool {
@ -62,3 +63,10 @@ func FindHostByIP(ip net.IP) (string, bool) {
return "", false return "", false
} }
func FlushFakeIP() error {
if mapper := DefaultHostMapper; mapper != nil {
return mapper.FlushFakeIP()
}
return nil
}

View file

@ -84,6 +84,13 @@ func (h *ResolverEnhancer) PatchFrom(o *ResolverEnhancer) {
} }
} }
func (h *ResolverEnhancer) FlushFakeIP() error {
if h.fakePool != nil {
return h.fakePool.FlushFakeIP()
}
return nil
}
func NewEnhancer(cfg Config) *ResolverEnhancer { func NewEnhancer(cfg Config) *ResolverEnhancer {
var fakePool *fakeip.Pool var fakePool *fakeip.Pool
var mapping *cache.LruCache var mapping *cache.LruCache

26
hub/route/cache.go Normal file
View file

@ -0,0 +1,26 @@
package route
import (
"net/http"
"github.com/Dreamacro/clash/component/resolver"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
)
func cacheRouter() http.Handler {
r := chi.NewRouter()
r.Post("/fakeip/flush", flushFakeIPPool)
return r
}
func flushFakeIPPool(w http.ResponseWriter, r *http.Request) {
err := resolver.FlushFakeIP()
if err != nil {
render.Status(r, http.StatusBadRequest)
render.JSON(w, r, newError(err.Error()))
return
}
render.NoContent(w, r)
}

View file

@ -73,6 +73,7 @@ func Start(addr string, secret string) {
r.Mount("/providers/proxies", proxyProviderRouter()) r.Mount("/providers/proxies", proxyProviderRouter())
r.Mount("/providers/rules", ruleProviderRouter()) r.Mount("/providers/rules", ruleProviderRouter())
r.Mount("/script", scriptRouter()) r.Mount("/script", scriptRouter())
r.Mount("/cache", cacheRouter())
}) })
if uiPath != "" { if uiPath != "" {
@ -132,7 +133,7 @@ func authentication(next http.Handler) http.Handler {
} }
func hello(w http.ResponseWriter, r *http.Request) { func hello(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, render.M{"hello": "clash"}) render.JSON(w, r, render.M{"hello": "clash.meta"})
} }
func traffic(w http.ResponseWriter, r *http.Request) { func traffic(w http.ResponseWriter, r *http.Request) {

View file

@ -3,9 +3,10 @@
package tun package tun
import ( import (
"errors"
"fmt" "fmt"
"os"
"runtime" "runtime"
"strings"
"github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
@ -53,9 +54,7 @@ func Open(name string, mtu uint32) (_ device.Device, err error) {
nt, err := tun.CreateTUN(t.name, forcedMTU) // forcedMTU do not work on wintun, need to be setting by other way nt, err := tun.CreateTUN(t.name, forcedMTU) // forcedMTU do not work on wintun, need to be setting by other way
// retry if abnormal exit on Windows at last time // retry if abnormal exit on Windows at last time
if err != nil && runtime.GOOS == "windows" && if err != nil && runtime.GOOS == "windows" && errors.Is(err, os.ErrExist) {
strings.HasSuffix(err.Error(), "file already exists.") {
nt, err = tun.CreateTUN(t.name, forcedMTU) nt, err = tun.CreateTUN(t.name, forcedMTU)
} }
@ -80,7 +79,9 @@ func (t *TUN) Read(packet []byte) (int, error) {
} }
buff := pool.Get(t.offset + cap(packet)) buff := pool.Get(t.offset + cap(packet))
defer pool.Put(buff) defer func() {
_ = pool.Put(buff)
}()
n, err := t.nt.Read(buff, t.offset) n, err := t.nt.Read(buff, t.offset)
if err != nil { if err != nil {

View file

@ -107,7 +107,7 @@ func main() {
} }
sigCh := make(chan os.Signal, 1) sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh <-sigCh
// cleanup // cleanup