RFC 7787

Distributed Node Consensus Protocol

๐Ÿ“… published April 2016, from ietf

RFC 7787: Distributed Node Consensus Protocol ๐ŸŽ€

Part 1 of 9 ๐Ÿ’–

Title block tea โ˜•

  • RFC number: 7787
  • Title: Distributed Node Consensus Protocol
  • Authors: M. Stenberg and S. Barth, both listed with affiliation Independent ๐ŸŒธ
  • Published by: Internet Engineering Task Force (IETF)
  • Category: Standards Track
  • ISSN: 2070-1721
  • Date: April 2016
  • Obsoletes / Updates: this header doesn't list either one ๐Ÿ™ˆ

Abstract โœจ

So this doc is all about DNCP, the Distributed Node Consensus Protocol ๐Ÿ’…. It's a generic state synchronization protocol, which basically means it keeps state in sync across a bunch of nodes, and it's built on the Trickle algorithm and hash trees ๐Ÿงš. Fair warning though: DNCP on its own is abstract, so it must be combined with a specific profile before you get a complete protocol you can actually implement ๐Ÿ”ฅ.


Status of This Memo ๐Ÿ“œ

This is an Internet Standards Track document ๐Ÿ’œ.

This document is a product of the Internet Engineering Task Force (IETF) ๐ŸŒˆ. It represents the consensus of the IETF community, it got public review, and the Internet Engineering Steering Group (IESG) approved it for publication ๐Ÿ‘‘. If you want more on Internet Standards, check out Section 2 of RFC 5741 ๐Ÿฆ‹.

Info about this doc's current status, any errata, and how to give feedback lives at http://www.rfc-editor.org/info/rfc7787 โœจ.

Copyright (c) 2016 IETF Trust and the persons identified as the document authors. All rights reserved ๐Ÿซถ.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they're in effect on the date this document was published ๐Ÿ“–. Please actually read these, because they spell out your rights and restrictions for this document ๐Ÿ™ˆ. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty as described in the Simplified BSD License ๐Ÿ’….

Table of Contents ๐ŸŒˆ

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
     1.1.  Applicability . . . . . . . . . . . . . . . . . . . . . .   4
   2.  Terminology . . . . . . . . . . . . . . . . . . . . . . . . .   6
     2.1.  Requirements Language . . . . . . . . . . . . . . . . . .   8
   3.  Overview  . . . . . . . . . . . . . . . . . . . . . . . . . .   8
   4.  Operation . . . . . . . . . . . . . . . . . . . . . . . . . .   9
     4.1.  Hash Tree . . . . . . . . . . . . . . . . . . . . . . . .   9
       4.1.1.  Calculating Network State and Node Data Hashes  . . .  10
       4.1.2.  Updating Network State and Node Data Hashes . . . . .  10
     4.2.  Data Transport  . . . . . . . . . . . . . . . . . . . . .  10
     4.3.  Trickle-Driven Status Updates . . . . . . . . . . . . . .  12
     4.4.  Processing of Received TLVs . . . . . . . . . . . . . . .  13
     4.5.  Discovering, Adding, and Removing Peers . . . . . . . . .  15
     4.6.  Data Liveliness Validation  . . . . . . . . . . . . . . .  16
   5.  Data Model  . . . . . . . . . . . . . . . . . . . . . . . . .  17
   6.  Optional Extensions . . . . . . . . . . . . . . . . . . . . .  19
     6.1.  Keep-Alives . . . . . . . . . . . . . . . . . . . . . . .  19
       6.1.1.  Data Model Additions  . . . . . . . . . . . . . . . .  20
       6.1.2.  Per-Endpoint Periodic Keep-Alives . . . . . . . . . .  20
       6.1.3.  Per-Peer Periodic Keep-Alives . . . . . . . . . . . .  20
       6.1.4.  Received TLV Processing Additions . . . . . . . . . .  21
       6.1.5.  Peer Removal  . . . . . . . . . . . . . . . . . . . .  21
     6.2.  Support for Dense Multicast-Enabled Links . . . . . . . .  21
   7.  Type-Length-Value Objects . . . . . . . . . . . . . . . . . .  22
     7.1.  Request TLVs  . . . . . . . . . . . . . . . . . . . . . .  23
       7.1.1.  Request Network State TLV . . . . . . . . . . . . . .  23
       7.1.2.  Request Node State TLV  . . . . . . . . . . . . . . .  24
     7.2.  Data TLVs . . . . . . . . . . . . . . . . . . . . . . . .  24
       7.2.1.  Node Endpoint TLV . . . . . . . . . . . . . . . . . .  24
       7.2.2.  Network State TLV . . . . . . . . . . . . . . . . . .  25
       7.2.3.  Node State TLV  . . . . . . . . . . . . . . . . . . .  25
     7.3.  Data TLVs within Node State TLV . . . . . . . . . . . . .  26
       7.3.1.  Peer TLV  . . . . . . . . . . . . . . . . . . . . . .  26
       7.3.2.  Keep-Alive Interval TLV . . . . . . . . . . . . . . .  27
   8.  Security and Trust Management . . . . . . . . . . . . . . . .  27
     8.1.  Trust Method Based on Pre-Shared Key  . . . . . . . . . .  27
     8.2.  PKI-Based Trust Method  . . . . . . . . . . . . . . . . .  28
     8.3.  Certificate-Based Trust Consensus Method  . . . . . . . .  28
       8.3.1.  Trust Verdicts  . . . . . . . . . . . . . . . . . . .  28
       8.3.2.  Trust Cache . . . . . . . . . . . . . . . . . . . . .  29
       8.3.3.  Announcement of Verdicts  . . . . . . . . . . . . . .  30
       8.3.4.  Bootstrap Ceremonies  . . . . . . . . . . . . . . . .  31
   9.  DNCP Profile-Specific Definitions . . . . . . . . . . . . . .  32
   10. Security Considerations . . . . . . . . . . . . . . . . . . .  34
   11. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  35
   12. References  . . . . . . . . . . . . . . . . . . . . . . . . .  36
     12.1.  Normative References . . . . . . . . . . . . . . . . . .  36
     12.2.  Informative References . . . . . . . . . . . . . . . . .  36
   Appendix A.  Alternative Modes of Operation . . . . . . . . . . .  38
     A.1.  Read-Only Operation . . . . . . . . . . . . . . . . . . .  38
     A.2.  Forwarding Operation  . . . . . . . . . . . . . . . . . .  38
   Appendix B.  DNCP Profile Additional Guidance . . . . . . . . . .  38
     B.1.  Unicast Transport -- UDP or TCP?  . . . . . . . . . . . .  38
     B.2.  (Optional) Multicast Transport  . . . . . . . . . . . . .  39
     B.3.  (Optional) Transport Security . . . . . . . . . . . . . .  39
   Appendix C.  Example Profile  . . . . . . . . . . . . . . . . . .  40
   Acknowledgements  . . . . . . . . . . . . . . . . . . . . . . . .  41
   Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  41

1. Introduction โœจ

DNCP is designed so every participating node can publish a small set of TLV (Type-Length-Value) tuples, at most 64 KB ๐Ÿ“, and everyone gets a shared, common view of the data published by every DNCP node that's currently bidirectionally reachable in the network ๐Ÿ’œ.

For state synchronization, there's a hash tree ๐ŸŒณ. First, a hash is calculated for the data set each node publishes, which is called node data. Then another hash gets calculated over those node data hashes ๐Ÿงš. The single resulting hash is the network state hash, and it's sent around using the Trickle algorithm [RFC6206] so every node agrees on the current state of the published data in the network ๐Ÿฆ‹. Here's the lowkey genius part: Trickle only sends these short network state hashes, and it sends them infrequently (in steady state, once the maximum Trickle interval per link or unicast connection has been reached). That makes DNCP super thrifty when updates happen rarely ๐Ÿ’…โœจ.

For keeping the topology and the data inside it alive, you get a combo of Trickled network state, keep-alives, and "other" ways of making sure reachability holds ๐Ÿซถ. The core idea is that if every node makes sure its peers are present, transitively, the whole network state stays up to date too ๐Ÿ‘‘.

1.1. Applicability ๐Ÿฆ‹

okay so DNCP is seriously useful for stuff like autonomous bootstrapping, discovery, and negotiation of embedded network devices like routers ๐Ÿค–. It can also be the base for running distributed algorithms like [RFC7596] or the use cases in Appendix C ๐Ÿ’…. DNCP is super abstract, so you can tune it for loads of different apps by defining profiles ๐ŸŽ€. A profile is where you pick:

  • unicast transport: a datagram or stream-oriented protocol (e.g., TCP, UDP, or the Stream Control Transmission Protocol (SCTP)) for generic protocol operation.
  • optional transport security: whether and when to use security based on Transport Layer Security (TLS) or Datagram Transport Layer Security (DTLS), if supported over the chosen transport.
  • optional multicast transport: a multicast-capable protocol like UDP that allows autonomous peer discovery or more efficient use of multiple access links.
  • communication scopes: either hop by hop only, relying on link-local addressing (e.g., for LANs), addresses with broader scopes (e.g., over WANs or the Internet) relying on an existing routing infrastructure, or a combination of both (e.g., to exchange state between multiple LANs over a WAN or the Internet).
  • payloads: additional specific payloads (e.g., IANA standardized, enterprise-specific, or private use).
  • extensions: possible protocol extensions, either predefined in this document or specific to a particular use case.

