mirror of
https://github.com/coredns/coredns.git
synced 2026-07-10 09:40:12 -04:00
* fix(dnssec): avoid caching empty signing results (#7996) Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * save only Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * do #8008 Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Fix Address used if tcp Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Fix bad using of dialer type Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * core: Add full TSIG verification in gRPC transport (#8006) * core: Add full TSIG verification in gRPC transport This PR add full TSIG verification in gRPC using dns.TsigVerify() so invalid signatures and timestamps are correctly detected instead of only checking key presence. Signed-off-by: Yong Tang <yong.tang.github@outlook.com> * Fix Signed-off-by: Yong Tang <yong.tang.github@outlook.com> * Fix Signed-off-by: Yong Tang <yong.tang.github@outlook.com> --------- Signed-off-by: Yong Tang <yong.tang.github@outlook.com> Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * core: Add full TSIG verification in QUIC transport (#8007) * core: Add full TSIG verification in QUIC transport This PR add full TSIG verification in QUIC using dns.TsigVerify() Signed-off-by: Yong Tang <yong.tang.github@outlook.com> * Fix Signed-off-by: Yong Tang <yong.tang.github@outlook.com> --------- Signed-off-by: Yong Tang <yong.tang.github@outlook.com> Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix(test): deduplicate TSIG test helpers (#8009) Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix(dnssec): return nil sigs on sign error (#7999) Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix(dnssec): return nil from ParseKeyFile on error (#8000) Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix(dnsserver): allow view server blocks in any declaration order (#8001) When using the view plugin, filtered and unfiltered server blocks can share the same zone and port. The zone overlap validation rejected this configuration when the unfiltered block was not declared last, because filtered configs treated an already-registered zone as an error. Skip the 'already defined' check for configs that have filter functions, since they are expected to coexist with an unfiltered catch-all block on the same zone/port. Fixes #7733 Signed-off-by: umut-polat <52835619+umut-polat@users.noreply.github.com> Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix(doh): use per-connection local address for PROXY protocol (#8005) Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix(transfer): batch AXFR records by message size instead of count (#8002) Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix(tls): use temp dir for keylog test path (#8010) Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Rename local_address option to source_address Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Rename local_address also in readme Add test Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Resolve change request in pr Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix ci lint Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Improve doc on source_address routing needs Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Remove added timeout Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * add use of source address also for health check query Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * remove untrailing newline from health_test.go Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix file format Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Update plugin/forward/setup_test.go Co-authored-by: Ville Vesilehto <ville@vesilehto.fi> Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Remove dead code in TestHealthLocalAddress Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Fix misspelling Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * Try to set default timeout Signed-off-by: Filippo <filippo.ferrazini@gmail.com> * fix format in health.go Signed-off-by: Filippo <filippo.ferrazini@gmail.com> --------- Signed-off-by: Filippo <filippo.ferrazini@gmail.com> Signed-off-by: Yong Tang <yong.tang.github@outlook.com> Signed-off-by: umut-polat <52835619+umut-polat@users.noreply.github.com> Co-authored-by: Ville Vesilehto <ville@vesilehto.fi> Co-authored-by: Yong Tang <yong.tang.github@outlook.com> Co-authored-by: Umut Polat <52835619+umut-polat@users.noreply.github.com> Co-authored-by: Cedric Wang <wangzongqi@msn.com>
186 lines
4.8 KiB
Go
186 lines
4.8 KiB
Go
package proxy
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"net"
|
|
"net/http"
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
// a persistConn holds the dns.Conn, its creation time, and the last used time.
|
|
type persistConn struct {
|
|
c *dns.Conn
|
|
created time.Time
|
|
used time.Time
|
|
}
|
|
|
|
// Transport hold the persistent cache.
|
|
type Transport struct {
|
|
avgDialTime int64 // kind of average time of dial time
|
|
conns [typeTotalCount][]*persistConn // Buckets for udp and tcp connections
|
|
expire time.Duration // After this duration an idle connection is expired.
|
|
maxAge time.Duration // After this duration a connection is closed regardless of activity; 0 means unlimited.
|
|
maxIdleConns int // Max idle connections per protocol type; 0 means unlimited.
|
|
addr string
|
|
tlsConfig *tls.Config
|
|
httpClient *http.Client
|
|
proxyName string
|
|
localAddress net.IP
|
|
|
|
mu sync.Mutex
|
|
stop chan struct{}
|
|
}
|
|
|
|
func newTransport(proxyName, addr string) *Transport {
|
|
t := &Transport{
|
|
avgDialTime: int64(maxDialTimeout / 2),
|
|
conns: [typeTotalCount][]*persistConn{},
|
|
expire: defaultExpire,
|
|
addr: addr,
|
|
stop: make(chan struct{}),
|
|
proxyName: proxyName,
|
|
}
|
|
|
|
return t
|
|
}
|
|
|
|
// connManager manages the persistent connection cache for UDP and TCP.
|
|
func (t *Transport) connManager() {
|
|
ticker := time.NewTicker(defaultExpire)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
t.cleanup(false)
|
|
case <-t.stop:
|
|
t.cleanup(true)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// closeConns closes connections.
|
|
func closeConns(conns []*persistConn) {
|
|
for _, pc := range conns {
|
|
pc.c.Close()
|
|
}
|
|
}
|
|
|
|
// cleanup removes connections from cache.
|
|
func (t *Transport) cleanup(all bool) {
|
|
var toClose []*persistConn
|
|
|
|
t.mu.Lock()
|
|
now := time.Now()
|
|
staleTime := now.Add(-t.expire)
|
|
// Pre-compute max-age deadline outside the loop to avoid repeated time.Now() calls.
|
|
var maxAgeDeadline time.Time
|
|
if t.maxAge > 0 {
|
|
maxAgeDeadline = now.Add(-t.maxAge)
|
|
}
|
|
for transtype, stack := range t.conns {
|
|
if len(stack) == 0 {
|
|
continue
|
|
}
|
|
if all {
|
|
t.conns[transtype] = nil
|
|
toClose = append(toClose, stack...)
|
|
continue
|
|
}
|
|
|
|
// When max-age is set, use a linear scan to evaluate both the idle-timeout
|
|
// (expire, based on last-used time) and the max-age (based on creation time).
|
|
if t.maxAge > 0 {
|
|
var alive []*persistConn
|
|
for _, pc := range stack {
|
|
if !pc.used.After(staleTime) || pc.created.Before(maxAgeDeadline) {
|
|
toClose = append(toClose, pc)
|
|
} else {
|
|
alive = append(alive, pc)
|
|
}
|
|
}
|
|
t.conns[transtype] = alive
|
|
continue
|
|
}
|
|
|
|
// Original expire-only path: connections are sorted by "used"; use binary search.
|
|
if stack[0].used.After(staleTime) {
|
|
continue
|
|
}
|
|
// connections in stack are sorted by "used"
|
|
good := sort.Search(len(stack), func(i int) bool {
|
|
return stack[i].used.After(staleTime)
|
|
})
|
|
t.conns[transtype] = stack[good:]
|
|
toClose = append(toClose, stack[:good]...)
|
|
}
|
|
t.mu.Unlock()
|
|
|
|
// Close connections after releasing lock
|
|
closeConns(toClose)
|
|
}
|
|
|
|
// Yield returns the connection to transport for reuse.
|
|
func (t *Transport) Yield(pc *persistConn) {
|
|
// Check if transport is stopped before acquiring lock
|
|
select {
|
|
case <-t.stop:
|
|
// If stopped, don't return to pool, just close
|
|
pc.c.Close()
|
|
return
|
|
default:
|
|
}
|
|
|
|
pc.used = time.Now() // update used time
|
|
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
|
|
transtype := t.transportTypeFromConn(pc)
|
|
|
|
if t.maxIdleConns > 0 && len(t.conns[transtype]) >= t.maxIdleConns {
|
|
pc.c.Close()
|
|
return
|
|
}
|
|
|
|
t.conns[transtype] = append(t.conns[transtype], pc)
|
|
}
|
|
|
|
// Start starts the transport's connection manager.
|
|
func (t *Transport) Start() { go t.connManager() }
|
|
|
|
// Stop stops the transport's connection manager.
|
|
func (t *Transport) Stop() { close(t.stop) }
|
|
|
|
// SetExpire sets the connection expire time in transport.
|
|
func (t *Transport) SetExpire(expire time.Duration) { t.expire = expire }
|
|
|
|
// SetMaxAge sets the maximum lifetime of a connection regardless of activity.
|
|
// A value of 0 (default) disables max-age and connections are only closed by expire (idle-timeout).
|
|
func (t *Transport) SetMaxAge(maxAge time.Duration) { t.maxAge = maxAge }
|
|
|
|
// SetMaxIdleConns sets the maximum idle connections per transport type.
|
|
// A value of 0 means unlimited (default).
|
|
func (t *Transport) SetMaxIdleConns(n int) { t.maxIdleConns = n }
|
|
|
|
// SetTLSConfig sets the TLS config in transport.
|
|
func (t *Transport) SetTLSConfig(cfg *tls.Config) { t.tlsConfig = cfg }
|
|
|
|
// GetTLSConfig returns the TLS config in transport.
|
|
func (t *Transport) GetTLSConfig() *tls.Config { return t.tlsConfig }
|
|
|
|
// SetLocalAddress sets the local address in transport.
|
|
func (t *Transport) SetLocalAddress(addr net.IP) {
|
|
t.localAddress = addr
|
|
}
|
|
|
|
const (
|
|
defaultExpire = 10 * time.Second
|
|
minDialTimeout = 1 * time.Second
|
|
maxDialTimeout = 30 * time.Second
|
|
)
|