github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/api/cidr.go (about)

     1  // Copyright 2016-2018 Authors of Cilium
     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 api
    16  
    17  import (
    18  	"net"
    19  	"strings"
    20  
    21  	"github.com/cilium/cilium/pkg/ip"
    22  	"github.com/cilium/cilium/pkg/labels"
    23  	cidrpkg "github.com/cilium/cilium/pkg/labels/cidr"
    24  )
    25  
    26  // CIDR specifies a block of IP addresses.
    27  // Example: 192.0.2.1/32
    28  type CIDR string
    29  
    30  // CIDRMatchAll is a []CIDR that matches everything
    31  var CIDRMatchAll = []CIDR{CIDR("0.0.0.0/0"), CIDR("::/0")}
    32  
    33  // MatchesAll determines whether the CIDR matches all traffic.
    34  func (c *CIDR) MatchesAll() bool {
    35  	for _, wildcard := range CIDRMatchAll {
    36  		if *c == wildcard {
    37  			return true
    38  		}
    39  	}
    40  	return false
    41  }
    42  
    43  // CIDRRule is a rule that specifies a CIDR prefix to/from which outside
    44  // communication  is allowed, along with an optional list of subnets within that
    45  // CIDR prefix to/from which outside communication is not allowed.
    46  type CIDRRule struct {
    47  	// CIDR is a CIDR prefix / IP Block.
    48  	//
    49  	Cidr CIDR `json:"cidr"`
    50  
    51  	// ExceptCIDRs is a list of IP blocks which the endpoint subject to the rule
    52  	// is not allowed to initiate connections to. These CIDR prefixes should be
    53  	// contained within Cidr. These exceptions are only applied to the Cidr in
    54  	// this CIDRRule, and do not apply to any other CIDR prefixes in any other
    55  	// CIDRRules.
    56  	//
    57  	// +optional
    58  	ExceptCIDRs []CIDR `json:"except,omitempty"`
    59  
    60  	// Generated indicates whether the rule was generated based on other rules
    61  	// or provided by user
    62  	Generated bool `json:"-"`
    63  }
    64  
    65  // String converts the CIDRRule into a human-readable string.
    66  func (r CIDRRule) String() string {
    67  	exceptCIDRs := ""
    68  	if len(r.ExceptCIDRs) > 0 {
    69  		exceptCIDRs = "-" + CIDRSlice(r.ExceptCIDRs).String()
    70  	}
    71  	return string(r.Cidr) + exceptCIDRs
    72  }
    73  
    74  // CIDRSlice is a slice of CIDRs. It allows receiver methods to be defined for
    75  // transforming the slice into other convenient forms such as
    76  // EndpointSelectorSlice.
    77  type CIDRSlice []CIDR
    78  
    79  // GetAsEndpointSelectors returns the provided CIDR slice as a slice of
    80  // endpoint selectors
    81  func (s CIDRSlice) GetAsEndpointSelectors() EndpointSelectorSlice {
    82  	// If multiple CIDRs representing reserved:world are in this CIDRSlice,
    83  	// we only have to add the EndpointSelector representing reserved:world
    84  	// once.
    85  	var hasWorldBeenAdded bool
    86  	slice := EndpointSelectorSlice{}
    87  	for _, cidr := range s {
    88  		if cidr.MatchesAll() && !hasWorldBeenAdded {
    89  			hasWorldBeenAdded = true
    90  			slice = append(slice, ReservedEndpointSelectors[labels.IDNameWorld])
    91  		}
    92  		lbl, err := cidrpkg.IPStringToLabel(string(cidr))
    93  		if err == nil {
    94  			slice = append(slice, NewESFromLabels(lbl))
    95  		}
    96  		// TODO: Log the error?
    97  	}
    98  
    99  	return slice
   100  }
   101  
   102  // StringSlice returns the CIDR slice as a slice of strings.
   103  func (s CIDRSlice) StringSlice() []string {
   104  	result := make([]string, 0, len(s))
   105  	for _, c := range s {
   106  		result = append(result, string(c))
   107  	}
   108  	return result
   109  }
   110  
   111  // String converts the CIDRSlice into a human-readable string.
   112  func (s CIDRSlice) String() string {
   113  	if len(s) == 0 {
   114  		return ""
   115  	}
   116  	return "[" + strings.Join(s.StringSlice(), ",") + "]"
   117  }
   118  
   119  // CIDRRuleSlice is a slice of CIDRRules. It allows receiver methods to be
   120  // defined for transforming the slice into other convenient forms such as
   121  // EndpointSelectorSlice.
   122  type CIDRRuleSlice []CIDRRule
   123  
   124  // GetAsEndpointSelectors returns the provided CIDRRule slice as a slice of
   125  // endpoint selectors
   126  func (s CIDRRuleSlice) GetAsEndpointSelectors() EndpointSelectorSlice {
   127  	cidrs := ComputeResultantCIDRSet(s)
   128  	return cidrs.GetAsEndpointSelectors()
   129  }
   130  
   131  // StringSlice returns the CIDRRuleSlice as a slice of strings.
   132  func (s CIDRRuleSlice) StringSlice() []string {
   133  	result := make([]string, 0, len(s))
   134  	for _, c := range s {
   135  		result = append(result, c.String())
   136  	}
   137  	return result
   138  }
   139  
   140  // ComputeResultantCIDRSet converts a slice of CIDRRules into a slice of
   141  // individual CIDRs. This expands the cidr defined by each CIDRRule, applies
   142  // the CIDR exceptions defined in "ExceptCIDRs", and forms a minimal set of
   143  // CIDRs that cover all of the CIDRRules.
   144  //
   145  // Assumes no error checking is necessary as CIDRRule.Sanitize already does this.
   146  func ComputeResultantCIDRSet(cidrs CIDRRuleSlice) CIDRSlice {
   147  	var allResultantAllowedCIDRs CIDRSlice
   148  	for _, s := range cidrs {
   149  		_, allowNet, _ := net.ParseCIDR(string(s.Cidr))
   150  
   151  		var removeSubnets []*net.IPNet
   152  		for _, t := range s.ExceptCIDRs {
   153  			_, removeSubnet, _ := net.ParseCIDR(string(t))
   154  			removeSubnets = append(removeSubnets, removeSubnet)
   155  		}
   156  		resultantAllowedCIDRs, _ := ip.RemoveCIDRs([]*net.IPNet{allowNet}, removeSubnets)
   157  
   158  		for _, u := range resultantAllowedCIDRs {
   159  			allResultantAllowedCIDRs = append(allResultantAllowedCIDRs, CIDR(u.String()))
   160  		}
   161  	}
   162  	return allResultantAllowedCIDRs
   163  }
   164  
   165  // IPsToCIDRRules generates CIDRRules for the IPs passed in./
   166  // This function will mark the rule to Generated true by default.
   167  func IPsToCIDRRules(ips []net.IP) (cidrRules []CIDRRule) {
   168  	for _, ip := range ips {
   169  		rule := CIDRRule{ExceptCIDRs: make([]CIDR, 0)}
   170  		rule.Generated = true
   171  		if ip.To4() != nil {
   172  			rule.Cidr = CIDR(ip.String() + "/32")
   173  		} else {
   174  			rule.Cidr = CIDR(ip.String() + "/128")
   175  		}
   176  		cidrRules = append(cidrRules, rule)
   177  	}
   178  	return cidrRules
   179  }