feat: add tls config for dot lookups

Ref https://github.com/mr-karan/doggo/issues/29
pull/41/head v0.5.2
Karan Sharma 2022-05-18 09:56:07 +05:30
parent 0ce04d0c13
commit 53f7b70af4
7 changed files with 83 additions and 78 deletions

View File

@ -216,6 +216,8 @@ URL scheme of the server is used to identify which resolver to use for lookups.
--timeout Specify timeout (in seconds) for the resolver to return a response. --timeout Specify timeout (in seconds) for the resolver to return a response.
-4 --ipv4 Use IPv4 only. -4 --ipv4 Use IPv4 only.
-6 --ipv6 Use IPv6 only. -6 --ipv6 Use IPv6 only.
--tls-hostname=HOSTNAME Provide a hostname for doing verification of the certificate if the provided DoT nameserver is an IP.
--skip-hostname-verification Skip TLS Hostname Verification in case of DOT Lookups.
``` ```

View File

@ -46,6 +46,8 @@ func main() {
f.BoolP("ipv4", "4", false, "Use IPv4 only") f.BoolP("ipv4", "4", false, "Use IPv4 only")
f.BoolP("ipv6", "6", false, "Use IPv6 only") f.BoolP("ipv6", "6", false, "Use IPv6 only")
f.String("strategy", "all", "Strategy to query nameservers in resolv.conf file (`all`, `random`, `first`)") f.String("strategy", "all", "Strategy to query nameservers in resolv.conf file (`all`, `random`, `first`)")
f.String("tls-hostname", "", "Provide a hostname for doing verification of the certificate if the provided DoT nameserver is an IP")
f.Bool("skip-hostname-verification", false, "Skip TLS Hostname Verification")
// Output Options // Output Options
f.BoolP("json", "J", false, "Set the output format as JSON") f.BoolP("json", "J", false, "Set the output format as JSON")
@ -129,6 +131,8 @@ func main() {
Timeout: app.QueryFlags.Timeout * time.Second, Timeout: app.QueryFlags.Timeout * time.Second,
Logger: app.Logger, Logger: app.Logger,
Strategy: app.QueryFlags.Strategy, Strategy: app.QueryFlags.Strategy,
InsecureSkipVerify: app.QueryFlags.InsecureSkipVerify,
TLSHostname: app.QueryFlags.TLSHostname,
}) })
if err != nil { if err != nil {
app.Logger.WithError(err).Error("error loading resolver") app.Logger.WithError(err).Error("error loading resolver")

View File

@ -53,6 +53,9 @@ var appHelpTextTemplate = `{{ "NAME" | color "" "heading" }}:
{{"--timeout" | color "yellow" ""}} Specify timeout (in seconds) for the resolver to return a response. {{"--timeout" | color "yellow" ""}} Specify timeout (in seconds) for the resolver to return a response.
{{"-4 --ipv4" | color "yellow" ""}} Use IPv4 only. {{"-4 --ipv4" | color "yellow" ""}} Use IPv4 only.
{{"-6 --ipv6" | color "yellow" ""}} Use IPv6 only. {{"-6 --ipv6" | color "yellow" ""}} Use IPv6 only.
{{"--ndots=INT" | color "yellow" ""}} Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise.
{{"--tls-hostname=HOSTNAME" | color "yellow" ""}} Provide a hostname for doing verification of the certificate if the provided DoT nameserver is an IP.
{{"--skip-hostname-verification" | color "yellow" ""}} Skip TLS Hostname Verification in case of DOT Lookups.
{{ "Output Options" | color "" "heading" }}: {{ "Output Options" | color "" "heading" }}:
{{"-J, --json " | color "yellow" ""}} Format the output as JSON. {{"-J, --json " | color "yellow" ""}} Format the output as JSON.

View File

@ -37,6 +37,8 @@ type QueryFlags struct {
UseSearchList bool `koanf:"search" json:"-"` UseSearchList bool `koanf:"search" json:"-"`
ReverseLookup bool `koanf:"reverse" reverse:"-"` ReverseLookup bool `koanf:"reverse" reverse:"-"`
Strategy string `koanf:"strategy" strategy:"-"` Strategy string `koanf:"strategy" strategy:"-"`
InsecureSkipVerify bool `koanf:"skip-hostname-verification" skip-hostname-verification:"-"`
TLSHostname string `koanf:"tls-hostname" tls-hostname:"-"`
} }
// Nameserver represents the type of Nameserver // Nameserver represents the type of Nameserver

View File

@ -1,6 +1,7 @@
package resolvers package resolvers
import ( import (
"crypto/tls"
"time" "time"
"github.com/miekg/dns" "github.com/miekg/dns"
@ -16,8 +17,6 @@ type ClassicResolver struct {
// ClassicResolverOpts holds options for setting up a Classic resolver. // ClassicResolverOpts holds options for setting up a Classic resolver.
type ClassicResolverOpts struct { type ClassicResolverOpts struct {
IPv4Only bool
IPv6Only bool
UseTLS bool UseTLS bool
UseTCP bool UseTCP bool
} }
@ -34,15 +33,20 @@ func NewClassicResolver(server string, classicOpts ClassicResolverOpts, resolver
net = "tcp" net = "tcp"
} }
if classicOpts.IPv4Only { if resolverOpts.UseIPv4 {
net = net + "4" net = net + "4"
} }
if classicOpts.IPv6Only { if resolverOpts.UseIPv6 {
net = net + "6" net = net + "6"
} }
if classicOpts.UseTLS { if classicOpts.UseTLS {
net = net + "-tls" net = net + "-tls"
// Provide extra TLS config for doing/skipping hostname verification.
client.TLSConfig = &tls.Config{
ServerName: resolverOpts.TLSHostname,
InsecureSkipVerify: resolverOpts.InsecureSkipVerify,
}
} }
client.Net = net client.Net = net

View File

@ -18,9 +18,6 @@ type DNSCryptResolver struct {
// DNSCryptResolverOpts holds options for setting up a DNSCrypt resolver. // DNSCryptResolverOpts holds options for setting up a DNSCrypt resolver.
type DNSCryptResolverOpts struct { type DNSCryptResolverOpts struct {
IPv4Only bool
IPv6Only bool
UseTLS bool
UseTCP bool UseTCP bool
} }
@ -30,6 +27,7 @@ func NewDNSCryptResolver(server string, dnscryptOpts DNSCryptResolverOpts, resol
if dnscryptOpts.UseTCP { if dnscryptOpts.UseTCP {
net = "tcp" net = "tcp"
} }
client := &dnscrypt.Client{Net: net, Timeout: resolverOpts.Timeout, UDPSize: 4096} client := &dnscrypt.Client{Net: net, Timeout: resolverOpts.Timeout, UDPSize: 4096}
resolverInfo, err := client.Dial(server) resolverInfo, err := client.Dial(server)
if err != nil { if err != nil {

View File

@ -11,14 +11,17 @@ import (
// Options represent a set of common options // Options represent a set of common options
// to configure a Resolver. // to configure a Resolver.
type Options struct { type Options struct {
Logger *logrus.Logger
Nameservers []models.Nameserver Nameservers []models.Nameserver
UseIPv4 bool UseIPv4 bool
UseIPv6 bool UseIPv6 bool
SearchList []string SearchList []string
Ndots int Ndots int
Timeout time.Duration Timeout time.Duration
Logger *logrus.Logger
Strategy string Strategy string
InsecureSkipVerify bool
TLSHostname string
} }
// Resolver implements the configuration for a DNS // Resolver implements the configuration for a DNS
@ -68,18 +71,13 @@ type Authority struct {
// LoadResolvers loads differently configured // LoadResolvers loads differently configured
// resolvers based on a list of nameserver. // resolvers based on a list of nameserver.
func LoadResolvers(opts Options) ([]Resolver, error) { func LoadResolvers(opts Options) ([]Resolver, error) {
var resolverOpts = Options{ // For each nameserver, initialise the correct resolver.
Timeout: opts.Timeout,
Ndots: opts.Ndots,
SearchList: opts.SearchList,
Logger: opts.Logger,
}
// for each nameserver, initialise the correct resolver
rslvrs := make([]Resolver, 0, len(opts.Nameservers)) rslvrs := make([]Resolver, 0, len(opts.Nameservers))
for _, ns := range opts.Nameservers { for _, ns := range opts.Nameservers {
if ns.Type == models.DOHResolver { if ns.Type == models.DOHResolver {
opts.Logger.Debug("initiating DOH resolver") opts.Logger.Debug("initiating DOH resolver")
rslvr, err := NewDOHResolver(ns.Address, resolverOpts) rslvr, err := NewDOHResolver(ns.Address, opts)
if err != nil { if err != nil {
return rslvrs, err return rslvrs, err
} }
@ -89,11 +87,9 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
opts.Logger.Debug("initiating DOT resolver") opts.Logger.Debug("initiating DOT resolver")
rslvr, err := NewClassicResolver(ns.Address, rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{ ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: true, UseTLS: true,
UseTCP: true, UseTCP: true,
}, resolverOpts) }, opts)
if err != nil { if err != nil {
return rslvrs, err return rslvrs, err
@ -104,11 +100,9 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
opts.Logger.Debug("initiating TCP resolver") opts.Logger.Debug("initiating TCP resolver")
rslvr, err := NewClassicResolver(ns.Address, rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{ ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: false, UseTLS: false,
UseTCP: true, UseTCP: true,
}, resolverOpts) }, opts)
if err != nil { if err != nil {
return rslvrs, err return rslvrs, err
} }
@ -118,11 +112,9 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
opts.Logger.Debug("initiating UDP resolver") opts.Logger.Debug("initiating UDP resolver")
rslvr, err := NewClassicResolver(ns.Address, rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{ ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: false, UseTLS: false,
UseTCP: false, UseTCP: false,
}, resolverOpts) }, opts)
if err != nil { if err != nil {
return rslvrs, err return rslvrs, err
} }
@ -133,7 +125,7 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
rslvr, err := NewDNSCryptResolver(ns.Address, rslvr, err := NewDNSCryptResolver(ns.Address,
DNSCryptResolverOpts{ DNSCryptResolverOpts{
UseTCP: false, UseTCP: false,
}, resolverOpts) }, opts)
if err != nil { if err != nil {
return rslvrs, err return rslvrs, err
} }
@ -141,7 +133,7 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
} }
if ns.Type == models.DOQResolver { if ns.Type == models.DOQResolver {
opts.Logger.Debug("initiating DOQ resolver") opts.Logger.Debug("initiating DOQ resolver")
rslvr, err := NewDOQResolver(ns.Address, resolverOpts) rslvr, err := NewDOQResolver(ns.Address, opts)
if err != nil { if err != nil {
return rslvrs, err return rslvrs, err
} }