Browse code

Build docker-proxy from git checkout like other external binaries

This means we can vendor libnetwork without special casing, and
it is built the same way as the other external binaries.

Signed-off-by: Justin Cormack <justin.cormack@docker.com>

Justin Cormack authored on 2016/10/19 08:30:47
Showing 20 changed files
... ...
@@ -222,10 +222,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
222 222
 	hello-world:latest@sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7
223 223
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
224 224
 
225
-# Install tomlv, runc, containerd and grimes
225
+# Install tomlv, runc, containerd, grimes, docker-proxy
226 226
 # Please edit hack/dockerfile/install-binaries.sh to update them.
227 227
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
228
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
228
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
229 229
 
230 230
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
231 231
 ENTRYPOINT ["hack/dind"]
... ...
@@ -165,10 +165,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
165 165
 	aarch64/hello-world:latest@sha256:65a4a158587b307bb02db4de41b836addb0c35175bdc801367b1ac1ddeb9afda
166 166
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
167 167
 
168
-# Install tomlv, runc, containerd and grimes
168
+# Install tomlv, runc, containerd, grimes, docker-proxy
169 169
 # Please edit hack/dockerfile/install-binaries.sh to update them.
170 170
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
171
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
171
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
172 172
 
173 173
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
174 174
 ENTRYPOINT ["hack/dind"]
... ...
@@ -164,10 +164,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
164 164
 	armhf/hello-world:latest@sha256:161dcecea0225975b2ad5f768058212c1e0d39e8211098666ffa1ac74cfb7791
165 165
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
166 166
 
167
-# Install tomlv, runc, containerd and grimes
167
+# Install tomlv, runc, containerd, grimes, docker-proxy
168 168
 # Please edit hack/dockerfile/install-binaries.sh to update them.
169 169
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
170
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
170
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
171 171
 
172 172
 ENTRYPOINT ["hack/dind"]
173 173
 
... ...
@@ -183,10 +183,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
183 183
 	ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974
184 184
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
185 185
 
186
-# Install tomlv, runc, containerd and grimes
186
+# Install tomlv, runc, containerd, grimes, docker-proxy
187 187
 # Please edit hack/dockerfile/install-binaries.sh to update them.
188 188
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
189
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
189
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
190 190
 
191 191
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
192 192
 ENTRYPOINT ["hack/dind"]
... ...
@@ -175,10 +175,10 @@ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
175 175
 	s390x/hello-world:latest@sha256:780d80b3a7677c3788c0d5cd9168281320c8d4a6d9183892d8ee5cdd610f5699
176 176
 # See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)
177 177
 
178
-# Install tomlv, runc, containerd and grimes
178
+# Install tomlv, runc, containerd, grimes, docker-proxy
179 179
 # Please edit hack/dockerfile/install-binaries.sh to update them.
180 180
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
181
-RUN /tmp/install-binaries.sh tomlv runc containerd grimes
181
+RUN /tmp/install-binaries.sh tomlv runc containerd grimes proxy
182 182
 
183 183
 # Wrap all commands in the "docker-in-docker" script to allow nested containers
184 184
 ENTRYPOINT ["hack/dind"]
... ...
@@ -56,10 +56,10 @@ ENV PATH /go/bin:/usr/local/go/bin:$PATH
56 56
 ENV GOPATH /go:/go/src/github.com/docker/docker/vendor
57 57
 ENV CGO_LDFLAGS -L/lib
58 58
 
59
-# Install runc, containerd and grimes
59
+# Install runc, containerd, grimes and docker-proxy
60 60
 # Please edit hack/dockerfile/install-binaries.sh to update them.
61 61
 COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
62
-RUN /tmp/install-binaries.sh runc containerd grimes
62
+RUN /tmp/install-binaries.sh runc containerd grimes proxy
63 63
 
64 64
 ENV AUTO_GOPATH 1
65 65
 WORKDIR /usr/src/docker
