Browse Source

Vendor new connections library.

Signed-off-by: David Calavera <david.calavera@gmail.com>
David Calavera 9 years ago
parent
commit
ad7fa01102

+ 1 - 0
hack/vendor.sh

@@ -21,6 +21,7 @@ clone git github.com/tchap/go-patricia v2.1.0
 clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b
 clone git golang.org/x/net 47990a1ba55743e6ef1affd3a14e5bac8553615d https://github.com/golang/net.git
 clone git github.com/docker/go-units v0.2.0
+clone git github.com/docker/go-connections 96cdf8190a45946d0f19576732e2a410c6f84a31
 
 #get libnetwork packages
 clone git github.com/docker/libnetwork bbd6e6d8ca1e7c9b42f6f53277b0bde72847ff90

+ 55 - 0
vendor/src/github.com/docker/go-connections/CONTRIBUTING.md

@@ -0,0 +1,55 @@
+# Contributing to Docker
+
+### Sign your work
+
+The sign-off is a simple line at the end of the explanation for the patch. Your
+signature certifies that you wrote the patch or otherwise have the right to pass
+it on as an open-source patch. The rules are pretty simple: if you can certify
+the below (from [developercertificate.org](http://developercertificate.org/)):
+
+```
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+660 York Street, Suite 102,
+San Francisco, CA 94110 USA
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the open source license
+    indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+    of my knowledge, is covered under an appropriate open source
+    license and I have the right under that license to submit that
+    work with modifications, whether created in whole or in part
+    by me, under the same open source license (unless I am
+    permitted to submit under a different license), as indicated
+    in the file; or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a), (b) or (c) and I have not modified
+    it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
+```
+
+Then you just add a line to every git commit message:
+
+    Signed-off-by: Joe Smith <joe.smith@email.com>
+
+Use your real name (sorry, no pseudonyms or anonymous contributions.)
+
+If you set your `user.name` and `user.email` git configs, you can sign your
+commit automatically with `git commit -s`.

+ 191 - 0
vendor/src/github.com/docker/go-connections/LICENSE

@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2015 Docker, Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 27 - 0
vendor/src/github.com/docker/go-connections/MAINTAINERS

@@ -0,0 +1,27 @@
+# go-connections maintainers file
+#
+# This file describes who runs the docker/go-connections project and how.
+# This is a living document - if you see something out of date or missing, speak up!
+#
+# It is structured to be consumable by both humans and programs.
+# To extract its contents programmatically, use any TOML-compliant parser.
+#
+# This file is compiled into the MAINTAINERS file in docker/opensource.
+#
+[Org]
+	[Org."Core maintainers"]
+		people = [
+			"calavera",
+		]
+
+[people]
+
+# A reference list of all people associated with the project.
+# All other sections should refer to people by their canonical key
+# in the people section.
+
+	# ADD YOURSELF HERE IN ALPHABETICAL ORDER
+	[people.calavera]
+	Name = "David Calavera"
+	Email = "david.calavera@gmail.com"
+	GitHub = "calavera"

+ 13 - 0
vendor/src/github.com/docker/go-connections/README.md

@@ -0,0 +1,13 @@
+[![GoDoc](https://godoc.org/github.com/docker/go-connections?status.svg)](https://godoc.org/github.com/docker/go-connections)
+
+# Introduction
+
+go-connections provides common package to work with network connections.
+
+## Usage
+
+See the [docs in godoc](https://godoc.org/github.com/docker/go-connections) for examples and documentation.
+
+## License
+
+go-connections is licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full license text.

+ 14 - 0
vendor/src/github.com/docker/go-connections/circle.yml

@@ -0,0 +1,14 @@
+dependencies:
+  pre:
+    # setup ipv6
+    - sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0 net.ipv6.conf.default.disable_ipv6=0 net.ipv6.conf.all.disable_ipv6=0
+  post:
+    # install golint
+    - go get github.com/golang/lint/golint
+
+test:
+  pre:
+    # run analysis before tests
+    - go vet ./...
+    - test -z "$(golint ./... | tee /dev/stderr)"
+    - test -z "$(gofmt -s -l . | tee /dev/stderr)"

+ 3 - 0
vendor/src/github.com/docker/go-connections/doc.go

@@ -0,0 +1,3 @@
+// Package connections provides libraries to work with network connections.
+// This library is divided in several components for specific usage.
+package connections

+ 225 - 0
vendor/src/github.com/docker/go-connections/nat/nat.go

@@ -0,0 +1,225 @@
+// Package nat is a convenience package for manipulation of strings describing network ports.
+package nat
+
+import (
+	"fmt"
+	"net"
+	"strconv"
+	"strings"
+
+	"github.com/docker/docker/pkg/parsers"
+)
+
+const (
+	// portSpecTemplate is the expected format for port specifications
+	portSpecTemplate = "ip:hostPort:containerPort"
+)
+
+// PortBinding represents a binding between a Host IP address and a Host Port
+type PortBinding struct {
+	// HostIP is the host IP Address
+	HostIP string `json:"HostIp"`
+	// HostPort is the host port number
+	HostPort string
+}
+
+// PortMap is a collection of PortBinding indexed by Port
+type PortMap map[Port][]PortBinding
+
+// PortSet is a collection of structs indexed by Port
+type PortSet map[Port]struct{}
+
+// Port is a string containing port number and protocol in the format "80/tcp"
+type Port string
+
+// NewPort creates a new instance of a Port given a protocol and port number or port range
+func NewPort(proto, port string) (Port, error) {
+	// Check for parsing issues on "port" now so we can avoid having
+	// to check it later on.
+
+	portStartInt, portEndInt, err := ParsePortRange(port)
+	if err != nil {
+		return "", err
+	}
+
+	if portStartInt == portEndInt {
+		return Port(fmt.Sprintf("%d/%s", portStartInt, proto)), nil
+	}
+	return Port(fmt.Sprintf("%d-%d/%s", portStartInt, portEndInt, proto)), nil
+}
+
+// ParsePort parses the port number string and returns an int
+func ParsePort(rawPort string) (int, error) {
+	if len(rawPort) == 0 {
+		return 0, nil
+	}
+	port, err := strconv.ParseUint(rawPort, 10, 16)
+	if err != nil {
+		return 0, err
+	}
+	return int(port), nil
+}
+
+// ParsePortRange parses the port range string and returns start/end ints
+func ParsePortRange(rawPort string) (int, int, error) {
+	if len(rawPort) == 0 {
+		return 0, 0, nil
+	}
+	start, end, err := parsers.ParsePortRange(rawPort)
+	if err != nil {
+		return 0, 0, err
+	}
+	return int(start), int(end), nil
+}
+
+// Proto returns the protocol of a Port
+func (p Port) Proto() string {
+	proto, _ := SplitProtoPort(string(p))
+	return proto
+}
+
+// Port returns the port number of a Port
+func (p Port) Port() string {
+	_, port := SplitProtoPort(string(p))
+	return port
+}
+
+// Int returns the port number of a Port as an int
+func (p Port) Int() int {
+	portStr := p.Port()
+	if len(portStr) == 0 {
+		return 0
+	}
+
+	// We don't need to check for an error because we're going to
+	// assume that any error would have been found, and reported, in NewPort()
+	port, _ := strconv.ParseUint(portStr, 10, 16)
+	return int(port)
+}
+
+// Range returns the start/end port numbers of a Port range as ints
+func (p Port) Range() (int, int, error) {
+	return ParsePortRange(p.Port())
+}
+
+// SplitProtoPort splits a port in the format of proto/port
+func SplitProtoPort(rawPort string) (string, string) {
+	parts := strings.Split(rawPort, "/")
+	l := len(parts)
+	if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 {
+		return "", ""
+	}
+	if l == 1 {
+		return "tcp", rawPort
+	}
+	if len(parts[1]) == 0 {
+		return "tcp", parts[0]
+	}
+	return parts[1], parts[0]
+}
+
+func validateProto(proto string) bool {
+	for _, availableProto := range []string{"tcp", "udp"} {
+		if availableProto == proto {
+			return true
+		}
+	}
+	return false
+}
+
+// ParsePortSpecs receives port specs in the format of ip:public:private/proto and parses
+// these in to the internal types
+func ParsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) {
+	var (
+		exposedPorts = make(map[Port]struct{}, len(ports))
+		bindings     = make(map[Port][]PortBinding)
+	)
+
+	for _, rawPort := range ports {
+		proto := "tcp"
+
+		if i := strings.LastIndex(rawPort, "/"); i != -1 {
+			proto = rawPort[i+1:]
+			rawPort = rawPort[:i]
+		}
+		if !strings.Contains(rawPort, ":") {
+			rawPort = fmt.Sprintf("::%s", rawPort)
+		} else if len(strings.Split(rawPort, ":")) == 2 {
+			rawPort = fmt.Sprintf(":%s", rawPort)
+		}
+
+		parts, err := parsers.PartParser(portSpecTemplate, rawPort)
+		if err != nil {
+			return nil, nil, err
+		}
+
+		var (
+			containerPort = parts["containerPort"]
+			rawIP         = parts["ip"]
+			hostPort      = parts["hostPort"]
+		)
+
+		if rawIP != "" && net.ParseIP(rawIP) == nil {
+			return nil, nil, fmt.Errorf("Invalid ip address: %s", rawIP)
+		}
+		if containerPort == "" {
+			return nil, nil, fmt.Errorf("No port specified: %s<empty>", rawPort)
+		}
+
+		startPort, endPort, err := parsers.ParsePortRange(containerPort)
+		if err != nil {
+			return nil, nil, fmt.Errorf("Invalid containerPort: %s", containerPort)
+		}
+
+		var startHostPort, endHostPort uint64 = 0, 0
+		if len(hostPort) > 0 {
+			startHostPort, endHostPort, err = parsers.ParsePortRange(hostPort)
+			if err != nil {
+				return nil, nil, fmt.Errorf("Invalid hostPort: %s", hostPort)
+			}
+		}
+
+		if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) {
+			// Allow host port range iff containerPort is not a range.
+			// In this case, use the host port range as the dynamic
+			// host port range to allocate into.
+			if endPort != startPort {
+				return nil, nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort)
+			}
+		}
+
+		if !validateProto(strings.ToLower(proto)) {
+			return nil, nil, fmt.Errorf("Invalid proto: %s", proto)
+		}
+
+		for i := uint64(0); i <= (endPort - startPort); i++ {
+			containerPort = strconv.FormatUint(startPort+i, 10)
+			if len(hostPort) > 0 {
+				hostPort = strconv.FormatUint(startHostPort+i, 10)
+			}
+			// Set hostPort to a range only if there is a single container port
+			// and a dynamic host port.
+			if startPort == endPort && startHostPort != endHostPort {
+				hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10))
+			}
+			port, err := NewPort(strings.ToLower(proto), containerPort)
+			if err != nil {
+				return nil, nil, err
+			}
+			if _, exists := exposedPorts[port]; !exists {
+				exposedPorts[port] = struct{}{}
+			}
+
+			binding := PortBinding{
+				HostIP:   rawIP,
+				HostPort: hostPort,
+			}
+			bslice, exists := bindings[port]
+			if !exists {
+				bslice = []PortBinding{}
+			}
+			bindings[port] = append(bslice, binding)
+		}
+	}
+	return exposedPorts, bindings, nil
+}

