github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/common/networking/ports.go (about)

     1  // Copyright 2016 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package networking
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  
    21  	"github.com/appc/spec/schema"
    22  	"github.com/appc/spec/schema/types"
    23  )
    24  
    25  // ForwardedPort describes a port that will be
    26  // forwarded (mapped) from the host to the pod
    27  type ForwardedPort struct {
    28  	PodPort  types.Port
    29  	HostPort types.ExposedPort
    30  }
    31  
    32  // findAppPort looks through the manifest to find a port with a given name.
    33  // If multiple apps expose the same port name, it will fail
    34  func findAppPort(manifest *schema.PodManifest, portName types.ACName) (*types.Port, error) {
    35  	var foundPort *types.Port
    36  
    37  	for _, app := range manifest.Apps {
    38  		for _, port := range app.App.Ports {
    39  			if portName == port.Name {
    40  				if foundPort != nil { // error: ambiguous
    41  					return nil, fmt.Errorf("port name %q defined multiple apps", portName)
    42  				}
    43  				p := port // duplicate b/c port gets overwritten
    44  				foundPort = &p
    45  			}
    46  		}
    47  	}
    48  	return foundPort, nil
    49  }
    50  
    51  // ForwardedPorts matches up ExposedPorts (host ports) with Ports on the app side.
    52  // By default, it tries to match up by name - apps expose ports, and the podspec
    53  // maps them. The podspec can also map from host to pod, without a corresponding app
    54  // (which is needed for CRI)
    55  // This will error if:
    56  // - a name is ambiguous
    57  // - the same port:proto combination is forwarded
    58  func ForwardedPorts(manifest *schema.PodManifest) ([]ForwardedPort, error) {
    59  	var fps []ForwardedPort
    60  	var err error
    61  
    62  	// For every ExposedPort, find its corresponding PodPort
    63  	for _, ep := range manifest.Ports {
    64  		podPort := ep.PodPort
    65  
    66  		// If there is no direct mapping, search for the port by name
    67  		if podPort == nil {
    68  			podPort, err = findAppPort(manifest, ep.Name)
    69  			if err != nil {
    70  				return nil, err
    71  			}
    72  			if podPort == nil {
    73  				return nil, fmt.Errorf("port name %q could not be found in any apps", ep.Name)
    74  			}
    75  		}
    76  		fp := ForwardedPort{
    77  			HostPort: ep,
    78  			PodPort:  *podPort,
    79  		}
    80  		fp.HostPort.PodPort = &fp.PodPort
    81  		if fp.HostPort.HostIP == nil {
    82  			fp.HostPort.HostIP = net.IPv4(0, 0, 0, 0)
    83  		}
    84  
    85  		// Check all already-existing ports for conflicts
    86  		for idx := range fps {
    87  			if fp.conflicts(&fps[idx]) {
    88  				return nil, fmt.Errorf("port %s-%s:%d already mapped to pod port %d",
    89  					fp.PodPort.Protocol, fp.HostPort.HostIP.String(), fp.HostPort.HostPort, fps[idx].PodPort.Port)
    90  			}
    91  		}
    92  
    93  		fps = append(fps, fp)
    94  	}
    95  	return fps, nil
    96  }
    97  
    98  // conflicts checks if two ports conflict with each other
    99  func (fp *ForwardedPort) conflicts(fp1 *ForwardedPort) bool {
   100  	if fp.PodPort.Protocol != fp1.PodPort.Protocol {
   101  		return false
   102  	}
   103  
   104  	if fp.HostPort.HostPort != fp1.HostPort.HostPort {
   105  		return false
   106  	}
   107  
   108  	// If either port has the 0.0.0.0 address, they conflict
   109  	zeroAddr := net.IPv4(0, 0, 0, 0)
   110  	if fp.HostPort.HostIP.Equal(zeroAddr) || fp1.HostPort.HostIP.Equal(zeroAddr) {
   111  		return true
   112  	}
   113  
   114  	if fp.HostPort.HostIP.Equal(fp1.HostPort.HostIP) {
   115  		return true
   116  	}
   117  
   118  	return false
   119  }