... ...
@@ -124,9 +124,6 @@ clean() {
124 124
 		findArgs+=( -path "vendor/src/$import" )
125 125
 	done
126 126
 
127
-	# The docker proxy command is built from libnetwork
128
-	findArgs+=( -or -path vendor/src/github.com/docker/libnetwork/cmd/proxy )
129
-
130 127
 	local IFS=$'\n'
131 128
 	local prune=( $($find vendor -depth -type d -not '(' "${findArgs[@]}" ')') )
132 129
 	unset IFS
... ...
@@ -6,6 +6,7 @@ TOMLV_COMMIT=9baf8a8a9f2ed20a8e54160840c492f937eeaf9a
6 6
 RUNC_COMMIT=02f8fa7863dd3f82909a73e2061897828460d52f
7 7
 CONTAINERD_COMMIT=52ef1ceb4b660c42cf4ea9013180a5663968d4c7
8 8
 GRIMES_COMMIT=74341e923bdf06cfb6b70cf54089c4d3ac87ec2d
9
+LIBNETWORK_COMMIT=0f534354b813003a754606689722fe253101bc4e
9 10
 
10 11
 export GOPATH="$(mktemp -d)"
11 12
 
... ...
@@ -66,8 +67,16 @@ do
66 66
 			cp init /usr/local/bin/docker-init
67 67
 			;;
68 68
 
69
+		proxy)
70
+			echo "Install docker-proxy version $LIBNETWORK_COMMIT"
71
+			git clone https://github.com/docker/libnetwork.git "$GOPATH/src/github.com/docker/libnetwork"
72
+			cd "$GOPATH/src/github.com/docker/libnetwork"
73
+			git checkout -q "$LIBNETWORK_COMMIT"
74
+			CGO_ENABLED=0 go build -v -o /usr/local/bin/docker-proxy github.com/docker/libnetwork/cmd/proxy
75
+			;;
76
+
69 77
 		*)
70
-			echo echo "Usage: $0 [tomlv|runc|containerd|grimes]"
78
+			echo echo "Usage: $0 [tomlv|runc|containerd|grimes|proxy]"
71 79
 			exit 1
72 80
 
73 81
 	esac
... ...
@@ -263,7 +263,7 @@ copy_binaries() {
263 263
 	if [ "$(go env GOOS)/$(go env GOARCH)" == "$(go env GOHOSTOS)/$(go env GOHOSTARCH)" ]; then
264 264
 		if [ -x /usr/local/bin/docker-runc ]; then
265 265
 			echo "Copying nested executables into $dir"
266
-			for file in containerd containerd-shim containerd-ctr runc init; do
266
+			for file in containerd containerd-shim containerd-ctr runc init proxy; do
267 267
 				cp `which "docker-$file"` "$dir/"
268 268
 				if [ "$2" == "hash" ]; then
269 269
 					hash_files "$dir/docker-$file"
... ...
@@ -24,11 +24,12 @@ override_dh_auto_install:
24 24
 	mkdir -p debian/docker-engine/usr/bin
25 25
 	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-client/docker)" debian/docker-engine/usr/bin/docker
26 26
 	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/dockerd)" debian/docker-engine/usr/bin/dockerd
27
-	cp -aT "$$(readlink -f bundles/$(VERSION)/dynbinary-daemon/docker-proxy)" debian/docker-engine/usr/bin/docker-proxy
27
+	cp -aT /usr/local/bin/docker-proxy debian/docker-engine/usr/bin/docker-proxy
28 28
 	cp -aT /usr/local/bin/docker-containerd debian/docker-engine/usr/bin/docker-containerd
29 29
 	cp -aT /usr/local/bin/docker-containerd-shim debian/docker-engine/usr/bin/docker-containerd-shim
30 30
 	cp -aT /usr/local/bin/docker-containerd-ctr debian/docker-engine/usr/bin/docker-containerd-ctr
31 31
 	cp -aT /usr/local/bin/docker-runc debian/docker-engine/usr/bin/docker-runc
32
+	cp -aT /usr/local/bin/docker-init debian/docker-engine/usr/bin/docker-init
32 33
 	mkdir -p debian/docker-engine/usr/lib/docker
33 34
 
34 35
 override_dh_installinit:
... ...
@@ -126,7 +126,9 @@ export DOCKER_GITCOMMIT=%{_gitcommit}
126 126
 install -d $RPM_BUILD_ROOT/%{_bindir}
127 127
 install -p -m 755 bundles/%{_origversion}/dynbinary-client/docker-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker
128 128
 install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/dockerd-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/dockerd
129
-install -p -m 755 bundles/%{_origversion}/dynbinary-daemon/docker-proxy-%{_origversion} $RPM_BUILD_ROOT/%{_bindir}/docker-proxy
129
+
130
+# install proxy
131
+install -p -m 755 /usr/local/bin/docker-proxy $RPM_BUILD_ROOT/%{_bindir}/docker-proxy
130 132
 
