How to interpret multiaddr?

How are multiaddr supposed to be interpreted?

When I see /ip4/127.0.0.1/tcp/80, I interpret this as an ipv4 address that can be connected to using tcp via port 80.

But what about something like this /dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt?

Also does the specification specify the order? for example is /ip4/127.0.0.1/tcp/80 as valid as /tcp/80/ip4/127.0.0.1 ?

I really could not find any information that expounds on the specification. Unfortunately. the specification section on Github here is very scanty.

You read them left to right and each protocol stack on the previous ones.

That correct.

Not that I know of, because that would require a full description of all protocols, it’s up to implementations.

But think about what such protocol would be, it would be IP running over TCP.
Which doesn’t make any sense, TCP use IP in the first place, you can’t just use TCP on it’s own.
And IP can’t be tunneled in a TCP stream like that, you need various PTP protocols which handle wrapping the IP packets.

First /p2p, this is the public key field, it will contain a hash or the raw public key if it’s small enough (RSA would be a hash, ECC is embeded)

/dnsaddr is a special one.
So dnsaddr stores the actual address in TXT records, so you query _dnsaddr.bootstrap.libp2p.io:

$ dig -t TXT _dnsaddr.bootstrap.libp2p.io
_dnsaddr.bootstrap.libp2p.io. 324 IN	TXT	"dnsaddr=/dnsaddr/sjc-1.bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN"
_dnsaddr.bootstrap.libp2p.io. 324 IN	TXT	"dnsaddr=/dnsaddr/nrt-1.bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
_dnsaddr.bootstrap.libp2p.io. 324 IN	TXT	"dnsaddr=/dnsaddr/ewr-1.bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa"
_dnsaddr.bootstrap.libp2p.io. 324 IN	TXT	"dnsaddr=/dnsaddr/ams-rust.bootstrap.libp2p.io/p2p/12D3KooWEZXjE41uU4EL2gpkAQeDXYok6wghN7wwNVPF5bwkaNfS"
_dnsaddr.bootstrap.libp2p.io. 324 IN	TXT	"dnsaddr=/dnsaddr/ams-2.bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb"
_dnsaddr.bootstrap.libp2p.io. 324 IN	TXT	"dnsaddr=/dnsaddr/sjc-2.bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp

As you can see we have many different addresses however they all include the /p2p field, the rule is we have to pick the one matching the outer address (QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt we seen earlier).
Which is:

/dnsaddr/nrt-1.bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt

Then since we have an other dnsaddr address we just repeat this process:

$ dig -t TXT _dnsaddr.nrt-1.bootstrap.libp2p.io
_dnsaddr.nrt-1.bootstrap.libp2p.io. 600	IN TXT	"dnsaddr=/ip4/147.75.94.115/tcp/4001/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
_dnsaddr.nrt-1.bootstrap.libp2p.io. 600	IN TXT	"dnsaddr=/ip4/147.75.94.115/udp/4001/quic/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
_dnsaddr.nrt-1.bootstrap.libp2p.io. 600	IN TXT	"dnsaddr=/ip6/2604:1380:3000:1f00::1/tcp/4001/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
_dnsaddr.nrt-1.bootstrap.libp2p.io. 600	IN TXT	"dnsaddr=/ip6/2604:1380:3000:1f00::1/udp/4001/quic/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
_dnsaddr.nrt-1.bootstrap.libp2p.io. 600	IN TXT	"dnsaddr=/dns4/nrt-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"
_dnsaddr.nrt-1.bootstrap.libp2p.io. 600	IN TXT	"dnsaddr=/dns6/nrt-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt"

This time we have many different addresses matching, but hopefully this should be clear enough by now, you just expand with all of them that match the public key.

Oh also the dns4 and dns6 do A and AAAA resolutions instead of TXT, and expand the results with corresponding ip4 and ip6 blocks.

1 Like