1
0

handshake_manager.go 43 KB

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