Parcourir la source

Prevent dynamic allocation of previously allocated ports

Docker-DCO-1.1-Signed-off-by: Andy Kipp <andy@rstudio.com> (github: kippandrew)
Andy Kipp il y a 11 ans
Parent
commit
f7b6fbbd76

+ 25 - 7
runtime/networkdriver/portallocator/portallocator.go

@@ -100,22 +100,30 @@ func ReleaseAll() error {
 }
 
 func registerDynamicPort(ip net.IP, proto string) (int, error) {
-	allocated := defaultAllocatedPorts[proto]
-
-	port := nextPort(proto)
-	if port > EndPortRange {
-		return 0, ErrPortExceedsRange
-	}
 
 	if !equalsDefault(ip) {
 		registerIP(ip)
 
 		ipAllocated := otherAllocatedPorts[ip.String()][proto]
+
+		port, err := findNextPort(proto, ipAllocated)
+		if err != nil {
+			return 0, err
+		}
 		ipAllocated.Push(port)
+		return port, nil
+
 	} else {
+
+		allocated := defaultAllocatedPorts[proto]
+
+		port, err := findNextPort(proto, allocated)
+		if err != nil {
+			return 0, err
+		}
 		allocated.Push(port)
+		return port, nil
 	}
-	return port, nil
 }
 
 func registerSetPort(ip net.IP, proto string, port int) error {
@@ -142,6 +150,16 @@ func equalsDefault(ip net.IP) bool {
 	return ip == nil || ip.Equal(defaultIP)
 }
 
+func findNextPort(proto string, allocated *collections.OrderedIntSet) (int, error) {
+	port := 0
+	for port = nextPort(proto); allocated.Exists(port); port = nextPort(proto) {
+	}
+	if port > EndPortRange {
+		return 0, ErrPortExceedsRange
+	}
+	return port, nil
+}
+
 func nextPort(proto string) int {
 	c := currentDynamicPort[proto] + 1
 	currentDynamicPort[proto] = c

+ 7 - 0
runtime/networkdriver/portallocator/portallocator_test.go

@@ -181,4 +181,11 @@ func TestPortAllocation(t *testing.T) {
 	if _, err := RequestPort(ip, "tcp", 80); err != nil {
 		t.Fatal(err)
 	}
+
+	port, err = RequestPort(ip, "tcp", 0)
+	port2, err := RequestPort(ip, "tcp", port+1)
+	port3, err := RequestPort(ip, "tcp", 0)
+	if port3 == port2 {
+		t.Fatal("A dynamic port should never allocate a used port")
+	}
 }