131 133
 # install containerd
132 134
 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
136 136
 # install runc
137 137
 install -p -m 755 /usr/local/bin/docker-runc $RPM_BUILD_ROOT/%{_bindir}/docker-runc
138 138
 
139
+# install grimes
140
+install -p -m 755 /usr/local/bin/docker-init $RPM_BUILD_ROOT/%{_bindir}/docker-init
141
+
139 142
 # install udev rules
140 143
 install -d $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d
141 144
 install -p -m 644 contrib/udev/80-docker.rules $RPM_BUILD_ROOT/%{_sysconfdir}/udev/rules.d/80-docker.rules
... ...
@@ -9,8 +9,5 @@ set -e
9 9
 	export BINARY_SHORT_NAME="$DOCKER_DAEMON_BINARY_NAME"
10 10
 	export SOURCE_PATH='./cmd/dockerd'
11 11
 	source "${MAKEDIR}/.binary"
12
-	export BINARY_SHORT_NAME="$DOCKER_PROXY_BINARY_NAME"
13
-	export SOURCE_PATH='./vendor/src/github.com/docker/libnetwork/cmd/proxy'
14
-	source "${MAKEDIR}/.binary"
15 12
 	copy_binaries "$DEST" 'hash'
16 13
 )
... ...
@@ -73,8 +73,8 @@ set -e
73 73
 		EOF
74 74
 
75 75
 		cat >> "$DEST/$version/Dockerfile.build" <<-EOF
76
-			# Install runc and containerd
77
-			RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic
76
+			# Install runc, containerd, proxy and grimes
77
+			RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic proxy grimes
78 78
 		EOF
79 79
 
80 80
 		if [ "$DOCKER_EXPERIMENTAL" ]; then
... ...
@@ -93,8 +93,8 @@ set -e
93 93
 		EOF
94 94
 
95 95
 		cat >> "$DEST/$version/Dockerfile.build" <<-EOF
96
-			# Install runc and containerd
97
-			RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic
96
+			# Install runc, containerd, proxy and grimes
97
+			RUN ./hack/dockerfile/install-binaries.sh runc-dynamic containerd-dynamic proxy grimes
98 98
 		EOF
99 99
 
100 100
 		if [ "$DOCKER_EXPERIMENTAL" ]; then
... ...
@@ -9,8 +9,4 @@ set -e
9 9
 	export BUILDFLAGS=( "${BUILDFLAGS[@]/netgo /}" ) # disable netgo, since we don't need it for a dynamic binary
10 10
 	export BUILDFLAGS=( "${BUILDFLAGS[@]/static_build /}" ) # we're not building a "static" binary here
11 11
 	source "${MAKEDIR}/.binary"
12
-	export BINARY_SHORT_NAME='docker-proxy'
13
-	export SOURCE_PATH='./vendor/src/github.com/docker/libnetwork/cmd/proxy'
14
-	export LDFLAGS_STATIC_DOCKER='-linkmode=external'
15
-	source "${MAKEDIR}/.binary"
16 12
 )