ngl, there are some situations where the protocol as defined here is kinda the wrong pick ๐Ÿ™ˆ. This list is the quick overview, and the paragraphs after it go deeper on each one.

  • large amounts of data: nodes are limited to 64 KB of published data.
  • very dense unicast-only networks: nodes include information about all immediate neighbors as part of their published data.
  • predominantly minimal data changes: node data is always transported as is, which leads to a relatively large transmission overhead for changes affecting only a small part of it.
  • frequently changing data: DNCP with its use of Trickle is optimized for the steady state and less efficient otherwise.
  • large amounts of very constrained nodes: DNCP requires each node to store the entirety of the data published by all nodes.

The topology of the devices isn't limited, and it's automatically discovered โœจ. When you rely on link-local communication exclusively, all links with DNCP nodes need to be at least transitively connected by routers running the protocol on multiple endpoints, so they form one connected network ๐Ÿ”—. That said, there's no requirement for every device in a physical network to run the protocol. Especially if globally scoped addresses are used, DNCP peers don't need to be on the same or even neighboring physical links ๐ŸŒ. Autonomous discovery features are usually used in local network scenarios, but with security enabled, DNCP can also be used over unsecured public networks ๐Ÿ”. Network size is restricted merely by the capabilities of the devices, meaning each DNCP node needs to be able to store the entirety of the data published by all nodes ๐Ÿ’พ. The data associated with each individual node identifier is limited to about 64 KB in this document. However, protocol extensions could be defined to mitigate this or other protocol limitations if the need arises ๐Ÿงฉ.

DNCP is most suitable for data that changes only infrequently, so you get the maximum benefit from using Trickle ๐ŸŒธ. As the network of nodes grows, or the frequency of data changes per node increases, Trickle is eventually used less and less, and the benefit of using DNCP shrinks. In these cases, Trickle just adds extra complexity to the specification with very little added value ๐Ÿ˜ญ.

You can roughly evaluate how suitable DNCP is for an application by looking at the expected average network-wide state change interval A_NC_I. You compute it by dividing the mean interval at which a node originates a new TLV set by the number of participating nodes ๐Ÿงฎ. If keep-alives are used, A_NC_I is the minimum of the computed A_NC_I and the keep-alive interval. If A_NC_I is less than the (application-specific) Trickle minimum interval, DNCP is most likely unsuitable for the application, because Trickle won't be utilized most of the time ๐Ÿ™…โ€โ™€๏ธ.

If constant rapid state changes are needed, the better choice is an additional point-to-point channel whose address or locator is published using DNCP ๐Ÿฆ‹. Still, if doing that doesn't raise A_NC_I above the (sensibly chosen) Trickle interval parameters for a particular application, using DNCP is probably not suitable for that application.

Another thing to think about is the size of the TLV set a node publishes compared to the size of the deltas in that TLV set ๐Ÿ“. If the TLV set published by a node is very large and has frequent small changes, DNCP as currently specified may be unsuitable, because it lacks a delta synchronization scheme. That's how it keeps the implementation simple ๐Ÿงธ.

DNCP can be used in networks where only unicast transport is available ๐Ÿ“ก. DNCP uses the least amount of bandwidth when multicast is utilized, but even in pure unicast mode, using Trickle (ideally with k < 2) gives you a protocol with an exponential backoff timer and fewer transmissions than a simpler protocol that doesn't use Trickle ๐ŸŽ‰.


2. Terminology ๐Ÿ“–

here's the glossary, bestie, so we're all speaking the same language ๐Ÿ’œ

DNCP profile      the values for the set of parameters given in
                  Section 9.  They are prefixed with DNCP_ in this
                  document.  The profile also specifies the set of
                  optional DNCP extensions to be used.  For a simple
                  example DNCP profile, see Appendix C.

DNCP-based        a protocol that provides a DNCP profile, according
protocol          to Section 9, and zero or more TLV assignments from
                  the per-DNCP profile TLV registry as well as their
                  processing rules.

DNCP node         a single node that runs a DNCP-based protocol.

Link              a link-layer media over which directly connected
                  nodes can communicate.

DNCP network      a set of DNCP nodes running a DNCP-based
                  protocol(s) with a matching DNCP profile(s).  The
                  set consists of nodes that have discovered each
                  other using the transport method defined in the
                  DNCP profile, via multicast on local links, and/or
                  by using unicast communication.

Node identifier   an opaque fixed-length identifier consisting of
                  DNCP_NODE_IDENTIFIER_LENGTH bytes that uniquely
                  identifies a DNCP node within a DNCP network.

Interface         a node's attachment to a particular link.

Address           an identifier used as the source or destination of
                  a DNCP message flow, e.g., a tuple (IPv6 address,
                  UDP port) for an IPv6 UDP transport.

Endpoint          a locally configured termination point for
                  (potential or established) DNCP message flows.  An
                  endpoint is the source and destination for separate
                  unicast message flows to individual nodes and
                  optionally for multicast messages to all thereby
                  reachable nodes (e.g., for node discovery).
                  Endpoints are usually in one of the transport modes
                  specified in Section 4.2.

Endpoint          a 32-bit opaque and locally unique value, which
identifier        identifies a particular endpoint of a particular
                  DNCP node.  The value 0 is reserved for DNCP and
                  DNCP-based protocol purposes and not used to
                  identify an actual endpoint.  This definition is in
                  sync with the interface index definition in
                  [RFC3493], as the non-zero small positive integers
                  should comfortably fit within 32 bits.

Peer              another DNCP node with which a DNCP node
                  communicates using at least one particular local
                  and remote endpoint pair.

Node data         a set of TLVs published and owned by a node in the
                  DNCP network.  Other nodes pass it along as is,
                  even if they cannot fully interpret it.

Origination time  the (estimated) time when the node data set with
                  the current sequence number was published.

Node state        a set of metadata attributes for node data.  It
                  includes a sequence number for versioning, a hash
                  value for comparing equality of stored node data,
                  and a timestamp indicating the time passed since
                  its last publication (i.e., since the origination
                  time).  The hash function and the length of the
                  hash value are defined in the DNCP profile.

Network state    a hash value that represents the current state of
hash              the network.  The hash function and the length of
                  the hash value are defined in the DNCP profile.
                  Whenever a node is added, removed, or updates its
                  published node data, this hash value changes as
                  well.  For calculation, please see Section 4.1.

Trust verdict     a statement about the trustworthiness of a
                  certificate announced by a node participating in
                  the certificate-based trust consensus mechanism.

Effective trust   the trust verdict with the highest priority within
verdict           the set of trust verdicts announced for the
                  certificate in the DNCP network.

Topology graph    the undirected graph of DNCP nodes produced by
                  retaining only bidirectional peer relationships
                  between nodes.

Bidirectionally   a peer is locally unidirectionally reachable if a
reachable         consistent multicast or any unicast DNCP message
                  has been received by the local node (see Section
                  4.5).  If said peer in return also considers the
                  local node unidirectionally reachable, then
                  bidirectionally reachability is established.  As
                  this process is based on publishing peer
                  relationships and evaluating the resulting topology
                  graph as described in Section 4.6, this information
                  is available to the whole DNCP network.

Trickle instance  a distinct Trickle [RFC6206] algorithm state kept
                  by a node (Section 5) and related to an endpoint or
                  a particular (peer, endpoint) tuple with Trickle
                  variables I, t, and c.  See Section 4.3.

2.1. Requirements Language ๐Ÿซถ

so, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be read as described in RFC 2119 [RFC2119] ๐Ÿ“œโœจ

3. Overview โœจ

okay bestie, so DNCP mostly chats one-on-one with each node over unicast ๐Ÿ’Œ but it can also shout to everyone with multicast ๐Ÿ“ข for Trickle-based shared state updates and topology discovery. If you're running pure unicast over an unreliable transport, Trickle also runs between peers ๐Ÿ”

DNCP talks in TLVs (Section 7) ๐Ÿ’ฌ and defines a set of mandatory and optional ones it needs to work. They sort into three groups: ones for asking for info (Section 7.1), ones for sending data (Section 7.2), and ones that get published as data (Section 7.3). DNCP-based protocols usually add their own TLVs on top to level up their features ๐ŸŽ€

DNCP maps out the topology of the network ๐Ÿ—บ๏ธ and keeps published node data feeling alive by making sure the publishing node can be reached both ways ๐Ÿซถ New potential peers can be found on their own on multicast-enabled links ๐Ÿฆ‹ Their addresses can be configured by hand, or found some other way that the DNCP profile defines. The profile might name a well-known anycast address, or hand over the remote address to contact through another protocol, like DHCPv6 [RFC3315] ๐Ÿ’…

Every node keeps a hash tree of height 1 that's rooted in itself ๐ŸŒณ It represents the state of every node it can currently reach (see Section 4.1), and Trickle is what kicks off synchronization (see Section 4.3). So whether peers need to check for state changes just comes down to comparing their roots, aka their own calculated network state hashes ๐Ÿ”

Before a node joins a DNCP network, it starts with a hash tree that has one leaf if it publishes any TLVs, and zero leaves if it doesn't ๐ŸŒฑ Then it announces its network state hash, calculated from that tree, via Trickle on every endpoint it's configured with ๐Ÿ“ฃ

When a node notices an update (like getting a different network state hash from a peer ๐Ÿ‘€), the one who started the event gets asked for a list of the state of every node, which is all the info needed to work out its own hash tree ๐Ÿ“‹ The node checks that list to see if its own info is out of date. If it is, it asks for the actual node data that changed ๐Ÿ’–

Anytime a node's local copy of node data and its hash tree get updated (because its own node state changed, another node's did, or a peer got added or removed) ๐Ÿ”„, its Trickle instances get reset. That eventually pushes the update out to all of its peers ๐Ÿš€


