handshake_manager.go 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624
  1. package nebula
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/rand"
  6. "encoding/binary"
  7. "errors"
  8. "log/slog"
  9. "net/netip"
  10. "slices"
  11. "sync"
  12. "time"
  13. "github.com/rcrowley/go-metrics"
  14. "github.com/slackhq/nebula/cert"
  15. "github.com/slackhq/nebula/handshake"
  16. "github.com/slackhq/nebula/header"
  17. "github.com/slackhq/nebula/udp"
  18. )
  19. const (
  20. DefaultHandshakeTryInterval = time.Millisecond * 100
  21. DefaultHandshakeRetries = 10
  22. DefaultHandshakeTriggerBuffer = 64
  23. // maxCachedPackets is how many unsent packets we'll buffer per pending
  24. // handshake before dropping further ones.
  25. maxCachedPackets = 100
  26. // HandshakePacket map keys mirror the IX protocol stage convention:
  27. // stage 0 = the initiator's first message (and what the responder
  28. // receives, stripped of header)
  29. // stage 2 = the responder's reply
  30. // Other handshake patterns will need new keys when added.
  31. handshakePacketStage0 uint8 = 0
  32. handshakePacketStage2 uint8 = 2
  33. )
  34. var (
  35. defaultHandshakeConfig = HandshakeConfig{
  36. tryInterval: DefaultHandshakeTryInterval,
  37. retries: DefaultHandshakeRetries,
  38. triggerBuffer: DefaultHandshakeTriggerBuffer,
  39. }
  40. )
  41. type HandshakeConfig struct {
  42. tryInterval time.Duration
  43. retries int64
  44. triggerBuffer int
  45. // Multiport lane parameters; laneCount == 0 means multiport is disabled.
  46. // laneCount includes implicit lane 0 (the base tunnel), so lanes
  47. // 1..laneCount-1 are initiated. lanePortCount/laneBasePort describe our
  48. // own bound port range and are advertised in every handshake payload.
  49. laneCount int
  50. lanePortCount uint16
  51. laneBasePort uint16
  52. messageMetrics *MessageMetrics
  53. }
  54. type HandshakeManager struct {
  55. // Mutex for interacting with the vpnIps and indexes maps
  56. sync.RWMutex
  57. vpnIps map[netip.Addr]*HandshakeHostInfo
  58. indexes map[uint32]*HandshakeHostInfo
  59. mainHostMap *HostMap
  60. lightHouse *LightHouse
  61. outside udp.Conn
  62. config HandshakeConfig
  63. OutboundHandshakeTimer *LockingTimerWheel[netip.Addr]
  64. // OutboundLaneTimer drives lane handshake retries. Lanes never enter
  65. // vpnIps (they would collide with base handshakes for the same address),
  66. // so their wheel is keyed by pending localIndexId instead.
  67. OutboundLaneTimer *LockingTimerWheel[uint32]
  68. messageMetrics *MessageMetrics
  69. metricInitiated metrics.Counter
  70. metricTimedOut metrics.Counter
  71. f *Interface
  72. l *slog.Logger
  73. // can be used to trigger outbound handshake for the given vpnIp
  74. trigger chan netip.Addr
  75. }
  76. type HandshakeHostInfo struct {
  77. sync.Mutex
  78. startTime time.Time // Time that we first started trying with this handshake
  79. ready bool // Is the handshake ready
  80. initiatingVersionOverride cert.Version // Should we use a non-default cert version for this handshake?
  81. counter int64 // How many attempts have we made so far
  82. lastRemotes []netip.AddrPort // Remotes that we sent to during the previous attempt
  83. lastRelays []netip.Addr // Relays we attempted to use during the previous attempt
  84. packetStore []*cachedPacket // A set of packets to be transmitted once the handshake completes
  85. hostinfo *HostInfo
  86. machine *handshake.Machine // The handshake state machine, set during stage 0 (initiator) or beginHandshake (responder multi-message)
  87. // laneTarget is the single pinned destination for a lane handshake
  88. // (base-tunnel remote IP at the peer's lane port). Lane handshakes never
  89. // broadcast to the RemoteList.
  90. laneTarget netip.AddrPort
  91. }
  92. func (hh *HandshakeHostInfo) cachePacket(l *slog.Logger, t header.MessageType, st header.MessageSubType, packet []byte, f packetCallback, m *cachedPacketMetrics) {
  93. if len(hh.packetStore) < maxCachedPackets {
  94. tempPacket := make([]byte, len(packet))
  95. copy(tempPacket, packet)
  96. hh.packetStore = append(hh.packetStore, &cachedPacket{t, st, f, tempPacket})
  97. if l.Enabled(context.Background(), slog.LevelDebug) {
  98. hh.hostinfo.logger(l).Debug("Packet store",
  99. "length", len(hh.packetStore),
  100. "stored", true,
  101. )
  102. }
  103. } else {
  104. m.dropped.Inc(1)
  105. if l.Enabled(context.Background(), slog.LevelDebug) {
  106. hh.hostinfo.logger(l).Debug("Packet store",
  107. "length", len(hh.packetStore),
  108. "stored", false,
  109. )
  110. }
  111. }
  112. }
  113. func NewHandshakeManager(l *slog.Logger, mainHostMap *HostMap, lightHouse *LightHouse, outside udp.Conn, config HandshakeConfig) *HandshakeManager {
  114. return &HandshakeManager{
  115. vpnIps: map[netip.Addr]*HandshakeHostInfo{},
  116. indexes: map[uint32]*HandshakeHostInfo{},
  117. mainHostMap: mainHostMap,
  118. lightHouse: lightHouse,
  119. outside: outside,
  120. config: config,
  121. trigger: make(chan netip.Addr, config.triggerBuffer),
  122. OutboundHandshakeTimer: NewLockingTimerWheel[netip.Addr](config.tryInterval, hsTimeout(config.retries, config.tryInterval)),
  123. OutboundLaneTimer: NewLockingTimerWheel[uint32](config.tryInterval, hsTimeout(config.retries, config.tryInterval)),
  124. messageMetrics: config.messageMetrics,
  125. metricInitiated: metrics.GetOrRegisterCounter("handshake_manager.initiated", nil),
  126. metricTimedOut: metrics.GetOrRegisterCounter("handshake_manager.timed_out", nil),
  127. l: l,
  128. }
  129. }
  130. func (hm *HandshakeManager) Run(ctx context.Context) {
  131. clockSource := time.NewTicker(hm.config.tryInterval)
  132. defer clockSource.Stop()
  133. for {
  134. select {
  135. case <-ctx.Done():
  136. return
  137. case vpnIP := <-hm.trigger:
  138. hm.handleOutbound(vpnIP, true)
  139. case now := <-clockSource.C:
  140. hm.NextOutboundHandshakeTimerTick(now)
  141. hm.NextOutboundLaneTimerTick(now)
  142. }
  143. }
  144. }
  145. func (hm *HandshakeManager) HandleIncoming(via ViaSender, packet []byte, h *header.H) {
  146. // Gate on known handshake subtypes. Unknown subtypes (or future ones we
  147. // don't yet support) are dropped here rather than silently routed through
  148. // the IX path. Add a case when introducing a new pattern.
  149. switch h.Subtype {
  150. case header.HandshakeIXPSK0:
  151. // supported
  152. default:
  153. hm.l.Debug("dropping handshake with unsupported subtype",
  154. "from", via, "subtype", h.Subtype)
  155. return
  156. }
  157. // First remote allow list check before we know the vpnIp
  158. if !via.IsRelayed {
  159. if !hm.lightHouse.GetRemoteAllowList().AllowUnknownVpnAddr(via.UdpAddr.Addr()) {
  160. hm.l.Debug("lighthouse.remote_allow_list denied incoming handshake", "from", via)
  161. return
  162. }
  163. }
  164. // First message of a new handshake. The wire format requires RemoteIndex
  165. // to be zero here (the initiator has no responder index to fill in yet),
  166. // and generateIndex never allocates 0, so any non-zero RemoteIndex on a
  167. // stage-1 packet is malformed or someone probing for an index collision.
  168. // Drop without paying the cost of running noise on a pending Machine.
  169. if h.MessageCounter == 1 {
  170. if h.RemoteIndex != 0 {
  171. hm.l.Debug("dropping stage-1 handshake with non-zero RemoteIndex",
  172. "from", via, "remoteIndex", h.RemoteIndex)
  173. return
  174. }
  175. hm.beginHandshake(via, packet, h)
  176. return
  177. }
  178. // Continuation message must match a pending handshake by index.
  179. // Anything else is an orphaned packet (e.g., late retransmit after
  180. // timeout) and is dropped.
  181. if hh := hm.queryIndex(h.RemoteIndex); hh != nil {
  182. hm.continueHandshake(via, hh, packet)
  183. return
  184. }
  185. }
  186. func (hm *HandshakeManager) NextOutboundHandshakeTimerTick(now time.Time) {
  187. hm.OutboundHandshakeTimer.Advance(now)
  188. for {
  189. vpnIp, has := hm.OutboundHandshakeTimer.Purge()
  190. if !has {
  191. break
  192. }
  193. hm.handleOutbound(vpnIp, false)
  194. }
  195. }
  196. func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthouseTriggered bool) {
  197. hh := hm.queryVpnIp(vpnIp)
  198. if hh == nil {
  199. return
  200. }
  201. hh.Lock()
  202. defer hh.Unlock()
  203. hostinfo := hh.hostinfo
  204. // If we are out of time, clean up
  205. if hh.counter >= hm.config.retries {
  206. fields := []any{
  207. "udpAddrs", hh.hostinfo.remotes.CopyAddrs(hm.mainHostMap.GetPreferredRanges()),
  208. "initiatorIndex", hh.hostinfo.localIndexId,
  209. "durationNs", time.Since(hh.startTime).Nanoseconds(),
  210. }
  211. // hh.machine can be nil here if buildStage0Packet never succeeded
  212. // (e.g., no certificate available). In that case there's no useful
  213. // handshake metadata to log.
  214. if hh.machine != nil {
  215. fields = append(fields, "handshake", m{
  216. "stage": uint64(hh.machine.MessageIndex()),
  217. "style": header.SubTypeName(header.Handshake, hh.machine.Subtype()),
  218. })
  219. }
  220. hh.hostinfo.logger(hm.l).Info("Handshake timed out", fields...)
  221. hm.metricTimedOut.Inc(1)
  222. hm.DeleteHostInfo(hostinfo)
  223. return
  224. }
  225. // Increment the counter to increase our delay, linear backoff
  226. hh.counter++
  227. // Check if we have a handshake packet to transmit yet
  228. if !hh.ready {
  229. if !hm.buildStage0Packet(hh) {
  230. hm.OutboundHandshakeTimer.Add(vpnIp, hm.config.tryInterval*time.Duration(hh.counter))
  231. return
  232. }
  233. }
  234. // TODO: this hardcodes "always retransmit stage 0", which is correct for
  235. // IX (the initiator only ever sends one packet, msg1) but wrong the
  236. // moment a 3+ message pattern lands. The retry loop should resend the
  237. // most recent outgoing message, not always stage 0. That implies
  238. // HandshakeHostInfo tracking a single "currentOutbound" packet (bytes +
  239. // header metadata) that gets replaced as the handshake progresses,
  240. // instead of indexing into HandshakePacket.
  241. stage0 := hostinfo.HandshakePacket[handshakePacketStage0]
  242. hsFields := m{
  243. "stage": uint64(hh.machine.MessageIndex()),
  244. "style": header.SubTypeName(header.Handshake, hh.machine.Subtype()),
  245. }
  246. // Get a remotes object if we don't already have one.
  247. // This is mainly to protect us as this should never be the case
  248. // NB ^ This comment doesn't jive. It's how the thing gets initialized.
  249. // It's the common path. Should it update every time, in case a future LH query/queries give us more info?
  250. if hostinfo.remotes == nil {
  251. hostinfo.remotes = hm.lightHouse.QueryCache([]netip.Addr{vpnIp})
  252. }
  253. remotes := hostinfo.remotes.CopyAddrs(hm.mainHostMap.GetPreferredRanges())
  254. remotesHaveChanged := !slices.Equal(remotes, hh.lastRemotes)
  255. // We only care about a lighthouse trigger if we have new remotes to send to.
  256. // This is a very specific optimization for a fast lighthouse reply.
  257. if lighthouseTriggered && !remotesHaveChanged {
  258. // If we didn't return here a lighthouse could cause us to aggressively send handshakes
  259. return
  260. }
  261. hh.lastRemotes = remotes
  262. // This will generate a load of queries for hosts with only 1 ip
  263. // (such as ones registered to the lighthouse with only a private IP)
  264. // So we only do it one time after attempting 5 handshakes already.
  265. if len(remotes) <= 1 && hh.counter == 5 {
  266. // If we only have 1 remote it is highly likely our query raced with the other host registered within the lighthouse
  267. // Our vpnIp here has a tunnel with a lighthouse but has yet to send a host update packet there so we only know about
  268. // the learned public ip for them. Query again to short circuit the promotion counter
  269. hm.lightHouse.QueryServer(vpnIp)
  270. }
  271. // Send the handshake to all known ips, stage 2 takes care of assigning the hostinfo.remote based on the first to reply
  272. var sentTo []netip.AddrPort
  273. hostinfo.remotes.ForEach(hm.mainHostMap.GetPreferredRanges(), func(addr netip.AddrPort, _ bool) {
  274. hm.messageMetrics.Tx(header.Handshake, hh.machine.Subtype(), 1)
  275. err := hm.outside.WriteTo(stage0, addr)
  276. if err != nil {
  277. // These repeat every attempt, so match the success log below and only shout when the remotes changed
  278. level := slog.LevelDebug
  279. if remotesHaveChanged {
  280. level = slog.LevelError
  281. }
  282. hostinfo.logger(hm.l).Log(context.Background(), level, "Failed to send handshake message",
  283. "udpAddr", addr,
  284. "initiatorIndex", hostinfo.localIndexId,
  285. "handshake", hsFields,
  286. "error", err,
  287. )
  288. } else {
  289. sentTo = append(sentTo, addr)
  290. }
  291. })
  292. // Don't be too noisy or confusing if we fail to send a handshake - if we don't get through we'll eventually log a timeout,
  293. // so only log when the list of remotes has changed
  294. if remotesHaveChanged {
  295. hostinfo.logger(hm.l).Info("Handshake message sent",
  296. "udpAddrs", sentTo,
  297. "initiatorIndex", hostinfo.localIndexId,
  298. "handshake", hsFields,
  299. )
  300. } else if hm.l.Enabled(context.Background(), slog.LevelDebug) {
  301. hostinfo.logger(hm.l).Debug("Handshake message sent",
  302. "udpAddrs", sentTo,
  303. "initiatorIndex", hostinfo.localIndexId,
  304. "handshake", hsFields,
  305. )
  306. }
  307. hm.f.relayManager.StartRelays(hm.f, vpnIp, hh, stage0)
  308. // If a lighthouse triggered this attempt then we are still in the timer wheel and do not need to re-add
  309. if !lighthouseTriggered {
  310. hm.OutboundHandshakeTimer.Add(vpnIp, hm.config.tryInterval*time.Duration(hh.counter))
  311. }
  312. }
  313. // GetOrHandshake will try to find a hostinfo with a fully formed tunnel or start a new handshake if one is not present
  314. // The 2nd argument will be true if the hostinfo is ready to transmit traffic
  315. func (hm *HandshakeManager) GetOrHandshake(vpnIp netip.Addr, cacheCb func(*HandshakeHostInfo)) (*HostInfo, bool) {
  316. hm.mainHostMap.RLock()
  317. h, ok := hm.mainHostMap.Hosts[vpnIp]
  318. hm.mainHostMap.RUnlock()
  319. if ok {
  320. // Do not attempt promotion if you are a lighthouse
  321. if !hm.lightHouse.amLighthouse {
  322. h.TryPromoteBest(hm.mainHostMap.GetPreferredRanges(), hm.f)
  323. }
  324. return h, true
  325. }
  326. return hm.StartHandshake(vpnIp, cacheCb), false
  327. }
  328. // StartHandshake will ensure a handshake is currently being attempted for the provided vpn ip
  329. func (hm *HandshakeManager) StartHandshake(vpnAddr netip.Addr, cacheCb func(*HandshakeHostInfo)) *HostInfo {
  330. hm.Lock()
  331. if hh, ok := hm.vpnIps[vpnAddr]; ok {
  332. // We are already trying to handshake with this vpn ip
  333. if cacheCb != nil {
  334. cacheCb(hh)
  335. }
  336. hm.Unlock()
  337. return hh.hostinfo
  338. }
  339. hostinfo := &HostInfo{
  340. vpnAddrs: []netip.Addr{vpnAddr},
  341. HandshakePacket: make(map[uint8][]byte, 0),
  342. relayState: RelayState{
  343. relays: nil,
  344. relayForByAddr: map[netip.Addr]*Relay{},
  345. relayForByIdx: map[uint32]*Relay{},
  346. },
  347. }
  348. hh := &HandshakeHostInfo{
  349. hostinfo: hostinfo,
  350. startTime: time.Now(),
  351. }
  352. hm.vpnIps[vpnAddr] = hh
  353. hm.metricInitiated.Inc(1)
  354. hm.OutboundHandshakeTimer.Add(vpnAddr, hm.config.tryInterval)
  355. if cacheCb != nil {
  356. cacheCb(hh)
  357. }
  358. // If this is a static host, we don't need to wait for the HostQueryReply
  359. // We can trigger the handshake right now
  360. _, doTrigger := hm.lightHouse.GetStaticHostList()[vpnAddr]
  361. if !doTrigger {
  362. // Add any calculated remotes, and trigger early handshake if one found
  363. doTrigger = hm.lightHouse.addCalculatedRemotes(vpnAddr)
  364. }
  365. if doTrigger {
  366. select {
  367. case hm.trigger <- vpnAddr:
  368. default:
  369. }
  370. }
  371. hm.Unlock()
  372. hm.lightHouse.QueryServer(vpnAddr)
  373. return hostinfo
  374. }
  375. var (
  376. ErrExistingHostInfo = errors.New("existing hostinfo")
  377. ErrAlreadySeen = errors.New("already seen")
  378. ErrLocalIndexCollision = errors.New("local index collision")
  379. )
  380. // CheckAndComplete checks for any conflicts in the main and pending hostmap
  381. // before adding hostinfo to main. If err is nil, it was added. Otherwise err will be:
  382. //
  383. // ErrAlreadySeen if we already have an entry in the hostmap that has seen the
  384. // exact same handshake packet
  385. //
  386. // ErrExistingHostInfo if we already have an entry in the hostmap for this
  387. // VpnIp and the new handshake was older than the one we currently have
  388. //
  389. // ErrLocalIndexCollision if we already have an entry in the main or pending
  390. // hostmap for the hostinfo.localIndexId.
  391. func (hm *HandshakeManager) CheckAndComplete(hostinfo *HostInfo, handshakePacket uint8, f *Interface) (*HostInfo, error) {
  392. hm.mainHostMap.Lock()
  393. defer hm.mainHostMap.Unlock()
  394. hm.Lock()
  395. defer hm.Unlock()
  396. // Check if we already have a tunnel with this vpn ip
  397. existingHostInfo, found := hm.mainHostMap.Hosts[hostinfo.vpnAddrs[0]]
  398. if found && existingHostInfo != nil {
  399. // Is it just a delayed handshake packet? Check every hostinfo we hold for this address.
  400. for _, testHostInfo := range hm.mainHostMap.unlockedGetHostList(hostinfo.vpnAddrs[0]) {
  401. if bytes.Equal(hostinfo.HandshakePacket[handshakePacket], testHostInfo.HandshakePacket[handshakePacket]) {
  402. return testHostInfo, ErrAlreadySeen
  403. }
  404. }
  405. // Is this a newer handshake?
  406. if existingHostInfo.lastHandshakeTime >= hostinfo.lastHandshakeTime && !existingHostInfo.ConnectionState.initiator {
  407. return existingHostInfo, ErrExistingHostInfo
  408. }
  409. existingHostInfo.logger(hm.l).Info("Taking new handshake")
  410. }
  411. existingIndex, found := hm.mainHostMap.Indexes[hostinfo.localIndexId]
  412. if found {
  413. // We have a collision, but for a different hostinfo
  414. return existingIndex, ErrLocalIndexCollision
  415. }
  416. existingPendingIndex, found := hm.indexes[hostinfo.localIndexId]
  417. if found && existingPendingIndex.hostinfo != hostinfo {
  418. // We have a collision, but for a different hostinfo
  419. return existingPendingIndex.hostinfo, ErrLocalIndexCollision
  420. }
  421. existingRemoteIndex, found := hm.mainHostMap.RemoteIndexes[hostinfo.remoteIndexId]
  422. if found && existingRemoteIndex != nil && existingRemoteIndex.vpnAddrs[0] != hostinfo.vpnAddrs[0] {
  423. // We have a collision, but this can happen since we can't control
  424. // the remote ID. Just log about the situation as a note.
  425. hostinfo.logger(hm.l).Info("New host shadows existing host remoteIndex",
  426. "collision", existingRemoteIndex.vpnAddrs,
  427. )
  428. }
  429. hm.mainHostMap.unlockedAddHostInfo(hostinfo, f)
  430. return existingHostInfo, nil
  431. }
  432. // Complete is a simpler version of CheckAndComplete when we already know we
  433. // won't have a localIndexId collision because we already have an entry in the
  434. // pendingHostMap. An existing hostinfo is returned if there was one.
  435. func (hm *HandshakeManager) Complete(hostinfo *HostInfo, f *Interface) {
  436. hm.mainHostMap.Lock()
  437. defer hm.mainHostMap.Unlock()
  438. hm.Lock()
  439. defer hm.Unlock()
  440. existingRemoteIndex, found := hm.mainHostMap.RemoteIndexes[hostinfo.remoteIndexId]
  441. if found && existingRemoteIndex != nil {
  442. // We have a collision, but this can happen since we can't control
  443. // the remote ID. Just log about the situation as a note.
  444. hostinfo.logger(hm.l).Info("New host shadows existing host remoteIndex",
  445. "collision", existingRemoteIndex.vpnAddrs,
  446. )
  447. }
  448. // We need to remove from the pending hostmap first to avoid undoing work when after to the main hostmap.
  449. hm.unlockedDeleteHostInfo(hostinfo)
  450. hm.mainHostMap.unlockedAddHostInfo(hostinfo, f)
  451. }
  452. // allocateIndex generates a unique localIndexId for this HostInfo
  453. // and adds it to the pendingHostMap. Will error if we are unable to generate
  454. // a unique localIndexId
  455. func (hm *HandshakeManager) allocateIndex(hh *HandshakeHostInfo) (uint32, error) {
  456. hm.mainHostMap.RLock()
  457. defer hm.mainHostMap.RUnlock()
  458. hm.Lock()
  459. defer hm.Unlock()
  460. for range 32 {
  461. index, err := generateIndex(hm.l)
  462. if err != nil {
  463. return 0, err
  464. }
  465. _, inPending := hm.indexes[index]
  466. _, inMain := hm.mainHostMap.Indexes[index]
  467. if !inMain && !inPending {
  468. hh.hostinfo.localIndexId = index
  469. hm.indexes[index] = hh
  470. return index, nil
  471. }
  472. }
  473. return 0, errors.New("failed to generate unique localIndexId")
  474. }
  475. func (hm *HandshakeManager) DeleteHostInfo(hostinfo *HostInfo) {
  476. hm.Lock()
  477. defer hm.Unlock()
  478. hm.unlockedDeleteHostInfo(hostinfo)
  479. }
  480. func (hm *HandshakeManager) unlockedDeleteHostInfo(hostinfo *HostInfo) {
  481. for _, addr := range hostinfo.vpnAddrs {
  482. // Only delete the pending entry if it is actually ours. Lane
  483. // handshakes never live in vpnIps, and an unconditional delete here
  484. // could evict a concurrently pending base handshake for the same
  485. // address.
  486. if cur, ok := hm.vpnIps[addr]; ok && cur.hostinfo == hostinfo {
  487. delete(hm.vpnIps, addr)
  488. }
  489. }
  490. if len(hm.vpnIps) == 0 {
  491. hm.vpnIps = map[netip.Addr]*HandshakeHostInfo{}
  492. }
  493. delete(hm.indexes, hostinfo.localIndexId)
  494. if len(hm.indexes) == 0 {
  495. hm.indexes = map[uint32]*HandshakeHostInfo{}
  496. }
  497. if hm.l.Enabled(context.Background(), slog.LevelDebug) {
  498. hm.l.Debug("Pending hostmap hostInfo deleted",
  499. "hostMap", m{"mapTotalSize": len(hm.vpnIps),
  500. "vpnAddrs": hostinfo.vpnAddrs, "indexNumber": hostinfo.localIndexId, "remoteIndexNumber": hostinfo.remoteIndexId},
  501. )
  502. }
  503. }
  504. func (hm *HandshakeManager) QueryVpnAddr(vpnIp netip.Addr) *HostInfo {
  505. hh := hm.queryVpnIp(vpnIp)
  506. if hh != nil {
  507. return hh.hostinfo
  508. }
  509. return nil
  510. }
  511. func (hm *HandshakeManager) queryVpnIp(vpnIp netip.Addr) *HandshakeHostInfo {
  512. hm.RLock()
  513. defer hm.RUnlock()
  514. return hm.vpnIps[vpnIp]
  515. }
  516. func (hm *HandshakeManager) QueryIndex(index uint32) *HostInfo {
  517. hh := hm.queryIndex(index)
  518. if hh != nil {
  519. return hh.hostinfo
  520. }
  521. return nil
  522. }
  523. func (hm *HandshakeManager) queryIndex(index uint32) *HandshakeHostInfo {
  524. hm.RLock()
  525. defer hm.RUnlock()
  526. return hm.indexes[index]
  527. }
  528. func (hm *HandshakeManager) GetPreferredRanges() []netip.Prefix {
  529. return hm.mainHostMap.GetPreferredRanges()
  530. }
  531. func (hm *HandshakeManager) ForEachVpnAddr(f controlEach) {
  532. hm.RLock()
  533. defer hm.RUnlock()
  534. for _, v := range hm.vpnIps {
  535. f(v.hostinfo)
  536. }
  537. }
  538. func (hm *HandshakeManager) ForEachIndex(f controlEach) {
  539. hm.RLock()
  540. defer hm.RUnlock()
  541. for _, v := range hm.indexes {
  542. f(v.hostinfo)
  543. }
  544. }
  545. func (hm *HandshakeManager) EmitStats() {
  546. hm.RLock()
  547. hostLen := len(hm.vpnIps)
  548. indexLen := len(hm.indexes)
  549. hm.RUnlock()
  550. metrics.GetOrRegisterGauge("hostmap.pending.hosts", nil).Update(int64(hostLen))
  551. metrics.GetOrRegisterGauge("hostmap.pending.indexes", nil).Update(int64(indexLen))
  552. hm.mainHostMap.EmitStats()
  553. }
  554. // Utility functions below
  555. func generateIndex(l *slog.Logger) (uint32, error) {
  556. b := make([]byte, 4)
  557. // Let zero mean we don't know the ID, so don't generate zero
  558. var index uint32
  559. for index == 0 {
  560. _, err := rand.Read(b)
  561. if err != nil {
  562. l.Error("Failed to generate index", "error", err)
  563. return 0, err
  564. }
  565. index = binary.BigEndian.Uint32(b)
  566. }
  567. if l.Enabled(context.Background(), slog.LevelDebug) {
  568. l.Debug("Generated index", "index", index)
  569. }
  570. return index, nil
  571. }
  572. func hsTimeout(tries int64, interval time.Duration) time.Duration {
  573. return time.Duration(tries / 2 * ((2 * int64(interval)) + (tries-1)*int64(interval)))
  574. }
  575. // buildStage0Packet creates the initial handshake packet for the initiator.
  576. func (hm *HandshakeManager) buildStage0Packet(hh *HandshakeHostInfo) bool {
  577. cs := hm.f.pki.getCertState()
  578. v := cs.DefaultVersion()
  579. if hh.initiatingVersionOverride != cert.VersionPre1 {
  580. v = hh.initiatingVersionOverride
  581. } else if v < cert.Version2 {
  582. for _, a := range hh.hostinfo.vpnAddrs {
  583. if a.Is6() {
  584. v = cert.Version2
  585. break
  586. }
  587. }
  588. }
  589. cred := cs.GetCredential(v)
  590. if cred == nil {
  591. hm.f.l.Error("Unable to handshake with host because no certificate is available",
  592. "vpnAddrs", hh.hostinfo.vpnAddrs, "certVersion", v)
  593. return false
  594. }
  595. machine, err := handshake.NewMachine(
  596. v, cs.GetCredential,
  597. hm.certVerifier(), func() (uint32, error) { return hm.allocateIndex(hh) },
  598. true, header.HandshakeIXPSK0,
  599. hm.laneAdvert(uint32(hh.hostinfo.laneIndex)),
  600. )
  601. if err != nil {
  602. hm.f.l.Error("Failed to create handshake machine",
  603. "vpnAddrs", hh.hostinfo.vpnAddrs, "error", err)
  604. return false
  605. }
  606. msg, err := machine.Initiate(nil)
  607. if err != nil {
  608. hm.f.l.Error("Failed to initiate handshake",
  609. "vpnAddrs", hh.hostinfo.vpnAddrs, "error", err)
  610. return false
  611. }
  612. // hostinfo.ConnectionState stays nil until the handshake completes in
  613. // continueHandshake. Pre-completion control surfaces guard with nil
  614. // checks; the data plane never observes a pending hostinfo.
  615. hh.hostinfo.HandshakePacket[handshakePacketStage0] = msg
  616. hh.machine = machine
  617. hh.ready = true
  618. return true
  619. }
  620. // laneAdvert returns our multiport advert for a handshake payload, or nil
  621. // when multiport is disabled (which keeps the payload byte-identical to
  622. // vanilla). laneIndex is 0 for base handshakes and our lane number for lane
  623. // handshakes.
  624. func (hm *HandshakeManager) laneAdvert(laneIndex uint32) *handshake.LaneDetails {
  625. if hm.config.laneCount == 0 {
  626. return nil
  627. }
  628. return &handshake.LaneDetails{
  629. PortCount: uint32(hm.config.lanePortCount),
  630. BasePort: uint32(hm.config.laneBasePort),
  631. LaneIndex: laneIndex,
  632. }
  633. }
  634. // maybeAllocLaneState attaches a laneState to a just-completed base tunnel
  635. // when both sides advertised multiport. Must run before the hostinfo becomes
  636. // visible in the hostmap: the data plane reads base.lanes lock-free.
  637. func (hm *HandshakeManager) maybeAllocLaneState(hostinfo *HostInfo, result *handshake.Result) {
  638. if hm.config.laneCount == 0 || result.PeerPortCount == 0 || result.PeerLaneIndex != 0 {
  639. return
  640. }
  641. peerPorts := result.PeerPortCount
  642. if peerPorts > 256 {
  643. // A certified-but-hostile peer doesn't get to size our state.
  644. peerPorts = 256
  645. }
  646. var offset uint16
  647. if len(hm.f.myVpnAddrs) > 0 && len(hostinfo.vpnAddrs) > 0 {
  648. offset = lanePortOffset(hm.f.myVpnAddrs[0], hostinfo.vpnAddrs[0], uint16(peerPorts))
  649. }
  650. hostinfo.lanes = newLaneState(hm.config.laneCount, uint16(peerPorts), uint16(result.PeerBasePort), offset)
  651. }
  652. // EnsureLanes starts lane handshakes for every empty, non-pending, retry-due
  653. // slot of a base tunnel that the data plane has asked for. Called on base
  654. // handshake completion (both sides) and from the connection manager's
  655. // per-tunnel tick, so a demanded lane is established, and a dead one
  656. // re-established, within one check interval subject to per-slot backoff.
  657. //
  658. // Demand is what makes lanes lazy: nothing is built when the base tunnel
  659. // completes, only when a routine actually has traffic for the peer and finds
  660. // its slot empty (see noteLaneDemand). Consuming the flag here rather than
  661. // leaving it set also means a lane that dies after its routine went quiet
  662. // stays dead instead of being rebuilt forever.
  663. func (hm *HandshakeManager) EnsureLanes(base *HostInfo) {
  664. ls := base.lanes
  665. if ls == nil || hm.config.laneCount <= 1 {
  666. return
  667. }
  668. now := time.Now()
  669. var starts []int
  670. ls.Lock()
  671. n := min(len(ls.txLanes), hm.config.laneCount)
  672. for i := 1; i < n; i++ {
  673. if ls.txLanes[i].Load() != nil || ls.txPending[i] || now.Before(ls.txRetryAt[i]) {
  674. continue
  675. }
  676. // Checked last: a slot that isn't startable keeps its demand for the
  677. // tick that can act on it.
  678. if !ls.takeLaneDemand(i) {
  679. continue
  680. }
  681. ls.txPending[i] = true
  682. starts = append(starts, i)
  683. }
  684. ls.Unlock()
  685. for _, i := range starts {
  686. hm.startLaneHandshake(base, i)
  687. }
  688. }
  689. // startLaneHandshake initiates lane i of base: a full Noise handshake from
  690. // local socket i to the peer's advertised lane port. The caller has already
  691. // claimed the slot (txPending[i] = true); every failure path must release it
  692. // via noteLaneFailure.
  693. func (hm *HandshakeManager) startLaneHandshake(base *HostInfo, i int) {
  694. ls := base.lanes
  695. remote := base.GetRemote()
  696. if !remote.IsValid() || ls.peerPortCount == 0 {
  697. // Relay-only peer (or a zero advert that should not have allocated
  698. // lanes). Retried if a direct path shows up later.
  699. ls.noteLaneFailure(i)
  700. return
  701. }
  702. target := netip.AddrPortFrom(remote.Addr(), ls.laneTargetPort(i))
  703. hostinfo := &HostInfo{
  704. vpnAddrs: slices.Clone(base.vpnAddrs),
  705. HandshakePacket: make(map[uint8][]byte, 0),
  706. relayState: RelayState{
  707. relays: nil,
  708. relayForByAddr: map[netip.Addr]*Relay{},
  709. relayForByIdx: map[uint32]*Relay{},
  710. },
  711. // A private RemoteList: SetRemote must never leak lane ports into the
  712. // shared lighthouse-learned cache that base handshakes broadcast to.
  713. remotes: NewRemoteList(base.vpnAddrs, nil),
  714. sockIdx: i,
  715. laneIndex: uint16(i),
  716. laneOwned: true,
  717. parent: base,
  718. }
  719. hh := &HandshakeHostInfo{
  720. hostinfo: hostinfo,
  721. startTime: time.Now(),
  722. laneTarget: target,
  723. }
  724. if cs := base.ConnectionState; cs != nil && cs.myCert != nil {
  725. // Pin the lane to the base tunnel's negotiated cert version rather
  726. // than re-running version selection.
  727. hh.initiatingVersionOverride = cs.myCert.Version()
  728. }
  729. // Build stage 0 eagerly: allocateIndex registers hh in hm.indexes so
  730. // continueHandshake can find it, and gives us the key for the lane timer.
  731. hh.Lock()
  732. ok := hm.buildStage0Packet(hh)
  733. hh.Unlock()
  734. if !ok {
  735. ls.noteLaneFailure(i)
  736. return
  737. }
  738. hostinfo.logger(hm.l).Info("Lane handshake started",
  739. "laneIndex", i,
  740. "udpAddr", target,
  741. "initiatorIndex", hostinfo.localIndexId,
  742. )
  743. hm.metricInitiated.Inc(1)
  744. hm.OutboundLaneTimer.Add(hostinfo.localIndexId, hm.config.tryInterval)
  745. hm.handleOutboundLane(hostinfo.localIndexId)
  746. }
  747. func (hm *HandshakeManager) NextOutboundLaneTimerTick(now time.Time) {
  748. hm.OutboundLaneTimer.Advance(now)
  749. for {
  750. idx, has := hm.OutboundLaneTimer.Purge()
  751. if !has {
  752. break
  753. }
  754. hm.handleOutboundLane(idx)
  755. }
  756. }
  757. // handleOutboundLane is handleOutbound for lane handshakes: single pinned
  758. // target, egress via the lane's own socket, no lighthouse and no relays.
  759. func (hm *HandshakeManager) handleOutboundLane(localIndex uint32) {
  760. hh := hm.queryIndex(localIndex)
  761. if hh == nil || !hh.hostinfo.isLane() {
  762. return
  763. }
  764. hh.Lock()
  765. defer hh.Unlock()
  766. hostinfo := hh.hostinfo
  767. if hh.counter >= hm.config.retries {
  768. hostinfo.logger(hm.l).Info("Lane handshake timed out",
  769. "laneIndex", hostinfo.laneIndex,
  770. "udpAddr", hh.laneTarget,
  771. "initiatorIndex", hostinfo.localIndexId,
  772. "durationNs", time.Since(hh.startTime).Nanoseconds(),
  773. )
  774. hm.metricTimedOut.Inc(1)
  775. hm.DeleteHostInfo(hostinfo)
  776. hostinfo.parent.lanes.noteLaneFailure(int(hostinfo.laneIndex))
  777. return
  778. }
  779. hh.counter++
  780. stage0 := hostinfo.HandshakePacket[handshakePacketStage0]
  781. hm.messageMetrics.Tx(header.Handshake, hh.machine.Subtype(), 1)
  782. err := hm.f.writers[hostinfo.sockIdx].WriteTo(stage0, hh.laneTarget)
  783. if err != nil {
  784. hostinfo.logger(hm.l).Error("Failed to send lane handshake message",
  785. "laneIndex", hostinfo.laneIndex,
  786. "udpAddr", hh.laneTarget,
  787. "initiatorIndex", hostinfo.localIndexId,
  788. "error", err,
  789. )
  790. } else if hm.l.Enabled(context.Background(), slog.LevelDebug) {
  791. hostinfo.logger(hm.l).Debug("Lane handshake message sent",
  792. "laneIndex", hostinfo.laneIndex,
  793. "udpAddr", hh.laneTarget,
  794. "initiatorIndex", hostinfo.localIndexId,
  795. )
  796. }
  797. hm.OutboundLaneTimer.Add(localIndex, hm.config.tryInterval*time.Duration(hh.counter))
  798. }
  799. // deletePendingHostInfo abandons a pending handshake. For lanes it also
  800. // releases the base's slot claim with failure backoff so ensureLanes can
  801. // retry later.
  802. func (hm *HandshakeManager) deletePendingHostInfo(hostinfo *HostInfo) {
  803. hm.DeleteHostInfo(hostinfo)
  804. if hostinfo.isLane() {
  805. hostinfo.parent.lanes.noteLaneFailure(int(hostinfo.laneIndex))
  806. }
  807. }
  808. // completeLane moves a finished lane out of the pending map and registers it
  809. // in the main hostmap's index maps (never Hosts). The caller publishes it to
  810. // the base's txLanes/peerLanes afterwards.
  811. func (hm *HandshakeManager) completeLane(hostinfo *HostInfo, f *Interface) {
  812. hm.mainHostMap.Lock()
  813. defer hm.mainHostMap.Unlock()
  814. hm.Lock()
  815. defer hm.Unlock()
  816. existingRemoteIndex, found := hm.mainHostMap.RemoteIndexes[hostinfo.remoteIndexId]
  817. if found && existingRemoteIndex != nil {
  818. hostinfo.logger(hm.l).Info("New lane shadows existing host remoteIndex",
  819. "collision", existingRemoteIndex.vpnAddrs,
  820. )
  821. }
  822. hm.unlockedDeleteHostInfo(hostinfo)
  823. hm.mainHostMap.unlockedAddLane(hostinfo, f)
  824. }
  825. // beginHandshake handles an incoming handshake packet that doesn't match any
  826. // existing pending handshake. It creates a new responder Machine and processes
  827. // the first message.
  828. func (hm *HandshakeManager) beginHandshake(via ViaSender, packet []byte, h *header.H) {
  829. f := hm.f
  830. cs := f.pki.getCertState()
  831. v := cs.DefaultVersion()
  832. if cs.GetCredential(v) == nil {
  833. f.l.Error("Unable to handshake with host because no certificate is available",
  834. "from", via, "certVersion", v)
  835. return
  836. }
  837. machine, err := handshake.NewMachine(
  838. v, cs.GetCredential,
  839. hm.certVerifier(), func() (uint32, error) { return generateIndex(f.l) },
  840. false, header.HandshakeIXPSK0,
  841. hm.laneAdvert(0),
  842. )
  843. if err != nil {
  844. f.l.Error("Failed to create handshake machine", "from", via, "error", err)
  845. return
  846. }
  847. response, result, err := machine.ProcessPacket(nil, packet)
  848. if err != nil {
  849. f.l.Error("Failed to process handshake packet", "from", via, "error", err)
  850. return
  851. }
  852. if result == nil {
  853. // Multi-message pattern: the responder Machine would need to be
  854. // registered in hm.indexes so a future inbound packet finds it via
  855. // continueHandshake. The current manager doesn't do that yet, so
  856. // fail loudly rather than silently dropping the in-flight handshake.
  857. // TODO: support multi-message responder flows (XX, pqIX, etc.).
  858. // See also the IX-shaped cipher key assignment in handshake.Machine.
  859. f.l.Error("multi-message handshake responder is not supported",
  860. "from", via, "error", handshake.ErrMultiMessageUnsupported)
  861. return
  862. }
  863. remoteCert := result.RemoteCert
  864. if remoteCert == nil {
  865. f.l.Error("Handshake did not produce a peer certificate", "from", via)
  866. return
  867. }
  868. // Validate peer identity
  869. vpnAddrs, anyVpnAddrsInCommon, ok := hm.validatePeerCert(via, remoteCert)
  870. if !ok {
  871. return
  872. }
  873. // A nonzero lane tag makes this a lane handshake for an existing base
  874. // tunnel rather than a (possibly duplicate) tunnel of its own.
  875. if result.PeerLaneIndex > 0 {
  876. hm.completeLaneResponder(via, packet, response, result, vpnAddrs)
  877. return
  878. }
  879. connState, err := newConnectionStateFromResult(result)
  880. if err != nil {
  881. f.l.Error("Discarding handshake with an invalid message index", "error", err, "vpnAddrs", vpnAddrs)
  882. return
  883. }
  884. hostinfo := &HostInfo{
  885. ConnectionState: connState,
  886. localIndexId: result.LocalIndex,
  887. remoteIndexId: result.RemoteIndex,
  888. vpnAddrs: vpnAddrs,
  889. HandshakePacket: make(map[uint8][]byte, 0),
  890. lastHandshakeTime: result.HandshakeTime,
  891. relayState: RelayState{
  892. relays: nil,
  893. relayForByAddr: map[netip.Addr]*Relay{},
  894. relayForByIdx: map[uint32]*Relay{},
  895. },
  896. }
  897. msg := "Handshake message received"
  898. if !anyVpnAddrsInCommon {
  899. msg = "Handshake message received, but no vpnNetworks in common."
  900. }
  901. f.l.Info(msg,
  902. "vpnAddrs", vpnAddrs,
  903. "from", via,
  904. "certName", remoteCert.Certificate.Name(),
  905. "certVersion", remoteCert.Certificate.Version(),
  906. "fingerprint", remoteCert.Fingerprint,
  907. "issuer", remoteCert.Certificate.Issuer(),
  908. "initiatorIndex", result.RemoteIndex,
  909. "responderIndex", result.LocalIndex,
  910. "handshake", m{"stage": uint64(machine.MessageIndex()), "style": header.SubTypeName(header.Handshake, machine.Subtype())},
  911. )
  912. // packet aliases the listener's incoming buffer, so this copy must stay.
  913. hostinfo.HandshakePacket[handshakePacketStage0] = make([]byte, len(packet[header.Len:]))
  914. copy(hostinfo.HandshakePacket[handshakePacketStage0], packet[header.Len:])
  915. // response was freshly allocated by ProcessPacket; safe to retain directly.
  916. if response != nil {
  917. hostinfo.HandshakePacket[handshakePacketStage2] = response
  918. }
  919. hostinfo.remotes = f.lightHouse.QueryCache(vpnAddrs)
  920. if !via.IsRelayed {
  921. hostinfo.SetRemote(via.UdpAddr)
  922. }
  923. hostinfo.buildNetworks(f.myVpnNetworksTable, remoteCert.Certificate)
  924. hm.maybeAllocLaneState(hostinfo, result)
  925. existing, err := hm.CheckAndComplete(hostinfo, handshakePacketStage0, f)
  926. if err != nil {
  927. hm.handleCheckAndCompleteError(err, existing, hostinfo, via)
  928. return
  929. }
  930. hm.sendHandshakeResponse(via, response, hostinfo, false)
  931. hostinfo.remotes.RefreshFromHandshake(vpnAddrs)
  932. hm.EnsureLanes(hostinfo)
  933. // Don't wait for UpdateWorker
  934. if f.lightHouse.IsAnyLighthouseAddr(vpnAddrs) {
  935. f.lightHouse.TriggerUpdate()
  936. }
  937. }
  938. // completeLaneResponder finishes the responder side of a lane handshake:
  939. // associate with the base tunnel by the peer's certified vpn address, dedup
  940. // replays per lane, register the lane in the index maps, and reply from the
  941. // arrival socket. Handshakes with no live base are dropped — the initiator's
  942. // retry loop converges once the base exists.
  943. func (hm *HandshakeManager) completeLaneResponder(via ViaSender, packet, response []byte, result *handshake.Result, vpnAddrs []netip.Addr) {
  944. f := hm.f
  945. if via.IsRelayed {
  946. hm.l.Debug("dropping relayed lane handshake", "vpnAddrs", vpnAddrs, "from", via)
  947. return
  948. }
  949. if hm.config.laneCount == 0 {
  950. hm.l.Debug("dropping lane handshake, multiport is disabled", "vpnAddrs", vpnAddrs, "from", via)
  951. return
  952. }
  953. base := hm.mainHostMap.QueryVpnAddr(vpnAddrs[0])
  954. if base == nil || base.ConnectionState == nil || base.lanes == nil {
  955. hm.l.Debug("dropping lane handshake with no base tunnel",
  956. "vpnAddrs", vpnAddrs, "from", via, "laneIndex", result.PeerLaneIndex)
  957. return
  958. }
  959. ls := base.lanes
  960. // The owner's lane index is bounded by its own advertised port count
  961. // (lanes are one-per-routine and PortCount == routines on the owner).
  962. laneIndex := result.PeerLaneIndex
  963. if laneIndex >= uint32(ls.peerPortCount) || laneIndex > 256 {
  964. hm.l.Debug("dropping lane handshake with out-of-range lane index",
  965. "vpnAddrs", vpnAddrs, "from", via, "laneIndex", laneIndex)
  966. return
  967. }
  968. // Per-lane replay dedup against the existing lane with the same index.
  969. stage0 := packet[header.Len:]
  970. var existing *HostInfo
  971. ls.Lock()
  972. for _, h := range ls.peerLanes {
  973. if h.laneIndex == uint16(laneIndex) {
  974. existing = h
  975. break
  976. }
  977. }
  978. ls.Unlock()
  979. if existing != nil {
  980. if bytes.Equal(stage0, existing.HandshakePacket[handshakePacketStage0]) {
  981. // Stage-0 retransmit: the peer is committed to the original
  982. // response's ephemeral keys, resend it from the arrival socket.
  983. if msg := existing.HandshakePacket[handshakePacketStage2]; msg != nil {
  984. hm.sendHandshakeResponse(via, msg, existing, true)
  985. }
  986. return
  987. }
  988. if existing.lastHandshakeTime >= result.HandshakeTime {
  989. existing.logger(hm.l).Debug("dropping stale lane handshake",
  990. "laneIndex", laneIndex, "from", via)
  991. return
  992. }
  993. // Newer handshake wins; the initiator only re-initiates after it
  994. // declared the old lane dead. Silent local teardown.
  995. hm.mainHostMap.DeleteHostInfo(existing)
  996. }
  997. connState, err := newConnectionStateFromResult(result)
  998. if err != nil {
  999. hm.l.Error("Discarding lane handshake with an invalid message index",
  1000. "error", err, "vpnAddrs", vpnAddrs, "laneIndex", laneIndex)
  1001. return
  1002. }
  1003. hostinfo := &HostInfo{
  1004. ConnectionState: connState,
  1005. localIndexId: result.LocalIndex,
  1006. remoteIndexId: result.RemoteIndex,
  1007. vpnAddrs: vpnAddrs,
  1008. HandshakePacket: make(map[uint8][]byte, 0),
  1009. lastHandshakeTime: result.HandshakeTime,
  1010. relayState: RelayState{
  1011. relays: nil,
  1012. relayForByAddr: map[netip.Addr]*Relay{},
  1013. relayForByIdx: map[uint32]*Relay{},
  1014. },
  1015. // Private RemoteList: lane roaming must not touch the shared
  1016. // lighthouse-learned cache.
  1017. remotes: NewRemoteList(vpnAddrs, nil),
  1018. sockIdx: via.SockIdx,
  1019. laneIndex: uint16(laneIndex),
  1020. laneOwned: false,
  1021. parent: base,
  1022. }
  1023. // packet aliases the listener's incoming buffer, so this copy must stay.
  1024. hostinfo.HandshakePacket[handshakePacketStage0] = make([]byte, len(stage0))
  1025. copy(hostinfo.HandshakePacket[handshakePacketStage0], stage0)
  1026. if response != nil {
  1027. hostinfo.HandshakePacket[handshakePacketStage2] = response
  1028. }
  1029. hostinfo.SetRemote(via.UdpAddr)
  1030. hostinfo.buildNetworks(f.myVpnNetworksTable, result.RemoteCert.Certificate)
  1031. // Index-collision checks, mirroring CheckAndComplete minus the Hosts
  1032. // dedup (lanes are keyed by (base, laneIndex), not by address).
  1033. hm.mainHostMap.Lock()
  1034. hm.Lock()
  1035. if existingIndex, found := hm.mainHostMap.Indexes[hostinfo.localIndexId]; found && existingIndex != hostinfo {
  1036. hm.Unlock()
  1037. hm.mainHostMap.Unlock()
  1038. hostinfo.logger(hm.l).Error("Failed to add lane due to localIndex collision", "laneIndex", laneIndex)
  1039. return
  1040. }
  1041. if existingPendingIndex, found := hm.indexes[hostinfo.localIndexId]; found && existingPendingIndex.hostinfo != hostinfo {
  1042. hm.Unlock()
  1043. hm.mainHostMap.Unlock()
  1044. hostinfo.logger(hm.l).Error("Failed to add lane due to pending localIndex collision", "laneIndex", laneIndex)
  1045. return
  1046. }
  1047. if existingRemoteIndex, found := hm.mainHostMap.RemoteIndexes[hostinfo.remoteIndexId]; found && existingRemoteIndex != nil {
  1048. hostinfo.logger(hm.l).Info("New lane shadows existing host remoteIndex",
  1049. "collision", existingRemoteIndex.vpnAddrs,
  1050. )
  1051. }
  1052. hm.mainHostMap.unlockedAddLane(hostinfo, f)
  1053. hm.Unlock()
  1054. hm.mainHostMap.Unlock()
  1055. ls.Lock()
  1056. ls.peerLanes = append(ls.peerLanes, hostinfo)
  1057. ls.Unlock()
  1058. hostinfo.logger(hm.l).Info("Lane handshake received",
  1059. "laneIndex", laneIndex,
  1060. "from", via,
  1061. "initiatorIndex", result.RemoteIndex,
  1062. "responderIndex", result.LocalIndex,
  1063. )
  1064. hm.sendHandshakeResponse(via, response, hostinfo, false)
  1065. }
  1066. // continueHandshake feeds an incoming packet to an existing pending handshake Machine.
  1067. func (hm *HandshakeManager) continueHandshake(via ViaSender, hh *HandshakeHostInfo, packet []byte) {
  1068. f := hm.f
  1069. hh.Lock()
  1070. defer hh.Unlock()
  1071. // Re-verify hh is still tracked. Between queryIndex returning and us taking
  1072. // hh.Lock, handleOutbound may have timed out and deleted it. Once we hold
  1073. // hh.Lock no other deleter can race our index: handleOutbound also takes
  1074. // hh.Lock first, and handleRecvError targets a main-hostmap entry with a
  1075. // different localIndexId.
  1076. hm.RLock()
  1077. cur, ok := hm.indexes[hh.hostinfo.localIndexId]
  1078. hm.RUnlock()
  1079. if !ok || cur != hh {
  1080. return
  1081. }
  1082. hostinfo := hh.hostinfo
  1083. if hostinfo.isLane() && via.IsRelayed {
  1084. // Lane handshakes are direct-only; a relayed continuation is a stray
  1085. // or a protocol violation. Drop without failing the machine so the
  1086. // direct stage-2 can still land.
  1087. f.l.Debug("dropping relayed lane handshake continuation",
  1088. "vpnAddrs", hostinfo.vpnAddrs, "from", via)
  1089. return
  1090. }
  1091. if !via.IsRelayed {
  1092. if !f.lightHouse.GetRemoteAllowList().AllowAll(hostinfo.vpnAddrs, via.UdpAddr.Addr()) {
  1093. f.l.Debug("lighthouse.remote_allow_list denied incoming handshake",
  1094. "vpnAddrs", hostinfo.vpnAddrs, "from", via)
  1095. return
  1096. }
  1097. }
  1098. machine := hh.machine
  1099. if machine == nil {
  1100. f.l.Error("No handshake machine available for continuation",
  1101. "vpnAddrs", hostinfo.vpnAddrs, "from", via)
  1102. hm.deletePendingHostInfo(hostinfo)
  1103. return
  1104. }
  1105. response, result, err := machine.ProcessPacket(nil, packet)
  1106. if err != nil {
  1107. // Recoverable errors are routine noise, log at Debug. Fatal errors get a Warn.
  1108. if machine.Failed() {
  1109. f.l.Warn("Failed to process handshake packet, abandoning",
  1110. "vpnAddrs", hostinfo.vpnAddrs, "from", via, "error", err)
  1111. hm.deletePendingHostInfo(hostinfo)
  1112. } else {
  1113. f.l.Debug("Failed to process handshake packet",
  1114. "vpnAddrs", hostinfo.vpnAddrs, "from", via, "error", err)
  1115. }
  1116. return
  1117. }
  1118. if response != nil {
  1119. hm.sendHandshakeResponse(via, response, hostinfo, false)
  1120. }
  1121. if result == nil {
  1122. return
  1123. }
  1124. // Handshake complete; build the ConnectionState now that we have keys and a verified peer cert.
  1125. cs, err := newConnectionStateFromResult(result)
  1126. if err != nil {
  1127. f.l.Error("Discarding handshake with an invalid message index", "error", err, "vpnAddrs", hostinfo.vpnAddrs)
  1128. hm.DeleteHostInfo(hostinfo)
  1129. return
  1130. }
  1131. hostinfo.ConnectionState = cs
  1132. remoteCert := result.RemoteCert
  1133. if remoteCert == nil {
  1134. f.l.Error("Handshake completed without peer certificate",
  1135. "vpnAddrs", hostinfo.vpnAddrs, "from", via)
  1136. hm.deletePendingHostInfo(hostinfo)
  1137. return
  1138. }
  1139. vpnNetworks := remoteCert.Certificate.Networks()
  1140. hostinfo.remoteIndexId = result.RemoteIndex
  1141. hostinfo.lastHandshakeTime = result.HandshakeTime
  1142. if !via.IsRelayed {
  1143. hostinfo.SetRemote(via.UdpAddr)
  1144. } else {
  1145. hostinfo.relayState.InsertRelayTo(via.relayHI.vpnAddrs[0])
  1146. }
  1147. // Verify correct host responded (initiator check)
  1148. vpnAddrs := make([]netip.Addr, len(vpnNetworks))
  1149. correctHostResponded := false
  1150. anyVpnAddrsInCommon := false
  1151. for i, network := range vpnNetworks {
  1152. // inside.go drops self-routed packets at the firewall stage, but we'd
  1153. // rather not let a self-handshake complete in the first place: it
  1154. // wastes a hostmap slot, suppresses no log, and obscures routing
  1155. // misconfig. Explicit refusal here mirrors the responder-side check
  1156. // in validatePeerCert.
  1157. if f.myVpnAddrsTable.Contains(network.Addr()) {
  1158. f.l.Error("Refusing to handshake with myself",
  1159. "vpnNetworks", vpnNetworks,
  1160. "from", via,
  1161. "certName", remoteCert.Certificate.Name(),
  1162. "certVersion", remoteCert.Certificate.Version(),
  1163. "fingerprint", remoteCert.Fingerprint,
  1164. "issuer", remoteCert.Certificate.Issuer(),
  1165. "handshake", m{"stage": uint64(machine.MessageIndex()), "style": header.SubTypeName(header.Handshake, machine.Subtype())},
  1166. )
  1167. hm.deletePendingHostInfo(hostinfo)
  1168. return
  1169. }
  1170. vpnAddrs[i] = network.Addr()
  1171. if hostinfo.vpnAddrs[0] == network.Addr() {
  1172. correctHostResponded = true
  1173. }
  1174. if f.myVpnNetworksTable.Contains(network.Addr()) {
  1175. anyVpnAddrsInCommon = true
  1176. }
  1177. }
  1178. if !correctHostResponded {
  1179. f.l.Info("Incorrect host responded to handshake",
  1180. "intendedVpnAddrs", hostinfo.vpnAddrs,
  1181. "haveVpnNetworks", vpnNetworks,
  1182. "from", via,
  1183. "certName", remoteCert.Certificate.Name(),
  1184. "certVersion", remoteCert.Certificate.Version(),
  1185. "fingerprint", remoteCert.Fingerprint,
  1186. "issuer", remoteCert.Certificate.Issuer(),
  1187. "handshake", m{"stage": uint64(machine.MessageIndex()), "style": header.SubTypeName(header.Handshake, machine.Subtype())},
  1188. )
  1189. if hostinfo.isLane() {
  1190. // No restart dance for lanes: close what the peer completed,
  1191. // release the slot with backoff, and let ensureLanes retry.
  1192. hm.deletePendingHostInfo(hostinfo)
  1193. hostinfo.vpnAddrs = vpnAddrs
  1194. f.sendCloseTunnel(hostinfo)
  1195. return
  1196. }
  1197. hm.DeleteHostInfo(hostinfo)
  1198. hm.StartHandshake(hostinfo.vpnAddrs[0], func(newHH *HandshakeHostInfo) {
  1199. newHH.hostinfo.remotes = hostinfo.remotes
  1200. newHH.hostinfo.remotes.BlockRemote(via)
  1201. newHH.packetStore = hh.packetStore
  1202. hh.packetStore = []*cachedPacket{}
  1203. hostinfo.vpnAddrs = vpnAddrs
  1204. f.sendCloseTunnel(hostinfo)
  1205. })
  1206. return
  1207. }
  1208. duration := time.Since(hh.startTime).Nanoseconds()
  1209. msg := "Handshake message received"
  1210. if !anyVpnAddrsInCommon {
  1211. msg = "Handshake message received, but no vpnNetworks in common."
  1212. }
  1213. f.l.Info(msg,
  1214. "vpnAddrs", vpnAddrs,
  1215. "from", via,
  1216. "certName", remoteCert.Certificate.Name(),
  1217. "certVersion", remoteCert.Certificate.Version(),
  1218. "fingerprint", remoteCert.Fingerprint,
  1219. "issuer", remoteCert.Certificate.Issuer(),
  1220. "initiatorIndex", result.LocalIndex,
  1221. "responderIndex", result.RemoteIndex,
  1222. "handshake", m{"stage": uint64(machine.MessageIndex()), "style": header.SubTypeName(header.Handshake, machine.Subtype())},
  1223. "durationNs", duration,
  1224. "sentCachedPackets", len(hh.packetStore),
  1225. )
  1226. hostinfo.vpnAddrs = vpnAddrs
  1227. hostinfo.buildNetworks(f.myVpnNetworksTable, remoteCert.Certificate)
  1228. if hostinfo.isLane() {
  1229. hm.completeLane(hostinfo, f)
  1230. // Publish to the data plane only after the lane is registered and its
  1231. // ConnectionState is fully populated; a routine that Loads non-nil
  1232. // must always see a usable tunnel.
  1233. ls := hostinfo.parent.lanes
  1234. i := int(hostinfo.laneIndex)
  1235. ls.Lock()
  1236. if i < len(ls.txPending) {
  1237. ls.txPending[i] = false
  1238. ls.txFails[i] = 0
  1239. }
  1240. ls.Unlock()
  1241. if i < len(ls.txLanes) {
  1242. ls.txLanes[i].Store(hostinfo)
  1243. }
  1244. f.metricHandshakes.Update(duration)
  1245. return
  1246. }
  1247. hm.maybeAllocLaneState(hostinfo, result)
  1248. hm.Complete(hostinfo, f)
  1249. hm.EnsureLanes(hostinfo)
  1250. if len(hh.packetStore) > 0 {
  1251. if f.l.Enabled(context.Background(), slog.LevelDebug) {
  1252. hostinfo.logger(f.l).Debug("Sending stored packets", "count", len(hh.packetStore))
  1253. }
  1254. nb := make([]byte, 12, 12)
  1255. out := make([]byte, mtu)
  1256. for _, cp := range hh.packetStore {
  1257. // TODO: use a SendBatch here. Each callback lands in
  1258. // sendNoMetrics -> WriteTo: one syscall per cached packet,
  1259. // where one sendmmsg could flush the whole store.
  1260. cp.callback(cp.messageType, cp.messageSubType, hostinfo, cp.packet, nb, out)
  1261. }
  1262. f.cachedPacketMetrics.sent.Inc(int64(len(hh.packetStore)))
  1263. }
  1264. hostinfo.remotes.RefreshFromHandshake(vpnAddrs)
  1265. f.metricHandshakes.Update(duration)
  1266. // Don't wait for UpdateWorker
  1267. if f.lightHouse.IsAnyLighthouseAddr(vpnAddrs) {
  1268. f.lightHouse.TriggerUpdate()
  1269. }
  1270. }
  1271. // validatePeerCert checks the peer certificate for self-connection and remote allow list.
  1272. // Returns the VPN addrs, whether any of them fall within one of our own VPN
  1273. // networks, and true if valid; false if rejected.
  1274. func (hm *HandshakeManager) validatePeerCert(via ViaSender, remoteCert *cert.CachedCertificate) ([]netip.Addr, bool, bool) {
  1275. f := hm.f
  1276. vpnNetworks := remoteCert.Certificate.Networks()
  1277. // The cert package rejects host certs with no networks at parse time, so
  1278. // reaching this state would mean an invariant was bypassed elsewhere.
  1279. // Refuse explicitly so downstream code (which indexes vpnAddrs[0]) can't
  1280. // panic if that invariant ever changes.
  1281. if len(vpnNetworks) == 0 {
  1282. f.l.Info("No networks in certificate",
  1283. "from", via, "cert", remoteCert)
  1284. return nil, false, false
  1285. }
  1286. vpnAddrs := make([]netip.Addr, len(vpnNetworks))
  1287. anyVpnAddrsInCommon := false
  1288. for i, network := range vpnNetworks {
  1289. if f.myVpnAddrsTable.Contains(network.Addr()) {
  1290. f.l.Error("Refusing to handshake with myself",
  1291. "vpnNetworks", vpnNetworks,
  1292. "from", via,
  1293. "certName", remoteCert.Certificate.Name(),
  1294. "certVersion", remoteCert.Certificate.Version(),
  1295. "fingerprint", remoteCert.Fingerprint,
  1296. "issuer", remoteCert.Certificate.Issuer(),
  1297. )
  1298. return nil, false, false
  1299. }
  1300. vpnAddrs[i] = network.Addr()
  1301. if f.myVpnNetworksTable.Contains(network.Addr()) {
  1302. anyVpnAddrsInCommon = true
  1303. }
  1304. }
  1305. if !via.IsRelayed {
  1306. if !f.lightHouse.GetRemoteAllowList().AllowAll(vpnAddrs, via.UdpAddr.Addr()) {
  1307. f.l.Debug("lighthouse.remote_allow_list denied incoming handshake",
  1308. "vpnAddrs", vpnAddrs, "from", via)
  1309. return nil, false, false
  1310. }
  1311. }
  1312. return vpnAddrs, anyVpnAddrsInCommon, true
  1313. }
  1314. // sendHandshakeResponse sends a handshake response via the appropriate transport.
  1315. // cached is true when msg is a stored response being retransmitted because
  1316. // the peer's stage-1 retransmit landed (the ErrAlreadySeen path); false on a
  1317. // fresh response.
  1318. func (hm *HandshakeManager) sendHandshakeResponse(via ViaSender, msg []byte, hostinfo *HostInfo, cached bool) {
  1319. if msg == nil {
  1320. return
  1321. }
  1322. f := hm.f
  1323. f.messageMetrics.Tx(header.Handshake, header.MessageSubType(msg[1]), 1)
  1324. // Common log fields. peerCert may be nil during intermediate
  1325. // multi-message flows (handshake hasn't completed yet); skip the cert
  1326. // block if so.
  1327. logFields := []any{
  1328. "vpnAddrs", hostinfo.vpnAddrs,
  1329. "handshake", m{"stage": uint64(2), "style": header.SubTypeName(header.Handshake, header.HandshakeIXPSK0)},
  1330. "cached", cached,
  1331. "initiatorIndex", hostinfo.remoteIndexId,
  1332. "responderIndex", hostinfo.localIndexId,
  1333. }
  1334. if peerCert := hostinfo.ConnectionState.peerCert; peerCert != nil {
  1335. logFields = append(logFields,
  1336. "certName", peerCert.Certificate.Name(),
  1337. "certVersion", peerCert.Certificate.Version(),
  1338. "fingerprint", peerCert.Fingerprint,
  1339. "issuer", peerCert.Certificate.Issuer(),
  1340. )
  1341. }
  1342. if !via.IsRelayed {
  1343. fields := append(logFields, "from", via)
  1344. // Reply from the socket the handshake arrived on so the initiator sees
  1345. // the source port it targeted. Identical to f.outside under vanilla
  1346. // config (all writers share one port); required for multiport lanes.
  1347. err := f.writers[via.SockIdx].WriteTo(msg, via.UdpAddr)
  1348. if err != nil {
  1349. f.l.Error("Failed to send handshake message", append(fields, "error", err)...)
  1350. } else {
  1351. f.l.Info("Handshake message sent", fields...)
  1352. }
  1353. } else {
  1354. if via.relay == nil {
  1355. f.l.Error("Handshake send failed: both addr and via.relay are nil.")
  1356. return
  1357. }
  1358. hostinfo.relayState.InsertRelayTo(via.relayHI.vpnAddrs[0])
  1359. // We received a valid handshake on this relay, so make sure the relay
  1360. // state reflects that, in case it had been marked Disestablished.
  1361. via.relayHI.relayState.UpdateRelayForByIdxState(via.relay.LocalIndex, Established)
  1362. f.SendVia(via.relayHI, via.relay, msg, make([]byte, 12), make([]byte, mtu), false, 0)
  1363. f.l.Info("Handshake message sent", append(logFields, "relay", via.relayHI.vpnAddrs[0])...)
  1364. }
  1365. }
  1366. // handleCheckAndCompleteError handles errors from CheckAndComplete.
  1367. // This only fires from the responder-side beginHandshake path, after the
  1368. // peer cert has been validated and ConnectionState populated, so peerCert
  1369. // is always non-nil for the cases that log it.
  1370. func (hm *HandshakeManager) handleCheckAndCompleteError(err error, existing, hostinfo *HostInfo, via ViaSender) {
  1371. f := hm.f
  1372. peerCert := hostinfo.ConnectionState.peerCert
  1373. hsFields := m{"stage": uint64(1), "style": header.SubTypeName(header.Handshake, header.HandshakeIXPSK0)}
  1374. switch err {
  1375. case ErrAlreadySeen:
  1376. if existing.SetRemoteIfPreferred(f.hostMap, via) {
  1377. f.SendMessageToVpnAddr(header.Test, header.TestRequest, hostinfo.vpnAddrs[0], []byte(""), make([]byte, 12, 12), make([]byte, mtu))
  1378. }
  1379. // Resend the original response. The peer is committed to that response's
  1380. // ephemeral keys; a freshly-built one would have different keys and break
  1381. // the tunnel even though both sides "completed" the handshake.
  1382. if msg := existing.HandshakePacket[handshakePacketStage2]; msg != nil {
  1383. hm.sendHandshakeResponse(via, msg, existing, true)
  1384. }
  1385. case ErrExistingHostInfo:
  1386. f.l.Info("Handshake too old",
  1387. "vpnAddrs", hostinfo.vpnAddrs,
  1388. "from", via,
  1389. "certName", peerCert.Certificate.Name(),
  1390. "certVersion", peerCert.Certificate.Version(),
  1391. "fingerprint", peerCert.Fingerprint,
  1392. "issuer", peerCert.Certificate.Issuer(),
  1393. "oldHandshakeTime", existing.lastHandshakeTime,
  1394. "newHandshakeTime", hostinfo.lastHandshakeTime,
  1395. "initiatorIndex", hostinfo.remoteIndexId,
  1396. "responderIndex", hostinfo.localIndexId,
  1397. "handshake", hsFields,
  1398. )
  1399. f.SendMessageToVpnAddr(header.Test, header.TestRequest, hostinfo.vpnAddrs[0], []byte(""), make([]byte, 12, 12), make([]byte, mtu))
  1400. case ErrLocalIndexCollision:
  1401. f.l.Error("Failed to add HostInfo due to localIndex collision",
  1402. "vpnAddrs", hostinfo.vpnAddrs,
  1403. "from", via,
  1404. "certName", peerCert.Certificate.Name(),
  1405. "certVersion", peerCert.Certificate.Version(),
  1406. "fingerprint", peerCert.Fingerprint,
  1407. "issuer", peerCert.Certificate.Issuer(),
  1408. "localIndex", hostinfo.localIndexId,
  1409. "initiatorIndex", hostinfo.remoteIndexId,
  1410. "responderIndex", hostinfo.localIndexId,
  1411. "handshake", hsFields,
  1412. )
  1413. default:
  1414. f.l.Error("Failed to add HostInfo to HostMap",
  1415. "vpnAddrs", hostinfo.vpnAddrs,
  1416. "from", via,
  1417. "error", err,
  1418. "certName", peerCert.Certificate.Name(),
  1419. "certVersion", peerCert.Certificate.Version(),
  1420. "fingerprint", peerCert.Fingerprint,
  1421. "issuer", peerCert.Certificate.Issuer(),
  1422. "initiatorIndex", hostinfo.remoteIndexId,
  1423. "responderIndex", hostinfo.localIndexId,
  1424. "handshake", hsFields,
  1425. )
  1426. }
  1427. }
  1428. // certVerifier returns a CertVerifier that validates certs against the current CA pool.
  1429. func (hm *HandshakeManager) certVerifier() handshake.CertVerifier {
  1430. return func(c cert.Certificate) (*cert.CachedCertificate, error) {
  1431. return hm.f.pki.GetCAPool().VerifyCertificate(time.Now(), c)
  1432. }
  1433. }