diff --git a/adapters/outbound/direct.go b/adapters/outbound/direct.go index d2b7a9ab..1da750bc 100644 --- a/adapters/outbound/direct.go +++ b/adapters/outbound/direct.go @@ -4,6 +4,7 @@ import ( "context" "net" + "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" ) @@ -26,7 +27,7 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, } func (d *Direct) DialUDP(metadata *C.Metadata) (C.PacketConn, error) { - pc, err := net.ListenPacket("udp", "") + pc, err := dialer.ListenPacket("udp", "") if err != nil { return nil, err } diff --git a/adapters/outbound/shadowsocks.go b/adapters/outbound/shadowsocks.go index 217c8e2e..f0313e99 100644 --- a/adapters/outbound/shadowsocks.go +++ b/adapters/outbound/shadowsocks.go @@ -9,6 +9,7 @@ import ( "strconv" "github.com/Dreamacro/clash/common/structure" + "github.com/Dreamacro/clash/component/dialer" obfs "github.com/Dreamacro/clash/component/simple-obfs" "github.com/Dreamacro/clash/component/socks5" v2rayObfs "github.com/Dreamacro/clash/component/v2ray-plugin" @@ -83,7 +84,7 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (C } func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (C.PacketConn, error) { - pc, err := net.ListenPacket("udp", "") + pc, err := dialer.ListenPacket("udp", "") if err != nil { return nil, err } diff --git a/adapters/outbound/socks5.go b/adapters/outbound/socks5.go index 79cf05b7..8c5b61f6 100644 --- a/adapters/outbound/socks5.go +++ b/adapters/outbound/socks5.go @@ -9,6 +9,7 @@ import ( "net" "strconv" + "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/socks5" C "github.com/Dreamacro/clash/constant" ) @@ -96,7 +97,7 @@ func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) { return } - pc, err := net.ListenPacket("udp", "") + pc, err := dialer.ListenPacket("udp", "") if err != nil { return } diff --git a/adapters/outbound/util.go b/adapters/outbound/util.go index b3deb0a7..e082954b 100644 --- a/adapters/outbound/util.go +++ b/adapters/outbound/util.go @@ -11,6 +11,7 @@ import ( "sync" "time" + "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/socks5" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/dns" @@ -107,7 +108,7 @@ func dialContext(ctx context.Context, network, address string) (net.Conn, error) var primary, fallback dialResult startRacer := func(ctx context.Context, host string, ipv6 bool) { - dialer := net.Dialer{} + dialer := dialer.Dialer() result := dialResult{ipv6: ipv6, done: true} defer func() { select { diff --git a/adapters/provider/vehicle.go b/adapters/provider/vehicle.go index 0b949368..cc873a90 100644 --- a/adapters/provider/vehicle.go +++ b/adapters/provider/vehicle.go @@ -5,6 +5,8 @@ import ( "io/ioutil" "net/http" "time" + + "github.com/Dreamacro/clash/component/dialer" ) // Vehicle Type @@ -85,6 +87,7 @@ func (h *HTTPVehicle) Read() ([]byte, error) { IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, + DialContext: dialer.DialContext, } client := http.Client{Transport: transport} diff --git a/common/cache/lrucache.go b/common/cache/lrucache.go index a73b0b9e..6fe1d74c 100644 --- a/common/cache/lrucache.go +++ b/common/cache/lrucache.go @@ -12,7 +12,7 @@ import ( type Option func(*LruCache) // EvictCallback is used to get a callback when a cache entry is evicted -type EvictCallback func(key interface{}, value interface{}) +type EvictCallback = func(key interface{}, value interface{}) // WithEvict set the evict callback func WithEvict(cb EvictCallback) Option { diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go new file mode 100644 index 00000000..bb8f122e --- /dev/null +++ b/component/dialer/dialer.go @@ -0,0 +1,38 @@ +package dialer + +import ( + "context" + "net" +) + +func Dialer() *net.Dialer { + dialer := &net.Dialer{} + if DialerHook != nil { + DialerHook(dialer) + } + + return dialer +} + +func ListenConfig() *net.ListenConfig { + cfg := &net.ListenConfig{} + if ListenConfigHook != nil { + ListenConfigHook(cfg) + } + + return cfg +} + +func Dial(network, address string) (net.Conn, error) { + return DialContext(context.Background(), network, address) +} + +func DialContext(ctx context.Context, network, address string) (net.Conn, error) { + dailer := Dialer() + return dailer.DialContext(ctx, network, address) +} + +func ListenPacket(network, address string) (net.PacketConn, error) { + lc := ListenConfig() + return lc.ListenPacket(context.Background(), network, address) +} diff --git a/component/dialer/hook.go b/component/dialer/hook.go new file mode 100644 index 00000000..4ef71143 --- /dev/null +++ b/component/dialer/hook.go @@ -0,0 +1,11 @@ +package dialer + +import "net" + +type DialerHookFunc = func(*net.Dialer) +type ListenConfigHookFunc = func(*net.ListenConfig) + +var ( + DialerHook DialerHookFunc = nil + ListenConfigHook ListenConfigHookFunc = nil +) diff --git a/dns/client.go b/dns/client.go index b79a997d..91ba7ec5 100644 --- a/dns/client.go +++ b/dns/client.go @@ -3,6 +3,8 @@ package dns import ( "context" + "github.com/Dreamacro/clash/component/dialer" + D "github.com/miekg/dns" ) @@ -16,6 +18,8 @@ func (c *client) Exchange(m *D.Msg) (msg *D.Msg, err error) { } func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { + c.Client.Dialer = dialer.Dialer() + // Please note that miekg/dns ExchangeContext doesn't respond to context cancel. msg, _, err = c.Client.ExchangeContext(ctx, m, c.Address) return diff --git a/dns/doh.go b/dns/doh.go index d8d60772..4aecd355 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -7,6 +7,8 @@ import ( "io/ioutil" "net/http" + "github.com/Dreamacro/clash/component/dialer" + D "github.com/miekg/dns" ) @@ -17,6 +19,7 @@ const ( var dohTransport = &http.Transport{ TLSClientConfig: &tls.Config{ClientSessionCache: globalSessionCache}, + DialContext: dialer.DialContext, } type dohClient struct {