<?xml version="1.0"?><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" dir="ltr"><head><title>EER - ERIS over CoAP</title><style type="text/css">body {
    max-width: 900px;
    margin-top: 3em;
    margin-bottom: 5em;
    margin-left: auto;
    margin-right: auto;
    text-align: left;
    line-height: 1.6;
    font-family: &quot;courier new&quot;, courier, monospace;
    font-size: 12pt;
}

#logo {
    margin: auto;
    width: 70px;
    display: block;
}

nav ul {
    list-style-type: none;
    display: flex;
    margin: 0;
    padding: 0;
}
nav ul li {
    margin: auto; padding: 2.0rem;
}
nav ul li a::before {
    content: &quot;[&quot;
}
nav ul li a::after {
    content: &quot;]&quot;
}

.banner {width: 25%; display: block; margin: auto; padding: 2.0rem;}
.banners {display: flex;}

h1 {text-align: center;}

h2 {margin-top: 4em; text-align: center;}

h3 {margin-top: 2em;}

table {border-collapse: collapse; width: 100%; margin: 1.5rem 0;}

td, th {border: 1px solid black; text-align: left; padding: 0.5rem;}

th {background: goldenrod; font-weight: bold;}

pre {
    max-width: 100%;
    overflow: auto;
}

code {
    font-size: 90%;
    background-color: whitesmoke;
}


