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