mirror of
https://github.com/containers/podman.git
synced 2025-06-06 23:08:04 +08:00
Fix up handling of user defined network namespaces
If user specifies network namespace and the /etc/netns/XXX/resolv.conf exists, we should use this rather then /etc/resolv.conf Also fail cleaner if the user specifies an invalid Network Namespace. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -40,6 +40,7 @@ ooe.sh sudo dnf install -y \
|
|||||||
golang-github-cpuguy83-go-md2man \
|
golang-github-cpuguy83-go-md2man \
|
||||||
gpgme-devel \
|
gpgme-devel \
|
||||||
iptables \
|
iptables \
|
||||||
|
iproute \
|
||||||
libassuan-devel \
|
libassuan-devel \
|
||||||
libcap-devel \
|
libcap-devel \
|
||||||
libnet \
|
libnet \
|
||||||
|
@ -48,6 +48,7 @@ ooe.sh sudo -E apt-get -qq install \
|
|||||||
gettext \
|
gettext \
|
||||||
go-md2man \
|
go-md2man \
|
||||||
golang \
|
golang \
|
||||||
|
iproute \
|
||||||
iptables \
|
iptables \
|
||||||
libaio-dev \
|
libaio-dev \
|
||||||
libapparmor-dev \
|
libapparmor-dev \
|
||||||
|
@ -28,6 +28,8 @@ servers in the created `resolv.conf`). Additionally, an empty file is created in
|
|||||||
each container to indicate to programs they are running in a container. This file
|
each container to indicate to programs they are running in a container. This file
|
||||||
is located at `/run/.containerenv`.
|
is located at `/run/.containerenv`.
|
||||||
|
|
||||||
|
When running from a user defined network namespace, the /etc/netns/NSNAME/resolv.conf will be used if it exists, otherwise /etc/resolv.conf will be used.
|
||||||
|
|
||||||
## OPTIONS
|
## OPTIONS
|
||||||
**--add-host**=[]
|
**--add-host**=[]
|
||||||
|
|
||||||
@ -694,21 +696,21 @@ Current supported mount TYPES are bind, and tmpfs.
|
|||||||
|
|
||||||
Common Options:
|
Common Options:
|
||||||
|
|
||||||
· src, source: mount source spec for bind and volume. Mandatory for bind.
|
· src, source: mount source spec for bind and volume. Mandatory for bind.
|
||||||
|
|
||||||
· dst, destination, target: mount destination spec.
|
· dst, destination, target: mount destination spec.
|
||||||
|
|
||||||
· ro, read-only: true or false (default).
|
· ro, read-only: true or false (default).
|
||||||
|
|
||||||
Options specific to bind:
|
Options specific to bind:
|
||||||
|
|
||||||
· bind-propagation: Z, z, shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2).
|
· bind-propagation: Z, z, shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2).
|
||||||
|
|
||||||
Options specific to tmpfs:
|
Options specific to tmpfs:
|
||||||
|
|
||||||
· tmpfs-size: Size of the tmpfs mount in bytes. Unlimited by default in Linux.
|
· tmpfs-size: Size of the tmpfs mount in bytes. Unlimited by default in Linux.
|
||||||
|
|
||||||
· tmpfs-mode: File mode of the tmpfs in octal. (e.g. 700 or 0700.) Defaults to 1777 in Linux.
|
· tmpfs-mode: File mode of the tmpfs in octal. (e.g. 700 or 0700.) Defaults to 1777 in Linux.
|
||||||
|
|
||||||
**--userns**=""
|
**--userns**=""
|
||||||
|
|
||||||
|
@ -758,8 +758,24 @@ func (c *Container) makeBindMounts() error {
|
|||||||
|
|
||||||
// generateResolvConf generates a containers resolv.conf
|
// generateResolvConf generates a containers resolv.conf
|
||||||
func (c *Container) generateResolvConf() (string, error) {
|
func (c *Container) generateResolvConf() (string, error) {
|
||||||
|
resolvConf := "/etc/resolv.conf"
|
||||||
|
for _, ns := range c.config.Spec.Linux.Namespaces {
|
||||||
|
if ns.Type == spec.NetworkNamespace {
|
||||||
|
if ns.Path != "" && !strings.HasPrefix(ns.Path, "/proc/") {
|
||||||
|
definedPath := filepath.Join("/etc/netns", filepath.Base(ns.Path), "resolv.conf")
|
||||||
|
_, err := os.Stat(definedPath)
|
||||||
|
if err == nil {
|
||||||
|
resolvConf = definedPath
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return "", errors.Wrapf(err, "failed to stat %s", definedPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Determine the endpoint for resolv.conf in case it is a symlink
|
// Determine the endpoint for resolv.conf in case it is a symlink
|
||||||
resolvPath, err := filepath.EvalSymlinks("/etc/resolv.conf")
|
resolvPath, err := filepath.EvalSymlinks(resolvConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -904,10 +904,10 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmo
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctr.config.PostConfigureNetNS = postConfigureNetNS
|
ctr.config.PostConfigureNetNS = postConfigureNetNS
|
||||||
ctr.config.CreateNetNS = true
|
ctr.config.NetMode = namespaces.NetworkMode(netmode)
|
||||||
|
ctr.config.CreateNetNS = !ctr.config.NetMode.IsUserDefined()
|
||||||
ctr.config.PortMappings = portMappings
|
ctr.config.PortMappings = portMappings
|
||||||
ctr.config.Networks = networks
|
ctr.config.Networks = networks
|
||||||
ctr.config.NetMode = namespaces.NetworkMode(netmode)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -446,7 +446,15 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime, pod *l
|
|||||||
}
|
}
|
||||||
|
|
||||||
if IsNS(string(c.NetMode)) {
|
if IsNS(string(c.NetMode)) {
|
||||||
// pass
|
split := strings.SplitN(string(c.NetMode), ":", 2)
|
||||||
|
if len(split[0]) != 2 {
|
||||||
|
return nil, errors.Errorf("invalid user defined network namespace %q", c.NetMode.UserDefined())
|
||||||
|
}
|
||||||
|
_, err := os.Stat(split[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
options = append(options, libpod.WithNetNS(portBindings, false, string(c.NetMode), networks))
|
||||||
} else if c.NetMode.IsContainer() {
|
} else if c.NetMode.IsContainer() {
|
||||||
connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.Container())
|
connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.Container())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -36,19 +36,19 @@ var _ = Describe("Podman run networking", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("podman run network connection with default bridge", func() {
|
It("podman run network connection with default bridge", func() {
|
||||||
session := podmanTest.Podman([]string{"run", "-dt", ALPINE, "wget", "www.projectatomic.io"})
|
session := podmanTest.Podman([]string{"run", "-dt", ALPINE, "wget", "www.podman.io"})
|
||||||
session.Wait(90)
|
session.Wait(90)
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman run network connection with host", func() {
|
It("podman run network connection with host", func() {
|
||||||
session := podmanTest.Podman([]string{"run", "-dt", "--network", "host", ALPINE, "wget", "www.projectatomic.io"})
|
session := podmanTest.Podman([]string{"run", "-dt", "--network", "host", ALPINE, "wget", "www.podman.io"})
|
||||||
session.Wait(90)
|
session.Wait(90)
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman run network connection with loopback", func() {
|
It("podman run network connection with loopback", func() {
|
||||||
session := podmanTest.Podman([]string{"run", "-dt", "--network", "host", ALPINE, "wget", "www.projectatomic.io"})
|
session := podmanTest.Podman([]string{"run", "-dt", "--network", "host", ALPINE, "wget", "www.podman.io"})
|
||||||
session.Wait(90)
|
session.Wait(90)
|
||||||
Expect(session.ExitCode()).To(Equal(0))
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
})
|
})
|
||||||
@ -178,4 +178,37 @@ var _ = Describe("Podman run networking", func() {
|
|||||||
Expect(exec4.ExitCode()).To(Equal(0))
|
Expect(exec4.ExitCode()).To(Equal(0))
|
||||||
Expect(exec4.OutputToString()).To(ContainSubstring("192.0.2.2 test1"))
|
Expect(exec4.OutputToString()).To(ContainSubstring("192.0.2.2 test1"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("podman run network in user created network namespace", func() {
|
||||||
|
if Containerized() {
|
||||||
|
Skip("Can not be run within a container.")
|
||||||
|
}
|
||||||
|
SystemExec("ip", []string{"netns", "add", "xxx"})
|
||||||
|
session := podmanTest.Podman([]string{"run", "-dt", "--net", "ns:/run/netns/xxx", ALPINE, "wget", "www.podman.io"})
|
||||||
|
session.Wait(90)
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
SystemExec("ip", []string{"netns", "delete", "xxx"})
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman run n user created network namespace with resolv.conf", func() {
|
||||||
|
if Containerized() {
|
||||||
|
Skip("Can not be run within a container.")
|
||||||
|
}
|
||||||
|
SystemExec("ip", []string{"netns", "add", "xxx"})
|
||||||
|
SystemExec("mkdir", []string{"-p", "/etc/netns/xxx"})
|
||||||
|
SystemExec("bash", []string{"-c", "echo nameserver 11.11.11.11 > /etc/netns/xxx/resolv.conf"})
|
||||||
|
session := podmanTest.Podman([]string{"run", "--net", "ns:/run/netns/xxx", ALPINE, "cat", "/etc/resolv.conf"})
|
||||||
|
session.Wait(90)
|
||||||
|
Expect(session.ExitCode()).To(Equal(0))
|
||||||
|
Expect(session.OutputToString()).To(ContainSubstring("11.11.11.11"))
|
||||||
|
SystemExec("ip", []string{"netns", "delete", "xxx"})
|
||||||
|
SystemExec("rm", []string{"-rf", "/etc/netns/xxx"})
|
||||||
|
})
|
||||||
|
|
||||||
|
It("podman run network in bogus user created network namespace", func() {
|
||||||
|
session := podmanTest.Podman([]string{"run", "-dt", "--net", "ns:/run/netns/xxy", ALPINE, "wget", "www.podman.io"})
|
||||||
|
session.Wait(90)
|
||||||
|
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||||
|
Expect(session.ErrorToString()).To(ContainSubstring("stat /run/netns/xxy: no such file or directory"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user