mirror of
https://github.com/containers/podman.git
synced 2025-05-21 09:05:56 +08:00
use resolvconf package from c/common/libnetwork
Podman and Buildah should use the same code the generate the resolv.conf file. This mostly moved the podman code into c/common and created a better API for it so buildah can use it as well. [NO NEW TESTS NEEDED] All existing tests should continue to pass. Fixes #13599 (There is no way to test this in CI without breaking the hosts resolv.conf) Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
@ -17,6 +17,7 @@ import (
|
|||||||
"github.com/containers/buildah/pkg/overlay"
|
"github.com/containers/buildah/pkg/overlay"
|
||||||
butil "github.com/containers/buildah/util"
|
butil "github.com/containers/buildah/util"
|
||||||
"github.com/containers/common/libnetwork/etchosts"
|
"github.com/containers/common/libnetwork/etchosts"
|
||||||
|
"github.com/containers/common/libnetwork/resolvconf"
|
||||||
"github.com/containers/common/pkg/cgroups"
|
"github.com/containers/common/pkg/cgroups"
|
||||||
"github.com/containers/common/pkg/chown"
|
"github.com/containers/common/pkg/chown"
|
||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
@ -986,7 +987,7 @@ func (c *Container) checkDependenciesRunning() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Container) completeNetworkSetup() error {
|
func (c *Container) completeNetworkSetup() error {
|
||||||
var outResolvConf []string
|
var nameservers []string
|
||||||
netDisabled, err := c.NetworkDisabled()
|
netDisabled, err := c.NetworkDisabled()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1004,7 +1005,7 @@ func (c *Container) completeNetworkSetup() error {
|
|||||||
// collect any dns servers that cni tells us to use (dnsname)
|
// collect any dns servers that cni tells us to use (dnsname)
|
||||||
for _, status := range c.getNetworkStatus() {
|
for _, status := range c.getNetworkStatus() {
|
||||||
for _, server := range status.DNSServerIPs {
|
for _, server := range status.DNSServerIPs {
|
||||||
outResolvConf = append(outResolvConf, fmt.Sprintf("nameserver %s", server))
|
nameservers = append(nameservers, server.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check if we have a bindmount for /etc/hosts
|
// check if we have a bindmount for /etc/hosts
|
||||||
@ -1020,24 +1021,12 @@ func (c *Container) completeNetworkSetup() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if we have a bindmount for resolv.conf
|
// check if we have a bindmount for resolv.conf
|
||||||
resolvBindMount := state.BindMounts["/etc/resolv.conf"]
|
resolvBindMount := state.BindMounts[resolvconf.DefaultResolvConf]
|
||||||
if len(outResolvConf) < 1 || resolvBindMount == "" || len(c.config.NetNsCtr) > 0 {
|
if len(nameservers) < 1 || resolvBindMount == "" || len(c.config.NetNsCtr) > 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// read the existing resolv.conf
|
|
||||||
b, err := ioutil.ReadFile(resolvBindMount)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, line := range strings.Split(string(b), "\n") {
|
|
||||||
// only keep things that don't start with nameserver from the old
|
|
||||||
// resolv.conf file
|
|
||||||
if !strings.HasPrefix(line, "nameserver") {
|
|
||||||
outResolvConf = append([]string{line}, outResolvConf...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// write and return
|
// write and return
|
||||||
return ioutil.WriteFile(resolvBindMount, []byte(strings.Join(outResolvConf, "\n")), 0644)
|
return resolvconf.Add(resolvBindMount, nameservers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a container, creating it in the runtime
|
// Initialize a container, creating it in the runtime
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
@ -29,6 +28,7 @@ import (
|
|||||||
"github.com/containers/buildah/pkg/overlay"
|
"github.com/containers/buildah/pkg/overlay"
|
||||||
butil "github.com/containers/buildah/util"
|
butil "github.com/containers/buildah/util"
|
||||||
"github.com/containers/common/libnetwork/etchosts"
|
"github.com/containers/common/libnetwork/etchosts"
|
||||||
|
"github.com/containers/common/libnetwork/resolvconf"
|
||||||
"github.com/containers/common/libnetwork/types"
|
"github.com/containers/common/libnetwork/types"
|
||||||
"github.com/containers/common/pkg/apparmor"
|
"github.com/containers/common/pkg/apparmor"
|
||||||
"github.com/containers/common/pkg/cgroups"
|
"github.com/containers/common/pkg/cgroups"
|
||||||
@ -44,7 +44,6 @@ import (
|
|||||||
"github.com/containers/podman/v4/pkg/checkpoint/crutils"
|
"github.com/containers/podman/v4/pkg/checkpoint/crutils"
|
||||||
"github.com/containers/podman/v4/pkg/criu"
|
"github.com/containers/podman/v4/pkg/criu"
|
||||||
"github.com/containers/podman/v4/pkg/lookup"
|
"github.com/containers/podman/v4/pkg/lookup"
|
||||||
"github.com/containers/podman/v4/pkg/resolvconf"
|
|
||||||
"github.com/containers/podman/v4/pkg/rootless"
|
"github.com/containers/podman/v4/pkg/rootless"
|
||||||
"github.com/containers/podman/v4/pkg/util"
|
"github.com/containers/podman/v4/pkg/util"
|
||||||
"github.com/containers/podman/v4/utils"
|
"github.com/containers/podman/v4/utils"
|
||||||
@ -2308,49 +2307,10 @@ rootless=%d
|
|||||||
// generateResolvConf generates a containers resolv.conf
|
// generateResolvConf generates a containers resolv.conf
|
||||||
func (c *Container) generateResolvConf() error {
|
func (c *Container) generateResolvConf() error {
|
||||||
var (
|
var (
|
||||||
nameservers []string
|
|
||||||
networkNameServers []string
|
networkNameServers []string
|
||||||
networkSearchDomains []string
|
networkSearchDomains []string
|
||||||
)
|
)
|
||||||
|
|
||||||
hostns := true
|
|
||||||
resolvConf := "/etc/resolv.conf"
|
|
||||||
for _, namespace := range c.config.Spec.Linux.Namespaces {
|
|
||||||
if namespace.Type == spec.NetworkNamespace {
|
|
||||||
hostns = false
|
|
||||||
if namespace.Path != "" && !strings.HasPrefix(namespace.Path, "/proc/") {
|
|
||||||
definedPath := filepath.Join("/etc/netns", filepath.Base(namespace.Path), "resolv.conf")
|
|
||||||
_, err := os.Stat(definedPath)
|
|
||||||
if err == nil {
|
|
||||||
resolvConf = definedPath
|
|
||||||
} else if !os.IsNotExist(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contents, err := ioutil.ReadFile(resolvConf)
|
|
||||||
// resolv.conf doesn't have to exists
|
|
||||||
if err != nil && !os.IsNotExist(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ns := resolvconf.GetNameservers(contents)
|
|
||||||
// check if systemd-resolved is used, assume it is used when 127.0.0.53 is the only nameserver
|
|
||||||
if !hostns && len(ns) == 1 && ns[0] == "127.0.0.53" {
|
|
||||||
// read the actual resolv.conf file for systemd-resolved
|
|
||||||
resolvedContents, err := ioutil.ReadFile("/run/systemd/resolve/resolv.conf")
|
|
||||||
if err != nil {
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
return errors.Wrapf(err, "detected that systemd-resolved is in use, but could not locate real resolv.conf")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
contents = resolvedContents
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
netStatus := c.getNetworkStatus()
|
netStatus := c.getNetworkStatus()
|
||||||
for _, status := range netStatus {
|
for _, status := range netStatus {
|
||||||
if status.DNSServerIPs != nil {
|
if status.DNSServerIPs != nil {
|
||||||
@ -2370,34 +2330,18 @@ func (c *Container) generateResolvConf() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the container's /etc/resolv.conf is compatible with its
|
nameservers := make([]string, 0, len(c.runtime.config.Containers.DNSServers)+len(c.config.DNSServer))
|
||||||
// network configuration.
|
nameservers = append(nameservers, c.runtime.config.Containers.DNSServers...)
|
||||||
resolv, err := resolvconf.FilterResolvDNS(contents, ipv6, !hostns)
|
for _, ip := range c.config.DNSServer {
|
||||||
if err != nil {
|
nameservers = append(nameservers, ip.String())
|
||||||
return errors.Wrapf(err, "error parsing host resolv.conf")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dns := make([]net.IP, 0, len(c.runtime.config.Containers.DNSServers)+len(c.config.DNSServer))
|
|
||||||
for _, i := range c.runtime.config.Containers.DNSServers {
|
|
||||||
result := net.ParseIP(i)
|
|
||||||
if result == nil {
|
|
||||||
return errors.Wrapf(define.ErrInvalidArg, "invalid IP address %s", i)
|
|
||||||
}
|
|
||||||
dns = append(dns, result)
|
|
||||||
}
|
|
||||||
dns = append(dns, c.config.DNSServer...)
|
|
||||||
// If the user provided dns, it trumps all; then dns masq; then resolv.conf
|
// If the user provided dns, it trumps all; then dns masq; then resolv.conf
|
||||||
var search []string
|
var search []string
|
||||||
switch {
|
keepHostServers := false
|
||||||
case len(dns) > 0:
|
if len(nameservers) == 0 {
|
||||||
// We store DNS servers as net.IP, so need to convert to string
|
keepHostServers = true
|
||||||
for _, server := range dns {
|
|
||||||
nameservers = append(nameservers, server.String())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// Make a new resolv.conf
|
|
||||||
// first add the nameservers from the networks status
|
// first add the nameservers from the networks status
|
||||||
nameservers = append(nameservers, networkNameServers...)
|
nameservers = networkNameServers
|
||||||
// when we add network dns server we also have to add the search domains
|
// when we add network dns server we also have to add the search domains
|
||||||
search = networkSearchDomains
|
search = networkSearchDomains
|
||||||
// slirp4netns has a built in DNS forwarder.
|
// slirp4netns has a built in DNS forwarder.
|
||||||
@ -2409,38 +2353,34 @@ func (c *Container) generateResolvConf() error {
|
|||||||
nameservers = append(nameservers, slirp4netnsDNS.String())
|
nameservers = append(nameservers, slirp4netnsDNS.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nameservers = append(nameservers, resolvconf.GetNameservers(resolv.Content)...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 {
|
if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 {
|
||||||
if !cutil.StringInSlice(".", c.config.DNSSearch) {
|
customSearch := make([]string, 0, len(c.config.DNSSearch)+len(c.runtime.config.Containers.DNSSearches))
|
||||||
search = append(search, c.runtime.config.Containers.DNSSearches...)
|
customSearch = append(customSearch, c.runtime.config.Containers.DNSSearches...)
|
||||||
search = append(search, c.config.DNSSearch...)
|
customSearch = append(customSearch, c.config.DNSSearch...)
|
||||||
}
|
search = customSearch
|
||||||
} else {
|
|
||||||
search = append(search, resolvconf.GetSearchDomains(resolv.Content)...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var options []string
|
options := make([]string, 0, len(c.config.DNSOption)+len(c.runtime.config.Containers.DNSOptions))
|
||||||
if len(c.config.DNSOption) > 0 || len(c.runtime.config.Containers.DNSOptions) > 0 {
|
options = append(options, c.runtime.config.Containers.DNSOptions...)
|
||||||
options = c.runtime.config.Containers.DNSOptions
|
options = append(options, c.config.DNSOption...)
|
||||||
options = append(options, c.config.DNSOption...)
|
|
||||||
} else {
|
|
||||||
options = resolvconf.GetOptions(resolv.Content)
|
|
||||||
}
|
|
||||||
|
|
||||||
destPath := filepath.Join(c.state.RunDir, "resolv.conf")
|
destPath := filepath.Join(c.state.RunDir, "resolv.conf")
|
||||||
|
|
||||||
if err := os.Remove(destPath); err != nil && !os.IsNotExist(err) {
|
if err := resolvconf.New(&resolvconf.Params{
|
||||||
return errors.Wrapf(err, "container %s", c.ID())
|
IPv6Enabled: ipv6,
|
||||||
}
|
KeepHostServers: keepHostServers,
|
||||||
|
Nameservers: nameservers,
|
||||||
// Build resolv.conf
|
Namespaces: c.config.Spec.Linux.Namespaces,
|
||||||
if _, err = resolvconf.Build(destPath, nameservers, search, options); err != nil {
|
Options: options,
|
||||||
|
Path: destPath,
|
||||||
|
Searches: search,
|
||||||
|
}); err != nil {
|
||||||
return errors.Wrapf(err, "error building resolv.conf for container %s", c.ID())
|
return errors.Wrapf(err, "error building resolv.conf for container %s", c.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.bindMountRootFile(destPath, "/etc/resolv.conf")
|
return c.bindMountRootFile(destPath, resolvconf.DefaultResolvConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a container uses IPv6.
|
// Check if a container uses IPv6.
|
||||||
@ -2481,31 +2421,13 @@ func (c *Container) addNameserver(ips []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do we have a resolv.conf at all?
|
// Do we have a resolv.conf at all?
|
||||||
path, ok := c.state.BindMounts["/etc/resolv.conf"]
|
path, ok := c.state.BindMounts[resolvconf.DefaultResolvConf]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read in full contents, parse out existing nameservers
|
if err := resolvconf.Add(path, ips); err != nil {
|
||||||
contents, err := ioutil.ReadFile(path)
|
return fmt.Errorf("adding new nameserver to container %s resolv.conf: %w", c.ID(), err)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ns := resolvconf.GetNameservers(contents)
|
|
||||||
options := resolvconf.GetOptions(contents)
|
|
||||||
search := resolvconf.GetSearchDomains(contents)
|
|
||||||
|
|
||||||
// We could verify that it doesn't already exist
|
|
||||||
// but extra nameservers shouldn't harm anything.
|
|
||||||
// Ensure we are the first entry in resolv.conf though, otherwise we
|
|
||||||
// might be after user-added servers.
|
|
||||||
ns = append(ips, ns...)
|
|
||||||
|
|
||||||
// We're rewriting the container's resolv.conf as part of this, but we
|
|
||||||
// hold the container lock, so there should be no risk of parallel
|
|
||||||
// modification.
|
|
||||||
if _, err := resolvconf.Build(path, ns, search, options); err != nil {
|
|
||||||
return errors.Wrapf(err, "error adding new nameserver to container %s resolv.conf", c.ID())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -2520,34 +2442,13 @@ func (c *Container) removeNameserver(ips []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do we have a resolv.conf at all?
|
// Do we have a resolv.conf at all?
|
||||||
path, ok := c.state.BindMounts["/etc/resolv.conf"]
|
path, ok := c.state.BindMounts[resolvconf.DefaultResolvConf]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read in full contents, parse out existing nameservers
|
if err := resolvconf.Remove(path, ips); err != nil {
|
||||||
contents, err := ioutil.ReadFile(path)
|
return fmt.Errorf("removing nameservers from container %s resolv.conf: %w", c.ID(), err)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ns := resolvconf.GetNameservers(contents)
|
|
||||||
options := resolvconf.GetOptions(contents)
|
|
||||||
search := resolvconf.GetSearchDomains(contents)
|
|
||||||
|
|
||||||
toRemove := make(map[string]bool)
|
|
||||||
for _, ip := range ips {
|
|
||||||
toRemove[ip] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
newNS := make([]string, 0, len(ns))
|
|
||||||
for _, server := range ns {
|
|
||||||
if !toRemove[server] {
|
|
||||||
newNS = append(newNS, server)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := resolvconf.Build(path, newNS, search, options); err != nil {
|
|
||||||
return errors.Wrapf(err, "error removing nameservers from container %s resolv.conf", c.ID())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/containers/common/libnetwork/etchosts"
|
"github.com/containers/common/libnetwork/etchosts"
|
||||||
|
"github.com/containers/common/libnetwork/resolvconf"
|
||||||
"github.com/containers/common/libnetwork/types"
|
"github.com/containers/common/libnetwork/types"
|
||||||
"github.com/containers/common/pkg/config"
|
"github.com/containers/common/pkg/config"
|
||||||
"github.com/containers/common/pkg/machine"
|
"github.com/containers/common/pkg/machine"
|
||||||
@ -30,11 +31,10 @@ import (
|
|||||||
"github.com/containers/podman/v4/libpod/events"
|
"github.com/containers/podman/v4/libpod/events"
|
||||||
"github.com/containers/podman/v4/pkg/errorhandling"
|
"github.com/containers/podman/v4/pkg/errorhandling"
|
||||||
"github.com/containers/podman/v4/pkg/namespaces"
|
"github.com/containers/podman/v4/pkg/namespaces"
|
||||||
"github.com/containers/podman/v4/pkg/resolvconf"
|
|
||||||
"github.com/containers/podman/v4/pkg/rootless"
|
"github.com/containers/podman/v4/pkg/rootless"
|
||||||
"github.com/containers/podman/v4/utils"
|
"github.com/containers/podman/v4/utils"
|
||||||
"github.com/containers/storage/pkg/lockfile"
|
"github.com/containers/storage/pkg/lockfile"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -526,23 +526,19 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
|
|||||||
return nil, errors.Wrapf(err, "failed to determine slirp4netns DNS address from cidr: %s", cidr.String())
|
return nil, errors.Wrapf(err, "failed to determine slirp4netns DNS address from cidr: %s", cidr.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conf, err := resolvconf.Get()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conf, err = resolvconf.FilterResolvDNS(conf.Content, netOptions.enableIPv6, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
searchDomains := resolvconf.GetSearchDomains(conf.Content)
|
|
||||||
dnsOptions := resolvconf.GetOptions(conf.Content)
|
|
||||||
nameServers := resolvconf.GetNameservers(conf.Content)
|
|
||||||
|
|
||||||
_, err = resolvconf.Build(filepath.Join(rootlessNetNsDir, "resolv.conf"), append([]string{resolveIP.String()}, nameServers...), searchDomains, dnsOptions)
|
if err := resolvconf.New(&resolvconf.Params{
|
||||||
if err != nil {
|
Path: filepath.Join(rootlessNetNsDir, "resolv.conf"),
|
||||||
|
// fake the netns since we want to filter localhost
|
||||||
|
Namespaces: []specs.LinuxNamespace{
|
||||||
|
{Type: specs.NetworkNamespace},
|
||||||
|
},
|
||||||
|
IPv6Enabled: netOptions.enableIPv6,
|
||||||
|
KeepHostServers: true,
|
||||||
|
Nameservers: []string{resolveIP.String()},
|
||||||
|
}); err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to create rootless netns resolv.conf")
|
return nil, errors.Wrap(err, "failed to create rootless netns resolv.conf")
|
||||||
}
|
}
|
||||||
|
|
||||||
// create cni directories to store files
|
// create cni directories to store files
|
||||||
// they will be bind mounted to the correct location in a extra mount ns
|
// they will be bind mounted to the correct location in a extra mount ns
|
||||||
err = os.MkdirAll(filepath.Join(rootlessNetNsDir, persistentCNIDir), 0700)
|
err = os.MkdirAll(filepath.Join(rootlessNetNsDir, persistentCNIDir), 0700)
|
||||||
@ -1089,7 +1085,7 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
|||||||
|
|
||||||
func (c *Container) joinedNetworkNSPath() string {
|
func (c *Container) joinedNetworkNSPath() string {
|
||||||
for _, namespace := range c.config.Spec.Linux.Namespaces {
|
for _, namespace := range c.config.Spec.Linux.Namespaces {
|
||||||
if namespace.Type == spec.NetworkNamespace {
|
if namespace.Type == specs.NetworkNamespace {
|
||||||
return namespace.Path
|
return namespace.Path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
// Originally from github.com/docker/libnetwork/resolvconf/dns
|
|
||||||
|
|
||||||
package dns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IPLocalhost is a regex pattern for IPv4 or IPv6 loopback range.
|
|
||||||
const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
|
|
||||||
|
|
||||||
// IPv4Localhost is a regex pattern for IPv4 localhost address range.
|
|
||||||
const IPv4Localhost = `(127\.([0-9]{1,3}\.){2}[0-9]{1,3})`
|
|
||||||
|
|
||||||
var localhostIPRegexp = regexp.MustCompile(IPLocalhost)
|
|
||||||
var localhostIPv4Regexp = regexp.MustCompile(IPv4Localhost)
|
|
||||||
|
|
||||||
// IsLocalhost returns true if ip matches the localhost IP regular expression.
|
|
||||||
// Used for determining if nameserver settings are being passed which are
|
|
||||||
// localhost addresses
|
|
||||||
func IsLocalhost(ip string) bool {
|
|
||||||
return localhostIPRegexp.MatchString(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsIPv4Localhost returns true if ip matches the IPv4 localhost regular expression.
|
|
||||||
func IsIPv4Localhost(ip string) bool {
|
|
||||||
return localhostIPv4Regexp.MatchString(ip)
|
|
||||||
}
|
|
182
vendor/github.com/containers/common/libnetwork/resolvconf/resolv.go
generated
vendored
Normal file
182
vendor/github.com/containers/common/libnetwork/resolvconf/resolv.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package resolvconf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/util"
|
||||||
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
localhost = "127.0.0.1"
|
||||||
|
systemdResolvedIP = "127.0.0.53"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Params for the New() function.
|
||||||
|
type Params struct {
|
||||||
|
// Path is the path to new resolv.conf file which should be created.
|
||||||
|
Path string
|
||||||
|
// Namespaces is the list of container namespaces.
|
||||||
|
// This is required to fist check for a resolv.conf under /etc/netns,
|
||||||
|
// created by "ip netns". Also used to check if the container has a
|
||||||
|
// netns in which case localhost nameserver must be filtered.
|
||||||
|
Namespaces []specs.LinuxNamespace
|
||||||
|
// IPv6Enabled will filter ipv6 nameservers when not set to true.
|
||||||
|
IPv6Enabled bool
|
||||||
|
// KeepHostServers can be set when it is required to still keep the
|
||||||
|
// original resolv.conf content even when custom Nameserver/Searches/Options
|
||||||
|
// are set. In this case they will be appended to the given values.
|
||||||
|
KeepHostServers bool
|
||||||
|
// Nameservers is a list of nameservers the container should use,
|
||||||
|
// instead of the default ones from the host.
|
||||||
|
Nameservers []string
|
||||||
|
// Searches is a list of dns search domains the container should use,
|
||||||
|
// instead of the default ones from the host.
|
||||||
|
Searches []string
|
||||||
|
// Options is a list of dns options the container should use,
|
||||||
|
// instead of the default ones from the host.
|
||||||
|
Options []string
|
||||||
|
|
||||||
|
// resolvConfPath is the path which should be used as base to get the dns
|
||||||
|
// options. This should only be used for testing purposes. For all other
|
||||||
|
// callers this defaults to /etc/resolv.conf.
|
||||||
|
resolvConfPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDefaultResolvConf(params *Params) ([]byte, bool, error) {
|
||||||
|
resolveConf := DefaultResolvConf
|
||||||
|
// this is only used by testing
|
||||||
|
if params.resolvConfPath != "" {
|
||||||
|
resolveConf = params.resolvConfPath
|
||||||
|
}
|
||||||
|
hostNS := true
|
||||||
|
for _, ns := range params.Namespaces {
|
||||||
|
if ns.Type == specs.NetworkNamespace {
|
||||||
|
hostNS = false
|
||||||
|
if ns.Path != "" && !strings.HasPrefix(ns.Path, "/proc/") {
|
||||||
|
// check for netns created by "ip netns"
|
||||||
|
path := filepath.Join("/etc/netns", filepath.Base(ns.Path), "resolv.conf")
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
if err == nil {
|
||||||
|
resolveConf = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contents, err := os.ReadFile(resolveConf)
|
||||||
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
if hostNS {
|
||||||
|
return contents, hostNS, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ns := getNameservers(contents)
|
||||||
|
// Check for local only resolver, in this case we want to get the real nameservers
|
||||||
|
// since localhost is not reachable from the netns.
|
||||||
|
if len(ns) == 1 {
|
||||||
|
var path string
|
||||||
|
switch ns[0] {
|
||||||
|
case systemdResolvedIP:
|
||||||
|
// used by systemd-resolved
|
||||||
|
path = "/run/systemd/resolve/resolv.conf"
|
||||||
|
case localhost:
|
||||||
|
// used by NetworkManager https://github.com/containers/podman/issues/13599
|
||||||
|
path = "/run/NetworkManager/no-stub-resolv.conf"
|
||||||
|
}
|
||||||
|
if path != "" {
|
||||||
|
// read the actual resolv.conf file for
|
||||||
|
resolvedContents, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
// do not error when the file does not exists, the detection logic is not perfect
|
||||||
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return nil, false, fmt.Errorf("local resolver detected, but could not read real resolv.conf at %q: %w", path, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logrus.Debugf("found local resolver, using %q to get the nameservers", path)
|
||||||
|
contents = resolvedContents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contents, hostNS, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsetSearchDomainsIfNeeded removes the search domain when they contain a single dot as element.
|
||||||
|
func unsetSearchDomainsIfNeeded(searches []string) []string {
|
||||||
|
if util.StringInSlice(".", searches) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return searches
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new resolv.conf file with the given params.
|
||||||
|
func New(params *Params) error {
|
||||||
|
// short path, if everything is given there is no need to actually read the hosts /etc/resolv.conf
|
||||||
|
if len(params.Nameservers) > 0 && len(params.Options) > 0 && len(params.Searches) > 0 && !params.KeepHostServers {
|
||||||
|
return build(params.Path, params.Nameservers, unsetSearchDomainsIfNeeded(params.Searches), params.Options)
|
||||||
|
}
|
||||||
|
|
||||||
|
content, hostNS, err := getDefaultResolvConf(params)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get the default /etc/resolv.conf content: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content = filterResolvDNS(content, params.IPv6Enabled, !hostNS)
|
||||||
|
|
||||||
|
nameservers := params.Nameservers
|
||||||
|
if len(nameservers) == 0 || params.KeepHostServers {
|
||||||
|
nameservers = append(nameservers, getNameservers(content)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
searches := unsetSearchDomainsIfNeeded(params.Searches)
|
||||||
|
// if no params.Searches then use host ones
|
||||||
|
// otherwise make sure that they were no explicitly unset before adding host ones
|
||||||
|
if len(params.Searches) == 0 || (params.KeepHostServers && len(searches) > 0) {
|
||||||
|
searches = append(searches, getSearchDomains(content)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
options := params.Options
|
||||||
|
if len(options) == 0 || params.KeepHostServers {
|
||||||
|
options = append(options, getOptions(content)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return build(params.Path, nameservers, searches, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add will add the given nameservers to the given resolv.conf file.
|
||||||
|
// It will add the nameserver in front of the existing ones.
|
||||||
|
func Add(path string, nameservers []string) error {
|
||||||
|
contents, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nameservers = append(nameservers, getNameservers(contents)...)
|
||||||
|
return build(path, nameservers, getSearchDomains(contents), getOptions(contents))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the given nameserver from the given resolv.conf file.
|
||||||
|
func Remove(path string, nameservers []string) error {
|
||||||
|
contents, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
oldNameservers := getNameservers(contents)
|
||||||
|
newNameserver := make([]string, 0, len(oldNameservers))
|
||||||
|
for _, ns := range oldNameservers {
|
||||||
|
if !util.StringInSlice(ns, nameservers) {
|
||||||
|
newNameserver = append(newNameserver, ns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return build(path, newNameserver, getSearchDomains(contents), getOptions(contents))
|
||||||
|
}
|
@ -1,26 +1,23 @@
|
|||||||
// Package resolvconf provides utility code to query and update DNS configuration in /etc/resolv.conf.
|
// Package resolvconf provides utility code to query and update DNS configuration in /etc/resolv.conf.
|
||||||
// Originally from github.com/docker/libnetwork/resolvconf.
|
// Originally from github.com/docker/libnetwork/resolvconf but heavily modified to better work with podman.
|
||||||
package resolvconf
|
package resolvconf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/containers/podman/v4/pkg/resolvconf/dns"
|
|
||||||
"github.com/containers/storage/pkg/ioutils"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultResolvConf points to the default file used for dns configuration on a linux machine
|
// DefaultResolvConf points to the default file used for dns configuration on a linux machine.
|
||||||
DefaultResolvConf = "/etc/resolv.conf"
|
DefaultResolvConf = "/etc/resolv.conf"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Note: the default IPv4 & IPv6 resolvers are set to Google's Public DNS
|
// Note: the default IPv4 & IPv6 resolvers are set to Google's Public DNS.
|
||||||
defaultIPv4Dns = []string{"nameserver 8.8.8.8", "nameserver 8.8.4.4"}
|
defaultIPv4Dns = []string{"nameserver 8.8.8.8", "nameserver 8.8.4.4"}
|
||||||
defaultIPv6Dns = []string{"nameserver 2001:4860:4860::8888", "nameserver 2001:4860:4860::8844"}
|
defaultIPv6Dns = []string{"nameserver 2001:4860:4860::8888", "nameserver 2001:4860:4860::8844"}
|
||||||
ipv4NumBlock = `(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)`
|
ipv4NumBlock = `(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)`
|
||||||
@ -29,94 +26,30 @@ var (
|
|||||||
// will *not match* IPv4-Embedded IPv6 Addresses (RFC6052), but that and other variants
|
// will *not match* IPv4-Embedded IPv6 Addresses (RFC6052), but that and other variants
|
||||||
// -- e.g. other link-local types -- either won't work in containers or are unnecessary.
|
// -- e.g. other link-local types -- either won't work in containers or are unnecessary.
|
||||||
// For readability and sufficiency for Docker purposes this seemed more reasonable than a
|
// For readability and sufficiency for Docker purposes this seemed more reasonable than a
|
||||||
// 1000+ character regexp with exact and complete IPv6 validation
|
// 1000+ character regexp with exact and complete IPv6 validation.
|
||||||
ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})(%\w+)?`
|
ipv6Address = `([0-9A-Fa-f]{0,4}:){2,7}([0-9A-Fa-f]{0,4})(%\w+)?`
|
||||||
|
|
||||||
localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + dns.IPLocalhost + `\s*\n*`)
|
// ipLocalhost is a regex pattern for IPv4 or IPv6 loopback range.
|
||||||
|
ipLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)`
|
||||||
|
|
||||||
|
localhostNSRegexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipLocalhost + `\s*\n*`)
|
||||||
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
|
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
|
||||||
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
|
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
|
||||||
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
|
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
|
||||||
optionsRegexp = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`)
|
optionsRegexp = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
var lastModified struct {
|
// filterResolvDNS cleans up the config in resolvConf. It has two main jobs:
|
||||||
sync.Mutex
|
|
||||||
sha256 string
|
|
||||||
contents []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// File contains the resolv.conf content and its hash
|
|
||||||
type File struct {
|
|
||||||
Content []byte
|
|
||||||
Hash string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the contents of /etc/resolv.conf and its hash
|
|
||||||
func Get() (*File, error) {
|
|
||||||
return GetSpecific(DefaultResolvConf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSpecific returns the contents of the user specified resolv.conf file and its hash
|
|
||||||
func GetSpecific(path string) (*File, error) {
|
|
||||||
resolv, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
hash, err := ioutils.HashData(bytes.NewReader(resolv))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &File{Content: resolv, Hash: hash}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetIfChanged retrieves the host /etc/resolv.conf file, checks against the last hash
|
|
||||||
// and, if modified since last check, returns the bytes and new hash.
|
|
||||||
// This feature is used by the resolv.conf updater for containers
|
|
||||||
func GetIfChanged() (*File, error) {
|
|
||||||
lastModified.Lock()
|
|
||||||
defer lastModified.Unlock()
|
|
||||||
|
|
||||||
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
newHash, err := ioutils.HashData(bytes.NewReader(resolv))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if lastModified.sha256 != newHash {
|
|
||||||
lastModified.sha256 = newHash
|
|
||||||
lastModified.contents = resolv
|
|
||||||
return &File{Content: resolv, Hash: newHash}, nil
|
|
||||||
}
|
|
||||||
// nothing changed, so return no data
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLastModified retrieves the last used contents and hash of the host resolv.conf.
|
|
||||||
// Used by containers updating on restart
|
|
||||||
func GetLastModified() *File {
|
|
||||||
lastModified.Lock()
|
|
||||||
defer lastModified.Unlock()
|
|
||||||
|
|
||||||
return &File{Content: lastModified.contents, Hash: lastModified.sha256}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FilterResolvDNS cleans up the config in resolvConf. It has two main jobs:
|
|
||||||
// 1. If a netns is enabled, it looks for localhost (127.*|::1) entries in the provided
|
// 1. If a netns is enabled, it looks for localhost (127.*|::1) entries in the provided
|
||||||
// resolv.conf, removing local nameserver entries, and, if the resulting
|
// resolv.conf, removing local nameserver entries, and, if the resulting
|
||||||
// cleaned config has no defined nameservers left, adds default DNS entries
|
// cleaned config has no defined nameservers left, adds default DNS entries
|
||||||
// 2. Given the caller provides the enable/disable state of IPv6, the filter
|
// 2. Given the caller provides the enable/disable state of IPv6, the filter
|
||||||
// code will remove all IPv6 nameservers if it is not enabled for containers
|
// code will remove all IPv6 nameservers if it is not enabled for containers
|
||||||
//
|
//
|
||||||
func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) (*File, error) {
|
func filterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) []byte {
|
||||||
// If we're using the host netns, we have nothing to do besides hash the file.
|
// If we're using the host netns, we have nothing to do besides hash the file.
|
||||||
if !netnsEnabled {
|
if !netnsEnabled {
|
||||||
hash, err := ioutils.HashData(bytes.NewReader(resolvConf))
|
return resolvConf
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &File{Content: resolvConf, Hash: hash}, nil
|
|
||||||
}
|
}
|
||||||
cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{})
|
cleanedResolvConf := localhostNSRegexp.ReplaceAll(resolvConf, []byte{})
|
||||||
// if IPv6 is not enabled, also clean out any IPv6 address nameserver
|
// if IPv6 is not enabled, also clean out any IPv6 address nameserver
|
||||||
@ -125,7 +58,7 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) (*F
|
|||||||
}
|
}
|
||||||
// if the resulting resolvConf has no more nameservers defined, add appropriate
|
// if the resulting resolvConf has no more nameservers defined, add appropriate
|
||||||
// default DNS servers for IPv4 and (optionally) IPv6
|
// default DNS servers for IPv4 and (optionally) IPv6
|
||||||
if len(GetNameservers(cleanedResolvConf)) == 0 {
|
if len(getNameservers(cleanedResolvConf)) == 0 {
|
||||||
logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers: %v", defaultIPv4Dns)
|
logrus.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers: %v", defaultIPv4Dns)
|
||||||
dns := defaultIPv4Dns
|
dns := defaultIPv4Dns
|
||||||
if ipv6Enabled {
|
if ipv6Enabled {
|
||||||
@ -134,19 +67,15 @@ func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool, netnsEnabled bool) (*F
|
|||||||
}
|
}
|
||||||
cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
|
cleanedResolvConf = append(cleanedResolvConf, []byte("\n"+strings.Join(dns, "\n"))...)
|
||||||
}
|
}
|
||||||
hash, err := ioutils.HashData(bytes.NewReader(cleanedResolvConf))
|
return cleanedResolvConf
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &File{Content: cleanedResolvConf, Hash: hash}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLines parses input into lines and strips away comments.
|
// getLines parses input into lines and strips away comments.
|
||||||
func getLines(input []byte, commentMarker []byte) [][]byte {
|
func getLines(input []byte) [][]byte {
|
||||||
lines := bytes.Split(input, []byte("\n"))
|
lines := bytes.Split(input, []byte("\n"))
|
||||||
var output [][]byte
|
var output [][]byte
|
||||||
for _, currentLine := range lines {
|
for _, currentLine := range lines {
|
||||||
var commentIndex = bytes.Index(currentLine, commentMarker)
|
commentIndex := bytes.Index(currentLine, []byte("#"))
|
||||||
if commentIndex == -1 {
|
if commentIndex == -1 {
|
||||||
output = append(output, currentLine)
|
output = append(output, currentLine)
|
||||||
} else {
|
} else {
|
||||||
@ -156,10 +85,10 @@ func getLines(input []byte, commentMarker []byte) [][]byte {
|
|||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf
|
// getNameservers returns nameservers (if any) listed in /etc/resolv.conf.
|
||||||
func GetNameservers(resolvConf []byte) []string {
|
func getNameservers(resolvConf []byte) []string {
|
||||||
nameservers := []string{}
|
nameservers := []string{}
|
||||||
for _, line := range getLines(resolvConf, []byte("#")) {
|
for _, line := range getLines(resolvConf) {
|
||||||
ns := nsRegexp.FindSubmatch(line)
|
ns := nsRegexp.FindSubmatch(line)
|
||||||
if len(ns) > 0 {
|
if len(ns) > 0 {
|
||||||
nameservers = append(nameservers, string(ns[1]))
|
nameservers = append(nameservers, string(ns[1]))
|
||||||
@ -168,30 +97,12 @@ func GetNameservers(resolvConf []byte) []string {
|
|||||||
return nameservers
|
return nameservers
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNameserversAsCIDR returns nameservers (if any) listed in
|
// getSearchDomains returns search domains (if any) listed in /etc/resolv.conf
|
||||||
// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32")
|
|
||||||
// This function's output is intended for net.ParseCIDR
|
|
||||||
func GetNameserversAsCIDR(resolvConf []byte) []string {
|
|
||||||
nameservers := []string{}
|
|
||||||
for _, nameserver := range GetNameservers(resolvConf) {
|
|
||||||
var address string
|
|
||||||
// If IPv6, strip zone if present
|
|
||||||
if strings.Contains(nameserver, ":") {
|
|
||||||
address = strings.Split(nameserver, "%")[0] + "/128"
|
|
||||||
} else {
|
|
||||||
address = nameserver + "/32"
|
|
||||||
}
|
|
||||||
nameservers = append(nameservers, address)
|
|
||||||
}
|
|
||||||
return nameservers
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSearchDomains returns search domains (if any) listed in /etc/resolv.conf
|
|
||||||
// If more than one search line is encountered, only the contents of the last
|
// If more than one search line is encountered, only the contents of the last
|
||||||
// one is returned.
|
// one is returned.
|
||||||
func GetSearchDomains(resolvConf []byte) []string {
|
func getSearchDomains(resolvConf []byte) []string {
|
||||||
domains := []string{}
|
domains := []string{}
|
||||||
for _, line := range getLines(resolvConf, []byte("#")) {
|
for _, line := range getLines(resolvConf) {
|
||||||
match := searchRegexp.FindSubmatch(line)
|
match := searchRegexp.FindSubmatch(line)
|
||||||
if match == nil {
|
if match == nil {
|
||||||
continue
|
continue
|
||||||
@ -201,12 +112,12 @@ func GetSearchDomains(resolvConf []byte) []string {
|
|||||||
return domains
|
return domains
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOptions returns options (if any) listed in /etc/resolv.conf
|
// getOptions returns options (if any) listed in /etc/resolv.conf
|
||||||
// If more than one options line is encountered, only the contents of the last
|
// If more than one options line is encountered, only the contents of the last
|
||||||
// one is returned.
|
// one is returned.
|
||||||
func GetOptions(resolvConf []byte) []string {
|
func getOptions(resolvConf []byte) []string {
|
||||||
options := []string{}
|
options := []string{}
|
||||||
for _, line := range getLines(resolvConf, []byte("#")) {
|
for _, line := range getLines(resolvConf) {
|
||||||
match := optionsRegexp.FindSubmatch(line)
|
match := optionsRegexp.FindSubmatch(line)
|
||||||
if match == nil {
|
if match == nil {
|
||||||
continue
|
continue
|
||||||
@ -216,35 +127,30 @@ func GetOptions(resolvConf []byte) []string {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build writes a configuration file to path containing a "nameserver" entry
|
// build writes a configuration file to path containing a "nameserver" entry
|
||||||
// for every element in dns, a "search" entry for every element in
|
// for every element in dns, a "search" entry for every element in
|
||||||
// dnsSearch, and an "options" entry for every element in dnsOptions.
|
// dnsSearch, and an "options" entry for every element in dnsOptions.
|
||||||
func Build(path string, dns, dnsSearch, dnsOptions []string) (*File, error) {
|
func build(path string, dns, dnsSearch, dnsOptions []string) error {
|
||||||
content := bytes.NewBuffer(nil)
|
content := new(bytes.Buffer)
|
||||||
if len(dnsSearch) > 0 {
|
if len(dnsSearch) > 0 {
|
||||||
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
|
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
|
||||||
if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
|
if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, dns := range dns {
|
for _, dns := range dns {
|
||||||
if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
|
if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(dnsOptions) > 0 {
|
if len(dnsOptions) > 0 {
|
||||||
if optsString := strings.Join(dnsOptions, " "); strings.Trim(optsString, " ") != "" {
|
if optsString := strings.Join(dnsOptions, " "); strings.Trim(optsString, " ") != "" {
|
||||||
if _, err := content.WriteString("options " + optsString + "\n"); err != nil {
|
if _, err := content.WriteString("options " + optsString + "\n"); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hash, err := ioutils.HashData(bytes.NewReader(content.Bytes()))
|
return os.WriteFile(path, content.Bytes(), 0o644)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &File{Content: content.Bytes(), Hash: hash}, ioutil.WriteFile(path, content.Bytes(), 0644)
|
|
||||||
}
|
}
|
1
vendor/modules.txt
vendored
1
vendor/modules.txt
vendored
@ -119,6 +119,7 @@ github.com/containers/common/libnetwork/etchosts
|
|||||||
github.com/containers/common/libnetwork/internal/util
|
github.com/containers/common/libnetwork/internal/util
|
||||||
github.com/containers/common/libnetwork/netavark
|
github.com/containers/common/libnetwork/netavark
|
||||||
github.com/containers/common/libnetwork/network
|
github.com/containers/common/libnetwork/network
|
||||||
|
github.com/containers/common/libnetwork/resolvconf
|
||||||
github.com/containers/common/libnetwork/types
|
github.com/containers/common/libnetwork/types
|
||||||
github.com/containers/common/libnetwork/util
|
github.com/containers/common/libnetwork/util
|
||||||
github.com/containers/common/pkg/apparmor
|
github.com/containers/common/pkg/apparmor
|
||||||
|
Reference in New Issue
Block a user