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 }