From b1dbd477e12f12c49d3333ac5d0645511e75c1a9 Mon Sep 17 00:00:00 2001 From: tomsweeneyredhat Date: Fri, 29 Mar 2024 20:31:13 -0400 Subject: [PATCH 1/3] [v5.0] Bump Buildah to v1.35.3 As the title says, bumping to Buildah v1.35.3 in preparation of Podman v5.0.1 [NO NEW TESTS NEEDED] Signed-off-by: tomsweeneyredhat --- go.mod | 4 +- go.sum | 8 +- .../containers/buildah/CHANGELOG.md | 9 + .../containers/buildah/changelog.txt | 7 + .../containers/buildah/define/types.go | 2 +- vendor/github.com/containers/buildah/run.go | 11 ++ .../containers/buildah/run_common.go | 168 ++++++++++-------- .../containers/buildah/run_freebsd.go | 50 +++++- .../containers/buildah/run_linux.go | 133 ++++++++------ .../common/libnetwork/etchosts/ip.go | 15 +- .../internal/rootlessnetns/netns_linux.go | 9 +- .../pasta/{pasta.go => pasta_linux.go} | 87 +++++++-- .../common/libnetwork/pasta/types.go | 15 ++ .../common/libnetwork/slirp4netns/const.go | 12 ++ .../libnetwork/slirp4netns/slirp4netns.go | 10 -- .../containers/common/libnetwork/util/ip.go | 17 ++ .../containers/common/version/version.go | 2 +- vendor/modules.txt | 4 +- 18 files changed, 374 insertions(+), 189 deletions(-) rename vendor/github.com/containers/common/libnetwork/pasta/{pasta.go => pasta_linux.go} (61%) create mode 100644 vendor/github.com/containers/common/libnetwork/pasta/types.go diff --git a/go.mod b/go.mod index 069d6e4cc4..313eb37655 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,8 @@ require ( github.com/checkpoint-restore/checkpointctl v1.1.0 github.com/checkpoint-restore/go-criu/v7 v7.0.0 github.com/containernetworking/plugins v1.4.0 - github.com/containers/buildah v1.35.1 - github.com/containers/common v0.58.0 + github.com/containers/buildah v1.35.3 + github.com/containers/common v0.58.1 github.com/containers/conmon v2.0.20+incompatible github.com/containers/gvisor-tap-vsock v0.7.3 github.com/containers/image/v5 v5.30.0 diff --git a/go.sum b/go.sum index d2d3ada137..0074c74a56 100644 --- a/go.sum +++ b/go.sum @@ -74,10 +74,10 @@ github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl3 github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw= github.com/containernetworking/plugins v1.4.0 h1:+w22VPYgk7nQHw7KT92lsRmuToHvb7wwSv9iTbXzzic= github.com/containernetworking/plugins v1.4.0/go.mod h1:UYhcOyjefnrQvKvmmyEKsUA+M9Nfn7tqULPpH0Pkcj0= -github.com/containers/buildah v1.35.1 h1:m4TF6V8b06cS4jH9/t39PUsUIjzDQg/P14FLpwjr40Y= -github.com/containers/buildah v1.35.1/go.mod h1:vVSVUlTu8+99H5j43gBJscpkb/quZvdJg78+6X1HeTM= -github.com/containers/common v0.58.0 h1:iQuwMxDD4ubZ9s1tmgdsiaHxMU4TdVBpV6kctJc6Bk8= -github.com/containers/common v0.58.0/go.mod h1:l3vMqanJGj7tZ3W/i76gEJ128VXgFUO1tLaohJXPvdk= +github.com/containers/buildah v1.35.3 h1:Dn8Krwm2PemBNNOMwp7uiMK2e5cW2ZjTdLRzKM789pc= +github.com/containers/buildah v1.35.3/go.mod h1:kYi6vTHdbr1gnRo3B/RhTHsY2if/w398+/RvCxAXqkQ= +github.com/containers/common v0.58.1 h1:E1DN9Lr7kgMVQy7AXLv1CYQCiqnweklMiYWbf0KOnqY= +github.com/containers/common v0.58.1/go.mod h1:l3vMqanJGj7tZ3W/i76gEJ128VXgFUO1tLaohJXPvdk= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/gvisor-tap-vsock v0.7.3 h1:yORnf15sP+sLFhxLNLgmB5/lOhldn9dRMHx/tmYtSOQ= diff --git a/vendor/github.com/containers/buildah/CHANGELOG.md b/vendor/github.com/containers/buildah/CHANGELOG.md index 5c4101610e..dff8796250 100644 --- a/vendor/github.com/containers/buildah/CHANGELOG.md +++ b/vendor/github.com/containers/buildah/CHANGELOG.md @@ -2,6 +2,15 @@ # Changelog +## v1.35.3 (2024-03-28) + + [release-1.35] Bump c/common to v0.58.1 + +## v1.35.2 (2024-03-22) + + [release-1.35] CVE-2024-24786 protobuf to 1.33 + [release-1.35] Bump to v1.35.2-dev + ## v1.35.1 (2024-03-18) [release-1.35] CVE-2024-1753 container escape fix diff --git a/vendor/github.com/containers/buildah/changelog.txt b/vendor/github.com/containers/buildah/changelog.txt index 8c3b7a791a..0f1b9de3d3 100644 --- a/vendor/github.com/containers/buildah/changelog.txt +++ b/vendor/github.com/containers/buildah/changelog.txt @@ -1,3 +1,10 @@ +- Changelog for v1.35.3 (2024-03-28) + * [release-1.35] Bump c/common to v0.58.1 + +- Changelog for v1.35.2 (2024-03-22) + * [release-1.35] CVE-2024-24786 protobuf to 1.33 + * [release-1.35] Bump to v1.35.2-dev + - Changelog for v1.35.1 (2024-03-18) * [release-1.35] CVE-2024-1753 container escape fix diff --git a/vendor/github.com/containers/buildah/define/types.go b/vendor/github.com/containers/buildah/define/types.go index 27d1128059..017354060f 100644 --- a/vendor/github.com/containers/buildah/define/types.go +++ b/vendor/github.com/containers/buildah/define/types.go @@ -29,7 +29,7 @@ const ( // identify working containers. Package = "buildah" // Version for the Package. Also used by .packit.sh for Packit builds. - Version = "1.35.1" + Version = "1.35.3" // DefaultRuntime if containers.conf fails. DefaultRuntime = "runc" diff --git a/vendor/github.com/containers/buildah/run.go b/vendor/github.com/containers/buildah/run.go index 77887dfe8f..c783953211 100644 --- a/vendor/github.com/containers/buildah/run.go +++ b/vendor/github.com/containers/buildah/run.go @@ -3,10 +3,12 @@ package buildah import ( "fmt" "io" + "net" "github.com/containers/buildah/define" "github.com/containers/buildah/internal" "github.com/containers/buildah/pkg/sshagent" + "github.com/containers/common/libnetwork/etchosts" "github.com/containers/image/v5/types" "github.com/containers/storage/pkg/lockfile" "github.com/opencontainers/runtime-spec/specs-go" @@ -207,3 +209,12 @@ type IDMaps struct { processUID int processGID int } + +// netResult type to hold network info for hosts/resolv.conf +type netResult struct { + entries etchosts.HostEntries + dnsServers []string + excludeIPs []net.IP + ipv6 bool + keepHostResolvers bool +} diff --git a/vendor/github.com/containers/buildah/run_common.go b/vendor/github.com/containers/buildah/run_common.go index 1843917367..06fbbddd46 100644 --- a/vendor/github.com/containers/buildah/run_common.go +++ b/vendor/github.com/containers/buildah/run_common.go @@ -55,30 +55,43 @@ import ( "golang.org/x/term" ) +func (b *Builder) createResolvConf(rdir string, chownOpts *idtools.IDPair) (string, error) { + cfile := filepath.Join(rdir, "resolv.conf") + f, err := os.Create(cfile) + if err != nil { + return "", err + } + defer f.Close() + + uid := 0 + gid := 0 + if chownOpts != nil { + uid = chownOpts.UID + gid = chownOpts.GID + } + if err = f.Chown(uid, gid); err != nil { + return "", err + } + + if err := relabel(cfile, b.MountLabel, false); err != nil { + return "", err + } + return cfile, nil +} + // addResolvConf copies files from host and sets them up to bind mount into container -func (b *Builder) addResolvConf(rdir string, chownOpts *idtools.IDPair, dnsServers, dnsSearch, dnsOptions []string, namespaces []specs.LinuxNamespace) (string, error) { +func (b *Builder) addResolvConfEntries(file string, networkNameServer []string, + namespaces []specs.LinuxNamespace, keepHostServers, ipv6 bool) error { defaultConfig, err := config.Default() if err != nil { - return "", fmt.Errorf("failed to get config: %w", err) + return fmt.Errorf("failed to get config: %w", err) } + dnsServers, dnsSearch, dnsOptions := b.CommonBuildOpts.DNSServers, b.CommonBuildOpts.DNSSearch, b.CommonBuildOpts.DNSOptions nameservers := make([]string, 0, len(defaultConfig.Containers.DNSServers.Get())+len(dnsServers)) nameservers = append(nameservers, defaultConfig.Containers.DNSServers.Get()...) nameservers = append(nameservers, dnsServers...) - keepHostServers := false - // special check for slirp ip - if len(nameservers) == 0 && b.Isolation == IsolationOCIRootless { - for _, ns := range namespaces { - if ns.Type == specs.NetworkNamespace && ns.Path == "" { - keepHostServers = true - // if we are using slirp4netns, also add the built-in DNS server. - logrus.Debugf("adding slirp4netns 10.0.2.3 built-in DNS server") - nameservers = append([]string{"10.0.2.3"}, nameservers...) - } - } - } - searches := make([]string, 0, len(defaultConfig.Containers.DNSSearches.Get())+len(dnsSearch)) searches = append(searches, defaultConfig.Containers.DNSSearches.Get()...) searches = append(searches, dnsSearch...) @@ -87,93 +100,66 @@ func (b *Builder) addResolvConf(rdir string, chownOpts *idtools.IDPair, dnsServe options = append(options, defaultConfig.Containers.DNSOptions.Get()...) options = append(options, dnsOptions...) - cfile := filepath.Join(rdir, "resolv.conf") + if len(nameservers) == 0 { + nameservers = networkNameServer + } + if err := resolvconf.New(&resolvconf.Params{ - Path: cfile, + Path: file, Namespaces: namespaces, - IPv6Enabled: true, // TODO we should check if we have ipv6 + IPv6Enabled: ipv6, KeepHostServers: keepHostServers, Nameservers: nameservers, Searches: searches, Options: options, }); err != nil { - return "", fmt.Errorf("building resolv.conf for container %s: %w", b.ContainerID, err) + return fmt.Errorf("building resolv.conf for container %s: %w", b.ContainerID, err) } + return nil +} + +// createHostsFile creates a containers hosts file +func (b *Builder) createHostsFile(rdir string, chownOpts *idtools.IDPair) (string, error) { + targetfile := filepath.Join(rdir, "hosts") + f, err := os.Create(targetfile) + if err != nil { + return "", err + } + defer f.Close() uid := 0 gid := 0 if chownOpts != nil { uid = chownOpts.UID gid = chownOpts.GID } - if err = os.Chown(cfile, uid, gid); err != nil { + if err := f.Chown(uid, gid); err != nil { return "", err } - - if err := relabel(cfile, b.MountLabel, false); err != nil { + if err := relabel(targetfile, b.MountLabel, false); err != nil { return "", err } - return cfile, nil + + return targetfile, nil } -// generateHosts creates a containers hosts file -func (b *Builder) generateHosts(rdir string, chownOpts *idtools.IDPair, imageRoot string, spec *specs.Spec) (string, error) { +func (b *Builder) addHostsEntries(file, imageRoot string, entries etchosts.HostEntries, exculde []net.IP) error { conf, err := config.Default() if err != nil { - return "", err + return err } - path, err := etchosts.GetBaseHostFile(conf.Containers.BaseHostsFile, imageRoot) + base, err := etchosts.GetBaseHostFile(conf.Containers.BaseHostsFile, imageRoot) if err != nil { - return "", err - } - - var entries etchosts.HostEntries - isHost := true - if spec.Linux != nil { - for _, ns := range spec.Linux.Namespaces { - if ns.Type == specs.NetworkNamespace { - isHost = false - break - } - } - } - // add host entry for local ip when running in host network - if spec.Hostname != "" && isHost { - ip := netUtil.GetLocalIP() - if ip != "" { - entries = append(entries, etchosts.HostEntry{ - Names: []string{spec.Hostname}, - IP: ip, - }) - } + return err } - - targetfile := filepath.Join(rdir, "hosts") - if err := etchosts.New(&etchosts.Params{ - BaseFile: path, + return etchosts.New(&etchosts.Params{ + BaseFile: base, ExtraHosts: b.CommonBuildOpts.AddHost, - HostContainersInternalIP: etchosts.GetHostContainersInternalIP(conf, nil, nil), - TargetFile: targetfile, + HostContainersInternalIP: etchosts.GetHostContainersInternalIPExcluding(conf, nil, nil, exculde), + TargetFile: file, ContainerIPs: entries, - }); err != nil { - return "", err - } - - uid := 0 - gid := 0 - if chownOpts != nil { - uid = chownOpts.UID - gid = chownOpts.GID - } - if err = os.Chown(targetfile, uid, gid); err != nil { - return "", err - } - if err := relabel(targetfile, b.MountLabel, false); err != nil { - return "", err - } - - return targetfile, nil + }) } // generateHostname creates a containers /etc/hostname file @@ -354,6 +340,27 @@ func getNetworkInterface(store storage.Store, cniConfDir, cniPluginPath string) return netInt, nil } +func netStatusToNetResult(netStatus map[string]netTypes.StatusBlock, hostnames []string) *netResult { + result := &netResult{ + keepHostResolvers: false, + } + for _, status := range netStatus { + for _, dns := range status.DNSServerIPs { + result.dnsServers = append(result.dnsServers, dns.String()) + } + for _, netInt := range status.Interfaces { + for _, netAddress := range netInt.Subnets { + e := etchosts.HostEntry{IP: netAddress.IPNet.IP.String(), Names: hostnames} + result.entries = append(result.entries, e) + if !result.ipv6 && netUtil.IsIPv6(netAddress.IPNet.IP) { + result.ipv6 = true + } + } + } + } + return result +} + // DefaultNamespaceOptions returns the default namespace settings from the // runtime-tools generator library. func DefaultNamespaceOptions() (define.NamespaceOptions, error) { @@ -1122,7 +1129,7 @@ func runUsingRuntimeMain() { } func (b *Builder) runUsingRuntimeSubproc(isolation define.Isolation, options RunOptions, configureNetwork bool, networkString string, - moreCreateArgs []string, spec *specs.Spec, rootPath, bundlePath, containerName, buildContainerName, hostsFile string) (err error) { + moreCreateArgs []string, spec *specs.Spec, rootPath, bundlePath, containerName, buildContainerName, hostsFile, resolvFile string) (err error) { // Lock the caller to a single OS-level thread. runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -1227,7 +1234,7 @@ func (b *Builder) runUsingRuntimeSubproc(isolation define.Isolation, options Run return fmt.Errorf("parsing pid %s as a number: %w", string(pidValue), err) } - teardown, netstatus, err := b.runConfigureNetwork(pid, isolation, options, networkString, containerName) + teardown, netResult, err := b.runConfigureNetwork(pid, isolation, options, networkString, containerName, []string{spec.Hostname, buildContainerName}) if teardown != nil { defer teardown() } @@ -1237,9 +1244,14 @@ func (b *Builder) runUsingRuntimeSubproc(isolation define.Isolation, options Run // only add hosts if we manage the hosts file if hostsFile != "" { - entries := etchosts.GetNetworkHostEntries(netstatus, spec.Hostname, buildContainerName) - // make sure to sync this with (b *Builder) generateHosts() - err = etchosts.Add(hostsFile, entries) + err = b.addHostsEntries(hostsFile, rootPath, netResult.entries, netResult.excludeIPs) + if err != nil { + return err + } + } + + if resolvFile != "" { + err = b.addResolvConfEntries(resolvFile, netResult.dnsServers, spec.Linux.Namespaces, netResult.keepHostResolvers, netResult.ipv6) if err != nil { return err } diff --git a/vendor/github.com/containers/buildah/run_freebsd.go b/vendor/github.com/containers/buildah/run_freebsd.go index 9e3ffad0bd..34512c6d6a 100644 --- a/vendor/github.com/containers/buildah/run_freebsd.go +++ b/vendor/github.com/containers/buildah/run_freebsd.go @@ -22,8 +22,10 @@ import ( "github.com/containers/buildah/pkg/parse" butil "github.com/containers/buildah/pkg/util" "github.com/containers/buildah/util" + "github.com/containers/common/libnetwork/etchosts" "github.com/containers/common/libnetwork/resolvconf" nettypes "github.com/containers/common/libnetwork/types" + netUtil "github.com/containers/common/libnetwork/util" "github.com/containers/common/pkg/config" "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/lockfile" @@ -202,21 +204,51 @@ func (b *Builder) Run(command []string, options RunOptions) error { } rootIDPair := &idtools.IDPair{UID: int(rootUID), GID: int(rootGID)} - hostFile := "" + hostsFile := "" if !options.NoHosts && !slices.Contains(volumes, config.DefaultHostsFile) && options.ConfigureNetwork != define.NetworkDisabled { - hostFile, err = b.generateHosts(path, rootIDPair, mountPoint, spec) + hostsFile, err = b.createHostsFile(path, rootIDPair) if err != nil { return err } - bindFiles[config.DefaultHostsFile] = hostFile + bindFiles[config.DefaultHostsFile] = hostsFile + + // Only add entries here if we do not have to setup network, + // if we do we have to do it much later after the network setup. + if !configureNetwork { + var entries etchosts.HostEntries + // add host entry for local ip when running in host network + if spec.Hostname != "" { + ip := netUtil.GetLocalIP() + if ip != "" { + entries = append(entries, etchosts.HostEntry{ + Names: []string{spec.Hostname}, + IP: ip, + }) + } + } + err = b.addHostsEntries(hostsFile, mountPoint, entries, nil) + if err != nil { + return err + } + } } + resolvFile := "" if !slices.Contains(volumes, resolvconf.DefaultResolvConf) && options.ConfigureNetwork != define.NetworkDisabled && !(len(b.CommonBuildOpts.DNSServers) == 1 && strings.ToLower(b.CommonBuildOpts.DNSServers[0]) == "none") { - resolvFile, err := b.addResolvConf(path, rootIDPair, b.CommonBuildOpts.DNSServers, b.CommonBuildOpts.DNSSearch, b.CommonBuildOpts.DNSOptions, nil) + resolvFile, err = b.createResolvConf(path, rootIDPair) if err != nil { return err } bindFiles[resolvconf.DefaultResolvConf] = resolvFile + + // Only add entries here if we do not have to do setup network, + // if we do we have to do it much later after the network setup. + if !configureNetwork { + err = b.addResolvConfEntries(resolvFile, nil, nil, false, true) + if err != nil { + return err + } + } } runMountInfo := runMountInfo{ @@ -290,7 +322,7 @@ func (b *Builder) Run(command []string, options RunOptions) error { } else { moreCreateArgs = nil } - err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, networkString, moreCreateArgs, spec, mountPoint, path, containerName, b.Container, hostFile) + err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, networkString, moreCreateArgs, spec, mountPoint, path, containerName, b.Container, hostsFile, resolvFile) case IsolationChroot: err = chroot.RunUsingChroot(spec, path, homeDir, options.Stdin, options.Stdout, options.Stderr) default: @@ -417,7 +449,7 @@ func setupCapabilities(g *generate.Generator, defaultCapabilities, adds, drops [ return nil } -func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, options RunOptions, networkString string, containerName string) (teardown func(), netStatus map[string]nettypes.StatusBlock, err error) { +func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, options RunOptions, networkString string, containerName string, hostnames []string) (func(), *netResult, error) { //if isolation == IsolationOCIRootless { //return setupRootlessNetwork(pid) //} @@ -451,19 +483,19 @@ func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, optio ContainerName: containerName, Networks: networks, } - _, err = b.NetworkInterface.Setup(mynetns, nettypes.SetupOptions{NetworkOptions: opts}) + netStatus, err := b.NetworkInterface.Setup(mynetns, nettypes.SetupOptions{NetworkOptions: opts}) if err != nil { return nil, nil, err } - teardown = func() { + teardown := func() { err := b.NetworkInterface.Teardown(mynetns, nettypes.TeardownOptions{NetworkOptions: opts}) if err != nil { logrus.Errorf("failed to cleanup network: %v", err) } } - return teardown, nil, nil + return teardown, netStatusToNetResult(netStatus, hostnames), nil } func setupNamespaces(logger *logrus.Logger, g *generate.Generator, namespaceOptions define.NamespaceOptions, idmapOptions define.IDMappingOptions, policy define.NetworkConfigurationPolicy) (configureNetwork bool, networkString string, configureUTS bool, err error) { diff --git a/vendor/github.com/containers/buildah/run_linux.go b/vendor/github.com/containers/buildah/run_linux.go index 03abaec5d4..5e4d8de871 100644 --- a/vendor/github.com/containers/buildah/run_linux.go +++ b/vendor/github.com/containers/buildah/run_linux.go @@ -7,13 +7,11 @@ import ( "context" "errors" "fmt" - "net" "os" "path/filepath" "strings" "syscall" - "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/buildah/bind" "github.com/containers/buildah/chroot" "github.com/containers/buildah/copier" @@ -25,6 +23,7 @@ import ( "github.com/containers/buildah/pkg/parse" butil "github.com/containers/buildah/pkg/util" "github.com/containers/buildah/util" + "github.com/containers/common/libnetwork/etchosts" "github.com/containers/common/libnetwork/pasta" "github.com/containers/common/libnetwork/resolvconf" "github.com/containers/common/libnetwork/slirp4netns" @@ -260,30 +259,69 @@ func (b *Builder) Run(command []string, options RunOptions) error { } rootIDPair := &idtools.IDPair{UID: int(rootUID), GID: int(rootGID)} - hostFile := "" + hostsFile := "" if !options.NoHosts && !slices.Contains(volumes, config.DefaultHostsFile) && options.ConfigureNetwork != define.NetworkDisabled { - hostFile, err = b.generateHosts(path, rootIDPair, mountPoint, spec) + hostsFile, err = b.createHostsFile(path, rootIDPair) if err != nil { return err } - bindFiles[config.DefaultHostsFile] = hostFile + bindFiles[config.DefaultHostsFile] = hostsFile + + // Only add entries here if we do not have to do setup network, + // if we do we have to do it much later after the network setup. + if !configureNetwork { + var entries etchosts.HostEntries + isHost := true + if spec.Linux != nil { + for _, ns := range spec.Linux.Namespaces { + if ns.Type == specs.NetworkNamespace { + isHost = false + break + } + } + } + // add host entry for local ip when running in host network + if spec.Hostname != "" && isHost { + ip := netUtil.GetLocalIP() + if ip != "" { + entries = append(entries, etchosts.HostEntry{ + Names: []string{spec.Hostname}, + IP: ip, + }) + } + } + err = b.addHostsEntries(hostsFile, mountPoint, entries, nil) + if err != nil { + return err + } + } } if !options.NoHostname && !(slices.Contains(volumes, "/etc/hostname")) { - hostFile, err := b.generateHostname(path, spec.Hostname, rootIDPair) + hostnameFile, err := b.generateHostname(path, spec.Hostname, rootIDPair) if err != nil { return err } // Bind /etc/hostname - bindFiles["/etc/hostname"] = hostFile + bindFiles["/etc/hostname"] = hostnameFile } + resolvFile := "" if !slices.Contains(volumes, resolvconf.DefaultResolvConf) && options.ConfigureNetwork != define.NetworkDisabled && !(len(b.CommonBuildOpts.DNSServers) == 1 && strings.ToLower(b.CommonBuildOpts.DNSServers[0]) == "none") { - resolvFile, err := b.addResolvConf(path, rootIDPair, b.CommonBuildOpts.DNSServers, b.CommonBuildOpts.DNSSearch, b.CommonBuildOpts.DNSOptions, spec.Linux.Namespaces) + resolvFile, err = b.createResolvConf(path, rootIDPair) if err != nil { return err } bindFiles[resolvconf.DefaultResolvConf] = resolvFile + + // Only add entries here if we do not have to do setup network, + // if we do we have to do it much later after the network setup. + if !configureNetwork { + err = b.addResolvConfEntries(resolvFile, nil, spec.Linux.Namespaces, false, true) + if err != nil { + return err + } + } } // Empty file, so no need to recreate if it exists if _, ok := bindFiles["/run/.containerenv"]; !ok { @@ -362,7 +400,7 @@ rootless=%d moreCreateArgs = append(moreCreateArgs, "--no-pivot") } err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, networkString, moreCreateArgs, spec, - mountPoint, path, define.Package+"-"+filepath.Base(path), b.Container, hostFile) + mountPoint, path, define.Package+"-"+filepath.Base(path), b.Container, hostsFile, resolvFile) case IsolationChroot: err = chroot.RunUsingChroot(spec, path, homeDir, options.Stdin, options.Stdout, options.Stderr) case IsolationOCIRootless: @@ -371,7 +409,7 @@ rootless=%d moreCreateArgs = append(moreCreateArgs, "--no-pivot") } err = b.runUsingRuntimeSubproc(isolation, options, configureNetwork, networkString, moreCreateArgs, spec, - mountPoint, path, define.Package+"-"+filepath.Base(path), b.Container, hostFile) + mountPoint, path, define.Package+"-"+filepath.Base(path), b.Container, hostsFile, resolvFile) default: err = errors.New("don't know how to run this command") } @@ -470,7 +508,7 @@ func addCommonOptsToSpec(commonOpts *define.CommonBuildOptions, g *generate.Gene return nil } -func setupSlirp4netnsNetwork(config *config.Config, netns, cid string, options []string) (func(), map[string]nettypes.StatusBlock, error) { +func setupSlirp4netnsNetwork(config *config.Config, netns, cid string, options, hostnames []string) (func(), *netResult, error) { // we need the TmpDir for the slirp4netns code if err := os.MkdirAll(config.Engine.TmpDir, 0o751); err != nil { return nil, nil, fmt.Errorf("failed to create tempdir: %w", err) @@ -491,30 +529,27 @@ func setupSlirp4netnsNetwork(config *config.Config, netns, cid string, options [ return nil, nil, fmt.Errorf("get slirp4netns ip: %w", err) } - // create fake status to make sure we get the correct ip in hosts - subnet := nettypes.IPNet{IPNet: net.IPNet{ - IP: *ip, - Mask: res.Subnet.Mask, - }} - netStatus := map[string]nettypes.StatusBlock{ - slirp4netns.BinaryName: { - Interfaces: map[string]nettypes.NetInterface{ - "tap0": { - Subnets: []nettypes.NetAddress{{IPNet: subnet}}, - }, - }, - }, + dns, err := slirp4netns.GetDNS(res.Subnet) + if err != nil { + return nil, nil, fmt.Errorf("get slirp4netns dns ip: %w", err) + } + + result := &netResult{ + entries: etchosts.HostEntries{{IP: ip.String(), Names: hostnames}}, + dnsServers: []string{dns.String()}, + ipv6: res.IPv6, + keepHostResolvers: true, } return func() { syscall.Kill(res.Pid, syscall.SIGKILL) // nolint:errcheck var status syscall.WaitStatus syscall.Wait4(res.Pid, &status, 0, nil) // nolint:errcheck - }, netStatus, nil + }, result, nil } -func setupPasta(config *config.Config, netns string, options []string) (func(), map[string]nettypes.StatusBlock, error) { - err := pasta.Setup(&pasta.SetupOptions{ +func setupPasta(config *config.Config, netns string, options, hostnames []string) (func(), *netResult, error) { + res, err := pasta.Setup2(&pasta.SetupOptions{ Config: config, Netns: netns, ExtraOptions: options, @@ -523,35 +558,23 @@ func setupPasta(config *config.Config, netns string, options []string) (func(), return nil, nil, err } - var ip string - err = ns.WithNetNSPath(netns, func(_ ns.NetNS) error { - // get the first ip in the netns and use this as our ip for /etc/hosts - ip = netUtil.GetLocalIP() - return nil - }) - if err != nil { - return nil, nil, err + var entries etchosts.HostEntries + if len(res.IPAddresses) > 0 { + entries = etchosts.HostEntries{{IP: res.IPAddresses[0].String(), Names: hostnames}} } - // create fake status to make sure we get the correct ip in hosts - subnet := nettypes.IPNet{IPNet: net.IPNet{ - IP: net.ParseIP(ip), - Mask: net.IPv4Mask(255, 255, 255, 0), - }} - netStatus := map[string]nettypes.StatusBlock{ - slirp4netns.BinaryName: { - Interfaces: map[string]nettypes.NetInterface{ - "tap0": { - Subnets: []nettypes.NetAddress{{IPNet: subnet}}, - }, - }, - }, + result := &netResult{ + entries: entries, + dnsServers: res.DNSForwardIPs, + excludeIPs: res.IPAddresses, + ipv6: res.IPv6, + keepHostResolvers: true, } - return nil, netStatus, nil + return nil, result, nil } -func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, options RunOptions, network, containerName string) (teardown func(), netStatus map[string]nettypes.StatusBlock, err error) { +func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, options RunOptions, network, containerName string, hostnames []string) (func(), *netResult, error) { netns := fmt.Sprintf("/proc/%d/ns/net", pid) var configureNetworks []string defConfig, err := config.Default() @@ -578,9 +601,9 @@ func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, optio switch { case name == slirp4netns.BinaryName: - return setupSlirp4netnsNetwork(defConfig, netns, containerName, netOpts) + return setupSlirp4netnsNetwork(defConfig, netns, containerName, netOpts, hostnames) case name == pasta.BinaryName: - return setupPasta(defConfig, netns, netOpts) + return setupPasta(defConfig, netns, netOpts, hostnames) // Basically default case except we make sure to not split an empty // name as this would return a slice with one empty string which is @@ -621,19 +644,19 @@ func (b *Builder) runConfigureNetwork(pid int, isolation define.Isolation, optio ContainerName: containerName, Networks: networks, } - netStatus, err = b.NetworkInterface.Setup(mynetns, nettypes.SetupOptions{NetworkOptions: opts}) + netStatus, err := b.NetworkInterface.Setup(mynetns, nettypes.SetupOptions{NetworkOptions: opts}) if err != nil { return nil, nil, err } - teardown = func() { + teardown := func() { err := b.NetworkInterface.Teardown(mynetns, nettypes.TeardownOptions{NetworkOptions: opts}) if err != nil { options.Logger.Errorf("failed to cleanup network: %v", err) } } - return teardown, netStatus, nil + return teardown, netStatusToNetResult(netStatus, hostnames), nil } // Create pipes to use for relaying stdio. diff --git a/vendor/github.com/containers/common/libnetwork/etchosts/ip.go b/vendor/github.com/containers/common/libnetwork/etchosts/ip.go index b81274abf7..909fcf67d2 100644 --- a/vendor/github.com/containers/common/libnetwork/etchosts/ip.go +++ b/vendor/github.com/containers/common/libnetwork/etchosts/ip.go @@ -1,6 +1,8 @@ package etchosts import ( + "net" + "github.com/containers/common/libnetwork/types" "github.com/containers/common/libnetwork/util" "github.com/containers/common/pkg/config" @@ -8,9 +10,16 @@ import ( "github.com/containers/storage/pkg/unshare" ) -// GetHostContainersInternalIP return the host.containers.internal ip +// GetHostContainersInternalIP returns the host.containers.internal ip // if netStatus is not nil then networkInterface also must be non nil otherwise this function panics func GetHostContainersInternalIP(conf *config.Config, netStatus map[string]types.StatusBlock, networkInterface types.ContainerNetwork) string { + return GetHostContainersInternalIPExcluding(conf, netStatus, networkInterface, nil) +} + +// GetHostContainersInternalIPExcluding returns the host.containers.internal ip +// Exclude are ips that should not be returned, this is useful to prevent returning the same ip as in the container. +// if netStatus is not nil then networkInterface also must be non nil otherwise this function panics +func GetHostContainersInternalIPExcluding(conf *config.Config, netStatus map[string]types.StatusBlock, networkInterface types.ContainerNetwork, exclude []net.IP) string { switch conf.Containers.HostContainersInternalIP { case "": // if empty (default) we will automatically choose one below @@ -27,7 +36,7 @@ func GetHostContainersInternalIP(conf *config.Config, netStatus map[string]types // Only use the bridge ip when root, as rootless the interfaces are created // inside the special netns and not the host so we cannot use them. if unshare.IsRootless() { - return util.GetLocalIP() + return util.GetLocalIPExcluding(exclude) } for net, status := range netStatus { network, err := networkInterface.NetworkInspect(net) @@ -51,7 +60,7 @@ func GetHostContainersInternalIP(conf *config.Config, netStatus map[string]types if ip != "" { return ip } - return util.GetLocalIP() + return util.GetLocalIPExcluding(exclude) } // GetNetworkHostEntries returns HostEntries for all ips in the network status diff --git a/vendor/github.com/containers/common/libnetwork/internal/rootlessnetns/netns_linux.go b/vendor/github.com/containers/common/libnetwork/internal/rootlessnetns/netns_linux.go index 1531ee52e8..98961935da 100644 --- a/vendor/github.com/containers/common/libnetwork/internal/rootlessnetns/netns_linux.go +++ b/vendor/github.com/containers/common/libnetwork/internal/rootlessnetns/netns_linux.go @@ -158,7 +158,8 @@ func (n *Netns) setupPasta(nsPath string) error { Netns: nsPath, ExtraOptions: []string{"--pid", pidPath}, } - if err := pasta.Setup(&pastaOpts); err != nil { + res, err := pasta.Setup2(&pastaOpts) + if err != nil { return fmt.Errorf("setting up Pasta: %w", err) } @@ -185,11 +186,9 @@ func (n *Netns) setupPasta(nsPath string) error { Namespaces: []specs.LinuxNamespace{ {Type: specs.NetworkNamespace}, }, - // TODO: Need a way to determine if there is a valid v6 address on any - // external interface of the system. - IPv6Enabled: false, + IPv6Enabled: res.IPv6, KeepHostServers: true, - Nameservers: []string{}, + Nameservers: res.DNSForwardIPs, }); err != nil { return wrapError("create resolv.conf", err) } diff --git a/vendor/github.com/containers/common/libnetwork/pasta/pasta.go b/vendor/github.com/containers/common/libnetwork/pasta/pasta_linux.go similarity index 61% rename from vendor/github.com/containers/common/libnetwork/pasta/pasta.go rename to vendor/github.com/containers/common/libnetwork/pasta/pasta_linux.go index 0da7607f62..4b31320b5c 100644 --- a/vendor/github.com/containers/common/libnetwork/pasta/pasta.go +++ b/vendor/github.com/containers/common/libnetwork/pasta/pasta_linux.go @@ -13,16 +13,23 @@ package pasta import ( "errors" "fmt" + "net" "os/exec" "strings" + "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/common/libnetwork/types" + "github.com/containers/common/libnetwork/util" "github.com/containers/common/pkg/config" "github.com/sirupsen/logrus" ) const ( - BinaryName = "pasta" + dnsForwardOpt = "--dns-forward" + + // dnsForwardIpv4 static ip used as nameserver address inside the netns, + // given this is a "link local" ip it should be very unlikely that it causes conflicts + dnsForwardIpv4 = "169.254.0.1" ) type SetupOptions struct { @@ -37,21 +44,25 @@ type SetupOptions struct { ExtraOptions []string } -// Setup start the pasta process for the given netns. -// The pasta binary is looked up in the HelperBinariesDir and $PATH. -// Note that there is no need any special cleanup logic, the pasta process will -// automatically exit when the netns path is deleted. func Setup(opts *SetupOptions) error { + _, err := Setup2(opts) + return err +} + +// Setup2 start the pasta process for the given netns. +// The pasta binary is looked up in the HelperBinariesDir and $PATH. +// Note that there is no need for any special cleanup logic, the pasta +// process will automatically exit when the netns path is deleted. +func Setup2(opts *SetupOptions) (*SetupResult, error) { NoTCPInitPorts := true NoUDPInitPorts := true NoTCPNamespacePorts := true NoUDPNamespacePorts := true NoMapGW := true - NoDNS := true path, err := opts.Config.FindHelperBinary(BinaryName, true) if err != nil { - return fmt.Errorf("could not find pasta, the network namespace can't be configured: %w", err) + return nil, fmt.Errorf("could not find pasta, the network namespace can't be configured: %w", err) } cmdArgs := []string{} @@ -72,7 +83,7 @@ func Setup(opts *SetupOptions) error { case "udp": cmdArgs = append(cmdArgs, "-u") default: - return fmt.Errorf("can't forward protocol: %s", protocol) + return nil, fmt.Errorf("can't forward protocol: %s", protocol) } arg := fmt.Sprintf("%s%d-%d:%d-%d", addr, @@ -89,6 +100,7 @@ func Setup(opts *SetupOptions) error { // then append the ones that were set on the cli cmdArgs = append(cmdArgs, opts.ExtraOptions...) + var dnsForwardIPs []string for i, opt := range cmdArgs { switch opt { case "-t", "--tcp-ports": @@ -103,11 +115,20 @@ func Setup(opts *SetupOptions) error { NoMapGW = false // not an actual pasta(1) option cmdArgs = append(cmdArgs[:i], cmdArgs[i+1:]...) - case "-D", "--dns", "--dns-forward": - NoDNS = false + case dnsForwardOpt: + // if there is no arg after it pasta will likely error out anyway due invalid cli args + if len(cmdArgs) > i+1 { + dnsForwardIPs = append(dnsForwardIPs, cmdArgs[i+1]) + } } } + if len(dnsForwardIPs) == 0 { + // the user did not request custom --dns-forward so add our own. + cmdArgs = append(cmdArgs, dnsForwardOpt, dnsForwardIpv4) + dnsForwardIPs = append(dnsForwardIPs, dnsForwardIpv4) + } + if NoTCPInitPorts { cmdArgs = append(cmdArgs, "-t", "none") } @@ -123,12 +144,6 @@ func Setup(opts *SetupOptions) error { if NoMapGW { cmdArgs = append(cmdArgs, "--no-map-gw") } - if NoDNS { - // disable pasta reading from /etc/resolv.conf which hides the - // "Couldn't get any nameserver address" warning when only - // localhost resolvers are configured. - cmdArgs = append(cmdArgs, "--dns", "none") - } // always pass --quiet to silence the info output from pasta cmdArgs = append(cmdArgs, "--quiet", "--netns", opts.Netns) @@ -140,10 +155,10 @@ func Setup(opts *SetupOptions) error { if err != nil { exitErr := &exec.ExitError{} if errors.As(err, &exitErr) { - return fmt.Errorf("pasta failed with exit code %d:\n%s", + return nil, fmt.Errorf("pasta failed with exit code %d:\n%s", exitErr.ExitCode(), string(out)) } - return fmt.Errorf("failed to start pasta: %w", err) + return nil, fmt.Errorf("failed to start pasta: %w", err) } if len(out) > 0 { @@ -154,5 +169,39 @@ func Setup(opts *SetupOptions) error { logrus.Infof("pasta logged warnings: %q", string(out)) } - return nil + var ipv4, ipv6 bool + result := &SetupResult{} + err = ns.WithNetNSPath(opts.Netns, func(_ ns.NetNS) error { + addrs, err := net.InterfaceAddrs() + if err != nil { + return err + } + for _, addr := range addrs { + // make sure to skip localhost and other special addresses + if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.IsGlobalUnicast() { + result.IPAddresses = append(result.IPAddresses, ipnet.IP) + if !ipv4 && util.IsIPv4(ipnet.IP) { + ipv4 = true + } + if !ipv6 && util.IsIPv6(ipnet.IP) { + ipv6 = true + } + } + } + return nil + }) + if err != nil { + return nil, err + } + + result.IPv6 = ipv6 + for _, ip := range dnsForwardIPs { + ipp := net.ParseIP(ip) + // add the namesever ip only if the address family matches + if ipv4 && util.IsIPv4(ipp) || ipv6 && util.IsIPv6(ipp) { + result.DNSForwardIPs = append(result.DNSForwardIPs, ip) + } + } + + return result, nil } diff --git a/vendor/github.com/containers/common/libnetwork/pasta/types.go b/vendor/github.com/containers/common/libnetwork/pasta/types.go new file mode 100644 index 0000000000..b601e51695 --- /dev/null +++ b/vendor/github.com/containers/common/libnetwork/pasta/types.go @@ -0,0 +1,15 @@ +package pasta + +import "net" + +const BinaryName = "pasta" + +type SetupResult struct { + // IpAddresses configured by pasta + IPAddresses []net.IP + // DNSForwardIP is the ip used in --dns-forward, it should be added as first + // entry to resolv.conf in the container. + DNSForwardIPs []string + // IPv6 says whenever pasta run with ipv6 support + IPv6 bool +} diff --git a/vendor/github.com/containers/common/libnetwork/slirp4netns/const.go b/vendor/github.com/containers/common/libnetwork/slirp4netns/const.go index 9dc0c2625a..fa95e5a90a 100644 --- a/vendor/github.com/containers/common/libnetwork/slirp4netns/const.go +++ b/vendor/github.com/containers/common/libnetwork/slirp4netns/const.go @@ -1,5 +1,7 @@ package slirp4netns +import "net" + const ( ipv6ConfDefaultAcceptDadSysctl = "/proc/sys/net/ipv6/conf/default/accept_dad" BinaryName = "slirp4netns" @@ -10,3 +12,13 @@ const ( // default slirp4ns subnet defaultSubnet = "10.0.2.0/24" ) + +// SetupResult return type from Setup() +type SetupResult struct { + // Pid of the created slirp4netns process + Pid int + // Subnet which is used by slirp4netns + Subnet *net.IPNet + // IPv6 whenever Ipv6 is enabled in slirp4netns + IPv6 bool +} diff --git a/vendor/github.com/containers/common/libnetwork/slirp4netns/slirp4netns.go b/vendor/github.com/containers/common/libnetwork/slirp4netns/slirp4netns.go index d378934145..6f713431c8 100644 --- a/vendor/github.com/containers/common/libnetwork/slirp4netns/slirp4netns.go +++ b/vendor/github.com/containers/common/libnetwork/slirp4netns/slirp4netns.go @@ -86,16 +86,6 @@ type SetupOptions struct { Pdeathsig syscall.Signal } -// SetupResult return type from Setup() -type SetupResult struct { - // Pid of the created slirp4netns process - Pid int - // Subnet which is used by slirp4netns - Subnet *net.IPNet - // IPv6 whenever Ipv6 is enabled in slirp4netns - IPv6 bool -} - type logrusDebugWriter struct { prefix string } diff --git a/vendor/github.com/containers/common/libnetwork/util/ip.go b/vendor/github.com/containers/common/libnetwork/util/ip.go index 1e426926e3..5dd93363bf 100644 --- a/vendor/github.com/containers/common/libnetwork/util/ip.go +++ b/vendor/github.com/containers/common/libnetwork/util/ip.go @@ -59,14 +59,31 @@ func NormalizeIP(ip *net.IP) { // If no ipv4 address is found it may return an ipv6 address. // When no ip is found and empty string is returned. func GetLocalIP() string { + return GetLocalIPExcluding(nil) +} + +// GetLocalIPExcluding returns the first non loopback local IPv4 of the host. +// If no ipv4 address is found it may return an ipv6 address. +// Additionally you can specify a list of ips that should not be returned. +// When no ip is found and empty string is returned. +func GetLocalIPExcluding(exclude []net.IP) string { addrs, err := net.InterfaceAddrs() if err != nil { return "" } ip := "" +outer: for _, address := range addrs { // check the address type and if it is not a loopback the display it if ipnet, ok := address.(*net.IPNet); ok && ipnet.IP.IsGlobalUnicast() { + // cannot use slices.Contains for net.IP + for _, eip := range exclude { + if eip.Equal(ipnet.IP) { + // ip should be excluded skip to next one + continue outer + } + } + if IsIPv4(ipnet.IP) { return ipnet.IP.String() } diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index cd77bf8926..87d93c9d69 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.58.0" +const Version = "0.58.1" diff --git a/vendor/modules.txt b/vendor/modules.txt index 6a30c4eb81..6f8266db34 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -141,7 +141,7 @@ github.com/containernetworking/cni/pkg/version # github.com/containernetworking/plugins v1.4.0 ## explicit; go 1.20 github.com/containernetworking/plugins/pkg/ns -# github.com/containers/buildah v1.35.1 +# github.com/containers/buildah v1.35.3 ## explicit; go 1.20 github.com/containers/buildah github.com/containers/buildah/bind @@ -171,7 +171,7 @@ github.com/containers/buildah/pkg/sshagent github.com/containers/buildah/pkg/util github.com/containers/buildah/pkg/volumes github.com/containers/buildah/util -# github.com/containers/common v0.58.0 +# github.com/containers/common v0.58.1 ## explicit; go 1.20 github.com/containers/common/internal github.com/containers/common/internal/attributedstring From 92b3cda79b0f0ec380d4ce2585d14b055d892cce Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Thu, 14 Mar 2024 14:59:05 +0100 Subject: [PATCH 2/3] [v5.0] use new c/common pasta2 setup logic to fix dns By default we just ignored any localhost reolvers, this is problematic for anyone with more complicated dns setups, i.e. split dns with systemd-reolved. To address this we now make use of the build in dns proxy in pasta. As such we need to set the default nameserver ip now. A second change is the option to exclude certain ips when generating the host.containers.internal ip. With that we no longer set it to the same ip as is used in the netns. The fix is not perfect as it could mean on a system with a single ip we no longer add the entry, however given the previous entry was incorrect anyway this seems like the better behavior. Fixes #22044 [NO NEW TESTS NEEDED] Signed-off-by: Paul Holzinger --- libpod/container.go | 2 ++ libpod/container_internal_common.go | 32 ++++++++++++++++++--------- libpod/container_internal_freebsd.go | 2 +- libpod/container_internal_linux.go | 7 +++++- libpod/networking_freebsd.go | 4 ---- libpod/networking_linux.go | 11 --------- libpod/networking_pasta_linux.go | 7 +++++- test/system/505-networking-pasta.bats | 7 ++++-- 8 files changed, 41 insertions(+), 31 deletions(-) diff --git a/libpod/container.go b/libpod/container.go index 45ec75a2f6..00616ccfa3 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/containers/common/libnetwork/pasta" "github.com/containers/common/libnetwork/types" "github.com/containers/common/pkg/config" "github.com/containers/common/pkg/secrets" @@ -127,6 +128,7 @@ type Container struct { restoreFromCheckpoint bool slirp4netnsSubnet *net.IPNet + pastaResult *pasta.SetupResult } // ContainerState contains the current state of the container diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index c6fa07e086..3bb6dfe1eb 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "math" + "net" "os" "os/user" "path" @@ -2116,8 +2117,8 @@ func (c *Container) addResolvConf() error { // first add the nameservers from the networks status nameservers = networkNameServers - // slirp4netns has a built in DNS forwarder. - nameservers = c.addSlirp4netnsDNS(nameservers) + // pasta and slirp4netns have a built in DNS forwarder. + nameservers = c.addSpecialDNS(nameservers) } // Set DNS search domains @@ -2167,6 +2168,10 @@ func (c *Container) checkForIPv6(netStatus map[string]types.StatusBlock) bool { } } + if c.pastaResult != nil { + return c.pastaResult.IPv6 + } + return c.isSlirp4netnsIPv6() } @@ -2225,11 +2230,10 @@ func (c *Container) getHostsEntries() (etchosts.HostEntries, error) { case c.config.NetMode.IsBridge(): entries = etchosts.GetNetworkHostEntries(c.state.NetworkStatus, names...) case c.config.NetMode.IsPasta(): - ip, err := getPastaIP(c.state) - if err != nil { - return nil, err + // this should never be the case but check just to be sure and not panic + if len(c.pastaResult.IPAddresses) > 0 { + entries = etchosts.HostEntries{{IP: c.pastaResult.IPAddresses[0].String(), Names: names}} } - entries = etchosts.HostEntries{{IP: ip.String(), Names: names}} case c.config.NetMode.IsSlirp4netns(): ip, err := getSlirp4netnsIP(c.slirp4netnsSubnet) if err != nil { @@ -2276,12 +2280,18 @@ func (c *Container) addHosts() error { return err } + var exclude []net.IP + if c.pastaResult != nil { + exclude = c.pastaResult.IPAddresses + } + return etchosts.New(&etchosts.Params{ - BaseFile: baseHostFile, - ExtraHosts: c.config.HostAdd, - ContainerIPs: containerIPsEntries, - HostContainersInternalIP: etchosts.GetHostContainersInternalIP(c.runtime.config, c.state.NetworkStatus, c.runtime.network), - TargetFile: targetFile, + BaseFile: baseHostFile, + ExtraHosts: c.config.HostAdd, + ContainerIPs: containerIPsEntries, + HostContainersInternalIP: etchosts.GetHostContainersInternalIPExcluding( + c.runtime.config, c.state.NetworkStatus, c.runtime.network, exclude), + TargetFile: targetFile, }) } diff --git a/libpod/container_internal_freebsd.go b/libpod/container_internal_freebsd.go index 0f8bca0a3d..995d519299 100644 --- a/libpod/container_internal_freebsd.go +++ b/libpod/container_internal_freebsd.go @@ -279,7 +279,7 @@ func (c *Container) setCgroupsPath(g *generate.Generator) error { return nil } -func (c *Container) addSlirp4netnsDNS(nameservers []string) []string { +func (c *Container) addSpecialDNS(nameservers []string) []string { return nameservers } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 9e279116ca..bbe88f209c 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -616,7 +616,12 @@ func (c *Container) setCgroupsPath(g *generate.Generator) error { return nil } -func (c *Container) addSlirp4netnsDNS(nameservers []string) []string { +// addSpecialDNS adds special dns servers for slirp4netns and pasta +func (c *Container) addSpecialDNS(nameservers []string) []string { + if c.pastaResult != nil { + nameservers = append(nameservers, c.pastaResult.DNSForwardIPs...) + } + // slirp4netns has a built in DNS forwarder. if c.config.NetMode.IsSlirp4netns() { slirp4netnsDNS, err := slirp4netns.GetDNS(c.slirp4netnsSubnet) diff --git a/libpod/networking_freebsd.go b/libpod/networking_freebsd.go index 2d5c5e4885..4dc0ff25e0 100644 --- a/libpod/networking_freebsd.go +++ b/libpod/networking_freebsd.go @@ -268,7 +268,3 @@ func (c *Container) reloadRootlessRLKPortMapping() error { func (c *Container) setupRootlessNetwork() error { return nil } - -func getPastaIP(state *ContainerState) (net.IP, error) { - return nil, fmt.Errorf("pasta networking is Linux only") -} diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index a8a057d991..3ffc9d7159 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -11,7 +11,6 @@ import ( "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/common/libnetwork/types" - netUtil "github.com/containers/common/libnetwork/util" "github.com/containers/common/pkg/netns" "github.com/containers/podman/v5/libpod/define" "github.com/containers/podman/v5/pkg/rootless" @@ -300,13 +299,3 @@ func (c *Container) inspectJoinedNetworkNS(networkns string) (q types.StatusBloc }) return result, err } - -func getPastaIP(state *ContainerState) (net.IP, error) { - var ip string - err := ns.WithNetNSPath(state.NetNS, func(_ ns.NetNS) error { - // get the first ip in the netns - ip = netUtil.GetLocalIP() - return nil - }) - return net.ParseIP(ip), err -} diff --git a/libpod/networking_pasta_linux.go b/libpod/networking_pasta_linux.go index 97e8118e7c..7934bc5917 100644 --- a/libpod/networking_pasta_linux.go +++ b/libpod/networking_pasta_linux.go @@ -12,10 +12,15 @@ package libpod import "github.com/containers/common/libnetwork/pasta" func (r *Runtime) setupPasta(ctr *Container, netns string) error { - return pasta.Setup(&pasta.SetupOptions{ + res, err := pasta.Setup2(&pasta.SetupOptions{ Config: r.config, Netns: netns, Ports: ctr.convertPortMappings(), ExtraOptions: ctr.config.NetworkOptions[pasta.BinaryName], }) + if err != nil { + return err + } + ctr.pastaResult = res + return nil } diff --git a/test/system/505-networking-pasta.bats b/test/system/505-networking-pasta.bats index ea968393ac..229b0adfeb 100644 --- a/test/system/505-networking-pasta.bats +++ b/test/system/505-networking-pasta.bats @@ -431,9 +431,12 @@ function pasta_test_do() { @test "Local forwarder, IPv4" { skip_if_no_ipv4 "IPv4 not routable on the host" - run_podman run --dns 198.51.100.1 \ - --net=pasta:--dns-forward,198.51.100.1 $IMAGE nslookup 127.0.0.1 || : + # pasta is the default now so no need to set it + run_podman run --rm $IMAGE grep nameserver /etc/resolv.conf + assert "${lines[0]}" == "nameserver 169.254.0.1" "default dns forward server" + run_podman run --rm --net=pasta:--dns-forward,198.51.100.1 \ + $IMAGE nslookup 127.0.0.1 || : assert "$output" =~ "1.0.0.127.in-addr.arpa" "No answer from resolver" } From 2967eb9a264cd36dcb3042d4e0b1a38b345f9df8 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Tue, 19 Mar 2024 12:21:18 +0100 Subject: [PATCH 3/3] [v5.0] libpod: restart always reconfigure the netns Always teardown the network, trying to reuse the netns has caused a significant amount of bugs in this code here. It also never worked for containers with user namespaces. So once and for all simplify this by never reusing the netns. Originally this was done to have a faster restart of containers but with netavark now we are much faster so it shouldn't be that noticeable in practice. It also makes more sense to reconfigure the netns as it is likely that the container exited due some broken network state in which case reusing would just cause more harm than good. The main motivation for this change was the pasta change to use --dns-forward by default. As the restarted contianer had no idea what nameserver to use as pasta just kept running. [NO NEW TESTS NEEDED] Signed-off-by: Paul Holzinger Signed-off-by: tomsweeneyredhat --- libpod/container_internal.go | 28 +++++++++++----------------- libpod/container_internal_linux.go | 21 --------------------- 2 files changed, 11 insertions(+), 38 deletions(-) diff --git a/libpod/container_internal.go b/libpod/container_internal.go index a7d07da537..1b30292346 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -301,29 +301,23 @@ func (c *Container) handleRestartPolicy(ctx context.Context) (_ bool, retErr err } }() - // Now this is a bit of a mess, normally we try to reuse the netns but if a userns - // is used this is not possible as it must be owned by the userns which is created - // by the oci runtime. Thus we need to teardown the netns so that the runtime - // creates the users+netns and then we setup in completeNetworkSetup() again. - if c.config.PostConfigureNetNS { - if err := c.cleanupNetwork(); err != nil { - return false, err - } + // Always teardown the network, trying to reuse the netns has caused + // a significant amount of bugs in this code here. It also never worked + // for containers with user namespaces. So once and for all simplify this + // by never reusing the netns. Originally this was done to have a faster + // restart of containers but with netavark now we are much faster so it + // shouldn't be that noticeable in practice. It also makes more sense to + // reconfigure the netns as it is likely that the container exited due + // some broken network state in which case reusing would just cause more + // harm than good. + if err := c.cleanupNetwork(); err != nil { + return false, err } if err := c.prepare(); err != nil { return false, err } - // only do this if the container is not in a userns, if we are the cleanupNetwork() - // was called above and a proper network setup is needed which is part of the init() below. - if !c.config.PostConfigureNetNS { - // set up slirp4netns again because slirp4netns will die when conmon exits - if err := c.setupRootlessNetwork(); err != nil { - return false, err - } - } - if c.state.State == define.ContainerStateStopped { // Reinitialize the container if we need to if err := c.reinit(ctx, true); err != nil { diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index bbe88f209c..5385d95705 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -413,27 +413,6 @@ func (c *Container) getOCICgroupPath() (string, error) { } } -// If the container is rootless, set up the slirp4netns network -func (c *Container) setupRootlessNetwork() error { - // set up slirp4netns again because slirp4netns will die when conmon exits - if c.config.NetMode.IsSlirp4netns() { - err := c.runtime.setupSlirp4netns(c, c.state.NetNS) - if err != nil { - return err - } - } - - // set up rootlesskit port forwarder again since it dies when conmon exits - // we use rootlesskit port forwarder only as rootless and when bridge network is used - if rootless.IsRootless() && c.config.NetMode.IsBridge() && len(c.config.PortMappings) > 0 { - err := c.runtime.setupRootlessPortMappingViaRLK(c, c.state.NetNS, c.state.NetworkStatus) - if err != nil { - return err - } - } - return nil -} - func openDirectory(path string) (fd int, err error) { return unix.Open(path, unix.O_RDONLY|unix.O_PATH, 0) }