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

     1  package nebula
     2  
     3  import (
     4  	"errors"
     5  	"net"
     6  	"sync"
     7  	"sync/atomic"
     8  	"time"
     9  
    10  	"github.com/rcrowley/go-metrics"
    11  	"github.com/sirupsen/logrus"
    12  	"github.com/slackhq/nebula/cert"
    13  	"github.com/slackhq/nebula/cidr"
    14  	"github.com/slackhq/nebula/config"
    15  	"github.com/slackhq/nebula/header"
    16  	"github.com/slackhq/nebula/iputil"
    17  	"github.com/slackhq/nebula/udp"
    18  )
    19  
    20  // const ProbeLen = 100
    21  const defaultPromoteEvery = 1000       // Count of packets sent before we try moving a tunnel to a preferred underlay ip address
    22  const defaultReQueryEvery = 5000       // Count of packets sent before re-querying a hostinfo to the lighthouse
    23  const defaultReQueryWait = time.Minute // Minimum amount of seconds to wait before re-querying a hostinfo the lighthouse. Evaluated every ReQueryEvery
    24  const MaxRemotes = 10
    25  const maxRecvError = 4
    26  
    27  // MaxHostInfosPerVpnIp is the max number of hostinfos we will track for a given vpn ip
    28  // 5 allows for an initial handshake and each host pair re-handshaking twice
    29  const MaxHostInfosPerVpnIp = 5
    30  
    31  // How long we should prevent roaming back to the previous IP.
    32  // This helps prevent flapping due to packets already in flight
    33  const RoamingSuppressSeconds = 2
    34  
    35  const (
    36  	Requested = iota
    37  	PeerRequested
    38  	Established
    39  )
    40  
    41  const (
    42  	Unknowntype = iota
    43  	ForwardingType
    44  	TerminalType
    45  )
    46  
    47  type Relay struct {
    48  	Type        int
    49  	State       int
    50  	LocalIndex  uint32
    51  	RemoteIndex uint32
    52  	PeerIp      iputil.VpnIp
    53  }
    54  
    55  type HostMap struct {
    56  	sync.RWMutex    //Because we concurrently read and write to our maps
    57  	Indexes         map[uint32]*HostInfo
    58  	Relays          map[uint32]*HostInfo // Maps a Relay IDX to a Relay HostInfo object
    59  	RemoteIndexes   map[uint32]*HostInfo
    60  	Hosts           map[iputil.VpnIp]*HostInfo
    61  	preferredRanges atomic.Pointer[[]*net.IPNet]
    62  	vpnCIDR         *net.IPNet
    63  	l               *logrus.Logger
    64  }
    65  
    66  // For synchronization, treat the pointed-to Relay struct as immutable. To edit the Relay
    67  // struct, make a copy of an existing value, edit the fileds in the copy, and
    68  // then store a pointer to the new copy in both realyForBy* maps.
    69  type RelayState struct {
    70  	sync.RWMutex
    71  
    72  	relays        map[iputil.VpnIp]struct{} // Set of VpnIp's of Hosts to use as relays to access this peer
    73  	relayForByIp  map[iputil.VpnIp]*Relay   // Maps VpnIps of peers for which this HostInfo is a relay to some Relay info
    74  	relayForByIdx map[uint32]*Relay         // Maps a local index to some Relay info
    75  }
    76  
    77  func (rs *RelayState) DeleteRelay(ip iputil.VpnIp) {
    78  	rs.Lock()
    79  	defer rs.Unlock()
    80  	delete(rs.relays, ip)
    81  }
    82  
    83  func (rs *RelayState) CopyAllRelayFor() []*Relay {
    84  	rs.RLock()
    85  	defer rs.RUnlock()
    86  	ret := make([]*Relay, 0, len(rs.relayForByIdx))
    87  	for _, r := range rs.relayForByIdx {
    88  		ret = append(ret, r)
    89  	}
    90  	return ret
    91  }
    92  
    93  func (rs *RelayState) GetRelayForByIp(ip iputil.VpnIp) (*Relay, bool) {
    94  	rs.RLock()
    95  	defer rs.RUnlock()
    96  	r, ok := rs.relayForByIp[ip]
    97  	return r, ok
    98  }
    99  
   100  func (rs *RelayState) InsertRelayTo(ip iputil.VpnIp) {
   101  	rs.Lock()
   102  	defer rs.Unlock()
   103  	rs.relays[ip] = struct{}{}
   104  }
   105  
   106  func (rs *RelayState) CopyRelayIps() []iputil.VpnIp {
   107  	rs.RLock()
   108  	defer rs.RUnlock()
   109  	ret := make([]iputil.VpnIp, 0, len(rs.relays))
   110  	for ip := range rs.relays {
   111  		ret = append(ret, ip)
   112  	}
   113  	return ret
   114  }
   115  
   116  func (rs *RelayState) CopyRelayForIps() []iputil.VpnIp {
   117  	rs.RLock()
   118  	defer rs.RUnlock()
   119  	currentRelays := make([]iputil.VpnIp, 0, len(rs.relayForByIp))
   120  	for relayIp := range rs.relayForByIp {
   121  		currentRelays = append(currentRelays, relayIp)
   122  	}
   123  	return currentRelays
   124  }
   125  
   126  func (rs *RelayState) CopyRelayForIdxs() []uint32 {
   127  	rs.RLock()
   128  	defer rs.RUnlock()
   129  	ret := make([]uint32, 0, len(rs.relayForByIdx))
   130  	for i := range rs.relayForByIdx {
   131  		ret = append(ret, i)
   132  	}
   133  	return ret
   134  }
   135  
   136  func (rs *RelayState) RemoveRelay(localIdx uint32) (iputil.VpnIp, bool) {
   137  	rs.Lock()
   138  	defer rs.Unlock()
   139  	r, ok := rs.relayForByIdx[localIdx]
   140  	if !ok {
   141  		return iputil.VpnIp(0), false
   142  	}
   143  	delete(rs.relayForByIdx, localIdx)
   144  	delete(rs.relayForByIp, r.PeerIp)
   145  	return r.PeerIp, true
   146  }
   147  
   148  func (rs *RelayState) CompleteRelayByIP(vpnIp iputil.VpnIp, remoteIdx uint32) bool {
   149  	rs.Lock()
   150  	defer rs.Unlock()
   151  	r, ok := rs.relayForByIp[vpnIp]
   152  	if !ok {
   153  		return false
   154  	}
   155  	newRelay := *r
   156  	newRelay.State = Established
   157  	newRelay.RemoteIndex = remoteIdx
   158  	rs.relayForByIdx[r.LocalIndex] = &newRelay
   159  	rs.relayForByIp[r.PeerIp] = &newRelay
   160  	return true
   161  }
   162  
   163  func (rs *RelayState) CompleteRelayByIdx(localIdx uint32, remoteIdx uint32) (*Relay, bool) {
   164  	rs.Lock()
   165  	defer rs.Unlock()
   166  	r, ok := rs.relayForByIdx[localIdx]
   167  	if !ok {
   168  		return nil, false
   169  	}
   170  	newRelay := *r
   171  	newRelay.State = Established
   172  	newRelay.RemoteIndex = remoteIdx
   173  	rs.relayForByIdx[r.LocalIndex] = &newRelay
   174  	rs.relayForByIp[r.PeerIp] = &newRelay
   175  	return &newRelay, true
   176  }
   177  
   178  func (rs *RelayState) QueryRelayForByIp(vpnIp iputil.VpnIp) (*Relay, bool) {
   179  	rs.RLock()
   180  	defer rs.RUnlock()
   181  	r, ok := rs.relayForByIp[vpnIp]
   182  	return r, ok
   183  }
   184  
   185  func (rs *RelayState) QueryRelayForByIdx(idx uint32) (*Relay, bool) {
   186  	rs.RLock()
   187  	defer rs.RUnlock()
   188  	r, ok := rs.relayForByIdx[idx]
   189  	return r, ok
   190  }
   191  
   192  func (rs *RelayState) InsertRelay(ip iputil.VpnIp, idx uint32, r *Relay) {
   193  	rs.Lock()
   194  	defer rs.Unlock()
   195  	rs.relayForByIp[ip] = r
   196  	rs.relayForByIdx[idx] = r
   197  }
   198  
   199  type HostInfo struct {
   200  	remote          *udp.Addr
   201  	remotes         *RemoteList
   202  	promoteCounter  atomic.Uint32
   203  	ConnectionState *ConnectionState
   204  	remoteIndexId   uint32
   205  	localIndexId    uint32
   206  	vpnIp           iputil.VpnIp
   207  	recvError       atomic.Uint32
   208  	remoteCidr      *cidr.Tree4[struct{}]
   209  	relayState      RelayState
   210  
   211  	// HandshakePacket records the packets used to create this hostinfo
   212  	// We need these to avoid replayed handshake packets creating new hostinfos which causes churn
   213  	HandshakePacket map[uint8][]byte
   214  
   215  	// nextLHQuery is the earliest we can ask the lighthouse for new information.
   216  	// This is used to limit lighthouse re-queries in chatty clients
   217  	nextLHQuery atomic.Int64
   218  
   219  	// lastRebindCount is the other side of Interface.rebindCount, if these values don't match then we need to ask LH
   220  	// for a punch from the remote end of this tunnel. The goal being to prime their conntrack for our traffic just like
   221  	// with a handshake
   222  	lastRebindCount int8
   223  
   224  	// lastHandshakeTime records the time the remote side told us about at the stage when the handshake was completed locally
   225  	// Stage 1 packet will contain it if I am a responder, stage 2 packet if I am an initiator
   226  	// This is used to avoid an attack where a handshake packet is replayed after some time
   227  	lastHandshakeTime uint64
   228  
   229  	lastRoam       time.Time
   230  	lastRoamRemote *udp.Addr
   231  
   232  	// Used to track other hostinfos for this vpn ip since only 1 can be primary
   233  	// Synchronised via hostmap lock and not the hostinfo lock.
   234  	next, prev *HostInfo
   235  }
   236  
   237  type ViaSender struct {
   238  	relayHI   *HostInfo // relayHI is the host info object of the relay
   239  	remoteIdx uint32    // remoteIdx is the index included in the header of the received packet
   240  	relay     *Relay    // relay contains the rest of the relay information, including the PeerIP of the host trying to communicate with us.
   241  }
   242  
   243  type cachedPacket struct {
   244  	messageType    header.MessageType
   245  	messageSubType header.MessageSubType
   246  	callback       packetCallback
   247  	packet         []byte
   248  }
   249  
   250  type packetCallback func(t header.MessageType, st header.MessageSubType, h *HostInfo, p, nb, out []byte)
   251  
   252  type cachedPacketMetrics struct {
   253  	sent    metrics.Counter
   254  	dropped metrics.Counter
   255  }
   256  
   257  func NewHostMapFromConfig(l *logrus.Logger, vpnCIDR *net.IPNet, c *config.C) *HostMap {
   258  	hm := newHostMap(l, vpnCIDR)
   259  
   260  	hm.reload(c, true)
   261  	c.RegisterReloadCallback(func(c *config.C) {
   262  		hm.reload(c, false)
   263  	})
   264  
   265  	l.WithField("network", hm.vpnCIDR.String()).
   266  		WithField("preferredRanges", hm.GetPreferredRanges()).
   267  		Info("Main HostMap created")
   268  
   269  	return hm
   270  }
   271  
   272  func newHostMap(l *logrus.Logger, vpnCIDR *net.IPNet) *HostMap {
   273  	return &HostMap{
   274  		Indexes:       map[uint32]*HostInfo{},
   275  		Relays:        map[uint32]*HostInfo{},
   276  		RemoteIndexes: map[uint32]*HostInfo{},
   277  		Hosts:         map[iputil.VpnIp]*HostInfo{},
   278  		vpnCIDR:       vpnCIDR,
   279  		l:             l,
   280  	}
   281  }
   282  
   283  func (hm *HostMap) reload(c *config.C, initial bool) {
   284  	if initial || c.HasChanged("preferred_ranges") {
   285  		var preferredRanges []*net.IPNet
   286  		rawPreferredRanges := c.GetStringSlice("preferred_ranges", []string{})
   287  
   288  		for _, rawPreferredRange := range rawPreferredRanges {
   289  			_, preferredRange, err := net.ParseCIDR(rawPreferredRange)
   290  
   291  			if err != nil {
   292  				hm.l.WithError(err).WithField("range", rawPreferredRanges).Warn("Failed to parse preferred ranges, ignoring")
   293  				continue
   294  			}
   295  
   296  			preferredRanges = append(preferredRanges, preferredRange)
   297  		}
   298  
   299  		oldRanges := hm.preferredRanges.Swap(&preferredRanges)
   300  		if !initial {
   301  			hm.l.WithField("oldPreferredRanges", *oldRanges).WithField("newPreferredRanges", preferredRanges).Info("preferred_ranges changed")
   302  		}
   303  	}
   304  }
   305  
   306  // EmitStats reports host, index, and relay counts to the stats collection system
   307  func (hm *HostMap) EmitStats() {
   308  	hm.RLock()
   309  	hostLen := len(hm.Hosts)
   310  	indexLen := len(hm.Indexes)
   311  	remoteIndexLen := len(hm.RemoteIndexes)
   312  	relaysLen := len(hm.Relays)
   313  	hm.RUnlock()
   314  
   315  	metrics.GetOrRegisterGauge("hostmap.main.hosts", nil).Update(int64(hostLen))
   316  	metrics.GetOrRegisterGauge("hostmap.main.indexes", nil).Update(int64(indexLen))
   317  	metrics.GetOrRegisterGauge("hostmap.main.remoteIndexes", nil).Update(int64(remoteIndexLen))
   318  	metrics.GetOrRegisterGauge("hostmap.main.relayIndexes", nil).Update(int64(relaysLen))
   319  }
   320  
   321  func (hm *HostMap) RemoveRelay(localIdx uint32) {
   322  	hm.Lock()
   323  	_, ok := hm.Relays[localIdx]
   324  	if !ok {
   325  		hm.Unlock()
   326  		return
   327  	}
   328  	delete(hm.Relays, localIdx)
   329  	hm.Unlock()
   330  }
   331  
   332  // DeleteHostInfo will fully unlink the hostinfo and return true if it was the final hostinfo for this vpn ip
   333  func (hm *HostMap) DeleteHostInfo(hostinfo *HostInfo) bool {
   334  	// Delete the host itself, ensuring it's not modified anymore
   335  	hm.Lock()
   336  	// If we have a previous or next hostinfo then we are not the last one for this vpn ip
   337  	final := (hostinfo.next == nil && hostinfo.prev == nil)
   338  	hm.unlockedDeleteHostInfo(hostinfo)
   339  	hm.Unlock()
   340  
   341  	return final
   342  }
   343  
   344  func (hm *HostMap) MakePrimary(hostinfo *HostInfo) {
   345  	hm.Lock()
   346  	defer hm.Unlock()
   347  	hm.unlockedMakePrimary(hostinfo)
   348  }
   349  
   350  func (hm *HostMap) unlockedMakePrimary(hostinfo *HostInfo) {
   351  	oldHostinfo := hm.Hosts[hostinfo.vpnIp]
   352  	if oldHostinfo == hostinfo {
   353  		return
   354  	}
   355  
   356  	if hostinfo.prev != nil {
   357  		hostinfo.prev.next = hostinfo.next
   358  	}
   359  
   360  	if hostinfo.next != nil {
   361  		hostinfo.next.prev = hostinfo.prev
   362  	}
   363  
   364  	hm.Hosts[hostinfo.vpnIp] = hostinfo
   365  
   366  	if oldHostinfo == nil {
   367  		return
   368  	}
   369  
   370  	hostinfo.next = oldHostinfo
   371  	oldHostinfo.prev = hostinfo
   372  	hostinfo.prev = nil
   373  }
   374  
   375  func (hm *HostMap) unlockedDeleteHostInfo(hostinfo *HostInfo) {
   376  	primary, ok := hm.Hosts[hostinfo.vpnIp]
   377  	if ok && primary == hostinfo {
   378  		// The vpnIp pointer points to the same hostinfo as the local index id, we can remove it
   379  		delete(hm.Hosts, hostinfo.vpnIp)
   380  		if len(hm.Hosts) == 0 {
   381  			hm.Hosts = map[iputil.VpnIp]*HostInfo{}
   382  		}
   383  
   384  		if hostinfo.next != nil {
   385  			// We had more than 1 hostinfo at this vpnip, promote the next in the list to primary
   386  			hm.Hosts[hostinfo.vpnIp] = hostinfo.next
   387  			// It is primary, there is no previous hostinfo now
   388  			hostinfo.next.prev = nil
   389  		}
   390  
   391  	} else {
   392  		// Relink if we were in the middle of multiple hostinfos for this vpn ip
   393  		if hostinfo.prev != nil {
   394  			hostinfo.prev.next = hostinfo.next
   395  		}
   396  
   397  		if hostinfo.next != nil {
   398  			hostinfo.next.prev = hostinfo.prev
   399  		}
   400  	}
   401  
   402  	hostinfo.next = nil
   403  	hostinfo.prev = nil
   404  
   405  	// The remote index uses index ids outside our control so lets make sure we are only removing
   406  	// the remote index pointer here if it points to the hostinfo we are deleting
   407  	hostinfo2, ok := hm.RemoteIndexes[hostinfo.remoteIndexId]
   408  	if ok && hostinfo2 == hostinfo {
   409  		delete(hm.RemoteIndexes, hostinfo.remoteIndexId)
   410  		if len(hm.RemoteIndexes) == 0 {
   411  			hm.RemoteIndexes = map[uint32]*HostInfo{}
   412  		}
   413  	}
   414  
   415  	delete(hm.Indexes, hostinfo.localIndexId)
   416  	if len(hm.Indexes) == 0 {
   417  		hm.Indexes = map[uint32]*HostInfo{}
   418  	}
   419  
   420  	if hm.l.Level >= logrus.DebugLevel {
   421  		hm.l.WithField("hostMap", m{"mapTotalSize": len(hm.Hosts),
   422  			"vpnIp": hostinfo.vpnIp, "indexNumber": hostinfo.localIndexId, "remoteIndexNumber": hostinfo.remoteIndexId}).
   423  			Debug("Hostmap hostInfo deleted")
   424  	}
   425  
   426  	for _, localRelayIdx := range hostinfo.relayState.CopyRelayForIdxs() {
   427  		delete(hm.Relays, localRelayIdx)
   428  	}
   429  }
   430  
   431  func (hm *HostMap) QueryIndex(index uint32) *HostInfo {
   432  	hm.RLock()
   433  	if h, ok := hm.Indexes[index]; ok {
   434  		hm.RUnlock()
   435  		return h
   436  	} else {
   437  		hm.RUnlock()
   438  		return nil
   439  	}
   440  }
   441  
   442  func (hm *HostMap) QueryRelayIndex(index uint32) *HostInfo {
   443  	hm.RLock()
   444  	if h, ok := hm.Relays[index]; ok {
   445  		hm.RUnlock()
   446  		return h
   447  	} else {
   448  		hm.RUnlock()
   449  		return nil
   450  	}
   451  }
   452  
   453  func (hm *HostMap) QueryReverseIndex(index uint32) *HostInfo {
   454  	hm.RLock()
   455  	if h, ok := hm.RemoteIndexes[index]; ok {
   456  		hm.RUnlock()
   457  		return h
   458  	} else {
   459  		hm.RUnlock()
   460  		return nil
   461  	}
   462  }
   463  
   464  func (hm *HostMap) QueryVpnIp(vpnIp iputil.VpnIp) *HostInfo {
   465  	return hm.queryVpnIp(vpnIp, nil)
   466  }
   467  
   468  func (hm *HostMap) QueryVpnIpRelayFor(targetIp, relayHostIp iputil.VpnIp) (*HostInfo, *Relay, error) {
   469  	hm.RLock()
   470  	defer hm.RUnlock()
   471  
   472  	h, ok := hm.Hosts[relayHostIp]
   473  	if !ok {
   474  		return nil, nil, errors.New("unable to find host")
   475  	}
   476  	for h != nil {
   477  		r, ok := h.relayState.QueryRelayForByIp(targetIp)
   478  		if ok && r.State == Established {
   479  			return h, r, nil
   480  		}
   481  		h = h.next
   482  	}
   483  	return nil, nil, errors.New("unable to find host with relay")
   484  }
   485  
   486  func (hm *HostMap) queryVpnIp(vpnIp iputil.VpnIp, promoteIfce *Interface) *HostInfo {
   487  	hm.RLock()
   488  	if h, ok := hm.Hosts[vpnIp]; ok {
   489  		hm.RUnlock()
   490  		// Do not attempt promotion if you are a lighthouse
   491  		if promoteIfce != nil && !promoteIfce.lightHouse.amLighthouse {
   492  			h.TryPromoteBest(hm.GetPreferredRanges(), promoteIfce)
   493  		}
   494  		return h
   495  
   496  	}
   497  
   498  	hm.RUnlock()
   499  	return nil
   500  }
   501  
   502  // unlockedAddHostInfo assumes you have a write-lock and will add a hostinfo object to the hostmap Indexes and RemoteIndexes maps.
   503  // If an entry exists for the Hosts table (vpnIp -> hostinfo) then the provided hostinfo will be made primary
   504  func (hm *HostMap) unlockedAddHostInfo(hostinfo *HostInfo, f *Interface) {
   505  	if f.serveDns {
   506  		remoteCert := hostinfo.ConnectionState.peerCert
   507  		dnsR.Add(remoteCert.Details.Name+".", remoteCert.Details.Ips[0].IP.String())
   508  	}
   509  
   510  	existing := hm.Hosts[hostinfo.vpnIp]
   511  	hm.Hosts[hostinfo.vpnIp] = hostinfo
   512  
   513  	if existing != nil {
   514  		hostinfo.next = existing
   515  		existing.prev = hostinfo
   516  	}
   517  
   518  	hm.Indexes[hostinfo.localIndexId] = hostinfo
   519  	hm.RemoteIndexes[hostinfo.remoteIndexId] = hostinfo
   520  
   521  	if hm.l.Level >= logrus.DebugLevel {
   522  		hm.l.WithField("hostMap", m{"vpnIp": hostinfo.vpnIp, "mapTotalSize": len(hm.Hosts),
   523  			"hostinfo": m{"existing": true, "localIndexId": hostinfo.localIndexId, "hostId": hostinfo.vpnIp}}).
   524  			Debug("Hostmap vpnIp added")
   525  	}
   526  
   527  	i := 1
   528  	check := hostinfo
   529  	for check != nil {
   530  		if i > MaxHostInfosPerVpnIp {
   531  			hm.unlockedDeleteHostInfo(check)
   532  		}
   533  		check = check.next
   534  		i++
   535  	}
   536  }
   537  
   538  func (hm *HostMap) GetPreferredRanges() []*net.IPNet {
   539  	//NOTE: if preferredRanges is ever not stored before a load this will fail to dereference a nil pointer
   540  	return *hm.preferredRanges.Load()
   541  }
   542  
   543  func (hm *HostMap) ForEachVpnIp(f controlEach) {
   544  	hm.RLock()
   545  	defer hm.RUnlock()
   546  
   547  	for _, v := range hm.Hosts {
   548  		f(v)
   549  	}
   550  }
   551  
   552  func (hm *HostMap) ForEachIndex(f controlEach) {
   553  	hm.RLock()
   554  	defer hm.RUnlock()
   555  
   556  	for _, v := range hm.Indexes {
   557  		f(v)
   558  	}
   559  }
   560  
   561  // TryPromoteBest handles re-querying lighthouses and probing for better paths
   562  // NOTE: It is an error to call this if you are a lighthouse since they should not roam clients!
   563  func (i *HostInfo) TryPromoteBest(preferredRanges []*net.IPNet, ifce *Interface) {
   564  	c := i.promoteCounter.Add(1)
   565  	if c%ifce.tryPromoteEvery.Load() == 0 {
   566  		remote := i.remote
   567  
   568  		// return early if we are already on a preferred remote
   569  		if remote != nil {
   570  			rIP := remote.IP
   571  			for _, l := range preferredRanges {
   572  				if l.Contains(rIP) {
   573  					return
   574  				}
   575  			}
   576  		}
   577  
   578  		i.remotes.ForEach(preferredRanges, func(addr *udp.Addr, preferred bool) {
   579  			if remote != nil && (addr == nil || !preferred) {
   580  				return
   581  			}
   582  
   583  			// Try to send a test packet to that host, this should
   584  			// cause it to detect a roaming event and switch remotes
   585  			ifce.sendTo(header.Test, header.TestRequest, i.ConnectionState, i, addr, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
   586  		})
   587  	}
   588  
   589  	// Re query our lighthouses for new remotes occasionally
   590  	if c%ifce.reQueryEvery.Load() == 0 && ifce.lightHouse != nil {
   591  		now := time.Now().UnixNano()
   592  		if now < i.nextLHQuery.Load() {
   593  			return
   594  		}
   595  
   596  		i.nextLHQuery.Store(now + ifce.reQueryWait.Load())
   597  		ifce.lightHouse.QueryServer(i.vpnIp)
   598  	}
   599  }
   600  
   601  func (i *HostInfo) GetCert() *cert.NebulaCertificate {
   602  	if i.ConnectionState != nil {
   603  		return i.ConnectionState.peerCert
   604  	}
   605  	return nil
   606  }
   607  
   608  func (i *HostInfo) SetRemote(remote *udp.Addr) {
   609  	// We copy here because we likely got this remote from a source that reuses the object
   610  	if !i.remote.Equals(remote) {
   611  		i.remote = remote.Copy()
   612  		i.remotes.LearnRemote(i.vpnIp, remote.Copy())
   613  	}
   614  }
   615  
   616  // SetRemoteIfPreferred returns true if the remote was changed. The lastRoam
   617  // time on the HostInfo will also be updated.
   618  func (i *HostInfo) SetRemoteIfPreferred(hm *HostMap, newRemote *udp.Addr) bool {
   619  	if newRemote == nil {
   620  		// relays have nil udp Addrs
   621  		return false
   622  	}
   623  	currentRemote := i.remote
   624  	if currentRemote == nil {
   625  		i.SetRemote(newRemote)
   626  		return true
   627  	}
   628  
   629  	// NOTE: We do this loop here instead of calling `isPreferred` in
   630  	// remote_list.go so that we only have to loop over preferredRanges once.
   631  	newIsPreferred := false
   632  	for _, l := range hm.GetPreferredRanges() {
   633  		// return early if we are already on a preferred remote
   634  		if l.Contains(currentRemote.IP) {
   635  			return false
   636  		}
   637  
   638  		if l.Contains(newRemote.IP) {
   639  			newIsPreferred = true
   640  		}
   641  	}
   642  
   643  	if newIsPreferred {
   644  		// Consider this a roaming event
   645  		i.lastRoam = time.Now()
   646  		i.lastRoamRemote = currentRemote.Copy()
   647  
   648  		i.SetRemote(newRemote)
   649  
   650  		return true
   651  	}
   652  
   653  	return false
   654  }
   655  
   656  func (i *HostInfo) RecvErrorExceeded() bool {
   657  	if i.recvError.Add(1) >= maxRecvError {
   658  		return true
   659  	}
   660  	return true
   661  }
   662  
   663  func (i *HostInfo) CreateRemoteCIDR(c *cert.NebulaCertificate) {
   664  	if len(c.Details.Ips) == 1 && len(c.Details.Subnets) == 0 {
   665  		// Simple case, no CIDRTree needed
   666  		return
   667  	}
   668  
   669  	remoteCidr := cidr.NewTree4[struct{}]()
   670  	for _, ip := range c.Details.Ips {
   671  		remoteCidr.AddCIDR(&net.IPNet{IP: ip.IP, Mask: net.IPMask{255, 255, 255, 255}}, struct{}{})
   672  	}
   673  
   674  	for _, n := range c.Details.Subnets {
   675  		remoteCidr.AddCIDR(n, struct{}{})
   676  	}
   677  	i.remoteCidr = remoteCidr
   678  }
   679  
   680  func (i *HostInfo) logger(l *logrus.Logger) *logrus.Entry {
   681  	if i == nil {
   682  		return logrus.NewEntry(l)
   683  	}
   684  
   685  	li := l.WithField("vpnIp", i.vpnIp).
   686  		WithField("localIndex", i.localIndexId).
   687  		WithField("remoteIndex", i.remoteIndexId)
   688  
   689  	if connState := i.ConnectionState; connState != nil {
   690  		if peerCert := connState.peerCert; peerCert != nil {
   691  			li = li.WithField("certName", peerCert.Details.Name)
   692  		}
   693  	}
   694  
   695  	return li
   696  }
   697  
   698  // Utility functions
   699  
   700  func localIps(l *logrus.Logger, allowList *LocalAllowList) *[]net.IP {
   701  	//FIXME: This function is pretty garbage
   702  	var ips []net.IP
   703  	ifaces, _ := net.Interfaces()
   704  	for _, i := range ifaces {
   705  		allow := allowList.AllowName(i.Name)
   706  		if l.Level >= logrus.TraceLevel {
   707  			l.WithField("interfaceName", i.Name).WithField("allow", allow).Trace("localAllowList.AllowName")
   708  		}
   709  
   710  		if !allow {
   711  			continue
   712  		}
   713  		addrs, _ := i.Addrs()
   714  		for _, addr := range addrs {
   715  			var ip net.IP
   716  			switch v := addr.(type) {
   717  			case *net.IPNet:
   718  				//continue
   719  				ip = v.IP
   720  			case *net.IPAddr:
   721  				ip = v.IP
   722  			}
   723  
   724  			//TODO: Filtering out link local for now, this is probably the most correct thing
   725  			//TODO: Would be nice to filter out SLAAC MAC based ips as well
   726  			if ip.IsLoopback() == false && !ip.IsLinkLocalUnicast() {
   727  				allow := allowList.Allow(ip)
   728  				if l.Level >= logrus.TraceLevel {
   729  					l.WithField("localIp", ip).WithField("allow", allow).Trace("localAllowList.Allow")
   730  				}
   731  				if !allow {
   732  					continue
   733  				}
   734  
   735  				ips = append(ips, ip)
   736  			}
   737  		}
   738  	}
   739  	return &ips
   740  }