github.com/core-coin/go-core/v2@v2.1.9/p2p/discover/v4wire/v4wire.go (about)

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