+ 525 - 0
vendor/src/github.com/docker/go-connections/nat/nat_test.go

@@ -0,0 +1,525 @@
+package nat
+
+import (
+	"testing"
+)
+
+func TestParsePort(t *testing.T) {
+	var (
+		p   int
+		err error
+	)
+
+	p, err = ParsePort("1234")
+
+	if err != nil || p != 1234 {
+		t.Fatal("Parsing '1234' did not succeed")
+	}
+
+	// FIXME currently this is a valid port. I don't think it should be.
+	// I'm leaving this test commented out until we make a decision.
+	// - erikh
+
+	/*
+		p, err = ParsePort("0123")
+
+		if err != nil {
+		    t.Fatal("Successfully parsed port '0123' to '123'")
+		}
+	*/
+
+	p, err = ParsePort("asdf")
+
+	if err == nil || p != 0 {
+		t.Fatal("Parsing port 'asdf' succeeded")
+	}
+
+	p, err = ParsePort("1asdf")
+
+	if err == nil || p != 0 {
+		t.Fatal("Parsing port '1asdf' succeeded")
+	}
+}
+
+func TestParsePortRange(t *testing.T) {
+	var (
+		begin int
+		end   int
+		err   error
+	)
+
+	type TestRange struct {
+		Range string
+		Begin int
+		End   int
+	}
+	validRanges := []TestRange{
+		{"1234", 1234, 1234},
+		{"1234-1234", 1234, 1234},
+		{"1234-1235", 1234, 1235},
+		{"8000-9000", 8000, 9000},
+		{"0", 0, 0},
+		{"0-0", 0, 0},
+	}
+
+	for _, r := range validRanges {
+		begin, end, err = ParsePortRange(r.Range)
+
+		if err != nil || begin != r.Begin {
+			t.Fatalf("Parsing port range '%s' did not succeed. Expected begin %d, got %d", r.Range, r.Begin, begin)
+		}
+		if err != nil || end != r.End {
+			t.Fatalf("Parsing port range '%s' did not succeed. Expected end %d, got %d", r.Range, r.End, end)
+		}
+	}
+
+	invalidRanges := []string{
+		"asdf",
+		"1asdf",
+		"9000-8000",
+		"9000-",
+		"-8000",
+		"-8000-",
+	}
+
+	for _, r := range invalidRanges {
+		begin, end, err = ParsePortRange(r)
+
+		if err == nil || begin != 0 || end != 0 {
+			t.Fatalf("Parsing port range '%s' succeeded", r)
+		}
+	}
+}
+
+func TestPort(t *testing.T) {
+	p, err := NewPort("tcp", "1234")
+
+	if err != nil {
+		t.Fatalf("tcp, 1234 had a parsing issue: %v", err)
+	}
+
+	if string(p) != "1234/tcp" {
+		t.Fatal("tcp, 1234 did not result in the string 1234/tcp")
+	}
+
+	if p.Proto() != "tcp" {
+		t.Fatal("protocol was not tcp")
+	}
+
+	if p.Port() != "1234" {
+		t.Fatal("port string value was not 1234")
+	}
+
+	if p.Int() != 1234 {
+		t.Fatal("port int value was not 1234")
+	}
+
+	p, err = NewPort("tcp", "asd1234")
+	if err == nil {
+		t.Fatal("tcp, asd1234 was supposed to fail")
+	}
+
+	p, err = NewPort("tcp", "1234-1230")
+	if err == nil {
+		t.Fatal("tcp, 1234-1230 was supposed to fail")
+	}
+
+	p, err = NewPort("tcp", "1234-1242")
+	if err != nil {
+		t.Fatalf("tcp, 1234-1242 had a parsing issue: %v", err)
+	}
+
+	if string(p) != "1234-1242/tcp" {
+		t.Fatal("tcp, 1234-1242 did not result in the string 1234-1242/tcp")
+	}
+}
+
+func TestSplitProtoPort(t *testing.T) {
+	var (
+		proto string
+		port  string
+	)
+
+	proto, port = SplitProtoPort("1234/tcp")
+
+	if proto != "tcp" || port != "1234" {
+		t.Fatal("Could not split 1234/tcp properly")
+	}
+
+	proto, port = SplitProtoPort("")
+
+	if proto != "" || port != "" {
+		t.Fatal("parsing an empty string yielded surprising results", proto, port)
+	}
+
+	proto, port = SplitProtoPort("1234")
+
+	if proto != "tcp" || port != "1234" {
+		t.Fatal("tcp is not the default protocol for portspec '1234'", proto, port)
+	}
+
+	proto, port = SplitProtoPort("1234/")
+
+	if proto != "tcp" || port != "1234" {
+		t.Fatal("parsing '1234/' yielded:" + port + "/" + proto)
+	}
+
+	proto, port = SplitProtoPort("/tcp")
+
+	if proto != "" || port != "" {
+		t.Fatal("parsing '/tcp' yielded:" + port + "/" + proto)
+	}
+}
+
+func TestParsePortSpecs(t *testing.T) {
+	var (
+		portMap    map[Port]struct{}
+		bindingMap map[Port][]PortBinding
+		err        error
+	)
+
+	portMap, bindingMap, err = ParsePortSpecs([]string{"1234/tcp", "2345/udp"})
+
+	if err != nil {
+		t.Fatalf("Error while processing ParsePortSpecs: %s", err)
+	}
+
+	if _, ok := portMap[Port("1234/tcp")]; !ok {
+		t.Fatal("1234/tcp was not parsed properly")
+	}
+
+	if _, ok := portMap[Port("2345/udp")]; !ok {
+		t.Fatal("2345/udp was not parsed properly")
+	}
+
+	for portspec, bindings := range bindingMap {
+		if len(bindings) != 1 {
+			t.Fatalf("%s should have exactly one binding", portspec)
+		}
+
+		if bindings[0].HostIP != "" {
+			t.Fatalf("HostIP should not be set for %s", portspec)
+		}
+
+		if bindings[0].HostPort != "" {
+			t.Fatalf("HostPort should not be set for %s", portspec)
+		}
+	}
+
+	portMap, bindingMap, err = ParsePortSpecs([]string{"1234:1234/tcp", "2345:2345/udp"})
+
+	if err != nil {
+		t.Fatalf("Error while processing ParsePortSpecs: %s", err)
+	}
+
+	if _, ok := portMap[Port("1234/tcp")]; !ok {
+		t.Fatal("1234/tcp was not parsed properly")
+	}
+
+	if _, ok := portMap[Port("2345/udp")]; !ok {
+		t.Fatal("2345/udp was not parsed properly")
+	}
+
+	for portspec, bindings := range bindingMap {
+		_, port := SplitProtoPort(string(portspec))
+
+		if len(bindings) != 1 {
+			t.Fatalf("%s should have exactly one binding", portspec)
+		}
+
+		if bindings[0].HostIP != "" {
+			t.Fatalf("HostIP should not be set for %s", portspec)
+		}
+
+		if bindings[0].HostPort != port {
+			t.Fatalf("HostPort should be %s for %s", port, portspec)
+		}
+	}
+
+	portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234:1234/tcp", "0.0.0.0:2345:2345/udp"})
+
+	if err != nil {
+		t.Fatalf("Error while processing ParsePortSpecs: %s", err)
+	}
+
+	if _, ok := portMap[Port("1234/tcp")]; !ok {
+		t.Fatal("1234/tcp was not parsed properly")
+	}
+
+	if _, ok := portMap[Port("2345/udp")]; !ok {
+		t.Fatal("2345/udp was not parsed properly")
+	}
+
+	for portspec, bindings := range bindingMap {
+		_, port := SplitProtoPort(string(portspec))
+
+		if len(bindings) != 1 {
+			t.Fatalf("%s should have exactly one binding", portspec)
+		}
+
+		if bindings[0].HostIP != "0.0.0.0" {
+			t.Fatalf("HostIP is not 0.0.0.0 for %s", portspec)
+		}
+
+		if bindings[0].HostPort != port {
+			t.Fatalf("HostPort should be %s for %s", port, portspec)
+		}
+	}
+
+	_, _, err = ParsePortSpecs([]string{"localhost:1234:1234/tcp"})
+
+	if err == nil {
+		t.Fatal("Received no error while trying to parse a hostname instead of ip")
+	}
+}
+
+func TestParsePortSpecsWithRange(t *testing.T) {
+	var (
+		portMap    map[Port]struct{}
+		bindingMap map[Port][]PortBinding
+		err        error
+	)
+
+	portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236/tcp", "2345-2347/udp"})
+
+	if err != nil {
+		t.Fatalf("Error while processing ParsePortSpecs: %s", err)
+	}
+
+	if _, ok := portMap[Port("1235/tcp")]; !ok {
+		t.Fatal("1234/tcp was not parsed properly")
+	}
+
+	if _, ok := portMap[Port("2346/udp")]; !ok {
+		t.Fatal("2345/udp was not parsed properly")
+	}
+
+	for portspec, bindings := range bindingMap {
+		if len(bindings) != 1 {
+			t.Fatalf("%s should have exactly one binding", portspec)
+		}
+
+		if bindings[0].HostIP != "" {
+			t.Fatalf("HostIP should not be set for %s", portspec)
+		}
+
+		if bindings[0].HostPort != "" {
+			t.Fatalf("HostPort should not be set for %s", portspec)
+		}
+	}
+
+	portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236:1234-1236/tcp", "2345-2347:2345-2347/udp"})
+
+	if err != nil {
+		t.Fatalf("Error while processing ParsePortSpecs: %s", err)
+	}
+
+	if _, ok := portMap[Port("1235/tcp")]; !ok {
+		t.Fatal("1234/tcp was not parsed properly")
+	}
+
+	if _, ok := portMap[Port("2346/udp")]; !ok {
+		t.Fatal("2345/udp was not parsed properly")
+	}
+
+	for portspec, bindings := range bindingMap {
+		_, port := SplitProtoPort(string(portspec))
+		if len(bindings) != 1 {
+			t.Fatalf("%s should have exactly one binding", portspec)
+		}
+
+		if bindings[0].HostIP != "" {
+			t.Fatalf("HostIP should not be set for %s", portspec)
+		}
+
+		if bindings[0].HostPort != port {
+			t.Fatalf("HostPort should be %s for %s", port, portspec)
+		}
+	}
+
+	portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234-1236:1234-1236/tcp", "0.0.0.0:2345-2347:2345-2347/udp"})
+
+	if err != nil {
+		t.Fatalf("Error while processing ParsePortSpecs: %s", err)
+	}
+
+	if _, ok := portMap[Port("1235/tcp")]; !ok {
+		t.Fatal("1234/tcp was not parsed properly")
+	}
+
+	if _, ok := portMap[Port("2346/udp")]; !ok {
+		t.Fatal("2345/udp was not parsed properly")
+	}
+
+	for portspec, bindings := range bindingMap {
+		_, port := SplitProtoPort(string(portspec))
+		if len(bindings) != 1 || bindings[0].HostIP != "0.0.0.0" || bindings[0].HostPort != port {
+			t.Fatalf("Expect single binding to port %s but found %s", port, bindings)
+		}
+	}
+
+	_, _, err = ParsePortSpecs([]string{"localhost:1234-1236:1234-1236/tcp"})
+
+	if err == nil {
+		t.Fatal("Received no error while trying to parse a hostname instead of ip")
+	}
+}
+
+func TestParseNetworkOptsPrivateOnly(t *testing.T) {
+	ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::80"})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(ports) != 1 {
+		t.Logf("Expected 1 got %d", len(ports))
+		t.FailNow()
+	}
+	if len(bindings) != 1 {
+		t.Logf("Expected 1 got %d", len(bindings))
+		t.FailNow()
+	}
+	for k := range ports {
+		if k.Proto() != "tcp" {
+			t.Logf("Expected tcp got %s", k.Proto())
+			t.Fail()
+		}
+		if k.Port() != "80" {
+			t.Logf("Expected 80 got %s", k.Port())
+			t.Fail()
+		}
+		b, exists := bindings[k]
+		if !exists {
+			t.Log("Binding does not exist")
+			t.FailNow()
+		}
+		if len(b) != 1 {
+			t.Logf("Expected 1 got %d", len(b))
+			t.FailNow()
+		}
+		s := b[0]
+		if s.HostPort != "" {
+			t.Logf("Expected \"\" got %s", s.HostPort)
+			t.Fail()
+		}
+		if s.HostIP != "192.168.1.100" {
+			t.Fail()
+		}
+	}
+}
+
+func TestParseNetworkOptsPublic(t *testing.T) {
+	ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:8080:80"})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(ports) != 1 {
+		t.Logf("Expected 1 got %d", len(ports))
+		t.FailNow()
+	}
+	if len(bindings) != 1 {
+		t.Logf("Expected 1 got %d", len(bindings))
+		t.FailNow()
+	}
+	for k := range ports {
+		if k.Proto() != "tcp" {
+			t.Logf("Expected tcp got %s", k.Proto())
+			t.Fail()
+		}
+		if k.Port() != "80" {
+			t.Logf("Expected 80 got %s", k.Port())
+			t.Fail()
+		}
+		b, exists := bindings[k]
+		if !exists {
+			t.Log("Binding does not exist")
+			t.FailNow()
+		}
+		if len(b) != 1 {
+			t.Logf("Expected 1 got %d", len(b))
+			t.FailNow()
+		}
+		s := b[0]
+		if s.HostPort != "8080" {
+			t.Logf("Expected 8080 got %s", s.HostPort)
+			t.Fail()
+		}
+		if s.HostIP != "192.168.1.100" {
+			t.Fail()
+		}
+	}
+}
+
+func TestParseNetworkOptsPublicNoPort(t *testing.T) {
+	ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100"})
+
+	if err == nil {
+		t.Logf("Expected error Invalid containerPort")
+		t.Fail()
+	}
+	if ports != nil {
+		t.Logf("Expected nil got %s", ports)
+		t.Fail()
+	}
+	if bindings != nil {
+		t.Logf("Expected nil got %s", bindings)
+		t.Fail()
+	}
+}
+
+func TestParseNetworkOptsNegativePorts(t *testing.T) {
+	ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:-1:-1"})
+
+	if err == nil {
+		t.Fail()
+	}
+	if len(ports) != 0 {
+		t.Logf("Expected nil got %d", len(ports))
+		t.Fail()
+	}
+	if len(bindings) != 0 {
+		t.Logf("Expected 0 got %d", len(bindings))
+		t.Fail()
+	}
+}
+
+func TestParseNetworkOptsUdp(t *testing.T) {
+	ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::6000/udp"})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(ports) != 1 {
+		t.Logf("Expected 1 got %d", len(ports))
+		t.FailNow()
+	}
+	if len(bindings) != 1 {
+		t.Logf("Expected 1 got %d", len(bindings))
+		t.FailNow()
+	}
+	for k := range ports {
+		if k.Proto() != "udp" {
+			t.Logf("Expected udp got %s", k.Proto())
+			t.Fail()
+		}
+		if k.Port() != "6000" {
+			t.Logf("Expected 6000 got %s", k.Port())
+			t.Fail()
+		}
+		b, exists := bindings[k]
+		if !exists {
+			t.Log("Binding does not exist")
+			t.FailNow()
+		}
+		if len(b) != 1 {
+			t.Logf("Expected 1 got %d", len(b))
+			t.FailNow()
+		}
+		s := b[0]
+		if s.HostPort != "" {
+			t.Logf("Expected \"\" got %s", s.HostPort)
+			t.Fail()
+		}
+		if s.HostIP != "192.168.1.100" {
+			t.Fail()
+		}
+	}
+}

