handshake_ix.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. package nebula
  2. import (
  3. "sync/atomic"
  4. "time"
  5. "github.com/golang/protobuf/proto"
  6. "github.com/slackhq/nebula/header"
  7. "github.com/slackhq/nebula/iputil"
  8. "github.com/slackhq/nebula/udp"
  9. )
  10. // NOISE IX Handshakes
  11. // This function constructs a handshake packet, but does not actually send it
  12. // Sending is done by the handshake manager
  13. func ixHandshakeStage0(f *Interface, vpnIp iputil.VpnIp, hostinfo *HostInfo) {
  14. // This queries the lighthouse if we don't know a remote for the host
  15. // We do it here to provoke the lighthouse to preempt our timer wheel and trigger the stage 1 packet to send
  16. // more quickly, effect is a quicker handshake.
  17. if hostinfo.remote == nil {
  18. f.lightHouse.QueryServer(vpnIp, f)
  19. }
  20. err := f.handshakeManager.AddIndexHostInfo(hostinfo)
  21. if err != nil {
  22. f.l.WithError(err).WithField("vpnIp", vpnIp).
  23. WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to generate index")
  24. return
  25. }
  26. ci := hostinfo.ConnectionState
  27. hsProto := &NebulaHandshakeDetails{
  28. InitiatorIndex: hostinfo.localIndexId,
  29. Time: uint64(time.Now().UnixNano()),
  30. Cert: ci.certState.rawCertificateNoKey,
  31. }
  32. hsBytes := []byte{}
  33. hs := &NebulaHandshake{
  34. Details: hsProto,
  35. }
  36. hsBytes, err = proto.Marshal(hs)
  37. if err != nil {
  38. f.l.WithError(err).WithField("vpnIp", vpnIp).
  39. WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to marshal handshake message")
  40. return
  41. }
  42. h := header.Encode(make([]byte, header.Len), header.Version, header.Handshake, header.HandshakeIXPSK0, 0, 1)
  43. atomic.AddUint64(&ci.atomicMessageCounter, 1)
  44. msg, _, _, err := ci.H.WriteMessage(h, hsBytes)
  45. if err != nil {
  46. f.l.WithError(err).WithField("vpnIp", vpnIp).
  47. WithField("handshake", m{"stage": 0, "style": "ix_psk0"}).Error("Failed to call noise.WriteMessage")
  48. return
  49. }
  50. // We are sending handshake packet 1, so we don't expect to receive
  51. // handshake packet 1 from the responder
  52. ci.window.Update(f.l, 1)
  53. hostinfo.HandshakePacket[0] = msg
  54. hostinfo.HandshakeReady = true
  55. hostinfo.handshakeStart = time.Now()
  56. }
  57. func ixHandshakeStage1(f *Interface, addr *udp.Addr, packet []byte, h *header.H) {
  58. var (
  59. err error
  60. ci *ConnectionState
  61. msg []byte
  62. )
  63. hs := &NebulaHandshake{}
  64. // Handle multiple possible psk options, ensure the protobuf comes out clean too
  65. for _, p := range f.psk.Cache {
  66. //TODO: benchmark generation time of makePsk
  67. ci, err = f.newConnectionState(f.l, false, p)
  68. if err != nil {
  69. f.l.WithError(err).WithField("udpAddr", addr).Error("Failed to get a new connection state")
  70. continue
  71. }
  72. msg, _, _, err = ci.H.ReadMessage(nil, packet[header.Len:])
  73. if err != nil {
  74. // Calls to ReadMessage with an incorrect psk should fail, try the next one if we have one
  75. continue
  76. }
  77. // Sometimes ReadMessage returns fine with a nil psk even if the handshake is using a psk, ensure our protobuf
  78. // comes out clean as well
  79. err = proto.Unmarshal(msg, hs)
  80. if err == nil {
  81. // There was no error, we can continue with this handshake
  82. break
  83. }
  84. // The unmarshal failed, try the next psk if we have one
  85. }
  86. // We finished with an error, log it and get out
  87. if err != nil {
  88. // We aren't logging the error here because we can't be sure of the failure when using psk
  89. f.l.WithField("udpAddr", addr).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
  90. Error("Was unable to decrypt the handshake")
  91. return
  92. }
  93. // Mark packet 1 as seen so it doesn't show up as missed
  94. ci.window.Update(f.l, 1)
  95. remoteCert, err := RecombineCertAndValidate(ci.H, hs.Details.Cert, f.caPool)
  96. if err != nil {
  97. f.l.WithError(err).WithField("udpAddr", addr).
  98. WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).WithField("cert", remoteCert).
  99. Info("Invalid certificate from host")
  100. return
  101. }
  102. vpnIp := iputil.Ip2VpnIp(remoteCert.Details.Ips[0].IP)
  103. certName := remoteCert.Details.Name
  104. fingerprint, _ := remoteCert.Sha256Sum()
  105. issuer := remoteCert.Details.Issuer
  106. if vpnIp == f.myVpnIp {
  107. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  108. WithField("certName", certName).
  109. WithField("fingerprint", fingerprint).
  110. WithField("issuer", issuer).
  111. WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Refusing to handshake with myself")
  112. return
  113. }
  114. if !f.lightHouse.remoteAllowList.Allow(vpnIp, addr.IP) {
  115. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).Debug("lighthouse.remote_allow_list denied incoming handshake")
  116. return
  117. }
  118. myIndex, err := generateIndex(f.l)
  119. if err != nil {
  120. f.l.WithError(err).WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  121. WithField("certName", certName).
  122. WithField("fingerprint", fingerprint).
  123. WithField("issuer", issuer).
  124. WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to generate index")
  125. return
  126. }
  127. hostinfo := &HostInfo{
  128. ConnectionState: ci,
  129. localIndexId: myIndex,
  130. remoteIndexId: hs.Details.InitiatorIndex,
  131. vpnIp: vpnIp,
  132. HandshakePacket: make(map[uint8][]byte, 0),
  133. lastHandshakeTime: hs.Details.Time,
  134. }
  135. hostinfo.Lock()
  136. defer hostinfo.Unlock()
  137. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  138. WithField("certName", certName).
  139. WithField("fingerprint", fingerprint).
  140. WithField("issuer", issuer).
  141. WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
  142. WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
  143. Info("Handshake message received")
  144. hs.Details.ResponderIndex = myIndex
  145. hs.Details.Cert = ci.certState.rawCertificateNoKey
  146. // Update the time in case their clock is way off from ours
  147. hs.Details.Time = uint64(time.Now().UnixNano())
  148. hsBytes, err := proto.Marshal(hs)
  149. if err != nil {
  150. f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
  151. WithField("certName", certName).
  152. WithField("fingerprint", fingerprint).
  153. WithField("issuer", issuer).
  154. WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to marshal handshake message")
  155. return
  156. }
  157. nh := header.Encode(make([]byte, header.Len), header.Version, header.Handshake, header.HandshakeIXPSK0, hs.Details.InitiatorIndex, 2)
  158. msg, dKey, eKey, err := ci.H.WriteMessage(nh, hsBytes)
  159. if err != nil {
  160. f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
  161. WithField("certName", certName).
  162. WithField("fingerprint", fingerprint).
  163. WithField("issuer", issuer).
  164. WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Failed to call noise.WriteMessage")
  165. return
  166. } else if dKey == nil || eKey == nil {
  167. f.l.WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
  168. WithField("certName", certName).
  169. WithField("fingerprint", fingerprint).
  170. WithField("issuer", issuer).
  171. WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).Error("Noise did not arrive at a key")
  172. return
  173. }
  174. hostinfo.HandshakePacket[0] = make([]byte, len(packet[header.Len:]))
  175. copy(hostinfo.HandshakePacket[0], packet[header.Len:])
  176. // Regardless of whether you are the sender or receiver, you should arrive here
  177. // and complete standing up the connection.
  178. hostinfo.HandshakePacket[2] = make([]byte, len(msg))
  179. copy(hostinfo.HandshakePacket[2], msg)
  180. // We are sending handshake packet 2, so we don't expect to receive
  181. // handshake packet 2 from the initiator.
  182. ci.window.Update(f.l, 2)
  183. ci.peerCert = remoteCert
  184. ci.dKey = NewNebulaCipherState(dKey)
  185. ci.eKey = NewNebulaCipherState(eKey)
  186. hostinfo.remotes = f.lightHouse.QueryCache(vpnIp)
  187. hostinfo.SetRemote(addr)
  188. hostinfo.CreateRemoteCIDR(remoteCert)
  189. // Only overwrite existing record if we should win the handshake race
  190. overwrite := vpnIp > f.myVpnIp
  191. existing, err := f.handshakeManager.CheckAndComplete(hostinfo, 0, overwrite, f)
  192. if err != nil {
  193. switch err {
  194. case ErrAlreadySeen:
  195. // Update remote if preferred (Note we have to switch to locking
  196. // the existing hostinfo, and then switch back so the defer Unlock
  197. // higher in this function still works)
  198. hostinfo.Unlock()
  199. existing.Lock()
  200. // Update remote if preferred
  201. if existing.SetRemoteIfPreferred(f.hostMap, addr) {
  202. // Send a test packet to ensure the other side has also switched to
  203. // the preferred remote
  204. f.SendMessageToVpnIp(header.Test, header.TestRequest, vpnIp, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
  205. }
  206. existing.Unlock()
  207. hostinfo.Lock()
  208. msg = existing.HandshakePacket[2]
  209. f.messageMetrics.Tx(header.Handshake, header.MessageSubType(msg[1]), 1)
  210. err := f.outside.WriteTo(msg, addr)
  211. if err != nil {
  212. f.l.WithField("vpnIp", existing.vpnIp).WithField("udpAddr", addr).
  213. WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("cached", true).
  214. WithError(err).Error("Failed to send handshake message")
  215. } else {
  216. f.l.WithField("vpnIp", existing.vpnIp).WithField("udpAddr", addr).
  217. WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("cached", true).
  218. Info("Handshake message sent")
  219. }
  220. return
  221. case ErrExistingHostInfo:
  222. // This means there was an existing tunnel and this handshake was older than the one we are currently based on
  223. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  224. WithField("certName", certName).
  225. WithField("oldHandshakeTime", existing.lastHandshakeTime).
  226. WithField("newHandshakeTime", hostinfo.lastHandshakeTime).
  227. WithField("fingerprint", fingerprint).
  228. WithField("issuer", issuer).
  229. WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
  230. WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
  231. Info("Handshake too old")
  232. // Send a test packet to trigger an authenticated tunnel test, this should suss out any lingering tunnel issues
  233. f.SendMessageToVpnIp(header.Test, header.TestRequest, vpnIp, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
  234. return
  235. case ErrLocalIndexCollision:
  236. // This means we failed to insert because of collision on localIndexId. Just let the next handshake packet retry
  237. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  238. WithField("certName", certName).
  239. WithField("fingerprint", fingerprint).
  240. WithField("issuer", issuer).
  241. WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
  242. WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
  243. WithField("localIndex", hostinfo.localIndexId).WithField("collision", existing.vpnIp).
  244. Error("Failed to add HostInfo due to localIndex collision")
  245. return
  246. case ErrExistingHandshake:
  247. // We have a race where both parties think they are an initiator and this tunnel lost, let the other one finish
  248. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  249. WithField("certName", certName).
  250. WithField("fingerprint", fingerprint).
  251. WithField("issuer", issuer).
  252. WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
  253. WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
  254. Error("Prevented a pending handshake race")
  255. return
  256. default:
  257. // Shouldn't happen, but just in case someone adds a new error type to CheckAndComplete
  258. // And we forget to update it here
  259. f.l.WithError(err).WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  260. WithField("certName", certName).
  261. WithField("fingerprint", fingerprint).
  262. WithField("issuer", issuer).
  263. WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
  264. WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 1, "style": "ix_psk0"}).
  265. Error("Failed to add HostInfo to HostMap")
  266. return
  267. }
  268. }
  269. // Do the send
  270. f.messageMetrics.Tx(header.Handshake, header.MessageSubType(msg[1]), 1)
  271. err = f.outside.WriteTo(msg, addr)
  272. if err != nil {
  273. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  274. WithField("certName", certName).
  275. WithField("fingerprint", fingerprint).
  276. WithField("issuer", issuer).
  277. WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
  278. WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
  279. WithError(err).Error("Failed to send handshake")
  280. } else {
  281. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  282. WithField("certName", certName).
  283. WithField("fingerprint", fingerprint).
  284. WithField("issuer", issuer).
  285. WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
  286. WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
  287. WithField("sentCachedPackets", len(hostinfo.packetStore)).
  288. Info("Handshake message sent")
  289. }
  290. hostinfo.handshakeComplete(f.l, f.cachedPacketMetrics)
  291. return
  292. }
  293. func ixHandshakeStage2(f *Interface, addr *udp.Addr, hostinfo *HostInfo, packet []byte, h *header.H) bool {
  294. if hostinfo == nil {
  295. // Nothing here to tear down, got a bogus stage 2 packet
  296. return true
  297. }
  298. hostinfo.Lock()
  299. defer hostinfo.Unlock()
  300. if !f.lightHouse.remoteAllowList.Allow(hostinfo.vpnIp, addr.IP) {
  301. f.l.WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).Debug("lighthouse.remote_allow_list denied incoming handshake")
  302. return false
  303. }
  304. ci := hostinfo.ConnectionState
  305. if ci.ready {
  306. f.l.WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
  307. WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("header", h).
  308. Info("Handshake is already complete")
  309. // Update remote if preferred
  310. if hostinfo.SetRemoteIfPreferred(f.hostMap, addr) {
  311. // Send a test packet to ensure the other side has also switched to
  312. // the preferred remote
  313. f.SendMessageToVpnIp(header.Test, header.TestRequest, hostinfo.vpnIp, []byte(""), make([]byte, 12, 12), make([]byte, mtu))
  314. }
  315. // We already have a complete tunnel, there is nothing that can be done by processing further stage 1 packets
  316. return false
  317. }
  318. msg, eKey, dKey, err := ci.H.ReadMessage(nil, packet[header.Len:])
  319. if err != nil {
  320. f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
  321. WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).WithField("header", h).
  322. Error("Failed to call noise.ReadMessage")
  323. // We don't want to tear down the connection on a bad ReadMessage because it could be an attacker trying
  324. // to DOS us. Every other error condition after should to allow a possible good handshake to complete in the
  325. // near future
  326. return false
  327. } else if dKey == nil || eKey == nil {
  328. f.l.WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
  329. WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
  330. Error("Noise did not arrive at a key")
  331. // This should be impossible in IX but just in case, if we get here then there is no chance to recover
  332. // the handshake state machine. Tear it down
  333. return true
  334. }
  335. hs := &NebulaHandshake{}
  336. err = proto.Unmarshal(msg, hs)
  337. if err != nil || hs.Details == nil {
  338. f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
  339. WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).Error("Failed unmarshal handshake message")
  340. // The handshake state machine is complete, if things break now there is no chance to recover. Tear down and start again
  341. return true
  342. }
  343. remoteCert, err := RecombineCertAndValidate(ci.H, hs.Details.Cert, f.caPool)
  344. if err != nil {
  345. f.l.WithError(err).WithField("vpnIp", hostinfo.vpnIp).WithField("udpAddr", addr).
  346. WithField("cert", remoteCert).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
  347. Error("Invalid certificate from host")
  348. // The handshake state machine is complete, if things break now there is no chance to recover. Tear down and start again
  349. return true
  350. }
  351. vpnIp := iputil.Ip2VpnIp(remoteCert.Details.Ips[0].IP)
  352. certName := remoteCert.Details.Name
  353. fingerprint, _ := remoteCert.Sha256Sum()
  354. issuer := remoteCert.Details.Issuer
  355. // Ensure the right host responded
  356. if vpnIp != hostinfo.vpnIp {
  357. f.l.WithField("intendedVpnIp", hostinfo.vpnIp).WithField("haveVpnIp", vpnIp).
  358. WithField("udpAddr", addr).WithField("certName", certName).
  359. WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
  360. Info("Incorrect host responded to handshake")
  361. // Release our old handshake from pending, it should not continue
  362. f.handshakeManager.pendingHostMap.DeleteHostInfo(hostinfo)
  363. // Create a new hostinfo/handshake for the intended vpn ip
  364. //TODO: this adds it to the timer wheel in a way that aggressively retries
  365. newHostInfo := f.getOrHandshake(hostinfo.vpnIp)
  366. newHostInfo.Lock()
  367. // Block the current used address
  368. newHostInfo.remotes = hostinfo.remotes
  369. newHostInfo.remotes.BlockRemote(addr)
  370. // Get the correct remote list for the host we did handshake with
  371. hostinfo.remotes = f.lightHouse.QueryCache(vpnIp)
  372. f.l.WithField("blockedUdpAddrs", newHostInfo.remotes.CopyBlockedRemotes()).WithField("vpnIp", vpnIp).
  373. WithField("remotes", newHostInfo.remotes.CopyAddrs(f.hostMap.preferredRanges)).
  374. Info("Blocked addresses for handshakes")
  375. // Swap the packet store to benefit the original intended recipient
  376. hostinfo.ConnectionState.queueLock.Lock()
  377. newHostInfo.packetStore = hostinfo.packetStore
  378. hostinfo.packetStore = []*cachedPacket{}
  379. hostinfo.ConnectionState.queueLock.Unlock()
  380. // Finally, put the correct vpn ip in the host info, tell them to close the tunnel, and return true to tear down
  381. hostinfo.vpnIp = vpnIp
  382. f.sendCloseTunnel(hostinfo)
  383. newHostInfo.Unlock()
  384. return true
  385. }
  386. // Mark packet 2 as seen so it doesn't show up as missed
  387. ci.window.Update(f.l, 2)
  388. duration := time.Since(hostinfo.handshakeStart).Nanoseconds()
  389. f.l.WithField("vpnIp", vpnIp).WithField("udpAddr", addr).
  390. WithField("certName", certName).
  391. WithField("fingerprint", fingerprint).
  392. WithField("issuer", issuer).
  393. WithField("initiatorIndex", hs.Details.InitiatorIndex).WithField("responderIndex", hs.Details.ResponderIndex).
  394. WithField("remoteIndex", h.RemoteIndex).WithField("handshake", m{"stage": 2, "style": "ix_psk0"}).
  395. WithField("durationNs", duration).
  396. WithField("sentCachedPackets", len(hostinfo.packetStore)).
  397. Info("Handshake message received")
  398. hostinfo.remoteIndexId = hs.Details.ResponderIndex
  399. hostinfo.lastHandshakeTime = hs.Details.Time
  400. // Store their cert and our symmetric keys
  401. ci.peerCert = remoteCert
  402. ci.dKey = NewNebulaCipherState(dKey)
  403. ci.eKey = NewNebulaCipherState(eKey)
  404. // Make sure the current udpAddr being used is set for responding
  405. hostinfo.SetRemote(addr)
  406. // Build up the radix for the firewall if we have subnets in the cert
  407. hostinfo.CreateRemoteCIDR(remoteCert)
  408. // Complete our handshake and update metrics, this will replace any existing tunnels for this vpnIp
  409. //TODO: Complete here does not do a race avoidance, it will just take the new tunnel. Is this ok?
  410. f.handshakeManager.Complete(hostinfo, f)
  411. hostinfo.handshakeComplete(f.l, f.cachedPacketMetrics)
  412. f.metricHandshakes.Update(duration)
  413. return false
  414. }