handshake_manager.go 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  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 may carry traffic. 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. messageMetrics *MessageMetrics
  65. metricInitiated metrics.Counter
  66. metricTimedOut metrics.Counter
  67. f *Interface
  68. l *slog.Logger
  69. // can be used to trigger outbound handshake for the given vpnIp
  70. trigger chan netip.Addr
  71. }
  72. type HandshakeHostInfo struct {
  73. sync.Mutex
  74. startTime time.Time // Time that we first started trying with this handshake
  75. ready bool // Is the handshake ready
  76. initiatingVersionOverride cert.Version // Should we use a non-default cert version for this handshake?
  77. counter int64 // How many attempts have we made so far
  78. lastRemotes []netip.AddrPort // Remotes that we sent to during the previous attempt
  79. lastRelays []netip.Addr // Relays we attempted to use during the previous attempt
  80. packetStore []*cachedPacket // A set of packets to be transmitted once the handshake completes
  81. hostinfo *HostInfo
  82. machine *handshake.Machine // The handshake state machine, set during stage 0 (initiator) or beginHandshake (responder multi-message)
  83. }
  84. func (hh *HandshakeHostInfo) cachePacket(l *slog.Logger, t header.MessageType, st header.MessageSubType, packet []byte, f packetCallback, m *cachedPacketMetrics) {
  85. if len(hh.packetStore) < maxCachedPackets {
  86. tempPacket := make([]byte, len(packet))
  87. copy(tempPacket, packet)
  88. hh.packetStore = append(hh.packetStore, &cachedPacket{t, st, f, tempPacket})
  89. if l.Enabled(context.Background(), slog.LevelDebug) {
  90. hh.hostinfo.logger(l).Debug("Packet store",
  91. "length", len(hh.packetStore),
  92. "stored", true,
  93. )
  94. }
  95. } else {
  96. m.dropped.Inc(1)
  97. if l.Enabled(context.Background(), slog.LevelDebug) {
  98. hh.hostinfo.logger(l).Debug("Packet store",
  99. "length", len(hh.packetStore),
  100. "stored", false,
  101. )
  102. }
  103. }
  104. }
  105. func NewHandshakeManager(l *slog.Logger, mainHostMap *HostMap, lightHouse *LightHouse, outside udp.Conn, config HandshakeConfig) *HandshakeManager {
  106. return &HandshakeManager{
  107. vpnIps: map[netip.Addr]*HandshakeHostInfo{},
  108. indexes: map[uint32]*HandshakeHostInfo{},
  109. mainHostMap: mainHostMap,
  110. lightHouse: lightHouse,
  111. outside: outside,
  112. config: config,
  113. trigger: make(chan netip.Addr, config.triggerBuffer),
  114. OutboundHandshakeTimer: NewLockingTimerWheel[netip.Addr](config.tryInterval, hsTimeout(config.retries, config.tryInterval)),
  115. messageMetrics: config.messageMetrics,
  116. metricInitiated: metrics.GetOrRegisterCounter("handshake_manager.initiated", nil),
  117. metricTimedOut: metrics.GetOrRegisterCounter("handshake_manager.timed_out", nil),
  118. l: l,
  119. }
  120. }
  121. func (hm *HandshakeManager) Run(ctx context.Context) {
  122. clockSource := time.NewTicker(hm.config.tryInterval)
  123. defer clockSource.Stop()
  124. for {
  125. select {
  126. case <-ctx.Done():
  127. return
  128. case vpnIP := <-hm.trigger:
  129. hm.handleOutbound(vpnIP, true)
  130. case now := <-clockSource.C:
  131. hm.NextOutboundHandshakeTimerTick(now)
  132. }
  133. }
  134. }
  135. func (hm *HandshakeManager) HandleIncoming(via ViaSender, packet []byte, h *header.H) {
  136. // Gate on known handshake subtypes. Unknown subtypes (or future ones we
  137. // don't yet support) are dropped here rather than silently routed through
  138. // the IX path. Add a case when introducing a new pattern.
  139. switch h.Subtype {
  140. case header.HandshakeIXPSK0:
  141. // supported
  142. default:
  143. hm.l.Debug("dropping handshake with unsupported subtype",
  144. "from", via, "subtype", h.Subtype)
  145. return
  146. }
  147. // First remote allow list check before we know the vpnIp
  148. if !via.IsRelayed {
  149. if !hm.lightHouse.GetRemoteAllowList().AllowUnknownVpnAddr(via.UdpAddr.Addr()) {
  150. hm.l.Debug("lighthouse.remote_allow_list denied incoming handshake", "from", via)
  151. return
  152. }
  153. }
  154. // First message of a new handshake. The wire format requires RemoteIndex
  155. // to be zero here (the initiator has no responder index to fill in yet),
  156. // and generateIndex never allocates 0, so any non-zero RemoteIndex on a
  157. // stage-1 packet is malformed or someone probing for an index collision.
  158. // Drop without paying the cost of running noise on a pending Machine.
  159. if h.MessageCounter == 1 {
  160. if h.RemoteIndex != 0 {
  161. hm.l.Debug("dropping stage-1 handshake with non-zero RemoteIndex",
  162. "from", via, "remoteIndex", h.RemoteIndex)
  163. return
  164. }
  165. hm.beginHandshake(via, packet, h)
  166. return
  167. }
  168. // Continuation message must match a pending handshake by index.
  169. // Anything else is an orphaned packet (e.g., late retransmit after
  170. // timeout) and is dropped.
  171. if hh := hm.queryIndex(h.RemoteIndex); hh != nil {
  172. hm.continueHandshake(via, hh, packet)
  173. return
  174. }
  175. }
  176. func (hm *HandshakeManager) NextOutboundHandshakeTimerTick(now time.Time) {
  177. hm.OutboundHandshakeTimer.Advance(now)
  178. for {
  179. vpnIp, has := hm.OutboundHandshakeTimer.Purge()
  180. if !has {
  181. break
  182. }
  183. hm.handleOutbound(vpnIp, false)
  184. }
  185. }
  186. func (hm *HandshakeManager) handleOutbound(vpnIp netip.Addr, lighthouseTriggered bool) {
  187. hh := hm.queryVpnIp(vpnIp)
  188. if hh == nil {
  189. return
  190. }
  191. hh.Lock()
  192. defer hh.Unlock()
  193. hostinfo := hh.hostinfo
  194. // If we are out of time, clean up
  195. if hh.counter >= hm.config.retries {
  196. fields := []any{
  197. "udpAddrs", hh.hostinfo.remotes.CopyAddrs(hm.mainHostMap.GetPreferredRanges()),
  198. "initiatorIndex", hh.hostinfo.localIndexId,
  199. "durationNs", time.Since(hh.startTime).Nanoseconds(),
  200. }
  201. // hh.machine can be nil here if buildStage0Packet never succeeded
  202. // (e.g., no certificate available). In that case there's no useful
  203. // handshake metadata to log.
  204. if hh.machine != nil {
  205. fields = append(fields, "handshake", m{
  206. "stage": uint64(hh.machine.MessageIndex()),
  207. "style": header.SubTypeName(header.Handshake, hh.machine.Subtype()),
  208. })
  209. }
  210. hh.hostinfo.logger(hm.l).Info("Handshake timed out", fields...)
  211. hm.metricTimedOut.Inc(1)
  212. hm.DeleteHostInfo(hostinfo)
  213. return
  214. }
  215. // Increment the counter to increase our delay, linear backoff
  216. hh.counter++
  217. // Check if we have a handshake packet to transmit yet
  218. if !hh.ready {
  219. if !hm.buildStage0Packet(hh) {
  220. hm.OutboundHandshakeTimer.Add(vpnIp, hm.config.tryInterval*time.Duration(hh.counter))
  221. return
  222. }
  223. }
  224. // TODO: this hardcodes "always retransmit stage 0", which is correct for
  225. // IX (the initiator only ever sends one packet, msg1) but wrong the
  226. // moment a 3+ message pattern lands. The retry loop should resend the
  227. // most recent outgoing message, not always stage 0. That implies
  228. // HandshakeHostInfo tracking a single "currentOutbound" packet (bytes +
  229. // header metadata) that gets replaced as the handshake progresses,
  230. // instead of indexing into HandshakePacket.
  231. stage0 := hostinfo.HandshakePacket[handshakePacketStage0]
  232. hsFields := m{
  233. "stage": uint64(hh.machine.MessageIndex()),
  234. "style": header.SubTypeName(header.Handshake, hh.machine.Subtype()),
  235. }
  236. // Get a remotes object if we don't already have one.
  237. // This is mainly to protect us as this should never be the case
  238. // NB ^ This comment doesn't jive. It's how the thing gets initialized.
  239. // It's the common path. Should it update every time, in case a future LH query/queries give us more info?
  240. if hostinfo.remotes == nil {
  241. hostinfo.remotes = hm.lightHouse.QueryCache([]netip.Addr{vpnIp})
  242. }
  243. remotes := hostinfo.remotes.CopyAddrs(hm.mainHostMap.GetPreferredRanges())
  244. remotesHaveChanged := !slices.Equal(remotes, hh.lastRemotes)
  245. // We only care about a lighthouse trigger if we have new remotes to send to.
  246. // This is a very specific optimization for a fast lighthouse reply.
  247. if lighthouseTriggered && !remotesHaveChanged {
  248. // If we didn't return here a lighthouse could cause us to aggressively send handshakes
  249. return
  250. }
  251. hh.lastRemotes = remotes
  252. // This will generate a load of queries for hosts with only 1 ip
  253. // (such as ones registered to the lighthouse with only a private IP)
  254. // So we only do it one time after attempting 5 handshakes already.
  255. if len(remotes) <= 1 && hh.counter == 5 {
  256. // If we only have 1 remote it is highly likely our query raced with the other host registered within the lighthouse
  257. // Our vpnIp here has a tunnel with a lighthouse but has yet to send a host update packet there so we only know about
  258. // the learned public ip for them. Query again to short circuit the promotion counter
  259. hm.lightHouse.QueryServer(vpnIp)
  260. }
  261. // Send the handshake to all known ips, stage 2 takes care of assigning the hostinfo.remote based on the first to reply
  262. var sentTo []netip.AddrPort
  263. hostinfo.remotes.ForEach(hm.mainHostMap.GetPreferredRanges(), func(addr netip.AddrPort, _ bool) {
  264. hm.messageMetrics.Tx(header.Handshake, hh.machine.Subtype(), 1)
  265. err := hm.outside.WriteTo(stage0, addr)
  266. if err != nil {
  267. // These repeat every attempt, so match the success log below and only shout when the remotes changed
  268. level := slog.LevelDebug
  269. if remotesHaveChanged {
  270. level = slog.LevelError
  271. }
  272. hostinfo.logger(hm.l).Log(context.Background(), level, "Failed to send handshake message",
  273. "udpAddr", addr,
  274. "initiatorIndex", hostinfo.localIndexId,
  275. "handshake", hsFields,
  276. "error", err,
  277. )
  278. } else {
  279. sentTo = append(sentTo, addr)
  280. }
  281. })
  282. // 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,
  283. // so only log when the list of remotes has changed
  284. if remotesHaveChanged {
  285. hostinfo.logger(hm.l).Info("Handshake message sent",
  286. "udpAddrs", sentTo,
  287. "initiatorIndex", hostinfo.localIndexId,
  288. "handshake", hsFields,
  289. )
  290. } else if hm.l.Enabled(context.Background(), slog.LevelDebug) {
  291. hostinfo.logger(hm.l).Debug("Handshake message sent",
  292. "udpAddrs", sentTo,
  293. "initiatorIndex", hostinfo.localIndexId,
  294. "handshake", hsFields,
  295. )
  296. }
  297. hm.f.relayManager.StartRelays(hm.f, vpnIp, hh, stage0)
  298. // If a lighthouse triggered this attempt then we are still in the timer wheel and do not need to re-add
  299. if !lighthouseTriggered {
  300. hm.OutboundHandshakeTimer.Add(vpnIp, hm.config.tryInterval*time.Duration(hh.counter))
  301. }
  302. }
  303. // GetOrHandshake will try to find a hostinfo with a fully formed tunnel or start a new handshake if one is not present
  304. // The 2nd argument will be true if the hostinfo is ready to transmit traffic
  305. func (hm *HandshakeManager) GetOrHandshake(vpnIp netip.Addr, cacheCb func(*HandshakeHostInfo)) (*HostInfo, bool) {
  306. hm.mainHostMap.RLock()
  307. h, ok := hm.mainHostMap.Hosts[vpnIp]
  308. hm.mainHostMap.RUnlock()
  309. if ok {
  310. // Do not attempt promotion if you are a lighthouse
  311. if !hm.lightHouse.amLighthouse {
  312. h.TryPromoteBest(hm.mainHostMap.GetPreferredRanges(), hm.f)
  313. }
  314. return h, true
  315. }
  316. return hm.StartHandshake(vpnIp, cacheCb), false
  317. }
  318. // StartHandshake will ensure a handshake is currently being attempted for the provided vpn ip
  319. func (hm *HandshakeManager) StartHandshake(vpnAddr netip.Addr, cacheCb func(*HandshakeHostInfo)) *HostInfo {
  320. hm.Lock()
  321. if hh, ok := hm.vpnIps[vpnAddr]; ok {
  322. // We are already trying to handshake with this vpn ip
  323. if cacheCb != nil {
  324. cacheCb(hh)
  325. }
  326. hm.Unlock()
  327. return hh.hostinfo
  328. }
  329. hostinfo := &HostInfo{
  330. vpnAddrs: []netip.Addr{vpnAddr},
  331. HandshakePacket: make(map[uint8][]byte, 0),
  332. relayState: RelayState{
  333. relays: nil,
  334. relayForByAddr: map[netip.Addr]*Relay{},
  335. relayForByIdx: map[uint32]*Relay{},
  336. },
  337. }
  338. hh := &HandshakeHostInfo{
  339. hostinfo: hostinfo,
  340. startTime: time.Now(),
  341. }
  342. hm.vpnIps[vpnAddr] = hh
  343. hm.metricInitiated.Inc(1)
  344. hm.OutboundHandshakeTimer.Add(vpnAddr, hm.config.tryInterval)
  345. if cacheCb != nil {
  346. cacheCb(hh)
  347. }
  348. // If this is a static host, we don't need to wait for the HostQueryReply
  349. // We can trigger the handshake right now
  350. _, doTrigger := hm.lightHouse.GetStaticHostList()[vpnAddr]
  351. if !doTrigger {
  352. // Add any calculated remotes, and trigger early handshake if one found
  353. doTrigger = hm.lightHouse.addCalculatedRemotes(vpnAddr)
  354. }
  355. if doTrigger {
  356. select {
  357. case hm.trigger <- vpnAddr:
  358. default:
  359. }
  360. }
  361. hm.Unlock()
  362. hm.lightHouse.QueryServer(vpnAddr)
  363. return hostinfo
  364. }
  365. var (
  366. ErrExistingHostInfo = errors.New("existing hostinfo")
  367. ErrAlreadySeen = errors.New("already seen")
  368. ErrLocalIndexCollision = errors.New("local index collision")
  369. )
  370. // CheckAndComplete checks for any conflicts in the main and pending hostmap
  371. // before adding hostinfo to main. If err is nil, it was added. Otherwise err will be:
  372. //
  373. // ErrAlreadySeen if we already have an entry in the hostmap that has seen the
  374. // exact same handshake packet
  375. //
  376. // ErrExistingHostInfo if we already have an entry in the hostmap for this
  377. // VpnIp and the new handshake was older than the one we currently have
  378. //
  379. // ErrLocalIndexCollision if we already have an entry in the main or pending
  380. // hostmap for the hostinfo.localIndexId.
  381. func (hm *HandshakeManager) CheckAndComplete(hostinfo *HostInfo, handshakePacket uint8, f *Interface) (*HostInfo, error) {
  382. hm.mainHostMap.Lock()
  383. defer hm.mainHostMap.Unlock()
  384. hm.Lock()
  385. defer hm.Unlock()
  386. // Check if we already have a tunnel with this vpn ip
  387. existingHostInfo, found := hm.mainHostMap.Hosts[hostinfo.vpnAddrs[0]]
  388. if found && existingHostInfo != nil {
  389. // Is it just a delayed handshake packet? Check every hostinfo we hold for this address.
  390. for _, testHostInfo := range hm.mainHostMap.unlockedGetHostList(hostinfo.vpnAddrs[0]) {
  391. if bytes.Equal(hostinfo.HandshakePacket[handshakePacket], testHostInfo.HandshakePacket[handshakePacket]) {
  392. return testHostInfo, ErrAlreadySeen
  393. }
  394. }
  395. // Is this a newer handshake?
  396. if existingHostInfo.lastHandshakeTime >= hostinfo.lastHandshakeTime && !existingHostInfo.ConnectionState.initiator {
  397. return existingHostInfo, ErrExistingHostInfo
  398. }
  399. existingHostInfo.logger(hm.l).Info("Taking new handshake")
  400. }
  401. existingIndex, found := hm.mainHostMap.Indexes[hostinfo.localIndexId]
  402. if found {
  403. // We have a collision, but for a different hostinfo
  404. return existingIndex, ErrLocalIndexCollision
  405. }
  406. existingPendingIndex, found := hm.indexes[hostinfo.localIndexId]
  407. if found && existingPendingIndex.hostinfo != hostinfo {
  408. // We have a collision, but for a different hostinfo
  409. return existingPendingIndex.hostinfo, ErrLocalIndexCollision
  410. }
  411. existingRemoteIndex, found := hm.mainHostMap.RemoteIndexes[hostinfo.remoteIndexId]
  412. if found && existingRemoteIndex != nil && existingRemoteIndex.vpnAddrs[0] != hostinfo.vpnAddrs[0] {
  413. // We have a collision, but this can happen since we can't control
  414. // the remote ID. Just log about the situation as a note.
  415. hostinfo.logger(hm.l).Info("New host shadows existing host remoteIndex",
  416. "collision", existingRemoteIndex.vpnAddrs,
  417. )
  418. }
  419. hm.mainHostMap.unlockedAddHostInfo(hostinfo, f)
  420. return existingHostInfo, nil
  421. }
  422. // Complete is a simpler version of CheckAndComplete when we already know we
  423. // won't have a localIndexId collision because we already have an entry in the
  424. // pendingHostMap. An existing hostinfo is returned if there was one.
  425. func (hm *HandshakeManager) Complete(hostinfo *HostInfo, f *Interface) {
  426. hm.mainHostMap.Lock()
  427. defer hm.mainHostMap.Unlock()
  428. hm.Lock()
  429. defer hm.Unlock()
  430. existingRemoteIndex, found := hm.mainHostMap.RemoteIndexes[hostinfo.remoteIndexId]
  431. if found && existingRemoteIndex != nil {
  432. // We have a collision, but this can happen since we can't control
  433. // the remote ID. Just log about the situation as a note.
  434. hostinfo.logger(hm.l).Info("New host shadows existing host remoteIndex",
  435. "collision", existingRemoteIndex.vpnAddrs,
  436. )
  437. }
  438. // We need to remove from the pending hostmap first to avoid undoing work when after to the main hostmap.
  439. hm.unlockedDeleteHostInfo(hostinfo)
  440. hm.mainHostMap.unlockedAddHostInfo(hostinfo, f)
  441. }
  442. // allocateIndex generates a unique localIndexId for this HostInfo
  443. // and adds it to the pendingHostMap. Will error if we are unable to generate
  444. // a unique localIndexId
  445. func (hm *HandshakeManager) allocateIndex(hh *HandshakeHostInfo) (uint32, error) {
  446. hm.mainHostMap.RLock()
  447. defer hm.mainHostMap.RUnlock()
  448. hm.Lock()
  449. defer hm.Unlock()
  450. for range 32 {
  451. index, err := generateIndex(hm.l)
  452. if err != nil {
  453. return 0, err
  454. }
  455. _, inPending := hm.indexes[index]
  456. _, inMain := hm.mainHostMap.Indexes[index]
  457. if !inMain && !inPending {
  458. hh.hostinfo.localIndexId = index
  459. hm.indexes[index] = hh
  460. return index, nil
  461. }
  462. }
  463. return 0, errors.New("failed to generate unique localIndexId")
  464. }
  465. func (hm *HandshakeManager) DeleteHostInfo(hostinfo *HostInfo) {
  466. hm.Lock()
  467. defer hm.Unlock()
  468. hm.unlockedDeleteHostInfo(hostinfo)
  469. }
  470. func (hm *HandshakeManager) unlockedDeleteHostInfo(hostinfo *HostInfo) {
  471. for _, addr := range hostinfo.vpnAddrs {
  472. // Only delete the pending entry if it is actually ours: an
  473. // unconditional delete could evict a concurrently pending handshake for
  474. // the same address.
  475. if cur, ok := hm.vpnIps[addr]; ok && cur.hostinfo == hostinfo {
  476. delete(hm.vpnIps, addr)
  477. }
  478. }
  479. if len(hm.vpnIps) == 0 {
  480. hm.vpnIps = map[netip.Addr]*HandshakeHostInfo{}
  481. }
  482. delete(hm.indexes, hostinfo.localIndexId)
  483. if len(hm.indexes) == 0 {
  484. hm.indexes = map[uint32]*HandshakeHostInfo{}
  485. }
  486. if hm.l.Enabled(context.Background(), slog.LevelDebug) {
  487. hm.l.Debug("Pending hostmap hostInfo deleted",
  488. "hostMap", m{"mapTotalSize": len(hm.vpnIps),
  489. "vpnAddrs": hostinfo.vpnAddrs, "indexNumber": hostinfo.localIndexId, "remoteIndexNumber": hostinfo.remoteIndexId},
  490. )
  491. }
  492. }
  493. func (hm *HandshakeManager) QueryVpnAddr(vpnIp netip.Addr) *HostInfo {
  494. hh := hm.queryVpnIp(vpnIp)
  495. if hh != nil {
  496. return hh.hostinfo
  497. }
  498. return nil
  499. }
  500. func (hm *HandshakeManager) queryVpnIp(vpnIp netip.Addr) *HandshakeHostInfo {
  501. hm.RLock()
  502. defer hm.RUnlock()
  503. return hm.vpnIps[vpnIp]
  504. }
  505. func (hm *HandshakeManager) QueryIndex(index uint32) *HostInfo {
  506. hh := hm.queryIndex(index)
  507. if hh != nil {
  508. return hh.hostinfo
  509. }
  510. return nil
  511. }
  512. func (hm *HandshakeManager) queryIndex(index uint32) *HandshakeHostInfo {
  513. hm.RLock()
  514. defer hm.RUnlock()
  515. return hm.indexes[index]
  516. }
  517. func (hm *HandshakeManager) GetPreferredRanges() []netip.Prefix {
  518. return hm.mainHostMap.GetPreferredRanges()
  519. }
  520. func (hm *HandshakeManager) ForEachVpnAddr(f controlEach) {
  521. hm.RLock()
  522. defer hm.RUnlock()
  523. for _, v := range hm.vpnIps {
  524. f(v.hostinfo)
  525. }
  526. }
  527. func (hm *HandshakeManager) ForEachIndex(f controlEach) {
  528. hm.RLock()
  529. defer hm.RUnlock()
  530. for _, v := range hm.indexes {
  531. f(v.hostinfo)
  532. }
  533. }
  534. func (hm *HandshakeManager) EmitStats() {
  535. hm.RLock()
  536. hostLen := len(hm.vpnIps)
  537. indexLen := len(hm.indexes)
  538. hm.RUnlock()
  539. metrics.GetOrRegisterGauge("hostmap.pending.hosts", nil).Update(int64(hostLen))
  540. metrics.GetOrRegisterGauge("hostmap.pending.indexes", nil).Update(int64(indexLen))
  541. hm.mainHostMap.EmitStats()
  542. }
  543. // Utility functions below
  544. func generateIndex(l *slog.Logger) (uint32, error) {
  545. b := make([]byte, 4)
  546. // Let zero mean we don't know the ID, so don't generate zero
  547. var index uint32
  548. for index == 0 {
  549. _, err := rand.Read(b)
  550. if err != nil {
  551. l.Error("Failed to generate index", "error", err)
  552. return 0, err
  553. }
  554. index = binary.BigEndian.Uint32(b)
  555. }
  556. if l.Enabled(context.Background(), slog.LevelDebug) {
  557. l.Debug("Generated index", "index", index)
  558. }
  559. return index, nil
  560. }
  561. func hsTimeout(tries int64, interval time.Duration) time.Duration {
  562. return time.Duration(tries / 2 * ((2 * int64(interval)) + (tries-1)*int64(interval)))
  563. }
  564. // buildStage0Packet creates the initial handshake packet for the initiator.
  565. func (hm *HandshakeManager) buildStage0Packet(hh *HandshakeHostInfo) bool {
  566. cs := hm.f.pki.getCertState()
  567. v := cs.DefaultVersion()
  568. if hh.initiatingVersionOverride != cert.VersionPre1 {
  569. v = hh.initiatingVersionOverride
  570. } else if v < cert.Version2 {
  571. for _, a := range hh.hostinfo.vpnAddrs {
  572. if a.Is6() {
  573. v = cert.Version2
  574. break
  575. }
  576. }
  577. }
  578. cred := cs.GetCredential(v)
  579. if cred == nil {
  580. hm.f.l.Error("Unable to handshake with host because no certificate is available",
  581. "vpnAddrs", hh.hostinfo.vpnAddrs, "certVersion", v)
  582. return false
  583. }
  584. machine, err := handshake.NewMachine(
  585. v, cs.GetCredential,
  586. hm.certVerifier(), func() (uint32, error) { return hm.allocateIndex(hh) },
  587. true, header.HandshakeIXPSK0,
  588. hm.laneAdvert(),
  589. )
  590. if err != nil {
  591. hm.f.l.Error("Failed to create handshake machine",
  592. "vpnAddrs", hh.hostinfo.vpnAddrs, "error", err)
  593. return false
  594. }
  595. msg, err := machine.Initiate(nil)
  596. if err != nil {
  597. hm.f.l.Error("Failed to initiate handshake",
  598. "vpnAddrs", hh.hostinfo.vpnAddrs, "error", err)
  599. return false
  600. }
  601. // hostinfo.ConnectionState stays nil until the handshake completes in
  602. // continueHandshake. Pre-completion control surfaces guard with nil
  603. // checks; the data plane never observes a pending hostinfo.
  604. hh.hostinfo.HandshakePacket[handshakePacketStage0] = msg
  605. hh.machine = machine
  606. hh.ready = true
  607. return true
  608. }
  609. // laneAdvert returns our multiport advert for a handshake payload, or nil
  610. // when multiport is disabled (which keeps the payload byte-identical to
  611. // vanilla).
  612. func (hm *HandshakeManager) laneAdvert() *handshake.LaneDetails {
  613. if hm.config.laneCount == 0 {
  614. return nil
  615. }
  616. return &handshake.LaneDetails{
  617. PortCount: uint32(hm.config.lanePortCount),
  618. BasePort: uint32(hm.config.laneBasePort),
  619. TxLanes: uint32(hm.config.laneCount),
  620. }
  621. }
  622. // maybeAllocLanes derives the multiport lane sessions for a just-completed
  623. // tunnel. Must run before the hostinfo becomes visible in the hostmap: the data
  624. // plane reads hostinfo.lanes with no synchronization at all.
  625. //
  626. // A failure here costs the tunnel its lanes, not the tunnel: the base session is
  627. // already usable and every lane the data plane wants falls back to it.
  628. func (hm *HandshakeManager) maybeAllocLanes(hostinfo *HostInfo, result *handshake.Result) {
  629. if hm.config.laneCount == 0 || result.PeerPortCount == 0 {
  630. return
  631. }
  632. if len(hm.f.myVpnAddrs) == 0 || len(hostinfo.vpnAddrs) == 0 {
  633. return
  634. }
  635. ls, err := newLaneSet(result, hm.config.laneCount, hm.f.myVpnAddrs[0], hostinfo.vpnAddrs[0])
  636. if err != nil {
  637. hostinfo.logger(hm.l).Error("Failed to derive multiport lanes", "error", err)
  638. return
  639. }
  640. hostinfo.lanes = ls
  641. }
  642. // beginHandshake handles an incoming handshake packet that doesn't match any
  643. // existing pending handshake. It creates a new responder Machine and processes
  644. // the first message.
  645. func (hm *HandshakeManager) beginHandshake(via ViaSender, packet []byte, h *header.H) {
  646. f := hm.f
  647. cs := f.pki.getCertState()
  648. v := cs.DefaultVersion()
  649. if cs.GetCredential(v) == nil {
  650. f.l.Error("Unable to handshake with host because no certificate is available",
  651. "from", via, "certVersion", v)
  652. return
  653. }
  654. machine, err := handshake.NewMachine(
  655. v, cs.GetCredential,
  656. hm.certVerifier(), func() (uint32, error) { return generateIndex(f.l) },
  657. false, header.HandshakeIXPSK0,
  658. hm.laneAdvert(),
  659. )
  660. if err != nil {
  661. f.l.Error("Failed to create handshake machine", "from", via, "error", err)
  662. return
  663. }
  664. response, result, err := machine.ProcessPacket(nil, packet)
  665. if err != nil {
  666. f.l.Error("Failed to process handshake packet", "from", via, "error", err)
  667. return
  668. }
  669. if result == nil {
  670. // Multi-message pattern: the responder Machine would need to be
  671. // registered in hm.indexes so a future inbound packet finds it via
  672. // continueHandshake. The current manager doesn't do that yet, so
  673. // fail loudly rather than silently dropping the in-flight handshake.
  674. // TODO: support multi-message responder flows (XX, pqIX, etc.).
  675. // See also the IX-shaped cipher key assignment in handshake.Machine.
  676. f.l.Error("multi-message handshake responder is not supported",
  677. "from", via, "error", handshake.ErrMultiMessageUnsupported)
  678. return
  679. }
  680. remoteCert := result.RemoteCert
  681. if remoteCert == nil {
  682. f.l.Error("Handshake did not produce a peer certificate", "from", via)
  683. return
  684. }
  685. // Validate peer identity
  686. vpnAddrs, anyVpnAddrsInCommon, ok := hm.validatePeerCert(via, remoteCert)
  687. if !ok {
  688. return
  689. }
  690. connState, err := newConnectionStateFromResult(result)
  691. if err != nil {
  692. f.l.Error("Discarding handshake with an invalid message index", "error", err, "vpnAddrs", vpnAddrs)
  693. return
  694. }
  695. hostinfo := &HostInfo{
  696. ConnectionState: connState,
  697. localIndexId: result.LocalIndex,
  698. remoteIndexId: result.RemoteIndex,
  699. vpnAddrs: vpnAddrs,
  700. HandshakePacket: make(map[uint8][]byte, 0),
  701. lastHandshakeTime: result.HandshakeTime,
  702. relayState: RelayState{
  703. relays: nil,
  704. relayForByAddr: map[netip.Addr]*Relay{},
  705. relayForByIdx: map[uint32]*Relay{},
  706. },
  707. }
  708. msg := "Handshake message received"
  709. if !anyVpnAddrsInCommon {
  710. msg = "Handshake message received, but no vpnNetworks in common."
  711. }
  712. f.l.Info(msg,
  713. "vpnAddrs", vpnAddrs,
  714. "from", via,
  715. "certName", remoteCert.Certificate.Name(),
  716. "certVersion", remoteCert.Certificate.Version(),
  717. "fingerprint", remoteCert.Fingerprint,
  718. "issuer", remoteCert.Certificate.Issuer(),
  719. "initiatorIndex", result.RemoteIndex,
  720. "responderIndex", result.LocalIndex,
  721. "handshake", m{"stage": uint64(machine.MessageIndex()), "style": header.SubTypeName(header.Handshake, machine.Subtype())},
  722. )
  723. // packet aliases the listener's incoming buffer, so this copy must stay.
  724. hostinfo.HandshakePacket[handshakePacketStage0] = make([]byte, len(packet[header.Len:]))
  725. copy(hostinfo.HandshakePacket[handshakePacketStage0], packet[header.Len:])
  726. // response was freshly allocated by ProcessPacket; safe to retain directly.
  727. if response != nil {
  728. hostinfo.HandshakePacket[handshakePacketStage2] = response
  729. }
  730. hostinfo.remotes = f.lightHouse.QueryCache(vpnAddrs)
  731. if !via.IsRelayed {
  732. hostinfo.SetRemote(via.UdpAddr)
  733. }
  734. hostinfo.buildNetworks(f.myVpnNetworksTable, remoteCert.Certificate)
  735. hm.maybeAllocLanes(hostinfo, result)
  736. existing, err := hm.CheckAndComplete(hostinfo, handshakePacketStage0, f)
  737. if err != nil {
  738. hm.handleCheckAndCompleteError(err, existing, hostinfo, via)
  739. return
  740. }
  741. hm.sendHandshakeResponse(via, response, hostinfo, false)
  742. hostinfo.remotes.RefreshFromHandshake(vpnAddrs)
  743. // Don't wait for UpdateWorker
  744. if f.lightHouse.IsAnyLighthouseAddr(vpnAddrs) {
  745. f.lightHouse.TriggerUpdate()
  746. }
  747. }
  748. // continueHandshake feeds an incoming packet to an existing pending handshake Machine.
  749. func (hm *HandshakeManager) continueHandshake(via ViaSender, hh *HandshakeHostInfo, packet []byte) {
  750. f := hm.f
  751. hh.Lock()
  752. defer hh.Unlock()
  753. // Re-verify hh is still tracked. Between queryIndex returning and us taking
  754. // hh.Lock, handleOutbound may have timed out and deleted it. Once we hold
  755. // hh.Lock no other deleter can race our index: handleOutbound also takes
  756. // hh.Lock first, and handleRecvError targets a main-hostmap entry with a
  757. // different localIndexId.
  758. hm.RLock()
  759. cur, ok := hm.indexes[hh.hostinfo.localIndexId]
  760. hm.RUnlock()
  761. if !ok || cur != hh {
  762. return
  763. }
  764. hostinfo := hh.hostinfo
  765. if !via.IsRelayed {
  766. if !f.lightHouse.GetRemoteAllowList().AllowAll(hostinfo.vpnAddrs, via.UdpAddr.Addr()) {
  767. f.l.Debug("lighthouse.remote_allow_list denied incoming handshake",
  768. "vpnAddrs", hostinfo.vpnAddrs, "from", via)
  769. return
  770. }
  771. }
  772. machine := hh.machine
  773. if machine == nil {
  774. f.l.Error("No handshake machine available for continuation",
  775. "vpnAddrs", hostinfo.vpnAddrs, "from", via)
  776. hm.DeleteHostInfo(hostinfo)
  777. return
  778. }
  779. response, result, err := machine.ProcessPacket(nil, packet)
  780. if err != nil {
  781. // Recoverable errors are routine noise, log at Debug. Fatal errors get a Warn.
  782. if machine.Failed() {
  783. f.l.Warn("Failed to process handshake packet, abandoning",
  784. "vpnAddrs", hostinfo.vpnAddrs, "from", via, "error", err)
  785. hm.DeleteHostInfo(hostinfo)
  786. } else {
  787. f.l.Debug("Failed to process handshake packet",
  788. "vpnAddrs", hostinfo.vpnAddrs, "from", via, "error", err)
  789. }
  790. return
  791. }
  792. if response != nil {
  793. hm.sendHandshakeResponse(via, response, hostinfo, false)
  794. }
  795. if result == nil {
  796. return
  797. }
  798. // Handshake complete; build the ConnectionState now that we have keys and a verified peer cert.
  799. cs, err := newConnectionStateFromResult(result)
  800. if err != nil {
  801. f.l.Error("Discarding handshake with an invalid message index", "error", err, "vpnAddrs", hostinfo.vpnAddrs)
  802. hm.DeleteHostInfo(hostinfo)
  803. return
  804. }
  805. hostinfo.ConnectionState = cs
  806. remoteCert := result.RemoteCert
  807. if remoteCert == nil {
  808. f.l.Error("Handshake completed without peer certificate",
  809. "vpnAddrs", hostinfo.vpnAddrs, "from", via)
  810. hm.DeleteHostInfo(hostinfo)
  811. return
  812. }
  813. vpnNetworks := remoteCert.Certificate.Networks()
  814. hostinfo.remoteIndexId = result.RemoteIndex
  815. hostinfo.lastHandshakeTime = result.HandshakeTime
  816. if !via.IsRelayed {
  817. hostinfo.SetRemote(via.UdpAddr)
  818. } else {
  819. hostinfo.relayState.InsertRelayTo(via.relayHI.vpnAddrs[0])
  820. }
  821. // Verify correct host responded (initiator check)
  822. vpnAddrs := make([]netip.Addr, len(vpnNetworks))
  823. correctHostResponded := false
  824. anyVpnAddrsInCommon := false
  825. for i, network := range vpnNetworks {
  826. // inside.go drops self-routed packets at the firewall stage, but we'd
  827. // rather not let a self-handshake complete in the first place: it
  828. // wastes a hostmap slot, suppresses no log, and obscures routing
  829. // misconfig. Explicit refusal here mirrors the responder-side check
  830. // in validatePeerCert.
  831. if f.myVpnAddrsTable.Contains(network.Addr()) {
  832. f.l.Error("Refusing to handshake with myself",
  833. "vpnNetworks", vpnNetworks,
  834. "from", via,
  835. "certName", remoteCert.Certificate.Name(),
  836. "certVersion", remoteCert.Certificate.Version(),
  837. "fingerprint", remoteCert.Fingerprint,
  838. "issuer", remoteCert.Certificate.Issuer(),
  839. "handshake", m{"stage": uint64(machine.MessageIndex()), "style": header.SubTypeName(header.Handshake, machine.Subtype())},
  840. )
  841. hm.DeleteHostInfo(hostinfo)
  842. return
  843. }
  844. vpnAddrs[i] = network.Addr()
  845. if hostinfo.vpnAddrs[0] == network.Addr() {
  846. correctHostResponded = true
  847. }
  848. if f.myVpnNetworksTable.Contains(network.Addr()) {
  849. anyVpnAddrsInCommon = true
  850. }
  851. }
  852. if !correctHostResponded {
  853. f.l.Info("Incorrect host responded to handshake",
  854. "intendedVpnAddrs", hostinfo.vpnAddrs,
  855. "haveVpnNetworks", vpnNetworks,
  856. "from", via,
  857. "certName", remoteCert.Certificate.Name(),
  858. "certVersion", remoteCert.Certificate.Version(),
  859. "fingerprint", remoteCert.Fingerprint,
  860. "issuer", remoteCert.Certificate.Issuer(),
  861. "handshake", m{"stage": uint64(machine.MessageIndex()), "style": header.SubTypeName(header.Handshake, machine.Subtype())},
  862. )
  863. hm.DeleteHostInfo(hostinfo)
  864. hm.StartHandshake(hostinfo.vpnAddrs[0], func(newHH *HandshakeHostInfo) {
  865. newHH.hostinfo.remotes = hostinfo.remotes
  866. newHH.hostinfo.remotes.BlockRemote(via)
  867. newHH.packetStore = hh.packetStore
  868. hh.packetStore = []*cachedPacket{}
  869. hostinfo.vpnAddrs = vpnAddrs
  870. f.sendCloseTunnel(hostinfo)
  871. })
  872. return
  873. }
  874. duration := time.Since(hh.startTime).Nanoseconds()
  875. msg := "Handshake message received"
  876. if !anyVpnAddrsInCommon {
  877. msg = "Handshake message received, but no vpnNetworks in common."
  878. }
  879. f.l.Info(msg,
  880. "vpnAddrs", vpnAddrs,
  881. "from", via,
  882. "certName", remoteCert.Certificate.Name(),
  883. "certVersion", remoteCert.Certificate.Version(),
  884. "fingerprint", remoteCert.Fingerprint,
  885. "issuer", remoteCert.Certificate.Issuer(),
  886. "initiatorIndex", result.LocalIndex,
  887. "responderIndex", result.RemoteIndex,
  888. "handshake", m{"stage": uint64(machine.MessageIndex()), "style": header.SubTypeName(header.Handshake, machine.Subtype())},
  889. "durationNs", duration,
  890. "sentCachedPackets", len(hh.packetStore),
  891. )
  892. hostinfo.vpnAddrs = vpnAddrs
  893. hostinfo.buildNetworks(f.myVpnNetworksTable, remoteCert.Certificate)
  894. hm.maybeAllocLanes(hostinfo, result)
  895. hm.Complete(hostinfo, f)
  896. if len(hh.packetStore) > 0 {
  897. if f.l.Enabled(context.Background(), slog.LevelDebug) {
  898. hostinfo.logger(f.l).Debug("Sending stored packets", "count", len(hh.packetStore))
  899. }
  900. nb := make([]byte, 12, 12)
  901. out := make([]byte, mtu)
  902. for _, cp := range hh.packetStore {
  903. // TODO: use a SendBatch here. Each callback lands in
  904. // sendNoMetrics -> WriteTo: one syscall per cached packet,
  905. // where one sendmmsg could flush the whole store.
  906. cp.callback(cp.messageType, cp.messageSubType, hostinfo, cp.packet, nb, out)
  907. }
  908. f.cachedPacketMetrics.sent.Inc(int64(len(hh.packetStore)))
  909. }
  910. hostinfo.remotes.RefreshFromHandshake(vpnAddrs)
  911. f.metricHandshakes.Update(duration)
  912. // Don't wait for UpdateWorker
  913. if f.lightHouse.IsAnyLighthouseAddr(vpnAddrs) {
  914. f.lightHouse.TriggerUpdate()
  915. }
  916. }
  917. // validatePeerCert checks the peer certificate for self-connection and remote allow list.
  918. // Returns the VPN addrs, whether any of them fall within one of our own VPN
  919. // networks, and true if valid; false if rejected.
  920. func (hm *HandshakeManager) validatePeerCert(via ViaSender, remoteCert *cert.CachedCertificate) ([]netip.Addr, bool, bool) {
  921. f := hm.f
  922. vpnNetworks := remoteCert.Certificate.Networks()
  923. // The cert package rejects host certs with no networks at parse time, so
  924. // reaching this state would mean an invariant was bypassed elsewhere.
  925. // Refuse explicitly so downstream code (which indexes vpnAddrs[0]) can't
  926. // panic if that invariant ever changes.
  927. if len(vpnNetworks) == 0 {
  928. f.l.Info("No networks in certificate",
  929. "from", via, "cert", remoteCert)
  930. return nil, false, false
  931. }
  932. vpnAddrs := make([]netip.Addr, len(vpnNetworks))
  933. anyVpnAddrsInCommon := false
  934. for i, network := range vpnNetworks {
  935. if f.myVpnAddrsTable.Contains(network.Addr()) {
  936. f.l.Error("Refusing to handshake with myself",
  937. "vpnNetworks", vpnNetworks,
  938. "from", via,
  939. "certName", remoteCert.Certificate.Name(),
  940. "certVersion", remoteCert.Certificate.Version(),
  941. "fingerprint", remoteCert.Fingerprint,
  942. "issuer", remoteCert.Certificate.Issuer(),
  943. )
  944. return nil, false, false
  945. }
  946. vpnAddrs[i] = network.Addr()
  947. if f.myVpnNetworksTable.Contains(network.Addr()) {
  948. anyVpnAddrsInCommon = true
  949. }
  950. }
  951. if !via.IsRelayed {
  952. if !f.lightHouse.GetRemoteAllowList().AllowAll(vpnAddrs, via.UdpAddr.Addr()) {
  953. f.l.Debug("lighthouse.remote_allow_list denied incoming handshake",
  954. "vpnAddrs", vpnAddrs, "from", via)
  955. return nil, false, false
  956. }
  957. }
  958. return vpnAddrs, anyVpnAddrsInCommon, true
  959. }
  960. // sendHandshakeResponse sends a handshake response via the appropriate transport.
  961. // cached is true when msg is a stored response being retransmitted because
  962. // the peer's stage-1 retransmit landed (the ErrAlreadySeen path); false on a
  963. // fresh response.
  964. func (hm *HandshakeManager) sendHandshakeResponse(via ViaSender, msg []byte, hostinfo *HostInfo, cached bool) {
  965. if msg == nil {
  966. return
  967. }
  968. f := hm.f
  969. f.messageMetrics.Tx(header.Handshake, header.MessageSubType(msg[1]), 1)
  970. // Common log fields. peerCert may be nil during intermediate
  971. // multi-message flows (handshake hasn't completed yet); skip the cert
  972. // block if so.
  973. logFields := []any{
  974. "vpnAddrs", hostinfo.vpnAddrs,
  975. "handshake", m{"stage": uint64(2), "style": header.SubTypeName(header.Handshake, header.HandshakeIXPSK0)},
  976. "cached", cached,
  977. "initiatorIndex", hostinfo.remoteIndexId,
  978. "responderIndex", hostinfo.localIndexId,
  979. }
  980. if peerCert := hostinfo.ConnectionState.peerCert; peerCert != nil {
  981. logFields = append(logFields,
  982. "certName", peerCert.Certificate.Name(),
  983. "certVersion", peerCert.Certificate.Version(),
  984. "fingerprint", peerCert.Fingerprint,
  985. "issuer", peerCert.Certificate.Issuer(),
  986. )
  987. }
  988. if !via.IsRelayed {
  989. fields := append(logFields, "from", via)
  990. // Reply from the socket the handshake arrived on so the initiator sees
  991. // the source port it targeted. Identical to f.outside under vanilla
  992. // config (all writers share one port); required for multiport lanes.
  993. err := f.writers[via.SockIdx].WriteTo(msg, via.UdpAddr)
  994. if err != nil {
  995. f.l.Error("Failed to send handshake message", append(fields, "error", err)...)
  996. } else {
  997. f.l.Info("Handshake message sent", fields...)
  998. }
  999. } else {
  1000. if via.relay == nil {
  1001. f.l.Error("Handshake send failed: both addr and via.relay are nil.")
  1002. return
  1003. }
  1004. hostinfo.relayState.InsertRelayTo(via.relayHI.vpnAddrs[0])
  1005. // We received a valid handshake on this relay, so make sure the relay
  1006. // state reflects that, in case it had been marked Disestablished.
  1007. via.relayHI.relayState.UpdateRelayForByIdxState(via.relay.LocalIndex, Established)
  1008. f.SendVia(via.relayHI, via.relay, msg, make([]byte, 12), make([]byte, mtu), false, 0)
  1009. f.l.Info("Handshake message sent", append(logFields, "relay", via.relayHI.vpnAddrs[0])...)
  1010. }
  1011. }
  1012. // handleCheckAndCompleteError handles errors from CheckAndComplete.
  1013. // This only fires from the responder-side beginHandshake path, after the
  1014. // peer cert has been validated and ConnectionState populated, so peerCert
  1015. // is always non-nil for the cases that log it.
  1016. func (hm *HandshakeManager) handleCheckAndCompleteError(err error, existing, hostinfo *HostInfo, via ViaSender) {
  1017. f := hm.f
  1018. peerCert := hostinfo.ConnectionState.peerCert
  1019. hsFields := m{"stage": uint64(1), "style": header.SubTypeName(header.Handshake, header.HandshakeIXPSK0)}
  1020. switch err {
  1021. case ErrAlreadySeen:
  1022. if existing.SetRemoteIfPreferred(f.hostMap, via) {
  1023. f.SendMessageToVpnAddr(header.Test, header.TestRequest, hostinfo.vpnAddrs[0], []byte(""), make([]byte, 12, 12), make([]byte, mtu))
  1024. }
  1025. // Resend the original response. The peer is committed to that response's
  1026. // ephemeral keys; a freshly-built one would have different keys and break
  1027. // the tunnel even though both sides "completed" the handshake.
  1028. if msg := existing.HandshakePacket[handshakePacketStage2]; msg != nil {
  1029. hm.sendHandshakeResponse(via, msg, existing, true)
  1030. }
  1031. case ErrExistingHostInfo:
  1032. f.l.Info("Handshake too old",
  1033. "vpnAddrs", hostinfo.vpnAddrs,
  1034. "from", via,
  1035. "certName", peerCert.Certificate.Name(),
  1036. "certVersion", peerCert.Certificate.Version(),
  1037. "fingerprint", peerCert.Fingerprint,
  1038. "issuer", peerCert.Certificate.Issuer(),
  1039. "oldHandshakeTime", existing.lastHandshakeTime,
  1040. "newHandshakeTime", hostinfo.lastHandshakeTime,
  1041. "initiatorIndex", hostinfo.remoteIndexId,
  1042. "responderIndex", hostinfo.localIndexId,
  1043. "handshake", hsFields,
  1044. )
  1045. f.SendMessageToVpnAddr(header.Test, header.TestRequest, hostinfo.vpnAddrs[0], []byte(""), make([]byte, 12, 12), make([]byte, mtu))
  1046. case ErrLocalIndexCollision:
  1047. f.l.Error("Failed to add HostInfo due to localIndex collision",
  1048. "vpnAddrs", hostinfo.vpnAddrs,
  1049. "from", via,
  1050. "certName", peerCert.Certificate.Name(),
  1051. "certVersion", peerCert.Certificate.Version(),
  1052. "fingerprint", peerCert.Fingerprint,
  1053. "issuer", peerCert.Certificate.Issuer(),
  1054. "localIndex", hostinfo.localIndexId,
  1055. "initiatorIndex", hostinfo.remoteIndexId,
  1056. "responderIndex", hostinfo.localIndexId,
  1057. "handshake", hsFields,
  1058. )
  1059. default:
  1060. f.l.Error("Failed to add HostInfo to HostMap",
  1061. "vpnAddrs", hostinfo.vpnAddrs,
  1062. "from", via,
  1063. "error", err,
  1064. "certName", peerCert.Certificate.Name(),
  1065. "certVersion", peerCert.Certificate.Version(),
  1066. "fingerprint", peerCert.Fingerprint,
  1067. "issuer", peerCert.Certificate.Issuer(),
  1068. "initiatorIndex", hostinfo.remoteIndexId,
  1069. "responderIndex", hostinfo.localIndexId,
  1070. "handshake", hsFields,
  1071. )
  1072. }
  1073. }
  1074. // certVerifier returns a CertVerifier that validates certs against the current CA pool.
  1075. func (hm *HandshakeManager) certVerifier() handshake.CertVerifier {
  1076. return func(c cert.Certificate) (*cert.CachedCertificate, error) {
  1077. return hm.f.pki.GetCAPool().VerifyCertificate(time.Now(), c)
  1078. }
  1079. }