github.com/phillinzzz/newBsc@v1.1.6/p2p/discover/v5wire/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 v5wire 18 19 import ( 20 "crypto/ecdsa" 21 crand "crypto/rand" 22 "encoding/binary" 23 "time" 24 25 "github.com/phillinzzz/newBsc/common/mclock" 26 "github.com/phillinzzz/newBsc/crypto" 27 "github.com/phillinzzz/newBsc/p2p/enode" 28 "github.com/hashicorp/golang-lru/simplelru" 29 ) 30 31 const handshakeTimeout = time.Second 32 33 // The SessionCache keeps negotiated encryption keys and 34 // state for in-progress handshakes in the Discovery v5 wire protocol. 35 type SessionCache struct { 36 sessions *simplelru.LRU 37 handshakes map[sessionID]*Whoareyou 38 clock mclock.Clock 39 40 // hooks for overriding randomness. 41 nonceGen func(uint32) (Nonce, error) 42 maskingIVGen func([]byte) error 43 ephemeralKeyGen func() (*ecdsa.PrivateKey, error) 44 } 45 46 // sessionID identifies a session or handshake. 47 type sessionID struct { 48 id enode.ID 49 addr string 50 } 51 52 // session contains session information 53 type session struct { 54 writeKey []byte 55 readKey []byte 56 nonceCounter uint32 57 } 58 59 // keysFlipped returns a copy of s with the read and write keys flipped. 60 func (s *session) keysFlipped() *session { 61 return &session{s.readKey, s.writeKey, s.nonceCounter} 62 } 63 64 func NewSessionCache(maxItems int, clock mclock.Clock) *SessionCache { 65 cache, err := simplelru.NewLRU(maxItems, nil) 66 if err != nil { 67 panic("can't create session cache") 68 } 69 return &SessionCache{ 70 sessions: cache, 71 handshakes: make(map[sessionID]*Whoareyou), 72 clock: clock, 73 nonceGen: generateNonce, 74 maskingIVGen: generateMaskingIV, 75 ephemeralKeyGen: crypto.GenerateKey, 76 } 77 } 78 79 func generateNonce(counter uint32) (n Nonce, err error) { 80 binary.BigEndian.PutUint32(n[:4], counter) 81 _, err = crand.Read(n[4:]) 82 return n, err 83 } 84 85 func generateMaskingIV(buf []byte) error { 86 _, err := crand.Read(buf) 87 return err 88 } 89 90 // nextNonce creates a nonce for encrypting a message to the given session. 91 func (sc *SessionCache) nextNonce(s *session) (Nonce, error) { 92 s.nonceCounter++ 93 return sc.nonceGen(s.nonceCounter) 94 } 95 96 // session returns the current session for the given node, if any. 97 func (sc *SessionCache) session(id enode.ID, addr string) *session { 98 item, ok := sc.sessions.Get(sessionID{id, addr}) 99 if !ok { 100 return nil 101 } 102 return item.(*session) 103 } 104 105 // readKey returns the current read key for the given node. 106 func (sc *SessionCache) readKey(id enode.ID, addr string) []byte { 107 if s := sc.session(id, addr); s != nil { 108 return s.readKey 109 } 110 return nil 111 } 112 113 // storeNewSession stores new encryption keys in the cache. 114 func (sc *SessionCache) storeNewSession(id enode.ID, addr string, s *session) { 115 sc.sessions.Add(sessionID{id, addr}, s) 116 } 117 118 // getHandshake gets the handshake challenge we previously sent to the given remote node. 119 func (sc *SessionCache) getHandshake(id enode.ID, addr string) *Whoareyou { 120 return sc.handshakes[sessionID{id, addr}] 121 } 122 123 // storeSentHandshake stores the handshake challenge sent to the given remote node. 124 func (sc *SessionCache) storeSentHandshake(id enode.ID, addr string, challenge *Whoareyou) { 125 challenge.sent = sc.clock.Now() 126 sc.handshakes[sessionID{id, addr}] = challenge 127 } 128 129 // deleteHandshake deletes handshake data for the given node. 130 func (sc *SessionCache) deleteHandshake(id enode.ID, addr string) { 131 delete(sc.handshakes, sessionID{id, addr}) 132 } 133 134 // handshakeGC deletes timed-out handshakes. 135 func (sc *SessionCache) handshakeGC() { 136 deadline := sc.clock.Now().Add(-handshakeTimeout) 137 for key, challenge := range sc.handshakes { 138 if challenge.sent < deadline { 139 delete(sc.handshakes, key) 140 } 141 } 142 }