4. Operation

4.1. Hash Tree

Every DNCP node keeps an arbitrary-width hash tree of height 1 ๐ŸŒฒ The root is the overall network state hash, and it's how nodes (two or more of them) check that they all see the same network ๐Ÿ‘ฏ Each leaf stands for one bidirectionally reachable DNCP node. Whenever a node gets added to or removed from the topology graph (Section 4.6), it gets added or removed as a leaf too ๐Ÿ“ At any moment, the leaves are lined up in ascending order of the node identifiers they represent ๐Ÿ“

4.1.1. Calculating Network State and Node Data Hashes

The network state hash and the node data hashes both get calculated with the hash function from the DNCP profile (Section 9), truncated to however many bits the profile says ๐Ÿ”

Each node data hash comes from running that function and truncation on that node's node data, exactly as it's published in the Node State TLV ๐Ÿง Those node data sets are always kept in the order defined in Section 7.2.3 ๐Ÿ“š

The network state hash is the function and truncation run on the concatenated network state ๐Ÿ’ซ To build that, each node's sequence number (in network byte order) gets glued onto its node data hash, making one per-node datum for every node ๐Ÿงฉ Then all those per-node data get concatenated in ascending order of node identifier, which is the same order the nodes sit in the hash tree ๐ŸŒธ

4.1.2. Updating Network State and Node Data Hashes

The network state hash and node data hashes get updated on demand, and any time locally stored per-node state changes ๐Ÿ”ง That includes local unidirectional reachability as encoded in the published Peer TLVs (Section 7.3.1). Combined with remote data, it also gives a node awareness of bidirectional reachability changes ๐Ÿ‘€โœจ

4.2. Data Transport

DNCP doesn't ask much from the underlying transport ๐Ÿฅฐ It just needs some way to send either unicast datagrams or stream data to a peer, plus a way to send multicast datagrams if multicast mode is in use. Multicast only exists to spot potential new DNCP nodes and to send status messages that simply say "hey, go start a unicast exchange" ๐Ÿ“ฃ So the multicast transport doesn't have to be secured ๐Ÿ™Œ If you want unicast security and one of the built-in security methods, you need some TLS-derived transport too, like TLS [RFC5246] on top of TCP or DTLS [RFC6347] on top of UDP ๐Ÿ”’ Those give you integrity protection and confidentiality for node data, plus authentication and authorization using the schemes in "Security and Trust Management" (Section 8) ๐Ÿ›ก๏ธ The DNCP profile MUST provide a specific definition of the transport(s) in use and their parameters ๐Ÿ“

TLVs (Section 7) get sent over the transport exactly as they are ๐Ÿ“ฆ They SHOULD go out together, unless things like MTU considerations mean they have to be split into several batches ๐Ÿ“ฎ DNCP doesn't fragment or reassemble TLVs, so the underlying transport MUST be ensured to handle those jobs if they're needed ๐Ÿงต When this document says to send one or more TLVs, the sender doesn't have to keep track of packets once they've been handed to the transport ๐Ÿ™…โ€โ™€๏ธ Reliability comes entirely from the explicitly defined timers and state machines, like Trickle (Section 4.3) โฐ TLVs are handled one at a time and statelessly, so they don't have to arrive in any particular order ๐Ÿ’ƒ There's one exception ๐Ÿšจ To form bidirectional peer relationships, DNCP needs to know the endpoints used for communication. Since bidirectional peer relationships are needed to validate liveliness of published node data (Section 4.6), a DNCP node MUST send a Node Endpoint TLV (Section 7.2.1) ๐Ÿซถ When it gets sent depends on the transport, but conceptually it should be available whenever a Network State TLV is being processed ๐ŸŽฏ

  • If you're using a stream transport, the TLV MUST be sent at least once per connection, but SHOULD NOT be sent more than once ๐ŸŒŠ
  • If you're using a datagram transport, it MUST be included in every datagram that also contains a Network State TLV (Section 7.2.2), and it MUST be located before any such TLV ๐Ÿ“จ It SHOULD also be included in any other datagram to speed up initial peer detection ๐Ÿƒโ€โ™€๏ธ

With all the different transport options and possible endpoint configurations, a DNCP endpoint can be used in a few transport modes ๐ŸŽ€

Unicast:

  • If only reliable unicast transport is used, Trickle isn't used at all ๐Ÿ™…โ€โ™€๏ธ Whenever the locally calculated network state hash changes, one Network State TLV (Section 7.2.2) gets sent to every unicast peer ๐Ÿ’Œ Recently changed Node State TLVs (Section 7.2.3) MAY be included too ๐Ÿ’…
  • If only unreliable unicast transport is used, Trickle state is kept per peer, and it's used to send Network State TLVs now and then, as specified in Section 4.3 โณ

Multicast+Unicast: If multicast datagram transport is available on an endpoint, Trickle state is only kept for the endpoint as a whole ๐ŸŒ It's used to send Network State TLVs periodically, as specified in Section 4.3 ๐Ÿ” On top of that, per-endpoint keep-alives MAY be defined in the DNCP profile, as specified in Section 6.1.2 ๐Ÿ’œ

MulticastListen+Unicast: This is basically just like unicast, except multicast transmissions get listened to so the node can notice changes to the highest node identifier ๐Ÿ‘‚ This mode is only used if the DNCP profile supports dense multicast-enabled link optimization (Section 6.2) โœจ

4.3. Trickle-Driven Status Updates

The Trickle algorithm [RFC6206] keeps protocol reliability intact over unreliable multicast or unicast transports ๐Ÿฆ‹ For reliable unicast transports, the actual algorithm isn't needed, so it's skipped (Section 4.2) ๐Ÿ™ˆ DNCP keeps multiple Trickle states, as defined in Section 5 ๐Ÿงฉ Each one can run on different parameters (more on that below) and has one job: make sure a specific peer, or all peers on that endpoint, keep getting the node's current locally calculated network state hash so they can compare notes and catch any divergence in what they think the network looks like ๐Ÿ‘€๐Ÿ’–

Trickle has 3 parameters: Imin, Imax, and k ๐ŸŽ€ Imin and Imax are the minimum value for I and the maximum number of doublings of Imin, where I is the time interval during which at least k Trickle updates have to be seen on an endpoint to stop local state from being sent ๐Ÿ™Š The actual suggested Trickle parameters are specific to the DNCP profile, as described in Section 9 ๐Ÿ“‹

All Trickle instances from Section 5 are treated as inconsistent and reset if, and only if, the locally calculated network state hash changes โœจ That happens either because the local node's own node data changed, or because it got newer data from another node (Section 4.1) ๐Ÿ”„ A node MUST NOT reset its Trickle state just because it received a Network State TLV (Section 7.2.2) with a network state hash that's different from its own calculated one ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’…

Every time a particular Trickle instance says an update should go out, the node MUST send a Network State TLV (Section 7.2.2) if and only if one of these is true ๐Ÿ“ฃ

  • The endpoint is in Multicast+Unicast transport mode, and then the TLV MUST be sent over multicast ๐Ÿ“ข
  • The endpoint is NOT in Multicast+Unicast transport mode, and the unicast transport is unreliable, and then the TLV MUST be sent over unicast ๐Ÿ’Œ

A (sub)set of all Node State TLVs (Section 7.2.3) MAY also be included ๐ŸŒธ That's unless the DNCP profile says it's undesirable for some reason, or unless sending them over insecure multicast would expose node state TLVs when unicast is secure ๐Ÿ” Don't let those node state TLVs leak, bestie! ๐Ÿ˜ญ๐Ÿซถ

4.4. Processing of Received TLVs โœจ

Okay bestie, this section is where we figure out what a node does with each TLV it receives ๐Ÿ’…. The DNCP profile can say when to ignore certain TLVs, like if they'd mess with security stuff ๐Ÿ”. Check Section 9 for what can safely be ignored in a profile ๐ŸŽ€. Any "reply" mentioned below just means sending the TLV(s) back to whoever sent the TLV we're handling ๐Ÿ’Œ. All replies MUST be sent using unicast ๐Ÿฆ‹. If the TLV we're replying to came in over multicast and was sent to a multiple access link, the reply MUST be delayed by a random time in [0, Imin/2] ๐Ÿซถ. This keeps everyone from replying at the exact same moment and causing chaos on some links ๐Ÿ˜ญ, unless the DNCP profile says otherwise ๐ŸŒธ. An implementation MAY also rate limit replies or skip them for a little while โœจ. BUT, if the profile doesn't forbid the TLV, an implementation MUST still reply to retransmissions with a non-zero probability, or else it could starve and break state synchronization ๐Ÿ’€.

A DNCP node MUST process TLVs from any valid (correctly scoped, you know the vibe) address, as the DNCP profile and endpoint configuration say ๐ŸŒˆ. This is true whether or not the address belongs to a known peer ๐Ÿงš. It's super useful for monitoring or other host software that wants to map the DNCP topology without adding anything to the network state ๐Ÿ‘‘.

