github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/p2p/discover/v5_session.go (about) 1 // Copyright 2020 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package discover 18 19 import ( 20 crand "crypto/rand" 21 22 "github.com/hashicorp/golang-lru/simplelru" 23 "github.com/zhiqiangxu/go-ethereum/common/mclock" 24 "github.com/zhiqiangxu/go-ethereum/p2p/enode" 25 ) 26 27 // The sessionCache keeps negotiated encryption keys and 28 // state for in-progress handshakes in the Discovery v5 wire protocol. 29 type sessionCache struct { 30 sessions *simplelru.LRU 31 handshakes map[sessionID]*whoareyouV5 32 clock mclock.Clock 33 } 34 35 // sessionID identifies a session or handshake. 36 type sessionID struct { 37 id enode.ID 38 addr string 39 } 40 41 // session contains session information 42 type session struct { 43 writeKey []byte 44 readKey []byte 45 nonceCounter uint32 46 } 47 48 func newSessionCache(maxItems int, clock mclock.Clock) *sessionCache { 49 cache, err := simplelru.NewLRU(maxItems, nil) 50 if err != nil { 51 panic("can't create session cache") 52 } 53 return &sessionCache{ 54 sessions: cache, 55 handshakes: make(map[sessionID]*whoareyouV5), 56 clock: clock, 57 } 58 } 59 60 // nextNonce creates a nonce for encrypting a message to the given session. 61 func (sc *sessionCache) nextNonce(id enode.ID, addr string) []byte { 62 n := make([]byte, gcmNonceSize) 63 crand.Read(n) 64 return n 65 } 66 67 // session returns the current session for the given node, if any. 68 func (sc *sessionCache) session(id enode.ID, addr string) *session { 69 item, ok := sc.sessions.Get(sessionID{id, addr}) 70 if !ok { 71 return nil 72 } 73 return item.(*session) 74 } 75 76 // readKey returns the current read key for the given node. 77 func (sc *sessionCache) readKey(id enode.ID, addr string) []byte { 78 if s := sc.session(id, addr); s != nil { 79 return s.readKey 80 } 81 return nil 82 } 83 84 // writeKey returns the current read key for the given node. 85 func (sc *sessionCache) writeKey(id enode.ID, addr string) []byte { 86 if s := sc.session(id, addr); s != nil { 87 return s.writeKey 88 } 89 return nil 90 } 91 92 // storeNewSession stores new encryption keys in the cache. 93 func (sc *sessionCache) storeNewSession(id enode.ID, addr string, r, w []byte) { 94 sc.sessions.Add(sessionID{id, addr}, &session{ 95 readKey: r, writeKey: w, 96 }) 97 } 98 99 // getHandshake gets the handshake challenge we previously sent to the given remote node. 100 func (sc *sessionCache) getHandshake(id enode.ID, addr string) *whoareyouV5 { 101 return sc.handshakes[sessionID{id, addr}] 102 } 103 104 // storeSentHandshake stores the handshake challenge sent to the given remote node. 105 func (sc *sessionCache) storeSentHandshake(id enode.ID, addr string, challenge *whoareyouV5) { 106 challenge.sent = sc.clock.Now() 107 sc.handshakes[sessionID{id, addr}] = challenge 108 } 109 110 // deleteHandshake deletes handshake data for the given node. 111 func (sc *sessionCache) deleteHandshake(id enode.ID, addr string) { 112 delete(sc.handshakes, sessionID{id, addr}) 113 } 114 115 // handshakeGC deletes timed-out handshakes. 116 func (sc *sessionCache) handshakeGC() { 117 deadline := sc.clock.Now().Add(-handshakeTimeout) 118 for key, challenge := range sc.handshakes { 119 if challenge.sent < deadline { 120 delete(sc.handshakes, key) 121 } 122 } 123 }