-
-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
36 changed files
with
680 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package config | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/qdm12/dns/v2/pkg/provider" | ||
"github.com/qdm12/gosettings" | ||
"github.com/qdm12/gosettings/reader" | ||
"github.com/qdm12/gotree" | ||
) | ||
|
||
type Plain struct { | ||
// UpstreamResolvers is a list of DNS upstream resolvers to use. | ||
UpstreamResolvers []string | ||
// Timeout is the maximum duration to wait for a response from | ||
// upstream plaintext DNS servers. If left unset, it defaults to | ||
// 1 second. | ||
Timeout time.Duration | ||
} | ||
|
||
func (p *Plain) setDefaults() { | ||
p.UpstreamResolvers = gosettings.DefaultSlice(p.UpstreamResolvers, []string{ | ||
provider.Cloudflare().Name, | ||
provider.Google().Name, | ||
}) | ||
|
||
p.Timeout = gosettings.DefaultComparable(p.Timeout, time.Second) | ||
} | ||
|
||
func (p *Plain) validate() (err error) { | ||
err = checkUpstreamResolverNames(p.UpstreamResolvers) | ||
if err != nil { | ||
return fmt.Errorf("upstream resolvers: %w", err) | ||
} | ||
|
||
const minTimeout = time.Millisecond | ||
if p.Timeout < minTimeout { | ||
return fmt.Errorf("%w: %s must be at least %s", | ||
ErrTimeoutTooSmall, p.Timeout, minTimeout) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (p *Plain) String() string { | ||
return p.ToLinesNode().String() | ||
} | ||
|
||
func (p *Plain) ToLinesNode() (node *gotree.Node) { | ||
node = gotree.New("Plaintext:") | ||
|
||
node.Appendf("Upstream resolvers: %s", andStrings(p.UpstreamResolvers)) | ||
node.Appendf("Request timeout: %s", p.Timeout) | ||
|
||
return node | ||
} | ||
|
||
func (p *Plain) read(reader *reader.Reader) (err error) { | ||
p.UpstreamResolvers = reader.CSV("PLAIN_RESOLVERS") | ||
p.Timeout, err = reader.Duration("PLAIN_TIMEOUT") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package plain | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net" | ||
|
||
"github.com/qdm12/dns/v2/internal/picker" | ||
"github.com/qdm12/dns/v2/pkg/provider" | ||
) | ||
|
||
type Dialer struct { | ||
picker *picker.Picker | ||
servers []provider.PlainServer | ||
ipv6 bool | ||
netDialer *net.Dialer | ||
warner Warner | ||
metrics Metrics | ||
} | ||
|
||
func New(settings Settings) (dial *Dialer, err error) { | ||
settings.SetDefaults() | ||
err = settings.Validate() | ||
if err != nil { | ||
return nil, fmt.Errorf("validating settings: %w", err) | ||
} | ||
|
||
servers := make([]provider.PlainServer, len(settings.UpstreamResolvers)) | ||
for i, upstreamResolver := range settings.UpstreamResolvers { | ||
servers[i] = upstreamResolver.Plain | ||
} | ||
|
||
return &Dialer{ | ||
picker: picker.New(), | ||
servers: servers, | ||
ipv6: settings.IPVersion == "ipv6", | ||
netDialer: &net.Dialer{ | ||
Timeout: settings.Timeout, | ||
}, | ||
warner: settings.Warner, | ||
metrics: settings.Metrics, | ||
}, nil | ||
} | ||
|
||
func (d *Dialer) String() string { | ||
return "dns over plaintext" | ||
} | ||
|
||
func (d *Dialer) Dial(ctx context.Context, network, _ string) ( | ||
conn net.Conn, err error, | ||
) { | ||
serverAddress := pickAddress(d.picker, d.servers, d.ipv6) | ||
|
||
udpConn, err := d.netDialer.DialContext(ctx, network, serverAddress) | ||
if err != nil { | ||
d.warner.Warn(err.Error()) | ||
d.metrics.PlainDialInc(serverAddress, "error") | ||
return nil, err | ||
} | ||
|
||
d.metrics.PlainDialInc(serverAddress, "success") | ||
return udpConn, nil | ||
} | ||
|
||
func pickAddress(picker *picker.Picker, servers []provider.PlainServer, | ||
ipv6 bool, | ||
) (address string) { | ||
server := picker.PlainServer(servers) | ||
addrPort := picker.PlainAddrPort(server, ipv6) | ||
return addrPort.String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package plain | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/qdm12/dns/v2/internal/picker" | ||
"github.com/qdm12/dns/v2/pkg/provider" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func Test_pickAddress(t *testing.T) { | ||
t.Parallel() | ||
|
||
picker := picker.New() | ||
servers := []provider.PlainServer{ | ||
provider.Cloudflare().Plain, | ||
provider.Google().Plain, | ||
} | ||
const ipv6 = true | ||
|
||
address := pickAddress(picker, servers, ipv6) | ||
|
||
found := false | ||
for _, server := range servers { | ||
ips := server.IPv4 | ||
if ipv6 { | ||
ips = append(ips, server.IPv6...) | ||
} | ||
for _, addrPort := range ips { | ||
if addrPort.String() == address { | ||
found = true | ||
break | ||
} | ||
} | ||
if found { | ||
break | ||
} | ||
} | ||
|
||
assert.True(t, found) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package plain | ||
|
||
type Metrics interface { | ||
PlainDialInc(address, outcome string) | ||
} | ||
|
||
type Warner interface { | ||
Warn(s string) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Package noop defines a No-Op metric implementation for DoT. | ||
package noop | ||
|
||
type Metrics struct{} | ||
|
||
func New() *Metrics { | ||
return &Metrics{} | ||
} | ||
|
||
func (m *Metrics) PlainDialInc(string, string) {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package prometheus | ||
|
||
import ( | ||
"github.com/prometheus/client_golang/prometheus" | ||
"github.com/qdm12/dns/v2/internal/metrics/prometheus/helpers" | ||
prom "github.com/qdm12/dns/v2/pkg/metrics/prometheus" | ||
) | ||
|
||
type counters struct { | ||
plainDial *prometheus.CounterVec | ||
} | ||
|
||
func newCounters(settings prom.Settings) (c *counters, err error) { | ||
prefix := settings.Prefix | ||
c = &counters{ | ||
plainDial: helpers.NewCounterVec(prefix, "plain_dials", | ||
"Plain dials by address and outcome", []string{"address", "outcome"}), | ||
} | ||
|
||
err = helpers.Register(settings.Registry, c.plainDial) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return c, nil | ||
} | ||
|
||
func (c *counters) PlainDialInc(address, outcome string) { | ||
c.plainDial.WithLabelValues(address, outcome).Inc() | ||
} |
Oops, something went wrong.