Skip to content

Commit

Permalink
Pull request 250: 4262-ipv6-pref
Browse files Browse the repository at this point in the history
Updates AdguardTeam/AdGuardHome#4262.

Squashed commit of the following:

commit 0f2c311
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Apr 3 17:39:16 2023 +0300

    all: add ip proto pref
  • Loading branch information
ainar-g committed Apr 3, 2023
1 parent 8ae0746 commit f8f22ab
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 7 deletions.
51 changes: 51 additions & 0 deletions internal/netutil/netutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Package netutil contains network-related utilities common among dnsproxy
// packages.
//
// TODO(a.garipov): Move improved versions of these into netutil in module
// golibs.
package netutil

import (
"net"

glnetutil "github.com/AdguardTeam/golibs/netutil"
"golang.org/x/exp/slices"
)

// SortIPAddrs sorts addrs in accordance with the protocol preferences. Invalid
// addresses are sorted near the end. Zones are ignored.
//
// TODO(a.garipov): Use netip.Addr instead of net.IPAddr everywhere where this
// is called.
func SortIPAddrs(addrs []net.IPAddr, preferIPv6 bool) {
l := len(addrs)
if l <= 1 {
return
}

slices.SortStableFunc(addrs, func(addrA, addrB net.IPAddr) (sortsBefore bool) {
// Assume that len(addrs) is mostly small, so these conversions aren't
// as expensive as they could have been.
a, err := glnetutil.IPToAddrNoMapped(addrA.IP)
if err != nil {
return false
}

b, err := glnetutil.IPToAddrNoMapped(addrB.IP)
if err != nil {
return false
}

aIs4 := a.Is4()
bIs4 := b.Is4()
if aIs4 != bIs4 {
if aIs4 {
return !preferIPv6
}

return preferIPv6
}

return a.Less(b)
})
}
52 changes: 52 additions & 0 deletions internal/netutil/netutil_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package netutil_test

import (
"fmt"
"net"

"github.com/AdguardTeam/dnsproxy/internal/netutil"
)

func ExampleSortIPAddrs() {
printAddrs := func(header string, addrs []net.IPAddr) {
fmt.Printf("%s:\n", header)
for i, a := range addrs {
fmt.Printf("%d: %s\n", i+1, a.IP)
}

fmt.Println()
}

addrs := []net.IPAddr{{
IP: net.ParseIP("1.2.3.4"),
}, {
IP: net.ParseIP("1.2.3.5"),
}, {
IP: net.ParseIP("2a00::1234"),
}, {
IP: net.ParseIP("2a00::1235"),
}, {
IP: nil,
}}
netutil.SortIPAddrs(addrs, false)
printAddrs("IPv4 preferred", addrs)

netutil.SortIPAddrs(addrs, true)
printAddrs("IPv6 preferred", addrs)

// Output:
//
// IPv4 preferred:
// 1: 1.2.3.4
// 2: 1.2.3.5
// 3: 2a00::1234
// 4: 2a00::1235
// 5: <nil>
//
// IPv6 preferred:
// 1: 2a00::1234
// 2: 2a00::1235
// 3: 1.2.3.4
// 4: 1.2.3.5
// 5: <nil>
}
4 changes: 4 additions & 0 deletions proxy/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ type Config struct {
// value disables the feature. An empty value will be interpreted as the
// default Well-Known Prefix.
DNS64Prefs []netip.Prefix

// PreferIPv6 tells the proxy to prefer IPv6 addresses when bootstrapping
// upstreams that use hostnames.
PreferIPv6 bool
}