+ 98 - 0
vendor/src/github.com/docker/go-connections/nat/sort.go

@@ -0,0 +1,98 @@
+package nat
+
+import (
+	"sort"
+	"strings"
+
+	"github.com/docker/docker/pkg/parsers"
+)
+
+type portSorter struct {
+	ports []Port
+	by    func(i, j Port) bool
+}
+
+func (s *portSorter) Len() int {
+	return len(s.ports)
+}
+
+func (s *portSorter) Swap(i, j int) {
+	s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
+}
+
+func (s *portSorter) Less(i, j int) bool {
+	ip := s.ports[i]
+	jp := s.ports[j]
+
+	return s.by(ip, jp)
+}
+
+// Sort sorts a list of ports using the provided predicate
+// This function should compare `i` and `j`, returning true if `i` is
+// considered to be less than `j`
+func Sort(ports []Port, predicate func(i, j Port) bool) {
+	s := &portSorter{ports, predicate}
+	sort.Sort(s)
+}
+
+type portMapEntry struct {
+	port    Port
+	binding PortBinding
+}
+
+type portMapSorter []portMapEntry
+
+func (s portMapSorter) Len() int      { return len(s) }
+func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// sort the port so that the order is:
+// 1. port with larger specified bindings
+// 2. larger port
+// 3. port with tcp protocol
+func (s portMapSorter) Less(i, j int) bool {
+	pi, pj := s[i].port, s[j].port
+	hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort)
+	return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp")
+}
+
+// SortPortMap sorts the list of ports and their respected mapping. The ports
+// will explicit HostPort will be placed first.
+func SortPortMap(ports []Port, bindings PortMap) {
+	s := portMapSorter{}
+	for _, p := range ports {
+		if binding, ok := bindings[p]; ok {
+			for _, b := range binding {
+				s = append(s, portMapEntry{port: p, binding: b})
+			}
+			bindings[p] = []PortBinding{}
+		} else {
+			s = append(s, portMapEntry{port: p})
+		}
+	}
+
+	sort.Sort(s)
+	var (
+		i  int
+		pm = make(map[Port]struct{})
+	)
+	// reorder ports
+	for _, entry := range s {
+		if _, ok := pm[entry.port]; !ok {
+			ports[i] = entry.port
+			pm[entry.port] = struct{}{}
+			i++
+		}
+		// reorder bindings for this port
+		if _, ok := bindings[entry.port]; ok {
+			bindings[entry.port] = append(bindings[entry.port], entry.binding)
+		}
+	}
+}
+
+func toInt(s string) uint64 {
+	i, _, err := parsers.ParsePortRange(s)
+	if err != nil {
+		i = 0
+	}
+	return i
+}

