This package is a wrapper for the libnetwork/internal/resolvconf package,
which is a modernized, more performant rewrite of the original parsing
code.
The libnetwork/resolvconf package was still maintained because it was
used by BuildKit, but since [moby/buildkit@3d43066], BuildKit maintains
its own copy of the internal package.
The only remaining uses of this package was as part of some tests (which
would also benefit of using the internal pacakge's implementation directly),
and a _single_ use of `resolvconf.Path` in the daemon, which cannot use
the internal package currently because it's internal to libnetwork.
This patch:
- Removes all functions that were not used.
- Rewrites some tests in libnetwork to use the internal/resolvconf package
directly, instead of depending on the wrapper.
- Add TODOs to consider moving the "Path" function separate (which could
be in daemon/config if we consider it to be the default for the daemon's
resolvconf path configuration).
[moby/buildkit@3d43066]: https://github.com/moby/buildkit/commit/3d43066f2e814d4d10383ba871256245edf08a25
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -146,6 +146,7 @@ func setupResolvConf(config *config.Config) {
|
| 146 | 146 |
if config.ResolvConf != "" {
|
| 147 | 147 |
return |
| 148 | 148 |
} |
| 149 |
+ // FIXME(thaJeztah): we can't use [github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf.Path] here, because it's internal to libnetwork. |
|
| 149 | 150 |
config.ResolvConf = resolvconf.Path() |
| 150 | 151 |
} |
| 151 | 152 |
|
| ... | ... |
@@ -3,14 +3,15 @@ |
| 3 | 3 |
package netutils |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "bytes" |
|
| 6 | 7 |
"net/netip" |
| 7 | 8 |
"os" |
| 8 | 9 |
"slices" |
| 9 | 10 |
|
| 10 | 11 |
"github.com/moby/moby/v2/daemon/libnetwork/internal/netiputil" |
| 12 |
+ "github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf" |
|
| 11 | 13 |
"github.com/moby/moby/v2/daemon/libnetwork/nlwrap" |
| 12 | 14 |
"github.com/moby/moby/v2/daemon/libnetwork/ns" |
| 13 |
- "github.com/moby/moby/v2/daemon/libnetwork/resolvconf" |
|
| 14 | 15 |
"github.com/moby/moby/v2/daemon/libnetwork/types" |
| 15 | 16 |
"github.com/pkg/errors" |
| 16 | 17 |
"github.com/vishvananda/netlink" |
| ... | ... |
@@ -62,7 +63,7 @@ func InferReservedNetworks(v6 bool) []netip.Prefix {
|
| 62 | 62 |
// We don't really care if os.ReadFile fails here. It either doesn't exist, |
| 63 | 63 |
// or we can't read it for some reason. |
| 64 | 64 |
if rc, err := os.ReadFile(resolvconf.Path()); err == nil {
|
| 65 |
- reserved = slices.DeleteFunc(resolvconf.GetNameserversAsPrefix(rc), func(p netip.Prefix) bool {
|
|
| 65 |
+ reserved = slices.DeleteFunc(tryGetNameserversAsPrefix(rc), func(p netip.Prefix) bool {
|
|
| 66 | 66 |
return p.Addr().Is6() != v6 |
| 67 | 67 |
}) |
| 68 | 68 |
} |
| ... | ... |
@@ -75,6 +76,22 @@ func InferReservedNetworks(v6 bool) []netip.Prefix {
|
| 75 | 75 |
return reserved |
| 76 | 76 |
} |
| 77 | 77 |
|
| 78 |
+// tryGetNameserversAsPrefix returns nameservers (if any) listed in |
|
| 79 |
+// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32"). It ignores |
|
| 80 |
+// failures to parse the file, as this utility is used as a "best-effort". |
|
| 81 |
+func tryGetNameserversAsPrefix(resolvConf []byte) []netip.Prefix {
|
|
| 82 |
+ rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "") |
|
| 83 |
+ if err != nil {
|
|
| 84 |
+ return nil |
|
| 85 |
+ } |
|
| 86 |
+ nsAddrs := rc.NameServers() |
|
| 87 |
+ nameservers := make([]netip.Prefix, 0, len(nsAddrs)) |
|
| 88 |
+ for _, addr := range nsAddrs {
|
|
| 89 |
+ nameservers = append(nameservers, netip.PrefixFrom(addr, addr.BitLen())) |
|
| 90 |
+ } |
|
| 91 |
+ return nameservers |
|
| 92 |
+} |
|
| 93 |
+ |
|
| 78 | 94 |
// queryOnLinkRoutes returns a list of on-link routes available on the host. |
| 79 | 95 |
// Only IPv4 prefixes are returned as there's no such thing as on-link |
| 80 | 96 |
// routes for IPv6. |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"strings" |
| 9 | 9 |
"testing" |
| 10 | 10 |
|
| 11 |
+ "github.com/google/go-cmp/cmp/cmpopts" |
|
| 11 | 12 |
"github.com/moby/moby/v2/daemon/libnetwork/internal/netiputil" |
| 12 | 13 |
"github.com/moby/moby/v2/internal/testutils/netnsutils" |
| 13 | 14 |
"github.com/vishvananda/netlink" |
| ... | ... |
@@ -60,6 +61,61 @@ func TestGenerateRandomName(t *testing.T) {
|
| 60 | 60 |
} |
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 |
+func TestGetNameserversAsPrefix(t *testing.T) {
|
|
| 64 |
+ for _, tc := range []struct {
|
|
| 65 |
+ input string |
|
| 66 |
+ result []netip.Prefix |
|
| 67 |
+ }{
|
|
| 68 |
+ {
|
|
| 69 |
+ input: ``, |
|
| 70 |
+ result: []netip.Prefix{},
|
|
| 71 |
+ }, |
|
| 72 |
+ {
|
|
| 73 |
+ input: `search example.com`, |
|
| 74 |
+ result: []netip.Prefix{},
|
|
| 75 |
+ }, |
|
| 76 |
+ {
|
|
| 77 |
+ input: ` nameserver 1.2.3.4 `, |
|
| 78 |
+ result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
|
|
| 79 |
+ }, |
|
| 80 |
+ {
|
|
| 81 |
+ input: ` |
|
| 82 |
+nameserver 1.2.3.4 |
|
| 83 |
+nameserver 40.3.200.10 |
|
| 84 |
+search example.com`, |
|
| 85 |
+ result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32"), netip.MustParsePrefix("40.3.200.10/32")},
|
|
| 86 |
+ }, |
|
| 87 |
+ {
|
|
| 88 |
+ input: `nameserver 1.2.3.4 |
|
| 89 |
+search example.com |
|
| 90 |
+nameserver 4.30.20.100`, |
|
| 91 |
+ result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32"), netip.MustParsePrefix("4.30.20.100/32")},
|
|
| 92 |
+ }, |
|
| 93 |
+ {
|
|
| 94 |
+ input: `search example.com |
|
| 95 |
+nameserver 1.2.3.4 |
|
| 96 |
+#nameserver 4.3.2.1`, |
|
| 97 |
+ result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
|
|
| 98 |
+ }, |
|
| 99 |
+ {
|
|
| 100 |
+ input: `search example.com |
|
| 101 |
+nameserver 1.2.3.4 # not 4.3.2.1`, |
|
| 102 |
+ result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
|
|
| 103 |
+ }, |
|
| 104 |
+ {
|
|
| 105 |
+ input: `nameserver fd6f:c490:ec68::1`, |
|
| 106 |
+ result: []netip.Prefix{netip.MustParsePrefix("fd6f:c490:ec68::1/128")},
|
|
| 107 |
+ }, |
|
| 108 |
+ {
|
|
| 109 |
+ input: `nameserver fe80::1234%eth0`, |
|
| 110 |
+ result: []netip.Prefix{netip.MustParsePrefix("fe80::1234/128")},
|
|
| 111 |
+ }, |
|
| 112 |
+ } {
|
|
| 113 |
+ test := tryGetNameserversAsPrefix([]byte(tc.input)) |
|
| 114 |
+ assert.DeepEqual(t, test, tc.result, cmpopts.EquateComparable(netip.Prefix{}))
|
|
| 115 |
+ } |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 63 | 118 |
// Test mac generation. |
| 64 | 119 |
func TestUtilGenerateRandomMAC(t *testing.T) {
|
| 65 | 120 |
mac1 := GenerateRandomMAC() |
| ... | ... |
@@ -1,159 +1,14 @@ |
| 1 |
-// Package resolvconf provides utility code to query and update DNS configuration in /etc/resolv.conf |
|
| 1 |
+// Package resolvconf provides utility code to get the host's "resolv.conf" path. |
|
| 2 | 2 |
package resolvconf |
| 3 | 3 |
|
| 4 |
-import ( |
|
| 5 |
- "bytes" |
|
| 6 |
- "fmt" |
|
| 7 |
- "net/netip" |
|
| 8 |
- "os" |
|
| 9 |
- |
|
| 10 |
- "github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf" |
|
| 11 |
- "github.com/opencontainers/go-digest" |
|
| 12 |
-) |
|
| 13 |
- |
|
| 14 |
-// constants for the IP address type |
|
| 15 |
-const ( |
|
| 16 |
- IP = iota // IPv4 and IPv6 |
|
| 17 |
- IPv4 |
|
| 18 |
- IPv6 |
|
| 19 |
-) |
|
| 20 |
- |
|
| 21 |
-// File contains the resolv.conf content and its hash |
|
| 22 |
-type File struct {
|
|
| 23 |
- Content []byte |
|
| 24 |
- Hash []byte |
|
| 25 |
-} |
|
| 4 |
+import "github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf" |
|
| 26 | 5 |
|
| 6 |
+// Path is an alias for [resolvconf.Path], which is internal to libnetwork. |
|
| 7 |
+// |
|
| 8 |
+// FIXME(thaJeztah): remove this when possible. This is only used in [github.com/moby/moby/v2/daemon.setupResolvConf]. |
|
| 9 |
+// Either we can move "libnetwork/internal/resolvconf" to "daemon/internal", |
|
| 10 |
+// or move the "Path" function to daemon/config (considering it a default |
|
| 11 |
+// for the daemon's config). |
|
| 27 | 12 |
func Path() string {
|
| 28 | 13 |
return resolvconf.Path() |
| 29 | 14 |
} |
| 30 |
- |
|
| 31 |
-// Get returns the contents of /etc/resolv.conf and its hash |
|
| 32 |
-func Get() (*File, error) {
|
|
| 33 |
- return GetSpecific(Path()) |
|
| 34 |
-} |
|
| 35 |
- |
|
| 36 |
-// GetSpecific returns the contents of the user specified resolv.conf file and its hash |
|
| 37 |
-func GetSpecific(path string) (*File, error) {
|
|
| 38 |
- resolv, err := os.ReadFile(path) |
|
| 39 |
- if err != nil {
|
|
| 40 |
- return nil, err |
|
| 41 |
- } |
|
| 42 |
- hash := digest.FromBytes(resolv) |
|
| 43 |
- return &File{Content: resolv, Hash: []byte(hash)}, nil
|
|
| 44 |
-} |
|
| 45 |
- |
|
| 46 |
-// FilterResolvDNS cleans up the config in resolvConf. It has two main jobs: |
|
| 47 |
-// 1. It looks for localhost (127.*|::1) entries in the provided |
|
| 48 |
-// resolv.conf, removing local nameserver entries, and, if the resulting |
|
| 49 |
-// cleaned config has no defined nameservers left, adds default DNS entries |
|
| 50 |
-// 2. Given the caller provides the enable/disable state of IPv6, the filter |
|
| 51 |
-// code will remove all IPv6 nameservers if it is not enabled for containers |
|
| 52 |
-func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) {
|
|
| 53 |
- rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "") |
|
| 54 |
- if err != nil {
|
|
| 55 |
- return nil, err |
|
| 56 |
- } |
|
| 57 |
- rc.TransformForLegacyNw(ipv6Enabled) |
|
| 58 |
- content, err := rc.Generate(false) |
|
| 59 |
- if err != nil {
|
|
| 60 |
- return nil, err |
|
| 61 |
- } |
|
| 62 |
- hash := digest.FromBytes(content) |
|
| 63 |
- return &File{Content: content, Hash: []byte(hash)}, nil
|
|
| 64 |
-} |
|
| 65 |
- |
|
| 66 |
-// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf |
|
| 67 |
-func GetNameservers(resolvConf []byte, kind int) []string {
|
|
| 68 |
- rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "") |
|
| 69 |
- if err != nil {
|
|
| 70 |
- return nil |
|
| 71 |
- } |
|
| 72 |
- nsAddrs := rc.NameServers() |
|
| 73 |
- var nameservers []string |
|
| 74 |
- for _, addr := range nsAddrs {
|
|
| 75 |
- if kind == IP {
|
|
| 76 |
- nameservers = append(nameservers, addr.String()) |
|
| 77 |
- } else if kind == IPv4 && addr.Is4() {
|
|
| 78 |
- nameservers = append(nameservers, addr.String()) |
|
| 79 |
- } else if kind == IPv6 && addr.Is6() {
|
|
| 80 |
- nameservers = append(nameservers, addr.String()) |
|
| 81 |
- } |
|
| 82 |
- } |
|
| 83 |
- return nameservers |
|
| 84 |
-} |
|
| 85 |
- |
|
| 86 |
-// GetNameserversAsPrefix returns nameservers (if any) listed in |
|
| 87 |
-// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32") |
|
| 88 |
-func GetNameserversAsPrefix(resolvConf []byte) []netip.Prefix {
|
|
| 89 |
- rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "") |
|
| 90 |
- if err != nil {
|
|
| 91 |
- return nil |
|
| 92 |
- } |
|
| 93 |
- nsAddrs := rc.NameServers() |
|
| 94 |
- nameservers := make([]netip.Prefix, 0, len(nsAddrs)) |
|
| 95 |
- for _, addr := range nsAddrs {
|
|
| 96 |
- nameservers = append(nameservers, netip.PrefixFrom(addr, addr.BitLen())) |
|
| 97 |
- } |
|
| 98 |
- return nameservers |
|
| 99 |
-} |
|
| 100 |
- |
|
| 101 |
-// GetSearchDomains returns search domains (if any) listed in /etc/resolv.conf |
|
| 102 |
-// If more than one search line is encountered, only the contents of the last |
|
| 103 |
-// one is returned. |
|
| 104 |
-func GetSearchDomains(resolvConf []byte) []string {
|
|
| 105 |
- rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "") |
|
| 106 |
- if err != nil {
|
|
| 107 |
- return nil |
|
| 108 |
- } |
|
| 109 |
- return rc.Search() |
|
| 110 |
-} |
|
| 111 |
- |
|
| 112 |
-// GetOptions returns options (if any) listed in /etc/resolv.conf |
|
| 113 |
-// If more than one options line is encountered, only the contents of the last |
|
| 114 |
-// one is returned. |
|
| 115 |
-func GetOptions(resolvConf []byte) []string {
|
|
| 116 |
- rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "") |
|
| 117 |
- if err != nil {
|
|
| 118 |
- return nil |
|
| 119 |
- } |
|
| 120 |
- return rc.Options() |
|
| 121 |
-} |
|
| 122 |
- |
|
| 123 |
-// Build generates and writes a configuration file to path containing a nameserver |
|
| 124 |
-// entry for every element in nameservers, a "search" entry for every element in |
|
| 125 |
-// dnsSearch, and an "options" entry for every element in dnsOptions. It returns |
|
| 126 |
-// a File containing the generated content and its (sha256) hash. |
|
| 127 |
-// |
|
| 128 |
-// Note that the resolv.conf file is written, but the hash file is not. |
|
| 129 |
-func Build(path string, nameservers, dnsSearch, dnsOptions []string) (*File, error) {
|
|
| 130 |
- var ns []netip.Addr |
|
| 131 |
- for _, addr := range nameservers {
|
|
| 132 |
- ipAddr, err := netip.ParseAddr(addr) |
|
| 133 |
- if err != nil {
|
|
| 134 |
- return nil, fmt.Errorf("bad nameserver address: %w", err)
|
|
| 135 |
- } |
|
| 136 |
- ns = append(ns, ipAddr) |
|
| 137 |
- } |
|
| 138 |
- rc := resolvconf.ResolvConf{}
|
|
| 139 |
- rc.OverrideNameServers(ns) |
|
| 140 |
- rc.OverrideSearch(dnsSearch) |
|
| 141 |
- rc.OverrideOptions(dnsOptions) |
|
| 142 |
- |
|
| 143 |
- content, err := rc.Generate(false) |
|
| 144 |
- if err != nil {
|
|
| 145 |
- return nil, err |
|
| 146 |
- } |
|
| 147 |
- |
|
| 148 |
- // Write the resolv.conf file - it's bind-mounted into the container, so can't |
|
| 149 |
- // move a temp file into place, just have to truncate and write it. |
|
| 150 |
- // |
|
| 151 |
- // TODO(thaJeztah): the Build function is currently only used by BuildKit, which only uses "File.Content", and doesn't require the file to be written. |
|
| 152 |
- if err := os.WriteFile(path, content, 0o644); err != nil {
|
|
| 153 |
- return nil, err |
|
| 154 |
- } |
|
| 155 |
- |
|
| 156 |
- // TODO(thaJeztah): the Build function is currently only used by BuildKit, which does not use the Hash |
|
| 157 |
- hash := digest.FromBytes(content) |
|
| 158 |
- return &File{Content: content, Hash: []byte(hash)}, nil
|
|
| 159 |
-} |
| 160 | 15 |
deleted file mode 100644 |
| ... | ... |
@@ -1,455 +0,0 @@ |
| 1 |
-//go:build !windows |
|
| 2 |
- |
|
| 3 |
-package resolvconf |
|
| 4 |
- |
|
| 5 |
-import ( |
|
| 6 |
- "bytes" |
|
| 7 |
- "net/netip" |
|
| 8 |
- "os" |
|
| 9 |
- "strings" |
|
| 10 |
- "testing" |
|
| 11 |
- |
|
| 12 |
- "github.com/google/go-cmp/cmp/cmpopts" |
|
| 13 |
- "github.com/opencontainers/go-digest" |
|
| 14 |
- "gotest.tools/v3/assert" |
|
| 15 |
- is "gotest.tools/v3/assert/cmp" |
|
| 16 |
-) |
|
| 17 |
- |
|
| 18 |
-func TestGet(t *testing.T) {
|
|
| 19 |
- actual, err := Get() |
|
| 20 |
- if err != nil {
|
|
| 21 |
- t.Fatal(err) |
|
| 22 |
- } |
|
| 23 |
- expected, err := os.ReadFile(Path()) |
|
| 24 |
- if err != nil {
|
|
| 25 |
- t.Fatal(err) |
|
| 26 |
- } |
|
| 27 |
- if !bytes.Equal(actual.Content, expected) {
|
|
| 28 |
- t.Errorf("%s and GetResolvConf have different content.", Path())
|
|
| 29 |
- } |
|
| 30 |
- hash := digest.FromBytes(expected) |
|
| 31 |
- if !bytes.Equal(actual.Hash, []byte(hash)) {
|
|
| 32 |
- t.Errorf("%s and GetResolvConf have different hashes.", Path())
|
|
| 33 |
- } |
|
| 34 |
-} |
|
| 35 |
- |
|
| 36 |
-func TestGetNameservers(t *testing.T) {
|
|
| 37 |
- for _, tc := range []struct {
|
|
| 38 |
- input string |
|
| 39 |
- result []string |
|
| 40 |
- }{
|
|
| 41 |
- {
|
|
| 42 |
- input: ``, |
|
| 43 |
- }, |
|
| 44 |
- {
|
|
| 45 |
- input: `search example.com`, |
|
| 46 |
- }, |
|
| 47 |
- {
|
|
| 48 |
- input: ` nameserver 1.2.3.4 `, |
|
| 49 |
- result: []string{"1.2.3.4"},
|
|
| 50 |
- }, |
|
| 51 |
- {
|
|
| 52 |
- input: ` |
|
| 53 |
-nameserver 1.2.3.4 |
|
| 54 |
-nameserver 40.3.200.10 |
|
| 55 |
-search example.com`, |
|
| 56 |
- result: []string{"1.2.3.4", "40.3.200.10"},
|
|
| 57 |
- }, |
|
| 58 |
- {
|
|
| 59 |
- input: `nameserver 1.2.3.4 |
|
| 60 |
-search example.com |
|
| 61 |
-nameserver 4.30.20.100`, |
|
| 62 |
- result: []string{"1.2.3.4", "4.30.20.100"},
|
|
| 63 |
- }, |
|
| 64 |
- {
|
|
| 65 |
- input: `search example.com |
|
| 66 |
-nameserver 1.2.3.4 |
|
| 67 |
-#nameserver 4.3.2.1`, |
|
| 68 |
- result: []string{"1.2.3.4"},
|
|
| 69 |
- }, |
|
| 70 |
- {
|
|
| 71 |
- input: `search example.com |
|
| 72 |
-nameserver 1.2.3.4 # not 4.3.2.1`, |
|
| 73 |
- result: []string{"1.2.3.4"},
|
|
| 74 |
- }, |
|
| 75 |
- } {
|
|
| 76 |
- test := GetNameservers([]byte(tc.input), IP) |
|
| 77 |
- if !strSlicesEqual(test, tc.result) {
|
|
| 78 |
- t.Errorf("Wrong nameserver string {%s} should be %v. Input: %s", test, tc.result, tc.input)
|
|
| 79 |
- } |
|
| 80 |
- } |
|
| 81 |
-} |
|
| 82 |
- |
|
| 83 |
-func TestGetNameserversAsPrefix(t *testing.T) {
|
|
| 84 |
- for _, tc := range []struct {
|
|
| 85 |
- input string |
|
| 86 |
- result []netip.Prefix |
|
| 87 |
- }{
|
|
| 88 |
- {
|
|
| 89 |
- input: ``, |
|
| 90 |
- result: []netip.Prefix{},
|
|
| 91 |
- }, |
|
| 92 |
- {
|
|
| 93 |
- input: `search example.com`, |
|
| 94 |
- result: []netip.Prefix{},
|
|
| 95 |
- }, |
|
| 96 |
- {
|
|
| 97 |
- input: ` nameserver 1.2.3.4 `, |
|
| 98 |
- result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
|
|
| 99 |
- }, |
|
| 100 |
- {
|
|
| 101 |
- input: ` |
|
| 102 |
-nameserver 1.2.3.4 |
|
| 103 |
-nameserver 40.3.200.10 |
|
| 104 |
-search example.com`, |
|
| 105 |
- result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32"), netip.MustParsePrefix("40.3.200.10/32")},
|
|
| 106 |
- }, |
|
| 107 |
- {
|
|
| 108 |
- input: `nameserver 1.2.3.4 |
|
| 109 |
-search example.com |
|
| 110 |
-nameserver 4.30.20.100`, |
|
| 111 |
- result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32"), netip.MustParsePrefix("4.30.20.100/32")},
|
|
| 112 |
- }, |
|
| 113 |
- {
|
|
| 114 |
- input: `search example.com |
|
| 115 |
-nameserver 1.2.3.4 |
|
| 116 |
-#nameserver 4.3.2.1`, |
|
| 117 |
- result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
|
|
| 118 |
- }, |
|
| 119 |
- {
|
|
| 120 |
- input: `search example.com |
|
| 121 |
-nameserver 1.2.3.4 # not 4.3.2.1`, |
|
| 122 |
- result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
|
|
| 123 |
- }, |
|
| 124 |
- {
|
|
| 125 |
- input: `nameserver fd6f:c490:ec68::1`, |
|
| 126 |
- result: []netip.Prefix{netip.MustParsePrefix("fd6f:c490:ec68::1/128")},
|
|
| 127 |
- }, |
|
| 128 |
- {
|
|
| 129 |
- input: `nameserver fe80::1234%eth0`, |
|
| 130 |
- result: []netip.Prefix{netip.MustParsePrefix("fe80::1234/128")},
|
|
| 131 |
- }, |
|
| 132 |
- } {
|
|
| 133 |
- test := GetNameserversAsPrefix([]byte(tc.input)) |
|
| 134 |
- assert.DeepEqual(t, test, tc.result, cmpopts.EquateComparable(netip.Prefix{}))
|
|
| 135 |
- } |
|
| 136 |
-} |
|
| 137 |
- |
|
| 138 |
-func TestGetSearchDomains(t *testing.T) {
|
|
| 139 |
- for _, tc := range []struct {
|
|
| 140 |
- input string |
|
| 141 |
- result []string |
|
| 142 |
- }{
|
|
| 143 |
- {
|
|
| 144 |
- input: ``, |
|
| 145 |
- }, |
|
| 146 |
- {
|
|
| 147 |
- input: `# ignored`, |
|
| 148 |
- }, |
|
| 149 |
- {
|
|
| 150 |
- input: `search example.com`, |
|
| 151 |
- result: []string{"example.com"},
|
|
| 152 |
- }, |
|
| 153 |
- {
|
|
| 154 |
- input: `search example.com # notignored`, |
|
| 155 |
- result: []string{"example.com", "#", "notignored"},
|
|
| 156 |
- }, |
|
| 157 |
- {
|
|
| 158 |
- input: ` search example.com `, |
|
| 159 |
- result: []string{"example.com"},
|
|
| 160 |
- }, |
|
| 161 |
- {
|
|
| 162 |
- input: ` search example.com # notignored`, |
|
| 163 |
- result: []string{"example.com", "#", "notignored"},
|
|
| 164 |
- }, |
|
| 165 |
- {
|
|
| 166 |
- input: `search foo.example.com example.com`, |
|
| 167 |
- result: []string{"foo.example.com", "example.com"},
|
|
| 168 |
- }, |
|
| 169 |
- {
|
|
| 170 |
- input: ` search foo.example.com example.com `, |
|
| 171 |
- result: []string{"foo.example.com", "example.com"},
|
|
| 172 |
- }, |
|
| 173 |
- {
|
|
| 174 |
- input: ` search foo.example.com example.com # notignored`, |
|
| 175 |
- result: []string{"foo.example.com", "example.com", "#", "notignored"},
|
|
| 176 |
- }, |
|
| 177 |
- {
|
|
| 178 |
- input: `nameserver 1.2.3.4 |
|
| 179 |
-search foo.example.com example.com`, |
|
| 180 |
- result: []string{"foo.example.com", "example.com"},
|
|
| 181 |
- }, |
|
| 182 |
- {
|
|
| 183 |
- input: `nameserver 1.2.3.4 |
|
| 184 |
-search dup1.example.com dup2.example.com |
|
| 185 |
-search foo.example.com example.com`, |
|
| 186 |
- result: []string{"foo.example.com", "example.com"},
|
|
| 187 |
- }, |
|
| 188 |
- {
|
|
| 189 |
- input: `nameserver 1.2.3.4 |
|
| 190 |
-search foo.example.com example.com |
|
| 191 |
-nameserver 4.30.20.100`, |
|
| 192 |
- result: []string{"foo.example.com", "example.com"},
|
|
| 193 |
- }, |
|
| 194 |
- {
|
|
| 195 |
- input: `domain an.example`, |
|
| 196 |
- result: []string{"an.example"},
|
|
| 197 |
- }, |
|
| 198 |
- } {
|
|
| 199 |
- test := GetSearchDomains([]byte(tc.input)) |
|
| 200 |
- if !strSlicesEqual(test, tc.result) {
|
|
| 201 |
- t.Errorf("Wrong search domain string {%s} should be %v. Input: %s", test, tc.result, tc.input)
|
|
| 202 |
- } |
|
| 203 |
- } |
|
| 204 |
-} |
|
| 205 |
- |
|
| 206 |
-func TestGetOptions(t *testing.T) {
|
|
| 207 |
- for _, tc := range []struct {
|
|
| 208 |
- input string |
|
| 209 |
- result []string |
|
| 210 |
- }{
|
|
| 211 |
- {
|
|
| 212 |
- input: ``, |
|
| 213 |
- }, |
|
| 214 |
- {
|
|
| 215 |
- input: `# ignored`, |
|
| 216 |
- }, |
|
| 217 |
- {
|
|
| 218 |
- input: `; ignored`, |
|
| 219 |
- }, |
|
| 220 |
- {
|
|
| 221 |
- input: `nameserver 1.2.3.4`, |
|
| 222 |
- }, |
|
| 223 |
- {
|
|
| 224 |
- input: `options opt1`, |
|
| 225 |
- result: []string{"opt1"},
|
|
| 226 |
- }, |
|
| 227 |
- {
|
|
| 228 |
- input: `options opt1 # notignored`, |
|
| 229 |
- result: []string{"opt1", "#", "notignored"},
|
|
| 230 |
- }, |
|
| 231 |
- {
|
|
| 232 |
- input: `options opt1 ; notignored`, |
|
| 233 |
- result: []string{"opt1", ";", "notignored"},
|
|
| 234 |
- }, |
|
| 235 |
- {
|
|
| 236 |
- input: ` options opt1 `, |
|
| 237 |
- result: []string{"opt1"},
|
|
| 238 |
- }, |
|
| 239 |
- {
|
|
| 240 |
- input: ` options opt1 # notignored`, |
|
| 241 |
- result: []string{"opt1", "#", "notignored"},
|
|
| 242 |
- }, |
|
| 243 |
- {
|
|
| 244 |
- input: `options opt1 opt2 opt3`, |
|
| 245 |
- result: []string{"opt1", "opt2", "opt3"},
|
|
| 246 |
- }, |
|
| 247 |
- {
|
|
| 248 |
- input: `options opt1 opt2 opt3 # notignored`, |
|
| 249 |
- result: []string{"opt1", "opt2", "opt3", "#", "notignored"},
|
|
| 250 |
- }, |
|
| 251 |
- {
|
|
| 252 |
- input: ` options opt1 opt2 opt3 `, |
|
| 253 |
- result: []string{"opt1", "opt2", "opt3"},
|
|
| 254 |
- }, |
|
| 255 |
- {
|
|
| 256 |
- input: ` options opt1 opt2 opt3 # notignored`, |
|
| 257 |
- result: []string{"opt1", "opt2", "opt3", "#", "notignored"},
|
|
| 258 |
- }, |
|
| 259 |
- {
|
|
| 260 |
- input: `nameserver 1.2.3.4 |
|
| 261 |
-options opt1 opt2 opt3`, |
|
| 262 |
- result: []string{"opt1", "opt2", "opt3"},
|
|
| 263 |
- }, |
|
| 264 |
- {
|
|
| 265 |
- input: `nameserver 1.2.3.4 |
|
| 266 |
-options opt1 opt2 |
|
| 267 |
-options opt3 opt4`, |
|
| 268 |
- result: []string{"opt1", "opt2", "opt3", "opt4"},
|
|
| 269 |
- }, |
|
| 270 |
- } {
|
|
| 271 |
- test := GetOptions([]byte(tc.input)) |
|
| 272 |
- if !strSlicesEqual(test, tc.result) {
|
|
| 273 |
- t.Errorf("Wrong options string {%s} should be %v. Input: %s", test, tc.result, tc.input)
|
|
| 274 |
- } |
|
| 275 |
- } |
|
| 276 |
-} |
|
| 277 |
- |
|
| 278 |
-func strSlicesEqual(a, b []string) bool {
|
|
| 279 |
- if len(a) != len(b) {
|
|
| 280 |
- return false |
|
| 281 |
- } |
|
| 282 |
- |
|
| 283 |
- for i, v := range a {
|
|
| 284 |
- if v != b[i] {
|
|
| 285 |
- return false |
|
| 286 |
- } |
|
| 287 |
- } |
|
| 288 |
- |
|
| 289 |
- return true |
|
| 290 |
-} |
|
| 291 |
- |
|
| 292 |
-const ( |
|
| 293 |
- // Example IP-addresses as defined in [RFC 5737], [RFC 3849, section 2]. |
|
| 294 |
- // |
|
| 295 |
- // [RFC 5737]: https://datatracker.ietf.org/doc/html/rfc5737 |
|
| 296 |
- // [RFC 3849, section 2]: https://datatracker.ietf.org/doc/html/rfc3849#section-2 |
|
| 297 |
- testNS1 = "192.0.2.1" |
|
| 298 |
- testNS2 = "2001:db8::1" |
|
| 299 |
- testNS3 = "203.0.113.3" |
|
| 300 |
-) |
|
| 301 |
- |
|
| 302 |
-func TestBuild(t *testing.T) {
|
|
| 303 |
- tests := []struct {
|
|
| 304 |
- doc string |
|
| 305 |
- nameServers []string |
|
| 306 |
- dnsSearch []string |
|
| 307 |
- dnsOptions []string |
|
| 308 |
- expOut string |
|
| 309 |
- expErr string |
|
| 310 |
- }{
|
|
| 311 |
- {
|
|
| 312 |
- doc: "no options", |
|
| 313 |
- expOut: ``, |
|
| 314 |
- }, |
|
| 315 |
- {
|
|
| 316 |
- doc: "all options", |
|
| 317 |
- nameServers: []string{testNS1, testNS2, testNS3},
|
|
| 318 |
- dnsSearch: []string{"search1"},
|
|
| 319 |
- dnsOptions: []string{"opt1"},
|
|
| 320 |
- expOut: `nameserver 192.0.2.1 |
|
| 321 |
-nameserver 2001:db8::1 |
|
| 322 |
-nameserver 203.0.113.3 |
|
| 323 |
-search search1 |
|
| 324 |
-options opt1 |
|
| 325 |
-`, |
|
| 326 |
- }, |
|
| 327 |
- {
|
|
| 328 |
- doc: "zero-length dns search", |
|
| 329 |
- nameServers: []string{testNS1, testNS2, testNS3},
|
|
| 330 |
- dnsSearch: []string{"."},
|
|
| 331 |
- dnsOptions: []string{"opt1"},
|
|
| 332 |
- expOut: `nameserver 192.0.2.1 |
|
| 333 |
-nameserver 2001:db8::1 |
|
| 334 |
-nameserver 203.0.113.3 |
|
| 335 |
-options opt1 |
|
| 336 |
-`, |
|
| 337 |
- }, |
|
| 338 |
- {
|
|
| 339 |
- doc: "no dns options", |
|
| 340 |
- nameServers: []string{testNS1, testNS2, testNS3},
|
|
| 341 |
- dnsSearch: []string{"search1"},
|
|
| 342 |
- dnsOptions: []string{},
|
|
| 343 |
- expOut: `nameserver 192.0.2.1 |
|
| 344 |
-nameserver 2001:db8::1 |
|
| 345 |
-nameserver 203.0.113.3 |
|
| 346 |
-search search1 |
|
| 347 |
-`, |
|
| 348 |
- }, |
|
| 349 |
- {
|
|
| 350 |
- doc: "invalid nameserver", |
|
| 351 |
- nameServers: []string{"resolver.example.com"},
|
|
| 352 |
- expErr: `bad nameserver address: ParseAddr("resolver.example.com"): unexpected character (at "resolver.example.com")`,
|
|
| 353 |
- }, |
|
| 354 |
- } |
|
| 355 |
- |
|
| 356 |
- tmpDir := t.TempDir() |
|
| 357 |
- for _, tc := range tests {
|
|
| 358 |
- t.Run(tc.doc, func(t *testing.T) {
|
|
| 359 |
- file, err := os.CreateTemp(tmpDir, "") |
|
| 360 |
- assert.NilError(t, err) |
|
| 361 |
- |
|
| 362 |
- f, err := Build(file.Name(), tc.nameServers, tc.dnsSearch, tc.dnsOptions) |
|
| 363 |
- if tc.expErr != "" {
|
|
| 364 |
- assert.Error(t, err, tc.expErr) |
|
| 365 |
- } else if err != nil {
|
|
| 366 |
- assert.NilError(t, err) |
|
| 367 |
- assert.Equal(t, string(f.Content), tc.expOut) |
|
| 368 |
- } |
|
| 369 |
- |
|
| 370 |
- // Verify the content matches the expected; for error-cases, |
|
| 371 |
- // this verifies the file is empty. |
|
| 372 |
- content, err := os.ReadFile(file.Name()) |
|
| 373 |
- assert.NilError(t, err) |
|
| 374 |
- assert.Equal(t, string(content), tc.expOut) |
|
| 375 |
- }) |
|
| 376 |
- } |
|
| 377 |
-} |
|
| 378 |
- |
|
| 379 |
-func TestFilterResolvDNS(t *testing.T) {
|
|
| 380 |
- testcases := []struct {
|
|
| 381 |
- name string |
|
| 382 |
- input string |
|
| 383 |
- ipv6Enabled bool |
|
| 384 |
- expOut string |
|
| 385 |
- }{
|
|
| 386 |
- {
|
|
| 387 |
- name: "No localhost", |
|
| 388 |
- input: "nameserver 10.16.60.14\nnameserver 10.16.60.21\n", |
|
| 389 |
- expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", |
|
| 390 |
- }, |
|
| 391 |
- {
|
|
| 392 |
- name: "Localhost last", |
|
| 393 |
- input: "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\n", |
|
| 394 |
- expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", |
|
| 395 |
- }, |
|
| 396 |
- {
|
|
| 397 |
- name: "Localhost middle", |
|
| 398 |
- input: "nameserver 10.16.60.14\nnameserver 127.0.0.1\nnameserver 10.16.60.21\n", |
|
| 399 |
- expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", |
|
| 400 |
- }, |
|
| 401 |
- {
|
|
| 402 |
- name: "Localhost first", |
|
| 403 |
- input: "nameserver 127.0.1.1\nnameserver 10.16.60.14\nnameserver 10.16.60.21\n", |
|
| 404 |
- expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", |
|
| 405 |
- }, |
|
| 406 |
- {
|
|
| 407 |
- name: "IPv6 Localhost", |
|
| 408 |
- input: "nameserver ::1\nnameserver 10.16.60.14\nnameserver 127.0.2.1\nnameserver 10.16.60.21\n", |
|
| 409 |
- expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", |
|
| 410 |
- }, |
|
| 411 |
- {
|
|
| 412 |
- name: "Two IPv6 Localhosts", |
|
| 413 |
- input: "nameserver 10.16.60.14\nnameserver ::1\nnameserver 10.16.60.21\nnameserver ::1", |
|
| 414 |
- expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", |
|
| 415 |
- }, |
|
| 416 |
- {
|
|
| 417 |
- name: "IPv6 disabled", |
|
| 418 |
- input: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1", |
|
| 419 |
- expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", |
|
| 420 |
- }, |
|
| 421 |
- {
|
|
| 422 |
- name: "IPv6 link-local disabled", |
|
| 423 |
- input: "nameserver 10.16.60.14\nnameserver FE80::BB1%1\nnameserver FE80::BB1%eth0\nnameserver 10.16.60.21", |
|
| 424 |
- expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21", |
|
| 425 |
- }, |
|
| 426 |
- {
|
|
| 427 |
- name: "IPv6 enabled", |
|
| 428 |
- input: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1\n", |
|
| 429 |
- ipv6Enabled: true, |
|
| 430 |
- expOut: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21", |
|
| 431 |
- }, |
|
| 432 |
- {
|
|
| 433 |
- // with IPv6 enabled, and no non-localhost servers, Google defaults (both IPv4+IPv6) should be added |
|
| 434 |
- name: "localhost only IPv6", |
|
| 435 |
- input: "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1", |
|
| 436 |
- ipv6Enabled: true, |
|
| 437 |
- expOut: "nameserver 8.8.8.8\nnameserver 8.8.4.4\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844", |
|
| 438 |
- }, |
|
| 439 |
- {
|
|
| 440 |
- // with IPv6 disabled, and no non-localhost servers, Google defaults (only IPv4) should be added |
|
| 441 |
- name: "localhost only no IPv6", |
|
| 442 |
- input: "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1", |
|
| 443 |
- expOut: "nameserver 8.8.8.8\nnameserver 8.8.4.4", |
|
| 444 |
- }, |
|
| 445 |
- } |
|
| 446 |
- |
|
| 447 |
- for _, tc := range testcases {
|
|
| 448 |
- t.Run(tc.name, func(t *testing.T) {
|
|
| 449 |
- f, err := FilterResolvDNS([]byte(tc.input), tc.ipv6Enabled) |
|
| 450 |
- assert.Check(t, is.Nil(err)) |
|
| 451 |
- out := strings.TrimSpace(string(f.Content)) |
|
| 452 |
- assert.Check(t, is.Equal(out, tc.expOut)) |
|
| 453 |
- }) |
|
| 454 |
- } |
|
| 455 |
-} |
| ... | ... |
@@ -3,15 +3,26 @@ |
| 3 | 3 |
package libnetwork |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "bytes" |
|
| 6 | 7 |
"context" |
| 8 |
+ "os" |
|
| 7 | 9 |
"testing" |
| 8 | 10 |
|
| 9 | 11 |
"github.com/moby/moby/v2/daemon/libnetwork/config" |
| 10 |
- "github.com/moby/moby/v2/daemon/libnetwork/resolvconf" |
|
| 12 |
+ "github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf" |
|
| 11 | 13 |
"gotest.tools/v3/assert" |
| 12 | 14 |
is "gotest.tools/v3/assert/cmp" |
| 13 | 15 |
) |
| 14 | 16 |
|
| 17 |
+func getResolvConfOptions(t *testing.T, rcPath string) []string {
|
|
| 18 |
+ t.Helper() |
|
| 19 |
+ resolv, err := os.ReadFile(rcPath) |
|
| 20 |
+ assert.NilError(t, err) |
|
| 21 |
+ rc, err := resolvconf.Parse(bytes.NewBuffer(resolv), "") |
|
| 22 |
+ assert.NilError(t, err) |
|
| 23 |
+ return rc.Options() |
|
| 24 |
+} |
|
| 25 |
+ |
|
| 15 | 26 |
func TestDNSOptions(t *testing.T) {
|
| 16 | 27 |
c, err := New(context.Background(), config.OptionDataDir(t.TempDir())) |
| 17 | 28 |
assert.NilError(t, err) |
| ... | ... |
@@ -32,26 +43,20 @@ func TestDNSOptions(t *testing.T) {
|
| 32 | 32 |
assert.NilError(t, err) |
| 33 | 33 |
err = sb.rebuildDNS() |
| 34 | 34 |
assert.NilError(t, err) |
| 35 |
- currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath) |
|
| 36 |
- assert.NilError(t, err) |
|
| 37 |
- dnsOptionsList := resolvconf.GetOptions(currRC.Content) |
|
| 35 |
+ dnsOptionsList := getResolvConfOptions(t, sb.config.resolvConfPath) |
|
| 38 | 36 |
assert.Check(t, is.Len(dnsOptionsList, 1)) |
| 39 | 37 |
assert.Check(t, is.Equal("ndots:0", dnsOptionsList[0]))
|
| 40 | 38 |
|
| 41 | 39 |
sb.config.dnsOptionsList = []string{"ndots:5"}
|
| 42 | 40 |
err = sb.setupDNS() |
| 43 | 41 |
assert.NilError(t, err) |
| 44 |
- currRC, err = resolvconf.GetSpecific(sb.config.resolvConfPath) |
|
| 45 |
- assert.NilError(t, err) |
|
| 46 |
- dnsOptionsList = resolvconf.GetOptions(currRC.Content) |
|
| 42 |
+ dnsOptionsList = getResolvConfOptions(t, sb.config.resolvConfPath) |
|
| 47 | 43 |
assert.Check(t, is.Len(dnsOptionsList, 1)) |
| 48 | 44 |
assert.Check(t, is.Equal("ndots:5", dnsOptionsList[0]))
|
| 49 | 45 |
|
| 50 | 46 |
err = sb.rebuildDNS() |
| 51 | 47 |
assert.NilError(t, err) |
| 52 |
- currRC, err = resolvconf.GetSpecific(sb.config.resolvConfPath) |
|
| 53 |
- assert.NilError(t, err) |
|
| 54 |
- dnsOptionsList = resolvconf.GetOptions(currRC.Content) |
|
| 48 |
+ dnsOptionsList = getResolvConfOptions(t, sb.config.resolvConfPath) |
|
| 55 | 49 |
assert.Check(t, is.Len(dnsOptionsList, 1)) |
| 56 | 50 |
assert.Check(t, is.Equal("ndots:5", dnsOptionsList[0]))
|
| 57 | 51 |
|
| ... | ... |
@@ -65,9 +70,7 @@ func TestDNSOptions(t *testing.T) {
|
| 65 | 65 |
assert.NilError(t, err) |
| 66 | 66 |
err = sb2.rebuildDNS() |
| 67 | 67 |
assert.NilError(t, err) |
| 68 |
- currRC, err = resolvconf.GetSpecific(sb2.config.resolvConfPath) |
|
| 69 |
- assert.NilError(t, err) |
|
| 70 |
- dnsOptionsList = resolvconf.GetOptions(currRC.Content) |
|
| 68 |
+ dnsOptionsList = getResolvConfOptions(t, sb2.config.resolvConfPath) |
|
| 71 | 69 |
assert.Check(t, is.Len(dnsOptionsList, 1)) |
| 72 | 70 |
assert.Check(t, is.Equal("ndots:0", dnsOptionsList[0]))
|
| 73 | 71 |
|
| ... | ... |
@@ -76,9 +79,7 @@ func TestDNSOptions(t *testing.T) {
|
| 76 | 76 |
assert.NilError(t, err) |
| 77 | 77 |
err = sb2.rebuildDNS() |
| 78 | 78 |
assert.NilError(t, err) |
| 79 |
- currRC, err = resolvconf.GetSpecific(sb2.config.resolvConfPath) |
|
| 80 |
- assert.NilError(t, err) |
|
| 81 |
- dnsOptionsList = resolvconf.GetOptions(currRC.Content) |
|
| 79 |
+ dnsOptionsList = getResolvConfOptions(t, sb2.config.resolvConfPath) |
|
| 82 | 80 |
assert.Check(t, is.DeepEqual([]string{"ndots:0"}, dnsOptionsList))
|
| 83 | 81 |
|
| 84 | 82 |
sb2.config.dnsOptionsList = []string{"ndots:-1"}
|
| ... | ... |
@@ -86,8 +87,6 @@ func TestDNSOptions(t *testing.T) {
|
| 86 | 86 |
assert.NilError(t, err) |
| 87 | 87 |
err = sb2.rebuildDNS() |
| 88 | 88 |
assert.NilError(t, err) |
| 89 |
- currRC, err = resolvconf.GetSpecific(sb2.config.resolvConfPath) |
|
| 90 |
- assert.NilError(t, err) |
|
| 91 |
- dnsOptionsList = resolvconf.GetOptions(currRC.Content) |
|
| 89 |
+ dnsOptionsList = getResolvConfOptions(t, sb2.config.resolvConfPath) |
|
| 92 | 90 |
assert.Check(t, is.DeepEqual([]string{"ndots:0"}, dnsOptionsList))
|
| 93 | 91 |
} |
| ... | ... |
@@ -12,8 +12,7 @@ import ( |
| 12 | 12 |
"github.com/moby/moby/v2/errdefs" |
| 13 | 13 |
) |
| 14 | 14 |
|
| 15 |
-// constants for the IP address type |
|
| 16 |
-// Deprecated: use the consts defined in github.com/docker/docker/libnetwork/resolvconf |
|
| 15 |
+// constants for the IP address type. |
|
| 17 | 16 |
const ( |
| 18 | 17 |
IP = iota // IPv4 and IPv6 |
| 19 | 18 |
IPv4 |