| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848 | package nebulaimport (	"errors"	"fmt"	"net"	"sync"	"sync/atomic"	"time"	"github.com/rcrowley/go-metrics"	"github.com/sirupsen/logrus"	"github.com/slackhq/nebula/cert"	"github.com/slackhq/nebula/cidr"	"github.com/slackhq/nebula/header"	"github.com/slackhq/nebula/iputil"	"github.com/slackhq/nebula/udp")// const ProbeLen = 100const PromoteEvery = 1000const ReQueryEvery = 5000const MaxRemotes = 10// MaxHostInfosPerVpnIp is the max number of hostinfos we will track for a given vpn ip// 5 allows for an initial handshake and each host pair re-handshaking twiceconst MaxHostInfosPerVpnIp = 5// How long we should prevent roaming back to the previous IP.// This helps prevent flapping due to packets already in flightconst RoamingSuppressSeconds = 2const (	Requested = iota	PeerRequested	Established)const (	Unknowntype = iota	ForwardingType	TerminalType)type Relay struct {	Type        int	State       int	LocalIndex  uint32	RemoteIndex uint32	PeerIp      iputil.VpnIp}type HostMap struct {	sync.RWMutex    //Because we concurrently read and write to our maps	name            string	Indexes         map[uint32]*HostInfo	Relays          map[uint32]*HostInfo // Maps a Relay IDX to a Relay HostInfo object	RemoteIndexes   map[uint32]*HostInfo	Hosts           map[iputil.VpnIp]*HostInfo	preferredRanges []*net.IPNet	vpnCIDR         *net.IPNet	metricsEnabled  bool	l               *logrus.Logger}// For synchronization, treat the pointed-to Relay struct as immutable. To edit the Relay// struct, make a copy of an existing value, edit the fileds in the copy, and// then store a pointer to the new copy in both realyForBy* maps.type RelayState struct {	sync.RWMutex	relays        map[iputil.VpnIp]struct{} // Set of VpnIp's of Hosts to use as relays to access this peer	relayForByIp  map[iputil.VpnIp]*Relay   // Maps VpnIps of peers for which this HostInfo is a relay to some Relay info	relayForByIdx map[uint32]*Relay         // Maps a local index to some Relay info}func (rs *RelayState) DeleteRelay(ip iputil.VpnIp) {	rs.Lock()	defer rs.Unlock()	delete(rs.relays, ip)}func (rs *RelayState) CopyAllRelayFor() []*Relay {	rs.RLock()	defer rs.RUnlock()	ret := make([]*Relay, 0, len(rs.relayForByIdx))	for _, r := range rs.relayForByIdx {		ret = append(ret, r)	}	return ret}func (rs *RelayState) GetRelayForByIp(ip iputil.VpnIp) (*Relay, bool) {	rs.RLock()	defer rs.RUnlock()	r, ok := rs.relayForByIp[ip]	return r, ok}func (rs *RelayState) InsertRelayTo(ip iputil.VpnIp) {	rs.Lock()	defer rs.Unlock()	rs.relays[ip] = struct{}{}}func (rs *RelayState) CopyRelayIps() []iputil.VpnIp {	rs.RLock()	defer rs.RUnlock()	ret := make([]iputil.VpnIp, 0, len(rs.relays))	for ip := range rs.relays {		ret = append(ret, ip)	}	return ret}func (rs *RelayState) CopyRelayForIps() []iputil.VpnIp {	rs.RLock()	defer rs.RUnlock()	currentRelays := make([]iputil.VpnIp, 0, len(rs.relayForByIp))	for relayIp := range rs.relayForByIp {		currentRelays = append(currentRelays, relayIp)	}	return currentRelays}func (rs *RelayState) CopyRelayForIdxs() []uint32 {	rs.RLock()	defer rs.RUnlock()	ret := make([]uint32, 0, len(rs.relayForByIdx))	for i := range rs.relayForByIdx {		ret = append(ret, i)	}	return ret}func (rs *RelayState) RemoveRelay(localIdx uint32) (iputil.VpnIp, bool) {	rs.Lock()	defer rs.Unlock()	r, ok := rs.relayForByIdx[localIdx]	if !ok {		return iputil.VpnIp(0), false	}	delete(rs.relayForByIdx, localIdx)	delete(rs.relayForByIp, r.PeerIp)	return r.PeerIp, true}func (rs *RelayState) CompleteRelayByIP(vpnIp iputil.VpnIp, remoteIdx uint32) bool {	rs.Lock()	defer rs.Unlock()	r, ok := rs.relayForByIp[vpnIp]	if !ok {		return false	}	newRelay := *r	newRelay.State = Established	newRelay.RemoteIndex = remoteIdx	rs.relayForByIdx[r.LocalIndex] = &newRelay	rs.relayForByIp[r.PeerIp] = &newRelay	return true}func (rs *RelayState) CompleteRelayByIdx(localIdx uint32, remoteIdx uint32) (*Relay, bool) {	rs.Lock()	defer rs.Unlock()	r, ok := rs.relayForByIdx[localIdx]	if !ok {		return nil, false	}	newRelay := *r	newRelay.State = Established	newRelay.RemoteIndex = remoteIdx	rs.relayForByIdx[r.LocalIndex] = &newRelay	rs.relayForByIp[r.PeerIp] = &newRelay	return &newRelay, true}func (rs *RelayState) QueryRelayForByIp(vpnIp iputil.VpnIp) (*Relay, bool) {	rs.RLock()	defer rs.RUnlock()	r, ok := rs.relayForByIp[vpnIp]	return r, ok}func (rs *RelayState) QueryRelayForByIdx(idx uint32) (*Relay, bool) {	rs.RLock()	defer rs.RUnlock()	r, ok := rs.relayForByIdx[idx]	return r, ok}func (rs *RelayState) InsertRelay(ip iputil.VpnIp, idx uint32, r *Relay) {	rs.Lock()	defer rs.Unlock()	rs.relayForByIp[ip] = r	rs.relayForByIdx[idx] = r}type HostInfo struct {	sync.RWMutex	remote               *udp.Addr	remotes              *RemoteList	promoteCounter       atomic.Uint32	ConnectionState      *ConnectionState	handshakeStart       time.Time        //todo: this an entry in the handshake manager	HandshakeReady       bool             //todo: being in the manager means you are ready	HandshakeCounter     int              //todo: another handshake manager entry	HandshakeLastRemotes []*udp.Addr      //todo: another handshake manager entry, which remotes we sent to last time	HandshakeComplete    bool             //todo: this should go away in favor of ConnectionState.ready	HandshakePacket      map[uint8][]byte //todo: this is other handshake manager entry	packetStore          []*cachedPacket  //todo: this is other handshake manager entry	remoteIndexId        uint32	localIndexId         uint32	vpnIp                iputil.VpnIp	recvError            int	remoteCidr           *cidr.Tree4	relayState           RelayState	// lastRebindCount is the other side of Interface.rebindCount, if these values don't match then we need to ask LH	// for a punch from the remote end of this tunnel. The goal being to prime their conntrack for our traffic just like	// with a handshake	lastRebindCount int8	// lastHandshakeTime records the time the remote side told us about at the stage when the handshake was completed locally	// Stage 1 packet will contain it if I am a responder, stage 2 packet if I am an initiator	// This is used to avoid an attack where a handshake packet is replayed after some time	lastHandshakeTime uint64	lastRoam       time.Time	lastRoamRemote *udp.Addr	// Used to track other hostinfos for this vpn ip since only 1 can be primary	// Synchronised via hostmap lock and not the hostinfo lock.	next, prev *HostInfo}type ViaSender struct {	relayHI   *HostInfo // relayHI is the host info object of the relay	remoteIdx uint32    // remoteIdx is the index included in the header of the received packet	relay     *Relay    // relay contains the rest of the relay information, including the PeerIP of the host trying to communicate with us.}type cachedPacket struct {	messageType    header.MessageType	messageSubType header.MessageSubType	callback       packetCallback	packet         []byte}type packetCallback func(t header.MessageType, st header.MessageSubType, h *HostInfo, p, nb, out []byte)type cachedPacketMetrics struct {	sent    metrics.Counter	dropped metrics.Counter}func NewHostMap(l *logrus.Logger, name string, vpnCIDR *net.IPNet, preferredRanges []*net.IPNet) *HostMap {	h := map[iputil.VpnIp]*HostInfo{}	i := map[uint32]*HostInfo{}	r := map[uint32]*HostInfo{}	relays := map[uint32]*HostInfo{}	m := HostMap{		name:            name,		Indexes:         i,		Relays:          relays,		RemoteIndexes:   r,		Hosts:           h,		preferredRanges: preferredRanges,		vpnCIDR:         vpnCIDR,		l:               l,	}	return &m}// UpdateStats takes a name and reports host and index counts to the stats collection systemfunc (hm *HostMap) EmitStats(name string) {	hm.RLock()	hostLen := len(hm.Hosts)	indexLen := len(hm.Indexes)	remoteIndexLen := len(hm.RemoteIndexes)	relaysLen := len(hm.Relays)	hm.RUnlock()	metrics.GetOrRegisterGauge("hostmap."+name+".hosts", nil).Update(int64(hostLen))	metrics.GetOrRegisterGauge("hostmap."+name+".indexes", nil).Update(int64(indexLen))	metrics.GetOrRegisterGauge("hostmap."+name+".remoteIndexes", nil).Update(int64(remoteIndexLen))	metrics.GetOrRegisterGauge("hostmap."+name+".relayIndexes", nil).Update(int64(relaysLen))}func (hm *HostMap) RemoveRelay(localIdx uint32) {	hm.Lock()	_, ok := hm.Relays[localIdx]	if !ok {		hm.Unlock()		return	}	delete(hm.Relays, localIdx)	hm.Unlock()}func (hm *HostMap) GetIndexByVpnIp(vpnIp iputil.VpnIp) (uint32, error) {	hm.RLock()	if i, ok := hm.Hosts[vpnIp]; ok {		index := i.localIndexId		hm.RUnlock()		return index, nil	}	hm.RUnlock()	return 0, errors.New("vpn IP not found")}func (hm *HostMap) Add(ip iputil.VpnIp, hostinfo *HostInfo) {	hm.Lock()	hm.Hosts[ip] = hostinfo	hm.Unlock()}func (hm *HostMap) AddVpnIp(vpnIp iputil.VpnIp, init func(hostinfo *HostInfo)) (hostinfo *HostInfo, created bool) {	hm.RLock()	if h, ok := hm.Hosts[vpnIp]; !ok {		hm.RUnlock()		h = &HostInfo{			vpnIp:           vpnIp,			HandshakePacket: make(map[uint8][]byte, 0),			relayState: RelayState{				relays:        map[iputil.VpnIp]struct{}{},				relayForByIp:  map[iputil.VpnIp]*Relay{},				relayForByIdx: map[uint32]*Relay{},			},		}		if init != nil {			init(h)		}		hm.Lock()		hm.Hosts[vpnIp] = h		hm.Unlock()		return h, true	} else {		hm.RUnlock()		return h, false	}}// Only used by pendingHostMap when the remote index is not initially knownfunc (hm *HostMap) addRemoteIndexHostInfo(index uint32, h *HostInfo) {	hm.Lock()	h.remoteIndexId = index	hm.RemoteIndexes[index] = h	hm.Unlock()	if hm.l.Level > logrus.DebugLevel {		hm.l.WithField("hostMap", m{"mapName": hm.name, "indexNumber": index, "mapTotalSize": len(hm.Indexes),			"hostinfo": m{"existing": true, "localIndexId": h.localIndexId, "hostId": h.vpnIp}}).			Debug("Hostmap remoteIndex added")	}}// DeleteReverseIndex is used to clean up on recv_error// This function should only ever be called on the pending hostmapfunc (hm *HostMap) DeleteReverseIndex(index uint32) {	hm.Lock()	hostinfo, ok := hm.RemoteIndexes[index]	if ok {		delete(hm.Indexes, hostinfo.localIndexId)		delete(hm.RemoteIndexes, index)		// Check if we have an entry under hostId that matches the same hostinfo		// instance. Clean it up as well if we do (they might not match in pendingHostmap)		var hostinfo2 *HostInfo		hostinfo2, ok = hm.Hosts[hostinfo.vpnIp]		if ok && hostinfo2 == hostinfo {			delete(hm.Hosts, hostinfo.vpnIp)		}	}	hm.Unlock()	if hm.l.Level >= logrus.DebugLevel {		hm.l.WithField("hostMap", m{"mapName": hm.name, "indexNumber": index, "mapTotalSize": len(hm.Indexes)}).			Debug("Hostmap remote index deleted")	}}// DeleteHostInfo will fully unlink the hostinfo and return true if it was the final hostinfo for this vpn ipfunc (hm *HostMap) DeleteHostInfo(hostinfo *HostInfo) bool {	// Delete the host itself, ensuring it's not modified anymore	hm.Lock()	// If we have a previous or next hostinfo then we are not the last one for this vpn ip	final := (hostinfo.next == nil && hostinfo.prev == nil)	hm.unlockedDeleteHostInfo(hostinfo)	hm.Unlock()	return final}func (hm *HostMap) DeleteRelayIdx(localIdx uint32) {	hm.Lock()	defer hm.Unlock()	delete(hm.RemoteIndexes, localIdx)}func (hm *HostMap) MakePrimary(hostinfo *HostInfo) {	hm.Lock()	defer hm.Unlock()	hm.unlockedMakePrimary(hostinfo)}func (hm *HostMap) unlockedMakePrimary(hostinfo *HostInfo) {	oldHostinfo := hm.Hosts[hostinfo.vpnIp]	if oldHostinfo == hostinfo {		return	}	if hostinfo.prev != nil {		hostinfo.prev.next = hostinfo.next	}	if hostinfo.next != nil {		hostinfo.next.prev = hostinfo.prev	}	hm.Hosts[hostinfo.vpnIp] = hostinfo	if oldHostinfo == nil {		return	}	hostinfo.next = oldHostinfo	oldHostinfo.prev = hostinfo	hostinfo.prev = nil}func (hm *HostMap) unlockedDeleteHostInfo(hostinfo *HostInfo) {	primary, ok := hm.Hosts[hostinfo.vpnIp]	if ok && primary == hostinfo {		// The vpnIp pointer points to the same hostinfo as the local index id, we can remove it		delete(hm.Hosts, hostinfo.vpnIp)		if len(hm.Hosts) == 0 {			hm.Hosts = map[iputil.VpnIp]*HostInfo{}		}		if hostinfo.next != nil {			// We had more than 1 hostinfo at this vpnip, promote the next in the list to primary			hm.Hosts[hostinfo.vpnIp] = hostinfo.next			// It is primary, there is no previous hostinfo now			hostinfo.next.prev = nil		}	} else {		// Relink if we were in the middle of multiple hostinfos for this vpn ip		if hostinfo.prev != nil {			hostinfo.prev.next = hostinfo.next		}		if hostinfo.next != nil {			hostinfo.next.prev = hostinfo.prev		}	}	hostinfo.next = nil	hostinfo.prev = nil	// The remote index uses index ids outside our control so lets make sure we are only removing	// the remote index pointer here if it points to the hostinfo we are deleting	hostinfo2, ok := hm.RemoteIndexes[hostinfo.remoteIndexId]	if ok && hostinfo2 == hostinfo {		delete(hm.RemoteIndexes, hostinfo.remoteIndexId)		if len(hm.RemoteIndexes) == 0 {			hm.RemoteIndexes = map[uint32]*HostInfo{}		}	}	delete(hm.Indexes, hostinfo.localIndexId)	if len(hm.Indexes) == 0 {		hm.Indexes = map[uint32]*HostInfo{}	}	if hm.l.Level >= logrus.DebugLevel {		hm.l.WithField("hostMap", m{"mapName": hm.name, "mapTotalSize": len(hm.Hosts),			"vpnIp": hostinfo.vpnIp, "indexNumber": hostinfo.localIndexId, "remoteIndexNumber": hostinfo.remoteIndexId}).			Debug("Hostmap hostInfo deleted")	}	for _, localRelayIdx := range hostinfo.relayState.CopyRelayForIdxs() {		delete(hm.Relays, localRelayIdx)	}}func (hm *HostMap) QueryIndex(index uint32) (*HostInfo, error) {	//TODO: we probably just want to return bool instead of error, or at least a static error	hm.RLock()	if h, ok := hm.Indexes[index]; ok {		hm.RUnlock()		return h, nil	} else {		hm.RUnlock()		return nil, errors.New("unable to find index")	}}// Retrieves a HostInfo by Index. Returns whether the HostInfo is primary at time of query.// This helper exists so that the hostinfo.prev pointer can be read while the hostmap lock is held.func (hm *HostMap) QueryIndexIsPrimary(index uint32) (*HostInfo, bool, error) {	//TODO: we probably just want to return bool instead of error, or at least a static error	hm.RLock()	if h, ok := hm.Indexes[index]; ok {		hm.RUnlock()		return h, h.prev == nil, nil	} else {		hm.RUnlock()		return nil, false, errors.New("unable to find index")	}}func (hm *HostMap) QueryRelayIndex(index uint32) (*HostInfo, error) {	//TODO: we probably just want to return bool instead of error, or at least a static error	hm.RLock()	if h, ok := hm.Relays[index]; ok {		hm.RUnlock()		return h, nil	} else {		hm.RUnlock()		return nil, errors.New("unable to find index")	}}func (hm *HostMap) QueryReverseIndex(index uint32) (*HostInfo, error) {	hm.RLock()	if h, ok := hm.RemoteIndexes[index]; ok {		hm.RUnlock()		return h, nil	} else {		hm.RUnlock()		return nil, fmt.Errorf("unable to find reverse index or connectionstate nil in %s hostmap", hm.name)	}}func (hm *HostMap) QueryVpnIp(vpnIp iputil.VpnIp) (*HostInfo, error) {	return hm.queryVpnIp(vpnIp, nil)}func (hm *HostMap) QueryVpnIpRelayFor(targetIp, relayHostIp iputil.VpnIp) (*HostInfo, *Relay, error) {	hm.RLock()	defer hm.RUnlock()	h, ok := hm.Hosts[relayHostIp]	if !ok {		return nil, nil, errors.New("unable to find host")	}	for h != nil {		r, ok := h.relayState.QueryRelayForByIp(targetIp)		if ok && r.State == Established {			return h, r, nil		}		h = h.next	}	return nil, nil, errors.New("unable to find host with relay")}// PromoteBestQueryVpnIp will attempt to lazily switch to the best remote every// `PromoteEvery` calls to this function for a given host.func (hm *HostMap) PromoteBestQueryVpnIp(vpnIp iputil.VpnIp, ifce *Interface) (*HostInfo, error) {	return hm.queryVpnIp(vpnIp, ifce)}func (hm *HostMap) queryVpnIp(vpnIp iputil.VpnIp, promoteIfce *Interface) (*HostInfo, error) {	hm.RLock()	if h, ok := hm.Hosts[vpnIp]; ok {		hm.RUnlock()		// Do not attempt promotion if you are a lighthouse		if promoteIfce != nil && !promoteIfce.lightHouse.amLighthouse {			h.TryPromoteBest(hm.preferredRanges, promoteIfce)		}		return h, nil	}	hm.RUnlock()	return nil, errors.New("unable to find host")}// unlockedAddHostInfo assumes you have a write-lock and will add a hostinfo object to the hostmap Indexes and RemoteIndexes maps.// If an entry exists for the Hosts table (vpnIp -> hostinfo) then the provided hostinfo will be made primaryfunc (hm *HostMap) unlockedAddHostInfo(hostinfo *HostInfo, f *Interface) {	if f.serveDns {		remoteCert := hostinfo.ConnectionState.peerCert		dnsR.Add(remoteCert.Details.Name+".", remoteCert.Details.Ips[0].IP.String())	}	existing := hm.Hosts[hostinfo.vpnIp]	hm.Hosts[hostinfo.vpnIp] = hostinfo	if existing != nil {		hostinfo.next = existing		existing.prev = hostinfo	}	hm.Indexes[hostinfo.localIndexId] = hostinfo	hm.RemoteIndexes[hostinfo.remoteIndexId] = hostinfo	if hm.l.Level >= logrus.DebugLevel {		hm.l.WithField("hostMap", m{"mapName": hm.name, "vpnIp": hostinfo.vpnIp, "mapTotalSize": len(hm.Hosts),			"hostinfo": m{"existing": true, "localIndexId": hostinfo.localIndexId, "hostId": hostinfo.vpnIp}}).			Debug("Hostmap vpnIp added")	}	i := 1	check := hostinfo	for check != nil {		if i > MaxHostInfosPerVpnIp {			hm.unlockedDeleteHostInfo(check)		}		check = check.next		i++	}}// TryPromoteBest handles re-querying lighthouses and probing for better paths// NOTE: It is an error to call this if you are a lighthouse since they should not roam clients!func (i *HostInfo) TryPromoteBest(preferredRanges []*net.IPNet, ifce *Interface) {	c := i.promoteCounter.Add(1)	if c%PromoteEvery == 0 {		// The lock here is currently protecting i.remote access		i.RLock()		remote := i.remote		i.RUnlock()		// return early if we are already on a preferred remote		if remote != nil {			rIP := remote.IP			for _, l := range preferredRanges {				if l.Contains(rIP) {					return				}			}		}		i.remotes.ForEach(preferredRanges, func(addr *udp.Addr, preferred bool) {			if remote != nil && (addr == nil || !preferred) {				return			}			// Try to send a test packet to that host, this should			// cause it to detect a roaming event and switch remotes			ifce.sendTo(header.Test, header.TestRequest, i.ConnectionState, i, addr, []byte(""), make([]byte, 12, 12), make([]byte, mtu))		})	}	// Re query our lighthouses for new remotes occasionally	if c%ReQueryEvery == 0 && ifce.lightHouse != nil {		ifce.lightHouse.QueryServer(i.vpnIp, ifce)	}}func (i *HostInfo) cachePacket(l *logrus.Logger, t header.MessageType, st header.MessageSubType, packet []byte, f packetCallback, m *cachedPacketMetrics) {	//TODO: return the error so we can log with more context	if len(i.packetStore) < 100 {		tempPacket := make([]byte, len(packet))		copy(tempPacket, packet)		//l.WithField("trace", string(debug.Stack())).Error("Caching packet", tempPacket)		i.packetStore = append(i.packetStore, &cachedPacket{t, st, f, tempPacket})		if l.Level >= logrus.DebugLevel {			i.logger(l).				WithField("length", len(i.packetStore)).				WithField("stored", true).				Debugf("Packet store")		}	} else if l.Level >= logrus.DebugLevel {		m.dropped.Inc(1)		i.logger(l).			WithField("length", len(i.packetStore)).			WithField("stored", false).			Debugf("Packet store")	}}// handshakeComplete will set the connection as ready to communicate, as well as flush any stored packetsfunc (i *HostInfo) handshakeComplete(l *logrus.Logger, m *cachedPacketMetrics) {	//TODO: I'm not certain the distinction between handshake complete and ConnectionState being ready matters because:	//TODO: HandshakeComplete means send stored packets and ConnectionState.ready means we are ready to send	//TODO: if the transition from HandhsakeComplete to ConnectionState.ready happens all within this function they are identical	i.ConnectionState.queueLock.Lock()	i.HandshakeComplete = true	//TODO: this should be managed by the handshake state machine to set it based on how many handshake were seen.	// Clamping it to 2 gets us out of the woods for now	i.ConnectionState.messageCounter.Store(2)	if l.Level >= logrus.DebugLevel {		i.logger(l).Debugf("Sending %d stored packets", len(i.packetStore))	}	if len(i.packetStore) > 0 {		nb := make([]byte, 12, 12)		out := make([]byte, mtu)		for _, cp := range i.packetStore {			cp.callback(cp.messageType, cp.messageSubType, i, cp.packet, nb, out)		}		m.sent.Inc(int64(len(i.packetStore)))	}	i.remotes.ResetBlockedRemotes()	i.packetStore = make([]*cachedPacket, 0)	i.ConnectionState.ready = true	i.ConnectionState.queueLock.Unlock()}func (i *HostInfo) GetCert() *cert.NebulaCertificate {	if i.ConnectionState != nil {		return i.ConnectionState.peerCert	}	return nil}func (i *HostInfo) SetRemote(remote *udp.Addr) {	// We copy here because we likely got this remote from a source that reuses the object	if !i.remote.Equals(remote) {		i.remote = remote.Copy()		i.remotes.LearnRemote(i.vpnIp, remote.Copy())	}}// SetRemoteIfPreferred returns true if the remote was changed. The lastRoam// time on the HostInfo will also be updated.func (i *HostInfo) SetRemoteIfPreferred(hm *HostMap, newRemote *udp.Addr) bool {	if newRemote == nil {		// relays have nil udp Addrs		return false	}	currentRemote := i.remote	if currentRemote == nil {		i.SetRemote(newRemote)		return true	}	// NOTE: We do this loop here instead of calling `isPreferred` in	// remote_list.go so that we only have to loop over preferredRanges once.	newIsPreferred := false	for _, l := range hm.preferredRanges {		// return early if we are already on a preferred remote		if l.Contains(currentRemote.IP) {			return false		}		if l.Contains(newRemote.IP) {			newIsPreferred = true		}	}	if newIsPreferred {		// Consider this a roaming event		i.lastRoam = time.Now()		i.lastRoamRemote = currentRemote.Copy()		i.SetRemote(newRemote)		return true	}	return false}func (i *HostInfo) RecvErrorExceeded() bool {	if i.recvError < 3 {		i.recvError += 1		return false	}	return true}func (i *HostInfo) CreateRemoteCIDR(c *cert.NebulaCertificate) {	if len(c.Details.Ips) == 1 && len(c.Details.Subnets) == 0 {		// Simple case, no CIDRTree needed		return	}	remoteCidr := cidr.NewTree4()	for _, ip := range c.Details.Ips {		remoteCidr.AddCIDR(&net.IPNet{IP: ip.IP, Mask: net.IPMask{255, 255, 255, 255}}, struct{}{})	}	for _, n := range c.Details.Subnets {		remoteCidr.AddCIDR(n, struct{}{})	}	i.remoteCidr = remoteCidr}func (i *HostInfo) logger(l *logrus.Logger) *logrus.Entry {	if i == nil {		return logrus.NewEntry(l)	}	li := l.WithField("vpnIp", i.vpnIp).		WithField("localIndex", i.localIndexId).		WithField("remoteIndex", i.remoteIndexId)	if connState := i.ConnectionState; connState != nil {		if peerCert := connState.peerCert; peerCert != nil {			li = li.WithField("certName", peerCert.Details.Name)		}	}	return li}// Utility functionsfunc localIps(l *logrus.Logger, allowList *LocalAllowList) *[]net.IP {	//FIXME: This function is pretty garbage	var ips []net.IP	ifaces, _ := net.Interfaces()	for _, i := range ifaces {		allow := allowList.AllowName(i.Name)		if l.Level >= logrus.TraceLevel {			l.WithField("interfaceName", i.Name).WithField("allow", allow).Trace("localAllowList.AllowName")		}		if !allow {			continue		}		addrs, _ := i.Addrs()		for _, addr := range addrs {			var ip net.IP			switch v := addr.(type) {			case *net.IPNet:				//continue				ip = v.IP			case *net.IPAddr:				ip = v.IP			}			//TODO: Filtering out link local for now, this is probably the most correct thing			//TODO: Would be nice to filter out SLAAC MAC based ips as well			if ip.IsLoopback() == false && !ip.IsLinkLocalUnicast() {				allow := allowList.Allow(ip)				if l.Level >= logrus.TraceLevel {					l.WithField("localIp", ip).WithField("allow", allow).Trace("localAllowList.Allow")				}				if !allow {					continue				}				ips = append(ips, ip)			}		}	}	return &ips}
 |