+ 85 - 0
vendor/src/github.com/docker/go-connections/nat/sort_test.go

@@ -0,0 +1,85 @@
+package nat
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+)
+
+func TestSortUniquePorts(t *testing.T) {
+	ports := []Port{
+		Port("6379/tcp"),
+		Port("22/tcp"),
+	}
+
+	Sort(ports, func(ip, jp Port) bool {
+		return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
+	})
+
+	first := ports[0]
+	if fmt.Sprint(first) != "22/tcp" {
+		t.Log(fmt.Sprint(first))
+		t.Fail()
+	}
+}
+
+func TestSortSamePortWithDifferentProto(t *testing.T) {
+	ports := []Port{
+		Port("8888/tcp"),
+		Port("8888/udp"),
+		Port("6379/tcp"),
+		Port("6379/udp"),
+	}
+
+	Sort(ports, func(ip, jp Port) bool {
+		return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
+	})
+
+	first := ports[0]
+	if fmt.Sprint(first) != "6379/tcp" {
+		t.Fail()
+	}
+}
+
+func TestSortPortMap(t *testing.T) {
+	ports := []Port{
+		Port("22/tcp"),
+		Port("22/udp"),
+		Port("8000/tcp"),
+		Port("6379/tcp"),
+		Port("9999/tcp"),
+	}
+
+	portMap := PortMap{
+		Port("22/tcp"): []PortBinding{
+			{},
+		},
+		Port("8000/tcp"): []PortBinding{
+			{},
+		},
+		Port("6379/tcp"): []PortBinding{
+			{},
+			{HostIP: "0.0.0.0", HostPort: "32749"},
+		},
+		Port("9999/tcp"): []PortBinding{
+			{HostIP: "0.0.0.0", HostPort: "40000"},
+		},
+	}
+
+	SortPortMap(ports, portMap)
+	if !reflect.DeepEqual(ports, []Port{
+		Port("9999/tcp"),
+		Port("6379/tcp"),
+		Port("8000/tcp"),
+		Port("22/tcp"),
+		Port("22/udp"),
+	}) {
+		t.Errorf("failed to prioritize port with explicit mappings, got %v", ports)
+	}
+	if pm := portMap[Port("6379/tcp")]; !reflect.DeepEqual(pm, []PortBinding{
+		{HostIP: "0.0.0.0", HostPort: "32749"},
+		{},
+	}) {
+		t.Errorf("failed to prioritize bindings with explicit mappings, got %v", pm)
+	}
+}

