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