Merge branch 'dev' into release

This commit is contained in:
Skyxim 2022-06-04 19:28:32 +08:00
commit f03f33840e
40 changed files with 420 additions and 189 deletions

View File

@ -8,11 +8,13 @@ import (
"github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/constant/provider"
"time"
) )
type Fallback struct { type Fallback struct {
*GroupBase *GroupBase
disableUDP bool disableUDP bool
testUrl string
selected string selected string
} }
@ -91,14 +93,26 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy {
} }
func (f *Fallback) Set(name string) error { func (f *Fallback) Set(name string) error {
var p C.Proxy
for _, proxy := range f.GetProxies(false) { for _, proxy := range f.GetProxies(false) {
if proxy.Name() == name { if proxy.Name() == name {
f.selected = name p = proxy
return nil 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 { func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
@ -114,5 +128,6 @@ func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider)
providers, providers,
}), }),
disableUDP: option.DisableUDP, disableUDP: option.DisableUDP,
testUrl: option.URL,
} }
} }

View File

@ -146,14 +146,14 @@ func (gb *GroupBase) onDialFailed() {
gb.failedTimes++ gb.failedTimes++
if gb.failedTimes == 1 { if gb.failedTimes == 1 {
log.Warnln("ProxyGroup: %s first failed", gb.Name()) log.Debugln("ProxyGroup: %s first failed", gb.Name())
gb.failedTime = time.Now() gb.failedTime = time.Now()
} else { } else {
if time.Since(gb.failedTime) > gb.failedTimeoutInterval() { if time.Since(gb.failedTime) > gb.failedTimeoutInterval() {
return 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() { if gb.failedTimes >= gb.maxFailedTimes() {
gb.failedTesting.Store(true) gb.failedTesting.Store(true)
log.Warnln("because %s failed multiple times, active health check", gb.Name()) log.Warnln("because %s failed multiple times, active health check", gb.Name())

View File

@ -75,7 +75,7 @@ func (pp *proxySetProvider) Initial() error {
pp.onUpdate(elm) pp.onUpdate(elm)
if pp.healthCheck.auto() { if pp.healthCheck.auto() {
go pp.healthCheck.process() defer func() { go pp.healthCheck.process() }()
} }
return nil return nil

View File

@ -2,16 +2,12 @@ package provider
import ( import (
"context" "context"
"github.com/Dreamacro/clash/listener/inner" netHttp "github.com/Dreamacro/clash/component/http"
types "github.com/Dreamacro/clash/constant/provider"
"io" "io"
"net"
"net/http" "net/http"
"net/url"
"os" "os"
"time" "time"
netHttp "github.com/Dreamacro/clash/common/net"
types "github.com/Dreamacro/clash/constant/provider"
) )
type FileVehicle struct { type FileVehicle struct {
@ -50,52 +46,16 @@ func (h *HTTPVehicle) Path() string {
func (h *HTTPVehicle) Read() ([]byte, error) { func (h *HTTPVehicle) Read() ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel() defer cancel()
resp, err := netHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil)
uri, err := url.Parse(h.url)
if err != nil { if err != nil {
return nil, err 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() defer resp.Body.Close()
buf, err := io.ReadAll(resp.Body) buf, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return buf, nil return buf, nil
} }

View File

@ -1,5 +0,0 @@
package net
const (
UA = "Clash"
)

View File

@ -30,7 +30,7 @@ func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*route
return nil, fmt.Errorf("empty listname in rule: %s", siteWithAttr) 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 { if err != nil {
return nil, err 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) { 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 var loaders map[string]func() LoaderImplementation

View File

@ -5,8 +5,10 @@ import (
) )
type LoaderImplementation interface { type LoaderImplementation interface {
LoadSite(filename, list string) ([]*router.Domain, error) LoadSiteByPath(filename, list string) ([]*router.Domain, error)
LoadIP(filename, country string) ([]*router.CIDR, 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 { type Loader interface {

View File

@ -1,6 +1,7 @@
package memconservative package memconservative
import ( import (
"errors"
"fmt" "fmt"
"runtime" "runtime"
@ -13,7 +14,7 @@ type memConservativeLoader struct {
geositecache GeoSiteCache 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() defer runtime.GC()
geoip, err := m.geoipcache.Unmarshal(filename, country) geoip, err := m.geoipcache.Unmarshal(filename, country)
if err != nil { if err != nil {
@ -22,7 +23,11 @@ func (m *memConservativeLoader) LoadIP(filename, country string) ([]*router.CIDR
return geoip.Cidr, nil 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() defer runtime.GC()
geosite, err := m.geositecache.Unmarshal(filename, list) geosite, err := m.geositecache.Unmarshal(filename, list)
if err != nil { if err != nil {
@ -31,6 +36,10 @@ func (m *memConservativeLoader) LoadSite(filename, list string) ([]*router.Domai
return geosite.Domain, nil 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 { func newMemConservativeLoader() geodata.LoaderImplementation {
return &memConservativeLoader{make(map[string]*router.GeoIP), make(map[string]*router.GeoSite)} return &memConservativeLoader{make(map[string]*router.GeoIP), make(map[string]*router.GeoSite)}
} }

View File

@ -29,11 +29,7 @@ func ReadAsset(file string) ([]byte, error) {
return ReadFile(C.Path.GetAssetLocation(file)) return ReadFile(C.Path.GetAssetLocation(file))
} }
func loadIP(filename, country string) ([]*router.CIDR, error) { func loadIP(geoipBytes []byte, 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())
}
var geoipList router.GeoIPList var geoipList router.GeoIPList
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil { if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
return nil, err 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) { func loadSite(geositeBytes []byte, 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())
}
var geositeList router.GeoSiteList var geositeList router.GeoSiteList
if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil { if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
return nil, err 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{} type standardLoader struct{}
func (d standardLoader) LoadSite(filename, list string) ([]*router.Domain, error) { func (d standardLoader) LoadSiteByPath(filename, list string) ([]*router.Domain, error) {
return loadSite(filename, list) 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) { func (d standardLoader) LoadSiteByBytes(geositeBytes []byte, list string) ([]*router.Domain, error) {
return loadIP(filename, country) 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() { func init() {

64
component/http/http.go Normal file
View File

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

View File

@ -6,77 +6,75 @@ import (
_ "github.com/Dreamacro/clash/component/geodata/standard" _ "github.com/Dreamacro/clash/component/geodata/standard"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/oschwald/geoip2-golang" "github.com/oschwald/geoip2-golang"
"os" "io/ioutil"
"net/http"
"runtime" "runtime"
) )
func UpdateGeoDatabases() error { func UpdateGeoDatabases() error {
var ( defer runtime.GC()
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 {
geoLoader, err := geodata.GetGeoDataLoader("standard") geoLoader, err := geodata.GetGeoDataLoader("standard")
if err != nil { if err != nil {
return err 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)
} }

View File

@ -0,0 +1,7 @@
//go:build no_doq
package features
func init() {
TAGS = append(TAGS, "no_doq")
}

View File

@ -0,0 +1,7 @@
//go:build no_gvisor
package features
func init() {
TAGS = append(TAGS, "no_gvisor")
}

View File

@ -0,0 +1,3 @@
package features
var TAGS = make([]string, 0, 0)

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package device package device
import ( import (

View File

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

View File

@ -4,24 +4,13 @@ package fdbased
import ( import (
"fmt" "fmt"
"os"
"strconv" "strconv"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"golang.org/x/sys/unix" "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) { func Open(name string, mtu uint32) (device.Device, error) {
fd, err := strconv.Atoi(name) fd, err := strconv.Atoi(name)
if err != nil { if err != nil {

View File

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

View File

@ -0,0 +1,14 @@
//go:build no_gvisor
package fdbased
import (
"os"
)
type FD struct {
fd int
mtu uint32
file *os.File
}

View File

@ -7,7 +7,6 @@ import (
"os" "os"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"github.com/Dreamacro/clash/listener/tun/device/iobased"
) )
func open(fd int, mtu uint32) (device.Device, error) { 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 { func (f *FD) useEndpoint() error {
ep, err := iobased.New(os.NewFile(uintptr(f.fd), f.Name()), f.mtu, 0) return newEp(f)
if err != nil {
return fmt.Errorf("create endpoint: %w", err)
}
f.LinkEndpoint = ep
return nil
} }
func (f *FD) useIOBased() error { func (f *FD) useIOBased() error {

View File

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

View File

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

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
// Package iobased provides the implementation of io.ReadWriter // Package iobased provides the implementation of io.ReadWriter
// based data-link layer endpoints. // based data-link layer endpoints.
package iobased package iobased

View File

@ -0,0 +1 @@
package iobased

View File

@ -8,22 +8,10 @@ import (
"runtime" "runtime"
"github.com/Dreamacro/clash/listener/tun/device" "github.com/Dreamacro/clash/listener/tun/device"
"github.com/Dreamacro/clash/listener/tun/device/iobased"
"golang.zx2c4.com/wireguard/tun" "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) { func Open(name string, mtu uint32) (_ device.Device, err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -91,11 +79,7 @@ func (t *TUN) Write(packet []byte) (int, error) {
} }
func (t *TUN) Close() error { func (t *TUN) Close() error {
defer func(ep *iobased.Endpoint) { defer closeIO(t)
if ep != nil {
ep.Close()
}
}(t.Endpoint)
return t.nt.Close() return t.nt.Close()
} }
@ -105,12 +89,7 @@ func (t *TUN) Name() string {
} }
func (t *TUN) UseEndpoint() error { func (t *TUN) UseEndpoint() error {
ep, err := iobased.New(t, t.mtu, t.offset) return newEq(t)
if err != nil {
return fmt.Errorf("create endpoint: %w", err)
}
t.Endpoint = ep
return nil
} }
func (t *TUN) UseIOBased() error { func (t *TUN) UseIOBased() error {

View File

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

View File

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

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package adapter package adapter
import ( import (

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package adapter package adapter
// Handler is a TCP/UDP connection handler that implements // Handler is a TCP/UDP connection handler that implements

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package gvisor package gvisor
import ( import (

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package gvisor package gvisor
import ( import (

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package option package option
import ( import (

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package gvisor package gvisor
import ( import (

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
// Package gvisor provides a thin wrapper around a gVisor's stack. // Package gvisor provides a thin wrapper around a gVisor's stack.
package gvisor package gvisor
@ -64,8 +66,9 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
// Generate unique NIC id. // Generate unique NIC id.
nicID := tcpip.NICID(s.Stack.UniqueID()) nicID := tcpip.NICID(s.Stack.UniqueID())
defaultOpts := []option.Option{option.WithDefault()}
opts = append(opts, defaultOpts = append(defaultOpts, opts...)
opts = append(defaultOpts,
// Create stack NIC and then bind link endpoint to it. // Create stack NIC and then bind link endpoint to it.
withCreatingNIC(nicID, device), withCreatingNIC(nicID, device),

View File

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

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package gvisor package gvisor
import ( import (

View File

@ -1,3 +1,5 @@
//go:build !no_gvisor
package gvisor package gvisor
import ( import (

View File

@ -13,7 +13,6 @@ import (
"github.com/Dreamacro/clash/listener/tun/ipstack" "github.com/Dreamacro/clash/listener/tun/ipstack"
"github.com/Dreamacro/clash/listener/tun/ipstack/commons" "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor" "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/listener/tun/ipstack/system"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"net/netip" "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) 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 { if err != nil {
_ = tunDevice.Close() _ = tunDevice.Close()

View File

@ -3,10 +3,12 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"github.com/Dreamacro/clash/constant/features"
"os" "os"
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings"
"syscall" "syscall"
"github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/config"
@ -50,7 +52,12 @@ func init() {
func main() { func main() {
_, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {})) _, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {}))
if version { 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)
if len(features.TAGS) != 0 {
fmt.Printf("Use tags: %s\n", strings.Join(features.TAGS, ", "))
}
return return
} }

View File

@ -30,20 +30,24 @@ func (c *classicalStrategy) ShouldResolveIP() bool {
} }
func (c *classicalStrategy) OnUpdate(rules []string) { func (c *classicalStrategy) OnUpdate(rules []string) {
var classicalRules []C.Rule
shouldResolveIP := false
for _, rawRule := range rules { for _, rawRule := range rules {
ruleType, rule, params := ruleParse(rawRule) ruleType, rule, params := ruleParse(rawRule)
r, err := parseRule(ruleType, rule, "", params) r, err := parseRule(ruleType, rule, "", params)
if err != nil { if err != nil {
log.Warnln("parse rule error:[%s]", err.Error()) log.Warnln("parse rule error:[%s]", err.Error())
} else { } else {
if !c.shouldResolveIP { if !shouldResolveIP {
c.shouldResolveIP = r.ShouldResolveIP() shouldResolveIP = r.ShouldResolveIP()
} }
c.rules = append(c.rules, r) classicalRules = append(classicalRules, r)
c.count++
} }
} }
c.rules = classicalRules
c.count = len(classicalRules)
} }
func NewClassicalStrategy() *classicalStrategy { func NewClassicalStrategy() *classicalStrategy {