Compare commits
18 Commits
v1.2.0_tun
...
v1.12.4_tu
Author | SHA1 | Date | |
---|---|---|---|
54e46d1599 | |||
ae6cc1d67d | |||
e1fe8ce3b2 | |||
b9ee4b902f | |||
7731a684b1 | |||
1f12ef069b | |||
e31be4edc2 | |||
f1fc0ef2ff | |||
98fea448c1 | |||
c0ea0cfd5d | |||
f700f4b6a3 | |||
f750bc96cb | |||
0002064c07 | |||
9ef850a55b | |||
37ed4a2b94 | |||
26dd6343a1 | |||
c1821e28d3 | |||
763929997b |
10
README.md
10
README.md
@ -13,11 +13,11 @@
|
||||
<img src="https://goreportcard.com/badge/github.com/Dreamacro/clash?style=flat-square">
|
||||
</a>
|
||||
<img src="https://img.shields.io/github/go-mod/go-version/Dreamacro/clash?style=flat-square">
|
||||
<a href="https://github.com/Dreamacro/clash/releases">
|
||||
<img src="https://img.shields.io/github/release/Dreamacro/clash/all.svg?style=flat-square">
|
||||
<a href="https://github.com/yaling888/clash/releases">
|
||||
<img src="https://img.shields.io/github/release/yaling888/clash/all.svg?style=flat-square">
|
||||
</a>
|
||||
<a href="https://github.com/Dreamacro/clash/releases/tag/premium">
|
||||
<img src="https://img.shields.io/badge/release-Premium-00b4f0?style=flat-square">
|
||||
<a href="https://github.com/yaling888/clash/releases/tag/plus_pro">
|
||||
<img src="https://img.shields.io/badge/release-Plus Pro-00b4f0?style=flat-square">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@ -363,7 +363,7 @@ external-ui: dashboard
|
||||
Open [http://127.0.0.1:9090/ui/](http://127.0.0.1:9090/ui/) by web browser.
|
||||
|
||||
## Plus Pro Release
|
||||
[Release](https://github.com/yaling888/clash/releases/tag/plus)
|
||||
[Release](https://github.com/yaling888/clash/releases/tag/plus_pro)
|
||||
|
||||
## Development
|
||||
If you want to build an application that uses clash as a library, check out the the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library)
|
||||
|
@ -23,7 +23,7 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...
|
||||
|
||||
tcpKeepAlive(c)
|
||||
|
||||
if !metadata.DstIP.IsValid() && c.RemoteAddr() != nil {
|
||||
if !metadata.Resolved() && c.RemoteAddr() != nil {
|
||||
if h, _, err := net.SplitHostPort(c.RemoteAddr().String()); err == nil {
|
||||
metadata.DstIP = netip.MustParseAddr(h)
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ func (m *Mitm) DialContext(_ context.Context, metadata *C.Metadata, _ ...dialer.
|
||||
|
||||
_ = c.SetKeepAlive(true)
|
||||
_ = c.SetKeepAlivePeriod(60 * time.Second)
|
||||
_ = c.SetLinger(0)
|
||||
|
||||
metadata.Type = C.MITM
|
||||
|
||||
|
@ -15,6 +15,7 @@ func tcpKeepAlive(c net.Conn) {
|
||||
if tcp, ok := c.(*net.TCPConn); ok {
|
||||
_ = tcp.SetKeepAlive(true)
|
||||
_ = tcp.SetKeepAlivePeriod(30 * time.Second)
|
||||
_ = tcp.SetLinger(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
func (v *Vless) StreamPacketConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr
|
||||
if !metadata.Resolved() {
|
||||
ip, err := resolver.ResolveIP(metadata.Host)
|
||||
ip, err := resolver.ResolveFirstIP(metadata.Host)
|
||||
if err != nil {
|
||||
return nil, errors.New("can't resolve ip")
|
||||
}
|
||||
@ -245,7 +245,7 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
||||
if v.transport != nil && len(opts) == 0 {
|
||||
// vless use stream-oriented udp with a special address, so we needs a net.UDPAddr
|
||||
if !metadata.Resolved() {
|
||||
ip, err := resolver.ResolveIP(metadata.Host)
|
||||
ip, err := resolver.ResolveFirstIP(metadata.Host)
|
||||
if err != nil {
|
||||
return nil, errors.New("can't resolve ip")
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/common/convert"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
@ -90,17 +91,16 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
wsOpts := &vmess.WebsocketConfig{
|
||||
Host: host,
|
||||
Port: port,
|
||||
Headers: http.Header{},
|
||||
Path: v.option.WSOpts.Path,
|
||||
MaxEarlyData: v.option.WSOpts.MaxEarlyData,
|
||||
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
|
||||
}
|
||||
|
||||
if len(v.option.WSOpts.Headers) != 0 {
|
||||
header := http.Header{}
|
||||
for key, value := range v.option.WSOpts.Headers {
|
||||
header.Add(key, value)
|
||||
wsOpts.Headers.Add(key, value)
|
||||
}
|
||||
wsOpts.Headers = header
|
||||
}
|
||||
|
||||
if v.option.TLS {
|
||||
@ -115,6 +115,11 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
} else if host := wsOpts.Headers.Get("Host"); host != "" {
|
||||
wsOpts.TLSConfig.ServerName = host
|
||||
}
|
||||
} else {
|
||||
if wsOpts.Headers.Get("Host") == "" {
|
||||
wsOpts.Headers.Set("Host", convert.RandHost())
|
||||
}
|
||||
convert.SetUserAgent(wsOpts.Headers)
|
||||
}
|
||||
c, err = vmess.StreamWebsocketConn(c, wsOpts)
|
||||
case "http":
|
||||
@ -198,7 +203,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
func (v *Vmess) StreamPacketConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr
|
||||
if !metadata.Resolved() {
|
||||
ip, err := resolver.ResolveIP(metadata.Host)
|
||||
ip, err := resolver.ResolveFirstIP(metadata.Host)
|
||||
if err != nil {
|
||||
return c, fmt.Errorf("can't resolve ip: %w", err)
|
||||
}
|
||||
@ -250,7 +255,7 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
|
||||
if v.transport != nil && len(opts) == 0 {
|
||||
// vmess use stream-oriented udp with a special address, so we needs a net.UDPAddr
|
||||
if !metadata.Resolved() {
|
||||
ip, err := resolver.ResolveIP(metadata.Host)
|
||||
ip, err := resolver.ResolveFirstIP(metadata.Host)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't resolve ip: %w", err)
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package outboundgroup
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter"
|
||||
"github.com/Dreamacro/clash/adapter/outbound"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/constant/provider"
|
||||
)
|
||||
@ -11,14 +13,19 @@ const (
|
||||
defaultGetProxiesDuration = time.Second * 5
|
||||
)
|
||||
|
||||
var defaultRejectProxy = adapter.NewProxy(outbound.NewReject())
|
||||
|
||||
func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Proxy {
|
||||
proxies := []C.Proxy{}
|
||||
for _, provider := range providers {
|
||||
for _, pd := range providers {
|
||||
if touch {
|
||||
proxies = append(proxies, provider.ProxiesWithTouch()...)
|
||||
proxies = append(proxies, pd.ProxiesWithTouch()...)
|
||||
} else {
|
||||
proxies = append(proxies, provider.Proxies()...)
|
||||
proxies = append(proxies, pd.Proxies()...)
|
||||
}
|
||||
}
|
||||
if len(proxies) == 0 {
|
||||
proxies = append(proxies, defaultRejectProxy)
|
||||
}
|
||||
return proxies
|
||||
}
|
||||
|
@ -30,10 +30,8 @@ type LoadBalance struct {
|
||||
var errStrategy = errors.New("unsupported strategy")
|
||||
|
||||
func parseStrategy(config map[string]any) string {
|
||||
if elm, ok := config["strategy"]; ok {
|
||||
if strategy, ok := elm.(string); ok {
|
||||
return strategy
|
||||
}
|
||||
if strategy, ok := config["strategy"].(string); ok {
|
||||
return strategy
|
||||
}
|
||||
return "consistent-hashing"
|
||||
}
|
||||
|
@ -78,30 +78,18 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
|
||||
return nil, errDuplicateProvider
|
||||
}
|
||||
|
||||
// select don't need health check
|
||||
if groupOption.Type == "select" || groupOption.Type == "relay" {
|
||||
hc := provider.NewHealthCheck(ps, "", 0, true)
|
||||
pd, err := provider.NewCompatibleProvider(groupName, ps, hc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
providers = append(providers, pd)
|
||||
providersMap[groupName] = pd
|
||||
} else {
|
||||
if groupOption.URL == "" || groupOption.Interval == 0 {
|
||||
return nil, errMissHealthCheck
|
||||
}
|
||||
|
||||
hc := provider.NewHealthCheck(ps, groupOption.URL, uint(groupOption.Interval), groupOption.Lazy)
|
||||
pd, err := provider.NewCompatibleProvider(groupName, ps, hc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
providers = append(providers, pd)
|
||||
providersMap[groupName] = pd
|
||||
hc, err := newHealthCheck(ps, groupOption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pd, err := provider.NewCompatibleProvider(groupName, ps, hc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
providers = append(providers, pd)
|
||||
providersMap[groupName] = pd
|
||||
}
|
||||
|
||||
if len(groupOption.Use) != 0 {
|
||||
@ -109,7 +97,12 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
providers = append(providers, list...)
|
||||
|
||||
if groupOption.Type == "fallback" {
|
||||
providers = append(list, providers...)
|
||||
} else {
|
||||
providers = append(providers, list...)
|
||||
}
|
||||
}
|
||||
|
||||
var group C.ProxyAdapter
|
||||
@ -163,22 +156,18 @@ func getProviders(mapping map[string]types.ProxyProvider, groupOption *GroupComm
|
||||
}
|
||||
|
||||
if filterRegx != nil {
|
||||
var hc *provider.HealthCheck
|
||||
if groupOption.Type == "select" || groupOption.Type == "relay" {
|
||||
hc = provider.NewHealthCheck([]C.Proxy{}, "", 0, true)
|
||||
} else {
|
||||
if groupOption.URL == "" || groupOption.Interval == 0 {
|
||||
return nil, errMissHealthCheck
|
||||
}
|
||||
hc = provider.NewHealthCheck([]C.Proxy{}, groupOption.URL, uint(groupOption.Interval), groupOption.Lazy)
|
||||
hc, err := newHealthCheck([]C.Proxy{}, groupOption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, ok = mapping[groupName]; ok {
|
||||
groupName += "->" + p.Name()
|
||||
gName := groupName
|
||||
if _, ok = mapping[gName]; ok {
|
||||
gName = groupName + " -> " + p.Name()
|
||||
}
|
||||
|
||||
pd := p.(*provider.ProxySetProvider)
|
||||
p = provider.NewProxyFilterProvider(groupName, pd, hc, filterRegx)
|
||||
p = provider.NewProxyFilterProvider(gName, pd, hc, filterRegx)
|
||||
pd.RegisterProvidersInUse(p)
|
||||
}
|
||||
|
||||
@ -186,3 +175,18 @@ func getProviders(mapping map[string]types.ProxyProvider, groupOption *GroupComm
|
||||
}
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func newHealthCheck(ps []C.Proxy, groupOption *GroupCommonOption) (*provider.HealthCheck, error) {
|
||||
var hc *provider.HealthCheck
|
||||
|
||||
// select don't need health check
|
||||
if groupOption.Type == "select" || groupOption.Type == "relay" {
|
||||
hc = provider.NewHealthCheck(ps, "", 0, true)
|
||||
} else {
|
||||
if groupOption.URL == "" || groupOption.Interval == 0 {
|
||||
return nil, errMissHealthCheck
|
||||
}
|
||||
hc = provider.NewHealthCheck(ps, groupOption.URL, uint(groupOption.Interval), groupOption.Lazy)
|
||||
}
|
||||
return hc, nil
|
||||
}
|
||||
|
@ -98,7 +98,11 @@ func (s *Selector) selectedProxy(touch bool) C.Proxy {
|
||||
}
|
||||
|
||||
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
|
||||
selected := providers[0].Proxies()[0].Name()
|
||||
selected := "REJECT"
|
||||
if len(providers) != 0 && len(providers[0].Proxies()) != 0 {
|
||||
selected = providers[0].Proxies()[0].Name()
|
||||
}
|
||||
|
||||
return &Selector{
|
||||
Base: outbound.NewBase(outbound.BaseOption{
|
||||
Name: option.Name,
|
||||
|
@ -125,10 +125,8 @@ func parseURLTestOption(config map[string]any) []urlTestOption {
|
||||
opts := []urlTestOption{}
|
||||
|
||||
// tolerance
|
||||
if elm, ok := config["tolerance"]; ok {
|
||||
if tolerance, ok := elm.(int); ok {
|
||||
opts = append(opts, urlTestWithTolerance(uint16(tolerance)))
|
||||
}
|
||||
if tolerance, ok := config["tolerance"].(int); ok {
|
||||
opts = append(opts, urlTestWithTolerance(uint16(tolerance)))
|
||||
}
|
||||
|
||||
return opts
|
||||
|
@ -48,5 +48,6 @@ func tcpKeepAlive(c net.Conn) {
|
||||
if tcp, ok := c.(*net.TCPConn); ok {
|
||||
_ = tcp.SetKeepAlive(true)
|
||||
_ = tcp.SetKeepAlivePeriod(30 * time.Second)
|
||||
_ = tcp.SetLinger(0)
|
||||
}
|
||||
}
|
||||
|
@ -57,8 +57,9 @@ func ParseProxy(mapping map[string]any, forceCertVerify bool) (C.Proxy, error) {
|
||||
case "vmess":
|
||||
vmessOption := &outbound.VmessOption{
|
||||
HTTPOpts: outbound.HTTPOptions{
|
||||
Method: "GET",
|
||||
Path: []string{"/"},
|
||||
Method: "GET",
|
||||
Path: []string{"/"},
|
||||
Headers: make(map[string][]string),
|
||||
},
|
||||
}
|
||||
err = decoder.Decode(mapping, vmessOption)
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"crypto/md5"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
types "github.com/Dreamacro/clash/constant/provider"
|
||||
@ -14,6 +15,8 @@ import (
|
||||
var (
|
||||
fileMode os.FileMode = 0o666
|
||||
dirMode os.FileMode = 0o755
|
||||
|
||||
commentRegx = regexp.MustCompile(`(.*#.*\n)`)
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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] {
|
||||
var ticker *time.Ticker
|
||||
if interval != 0 {
|
||||
|
@ -25,10 +25,16 @@ type HealthCheck struct {
|
||||
interval uint
|
||||
lazy bool
|
||||
lastTouch *atomic.Int64
|
||||
running *atomic.Bool
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func (hc *HealthCheck) process() {
|
||||
if hc.running.Load() {
|
||||
return
|
||||
}
|
||||
hc.running.Store(true)
|
||||
|
||||
ticker := time.NewTicker(time.Duration(hc.interval) * time.Second)
|
||||
|
||||
go func() {
|
||||
@ -84,6 +90,10 @@ func (hc *HealthCheck) check() {
|
||||
}
|
||||
|
||||
func (hc *HealthCheck) close() {
|
||||
if !hc.running.Load() {
|
||||
return
|
||||
}
|
||||
hc.running.Store(false)
|
||||
hc.done <- struct{}{}
|
||||
}
|
||||
|
||||
@ -94,6 +104,7 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool) *He
|
||||
interval: interval,
|
||||
lazy: lazy,
|
||||
lastTouch: atomic.NewInt64(0),
|
||||
running: atomic.NewBool(false),
|
||||
done: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +234,9 @@ func (pf *proxyFilterProvider) HealthCheck() {
|
||||
}
|
||||
|
||||
func (pf *proxyFilterProvider) Update() error {
|
||||
var proxies []C.Proxy
|
||||
pf.healthCheck.close()
|
||||
|
||||
proxies := []C.Proxy{}
|
||||
if pf.filter != nil {
|
||||
for _, proxy := range pf.psd.Proxies() {
|
||||
if !pf.filter.MatchString(proxy.Name()) {
|
||||
@ -248,6 +250,10 @@ func (pf *proxyFilterProvider) Update() error {
|
||||
|
||||
pf.proxies = proxies
|
||||
pf.healthCheck.setProxy(proxies)
|
||||
|
||||
if len(proxies) != 0 && pf.healthCheck.auto() {
|
||||
go pf.healthCheck.process()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -286,10 +292,6 @@ func NewProxyFilterProvider(name string, psd *ProxySetProvider, hc *HealthCheck,
|
||||
|
||||
_ = pd.Update()
|
||||
|
||||
if hc.auto() {
|
||||
go hc.process()
|
||||
}
|
||||
|
||||
wrapper := &ProxyFilterProvider{pd}
|
||||
runtime.SetFinalizer(wrapper, stopProxyFilterProvider)
|
||||
return wrapper
|
||||
@ -308,7 +310,7 @@ func proxiesParseAndFilter(filter string, filterReg *regexp.Regexp, forceCertVer
|
||||
if err := yaml.Unmarshal(buf, schema); err != nil {
|
||||
proxies, err1 := convert.ConvertsV2Ray(buf)
|
||||
if err1 != nil {
|
||||
return nil, fmt.Errorf("%s, %w", err.Error(), err1)
|
||||
return nil, fmt.Errorf("%w, %s", err, err1.Error())
|
||||
}
|
||||
schema.Proxies = proxies
|
||||
}
|
||||
@ -319,12 +321,13 @@ func proxiesParseAndFilter(filter string, filterReg *regexp.Regexp, forceCertVer
|
||||
|
||||
proxies := []C.Proxy{}
|
||||
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
|
||||
}
|
||||
|
||||
if prefixName != "" {
|
||||
mapping["name"] = prefixName + mapping["name"].(string)
|
||||
mapping["name"] = prefixName + name
|
||||
}
|
||||
|
||||
proxy, err := adapter.ParseProxy(mapping, forceCertVerify)
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/Dreamacro/clash/common/convert"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
types "github.com/Dreamacro/clash/constant/provider"
|
||||
)
|
||||
|
||||
@ -72,9 +71,7 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
|
||||
req.SetBasicAuth(user.Username(), password)
|
||||
}
|
||||
|
||||
if req.UserAgent() == "" {
|
||||
convert.SetUserAgent(req)
|
||||
}
|
||||
convert.SetUserAgent(req.Header)
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
@ -84,13 +81,11 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
DialContext: func(ctx context.Context, network, address string) (conn net.Conn, err error) {
|
||||
conn, err = dialer.DialContext(ctx, network, address) // with direct
|
||||
if err != nil {
|
||||
// fallback to tun if tun enabled
|
||||
conn, err = (&net.Dialer{Timeout: C.DefaultTCPTimeout}).Dial(network, address)
|
||||
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
if req.URL.Scheme == "https" {
|
||||
return (&net.Dialer{}).DialContext(ctx, network, address) // forward to tun if tun enabled
|
||||
}
|
||||
return
|
||||
return dialer.DialContext(ctx, network, address, dialer.WithDirect()) // with direct
|
||||
},
|
||||
}
|
||||
|
||||
@ -108,7 +103,7 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
return removeComment(buf), nil
|
||||
}
|
||||
|
||||
func NewHTTPVehicle(url string, path string, header http.Header) *HTTPVehicle {
|
||||
|
@ -2,6 +2,7 @@ package cert
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"sync"
|
||||
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
)
|
||||
@ -9,10 +10,14 @@ import (
|
||||
// DomainTrieCertsStorage cache wildcard certificates
|
||||
type DomainTrieCertsStorage struct {
|
||||
certsCache *trie.DomainTrie[*tls.Certificate]
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// Get gets the certificate from the storage
|
||||
func (c *DomainTrieCertsStorage) Get(key string) (*tls.Certificate, bool) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
ca := c.certsCache.Search(key)
|
||||
if ca == nil {
|
||||
return nil, false
|
||||
@ -22,7 +27,9 @@ func (c *DomainTrieCertsStorage) Get(key string) (*tls.Certificate, bool) {
|
||||
|
||||
// Set saves the certificate to the storage
|
||||
func (c *DomainTrieCertsStorage) Set(key string, cert *tls.Certificate) {
|
||||
c.lock.Lock()
|
||||
_ = c.certsCache.Insert(key, cert)
|
||||
c.lock.Unlock()
|
||||
}
|
||||
|
||||
func NewDomainTrieCertsStorage() *DomainTrieCertsStorage {
|
||||
|
@ -21,21 +21,24 @@ func DecodeBase64(buf []byte) ([]byte, error) {
|
||||
return dBuf[:n], nil
|
||||
}
|
||||
|
||||
// DecodeBase64StringToString decode base64 string to string
|
||||
func DecodeBase64StringToString(s string) (string, error) {
|
||||
dBuf, err := enc.DecodeString(s)
|
||||
func DecodeRawBase64(buf []byte) ([]byte, error) {
|
||||
dBuf := make([]byte, base64.RawStdEncoding.DecodedLen(len(buf)))
|
||||
n, err := base64.RawStdEncoding.Decode(dBuf, buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return string(dBuf), nil
|
||||
return dBuf[:n], nil
|
||||
}
|
||||
|
||||
// ConvertsV2Ray convert V2Ray subscribe proxies data to clash proxies config
|
||||
func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
||||
data, err := DecodeBase64(buf)
|
||||
if err != nil {
|
||||
data = buf
|
||||
data, err = DecodeRawBase64(buf)
|
||||
if err != nil {
|
||||
data = buf
|
||||
}
|
||||
}
|
||||
|
||||
arr := strings.Split(string(data), "\n")
|
||||
@ -62,7 +65,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
q := urlTrojan.Query()
|
||||
query := urlTrojan.Query()
|
||||
|
||||
name := uniqueName(names, urlTrojan.Fragment)
|
||||
trojan := make(map[string]any, 20)
|
||||
@ -75,12 +78,12 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
||||
trojan["udp"] = true
|
||||
trojan["skip-cert-verify"] = false
|
||||
|
||||
sni := q.Get("sni")
|
||||
sni := query.Get("sni")
|
||||
if sni != "" {
|
||||
trojan["sni"] = sni
|
||||
}
|
||||
|
||||
network := strings.ToLower(q.Get("type"))
|
||||
network := strings.ToLower(query.Get("type"))
|
||||
if network != "" {
|
||||
trojan["network"] = network
|
||||
}
|
||||
@ -92,7 +95,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
||||
headers["Host"] = RandHost()
|
||||
headers["User-Agent"] = RandUserAgent()
|
||||
|
||||
wsOpts["path"] = q.Get("path")
|
||||
wsOpts["path"] = query.Get("path")
|
||||
wsOpts["headers"] = headers
|
||||
|
||||
trojan["ws-opts"] = wsOpts
|
||||
@ -267,7 +270,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
q := urlVless.Query()
|
||||
query := urlVless.Query()
|
||||
|
||||
name := uniqueName(names, urlVless.Fragment)
|
||||
vless := make(map[string]any, 20)
|
||||
@ -280,17 +283,17 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
||||
vless["udp"] = true
|
||||
vless["skip-cert-verify"] = false
|
||||
|
||||
sni := q.Get("sni")
|
||||
sni := query.Get("sni")
|
||||
if sni != "" {
|
||||
vless["servername"] = sni
|
||||
}
|
||||
|
||||
flow := strings.ToLower(q.Get("flow"))
|
||||
flow := strings.ToLower(query.Get("flow"))
|
||||
if flow != "" {
|
||||
vless["flow"] = flow
|
||||
}
|
||||
|
||||
network := strings.ToLower(q.Get("type"))
|
||||
network := strings.ToLower(query.Get("type"))
|
||||
if network != "" {
|
||||
vless["network"] = network
|
||||
}
|
||||
@ -302,7 +305,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
|
||||
headers["Host"] = RandHost()
|
||||
headers["User-Agent"] = RandUserAgent()
|
||||
|
||||
wsOpts["path"] = q.Get("path")
|
||||
wsOpts["path"] = query.Get("path")
|
||||
wsOpts["headers"] = headers
|
||||
|
||||
vless["ws-opts"] = wsOpts
|
||||
@ -335,7 +338,7 @@ func uniqueName(names map[string]int, name string) string {
|
||||
if index, ok := names[name]; ok {
|
||||
index++
|
||||
names[name] = index
|
||||
name = name + "-" + fmt.Sprintf("%02d", index)
|
||||
name = fmt.Sprintf("%s-%02d", name, index)
|
||||
} else {
|
||||
index = 0
|
||||
names[name] = index
|
||||
|
@ -29,7 +29,6 @@ var hostsSuffix = []string{
|
||||
".alidns.com",
|
||||
".cdngslb.com",
|
||||
".mxhichina.com",
|
||||
".alibabadns.com",
|
||||
}
|
||||
|
||||
var userAgents = []string{
|
||||
@ -307,7 +306,10 @@ func RandUserAgent() string {
|
||||
return userAgents[rand.Intn(uaLen)]
|
||||
}
|
||||
|
||||
func SetUserAgent(req *http.Request) {
|
||||
func SetUserAgent(header http.Header) {
|
||||
if header.Get("User-Agent") != "" {
|
||||
return
|
||||
}
|
||||
userAgent := RandUserAgent()
|
||||
req.Header.Set("User-Agent", userAgent)
|
||||
header.Set("User-Agent", userAgent)
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
// Relay copies between left and right bidirectionally.
|
||||
@ -16,18 +14,14 @@ func Relay(leftConn, rightConn net.Conn) {
|
||||
tcpKeepAlive(rightConn)
|
||||
|
||||
go func() {
|
||||
buf := pool.Get(pool.RelayBufferSize)
|
||||
// Wrapping to avoid using *net.TCPConn.(ReadFrom)
|
||||
// See also https://github.com/Dreamacro/clash/pull/1209
|
||||
_, err := io.CopyBuffer(WriteOnlyWriter{Writer: leftConn}, ReadOnlyReader{Reader: rightConn}, buf)
|
||||
_ = pool.Put(buf)
|
||||
_, err := io.Copy(WriteOnlyWriter{Writer: leftConn}, ReadOnlyReader{Reader: rightConn})
|
||||
_ = leftConn.SetReadDeadline(time.Now())
|
||||
ch <- err
|
||||
}()
|
||||
|
||||
buf := pool.Get(pool.RelayBufferSize)
|
||||
_, _ = io.CopyBuffer(WriteOnlyWriter{Writer: rightConn}, ReadOnlyReader{Reader: leftConn}, buf)
|
||||
_ = pool.Put(buf)
|
||||
_, _ = io.Copy(WriteOnlyWriter{Writer: rightConn}, ReadOnlyReader{Reader: leftConn})
|
||||
_ = rightConn.SetReadDeadline(time.Now())
|
||||
<-ch
|
||||
}
|
||||
|
@ -29,13 +29,13 @@ func bindMarkToControl(mark int, chain controlFn) controlFn {
|
||||
return
|
||||
}
|
||||
|
||||
return c.Control(func(fd uintptr) {
|
||||
switch network {
|
||||
case "tcp4", "udp4":
|
||||
_ = 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)
|
||||
}
|
||||
var innerErr error
|
||||
err = c.Control(func(fd uintptr) {
|
||||
innerErr = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_MARK, mark)
|
||||
})
|
||||
if err == nil && innerErr != nil {
|
||||
err = innerErr
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ package geodata
|
||||
|
||||
import (
|
||||
"github.com/Dreamacro/clash/component/geodata/router"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) {
|
||||
func loadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) {
|
||||
geoLoaderName := "standard"
|
||||
geoLoader, err := GetGeoDataLoader(geoLoaderName)
|
||||
if err != nil {
|
||||
@ -28,3 +30,33 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error)
|
||||
|
||||
return matcher, len(domains), nil
|
||||
}
|
||||
|
||||
var ruleProviders = make(map[string]*router.DomainMatcher)
|
||||
|
||||
// HasProvider has geo site provider by county code
|
||||
func HasProvider(countyCode string) (ok bool) {
|
||||
_, ok = ruleProviders[countyCode]
|
||||
return ok
|
||||
}
|
||||
|
||||
// GetProvidersList get geo site providers
|
||||
func GetProvidersList(countyCode string) []*router.DomainMatcher {
|
||||
return maps.Values(ruleProviders)
|
||||
}
|
||||
|
||||
// GetProviderByCode get geo site provider by county code
|
||||
func GetProviderByCode(countyCode string) (matcher *router.DomainMatcher, ok bool) {
|
||||
matcher, ok = ruleProviders[countyCode]
|
||||
return
|
||||
}
|
||||
|
||||
func LoadProviderByCode(countyCode string) (matcher *router.DomainMatcher, count int, err error) {
|
||||
var ok bool
|
||||
matcher, ok = ruleProviders[countyCode]
|
||||
if !ok {
|
||||
if matcher, count, err = loadGeoSiteMatcher(countyCode); err == nil {
|
||||
ruleProviders[countyCode] = matcher
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -2,11 +2,7 @@ package process
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -23,49 +19,3 @@ const (
|
||||
func FindProcessName(network string, srcIP netip.Addr, srcPort int) (string, error) {
|
||||
return findProcessName(network, srcIP, srcPort)
|
||||
}
|
||||
|
||||
func ShouldFindProcess(metadata *C.Metadata) bool {
|
||||
if metadata.Process != "" {
|
||||
return false
|
||||
}
|
||||
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 {
|
||||
ips := []netip.Addr{netip.IPv4Unspecified(), netip.IPv6Unspecified()}
|
||||
|
||||
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"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@ -63,10 +61,10 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) {
|
||||
switch {
|
||||
case flag&0x1 > 0 && isIPv4:
|
||||
// ipv4
|
||||
srcIP = nnip.IpToAddr(buf[inp+76 : inp+80])
|
||||
srcIP, _ = netip.AddrFromSlice(buf[inp+76 : inp+80])
|
||||
case flag&0x2 > 0 && !isIPv4:
|
||||
// ipv6
|
||||
srcIP = nnip.IpToAddr(buf[inp+64 : inp+80])
|
||||
srcIP, _ = netip.AddrFromSlice(buf[inp+64 : inp+80])
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
)
|
||||
|
||||
@ -135,10 +134,10 @@ func (s *searcher) Search(buf []byte, ip netip.Addr, port uint16, isTCP bool) (u
|
||||
switch {
|
||||
case flag&0x1 > 0 && isIPv4:
|
||||
// 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:
|
||||
// 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:
|
||||
continue
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@ -132,7 +131,7 @@ func (s *searcher) Search(b []byte, ip netip.Addr, port uint16) (uint32, error)
|
||||
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
|
||||
if ip != srcIP && (!srcIP.IsUnspecified() || s.tcpState != -1) {
|
||||
continue
|
||||
|
@ -37,17 +37,17 @@ var (
|
||||
)
|
||||
|
||||
type Resolver interface {
|
||||
ResolveIP(host string) (ip netip.Addr, err error)
|
||||
ResolveIPv4(host string) (ip netip.Addr, err error)
|
||||
ResolveIPv6(host string) (ip netip.Addr, err error)
|
||||
ResolveIP(host string, random bool) (ip netip.Addr, err error)
|
||||
ResolveIPv4(host string, random bool) (ip netip.Addr, err error)
|
||||
ResolveIPv6(host string, random bool) (ip netip.Addr, err error)
|
||||
}
|
||||
|
||||
// ResolveIPv4 with a host, return ipv4
|
||||
func ResolveIPv4(host string) (netip.Addr, error) {
|
||||
return ResolveIPv4WithResolver(host, DefaultResolver)
|
||||
return resolveIPv4(host, true)
|
||||
}
|
||||
|
||||
func ResolveIPv4WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
func ResolveIPv4WithResolver(host string, r Resolver, random bool) (netip.Addr, error) {
|
||||
if node := DefaultHosts.Search(host); node != nil {
|
||||
if ip := node.Data; ip.Is4() {
|
||||
return ip, nil
|
||||
@ -56,6 +56,7 @@ func ResolveIPv4WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
|
||||
ip, err := netip.ParseAddr(host)
|
||||
if err == nil {
|
||||
ip = ip.Unmap()
|
||||
if ip.Is4() {
|
||||
return ip, nil
|
||||
}
|
||||
@ -63,7 +64,7 @@ func ResolveIPv4WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return r.ResolveIPv4(host)
|
||||
return r.ResolveIPv4(host, random)
|
||||
}
|
||||
|
||||
if DefaultResolver == nil {
|
||||
@ -76,7 +77,11 @@ func ResolveIPv4WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
return netip.Addr{}, ErrIPNotFound
|
||||
}
|
||||
|
||||
ip := ipAddrs[rand.Intn(len(ipAddrs))].To4()
|
||||
index := 0
|
||||
if random {
|
||||
index = rand.Intn(len(ipAddrs))
|
||||
}
|
||||
ip := ipAddrs[index].To4()
|
||||
if ip == nil {
|
||||
return netip.Addr{}, ErrIPVersion
|
||||
}
|
||||
@ -89,10 +94,10 @@ func ResolveIPv4WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
|
||||
// ResolveIPv6 with a host, return ipv6
|
||||
func ResolveIPv6(host string) (netip.Addr, error) {
|
||||
return ResolveIPv6WithResolver(host, DefaultResolver)
|
||||
return ResolveIPv6WithResolver(host, DefaultResolver, true)
|
||||
}
|
||||
|
||||
func ResolveIPv6WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
func ResolveIPv6WithResolver(host string, r Resolver, random bool) (netip.Addr, error) {
|
||||
if DisableIPv6 {
|
||||
return netip.Addr{}, ErrIPv6Disabled
|
||||
}
|
||||
@ -112,7 +117,7 @@ func ResolveIPv6WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
return r.ResolveIPv6(host)
|
||||
return r.ResolveIPv6(host, random)
|
||||
}
|
||||
|
||||
if DefaultResolver == nil {
|
||||
@ -125,25 +130,29 @@ func ResolveIPv6WithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
return netip.Addr{}, ErrIPNotFound
|
||||
}
|
||||
|
||||
return netip.AddrFrom16(*(*[16]byte)(ipAddrs[rand.Intn(len(ipAddrs))])), nil
|
||||
index := 0
|
||||
if random {
|
||||
index = rand.Intn(len(ipAddrs))
|
||||
}
|
||||
return netip.AddrFrom16(*(*[16]byte)(ipAddrs[index])), nil
|
||||
}
|
||||
|
||||
return netip.Addr{}, ErrIPNotFound
|
||||
}
|
||||
|
||||
// ResolveIPWithResolver same as ResolveIP, but with a resolver
|
||||
func ResolveIPWithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
func ResolveIPWithResolver(host string, r Resolver, random bool) (netip.Addr, error) {
|
||||
if node := DefaultHosts.Search(host); node != nil {
|
||||
return node.Data, nil
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
if DisableIPv6 {
|
||||
return r.ResolveIPv4(host)
|
||||
return r.ResolveIPv4(host, random)
|
||||
}
|
||||
return r.ResolveIP(host)
|
||||
return r.ResolveIP(host, random)
|
||||
} else if DisableIPv6 {
|
||||
return ResolveIPv4(host)
|
||||
return resolveIPv4(host, random)
|
||||
}
|
||||
|
||||
ip, err := netip.ParseAddr(host)
|
||||
@ -165,13 +174,18 @@ func ResolveIPWithResolver(host string, r Resolver) (netip.Addr, error) {
|
||||
|
||||
// ResolveIP with a host, return ip
|
||||
func ResolveIP(host string) (netip.Addr, error) {
|
||||
return ResolveIPWithResolver(host, DefaultResolver)
|
||||
return resolveIP(host, true)
|
||||
}
|
||||
|
||||
// ResolveFirstIP with a host, return ip
|
||||
func ResolveFirstIP(host string) (netip.Addr, error) {
|
||||
return resolveIP(host, false)
|
||||
}
|
||||
|
||||
// ResolveIPv4ProxyServerHost proxies server host only
|
||||
func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveIPv4WithResolver(host, ProxyServerHostResolver)
|
||||
return ResolveIPv4WithResolver(host, ProxyServerHostResolver, true)
|
||||
}
|
||||
return ResolveIPv4(host)
|
||||
}
|
||||
@ -179,7 +193,7 @@ func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) {
|
||||
// ResolveIPv6ProxyServerHost proxies server host only
|
||||
func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveIPv6WithResolver(host, ProxyServerHostResolver)
|
||||
return ResolveIPv6WithResolver(host, ProxyServerHostResolver, true)
|
||||
}
|
||||
return ResolveIPv6(host)
|
||||
}
|
||||
@ -187,7 +201,15 @@ func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) {
|
||||
// ResolveProxyServerHost proxies server host only
|
||||
func ResolveProxyServerHost(host string) (netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveIPWithResolver(host, ProxyServerHostResolver)
|
||||
return ResolveIPWithResolver(host, ProxyServerHostResolver, true)
|
||||
}
|
||||
return ResolveIP(host)
|
||||
}
|
||||
|
||||
func resolveIP(host string, random bool) (netip.Addr, error) {
|
||||
return ResolveIPWithResolver(host, DefaultResolver, random)
|
||||
}
|
||||
|
||||
func resolveIPv4(host string, random bool) (netip.Addr, error) {
|
||||
return ResolveIPv4WithResolver(host, DefaultResolver, random)
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/Dreamacro/clash/component/fakeip"
|
||||
"github.com/Dreamacro/clash/component/geodata"
|
||||
"github.com/Dreamacro/clash/component/geodata/router"
|
||||
_ "github.com/Dreamacro/clash/component/geodata/standard"
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
providerTypes "github.com/Dreamacro/clash/constant/provider"
|
||||
@ -98,12 +99,13 @@ type Profile struct {
|
||||
|
||||
// Tun config
|
||||
type Tun struct {
|
||||
Enable bool `yaml:"enable" json:"enable"`
|
||||
Device string `yaml:"device" json:"device"`
|
||||
Stack C.TUNStack `yaml:"stack" json:"stack"`
|
||||
DNSHijack []C.DNSUrl `yaml:"dns-hijack" json:"dns-hijack"`
|
||||
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
|
||||
AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"`
|
||||
Enable bool `yaml:"enable" json:"enable"`
|
||||
Device string `yaml:"device" json:"device"`
|
||||
Stack C.TUNStack `yaml:"stack" json:"stack"`
|
||||
DNSHijack []C.DNSUrl `yaml:"dns-hijack" json:"dns-hijack"`
|
||||
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
|
||||
AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"`
|
||||
TunAddressPrefix *netip.Prefix `yaml:"_" json:"_"`
|
||||
}
|
||||
|
||||
// IPTables config
|
||||
@ -316,7 +318,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
}
|
||||
config.Hosts = hosts
|
||||
|
||||
dnsCfg, err := parseDNS(rawCfg, hosts, rules)
|
||||
dnsCfg, err := parseDNS(rawCfg, hosts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -674,37 +676,27 @@ func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) {
|
||||
return ipNets, nil
|
||||
}
|
||||
|
||||
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
|
||||
func parseFallbackGeoSite(countries []string) ([]*router.DomainMatcher, error) {
|
||||
var sites []*router.DomainMatcher
|
||||
|
||||
for _, country := range countries {
|
||||
found := false
|
||||
for _, rule := range rules {
|
||||
if rule.RuleType() == C.GEOSITE {
|
||||
if strings.EqualFold(country, rule.Payload()) {
|
||||
found = true
|
||||
sites = append(sites, rule.(C.RuleGeoSite).GetDomainMatcher())
|
||||
log.Infoln("Start initial GeoSite dns fallback filter from rule `%s`", country)
|
||||
}
|
||||
}
|
||||
matcher, recordsCount, err := geodata.LoadProviderByCode(country)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !found {
|
||||
matcher, recordsCount, err := geodata.LoadGeoSiteMatcher(country)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sites = append(sites, matcher)
|
||||
|
||||
sites = append(sites, matcher)
|
||||
|
||||
log.Infoln("Start initial GeoSite dns fallback filter `%s`, records: %d", country, recordsCount)
|
||||
cont := fmt.Sprintf("%d", recordsCount)
|
||||
if recordsCount == 0 {
|
||||
cont = "from cache"
|
||||
}
|
||||
log.Infoln("Start initial GeoSite dns fallback filter `%s`, records: %s", country, cont)
|
||||
}
|
||||
runtime.GC()
|
||||
return sites, nil
|
||||
}
|
||||
|
||||
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr], rules []C.Rule) (*DNS, error) {
|
||||
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr]) (*DNS, error) {
|
||||
cfg := rawCfg.DNS
|
||||
if cfg.Enable && len(cfg.NameServer) == 0 {
|
||||
return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
|
||||
@ -798,7 +790,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr], rules []C.R
|
||||
dnsCfg.FallbackFilter.IPCIDR = fallbackip
|
||||
}
|
||||
dnsCfg.FallbackFilter.Domain = cfg.FallbackFilter.Domain
|
||||
fallbackGeoSite, err := parseFallbackGeoSite(cfg.FallbackFilter.GeoSite, rules)
|
||||
fallbackGeoSite, err := parseFallbackGeoSite(cfg.FallbackFilter.GeoSite)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load GeoSite dns fallback filter error, %w", err)
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func doGet(url string) (resp *http.Response, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
convert.SetUserAgent(req)
|
||||
convert.SetUserAgent(req.Header)
|
||||
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
return
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"runtime"
|
||||
|
||||
"github.com/Dreamacro/clash/component/geodata"
|
||||
_ "github.com/Dreamacro/clash/component/geodata/standard"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
|
||||
"github.com/oschwald/geoip2-golang"
|
||||
|
@ -36,7 +36,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
|
||||
if c.r == nil {
|
||||
return nil, fmt.Errorf("dns %s not a valid ip", c.host)
|
||||
} else {
|
||||
if ip, err = resolver.ResolveIPWithResolver(c.host, c.r); err != nil {
|
||||
if ip, err = resolver.ResolveIPWithResolver(c.host, c.r, true); err != nil {
|
||||
return nil, fmt.Errorf("use default dns resolve failed: %w", err)
|
||||
}
|
||||
c.host = ip.String()
|
||||
|
@ -94,7 +94,7 @@ func newDoHClient(url string, r *Resolver, proxyAdapter string) *dohClient {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ip, err := resolver.ResolveIPWithResolver(host, r)
|
||||
ip, err := resolver.ResolveIPWithResolver(host, r, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ import (
|
||||
"golang.org/x/sync/singleflight"
|
||||
)
|
||||
|
||||
var _ resolver.Resolver = (*Resolver)(nil)
|
||||
|
||||
type dnsClient interface {
|
||||
Exchange(m *D.Msg) (msg *D.Msg, err error)
|
||||
ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error)
|
||||
@ -45,18 +47,18 @@ type Resolver struct {
|
||||
}
|
||||
|
||||
// ResolveIP request with TypeA and TypeAAAA, priority return TypeA
|
||||
func (r *Resolver) ResolveIP(host string) (ip netip.Addr, err error) {
|
||||
func (r *Resolver) ResolveIP(host string, random bool) (ip netip.Addr, err error) {
|
||||
ch := make(chan netip.Addr, 1)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
ip, err := r.resolveIP(host, D.TypeAAAA)
|
||||
ip, err := r.resolveIP(host, D.TypeAAAA, random)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ch <- ip
|
||||
}()
|
||||
|
||||
ip, err = r.resolveIP(host, D.TypeA)
|
||||
ip, err = r.resolveIP(host, D.TypeA, random)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
@ -70,13 +72,13 @@ func (r *Resolver) ResolveIP(host string) (ip netip.Addr, err error) {
|
||||
}
|
||||
|
||||
// ResolveIPv4 request with TypeA
|
||||
func (r *Resolver) ResolveIPv4(host string) (ip netip.Addr, err error) {
|
||||
return r.resolveIP(host, D.TypeA)
|
||||
func (r *Resolver) ResolveIPv4(host string, random bool) (ip netip.Addr, err error) {
|
||||
return r.resolveIP(host, D.TypeA, random)
|
||||
}
|
||||
|
||||
// ResolveIPv6 request with TypeAAAA
|
||||
func (r *Resolver) ResolveIPv6(host string) (ip netip.Addr, err error) {
|
||||
return r.resolveIP(host, D.TypeAAAA)
|
||||
func (r *Resolver) ResolveIPv6(host string, random bool) (ip netip.Addr, err error) {
|
||||
return r.resolveIP(host, D.TypeAAAA, random)
|
||||
}
|
||||
|
||||
func (r *Resolver) shouldIPFallback(ip netip.Addr) bool {
|
||||
@ -255,9 +257,10 @@ func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err er
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Resolver) resolveIP(host string, dnsType uint16) (ip netip.Addr, err error) {
|
||||
func (r *Resolver) resolveIP(host string, dnsType uint16, random bool) (ip netip.Addr, err error) {
|
||||
ip, err = netip.ParseAddr(host)
|
||||
if err == nil {
|
||||
ip = ip.Unmap()
|
||||
isIPv4 := ip.Is4()
|
||||
if dnsType == D.TypeAAAA && !isIPv4 {
|
||||
return ip, nil
|
||||
@ -282,7 +285,12 @@ func (r *Resolver) resolveIP(host string, dnsType uint16) (ip netip.Addr, err er
|
||||
return netip.Addr{}, resolver.ErrIPNotFound
|
||||
}
|
||||
|
||||
ip = ips[rand.Intn(ipLength)]
|
||||
index := 0
|
||||
if random {
|
||||
index = rand.Intn(ipLength)
|
||||
}
|
||||
|
||||
ip = ips[index]
|
||||
return
|
||||
}
|
||||
|
||||
|
16
go.mod
16
go.mod
@ -9,26 +9,26 @@ require (
|
||||
github.com/gofrs/uuid v4.2.0+incompatible
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f
|
||||
github.com/miekg/dns v1.1.49
|
||||
github.com/miekg/dns v1.1.50
|
||||
github.com/oschwald/geoip2-golang v1.7.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/stretchr/testify v1.7.2
|
||||
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
go.uber.org/atomic v1.9.0
|
||||
go.uber.org/automaxprocs v1.5.1
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
|
||||
golang.org/x/exp v0.0.0-20220602145555-4a0574d9293f
|
||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
||||
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b
|
||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858
|
||||
golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4
|
||||
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e
|
||||
google.golang.org/protobuf v1.28.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gvisor.dev/gvisor v0.0.0-20220601233344-46e478629075
|
||||
gvisor.dev/gvisor v0.0.0-20220630235058-ce952880a3d3
|
||||
)
|
||||
|
||||
require (
|
||||
|
34
go.sum
34
go.sum
@ -20,7 +20,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
@ -45,8 +45,8 @@ github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcK
|
||||
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
|
||||
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||
github.com/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8=
|
||||
github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/oschwald/geoip2-golang v1.7.0 h1:JW1r5AKi+vv2ujSxjKthySK3jo8w8oKWPyXsw+Qs/S8=
|
||||
github.com/oschwald/geoip2-golang v1.7.0/go.mod h1:mdI/C7iK7NVMcIDDtf4bCKMJ7r0o7UwGeCo9eiitCMQ=
|
||||
github.com/oschwald/maxminddb-golang v1.9.0 h1:tIk4nv6VT9OiPyrnDAfJS1s1xKDQMZOsGojab6EjC1Y=
|
||||
@ -62,8 +62,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
||||
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 h1:4mkzGhKqt3JO1BWYjtD3iRFyAx4ow67hmSqOcGjuxqQ=
|
||||
@ -78,10 +78,10 @@ go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
|
||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20220602145555-4a0574d9293f h1:KK6mxegmt5hGJRcAnEDjSNLxIRhZxDcgwMbcO/lMCRM=
|
||||
golang.org/x/exp v0.0.0-20220602145555-4a0574d9293f/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d h1:vtUKgx8dahOomfFzLREU8nSv25YHnTgLBn4rDnWZdU0=
|
||||
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
@ -97,8 +97,8 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
|
||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||
@ -123,16 +123,16 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8=
|
||||
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab h1:eHo2TTVBaAPw9lDGK2Gb9GyPMXT6g7O63W6sx3ylbzU=
|
||||
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@ -158,5 +158,5 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gvisor.dev/gvisor v0.0.0-20220601233344-46e478629075 h1:ucwwit0X39HmMQ1iSeNCIXw4g/B8bi+O6TSxxDbPs9E=
|
||||
gvisor.dev/gvisor v0.0.0-20220601233344-46e478629075/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||
gvisor.dev/gvisor v0.0.0-20220630235058-ce952880a3d3 h1:rnajnEGeshXCEr3k/7pWAM6zXh1Ws4jkZgWuWXjCJSw=
|
||||
gvisor.dev/gvisor v0.0.0-20220630235058-ce952880a3d3/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||
|
@ -82,7 +82,7 @@ func ApplyConfig(cfg *config.Config, force bool) {
|
||||
updateHosts(cfg.Hosts)
|
||||
updateMitm(cfg.Mitm)
|
||||
updateProfile(cfg)
|
||||
updateDNS(cfg.DNS, cfg.General.Tun)
|
||||
updateDNS(cfg.DNS, &cfg.General.Tun)
|
||||
updateGeneral(cfg.General, force)
|
||||
updateIPTables(cfg)
|
||||
updateExperimental(cfg)
|
||||
@ -121,7 +121,7 @@ func GetGeneral() *config.General {
|
||||
|
||||
func updateExperimental(_ *config.Config) {}
|
||||
|
||||
func updateDNS(c *config.DNS, t config.Tun) {
|
||||
func updateDNS(c *config.DNS, t *config.Tun) {
|
||||
cfg := dns.Config{
|
||||
Main: c.NameServer,
|
||||
Fallback: c.Fallback,
|
||||
@ -141,6 +141,11 @@ func updateDNS(c *config.DNS, t config.Tun) {
|
||||
ProxyServer: c.ProxyServerNameserver,
|
||||
}
|
||||
|
||||
// deprecated warnning
|
||||
if cfg.EnhancedMode == C.DNSMapping {
|
||||
log.Warnln("[DNS] %s is deprecated, please use %s instead", cfg.EnhancedMode.String(), C.DNSFakeIP.String())
|
||||
}
|
||||
|
||||
r := dns.NewResolver(cfg)
|
||||
pr := dns.NewProxyServerHostResolver(r)
|
||||
m := dns.NewEnhancer(cfg)
|
||||
@ -174,7 +179,7 @@ func updateDNS(c *config.DNS, t config.Tun) {
|
||||
}
|
||||
|
||||
if cfg.Pool != nil {
|
||||
P.SetTunAddressPrefix(cfg.Pool.IPNet())
|
||||
t.TunAddressPrefix = cfg.Pool.IPNet()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,13 +169,13 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
|
||||
if req.Payload != "" {
|
||||
log.Warnln("[REST-API] update config by payload")
|
||||
cfg, err = executor.ParseWithBytes([]byte(req.Payload))
|
||||
if err != nil {
|
||||
render.Status(r, http.StatusBadRequest)
|
||||
render.JSON(w, r, newError(err.Error()))
|
||||
return
|
||||
}
|
||||
log.Warnln("[REST-API] update config by payload")
|
||||
} else {
|
||||
if req.Path == "" {
|
||||
req.Path = constant.Path.Config()
|
||||
@ -186,13 +186,13 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Warnln("[REST-API] reload config from path: %s", req.Path)
|
||||
cfg, err = executor.ParseWithPath(req.Path)
|
||||
if err != nil {
|
||||
render.Status(r, http.StatusBadRequest)
|
||||
render.JSON(w, r, newError(err.Error()))
|
||||
return
|
||||
}
|
||||
log.Warnln("[REST-API] reload config from path: %s", req.Path)
|
||||
}
|
||||
|
||||
executor.ApplyConfig(cfg, force)
|
||||
|
@ -31,11 +31,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
allowLan = false
|
||||
bindAddress = "*"
|
||||
lastTunConf *config.Tun
|
||||
lastTunAddressPrefix *netip.Prefix
|
||||
tunAddressPrefix *netip.Prefix
|
||||
allowLan = false
|
||||
bindAddress = "*"
|
||||
lastTunConf *config.Tun
|
||||
|
||||
socksListener *socks.Listener
|
||||
socksUDPListener *socks.UDPListener
|
||||
@ -109,10 +107,6 @@ func SetBindAddress(host string) {
|
||||
bindAddress = host
|
||||
}
|
||||
|
||||
func SetTunAddressPrefix(tunAddress *netip.Prefix) {
|
||||
tunAddressPrefix = tunAddress
|
||||
}
|
||||
|
||||
func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) {
|
||||
httpMux.Lock()
|
||||
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)
|
||||
|
||||
if tunStackListener != nil {
|
||||
if !hasTunConfigChange(tunConf, tunAddressPrefix) {
|
||||
if !hasTunConfigChange(tunConf) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -379,7 +369,6 @@ func ReCreateTun(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *
|
||||
}
|
||||
|
||||
lastTunConf = tunConf
|
||||
lastTunAddressPrefix = tunAddressPrefix
|
||||
|
||||
if !tunConf.Enable {
|
||||
return
|
||||
@ -391,7 +380,7 @@ func ReCreateTun(tunConf *config.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- *
|
||||
udpIn: udpIn,
|
||||
}
|
||||
|
||||
tunStackListener, err = tun.New(tunConf, tunAddressPrefix, tcpIn, udpIn, callback)
|
||||
tunStackListener, err = tun.New(tunConf, tcpIn, udpIn, callback)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -535,7 +524,7 @@ func genAddr(host string, port int, allowLan bool) string {
|
||||
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 {
|
||||
return true
|
||||
}
|
||||
@ -558,11 +547,11 @@ func hasTunConfigChange(tunConf *config.Tun, tunAddressPrefix *netip.Prefix) boo
|
||||
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
|
||||
}
|
||||
|
||||
if tunAddressPrefix != nil && lastTunAddressPrefix != nil && *tunAddressPrefix != *lastTunAddressPrefix {
|
||||
if lastTunConf.TunAddressPrefix != nil && tunConf.TunAddressPrefix != nil && *lastTunConf.TunAddressPrefix != *tunConf.TunAddressPrefix {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,13 @@ package tproxy
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
type packet struct {
|
||||
lAddr *net.UDPAddr
|
||||
lAddr netip.AddrPort
|
||||
buf []byte
|
||||
}
|
||||
|
||||
@ -17,21 +18,21 @@ func (c *packet) Data() []byte {
|
||||
|
||||
// WriteBack opens a new socket binding `addr` to write UDP packet back
|
||||
func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
||||
tc, err := dialUDP("udp", addr.(*net.UDPAddr), c.lAddr)
|
||||
tc, err := dialUDP("udp", addr.(*net.UDPAddr).AddrPort(), c.lAddr)
|
||||
if err != nil {
|
||||
n = 0
|
||||
return
|
||||
}
|
||||
n, err = tc.Write(b)
|
||||
tc.Close()
|
||||
_ = tc.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// LocalAddr returns the source IP/Port of UDP Packet
|
||||
func (c *packet) LocalAddr() net.Addr {
|
||||
return c.lAddr
|
||||
return net.UDPAddrFromAddrPort(c.lAddr)
|
||||
}
|
||||
|
||||
func (c *packet) Drop() {
|
||||
pool.Put(c.buf)
|
||||
_ = pool.Put(c.buf)
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func (l *Listener) Close() error {
|
||||
|
||||
func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext) {
|
||||
target := socks5.ParseAddrToSocksAddr(conn.LocalAddr())
|
||||
conn.(*net.TCPConn).SetKeepAlive(true)
|
||||
_ = conn.(*net.TCPConn).SetKeepAlive(true)
|
||||
in <- inbound.NewSocket(target, conn, C.TPROXY)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package tproxy
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
@ -58,28 +59,33 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
|
||||
oob := make([]byte, 1024)
|
||||
for {
|
||||
buf := pool.Get(pool.UDPBufferSize)
|
||||
n, oobn, _, lAddr, err := c.ReadMsgUDP(buf, oob)
|
||||
n, oobn, _, lAddr, err := c.ReadMsgUDPAddrPort(buf, oob)
|
||||
if err != nil {
|
||||
pool.Put(buf)
|
||||
_ = pool.Put(buf)
|
||||
if rl.closed {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
rAddr, err := getOrigDst(oob, oobn)
|
||||
rAddr, err := getOrigDst(oob[:oobn])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
handlePacketConn(l, in, buf[:n], lAddr, rAddr)
|
||||
|
||||
if rAddr.Addr().Is4() {
|
||||
// try to unmap 4in6 address
|
||||
lAddr = netip.AddrPortFrom(lAddr.Addr().Unmap(), lAddr.Port())
|
||||
}
|
||||
handlePacketConn(in, buf[:n], lAddr, rAddr)
|
||||
}
|
||||
}()
|
||||
|
||||
return rl, nil
|
||||
}
|
||||
|
||||
func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
|
||||
target := socks5.ParseAddrToSocksAddr(rAddr)
|
||||
func handlePacketConn(in chan<- *inbound.PacketAdapter, buf []byte, lAddr, rAddr netip.AddrPort) {
|
||||
target := socks5.AddrFromStdAddrPort(rAddr)
|
||||
pkt := &packet{
|
||||
lAddr: lAddr,
|
||||
buf: buf,
|
||||
|
@ -3,13 +3,14 @@
|
||||
package tproxy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -19,7 +20,7 @@ const (
|
||||
|
||||
// dialUDP acts like net.DialUDP for transparent proxy.
|
||||
// It binds to a non-local address(`lAddr`).
|
||||
func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
func dialUDP(network string, lAddr, rAddr netip.AddrPort) (uc *net.UDPConn, err error) {
|
||||
rSockAddr, err := udpAddrToSockAddr(rAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -35,23 +36,25 @@ func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPCo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
syscall.Close(fd)
|
||||
}
|
||||
}()
|
||||
|
||||
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = syscall.Bind(fd, lSockAddr); err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = syscall.Connect(fd, rSockAddr); err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -60,35 +63,26 @@ func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPCo
|
||||
|
||||
c, err := net.FileConn(fdFile)
|
||||
if err != nil {
|
||||
syscall.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.(*net.UDPConn), nil
|
||||
}
|
||||
|
||||
func udpAddrToSockAddr(addr *net.UDPAddr) (syscall.Sockaddr, error) {
|
||||
switch {
|
||||
case addr.IP.To4() != nil:
|
||||
ip := [4]byte{}
|
||||
copy(ip[:], addr.IP.To4())
|
||||
|
||||
return &syscall.SockaddrInet4{Addr: ip, Port: addr.Port}, nil
|
||||
|
||||
default:
|
||||
ip := [16]byte{}
|
||||
copy(ip[:], addr.IP.To16())
|
||||
|
||||
zoneID, err := strconv.ParseUint(addr.Zone, 10, 32)
|
||||
if err != nil {
|
||||
zoneID = 0
|
||||
}
|
||||
|
||||
return &syscall.SockaddrInet6{Addr: ip, Port: addr.Port, ZoneId: uint32(zoneID)}, nil
|
||||
func udpAddrToSockAddr(addr netip.AddrPort) (syscall.Sockaddr, error) {
|
||||
if addr.Addr().Is4() {
|
||||
return &syscall.SockaddrInet4{Addr: addr.Addr().As4(), Port: int(addr.Port())}, nil
|
||||
}
|
||||
|
||||
zoneID, err := strconv.ParseUint(addr.Addr().Zone(), 10, 32)
|
||||
if err != nil {
|
||||
zoneID = 0
|
||||
}
|
||||
|
||||
return &syscall.SockaddrInet6{Addr: addr.Addr().As16(), Port: int(addr.Port()), ZoneId: uint32(zoneID)}, nil
|
||||
}
|
||||
|
||||
func udpAddrFamily(net string, lAddr, rAddr *net.UDPAddr) int {
|
||||
func udpAddrFamily(net string, lAddr, rAddr netip.AddrPort) int {
|
||||
switch net[len(net)-1] {
|
||||
case '4':
|
||||
return syscall.AF_INET
|
||||
@ -96,29 +90,35 @@ func udpAddrFamily(net string, lAddr, rAddr *net.UDPAddr) int {
|
||||
return syscall.AF_INET6
|
||||
}
|
||||
|
||||
if (lAddr == nil || lAddr.IP.To4() != nil) && (rAddr == nil || lAddr.IP.To4() != nil) {
|
||||
if lAddr.Addr().Is4() && rAddr.Addr().Is4() {
|
||||
return syscall.AF_INET
|
||||
}
|
||||
return syscall.AF_INET6
|
||||
}
|
||||
|
||||
func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
|
||||
msgs, err := syscall.ParseSocketControlMessage(oob[:oobn])
|
||||
func getOrigDst(oob []byte) (netip.AddrPort, error) {
|
||||
// oob contains socket control messages which we need to parse.
|
||||
scms, err := unix.ParseSocketControlMessage(oob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return netip.AddrPort{}, fmt.Errorf("parse control message: %w", err)
|
||||
}
|
||||
|
||||
for _, msg := range msgs {
|
||||
if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR {
|
||||
ip := net.IP(msg.Data[4:8])
|
||||
port := binary.BigEndian.Uint16(msg.Data[2:4])
|
||||
return &net.UDPAddr{IP: ip, Port: int(port)}, nil
|
||||
} else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == IPV6_RECVORIGDSTADDR {
|
||||
ip := net.IP(msg.Data[8:24])
|
||||
port := binary.BigEndian.Uint16(msg.Data[2:4])
|
||||
return &net.UDPAddr{IP: ip, Port: int(port)}, nil
|
||||
}
|
||||
// retrieve the destination address from the SCM.
|
||||
sa, err := unix.ParseOrigDstAddr(&scms[0])
|
||||
if err != nil {
|
||||
return netip.AddrPort{}, fmt.Errorf("retrieve destination: %w", err)
|
||||
}
|
||||
|
||||
return nil, errors.New("cannot find origDst")
|
||||
// encode the destination address into a cmsg.
|
||||
var rAddr netip.AddrPort
|
||||
switch v := sa.(type) {
|
||||
case *unix.SockaddrInet4:
|
||||
rAddr = netip.AddrPortFrom(netip.AddrFrom4(v.Addr), uint16(v.Port))
|
||||
case *unix.SockaddrInet6:
|
||||
rAddr = netip.AddrPortFrom(netip.AddrFrom16(v.Addr), uint16(v.Port))
|
||||
default:
|
||||
return netip.AddrPort{}, fmt.Errorf("unsupported address type: %T", v)
|
||||
}
|
||||
|
||||
return rAddr, nil
|
||||
}
|
||||
|
@ -5,12 +5,13 @@ package tproxy
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
|
||||
return nil, errors.New("UDP redir not supported on current platform")
|
||||
func getOrigDst(oob []byte) (netip.AddrPort, error) {
|
||||
return netip.AddrPort{}, errors.New("UDP redir not supported on current platform")
|
||||
}
|
||||
|
||||
func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||
func dialUDP(network string, lAddr, rAddr netip.AddrPort) (*net.UDPConn, error) {
|
||||
return nil, errors.New("UDP redir not supported on current platform")
|
||||
}
|
||||
|
@ -41,6 +41,10 @@ func (f *FD) Name() string {
|
||||
return strconv.Itoa(f.fd)
|
||||
}
|
||||
|
||||
func (f *FD) MTU() uint32 {
|
||||
return f.mtu
|
||||
}
|
||||
|
||||
func (f *FD) Close() error {
|
||||
err := unix.Close(f.fd)
|
||||
if f.file != nil {
|
||||
|
@ -4,8 +4,48 @@ import (
|
||||
"errors"
|
||||
|
||||
"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")
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -8,8 +8,10 @@ import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/channel"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
@ -93,23 +95,29 @@ func (e *Endpoint) dispatchLoop(cancel context.CancelFunc) {
|
||||
|
||||
mtu := int(e.mtu)
|
||||
for {
|
||||
data := make([]byte, mtu)
|
||||
data := pool.Get(mtu)
|
||||
|
||||
n, err := e.rw.Read(data)
|
||||
if err != nil {
|
||||
_ = pool.Put(data)
|
||||
break
|
||||
}
|
||||
|
||||
if n == 0 || n > mtu {
|
||||
_ = pool.Put(data)
|
||||
continue
|
||||
}
|
||||
|
||||
if !e.IsAttached() {
|
||||
_ = pool.Put(data)
|
||||
continue /* unattached, drop packet */
|
||||
}
|
||||
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: buffer.View(data[:n]).ToVectorisedView(),
|
||||
Payload: buffer.NewWithData(data[:n]),
|
||||
OnRelease: func() {
|
||||
_ = pool.Put(data)
|
||||
},
|
||||
})
|
||||
|
||||
switch header.IPVersion(data) {
|
||||
@ -117,6 +125,8 @@ func (e *Endpoint) dispatchLoop(cancel context.CancelFunc) {
|
||||
e.InjectInbound(header.IPv4ProtocolNumber, pkt)
|
||||
case header.IPv6Version:
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, pkt)
|
||||
default:
|
||||
_ = pool.Put(data)
|
||||
}
|
||||
pkt.DecRef()
|
||||
}
|
||||
@ -138,11 +148,8 @@ func (e *Endpoint) outboundLoop(ctx context.Context) {
|
||||
func (e *Endpoint) writePacket(pkt *stack.PacketBuffer) tcpip.Error {
|
||||
defer pkt.DecRef()
|
||||
|
||||
size := pkt.Size()
|
||||
views := pkt.Views()
|
||||
|
||||
vView := buffer.NewVectorisedView(size, views)
|
||||
if _, err := e.rw.Write(vView.ToView()); err != nil {
|
||||
buf := pkt.Buffer()
|
||||
if _, err := e.rw.Write(buf.Flatten()); err != nil {
|
||||
return &tcpip.ErrInvalidEndpointState{}
|
||||
}
|
||||
return nil
|
||||
|
@ -48,20 +48,20 @@ import (
|
||||
//go:linkname procWintunStartSession golang.zx2c4.com/wintun.procWintunStartSession
|
||||
|
||||
var (
|
||||
modwintun *lazyDLL
|
||||
procWintunCreateAdapter *lazyProc
|
||||
procWintunOpenAdapter *lazyProc
|
||||
procWintunCloseAdapter *lazyProc
|
||||
procWintunDeleteDriver *lazyProc
|
||||
procWintunGetAdapterLUID *lazyProc
|
||||
procWintunGetRunningDriverVersion *lazyProc
|
||||
procWintunAllocateSendPacket *lazyProc
|
||||
procWintunEndSession *lazyProc
|
||||
procWintunGetReadWaitEvent *lazyProc
|
||||
procWintunReceivePacket *lazyProc
|
||||
procWintunReleaseReceivePacket *lazyProc
|
||||
procWintunSendPacket *lazyProc
|
||||
procWintunStartSession *lazyProc
|
||||
modwintun = newLazyDLL("wintun.dll", setupLogger)
|
||||
procWintunCreateAdapter = modwintun.NewProc("WintunCreateAdapter")
|
||||
procWintunOpenAdapter = modwintun.NewProc("WintunOpenAdapter")
|
||||
procWintunCloseAdapter = modwintun.NewProc("WintunCloseAdapter")
|
||||
procWintunDeleteDriver = modwintun.NewProc("WintunDeleteDriver")
|
||||
procWintunGetAdapterLUID = modwintun.NewProc("WintunGetAdapterLUID")
|
||||
procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion")
|
||||
procWintunAllocateSendPacket = modwintun.NewProc("WintunAllocateSendPacket")
|
||||
procWintunEndSession = modwintun.NewProc("WintunEndSession")
|
||||
procWintunGetReadWaitEvent = modwintun.NewProc("WintunGetReadWaitEvent")
|
||||
procWintunReceivePacket = modwintun.NewProc("WintunReceivePacket")
|
||||
procWintunReleaseReceivePacket = modwintun.NewProc("WintunReleaseReceivePacket")
|
||||
procWintunSendPacket = modwintun.NewProc("WintunSendPacket")
|
||||
procWintunStartSession = modwintun.NewProc("WintunStartSession")
|
||||
)
|
||||
|
||||
type loggerLevel int
|
||||
@ -72,23 +72,6 @@ const (
|
||||
logErr
|
||||
)
|
||||
|
||||
func init() {
|
||||
modwintun = newLazyDLL("wintun.dll", setupLogger)
|
||||
procWintunCreateAdapter = modwintun.NewProc("WintunCreateAdapter")
|
||||
procWintunOpenAdapter = modwintun.NewProc("WintunOpenAdapter")
|
||||
procWintunCloseAdapter = modwintun.NewProc("WintunCloseAdapter")
|
||||
procWintunDeleteDriver = modwintun.NewProc("WintunDeleteDriver")
|
||||
procWintunGetAdapterLUID = modwintun.NewProc("WintunGetAdapterLUID")
|
||||
procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion")
|
||||
procWintunAllocateSendPacket = modwintun.NewProc("WintunAllocateSendPacket")
|
||||
procWintunEndSession = modwintun.NewProc("WintunEndSession")
|
||||
procWintunGetReadWaitEvent = modwintun.NewProc("WintunGetReadWaitEvent")
|
||||
procWintunReceivePacket = modwintun.NewProc("WintunReceivePacket")
|
||||
procWintunReleaseReceivePacket = modwintun.NewProc("WintunReleaseReceivePacket")
|
||||
procWintunSendPacket = modwintun.NewProc("WintunSendPacket")
|
||||
procWintunStartSession = modwintun.NewProc("WintunStartSession")
|
||||
}
|
||||
|
||||
func InitWintun() (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
@ -59,10 +59,13 @@ func Open(name string, mtu uint32) (_ device.Device, err error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get mtu: %w", err)
|
||||
}
|
||||
t.mtu = uint32(tunMTU)
|
||||
|
||||
if t.mtu == 0 {
|
||||
t.mtu = uint32(tunMTU)
|
||||
}
|
||||
|
||||
if t.offset > 0 {
|
||||
t.cache = make([]byte, 65535)
|
||||
t.cache = make([]byte, int(t.mtu)+t.offset)
|
||||
}
|
||||
|
||||
return t, nil
|
||||
@ -87,7 +90,11 @@ func (t *TUN) Write(packet []byte) (int, error) {
|
||||
|
||||
packet = append(t.cache[:t.offset], packet...)
|
||||
|
||||
return t.nt.Write(packet, t.offset)
|
||||
n, err := t.nt.Write(packet, t.offset)
|
||||
if n < t.offset {
|
||||
return 0, err
|
||||
}
|
||||
return n - t.offset, err
|
||||
}
|
||||
|
||||
func (t *TUN) Close() error {
|
||||
@ -104,6 +111,10 @@ func (t *TUN) Name() string {
|
||||
return name
|
||||
}
|
||||
|
||||
func (t *TUN) MTU() uint32 {
|
||||
return t.mtu
|
||||
}
|
||||
|
||||
func (t *TUN) UseEndpoint() error {
|
||||
ep, err := iobased.New(t, t.mtu, t.offset)
|
||||
if err != nil {
|
||||
|
@ -2,23 +2,15 @@ package adapter
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
// TCPConn implements the net.Conn interface.
|
||||
type TCPConn interface {
|
||||
net.Conn
|
||||
|
||||
// ID returns the transport endpoint id of TCPConn.
|
||||
ID() *stack.TransportEndpointID
|
||||
}
|
||||
|
||||
// UDPConn implements net.Conn and net.PacketConn.
|
||||
type UDPConn interface {
|
||||
net.Conn
|
||||
net.PacketConn
|
||||
|
||||
// ID returns the transport endpoint id of UDPConn.
|
||||
ID() *stack.TransportEndpointID
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
||||
@ -27,15 +26,7 @@ type gvHandler struct {
|
||||
}
|
||||
|
||||
func (gh *gvHandler) HandleTCP(tunConn adapter.TCPConn) {
|
||||
id := tunConn.ID()
|
||||
|
||||
rAddr := &net.UDPAddr{
|
||||
IP: net.IP(id.LocalAddress),
|
||||
Port: int(id.LocalPort),
|
||||
Zone: "",
|
||||
}
|
||||
|
||||
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), id.LocalPort)
|
||||
rAddrPort := tunConn.LocalAddr().(*net.TCPAddr).AddrPort()
|
||||
|
||||
if D.ShouldHijackDns(gh.dnsHijack, rAddrPort, "tcp") {
|
||||
go func() {
|
||||
@ -43,8 +34,8 @@ func (gh *gvHandler) HandleTCP(tunConn adapter.TCPConn) {
|
||||
|
||||
buf := pool.Get(pool.UDPBufferSize)
|
||||
defer func() {
|
||||
_ = pool.Put(buf)
|
||||
_ = tunConn.Close()
|
||||
_ = pool.Put(buf)
|
||||
}()
|
||||
|
||||
for {
|
||||
@ -78,26 +69,18 @@ func (gh *gvHandler) HandleTCP(tunConn adapter.TCPConn) {
|
||||
return
|
||||
}
|
||||
|
||||
gh.tcpIn <- inbound.NewSocket(socks5.ParseAddrToSocksAddr(rAddr), tunConn, C.TUN)
|
||||
gh.tcpIn <- inbound.NewSocket(socks5.AddrFromStdAddrPort(rAddrPort), tunConn, C.TUN)
|
||||
}
|
||||
|
||||
func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
|
||||
id := tunConn.ID()
|
||||
|
||||
rAddr := &net.UDPAddr{
|
||||
IP: net.IP(id.LocalAddress),
|
||||
Port: int(id.LocalPort),
|
||||
Zone: "",
|
||||
}
|
||||
|
||||
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), id.LocalPort)
|
||||
rAddrPort := tunConn.LocalAddr().(*net.UDPAddr).AddrPort()
|
||||
|
||||
if rAddrPort.Addr() == gh.gateway {
|
||||
_ = tunConn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
target := socks5.ParseAddrToSocksAddr(rAddr)
|
||||
target := socks5.AddrFromStdAddrPort(rAddrPort)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
@ -109,22 +92,20 @@ func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
|
||||
break
|
||||
}
|
||||
|
||||
payload := buf[:n]
|
||||
|
||||
if D.ShouldHijackDns(gh.dnsHijack, rAddrPort, "udp") {
|
||||
go func() {
|
||||
defer func() {
|
||||
_ = pool.Put(buf)
|
||||
}()
|
||||
|
||||
msg, err1 := D.RelayDnsPacket(payload)
|
||||
msg, err1 := D.RelayDnsPacket(buf[:n])
|
||||
if err1 != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = tunConn.WriteTo(msg, addr)
|
||||
|
||||
log.Debugln("[TUN] hijack dns udp: %s", rAddr.String())
|
||||
log.Debugln("[TUN] hijack dns udp: %s", rAddrPort.String())
|
||||
}()
|
||||
|
||||
continue
|
||||
@ -133,12 +114,14 @@ func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
|
||||
gvPacket := &packet{
|
||||
pc: tunConn,
|
||||
rAddr: addr,
|
||||
payload: payload,
|
||||
payload: buf,
|
||||
offset: n,
|
||||
}
|
||||
|
||||
select {
|
||||
case gh.udpIn <- inbound.NewPacket(target, gvPacket, C.TUN):
|
||||
default:
|
||||
gvPacket.Drop()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -70,7 +70,6 @@ func withTCPHandler(handle adapter.TCPHandleFunc) option.Option {
|
||||
|
||||
conn := &tcpConn{
|
||||
TCPConn: gonet.NewTCPConn(&wq, ep),
|
||||
id: id,
|
||||
}
|
||||
handle(conn)
|
||||
})
|
||||
@ -113,9 +112,4 @@ func setSocketOptions(s *stack.Stack, ep tcpip.Endpoint) tcpip.Error {
|
||||
|
||||
type tcpConn struct {
|
||||
*gonet.TCPConn
|
||||
id stack.TransportEndpointID
|
||||
}
|
||||
|
||||
func (c *tcpConn) ID() *stack.TransportEndpointID {
|
||||
return &c.id
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ func withUDPHandler(handle adapter.UDPHandleFunc) option.Option {
|
||||
|
||||
conn := &udpConn{
|
||||
UDPConn: gonet.NewUDPConn(s, &wq, ep),
|
||||
id: id,
|
||||
}
|
||||
handle(conn)
|
||||
})
|
||||
@ -40,21 +39,17 @@ func withUDPHandler(handle adapter.UDPHandleFunc) option.Option {
|
||||
|
||||
type udpConn struct {
|
||||
*gonet.UDPConn
|
||||
id stack.TransportEndpointID
|
||||
}
|
||||
|
||||
func (c *udpConn) ID() *stack.TransportEndpointID {
|
||||
return &c.id
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
pc adapter.UDPConn
|
||||
rAddr net.Addr
|
||||
payload []byte
|
||||
offset int
|
||||
}
|
||||
|
||||
func (c *packet) Data() []byte {
|
||||
return c.payload
|
||||
return c.payload[:c.offset]
|
||||
}
|
||||
|
||||
// WriteBack write UDP packet with source(ip, port) = `addr`
|
||||
|
@ -5,7 +5,9 @@ import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
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"
|
||||
)
|
||||
|
||||
@ -19,10 +21,27 @@ func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *
|
||||
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()
|
||||
udp := &UDP{
|
||||
device: device,
|
||||
buf: [pool.UDPBufferSize]byte{},
|
||||
buf: make([]byte, bufferSize),
|
||||
}
|
||||
tcp := &TCP{
|
||||
listener: listener,
|
||||
@ -38,7 +57,7 @@ func Start(device io.ReadWriter, gateway, portal, broadcast netip.Addr) (*TCP, *
|
||||
_ = udp.Close()
|
||||
}()
|
||||
|
||||
buf := make([]byte, pool.RelayBufferSize)
|
||||
buf := make([]byte, bufferSize)
|
||||
|
||||
for {
|
||||
n, err := device.Read(buf)
|
||||
|
@ -24,9 +24,9 @@ func (t *TCP) Accept() (net.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
addr := c.RemoteAddr().(*net.TCPAddr)
|
||||
tup := t.table.tupleOf(uint16(addr.Port))
|
||||
if !addr.IP.Equal(t.portal.AsSlice()) || tup == zeroTuple {
|
||||
addr := c.RemoteAddr().(*net.TCPAddr).AddrPort()
|
||||
tup := t.table.tupleOf(addr.Port())
|
||||
if addr.Addr() != t.portal || tup == zeroTuple {
|
||||
_ = c.Close()
|
||||
|
||||
return nil, net.InvalidAddrError("unknown remote addr")
|
||||
@ -34,6 +34,8 @@ func (t *TCP) Accept() (net.Conn, error) {
|
||||
|
||||
addition(c)
|
||||
|
||||
_ = c.SetLinger(0)
|
||||
|
||||
return &conn{
|
||||
Conn: c,
|
||||
tuple: tup,
|
||||
@ -52,16 +54,14 @@ func (t *TCP) SetDeadline(time time.Time) error {
|
||||
return t.listener.SetDeadline(time)
|
||||
}
|
||||
|
||||
func (c *conn) Close() error {
|
||||
return c.Conn.Close()
|
||||
}
|
||||
|
||||
func (c *conn) LocalAddr() net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: c.tuple.SourceAddr.Addr().AsSlice(),
|
||||
Port: int(c.tuple.SourceAddr.Port()),
|
||||
}
|
||||
return net.TCPAddrFromAddrPort(c.tuple.SourceAddr)
|
||||
}
|
||||
|
||||
func (c *conn) RemoteAddr() net.Addr {
|
||||
return &net.TCPAddr{
|
||||
IP: c.tuple.DestinationAddr.Addr().AsSlice(),
|
||||
Port: int(c.tuple.DestinationAddr.Port()),
|
||||
}
|
||||
return net.TCPAddrFromAddrPort(c.tuple.DestinationAddr)
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ import (
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
"github.com/Dreamacro/clash/common/nnip"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/tcpip"
|
||||
)
|
||||
|
||||
@ -16,8 +14,8 @@ type call struct {
|
||||
cond *sync.Cond
|
||||
buf []byte
|
||||
n int
|
||||
source net.Addr
|
||||
destination net.Addr
|
||||
source netip.AddrPort
|
||||
destination netip.AddrPort
|
||||
}
|
||||
|
||||
type UDP struct {
|
||||
@ -26,10 +24,10 @@ type UDP struct {
|
||||
queueLock sync.Mutex
|
||||
queue []*call
|
||||
bufLock sync.Mutex
|
||||
buf [pool.UDPBufferSize]byte
|
||||
buf []byte
|
||||
}
|
||||
|
||||
func (u *UDP) ReadFrom(buf []byte) (int, net.Addr, net.Addr, error) {
|
||||
func (u *UDP) ReadFrom(buf []byte) (int, netip.AddrPort, netip.AddrPort, error) {
|
||||
u.queueLock.Lock()
|
||||
defer u.queueLock.Unlock()
|
||||
|
||||
@ -38,8 +36,8 @@ func (u *UDP) ReadFrom(buf []byte) (int, net.Addr, net.Addr, error) {
|
||||
cond: sync.NewCond(&u.queueLock),
|
||||
buf: buf,
|
||||
n: -1,
|
||||
source: nil,
|
||||
destination: nil,
|
||||
source: netip.AddrPort{},
|
||||
destination: netip.AddrPort{},
|
||||
}
|
||||
|
||||
u.queue = append(u.queue, c)
|
||||
@ -51,10 +49,10 @@ func (u *UDP) ReadFrom(buf []byte) (int, net.Addr, net.Addr, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return -1, nil, nil, net.ErrClosed
|
||||
return -1, netip.AddrPort{}, netip.AddrPort{}, net.ErrClosed
|
||||
}
|
||||
|
||||
func (u *UDP) WriteTo(buf []byte, local net.Addr, remote net.Addr) (int, error) {
|
||||
func (u *UDP) WriteTo(buf []byte, local netip.AddrPort, remote netip.AddrPort) (int, error) {
|
||||
if u.closed {
|
||||
return 0, net.ErrClosed
|
||||
}
|
||||
@ -66,16 +64,7 @@ func (u *UDP) WriteTo(buf []byte, local net.Addr, remote net.Addr) (int, error)
|
||||
return 0, net.InvalidAddrError("invalid ip version")
|
||||
}
|
||||
|
||||
srcAddr, srcOk := local.(*net.UDPAddr)
|
||||
dstAddr, dstOk := remote.(*net.UDPAddr)
|
||||
if !srcOk || !dstOk {
|
||||
return 0, net.InvalidAddrError("invalid addr")
|
||||
}
|
||||
|
||||
srcAddrPort := netip.AddrPortFrom(nnip.IpToAddr(srcAddr.IP), uint16(srcAddr.Port))
|
||||
dstAddrPort := netip.AddrPortFrom(nnip.IpToAddr(dstAddr.IP), uint16(dstAddr.Port))
|
||||
|
||||
if !srcAddrPort.Addr().Is4() || !dstAddrPort.Addr().Is4() {
|
||||
if !local.Addr().Is4() || !remote.Addr().Is4() {
|
||||
return 0, net.InvalidAddrError("invalid ip version")
|
||||
}
|
||||
|
||||
@ -89,13 +78,13 @@ func (u *UDP) WriteTo(buf []byte, local net.Addr, remote net.Addr) (int, error)
|
||||
ip.SetFragmentOffset(0)
|
||||
ip.SetTimeToLive(64)
|
||||
ip.SetProtocol(tcpip.UDP)
|
||||
ip.SetSourceIP(srcAddrPort.Addr())
|
||||
ip.SetDestinationIP(dstAddrPort.Addr())
|
||||
ip.SetSourceIP(local.Addr())
|
||||
ip.SetDestinationIP(remote.Addr())
|
||||
|
||||
udp := tcpip.UDPPacket(ip.Payload())
|
||||
udp.SetLength(tcpip.UDPHeaderSize + uint16(len(buf)))
|
||||
udp.SetSourcePort(srcAddrPort.Port())
|
||||
udp.SetDestinationPort(dstAddrPort.Port())
|
||||
udp.SetSourcePort(local.Port())
|
||||
udp.SetDestinationPort(remote.Port())
|
||||
copy(udp.Payload(), buf)
|
||||
|
||||
ip.ResetChecksum()
|
||||
@ -131,14 +120,8 @@ func (u *UDP) handleUDPPacket(ip tcpip.IP, pkt tcpip.UDPPacket) {
|
||||
u.queueLock.Unlock()
|
||||
|
||||
if c != nil {
|
||||
c.source = &net.UDPAddr{
|
||||
IP: ip.SourceIP().AsSlice(),
|
||||
Port: int(pkt.SourcePort()),
|
||||
}
|
||||
c.destination = &net.UDPAddr{
|
||||
IP: ip.DestinationIP().AsSlice(),
|
||||
Port: int(pkt.DestinationPort()),
|
||||
}
|
||||
c.source = netip.AddrPortFrom(ip.SourceIP(), pkt.SourcePort())
|
||||
c.destination = netip.AddrPortFrom(ip.DestinationIP(), pkt.DestinationPort())
|
||||
c.n = copy(c.buf, pkt.Payload())
|
||||
c.cond.Signal()
|
||||
}
|
||||
|
@ -81,26 +81,23 @@ func New(device device.Device, dnsHijack []C.DNSUrl, tunAddress netip.Prefix, tc
|
||||
continue
|
||||
}
|
||||
|
||||
lAddr := conn.LocalAddr().(*net.TCPAddr)
|
||||
rAddr := conn.RemoteAddr().(*net.TCPAddr)
|
||||
lAddr := conn.LocalAddr().(*net.TCPAddr).AddrPort()
|
||||
rAddr := conn.RemoteAddr().(*net.TCPAddr).AddrPort()
|
||||
|
||||
lAddrPort := netip.AddrPortFrom(nnip.IpToAddr(lAddr.IP), uint16(lAddr.Port))
|
||||
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port))
|
||||
|
||||
if rAddrPort.Addr().IsLoopback() {
|
||||
if rAddr.Addr().IsLoopback() {
|
||||
_ = conn.Close()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if D.ShouldHijackDns(dnsAddr, rAddrPort, "tcp") {
|
||||
if D.ShouldHijackDns(dnsAddr, rAddr, "tcp") {
|
||||
go func() {
|
||||
log.Debugln("[TUN] hijack dns tcp: %s", rAddrPort.String())
|
||||
log.Debugln("[TUN] hijack dns tcp: %s", rAddr.String())
|
||||
|
||||
buf := pool.Get(pool.UDPBufferSize)
|
||||
defer func() {
|
||||
_ = pool.Put(buf)
|
||||
_ = conn.Close()
|
||||
_ = pool.Put(buf)
|
||||
}()
|
||||
|
||||
for {
|
||||
@ -137,10 +134,10 @@ func New(device device.Device, dnsHijack []C.DNSUrl, tunAddress netip.Prefix, tc
|
||||
metadata := &C.Metadata{
|
||||
NetWork: C.TCP,
|
||||
Type: C.TUN,
|
||||
SrcIP: lAddrPort.Addr(),
|
||||
DstIP: rAddrPort.Addr(),
|
||||
SrcPort: strconv.Itoa(lAddr.Port),
|
||||
DstPort: strconv.Itoa(rAddr.Port),
|
||||
SrcIP: lAddr.Addr(),
|
||||
DstIP: rAddr.Addr(),
|
||||
SrcPort: strconv.FormatUint(uint64(lAddr.Port()), 10),
|
||||
DstPort: strconv.FormatUint(uint64(rAddr.Port()), 10),
|
||||
AddrType: C.AtypIPv4,
|
||||
Host: "",
|
||||
}
|
||||
@ -159,56 +156,50 @@ func New(device device.Device, dnsHijack []C.DNSUrl, tunAddress netip.Prefix, tc
|
||||
for !ipStack.closed {
|
||||
buf := pool.Get(pool.UDPBufferSize)
|
||||
|
||||
n, lRAddr, rRAddr, err := stack.UDP().ReadFrom(buf)
|
||||
n, lAddr, rAddr, err := stack.UDP().ReadFrom(buf)
|
||||
if err != nil {
|
||||
_ = pool.Put(buf)
|
||||
break
|
||||
}
|
||||
|
||||
raw := buf[:n]
|
||||
lAddr := lRAddr.(*net.UDPAddr)
|
||||
rAddr := rRAddr.(*net.UDPAddr)
|
||||
|
||||
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port))
|
||||
|
||||
if rAddrPort.Addr().IsLoopback() || rAddrPort.Addr() == gateway {
|
||||
if rAddr.Addr().IsLoopback() || rAddr.Addr() == gateway {
|
||||
_ = pool.Put(buf)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if D.ShouldHijackDns(dnsAddr, rAddrPort, "udp") {
|
||||
if D.ShouldHijackDns(dnsAddr, rAddr, "udp") {
|
||||
go func() {
|
||||
msg, err := D.RelayDnsPacket(raw)
|
||||
if err != nil {
|
||||
defer func() {
|
||||
_ = pool.Put(buf)
|
||||
}()
|
||||
|
||||
msg, err := D.RelayDnsPacket(buf[:n])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = stack.UDP().WriteTo(msg, rAddr, lAddr)
|
||||
|
||||
_ = pool.Put(buf)
|
||||
|
||||
log.Debugln("[TUN] hijack dns udp: %s", rAddrPort.String())
|
||||
log.Debugln("[TUN] hijack dns udp: %s", rAddr.String())
|
||||
}()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
pkt := &packet{
|
||||
local: lAddr,
|
||||
data: raw,
|
||||
local: lAddr,
|
||||
data: buf,
|
||||
offset: n,
|
||||
writeBack: func(b []byte, addr net.Addr) (int, error) {
|
||||
return stack.UDP().WriteTo(b, rAddr, lAddr)
|
||||
},
|
||||
drop: func() {
|
||||
_ = pool.Put(buf)
|
||||
},
|
||||
}
|
||||
|
||||
select {
|
||||
case udpIn <- inbound.NewPacket(socks5.ParseAddrToSocksAddr(rAddr), pkt, C.TUN):
|
||||
case udpIn <- inbound.NewPacket(socks5.AddrFromStdAddrPort(rAddr), pkt, C.TUN):
|
||||
default:
|
||||
pkt.Drop()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,21 @@
|
||||
package system
|
||||
|
||||
import "net"
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
type packet struct {
|
||||
local *net.UDPAddr
|
||||
local netip.AddrPort
|
||||
data []byte
|
||||
offset int
|
||||
writeBack func(b []byte, addr net.Addr) (int, error)
|
||||
drop func()
|
||||
}
|
||||
|
||||
func (pkt *packet) Data() []byte {
|
||||
return pkt.data
|
||||
return pkt.data[:pkt.offset]
|
||||
}
|
||||
|
||||
func (pkt *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
||||
@ -18,9 +23,9 @@ func (pkt *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
||||
}
|
||||
|
||||
func (pkt *packet) Drop() {
|
||||
pkt.drop()
|
||||
_ = pool.Put(pkt.data)
|
||||
}
|
||||
|
||||
func (pkt *packet) LocalAddr() net.Addr {
|
||||
return pkt.local
|
||||
return net.UDPAddrFromAddrPort(pkt.local)
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
"github.com/Dreamacro/clash/common/cmd"
|
||||
"github.com/Dreamacro/clash/component/process"
|
||||
"github.com/Dreamacro/clash/config"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/listener/tun/device"
|
||||
@ -24,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
// 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 (
|
||||
tunAddress = netip.Prefix{}
|
||||
devName = tunConf.Device
|
||||
@ -48,16 +47,14 @@ func New(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan<- C.Con
|
||||
devName = generateDeviceName()
|
||||
}
|
||||
|
||||
if tunAddressPrefix != nil {
|
||||
tunAddress = *tunAddressPrefix
|
||||
if tunConf.TunAddressPrefix != nil {
|
||||
tunAddress = *tunConf.TunAddressPrefix
|
||||
}
|
||||
|
||||
if !tunAddress.IsValid() || !tunAddress.Addr().Is4() {
|
||||
tunAddress = netip.MustParsePrefix("198.18.0.1/16")
|
||||
}
|
||||
|
||||
process.AppendLocalIPs(tunAddress.Masked().Addr().Next())
|
||||
|
||||
// open tun device
|
||||
tunDevice, err = parseDevice(devName, uint32(mtu))
|
||||
if err != nil {
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/Dreamacro/clash/component/geodata"
|
||||
"github.com/Dreamacro/clash/component/geodata/router"
|
||||
_ "github.com/Dreamacro/clash/component/geodata/standard"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
)
|
||||
@ -47,12 +46,16 @@ func (gs *GEOSITE) GetDomainMatcher() *router.DomainMatcher {
|
||||
}
|
||||
|
||||
func NewGEOSITE(country string, adapter string) (*GEOSITE, error) {
|
||||
matcher, recordsCount, err := geodata.LoadGeoSiteMatcher(country)
|
||||
matcher, recordsCount, err := geodata.LoadProviderByCode(country)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load GeoSite data error, %s", err.Error())
|
||||
}
|
||||
|
||||
log.Infoln("Start initial GeoSite rule %s => %s, records: %d", country, adapter, recordsCount)
|
||||
count := fmt.Sprintf("%d", recordsCount)
|
||||
if recordsCount == 0 {
|
||||
count = "from cache"
|
||||
}
|
||||
log.Infoln("Start initial GeoSite rule %s => %s, records: %s", country, adapter, count)
|
||||
|
||||
geoSite := &GEOSITE{
|
||||
Base: &Base{},
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
|
||||
"github.com/Dreamacro/clash/component/auth"
|
||||
@ -398,6 +399,21 @@ func ParseAddrToSocksAddr(addr net.Addr) Addr {
|
||||
return parsed
|
||||
}
|
||||
|
||||
func AddrFromStdAddrPort(addrPort netip.AddrPort) Addr {
|
||||
addr := addrPort.Addr()
|
||||
if addr.Is4() {
|
||||
ip4 := addr.As4()
|
||||
return []byte{AtypIPv4, ip4[0], ip4[1], ip4[2], ip4[3], byte(addrPort.Port() >> 8), byte(addrPort.Port())}
|
||||
}
|
||||
|
||||
buf := make([]byte, 1+net.IPv6len+2)
|
||||
buf[0] = AtypIPv6
|
||||
copy(buf[1:], addr.AsSlice())
|
||||
buf[1+net.IPv6len] = byte(addrPort.Port() >> 8)
|
||||
buf[1+net.IPv6len+1] = byte(addrPort.Port())
|
||||
return buf
|
||||
}
|
||||
|
||||
// DecodeUDPPacket split `packet` to addr payload, and this function is mutable with `packet`
|
||||
func DecodeUDPPacket(packet []byte) (addr Addr, payload []byte, err error) {
|
||||
if len(packet) < 5 {
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/common/convert"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
@ -118,7 +119,7 @@ func (c *httpConn) Write(b []byte) (int, error) {
|
||||
buf.WriteString(body + "\r\n\r\n")
|
||||
} else {
|
||||
buf.WriteString("User-Agent: ")
|
||||
buf.WriteString(userAgent[rand.Intn(len(userAgent))])
|
||||
buf.WriteString(convert.RandUserAgent())
|
||||
buf.WriteString("\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Encoding: gzip, deflate\r\n")
|
||||
if c.post {
|
||||
packBoundary(buf)
|
||||
@ -150,256 +151,3 @@ func packBoundary(buf *bytes.Buffer) {
|
||||
}
|
||||
buf.WriteString("\r\n")
|
||||
}
|
||||
|
||||
var userAgent = []string{
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; Moto C Build/NRD90M.059) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 5.1.1; SM-J120M Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Build/NPPS25.137-93-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; SM-G570M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 5.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0; CAM-L03 Build/HUAWEICAM-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3",
|
||||
"Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; Datanyze; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 5.1.1; SM-J111M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Slackware/Chrome/12.0.742.100 Safari/534.30",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX3 Build/HUAWEIWAS-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.1805 Safari/537.36 MVisionPlayer/1.0.0.0",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; TRT-LX3 Build/HUAWEITRT-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0; vivo 1610 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 4.4.2; de-de; SAMSUNG GT-I9195 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX3 Build/HUAWEIANE-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; U; Linux i586; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; SM-G610M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0; vivo 1606 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; SM-G610M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.1; vivo 1716 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; SM-G570M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0; MYA-L22 Build/HUAWEIMYA-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; TRT-LX2 Build/HUAWEITRT-LX2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17",
|
||||
"Mozilla/5.0 (Linux; Android 6.0; CAM-L21 Build/HUAWEICAM-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24",
|
||||
"Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4X Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 4.4.2; SM-G7102 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L22 Build/HUAWEICUN-L22; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 5.1.1; A37fw Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; SM-J730GM Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.1.2; Redmi Note 5A Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36",
|
||||
"Mozilla/5.0 (Unknown; Linux) AppleWebKit/538.1 (KHTML, like Gecko) Chrome/v1.0.0 Safari/538.1",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; BLL-L22 Build/HUAWEIBLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.0; SM-J710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.1.1; CPH1723 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX3 Build/HUAWEIFIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 7.1; Mi A1 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36 MVisionPlayer/1.0.0.0",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 5.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.93 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; CPH1607 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; vivo 1603 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; Redmi 4A Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36",
|
||||
"Mozilla/5.0 (Linux; Android 6.0; vivo 1713 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
|
||||
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata
|
||||
|
||||
// local resolve UDP dns
|
||||
if !metadata.Resolved() {
|
||||
ip, err := resolver.ResolveIP(metadata.Host)
|
||||
ip, err := resolver.ResolveFirstIP(metadata.Host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -32,19 +32,21 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata
|
||||
return err
|
||||
}
|
||||
// reset timeout
|
||||
pc.SetReadDeadline(time.Now().Add(udpTimeout))
|
||||
_ = pc.SetReadDeadline(time.Now().Add(udpTimeout))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, fAddr net.Addr) {
|
||||
buf := pool.Get(pool.UDPBufferSize)
|
||||
defer pool.Put(buf)
|
||||
defer natTable.Delete(key)
|
||||
defer pc.Close()
|
||||
defer func() {
|
||||
_ = pc.Close()
|
||||
natTable.Delete(key)
|
||||
_ = pool.Put(buf)
|
||||
}()
|
||||
|
||||
for {
|
||||
pc.SetReadDeadline(time.Now().Add(udpTimeout))
|
||||
_ = pc.SetReadDeadline(time.Now().Add(udpTimeout))
|
||||
n, from, err := pc.ReadFrom(buf)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -190,19 +190,6 @@ func preHandleMetadata(metadata *C.Metadata) error {
|
||||
}
|
||||
}
|
||||
|
||||
// pre resolve process name
|
||||
srcPort, err := strconv.ParseUint(metadata.SrcPort, 10, 16)
|
||||
if err == nil && P.ShouldFindProcess(metadata) {
|
||||
path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(srcPort))
|
||||
if err != nil {
|
||||
log.Debugln("[Process] find process %s: %v", metadata.String(), err)
|
||||
} else {
|
||||
log.Debugln("[Process] %s from process %s", metadata.String(), path)
|
||||
metadata.Process = filepath.Base(path)
|
||||
metadata.ProcessPath = path
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -385,7 +372,10 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
||||
configMux.RLock()
|
||||
defer configMux.RUnlock()
|
||||
|
||||
var resolved bool
|
||||
var (
|
||||
resolved bool
|
||||
processFound bool
|
||||
)
|
||||
|
||||
if node := resolver.DefaultHosts.Search(metadata.Host); node != nil {
|
||||
metadata.DstIP = node.Data
|
||||
@ -404,6 +394,22 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) {
|
||||
resolved = true
|
||||
}
|
||||
|
||||
if !processFound && rule.ShouldFindProcess() {
|
||||
processFound = true
|
||||
|
||||
srcPort, err := strconv.ParseUint(metadata.SrcPort, 10, 16)
|
||||
if err == nil {
|
||||
path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(srcPort))
|
||||
if err != nil {
|
||||
log.Debugln("[Process] find process %s: %v", metadata.String(), err)
|
||||
} else {
|
||||
log.Debugln("[Process] %s from process %s", metadata.String(), path)
|
||||
metadata.Process = filepath.Base(path)
|
||||
metadata.ProcessPath = path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if rule.Match(metadata) {
|
||||
adapter, ok := proxies[rule.Adapter()]
|
||||
if !ok {
|
||||
|
Reference in New Issue
Block a user