+ 216 - 0
vendor/src/github.com/docker/go-connections/proxy/network_proxy_test.go

@@ -0,0 +1,216 @@
+package proxy
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"net"
+	"strings"
+	"testing"
+	"time"
+)
+
+var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
+var testBufSize = len(testBuf)
+
+type EchoServer interface {
+	Run()
+	Close()
+	LocalAddr() net.Addr
+}
+
+type TCPEchoServer struct {
+	listener net.Listener
+	testCtx  *testing.T
+}
+
+type UDPEchoServer struct {
+	conn    net.PacketConn
+	testCtx *testing.T
+}
+
+func NewEchoServer(t *testing.T, proto, address string) EchoServer {
+	var server EchoServer
+	if strings.HasPrefix(proto, "tcp") {
+		listener, err := net.Listen(proto, address)
+		if err != nil {
+			t.Fatal(err)
+		}
+		server = &TCPEchoServer{listener: listener, testCtx: t}
+	} else {
+		socket, err := net.ListenPacket(proto, address)
+		if err != nil {
+			t.Fatal(err)
+		}
+		server = &UDPEchoServer{conn: socket, testCtx: t}
+	}
+	return server
+}
+
+func (server *TCPEchoServer) Run() {
+	go func() {
+		for {
+			client, err := server.listener.Accept()
+			if err != nil {
+				return
+			}
+			go func(client net.Conn) {
+				if _, err := io.Copy(client, client); err != nil {
+					server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
+				}
+				client.Close()
+			}(client)
+		}
+	}()
+}
+
+func (server *TCPEchoServer) LocalAddr() net.Addr { return server.listener.Addr() }
+func (server *TCPEchoServer) Close()              { server.listener.Addr() }
+
+func (server *UDPEchoServer) Run() {
+	go func() {
+		readBuf := make([]byte, 1024)
+		for {
+			read, from, err := server.conn.ReadFrom(readBuf)
+			if err != nil {
+				return
+			}
+			for i := 0; i != read; {
+				written, err := server.conn.WriteTo(readBuf[i:read], from)
+				if err != nil {
+					break
+				}
+				i += written
+			}
+		}
+	}()
+}
+
+func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() }
+func (server *UDPEchoServer) Close()              { server.conn.Close() }
+
+func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
+	defer proxy.Close()
+	go proxy.Run()
+	client, err := net.Dial(proto, addr)
+	if err != nil {
+		t.Fatalf("Can't connect to the proxy: %v", err)
+	}
+	defer client.Close()
+	client.SetDeadline(time.Now().Add(10 * time.Second))
+	if _, err = client.Write(testBuf); err != nil {
+		t.Fatal(err)
+	}
+	recvBuf := make([]byte, testBufSize)
+	if _, err = client.Read(recvBuf); err != nil {
+		t.Fatal(err)
+	}
+	if !bytes.Equal(testBuf, recvBuf) {
+		t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
+	}
+}
+
+func testProxy(t *testing.T, proto string, proxy Proxy) {
+	testProxyAt(t, proto, proxy, proxy.FrontendAddr().String())
+}
+
+func TestTCP4Proxy(t *testing.T) {
+	backend := NewEchoServer(t, "tcp", "127.0.0.1:0")
+	defer backend.Close()
+	backend.Run()
+	frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
+	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
+	if err != nil {
+		t.Fatal(err)
+	}
+	testProxy(t, "tcp", proxy)
+}
+
+func TestTCP6Proxy(t *testing.T) {
+	backend := NewEchoServer(t, "tcp", "[::1]:0")
+	defer backend.Close()
+	backend.Run()
+	frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
+	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
+	if err != nil {
+		t.Fatal(err)
+	}
+	testProxy(t, "tcp", proxy)
+}
+
+func TestTCPDualStackProxy(t *testing.T) {
+	// If I understand `godoc -src net favoriteAddrFamily` (used by the
+	// net.Listen* functions) correctly this should work, but it doesn't.
+	t.Skip("No support for dual stack yet")
+	backend := NewEchoServer(t, "tcp", "[::1]:0")
+	defer backend.Close()
+	backend.Run()
+	frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
+	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
+	if err != nil {
+		t.Fatal(err)
+	}
+	ipv4ProxyAddr := &net.TCPAddr{
+		IP:   net.IPv4(127, 0, 0, 1),
+		Port: proxy.FrontendAddr().(*net.TCPAddr).Port,
+	}
+	testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String())
+}
+
+func TestUDP4Proxy(t *testing.T) {
+	backend := NewEchoServer(t, "udp", "127.0.0.1:0")
+	defer backend.Close()
+	backend.Run()
+	frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
+	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
+	if err != nil {
+		t.Fatal(err)
+	}
+	testProxy(t, "udp", proxy)
+}
+
+func TestUDP6Proxy(t *testing.T) {
+	backend := NewEchoServer(t, "udp", "[::1]:0")
+	defer backend.Close()
+	backend.Run()
+	frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0}
+	proxy, err := NewProxy(frontendAddr, backend.LocalAddr())
+	if err != nil {
+		t.Fatal(err)
+	}
+	testProxy(t, "udp", proxy)
+}
+
+func TestUDPWriteError(t *testing.T) {
+	frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
+	// Hopefully, this port will be free: */
+	backendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 25587}
+	proxy, err := NewProxy(frontendAddr, backendAddr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer proxy.Close()
+	go proxy.Run()
+	client, err := net.Dial("udp", "127.0.0.1:25587")
+	if err != nil {
+		t.Fatalf("Can't connect to the proxy: %v", err)
+	}
+	defer client.Close()
+	// Make sure the proxy doesn't stop when there is no actual backend:
+	client.Write(testBuf)
+	client.Write(testBuf)
+	backend := NewEchoServer(t, "udp", "127.0.0.1:25587")
+	defer backend.Close()
+	backend.Run()
+	client.SetDeadline(time.Now().Add(10 * time.Second))
+	if _, err = client.Write(testBuf); err != nil {
+		t.Fatal(err)
+	}
+	recvBuf := make([]byte, testBufSize)
+	if _, err = client.Read(recvBuf); err != nil {
+		t.Fatal(err)
+	}
+	if !bytes.Equal(testBuf, recvBuf) {
+		t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
+	}
+}

