summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiuseppe Scrivano <gscrivan@redhat.com>2018-07-16 13:40:59 +0200
committerAtomic Bot <atomic-devel@projectatomic.io>2018-07-19 13:21:50 +0000
commit9ae7b1a5b176176b1b6a0b8e5d191783b68d9b2c (patch)
tree198cea903d2d289cc83fe01a0dd8c05c6f8510d0
parent4a6f79b62b235c3b0c816c3b5117fac00d2bdadb (diff)
downloadpodman-9ae7b1a5b176176b1b6a0b8e5d191783b68d9b2c.tar.gz
podman-9ae7b1a5b176176b1b6a0b8e5d191783b68d9b2c.tar.bz2
podman-9ae7b1a5b176176b1b6a0b8e5d191783b68d9b2c.zip
oci: keep exposed ports busy and leak the fd into conmon
Bind all the specified TCP and UDP ports so that another process cannot reuse them. The fd of the listener is then leaked into conmon so that the socket is kept busy until the container exits. Closes: https://github.com/projectatomic/libpod/issues/210 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com> Closes: #1100 Approved by: mheon
-rw-r--r--libpod/oci.go58
-rw-r--r--test/e2e/run_networking_test.go4
2 files changed, 62 insertions, 0 deletions
diff --git a/libpod/oci.go b/libpod/oci.go
index 3eaf159e7..0483c0d53 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
+ "net"
"os"
"os/exec"
"path/filepath"
@@ -15,6 +16,7 @@ import (
"time"
"github.com/coreos/go-systemd/activation"
+ "github.com/cri-o/ocicni/pkg/ocicni"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux"
"github.com/opencontainers/selinux/go-selinux/label"
@@ -177,6 +179,51 @@ func waitPidsStop(pids []int, timeout time.Duration) error {
}
}
+func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
+ var files []*os.File
+ for _, i := range ports {
+ switch i.Protocol {
+ case "udp":
+ addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot resolve the UDP address")
+ }
+
+ server, err := net.ListenUDP("udp", addr)
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot listen on the UDP port")
+ }
+ f, err := server.File()
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot get file for UDP socket")
+ }
+ files = append(files, f)
+ break
+
+ case "tcp":
+ addr, err := net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot resolve the TCP address")
+ }
+
+ server, err := net.ListenTCP("tcp4", addr)
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot listen on the TCP port")
+ }
+ f, err := server.File()
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot get file for TCP socket")
+ }
+ files = append(files, f)
+ break
+ default:
+ return nil, fmt.Errorf("unknown protocol %s", i.Protocol)
+
+ }
+ }
+ return files, nil
+}
+
func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string) (err error) {
var stderrBuf bytes.Buffer
@@ -259,6 +306,17 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string) (er
cmd.Env = append(r.conmonEnv, fmt.Sprintf("_OCI_SYNCPIPE=%d", 3))
cmd.Env = append(cmd.Env, fmt.Sprintf("_OCI_STARTPIPE=%d", 4))
cmd.Env = append(cmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
+
+ ports, err := bindPorts(ctr.config.PortMappings)
+ if err != nil {
+ return err
+ }
+
+ // Leak the port we bound in the conmon process. These fd's won't be used
+ // by the container and conmon will keep the ports busy so that another
+ // process cannot use them.
+ cmd.ExtraFiles = append(cmd.ExtraFiles, ports...)
+
if notify, ok := os.LookupEnv("NOTIFY_SOCKET"); ok {
cmd.Env = append(cmd.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notify))
}
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index 9a2858ca1..e1c1608b9 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -65,6 +65,10 @@ var _ = Describe("Podman rmi", func() {
results.Wait(30)
Expect(results.ExitCode()).To(Equal(0))
Expect(results.OutputToString()).To(ContainSubstring("8000"))
+
+ ncBusy := podmanTest.SystemExec("nc", []string{"-l", "-p", "80"})
+ ncBusy.Wait(10)
+ Expect(ncBusy.ExitCode()).ToNot(Equal(0))
})
It("podman run network expose ports in image metadata", func() {