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