Upon receipt of:

  • Request Network State TLV (Section 7.1.1): The receiver MUST reply with a Network State TLV (Section 7.2.2) and a Node State TLV (Section 7.2.3) for each node data used to calculate the network state hash ๐Ÿ“. The Node State TLVs SHOULD NOT contain the optional node data part to avoid redundant transmission of node data, unless the DNCP profile explicitly specifies otherwise ๐Ÿ’œ.
  • Request Node State TLV (Section 7.1.2): If the receiver has node data for the corresponding node, it MUST reply with a Node State TLV (Section 7.2.3) for that node. The optional node data part MUST be included in the TLV ๐Ÿ”ฅ.
  • Network State TLV (Section 7.2.2): If the network state hash differs from the locally calculated one, and the receiver doesn't know about any particular node state differences with the sender, the receiver MUST reply with a Request Network State TLV (Section 7.1.1) ๐Ÿ™ˆ. These replies MUST be rate limited to at most one reply per link per unique network state hash within Imin โญ. The simplest way to do this is to keep a timestamp of requests and only send at most one Request Network State TLV (Section 7.1.1) per Imin โฐ. To speed up state synchronization, if a Request Network State TLV is sent in a reply, a local, current Network State TLV MAY also be sent ๐Ÿš€.
  • Node State TLV (Section 7.2.3):
    • If the node identifier matches the local node identifier and the TLV has a greater sequence number than the current local value, or the same sequence number with a different hash, the node SHOULD republish its own node data with a sequence number significantly greater than the received one (e.g., 1000) to reclaim the node identifier ๐Ÿ‘‘. This gap is needed so it's higher than any lingering copies of the node state floating around the network ๐Ÿซง. This can happen normally once because the local node restarted and didn't store its most recently used sequence number ๐Ÿ”„. If it happens more than once, or for nodes that aren't republishing their own node data, the DNCP profile MUST provide guidance on handling it, since it means another active node has the same node identifier ๐Ÿšจ.
    • If the node identifier does NOT match the local node identifier, and one or more of these are true:
      • The local information is outdated for the corresponding node (the local sequence number is less than the one in the TLV) ๐Ÿ•ฐ๏ธ.
      • The local information is potentially incorrect (the local sequence number matches but the node data hash differs) ๐Ÿค”.
      • There is no data for that node at all ๐Ÿซฅ.

Then:

  • If the TLV contains the Node Data field, it SHOULD also be verified by checking that the locally calculated hash of the node data matches the content of the H(Node Data) field in the TLV ๐Ÿ”. If they differ, the TLV SHOULD be ignored and not processed further ๐Ÿ™…โ€โ™€๏ธ.
  • If the TLV does NOT contain the Node Data field, and the H(Node Data) field differs from the local node data hash for that node (or there is none), the receiver MUST reply with a Request Node State TLV (Section 7.1.2) for that node ๐Ÿ™.
  • Otherwise, the receiver MUST update its locally stored state for that node (node data based on the Node Data field if present, sequence number, and relative time) to match the received TLV ๐Ÿ’–.

For comparison purposes of the sequence number, a looping comparison function MUST be used to avoid problems on overflow ๐Ÿ”. The comparison function a < b <=> ((a - b) % (2^32)) & (2^31) != 0, where (a % b) is the remainder of a modulo b and (a & b) is the bitwise conjunction of a and b, is RECOMMENDED unless the DNCP profile defines another one ๐Ÿงฎ.

  • Any other TLV: TLVs the receiver doesn't recognize MUST be silently ignored, unless they're sent inside another TLV (like TLVs within the Node Data field of a Node State TLV) ๐Ÿซ . Unrecognized TLVs inside the Node Data field of a Node State TLV MUST be retained for distribution to other nodes and for calculating the node data hash as described in Section 7.2.3, but they're ignored for every other purpose ๐Ÿง โœจ.

If secure unicast transport is configured for an endpoint, any Node State TLVs received over insecure multicast MUST be silently ignored ๐Ÿ”’๐Ÿซถ.


4.5. Discovering, Adding, and Removing Peers ๐Ÿฆ‹

Okay so peer relations get set up between neighbors using one or more mutually connected endpoints ๐Ÿค. Neighbors swap info about network state and published data directly, and then through transitivity, that info spreads across the whole network ๐ŸŒโœจ. Lowkey iconic.

New peers are found using the regular unicast or multicast transport the DNCP profile defines (Section 9) ๐Ÿ’Œ. Finding a peer and adding a peer are the same thing here ๐Ÿ™Œ. An unknown peer just gets discovered by receiving regular DNCP protocol TLVs from it, and there are no dedicated discovery messages or TLVs at all ๐Ÿ™…โ€โ™€๏ธ. For unicast-only transports, each node's transport addresses are either preconfigured or obtained through an external service discovery protocol ๐Ÿ—บ๏ธ. When there's a multicast transport, messages from unknown peers are handled the same way as multicast messages from peers that are already known, so new peers are simply discovered when they send their regular DNCP protocol TLVs over multicast ๐Ÿ“ก.

When receiving a Node Endpoint TLV (Section 7.2.1) on an endpoint from an unknown peer:

  • If it's received over unicast, the remote node MUST be added as a peer on the endpoint, and a Peer TLV (Section 7.3.1) MUST be created for it ๐ŸŽ€.
  • If it's received over multicast, the node MAY be sent a (possibly rate-limited) unicast Request Network State TLV (Section 7.1.1) ๐Ÿ’ซ.