// validateConfig verifies that the supplied configuration is valid and returns an error if it's not
Expand Down
5 changes: 4 additions & 1 deletion proxy/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package proxy
import (
"net"

proxynetutil "github.com/AdguardTeam/dnsproxy/internal/netutil"
"github.com/AdguardTeam/dnsproxy/proxyutil"
"github.com/AdguardTeam/golibs/errors"

Expand Down Expand Up @@ -65,5 +66,7 @@ func (p *Proxy) LookupIPAddr(host string) ([]net.IPAddr, error) {
return []net.IPAddr{}, errs[0]
}

return proxyutil.SortIPAddrs(ipAddrs), nil
proxynetutil.SortIPAddrs(ipAddrs, p.Config.PreferIPv6)

return ipAddrs, nil
}
3 changes: 3 additions & 0 deletions proxyutil/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ func AppendIPAddrs(ipAddrs *[]net.IPAddr, answers []dns.RR) {

// SortIPAddrs sorts the specified IP addresses array
// IPv4 addresses go first, then IPv6 addresses
//
// Deprecated: This function is deprecated. Packages in module dnsproxy should
// use internal/netutil.SortIPAddrs instead.
func SortIPAddrs(ipAddrs []net.IPAddr) []net.IPAddr {
l := len(ipAddrs)
if l <= 1 {
Expand Down
3 changes: 3 additions & 0 deletions upstream/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"sync"
"time"

proxynetutil "github.com/AdguardTeam/dnsproxy/internal/netutil"
"github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/log"
)
Expand Down Expand Up @@ -201,6 +202,8 @@ func (n *bootstrapper) get() (*tls.Config, dialHandler, error) {
return nil, nil, fmt.Errorf("lookup %s: %w", host, err)
}

proxynetutil.SortIPAddrs(addrs, n.options.PreferIPv6)

resolved := []string{}
for _, addr := range addrs {
if addr.IP.To4() == nil && addr.IP.To16() == nil {
Expand Down
18 changes: 16 additions & 2 deletions upstream/bootstrap_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/url"
"strings"

proxynetutil "github.com/AdguardTeam/dnsproxy/internal/netutil"
"github.com/AdguardTeam/dnsproxy/proxyutil"
"github.com/AdguardTeam/golibs/log"
"github.com/miekg/dns"
Expand Down Expand Up @@ -141,7 +142,14 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr,
if err != nil {
return nil, err
}
return proxyutil.SortIPAddrs(addrs), nil

// Use the previous dnsproxy behavior: prefer IPv4 by default.
//
// TODO(a.garipov): Consider unexporting this entire method or
// documenting that the order of addrs is undefined.
proxynetutil.SortIPAddrs(addrs, false)

return addrs, nil
}

if r.upstream == nil || len(host) == 0 {
Expand Down Expand Up @@ -171,5 +179,11 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr,
return []net.IPAddr{}, errs[0]
}

return proxyutil.SortIPAddrs(ipAddrs), nil
// Use the previous dnsproxy behavior: prefer IPv4 by default.
//
// TODO(a.garipov): Consider unexporting this entire method or documenting
// that the order of addrs is undefined.
proxynetutil.SortIPAddrs(ipAddrs, false)

return ipAddrs, nil
}
13 changes: 9 additions & 4 deletions upstream/upstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ type Options struct {
// DNS servers won't be used at all.
ServerIPAddrs []net.IP

// InsecureSkipVerify disables verifying the server's certificate.
InsecureSkipVerify bool

// HTTPVersions is a list of HTTP versions that should be supported by the
// DNS-over-HTTPS client. If not set, HTTP/1.1 and HTTP/2 will be used.
HTTPVersions []HTTPVersion
Expand All @@ -75,6 +72,13 @@ type Options struct {
// QUICTracer is an optional object that allows tracing every QUIC
// connection and logging every packet that goes through.
QUICTracer logging.Tracer

// InsecureSkipVerify disables verifying the server's certificate.
InsecureSkipVerify bool

// PreferIPv6 tells the bootstrapper to prefer IPv6 addresses for an
// upstream.
PreferIPv6 bool
}

// Clone copies o to a new struct. Note, that this is not a deep clone.
Expand All @@ -83,11 +87,12 @@ func (o *Options) Clone() (clone *Options) {
Bootstrap: o.Bootstrap,
Timeout: o.Timeout,
ServerIPAddrs: o.ServerIPAddrs,
InsecureSkipVerify: o.InsecureSkipVerify,
HTTPVersions: o.HTTPVersions,
VerifyServerCertificate: o.VerifyServerCertificate,
VerifyConnection: o.VerifyConnection,
VerifyDNSCryptCertificate: o.VerifyDNSCryptCertificate,
InsecureSkipVerify: o.InsecureSkipVerify,
PreferIPv6: o.PreferIPv6,
}
}

Expand Down

0 comments on commit f8f22ab

Please sign in to comment.