Skip to content

Commit

Permalink
Pull request: 5117 backport dns64
Browse files Browse the repository at this point in the history
Merge in DNS/dnsproxy from 5117-backport-dns64 to master

Updates AdguardTeam/AdGuardHome#5117.

Squashed commit of the following:

commit 7fcd7d8
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Feb 3 15:03:17 2023 +0300

    proxy: fix test

commit ec1b3d7
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Feb 3 14:00:42 2023 +0300

    proxy: imp docs

commit eb0b1e3
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Feb 2 20:08:40 2023 +0300

    proxy: imp and test

commit d4b9133
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Feb 2 17:40:56 2023 +0300

    proxy: fix race in test

commit ef90bd3
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Feb 2 15:33:04 2023 +0300

    proxy: fit gocyclo into 10, imp logs

commit 0e25eb6
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Feb 2 14:01:12 2023 +0300

    all: imp code, tests

commit a58f2f2
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Feb 1 14:35:30 2023 +0300

    proxy: fix const name

commit 266095a
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Feb 1 14:31:11 2023 +0300

    proxy: rm unused, exp const

commit ccafca5
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Wed Feb 1 13:41:19 2023 +0300

    proxy: backport dns64, depr old api
  • Loading branch information
EugeneOne1 authored and ainar-g committed Feb 6, 2023
1 parent ea04aad commit 5d50fff
Show file tree
Hide file tree
Showing 12 changed files with 900 additions and 339 deletions.
109 changes: 61 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,50 +37,52 @@ Usage:
dnsproxy [OPTIONS]
Application Options:
--config-path= yaml configuration file. Minimal working configuration in config.yaml.dist.
Options passed through command line will override the ones from this file.
-v, --verbose Verbose output (optional)
-o, --output= Path to the log file. If not set, write to stdout.
-l, --listen= Listening addresses
-p, --port= Listening ports. Zero value disables TCP and UDP listeners
-s, --https-port= Listening ports for DNS-over-HTTPS
-t, --tls-port= Listening ports for DNS-over-TLS
-q, --quic-port= Listening ports for DNS-over-QUIC
-y, --dnscrypt-port= Listening ports for DNSCrypt
-c, --tls-crt= Path to a file with the certificate chain
-k, --tls-key= Path to a file with the private key
--tls-min-version= Minimum TLS version, for example 1.0
--tls-max-version= Maximum TLS version, for example 1.3
--insecure Disable secure TLS certificate validation
-g, --dnscrypt-config= Path to a file with DNSCrypt configuration. You can generate one using https://github.com/ameshkov/dnscrypt
--http3 Enable HTTP/3 support
-u, --upstream= An upstream to be used (can be specified multiple times).
You can also specify path to a file with the list of servers
-b, --bootstrap= Bootstrap DNS for DoH and DoT, can be specified multiple times (default: 8.8.8.8:53)
-f, --fallback= Fallback resolvers to use when regular ones are unavailable, can be specified multiple times.
You can also specify path to a file with the list of servers
--all-servers If specified, parallel queries to all configured upstream servers are enabled
--fastest-addr Respond to A or AAAA requests only with the fastest IP address
--cache If specified, DNS cache is enabled
--cache-size= Cache size (in bytes). Default: 64k
--cache-min-ttl= Minimum TTL value for DNS entries, in seconds. Capped at 3600.
Artificially extending TTLs should only be done with careful consideration.
--cache-max-ttl= Maximum TTL value for DNS entries, in seconds.
--cache-optimistic If specified, optimistic DNS cache is enabled
-r, --ratelimit= Ratelimit (requests per second)
--refuse-any If specified, refuse ANY requests
--edns Use EDNS Client Subnet extension
--edns-addr= Send EDNS Client Address
--dns64 If specified, dnsproxy will act as a DNS64 server
--dns64-prefix= If specified, this is the DNS64 prefix dnsproxy will be using when it works as a DNS64 server.
If not specified, dnsproxy uses the 'Well-Known Prefix' 64:ff9b::
--ipv6-disabled If specified, all AAAA requests will be replied with NoError RCode and empty answer
--bogus-nxdomain= Transform the responses containing at least a single IP that matches specified addresses
and CIDRs into NXDOMAIN. Can be specified multiple times.
--udp-buf-size= Set the size of the UDP buffer in bytes. A value <= 0 will use the system default.
--max-go-routines= Set the maximum number of go routines. A value <= 0 will not not set a maximum.
--pprof If present, exposes pprof information on localhost:6060.
--version Prints the program version
--config-path= yaml configuration file. Minimal working configuration in config.yaml.dist.
Options passed through command line will override the ones from this file.
-v, --verbose Verbose output (optional)
-o, --output= Path to the log file. If not set, write to stdout.
-l, --listen= Listening addresses
-p, --port= Listening ports. Zero value disables TCP and UDP listeners
-s, --https-port= Listening ports for DNS-over-HTTPS
-t, --tls-port= Listening ports for DNS-over-TLS
-q, --quic-port= Listening ports for DNS-over-QUIC
-y, --dnscrypt-port= Listening ports for DNSCrypt
-c, --tls-crt= Path to a file with the certificate chain
-k, --tls-key= Path to a file with the private key
--tls-min-version= Minimum TLS version, for example 1.0
--tls-max-version= Maximum TLS version, for example 1.3
--insecure Disable secure TLS certificate validation
-g, --dnscrypt-config= Path to a file with DNSCrypt configuration. You can generate one using https://github.com/ameshkov/dnscrypt
--http3 Enable HTTP/3 support
-u, --upstream= An upstream to be used (can be specified multiple times).
You can also specify path to a file with the list of servers
-b, --bootstrap= Bootstrap DNS for DoH and DoT, can be specified multiple times (default: 8.8.8.8:53)
-f, --fallback= Fallback resolvers to use when regular ones are unavailable, can be specified multiple times.
You can also specify path to a file with the list of servers
--private-rdns-upstream= Private DNS upstreams to use for reverse DNS lookups of private addresses, can
be specified multiple times
--all-servers If specified, parallel queries to all configured upstream servers are enabled
--fastest-addr Respond to A or AAAA requests only with the fastest IP address
--cache If specified, DNS cache is enabled
--cache-size= Cache size (in bytes). Default: 64k
--cache-min-ttl= Minimum TTL value for DNS entries, in seconds. Capped at 3600.
Artificially extending TTLs should only be done with careful consideration.
--cache-max-ttl= Maximum TTL value for DNS entries, in seconds.
--cache-optimistic If specified, optimistic DNS cache is enabled
-r, --ratelimit= Ratelimit (requests per second)
--refuse-any If specified, refuse ANY requests
--edns Use EDNS Client Subnet extension
--edns-addr= Send EDNS Client Address
--dns64 If specified, dnsproxy will act as a DNS64 server
--dns64-prefix= Prefix used to handle DNS64. If not specified, dnsproxy uses the 'Well-Known Prefix' 64:ff9b::.
Can be specified multiple times
--ipv6-disabled If specified, all AAAA requests will be replied with NoError RCode and empty answer
--bogus-nxdomain= Transform the responses containing at least a single IP that matches specified addresses
and CIDRs into NXDOMAIN. Can be specified multiple times.
--udp-buf-size= Set the size of the UDP buffer in bytes. A value <= 0 will use the system default.
--max-go-routines= Set the maximum number of go routines. A value <= 0 will not not set a maximum.
--pprof If present, exposes pprof information on localhost:6060.
--version Prints the program version
Help Options:
-h, --help Show this help message
Expand Down Expand Up @@ -230,16 +232,27 @@ Loads upstreams list from a file.
> (with A but not AAAA records in the DNS). This lets IPv6-only clients use
> NAT64 gateways without any other configuration.
Enables DNS64 with the default "Well-Known Prefix" `64:ff9b::/96`:
See also [RFC 6147](https://datatracker.ietf.org/doc/html/rfc6147).
Enables DNS64 with the default [Well-Known Prefix][wkp]:
```shell
./dnsproxy -l 127.0.0.1 -p 5353 -u 8.8.8.8 --dns64
./dnsproxy -l 127.0.0.1 -p 5353 -u 8.8.8.8 --private-rdns-upstream=127.0.0.1 --dns64
```
You can also specify a custom DNS64 prefix:
You can also specify any number of custom DNS64 prefixes:
```shell
./dnsproxy -l 127.0.0.1 -p 5353 -u 8.8.8.8 --dns64 --dns64-prefix=64:ffff::
./dnsproxy -l 127.0.0.1 -p 5353 -u 8.8.8.8 --private-rdns-upstream=127.0.0.1 --dns64 --dns64-prefix=64:ffff:: --dns64-prefix=32:ffff::
```
Note that only the first specified prefix will be used for synthesis.
PTR queries for addresses within the specified ranges or the
[Well-Known one][wkp] could only be answered with locally appropriate data, so
dnsproxy will route those to the local upstream servers. Those should be
specified if DNS64 is enabled.
[wkp]: https://datatracker.ietf.org/doc/html/rfc6052#section-2.1
### Fastest addr + cache-min-ttl
This option would be useful to the users with problematic network connection.
Expand Down
93 changes: 55 additions & 38 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net"
"net/http"
"net/http/pprof"
"net/netip"
"os"
"os/signal"
"strings"
Expand All @@ -25,7 +26,6 @@ import (
// use the default option since it will cause some problems when config files
// are used.
type Options struct {

// Configuration file path (yaml), the config path should be read without
// using goFlags in order not to have default values overriding yaml
// options.
Expand Down Expand Up @@ -98,6 +98,10 @@ type Options struct {
// Fallback DNS resolver
Fallbacks []string `yaml:"fallback" short:"f" long:"fallback" description:"Fallback resolvers to use when regular ones are unavailable, can be specified multiple times. You can also specify path to a file with the list of servers"`

// PrivateRDNSUpstreams are upstreams to use for reverse DNS lookups of
// private addresses.
PrivateRDNSUpstreams []string `yaml:"private-rdns-upstream" long:"private-rdns-upstream" description:"Private DNS upstreams to use for reverse DNS lookups of private addresses, can be specified multiple times"`

// If true, parallel queries to all configured upstream servers
AllServers bool `yaml:"all-servers" long:"all-servers" description:"If specified, parallel queries to all configured upstream servers are enabled" optional:"yes" optional-value:"true"`

Expand Down Expand Up @@ -147,8 +151,10 @@ type Options struct {
// Defines whether DNS64 functionality is enabled or not
DNS64 bool `yaml:"dns64" long:"dns64" description:"If specified, dnsproxy will act as a DNS64 server" optional:"yes" optional-value:"true"`

// DNS64Prefix defines the DNS64 prefix that dnsproxy should use when it acts as a DNS64 server
DNS64Prefix string `yaml:"dns64-prefix" long:"dns64-prefix" description:"If specified, this is the DNS64 prefix dnsproxy will be using when it works as a DNS64 server. If not specified, dnsproxy uses the 'Well-Known Prefix' 64:ff9b::" required:"false"`
// DNS64Prefix defines the DNS64 prefixes that dnsproxy should use when it
// acts as a DNS64 server. If not specified, dnsproxy uses the default
// Well-Known Prefix. This option can be specified multiple times.
DNS64Prefix []string `yaml:"dns64-prefix" long:"dns64-prefix" description:"Prefix used to handle DNS64. If not specified, dnsproxy uses the 'Well-Known Prefix' 64:ff9b::. Can be specified multiple times" required:"false"`

// Other settings and options
// --
Expand Down Expand Up @@ -176,11 +182,10 @@ type Options struct {
// VersionString will be set through ldflags, contains current version
var VersionString = "dev" // nolint:gochecknoglobals

const defaultTimeout = 10 * time.Second

// defaultDNS64Prefix is a so-called "Well-Known Prefix" for DNS64.
// if dnsproxy operates as a DNS64 server, we'll be using it.
const defaultDNS64Prefix = "64:ff9b::/96"
const (
defaultTimeout = 10 * time.Second
defaultLocalTimeout = 1 * time.Second
)

func main() {
options := &Options{}
Expand Down Expand Up @@ -243,9 +248,6 @@ func run(options *Options) {
config := createProxyConfig(options)
dnsProxy := &proxy.Proxy{Config: config}

// Init DNS64 if needed.
initDNS64(dnsProxy, options)

// Add extra handler if needed.
if options.IPv6Disabled {
ipv6Configuration := ipv6Configuration{ipv6Disabled: options.IPv6Disabled}
Expand Down Expand Up @@ -321,20 +323,21 @@ func createProxyConfig(options *Options) proxy.Config {
MaxGoroutines: options.MaxGoRoutines,
}

// TODO(e.burkov): Make these methods of [Options].
initUpstreams(&config, options)
initEDNS(&config, options)
initBogusNXDomain(&config, options)
initTLSConfig(&config, options)
initDNSCryptConfig(&config, options)
initListenAddrs(&config, options)
initDNS64(&config, options)

return config
}

// initUpstreams inits upstream-related config
func initUpstreams(config *proxy.Config, options *Options) {
// Init upstreams
upstreams := loadServersList(options.Upstreams)

httpVersions := upstream.DefaultHTTPVersions
if options.HTTP3 {
Expand All @@ -345,24 +348,29 @@ func initUpstreams(config *proxy.Config, options *Options) {
}
}

var err error

upstreams := loadServersList(options.Upstreams)
upsOpts := &upstream.Options{
HTTPVersions: httpVersions,
InsecureSkipVerify: options.Insecure,
Bootstrap: options.BootstrapDNS,
Timeout: defaultTimeout,
}
upstreamConfig, err := proxy.ParseUpstreamsConfig(upstreams, upsOpts)
config.UpstreamConfig, err = proxy.ParseUpstreamsConfig(upstreams, upsOpts)
if err != nil {
log.Fatalf("error while parsing upstreams configuration: %s", err)
}
config.UpstreamConfig = upstreamConfig

if options.AllServers {
config.UpstreamMode = proxy.UModeParallel
} else if options.FastestAddress {
config.UpstreamMode = proxy.UModeFastestAddr
} else {
config.UpstreamMode = proxy.UModeLoadBalance
privUpstreams := loadServersList(options.PrivateRDNSUpstreams)
privUpsOpts := &upstream.Options{
HTTPVersions: httpVersions,
Bootstrap: options.BootstrapDNS,
Timeout: defaultLocalTimeout,
}
config.PrivateRDNSUpstreamConfig, err = proxy.ParseUpstreamsConfig(privUpstreams, privUpsOpts)
if err != nil {
log.Fatalf("error while parsing private rdns upstreams configuration: %s", err)
}

if options.Fallbacks != nil {
Expand All @@ -373,15 +381,27 @@ func initUpstreams(config *proxy.Config, options *Options) {
// separately.
//
// See https://github.com/AdguardTeam/dnsproxy/issues/161.
fallback, err := upstream.AddressToUpstream(f, upsOpts)
var fallback upstream.Upstream
fallback, err = upstream.AddressToUpstream(f, upsOpts)
if err != nil {
log.Fatalf("cannot parse the fallback %s (%s): %s", f, options.BootstrapDNS, err)
}
log.Printf("Fallback %d is %s", i, fallback.Address())

log.Printf("fallback at index %d is %s", i, fallback.Address())

fallbacks = append(fallbacks, fallback)
}

config.Fallbacks = fallbacks
}

if options.AllServers {
config.UpstreamMode = proxy.UModeParallel
} else if options.FastestAddress {
config.UpstreamMode = proxy.UModeFastestAddr
} else {
config.UpstreamMode = proxy.UModeLoadBalance
}
}

// initEDNS inits EDNS-related config
Expand Down Expand Up @@ -527,30 +547,27 @@ func initListenAddrs(config *proxy.Config, options *Options) {
}
}

// initDNS64 inits the DNS64 configuration for dnsproxy
func initDNS64(p *proxy.Proxy, options *Options) {
if !options.DNS64 {
// initDNS64 sets the DNS64 configuration into conf.
func initDNS64(conf *proxy.Config, options *Options) {
if conf.UseDNS64 = options.DNS64; !conf.UseDNS64 {
return
}

dns64Prefix := options.DNS64Prefix
if dns64Prefix == "" {
dns64Prefix = defaultDNS64Prefix
if len(conf.PrivateRDNSUpstreamConfig.Upstreams) == 0 {
log.Fatalf("at least one private upstream must be configured to use dns64")
}

// DNS64 prefix may be specified as a CIDR: "64:ff9b::/96"
ip, _, err := net.ParseCIDR(dns64Prefix)
if err != nil {
// Or it could be specified as an IP address: "64:ff9b::"
ip = net.ParseIP(dns64Prefix)
}
var prefs []netip.Prefix
for i, p := range options.DNS64Prefix {
pref, err := netip.ParsePrefix(p)
if err != nil {
log.Fatalf("parsing prefix at index %d: %v", i, err)
}

if ip == nil || len(ip) < net.IPv6len {
log.Fatalf("Invalid DNS64 prefix: %s", dns64Prefix)
return
prefs = append(prefs, pref)
}

p.SetNAT64Prefix(ip[:proxy.NAT64PrefixLength])
conf.DNS64Prefs = prefs
}

// IPv6 configuration
Expand Down
Loading

0 comments on commit 5d50fff

Please sign in to comment.