github.com/ethereum/go-ethereum@v1.16.1/p2p/discover/v5wire/msg.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 v5wire
    18  
    19  import (
    20  	"fmt"
    21  	"net"
    22  
    23  	"github.com/ethereum/go-ethereum/common/hexutil"
    24  	"github.com/ethereum/go-ethereum/common/mclock"
    25  	"github.com/ethereum/go-ethereum/p2p/enode"
    26  	"github.com/ethereum/go-ethereum/p2p/enr"
    27  	"github.com/ethereum/go-ethereum/rlp"
    28  )
    29  
    30  // Packet is implemented by all message types.
    31  type Packet interface {
    32  	Name() string        // Name returns a string corresponding to the message type.
    33  	Kind() byte          // Kind returns the message type.
    34  	RequestID() []byte   // Returns the request ID.
    35  	SetRequestID([]byte) // Sets the request ID.
    36  
    37  	// AppendLogInfo returns its argument 'ctx' with additional fields
    38  	// appended for logging purposes.
    39  	AppendLogInfo(ctx []interface{}) []interface{}
    40  }
    41  
    42  // Message types.
    43  const (
    44  	PingMsg byte = iota + 1
    45  	PongMsg
    46  	FindnodeMsg
    47  	NodesMsg
    48  	TalkRequestMsg
    49  	TalkResponseMsg
    50  	RequestTicketMsg
    51  	TicketMsg
    52  
    53  	UnknownPacket   = byte(255) // any non-decryptable packet
    54  	WhoareyouPacket = byte(254) // the WHOAREYOU packet
    55  )
    56  
    57  // Protocol messages.
    58  type (
    59  	// Unknown represents any packet that can't be decrypted.
    60  	Unknown struct {
    61  		Nonce Nonce
    62  	}
    63  
    64  	// WHOAREYOU contains the handshake challenge.
    65  	Whoareyou struct {
    66  		ChallengeData []byte   // Encoded challenge
    67  		Nonce         Nonce    // Nonce of request packet
    68  		IDNonce       [16]byte // Identity proof data
    69  		RecordSeq     uint64   // ENR sequence number of recipient
    70  
    71  		// Node is the locally known node record of recipient.
    72  		// This must be set by the caller of Encode.
    73  		Node *enode.Node
    74  
    75  		sent mclock.AbsTime // for handshake GC.
    76  
    77  		// Encoded is packet raw data for sending out, but should not be include in the RLP encoding.
    78  		Encoded []byte `rlp:"-"`
    79  	}
    80  
    81  	// PING is sent during liveness checks.
    82  	Ping struct {
    83  		ReqID  []byte
    84  		ENRSeq uint64
    85  	}
    86  
    87  	// PONG is the reply to PING.
    88  	Pong struct {
    89  		ReqID  []byte
    90  		ENRSeq uint64
    91  		ToIP   net.IP // These fields should mirror the UDP envelope address of the ping
    92  		ToPort uint16 // packet, which provides a way to discover the external address (after NAT).
    93  	}
    94  
    95  	// FINDNODE is a query for nodes in the given bucket.
    96  	Findnode struct {
    97  		ReqID     []byte
    98  		Distances []uint
    99  
   100  		// OpID is for debugging purposes and is not part of the packet encoding.
   101  		// It identifies the 'operation' on behalf of which the request was sent.
   102  		OpID uint64 `rlp:"-"`
   103  	}
   104  
   105  	// NODES is a response to FINDNODE.
   106  	Nodes struct {
   107  		ReqID     []byte
   108  		RespCount uint8 // total number of responses to the request
   109  		Nodes     []*enr.Record
   110  	}
   111  
   112  	// TALKREQ is an application-level request.
   113  	TalkRequest struct {
   114  		ReqID    []byte
   115  		Protocol string
   116  		Message  []byte
   117  	}
   118  
   119  	// TALKRESP is the reply to TALKREQ.
   120  	TalkResponse struct {
   121  		ReqID   []byte
   122  		Message []byte
   123  	}
   124  )
   125  
   126  // DecodeMessage decodes the message body of a packet.
   127  func DecodeMessage(ptype byte, body []byte) (Packet, error) {
   128  	var dec Packet
   129  	switch ptype {
   130  	case PingMsg:
   131  		dec = new(Ping)
   132  	case PongMsg:
   133  		dec = new(Pong)
   134  	case FindnodeMsg:
   135  		dec = new(Findnode)
   136  	case NodesMsg:
   137  		dec = new(Nodes)
   138  	case TalkRequestMsg:
   139  		dec = new(TalkRequest)
   140  	case TalkResponseMsg:
   141  		dec = new(TalkResponse)
   142  	default:
   143  		return nil, fmt.Errorf("unknown packet type %d", ptype)
   144  	}
   145  	if err := rlp.DecodeBytes(body, dec); err != nil {
   146  		return nil, err
   147  	}
   148  	if dec.RequestID() != nil && len(dec.RequestID()) > 8 {
   149  		return nil, ErrInvalidReqID
   150  	}
   151  	return dec, nil
   152  }
   153  
   154  func (*Whoareyou) Name() string        { return "WHOAREYOU/v5" }
   155  func (*Whoareyou) Kind() byte          { return WhoareyouPacket }
   156  func (*Whoareyou) RequestID() []byte   { return nil }
   157  func (*Whoareyou) SetRequestID([]byte) {}
   158  
   159  func (*Whoareyou) AppendLogInfo(ctx []interface{}) []interface{} {
   160  	return ctx
   161  }
   162  
   163  func (*Unknown) Name() string        { return "UNKNOWN/v5" }
   164  func (*Unknown) Kind() byte          { return UnknownPacket }
   165  func (*Unknown) RequestID() []byte   { return nil }
   166  func (*Unknown) SetRequestID([]byte) {}
   167  
   168  func (*Unknown) AppendLogInfo(ctx []interface{}) []interface{} {
   169  	return ctx
   170  }
   171  
   172  func (*Ping) Name() string             { return "PING/v5" }
   173  func (*Ping) Kind() byte               { return PingMsg }
   174  func (p *Ping) RequestID() []byte      { return p.ReqID }
   175  func (p *Ping) SetRequestID(id []byte) { p.ReqID = id }
   176  
   177  func (p *Ping) AppendLogInfo(ctx []interface{}) []interface{} {
   178  	return append(ctx, "req", hexutil.Bytes(p.ReqID), "enrseq", p.ENRSeq)
   179  }
   180  
   181  func (*Pong) Name() string             { return "PONG/v5" }
   182  func (*Pong) Kind() byte               { return PongMsg }
   183  func (p *Pong) RequestID() []byte      { return p.ReqID }
   184  func (p *Pong) SetRequestID(id []byte) { p.ReqID = id }
   185  
   186  func (p *Pong) AppendLogInfo(ctx []interface{}) []interface{} {
   187  	return append(ctx, "req", hexutil.Bytes(p.ReqID), "enrseq", p.ENRSeq)
   188  }
   189  
   190  func (p *Findnode) Name() string           { return "FINDNODE/v5" }
   191  func (p *Findnode) Kind() byte             { return FindnodeMsg }
   192  func (p *Findnode) RequestID() []byte      { return p.ReqID }
   193  func (p *Findnode) SetRequestID(id []byte) { p.ReqID = id }
   194  
   195  func (p *Findnode) AppendLogInfo(ctx []interface{}) []interface{} {
   196  	ctx = append(ctx, "req", hexutil.Bytes(p.ReqID))
   197  	if p.OpID != 0 {
   198  		ctx = append(ctx, "opid", p.OpID)
   199  	}
   200  	return ctx
   201  }
   202  
   203  func (*Nodes) Name() string             { return "NODES/v5" }
   204  func (*Nodes) Kind() byte               { return NodesMsg }
   205  func (p *Nodes) RequestID() []byte      { return p.ReqID }
   206  func (p *Nodes) SetRequestID(id []byte) { p.ReqID = id }
   207  
   208  func (p *Nodes) AppendLogInfo(ctx []interface{}) []interface{} {
   209  	return append(ctx,
   210  		"req", hexutil.Bytes(p.ReqID),
   211  		"tot", p.RespCount,
   212  		"n", len(p.Nodes),
   213  	)
   214  }
   215  
   216  func (*TalkRequest) Name() string             { return "TALKREQ/v5" }
   217  func (*TalkRequest) Kind() byte               { return TalkRequestMsg }
   218  func (p *TalkRequest) RequestID() []byte      { return p.ReqID }
   219  func (p *TalkRequest) SetRequestID(id []byte) { p.ReqID = id }
   220  
   221  func (p *TalkRequest) AppendLogInfo(ctx []interface{}) []interface{} {
   222  	return append(ctx, "proto", p.Protocol, "req", hexutil.Bytes(p.ReqID), "len", len(p.Message))
   223  }
   224  
   225  func (*TalkResponse) Name() string             { return "TALKRESP/v5" }
   226  func (*TalkResponse) Kind() byte               { return TalkResponseMsg }
   227  func (p *TalkResponse) RequestID() []byte      { return p.ReqID }
   228  func (p *TalkResponse) SetRequestID(id []byte) { p.ReqID = id }
   229  
   230  func (p *TalkResponse) AppendLogInfo(ctx []interface{}) []interface{} {
   231  	return append(ctx, "req", hexutil.Bytes(p.ReqID), "len", len(p.Message))
   232  }