+ 36 - 0
vendor/src/github.com/docker/go-connections/proxy/proxy.go

@@ -0,0 +1,36 @@
+// Package proxy provides a network Proxy interface and implementations for TCP and UDP.
+package proxy
+
+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"))
+	}
+}

+ 31 - 0
vendor/src/github.com/docker/go-connections/proxy/stub_proxy.go

@@ -0,0 +1,31 @@
+package proxy
+
+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
+}

+ 99 - 0
vendor/src/github.com/docker/go-connections/proxy/tcp_proxy.go

@@ -0,0 +1,99 @@
+package proxy
+
+import (
+	"io"
+	"net"
+	"syscall"
+
+	"github.com/Sirupsen/logrus"
+)
+
+// 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 {
+		logrus.Printf("Can't forward traffic to backend tcp/%v: %s\n", proxy.backendAddr, err)
+		client.Close()
+		return
+	}
+
+	event := make(chan int64)
+	var broker = func(to, from *net.TCPConn) {
+		written, err := io.Copy(to, from)
+		if 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()
+		event <- written
+	}
+
+	go broker(client, backend)
+	go broker(backend, client)
+
+	var transferred int64
+	for i := 0; i < 2; i++ {
+		select {
+		case written := <-event:
+			transferred += written
+		case <-quit:
+			// Interrupt the two brokers and "join" them.
+			client.Close()
+			backend.Close()
+			for ; i < 2; i++ {
+				transferred += <-event
+			}
+			return
+		}
+	}
+	client.Close()
+	backend.Close()
+}
+
+// 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 {
+			logrus.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 }

