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