diff --git a/Dockerfile b/Dockerfile index 7a040d0478..9b3ba56bea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -222,10 +222,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) -# Install tomlv, runc, containerd and grimes +# Install tomlv, runc, containerd, grimes, docker-proxy # Please edit hack/dockerfile/install-binaries.sh to update them. COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh -RUN /tmp/install-binaries.sh tomlv runc containerd grimes +RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy # Wrap all commands in the "docker-in-docker" script to allow nested containers ENTRYPOINT ["hack/dind"] diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index c882e7ef4a..86ea8d2c35 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -165,10 +165,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ aarch64/hello-world:latest@sha256:65a4a158587b307bb02db4de41b836addb0c35175bdc801367b1ac1ddeb9afda # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) -# Install tomlv, runc, containerd and grimes +# Install tomlv, runc, containerd, grimes, docker-proxy # Please edit hack/dockerfile/install-binaries.sh to update them. COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh -RUN /tmp/install-binaries.sh tomlv runc containerd grimes +RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy # Wrap all commands in the "docker-in-docker" script to allow nested containers ENTRYPOINT ["hack/dind"] diff --git a/Dockerfile.armhf b/Dockerfile.armhf index 1c9bd8c37d..40fd917eae 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -164,10 +164,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ armhf/hello-world:latest@sha256:161dcecea0225975b2ad5f768058212c1e0d39e8211098666ffa1ac74cfb7791 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) -# Install tomlv, runc, containerd and grimes +# Install tomlv, runc, containerd, grimes, docker-proxy # Please edit hack/dockerfile/install-binaries.sh to update them. COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh -RUN /tmp/install-binaries.sh tomlv runc containerd grimes +RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy ENTRYPOINT ["hack/dind"] diff --git a/Dockerfile.ppc64le b/Dockerfile.ppc64le index 6876831d9c..d3fe1237ba 100644 --- a/Dockerfile.ppc64le +++ b/Dockerfile.ppc64le @@ -183,10 +183,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) -# Install tomlv, runc, containerd and grimes +# Install tomlv, runc, containerd, grimes, docker-proxy # Please edit hack/dockerfile/install-binaries.sh to update them. COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh -RUN /tmp/install-binaries.sh tomlv runc containerd grimes +RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy # Wrap all commands in the "docker-in-docker" script to allow nested containers ENTRYPOINT ["hack/dind"] diff --git a/Dockerfile.s390x b/Dockerfile.s390x index 38064b59ed..cff0a8ee13 100644 --- a/Dockerfile.s390x +++ b/Dockerfile.s390x @@ -175,10 +175,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ s390x/hello-world:latest@sha256:780d80b3a7677c3788c0d5cd9168281320c8d4a6d9183892d8ee5cdd610f5699 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is) -# Install tomlv, runc, containerd and grimes +# Install tomlv, runc, containerd, grimes, docker-proxy # Please edit hack/dockerfile/install-binaries.sh to update them. COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh -RUN /tmp/install-binaries.sh tomlv runc containerd grimes +RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy # Wrap all commands in the "docker-in-docker" script to allow nested containers ENTRYPOINT ["hack/dind"] diff --git a/Dockerfile.simple b/Dockerfile.simple index b3453777d7..342939fa96 100644 --- a/Dockerfile.simple +++ b/Dockerfile.simple @@ -56,10 +56,10 @@ ENV PATH /go/bin:/usr/local/go/bin:$PATH ENV GOPATH /go:/go/src/github.com/docker/docker/vendor ENV CGO_LDFLAGS -L/lib -# Install runc, containerd and grimes +# Install runc, containerd, grimes and docker-proxy # Please edit hack/dockerfile/install-binaries.sh to update them. COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh -RUN /tmp/install-binaries.sh runc containerd grimes +RUN /tmp/install-binaries.sh runc containerd grimes proxy ENV AUTO_GOPATH 1 WORKDIR /usr/src/docker diff --git a/hack/.vendor-helpers.sh b/hack/.vendor-helpers.sh index 15a1546153..6ac9a174e1 100755 --- a/hack/.vendor-helpers.sh +++ b/hack/.vendor-helpers.sh @@ -124,9 +124,6 @@ clean() { findArgs+=( -path "vendor/src/$import" ) done - # The docker proxy command is built from libnetwork - findArgs+=( -or -path vendor/src/github.com/docker/libnetwork/cmd/proxy ) - local IFS=$'\n' local prune=( $($find vendor -depth -type d -not '(' "${findArgs[@]}" ')') ) unset IFS diff --git a/hack/dockerfile/install-binaries.sh b/hack/dockerfile/install-binaries.sh index 43a5a2dfd2..a6f640e163 100755 --- a/hack/dockerfile/install-binaries.sh +++ b/hack/dockerfile/install-binaries.sh @@ -6,6 +6,7 @@ TOMLV_COMMIT=9baf8a8a9f2ed20a8e54160840c492f937eeaf9a RUNC_COMMIT=02f8fa7863dd3f82909a73e2061897828460d52f CONTAINERD_COMMIT=52ef1ceb4b660c42cf4ea9013180a5663968d4c7 GRIMES_COMMIT=74341e923bdf06cfb6b70cf54089c4d3ac87ec2d +LIBNETWORK_COMMIT=0f534354b813003a754606689722fe253101bc4e export GOPATH="$(mktemp -d)" @@ -66,8 +67,16 @@ do cp init /usr/local/bin/docker-init ;; + proxy) + echo "Install docker-proxy version $LIBNETWORK_COMMIT" + git clone https://github.com/docker/libnetwork.git "$GOPATH/src/github.com/docker/libnetwork" + cd "$GOPATH/src/github.com/docker/libnetwork" + git checkout -q "$LIBNETWORK_COMMIT" + CGO_ENABLED=0 go build -v -o /usr/local/bin/docker-proxy github.com/docker/libnetwork/cmd/proxy + ;; + *) - echo echo "Usage: $0 [tomlv|runc|containerd|grimes]" + echo echo "Usage: $0 [tomlv|runc|containerd|grimes|proxy]" exit 1 esac diff --git a/hack/make.sh b/hack/make.sh index c9b3683c1f..d2a851d4ff 100755 --- a/hack/make.sh +++ b/hack/make.sh @@ -263,7 +263,7 @@ copy_binaries() { if [ "$(go env GOOS)/$(go env GOARCH)" == "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then if [ -x /usr/local/bin/docker-runc ]; then echo "Copying nested executables into $dir" - for file in containerd containerd-shim containerd-ctr runc init; do + for file in containerd containerd-shim containerd-ctr runc init proxy; do cp `which "docker-$file"` "$dir/" if [ "$2" == "hash" ]; then hash_files "$dir/docker-$file" diff --git a/hack/make/.build-deb/rules b/hack/make/.build-deb/rules index 884306f231..6522103e5d 100755 --- a/hack/make/.build-deb/rules +++ b/hack/make/.build-deb/rules @@ -24,11 +24,12 @@ override_dh_auto_install: mkdir -p debian/docker-engine/usr/bin cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-client/docker)" debian/docker-engine/usr/bin/docker cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/dockerd)" debian/docker-engine/usr/bin/dockerd - cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/docker-proxy)" debian/docker-engine/usr/bin/docker-proxy + cp -aT /usr/local/bin/docker-proxy debian/docker-engine/usr/bin/docker-proxy cp -aT /usr/local/bin/docker-containerd debian/docker-engine/usr/bin/docker-containerd cp -aT /usr/local/bin/docker-containerd-shim debian/docker-engine/usr/bin/docker-containerd-shim cp -aT /usr/local/bin/docker-containerd-ctr debian/docker-engine/usr/bin/docker-containerd-ctr cp -aT /usr/local/bin/docker-runc debian/docker-engine/usr/bin/docker-runc + cp -aT /usr/local/bin/docker-init debian/docker-engine/usr/bin/docker-init mkdir -p debian/docker-engine/usr/lib/docker override_dh_installinit: diff --git a/hack/make/.build-rpm/docker-engine.spec b/hack/make/.build-rpm/docker-engine.spec index 17486825c1..e22f7d27f3 100644 --- a/hack/make/.build-rpm/docker-engine.spec +++ b/hack/make/.build-rpm/docker-engine.spec @@ -126,7 +126,9 @@ export DOCKER_GITCOMMIT=%{_gitcommit} install -d $RPM_BUILD_ROOT/%{_bindir} install -p -m 755 bundles/%{_origversion}/dynbinary-client/docker-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/dockerd-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/dockerd -install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/docker-proxy-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker-proxy + +# install proxy +install -p -m 755 /usr/local/bin/docker-proxy $RPM_BUILD_ROOT/%{_bindir}/docker-proxy # install containerd install -p -m 755 /usr/local/bin/docker-containerd $RPM_BUILD_ROOT/%{_bindir}/docker-containerd @@ -136,6 +138,9 @@ install -p -m 755 /usr/local/bin/docker-containerd-ctr $RPM_BUILD_ROOT/%{_bindir # install runc install -p -m 755 /usr/local/bin/docker-runc $RPM_BUILD_ROOT/%{_bindir}/docker-runc +# install grimes +install -p -m 755 /usr/local/bin/docker-init $RPM_BUILD_ROOT/%{_bindir}/docker-init + # install udev rules install -d $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d install -p -m 644 contrib/udev/80-docker.rules $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d/80-docker.rules diff --git a/hack/make/binary-daemon b/hack/make/binary-daemon index 7ce47a2047..2ed5a51d16 100644 --- a/hack/make/binary-daemon +++ b/hack/make/binary-daemon @@ -9,8 +9,5 @@ set -e export BINARY_SHORT_NAME="$DOCKER_DAEMON_BINARY_NAME" export SOURCE_PATH='./cmd/dockerd' source "${MAKEDIR}/.binary" - export BINARY_SHORT_NAME="$DOCKER_PROXY_BINARY_NAME" - export SOURCE_PATH='./vendor/src/github.com/docker/libnetwork/cmd/proxy' - source "${MAKEDIR}/.binary" copy_binaries "$DEST" 'hash' ) diff --git a/hack/make/build-deb b/hack/make/build-deb index b3ae3df24b..6ca976fb91 100644 --- a/hack/make/build-deb +++ b/hack/make/build-deb @@ -73,8 +73,8 @@ set -e EOF cat >> "$DEST/$version/Dockerfile.build" <<-EOF - # Install runc and containerd - RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic + # Install runc, containerd, proxy and grimes + RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic proxy grimes EOF if [ "$DOCKER_EXPERIMENTAL" ]; then diff --git a/hack/make/build-rpm b/hack/make/build-rpm index 725fe8e7ad..02361fd9d6 100644 --- a/hack/make/build-rpm +++ b/hack/make/build-rpm @@ -93,8 +93,8 @@ set -e EOF cat >> "$DEST/$version/Dockerfile.build" <<-EOF - # Install runc and containerd - RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic + # Install runc, containerd, proxy and grimes + RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic proxy grimes EOF if [ "$DOCKER_EXPERIMENTAL" ]; then diff --git a/hack/make/dynbinary-daemon b/hack/make/dynbinary-daemon index 2d1ed25838..398b951d85 100644 --- a/hack/make/dynbinary-daemon +++ b/hack/make/dynbinary-daemon @@ -9,8 +9,4 @@ set -e export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here source "${MAKEDIR}/.binary" - export BINARY_SHORT_NAME='docker-proxy' - export SOURCE_PATH='./vendor/src/github.com/docker/libnetwork/cmd/proxy' - export LDFLAGS_STATIC_DOCKER='-linkmode=external' - source "${MAKEDIR}/.binary" ) diff --git a/vendor/src/github.com/docker/libnetwork/cmd/proxy/main.go b/vendor/src/github.com/docker/libnetwork/cmd/proxy/main.go deleted file mode 100644 index fb68796148..0000000000 --- a/vendor/src/github.com/docker/libnetwork/cmd/proxy/main.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - "net" - "os" - "os/signal" - "syscall" -) - -func main() { - f := os.NewFile(3, "signal-parent") - host, container := parseHostContainerAddrs() - - p, err := NewProxy(host, container) - if err != nil { - fmt.Fprintf(f, "1\n%s", err) - f.Close() - os.Exit(1) - } - go handleStopSignals(p) - fmt.Fprint(f, "0\n") - f.Close() - - // Run will block until the proxy stops - p.Run() -} - -// 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, container net.Addr) { - 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") - ) - - flag.Parse() - - switch *proto { - case "tcp": - host = &net.TCPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort} - container = &net.TCPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort} - case "udp": - host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort} - container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort} - default: - log.Fatalf("unsupported protocol %s", *proto) - } - - return host, container -} - -func handleStopSignals(p Proxy) { - s := make(chan os.Signal, 10) - signal.Notify(s, os.Interrupt, syscall.SIGTERM) - - for range s { - p.Close() - - os.Exit(0) - } -} diff --git a/vendor/src/github.com/docker/libnetwork/cmd/proxy/proxy.go b/vendor/src/github.com/docker/libnetwork/cmd/proxy/proxy.go deleted file mode 100644 index 44dd177bb6..0000000000 --- a/vendor/src/github.com/docker/libnetwork/cmd/proxy/proxy.go +++ /dev/null @@ -1,37 +0,0 @@ -// docker-proxy provides a network Proxy interface and implementations for TCP -// and UDP. -package main - -import ( - "fmt" - "net" -) - -// Proxy defines the behavior of a proxy. It forwards traffic back and forth -// between two endpoints : the frontend and the backend. -// It can be used to do software port-mapping between two addresses. -// e.g. forward all traffic between the frontend (host) 127.0.0.1:3000 -// to the backend (container) at 172.17.42.108:4000. -type Proxy interface { - // Run starts forwarding traffic back and forth between the front - // and back-end addresses. - Run() - // Close stops forwarding traffic and close both ends of the Proxy. - Close() - // FrontendAddr returns the address on which the proxy is listening. - FrontendAddr() net.Addr - // BackendAddr returns the proxied address. - BackendAddr() net.Addr -} - -// NewProxy creates a Proxy according to the specified frontendAddr and backendAddr. -func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) { - switch frontendAddr.(type) { - case *net.UDPAddr: - return NewUDPProxy(frontendAddr.(*net.UDPAddr), backendAddr.(*net.UDPAddr)) - case *net.TCPAddr: - return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr)) - default: - panic(fmt.Errorf("Unsupported protocol")) - } -} diff --git a/vendor/src/github.com/docker/libnetwork/cmd/proxy/stub_proxy.go b/vendor/src/github.com/docker/libnetwork/cmd/proxy/stub_proxy.go deleted file mode 100644 index 95e0e36352..0000000000 --- a/vendor/src/github.com/docker/libnetwork/cmd/proxy/stub_proxy.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "net" -) - -// StubProxy is a proxy that is a stub (does nothing). -type StubProxy struct { - frontendAddr net.Addr - backendAddr net.Addr -} - -// Run does nothing. -func (p *StubProxy) Run() {} - -// Close does nothing. -func (p *StubProxy) Close() {} - -// FrontendAddr returns the frontend address. -func (p *StubProxy) FrontendAddr() net.Addr { return p.frontendAddr } - -// BackendAddr returns the backend address. -func (p *StubProxy) BackendAddr() net.Addr { return p.backendAddr } - -// NewStubProxy creates a new StubProxy -func NewStubProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) { - return &StubProxy{ - frontendAddr: frontendAddr, - backendAddr: backendAddr, - }, nil -} diff --git a/vendor/src/github.com/docker/libnetwork/cmd/proxy/tcp_proxy.go b/vendor/src/github.com/docker/libnetwork/cmd/proxy/tcp_proxy.go deleted file mode 100644 index 1c713105db..0000000000 --- a/vendor/src/github.com/docker/libnetwork/cmd/proxy/tcp_proxy.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import ( - "io" - "log" - "net" - "sync" - "syscall" -) - -// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to -// handle TCP traffic forwarding between the frontend and backend addresses. -type TCPProxy struct { - listener *net.TCPListener - frontendAddr *net.TCPAddr - backendAddr *net.TCPAddr -} - -// NewTCPProxy creates a new TCPProxy. -func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) { - listener, err := net.ListenTCP("tcp", frontendAddr) - if err != nil { - return nil, err - } - // If the port in frontendAddr was 0 then ListenTCP will have a picked - // a port to listen on, hence the call to Addr to get that actual port: - return &TCPProxy{ - listener: listener, - frontendAddr: listener.Addr().(*net.TCPAddr), - backendAddr: backendAddr, - }, nil -} - -func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) { - backend, err := net.DialTCP("tcp", nil, proxy.backendAddr) - if err != nil { - log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err) - client.Close() - return - } - - var wg sync.WaitGroup - var broker = func(to, from *net.TCPConn) { - if _, err := io.Copy(to, from); err != nil { - // If the socket we are writing to is shutdown with - // SHUT_WR, forward it to the other end of the pipe: - if err, ok := err.(*net.OpError); ok && err.Err == syscall.EPIPE { - from.CloseWrite() - } - } - to.CloseRead() - wg.Done() - } - - wg.Add(2) - go broker(client, backend) - go broker(backend, client) - - finish := make(chan struct{}) - go func() { - wg.Wait() - close(finish) - }() - - select { - case <-quit: - case <-finish: - } - client.Close() - backend.Close() - <-finish -} - -// Run starts forwarding the traffic using TCP. -func (proxy *TCPProxy) Run() { - quit := make(chan bool) - defer close(quit) - for { - client, err := proxy.listener.Accept() - if err != nil { - log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) - return - } - go proxy.clientLoop(client.(*net.TCPConn), quit) - } -} - -// Close stops forwarding the traffic. -func (proxy *TCPProxy) Close() { proxy.listener.Close() } - -// FrontendAddr returns the TCP address on which the proxy is listening. -func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr } - -// BackendAddr returns the TCP proxied address. -func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr } diff --git a/vendor/src/github.com/docker/libnetwork/cmd/proxy/udp_proxy.go b/vendor/src/github.com/docker/libnetwork/cmd/proxy/udp_proxy.go deleted file mode 100644 index 12b96db646..0000000000 --- a/vendor/src/github.com/docker/libnetwork/cmd/proxy/udp_proxy.go +++ /dev/null @@ -1,168 +0,0 @@ -package main - -import ( - "encoding/binary" - "log" - "net" - "strings" - "sync" - "syscall" - "time" -) - -const ( - // UDPConnTrackTimeout is the timeout used for UDP connection tracking - UDPConnTrackTimeout = 90 * time.Second - // UDPBufSize is the buffer size for the UDP proxy - UDPBufSize = 65507 -) - -// A net.Addr where the IP is split into two fields so you can use it as a key -// in a map: -type connTrackKey struct { - IPHigh uint64 - IPLow uint64 - Port int -} - -func newConnTrackKey(addr *net.UDPAddr) *connTrackKey { - if len(addr.IP) == net.IPv4len { - return &connTrackKey{ - IPHigh: 0, - IPLow: uint64(binary.BigEndian.Uint32(addr.IP)), - Port: addr.Port, - } - } - return &connTrackKey{ - IPHigh: binary.BigEndian.Uint64(addr.IP[:8]), - IPLow: binary.BigEndian.Uint64(addr.IP[8:]), - Port: addr.Port, - } -} - -type connTrackMap map[connTrackKey]*net.UDPConn - -// UDPProxy is proxy for which handles UDP datagrams. It implements the Proxy -// interface to handle UDP traffic forwarding between the frontend and backend -// addresses. -type UDPProxy struct { - listener *net.UDPConn - frontendAddr *net.UDPAddr - backendAddr *net.UDPAddr - connTrackTable connTrackMap - connTrackLock sync.Mutex -} - -// NewUDPProxy creates a new UDPProxy. -func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) { - listener, err := net.ListenUDP("udp", frontendAddr) - if err != nil { - return nil, err - } - return &UDPProxy{ - listener: listener, - frontendAddr: listener.LocalAddr().(*net.UDPAddr), - backendAddr: backendAddr, - connTrackTable: make(connTrackMap), - }, nil -} - -func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) { - defer func() { - proxy.connTrackLock.Lock() - delete(proxy.connTrackTable, *clientKey) - proxy.connTrackLock.Unlock() - proxyConn.Close() - }() - - readBuf := make([]byte, UDPBufSize) - for { - proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout)) - again: - read, err := proxyConn.Read(readBuf) - if err != nil { - if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED { - // This will happen if the last write failed - // (e.g: nothing is actually listening on the - // proxied port on the container), ignore it - // and continue until UDPConnTrackTimeout - // expires: - goto again - } - return - } - for i := 0; i != read; { - written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr) - if err != nil { - return - } - i += written - } - } -} - -// Run starts forwarding the traffic using UDP. -func (proxy *UDPProxy) Run() { - readBuf := make([]byte, UDPBufSize) - for { - read, from, err := proxy.listener.ReadFromUDP(readBuf) - if err != nil { - // NOTE: Apparently ReadFrom doesn't return - // ECONNREFUSED like Read do (see comment in - // UDPProxy.replyLoop) - if !isClosedError(err) { - log.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err) - } - break - } - - fromKey := newConnTrackKey(from) - proxy.connTrackLock.Lock() - proxyConn, hit := proxy.connTrackTable[*fromKey] - if !hit { - proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr) - if err != nil { - log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) - proxy.connTrackLock.Unlock() - continue - } - proxy.connTrackTable[*fromKey] = proxyConn - go proxy.replyLoop(proxyConn, from, fromKey) - } - proxy.connTrackLock.Unlock() - for i := 0; i != read; { - written, err := proxyConn.Write(readBuf[i:read]) - if err != nil { - log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err) - break - } - i += written - } - } -} - -// Close stops forwarding the traffic. -func (proxy *UDPProxy) Close() { - proxy.listener.Close() - proxy.connTrackLock.Lock() - defer proxy.connTrackLock.Unlock() - for _, conn := range proxy.connTrackTable { - conn.Close() - } -} - -// FrontendAddr returns the UDP address on which the proxy is listening. -func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr } - -// BackendAddr returns the proxied UDP address. -func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr } - -func isClosedError(err error) bool { - /* This comparison is ugly, but unfortunately, net.go doesn't export errClosing. - * See: - * http://golang.org/src/pkg/net/net.go - * https://code.google.com/p/go/issues/detail?id=4337 - * https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ - */ - return strings.HasSuffix(err.Error(), "use of closed network connection") -}