aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSascha Grunert <sgrunert@suse.com>2020-10-16 10:57:29 +0200
committerSascha Grunert <sgrunert@suse.com>2020-10-19 11:19:12 +0200
commit49424fc02aaa3fa7d233e011d0e5f2589d2e09ac (patch)
tree0c9cec89f0466b31097b29c2153c510e1f4d2ca2
parentc3ecdd09ed6a9b17da9879d7f2765a6f5f3ace8a (diff)
downloadpodman-49424fc02aaa3fa7d233e011d0e5f2589d2e09ac.tar.gz
podman-49424fc02aaa3fa7d233e011d0e5f2589d2e09ac.tar.bz2
podman-49424fc02aaa3fa7d233e011d0e5f2589d2e09ac.zip
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 <sgrunert@suse.com>
-rw-r--r--pkg/specgen/generate/ports.go46
1 files changed, 38 insertions, 8 deletions
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
}