17 13
deleted file mode 100644
... ...
@@ -1,67 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"flag"
5
-	"fmt"
6
-	"log"
7
-	"net"
8
-	"os"
9
-	"os/signal"
10
-	"syscall"
11
-)
12
-
13
-func main() {
14
-	f := os.NewFile(3, "signal-parent")
15
-	host, container := parseHostContainerAddrs()
16
-
17
-	p, err := NewProxy(host, container)
18
-	if err != nil {
19
-		fmt.Fprintf(f, "1\n%s", err)
20
-		f.Close()
21
-		os.Exit(1)
22
-	}
23
-	go handleStopSignals(p)
24
-	fmt.Fprint(f, "0\n")
25
-	f.Close()
26
-
27
-	// Run will block until the proxy stops
28
-	p.Run()
29
-}
30
-
31
-// parseHostContainerAddrs parses the flags passed on reexec to create the TCP or UDP
32
-// net.Addrs to map the host and container ports
33
-func parseHostContainerAddrs() (host net.Addr, container net.Addr) {
34
-	var (
35
-		proto         = flag.String("proto", "tcp", "proxy protocol")
36
-		hostIP        = flag.String("host-ip", "", "host ip")
37
-		hostPort      = flag.Int("host-port", -1, "host port")
38
-		containerIP   = flag.String("container-ip", "", "container ip")
39
-		containerPort = flag.Int("container-port", -1, "container port")
40
-	)
41
-
42
-	flag.Parse()
43
-
44
-	switch *proto {
45
-	case "tcp":
46
-		host = &net.TCPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
47
-		container = &net.TCPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
48
-	case "udp":
49
-		host = &net.UDPAddr{IP: net.ParseIP(*hostIP), Port: *hostPort}
50
-		container = &net.UDPAddr{IP: net.ParseIP(*containerIP), Port: *containerPort}
51
-	default:
52
-		log.Fatalf("unsupported protocol %s", *proto)
53
-	}
54
-
55
-	return host, container
56
-}
57
-
58
-func handleStopSignals(p Proxy) {
59
-	s := make(chan os.Signal, 10)
60
-	signal.Notify(s, os.Interrupt, syscall.SIGTERM)
61
-
62
-	for range s {
63
-		p.Close()
64
-
65
-		os.Exit(0)
66
-	}
67
-}
68 1
deleted file mode 100644
... ...
@@ -1,37 +0,0 @@
1
-// docker-proxy provides a network Proxy interface and implementations for TCP
2
-// and UDP.
3
-package main
4
-
5
-import (
6
-	"fmt"
7
-	"net"
8
-)
9
-
10
-// Proxy defines the behavior of a proxy. It forwards traffic back and forth
11
-// between two endpoints : the frontend and the backend.
12
-// It can be used to do software port-mapping between two addresses.
13
-// e.g. forward all traffic between the frontend (host) 127.0.0.1:3000
14
-// to the backend (container) at 172.17.42.108:4000.
15
-type Proxy interface {
16
-	// Run starts forwarding traffic back and forth between the front
17
-	// and back-end addresses.
18
-	Run()
19
-	// Close stops forwarding traffic and close both ends of the Proxy.
20
-	Close()
21
-	// FrontendAddr returns the address on which the proxy is listening.
22
-	FrontendAddr() net.Addr
23
-	// BackendAddr returns the proxied address.
24
-	BackendAddr() net.Addr
25
-}
26
-
27
-// NewProxy creates a Proxy according to the specified frontendAddr and backendAddr.
28
-func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
29
-	switch frontendAddr.(type) {
30
-	case *net.UDPAddr:
31
-		return NewUDPProxy(frontendAddr.(*net.UDPAddr), backendAddr.(*net.UDPAddr))
32
-	case *net.TCPAddr:
33
-		return NewTCPProxy(frontendAddr.(*net.TCPAddr), backendAddr.(*net.TCPAddr))
34
-	default:
35
-		panic(fmt.Errorf("Unsupported protocol"))
36
-	}
37
-}
38 1
deleted file mode 100644
... ...
@@ -1,31 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"net"
5
-)
6
-
7
-// StubProxy is a proxy that is a stub (does nothing).
8
-type StubProxy struct {
9
-	frontendAddr net.Addr
10
-	backendAddr  net.Addr
11
-}
12
-
13
-// Run does nothing.
14
-func (p *StubProxy) Run() {}
15
-
16
-// Close does nothing.
17
-func (p *StubProxy) Close() {}
18
-
19
-// FrontendAddr returns the frontend address.
20
-func (p *StubProxy) FrontendAddr() net.Addr { return p.frontendAddr }
21
-
22
-// BackendAddr returns the backend address.
23
-func (p *StubProxy) BackendAddr() net.Addr { return p.backendAddr }
24
-
25
-// NewStubProxy creates a new StubProxy
26
-func NewStubProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) {
27
-	return &StubProxy{
28
-		frontendAddr: frontendAddr,
29
-		backendAddr:  backendAddr,
30
-	}, nil
31
-}
32 1
deleted file mode 100644
... ...
@@ -1,95 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"io"
5
-	"log"
6
-	"net"
7
-	"sync"
8
-	"syscall"
9
-)
10
-
11
-// TCPProxy is a proxy for TCP connections. It implements the Proxy interface to
12
-// handle TCP traffic forwarding between the frontend and backend addresses.
13
-type TCPProxy struct {
14
-	listener     *net.TCPListener
15
-	frontendAddr *net.TCPAddr
16
-	backendAddr  *net.TCPAddr
17
-}
18
-
19
-// NewTCPProxy creates a new TCPProxy.
20
-func NewTCPProxy(frontendAddr, backendAddr *net.TCPAddr) (*TCPProxy, error) {
21
-	listener, err := net.ListenTCP("tcp", frontendAddr)
22
-	if err != nil {
23
-		return nil, err
24
-	}
25
-	// If the port in frontendAddr was 0 then ListenTCP will have a picked
26
-	// a port to listen on, hence the call to Addr to get that actual port:
27
-	return &TCPProxy{
28
-		listener:     listener,
29
-		frontendAddr: listener.Addr().(*net.TCPAddr),
30
-		backendAddr:  backendAddr,
31
-	}, nil
32
-}
33
-
34
-func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) {
35
-	backend, err := net.DialTCP("tcp", nil, proxy.backendAddr)
36
-	if err != nil {
37
-		log.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err)
38
-		client.Close()
39
-		return
40
-	}
41
-
42
-	var wg sync.WaitGroup
43
-	var broker = func(to, from *net.TCPConn) {
44
-		if _, err := io.Copy(to, from); err != nil {
45
-			// If the socket we are writing to is shutdown with
46
-			// SHUT_WR, forward it to the other end of the pipe:
47
-			if err, ok := err.(*net.OpError); ok && err.Err == syscall.EPIPE {
48
-				from.CloseWrite()
49
-			}
50
-		}
51
-		to.CloseRead()
52
-		wg.Done()
53
-	}
54
-
55
-	wg.Add(2)
56
-	go broker(client, backend)
57
-	go broker(backend, client)
58
-
59
-	finish := make(chan struct{})
60
-	go func() {
61
-		wg.Wait()
62
-		close(finish)
63
-	}()
64
-
65
-	select {
66
-	case <-quit:
67
-	case <-finish:
68
-	}
69
-	client.Close()
70
-	backend.Close()
71
-	<-finish
72
-}
73
-
74
-// Run starts forwarding the traffic using TCP.
75
-func (proxy *TCPProxy) Run() {
76
-	quit := make(chan bool)
77
-	defer close(quit)
78
-	for {
79
-		client, err := proxy.listener.Accept()
80
-		if err != nil {
81
-			log.Printf("Stopping proxy on tcp/%v for tcp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
82
-			return
83
-		}
84
-		go proxy.clientLoop(client.(*net.TCPConn), quit)
85
-	}
86
-}
87
-
88
-// Close stops forwarding the traffic.
89
-func (proxy *TCPProxy) Close() { proxy.listener.Close() }
90
-
91
-// FrontendAddr returns the TCP address on which the proxy is listening.
92
-func (proxy *TCPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
93
-
94
-// BackendAddr returns the TCP proxied address.
95
-func (proxy *TCPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
96 1
deleted file mode 100644
... ...
@@ -1,168 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"encoding/binary"
5
-	"log"
6
-	"net"
7
-	"strings"
8
-	"sync"
9
-	"syscall"
10
-	"time"
11
-)
12
-
13
-const (
14
-	// UDPConnTrackTimeout is the timeout used for UDP connection tracking
15
-	UDPConnTrackTimeout = 90 * time.Second
16
-	// UDPBufSize is the buffer size for the UDP proxy
17
-	UDPBufSize = 65507
18
-)
19
-
20
-// A net.Addr where the IP is split into two fields so you can use it as a key
21
-// in a map:
22
-type connTrackKey struct {
23
-	IPHigh uint64
24
-	IPLow  uint64
25
-	Port   int
26
-}
27
-
28
-func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
29
-	if len(addr.IP) == net.IPv4len {
30
-		return &connTrackKey{
31
-			IPHigh: 0,
32
-			IPLow:  uint64(binary.BigEndian.Uint32(addr.IP)),
33
-			Port:   addr.Port,
34
-		}
35
-	}
36
-	return &connTrackKey{
37
-		IPHigh: binary.BigEndian.Uint64(addr.IP[:8]),
38
-		IPLow:  binary.BigEndian.Uint64(addr.IP[8:]),
39
-		Port:   addr.Port,
40
-	}
41
-}
42
-
43
-type connTrackMap map[connTrackKey]*net.UDPConn
44
-
45
-// UDPProxy is proxy for which handles UDP datagrams. It implements the Proxy
46
-// interface to handle UDP traffic forwarding between the frontend and backend
47
-// addresses.
48
-type UDPProxy struct {
49
-	listener       *net.UDPConn
50
-	frontendAddr   *net.UDPAddr
51
-	backendAddr    *net.UDPAddr
52
-	connTrackTable connTrackMap
53
-	connTrackLock  sync.Mutex
54
-}
55
-
56
-// NewUDPProxy creates a new UDPProxy.
57
-func NewUDPProxy(frontendAddr, backendAddr *net.UDPAddr) (*UDPProxy, error) {
58
-	listener, err := net.ListenUDP("udp", frontendAddr)
59
-	if err != nil {
60
-		return nil, err
61
-	}
62
-	return &UDPProxy{
63
-		listener:       listener,
64
-		frontendAddr:   listener.LocalAddr().(*net.UDPAddr),
65
-		backendAddr:    backendAddr,
66
-		connTrackTable: make(connTrackMap),
67
-	}, nil
68
-}
69
-
70
-func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) {
71
-	defer func() {
72
-		proxy.connTrackLock.Lock()
73
-		delete(proxy.connTrackTable, *clientKey)
74
-		proxy.connTrackLock.Unlock()
75
-		proxyConn.Close()
76
-	}()
77
-
78
-	readBuf := make([]byte, UDPBufSize)
79
-	for {
80
-		proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout))
81
-	again:
82
-		read, err := proxyConn.Read(readBuf)
83
-		if err != nil {
84
-			if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
85
-				// This will happen if the last write failed
86
-				// (e.g: nothing is actually listening on the
87
-				// proxied port on the container), ignore it
88
-				// and continue until UDPConnTrackTimeout
89
-				// expires:
90
-				goto again
91
-			}
92
-			return
93
-		}
94
-		for i := 0; i != read; {
95
-			written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr)
96
-			if err != nil {
97
-				return
98
-			}
99
-			i += written
100
-		}
101
-	}
102
-}
103
-
104
-// Run starts forwarding the traffic using UDP.
105
-func (proxy *UDPProxy) Run() {
106
-	readBuf := make([]byte, UDPBufSize)
107
-	for {
108
-		read, from, err := proxy.listener.ReadFromUDP(readBuf)
109
-		if err != nil {
110
-			// NOTE: Apparently ReadFrom doesn't return
111
-			// ECONNREFUSED like Read do (see comment in
112
-			// UDPProxy.replyLoop)
113
-			if !isClosedError(err) {
114
-				log.Printf("Stopping proxy on udp/%v for udp/%v (%s)", proxy.frontendAddr, proxy.backendAddr, err)
115
-			}
116
-			break
117
-		}
118
-
119
-		fromKey := newConnTrackKey(from)
120
-		proxy.connTrackLock.Lock()
121
-		proxyConn, hit := proxy.connTrackTable[*fromKey]
122
-		if !hit {
123
-			proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr)
124
-			if err != nil {
125
-				log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
126
-				proxy.connTrackLock.Unlock()
127
-				continue
128
-			}
129
-			proxy.connTrackTable[*fromKey] = proxyConn
130
-			go proxy.replyLoop(proxyConn, from, fromKey)
131
-		}
132
-		proxy.connTrackLock.Unlock()
133
-		for i := 0; i != read; {
134
-			written, err := proxyConn.Write(readBuf[i:read])
135
-			if err != nil {
136
-				log.Printf("Can't proxy a datagram to udp/%s: %s\n", proxy.backendAddr, err)
137
-				break
138
-			}
139
-			i += written
140
-		}
141
-	}
142
-}
143
-
144
-// Close stops forwarding the traffic.
145
-func (proxy *UDPProxy) Close() {
146
-	proxy.listener.Close()
147
-	proxy.connTrackLock.Lock()
148
-	defer proxy.connTrackLock.Unlock()
149
-	for _, conn := range proxy.connTrackTable {
150
-		conn.Close()
151
-	}
152
-}
153
-
154
-// FrontendAddr returns the UDP address on which the proxy is listening.
155
-func (proxy *UDPProxy) FrontendAddr() net.Addr { return proxy.frontendAddr }
156
-
157
-// BackendAddr returns the proxied UDP address.
158
-func (proxy *UDPProxy) BackendAddr() net.Addr { return proxy.backendAddr }
159
-
160
-func isClosedError(err error) bool {
161
-	/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing.
162
-	 * See:
163
-	 * http://golang.org/src/pkg/net/net.go
164
-	 * https://code.google.com/p/go/issues/detail?id=4337
165
-	 * https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ
166
-	 */
167
-	return strings.HasSuffix(err.Error(), "use of closed network connection")
168
-}