github.com/ethereum/go-ethereum@v1.16.1/p2p/discover/v4wire/v4wire.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 v4wire implements the Discovery v4 Wire Protocol.
    18  package v4wire
    19  
    20  import (
    21  	"bytes"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"errors"
    25  	"fmt"
    26  	"math/big"
    27  	"net"
    28  	"net/netip"
    29  	"time"
    30  
    31  	"github.com/ethereum/go-ethereum/common/math"
    32  	"github.com/ethereum/go-ethereum/crypto"
    33  	"github.com/ethereum/go-ethereum/p2p/enode"
    34  	"github.com/ethereum/go-ethereum/p2p/enr"
    35  	"github.com/ethereum/go-ethereum/rlp"
    36  )
    37  
    38  // RPC packet types
    39  const (
    40  	PingPacket = iota + 1 // zero is 'reserved'
    41  	PongPacket
    42  	FindnodePacket
    43  	NeighborsPacket
    44  	ENRRequestPacket
    45  	ENRResponsePacket
    46  )
    47  
    48  // RPC request structures
    49  type (
    50  	Ping struct {
    51  		Version    uint
    52  		From, To   Endpoint
    53  		Expiration uint64
    54  		ENRSeq     uint64 `rlp:"optional"` // Sequence number of local record, added by EIP-868.
    55  
    56  		// Ignore additional fields (for forward compatibility).
    57  		Rest []rlp.RawValue `rlp:"tail"`
    58  	}
    59  
    60  	// Pong is the reply to ping.
    61  	Pong struct {
    62  		// This field should mirror the UDP envelope address
    63  		// of the ping packet, which provides a way to discover the
    64  		// external address (after NAT).
    65  		To         Endpoint
    66  		ReplyTok   []byte // This contains the hash of the ping packet.
    67  		Expiration uint64 // Absolute timestamp at which the packet becomes invalid.
    68  		ENRSeq     uint64 `rlp:"optional"` // Sequence number of local record, added by EIP-868.
    69  
    70  		// Ignore additional fields (for forward compatibility).
    71  		Rest []rlp.RawValue `rlp:"tail"`
    72  	}
    73  
    74  	// Findnode is a query for nodes close to the given target.
    75  	Findnode struct {
    76  		Target     Pubkey
    77  		Expiration uint64
    78  		// Ignore additional fields (for forward compatibility).
    79  		Rest []rlp.RawValue `rlp:"tail"`
    80  	}
    81  
    82  	// Neighbors is the reply to findnode.
    83  	Neighbors struct {
    84  		Nodes      []Node
    85  		Expiration uint64
    86  		// Ignore additional fields (for forward compatibility).
    87  		Rest []rlp.RawValue `rlp:"tail"`
    88  	}
    89  
    90  	// ENRRequest queries for the remote node's record.
    91  	ENRRequest struct {
    92  		Expiration uint64
    93  		// Ignore additional fields (for forward compatibility).
    94  		Rest []rlp.RawValue `rlp:"tail"`
    95  	}
    96  
    97  	// ENRResponse is the reply to ENRRequest.
    98  	ENRResponse struct {
    99  		ReplyTok []byte // Hash of the ENRRequest packet.
   100  		Record   enr.Record
   101  		// Ignore additional fields (for forward compatibility).
   102  		Rest []rlp.RawValue `rlp:"tail"`
   103  	}
   104  )
   105  
   106  // MaxNeighbors is the maximum number of neighbor nodes in a Neighbors packet.
   107  const MaxNeighbors = 12
   108  
   109  // This code computes the MaxNeighbors constant value.
   110  
   111  // func init() {
   112  // 	var maxNeighbors int
   113  // 	p := Neighbors{Expiration: ^uint64(0)}
   114  // 	maxSizeNode := Node{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)}
   115  // 	for n := 0; ; n++ {
   116  // 		p.Nodes = append(p.Nodes, maxSizeNode)
   117  // 		size, _, err := rlp.EncodeToReader(p)
   118  // 		if err != nil {
   119  // 			// If this ever happens, it will be caught by the unit tests.
   120  // 			panic("cannot encode: " + err.Error())
   121  // 		}
   122  // 		if headSize+size+1 >= 1280 {
   123  // 			maxNeighbors = n
   124  // 			break
   125  // 		}
   126  // 	}
   127  // 	fmt.Println("maxNeighbors", maxNeighbors)
   128  // }
   129  
   130  // Pubkey represents an encoded 64-byte secp256k1 public key.
   131  type Pubkey [64]byte
   132  
   133  // ID returns the node ID corresponding to the public key.
   134  func (e Pubkey) ID() enode.ID {
   135  	return enode.ID(crypto.Keccak256Hash(e[:]))
   136  }
   137  
   138  // Node represents information about a node.
   139  type Node struct {
   140  	IP  net.IP // len 4 for IPv4 or 16 for IPv6
   141  	UDP uint16 // for discovery protocol
   142  	TCP uint16 // for RLPx protocol
   143  	ID  Pubkey
   144  }
   145  
   146  // Endpoint represents a network endpoint.
   147  type Endpoint struct {
   148  	IP  net.IP // len 4 for IPv4 or 16 for IPv6
   149  	UDP uint16 // for discovery protocol
   150  	TCP uint16 // for RLPx protocol
   151  }
   152  
   153  // NewEndpoint creates an endpoint.
   154  func NewEndpoint(addr netip.AddrPort, tcpPort uint16) Endpoint {
   155  	var ip net.IP
   156  	if addr.Addr().Is4() || addr.Addr().Is4In6() {
   157  		ip4 := addr.Addr().As4()
   158  		ip = ip4[:]
   159  	} else {
   160  		ip = addr.Addr().AsSlice()
   161  	}
   162  	return Endpoint{IP: ip, UDP: addr.Port(), TCP: tcpPort}
   163  }
   164  
   165  type Packet interface {
   166  	// Name is the name of the package, for logging purposes.
   167  	Name() string
   168  	// Kind is the packet type, for logging purposes.
   169  	Kind() byte
   170  }
   171  
   172  func (req *Ping) Name() string { return "PING/v4" }
   173  func (req *Ping) Kind() byte   { return PingPacket }
   174  
   175  func (req *Pong) Name() string { return "PONG/v4" }
   176  func (req *Pong) Kind() byte   { return PongPacket }
   177  
   178  func (req *Findnode) Name() string { return "FINDNODE/v4" }
   179  func (req *Findnode) Kind() byte   { return FindnodePacket }
   180  
   181  func (req *Neighbors) Name() string { return "NEIGHBORS/v4" }
   182  func (req *Neighbors) Kind() byte   { return NeighborsPacket }
   183  
   184  func (req *ENRRequest) Name() string { return "ENRREQUEST/v4" }
   185  func (req *ENRRequest) Kind() byte   { return ENRRequestPacket }
   186  
   187  func (req *ENRResponse) Name() string { return "ENRRESPONSE/v4" }
   188  func (req *ENRResponse) Kind() byte   { return ENRResponsePacket }
   189  
   190  // Expired checks whether the given UNIX time stamp is in the past.
   191  func Expired(ts uint64) bool {
   192  	return time.Unix(int64(ts), 0).Before(time.Now())
   193  }
   194  
   195  // Encoder/decoder.
   196  
   197  const (
   198  	macSize  = 32
   199  	sigSize  = crypto.SignatureLength
   200  	headSize = macSize + sigSize // space of packet frame data
   201  )
   202  
   203  var (
   204  	ErrPacketTooSmall = errors.New("too small")
   205  	ErrBadHash        = errors.New("bad hash")
   206  	ErrBadPoint       = errors.New("invalid curve point")
   207  )
   208  
   209  var headSpace = make([]byte, headSize)
   210  
   211  // Decode reads a discovery v4 packet.
   212  func Decode(input []byte) (Packet, Pubkey, []byte, error) {
   213  	if len(input) < headSize+1 {
   214  		return nil, Pubkey{}, nil, ErrPacketTooSmall
   215  	}
   216  	hash, sig, sigdata := input[:macSize], input[macSize:headSize], input[headSize:]
   217  	shouldhash := crypto.Keccak256(input[macSize:])
   218  	if !bytes.Equal(hash, shouldhash) {
   219  		return nil, Pubkey{}, nil, ErrBadHash
   220  	}
   221  	fromKey, err := recoverNodeKey(crypto.Keccak256(input[headSize:]), sig)
   222  	if err != nil {
   223  		return nil, fromKey, hash, err
   224  	}
   225  
   226  	var req Packet
   227  	switch ptype := sigdata[0]; ptype {
   228  	case PingPacket:
   229  		req = new(Ping)
   230  	case PongPacket:
   231  		req = new(Pong)
   232  	case FindnodePacket:
   233  		req = new(Findnode)
   234  	case NeighborsPacket:
   235  		req = new(Neighbors)
   236  	case ENRRequestPacket:
   237  		req = new(ENRRequest)
   238  	case ENRResponsePacket:
   239  		req = new(ENRResponse)
   240  	default:
   241  		return nil, fromKey, hash, fmt.Errorf("unknown type: %d", ptype)
   242  	}
   243  	// Here we use NewStream to allow for additional data after the first
   244  	// RLP object (forward-compatibility).
   245  	s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0)
   246  	err = s.Decode(req)
   247  	return req, fromKey, hash, err
   248  }
   249  
   250  // Encode encodes a discovery packet.
   251  func Encode(priv *ecdsa.PrivateKey, req Packet) (packet, hash []byte, err error) {
   252  	b := new(bytes.Buffer)
   253  	b.Write(headSpace)
   254  	b.WriteByte(req.Kind())
   255  	if err := rlp.Encode(b, req); err != nil {
   256  		return nil, nil, err
   257  	}
   258  	packet = b.Bytes()
   259  	sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
   260  	if err != nil {
   261  		return nil, nil, err
   262  	}
   263  	copy(packet[macSize:], sig)
   264  	// Add the hash to the front. Note: this doesn't protect the packet in any way.
   265  	hash = crypto.Keccak256(packet[macSize:])
   266  	copy(packet, hash)
   267  	return packet, hash, nil
   268  }
   269  
   270  // recoverNodeKey computes the public key used to sign the given hash from the signature.
   271  func recoverNodeKey(hash, sig []byte) (key Pubkey, err error) {
   272  	pubkey, err := crypto.Ecrecover(hash, sig)
   273  	if err != nil {
   274  		return key, err
   275  	}
   276  	copy(key[:], pubkey[1:])
   277  	return key, nil
   278  }
   279  
   280  // EncodePubkey encodes a secp256k1 public key.
   281  func EncodePubkey(key *ecdsa.PublicKey) Pubkey {
   282  	var e Pubkey
   283  	math.ReadBits(key.X, e[:len(e)/2])
   284  	math.ReadBits(key.Y, e[len(e)/2:])
   285  	return e
   286  }
   287  
   288  // DecodePubkey reads an encoded secp256k1 public key.
   289  func DecodePubkey(curve elliptic.Curve, e Pubkey) (*ecdsa.PublicKey, error) {
   290  	p := &ecdsa.PublicKey{Curve: curve, X: new(big.Int), Y: new(big.Int)}
   291  	half := len(e) / 2
   292  	p.X.SetBytes(e[:half])
   293  	p.Y.SetBytes(e[half:])
   294  	if !p.Curve.IsOnCurve(p.X, p.Y) {
   295  		return nil, ErrBadPoint
   296  	}
   297  	return p, nil
   298  }