+ 169 - 0
vendor/src/github.com/docker/go-connections/proxy/udp_proxy.go

@@ -0,0 +1,169 @@
+package proxy
+
+import (
+	"encoding/binary"
+	"net"
+	"strings"
+	"sync"
+	"syscall"
+	"time"
+
+	"github.com/Sirupsen/logrus"
+)
+
+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) {
+				logrus.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 {
+				logrus.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 {
+				logrus.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")
+}

+ 0 - 0
vendor/src/github.com/docker/go-connections/sockets/README.md


+ 43 - 0
vendor/src/github.com/docker/go-connections/sockets/tcp_socket.go

@@ -0,0 +1,43 @@
+// Package sockets provides helper functions to create and configure Unix or TCP sockets.
+package sockets
+
+import (
+	"crypto/tls"
+	"net"
+	"net/http"
+	"time"
+)
+
+// NewTCPSocket creates a TCP socket listener with the specified address and
+// and the specified tls configuration. If TLSConfig is set, will encapsulate the
+// TCP listener inside a TLS one.
+func NewTCPSocket(addr string, tlsConfig *tls.Config) (net.Listener, error) {
+	l, err := net.Listen("tcp", addr)
+	if err != nil {
+		return nil, err
+	}
+	if tlsConfig != nil {
+		tlsConfig.NextProtos = []string{"http/1.1"}
+		l = tls.NewListener(l, tlsConfig)
+	}
+	return l, nil
+}
+
+// ConfigureTCPTransport configures the specified Transport according to the
+// specified proto and addr.
+// If the proto is unix (using a unix socket to communicate) the compression
+// is disabled.
+func ConfigureTCPTransport(tr *http.Transport, proto, addr string) {
+	// Why 32? See https://github.com/docker/docker/pull/8035.
+	timeout := 32 * time.Second
+	if proto == "unix" {
+		// No need for compression in local communications.
+		tr.DisableCompression = true
+		tr.Dial = func(_, _ string) (net.Conn, error) {
+			return net.DialTimeout(proto, addr, timeout)
+		}
+	} else {
+		tr.Proxy = http.ProxyFromEnvironment
+		tr.Dial = (&net.Dialer{Timeout: timeout}).Dial
+	}
+}

+ 80 - 0
vendor/src/github.com/docker/go-connections/sockets/unix_socket.go

@@ -0,0 +1,80 @@
+// +build linux freebsd
+
+package sockets
+
+import (
+	"fmt"
+	"net"
+	"os"
+	"strconv"
+	"syscall"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/opencontainers/runc/libcontainer/user"
+)
+
+// NewUnixSocket creates a unix socket with the specified path and group.
+func NewUnixSocket(path, group string) (net.Listener, error) {
+	if err := syscall.Unlink(path); err != nil && !os.IsNotExist(err) {
+		return nil, err
+	}
+	mask := syscall.Umask(0777)
+	defer syscall.Umask(mask)
+	l, err := net.Listen("unix", path)
+	if err != nil {
+		return nil, err
+	}
+	if err := setSocketGroup(path, group); err != nil {
+		l.Close()
+		return nil, err
+	}
+	if err := os.Chmod(path, 0660); err != nil {
+		l.Close()
+		return nil, err
+	}
+	return l, nil
+}
+
+func setSocketGroup(path, group string) error {
+	if group == "" {
+		return nil
+	}
+	if err := changeGroup(path, group); err != nil {
+		if group != "docker" {
+			return err
+		}
+		logrus.Debugf("Warning: could not change group %s to docker: %v", path, err)
+	}
+	return nil
+}
+
+func changeGroup(path string, nameOrGid string) error {
+	gid, err := lookupGidByName(nameOrGid)
+	if err != nil {
+		return err
+	}
+	logrus.Debugf("%s group found. gid: %d", nameOrGid, gid)
+	return os.Chown(path, 0, gid)
+}
+
+func lookupGidByName(nameOrGid string) (int, error) {
+	groupFile, err := user.GetGroupPath()
+	if err != nil {
+		return -1, err
+	}
+	groups, err := user.ParseGroupFileFilter(groupFile, func(g user.Group) bool {
+		return g.Name == nameOrGid || strconv.Itoa(g.Gid) == nameOrGid
+	})
+	if err != nil {
+		return -1, err
+	}
+	if groups != nil && len(groups) > 0 {
+		return groups[0].Gid, nil
+	}
+	gid, err := strconv.Atoi(nameOrGid)
+	if err == nil {
+		logrus.Warnf("Could not find GID %d", gid)
+		return gid, nil
+	}
+	return -1, fmt.Errorf("Group %s not found", nameOrGid)
+}

+ 133 - 0
vendor/src/github.com/docker/go-connections/tlsconfig/config.go

@@ -0,0 +1,133 @@
+// Package tlsconfig provides primitives to retrieve secure-enough TLS configurations for both clients and servers.
+//
+// As a reminder from https://golang.org/pkg/crypto/tls/#Config:
+//	A Config structure is used to configure a TLS client or server. After one has been passed to a TLS function it must not be modified.
+//	A Config may be reused; the tls package will also not modify it.
+package tlsconfig
+
+import (
+	"crypto/tls"
+	"crypto/x509"
+	"fmt"
+	"io/ioutil"
+	"os"
+
+	"github.com/Sirupsen/logrus"
+)
+
+// Options represents the information needed to create client and server TLS configurations.
+type Options struct {
+	CAFile string
+
+	// If either CertFile or KeyFile is empty, Client() will not load them
+	// preventing the client from authenticating to the server.
+	// However, Server() requires them and will error out if they are empty.
+	CertFile string
+	KeyFile  string
+
+	// client-only option
+	InsecureSkipVerify bool
+	// server-only option
+	ClientAuth tls.ClientAuthType
+}
+
+// Extra (server-side) accepted CBC cipher suites - will phase out in the future
+var acceptedCBCCiphers = []uint16{
+	tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+	tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+	tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+	tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+	tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+	tls.TLS_RSA_WITH_AES_128_CBC_SHA,
+}
+
+// Client TLS cipher suites (dropping CBC ciphers for client preferred suite set)
+var clientCipherSuites = []uint16{
+	tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+	tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+}
+
+// DefaultServerAcceptedCiphers should be uses by code which already has a crypto/tls
+// options struct but wants to use a commonly accepted set of TLS cipher suites, with
+// known weak algorithms removed.
+var DefaultServerAcceptedCiphers = append(clientCipherSuites, acceptedCBCCiphers...)
+
+// ServerDefault is a secure-enough TLS configuration for the server TLS configuration.
+var ServerDefault = tls.Config{
+	// Avoid fallback to SSL protocols < TLS1.0
+	MinVersion:               tls.VersionTLS10,
+	PreferServerCipherSuites: true,
+	CipherSuites:             DefaultServerAcceptedCiphers,
+}
+
+// ClientDefault is a secure-enough TLS configuration for the client TLS configuration.
+var ClientDefault = tls.Config{
+	// Prefer TLS1.2 as the client minimum
+	MinVersion:   tls.VersionTLS12,
+	CipherSuites: clientCipherSuites,
+}
+
+// certPool returns an X.509 certificate pool from `caFile`, the certificate file.
+func certPool(caFile string) (*x509.CertPool, error) {
+	// If we should verify the server, we need to load a trusted ca
+	certPool := x509.NewCertPool()
+	pem, err := ioutil.ReadFile(caFile)
+	if err != nil {
+		return nil, fmt.Errorf("Could not read CA certificate %q: %v", caFile, err)
+	}
+	if !certPool.AppendCertsFromPEM(pem) {
+		return nil, fmt.Errorf("failed to append certificates from PEM file: %q", caFile)
+	}
+	s := certPool.Subjects()
+	subjects := make([]string, len(s))
+	for i, subject := range s {
+		subjects[i] = string(subject)
+	}
+	logrus.Debugf("Trusting certs with subjects: %v", subjects)
+	return certPool, nil
+}
+
+// Client returns a TLS configuration meant to be used by a client.
+func Client(options Options) (*tls.Config, error) {
+	tlsConfig := ClientDefault
+	tlsConfig.InsecureSkipVerify = options.InsecureSkipVerify
+	if !options.InsecureSkipVerify {
+		CAs, err := certPool(options.CAFile)
+		if err != nil {
+			return nil, err
+		}
+		tlsConfig.RootCAs = CAs
+	}
+
+	if options.CertFile != "" && options.KeyFile != "" {
+		tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
+		if err != nil {
+			return nil, fmt.Errorf("Could not load X509 key pair: %v. Make sure the key is not encrypted", err)
+		}
+		tlsConfig.Certificates = []tls.Certificate{tlsCert}
+	}
+
+	return &tlsConfig, nil
+}
+
+// Server returns a TLS configuration meant to be used by a server.
+func Server(options Options) (*tls.Config, error) {
+	tlsConfig := ServerDefault
+	tlsConfig.ClientAuth = options.ClientAuth
+	tlsCert, err := tls.LoadX509KeyPair(options.CertFile, options.KeyFile)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return nil, fmt.Errorf("Could not load X509 key pair (cert: %q, key: %q): %v", options.CertFile, options.KeyFile, err)
+		}
+		return nil, fmt.Errorf("Error reading X509 key pair (cert: %q, key: %q): %v. Make sure the key is not encrypted.", options.CertFile, options.KeyFile, err)
+	}
+	tlsConfig.Certificates = []tls.Certificate{tlsCert}
+	if options.ClientAuth >= tls.VerifyClientCertIfGiven {
+		CAs, err := certPool(options.CAFile)
+		if err != nil {
+			return nil, err
+		}
+		tlsConfig.ClientCAs = CAs
+	}
+	return &tlsConfig, nil
+}