IPFS ping protocol

I’ll write again bold for received messages, italic for transmitted.

This time I’ll not omit the length byte nor the new lines (which I’ll mark with \n), because the protocol seems to be more complex regarding the use of that. I’ll write binary bytes in hex form, e.g. 2 bytes one after the other I’ll write as 0x00 0x00.

I’m using still --disable-transport-encryption.

So the handshake insofar goes like this:
0x13 /multistream/1.0.0\n
0x13 /multistream/1.0.0\n
0x11 /plaintext/1.0.0\n
0x11 /plaintext/1.0.0\n
0x13 /multistream/1.0.0\n
0x13 /multistream/1.0.0\n
0x0D /mplex/6.7.0\n
0x0D /mplex/6.7.0\n
0x00 0x01 0
0x08 0x01 1
0x10 0x01 2
0x02 0x14 0x13 /multistream/1.0.0\n
0x0A 0x14 0x13 /multistream/1.0.0\n
0x12 0x14 0x13 /multistream/1.0.0\n

The explanation what is what is in previous posts.

Now in order to ping we must open a new stream and we can’t use the 3 ones opened by the IPFS on the other side as each has a separate function. We can just ignore those streams in order to just ping, but I didn’t at first and instead I tried to play with them.

In order to communicate with each of the streams opened by the IPFS we have to generate messages with proper headers of type (flag) 1, i.e. MessageReceiver and the ID.
We can generate the header byte in the reverse fashion as we decode it, using bitwise functions that’s header = (id << 3) | flag. So we first shift the ID 3 bits to the left and then we bitwise OR the bits on the right with the type (flag).

So each message we send has to have the header byte, but also two different length data bytes, along with the data itself, i.e. [header] [strlen(data) + 1] [strlen(data)] [data].

I sent first the ls\n command to see if I’ll get anything useful.
0x01 0x04 0x03 ls\n (for stream 0)
0x09 0x04 0x03 ls\n (for stream 1)
0x11 0x04 0x03 ls\n (for stream 2)

What I got were 2 byte responses with length byte of 0x00 and headers with each stream ID, but types (flags) of always in two cases 6 ResetInitiator and in one case 4 CloseInitiator. Which stream responded what was random, but always just 1 with close and 2 with reset.

After that I’ve sent to each the standard /multistream/1.0.0 back (with correct headers).

What I got in reply was the following each from a different stream ID (I’ll omit the headers, data bytes, newlines for clarity).
/libp2p/circuit/relay/0.1.0
/ipfs/kad/1.0.0
/ipfs/id/1.0.0

Which stream ID had which response was purely random.

To each of those I sent back again ls\n and same thing happened as before, only now I could identify which of those returns type 4 and which type 6. Type 4 (close) is returned by KAD and type 6 by the other 2.

Now let’s go to the ping protocol.
Again, I have to emphasize, that we don’t have to handshake the other streams. I just did it out of curiosity.

We have to open a new stream with stream ID for example 3, i.e. send a header with ID 3 and type (flag) 0. We get a multistream in response. Now we’re the initiator and IPFS is the receiver.

0x18 0x01 3
0x19 0x14 0x13 /multistream/1.0.0\n

We must respond with multistream back, note that header type is 2 MessageInitiator as we’re the initiator now.
0x1A 0x14 0x13 /multistream/1.0.0\n

Fun thing is that if we send now ls\n we get ls\n back, so theoretically we could use this already as ping. If we send anything else ending with \n we get back na, sending without a new line sends headers of flag 3 (close) and one of 5 (reset).

But let’s do it the proper way.

We send the same way as multistream /ipfs/ping/1.0.0 and we get the same thing back:
0x1A 0x12 0x11 /ipfs/ping/1.0.0\n
0x19 0x12 0x11 /ipfs/ping/1.0.0\n

Now we have to send 32 bytes of ping data (anything we want), but with just one length byte.
Before we were sending [header] [strlen(data) + 1] [strlen(data)] [data] for negotiation.
Now that we’re in ping mode we send it as [header] [strlen(data)] [data].

If we send anything less than 32 bytes, even if we mark it correctly in the header lenght, it will just stall. If we send anything more it will just read the first 32 bytes and send them back.

So how does it look like?
0x1A 0x20 12345678901234567890123456789012345678912
0x19 0x20 12345678901234567890123456789012345678912

We can repeat this last message for multiple pings and of course measure the time in between. :slight_smile:

1 Like