Default ports feature (#195)

* Static ports file added

* Removed .idea

* Added options for default ports

* Fixed var name ty[e

* Added default port function

* Fixed methods to be proper go

* Fixed port method

* Added blank add part

* Fixed http

* Fixed port bool

* Update to use host instead

* Fixed improper imp,amentation

* Better version

* Soltion for { in address

* Starting commit

* Removed unneeded code

* Added forgotten function

* Test for default-ports feature and simplify the function

* missing test

Co-authored-by: folbrich <frank.olbricht@gmail.com>
This commit is contained in:
Charles Porth
2022-01-08 16:41:04 -06:00
committed by GitHub
parent 4ca5495afc
commit a48eca521d
6 changed files with 260 additions and 2 deletions
+1 -1
View File
@@ -1 +1 @@
.idea/
.idea/
@@ -0,0 +1,154 @@
# This file shows a selection of well-known DNS resolvers and supported protocols to
# help build RoutedDNS configs. It isn't intended to be used directly but can for testing.
# Ports are not set in a config because they are set to use the default protocols port
title = "Resolvers for well-known DNS services"
# Cloudflare DNS-over-TLS
[resolvers.cloudflare-dot-1-1-1-1]
address = "1.1.1.1"
protocol = "dot"
[resolvers.cloudflare-dot-1-1-1-1-w-port]
address = "1.1.1.1:853"
protocol = "dot"
# Cloudflare DNS-over-HTTPS using the POST method
[resolvers.cloudflare-doh-1-1-1-1-post]
address = "https://1.1.1.1/dns-query"
protocol = "doh"
[resolvers.cloudflare-doh-1-0-0-1-post]
address = "https://1.0.0.1:443/dns-query"
protocol = "doh"
# Cloudflare DNS-over-HTTPS using the GET method
[resolvers.cloudflare-doh-1-1-1-1-get]
address = "https://1.1.1.1:443/dns-query{?dns}"
protocol = "doh"
doh = { method = "GET" }
[resolvers.cloudflare-doh-1-0-0-1-get]
address = "https://1.0.0.1/dns-query{?dns}"
protocol = "doh"
doh = { method = "GET" }
# Cloudflare DNS-over-HTTPS using the QUIC protocol
[resolvers.cloudflare-doh-quic]
address = "https://cloudflare-dns.com/dns-query"
protocol = "doh"
transport = "quic"
# Cloudflare plain DNS
[resolvers.cloudflare-udp-1-1-1-1]
address = "1.1.1.1"
protocol = "udp"
[resolvers.cloudflare-tcp-1-0-0-1]
address = "1.0.0.1:53"
protocol = "tcp"
# dnscrypt.ca server-1, DoH-GET
[resolvers.dnscrypt-1-doh-get]
address = "https://dns1.dnscrypt.ca:453/dns-query{?dns}"
protocol = "doh"
doh = { method = "GET" }
# dnscrypt.ca server-2, DoH-GET
[resolvers.dnscrypt-2-doh-get]
address = "https://dns2.dnscrypt.ca:453/dns-query{?dns}"
protocol = "doh"
doh = { method = "GET" }
# dnscrypt.ca server-1, DoH-POST
[resolvers.dnscrypt-1-doh-post]
address = "https://dns1.dnscrypt.ca:453/dns-query"
protocol = "doh"
# dnscrypt.ca server-2, DoH-POST
[resolvers.dnscrypt-2-doh-post]
address = "https://dns2.dnscrypt.ca:453/dns-query"
protocol = "doh"
# Google plain DNS
[resolvers.google-udp-8-8-8-8]
address = "8.8.8.8:53"
protocol = "udp"
[resolvers.google-tcp-8-8-4-4]
address = "8.8.4.4:53"
protocol = "udp"
# Google DNS-over-TLS
[resolvers.google-dot-8-8-8-8]
address = "8.8.8.8:853"
protocol = "dot"
[resolvers.google-dot-8-8-4-4]
address = "8.8.4.4"
protocol = "dot"
# Google DNS-over-HTTP using the POST method
[resolvers.google-doh-post]
address = "https://dns.google/dns-query"
protocol = "doh"
# Google DNS-over-HTTP using the GET method
[resolvers.google-doh-get]
address = "https://dns.google/dns-query{?dns}"
protocol = "doh"
doh = { method = "GET" }
# Google DNS-over-HTTP with bootstrapping to avoid initial lookup
[resolvers.google-doh-post-bootstrap]
address = "https://dns.google/dns-query"
protocol = "doh"
bootstrap-address = "8.8.8.8"
# Quad9 DNS-over-TLS
[resolvers.quad9-dot]
address = "9.9.9.9:853"
protocol = "dot"
# Quad9 DNS-over-HTTP using the POST method
[resolvers.quad9-doh-post]
address = "https://9.9.9.9/dns-query{?dns}"
protocol = "doh"
# CleanBrowsing DoT resolver
[resolvers.cleanbrowsing-dot]
address = "family-filter-dns.cleanbrowsing.org:853"
protocol = "dot"
# OpenDNS plain DNS (resolver1.opendns.com)
[resolvers.opendns-udp-1]
address = "208.67.222.222:53"
protocol = "udp"
# OpenDNS plain DNS (resolver2.opendns.com)
[resolvers.opendns-udp-2]
address = "208.67.222.220:53"
protocol = "udp"
# Adguard DNS-over-QUIC
[resolvers.adguard-doq]
address = "dns-unfiltered.adguard.com:8853"
protocol = "doq"
# Listeners
[listeners.local-udp]
address = "127.0.0.1:53"
protocol = "udp"
resolver = "cloudflare-doh-1-1-1-1-post"
[listeners.local-tcp]
address = "127.0.0.1"
protocol = "tcp"
resolver = "cloudflare-doh-1-1-1-1-post"
[listeners.all-dot]
address = ":853"
protocol = "dot"
resolver = "cloudflare-doh-1-1-1-1-post"
+11 -1
View File
@@ -182,7 +182,6 @@ func start(opt options, args []string) error {
if !ok && l.Protocol != "admin" {
return fmt.Errorf("listener '%s' references non-existant resolver, group or router '%s'", id, l.Resolver)
}
allowedNet, err := parseCIDRList(l.AllowedNet)
if err != nil {
return err
@@ -192,8 +191,10 @@ func start(opt options, args []string) error {
switch l.Protocol {
case "tcp":
l.Address = rdns.AddressWithDefault(l.Address, rdns.PlainDNSPort)
listeners = append(listeners, rdns.NewDNSListener(id, l.Address, "tcp", opt, resolver))
case "udp":
l.Address = rdns.AddressWithDefault(l.Address, rdns.PlainDNSPort)
listeners = append(listeners, rdns.NewDNSListener(id, l.Address, "udp", opt, resolver))
case "admin":
tlsConfig, err := rdns.TLSServerConfig(l.CA, l.ServerCrt, l.ServerKey, l.MutualTLS)
@@ -211,6 +212,7 @@ func start(opt options, args []string) error {
}
listeners = append(listeners, ln)
case "dot":
l.Address = rdns.AddressWithDefault(l.Address, rdns.DoTPort)
tlsConfig, err := rdns.TLSServerConfig(l.CA, l.ServerCrt, l.ServerKey, l.MutualTLS)
if err != nil {
return err
@@ -218,6 +220,7 @@ func start(opt options, args []string) error {
ln := rdns.NewDoTListener(id, l.Address, rdns.DoTListenerOptions{TLSConfig: tlsConfig, ListenOptions: opt}, resolver)
listeners = append(listeners, ln)
case "dtls":
l.Address = rdns.AddressWithDefault(l.Address, rdns.DTLSPort)
dtlsConfig, err := rdns.DTLSServerConfig(l.CA, l.ServerCrt, l.ServerKey, l.MutualTLS)
if err != nil {
return err
@@ -225,6 +228,11 @@ func start(opt options, args []string) error {
ln := rdns.NewDTLSListener(id, l.Address, rdns.DTLSListenerOptions{DTLSConfig: dtlsConfig, ListenOptions: opt}, resolver)
listeners = append(listeners, ln)
case "doh":
if l.Transport != "quic" {
l.Address = rdns.AddressWithDefault(l.Address, rdns.DoHPort)
} else if l.Transport == "quic" {
l.Address = rdns.AddressWithDefault(l.Address, rdns.DohQuicPort)
}
tlsConfig, err := rdns.TLSServerConfig(l.CA, l.ServerCrt, l.ServerKey, l.MutualTLS)
if err != nil {
return err
@@ -248,6 +256,8 @@ func start(opt options, args []string) error {
}
listeners = append(listeners, ln)
case "doq":
l.Address = rdns.AddressWithDefault(l.Address, rdns.DoQPort)
tlsConfig, err := rdns.TLSServerConfig(l.CA, l.ServerCrt, l.ServerKey, l.MutualTLS)
if err != nil {
return err
+11
View File
@@ -11,7 +11,10 @@ import (
func instantiateResolver(id string, r resolver, resolvers map[string]rdns.Resolver) error {
var err error
switch r.Protocol {
case "doq":
r.Address = rdns.AddressWithDefault(r.Address, rdns.DoQPort)
tlsConfig, err := rdns.TLSClientConfig(r.CA, r.ClientCrt, r.ClientKey)
if err != nil {
return err
@@ -26,6 +29,8 @@ func instantiateResolver(id string, r resolver, resolvers map[string]rdns.Resolv
return err
}
case "dot":
r.Address = rdns.AddressWithDefault(r.Address, rdns.DoTPort)
tlsConfig, err := rdns.TLSClientConfig(r.CA, r.ClientCrt, r.ClientKey)
if err != nil {
return err
@@ -40,6 +45,8 @@ func instantiateResolver(id string, r resolver, resolvers map[string]rdns.Resolv
return err
}
case "dtls":
r.Address = rdns.AddressWithDefault(r.Address, rdns.DTLSPort)
dtlsConfig, err := rdns.DTLSClientConfig(r.CA, r.ClientCrt, r.ClientKey)
if err != nil {
return err
@@ -55,6 +62,8 @@ func instantiateResolver(id string, r resolver, resolvers map[string]rdns.Resolv
return err
}
case "doh":
r.Address = rdns.AddressWithDefault(r.Address, rdns.DoHPort)
tlsConfig, err := rdns.TLSClientConfig(r.CA, r.ClientCrt, r.ClientKey)
if err != nil {
return err
@@ -71,6 +80,8 @@ func instantiateResolver(id string, r resolver, resolvers map[string]rdns.Resolv
return err
}
case "tcp", "udp":
r.Address = rdns.AddressWithDefault(r.Address, rdns.PlainDNSPort)
opt := rdns.DNSClientOptions{
LocalAddr: net.ParseIP(r.LocalAddr),
UDPSize: r.EDNS0UDPSize,
+47
View File
@@ -0,0 +1,47 @@
package rdns
import (
"net"
"net/url"
"strings"
)
var (
DoQPort string = "8853"
DohQuicPort string = "1443"
DoTPort string = "853"
DTLSPort string = DoTPort
DoHPort string = "443"
PlainDNSPort = "53"
)
// AddressWithDefault takes an endpoint or a URL and adds a port unless it
// already has one. If it fails to parse addr, it returns the original value.
func AddressWithDefault(addr, defaultPort string) string {
// Endpoints like DoH can contain URL templates, so we want to strip those
// off first
parts := strings.SplitN(addr, "{", 2)
endpointPart := parts[0]
var templatePart string
if len(parts) == 2 {
templatePart = "{" + parts[1]
}
// Now let's see if it's a URL. If it is, it'll have a "/" in it
if strings.Contains(endpointPart, "/") {
u, err := url.Parse(endpointPart)
if err != nil {
return addr
}
if u.Port() == "" {
u.Host = net.JoinHostPort(u.Host, defaultPort)
}
return u.String() + templatePart
}
// Here we know it's not a URL, so it should be either <host>:<port> or just <host>
if strings.Contains(endpointPart, ":") {
return addr
}
return net.JoinHostPort(endpointPart, defaultPort)
}
+36
View File
@@ -0,0 +1,36 @@
package rdns
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestDefaultPort(t *testing.T) {
tests := []struct {
address string
defaultPort string
expected string
}{
{"", DoTPort, ":853"},
{"localhost", DoTPort, "localhost:853"},
{"localhost:123", DoTPort, "localhost:123"},
{"1.2.3.4", DoTPort, "1.2.3.4:853"},
{"1.2.3.4:123", DoTPort, "1.2.3.4:123"},
{"https://localhost", DoHPort, "https://localhost:443"},
{"https://localhost:123", DoHPort, "https://localhost:123"},
{"https://localhost:123/path", DoHPort, "https://localhost:123/path"},
{"https://localhost/dns-query{?dns}", DoHPort, "https://localhost:443/dns-query{?dns}"},
{"https://1.1.1.1:443/dns-query{?dns}", DoHPort, "https://1.1.1.1:443/dns-query{?dns}"},
// Invalid endpoints should ideally not be changed
{"localhost:", DoTPort, "localhost:"},
{"localhost::123", DoTPort, "localhost::123"},
{"127.0.0.1:", DoTPort, "127.0.0.1:"},
{"127.0.0.1::123", DoTPort, "127.0.0.1::123"},
}
for _, test := range tests {
out := AddressWithDefault(test.address, test.defaultPort)
require.Equal(t, test.expected, out)
}
}