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