Chore: cleanup code
This commit is contained in:
parent
e1fe8ce3b2
commit
ae6cc1d67d
@ -30,10 +30,8 @@ type LoadBalance struct {
|
|||||||
var errStrategy = errors.New("unsupported strategy")
|
var errStrategy = errors.New("unsupported strategy")
|
||||||
|
|
||||||
func parseStrategy(config map[string]any) string {
|
func parseStrategy(config map[string]any) string {
|
||||||
if elm, ok := config["strategy"]; ok {
|
if strategy, ok := config["strategy"].(string); ok {
|
||||||
if strategy, ok := elm.(string); ok {
|
return strategy
|
||||||
return strategy
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return "consistent-hashing"
|
return "consistent-hashing"
|
||||||
}
|
}
|
||||||
|
@ -125,10 +125,8 @@ func parseURLTestOption(config map[string]any) []urlTestOption {
|
|||||||
opts := []urlTestOption{}
|
opts := []urlTestOption{}
|
||||||
|
|
||||||
// tolerance
|
// tolerance
|
||||||
if elm, ok := config["tolerance"]; ok {
|
if tolerance, ok := config["tolerance"].(int); ok {
|
||||||
if tolerance, ok := elm.(int); ok {
|
opts = append(opts, urlTestWithTolerance(uint16(tolerance)))
|
||||||
opts = append(opts, urlTestWithTolerance(uint16(tolerance)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return opts
|
return opts
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
func ParseProxy(mapping map[string]any, forceCertVerify bool) (C.Proxy, error) {
|
func ParseProxy(mapping map[string]any, forceCertVerify bool) (C.Proxy, error) {
|
||||||
decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true})
|
decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true})
|
||||||
proxyType, existType := mapping["type"]
|
proxyType, existType := mapping["type"].(string)
|
||||||
if !existType {
|
if !existType {
|
||||||
return nil, fmt.Errorf("missing type")
|
return nil, fmt.Errorf("missing type")
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ func ParseProxy(mapping map[string]any, forceCertVerify bool) (C.Proxy, error) {
|
|||||||
proxy C.ProxyAdapter
|
proxy C.ProxyAdapter
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
switch proxyType.(string) {
|
switch proxyType {
|
||||||
case "ss":
|
case "ss":
|
||||||
ssOption := &outbound.ShadowSocksOption{}
|
ssOption := &outbound.ShadowSocksOption{}
|
||||||
err = decoder.Decode(mapping, ssOption)
|
err = decoder.Decode(mapping, ssOption)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
types "github.com/Dreamacro/clash/constant/provider"
|
types "github.com/Dreamacro/clash/constant/provider"
|
||||||
@ -14,6 +15,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
fileMode os.FileMode = 0o666
|
fileMode os.FileMode = 0o666
|
||||||
dirMode os.FileMode = 0o755
|
dirMode os.FileMode = 0o755
|
||||||
|
|
||||||
|
commentRegx = regexp.MustCompile(`(.*#.*\n)`)
|
||||||
)
|
)
|
||||||
|
|
||||||
type parser[V any] func([]byte) (V, error)
|
type parser[V any] func([]byte) (V, error)
|
||||||
@ -168,6 +171,18 @@ func safeWrite(path string, buf []byte) error {
|
|||||||
return os.WriteFile(path, buf, fileMode)
|
return os.WriteFile(path, buf, fileMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeComment(buf []byte) []byte {
|
||||||
|
arr := commentRegx.FindAllSubmatch(buf, -1)
|
||||||
|
for _, subs := range arr {
|
||||||
|
sub := subs[0]
|
||||||
|
if !bytes.HasPrefix(bytes.TrimLeft(sub, " "), []byte("#")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
buf = bytes.Replace(buf, sub, []byte(""), 1)
|
||||||
|
}
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
func newFetcher[V any](name string, interval time.Duration, vehicle types.Vehicle, parser parser[V], onUpdate func(V)) *fetcher[V] {
|
func newFetcher[V any](name string, interval time.Duration, vehicle types.Vehicle, parser parser[V], onUpdate func(V)) *fetcher[V] {
|
||||||
var ticker *time.Ticker
|
var ticker *time.Ticker
|
||||||
if interval != 0 {
|
if interval != 0 {
|
||||||
|
@ -321,12 +321,13 @@ func proxiesParseAndFilter(filter string, filterReg *regexp.Regexp, forceCertVer
|
|||||||
|
|
||||||
proxies := []C.Proxy{}
|
proxies := []C.Proxy{}
|
||||||
for idx, mapping := range schema.Proxies {
|
for idx, mapping := range schema.Proxies {
|
||||||
if name, ok := mapping["name"]; ok && len(filter) > 0 && !filterReg.MatchString(name.(string)) {
|
name, ok := mapping["name"].(string)
|
||||||
|
if ok && len(filter) > 0 && !filterReg.MatchString(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if prefixName != "" {
|
if prefixName != "" {
|
||||||
mapping["name"] = prefixName + mapping["name"].(string)
|
mapping["name"] = prefixName + name
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy, err := adapter.ParseProxy(mapping, forceCertVerify)
|
proxy, err := adapter.ParseProxy(mapping, forceCertVerify)
|
||||||
|
@ -103,7 +103,7 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf, nil
|
return removeComment(buf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPVehicle(url string, path string, header http.Header) *HTTPVehicle {
|
func NewHTTPVehicle(url string, path string, header http.Header) *HTTPVehicle {
|
||||||
|
@ -2,6 +2,7 @@ package cert
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
)
|
)
|
||||||
@ -9,10 +10,14 @@ import (
|
|||||||
// DomainTrieCertsStorage cache wildcard certificates
|
// DomainTrieCertsStorage cache wildcard certificates
|
||||||
type DomainTrieCertsStorage struct {
|
type DomainTrieCertsStorage struct {
|
||||||
certsCache *trie.DomainTrie[*tls.Certificate]
|
certsCache *trie.DomainTrie[*tls.Certificate]
|
||||||
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get gets the certificate from the storage
|
// Get gets the certificate from the storage
|
||||||
func (c *DomainTrieCertsStorage) Get(key string) (*tls.Certificate, bool) {
|
func (c *DomainTrieCertsStorage) Get(key string) (*tls.Certificate, bool) {
|
||||||
|
c.lock.RLock()
|
||||||
|
defer c.lock.RUnlock()
|
||||||
|
|
||||||
ca := c.certsCache.Search(key)
|
ca := c.certsCache.Search(key)
|
||||||
if ca == nil {
|
if ca == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
@ -22,7 +27,9 @@ func (c *DomainTrieCertsStorage) Get(key string) (*tls.Certificate, bool) {
|
|||||||
|
|
||||||
// Set saves the certificate to the storage
|
// Set saves the certificate to the storage
|
||||||
func (c *DomainTrieCertsStorage) Set(key string, cert *tls.Certificate) {
|
func (c *DomainTrieCertsStorage) Set(key string, cert *tls.Certificate) {
|
||||||
|
c.lock.Lock()
|
||||||
_ = c.certsCache.Insert(key, cert)
|
_ = c.certsCache.Insert(key, cert)
|
||||||
|
c.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDomainTrieCertsStorage() *DomainTrieCertsStorage {
|
func NewDomainTrieCertsStorage() *DomainTrieCertsStorage {
|
||||||
|
@ -29,13 +29,13 @@ func bindMarkToControl(mark int, chain controlFn) controlFn {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Control(func(fd uintptr) {
|
var innerErr error
|
||||||
switch network {
|
err = c.Control(func(fd uintptr) {
|
||||||
case "tcp4", "udp4":
|
innerErr = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
|
||||||
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
|
|
||||||
case "tcp6", "udp6":
|
|
||||||
_ = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
if err == nil && innerErr != nil {
|
||||||
|
err = innerErr
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,7 @@ package process
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/nnip"
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -23,52 +19,3 @@ const (
|
|||||||
func FindProcessName(network string, srcIP netip.Addr, srcPort int) (string, error) {
|
func FindProcessName(network string, srcIP netip.Addr, srcPort int) (string, error) {
|
||||||
return findProcessName(network, srcIP, srcPort)
|
return findProcessName(network, srcIP, srcPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ShouldFindProcess(metadata *C.Metadata) bool {
|
|
||||||
if metadata.Process != "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if metadata.SrcIP.IsUnspecified() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, ip := range localIPs {
|
|
||||||
if ip == metadata.SrcIP {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func AppendLocalIPs(ip ...netip.Addr) {
|
|
||||||
localIPs = append(ip, localIPs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLocalIPs() []netip.Addr {
|
|
||||||
var ips []netip.Addr
|
|
||||||
|
|
||||||
netInterfaces, err := net.Interfaces()
|
|
||||||
if err != nil {
|
|
||||||
ips = append(ips, netip.AddrFrom4([4]byte{127, 0, 0, 1}), nnip.IpToAddr(net.IPv6loopback))
|
|
||||||
return ips
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(netInterfaces); i++ {
|
|
||||||
if (netInterfaces[i].Flags & net.FlagUp) != 0 {
|
|
||||||
adds, _ := netInterfaces[i].Addrs()
|
|
||||||
|
|
||||||
for _, address := range adds {
|
|
||||||
if ipNet, ok := address.(*net.IPNet); ok {
|
|
||||||
ips = append(ips, nnip.IpToAddr(ipNet.IP))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ips
|
|
||||||
}
|
|
||||||
|
|
||||||
var localIPs []netip.Addr
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
localIPs = getLocalIPs()
|
|
||||||
}
|
|
||||||
|
@ -6,8 +6,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/nnip"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,10 +61,10 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) {
|
|||||||
switch {
|
switch {
|
||||||
case flag&0x1 > 0 && isIPv4:
|
case flag&0x1 > 0 && isIPv4:
|
||||||
// ipv4
|
// ipv4
|
||||||
srcIP = nnip.IpToAddr(buf[inp+76 : inp+80])
|
srcIP, _ = netip.AddrFromSlice(buf[inp+76 : inp+80])
|
||||||
case flag&0x2 > 0 && !isIPv4:
|
case flag&0x2 > 0 && !isIPv4:
|
||||||
// ipv6
|
// ipv6
|
||||||
srcIP = nnip.IpToAddr(buf[inp+64 : inp+80])
|
srcIP, _ = netip.AddrFromSlice(buf[inp+64 : inp+80])
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/nnip"
|
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -135,10 +134,10 @@ func (s *searcher) Search(buf []byte, ip netip.Addr, port uint16, isTCP bool) (u
|
|||||||
switch {
|
switch {
|
||||||
case flag&0x1 > 0 && isIPv4:
|
case flag&0x1 > 0 && isIPv4:
|
||||||
// ipv4
|
// ipv4
|
||||||
srcIP = nnip.IpToAddr(buf[inp+s.ip : inp+s.ip+4])
|
srcIP, _ = netip.AddrFromSlice(buf[inp+s.ip : inp+s.ip+4])
|
||||||
case flag&0x2 > 0 && !isIPv4:
|
case flag&0x2 > 0 && !isIPv4:
|
||||||
// ipv6
|
// ipv6
|
||||||
srcIP = nnip.IpToAddr(buf[inp+s.ip-12 : inp+s.ip+4])
|
srcIP, _ = netip.AddrFromSlice(buf[inp+s.ip-12 : inp+s.ip+4])
|
||||||
default:
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/nnip"
|
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
@ -132,7 +131,7 @@ func (s *searcher) Search(b []byte, ip netip.Addr, port uint16) (uint32, error)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
srcIP := nnip.IpToAddr(row[s.ip : s.ip+s.ipSize])
|
srcIP, _ := netip.AddrFromSlice(row[s.ip : s.ip+s.ipSize])
|
||||||
// windows binds an unbound udp socket to 0.0.0.0/[::] while first sendto
|
// windows binds an unbound udp socket to 0.0.0.0/[::] while first sendto
|
||||||
if ip != srcIP && (!srcIP.IsUnspecified() || s.tcpState != -1) {
|
if ip != srcIP && (!srcIP.IsUnspecified() || s.tcpState != -1) {
|
||||||
continue
|
continue
|
||||||
|
@ -99,12 +99,13 @@ type Profile struct {
|
|||||||
|
|
||||||
// Tun config
|
// Tun config
|
||||||
type Tun struct {
|
type Tun struct {
|
||||||
Enable bool `yaml:"enable" json:"enable"`
|
Enable bool `yaml:"enable" json:"enable"`
|
||||||
Device string `yaml:"device" json:"device"`
|
Device string `yaml:"device" json:"device"`
|
||||||
Stack C.TUNStack `yaml:"stack" json:"stack"`
|
Stack C.TUNStack `yaml:"stack" json:"stack"`
|
||||||
DNSHijack []C.DNSUrl `yaml:"dns-hijack" json:"dns-hijack"`
|
DNSHijack []C.DNSUrl `yaml:"dns-hijack" json:"dns-hijack"`
|
||||||
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
|
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
|
||||||
AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"`
|
AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"`
|
||||||
|
TunAddressPrefix *netip.Prefix `yaml:"_" json:"_"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPTables config
|
// IPTables config
|
||||||
@ -415,11 +416,11 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
|
|||||||
|
|
||||||
// keep the original order of ProxyGroups in config file
|
// keep the original order of ProxyGroups in config file
|
||||||
for idx, mapping := range groupsConfig {
|
for idx, mapping := range groupsConfig {
|
||||||
groupName, existName := mapping["name"]
|
groupName, existName := mapping["name"].(string)
|
||||||
if !existName {
|
if !existName {
|
||||||
return nil, nil, fmt.Errorf("proxy group %d: missing name", idx)
|
return nil, nil, fmt.Errorf("proxy group %d: missing name", idx)
|
||||||
}
|
}
|
||||||
proxyList = append(proxyList, groupName.(string))
|
proxyList = append(proxyList, groupName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if any loop exists and sort the ProxyGroups
|
// check if any loop exists and sort the ProxyGroups
|
||||||
|
@ -82,7 +82,7 @@ func ApplyConfig(cfg *config.Config, force bool) {
|
|||||||
updateHosts(cfg.Hosts)
|
updateHosts(cfg.Hosts)
|
||||||
updateMitm(cfg.Mitm)
|
updateMitm(cfg.Mitm)
|
||||||
updateProfile(cfg)
|
updateProfile(cfg)
|
||||||
updateDNS(cfg.DNS, cfg.General.Tun)
|
updateDNS(cfg.DNS, &cfg.General.Tun)
|
||||||
updateGeneral(cfg.General, force)
|
updateGeneral(cfg.General, force)
|
||||||
updateIPTables(cfg)
|
updateIPTables(cfg)
|
||||||
updateExperimental(cfg)
|
updateExperimental(cfg)
|
||||||
@ -121,7 +121,7 @@ func GetGeneral() *config.General {
|
|||||||
|
|
||||||
func updateExperimental(_ *config.Config) {}
|
func updateExperimental(_ *config.Config) {}
|
||||||
|
|
||||||
func updateDNS(c *config.DNS, t config.Tun) {
|
func updateDNS(c *config.DNS, t *config.Tun) {
|
||||||
cfg := dns.Config{
|
cfg := dns.Config{
|
||||||
Main: c.NameServer,
|
Main: c.NameServer,
|
||||||
Fallback: c.Fallback,
|
Fallback: c.Fallback,
|
||||||
@ -179,7 +179,7 @@ func updateDNS(c *config.DNS, t config.Tun) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Pool != nil {
|
if cfg.Pool != nil {
|
||||||
P.SetTunAddressPrefix(cfg.Pool.IPNet())
|
t.TunAddressPrefix = cfg.Pool.IPNet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,11 +31,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
allowLan = false
|
allowLan = false
|
||||||
bindAddress = "*"
|
bindAddress = "*"
|
||||||
lastTunConf *config.Tun
|
lastTunConf *config.Tun
|
||||||
lastTunAddressPrefix *netip.Prefix
|
|
||||||
tunAddressPrefix *netip.Prefix
|
|
||||||
|
|
||||||
socksListener *socks.Listener
|
socksListener *socks.Listener
|
||||||
socksUDPListener *socks.UDPListener
|
socksUDPListener *socks.UDPListener
|
||||||
@ -109,10 +107,6 @@ func SetBindAddress(host string) {
|
|||||||
bindAddress = host
|
bindAddress = host
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetTunAddressPrefix(tunAddress *netip.Prefix) {
|
|
||||||
tunAddressPrefix = tunAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) {
|
func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) {
|
||||||
httpMux.Lock()
|
httpMux.Lock()
|
||||||
defer httpMux.Unlock()
|
defer httpMux.Unlock()
|
||||||
@ -363,14 +357,10 @@ func ReCreateTun(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if tunAddressPrefix == nil {
|
|
||||||
tunAddressPrefix = lastTunAddressPrefix
|
|
||||||
}
|
|
||||||
|
|
||||||
tunConf.DNSHijack = C.RemoveDuplicateDNSUrl(tunConf.DNSHijack)
|
tunConf.DNSHijack = C.RemoveDuplicateDNSUrl(tunConf.DNSHijack)
|
||||||
|
|
||||||
if tunStackListener != nil {
|
if tunStackListener != nil {
|
||||||
if !hasTunConfigChange(tunConf, tunAddressPrefix) {
|
if !hasTunConfigChange(tunConf) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +369,6 @@ func ReCreateTun(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *
|
|||||||
}
|
}
|
||||||
|
|
||||||
lastTunConf = tunConf
|
lastTunConf = tunConf
|
||||||
lastTunAddressPrefix = tunAddressPrefix
|
|
||||||
|
|
||||||
if !tunConf.Enable {
|
if !tunConf.Enable {
|
||||||
return
|
return
|
||||||
@ -391,7 +380,7 @@ func ReCreateTun(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *
|
|||||||
udpIn: udpIn,
|
udpIn: udpIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
tunStackListener, err = tun.New(tunConf, tunAddressPrefix, tcpIn, udpIn, callback)
|
tunStackListener, err = tun.New(tunConf, tcpIn, udpIn, callback)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -535,7 +524,7 @@ func genAddr(host string, port int, allowLan bool) string {
|
|||||||
return fmt.Sprintf("127.0.0.1:%d", port)
|
return fmt.Sprintf("127.0.0.1:%d", port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasTunConfigChange(tunConf *config.Tun, tunAddressPrefix *netip.Prefix) bool {
|
func hasTunConfigChange(tunConf *config.Tun) bool {
|
||||||
if lastTunConf == nil {
|
if lastTunConf == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -558,11 +547,11 @@ func hasTunConfigChange(tunConf *config.Tun, tunAddressPrefix *netip.Prefix) boo
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tunAddressPrefix != nil && lastTunAddressPrefix == nil) || (tunAddressPrefix == nil && lastTunAddressPrefix != nil) {
|
if (lastTunConf.TunAddressPrefix != nil && tunConf.TunAddressPrefix == nil) || (lastTunConf.TunAddressPrefix == nil && tunConf.TunAddressPrefix != nil) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if tunAddressPrefix != nil && lastTunAddressPrefix != nil && *tunAddressPrefix != *lastTunAddressPrefix {
|
if lastTunConf.TunAddressPrefix != nil && tunConf.TunAddressPrefix != nil && *lastTunConf.TunAddressPrefix != *tunConf.TunAddressPrefix {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,11 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rAddr.Addr().Is4() {
|
||||||
|
// try to unmap 4in6 address
|
||||||
|
lAddr = netip.AddrPortFrom(lAddr.Addr().Unmap(), lAddr.Port())
|
||||||
|
}
|
||||||
handlePacketConn(in, buf[:n], lAddr, rAddr)
|
handlePacketConn(in, buf[:n], lAddr, rAddr)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -41,6 +41,10 @@ func (f *FD) Name() string {
|
|||||||
return strconv.Itoa(f.fd)
|
return strconv.Itoa(f.fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FD) MTU() uint32 {
|
||||||
|
return f.mtu
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FD) Close() error {
|
func (f *FD) Close() error {
|
||||||
err := unix.Close(f.fd)
|
err := unix.Close(f.fd)
|
||||||
if f.file != nil {
|
if f.file != nil {
|
||||||
|
@ -4,8 +4,48 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/listener/tun/device"
|
"github.com/Dreamacro/clash/listener/tun/device"
|
||||||
|
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Open(name string, mtu uint32) (device.Device, error) {
|
type FD struct {
|
||||||
|
stack.LinkEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func Open(_ string, _ uint32) (device.Device, error) {
|
||||||
return nil, errors.New("not supported")
|
return nil, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FD) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FD) Type() string {
|
||||||
|
return Driver
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FD) Read(_ []byte) (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FD) Write(_ []byte) (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FD) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FD) UseEndpoint() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FD) UseIOBased() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FD) MTU() uint32 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ device.Device = (*FD)(nil)
|
||||||
|
@ -59,10 +59,13 @@ func Open(name string, mtu uint32) (_ device.Device, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("get mtu: %w", err)
|
return nil, fmt.Errorf("get mtu: %w", err)
|
||||||
}
|
}
|
||||||
t.mtu = uint32(tunMTU)
|
|
||||||
|
if t.mtu == 0 {
|
||||||
|
t.mtu = uint32(tunMTU)
|
||||||
|
}
|
||||||
|
|
||||||
if t.offset > 0 {
|
if t.offset > 0 {
|
||||||
t.cache = make([]byte, 65535)
|
t.cache = make([]byte, int(t.mtu)+t.offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
@ -108,6 +111,10 @@ func (t *TUN) Name() string {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TUN) MTU() uint32 {
|
||||||
|
return t.mtu
|
||||||
|
}
|
||||||
|
|
||||||
func (t *TUN) UseEndpoint() error {
|
func (t *TUN) UseEndpoint() error {
|
||||||
ep, err := iobased.New(t, t.mtu, t.offset)
|
ep, err := iobased.New(t, t.mtu, t.offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,8 +5,10 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
|
dev "github.com/Dreamacro/clash/listener/tun/device"
|
||||||
|
"github.com/Dreamacro/clash/listener/tun/device/fdbased"
|
||||||
|
"github.com/Dreamacro/clash/listener/tun/device/tun"
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
||||||
"github.com/Dreamacro/clash/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *UDP, error) {
|
func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *UDP, error) {
|
||||||
@ -19,10 +21,27 @@ func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
t dev.Device
|
||||||
|
mtu uint32
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
if t, ok = device.(*tun.TUN); ok {
|
||||||
|
mtu = t.MTU()
|
||||||
|
} else if t, ok = device.(*fdbased.FD); ok {
|
||||||
|
mtu = t.MTU()
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferSize := int(mtu)
|
||||||
|
|
||||||
|
if bufferSize == 0 {
|
||||||
|
bufferSize = 64 * 1024
|
||||||
|
}
|
||||||
|
|
||||||
tab := newTable()
|
tab := newTable()
|
||||||
udp := &UDP{
|
udp := &UDP{
|
||||||
device: device,
|
device: device,
|
||||||
buf: [0xffff]byte{},
|
buf: make([]byte, bufferSize),
|
||||||
}
|
}
|
||||||
tcp := &TCP{
|
tcp := &TCP{
|
||||||
listener: listener,
|
listener: listener,
|
||||||
@ -38,7 +57,7 @@ func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *
|
|||||||
_ = udp.Close()
|
_ = udp.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
buf := make([]byte, 0xffff)
|
buf := make([]byte, bufferSize)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
n, err := device.Read(buf)
|
n, err := device.Read(buf)
|
||||||
@ -133,11 +152,7 @@ func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
port, err = tab.newConn(tup)
|
port = tab.newConn(tup)
|
||||||
if err != nil {
|
|
||||||
log.Warnln("[STACK] drop tcp packet by system stack: %v", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ip.SetSourceIP(portal)
|
ip.SetSourceIP(portal)
|
||||||
@ -156,7 +171,7 @@ func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
go udp.handleUDPPacket(ip, u)
|
udp.handleUDPPacket(ip, u)
|
||||||
case tcpip.ICMP:
|
case tcpip.ICMP:
|
||||||
i := tcpip.ICMPPacket(ip.Payload())
|
i := tcpip.ICMPPacket(ip.Payload())
|
||||||
|
|
||||||
|
@ -1,13 +1,9 @@
|
|||||||
package nat
|
package nat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/generics/list"
|
"github.com/Dreamacro/clash/common/generics/list"
|
||||||
|
|
||||||
"golang.org/x/exp/maps"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -31,8 +27,6 @@ type table struct {
|
|||||||
tuples map[tuple]*list.Element[*binding]
|
tuples map[tuple]*list.Element[*binding]
|
||||||
ports [portLength]*list.Element[*binding]
|
ports [portLength]*list.Element[*binding]
|
||||||
available *list.List[*binding]
|
available *list.List[*binding]
|
||||||
mux sync.Mutex
|
|
||||||
count uint16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) tupleOf(port uint16) tuple {
|
func (t *table) tupleOf(port uint16) tuple {
|
||||||
@ -49,64 +43,27 @@ func (t *table) tupleOf(port uint16) tuple {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) portOf(tuple tuple) uint16 {
|
func (t *table) portOf(tuple tuple) uint16 {
|
||||||
t.mux.Lock()
|
|
||||||
elm := t.tuples[tuple]
|
elm := t.tuples[tuple]
|
||||||
if elm == nil {
|
if elm == nil {
|
||||||
t.mux.Unlock()
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
t.mux.Unlock()
|
|
||||||
|
|
||||||
t.available.MoveToFront(elm)
|
t.available.MoveToFront(elm)
|
||||||
|
|
||||||
return portBegin + elm.Value.offset
|
return portBegin + elm.Value.offset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) newConn(tuple tuple) (uint16, error) {
|
func (t *table) newConn(tuple tuple) uint16 {
|
||||||
t.mux.Lock()
|
elm := t.available.Back()
|
||||||
elm, err := t.availableConn()
|
b := elm.Value
|
||||||
if err != nil {
|
|
||||||
t.mux.Unlock()
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
elm.Value.tuple = tuple
|
delete(t.tuples, b.tuple)
|
||||||
t.tuples[tuple] = elm
|
t.tuples[tuple] = elm
|
||||||
t.mux.Unlock()
|
b.tuple = tuple
|
||||||
|
|
||||||
return portBegin + elm.Value.offset, nil
|
t.available.MoveToFront(elm)
|
||||||
}
|
|
||||||
|
|
||||||
func (t *table) availableConn() (*list.Element[*binding], error) {
|
return portBegin + b.offset
|
||||||
var elm *list.Element[*binding]
|
|
||||||
|
|
||||||
for i := 0; i < portLength; i++ {
|
|
||||||
elm = t.available.Back()
|
|
||||||
t.available.MoveToFront(elm)
|
|
||||||
|
|
||||||
offset := elm.Value.offset
|
|
||||||
tup := t.ports[offset].Value.tuple
|
|
||||||
if t.tuples[tup] != nil && tup.SourceAddr.IsValid() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.count == portLength { // resize
|
|
||||||
tuples := make(map[tuple]*list.Element[*binding], portLength)
|
|
||||||
maps.Copy(tuples, t.tuples)
|
|
||||||
t.tuples = tuples
|
|
||||||
t.count = 1
|
|
||||||
}
|
|
||||||
return elm, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("too many open files, limits [%d, %d]", portLength, len(t.tuples))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *table) closeConn(tuple tuple) {
|
|
||||||
t.mux.Lock()
|
|
||||||
delete(t.tuples, tuple)
|
|
||||||
t.count++
|
|
||||||
t.mux.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTable() *table {
|
func newTable() *table {
|
||||||
@ -114,7 +71,6 @@ func newTable() *table {
|
|||||||
tuples: make(map[tuple]*list.Element[*binding], portLength),
|
tuples: make(map[tuple]*list.Element[*binding], portLength),
|
||||||
ports: [portLength]*list.Element[*binding]{},
|
ports: [portLength]*list.Element[*binding]{},
|
||||||
available: list.New[*binding](),
|
available: list.New[*binding](),
|
||||||
count: 1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx := range result.ports {
|
for idx := range result.ports {
|
||||||
|
@ -16,8 +16,6 @@ type conn struct {
|
|||||||
net.Conn
|
net.Conn
|
||||||
|
|
||||||
tuple tuple
|
tuple tuple
|
||||||
|
|
||||||
close func()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TCP) Accept() (net.Conn, error) {
|
func (t *TCP) Accept() (net.Conn, error) {
|
||||||
@ -41,9 +39,6 @@ func (t *TCP) Accept() (net.Conn, error) {
|
|||||||
return &conn{
|
return &conn{
|
||||||
Conn: c,
|
Conn: c,
|
||||||
tuple: tup,
|
tuple: tup,
|
||||||
close: func() {
|
|
||||||
t.table.closeConn(tup)
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +55,6 @@ func (t *TCP) SetDeadline(time time.Time) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *conn) Close() error {
|
func (c *conn) Close() error {
|
||||||
c.close()
|
|
||||||
return c.Conn.Close()
|
return c.Conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ type UDP struct {
|
|||||||
queueLock sync.Mutex
|
queueLock sync.Mutex
|
||||||
queue []*call
|
queue []*call
|
||||||
bufLock sync.Mutex
|
bufLock sync.Mutex
|
||||||
buf [0xffff]byte
|
buf []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UDP) ReadFrom(buf []byte) (int, netip.AddrPort, netip.AddrPort, error) {
|
func (u *UDP) ReadFrom(buf []byte) (int, netip.AddrPort, netip.AddrPort, error) {
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/inbound"
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
"github.com/Dreamacro/clash/common/cmd"
|
"github.com/Dreamacro/clash/common/cmd"
|
||||||
"github.com/Dreamacro/clash/component/process"
|
|
||||||
"github.com/Dreamacro/clash/config"
|
"github.com/Dreamacro/clash/config"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/listener/tun/device"
|
"github.com/Dreamacro/clash/listener/tun/device"
|
||||||
@ -24,7 +23,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// New TunAdapter
|
// New TunAdapter
|
||||||
func New(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter, tunChangeCallback C.TUNChangeCallback) (ipstack.Stack, error) {
|
func New(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter, tunChangeCallback C.TUNChangeCallback) (ipstack.Stack, error) {
|
||||||
var (
|
var (
|
||||||
tunAddress = netip.Prefix{}
|
tunAddress = netip.Prefix{}
|
||||||
devName = tunConf.Device
|
devName = tunConf.Device
|
||||||
@ -48,16 +47,14 @@ func New(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan<- C.Con
|
|||||||
devName = generateDeviceName()
|
devName = generateDeviceName()
|
||||||
}
|
}
|
||||||
|
|
||||||
if tunAddressPrefix != nil {
|
if tunConf.TunAddressPrefix != nil {
|
||||||
tunAddress = *tunAddressPrefix
|
tunAddress = *tunConf.TunAddressPrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tunAddress.IsValid() || !tunAddress.Addr().Is4() {
|
if !tunAddress.IsValid() || !tunAddress.Addr().Is4() {
|
||||||
tunAddress = netip.MustParsePrefix("198.18.0.1/16")
|
tunAddress = netip.MustParsePrefix("198.18.0.1/16")
|
||||||
}
|
}
|
||||||
|
|
||||||
process.AppendLocalIPs(tunAddress.Masked().Addr().Next())
|
|
||||||
|
|
||||||
// open tun device
|
// open tun device
|
||||||
tunDevice, err = parseDevice(devName, uint32(mtu))
|
tunDevice, err = parseDevice(devName, uint32(mtu))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -394,7 +394,7 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
|||||||
resolved = true
|
resolved = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !processFound && rule.ShouldFindProcess() && P.ShouldFindProcess(metadata) {
|
if !processFound && rule.ShouldFindProcess() {
|
||||||
processFound = true
|
processFound = true
|
||||||
|
|
||||||
srcPort, err := strconv.ParseUint(metadata.SrcPort, 10, 16)
|
srcPort, err := strconv.ParseUint(metadata.SrcPort, 10, 16)
|
||||||
|
Reference in New Issue
Block a user