figure {width: 80%; display: block; margin: auto; padding: 2.0rem;}
img { margin: auto; max-width: 70%; }
footer { text-align: right; font-weight: 200; padding-top: 5em; }
footer span { padding: 0 0.5em 0 0.5em; }
</style></head><body><svg id="logo" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32"><defs><clipPath id="inside"><circle cx="16" cy="16" r="12" /></clipPath></defs><circle cx="16" cy="16" r="14" fill="goldenrod" stroke="black" stroke-width="2" /><path id="symbol" d="M 6,6 A 8,8 0 0,1 6,26 M 16,1 V 31 M 26,6 A 8,8 0 0,0 26,26" fill="none" stroke="black" stroke-width="2" clip-path="url(#inside)" /></svg><nav><a href="index.html">back to index</a></nav><article><h1>ERIS over CoAP</h1><p>ERIS is designed to traverse as many media as possible but in practice block transport should be dominated by only a handful of protocols selected for maximum interoperability. With that goal in mind this document describes a transport layer using the Constrained Application Protocol (CoAP) [<a href="https://datatracker.ietf.org/doc/rfc7252/">RFC 7252</a>]. CoAP may be transported over UDP [<a href="https://datatracker.ietf.org/doc/rfc7252/">RFC 7252</a>], stream transports such as TCP or WebSockets [<a href="https://www.rfc-editor.org/rfc/rfc8323">RFC 8323</a>], Unix sockets, over Delay Tolerant Networks [<a href="https://sci-hub.se/10.1109/FiCloud.2015.33">Auzias2015</a>] or experimental protocols such as GNUnet CADET.</p><p>The protocol described here is only concerned with opaque ERIS blocks and must never transport decoded ERIS content.</p><h2>Store URL</h2><p>The protocol defines a store that provides multiple resources (e.g. block access). A store is identified by an URL <a href="https://datatracker.ietf.org/doc/html/rfc3986">(RFC 3986</a>] - the <strong>store URL</strong>, resources are mapped to sub-paths of the store URL.</p><p>Examples:</p><ul><li><p>Store URL: <code>coap://example.net/my-eris-store</code></p><ul><li>URl of the blocks resource: <code>coap://example.net/my-eris-store/blocks</code></li></ul></li><li><p>Store URL: <code>coap+tcp://spam.works/eris/not-spam</code></p><ul><li>URL of blocks resource: <code>coap+tcp://spam.works/eris/not-spam/blocks</code></li></ul></li><li><p>Store URL: <code>coap+tcp://spam.works/eris/another-store</code></p><ul><li>URL of blocks resource: <code>coap+tcp://spam.works/eris/another-store/blocks</code></li></ul></li><li><p>Store URL: <code>coap+ws://jblis.xyz/stores/35bc6e8f-6b01-46f0-ba77-ddd41ae3ee51</code></p><ul><li><p>URL of blocks resource: <code>coap+ws://jblis.xyz/stores/35bc6e8f-6b01-46f0-ba77-ddd41ae3ee51/blocks</code></p></li></ul></li></ul><p>A CoAP endpoint can host multiple stores at different paths. The endpoint may use the same underlying storage for all stores. The individual stores can be used to manage specific block pinnings or quotas. The store URL might serve as a capability to post blocks and should in general not be shared indiscrimantely.</p><p>Applications that allow user-defined stores should allow stores to be defined by store URLs.</p><p>Store URLs can also be used for peer discovery.</p><h3>The <code>.well-known</code> store</h3><p>Endpoints may provide an endpoint wide store at the relative URL path <code>.well-known/eris</code>.</p><p>The <code>.well-known</code> store may be a read-only store that does not allow storing of blocks but provides access to all blocks stored by an endpoint.</p><h2>Store Resources</h2><h3><code>blocks</code></h3><p>An ERIS CoAP endpoint should at minimum provide a <code>blocks</code> resource that can be used to retrieve a stored block using the <code>GET</code> verbs.</p><h4>GET</h4><p>The <a href="https://www.rfc-editor.org/rfc/rfc7252.html#section-5.8.1">GET</a> verb retrieves a block.</p><p>The block reference (Blake2b256 digest) is encoded in the request as an URI-Query option. The block reference may be the digest as 32 octets or a Base32 [<a href="https://www.rfc-editor.org/info/rfc4648">RFC 4648</a>] encoding of 52 characters. The human readable form must use uppercase characters (Unicode codepoints 0x30-0x39 and 0x41-0x5A). Implementations must support paths in the human-readable form but should default to transmitting the raw encoding.</p><p>If the block is available the response code is 2.05 (Content) with a payload containing the block data. The payload must be in raw octets and the content format must be <em>application/octet-stream</em> (this is the default if no Content-Format option is present).</p><p>Example:</p><ul><li><p>Client sends a request for a block to the store at <code>coap://example.net/my-eris-store</code>:</p><ul><li>Uri-Host = &quot;example.net&quot;</li><li>Uri-Path = &quot;my-eris-store&quot;</li><li>Uri-Path = &quot;blocks&quot;</li><li>Uri-Query = &quot;H77AGSYKAVTQPUHODJTQA7WZPTWGTTKLRB2GLMF5H53NEKFJ3FUQ&quot;</li></ul></li><li>Sever retrieves block and responds with 2.05 (Content) with payload containing the block data.</li></ul><p>Optionally a <a href="https://www.rfc-editor.org/rfc/rfc7252.html#section-5.10.9">Size1 option</a> specifying the size of the block may be included in the request. This may be used by the server to optimize block retrieval. For example:</p><ul><li><p>Client sends a request for a block to the store at <code>coap://example.net/my-eris-store</code>:</p><ul><li>Uri-Host = &quot;example.net&quot;</li><li>Uri-Path = &quot;my-eris-store&quot;</li><li>Uri-Path = &quot;blocks&quot;</li><li>Uri-Query = &quot;H77AGSYKAVTQPUHODJTQA7WZPTWGTTKLRB2GLMF5H53NEKFJ3FUQ&quot;</li><li>Size1 = 1024</li></ul></li><li>Sever retrieves block and responds with 2.05 (Content) with payload containing the block data.</li></ul><p>Caching ERIS blocks is encouraged and can always be considered &quot;fresh&quot; in the CoAP caching model. This freshness is expressed with a large <a href="https://www.rfc-editor.org/rfc/rfc7252#section-5.10.5">Max-Age</a> option value. The default Max-Age value is 60 seconds so this option should be set to a large value (maximum of 0xFFFFFFFF, a long time) unless there is a compelling reason not to do so.</p><h4>PUT</h4><p>The <a href="https://www.rfc-editor.org/rfc/rfc7252.html#section-10.1.2">PUT</a> verb submits a block. The payload is the block.</p><p>If the block was successfully committed to storage or was already present the response code is 2.01 (Created).</p><p>Optionally the <code>Size1</code> option may be included to indicate the size of the block to be stored.</p><p>Stores that do not alow or do not support storing blocks may responds with 4.01 (Unauthorized) or 4.04 (Not Found).</p><p>Example:</p><ul><li><p>Client wants to store a block at the store <code>coap://example.net/my-eris-store</code>:</p><ul><li>Uri-Host = &quot;example.net&quot;</li><li>Uri-Path = &quot;my-eris-store&quot;</li><li>Uri-Path = &quot;blocks&quot;</li><li>Payload = BLOCK-DATA</li><li>Size1 = 1024</li></ul></li><li>Sever stores block and responds with 2.01 (Created)</li></ul><h2>Bi-directionality of requests</h2><p>CoAP allows bi-directional requests. A peer that initiates a connection can be both sender and recipient of requests. The terms server and client are relative to requests - a peer that sends a request is the client of the request and the receiving peer is the server of the request.</p><p>Peers that initiate a connection should also be able to respond to requests. Peers that accept connections may also make requests. This allows a more peer-to-peer exchange of blocks.</p><h2>Discovery</h2><p>ERIS CoAP block stores can be made discoverable via CoAP Resource Discovery (see <a href="https://www.rfc-editor.org/rfc/rfc7252#section-7.2">Section 7.2 of RFC 7252</a>). This is done by exposing information at the endpoint <code>.well-known/core</code> in the <a href="https://www.rfc-editor.org/rfc/rfc6690">CoRE Link Format (RFC 6690)</a>.</p><p>Services advertising ERIS CoAP block stores should expose the <em>store URL</em> as CoRE links using following parameters:</p><ul><li><code>if</code> (Interface Description): <code>&quot;http://purl.org/eris/coap&quot;</code></li><li><code>base</code>: This can be used to indicate that block transport should use CoAP over TCP instead of UDP (see <a href="https://www.rfc-editor.org/rfc/rfc9176">RFC 9176</a>).</li></ul><p>The mechanism can be used to discover peers on local networks (via multicast) and by learning new peers from already known peers.</p><h3>Discovery of store via multicast</h3><p>CoAP servers can be discovered by making a UDP multicast broadcast as described in <a href="https://www.rfc-editor.org/rfc/rfc7252#section-7.1">Section 7.1 of RFC 7252</a>.</p><p>An example:</p><ol><li>Server listens on an IPv6 UDP socket and joins the multicast group <code>ff02::fd</code> (all link-local CoAP nodes).</li><li>Client make a UDP multicast GET request to the endpoint <code>.well-known/core</code> and group <code>ff02::fd</code>.</li><li>Server responds with resources in the CoRE link format:</li></ol><pre><code>&lt;/&gt;;if=&quot;http://purl.org/eris/coap&quot;;base=coap+tcp:</code></pre><ol><li>Client connects to the ERIS block store at <code>coap+tcp://SERVER_ADDRESS/</code>. where <code>SERVER_ADDRESS</code> is the IP address contained in the UDP response.</li></ol><p>Note that the <code>base</code> parameter indicates that the store should be contacted via TCP even when the discovery is made via UDP.</p><h3>Discovery of new peers from already known peers</h3><p>A peer connecting to a server may learn about peers that the server knows by querying the CoRE links exposed by the server.</p><p>The server shares peers using the CoRE Link format as described above, using an URL where the shared peer can be reached.</p><p>For example:</p><ol><li>Server shares known peers <code>coap+tcp://eris.jblis.xyz/</code> and <code>coap+tcp://y.inqlab.net/</code> by serving following CoRE links at the endpoint <code>.well-known/core</code>:</li></ol><pre><code>&lt;/&gt;;if=&quot;http://purl.org/eris/coap&quot;,
&lt;coap+tcp://eris.jblis.xyz/&gt;;if=&quot;http://purl.org/eris/coap&quot;,
&lt;coap+tcp://y.inqlab.net/&gt;;if=&quot;http://purl.org/eris/coap&quot;</code></pre><ol><li>A peer connecting to the server can be discovered by making a GET request to <code>.well-known/core</code>.</li></ol><p>Note that the server also advertises itself as an ERIS CoAP store (using the relative URL <code>/</code>).</p><h2>Proxy and Hop-Limit</h2><p>Stores may proxy block requests to other stores. When doing so they should use and honor the CoAP <code>Hop-Limit</code> option as defined in <a href="https://www.rfc-editor.org/rfc/rfc8768.html">RFC 8768</a> to prevent infinite loops of requests. If no <code>Hop-Limit</code> option is set in a request, the store may only respond with locally available blocks and not proxy the request.</p><h3>Cross-Proxy between different networks</h3><p>A CoAP service may proxy block requests to other networks. It may advertise the ability to proxy to other networks using CoRE Link format and following parameters:</p><ul><li><code>rt=core.proxy</code>: This is defined in <a href="https://www.ietf.org/archive/id/draft-ietf-core-transport-indication-10.html#section-5.1">Section 5.1 of CoAP Transport Indication</a> and indicates that the service is available to act as a proxy.</li><li><code>proxy-scheme</code>: This parameter can be used to indicate the URI scheme of the network the proxy can reach.</li></ul><p>For example a service that can proxy requests to the <a href="https://www.ocapn.org/">OCapN</a> network may advertise itself using following CoRE link:</p><pre><code>&lt;/&gt;;if=&quot;http://purl.org/eris/coap&quot;;rt=core.proxy;proxy-scheme=ocapn</code></pre><p>Note that the <code>if=&quot;http://purl.org/eris/coap&quot;</code> is included to indicate that ERIS block store requests can be proxied. This is necessary as it is not possible to translate generic CoAP semantics to the proxied protocol.</p><p>A service using the proxy should use the <a href="https://www.rfc-editor.org/rfc/rfc7252#section-5.10.2">Proxy-Uri</a> option to indicate where the block store request should go. The <code>Uri-Path</code> and <code>Uri-Query</code> options MUST be used to understand the type of request. In that sense we diverge from RFC 7252, as it requires <code>Proxy-Uri</code> to take precedence over <code>Uri-Path</code> and <code>Uri-Query</code> options. This is not possible in our case as it may not be possible to encode the block store semantics in the URI of the network we proxy to.</p><p>The <a href="https://codeberg.org/eris/goblins-eris/src/branch/main/bin/eris-captp.scm"><code>eris-captp</code></a> script implements such a proxy to the <a href="https://www.ocapn.org/">OCapN</a> network. <a href="https://codeberg.org/eris/kapla/">Kapla</a> is a service that can use such proxies.</p><h2>Security Considerations</h2><p>In order to prevent passive adversaries from observing block access patterns (see <a href="http://purl.org/eris#name-observing-block-access">relevant section in ERIS specification</a>) adequate transport layer encryption should be used (or the protocol should be used over distances that can be physically secured).</p><p>This protocol does not recommend or define any specific transport layer encryption. Options include DTLS when using UDP (see <a href="https://www.rfc-editor.org/rfc/rfc7252#section-9.1">Section 9.1 of RFC 7252</a>), TLS (see <a href="https://www.rfc-editor.org/rfc/rfc8323#section-9">Section 9 of RFC 8323</a>), IPsec [<a href="https://datatracker.ietf.org/doc/html/rfc5406">RFC 5406</a>], <a href="https://torproject.org/">Tor</a> or <a href="https://yggdrasil-network.github.io/">Yggdrasil</a>).</p></article><footer><span><a href="https://codeberg.org/eris/eer/" title="Git repository from which this site is generated">Git</a></span><span><a href="https://creativecommons.org/licenses/by-sa/4.0/" title="Content licensed as CC-BY-SA-4.0">CC-BY-SA-4.0</a></span></footer></body></html>