Skip to content

Commit

Permalink
vpnkit-userland-proxy: bind ports in the VM on a best-effort basis
Browse files Browse the repository at this point in the history
When Docker attempts to expose a port on the host with

  docker run -p <external>:<internal>

We have to decide whether to also bind the same port in the VM. In
the case of addresses like `0.0.0.0:80` or `127.0.0.1:80` this can
make sense, and it will allow running a Docker registry in a container
and pushing directly to it, see [docker/for-mac#3611]

However it also opens us up to accidental port clashes between the
user's ports and any that we have allocated internally. Recently this
happened when a compose on kubernetes container was run with `--net=host`
and bound port 8080, see [docker/compose-on-kubenetes#70].

This patch adds support for "best-effort" binding in the VM and makes this
the default. This should re-enable the registry use-case while making us
robust to the compose on kubernetes problem. The only downside is that
if there is a port clash in the VM, the user won't be notified.

Signed-off-by: David Scott <dave.scott@docker.com>
  • Loading branch information
djs55 committed May 1, 2019
1 parent ee5dd64 commit 899ce38
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 6 deletions.
11 changes: 9 additions & 2 deletions go/cmd/vpnkit-userland-proxy/one.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,23 @@ import (
)

func onePort() {
host, _, container, localIP := parseHostContainerAddrs()
host, _, container, localBind := parseHostContainerAddrs()

var ipP libproxy.Proxy
var err error

if localIP {
switch localBind {
case alwaysLocalBind:
ipP, err = listenInVM(host, container)
if err != nil {
sendError(err)
}
case bestEffortLocalBind:
ipP, err = listenInVM(host, container)
if err != nil {
log.Printf("ignoring the error binding %s in the VM", host)
}
case neverLocalBind:
}

ctl, err := exposePort(host, container)
Expand Down
15 changes: 11 additions & 4 deletions go/cmd/vpnkit-userland-proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,25 @@ var vSockUDPPortOffset = 0x20000

// From docker/libnetwork/portmapper/proxy.go:

type localBind string

const (
bestEffortLocalBind = localBind("best-effort")
alwaysLocalBind = localBind("true")
neverLocalBind = localBind("false")
)

// parseHostContainerAddrs parses the flags passed on reexec to create the TCP or UDP
// net.Addrs to map the host and container ports
func parseHostContainerAddrs() (host net.Addr, port int, container net.Addr, localIP bool) {
func parseHostContainerAddrs() (host net.Addr, port int, container net.Addr, bind localBind) {
var (
proto = flag.String("proto", "tcp", "proxy protocol")
hostIP = flag.String("host-ip", "", "host ip")
hostPort = flag.Int("host-port", -1, "host port")
containerIP = flag.String("container-ip", "", "container ip")
containerPort = flag.Int("container-port", -1, "container port")
interactive = flag.Bool("i", false, "print success/failure to stdout/stderr")
noLocalIP = flag.Bool("no-local-ip", true, "bind only on the Host, not in the VM")
local = flag.String("no-local-ip", string(bestEffortLocalBind), "bind only on the Host, not in the VM")
)

flag.Parse()
Expand All @@ -71,8 +79,7 @@ func parseHostContainerAddrs() (host net.Addr, port int, container net.Addr, loc
default:
log.Fatalf("unsupported protocol %s", *proto)
}
localIP = !*noLocalIP
return host, port, container, localIP
return host, port, container, localBind(*local)
}

func handleStopSignals() {
Expand Down

0 comments on commit 899ce38

Please sign in to comment.