github.com/elfadel/cilium@v1.6.12/pkg/fqdn/helpers.go (about)

     1  // Copyright 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 fqdn
    16  
    17  import (
    18  	"net"
    19  	"regexp"
    20  	"strings"
    21  
    22  	"github.com/cilium/cilium/pkg/fqdn/matchpattern"
    23  	"github.com/cilium/cilium/pkg/ip"
    24  	"github.com/cilium/cilium/pkg/policy/api"
    25  	"github.com/miekg/dns"
    26  	"github.com/sirupsen/logrus"
    27  )
    28  
    29  // mapSelectorsToIPs iterates through a set of FQDNSelectors and evalutes whether
    30  // they match the DNS Names in the cache. If so, the set of IPs which the cache
    31  // maintains as mapping to each DNS Name are mapped to the matching FQDNSelector.
    32  // Returns the mapping of DNSName to set of IPs which back said DNS name, the
    33  // set of FQDNSelectors which do not map to any IPs, and the set of
    34  // FQDNSelectors mapping to a set of IPs.
    35  func mapSelectorsToIPs(fqdnSelectors map[api.FQDNSelector]struct{}, cache *DNSCache) (selectorsMissingIPs []api.FQDNSelector, selectorIPMapping map[api.FQDNSelector][]net.IP) {
    36  	missing := make(map[api.FQDNSelector]struct{}) // a set to dedup missing dnsNames
    37  	selectorIPMapping = make(map[api.FQDNSelector][]net.IP)
    38  
    39  	log.WithField("fqdnSelectors", fqdnSelectors).Debug("mapSelectorsToIPs")
    40  
    41  	// Map each FQDNSelector to set of CIDRs
    42  	for ToFQDN := range fqdnSelectors {
    43  		ipsSelected := make([]net.IP, 0)
    44  		// lookup matching DNS names
    45  		if len(ToFQDN.MatchName) > 0 {
    46  			dnsName := prepareMatchName(ToFQDN.MatchName)
    47  			lookupIPs := cache.Lookup(dnsName)
    48  
    49  			// Mark this FQDNSelector as having no IPs corresponding to it.
    50  			// FQDNSelectors are guaranteed to have only their MatchName OR
    51  			// their MatchPattern set (having both set is invalid per
    52  			// sanitization of FQDNSelectors).
    53  			if len(lookupIPs) == 0 {
    54  				missing[ToFQDN] = struct{}{}
    55  			}
    56  
    57  			log.WithFields(logrus.Fields{
    58  				"DNSName":   dnsName,
    59  				"IPs":       lookupIPs,
    60  				"matchName": ToFQDN.MatchName,
    61  			}).Debug("Emitting matching DNS Name -> IPs for FQDNSelector")
    62  			ipsSelected = append(ipsSelected, lookupIPs...)
    63  		}
    64  
    65  		if len(ToFQDN.MatchPattern) > 0 {
    66  			// lookup matching DNS names
    67  			dnsPattern := matchpattern.Sanitize(ToFQDN.MatchPattern)
    68  			patternREStr := matchpattern.ToRegexp(dnsPattern)
    69  			var (
    70  				err       error
    71  				patternRE *regexp.Regexp
    72  			)
    73  
    74  			if patternRE, err = regexp.Compile(patternREStr); err != nil {
    75  				log.WithError(err).Error("Error compiling matchPattern")
    76  			}
    77  			lookupIPs := cache.LookupByRegexp(patternRE)
    78  
    79  			// Mark this pattern missing; it will be unmarked in the loop below
    80  			missing[ToFQDN] = struct{}{}
    81  
    82  			for name, ips := range lookupIPs {
    83  				if len(ips) > 0 {
    84  					log.WithFields(logrus.Fields{
    85  						"DNSName":      name,
    86  						"IPs":          ips,
    87  						"matchPattern": ToFQDN.MatchPattern,
    88  					}).Debug("Emitting matching DNS Name -> IPs for FQDNSelector")
    89  					delete(missing, ToFQDN)
    90  					ipsSelected = append(ipsSelected, ips...)
    91  				}
    92  			}
    93  		}
    94  
    95  		ips := ip.KeepUniqueIPs(ipsSelected)
    96  		if len(ips) > 0 {
    97  			selectorIPMapping[ToFQDN] = ips
    98  		}
    99  	}
   100  
   101  	for dnsName := range missing {
   102  		selectorsMissingIPs = append(selectorsMissingIPs, dnsName)
   103  	}
   104  	return selectorsMissingIPs, selectorIPMapping
   105  }
   106  
   107  // sortedIPsAreEqual compares two lists of sorted IPs. If any differ it returns
   108  // false.
   109  func sortedIPsAreEqual(a, b []net.IP) bool {
   110  	// the IP set is definitely different if the lengths are different
   111  	if len(a) != len(b) {
   112  		return false
   113  	}
   114  
   115  	// lengths are equal, so each member in one set must be in the other
   116  	// Note: we sorted fullNewIPs above, and sorted oldIPs when they were
   117  	// inserted in this function, previously.
   118  	// If any IPs at the same index differ, updated = true.
   119  	for i := range a {
   120  		if !a[i].Equal(b[i]) {
   121  			return false
   122  		}
   123  	}
   124  	return true
   125  }
   126  
   127  // prepareMatchName ensures a ToFQDNs.matchName field is used consistently.
   128  func prepareMatchName(matchName string) string {
   129  	return strings.ToLower(dns.Fqdn(matchName))
   130  }
   131  
   132  // KeepUniqueNames it gets a array of strings and return a new array of strings
   133  // with the unique names.
   134  func KeepUniqueNames(names []string) []string {
   135  	result := []string{}
   136  	entries := map[string]bool{}
   137  
   138  	for _, item := range names {
   139  		if _, ok := entries[item]; ok {
   140  			continue
   141  		}
   142  		entries[item] = true
   143  		result = append(result, item)
   144  	}
   145  	return result
   146  }