If keep-alives specified in Section 6.1 are NOT sent by the peer (either the DNCP profile doesn't specify keep-alives, or that particular peer chooses not to send them), some other existing local transport-specific means (such as Ethernet carrier detection or TCP keep-alive) MUST be used to make sure it's still there ๐Ÿ‘€. If the peer doesn't send keep-alives and there's no way to verify its presence, the peer MUST be considered no longer present, and it SHOULD NOT be added back as a peer until it starts sending keep-alives again ๐Ÿ˜ข. When the peer is gone, the Peer TLV and the local DNCP peer state MUST be removed ๐Ÿงน. DNCP doesn't define an explicit message or TLV for a node announcing it's terminating DNCP operation ๐Ÿšช; however, a derived protocol could specify an extension if the need ever comes up ๐Ÿ’œ.

If the local endpoint is in the Multicast-Listen+Unicast transport mode, a Peer TLV (Section 7.3.1) MUST NOT be published for peers that don't have the highest node identifier ๐Ÿ‘‘๐Ÿ™…โ€โ™€๏ธ.


4.6. Data Liveliness Validation ๐Ÿซง

Okay this one is giving main character energy ๐ŸŽฌ. Keeping the hash tree (Section 4.1) up to date, and therefore updating the network state hash, depends on having current info about bidirectional node reachability, which comes from a topology graph โœจ. That graph changes whenever nodes get added or removed, or when bidirectional connectivity between existing nodes is gained or lost ๐Ÿ”„. So the graph MUST be updated either immediately or after a small delay that is shorter than the DNCP profile-defined Trickle Imin, whenever:

  • A Peer TLV or a whole node is added or removed, or
  • The origination time (in milliseconds) of some node's node data is less than current time - 2^32 + 2^15 โณ.

That artificial upper limit on the origination time is there to gracefully avoid overflows of the origination time, and to let the node republish its data as noted in Section 7.2.3 ๐ŸŒธ.

The topology graph update starts with the local node marked as reachable and every other node marked as unreachable ๐Ÿ. Then other nodes get iteratively marked as reachable using this algorithm: a candidate not-yet-reachable node N with an endpoint NE is marked as reachable if there's a reachable node R with an endpoint RE that meets ALL of these criteria ๐Ÿง:

  • The origination time (in milliseconds) of R's node data is greater than current time - 2^32 + 2^15 โฐ.
  • R publishes a Peer TLV with:
    • Peer Node Identifier = N's node identifier
    • Peer Endpoint Identifier = NE's endpoint identifier
    • Endpoint Identifier = RE's endpoint identifier
  • N publishes a Peer TLV with:
    • Peer Node Identifier = R's node identifier
    • Peer Endpoint Identifier = RE's endpoint identifier
    • Endpoint Identifier = NE's endpoint identifier

The algorithm stops when no more candidate nodes meeting these criteria can be found ๐Ÿ›‘.

DNCP nodes that haven't been reachable in the most recent topology graph traversal MUST NOT be used for calculating the network state hash, MUST NOT be provided to any applications that need the whole TLV graph, and MUST NOT be provided to remote nodes ๐Ÿšซ. They MAY be forgotten right after the topology graph traversal; however, it is RECOMMENDED to keep them at least briefly to speed up DNCP network state convergence ๐Ÿš€. This cuts down on the number of queries needed to reconverge, both during initial network convergence and when part of the network loses and then regains bidirectional connectivity within that time period ๐Ÿซถโœจ.

  1. Data Model ๐Ÿ’…

Okay so this section is basically a little tour of the local data structures a minimal implementation might use ๐Ÿงš It's only a convenience for the implementor, bestie, not a hard rule ๐ŸŽ€ Some of the optional extensions (Section 6) describe extra data requirements, and some optional parts of the core protocol may also require more ๐Ÿ’œ

A DNCP node has:

  • A data structure containing data about the most recently sent Request Network State TLVs (Section 7.1.1). The simplest option is keeping a timestamp of the most recent request (required to fulfill reply rate limiting specified in Section 4.4) โœจ

A DNCP node has the following for every DNCP node in the DNCP network:

  • Node identifier: the unique identifier of the node. The length, how it is produced, and how collisions are handled is up to the DNCP profile ๐ŸŒธ
  • Node data: the set of TLV tuples published by that particular node. As they are transmitted in a particular order (see Node State TLV (Section 7.2.3) for details), maintaining the order within the data structure here may be reasonable ๐Ÿฆ‹
  • Latest sequence number: the 32-bit sequence number that is incremented any time the TLV set is published. The comparison function used to compare them is described in Section 4.4 ๐Ÿ”ฅ
  • Origination time: the (estimated) time when the current TLV set with the current sequence number was published. It is used to populate the Milliseconds Since Origination field in a Node State TLV (Section 7.2.3). Ideally, it also has millisecond accuracy ๐Ÿซถ

Additionally, a DNCP node has a set of endpoints for which DNCP is configured to be used. For each such endpoint, a node has:

  • Endpoint identifier: the 32-bit opaque locally unique value identifying the endpoint within a node. It SHOULD NOT be reused immediately after an endpoint is disabled ๐Ÿ“
  • Trickle instance: the endpoint's Trickle instance with parameters I, T, and c (only on an endpoint in Multicast+Unicast transport mode) ๐ŸŒˆ

and one (or more) of the following:

  • Interface: the assigned local network interface ๐Ÿ‘‘
  • Unicast address: the DNCP node it should connect with ๐Ÿ’–
  • Set of addresses: the DNCP nodes from which connections are accepted ๐Ÿ’œ

For each remote (peer, endpoint) pair detected on a local endpoint, a DNCP node has:

  • Node identifier: the unique identifier of the peer ๐ŸŒธ
  • Endpoint identifier: the unique endpoint identifier used by the peer ๐ŸŽ€
  • Peer address: the most recently used address of the peer (authenticated and authorized, if security is enabled) ๐Ÿ”โœจ
  • Trickle instance: the particular peer's Trickle instance with parameters I, T, and c (only on an endpoint in unicast mode, when using an unreliable unicast transport) ๐Ÿฆ‹

6. Optional Extensions ๐ŸŒŸ

Okay so this section is all about extensions to the core protocol that a DNCP profile may choose to use ๐Ÿ’… If the profile doesn't pick them, they just don't apply ๐Ÿงš

6.1. Keep-Alives ๐Ÿ’–

So DNCP already has ways to discover and add new peers on an endpoint (Section 4.5), plus state change notifications โœจ But sometimes you still need another way to clear out old peers that aren't valid anymore, especially if the transport or lower layers don't handle it, as noted in Section 4.6 ๐Ÿซถ

If keep-alives are not specified in the DNCP profile, the rest of this subsection MUST be ignored ๐Ÿ™ˆ

A DNCP profile MAY specify either per-endpoint keep-alive support (sent using multicast to all DNCP nodes connected to a multicast-enabled link) or per-peer keep-alive support (sent using unicast to each peer individually) ๐ŸŒˆ

For every endpoint that a keep-alive is specified for in the DNCP profile, the endpoint-specific keep-alive interval MUST be maintained ๐Ÿ’œ By default, it is DNCP_KEEPALIVE_INTERVAL ๐ŸŽ€ If there's a local value that is preferred for any reason (configuration, energy conservation, media type, ...), it can be substituted instead ๐ŸŒธ If a non-default keep-alive interval is used on any endpoint, a DNCP node MUST publish an appropriate Keep-Alive Interval TLV(s) (Section 7.3.2) within its node data ๐Ÿ‘‘

6.1.1. Data Model Additions ๐Ÿงš

These are the extra data model bits needed to support keep-alives ๐Ÿ’…

For each configured endpoint that has per-endpoint keep-alives enabled:

  • Last sent: If a timestamp that indicates the last time a Network State TLV (Section 7.2.2) was sent over that interface ๐Ÿฆ‹

For each remote (peer, endpoint) pair detected on a local endpoint, a DNCP node has:

  • Last contact timestamp: A timestamp that indicates the last time a consistent Network State TLV (Section 7.2.2) was received from the peer over multicast or when anything was received over unicast. Failing to update it for a certain amount of time as specified in Section 6.1.5 results in the removal of the peer. When adding a new peer, it is initialized to the current time โฐ๐Ÿ’–
  • Last sent: If per-peer keep-alives are enabled, a timestamp that indicates the last time a Network State TLV (Section 7.2.2) was sent to that point-to-point peer. When adding a new peer, it is initialized to the current time ๐ŸŒท

6.1.2. Per-Endpoint Periodic Keep-Alives ๐Ÿ”ฅ

If per-endpoint keep-alives are enabled on an endpoint in Multicast+Unicast transport mode, and if no traffic containing a Network State TLV (Section 7.2.2) has been sent to a particular endpoint within the endpoint-specific keep-alive interval, a Network State TLV (Section 7.2.2) MUST be sent on that endpoint, and a new Trickle interval started, as specified in step 2 of Section 4.2 of [RFC6206]. The actual sending time SHOULD be further delayed by a random time span in [0, Imin/2] ๐Ÿซถ

6.1.3. Per-Peer Periodic Keep-Alives ๐ŸŒธ

If per-peer keep-alives are enabled on a unicast-only endpoint, and if no traffic containing a Network State TLV (Section 7.2.2) has been sent to a particular peer within the endpoint-specific keep-alive interval, a Network State TLV (Section 7.2.2) MUST be sent to the peer, and a new Trickle interval started, as specified in step 2 of Section 4.2 of [RFC6206] ๐Ÿฆ‹

6.1.4. Received TLV Processing Additions ๐Ÿ’œ

If a TLV is received over unicast from the peer, the Last contact timestamp for the peer MUST be updated ๐ŸŽ€

On receipt of a Network State TLV (Section 7.2.2) that is consistent with the locally calculated network state hash, the Last contact timestamp for the peer MUST be updated in order to maintain it as a peer ๐Ÿ‘‘

6.1.5. Peer Removal ๐Ÿ’€

For every peer on every endpoint, the endpoint-specific keep-alive interval must be calculated by looking for Keep-Alive Interval TLVs (Section 7.3.2) published by the node, and if none exist, use the default value of DNCP_KEEPALIVE_INTERVAL ๐Ÿงš If the peer's Last contact timestamp has not been updated for at least a locally chosen potentially endpoint-specific keep-alive multiplier (defaults to DNCP_KEEPALIVE_MULTIPLIER) times the peer's endpoint-specific keep-alive interval, the Peer TLV for that peer and the local DNCP peer state MUST be removed ๐Ÿ˜ญ

This optimization is needed to avoid a state space explosion ๐Ÿ’€ Given a large set of DNCP nodes publishing data on an endpoint that uses multicast on a link, every node will add a Peer TLV (Section 7.3.1) for each peer ๐Ÿ™ˆ While Trickle limits the amount of traffic on the link in stable state to some extent, the total amount of data that is added to and maintained in the DNCP network given N nodes on a multicast-enabled link is O(N^2) ๐Ÿ˜ฑ Additionally, if per-peer keep-alives are used, there will be O(N^2) keep-alives running on the link if the liveliness of peers is not ensured using some other way (e.g., TCP connection lifetime, Layer 2 notification, or per-endpoint keep-alive) ๐Ÿ’…

An upper bound for the number of peers that are allowed for a particular type of link that an endpoint in Multicast+Unicast transport mode is used on SHOULD be provided by a DNCP profile, but it MAY also be chosen at runtime ๐ŸŽ€ The main consideration when selecting a bound (if any) for a particular type of link should be whether it supports multicast traffic and whether a too large number of peers case is likely to happen during the use of that DNCP profile on that particular type of link ๐Ÿซถ If neither is likely, there is little point specifying support for this for that particular link type ๐Ÿคทโ€โ™€๏ธ

If a DNCP profile does not support this extension at all, the rest of this subsection MUST be ignored ๐Ÿ™ˆ This is because when this extension is used, the state within the DNCP network only contains a subset of the full topology of the network ๐Ÿง  Therefore, every node must be aware of the potential of it being used in a particular DNCP profile ๐Ÿ’–

If the specified upper bound is exceeded for some endpoint in Multicast+Unicast transport mode and if the node does not have the highest node identifier on the link, it SHOULD treat the endpoint as a unicast endpoint connected to the node that has the highest node identifier detected on the link, therefore transitioning to Multicast-listen+Unicast transport mode ๐Ÿฆ‹ See Section 4.2 for implications on the specific endpoint behavior ๐ŸŒธ The nodes in Multicast-listen+Unicast transport mode MUST keep listening to multicast traffic to both receive messages from the node(s) still in Multicast+Unicast mode and react to nodes with a greater node identifier appearing ๐Ÿ‘€ If the highest node identifier present on the link changes, the remote unicast address of the endpoints in Multicast-Listen+Unicast transport mode MUST be changed ๐ŸŒˆ If the node identifier of the local node is the highest one, the node MUST switch back to, or stay in, Multicast+Unicast mode and form peer relationships with all peers as specified in Section 4.5 ๐Ÿ‘‘

7. Type-Length-Value Objects โœจ

okay so TLVs are literally the building blocks of everything here ๐Ÿงฑ every piece of info is wrapped in a little Type + Length + Value box, and it's giving tidy ๐ŸŽ€

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |            Type               |           Length              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |               Value (if any) (+padding (if any))              |
   ..
   |                     (variable # of bytes)                     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                     (optional nested TLVs)                    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Each TLV is encoded as:

  • a 2-byte Type field
  • a 2-byte Length field, which holds the length of the Value field in bytes; 0 means no value ๐ŸŒธ
  • the value itself (if any)
  • padding bytes with a value of zero up to the next 4-byte boundary if the Length is not divisible by 4

Okay, the padding bit is lowkey important ๐Ÿ’… While padding bytes MUST NOT be included in the number stored in the Length field of the TLV, if the TLV is enclosed within another TLV, then the padding is included in the enclosing TLV's Length value. So the outer box counts the padding, but the inner one doesn't. Not me getting confused by this ๐Ÿ™ˆ

Each TLV that does not define optional fields or variable-length content MAY be sent with additional sub-TLVs appended after the TLV, so it can grow over time ๐Ÿฆ‹ When handling such TLV types, each node MUST accept received TLVs that are longer than the fixed fields specified for the particular type, and ignore the sub-TLVs with either unknown types or types not supported within that particular TLV. If any sub-TLVs are present, the Length field of the TLV describes the number of bytes from the first byte of the TLV's own Value (if any) to the last (padding) byte of the last sub-TLV.

Here's a cute example ๐Ÿง a type=123 (0x7b) TLV with value 'x' (120 = 0x78) is encoded as 007B 0001 7800 0000. If it also had a sub-TLV of type=124 (0x7c) with value 'y', it would be encoded as 007B 000C 7800 0000 007C 0001 7900 0000. Iconic, right? ๐Ÿ‘‘

In this section, the following special notation is used:

  • .. = octet string concatenation operation.
  • H(x) = non-cryptographic hash function specified by the DNCP profile.

In addition to the TLV types defined in this document, TLV Types 11-31 and 512-767 are unassigned and may be sequentially registered, starting at 11, by Standards Action [RFC5226] by extensions to DNCP that may be applicable in multiple DNCP profiles. ๐ŸŒˆ

7.1. Request TLVs

7.1.1. Request Network State TLV

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Type: Request network state (1)|          Length: >= 0         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

This TLV is used to ask for a response with a Network State TLV (Section 7.2.2) and all Node State TLVs (Section 7.2.3) (without node data). Basically "send me the overview, bestie" ๐Ÿ“ฌ

7.1.2. Request Node State TLV

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | Type: Request node state (2)  |          Length: > 0          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Node Identifier                        |
   |                  (length fixed in DNCP profile)               |
   ...
   |                                                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

This TLV is used to request a Node State TLV (Section 7.2.3) (including node data) for the node with the matching node identifier. The full tea, not the summary โ˜•

7.2. Data TLVs

7.2.1. Node Endpoint TLV

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |   Type: Node endpoint (3)     |          Length: > 4          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Node Identifier                        |
   |                  (length fixed in DNCP profile)               |
   ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                      Endpoint Identifier                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

This TLV identifies both the local node's node identifier and the particular endpoint's endpoint identifier, so it's a whole two-part vibe ๐Ÿซถ Section 4.2 specifies when it is sent.

7.2.2. Network State TLV

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |    Type: Network state (4)    |          Length: > 0          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |     H(sequence number of node 1 .. H(node data of node 1) ..  |
   |    .. sequence number of node N .. H(node data of node N))    |
   |                  (length fixed in DNCP profile)               |
   ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

This TLV contains the current network state hash calculated by its sender, like a vibe check for the whole network โœจ (Section 4.1 describes the algorithm).

7.2.3. Node State TLV

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |      Type: Node state (5)     |          Length: > 8          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Node Identifier                        |
   |                  (length fixed in DNCP profile)               |
   ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Sequence Number                         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                Milliseconds Since Origination                 |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         H(Node Data)                          |
   |                  (length fixed in DNCP profile)               |
   ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |       (optionally) Node Data (a set of nested TLVs)           |
   ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

This TLV represents the local node's knowledge about the published state of a node in the DNCP network, identified by the Node Identifier field in the TLV. It's the full gossip, spilled โ˜•

Every node, including the node publishing the node data, MUST update the Milliseconds Since Origination whenever it sends a Node State TLV, based on when the node estimates the data was originally published. This is, e.g., to ensure that any relative timestamps contained within the published node data can be correctly offset and interpreted. Ultimately, what is provided is just an approximation, as transmission delays are not accounted for. โฑ๏ธ

Absent any changes, if the originating node notices that the 32-bit Milliseconds Since Origination value would be close to overflow (greater than 2^32 - 2^16), the node MUST republish its TLVs even if there is no change. In other words, absent any other changes, the TLV set MUST be republished roughly every 48 days. the clock is ticking, bestie ๐Ÿ•ฐ๏ธ

The actual node data of the node may be included within the TLV as well as in the optional Node Data field. The set of TLVs MUST be strictly ordered based on ascending binary content (including TLV type and length). This enables, e.g., efficient state delta processing and no-copy indexing by TLV type by the recipient, which is so organised ๐Ÿ“š The node data content MUST be passed along exactly as it was received. It SHOULD be also verified on receipt that the locally calculated H(Node Data) matches the content of the field within the TLV, and if the hash differs, the TLV SHOULD be ignored. ๐Ÿ”

7.3. Data TLVs within Node State TLV

These TLVs are published by the DNCP nodes and are therefore only encoded in the Node Data field of Node State TLVs. If encountered outside Node State TLV, they MUST be silently ignored. Not invited to the party, so they just quietly leave ๐Ÿ™ˆ

7.3.1. Peer TLV

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |       Type: Peer (8)          |          Length: > 8          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                      Peer Node Identifier                     |
   |                  (length fixed in DNCP profile)               |
   ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Peer Endpoint Identifier                   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                   (Local) Endpoint Identifier                 |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

This TLV indicates that the node in question vouches that the specified peer is reachable by it on the specified local endpoint. The presence of this TLV at least guarantees that the node publishing it has received traffic from the peer recently. For guaranteed up-to-date bidirectional reachability, the existence of both nodes' matching Peer TLVs needs to be checked. It's a mutual follow situation, honestly ๐Ÿฆ‹

7.3.2. Keep-Alive Interval TLV

    0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   | Type: Keep-alive interval (9) |          Length: >= 8         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                      Endpoint Identifier                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           Interval                            |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

This TLV indicates a non-default interval being used to send keep-alives, as specified in Section 6.1. ๐Ÿ’“

Endpoint identifier is used to identify the particular (local) endpoint for which the interval applies on the sending node. If 0, it applies for ALL endpoints for which no specific TLV exists. Main character energy for the default ๐Ÿ’…

Interval specifies the interval in milliseconds at which the node sends keep-alives. A value of zero means no keep-alives are sent at all; in that case, some lower-layer mechanism that ensures the presence of nodes MUST be available and used. So no keep-alives doesn't mean no checking, it just means something else has to do the job ๐Ÿซ 


8. Security and Trust Management ๐Ÿ”

If specified in the DNCP profile, either DTLS [RFC6347] or TLS [RFC5246] may be used to authenticate and encrypt either some (if specified optional in the profile) or all unicast traffic. The following methods for establishing trust are defined, but it is up to the DNCP profile to specify which ones may, should, or must be supported. Security is serious, so the profile gets the final say ๐Ÿ™

8.1. Trust Method Based on Pre-Shared Key

A trust model based on Pre-Shared Key (PSK) is a simple security management mechanism that allows an administrator to deploy devices to an existing network by configuring them with a predefined key, similar to the configuration of an administrator password or Wi-Fi Protected Access (WPA) key. Although limited in nature, it is useful to provide a user-friendly security mechanism for smaller networks. A lil key, a lil trust, and everybody gets in ๐Ÿ—๏ธโœจ

8.2. PKI-Based Trust Method ๐Ÿ”

Okay so a PKI-based trust model is a bit more work to set up, ngl, because you need a bootstrapping process first ๐Ÿ˜ฉ. But the payoff is huge: trust gets managed from one central place, so it's the move for bigger networks that need an authoritative say over who's trusted ๐Ÿ’…โœจ.

8.3. Certificate-Based Trust Consensus Method ๐Ÿชช

Sometimes the methods above don't hit the sweet spot between security and user experience, like when you're bootstrapping a network that's mostly unmanaged ๐Ÿ™ˆ. This section gives you guidance for building an opportunistic security method [RFC7435] that DNCP profiles can build on and tweak for their own needs ๐ŸŒธ.

The certificate-based consensus model is all about balance: less trust-management effort, more flexibility ๐Ÿฆ‹. It runs on X.509 certificates, and every DNCP node can share a trust verdict on any other certificate. Then the network reaches a consensus on whether a node using that certificate, or any certificate signed by it, is trusted ๐Ÿซถ.

A DNCP node that isn't using this security method MUST ignore all announced trust verdicts and MUST NOT announce any such verdicts by itself. In other words, any other normative language in this subsection doesn't apply to it ๐Ÿ™…โ€โ™€๏ธ.

The current effective trust verdict for any certificate is the one with the highest priority out of all the trust verdicts announced for that certificate at that moment ๐Ÿ‘‘.

8.3.1. Trust Verdicts

Trust verdicts are basically DNCP nodes spilling the tea on how trustworthy an X.509 certificate is ๐Ÿ“. There are 5 possible verdicts, listed here in ascending priority:

  • 0 (Neutral): no trust verdict exists yet, but the DNCP network should work out one.
  • 1 (Cached Trust): the last known effective trust verdict was Configured or Cached Trust.
  • 2 (Cached Distrust): the last known effective trust verdict was Configured or Cached Distrust.
  • 3 (Configured Trust): trustworthy based on an external ceremony or configuration.
  • 4 (Configured Distrust): not trustworthy based on an external ceremony or configuration.

Trust verdicts fall into 3 groups, and each one has its own vibe ๐ŸŒˆ:

  • Configured verdicts announce the explicit trust verdicts a node has, based on any external trust bootstrap or predefined relationships it has with a given certificate ๐ŸŽ€.
  • Cached verdicts hold on to the last known trust state, just in case every node with configured verdicts about a given certificate has been disconnected or turned off ๐Ÿ’พ.
  • The Neutral verdict is for a brand new node that wants to join the network, so a final verdict can be figured out for it ๐Ÿงš.

The current effective trust verdict for any certificate is the one with the highest priority within the set of trust verdicts announced for that certificate in the DNCP network. A node MUST be trusted for participating in the DNCP network if and only if the current effective trust verdict for its own certificate, or for any certificate in its certificate hierarchy, is (Cached or Configured) Trust, and none of the certificates in its hierarchy have an effective trust verdict of (Cached or Configured) Distrust ๐Ÿ”ฅ. If a node has a configured verdict that's different from the current effective trust verdict for a certificate, the current effective trust verdict wins when deciding trustworthiness ๐Ÿ’…. Even so, the node still keeps and announces its configured verdict ๐Ÿซถ.

8.3.2. Trust Cache

Every node SHOULD keep a trust cache with the current effective trust verdicts for all certificates currently announced in the DNCP network ๐Ÿ—‚๏ธ. The cache is your backup plan for the last known state, for when no node is announcing a configured verdict for a known certificate ๐Ÿ›Ÿ. It SHOULD also be saved to non-volatile memory at reasonable time intervals, so it survives a reboot or power outage ๐Ÿ”‹.

Whenever a node (re)joins the network, or notices that the effective trust verdict for any certificate has changed, it syncs its cache. That means it stores the new effective trust verdicts and overwrites any old cached ones โœจ. Configured verdicts get stored in the cache as their matching cached counterparts ๐ŸŽ€. Neutral verdicts are never stored, and they never override existing cached verdicts ๐Ÿ™…โ€โ™€๏ธ.

8.3.3. Announcement of Verdicts

A node SHOULD always announce any configured verdicts it has set up by itself. It MUST announce them if doing so changes the current effective trust verdict for the matching certificate ๐Ÿ“ฃ. If there are no configured verdicts, the node MUST announce the Cached Trust verdicts it has stored in its trust cache when either of these is true ๐Ÿ’–:

  • The stored trust verdict is Cached Trust, and the current effective trust verdict for the certificate is Neutral or doesn't exist.
  • The stored trust verdict is Cached Distrust, and the current effective trust verdict for the certificate is Cached Trust.

A node rechecks these conditions every time it notices announced trust verdicts changing anywhere in the network ๐Ÿ‘€.

When a node runs into another node with a certificate hierarchy that has no effective trust verdict, it adds a Neutral Trust-Verdict TLV to its node data for every certificate in that hierarchy ๐Ÿงฉ. It keeps publishing it until an effective trust verdict other than Neutral shows up for any of those certificates, or until a reasonable amount of time has passed with no reaction and no further authentication attempts (10 minutes is suggested) โณ. These trust verdicts SHOULD also be limited in rate and number, so nobody can pull off a denial-of-service attack ๐Ÿ›ก๏ธ.

Trust verdicts are announced using Trust-Verdict TLVs ๐Ÿ“œ:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|   Type: Trust-Verdict (10)    |        Length: > 36           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Verdict    |                 (reserved)                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
|                                                               |
|                                                               |
|                      SHA-256 Fingerprint                      |
|                                                               |
|                                                               |
|                                                               |
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          Common Name                          |
  • Verdict represents the numerical index of the trust verdict ๐Ÿ”ข.
  • (reserved) is reserved for future additions. It MUST be set to 0 when creating TLVs and ignored when parsing them ๐Ÿšซ.
  • SHA-256 Fingerprint contains the SHA-256 [RFC6234] hash value of the certificate in DER format ๐Ÿ”.
  • Common Name contains the variable-length (1-64 bytes) common name of the certificate ๐Ÿท๏ธ.

8.3.4. Bootstrap Ceremonies

The list below isn't exhaustive, but it covers some of the ways to set up trust between DNCP nodes and node certificates ๐Ÿค. Trust establishment goes both ways. The existing network has to trust the new node, and the new node has to trust at least one of its peers. So both the new node and an already trusted node have to do a ceremony to bring a node into the DNCP network ๐Ÿ’œ. In every case, an administrator MUST be given external means to identify the node that belongs to a certificate, based on its fingerprint and a meaningful common name ๐Ÿ•ต๏ธโ€โ™€๏ธ.

8.3.4.1. Trust by Identification

A node doing certificate-based trust MUST provide an interface that can retrieve the current set of effective trust verdicts, fingerprints, and names of all known certificates, and that can set configured verdicts to be announced ๐Ÿ”. As an alternative, it MAY hand these capabilities to a companion DNCP node or application it already has a pre-established trust relationship with ๐Ÿค.

8.3.4.2. Preconfigured Trust

A node MAY be preconfigured to trust a certain set of node or CA certificates ๐Ÿ“‹. But those trust relationships MUST NOT spill over into unwanted or unrelated trust for nodes that aren't meant to run inside the same network (for example, all the other devices from the same manufacturer) ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’€.

8.3.4.3. Trust on Button Press

A node MAY offer a physical or virtual interface that temporarily puts one or more of its internal network interfaces into a mode where it trusts the certificate of the first DNCP node it can successfully connect with ๐Ÿ”˜โœจ.

8.3.4.4. Trust on First Use

A node that isn't associated with any other DNCP node MAY trust the certificate of the first DNCP node it can successfully establish a connection with ๐Ÿฅน. This method MUST NOT be used once the node has already associated with any other DNCP node ๐Ÿšซ๐Ÿ’….

9. DNCP Profile-Specific Definitions โœจ

Okay bestie, every DNCP profile MUST spell out the following things, no skipping ๐Ÿ’…

  • Transport ๐Ÿšš: It needs unicast and, optionally, multicast transport protocol(s). If you want multicast-based node and status discovery, a datagram-based transport that supports multicast has to be available.
  • Security ๐Ÿ”: The profile says how the transport is secured. The options are not at all, optionally, always with the TLS scheme defined here using one or more of the methods, or something else. If the links between DNCP nodes are secure or isolated enough, you can run DNCP securely without any authentication or encryption. Lowkey genius.
  • Transport parameters ๐Ÿ”ข: This covers things like port numbers and multicast addresses. Unicast, multicast, and secure unicast might each need their own parameters, if that applies.
  • Ignoring TLVs ๐Ÿ™ˆ: Here the profile says which TLVs get ignored on top of the ones in Section 4.4, for example for security reasons. The base spec already keeps node data inside Node State TLVs safe. If secure unicast is used, Node State TLVs are only sent over unicast, because multicast ones get ignored on receipt. But if a profile adds TLVs that live outside the node data, it should say whether those get ignored when they come in over multicast or non-secured unicast. A DNCP profile may define these DNCP TLVs as safe to ignore:
    • Anything received over multicast, except the Node Endpoint TLV (Section 7.2.1) and the Network State TLV (Section 7.2.2).
    • Any TLVs received over unreliable unicast or multicast at a rate that is too high. Trickle will still get everyone to eventual convergence, as long as the rate slows down at some point. ๐ŸŒˆ
  • Node identifier collisions ๐Ÿ’ฅ: The profile needs to say how to handle a node identifier collision, as described in Section 4.4. The main options are for one or both nodes to give themselves new node identifiers, or to notify someone about a fatal error condition in the DNCP network.
  • Trickle ranges ๐ŸŽข: The profile suggests Imin, Imax, and k ranges for implementations to use in the Trickle algorithm. Trickle doesn't need every implementation to use the same values to work. But values in similar orders of magnitude help implementations of a DNCP profile behave more consistently, and make it easier to estimate the lower and upper bounds for how long convergence takes. Main character energy for sure.
  • Hash function ๐Ÿงฎ: The profile says which hash function H(x) to use and how many bits of its output actually get used. The chosen hash function handles both hashing node data and producing the network state hash, which is a hash of the node data hashes. SHA-256, defined in [RFC6234], is the recommended default choice, but a non-cryptographic hash function could be used too. โš ๏ธ If the network state hash has a collision, the network gets split into partitions that think they're up to date when they actually aren't converged anymore. The network only converges again when some node data somewhere in the network changes, or when conflicting Node State TLVs get sent across the partition. That can happen either through "Trickle-Driven Status Updates" (Section 4.3) or as part of "Processing of Received TLVs" (Section 4.4). Also, if a node publishes node data with a hash that collides with any node data published before, the update may not be fully propagated, and the old version of the node data might get used instead. ๐Ÿ˜ญ
  • DNCP_NODE_IDENTIFIER_LENGTH ๐Ÿ“: This is the fixed length of a node identifier, in bytes.
  • Keep-alives ๐Ÿ’“: The profile says whether to send keep-alives, and if so, whether they're per-endpoint (which requires multicast transport) or per-peer. Keep-alives have their own parameters too:
    • DNCP_KEEPALIVE_INTERVAL: how often keep-alives get sent by default, if they're turned on.
    • DNCP_KEEPALIVE_MULTIPLIER: how many DNCP_KEEPALIVE_INTERVAL periods (or the keep-alive interval value supplied by the peer) a node can go unheard from and still count as valid. This is just a default, used when there's no other configuration info or per-endpoint configuration.
  • Dense multicast optimization ๐Ÿš€: The profile says whether to support the dense multicast-enabled link optimization (Section 6.2) or not.

For some guidance on picking transport and security options, check out Appendix B. ๐ŸŽ€


10. Security Considerations ๐Ÿšจ

Okay, this section is serious, so let's get into it ๐Ÿซฃ

DNCP-based protocols may use multicast to signal DNCP state changes and for keep-alive purposes. However, no actual published data TLVs get sent across that channel. So an attacker can only learn hash values of the state within DNCP, and may be able to trigger unicast synchronization attempts between nodes on a local link this way. A DNCP node MUST therefore rate limit its reactions to multicast packets. Non-negotiable, bestie. ๐Ÿ›‘

When you use DNCP to bootstrap a network, PKI-based solutions can run into problems when validating certificates. That's because accurate time might not be available, or because the network can't be used to check Certificate Revocation Lists or to do online validation. ๐Ÿ•ฐ๏ธ

The Certificate-based trust consensus mechanism defined in this document allows for a consenting revocation. But if a device gets compromised, the trust cache could be poisoned before the actual revocation happens. That would let the distrusted device rejoin the network under a different identity. ๐Ÿ˜ฑ Stopping an attack like this might require physical intervention and flushing the trust caches. Scary, but true.


11. IANA Considerations ๐Ÿงพ

IANA has set up a registry for the (decimal 16-bit) "DNCP TLV Types" under "Distributed Node Consensus Protocol (DNCP)". The registration procedure is Standards Action [RFC5226]. The initial contents are:

   0: Reserved

   1: Request network state

   2: Request node state

   3: Node endpoint

   4: Network state

   5: Node state

   6: Reserved for future use (was: Custom)

   7: Reserved for future use (was: Fragment count)

   8: Peer

   9: Keep-alive interval

   10: Trust-Verdict

   11-31: Unassigned

   32-511: Reserved for per-DNCP profile use

   512-767: Unassigned

   768-1023: Reserved for Private Use [RFC5226]

   1024-65535: Reserved for future use

12. References ๐Ÿ“š

12.1. Normative References ๐Ÿ’ช

12.2. Informative References ๐Ÿง 


Appendix A. Alternative Modes of Operation ๐Ÿฆ‹

Beyond what's in the main text, the protocol allows for other uses too. These are just examples. ๐ŸŒธ

A.1. Read-Only Operation ๐Ÿ‘€

If a node uses just a single endpoint and doesn't need to publish any TLVs, it doesn't need full DNCP node functionality. A limited node like this can get and keep a view of the TLV space by implementing the processing logic in Section 4.4. Such a node wouldn't need Trickle, peer maintenance, or even keep-alives at all. The DNCP nodes' use of those already guarantees that it eventually receives network state hashes and synchronizes node data, even when the transport is unreliable. Lowkey clever. ๐Ÿง โœจ

A.2. Forwarding Operation ๐Ÿ“ฌ

If a node with a pair of endpoints doesn't need to publish any TLVs, it can detect (for example) the nodes with the highest node identifier on each of the endpoints, if there are any. Any TLVs received from one of them get forwarded verbatim as unicast to the other node with the highest node identifier. ๐Ÿ’Œ

Tinkering with the TLVs would remove the guarantees this scheme depends on. Passive monitoring, though, would obviously be fine ๐Ÿ‘€. This kind of simple forwarding can't be chained, because it doesn't send anything proactively. ๐Ÿ™…โ€โ™€๏ธ


Appendix B. DNCP Profile Additional Guidance ๐ŸŽ€

This appendix explains what the design choices behind a DNCP profile mean for particular transport or security options. Read it before you pick your transport and security setup, it's giving very helpful energy ๐Ÿ’–

B.1. Unicast Transport -- UDP or TCP? ๐Ÿš€

okay so the node data a DNCP node publishes is capped at 64 KB ๐Ÿ™ˆ because the length field of the TLV it sits in is only 16 bits. Some transport choices can make that limit even smaller. If you use UDP datagrams for unicast, the upper bound is whatever the nodes and the underlying network can pass between each other, because DNCP doesn't define its own fragmentation scheme ๐Ÿ’€. So a profile that picks UDP has to either keep node data small (for example, a bit under the IPv6 default MTU if you're on IPv6) or specify a minimum that every node has to support. Even then, if you're doing non-link-local communication, you have to think about what middleboxes do to fragmented packets ๐Ÿ˜ญ. That's why a stream transport like TCP is probably the move if you want non-link-local communication or if fragmentation is likely to cause problems ๐Ÿซถ.

TCP comes with some extra perks too โœจ. It has a relatively long built-in keep-alive, and combined with connections closing after eventual failed retransmissions, that might be enough that you don't need the in-protocol keep-alive from Section 6.1 ๐Ÿฆ‹. It's also reliable, so you don't need Trickle on those unicast connections. Iconic ๐Ÿ’….

The big catch with TCP instead of UDP for DNCP-based profiles is that you lose control over when TLVs get received ๐Ÿ˜ฉ. UDP datagrams have some delay too, but TLVs sent over a reliable stream can get held up for a long time because of retransmissions. This isn't a problem if no relative, time-dependent information is stored in the TLVs of your DNCP-based protocol. For a protocol like that, TCP is a totally reasonable choice for unicast transport whenever it's available ๐ŸŒธ.

B.2. (Optional) Multicast Transport ๐Ÿ“ก

Multicast is needed for dynamic peer discovery and for triggering unicast exchanges ๐Ÿงš. For that job, unreliable datagram transport (=typically UDP) is the only transport option defined in this specification. DNCP-based protocols are allowed to define their own transport or peer discovery mechanism though, for example one based on Multicast DNS (mDNS) or DNS ๐Ÿ“.

If you do use multicast, you should specify a well-known address, plus the desired address scopes (for IPv6, for example) ๐Ÿ’œ. In most cases, link-local and possibly site-local are the useful scopes โœจ.

B.3. (Optional) Transport Security ๐Ÿ”

In terms of security, DTLS and TLS are equivalent, and they use a similar amount of state on devices ๐Ÿ’–. TLS sits on top of a stream protocol, but DTLS needs relatively long session caching inside the DTLS layer. Without it, you'd keep paying for expensive reauthentication and reauthorization whenever any state in the DNCP network changes, or whenever a per-peer keep-alive gets sent (if you've enabled one) ๐Ÿ˜ฉ.

