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  }