From 49424fc02aaa3fa7d233e011d0e5f2589d2e09ac Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Fri, 16 Oct 2020 10:57:29 +0200 Subject: Fix host to container port mapping for simple ranges This fixes the issue that a simple port range should map to a random port range from the host to the container, if no host port range is specified. For example this fails without applying the patch: ``` > podman run -it -p 6000-6066 alpine Error: cannot listen on the TCP port: listen tcp4 :53: bind: address already in use ``` The issue is that only the first port is randomly chosen and all following in the range start by 0 and increment. This is now fixed by tracking the ranges and then incrementing the random port if necessary. Signed-off-by: Sascha Grunert --- pkg/specgen/generate/ports.go | 46 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'pkg') diff --git a/pkg/specgen/generate/ports.go b/pkg/specgen/generate/ports.go index 7dd50ac0d..5c13c95b2 100644 --- a/pkg/specgen/generate/ports.go +++ b/pkg/specgen/generate/ports.go @@ -25,7 +25,12 @@ const ( func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping, map[string]map[string]map[uint16]uint16, map[string]map[string]map[uint16]uint16, error) { // First, we need to validate the ports passed in the specgen, and then // convert them into CNI port mappings. - finalMappings := []ocicni.PortMapping{} + type tempMapping struct { + mapping ocicni.PortMapping + startOfRange bool + isInRange bool + } + tempMappings := []tempMapping{} // To validate, we need two maps: one for host ports, one for container // ports. @@ -153,18 +158,32 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping, Protocol: p, HostIP: port.HostIP, } - finalMappings = append(finalMappings, cniPort) + tempMappings = append( + tempMappings, + tempMapping{ + mapping: cniPort, + startOfRange: port.Range > 0 && index == 0, + isInRange: port.Range > 0, + }, + ) } } } // Handle any 0 host ports now by setting random container ports. if postAssignHostPort { - remadeMappings := make([]ocicni.PortMapping, 0, len(finalMappings)) + remadeMappings := make([]ocicni.PortMapping, 0, len(tempMappings)) + + var ( + candidate int + err error + ) // Iterate over all - for _, p := range finalMappings { - if p.HostPort != 0 { + for _, tmp := range tempMappings { + p := tmp.mapping + + if p.HostPort != 0 && !tmp.isInRange { remadeMappings = append(remadeMappings, p) continue } @@ -192,9 +211,15 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping, // Max retries to ensure we don't loop forever. for i := 0; i < 15; i++ { - candidate, err := getRandomPort() - if err != nil { - return nil, nil, nil, errors.Wrapf(err, "error getting candidate host port for container port %d", p.ContainerPort) + // Only get a random candidate for single entries or the start + // of a range. Otherwise we just increment the candidate. + if !tmp.isInRange || tmp.startOfRange { + candidate, err = getRandomPort() + if err != nil { + return nil, nil, nil, errors.Wrapf(err, "error getting candidate host port for container port %d", p.ContainerPort) + } + } else { + candidate++ } if hostPortMap[uint16(candidate)] == 0 { @@ -213,6 +238,11 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping, return remadeMappings, containerPortValidate, hostPortValidate, nil } + finalMappings := []ocicni.PortMapping{} + for _, m := range tempMappings { + finalMappings = append(finalMappings, m.mapping) + } + return finalMappings, containerPortValidate, hostPortValidate, nil } -- cgit v1.2.3-54-g00ecf