Merge remote-tracking branch 'clash/dev' into Meta

# Conflicts:
#	.github/workflows/docker.yml
#	dns/server.go
#	go.mod
#	go.sum
#	hub/executor/executor.go
#	test/go.mod
#	test/go.sum
This commit is contained in:
Maze.tsz
2022-01-04 17:31:07 +08:00
24 changed files with 421 additions and 390 deletions

View File

@ -58,11 +58,11 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des
return nil
}
local := int64(0)
local := uint64(0)
if dialer.LocalAddr != nil {
_, port, err := net.SplitHostPort(dialer.LocalAddr.String())
if err == nil {
local, _ = strconv.ParseInt(port, 10, 16)
local, _ = strconv.ParseUint(port, 10, 16)
}
}
@ -82,7 +82,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add
port = "0"
}
local, _ := strconv.ParseInt(port, 10, 16)
local, _ := strconv.ParseUint(port, 10, 16)
addr, err := lookupLocalAddr(ifaceName, network, nil, int(local))
if err != nil {

View File

@ -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)

View File

@ -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()))

View File

@ -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
}

View File

@ -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))
}
}

View File

@ -1,8 +1,6 @@
package cachefile
import (
"bytes"
"encoding/gob"
"os"
"sync"
"time"
@ -90,6 +88,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
@ -113,69 +136,30 @@ func (c *CacheFile) Close() error {
return c.DB.Close()
}
// TODO: remove migrateCache until 2022
func migrateCache() {
defer func() {
options := bbolt.Options{Timeout: time.Second}
db, err := bbolt.Open(C.Path.Cache(), fileMode, &options)
switch err {
case bbolt.ErrInvalid, bbolt.ErrChecksum, bbolt.ErrVersionMismatch:
if err = os.Remove(C.Path.Cache()); err != nil {
log.Warnln("[CacheFile] remove invalid cache file error: %s", err.Error())
break
}
log.Infoln("[CacheFile] remove invalid cache file and create new one")
db, err = bbolt.Open(C.Path.Cache(), fileMode, &options)
func initCache() {
options := bbolt.Options{Timeout: time.Second}
db, err := bbolt.Open(C.Path.Cache(), fileMode, &options)
switch err {
case bbolt.ErrInvalid, bbolt.ErrChecksum, bbolt.ErrVersionMismatch:
if err = os.Remove(C.Path.Cache()); err != nil {
log.Warnln("[CacheFile] remove invalid cache file error: %s", err.Error())
break
}
if err != nil {
log.Warnln("[CacheFile] can't open cache file: %s", err.Error())
}
defaultCache = &CacheFile{
DB: db,
}
}()
buf, err := os.ReadFile(C.Path.OldCache())
log.Infoln("[CacheFile] remove invalid cache file and create new one")
db, err = bbolt.Open(C.Path.Cache(), fileMode, &options)
}
if err != nil {
return
log.Warnln("[CacheFile] can't open cache file: %s", err.Error())
}
defer os.Remove(C.Path.OldCache())
// read old cache file
type cache struct {
Selected map[string]string
defaultCache = &CacheFile{
DB: db,
}
model := &cache{
Selected: map[string]string{},
}
bufReader := bytes.NewBuffer(buf)
gob.NewDecoder(bufReader).Decode(model)
// write to new cache file
db, err := bbolt.Open(C.Path.Cache(), fileMode, nil)
if err != nil {
return
}
defer db.Close()
db.Batch(func(t *bbolt.Tx) error {
bucket, err := t.CreateBucketIfNotExists(bucketSelected)
if err != nil {
return err
}
for group, selected := range model.Selected {
if err := bucket.Put([]byte(group), []byte(selected)); err != nil {
return err
}
}
return nil
})
}
// Cache return singleton of CacheFile
func Cache() *CacheFile {
initOnce.Do(migrateCache)
initOnce.Do(initCache)
return defaultCache
}