github.com/btcsuite/btcd@v0.24.0/wire/message.go (about)

     1  // Copyright (c) 2013-2016 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wire
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"unicode/utf8"
    12  
    13  	"github.com/btcsuite/btcd/chaincfg/chainhash"
    14  )
    15  
    16  // MessageHeaderSize is the number of bytes in a bitcoin message header.
    17  // Bitcoin network (magic) 4 bytes + command 12 bytes + payload length 4 bytes +
    18  // checksum 4 bytes.
    19  const MessageHeaderSize = 24
    20  
    21  // CommandSize is the fixed size of all commands in the common bitcoin message
    22  // header.  Shorter commands must be zero padded.
    23  const CommandSize = 12
    24  
    25  // MaxMessagePayload is the maximum bytes a message can be regardless of other
    26  // individual limits imposed by messages themselves.
    27  const MaxMessagePayload = (1024 * 1024 * 32) // 32MB
    28  
    29  // Commands used in bitcoin message headers which describe the type of message.
    30  const (
    31  	CmdVersion      = "version"
    32  	CmdVerAck       = "verack"
    33  	CmdGetAddr      = "getaddr"
    34  	CmdAddr         = "addr"
    35  	CmdAddrV2       = "addrv2"
    36  	CmdGetBlocks    = "getblocks"
    37  	CmdInv          = "inv"
    38  	CmdGetData      = "getdata"
    39  	CmdNotFound     = "notfound"
    40  	CmdBlock        = "block"
    41  	CmdTx           = "tx"
    42  	CmdGetHeaders   = "getheaders"
    43  	CmdHeaders      = "headers"
    44  	CmdPing         = "ping"
    45  	CmdPong         = "pong"
    46  	CmdAlert        = "alert"
    47  	CmdMemPool      = "mempool"
    48  	CmdFilterAdd    = "filteradd"
    49  	CmdFilterClear  = "filterclear"
    50  	CmdFilterLoad   = "filterload"
    51  	CmdMerkleBlock  = "merkleblock"
    52  	CmdReject       = "reject"
    53  	CmdSendHeaders  = "sendheaders"
    54  	CmdFeeFilter    = "feefilter"
    55  	CmdGetCFilters  = "getcfilters"
    56  	CmdGetCFHeaders = "getcfheaders"
    57  	CmdGetCFCheckpt = "getcfcheckpt"
    58  	CmdCFilter      = "cfilter"
    59  	CmdCFHeaders    = "cfheaders"
    60  	CmdCFCheckpt    = "cfcheckpt"
    61  	CmdSendAddrV2   = "sendaddrv2"
    62  )
    63  
    64  // MessageEncoding represents the wire message encoding format to be used.
    65  type MessageEncoding uint32
    66  
    67  const (
    68  	// BaseEncoding encodes all messages in the default format specified
    69  	// for the Bitcoin wire protocol.
    70  	BaseEncoding MessageEncoding = 1 << iota
    71  
    72  	// WitnessEncoding encodes all messages other than transaction messages
    73  	// using the default Bitcoin wire protocol specification. For transaction
    74  	// messages, the new encoding format detailed in BIP0144 will be used.
    75  	WitnessEncoding
    76  )
    77  
    78  // LatestEncoding is the most recently specified encoding for the Bitcoin wire
    79  // protocol.
    80  var LatestEncoding = WitnessEncoding
    81  
    82  // ErrUnknownMessage is the error returned when decoding an unknown message.
    83  var ErrUnknownMessage = fmt.Errorf("received unknown message")
    84  
    85  // ErrInvalidHandshake is the error returned when a peer sends us a known
    86  // message that does not belong in the version-verack handshake.
    87  var ErrInvalidHandshake = fmt.Errorf("invalid message during handshake")
    88  
    89  // Message is an interface that describes a bitcoin message.  A type that
    90  // implements Message has complete control over the representation of its data
    91  // and may therefore contain additional or fewer fields than those which
    92  // are used directly in the protocol encoded message.
    93  type Message interface {
    94  	BtcDecode(io.Reader, uint32, MessageEncoding) error
    95  	BtcEncode(io.Writer, uint32, MessageEncoding) error
    96  	Command() string
    97  	MaxPayloadLength(uint32) uint32
    98  }
    99  
   100  // makeEmptyMessage creates a message of the appropriate concrete type based
   101  // on the command.
   102  func makeEmptyMessage(command string) (Message, error) {
   103  	var msg Message
   104  	switch command {
   105  	case CmdVersion:
   106  		msg = &MsgVersion{}
   107  
   108  	case CmdVerAck:
   109  		msg = &MsgVerAck{}
   110  
   111  	case CmdSendAddrV2:
   112  		msg = &MsgSendAddrV2{}
   113  
   114  	case CmdGetAddr:
   115  		msg = &MsgGetAddr{}
   116  
   117  	case CmdAddr:
   118  		msg = &MsgAddr{}
   119  
   120  	case CmdAddrV2:
   121  		msg = &MsgAddrV2{}
   122  
   123  	case CmdGetBlocks:
   124  		msg = &MsgGetBlocks{}
   125  
   126  	case CmdBlock:
   127  		msg = &MsgBlock{}
   128  
   129  	case CmdInv:
   130  		msg = &MsgInv{}
   131  
   132  	case CmdGetData:
   133  		msg = &MsgGetData{}
   134  
   135  	case CmdNotFound:
   136  		msg = &MsgNotFound{}
   137  
   138  	case CmdTx:
   139  		msg = &MsgTx{}
   140  
   141  	case CmdPing:
   142  		msg = &MsgPing{}
   143  
   144  	case CmdPong:
   145  		msg = &MsgPong{}
   146  
   147  	case CmdGetHeaders:
   148  		msg = &MsgGetHeaders{}
   149  
   150  	case CmdHeaders:
   151  		msg = &MsgHeaders{}
   152  
   153  	case CmdAlert:
   154  		msg = &MsgAlert{}
   155  
   156  	case CmdMemPool:
   157  		msg = &MsgMemPool{}
   158  
   159  	case CmdFilterAdd:
   160  		msg = &MsgFilterAdd{}
   161  
   162  	case CmdFilterClear:
   163  		msg = &MsgFilterClear{}
   164  
   165  	case CmdFilterLoad:
   166  		msg = &MsgFilterLoad{}
   167  
   168  	case CmdMerkleBlock:
   169  		msg = &MsgMerkleBlock{}
   170  
   171  	case CmdReject:
   172  		msg = &MsgReject{}
   173  
   174  	case CmdSendHeaders:
   175  		msg = &MsgSendHeaders{}
   176  
   177  	case CmdFeeFilter:
   178  		msg = &MsgFeeFilter{}
   179  
   180  	case CmdGetCFilters:
   181  		msg = &MsgGetCFilters{}
   182  
   183  	case CmdGetCFHeaders:
   184  		msg = &MsgGetCFHeaders{}
   185  
   186  	case CmdGetCFCheckpt:
   187  		msg = &MsgGetCFCheckpt{}
   188  
   189  	case CmdCFilter:
   190  		msg = &MsgCFilter{}
   191  
   192  	case CmdCFHeaders:
   193  		msg = &MsgCFHeaders{}
   194  
   195  	case CmdCFCheckpt:
   196  		msg = &MsgCFCheckpt{}
   197  
   198  	default:
   199  		return nil, ErrUnknownMessage
   200  	}
   201  	return msg, nil
   202  }
   203  
   204  // messageHeader defines the header structure for all bitcoin protocol messages.
   205  type messageHeader struct {
   206  	magic    BitcoinNet // 4 bytes
   207  	command  string     // 12 bytes
   208  	length   uint32     // 4 bytes
   209  	checksum [4]byte    // 4 bytes
   210  }
   211  
   212  // readMessageHeader reads a bitcoin message header from r.
   213  func readMessageHeader(r io.Reader) (int, *messageHeader, error) {
   214  	// Since readElements doesn't return the amount of bytes read, attempt
   215  	// to read the entire header into a buffer first in case there is a
   216  	// short read so the proper amount of read bytes are known.  This works
   217  	// since the header is a fixed size.
   218  	var headerBytes [MessageHeaderSize]byte
   219  	n, err := io.ReadFull(r, headerBytes[:])
   220  	if err != nil {
   221  		return n, nil, err
   222  	}
   223  	hr := bytes.NewReader(headerBytes[:])
   224  
   225  	// Create and populate a messageHeader struct from the raw header bytes.
   226  	hdr := messageHeader{}
   227  	var command [CommandSize]byte
   228  	readElements(hr, &hdr.magic, &command, &hdr.length, &hdr.checksum)
   229  
   230  	// Strip trailing zeros from command string.
   231  	hdr.command = string(bytes.TrimRight(command[:], "\x00"))
   232  
   233  	return n, &hdr, nil
   234  }
   235  
   236  // discardInput reads n bytes from reader r in chunks and discards the read
   237  // bytes.  This is used to skip payloads when various errors occur and helps
   238  // prevent rogue nodes from causing massive memory allocation through forging
   239  // header length.
   240  func discardInput(r io.Reader, n uint32) {
   241  	maxSize := uint32(10 * 1024) // 10k at a time
   242  	numReads := n / maxSize
   243  	bytesRemaining := n % maxSize
   244  	if n > 0 {
   245  		buf := make([]byte, maxSize)
   246  		for i := uint32(0); i < numReads; i++ {
   247  			io.ReadFull(r, buf)
   248  		}
   249  	}
   250  	if bytesRemaining > 0 {
   251  		buf := make([]byte, bytesRemaining)
   252  		io.ReadFull(r, buf)
   253  	}
   254  }
   255  
   256  // WriteMessageN writes a bitcoin Message to w including the necessary header
   257  // information and returns the number of bytes written.    This function is the
   258  // same as WriteMessage except it also returns the number of bytes written.
   259  func WriteMessageN(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) (int, error) {
   260  	return WriteMessageWithEncodingN(w, msg, pver, btcnet, BaseEncoding)
   261  }
   262  
   263  // WriteMessage writes a bitcoin Message to w including the necessary header
   264  // information.  This function is the same as WriteMessageN except it doesn't
   265  // doesn't return the number of bytes written.  This function is mainly provided
   266  // for backwards compatibility with the original API, but it's also useful for
   267  // callers that don't care about byte counts.
   268  func WriteMessage(w io.Writer, msg Message, pver uint32, btcnet BitcoinNet) error {
   269  	_, err := WriteMessageN(w, msg, pver, btcnet)
   270  	return err
   271  }
   272  
   273  // WriteMessageWithEncodingN writes a bitcoin Message to w including the
   274  // necessary header information and returns the number of bytes written.
   275  // This function is the same as WriteMessageN except it also allows the caller
   276  // to specify the message encoding format to be used when serializing wire
   277  // messages.
   278  func WriteMessageWithEncodingN(w io.Writer, msg Message, pver uint32,
   279  	btcnet BitcoinNet, encoding MessageEncoding) (int, error) {
   280  
   281  	totalBytes := 0
   282  
   283  	// Enforce max command size.
   284  	var command [CommandSize]byte
   285  	cmd := msg.Command()
   286  	if len(cmd) > CommandSize {
   287  		str := fmt.Sprintf("command [%s] is too long [max %v]",
   288  			cmd, CommandSize)
   289  		return totalBytes, messageError("WriteMessage", str)
   290  	}
   291  	copy(command[:], []byte(cmd))
   292  
   293  	// Encode the message payload.
   294  	var bw bytes.Buffer
   295  	err := msg.BtcEncode(&bw, pver, encoding)
   296  	if err != nil {
   297  		return totalBytes, err
   298  	}
   299  	payload := bw.Bytes()
   300  	lenp := len(payload)
   301  
   302  	// Enforce maximum overall message payload.
   303  	if lenp > MaxMessagePayload {
   304  		str := fmt.Sprintf("message payload is too large - encoded "+
   305  			"%d bytes, but maximum message payload is %d bytes",
   306  			lenp, MaxMessagePayload)
   307  		return totalBytes, messageError("WriteMessage", str)
   308  	}
   309  
   310  	// Enforce maximum message payload based on the message type.
   311  	mpl := msg.MaxPayloadLength(pver)
   312  	if uint32(lenp) > mpl {
   313  		str := fmt.Sprintf("message payload is too large - encoded "+
   314  			"%d bytes, but maximum message payload size for "+
   315  			"messages of type [%s] is %d.", lenp, cmd, mpl)
   316  		return totalBytes, messageError("WriteMessage", str)
   317  	}
   318  
   319  	// Create header for the message.
   320  	hdr := messageHeader{}
   321  	hdr.magic = btcnet
   322  	hdr.command = cmd
   323  	hdr.length = uint32(lenp)
   324  	copy(hdr.checksum[:], chainhash.DoubleHashB(payload)[0:4])
   325  
   326  	// Encode the header for the message.  This is done to a buffer
   327  	// rather than directly to the writer since writeElements doesn't
   328  	// return the number of bytes written.
   329  	hw := bytes.NewBuffer(make([]byte, 0, MessageHeaderSize))
   330  	writeElements(hw, hdr.magic, command, hdr.length, hdr.checksum)
   331  
   332  	// Write header.
   333  	n, err := w.Write(hw.Bytes())
   334  	totalBytes += n
   335  	if err != nil {
   336  		return totalBytes, err
   337  	}
   338  
   339  	// Only write the payload if there is one, e.g., verack messages don't
   340  	// have one.
   341  	if len(payload) > 0 {
   342  		n, err = w.Write(payload)
   343  		totalBytes += n
   344  	}
   345  
   346  	return totalBytes, err
   347  }
   348  
   349  // ReadMessageWithEncodingN reads, validates, and parses the next bitcoin Message
   350  // from r for the provided protocol version and bitcoin network.  It returns the
   351  // number of bytes read in addition to the parsed Message and raw bytes which
   352  // comprise the message.  This function is the same as ReadMessageN except it
   353  // allows the caller to specify which message encoding is to to consult when
   354  // decoding wire messages.
   355  func ReadMessageWithEncodingN(r io.Reader, pver uint32, btcnet BitcoinNet,
   356  	enc MessageEncoding) (int, Message, []byte, error) {
   357  
   358  	totalBytes := 0
   359  	n, hdr, err := readMessageHeader(r)
   360  	totalBytes += n
   361  	if err != nil {
   362  		return totalBytes, nil, nil, err
   363  	}
   364  
   365  	// Enforce maximum message payload.
   366  	if hdr.length > MaxMessagePayload {
   367  		str := fmt.Sprintf("message payload is too large - header "+
   368  			"indicates %d bytes, but max message payload is %d "+
   369  			"bytes.", hdr.length, MaxMessagePayload)
   370  		return totalBytes, nil, nil, messageError("ReadMessage", str)
   371  
   372  	}
   373  
   374  	// Check for messages from the wrong bitcoin network.
   375  	if hdr.magic != btcnet {
   376  		discardInput(r, hdr.length)
   377  		str := fmt.Sprintf("message from other network [%v]", hdr.magic)
   378  		return totalBytes, nil, nil, messageError("ReadMessage", str)
   379  	}
   380  
   381  	// Check for malformed commands.
   382  	command := hdr.command
   383  	if !utf8.ValidString(command) {
   384  		discardInput(r, hdr.length)
   385  		str := fmt.Sprintf("invalid command %v", []byte(command))
   386  		return totalBytes, nil, nil, messageError("ReadMessage", str)
   387  	}
   388  
   389  	// Create struct of appropriate message type based on the command.
   390  	msg, err := makeEmptyMessage(command)
   391  	if err != nil {
   392  		// makeEmptyMessage can only return ErrUnknownMessage and it is
   393  		// important that we bubble it up to the caller.
   394  		discardInput(r, hdr.length)
   395  		return totalBytes, nil, nil, err
   396  	}
   397  
   398  	// Check for maximum length based on the message type as a malicious client
   399  	// could otherwise create a well-formed header and set the length to max
   400  	// numbers in order to exhaust the machine's memory.
   401  	mpl := msg.MaxPayloadLength(pver)
   402  	if hdr.length > mpl {
   403  		discardInput(r, hdr.length)
   404  		str := fmt.Sprintf("payload exceeds max length - header "+
   405  			"indicates %v bytes, but max payload size for "+
   406  			"messages of type [%v] is %v.", hdr.length, command, mpl)
   407  		return totalBytes, nil, nil, messageError("ReadMessage", str)
   408  	}
   409  
   410  	// Read payload.
   411  	payload := make([]byte, hdr.length)
   412  	n, err = io.ReadFull(r, payload)
   413  	totalBytes += n
   414  	if err != nil {
   415  		return totalBytes, nil, nil, err
   416  	}
   417  
   418  	// Test checksum.
   419  	checksum := chainhash.DoubleHashB(payload)[0:4]
   420  	if !bytes.Equal(checksum, hdr.checksum[:]) {
   421  		str := fmt.Sprintf("payload checksum failed - header "+
   422  			"indicates %v, but actual checksum is %v.",
   423  			hdr.checksum, checksum)
   424  		return totalBytes, nil, nil, messageError("ReadMessage", str)
   425  	}
   426  
   427  	// Unmarshal message.  NOTE: This must be a *bytes.Buffer since the
   428  	// MsgVersion BtcDecode function requires it.
   429  	pr := bytes.NewBuffer(payload)
   430  	err = msg.BtcDecode(pr, pver, enc)
   431  	if err != nil {
   432  		return totalBytes, nil, nil, err
   433  	}
   434  
   435  	return totalBytes, msg, payload, nil
   436  }
   437  
   438  // ReadMessageN reads, validates, and parses the next bitcoin Message from r for
   439  // the provided protocol version and bitcoin network.  It returns the number of
   440  // bytes read in addition to the parsed Message and raw bytes which comprise the
   441  // message.  This function is the same as ReadMessage except it also returns the
   442  // number of bytes read.
   443  func ReadMessageN(r io.Reader, pver uint32, btcnet BitcoinNet) (int, Message, []byte, error) {
   444  	return ReadMessageWithEncodingN(r, pver, btcnet, BaseEncoding)
   445  }
   446  
   447  // ReadMessage reads, validates, and parses the next bitcoin Message from r for
   448  // the provided protocol version and bitcoin network.  It returns the parsed
   449  // Message and raw bytes which comprise the message.  This function only differs
   450  // from ReadMessageN in that it doesn't return the number of bytes read.  This
   451  // function is mainly provided for backwards compatibility with the original
   452  // API, but it's also useful for callers that don't care about byte counts.
   453  func ReadMessage(r io.Reader, pver uint32, btcnet BitcoinNet) (Message, []byte, error) {
   454  	_, msg, buf, err := ReadMessageN(r, pver, btcnet)
   455  	return msg, buf, err
   456  }