chore: reset resolver's connection after default interface changed

This commit is contained in:
wwqgtxx
2024-09-27 20:09:35 +08:00
parent 1633885794
commit acfc9f8baa
12 changed files with 103 additions and 37 deletions

View File

@@ -103,3 +103,5 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
return ret.msg, ret.err
}
}
func (c *client) ResetConnection() {}

View File

@@ -53,6 +53,12 @@ func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg,
return
}
func (d *dhcpClient) ResetConnection() {
for _, client := range d.clients {
client.ResetConnection()
}
}
func (d *dhcpClient) resolve(ctx context.Context) ([]dnsClient, error) {
d.lock.Lock()

View File

@@ -203,11 +203,23 @@ func (doh *dnsOverHTTPS) Close() (err error) {
return doh.closeClient(doh.client)
}
// closeClient cleans up resources used by client if necessary. Note, that at
// this point it should only be done for HTTP/3 as it may leak due to keep-alive
// connections.
func (doh *dnsOverHTTPS) ResetConnection() {
doh.clientMu.Lock()
defer doh.clientMu.Unlock()
if doh.client == nil {
return
}
_ = doh.closeClient(doh.client)
doh.client = nil
}
// closeClient cleans up resources used by client if necessary.
func (doh *dnsOverHTTPS) closeClient(client *http.Client) (err error) {
if isHTTP3(client) {
client.CloseIdleConnections()
if isHTTP3(client) { // HTTP/3 may leak due to keep-alive connections.
return client.Transport.(io.Closer).Close()
}
@@ -508,6 +520,13 @@ func (h *http3Transport) Close() (err error) {
return h.baseTransport.Close()
}
func (h *http3Transport) CloseIdleConnections() {
h.mu.RLock()
defer h.mu.RUnlock()
h.baseTransport.CloseIdleConnections()
}
// createTransportH3 tries to create an HTTP/3 transport for this upstream.
// We should be able to fall back to H1/H2 in case if HTTP/3 is unavailable or
// if it is too slow. In order to do that, this method will run two probes

View File

@@ -144,6 +144,10 @@ func (doq *dnsOverQUIC) Close() (err error) {
return err
}
func (doq *dnsOverQUIC) ResetConnection() {
doq.closeConnWithError(nil)
}
// exchangeQUIC attempts to open a QUIC connection, send the DNS message
// through it and return the response it got from the server.
func (doq *dnsOverQUIC) exchangeQUIC(ctx context.Context, msg *D.Msg) (resp *D.Msg, err error) {

View File

@@ -12,6 +12,7 @@ func FlushCacheWithDefaultResolver() {
if r := resolver.DefaultResolver; r != nil {
r.ClearCache()
}
resolver.ResetConnection()
}
func UpdateSystemDNS(addr []string) {
@@ -30,3 +31,9 @@ func UpdateSystemDNS(addr []string) {
func (c *systemClient) getDnsClients() ([]dnsClient, error) {
return systemResolver, nil
}
func (c *systemClient) ResetConnection() {
for _, r := range systemResolver {
r.ResetConnection()
}
}

View File

@@ -48,3 +48,5 @@ func (r rcodeClient) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, err
func (r rcodeClient) Address() string {
return r.addr
}
func (r rcodeClient) ResetConnection() {}

View File

@@ -24,6 +24,7 @@ import (
type dnsClient interface {
ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error)
Address() string
ResetConnection()
}
type dnsCache interface {
@@ -48,7 +49,7 @@ type Resolver struct {
group singleflight.Group[*D.Msg]
cache dnsCache
policy []dnsPolicy
proxyServer []dnsClient
defaultResolver *Resolver
}
func (r *Resolver) LookupIPPrimaryIPv4(ctx context.Context, host string) (ips []netip.Addr, err error) {
@@ -376,6 +377,20 @@ func (r *Resolver) ClearCache() {
}
}
func (r *Resolver) ResetConnection() {
if r != nil {
for _, c := range r.main {
c.ResetConnection()
}
for _, c := range r.fallback {
c.ResetConnection()
}
if dr := r.defaultResolver; dr != nil {
dr.ResetConnection()
}
}
}
type NameServer struct {
Net string
Addr string
@@ -425,16 +440,18 @@ type Config struct {
CacheAlgorithm string
}
func NewResolver(config Config) *Resolver {
var cache dnsCache
if config.CacheAlgorithm == "lru" {
cache = lru.New(lru.WithSize[string, *D.Msg](4096), lru.WithStale[string, *D.Msg](true))
func (config Config) newCache() dnsCache {
if config.CacheAlgorithm == "" || config.CacheAlgorithm == "lru" {
return lru.New(lru.WithSize[string, *D.Msg](4096), lru.WithStale[string, *D.Msg](true))
} else {
cache = arc.New(arc.WithSize[string, *D.Msg](4096))
return arc.New(arc.WithSize[string, *D.Msg](4096))
}
}
func NewResolver(config Config) (r *Resolver, pr *Resolver) {
defaultResolver := &Resolver{
main: transform(config.Default, nil),
cache: cache,
cache: config.newCache(),
ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond,
}
@@ -465,27 +482,29 @@ func NewResolver(config Config) *Resolver {
return
}
if config.CacheAlgorithm == "" || config.CacheAlgorithm == "lru" {
cache = lru.New(lru.WithSize[string, *D.Msg](4096), lru.WithStale[string, *D.Msg](true))
} else {
cache = arc.New(arc.WithSize[string, *D.Msg](4096))
}
r := &Resolver{
r = &Resolver{
ipv6: config.IPv6,
main: cacheTransform(config.Main),
cache: cache,
cache: config.newCache(),
hosts: config.Hosts,
ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond,
}
r.defaultResolver = defaultResolver
if len(config.ProxyServer) != 0 {
pr = &Resolver{
ipv6: config.IPv6,
main: cacheTransform(config.ProxyServer),
cache: config.newCache(),
hosts: config.Hosts,
ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond,
}
}
if len(config.Fallback) != 0 {
r.fallback = cacheTransform(config.Fallback)
}
if len(config.ProxyServer) != 0 {
r.proxyServer = cacheTransform(config.ProxyServer)
}
if len(config.Policy) != 0 {
r.policy = make([]dnsPolicy, 0)
@@ -516,18 +535,7 @@ func NewResolver(config Config) *Resolver {
r.fallbackIPFilters = config.FallbackIPFilter
r.fallbackDomainFilters = config.FallbackDomainFilter
return r
}
func NewProxyServerHostResolver(old *Resolver) *Resolver {
r := &Resolver{
ipv6: old.ipv6,
main: old.proxyServer,
cache: old.cache,
hosts: old.hosts,
ipv6Timeout: old.ipv6Timeout,
}
return r
return
}
var ParseNameServer func(servers []string) ([]NameServer, error) // define in config/config.go

View File

@@ -69,3 +69,5 @@ func (c *systemClient) getDnsClients() ([]dnsClient, error) {
}
return nil, err
}
func (c *systemClient) ResetConnection() {}