TLS implementations seem more mature and more widely available as open source than DTLS ones, at least at the time of writing ๐ŸŒˆ. This may be because TLS has a long history of use with HTTPS, which is very real ๐Ÿ‘‘.

Some libraries don't seem to support multiplexing insecure and secure communication on the same port ๐Ÿ™ƒ. So giving secured and unsecured communication distinct ports may be beneficial ๐ŸŽ€.

Appendix C. Example Profile ๐Ÿงช

This is the DNCP profile of SHSP, an experimental (and, for the purposes of this document, fictional) home automation protocol ๐Ÿ โœจ. The protocol is used to make a key-value store, published by each node, available to all the other nodes. That lets everyone do distributed monitoring and control of a home infrastructure, which is giving smart home energy ๐Ÿซถ. It defines only one additional TLV type: a key=value TLV containing a single key=value assignment for publication ๐Ÿ’œ.

  • Unicast transport: IPv6 TCP on port EXAMPLE-P1. Only absolute timestamps are used within the key=value data, and the protocol mainly focuses on Linux-based nodes, which support both protocols as well ๐Ÿง. Connections from and to non-link-local addresses are ignored, so this protocol doesn't get exposed outside the secure links ๐Ÿ”’.
  • Multicast transport: IPv6 UDP on port EXAMPLE-P2, to the link-local scoped multicast address ff02:EXAMPLE. At least one node per link in the home is assumed to facilitate node discovery, without depending on any other infrastructure ๐Ÿฆ‹.
  • Security: None. It is to be used only on trusted links (WPA2-x wireless, physically secure wired links) ๐Ÿ›ก๏ธ. Not gonna lie, this one is a little scary, so only use it on links you trust ๐Ÿ˜ฌ.
  • Additional TLVs to be ignored: None. No DNCP security is specified, and no new TLVs are defined outside of node data ๐ŸŒธ.
  • Node identifier length (DNCP_NODE_IDENTIFIER_LENGTH): 32 bits that are randomly generated ๐ŸŽฒ.
  • Node identifier collision handling: Pick a new random node identifier ๐Ÿ”.
  • Trickle parameters: Imin = 200 ms, Imax = 7, k = 1. This means at least one multicast per link in 25 seconds in stable state (0.2 * 2^7) โฑ๏ธโœจ.
  • Hash function H(x) + length: SHA-256, with only 128 bits used. It's relatively fast, and 128 bits should be plenty to prevent random conflicts (64 bits would most likely be sufficient, too) ๐Ÿ’….
  • No in-protocol keep-alives (Section 6.1): TCP keep-alive is to be used. In practice, TCP keep-alive is seldom encountered anyway, because changes in network state cause packets to be sent on the unicast connections, and connections that fail enough retransmissions get dropped long before the keep-alive would actually fire ๐Ÿ’€.
  • No support for dense multicast-enabled link optimization (Section 6.2): SHSP is a simple protocol for a few nodes (network-wide, not even to mention on a single link), so this optimization wouldn't provide any benefit ๐Ÿ™Œ.

Acknowledgements ๐Ÿซถ

Thanks to Ole Troan, Pierre Pfister, Mark Baugher, Mark Townsley, Juliusz Chroboczek, Jiazi Yi, Mikael Abrahamsson, Brian Carpenter, Thomas Clausen, DENG Hui, and Margaret Cullen for their contributions to the document ๐ŸŒท.

Thanks to Kaiwen Jin and Xavier Bonnetain for their related research work ๐Ÿ”ฌโœจ.

Authors' Addresses ๐Ÿ’Œ

Markus Stenberg
Independent
Helsinki  00930
Finland

Email: `markus.stenberg@iki.fi`
Steven Barth
Independent
Halle  06114
Germany

Email: `cyrus@openwrt.org`

That's the whole doc, bestie! ๐ŸŒˆ๐Ÿ’– Thank you for reading the entire thing with me ๐Ÿฆ‹๐Ÿ‘‘

๐Ÿ“ฆ where this page comes from