github.com/ethereum/go-ethereum@v1.16.1/p2p/discover/common.go (about) 1 // Copyright 2019 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 "crypto/ecdsa" 21 crand "crypto/rand" 22 "encoding/binary" 23 "math/rand" 24 "net" 25 "net/netip" 26 "sync" 27 "time" 28 29 "github.com/ethereum/go-ethereum/common/mclock" 30 "github.com/ethereum/go-ethereum/log" 31 "github.com/ethereum/go-ethereum/p2p/enode" 32 "github.com/ethereum/go-ethereum/p2p/enr" 33 "github.com/ethereum/go-ethereum/p2p/netutil" 34 ) 35 36 // UDPConn is a network connection on which discovery can operate. 37 type UDPConn interface { 38 ReadFromUDPAddrPort(b []byte) (n int, addr netip.AddrPort, err error) 39 WriteToUDPAddrPort(b []byte, addr netip.AddrPort) (n int, err error) 40 Close() error 41 LocalAddr() net.Addr 42 } 43 44 // Config holds settings for the discovery listener. 45 type Config struct { 46 // These settings are required and configure the UDP listener: 47 PrivateKey *ecdsa.PrivateKey 48 49 // All remaining settings are optional. 50 51 // Packet handling configuration: 52 NetRestrict *netutil.Netlist // list of allowed IP networks 53 Unhandled chan<- ReadPacket // unhandled packets are sent on this channel 54 V5RespTimeout time.Duration // timeout for v5 queries 55 56 // Node table configuration: 57 Bootnodes []*enode.Node // list of bootstrap nodes 58 PingInterval time.Duration // speed of node liveness check 59 RefreshInterval time.Duration // used in bucket refresh 60 NoFindnodeLivenessCheck bool // turns off validation of table nodes in FINDNODE handler 61 62 // The options below are useful in very specific cases, like in unit tests. 63 V5ProtocolID *[6]byte 64 Log log.Logger // if set, log messages go here 65 ValidSchemes enr.IdentityScheme // allowed identity schemes 66 Clock mclock.Clock 67 } 68 69 func (cfg Config) withDefaults() Config { 70 // Node table configuration: 71 if cfg.PingInterval == 0 { 72 cfg.PingInterval = 3 * time.Second 73 } 74 if cfg.RefreshInterval == 0 { 75 cfg.RefreshInterval = 30 * time.Minute 76 } 77 if cfg.V5RespTimeout == 0 { 78 cfg.V5RespTimeout = 700 * time.Millisecond 79 } 80 81 // Debug/test settings: 82 if cfg.Log == nil { 83 cfg.Log = log.Root() 84 } 85 if cfg.ValidSchemes == nil { 86 cfg.ValidSchemes = enode.ValidSchemes 87 } 88 if cfg.Clock == nil { 89 cfg.Clock = mclock.System{} 90 } 91 return cfg 92 } 93 94 // ListenUDP starts listening for discovery packets on the given UDP socket. 95 func ListenUDP(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { 96 return ListenV4(c, ln, cfg) 97 } 98 99 // ReadPacket is a packet that couldn't be handled. Those packets are sent to the unhandled 100 // channel if configured. 101 type ReadPacket struct { 102 Data []byte 103 Addr netip.AddrPort 104 } 105 106 type randomSource interface { 107 Intn(int) int 108 Int63n(int64) int64 109 Shuffle(int, func(int, int)) 110 } 111 112 // reseedingRandom is a random number generator that tracks when it was last re-seeded. 113 type reseedingRandom struct { 114 mu sync.Mutex 115 cur *rand.Rand 116 } 117 118 func (r *reseedingRandom) seed() { 119 var b [8]byte 120 crand.Read(b[:]) 121 seed := binary.BigEndian.Uint64(b[:]) 122 new := rand.New(rand.NewSource(int64(seed))) 123 124 r.mu.Lock() 125 r.cur = new 126 r.mu.Unlock() 127 } 128 129 func (r *reseedingRandom) Intn(n int) int { 130 r.mu.Lock() 131 defer r.mu.Unlock() 132 return r.cur.Intn(n) 133 } 134 135 func (r *reseedingRandom) Int63n(n int64) int64 { 136 r.mu.Lock() 137 defer r.mu.Unlock() 138 return r.cur.Int63n(n) 139 } 140 141 func (r *reseedingRandom) Shuffle(n int, swap func(i, j int)) { 142 r.mu.Lock() 143 defer r.mu.Unlock() 144 r.cur.Shuffle(n, swap) 145 }