Welcome to my homepage!
      email at this domain
      yancy at irc.libera.chat
    

This site is Lynx (web browser) friendly (mostly).




20240114
        -----BEGIN PGP PUBLIC KEY BLOCK-----

        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
        gspZr68=
        =YIfr
        -----END PGP PUBLIC KEY BLOCK-----
      

      02/26/26

      As of late, I've been debugging a Bitcoin P2P application.  In order to better understand the
      communication that's happening under the hood, I resorted to running a tcpdump which captures
      packets between said application and Bitcoin core.  Note that my experimentation thus far is
      using the V1 protocol which is un-encrypted.

      To initiate the packet capture with tcpdump:
        sudo tcpdump -i `interface` -w `file` host `host ip`

      where:
        `host ip` is an instance of Bitcoin core
        `interface` is my wireless nic wlp3s0
        `file` is the location to save the packet capture (pcap file), like /tmp/dump

      Then, to read the pcap file: tcpdump -qns 0 -X -r `file`

      A Bitcoin P2P application begins communication with a handshake.  This handshake specifies the
      first message is a Version Message sent by the client. The Version Message is defined by the
      Protocol documentation.  According to the docs, all message structures, including version begin
      with some header information (see Message Structure in proto docs above).

      The Message structure memory layout is as follows:

      magic: 4 bytes
      command: 12 bytes
      length: 4 bytes
      checksum: 4 bytes
      payload: variable size

      In the case of Version, the "command" will be version in ASCII: 7665 7273 696f 6e00 0000 0000.
      So, back to the packet capture, to find where the communication between said application and
      Bitcoin core starts, I find the first occurrence of that ASCII.  On my capture, that occurs on
      the 6th packet midway in.  The next 4 bytes directly following the command is the length of
      the payload or message.  For my capture, this looks like `6200 0000`.  A quote from the
      Protocol docs is "Almost all integers are encoded in little endian", so when we see something
      like `6200 0000`, this tells me that the payload is 98 bytes long.  The remaining 4 bytes are
      the checksum which are un-important for now.

      b247 e642 - no clue what this is - 4 bytes
      7665 7273 696f 6e00 0000 0000 - this is the word version in hex - 12 bytes
      6200 0000 - this is the length of the payload (body) which is 98 bytes - 4 bytes
      ae4a f87f - this is the checksum - 4 bytes

      As a side note, the 4 bytes directly proceeding the command should be the network magic.
      However, `b247 e642` are the bytes directly proceeding version, and that does not translate
      to any know "magic values" in the docs.

      Continuing on to the payload, AKA message body, which is of variable length, however in this
      case is 98 bytes.

      The payload, which is of type Version Message is as follows:

      version: 4 bytes
      services: 8 bytes
      timestamp: 8 bytes
      receive address: 26 bytes
      from address: 26 bytes
      nonce: 8 bytes
      user agent: variable size
      start height: 4 bytes
      realy: 1 bytes

      I find the next 4 bytes directly following checksum to be `7f11 0100` which translates to
      70015 (little endian).

      The payload continues as follows:

      7f11 0100 - this is the protocol version, which in decimal is 70015 (little endian) - 4 bytes
      0000 0000 0000 0000 - services - 8 bytes
      a83f 9c69 0000 0000 - timestamp - 8 bytes
      0000 0000 0000 0000 0000 0000 0000 0000 0000 ffff 7f00 0001 d431 - address rcv - 26 bytes
      0000 0000 0000 0000 0000 0000 0000 0000 0000 ffff 7f00 0001 d431 - address send - 26 bytes
      0000 0000 0000 0000 - nonce - 4 bytes
      0c2f 6c6f 7265 3a30 2e30 2e31 2f - user agent - ?
      0000 0000 - start height - 4 bytes
      00 - relay - 1

      User agent is a field to transmit the name of the software, whether it be Bitcoin Core or some
      other client.  Technically the field is of variable length, however since we know the length
      of the payload, 98 bytes, and all other fields are of known size, we can also know the length
      of user agent with some simple arithmetic: 98 - 4 - 8 - 8 - 26 - 26 - 8 - 4 - 1.  Also notice
      that the sending and the receiving address are the same.  This is no doubt because this is
      the first communication, so there is only really a sending address.  It's curious though that
      the receiving address would not simply be empty.

      The response from Bitcoin core will be the version message, so I look for the next occurrence
      of "version" in ASCII 7665 7273 696f 6e00 0000 0000.  Using the version hex as an anchor, I look at
      the proceeding and following bytes which reveal the following:

      magic: fabf b5da
      command: 7665 7273 696f 6e00 0000 0000
      length: 6700 0000
      checksum 4f01 cf12
      payload: ?

      This part threw me for a loop though.  I was expecting to find the payload directly following
      checksum, which is how the first version message by the initiating client appeared in the pcap
      file.  However, for whatever reason, bitcoin core sends the header and the message body in
      two separate packets.  There must be some bytes that go into the beginning of the header
      which causes the pcap file to have a payload _which does not directly follow_ the checksum.
      Looking halfway down the packet that follows Bitcoin Cores first packet response, I find:

      version: 8011 0100 - protocol version 70016
      services: 090c 0000
      timestamp: 0000 0000
      addr recv: 533f 9c69 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
      addr from: 0000 0000 0000 0000 090c 0000 0000 0000 0000 0000 0000 0000 0000
      nonce: 0000 0000
      user agent: 0000 0000 43dc 33f0  6041 cf80 112f 5361 746f 7368 693a 3330 2e39 392e 302f
      start height: 0000 0000
      relay: 01
    
      03/07/26

      Continuing on from last post on 02/26, in which I detailed the start of the handshake
      between two peers.  After the version message is first sent from initiating client,
      the receiving peer, a core node, responds sending back it's version message.  The core node
      now knows both the sender and it's own capable protocol version, so it computes the minimum
      of the two versions.  In the trace above, my initial request set protocol version `70015`
      and the receiver, in this case a core node, responded with `70016`.  Therefore, on the core
      node side, the session protocol will be computed as `70015`.

      In response to the version message, the core node sends a `verack` message, a header only
      message without a body.  You might say, a disembodied message.

      fabf b5da - network magic
      7665 7261 636b 0000 0000 0000 - verack command
      0000 0000 - note the length is zero signifying no body
      5df6 e0e2 - checksum

      The initiating client will do the same in response to the version message and set the
      session protocol for communication going forward.

      L -> R: Send version message with the local peer's version
      R -> L: Send version message back
      R -> L: Send verack message
      R:      Sets version to the minimum of the 2 versions
      L -> R: Send verack message after receiving version message from R
      L:      Sets version to the minimum of the 2 versions
      [0]

      Now that we know the session protocol version `70015` AKA: 
      `ProtocolVersion::INVALID_CB_NO_BAN_VERSION` in rust-bitcoin land [1], we know what
      messages to see next in our trace.

      The next message in the trace is a `sendcmpct` which is sent from core to the initiating
      client.

      Here is the `sendcmpct` header:
      fabf b5da - magic
      7365 6e64 636d 7063 7400 0000 - verack cmd
      0900 0000 - length 9
      e92f 5ef8 - checksum

      Tcpdump shows the size of the contained data in the next packet as `9` which matches what
      we just saw in the header (length 9).

      Body (payload):
      00 - mode (low-bandwidth)
      02 0000 0000 0000 00 - pch command

      Further discussion of `sendcmpct` can be found here [2].

      The very next message received from core is a ping command.  Ping [3] is used in protocol
      versions greater than `60000`, and since we negotiated a session version of `70015`,
      needing to respond to ping is no surprise.

      Ping Header:
      fabf b5da - magic
      7069 6e67 0000 0000 0000 0000 - ping command
      0800 0000 - length
      667e 2273 - checksum

      Ping Body:
      432f 5f84 912b c7de - nonce

      The client which initiated the communication in the first place with core, ought now respond
      with a Pong message using the corresponding nonce.
    
0. version handshake
1. rust-bitcoin
2. bip-0152
2. bip-0031