Cleanup ParseHostOrFile (#2100)

Create plugin/pkg/transport that holds the transport related functions.
This needed to be a new pkg to prevent cyclic import errors.

This cleans up a bunch of duplicated code in core/dnsserver that also
tried to parse a transport (now all done in transport.Parse).

Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
Miek Gieben
2018-09-19 07:29:37 +01:00
committed by GitHub
parent 2f1223c36a
commit c349446a23
24 changed files with 182 additions and 221 deletions

View File

@@ -35,16 +35,16 @@ func averageTimeout(currentAvg *int64, observedDuration time.Duration, weight in
atomic.AddInt64(currentAvg, int64(observedDuration-dt)/weight)
}
func (t *transport) dialTimeout() time.Duration {
func (t *Transport) dialTimeout() time.Duration {
return limitTimeout(&t.avgDialTime, minDialTimeout, maxDialTimeout)
}
func (t *transport) updateDialTimeout(newDialTime time.Duration) {
func (t *Transport) updateDialTimeout(newDialTime time.Duration) {
averageTimeout(&t.avgDialTime, newDialTime, cumulativeAvgWeight)
}
// Dial dials the address configured in transport, potentially reusing a connection or creating a new one.
func (t *transport) Dial(proto string) (*dns.Conn, bool, error) {
func (t *Transport) Dial(proto string) (*dns.Conn, bool, error) {
// If tls has been configured; use it.
if t.tlsConfig != nil {
proto = "tcp-tls"

View File

@@ -4,6 +4,7 @@ import (
"testing"
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/coredns/coredns/plugin/test"
"github.com/coredns/coredns/request"
@@ -19,7 +20,7 @@ func TestForward(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.SetProxy(p)
defer f.Close()
@@ -51,7 +52,7 @@ func TestForwardRefused(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.SetProxy(p)
defer f.Close()

View File

@@ -5,6 +5,8 @@ import (
"sync/atomic"
"time"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/miekg/dns"
)
@@ -17,10 +19,10 @@ type HealthChecker interface {
// dnsHc is a health checker for a DNS endpoint (DNS, and DoT).
type dnsHc struct{ c *dns.Client }
// NewHealthChecker returns a new HealthChecker based on protocol.
func NewHealthChecker(protocol int) HealthChecker {
switch protocol {
case DNS, TLS:
// NewHealthChecker returns a new HealthChecker based on transport.
func NewHealthChecker(trans string) HealthChecker {
switch trans {
case transport.DNS, transport.TLS:
c := new(dns.Client)
c.Net = "udp"
c.ReadTimeout = 1 * time.Second

View File

@@ -7,6 +7,7 @@ import (
"time"
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/coredns/coredns/plugin/test"
"github.com/miekg/dns"
@@ -25,7 +26,7 @@ func TestHealth(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.SetProxy(p)
defer f.Close()
@@ -65,7 +66,7 @@ func TestHealthTimeout(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.SetProxy(p)
defer f.Close()
@@ -109,7 +110,7 @@ func TestHealthFailTwice(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.SetProxy(p)
defer f.Close()
@@ -132,7 +133,7 @@ func TestHealthMaxFails(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.maxfails = 2
f.SetProxy(p)
@@ -163,7 +164,7 @@ func TestHealthNoMaxFails(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.maxfails = 0
f.SetProxy(p)

View File

@@ -7,6 +7,7 @@ package forward
import (
"context"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
@@ -81,7 +82,7 @@ func (f *Forward) Lookup(state request.Request, name string, typ uint16) (*dns.M
func NewLookup(addr []string) *Forward {
f := New()
for i := range addr {
p := NewProxy(addr[i], DNS)
p := NewProxy(addr[i], transport.DNS)
f.SetProxy(p)
}
return f

View File

@@ -4,6 +4,7 @@ import (
"testing"
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/coredns/coredns/plugin/test"
"github.com/coredns/coredns/request"
@@ -19,7 +20,7 @@ func TestLookup(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.SetProxy(p)
defer f.Close()

View File

@@ -15,10 +15,10 @@ type persistConn struct {
used time.Time
}
// transport hold the persistent cache.
type transport struct {
// Transport hold the persistent cache.
type Transport struct {
avgDialTime int64 // kind of average time of dial time
conns map[string][]*persistConn // Buckets for udp, tcp and tcp-tls.
conns map[string][]*persistConn // Buckets for udp, tcp and tcp-tls.
expire time.Duration // After this duration a connection is expired.
addr string
tlsConfig *tls.Config
@@ -29,8 +29,8 @@ type transport struct {
stop chan bool
}
func newTransport(addr string) *transport {
t := &transport{
func newTransport(addr string) *Transport {
t := &Transport{
avgDialTime: int64(defaultDialTimeout / 2),
conns: make(map[string][]*persistConn),
expire: defaultExpire,
@@ -45,7 +45,7 @@ func newTransport(addr string) *transport {
// len returns the number of connection, used for metrics. Can only be safely
// used inside connManager() because of data races.
func (t *transport) len() int {
func (t *Transport) len() int {
l := 0
for _, conns := range t.conns {
l += len(conns)
@@ -54,7 +54,7 @@ func (t *transport) len() int {
}
// connManagers manages the persistent connection cache for UDP and TCP.
func (t *transport) connManager() {
func (t *Transport) connManager() {
ticker := time.NewTicker(t.expire)
Wait:
for {
@@ -115,7 +115,7 @@ func closeConns(conns []*persistConn) {
}
// cleanup removes connections from cache.
func (t *transport) cleanup(all bool) {
func (t *Transport) cleanup(all bool) {
staleTime := time.Now().Add(-t.expire)
for proto, stack := range t.conns {
if len(stack) == 0 {
@@ -144,19 +144,19 @@ func (t *transport) cleanup(all bool) {
}
// Yield return the connection to transport for reuse.
func (t *transport) Yield(c *dns.Conn) { t.yield <- c }
func (t *Transport) Yield(c *dns.Conn) { t.yield <- c }
// Start starts the transport's connection manager.
func (t *transport) Start() { go t.connManager() }
func (t *Transport) Start() { go t.connManager() }
// Stop stops the transport's connection manager.
func (t *transport) Stop() { close(t.stop) }
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 }
func (t *Transport) SetExpire(expire time.Duration) { t.expire = expire }
// SetTLSConfig sets the TLS config in transport.
func (t *transport) SetTLSConfig(cfg *tls.Config) { t.tlsConfig = cfg }
func (t *Transport) SetTLSConfig(cfg *tls.Config) { t.tlsConfig = cfg }
const (
defaultExpire = 10 * time.Second

View File

@@ -1,30 +0,0 @@
package forward
// Copied from coredns/core/dnsserver/address.go
import (
"strings"
)
// protocol returns the protocol of the string s. The second string returns s
// with the prefix chopped off.
func protocol(s string) (int, string) {
switch {
case strings.HasPrefix(s, _tls+"://"):
return TLS, s[len(_tls)+3:]
case strings.HasPrefix(s, _dns+"://"):
return DNS, s[len(_dns)+3:]
}
return DNS, s
}
// Supported protocols.
const (
DNS = iota + 1
TLS
)
const (
_dns = "dns"
_tls = "tls"
)

View File

@@ -18,7 +18,7 @@ type Proxy struct {
// Connection caching
expire time.Duration
transport *transport
transport *Transport
// health checking
probe *up.Probe
@@ -26,7 +26,7 @@ type Proxy struct {
}
// NewProxy returns a new proxy.
func NewProxy(addr string, protocol int) *Proxy {
func NewProxy(addr, trans string) *Proxy {
p := &Proxy{
addr: addr,
fails: 0,
@@ -34,7 +34,7 @@ func NewProxy(addr string, protocol int) *Proxy {
transport: newTransport(addr),
avgRtt: int64(maxTimeout / 2),
}
p.health = NewHealthChecker(protocol)
p.health = NewHealthChecker(trans)
runtime.SetFinalizer(p, (*Proxy).finalizer)
return p
}

View File

@@ -5,6 +5,7 @@ import (
"testing"
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/coredns/coredns/plugin/test"
"github.com/coredns/coredns/request"
@@ -26,7 +27,7 @@ func TestProxyClose(t *testing.T) {
ctx := context.TODO()
for i := 0; i < 100; i++ {
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
p.start(hcInterval)
go func() { p.Connect(ctx, state, options{}) }()
@@ -95,7 +96,7 @@ func TestProxyTLSFail(t *testing.T) {
}
func TestProtocolSelection(t *testing.T) {
p := NewProxy("bad_address", DNS)
p := NewProxy("bad_address", transport.DNS)
stateUDP := request.Request{W: &test.ResponseWriter{}, Req: new(dns.Msg)}
stateTCP := request.Request{W: &test.ResponseWriter{TCP: true}, Req: new(dns.Msg)}

View File

@@ -2,7 +2,6 @@ package forward
import (
"fmt"
"net"
"strconv"
"time"
@@ -11,6 +10,7 @@ import (
"github.com/coredns/coredns/plugin/metrics"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
pkgtls "github.com/coredns/coredns/plugin/pkg/tls"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyfile"
@@ -93,8 +93,6 @@ func parseForward(c *caddy.Controller) (*Forward, error) {
func ParseForwardStanza(c *caddyfile.Dispenser) (*Forward, error) {
f := New()
protocols := map[int]int{}
if !c.Args(&f.from) {
return f, c.ArgErr()
}
@@ -105,41 +103,17 @@ func ParseForwardStanza(c *caddyfile.Dispenser) (*Forward, error) {
return f, c.ArgErr()
}
// A bit fiddly, but first check if we've got protocols and if so add them back in when we create the proxies.
protocols = make(map[int]int)
for i := range to {
protocols[i], to[i] = protocol(to[i])
}
// If parseHostPortOrFile expands a file with a lot of nameserver our accounting in protocols doesn't make
// any sense anymore... For now: lets don't care.
toHosts, err := dnsutil.ParseHostPortOrFile(to...)
if err != nil {
return f, err
}
for i, h := range toHosts {
// Double check the port, if e.g. is 53 and the transport is TLS make it 853.
// This can be somewhat annoying because you *can't* have TLS on port 53 then.
switch protocols[i] {
case TLS:
h1, p, err := net.SplitHostPort(h)
if err != nil {
break
}
// This is more of a bug in dnsutil.ParseHostPortOrFile that defaults to
// 53 because it doesn't know about the tls:// // and friends (that should be fixed). Hence
// Fix the port number here, back to what the user intended.
if p == "53" {
h = net.JoinHostPort(h1, "853")
}
}
// We can't set tlsConfig here, because we haven't parsed it yet.
// We set it below at the end of parseBlock, use nil now.
p := NewProxy(h, protocols[i])
transports := make([]string, len(toHosts))
for i, host := range toHosts {
trans, h := transport.Parse(host)
p := NewProxy(h, trans)
f.proxies = append(f.proxies, p)
transports[i] = trans
}
for c.NextBlock() {
@@ -153,7 +127,7 @@ func ParseForwardStanza(c *caddyfile.Dispenser) (*Forward, error) {
}
for i := range f.proxies {
// Only set this for proxies that need it.
if protocols[i] == TLS {
if transports[i] == transport.TLS {
f.proxies[i].SetTLSConfig(f.tlsConfig)
}
f.proxies[i].SetExpire(f.expire)

View File

@@ -5,6 +5,7 @@ import (
"testing"
"github.com/coredns/coredns/plugin/pkg/dnstest"
"github.com/coredns/coredns/plugin/pkg/transport"
"github.com/coredns/coredns/plugin/test"
"github.com/coredns/coredns/request"
@@ -34,7 +35,7 @@ func TestLookupTruncated(t *testing.T) {
})
defer s.Close()
p := NewProxy(s.Addr, DNS)
p := NewProxy(s.Addr, transport.DNS)
f := New()
f.SetProxy(p)
defer f.Close()
@@ -88,9 +89,9 @@ func TestForwardTruncated(t *testing.T) {
f := New()
p1 := NewProxy(s.Addr, DNS)
p1 := NewProxy(s.Addr, transport.DNS)
f.SetProxy(p1)
p2 := NewProxy(s.Addr, DNS)
p2 := NewProxy(s.Addr, transport.DNS)
f.SetProxy(p2)
defer f.Close()