Self-Describing Resource Locator
Table of Contents
1. Introduction
This document describes the Self-Describing Resource Locator (SDRI), a format for encoding addresses from well-established network protocols. Functionality-wise, it can be seen as a more specific form of uniform resource locator (URL); the "more specific" part comes from the fact that SDRL is self-describing - an SDRI also includes specification for the underlying layers.
SDRL is an attempt of redesigning multiaddr, originally designed and maintained by Protocol Labs.
This document is a very early draft; things might change in future versions.
1.1. Draft update
- 2025.8.2: Description for string escaping, type definitions and resolution. Added description for URL form.
- 2025.8.1: First version
2. General description
2.1. An example
An HTTP URL like this:
https://sebastian.graphics/blog/the-problem-with-wikipedia.html
…is described with SDRI like this:
/dns4/sebastian.graphics/https/blog$/the-problem-with-wikipedia.html
To break it up and explain each part:
# DNS resolve via default settings: # locally configured domain name server # UDP+TCP at port 53 # look for a domain named "sebastian.graphics" /dns4/sebastian.graphics # Use HTTPS with default setting: # TCP + TLS (version number negotiated) over port 443 # Use HTTP protocol; query for "blog/the-problem-with-wikipedia.html" # the slash is escaped with "$" /https/blog$/the-problem-with-wikipedia.html
In the example above /dns4 and /https are actually shorthands for often-used protocols; the fully qualified version would be something like this:
/ip4/{ns_ip}/53/dns4/sebastian.graphics/tcp+tls:*/443/http/blog$/the-problem-with-wikipedia.html
To break it down:
# use IPv4, locally configured domain name server ip
/ip4/{ns_ip}
# use port 53, which at this time produce an IPAddr w/ Port
/53
# use dns4, which would use the UDP+TCP combo on the
# previously specified port and the ip addr.
# look for "sebastian.graphics"
/dns4/sebastian.graphics
# on the produced IPv4 Address,
# use TCP and TLS (version determined by negotiation) at port 443
/tcp+tls:*/443
# use HTTP
# look for "blog/the-problem-with-wikipedia.html"
# the slash is escaped with "$".
/http/blog$/the-problem-with-wikipedia.html
And the examples listed at Multiformats website:
/ip4/127.0.0.1/udp/9090/quic # IPv4 address using UDP on port 9090, with QUIC /ip6/::1/tcp/3217 # IPv6 address using TCP on port 3217 /ip4/127.0.0.1/tcp/80/http/baz.jpg # IPv4 address using TCP on port 80, accessing an HTTP resource /dns4/foo.com/tcp/80/http/bar$/baz.jpg # DNS resolution (IPv4) using TCP on port 80, accessing an HTTP resource /dns6/foo.com/tcp/443/https # DNS resolution (IPv6) using TCP on port 443 for HTTPS # NOTE: apparently the use of /https above is deprecated and replaced with /tls/http now?
…can be written as follows:
/ip4/127.0.0.1/udp+quic/9090 /ip6/::1/tcp/3217 /ip4/127.0.0.1/tcp:80/http/baz.jpg /dns4/foo.com/tcp/80/bar$/baz.jpg /dns6/foo.com/tcp+tls/443/http/
2.2. The general scheme of things
- An SDRL is composed of one or more step components ("step" for short), each of which describes an independent step of the process required to gain access to the resource it describes.
- Step components are composed of attribute components ("attribute" for short), which are different elements needed to describe that particular step to be completed, like the port number or the IP address.
- Within each step component, attributes are described in the order of from lower-level to higher-level. For example, to describe a step that involves HTTP, one would first specify IP, then TCP, and then HTTP at last.
- Each step is to be described "as its own thing"; for example, an HTTPS request to a domain name would involve DNS name resolving; in this case, the whole course of DNS resolution is specified with the HTTPS part being put at the end; the order of things would be IP-DNS-TCP&TLS-HTTP.
3. Type description
To better help validating SDRL, a type system is designed and used to describe each attribute. This type system and the description of attributes are listed below.
3.1. Basic types
A few types are defined:
IPv4Addr- IPv4 address. The lexical syntax of this type follows the convention of 4 period-separated decimal numbers in the range of 0 to 255.IPv6Addr- IPv6 address. The lexical syntax of this type follows RFC 5952.IPAddr- This type is defined as a union ofIPv4AddrandIPv6Addr. AnyIPv4Addrand anyIPv6Addrmatches with this type during type checking.Port- Port number. The lexical syntax of this type would be a decimal nubmer.Version- Version string. The lexical syntax of this type is not strictly defined, since different protocols can have different ways of versioning; but the string*is considered a validVersion, which means that the version of the protocol would be decided by negotiation at runtime.String- An fully escaped arbitrary string. Escaping is necessary to prevent certain queries (e.g. paths in HTTP) to be errorneously interpreted as an attribute.- To escape a string, all occurences of the character
$is to be replaced with$$, and all occurences of the character/is to be replaced with$/. To un-escape a string, simply perform the reverse action - replace all$/with/, then all$$with$. - Under situations where only ASCII is allowed for an SDRL, the encoding scheme in RFC 3986 is to be used to the unescaped string.
- To escape a string, all occurences of the character
0- A type that matches nothingness. (See section "Resolution").
A "catch-all" type, * (different from the value * of the Version Type) is also defined to match any subjects and the lack thereof (in cases when the attribute is the first attribute of the SDRL).
3.2. Endpoint types
TransLayerEndpoint - A transport layer endpoint. AppLayerEndpoint - An application layer endpoint DataEndpoint = TransLayerEndpoint | AppLayerEndpoint
3.3. Annotated with port number
We allow arbitrary port number override. We define two special type constructors for it, written as follows:
[type]/Port- An object of type[type]with a port, e.g. an IPv4 address with a port number would have a type ofIPv4Addr/Port.[type]/Port?- An object of type[type], which may or may not come with a port. This types match with both[type]and[type]/Port.
With these two type constructors we have the following types:
IPv4Addr/Port - An IPv4 address with port IPv6Addr/Port - An IPv6 address with port IPv4Addr/Port? - An IPv4 address, which may or may not have a port IPv6Addr/Port? - An IPv6 address, which may or may not have a port TransLayerEndpoint/Port, TransLayerEndpoint/Port? AppLayerEndpoint/Port, AppLayerEndpoint/Port? DataEndpoint/Port, DataEndpoint/Port?
An attribute always uses the "latest" port number up till that point, unless a port number is provided as an argument. For example, the sequence of attributes /356/448/tcp contains two port number overrides (356 and 448, in that order) and an attribute of TCP; if there's no arguments for the /tcp part, then this TCP connection would use port number 448 (since it overrides the previously-set 356).
4. Attribute component definition
4.1. Conventions of description
The different path components is described in the following form:
/...
ArgumentTypes -> (SourceType -> TargetType)
# Description of this path component.
The first line describes its syntax form. Within this syntax form, the arguments of a path component is enclosed in square brackets (which is not a part of the actual path). For example, the syntax of TCP+TLS is written as /tcp+tls:[ver]/[portno], but you write e.g. /tcp+tls:*/443 instead of /tcp+tls:[*]/[443].
The types of a path component's arguments is described w/ a n-tuple enclosed in parentheses and each type separated with comma. When there is only one argument, the parentheses are omitted. When there's no arguments, () is written instead.
SourceType describes the required type of whatever that comes before the path component, and TargetType describes the resulting type of appending this path component to that. The description of types are detailed above.
Multiple type description line of a path component may exist. As long as one of them is applicable, the whole path should be seen as without typing errors.
4.2. Port override
/[portno]
Port -> (* -> */Port)
Port -> (*/Port -> */Port)
# annotate the subject with a port number.
# if there's already a port number present, this would
# override it.
# whatever immediately follows would use this port number.
4.3. Internet layer
/ip4/[ipv4-addr]
String -> (* -> IPv4Addr)
# ignore everything existing previously,
# make a new IPv4 address as the subject.
/ip6/[ipv6-addr]
String -> (* -> IPv6Addr)
# ignore everything existing previously,
# make a new IPv6 address as the subject.
4.4. Transport layer
4.4.1. TCP
/tcp
() -> (IPAddr/Port -> TransLayerEndpoint/Port)
Specify a TCP connection. use the previously specified port number.
/tcp/[portno]
Port -> (IPAddr/Port? -> TransLayerEndpoint/Port)
Specify a TCP connection at [portno].
/tcp+tls
() -> (IPAddr -> TransLayerEndpoint/Port)
() -> (IPAddr/Port -> TransLayerEndpoint/Port)
Specify an TCP+TLS endpoint. The version is determined by negotiation.
If the first type matches, the port is assume to be 443.
/tcp+tls:[ver]
Version -> (IPAddr -> TransLayerEndpoint/Port)
Version -> (IPAddr/Port -> TransLayerEndpoint/Port)
Specify an TCP+TLS endpoint.
If the first type matches, the port is assume to be 443.
/tcp+tls:[ver]/[portno]
(Version, Port) -> (IPAddr/Port? -> TransLayerEndpoint/Port)
Specify an TCP+TLS endpoint with the specified TLS version.
4.4.2. UDP
/udp
() -> (IPAddr/Port -> TransLayerEndpoint/Port)
Specify an UDP endpoint. Use the previously specified port number.
/udp/[portno]
Port -> (IPAddr/Port? -> TransLayerEndpoint/Port)
Specify an UDP endpoint.
/udp+quic
() -> (IPAddr/Port -> TransLayerEndpoint/Port)
Specify an UDP+QUIC endpoint. Use the previously specified port number.
/udp+quic/[portno]
Port -> (IPAddr/Port? -> TransLayerEndpoint/Port)
Specify an UDP+QUIC endpoint with the specified port number.
4.5. Application layer
4.5.1. DNS
/dns4/[domain]
String -> (0 -> IPv4Addr)
String -> (IPAddr -> IPv4Addr)
String -> (IPAddr/Port -> IPv4Addr)
String -> (DataEndpoint -> IPv4Addr)
Resolves a domain name to an IPv4Address w/ DNS. This follows the normal query procedure and attempts to obtain an IPv4 address in the end.
SHORTHAND: The first type, when applicable, is treated as the same as /ip4/[ns]/53/dns4/[domain] or /ip6/[ns]/53/dns4/[domain], depending on the user's local DNS configuration.
SHORTHAND: The second type, when applicable, is treated as the same as /53/dns4/[domain].
When applied to an IPAddr/Port, the transport layer is assumed to be UDP+TCP, which is what DNS normally uses.
/dns6/[domain]
String -> (0 -> IPv6Addr)
String -> (IPAddr -> IPv6Addr)
String -> (IPAddr/Port -> IPv6Addr)
String -> (DataEndpoint -> IPv6Addr)
Resolves a domain name to an IPv6Address w/ DNS. This follows the normal query procedure and attempts to obtain an IPv6 address in the end.
SHORTHAND: The first type, when applicable, is treated as the same as /ip4/[ns]/53/dns6/[domain] or /ip6/[ns]/53/dns6/[domain], depending on the user's local DNS configuration.
SHORTHAND: The second type, when applicable, is treated as the same as /53/dns6/[domain].
When applied to an IPAddr/Port, the transport layer is assumed to be UDP+TCP, which is what DNS normally uses.
4.5.2. HTTP
/http/[path...]
String -> (0 -> DataEndpoint)
String -> (IPAddr -> DataEndpoint)
String -> (IPAddr/Port -> DataEndpoint)
String -> (DataEndpoint -> DataEndpoint)
Returns an HTTP endpoint.
SHORTHAND: The first type, when applicable, is treated as if the port is 80 (i.e. /80/http)
4.6. Short hands
A few short hands can be defined as follow:
/https/[path...]
# Equivalent to:
# /tcp+tls:443/http/[path...]
5. Resolution
The resolution of an SDRL starts from the left-most attribute towards the right-most one. At any point in time, there will be a value (called the "subject"), and like what's specified above, each attributes (after taking enough arguments) produces a function which will convert the current subject into something else.
In the very beginning, the subject is empty (denoted by the type 0 mentioned above), which forces one to use one of the attributes that has a source type that matches it. Within the ones described above, only port override, /ip4 and /ip6 can be used (other than shorthands); and from there, one can use any of the attributes provided that their source types match with the type of the current subject.
5.1. Example
Imagine we run DNS over some HTTPS tunnel; we can describe it with SDRL like this:
/ip4/{some-ip}/tcp+tls:*/443/http/{some-path}/dns4/{some-domain}
The resolution process would be like this:
- In the beginning, the subject is empty (type
0) - The source type of the first attribute,
/ipv4/{some-ip}, is*. This matches with type0. The subject is now anIPv4Addr, whose actual value is specified with{some-ip}. - The second attribute would be
/tcp+tls:*/443, whose source type isIPAddrorIPAddr/Port(both of which matches withIPv4Addr, but the resolution should opt for the more specific ones if possible) and produces anTransLayerEndpoint/Port. The subject is now an TCP+TLS endpoint at the IPv4 address{some-ip}and port443. - The third attribute would be
/http/{some-path}, whose source type can be0,IPAddr,IPAddr/PortandDataEndpoint. The type of the current subject isTransLayerEndpoint/Port, which matches withDataEndpoint. The subject is now anDataEndpoint. - The fourth attribute would be
/dns4/{some-domain}, whose source type can be0,IPAddr,IPAddr/PortandDataEndpoint. The last one matches with the type of our current subject. This produces anIPv4Addr.
The overall result would thus be an IPv4Addr. This isn't an endpoint, but this behaviour is to be expected since it's a DNS query. Attributes for e.g. HTTP can follow after.
Appendix I: URL-compatible lexical form
An URL form of SDRL is defined to be the result of the following transformation:
- The scheme part of the URL shall be
sdrl. - There should not have an authority part, similar to the
file:scheme.- Omitting the authority part is also valid, but may cause visual confusion since most people are used to seeing at least two slashes at that particular part of URLs.
- The escaping of string shall follow the convention of URI instead of SDRL - while you should still escape slashes, you shoud percent-encode them instead of prefixing them with
$.
For example, the following SDRL:
/dns4/sebastian.graphics/https/blog$/the-problem-with-wikipedia.html
…should be this in URL:
sdrl:///dns4/sebastian.graphics/https/blog%2fthe-problem-with-wikipedia.html