github.com/slackhq/nebula@v1.9.0/remote_list.go (about)

     1  package nebula
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"net"
     7  	"net/netip"
     8  	"sort"
     9  	"strconv"
    10  	"sync"
    11  	"sync/atomic"
    12  	"time"
    13  
    14  	"github.com/sirupsen/logrus"
    15  	"github.com/slackhq/nebula/iputil"
    16  	"github.com/slackhq/nebula/udp"
    17  )
    18  
    19  // forEachFunc is used to benefit folks that want to do work inside the lock
    20  type forEachFunc func(addr *udp.Addr, preferred bool)
    21  
    22  // The checkFuncs here are to simplify bulk importing LH query response logic into a single function (reset slice and iterate)
    23  type checkFuncV4 func(vpnIp iputil.VpnIp, to *Ip4AndPort) bool
    24  type checkFuncV6 func(vpnIp iputil.VpnIp, to *Ip6AndPort) bool
    25  
    26  // CacheMap is a struct that better represents the lighthouse cache for humans
    27  // The string key is the owners vpnIp
    28  type CacheMap map[string]*Cache
    29  
    30  // Cache is the other part of CacheMap to better represent the lighthouse cache for humans
    31  // We don't reason about ipv4 vs ipv6 here
    32  type Cache struct {
    33  	Learned  []*udp.Addr `json:"learned,omitempty"`
    34  	Reported []*udp.Addr `json:"reported,omitempty"`
    35  	Relay    []*net.IP   `json:"relay"`
    36  }
    37  
    38  //TODO: Seems like we should plop static host entries in here too since the are protected by the lighthouse from deletion
    39  // We will never clean learned/reported information for them as it stands today
    40  
    41  // cache is an internal struct that splits v4 and v6 addresses inside the cache map
    42  type cache struct {
    43  	v4    *cacheV4
    44  	v6    *cacheV6
    45  	relay *cacheRelay
    46  }
    47  
    48  type cacheRelay struct {
    49  	relay []uint32
    50  }
    51  
    52  // cacheV4 stores learned and reported ipv4 records under cache
    53  type cacheV4 struct {
    54  	learned  *Ip4AndPort
    55  	reported []*Ip4AndPort
    56  }
    57  
    58  // cacheV4 stores learned and reported ipv6 records under cache
    59  type cacheV6 struct {
    60  	learned  *Ip6AndPort
    61  	reported []*Ip6AndPort
    62  }
    63  
    64  type hostnamePort struct {
    65  	name string
    66  	port uint16
    67  }
    68  
    69  type hostnamesResults struct {
    70  	hostnames     []hostnamePort
    71  	network       string
    72  	lookupTimeout time.Duration
    73  	cancelFn      func()
    74  	l             *logrus.Logger
    75  	ips           atomic.Pointer[map[netip.AddrPort]struct{}]
    76  }
    77  
    78  func NewHostnameResults(ctx context.Context, l *logrus.Logger, d time.Duration, network string, timeout time.Duration, hostPorts []string, onUpdate func()) (*hostnamesResults, error) {
    79  	r := &hostnamesResults{
    80  		hostnames:     make([]hostnamePort, len(hostPorts)),
    81  		network:       network,
    82  		lookupTimeout: timeout,
    83  		l:             l,
    84  	}
    85  
    86  	// Fastrack IP addresses to ensure they're immediately available for use.
    87  	// DNS lookups for hostnames that aren't hardcoded IP's will happen in a background goroutine.
    88  	performBackgroundLookup := false
    89  	ips := map[netip.AddrPort]struct{}{}
    90  	for idx, hostPort := range hostPorts {
    91  
    92  		rIp, sPort, err := net.SplitHostPort(hostPort)
    93  		if err != nil {
    94  			return nil, err
    95  		}
    96  
    97  		iPort, err := strconv.Atoi(sPort)
    98  		if err != nil {
    99  			return nil, err
   100  		}
   101  
   102  		r.hostnames[idx] = hostnamePort{name: rIp, port: uint16(iPort)}
   103  		addr, err := netip.ParseAddr(rIp)
   104  		if err != nil {
   105  			// This address is a hostname, not an IP address
   106  			performBackgroundLookup = true
   107  			continue
   108  		}
   109  
   110  		// Save the IP address immediately
   111  		ips[netip.AddrPortFrom(addr, uint16(iPort))] = struct{}{}
   112  	}
   113  	r.ips.Store(&ips)
   114  
   115  	// Time for the DNS lookup goroutine
   116  	if performBackgroundLookup {
   117  		newCtx, cancel := context.WithCancel(ctx)
   118  		r.cancelFn = cancel
   119  		ticker := time.NewTicker(d)
   120  		go func() {
   121  			defer ticker.Stop()
   122  			for {
   123  				netipAddrs := map[netip.AddrPort]struct{}{}
   124  				for _, hostPort := range r.hostnames {
   125  					timeoutCtx, timeoutCancel := context.WithTimeout(ctx, r.lookupTimeout)
   126  					addrs, err := net.DefaultResolver.LookupNetIP(timeoutCtx, r.network, hostPort.name)
   127  					timeoutCancel()
   128  					if err != nil {
   129  						l.WithFields(logrus.Fields{"hostname": hostPort.name, "network": r.network}).WithError(err).Error("DNS resolution failed for static_map host")
   130  						continue
   131  					}
   132  					for _, a := range addrs {
   133  						netipAddrs[netip.AddrPortFrom(a, hostPort.port)] = struct{}{}
   134  					}
   135  				}
   136  				origSet := r.ips.Load()
   137  				different := false
   138  				for a := range *origSet {
   139  					if _, ok := netipAddrs[a]; !ok {
   140  						different = true
   141  						break
   142  					}
   143  				}
   144  				if !different {
   145  					for a := range netipAddrs {
   146  						if _, ok := (*origSet)[a]; !ok {
   147  							different = true
   148  							break
   149  						}
   150  					}
   151  				}
   152  				if different {
   153  					l.WithFields(logrus.Fields{"origSet": origSet, "newSet": netipAddrs}).Info("DNS results changed for host list")
   154  					r.ips.Store(&netipAddrs)
   155  					onUpdate()
   156  				}
   157  				select {
   158  				case <-newCtx.Done():
   159  					return
   160  				case <-ticker.C:
   161  					continue
   162  				}
   163  			}
   164  		}()
   165  	}
   166  
   167  	return r, nil
   168  }
   169  
   170  func (hr *hostnamesResults) Cancel() {
   171  	if hr != nil && hr.cancelFn != nil {
   172  		hr.cancelFn()
   173  	}
   174  }
   175  
   176  func (hr *hostnamesResults) GetIPs() []netip.AddrPort {
   177  	var retSlice []netip.AddrPort
   178  	if hr != nil {
   179  		p := hr.ips.Load()
   180  		if p != nil {
   181  			for k := range *p {
   182  				retSlice = append(retSlice, k)
   183  			}
   184  		}
   185  	}
   186  	return retSlice
   187  }
   188  
   189  // RemoteList is a unifying concept for lighthouse servers and clients as well as hostinfos.
   190  // It serves as a local cache of query replies, host update notifications, and locally learned addresses
   191  type RemoteList struct {
   192  	// Every interaction with internals requires a lock!
   193  	sync.RWMutex
   194  
   195  	// A deduplicated set of addresses. Any accessor should lock beforehand.
   196  	addrs []*udp.Addr
   197  
   198  	// A set of relay addresses. VpnIp addresses that the remote identified as relays.
   199  	relays []*iputil.VpnIp
   200  
   201  	// These are maps to store v4 and v6 addresses per lighthouse
   202  	// Map key is the vpnIp of the person that told us about this the cached entries underneath.
   203  	// For learned addresses, this is the vpnIp that sent the packet
   204  	cache map[iputil.VpnIp]*cache
   205  
   206  	hr        *hostnamesResults
   207  	shouldAdd func(netip.Addr) bool
   208  
   209  	// This is a list of remotes that we have tried to handshake with and have returned from the wrong vpn ip.
   210  	// They should not be tried again during a handshake
   211  	badRemotes []*udp.Addr
   212  
   213  	// A flag that the cache may have changed and addrs needs to be rebuilt
   214  	shouldRebuild bool
   215  }
   216  
   217  // NewRemoteList creates a new empty RemoteList
   218  func NewRemoteList(shouldAdd func(netip.Addr) bool) *RemoteList {
   219  	return &RemoteList{
   220  		addrs:     make([]*udp.Addr, 0),
   221  		relays:    make([]*iputil.VpnIp, 0),
   222  		cache:     make(map[iputil.VpnIp]*cache),
   223  		shouldAdd: shouldAdd,
   224  	}
   225  }
   226  
   227  func (r *RemoteList) unlockedSetHostnamesResults(hr *hostnamesResults) {
   228  	// Cancel any existing hostnamesResults DNS goroutine to release resources
   229  	r.hr.Cancel()
   230  	r.hr = hr
   231  }
   232  
   233  // Len locks and reports the size of the deduplicated address list
   234  // The deduplication work may need to occur here, so you must pass preferredRanges
   235  func (r *RemoteList) Len(preferredRanges []*net.IPNet) int {
   236  	r.Rebuild(preferredRanges)
   237  	r.RLock()
   238  	defer r.RUnlock()
   239  	return len(r.addrs)
   240  }
   241  
   242  // ForEach locks and will call the forEachFunc for every deduplicated address in the list
   243  // The deduplication work may need to occur here, so you must pass preferredRanges
   244  func (r *RemoteList) ForEach(preferredRanges []*net.IPNet, forEach forEachFunc) {
   245  	r.Rebuild(preferredRanges)
   246  	r.RLock()
   247  	for _, v := range r.addrs {
   248  		forEach(v, isPreferred(v.IP, preferredRanges))
   249  	}
   250  	r.RUnlock()
   251  }
   252  
   253  // CopyAddrs locks and makes a deep copy of the deduplicated address list
   254  // The deduplication work may need to occur here, so you must pass preferredRanges
   255  func (r *RemoteList) CopyAddrs(preferredRanges []*net.IPNet) []*udp.Addr {
   256  	if r == nil {
   257  		return nil
   258  	}
   259  
   260  	r.Rebuild(preferredRanges)
   261  
   262  	r.RLock()
   263  	defer r.RUnlock()
   264  	c := make([]*udp.Addr, len(r.addrs))
   265  	for i, v := range r.addrs {
   266  		c[i] = v.Copy()
   267  	}
   268  	return c
   269  }
   270  
   271  // LearnRemote locks and sets the learned slot for the owner vpn ip to the provided addr
   272  // Currently this is only needed when HostInfo.SetRemote is called as that should cover both handshaking and roaming.
   273  // It will mark the deduplicated address list as dirty, so do not call it unless new information is available
   274  // TODO: this needs to support the allow list list
   275  func (r *RemoteList) LearnRemote(ownerVpnIp iputil.VpnIp, addr *udp.Addr) {
   276  	r.Lock()
   277  	defer r.Unlock()
   278  	if v4 := addr.IP.To4(); v4 != nil {
   279  		r.unlockedSetLearnedV4(ownerVpnIp, NewIp4AndPort(v4, uint32(addr.Port)))
   280  	} else {
   281  		r.unlockedSetLearnedV6(ownerVpnIp, NewIp6AndPort(addr.IP, uint32(addr.Port)))
   282  	}
   283  }
   284  
   285  // CopyCache locks and creates a more human friendly form of the internal address cache.
   286  // This may contain duplicates and blocked addresses
   287  func (r *RemoteList) CopyCache() *CacheMap {
   288  	r.RLock()
   289  	defer r.RUnlock()
   290  
   291  	cm := make(CacheMap)
   292  	getOrMake := func(vpnIp string) *Cache {
   293  		c := cm[vpnIp]
   294  		if c == nil {
   295  			c = &Cache{
   296  				Learned:  make([]*udp.Addr, 0),
   297  				Reported: make([]*udp.Addr, 0),
   298  				Relay:    make([]*net.IP, 0),
   299  			}
   300  			cm[vpnIp] = c
   301  		}
   302  		return c
   303  	}
   304  
   305  	for owner, mc := range r.cache {
   306  		c := getOrMake(owner.String())
   307  
   308  		if mc.v4 != nil {
   309  			if mc.v4.learned != nil {
   310  				c.Learned = append(c.Learned, NewUDPAddrFromLH4(mc.v4.learned))
   311  			}
   312  
   313  			for _, a := range mc.v4.reported {
   314  				c.Reported = append(c.Reported, NewUDPAddrFromLH4(a))
   315  			}
   316  		}
   317  
   318  		if mc.v6 != nil {
   319  			if mc.v6.learned != nil {
   320  				c.Learned = append(c.Learned, NewUDPAddrFromLH6(mc.v6.learned))
   321  			}
   322  
   323  			for _, a := range mc.v6.reported {
   324  				c.Reported = append(c.Reported, NewUDPAddrFromLH6(a))
   325  			}
   326  		}
   327  
   328  		if mc.relay != nil {
   329  			for _, a := range mc.relay.relay {
   330  				nip := iputil.VpnIp(a).ToIP()
   331  				c.Relay = append(c.Relay, &nip)
   332  			}
   333  		}
   334  	}
   335  
   336  	return &cm
   337  }
   338  
   339  // BlockRemote locks and records the address as bad, it will be excluded from the deduplicated address list
   340  func (r *RemoteList) BlockRemote(bad *udp.Addr) {
   341  	if bad == nil {
   342  		// relays can have nil udp Addrs
   343  		return
   344  	}
   345  	r.Lock()
   346  	defer r.Unlock()
   347  
   348  	// Check if we already blocked this addr
   349  	if r.unlockedIsBad(bad) {
   350  		return
   351  	}
   352  
   353  	// We copy here because we are taking something else's memory and we can't trust everything
   354  	r.badRemotes = append(r.badRemotes, bad.Copy())
   355  
   356  	// Mark the next interaction must recollect/dedupe
   357  	r.shouldRebuild = true
   358  }
   359  
   360  // CopyBlockedRemotes locks and makes a deep copy of the blocked remotes list
   361  func (r *RemoteList) CopyBlockedRemotes() []*udp.Addr {
   362  	r.RLock()
   363  	defer r.RUnlock()
   364  
   365  	c := make([]*udp.Addr, len(r.badRemotes))
   366  	for i, v := range r.badRemotes {
   367  		c[i] = v.Copy()
   368  	}
   369  	return c
   370  }
   371  
   372  // ResetBlockedRemotes locks and clears the blocked remotes list
   373  func (r *RemoteList) ResetBlockedRemotes() {
   374  	r.Lock()
   375  	r.badRemotes = nil
   376  	r.Unlock()
   377  }
   378  
   379  // Rebuild locks and generates the deduplicated address list only if there is work to be done
   380  // There is generally no reason to call this directly but it is safe to do so
   381  func (r *RemoteList) Rebuild(preferredRanges []*net.IPNet) {
   382  	r.Lock()
   383  	defer r.Unlock()
   384  
   385  	// Only rebuild if the cache changed
   386  	//TODO: shouldRebuild is probably pointless as we don't check for actual change when lighthouse updates come in
   387  	if r.shouldRebuild {
   388  		r.unlockedCollect()
   389  		r.shouldRebuild = false
   390  	}
   391  
   392  	// Always re-sort, preferredRanges can change via HUP
   393  	r.unlockedSort(preferredRanges)
   394  }
   395  
   396  // unlockedIsBad assumes you have the write lock and checks if the remote matches any entry in the blocked address list
   397  func (r *RemoteList) unlockedIsBad(remote *udp.Addr) bool {
   398  	for _, v := range r.badRemotes {
   399  		if v.Equals(remote) {
   400  			return true
   401  		}
   402  	}
   403  	return false
   404  }
   405  
   406  // unlockedSetLearnedV4 assumes you have the write lock and sets the current learned address for this owner and marks the
   407  // deduplicated address list as dirty
   408  func (r *RemoteList) unlockedSetLearnedV4(ownerVpnIp iputil.VpnIp, to *Ip4AndPort) {
   409  	r.shouldRebuild = true
   410  	r.unlockedGetOrMakeV4(ownerVpnIp).learned = to
   411  }
   412  
   413  // unlockedSetV4 assumes you have the write lock and resets the reported list of ips for this owner to the list provided
   414  // and marks the deduplicated address list as dirty
   415  func (r *RemoteList) unlockedSetV4(ownerVpnIp iputil.VpnIp, vpnIp iputil.VpnIp, to []*Ip4AndPort, check checkFuncV4) {
   416  	r.shouldRebuild = true
   417  	c := r.unlockedGetOrMakeV4(ownerVpnIp)
   418  
   419  	// Reset the slice
   420  	c.reported = c.reported[:0]
   421  
   422  	// We can't take their array but we can take their pointers
   423  	for _, v := range to[:minInt(len(to), MaxRemotes)] {
   424  		if check(vpnIp, v) {
   425  			c.reported = append(c.reported, v)
   426  		}
   427  	}
   428  }
   429  
   430  func (r *RemoteList) unlockedSetRelay(ownerVpnIp iputil.VpnIp, vpnIp iputil.VpnIp, to []uint32) {
   431  	r.shouldRebuild = true
   432  	c := r.unlockedGetOrMakeRelay(ownerVpnIp)
   433  
   434  	// Reset the slice
   435  	c.relay = c.relay[:0]
   436  
   437  	// We can't take their array but we can take their pointers
   438  	c.relay = append(c.relay, to[:minInt(len(to), MaxRemotes)]...)
   439  }
   440  
   441  // unlockedPrependV4 assumes you have the write lock and prepends the address in the reported list for this owner
   442  // This is only useful for establishing static hosts
   443  func (r *RemoteList) unlockedPrependV4(ownerVpnIp iputil.VpnIp, to *Ip4AndPort) {
   444  	r.shouldRebuild = true
   445  	c := r.unlockedGetOrMakeV4(ownerVpnIp)
   446  
   447  	// We are doing the easy append because this is rarely called
   448  	c.reported = append([]*Ip4AndPort{to}, c.reported...)
   449  	if len(c.reported) > MaxRemotes {
   450  		c.reported = c.reported[:MaxRemotes]
   451  	}
   452  }
   453  
   454  // unlockedSetLearnedV6 assumes you have the write lock and sets the current learned address for this owner and marks the
   455  // deduplicated address list as dirty
   456  func (r *RemoteList) unlockedSetLearnedV6(ownerVpnIp iputil.VpnIp, to *Ip6AndPort) {
   457  	r.shouldRebuild = true
   458  	r.unlockedGetOrMakeV6(ownerVpnIp).learned = to
   459  }
   460  
   461  // unlockedSetV6 assumes you have the write lock and resets the reported list of ips for this owner to the list provided
   462  // and marks the deduplicated address list as dirty
   463  func (r *RemoteList) unlockedSetV6(ownerVpnIp iputil.VpnIp, vpnIp iputil.VpnIp, to []*Ip6AndPort, check checkFuncV6) {
   464  	r.shouldRebuild = true
   465  	c := r.unlockedGetOrMakeV6(ownerVpnIp)
   466  
   467  	// Reset the slice
   468  	c.reported = c.reported[:0]
   469  
   470  	// We can't take their array but we can take their pointers
   471  	for _, v := range to[:minInt(len(to), MaxRemotes)] {
   472  		if check(vpnIp, v) {
   473  			c.reported = append(c.reported, v)
   474  		}
   475  	}
   476  }
   477  
   478  // unlockedPrependV6 assumes you have the write lock and prepends the address in the reported list for this owner
   479  // This is only useful for establishing static hosts
   480  func (r *RemoteList) unlockedPrependV6(ownerVpnIp iputil.VpnIp, to *Ip6AndPort) {
   481  	r.shouldRebuild = true
   482  	c := r.unlockedGetOrMakeV6(ownerVpnIp)
   483  
   484  	// We are doing the easy append because this is rarely called
   485  	c.reported = append([]*Ip6AndPort{to}, c.reported...)
   486  	if len(c.reported) > MaxRemotes {
   487  		c.reported = c.reported[:MaxRemotes]
   488  	}
   489  }
   490  
   491  func (r *RemoteList) unlockedGetOrMakeRelay(ownerVpnIp iputil.VpnIp) *cacheRelay {
   492  	am := r.cache[ownerVpnIp]
   493  	if am == nil {
   494  		am = &cache{}
   495  		r.cache[ownerVpnIp] = am
   496  	}
   497  	// Avoid occupying memory for relay if we never have any
   498  	if am.relay == nil {
   499  		am.relay = &cacheRelay{}
   500  	}
   501  	return am.relay
   502  }
   503  
   504  // unlockedGetOrMakeV4 assumes you have the write lock and builds the cache and owner entry. Only the v4 pointer is established.
   505  // The caller must dirty the learned address cache if required
   506  func (r *RemoteList) unlockedGetOrMakeV4(ownerVpnIp iputil.VpnIp) *cacheV4 {
   507  	am := r.cache[ownerVpnIp]
   508  	if am == nil {
   509  		am = &cache{}
   510  		r.cache[ownerVpnIp] = am
   511  	}
   512  	// Avoid occupying memory for v6 addresses if we never have any
   513  	if am.v4 == nil {
   514  		am.v4 = &cacheV4{}
   515  	}
   516  	return am.v4
   517  }
   518  
   519  // unlockedGetOrMakeV6 assumes you have the write lock and builds the cache and owner entry. Only the v6 pointer is established.
   520  // The caller must dirty the learned address cache if required
   521  func (r *RemoteList) unlockedGetOrMakeV6(ownerVpnIp iputil.VpnIp) *cacheV6 {
   522  	am := r.cache[ownerVpnIp]
   523  	if am == nil {
   524  		am = &cache{}
   525  		r.cache[ownerVpnIp] = am
   526  	}
   527  	// Avoid occupying memory for v4 addresses if we never have any
   528  	if am.v6 == nil {
   529  		am.v6 = &cacheV6{}
   530  	}
   531  	return am.v6
   532  }
   533  
   534  // unlockedCollect assumes you have the write lock and collects/transforms the cache into the deduped address list.
   535  // The result of this function can contain duplicates. unlockedSort handles cleaning it.
   536  func (r *RemoteList) unlockedCollect() {
   537  	addrs := r.addrs[:0]
   538  	relays := r.relays[:0]
   539  
   540  	for _, c := range r.cache {
   541  		if c.v4 != nil {
   542  			if c.v4.learned != nil {
   543  				u := NewUDPAddrFromLH4(c.v4.learned)
   544  				if !r.unlockedIsBad(u) {
   545  					addrs = append(addrs, u)
   546  				}
   547  			}
   548  
   549  			for _, v := range c.v4.reported {
   550  				u := NewUDPAddrFromLH4(v)
   551  				if !r.unlockedIsBad(u) {
   552  					addrs = append(addrs, u)
   553  				}
   554  			}
   555  		}
   556  
   557  		if c.v6 != nil {
   558  			if c.v6.learned != nil {
   559  				u := NewUDPAddrFromLH6(c.v6.learned)
   560  				if !r.unlockedIsBad(u) {
   561  					addrs = append(addrs, u)
   562  				}
   563  			}
   564  
   565  			for _, v := range c.v6.reported {
   566  				u := NewUDPAddrFromLH6(v)
   567  				if !r.unlockedIsBad(u) {
   568  					addrs = append(addrs, u)
   569  				}
   570  			}
   571  		}
   572  
   573  		if c.relay != nil {
   574  			for _, v := range c.relay.relay {
   575  				ip := iputil.VpnIp(v)
   576  				relays = append(relays, &ip)
   577  			}
   578  		}
   579  	}
   580  
   581  	dnsAddrs := r.hr.GetIPs()
   582  	for _, addr := range dnsAddrs {
   583  		if r.shouldAdd == nil || r.shouldAdd(addr.Addr()) {
   584  			v6 := addr.Addr().As16()
   585  			addrs = append(addrs, &udp.Addr{
   586  				IP:   v6[:],
   587  				Port: addr.Port(),
   588  			})
   589  		}
   590  	}
   591  
   592  	r.addrs = addrs
   593  	r.relays = relays
   594  
   595  }
   596  
   597  // unlockedSort assumes you have the write lock and performs the deduping and sorting of the address list
   598  func (r *RemoteList) unlockedSort(preferredRanges []*net.IPNet) {
   599  	n := len(r.addrs)
   600  	if n < 2 {
   601  		return
   602  	}
   603  
   604  	lessFunc := func(i, j int) bool {
   605  		a := r.addrs[i]
   606  		b := r.addrs[j]
   607  		// Preferred addresses first
   608  
   609  		aPref := isPreferred(a.IP, preferredRanges)
   610  		bPref := isPreferred(b.IP, preferredRanges)
   611  		switch {
   612  		case aPref && !bPref:
   613  			// If i is preferred and j is not, i is less than j
   614  			return true
   615  
   616  		case !aPref && bPref:
   617  			// If j is preferred then i is not due to the else, i is not less than j
   618  			return false
   619  
   620  		default:
   621  			// Both i an j are either preferred or not, sort within that
   622  		}
   623  
   624  		// ipv6 addresses 2nd
   625  		a4 := a.IP.To4()
   626  		b4 := b.IP.To4()
   627  		switch {
   628  		case a4 == nil && b4 != nil:
   629  			// If i is v6 and j is v4, i is less than j
   630  			return true
   631  
   632  		case a4 != nil && b4 == nil:
   633  			// If j is v6 and i is v4, i is not less than j
   634  			return false
   635  
   636  		case a4 != nil && b4 != nil:
   637  			// Special case for ipv4, a4 and b4 are not nil
   638  			aPrivate := isPrivateIP(a4)
   639  			bPrivate := isPrivateIP(b4)
   640  			switch {
   641  			case !aPrivate && bPrivate:
   642  				// If i is a public ip (not private) and j is a private ip, i is less then j
   643  				return true
   644  
   645  			case aPrivate && !bPrivate:
   646  				// If j is public (not private) then i is private due to the else, i is not less than j
   647  				return false
   648  
   649  			default:
   650  				// Both i an j are either public or private, sort within that
   651  			}
   652  
   653  		default:
   654  			// Both i an j are either ipv4 or ipv6, sort within that
   655  		}
   656  
   657  		// lexical order of ips 3rd
   658  		c := bytes.Compare(a.IP, b.IP)
   659  		if c == 0 {
   660  			// Ips are the same, Lexical order of ports 4th
   661  			return a.Port < b.Port
   662  		}
   663  
   664  		// Ip wasn't the same
   665  		return c < 0
   666  	}
   667  
   668  	// Sort it
   669  	sort.Slice(r.addrs, lessFunc)
   670  
   671  	// Deduplicate
   672  	a, b := 0, 1
   673  	for b < n {
   674  		if !r.addrs[a].Equals(r.addrs[b]) {
   675  			a++
   676  			if a != b {
   677  				r.addrs[a], r.addrs[b] = r.addrs[b], r.addrs[a]
   678  			}
   679  		}
   680  		b++
   681  	}
   682  
   683  	r.addrs = r.addrs[:a+1]
   684  	return
   685  }
   686  
   687  // minInt returns the minimum integer of a or b
   688  func minInt(a, b int) int {
   689  	if a < b {
   690  		return a
   691  	}
   692  	return b
   693  }
   694  
   695  // isPreferred returns true of the ip is contained in the preferredRanges list
   696  func isPreferred(ip net.IP, preferredRanges []*net.IPNet) bool {
   697  	//TODO: this would be better in a CIDR6Tree
   698  	for _, p := range preferredRanges {
   699  		if p.Contains(ip) {
   700  			return true
   701  		}
   702  	}
   703  	return false
   704  }
   705  
   706  var _, private24BitBlock, _ = net.ParseCIDR("10.0.0.0/8")
   707  var _, private20BitBlock, _ = net.ParseCIDR("172.16.0.0/12")
   708  var _, private16BitBlock, _ = net.ParseCIDR("192.168.0.0/16")
   709  
   710  // isPrivateIP returns true if the ip is contained by a rfc 1918 private range
   711  func isPrivateIP(ip net.IP) bool {
   712  	//TODO: another great cidrtree option
   713  	//TODO: Private for ipv6 or just let it ride?
   714  	return private24BitBlock.Contains(ip) || private20BitBlock.Contains(ip) || private16BitBlock.Contains(ip)
   715  }