RFC 8782

Distributed Denial-of-Service Open Threat Signaling (DOTS) Signal Channel Specification

📅 published May 2020, from ietf

RFC 8782: Distributed Denial-of-Service Open Threat Signaling (DOTS) Signal Channel Specification 🦋

okay bestie, the title block is giving formal, but here's the tea 🫖 This is an IETF doc (Internet Engineering Task Force) and it's RFC 8782. It went out in May 2020 as a Standards Track document with ISSN 2070-1721. The editors are T. Reddy.K (Ed., McAfee) and M. Boucadair (Ed., Orange), and the other authors are P. Patil (Cisco), A. Mortensen (Arbor Networks, Inc.), and N. Teague (Iron Mountain Data Centers) 💖 The header doesn't have any "Obsoletes" or "Updates" line, so it doesn't list any RFCs it replaces or changes.

Abstract ✨

This doc specifies the Distributed Denial-of-Service Open Threat Signaling (DOTS) signal channel. It's a protocol for telling a server that you need protection from Distributed Denial-of-Service (DDoS) attacks. The server is the one that can turn on network traffic mitigation for the client that asked 🧚

There's also a companion doc for the DOTS data channel. That one is its own separate reliable communication layer for DOTS management and configuration stuff 🌸

Status of This Memo 💅

This is an Internet Standards Track document, so it's the real deal 👑

It's a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community, and it got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more on Internet Standards, check Section 2 of RFC 7841 🍓

For the current status, any errata, and how to send feedback, go to https://www.rfc-editor.org/info/rfc8782 🦋

Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved. 💜

This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they're in effect on the date it was published. Please read these carefully, 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. They're provided without warranty, as described in the Simplified BSD License.

Table of Contents 💜

   1.  Introduction
   2.  Terminology
   3.  Design Overview
   4.  DOTS Signal Channel: Messages & Behaviors
     4.1.  DOTS Server(s) Discovery
     4.2.  CoAP URIs
     4.3.  Happy Eyeballs for DOTS Signal Channel
     4.4.  DOTS Mitigation Methods
       4.4.1.  Request Mitigation
       4.4.2.  Retrieve Information Related to a Mitigation
         4.4.2.1.  DOTS Servers Sending Mitigation Status
         4.4.2.2.  DOTS Clients Polling for Mitigation Status
       4.4.3.  Efficacy Update from DOTS Clients
       4.4.4.  Withdraw a Mitigation
     4.5.  DOTS Signal Channel Session Configuration
       4.5.1.  Discover Configuration Parameters
       4.5.2.  Convey DOTS Signal Channel Session Configuration
       4.5.3.  Configuration Freshness and Notifications
       4.5.4.  Delete DOTS Signal Channel Session Configuration
     4.6.  Redirected Signaling
     4.7.  Heartbeat Mechanism
   5.  DOTS Signal Channel YANG Modules
     5.1.  Tree Structure
     5.2.  IANA DOTS Signal Channel YANG Module
     5.3.  IETF DOTS Signal Channel YANG Module
   6.  YANG/JSON Mapping Parameters to CBOR
   7.  (D)TLS Protocol Profile and Performance Considerations
     7.1.  (D)TLS Protocol Profile
     7.2.  (D)TLS 1.3 Considerations
     7.3.  DTLS MTU and Fragmentation
   8.  Mutual Authentication of DOTS Agents & Authorization of DOTS
           Clients
   9.  IANA Considerations
     9.1.  DOTS Signal Channel UDP and TCP Port Number
     9.2.  Well-Known 'dots' URI
     9.3.  Media Type Registration
     9.4.  CoAP Content-Formats Registration
     9.5.  CBOR Tag Registration
     9.6.  DOTS Signal Channel Protocol Registry
       9.6.1.  DOTS Signal Channel CBOR Key Values Subregistry
         9.6.1.1.  Registration Template
         9.6.1.2.  Initial Subregistry Content
       9.6.2.  Status Codes Subregistry
       9.6.3.  Conflict Status Codes Subregistry
       9.6.4.  Conflict Cause Codes Subregistry
       9.6.5.  Attack Status Codes Subregistry
     9.7.  DOTS Signal Channel YANG Modules
   10. Security Considerations
   11. References
     11.1.  Normative References
     11.2.  Informative References
   Appendix A.  CUID Generation
   Acknowledgements
   Contributors
   Authors' Addresses

1. Introduction ✨

okay so a Distributed Denial-of-Service (DDoS) attack is a distributed attempt to make machines or network resources unavailable to their intended users 💀 Usually the attacker gets enough scale by taking over a bunch of end hosts and using those infected hosts to carry out and amplify the attack. The victim can be an application server, a host, a router, a firewall, or a whole network.

Network apps have finite resources. That's stuff like CPU cycles, how many processes or threads they can make and use, the maximum number of simultaneous connections they can handle, and the resources assigned to the control plane, etc. 🎀 When they process network traffic, apps are supposed to use those resources to deliver their intended functionality in the most efficient way. But a DDoS attacker may be able to stop an app from doing its job by making it exhaust its finite resources. Rude 😭

A TCP DDoS SYN flood [RFC4987], for example, is a memory-exhausting attack, while an ACK flood is a CPU-exhausting attack. Attacks on the link work by sending enough traffic that the link gets congested, which likely causes packet loss for legit traffic 🥺 Stateful firewalls can get attacked too, by traffic that makes the firewall keep an excessive number of states. That can jeopardize the firewall's operation overall, on top of likely performance impacts. Then the firewall runs out of memory and can't create the states it needs to process legit flows. Other possible DDoS attacks are discussed in [RFC4732] 🫠

Often, network admins can't figure out what's causing an attack. They may just realize that certain resources seem to be under attack 👀 This document defines a lightweight protocol that lets a DOTS client request mitigation from one or more DOTS servers for protection against detected, suspected, or anticipated attacks. This protocol enables cooperation between DOTS agents, so you can get a highly automated network defense that is robust, reliable, and secure. Quick note: "secure" here means the support of the features defined in Section 2.4 of [RFC8612] 🔐

Here's an example network diagram showing a DOTS agent deployment, in Figure 1. The DOTS server runs on the access network. The DOTS client sits on the LAN (Local Area Network), and the DOTS gateway is embedded in the CPE (Customer Premises Equipment) 🏠

   Network
   Resource         CPE Router        Access Network     __________
 +-----------+   +--------------+    +-------------+    /          \
 |           |___|              |____|             |___ | Internet |
 |DOTS Client|   | DOTS Gateway |    | DOTS Server |    |          |
 |           |   |              |    |             |    |          |
 +-----------+   +--------------+    +-------------+    \__________/

                 Figure 1: Sample DOTS Deployment (1)

DOTS servers can also be reachable over the Internet, like in Figure 2 🌐

   Network                                           DDoS Mitigation
   Resource         CPE Router        __________         Service
 +-----------+   +--------------+    /          \    +-------------+
 |           |___|              |____|          |___ |             |
 |DOTS Client|   | DOTS Gateway |    | Internet |    | DOTS Server |
 |           |   |              |    |          |    |             |
 +-----------+   +--------------+    \__________/    +-------------+

                 Figure 2: Sample DOTS Deployment (2)

In typical deployments, the DOTS client is in a different administrative domain than the DOTS server. For example, the DOTS client is embedded in a firewall protecting services that a customer owns and runs, while the DOTS server belongs to a different administrative entity (usually a service provider) that offers DDoS mitigation services. That latter entity might or might not provide connectivity services to the network hosting the DOTS client 💁‍♀️

The DOTS server may (not) be co-located with the DOTS mitigator. In typical deployments, the DOTS server is in the same administrative domain as the mitigator 🧚 The DOTS client can talk directly to a DOTS server, or indirectly via a DOTS gateway.

This document adheres to the DOTS architecture [DOTS-ARCH]. The requirements for the DOTS signal channel protocol are documented in [RFC8612]. This document satisfies all the use cases discussed in [DOTS-USE-CASES] ✨

This document focuses on the DOTS signal channel. It's a companion to the DOTS data channel specification [RFC8783], which defines a configuration and a bulk data exchange mechanism that supports the DOTS signal channel 🦋

2. Terminology ✨

okay bestie, this part is serious, so pay attention 🫶 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are interpreted as described in BCP 14 [RFC2119][RFC8174], but only when they appear in all capitals, exactly like that 💅 Lowercase versions are just regular words.

(D)TLS is used for statements that apply to both Transport Layer Security [RFC5246] [RFC8446] and Datagram Transport Layer Security [RFC6347]. If a statement only applies to one of them, the doc uses the specific term for that protocol 🎀

The reader should already know the terms defined in [RFC8612] 📚

The meaning of the symbols in YANG tree diagrams is defined in [RFC8340] 🌈

3. Design Overview ✨

okay so the DOTS signal channel is built on top of CoAP [RFC7252] (the Constrained Application Protocol) 🧚. CoAP was originally made for tiny devices and tiny networks, and it has so many features that make it perfect for DOTS: it expects packet loss, it supports asynchronous Non-confirmable messaging, it has congestion control, its small message overhead means it rarely needs fragmentation, it uses minimal resources, and it supports (D)TLS 💖. It's giving "built for this" energy.

DOTS clients and servers behave as CoAP endpoints. By default, a DOTS client (or server) acts as a CoAP client (or server). BUT, and this is the fun part 🙈, a DOTS client (or server) acts as a CoAP server (or client) for specific operations, like DOTS heartbeat operations (Section 4.7).

The DOTS signal channel is layered on top of existing standards, as you can see in Figure 3 🌸.

                      +---------------------+
                      | DOTS Signal Channel |
                      +---------------------+
                      |         CoAP        |
                      +----------+----------+
                      |   TLS    |   DTLS   |
                      +----------+----------+
                      |   TCP    |   UDP    |
                      +----------+----------+
                      |          IP         |
                      +---------------------+

 Figure 3: Abstract Layering of DOTS Signal Channel over CoAP over
                               (D)TLS

Now, ports 🎀. Sometimes a DOTS client and server have already agreed on a specific port number, either through explicit configuration or dynamic discovery [DOTS-SERVER-DISC]. If they haven't, the DOTS signal channel MUST run over port number 4646, as defined in Section 9.1, for both UDP and TCP. If you want to use a different port (not 4646), DOTS clients and servers SHOULD support a configurable parameter so you can supply the port you want to use 🦋.

okay bestie, quick tea ☕ on why NOT the default CoAP port 5684 ((D)TLS CoAP): using 5684 would make it easier to discover services and resources, which [RFC7252] talks about, and we want to avoid that. It also lets things behave differently in places where a DOTS gateway and an Internet of Things (IoT) gateway (for example, Figure 3 of [RFC7452]) are living in the same spot 🏠. The reason the default port matters at all is to make DOTS deployment simpler in situations where you don't need any explicit IP address configuration 🍓. Like, the default router can be the DOTS server, which makes life easier inside LANs (where CPEs have a DOTS gateway built in, as shown in Figures 1 and 2) without needing a super complicated discovery method or config tasks inside the LAN. It's also possible to use anycast addresses for DOTS servers so client configuration (service discovery included) gets easier. In that anycast setup, a DOTS client that starts a session to the DOTS server anycast address may either (1) get redirected to the DOTS server unicast address it should use, following the procedure in Section 4.6, or (2) get relayed to a unicast DOTS server. Slay 💅.

The signal channel uses the "coaps" URI scheme defined in Section 6 of [RFC7252] and the "coaps+tcp" URI scheme defined in Section 8.2 of [RFC8323]. These identify DOTS server resources that you can reach using CoAP over UDP secured with DTLS, and CoAP over TCP secured with TLS, respectively 🔥.

The DOTS signal channel can be set up between two DOTS agents before an attack or during one 🛡️. The DOTS client is the one that starts the signal channel. Then the DOTS client can negotiate, configure, and retrieve the signal channel session behavior with its DOTS peer (Section 4.5). Once the channel is up, the DOTS agents may send heartbeats periodically to keep it active (Section 4.7). At any time, the DOTS client may send a mitigation request message (Section 4.4) to a DOTS server over the active signal channel. While mitigation is active (because packet loss is way more likely during a DDoS attack, ngl 😭), the DOTS server periodically sends status messages to the client, including basic mitigation feedback details. Mitigation stays active until the DOTS client explicitly ends it or the mitigation lifetime runs out. Also, the DOTS server may rely on the signal channel session being lost to trigger mitigation for preconfigured mitigation requests (if there are any) ✨.

DOTS signaling can happen with DTLS over UDP and with TLS over TCP. DOTS requests can also be sent using IPv4 or IPv6 transfer capabilities. A Happy Eyeballs procedure for the DOTS signal channel is specified in Section 4.3 🧦.

A DOTS client is only allowed to access the resources it creates. Specifically, a DOTS client cannot retrieve data about mitigation requests that other DOTS clients in the same DOTS client domain made. Main character energy, but only for your own stuff 👑.

DOTS agents serialize their messages using Concise Binary Object Representation (CBOR) [RFC7049], which is a binary encoding scheme designed for small code and small message size 💜. CBOR-encoded payloads carry signal channel-specific payload messages that convey request parameters and response information, like errors. To make it easier to reuse data models across protocols, [RFC7951] specifies the JavaScript Object Notation (JSON) encoding of YANG-modeled data. A similar effort for CBOR is defined in [CORE-YANG-CBOR] 🌈.

DOTS agents figure out that a CBOR data structure is a DOTS signal channel object from the application context, like the port number assigned to the DOTS signal channel. The other way DOTS agents can indicate that a CBOR data structure is a DOTS signal channel object is by using the "application/dots+cbor" content type (Section 9.3) 🎀.

This document specifies a YANG module for representing DOTS mitigation scopes, DOTS signal channel session configuration data, and DOTS redirected signaling (Section 5). All parameters in the payload of the DOTS signal channel are mapped to CBOR types as specified in Table 5 (Section 6) 🧚.

To prevent fragmentation, DOTS agents must follow the recommendations documented in Section 4.6 of [RFC7252]. Check out Section 7.3 for more details 🫶.

DOTS agents MUST support GET, PUT, and DELETE CoAP methods. The payload in CoAP responses with 2.xx Response Codes MUST be of content type "application/dots+cbor". CoAP responses with 4.xx and 5.xx error Response Codes MUST include a diagnostic payload (Section 5.5.2 of [RFC7252]). That diagnostic payload may contain extra information to help with troubleshooting 🔍.

If an entity owns and runs multiple DOTS clients on the same network, the DOTS server might notice conflicting mitigation requests from those clients 🙃. This document doesn't try to list every condition under which a DOTS server would call two mitigation requests from different DOTS clients "conflicting", and it doesn't recommend how a DOTS server should process conflicting requests either. Those choices are implementation and deployment specific. That said, this document does specify the mechanisms for notifying DOTS clients when conflicts happen, including the conflict cause (Section 4.4) 💅.

If one or more translators are enabled between the client's network and the DOTS server (for example, Traditional NAT [RFC3022], CGN [RFC6888], NAT64 [RFC6146], or NPTv6 [RFC6296]), then any DOTS signal channel messages forwarded to a DOTS server MUST NOT include internal IP addresses/prefixes and/or port numbers. Instead, the external addresses/prefixes and/or port numbers that the translator assigned MUST be used 🌍. This document doesn't make any recommendations about how to discover translators. Here are some (not all) deployment examples you might consider:

  • Port Control Protocol (PCP) [RFC6887] or Session Traversal Utilities for NAT (STUN) [RFC8489] may be used to retrieve the external addresses/prefixes and/or port numbers. Info retrieved by PCP or STUN will be used to fill in the DOTS signal channel messages that get sent to a DOTS server 🦋.
  • A DOTS gateway may be co-located with the translator. The DOTS gateway will need to update the DOTS messages based on the local translator's binding table 🧚.

4. DOTS Signal Channel: Messages & Behaviors 🌸

4.1. DOTS Server(s) Discovery

This document assumes that DOTS clients already have the reachability information for their DOTS server(s), gotten through whatever means works, like local configuration or dynamic methods such as DHCP [DOTS-SERVER-DISC]. Describing those means is out of scope for this document 🙃.

Also out of scope is specifying how a DOTS client should send DOTS requests when multiple DOTS servers are provisioned (for example, contacting all DOTS servers, or selecting one from the list). That behavior is specified in other documents, like [DOTS-MH] 💜.

4.2. CoAP URIs

The DOTS server MUST support the use of the path prefix /.well-known/ as defined in [RFC8615], along with the registered name dots. Each DOTS operation is denoted by a path suffix that shows the intended operation. The operation path (Table 1) gets appended to the path prefix to form the URI used with a CoAP request to perform the desired DOTS operation 🎀.

      +-----------------------+----------------+-------------+
      | Operation             | Operation Path | Details     |
      +=======================+================+=============+
      | Mitigation            | /mitigate      | Section 4.4 |
      +-----------------------+----------------+-------------+
      | Session configuration | /config        | Section 4.5 |
      +-----------------------+----------------+-------------+
      | Heartbeat             | /hb            | Section 4.7 |
      +-----------------------+----------------+-------------+

             Table 1: Operations and Corresponding URIs

4.3. Happy Eyeballs for DOTS Signal Channel ✨

okay so bestie, [RFC8612] says DOTS agents have to support both connectionless and connection-oriented protocols 🦋 so the DOTS signal channel is built to run DTLS over UDP and TLS over TCP. A DOTS client might also get a list of IPv4 and IPv6 addresses (Section 4.1) that it can use to reach the DOTS server over UDP and TCP. If no list of addresses is configured or discovered, the DOTS client adds the IPv4/IPv6 addresses of its default router to the candidate list instead 🧚

Next up is the procedure for picking the address family and transport protocol used to send DOTS signal channel messages 💅

We need this because nobody wants long connection delays 😭 Say the IPv4 path to a DOTS server works fine but the IPv6 path is broken. A dual-stack DOTS client could end up waiting way longer than an IPv4-only client on the same network. There's also the UDP problem: if a middlebox between the client and server is blocking UDP, the DOTS client can't set up a DTLS association, so it has to fall back to TLS over TCP, and that takes forever too 🙈

So to dodge all of this, the DOTS client tries to connect to its DOTS server(s) over both IPv6 and IPv4, and it tries both DTLS over UDP and TLS over TCP, following a DOTS Happy Eyeballs approach 🎀 It's kind of similar to the Happy Eyeballs mechanism in [RFC8305]. The connection attempts happen when the DOTS client initializes or, more generally, whenever it has to pick an address family and transport to contact its DOTS server. Whatever the Happy Eyeballs procedure ends up with is what the DOTS client uses for its later messages to the DOTS server. Here's how this differs from [RFC8305] 👑

  • The order of preference for the DOTS signal channel address family and transport protocol (most preferred first) is: UDP over IPv6, UDP over IPv4, TCP over IPv6, and finally TCP over IPv4. This order follows the address preference order in [RFC6724] and the DOTS signal channel preference for UDP over TCP (to avoid TCP's head of line blocking) 🌸
  • After a connection is successfully established, the DOTS client MUST cache information about the outcome of each connection attempt for a specific period of time, and it uses that info so it doesn't thrash the network with new attempts. The cached info gets flushed once its age goes past a specific period on the order of a few minutes (e.g., 10 min). Typically, if the DOTS client has to reconnect to the same DOTS server within a few seconds after the Happy Eyeballs mechanism finishes, the cache keeps things from thrashing the network, especially when DDoS attack traffic is around 💜
  • If a DOTS signal channel session is set up with TLS (but DTLS failed), the DOTS client periodically repeats the process to find out whether DOTS signal channel messages over DTLS and UDP are available from the DOTS server. That way the DOTS client can move the DOTS signal channel from TCP to UDP 🦋 This probing SHOULD NOT be done more often than every 24 hours, and MUST NOT be done more often than every 5 minutes.

When connection attempts happen during an attack, the DOTS client SHOULD use a "Connection Attempt Delay" [RFC8305] set to 100 ms ⭐

In Figure 4, the DOTS client goes through its connection attempts following the rules in [RFC8305]. In this example, the IPv6 path is broken and a middlebox drops UDP traffic, but it doesn't matter much for the DOTS client because it doesn't have to wait long before trying IPv4 and TCP 🍓

    +-----------+                                         +-----------+
    |DOTS Client|                                         |DOTS Server|
    +-----------+                                         +-----------+
          |                                                     |
       T0 |--DTLS ClientHello, IPv6 ---->X                      |
       T1 |--DTLS ClientHello, IPv4 ---->X                      |
       T2 |--TCP SYN, IPv6-------------->X                      |
       T3 |--TCP SYN, IPv4------------------------------------->|
          |<-TCP SYNACK-----------------------------------------|
          |--TCP ACK------------------------------------------->|
          |<------------Establish TLS Session------------------>|
          |----------------DOTS signal------------------------->|
          |                                                     |

     Note:
      * Retransmission messages are not shown.
      * T1-T0=T2-T1=T3-T2= Connection Attempt Delay.

                Figure 4: DOTS Happy Eyeballs (Sample Flow)

A single DOTS signal channel between DOTS agents can carry multiple DOTS signal messages. To reduce the workload on both the DOTS client and the DOTS server, DOTS clients SHOULD reuse the (D)TLS session 🫶


4.4. DOTS Mitigation Methods 🛡️

A DOTS client uses the following methods to request mitigation, withdraw a request, or check on the status of mitigation requests 💖

PUT:      DOTS clients use the PUT method to request mitigation from
          a DOTS server (Section 4.4.1).  During active mitigation,
          DOTS clients may use PUT requests to carry mitigation
          efficacy updates to the DOTS server (Section 4.4.3).

GET:      DOTS clients may use the GET method to subscribe to DOTS
          server status messages or to retrieve the list of its
          mitigations maintained by a DOTS server (Section 4.4.2).

DELETE:   DOTS clients use the DELETE method to withdraw a request
          for mitigation from a DOTS server (Section 4.4.4).

Mitigation request and response messages are marked as Non-confirmable messages (Section 2.2 of [RFC7252]) ✨

DOTS agents MUST NOT send more than one UDP datagram per round-trip time (RTT) to the peer DOTS agent on average, following the data transmission guidelines in Section 3.1.3 of [RFC8085] 🔥

Requests the DOTS client marks as Non-confirmable messages get sent at regular intervals until the DOTS server sends a response 🍓 If the DOTS client can't maintain an RTT estimate, it MUST NOT send more than one Non-confirmable request every 3 seconds, and it SHOULD use an even less aggressive rate whenever it can (case 2 in Section 3.1.3 of [RFC8085]). Mitigation requests MUST NOT be delayed because of checks on the probing rate (Section 4.7 of [RFC7252]) 🙅‍♀️

JSON encoding of YANG modeled data [RFC7951] is used to show the various methods in the subsections that follow. The examples also use the Labels defined in Sections 9.6.2, 9.6.3, 9.6.4, and 9.6.5 🌈

4.4.1. Request Mitigation 🚨

When a DOTS client needs mitigation for some reason, it uses the CoAP PUT method to send a mitigation request to its DOTS server(s) (Figures 5 and 6) 💜

If a DOTS client is entitled to solicit the DOTS service, the DOTS server turns on mitigation for that client. It does this by passing the DOTS client's request along to a mitigator (which may be co-located with the DOTS server) and then relaying the feedback from that selected mitigator back to the requesting DOTS client 🧚

  Header: PUT (Code=0.03)
  Uri-Path: ".well-known"
  Uri-Path: "dots"
  Uri-Path: "mitigate"
  Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
  Uri-Path: "mid=123"
  Content-Format: "application/dots+cbor"

  {
    ...
  }

           Figure 5: PUT to Convey DOTS Mitigation Requests

The order of the Uri-Path options matters, because it defines the CoAP resource. In particular, mid MUST follow cuid 👑

The Uri-Path parameters below are in addition to the ones defined in Section 4.2:

cuid: Short for Client Unique Identifier 🫧 It's a globally unique identifier meant to prevent collisions among DOTS clients, especially those in the same domain. It MUST be generated by DOTS clients.

For the reasons discussed in Appendix A, implementations SHOULD set 'cuid' using this procedure 🔐 First, the DOTS client feeds one of the following into the SHA-256 [RFC6234] cryptographic hash: the DER-encoded ASN.1 representation of the Subject Public Key Info (SPKI) of its X.509 certificate [RFC5280], its raw public key [RFC7250], the "Pre-Shared Key (PSK) identity" it uses in the TLS 1.2 ClientKeyExchange message, or the "identity" it uses in the "pre_shared_key" TLS 1.3 extension. Then the hash output is truncated to 16 bytes, which means stripping off the final 16 bytes. The truncated output gets base64url encoded (Section 5 of [RFC4648]) with the trailing "=" removed, and that value becomes the 'cuid'.

The 'cuid' is meant to stay stable when talking to a given DOTS server. In other words, the 'cuid' used by a DOTS client SHOULD NOT change over time. A single DOTS client MAY use distinct 'cuid' values per DOTS server.

If a DOTS client has to change its 'cuid' for some reason, it MUST NOT do that while mitigations are still active for the old 'cuid'. The 'cuid' SHOULD be 22 characters long to avoid DOTS signal message fragmentation over UDP. And if that DOTS client created aliases and filtering entries at the DOTS server through the DOTS data channel, it MUST delete all the entries bound to the old 'cuid' and reinstall them using the new one 🎀

DOTS servers MUST return the 4.09 (Conflict) error code to a DOTS peer to say the 'cuid' is already in use by another DOTS client. When the DOTS peer gets that error code, it MUST generate a new 'cuid' (e.g., using [RFC4122]) 💥

Client-domain DOTS gateways MUST handle 'cuid' collisions directly, and it is RECOMMENDED that server-domain DOTS gateways handle 'cuid' collisions directly too 🌸

DOTS gateways MAY rewrite the 'cuid' used by peer DOTS clients. What triggers that rewriting is out of scope 🙃

This is a mandatory Uri-Path parameter ⭐

mid: The identifier for the mitigation request, represented as an integer 🔢 This identifier MUST be unique for each mitigation request bound to the DOTS client. That means the 'mid' value in a mitigation request has to be unique (per 'cuid' and DOTS server) compared to the 'mid' values of active mitigation requests sent from the DOTS client to the DOTS server 🧩

To handle out-of-order delivery of mitigation requests, 'mid' values MUST increase monotonically 📈

If the 'mid' value reaches 3/4 of (2^(32) - 1) (i.e., 3221225471) and no attack is detected, the DOTS client MUST reset 'mid' to 0 to handle 'mid' rollover 🔄 If the DOTS client keeps mitigation requests with preconfigured scopes, it MUST recreate them with the 'mid' restarting at 0.

This identifier MUST be generated by the DOTS client 💜

This is a mandatory Uri-Path parameter. 🎀

Okay so 'cuid' and 'mid' MUST NOT appear in the PUT request message body (Figure 6), bestie. The schema in Figure 6 uses the types from Section 6 💅. Heads up: this figure, and any other schema figure like it, is a non-normative sketch of the message structure 🧚

{
  "ietf-dots-signal-channel:mitigation-scope": {
    "scope": [
      {
        "target-prefix": [
           "string"
         ],
        "target-port-range": [
           {
             "lower-port": number,
             "upper-port": number
           }
         ],
         "target-protocol": [
           number
         ],
         "target-fqdn": [
           "string"
         ],
         "target-uri": [
           "string"
         ],
         "alias-name": [
           "string"
         ],
        "lifetime": number,
        "trigger-mitigation": true|false
      }
    ]
  }
}
   Figure 6: PUT to Convey DOTS Mitigation Requests (Message Body
                              Schema)

Here's the breakdown of the CBOR body from Figure 6 in the PUT request 💖

target-prefix: This is a list of prefixes for the resources under attack, written in Classless Inter-Domain Routing (CIDR) notation [RFC4632] 🌸

As a reminder, the prefix length is less than or equal to 32 (or 128) for IPv4 (or IPv6) ✨

The prefix list MUST NOT include broadcast, loopback, or multicast addresses. Those count as invalid values 🙅‍♀️ On top of that, the DOTS server MUST validate that target prefixes are within the scope of the DOTS client domain. DOTS servers may support other validation checks too.

This is an optional attribute.

target-port-range: This is a list of port numbers bound to the resources under attack 🦋

A port range is defined by two bounds: a lower port number ('lower-port') and an upper port number ('upper-port'). When only 'lower-port' is present, it represents a single port number.

For TCP, UDP, Stream Control Transmission Protocol (SCTP) [RFC4960], or Datagram Congestion Control Protocol (DCCP) [RFC4340], a range of ports can be, for example, 0-1023, 1024-65535, or 1024-49151 🍓

This is an optional attribute.

target-protocol: This is a list of protocols involved in an attack. The values come from the IANA protocol registry [IANA-Proto] 🧚

If 'target-protocol' is not specified, then the request applies to any protocol.

This is an optional attribute.

target-fqdn: This is a list of Fully Qualified Domain Names (FQDNs) identifying resources under attack [RFC8499] 🌈

How a name gets passed to an underlying name resolution library is implementation and deployment specific. Still, once the name resolves into one or more IP addresses, DOTS servers MUST apply the same validation checks as those for 'target-prefix' 💜

The use of FQDNs may be suboptimal, because:

  • It induces both an extra load and increased delays on the DOTS server, which has to handle and manage DNS resolution requests. 😭
  • It does not guarantee that the DOTS server will resolve a name to the same IP addresses that the DOTS client does. 💀

This is an optional attribute.

target-uri: This is a list of URIs [RFC3986] identifying resources under attack 🔥

The same validation checks used for 'target-fqdn' MUST be followed by DOTS servers to validate a target URI.

This is an optional attribute.

alias-name: This is a list of aliases for the resources the mitigation is requested for. Aliases can be created using the DOTS data channel (Section 6.1 of [RFC8783]), direct configuration, or other means 👑

An alias is used in later signal channel exchanges to refer to the resources under attack more efficiently ✨

This is an optional attribute.

lifetime: This is the lifetime of the mitigation request, in seconds ⏳ The RECOMMENDED lifetime of a mitigation request is 3600 seconds. That value was picked to be long enough that refreshing isn't typically a burden on the DOTS client, while still making the request expire in a timely manner when the client has unexpectedly quit 🫶

DOTS clients MUST include this parameter in their mitigation requests. When this lifetime expires, and the request hasn't been refreshed, the mitigation request is removed. The request can be refreshed by sending the same request again 🔄

A lifetime of '0' in a mitigation request is an invalid value.

A lifetime of negative one (-1) indicates an indefinite lifetime for the mitigation request. The DOTS server MAY refuse an indefinite lifetime for policy reasons. The granted lifetime value is returned in the response. DOTS clients MUST be prepared to not be granted mitigations with indefinite lifetimes 🤷‍♀️

The DOTS server MUST always indicate the actual lifetime in the response, and the remaining lifetime in status messages sent to the DOTS client ⭐

This is a mandatory attribute.

trigger-mitigation: If the parameter is set to 'false', DDoS mitigation will not be triggered for the mitigation request unless the DOTS signal channel session is lost 🙈

If the DOTS client stops responding to heartbeat messages, the DOTS server can detect that the DOTS signal channel session is lost. More details are in Section 4.7 💖

The default value of the parameter is 'true', which means the mitigation starts immediately. If 'trigger-mitigation' is not present in a request, that's equivalent to receiving a request with 'trigger-mitigation' set to 'true' ✨

This is an optional attribute.

In deployments where server-domain DOTS gateways are enabled, identity information about the origin source client domain ('cdid') SHOULD be propagated to the DOTS server. That information helps the DOTS server enforce policies like grouping DOTS clients that belong to the same DOTS domain, limiting the number of DOTS requests, and identifying the mitigation scope 👑 These policies can be enforced per client, per client domain, or both. The identity information may also be used for auditing and debugging purposes 🧚

Figure 7 shows an example of a request relayed by a server-domain DOTS gateway 🦋

Header: PUT (Code=0.03)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "mitigate"
Uri-Path: "cdid=7eeaf349529eb55ed50113"
Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
Uri-Path: "mid=123"
Content-Format: "application/dots+cbor"

{
  ...
}
   Figure 7: PUT for DOTS Mitigation Request as Relayed by a DOTS
                              Gateway

A server-domain DOTS gateway SHOULD add the following Uri-Path parameter:

cdid: This stands for Client Domain Identifier. The 'cdid' is conveyed by a server-domain DOTS gateway to pass the source domain identity from the gateway's client-facing side to its server-facing side, and from the gateway's server-facing side to the DOTS server. The DOTS server may use 'cdid' for policy enforcement (for example, enforcing a quota on filtering rules), and those policies are deployment specific 🌸

Server-domain DOTS gateways SHOULD support a configuration option that controls whether the 'cdid' parameter is inserted.

So that deployments needing per-client policies, per-client-domain policies, or a mix of both can work, server-domain DOTS gateways that are set to insert the 'cdid' parameter MUST supply, in the 'cdid', the SPKI hash of the DOTS client X.509 certificate, the DOTS client raw public key, or the hash of the "PSK identity". They follow the same rules used to generate the hash conveyed in 'cuid'. The ultimate DOTS server then uses it to work out the corresponding client's domain 🔍 A 'cdid' generated by a server-domain gateway is likely to be the same as the 'cuid', except when the DOTS message was relayed by a client-domain DOTS gateway or when the 'cuid' was generated by a rogue DOTS client 👀

If a DOTS client is provisioned, for example, with distinct certificates depending on the peer server-domain DOTS gateway, the server-domain DOTS gateway may supply distinct 'cdid' values. The ultimate DOTS server MUST treat those 'cdid' values as equivalent 🫶

The 'cdid' attribute MUST NOT be generated and included by DOTS clients.

DOTS servers MUST ignore 'cdid' attributes that are directly supplied by source DOTS clients or client-domain DOTS gateways. This means first server-domain DOTS gateways MUST strip 'cdid' attributes supplied by DOTS clients. DOTS servers SHOULD support a configuration parameter to identify DOTS gateways that are trusted to supply 'cdid' attributes 🔐

Only single-valued 'cdid' is defined in this document. That means only the first on-path server-domain DOTS gateway can insert a 'cdid' value. This specification does not allow multiple server-domain DOTS gateways on the path to each insert a 'cdid' value for each gateway 🚫

This is an optional Uri-Path. When present, 'cdid' MUST be positioned before 'cuid' 📍

A DOTS gateway SHOULD add the CoAP Hop-Limit option [RFC8768] 🧚

Because handling partial failure cases is so complicated, this specification does not allow multiple mitigation requests in the same PUT request. Concretely, a DOTS client MUST NOT include multiple entries in the 'scope' array of the same PUT request 🙅‍♀️

FQDN and URI mitigation scopes are kind of like a scope alias, where the addresses associated with the domain name or URI (as resolved by the DOTS server) represent the scope of the mitigation 🌈 More specifically, the IP addresses that the host subcomponent of the authority component of a URI resolves to represent the 'target-prefix'. The URI scheme represents the 'target-protocol', and the port subcomponent of the authority component of a URI represents the 'target-port-range'. If the optional port information is not present in the authority component, the default port defined for the URI scheme represents the 'target-port' 💖

In the PUT request, at least one of the attributes 'target-prefix', 'target-fqdn', 'target-uri', or 'alias-name' MUST be present ✨

Attributes and Uri-Path parameters with empty values MUST NOT be present in a request, because an empty value will render the entire request invalid 💀

Figure 8 shows a PUT request example signalling that servers 2001:db8:6401::1 and 2001:db8:6401::2 are receiving attack traffic on TCP port numbers 80, 8080, and 443 🎀 The presence of 'cdid' means a server-domain DOTS gateway has modified the initial PUT request sent by the DOTS client. Note that 'cdid' MUST NOT appear in the PUT request message body 🫶

Header: PUT (Code=0.03)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "mitigate"
Uri-Path: "cdid=7eeaf349529eb55ed50113"
Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
Uri-Path: "mid=123"
Content-Format: "application/dots+cbor"

Figure 8: PUT for DOTS Mitigation Request (An Example)

okay so the CBOR version of that same payload is next, and it's giving very precise little byte art 🦋

A1                                      # map(1)
   01                                   # unsigned(1)
   A1                                   # map(1)
      02                                # unsigned(2)
      81                                # array(1)
         A4                             # map(4)
            06                          # unsigned(6)
            82                          # array(2)
               74                       # text(20)
                  323030313A6462383A363430313A3A312F313238
               74                       # text(20)
                  323030313A6462383A363430313A3A322F313238
            07                          # unsigned(7)
            83                          # array(3)
               A1                       # map(1)
                  08                    # unsigned(8)
                  18 50                 # unsigned(80)
               A1                       # map(1)
                  08                    # unsigned(8)
                  19 01BB               # unsigned(443)
               A1                       # map(1)
                  08                    # unsigned(8)
                  19 1F90               # unsigned(8080)
            0A                          # unsigned(10)
            81                          # array(1)
               06                       # unsigned(6)
            0E                          # unsigned(14)
            19 0E10                     # unsigned(3600)

Figure 9: PUT for DOTS Mitigation Request (CBOR)


bestie, the security bit is the main character moment 👑 In both DOTS signal and data channel sessions, the DOTS client MUST authenticate itself to the DOTS server (Section 8). The DOTS server MAY use the algorithm presented in Section 7 of [RFC7589] to derive the DOTS client identity or username from the client certificate. That DOTS client identity is what lets the DOTS server accept mitigation requests with scopes that the DOTS client is authorized to manage 🔐

the DOTS server couples the DOTS signal and data channel sessions using the DOTS client identity and optionally the cdid parameter value. This means it can check whether the aliases in the mitigation request were actually created by that same DOTS client through the DOTS data channel session. if the aliases weren't created by the DOTS client, the DOTS server MUST return 4.00 (Bad Request) in the response 🙅‍♀️

the DOTS server also couples the DOTS signal channel sessions using the DOTS client identity and optionally the cdid parameter value. It uses the mid and cuid Uri-Path parameter values to spot duplicate mitigation requests 👀 And if the mitigation request has the alias-name plus other parameters that identify the target resources (like target-prefix, target-port-range, target-fqdn, or target-uri), the DOTS server appends the parameter values in alias-name to the matching values in target-prefix, target-port-range, target-fqdn, or target-uri 🧚

the DOTS server tells you how the PUT went using CoAP Response Codes. CoAP 2.xx codes are success 🎉 CoAP 4.xx codes are some sort of invalid requests (client errors) 💀 COAP 5.xx codes come back if the DOTS server is in an error state or is currently unavailable to provide mitigation for the mitigation request from the DOTS client 😭

Figure 10 shows an example response to a PUT request that the DOTS server processed successfully (so, CoAP 2.xx Response Codes) ✨ This version of the specification forbids cuid and cdid (if used) from being returned in a response message body. no sneaking them back in 🙅‍♀️

{
  "ietf-dots-signal-channel:mitigation-scope": {
     "scope": [
        {
          "mid": 123,
          "lifetime": 3600
        }
      ]
   }
}

Figure 10: 2.xx Response Body


okay so if the request is missing a mandatory attribute, doesn't include cuid or mid Uri-Path options, includes multiple scope parameters, or contains invalid or unknown parameters, the DOTS server MUST reply with 4.00 (Bad Request) 🚫 DOTS agents can safely ignore comprehension-optional parameters they don't understand (Section 9.6.1.1) 🫶

a DOTS server that gets a mitigation request with a lifetime set to 0 MUST reply with a 4.00 (Bad Request) 💅

if the DOTS server can't find the mid parameter value from the PUT request in its configuration data, it MAY accept the mitigation request by sending back a 2.01 (Created) response to the DOTS client. The DOTS server will then try to mitigate the attack 🛡️ A DOTS server could reject mitigation requests when it's near capacity or needs to rate-limit a particular client, for example 🌸

now the ordering part, which is lowkey intense 🔥 The relative order of two mitigation requests with the same trigger-mitigation type from a DOTS client is decided by comparing their mid values. if two of them have the same trigger-mitigation type and overlapping mitigation scopes, the request with the highest numeric mid value overrides the other one 👑 Two mitigation requests from a DOTS client have overlapping scopes if there's a common IP address, IP prefix, FQDN, URI, or alias. To avoid keeping a long list of overlapping requests (same trigger-mitigation type and overlapping scopes) from a DOTS client, and to avoid error-prone provisioning, the overlapped lower numeric mid MUST be automatically deleted and no longer available at the DOTS server 🗑️ For example, if the DOTS server gets a mitigation request that overlaps with an existing mitigation with a higher numeric mid, the DOTS server rejects the request by returning 4.09 (Conflict) to the DOTS client 🙈 The response includes enough info for the DOTS client to recognize where the conflict came from, as described in the conflict-information subtree below, with only the relevant nodes listed:

  • conflict-information: Indicates that a mitigation request is conflicting with another mitigation request. This optional attribute has the following structure:
    • conflict-cause: Indicates the cause of the conflict. The following values are defined:
      • 1: Overlapping targets. conflict-scope provides more details about the conflicting target clauses.
    • conflict-scope: Characterizes the exact conflict scope. It may include a list of IP addresses, a list of prefixes, a list of port numbers, a list of target protocols, a list of FQDNs, a list of URIs, a list of aliases, or a mid.

if the DOTS server gets a mitigation request that overlaps with an active mitigation request, but both have distinct trigger-mitigation types, the DOTS server SHOULD deactivate (absent explicit policy/configuration otherwise) the mitigation request with trigger-mitigation set to false 🦋 Especially, if the mitigation request with trigger-mitigation set to false is active, the DOTS server withdraws it (status code is set to 7 as defined in Table 3) and transitions its status to 8 ✨

upon DOTS signal channel session loss with a peer DOTS client, the DOTS server SHOULD withdraw (absent explicit policy/configuration otherwise) any active mitigation requests that overlap with mitigation requests having trigger-mitigation set to false from that DOTS client. The loss of the session implicitly activates those preconfigured mitigation requests, and they take precedence 🌈 Note that the active-but-terminating period is not observed for mitigations withdrawn at the initiative of the DOTS server.

DOTS clients may adopt various strategies for setting the scopes of immediate and preconfigured mitigation requests to avoid potential conflicts 🧠 For example, a DOTS client may tweak preconfigured scopes so that the scope of any overlapping immediate mitigation request is a subset of the preconfigured scopes. Also, if an immediate mitigation request overlaps with any of the preconfigured scopes, the DOTS client sets the scope of that overlapping immediate request to be a subset of the preconfigured scopes. That way you get broad mitigation when the DOTS signal channel collapses and the best chance of recovery 💖

if the request conflicts with an existing mitigation request from a different DOTS client, the DOTS server may return 2.01 (Created) or 4.09 (Conflict) to the requesting DOTS client. If the DOTS server decides to keep the new mitigation request, it returns 2.01 (Created) to the requesting DOTS client. If the DOTS server decides to reject the new mitigation request, it returns 4.09 (Conflict) to the requesting DOTS client. For both 2.01 (Created) and 4.09 (Conflict) responses, the response includes enough info for the DOTS client to recognize the source of the conflict, as described below:

  • conflict-information: Indicates that a mitigation request is conflicting with other mitigation request(s) from other DOTS client(s). This optional attribute has the following structure:
    • conflict-status: Indicates the status of a conflicting mitigation request. The following values are defined:
      • 1: DOTS server has detected conflicting mitigation requests from different DOTS clients. This mitigation request is currently inactive until the conflicts are resolved. Another mitigation request is active.
      • 2: DOTS server has detected conflicting mitigation requests from different DOTS clients. This mitigation request is currently active.
      • 3: DOTS server has detected conflicting mitigation requests from different DOTS clients. All conflicting mitigation requests are inactive.
    • conflict-cause: Indicates the cause of the conflict. The following values are defined:
      • 1: Overlapping targets. conflict-scope provides more details about the conflicting target clauses.
      • 2: Conflicts with an existing accept-list. This code is returned when the DDoS mitigation detects source addresses/prefixes in the accept-listed ACLs are attacking the target.

3: CUID Collision 💜 This code shows up when a DOTS client tries to use a cuid that some other DOTS client is already using 🙈 It means the request got rejected, so the DOTS client has to send a fresh request with a new cuid (check out the example in Figure 11 ✨). Heads up, though: conflict-status, conflict-scope, and retry-timer MUST NOT be returned in this error response 🚫

  • conflict-scope 🎯: this describes exactly where the conflict is happening. It can list IP addresses, prefixes, port numbers, target protocols, FQDNs, URIs, or aliases, or it can point at conflicting ACLs using an acl-name (usually from [RFC8783]) 💅
  • retry-timer ⏰: this is a number in seconds, telling the DOTS client when it can try the same request again. The DOTS server only sends retry-timer to DOTS client(s) whose mitigation request just got deactivated 🦋 If the client resends the same mitigation request before that timer runs out, the DOTS server will probably reject it again for the same reasons, so patience is key 🫶

The retry-timer SHOULD be equal to the lifetime of the active mitigation request that caused the conflicting mitigation request to be deactivated 🌸

If the DOTS server decides to keep track of the deactivated mitigation request, it updates that request's lifetime to retry-timer + 45 seconds 🧚 (so this mitigation request stays deactivated for the entire retry-timer + 45 seconds window). That gives the DOTS client a sweet little gap: it can refresh the deactivated request after retry-timer seconds, but before the lifetime expires, and check whether the conflict has been cleared ✨

Okay, here's the example, bestie 🎀 Figure 11 shows a conflicting cuid getting swapped out for a new one:

     Header: PUT (Code=0.03)
     Uri-Path: ".well-known"
     Uri-Path: "dots"
     Uri-Path: "mitigate"
     Uri-Path: "cuid=7eeaf349529eb55ed50113"
     Uri-Path: "mid=12"

(1) Request with a conflicting 'cuid'

     {
       "ietf-dots-signal-channel:mitigation-scope": {
          "scope": [
             {
               "conflict-information": {
                 "conflict-cause": "cuid-collision"
                }
             }
           ]
        }
     }

(2) Message body of the 4.09 (Conflict) response from the DOTS server

     Header: PUT (Code=0.03)
     Uri-Path: ".well-known"
     Uri-Path: "dots"
     Uri-Path: "mitigate"
     Uri-Path: "cuid=f30d281ce6b64fc5a0b91e"
     Uri-Path: "mid=12"

(3) Request with a new 'cuid'

Figure 11: Example of Generating a New 'cuid'

As an active attack evolves, DOTS clients can adjust how much mitigation they're asking for 🔥 by narrowing down the resources that need protecting. To do that, they send a PUT request with a new mid value, and that new one overrides the existing mitigation request whose scopes overlap with it 👑

If a mitigation request needs to keep going past its originally negotiated lifetime, the DOTS client has to refresh it by sending a new PUT request 🌈 This PUT request MUST use the same mid value, and it MUST repeat every other parameter from the original mitigation request, except that it can change the lifetime parameter value 💖 When that happens, the DOTS server MAY update the mitigation request, and a 2.04 (Changed) response tells the client the update went through ✅ If that's not the case, the DOTS server MUST reject the request with a 4.00 (Bad Request) 💀

okay so a GET request is how a DOTS client peeks at its mitigations (including their status) on a DOTS server 👀💅

cuid is a mandatory Uri-Path parameter for GET requests 🎀

Uri-Path parameters with empty values MUST NOT be present in a request. no empty vibes allowed 🙅‍♀️

The same considerations for manipulating the cdid parameter by server-domain DOTS gateways that we covered in Section 4.4.1 MUST be followed for GET requests 🫶

The c Uri-Query option is how you pick which data nodes you want back: configuration ones, non-configuration ones, or both 🦋 The c (content) parameter and its permitted values from Table 2 [COMI] can grab non-configuration data (the attack mitigation status), configuration data, or both. The DOTS server MAY support this optional filtering capability. It can safely ignore it if it isn't supported 🌸 If the DOTS client does support the optional filtering capability, it SHOULD use the c=n query (to get back only the dynamically changing data) or the c=c query (to get back the static configuration values) when the DDoS attack is active. That keeps the response size small, and honestly that's so smart 🧚

      +-------+-----------------------------------------------------+
      | Value | Description                                         |
      +=======+=====================================================+
      | c     | Return only configuration descendant data nodes     |
      +-------+-----------------------------------------------------+
      | n     | Return only non-configuration descendant data nodes |
      +-------+-----------------------------------------------------+
      | a     | Return all descendant data nodes                    |
      +-------+-----------------------------------------------------+

               Table 2: Permitted Values of the 'c' Parameter

okay now the big-response situation 😭 A DOTS client can use block-wise transfer [RFC7959] to grab its whole list of mitigations from a DOTS server. It can send a Block2 Option in a GET request with NUM = 0 to keep the response size in check 🍓 If the representation of all the active mitigation requests tied to that DOTS client won't fit in a single datagram, the DOTS server MUST use the Block2 Option with NUM = 0 in the GET response. The Size2 Option may be included in the response to show the total size of the resource representation. Then the DOTS client gets the rest by sending more GET requests with Block2 Options whose NUM values are greater than zero. The DOTS client MUST adhere to the block size preferences the DOTS server sends back in the response 💜 And if the DOTS server uses the Block2 Option in the GET response and the resource is dynamically changing (like a c=n or c=a query), the DOTS server MUST include the ETag Option in the response. The DOTS client MUST include that same ETag value in its later GET requests for the rest of the representation. It's giving consistency 🔥

Here are the examples showing how a DOTS client grabs active mitigation requests from a DOTS server 🌈 In particular:

  • Figure 12 is a GET request that retrieves all DOTS mitigation requests signaled by a DOTS client.
  • Figure 13 is a GET request that retrieves one specific DOTS mitigation request signaled by a DOTS client. The configuration data in the response is formatted in the same order the DOTS server processed it in the original mitigation request.

Both of these examples assume the default of c=a, which means the DOTS client is asking for all the data the DOTS server can report 👑

  Header: GET (Code=0.01)
  Uri-Path: ".well-known"
  Uri-Path: "dots"
  Uri-Path: "mitigate"
  Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
  Observe: 0

       Figure 12: GET to Retrieve All DOTS Mitigation Requests
  Header: GET (Code=0.01)
  Uri-Path: ".well-known"
  Uri-Path: "dots"
  Uri-Path: "mitigate"
  Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
  Uri-Path: "mid=12332"
  Observe: 0

    Figure 13: GET to Retrieve a Specific DOTS Mitigation Request

If the DOTS server can't find the mid Uri-Path value from the GET request in its configuration data for the requesting DOTS client, it MUST respond with a 4.04 (Not Found) error Response Code. Same deal for a request to retrieve all mitigation records (no mid Uri-Path defined) for a given DOTS client: if the DOTS server doesn't find any mitigation record for that client, the same error MUST be returned 🙈 As a reminder, a DOTS client is identified by its identity (for example, client certificate or cuid) and optionally by the cdid. bestie, don't forget that part!


Figure 14 is a response example showing all the active mitigation requests tied to the DOTS client, as the DOTS server has them. The response tells you the mitigation status of each mitigation request 🦋

{
  "ietf-dots-signal-channel:mitigation-scope": {
    "scope": [
      {
        "mid": 12332,
        "mitigation-start": "1507818434",
        "target-prefix": [
             "2001:db8:6401::1/128",
             "2001:db8:6401::2/128"
        ],
        "target-protocol": [
          17
        ],
        "lifetime": 1756,
        "status": "attack-successfully-mitigated",
        "bytes-dropped": "134334555",
        "bps-dropped": "43344",
        "pkts-dropped": "333334444",
        "pps-dropped": "432432"
      },
      {
        "mid": 12333,
        "mitigation-start": "1507818393",
        "target-prefix": [
             "2001:db8:6401::1/128",
             "2001:db8:6401::2/128"
        ],
        "target-protocol": [
          6
        ],
        "lifetime": 1755,
        "status": "attack-stopped",
        "bytes-dropped": "0",
        "bps-dropped": "0",
        "pkts-dropped": "0",
        "pps-dropped": "0"
      }
    ]
  }
}

              Figure 14: Response Body to a GET Request

Now let's talk about the mitigation status parameters, because they're the good stuff 🧁

  • mitigation-start: The start time, in seconds, relative to 1970-01-01T00:00Z in UTC time (Section 2.4.1 of [RFC7049]). The CBOR encoding is modified so that the leading tag 1 (epoch-based date/time) MUST be omitted. This one is mandatory whenever an attack mitigation is active. Specifically, mitigation-start is not returned for a mitigation whose status code is set to 8 💀
  • lifetime: The remaining lifetime of the mitigation request, in seconds. This one is mandatory too 🫶
  • status: The status of the attack mitigation. All the possible values are explained in Table 3. Also mandatory, obviously 👑
  • bytes-dropped: The total dropped byte count for the mitigation request since the attack mitigation was triggered. The count wraps around when it hits the maximum value of unsigned integer64. This one is optional 🌸
  • bps-dropped: The average number of dropped bytes per second for the mitigation request since the attack mitigation was triggered. This average SHOULD be over five-minute intervals (so you measure bytes into five-minute buckets, then average those buckets over the time since the mitigation was triggered). This one is optional too ✨
  • pkts-dropped: The total number of dropped packets for the mitigation request since the attack mitigation was triggered. The count wraps around when it reaches the maximum value of unsigned integer64. Optional, babe 🍓
  • pps-dropped: The average number of dropped packets per second for the mitigation request since the attack mitigation was triggered. This average SHOULD be over five-minute intervals (so you measure packets into five-minute buckets, then average those buckets over the time since the mitigation was triggered). Also optional 🧚

And here's the status table, the one that tells you exactly what's going on with the attack 💜

  +-----------+----------------------------------------------------+
  | Parameter | Description                                        |
  |     Value |                                                    |
  +===========+====================================================+
  |         1 | Attack mitigation setup is in progress (e.g.,      |
  |           | changing the network path to redirect the inbound  |
  |           | traffic to a DOTS mitigator).                      |
  +-----------+----------------------------------------------------+
  |         2 | Attack is being successfully mitigated (e.g.,      |
  |           | traffic is redirected to a DDoS mitigator and      |
  |           | attack traffic is dropped).                        |
  +-----------+----------------------------------------------------+
  |         3 | Attack has stopped and the DOTS client can         |
  |           | withdraw the mitigation request.  This status code |
  |           | will be transmitted for immediate mitigation       |
  |           | requests till the mitigation is withdrawn or the   |
  |           | lifetime expires.  For mitigation requests with    |
  |           | preconfigured scopes (i.e., 'trigger-mitigation'   |
  |           | set to 'false'), this status code will be          |
  |           | transmitted four times and then transition to "8". |
  +-----------+----------------------------------------------------+
  |         4 | Attack has exceeded the mitigation provider        |
  |           | capability.                                        |
  +-----------+----------------------------------------------------+
  |         5 | DOTS client has withdrawn the mitigation request   |
  |           | and the mitigation is active but terminating.      |
  +-----------+----------------------------------------------------+
  |         6 | Attack mitigation is now terminated.               |
  +-----------+----------------------------------------------------+
  |         7 | Attack mitigation is withdrawn (by the DOTS        |
  |           | server).  If a mitigation request with 'trigger-   |
  |           | mitigation' set to 'false' is withdrawn because it |
  |           | overlaps with an immediate mitigation request,     |
  |           | this status code will be transmitted four times    |
  |           | and then transition to "8" for the mitigation      |
  |           | request with preconfigured scopes.                 |
  +-----------+----------------------------------------------------+
  |         8 | Attack mitigation will be triggered for the        |
  |           | mitigation request only when the DOTS signal       |
  |           | channel session is lost.                           |
  +-----------+----------------------------------------------------+

                Table 3: Values of 'status' Parameter

4.4.2.1. DOTS Servers Sending Mitigation Status ✨

okay so the Observe Option from [RFC7641] extends CoAP with a way to "observe" a resource on a CoAP server 🦋. The client grabs a representation of the resource and asks the server to keep it updated for as long as the client is interested 💖. DOTS implementations MUST use the Observe Option for both 'mitigate' and 'config' (Section 4.2) 👑.

A DOTS client sends a GET request with the Observe Option set to 0 to get asynchronous notifications of attack mitigation status from the DOTS server 📬.

Unidirectional mitigation notifications inside the bidirectional signal channel are what let the two agents talk asynchronously 🔥. [RFC7641] says that (1) a notification can go out in a Confirmable or a Non-confirmable message, and (2) the message type is usually application dependent and can be picked by the server for each notification individually 🧚. For the DOTS server application, the message type MUST always be set to Non-confirmable, even if the underlying CoAP library decides to send a notification in a Confirmable message 🙈. This overrides the behavior in Section 4.5 of [RFC7641], which would send a Confirmable message instead of a Non-confirmable one at least every 24 hours. Why? First, the DOTS signal channel uses a heartbeat mechanism to check whether the DOTS client is still alive 💜. Second, Confirmable messages are not suitable during an attack 💀.

Packet loss is much more likely during a DDoS attack, so the DOTS server periodically sends attack mitigation status to the DOTS client and also notifies the DOTS client whenever the status of the attack mitigation changes 🌸. If the DOTS server cannot maintain an RTT estimate, it MUST NOT send more than one asynchronous notification every 3 seconds, and it SHOULD use an even less aggressive rate whenever possible (case 2 in Section 3.1.3 of [RFC8085]) 🐢.

When conflicting requests show up, the DOTS server enforces the matching policy. That could be accept all requests, reject all requests, accept only one request but reject all the others, and so on 🎀. It's assumed that this policy comes from the DOTS server administrator or is a default behavior of the DOTS server implementation. Then the DOTS server sends notification messages to the DOTS client(s) at the origin of the conflict (see the conflict parameters defined in Section 4.4.1) 💅. A conflict notification message includes info about the conflict cause, scope, and the status of the mitigation request(s). For example:

  • A notification message with 'status' set to 7 (Attack mitigation is withdrawn) and 'conflict-status' set to 1 is sent to a DOTS client to say that an active mitigation request got deactivated because a conflict was detected 😭.
  • A notification message with 'status' set to 1 (Attack mitigation is in progress) and 'conflict-status' set to 2 is sent to a DOTS client to say that this mitigation request is in progress, but a conflict was detected 👀.

When a DOTS client gets a conflict notification saying a mitigation request was deactivated because of a conflict, it MUST NOT resend the same mitigation request before the expiry of 'retry-timer' ⛔. It is also recommended that DOTS clients support ways to alert administrators about mitigation conflicts 📣.

A DOTS client that no longer wants notifications can just "forget" the observation 🫠. When the DOTS server sends the next notification, the DOTS client won't recognize the token in that message, so it will send back a Reset message. That makes the DOTS server remove the associated entry. Or, the DOTS client can explicitly de-register by issuing a GET request with the Token field set to the token of the observation being canceled, plus an Observe Option set to 1 (de-register). The explicit way is more deterministic, so it is RECOMMENDED 🎯.

Figure 15 shows a DOTS client asking a DOTS server to send notifications about a mitigation request 🧁. Heads up: for mitigations with preconfigured scopes (i.e., 'trigger-mitigation' set to false), the state will need to go from 3 (attack-stopped) to 8 (attack-mitigation-signal-loss) 🌈.

+-----------+                              +-----------+
|DOTS Client|                              |DOTS Server|
+-----------+                              +-----------+
      |                                          |
      |  GET /<mid>                              |
      |  Token: 0x4a                             | Registration
      |  Observe: 0                              |
      +----------------------------------------->|
      |                                          |
      |  2.05 Content                            |
      |  Token: 0x4a                             | Notification of
      |  Observe: 12                             | the current state
      |  status: "attack-mitigation-in-progress" |
      |<-----------------------------------------+
      |                                          |
      |  2.05 Content                            |
      |  Token: 0x4a                             | Notification upon
      |  Observe: 44                             | a state change
      |  status: "attack-successfully-mitigated" |
      |<-----------------------------------------+
      |                                          |
      |  2.05 Content                            |
      |  Token: 0x4a                             | Notification upon
      |  Observe: 60                             | a state change
      |  status: "attack-stopped"                |
      |<-----------------------------------------+
      |                                          |
                         ...

Figure 15: Notifications of Attack Mitigation Status

4.4.2.2. DOTS Clients Polling for Mitigation Status

Polling time! 🍓 The DOTS client can send GET requests at frequent intervals without the Observe Option to fetch the configuration data of the mitigation request and the non-configuration data (i.e., the attack status) 🔍. DOTS clients MAY be configured with a policy that sets how often they poll DOTS servers for mitigation status. That frequency MUST NOT be more than one UDP datagram per RTT, as discussed in Section 3.1.3 of [RFC8085] 🚦.

If the DOTS server has managed to mitigate the attack and the attack has stopped, the DOTS server says so in the status ✅. In that case, the DOTS client recalls the mitigation request by issuing a DELETE request for it (Section 4.4.4) 🧹.

A DOTS client SHOULD react to the status of the attack based on what the DOTS server reports, instead of doing its own detection that the attack has been mitigated 🧠. This way the DOTS client doesn't recall a mitigation request too early. The client might not sense the DDoS attack on its own resources, while the DOTS server could still be actively mitigating it because the attack isn't completely averted 😬.

4.4.3. Efficacy Update from DOTS Clients

While DDoS mitigation is in progress, packets can go missing, so a DOTS client MAY periodically send DOTS mitigation efficacy updates to the relevant DOTS server 📡. A PUT request carries the mitigation efficacy update to the DOTS server. This PUT request is treated as a refresh of the current mitigation 🔄.

The PUT request used for the efficacy update MUST include all the parameters from the PUT request that carried the DOTS mitigation request (Section 4.4.1), unchanged apart from the 'lifetime' parameter value. If that's not the case, the DOTS server MUST reject the request with a 4.00 (Bad Request) 🙅‍♀️.

The If-Match Option (Section 5.10.8.1 of [RFC7252]) with an empty value is used to make the PUT request conditional on the current existence of the mitigation request. If UDP is the transport, CoAP requests can arrive out of order 🌀. For example, the DOTS client may send a PUT request for an efficacy update and then a DELETE request to withdraw the mitigation request, but the DELETE request reaches the DOTS server before the PUT does. To handle out-of-order delivery, if an If-Match Option is present in the PUT request and the 'mid' in the request matches a mitigation request from that DOTS client, the DOTS server processes the request. If no match is found, the DOTS server silently ignores the PUT request 🤫.

Here's an example of an efficacy update message with an If-Match Option that has an empty value 💌:

Header: PUT (Code=0.03)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "mitigate"
Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
Uri-Path: "mid=123"
If-Match:
Content-Format: "application/dots+cbor"

{
 "ietf-dots-signal-channel:mitigation-scope": {
   "scope": [
     {
       "target-prefix": [
          "2001:db8:6401::1/128",
          "2001:db8:6401::2/128"
        ],
       "target-port-range": [
         {
           "lower-port": 80
         },
         {
           "lower-port": 443
         },
         {
            "lower-port": 8080
         }
       ],
       "target-protocol": [
          6
       ],
       "attack-status": "under-attack"
     }
   ]
 }
}

Figure 16: An Example of Efficacy Update

The 'attack-status' parameter is a mandatory attribute when performing an efficacy update 🫶. The possible values for 'attack-status' are described in Table 4 📊.

+-----------+-------------------------------------+
| Parameter | Description                         |
|     Value |                                     |
+===========+=====================================+
|         1 | The DOTS client determines that it  |
|           | is still under attack.              |
+-----------+-------------------------------------+
|         2 | The DOTS client determines that the |
|           | attack is successfully mitigated    |
|           | (e.g., attack traffic is not seen). |
+-----------+-------------------------------------+

Table 4: Values of 'attack-status' Parameter

The DOTS server reports the result of processing a PUT request using CoAP Response Codes 💫. Response Code 2.04 (Changed) comes back if the DOTS server accepted the mitigation efficacy update ✨. The error Response Code 5.03 (Service Unavailable) comes back if the DOTS server has erred or can't perform the mitigation 🥺. As specified in [RFC7252], 5.03 uses the Max-Age Option to say how many seconds to wait before retrying ⏳.

4.4.4. Withdraw a Mitigation ✨

okay so DELETE requests are how a DOTS client withdraws mitigation requests from DOTS servers 🧹 (see Figure 17 💅).

cuid and mid are mandatory Uri-Path parameters for DELETE requests 🎀.

The same rules for handling the cdid parameter by DOTS gateways that we covered in Section 4.4.1 MUST be followed for DELETE requests too 🫶. And Uri-Path parameters with empty values MUST NOT be present in a request 🙈.

  Header: DELETE (Code=0.04)
  Uri-Path: ".well-known"
  Uri-Path: "dots"
  Uri-Path: "mitigate"
  Uri-Path: "cuid=dz6pHjaADkaFTbjr0JGBpw"
  Uri-Path: "mid=123"

Figure 17: Withdraw a DOTS Mitigation

If the DELETE request doesn't include both cuid and mid parameters, the DOTS server MUST reply with a 4.00 (Bad Request) 💀.

Once the request is validated, the DOTS server immediately acknowledges the withdrawal with a 2.02 (Deleted) Response Code and no response payload ✨. It sends back 2.02 (Deleted) even if the mid value in the DELETE request doesn't exist in its configuration data beforehand. Iconic behavior, honestly 💅.

If the DOTS server does find the mid value in its configuration data for that DOTS client, things get a little more dramatic 🌊. To protect against route or DNS flapping caused by a DOTS client rapidly removing a mitigation, and to soften the effect of oscillating attacks, the DOTS server MAY allow mitigation to keep going for a limited period after it acknowledges the withdrawal 🦋. During this period, the DOTS server status messages SHOULD indicate that mitigation is active but terminating (Section 4.4.2) 🌸.

The initial active-but-terminating period SHOULD be long enough to absorb the latency caused by route propagation ⏳. It SHOULD be set by default to 120 seconds ⭐. If the client requests mitigation again before that initial period runs out, the DOTS server MAY exponentially increase the active-but-terminating period (the base of the exponent is 2) up to a maximum of 300 seconds (5 minutes) 📈.

Once the active-but-terminating period elapses, the DOTS server MUST treat the mitigation as terminated, since the DOTS client is no longer responsible for it 🏁.

If a mitigation is triggered by a signal channel loss, the DOTS server relies on normal triggers to stop that mitigation. Those are typically a valid DELETE request, expiry of the mitigation lifetime, or scrubbing of the traffic to the attack target. In particular, the DOTS server MUST NOT consider the signal channel recovery as a trigger to stop the mitigation 🚫💜

4.5. DOTS Signal Channel Session Configuration 🌈

A DOTS client can negotiate, configure, and retrieve DOTS signal channel session behavior with its DOTS peers 🧚. The DOTS signal channel can be used to configure things like these:

  • a. Heartbeat interval (heartbeat-interval): DOTS agents regularly send heartbeats to each other once mutual authentication succeeds, to keep the DOTS signal channel open 💓. Heartbeat messages go between DOTS agents every heartbeat-interval seconds to check the current status of the DOTS signal channel session 🫀.
  • b. Missing heartbeats allowed (missing-hb-allowed): This variable is the maximum number of consecutive heartbeat messages a DOTS agent can go without a response before it decides the session is disconnected or defunct 📵.
  • c. Acceptable probing rate (probing-rate): This parameter is the average data rate that a DOTS agent must not exceed when sending to a peer DOTS agent that isn't responding 🐢.
  • d. Acceptable signal loss ratio: The maximum retransmissions, retransmission timeout value, and other message transmission parameters for Confirmable messages over the DOTS signal channel 📡.

When the DOTS signal channel runs over a reliable transport (like TCP), CoAP's reliability mechanisms over UDP aren't needed, because the TCP connection already handles retransmissions and deduplication 🧼 [RFC8323]. A quick reminder: CoAP over reliable transports doesn't support Confirmable or Non-confirmable message types 🙅‍♀️. So the transmission-related parameters (missing-hb-allowed and the acceptable signal loss ratio) are only negotiated for DOTS over unreliable transports 🌀.

The same or different configuration sets can be used when a mitigation is active (mitigating-config) and when no mitigation is active (idle-config) 🔄. This is super handy for DOTS servers that want to lower heartbeat frequency or stop heartbeat exchanges entirely when an active DOTS client hasn't requested mitigation 😴. If distinct configurations are used, DOTS agents MUST follow the appropriate set based on mitigation activity. For example, if no mitigation request is active (also called 'idle' time), the values related to idle-config must be followed 🧘. DOTS agents MUST also automatically switch to the other configuration when mitigation activity changes. So if an attack mitigation launches after an 'idle' period, the DOTS agent switches from the idle-config values to the mitigating-config values ⚡.

CoAP requests and responses are marked as Confirmable messages when they need reliable delivery 📬. DOTS signal channel session configuration requests and responses are marked as Confirmable messages too 💌. As Section 2.1 of [RFC7252] explains, a Confirmable message gets retransmitted using a default timeout and exponential backoff between retransmissions, until the DOTS server sends an Acknowledgement message (ACK) with the same Message ID that came from the DOTS client 🔁.

Message transmission parameters are defined in Section 4.8 of [RFC7252] 📏. The DOTS server can either piggyback the response in the Acknowledgement message or, if it can't respond right away to a request carried in a Confirmable message, send just an Empty Acknowledgement message so the DOTS client stops retransmitting 🛑. Empty Acknowledgement messages are explained in Section 2.2 of [RFC7252] 📖. When the response is ready, the server sends it in a new Confirmable message, which the DOTS client then needs to acknowledge (see Sections 5.2.1 and 5.2.2 of [RFC7252]) 💫. Requests and responses exchanged between DOTS agents during 'idle' time are marked as Confirmable messages, except for heartbeat messages 🫶.

Implementation Note: A DOTS client that gets a response in a Confirmable message might want to clean up its message state right after sending the ACK 🧽. But if that ACK gets lost and the DOTS server retransmits the Confirmable message, the DOTS client may no longer have any state to match that response to. From the DOTS client's point of view, the retransmission is unexpected. The DOTS client will send a Reset message so it doesn't receive any more retransmissions. This behavior is normal and not an indication of an error (see Section 5.3.2 of [RFC7252] for more details) 🙃

4.5.1. Discover Configuration Parameters ✨

Okay so bestie, this is the part where the DOTS client goes "hey server, what settings are you cool with?" 💅 It's a GET request that asks for the acceptable settings (like the minimum and maximum values) plus the current ones 🦋. This conversation happens only between a DOTS client and its immediate peer DOTS server, so this GET request MUST NOT be relayed by a DOTS gateway. No middleman drama here 🙅‍♀️💖

Here's what the request looks like 🎀 (Figure 18):

Header: GET (Code=0.01)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "config"

Figure 18: GET to Retrieve Configuration

So the DOTS server replies with a 2.05 (Content) response 🌸, and that response tells the client the current, minimum, and maximum values it's willing to accept (Figure 19) ✨. Literally the server showing its whole settings menu 💅🍓

{
  "ietf-dots-signal-channel:signal-config": {
    "mitigating-config": {
      "heartbeat-interval": {
        "max-value": number,
        "min-value": number,
        "current-value": number
      },
      "missing-hb-allowed": {
        "max-value": number,
        "min-value": number,
        "current-value": number
      },
      "probing-rate": {
        "max-value": number,
        "min-value": number,
        "current-value": number
      },
      "max-retransmit": {
        "max-value": number,
        "min-value": number,
        "current-value": number
      },
      "ack-timeout": {
        "max-value-decimal": "string",
        "min-value-decimal": "string",
        "current-value-decimal": "string"
      },
      "ack-random-factor": {
        "max-value-decimal": "string",
        "min-value-decimal": "string",
        "current-value-decimal": "string"
      }
    },
    "idle-config": {
      "heartbeat-interval": {
        "max-value": number,
        "min-value": number,
        "current-value": number
      },
      "missing-hb-allowed": {
        "max-value": number,
        "min-value": number,
        "current-value": number
      },
      "probing-rate": {
        "max-value": number,
        "min-value": number,
        "current-value": number
      },
      "max-retransmit": {
        "max-value": number,
        "min-value": number,
        "current-value": number
      },
      "ack-timeout": {
        "max-value-decimal": "string",
        "min-value-decimal": "string",
        "current-value-decimal": "string"
      },
      "ack-random-factor": {
        "max-value-decimal": "string",
        "min-value-decimal": "string",
        "current-value-decimal": "string"
      }
    }
  }
}

Figure 19: GET Configuration Response Body Schema

Now let's break down each parameter 🔥 (these are the ones in Figure 19):

  • mitigating-config 💜: the set of settings to use while a mitigation is active. These may be included:
    • heartbeat-interval 💖: the time in seconds between two consecutive heartbeat messages. Setting it to '0' turns the heartbeat mechanism off 😭. This is an optional attribute.
    • missing-hb-allowed 🫶: the maximum number of consecutive heartbeat messages the DOTS agent can go without getting a response before it decides the session is disconnected. This is an optional attribute.
    • probing-rate 🌈: the average data rate that a DOTS agent MUST NOT exceed when sending to a peer DOTS agent that doesn't respond (this is the PROBING_RATE parameter in CoAP). This is an optional attribute.
    • max-retransmit 🔁: the maximum number of retransmissions for a message (this is the MAX_RETRANSMIT parameter in CoAP). This is an optional attribute.
    • ack-timeout ⏱️: the timeout value in seconds used to work out the initial retransmission timeout (this is the ACK_TIMEOUT parameter in CoAP). This is an optional attribute.
    • ack-random-factor 🎲: a random factor that influences the timing of retransmissions (this is the ACK_RANDOM_FACTOR parameter in CoAP). This is an optional attribute.
  • idle-config 🦋: the set of settings to use when no mitigation is active. It has the same structure as 'mitigating-config'.

Last but not least, Figure 20 shows an example of acceptable and current settings on a DOTS server 🧚. The same acceptable configuration is used during both mitigation and idle times, so no switching outfits needed 👑✨

{
  "ietf-dots-signal-channel:signal-config": {
    "mitigating-config": {
      "heartbeat-interval": {
        "max-value": 240,
        "min-value": 15,
        "current-value": 30
      },
      "missing-hb-allowed": {
        "max-value": 20,
        "min-value": 3,
        "current-value": 15
      },
      "probing-rate": {
        "max-value": 20,
        "min-value": 5,
        "current-value": 15
      },
      "max-retransmit": {
        "max-value": 15,
        "min-value": 2,
        "current-value": 3
      },
      "ack-timeout": {
        "max-value-decimal": "30.00",
        "min-value-decimal": "1.00",
        "current-value-decimal": "2.00"
      },
      "ack-random-factor": {
        "max-value-decimal": "4.00",
        "min-value-decimal": "1.10",
        "current-value-decimal": "1.50"
      }
    },
    "idle-config": {
      "heartbeat-interval": {
        "max-value": 240,
        "min-value": 15,
        "current-value": 30
      },
      "missing-hb-allowed": {
        "max-value": 20,
        "min-value": 3,
        "current-value": 15
      },
      "probing-rate": {
        "max-value": 20,
        "min-value": 5,
        "current-value": 15
      },
      "max-retransmit": {
        "max-value": 15,
        "min-value": 2,
        "current-value": 3
      },
      "ack-timeout": {
        "max-value-decimal": "30.00",
        "min-value-decimal": "1.00",
        "current-value-decimal": "2.00"
      },
      "ack-random-factor": {
        "max-value-decimal": "4.00",
        "min-value-decimal": "1.10",
        "current-value-decimal": "1.50"
      }
    }
  }
}

Figure 20: Example of a Configuration Response Body


4.5.2. Convey DOTS Signal Channel Session Configuration 🎀

okay so this is where the client actually sends its signal channel settings over to the server 💌 it's a PUT request (see Figures 21 and 22 🦋), and the whole point is conveying the configuration parameters for the signal channel, like the heartbeat interval and max retransmissions. the CoAP transmission parameters are defined in Section 4.8 of [RFC7252] 🧚 the RECOMMENDED values are ack-timeout (2 seconds), max-retransmit (3), and ack-random-factor (1.5). on top of those, the RECOMMENDED specific DOTS transmission parameter values are heartbeat-interval (30 seconds) and missing-hb-allowed (15) 💖

📝 bestie, this next bit is a whole note, so read it slowly 🙈 heartbeat-interval should be tweaked to also assist DOTS messages for NAT traversal (SIG-011 of [RFC8612]). According to [RFC8085], heartbeat messages must not be sent more frequently than once every 15 seconds and should use longer intervals when possible. Furthermore, [RFC4787] recommends that NATs use a state timeout of 2 minutes or longer, but experience shows that sending packets every 15 to 30 seconds is necessary to prevent the majority of middleboxes from losing state for UDP flows. From that standpoint, the RECOMMENDED minimum heartbeat-interval is 15 seconds and the RECOMMENDED maximum heartbeat-interval is 240 seconds. The recommended value of 30 seconds is selected to anticipate the expiry of NAT state. A heartbeat-interval of 30 seconds may be considered to be too chatty in some deployments. For such deployments, DOTS agents may negotiate longer heartbeat-interval values to prevent any network overload with too frequent heartbeats. Different heartbeat intervals can be defined for mitigating-config and idle-config to reduce being too chatty during idle times. If there is an on-path translator between the DOTS client (standalone or part of a DOTS gateway) and the DOTS server, the mitigating-config heartbeat-interval has to be smaller than the translator session timeout. It is recommended that the idle-config heartbeat-interval also be smaller than the translator session timeout to prevent translator traversal issues or that it be disabled entirely. Means to discover the lifetime assigned by a translator are out of scope. Given that the size of the heartbeat request cannot exceed (heartbeat-interval * probing-rate) bytes, probing-rate should be set appropriately to avoid slowing down heartbeat exchanges. For example, probing-rate may be set to 2 * ("size of encrypted DOTS heartbeat request"/heartbeat-interval) or (("size of encrypted DOTS heartbeat request" + "average size of an encrypted mitigation request")/heartbeat-interval). Absent any explicit configuration or inability to dynamically adjust probing-rate values (Section 4.8.1 of [RFC7252]), DOTS agents use 5 bytes/second as a default probing-rate value.

if the DOTS agent wants to change the default values of message transmission parameters, it SHOULD follow the guidance given in Section 4.8.1 of [RFC7252] ✨ the DOTS agents MUST use the negotiated values for message transmission parameters, and default values for non-negotiated ones.

the signal channel session configuration only applies to a single DOTS signal channel session between DOTS agents, so the cuid Uri-Path MUST NOT be used 🙅‍♀️

Header: PUT (Code=0.03)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "config"
Uri-Path: "sid=123"
Content-Format: "application/dots+cbor"

{
 ...
}

     Figure 21: PUT to Convey the DOTS Signal Channel Session
                        Configuration Data

the extra Uri-Path parameter on top of the ones in Table 1 is sid 🔥

  • sid: Session Identifier is an identifier for the DOTS signal channel session configuration data, represented as an integer. This identifier MUST be generated by DOTS clients. sid values MUST increase monotonically (when a new PUT is generated by a DOTS client to convey the configuration parameters for the signal channel). This is a mandatory attribute.

the meaning of the parameters in the CBOR body (Figure 22) is defined in Section 4.5.1 💅

{
  "ietf-dots-signal-channel:signal-config": {
    "mitigating-config": {
      "heartbeat-interval": {
        "current-value": number
      },
      "missing-hb-allowed": {
        "current-value": number
      },
      "probing-rate": {
        "current-value": number
      },
      "max-retransmit": {
        "current-value": number
      },
      "ack-timeout": {
        "current-value-decimal": "string"
      },
      "ack-random-factor": {
        "current-value-decimal": "string"
      }
    },
    "idle-config": {
      "heartbeat-interval": {
        "current-value": number
      },
      "missing-hb-allowed": {
        "current-value": number
      },
      "probing-rate": {
        "current-value": number
      },
      "max-retransmit": {
        "current-value": number
      },
      "ack-timeout": {
        "current-value-decimal": "string"
      },
      "ack-random-factor": {
        "current-value-decimal": "string"
      }
    }
  }
}

     Figure 22: PUT to Convey the DOTS Signal Channel Session
             Configuration Data (Message Body Schema)

at least one of the attributes heartbeat-interval, missing-hb-allowed, probing-rate, max-retransmit, ack-timeout, and ack-random-factor MUST be present in the PUT request 🫶 also, heartbeat-interval, missing-hb-allowed, probing-rate, max-retransmit, ack-timeout, and ack-random-factor, if present, do not need to be provided for both mitigating-config and idle-config in a PUT request.

a PUT request with a higher numeric sid value overrides the configuration data installed by a PUT with a lower numeric sid value 👑 to avoid keeping a long list of sid requests from a DOTS client, the lower numeric sid MUST be automatically deleted and no longer available at the DOTS server.

Figure 23 is a PUT example for conveying the configuration parameters 🌈 in this one, the heartbeat mechanism is disabled when no mitigation is active, while the heartbeat interval is set to 30 when a mitigation is active.

Header: PUT (Code=0.03)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "config"
Uri-Path: "sid=123"
Content-Format: "application/dots+cbor"

{
  "ietf-dots-signal-channel:signal-config": {
    "mitigating-config": {
      "heartbeat-interval": {
        "current-value": 30
      },
      "missing-hb-allowed": {
        "current-value": 15
      },
      "probing-rate": {
        "current-value": 15
      },
      "max-retransmit": {
        "current-value": 3
      },
      "ack-timeout": {
        "current-value-decimal": "2.00"
      },
      "ack-random-factor": {
        "current-value-decimal": "1.50"
      }
    },
    "idle-config": {
      "heartbeat-interval": {
        "current-value": 0
      },
      "max-retransmit": {
        "current-value": 3
      },
      "ack-timeout": {
        "current-value-decimal": "2.00"
      },
      "ack-random-factor": {
        "current-value-decimal": "1.50"
      }
    }
  }
}

      Figure 23: PUT to Convey the Configuration Parameters

the DOTS server tells you how it went using CoAP Response Codes 📬

  • if the request is missing a mandatory attribute, doesn't include a sid Uri-Path, or has one or more invalid or unknown parameters, 4.00 (Bad Request) MUST be returned in the response 💀
  • if the DOTS server doesn't find the sid value from the PUT in its configuration data, and it has accepted the configuration parameters, then 2.01 (Created) MUST be returned in the response ✨
  • if the DOTS server does find the sid value from the PUT in its configuration data, and it has accepted the updated configuration parameters, 2.04 (Changed) MUST be returned in the response 🦋
  • if any of the heartbeat-interval, missing-hb-allowed, probing-rate, max-retransmit, target-protocol, ack-timeout, and ack-random-factor attribute values aren't acceptable to the DOTS server, 4.22 (Unprocessable Entity) MUST be returned in the response. when the DOTS client gets this error code, it SHOULD retrieve the maximum and minimum attribute values the DOTS server will accept (Section 4.5.1) 🙈

the DOTS client may retry and send the PUT request with updated attribute values the DOTS server accepts 🌸

a DOTS client may send a GET with a sid Uri-Path parameter to retrieve the negotiated configuration 🧚 the response doesn't need to include sid in its message body.

4.5.3. Configuration Freshness and Notifications ✨

Okay bestie, so the DOTS server SHOULD slap a Max-Age Option (Section 5.10.5 of [RFC7252]) on any configuration it sends, so the client knows how long that config is valid 💅. That's how the server gets to update the config if something changes on its side. For example, the new config could tell a DOTS client to stop sending heartbeats or send them less often 💖.

It is NOT RECOMMENDED to return a Max-Age Option set to 0 🙈.

Returning a Max-Age Option set to 2^(32)-1 means the config has an infinite lifetime, so it basically never expires 🌈.

If a DOTS client gets a non-zero Max-Age Option, it MUST issue a GET request with a 'sid' Uri-Path parameter to grab the current, acceptable config before the Max-Age value runs out 🏃‍♀️. The client and the server both treat this request as a refresh of the signal channel config parameters 🔄. When a DDoS attack is active, DOTS clients MUST NOT send refresh requests, and the DOTS server MUST NOT terminate the (D)TLS session after the Max-Age value returned in the response expires 😭🔥.

If there's no Max-Age Option in a response, the DOTS client sends GET requests to refresh the config every 60 seconds (Section 5.10.5 of [RFC7252]) 🕰️. To stop that from flooding the server, it is RECOMMENDED that DOTS servers return a Max-Age Option in GET responses 🫶. Which value to use, and how it gets set, is implementation and deployment specific, so figure that out for your setup 🎀.

If an Observe Option set to 0 is included in the configuration request, the DOTS server sends notifications of any configuration change (Section 4.2 of [RFC7641]) 👀✨.

If a DOTS server notices that a misbehaving DOTS client hasn't contacted it after Max-Age has expired to get the signal channel config data, it MAY terminate the (D)TLS session 🙅‍♀️. A (D)TLS session gets terminated when an authenticated message that closes the connection is received, like a fatal alert (Section 6 of [RFC8446]) 💀.

4.5.4. Delete DOTS Signal Channel Session Configuration 🧹

A DELETE request is used to delete the installed DOTS signal channel session configuration data (Figure 24) 🗑️.

  Header: DELETE (Code=0.04)
  Uri-Path: ".well-known"
  Uri-Path: "dots"
  Uri-Path: "config"
  Uri-Path: "sid=123"
                 Figure 24: Delete Configuration

The DOTS server resets the DOTS signal channel session config back to the default values, and it confirms the DOTS client's request to remove that config with a 2.02 (Deleted) Response Code 🌸.

Upon bootstrapping or reboot, a DOTS client MAY send a DELETE request to set the config parameters back to default values 🔁. That kind of request does not include any 'sid' 🧚.

4.6. Redirected Signaling 🦋

Redirected DOTS signaling is discussed in detail in Section 3.2.2 of [DOTS-ARCH] 📚.

If a DOTS server wants to send a DOTS client over to an alternative DOTS server for a signal session, the Response Code 5.03 (Service Unavailable) will be returned in the response to the DOTS client 👉.

The DOTS server can return the error Response Code 5.03 in response to a request from the DOTS client, or it can convey the error Response Code 5.03 in a unidirectional notification response from the DOTS server 📨.

The DOTS server, in the error response, conveys the alternate DOTS server's FQDN and the alternate DOTS server's IP address(es) values in the CBOR body (Figure 25) 🎁.

{
  "ietf-dots-signal-channel:redirected-signal": {
    "alt-server": "string",
    "alt-server-record": [
       "string"
    ]
  }
}
       Figure 25: Redirected Server Error Response Body Schema

The parameters are described below:

  • alt-server: FQDN of an alternate DOTS server.
    • This is a mandatory attribute.
  • alt-server-record: A list of IP addresses of an alternate DOTS server.
    • This is an optional attribute.

The DOTS server returns the Time to Live (TTL) of the alternate DOTS server in a Max-Age Option ⏳. That's the time interval the alternate DOTS server may be cached for use by a DOTS client 💜. A Max-Age Option set to 2^(32)-1 is equivalent to receiving an infinite TTL ♾️. That value means the alternate DOTS server is to be used until it redirects the traffic with another 5.03 response that conveys an alternate server's FQDN 🔥.

A Max-Age Option set to '0' may be returned for redirecting mitigation requests 🙌. Such a value means the redirection only applies to the mitigation request in progress 🎯. Returning a short TTL in a Max-Age Option may adversely impact DOTS clients on slow links 🐌. Returning short values should be avoided under such conditions 🙅‍♀️.

If the alternate DOTS server's TTL has expired, the DOTS client MUST use the DOTS server(s) that were provisioned using the means discussed in Section 4.1 💖. This fallback mechanism is triggered immediately upon expiry of the TTL, except when a DDoS attack is active ⚡.

Requests issued by misbehaving DOTS clients that do not honor the TTL conveyed in the Max-Age Option, or that do not react to explicit redirect messages, can be rejected by DOTS servers 🚫.

Figure 26 shows a 5.03 response example conveying the DOTS alternate server 'alt-server.example' together with its IP addresses 2001:db8:6401::1 and 2001:db8:6401::2 🦄.

{
  "ietf-dots-signal-channel:redirected-signal": {
    "alt-server": "alt-server.example",
    "alt-server-record": [
       "2001:db8:6401::1",
       "2001:db8:6401::2"
    ]
  }
}
      Figure 26: Example of Redirected Server Error Response Body

When the DOTS client receives a 5.03 response with an alternate server included, it considers the current request to have failed, but it SHOULD try resending the request to the alternate DOTS server 🔁✨. During a DDoS attack, the DNS server may be the target of another DDoS attack 😱. The alternate DOTS server's IP addresses conveyed in the 5.03 response help the DOTS client skip the DNS lookup of the alternate DOTS server 🏃‍♀️💨, at the cost of trusting the first DOTS server to provide accurate information 🤝. The DOTS client can then try to establish a UDP or a TCP session with the alternate DOTS server 🔌. The DOTS client MAY implement a method to construct IPv4-embedded IPv6 addresses [RFC6052] 🧩. This is required to handle the scenario where an IPv6-only DOTS client communicates with an IPv4-only alternate DOTS server 🌉.

If the DOTS client has been redirected to a DOTS server it has already communicated with within the last five (5) minutes, it MUST ignore the redirection and try to contact other DOTS servers listed in the local configuration or discovered using dynamic means such as DHCP or SRV procedures [DOTS-SERVER-DISC] 🔍. It is RECOMMENDED that DOTS clients support the means to alert administrators about redirect loops 🚨💅.

4.7. Heartbeat Mechanism 💖

okay bestie, heartbeats are how a DOTS agent says "hey, I'm still here" 🫶 They show signal health and help tell an idle signal channel apart from one that's disconnected or defunct 💀 Each DOTS agent sends a heartbeat over the signal channel to keep its own half alive (this lines up with the "consents" recommendation in Section 6 of [RFC8085] ✨). It also expects heartbeats from its peer, and it may consider the session terminated if the peer's heartbeats go quiet for way too long 😭 Basically, when things are calm, the DOTS client pokes the DOTS server to make sure its cryptographic state is still there, and vice versa 🦋 Those little probes can also keep firewall and/or stateful translator bindings alive, and they cut down on how often you have to set up a brand new handshake when a DOTS signal needs to go out 🔥

Implementation Note 🧠: Given that CoAP roles can be multiplexed over the same session as discussed in [RFC7252] and are already supported by CoAP implementations, both the DOTS client and server can send DOTS heartbeat requests.

The DOTS heartbeat mechanism uses Non-confirmable PUT requests (Figure 27) with an expected 2.04 (Changed) Response Code (Figure 28). This procedure happens between a DOTS agent and its immediate peer DOTS agent, so this PUT request MUST NOT be relayed by a DOTS gateway 🙅‍♀️ The PUT request used for DOTS heartbeat MUST NOT have a 'cuid', 'cdid', or 'mid' Uri-Path.

Header: PUT (Code=0.03)
Uri-Path: ".well-known"
Uri-Path: "dots"
Uri-Path: "hb"
Content-Format: "application/dots+cbor"

{
  "ietf-dots-signal-channel:heartbeat": {
     "peer-hb-status": true
   }
}

Figure 27: PUT to Check Peer DOTS Agent Is Responding

The mandatory 'peer-hb-status' attribute is set to 'true' (or 'false') to say whether a DOTS agent is (or is not) getting heartbeat messages from its peer in the last 2 * 'heartbeat-interval' period ⏰ That info helps a peer DOTS agent spot or confirm connectivity issues and react accordingly. For example, if a DOTS client gets a 2.04 response to its heartbeat messages but no server-initiated heartbeat messages, the DOTS client sets 'peer-hb-status' to 'false'. Then the DOTS server will need to try another strategy for sending the heartbeats (e.g., adjust the heartbeat interval or send a server-initiated heartbeat immediately after receiving a client-initiated heartbeat message) 🔄

Header: (Code=2.04)

Figure 28: Response to a DOTS Heartbeat Request

DOTS servers MAY trigger their heartbeat requests immediately after receiving heartbeat probes from peer DOTS clients ✨ As a reminder, it's the DOTS clients' job to make sure on-path translators/firewalls are keeping a binding, so the same external IP address and/or port number is retained for the DOTS signal channel session 👑

Under normal traffic conditions (i.e., no attack is ongoing), if a DOTS agent doesn't get any response from the peer DOTS agent for 'missing-hb-allowed' number of consecutive heartbeat messages, it concludes that the DOTS signal channel session is disconnected. The DOTS client MUST then try to reestablish the DOTS signal channel session, preferably by resuming the (D)TLS session 🎀

Note: If a new DOTS signal channel session can't be established, the DOTS client SHOULD NOT retry to establish the DOTS signal channel session more frequently than every 300 seconds (5 minutes), and MUST NOT retry more frequently than every 60 seconds (1 minute). It is recommended that DOTS clients support the means to alert administrators about the failure to establish a (D)TLS session 📣

In case of a massive DDoS attack that saturates the incoming link(s) to the DOTS client, all traffic from the DOTS server to the DOTS client will likely be dropped, even though the DOTS server still receives heartbeat requests along with DOTS messages sent by the DOTS client 😭 In this scenario, DOTS clients MUST behave differently to handle message transmission and DOTS signal channel session liveliness during link saturation:

  • The DOTS client MUST NOT consider the DOTS signal channel session terminated, even after a maximum 'missing-hb-allowed' threshold is reached. The DOTS client SHOULD keep using the current DOTS signal channel session to send heartbeat requests over it, so that the DOTS server knows the DOTS client has not disconnected the DOTS signal channel session 💜
  • After the maximum 'missing-hb-allowed' threshold is reached, the DOTS client SHOULD try to establish a new DOTS signal channel session. The DOTS client SHOULD send mitigation requests over the current DOTS signal channel session and, in parallel, send the mitigation requests over the new DOTS signal channel session. This may be handled, for example, by resumption of the (D)TLS session or by using 0-RTT mode in DTLS 1.3 to piggyback the mitigation request in the ClientHello message 🚀
  • As soon as the link is no longer saturated, if traffic from the DOTS server reaches the DOTS client over the current DOTS signal channel session, the DOTS client can stop the new DOTS signal channel session attempt, or, if a new DOTS signal channel session is successful, disconnect the current DOTS signal channel session 🌸

If the DOTS server receives traffic from the peer DOTS client (e.g., peer DOTS client-initiated heartbeats) but the maximum 'missing-hb-allowed' threshold is reached, the DOTS server MUST NOT consider the DOTS signal channel session disconnected. The DOTS server MUST keep using the current DOTS signal channel session so that the DOTS client can send mitigation requests over it 🛡️ In this case, the DOTS server can identify that the DOTS client is under attack and that the inbound link to the DOTS client (domain) is saturated. Furthermore, if the DOTS server does not receive a mitigation request from the DOTS client, it implies that the DOTS client has not detected the attack or, if an attack mitigation is in progress, that the applied DDoS mitigation actions are not yet effectively handling the DDoS attack volume 🧐

If the DOTS server does not receive any traffic from the peer DOTS client during the time span required to exhaust the maximum 'missing-hb-allowed' threshold, the DOTS server concludes the session is disconnected. The DOTS server can then trigger preconfigured mitigation requests for this DOTS client (if any) 🍓

In DOTS over TCP, the sender of a DOTS heartbeat message has to allow up to 'heartbeat-interval' seconds when waiting for a heartbeat reply ⏳ When a DOTS client detects a failure, it proceeds with session recovery, following the same approach used for unreliable transports 🦋


5. DOTS Signal Channel YANG Modules 🌈

This document defines a YANG module [RFC7950] for DOTS mitigation scope, DOTS signal channel session configuration data, DOTS redirection signaling, and DOTS heartbeats 💅

This YANG module (ietf-dots-signal-channel) defines the DOTS client interaction with the DOTS server as seen by the DOTS client. A DOTS server is allowed to update the non-configurable 'ro' entities in the responses. This YANG module is not intended to be used via NETCONF/RESTCONF for DOTS server management purposes, since such a module is out of the scope of this document. It only provides a data model and encoding, not a management data model 🧚

A companion YANG module is defined to include a collection of types defined by IANA: iana-dots-signal-channel (Section 5.2) 💜

5.1. Tree Structure ✨

okay so this is the tree map for the ietf-dots-signal-channel module (that's Section 5.3, bestie 🌸). A DOTS signal message can be a mitigation, a configuration, a redirect, or a heartbeat message. Four vibes, one channel 💅

   module: ietf-dots-signal-channel
     +--rw dots-signal
        +--rw (message-type)?
           +--:(mitigation-scope)
           |  +--rw scope* [cuid mid]
           |     +--rw cdid?                   string
           |     +--rw cuid                    string
           |     +--rw mid                     uint32
           |     +--rw target-prefix*          inet:ip-prefix
           |     +--rw target-port-range*      [lower-port]
           |     |  +--rw lower-port    inet:port-number
           |     |  +--rw upper-port?   inet:port-number
           |     +--rw target-protocol*        uint8
           |     +--rw target-fqdn*            inet:domain-name
           |     +--rw target-uri*             inet:uri
           |     +--rw alias-name*             string
           |     +--rw lifetime?               int32
           |     +--rw trigger-mitigation?     boolean
           |     +--ro mitigation-start?       uint64
           |     +--ro status?                 iana-signal:status
           |     +--ro conflict-information
           |     |  +--ro conflict-status?   iana-signal:conflict-status
           |     |  +--ro conflict-cause?    iana-signal:conflict-cause
           |     |  +--ro retry-timer?       uint32
           |     |  +--ro conflict-scope
           |     |     +--ro target-prefix*       inet:ip-prefix
           |     |     +--ro target-port-range*   [lower-port]
           |     |     |  +--ro lower-port      inet:port-number
           |     |     |  +--ro upper-port?     inet:port-number
           |     |     +--ro target-protocol*     uint8
           |     |     +--ro target-fqdn*         inet:domain-name
           |     |     +--ro target-uri*          inet:uri
           |     |     +--ro alias-name*          string
           |     |     +--ro acl-list* [acl-name]
           |     |     |  +--ro acl-name
           |     |     |  |   -> /ietf-data:dots-data/dots-client/acls/
           |     |     |  |      acl/name
           |     |     |  +--ro acl-type?
           |     |     |      -> /ietf-data:dots-data/dots-client/acls/
           |     |     |         acl/type
           |     |     +--ro mid?                 -> ../../../mid
           |     +--ro bytes-dropped?          yang:zero-based-counter64
           |     +--ro bps-dropped?            yang:gauge64
           |     +--ro pkts-dropped?           yang:zero-based-counter64
           |     +--ro pps-dropped?            yang:gauge64
           |     +--rw attack-status?          iana-signal:attack-status
           +--:(signal-config)
           |  +--rw sid                   uint32
           |  +--rw mitigating-config
           |  |  +--rw heartbeat-interval
           |  |  |  +--ro max-value?       uint16
           |  |  |  +--ro min-value?       uint16
           |  |  |  +--rw current-value?   uint16
           |  |  +--rw missing-hb-allowed
           |  |  |  +--ro max-value?       uint16
           |  |  |  +--ro min-value?       uint16
           |  |  |  +--rw current-value?   uint16
           |  |  +--rw probing-rate
           |  |  |  +--ro max-value?       uint16
           |  |  |  +--ro min-value?       uint16
           |  |  |  +--rw current-value?   uint16
           |  |  +--rw max-retransmit
           |  |  |  +--ro max-value?       uint16
           |  |  |  +--ro min-value?       uint16
           |  |  |  +--rw current-value?   uint16
           |  |  +--rw ack-timeout
           |  |  |  +--ro max-value-decimal?       decimal64
           |  |  |  +--ro min-value-decimal?       decimal64
           |  |  |  +--rw current-value-decimal?   decimal64
           |  |  +--rw ack-random-factor
           |  |     +--ro max-value-decimal?       decimal64
           |  |     +--ro min-value-decimal?       decimal64
           |  |     +--rw current-value-decimal?   decimal64
           |  +--rw idle-config
           |     +--rw heartbeat-interval
           |     |  +--ro max-value?       uint16
           |     |  +--ro min-value?       uint16
           |     |  +--rw current-value?   uint16
           |     +--rw missing-hb-allowed
           |     |  +--ro max-value?       uint16
           |     |  +--ro min-value?       uint16
           |     |  +--rw current-value?   uint16
           |     +--rw probing-rate
           |     |  +--ro max-value?       uint16
           |     |  +--ro min-value?       uint16
           |     |  +--rw current-value?   uint16
           |     +--rw max-retransmit
           |     |  +--ro max-value?       uint16
           |     |  +--ro min-value?       uint16
           |     |  +--rw current-value?   uint16
           |     +--rw ack-timeout
           |     |  +--ro max-value-decimal?       decimal64
           |     |  +--ro min-value-decimal?       decimal64
           |     |  +--rw current-value-decimal?   decimal64
           |     +--rw ack-random-factor
           |        +--ro max-value-decimal?       decimal64
           |        +--ro min-value-decimal?       decimal64
           |        +--rw current-value-decimal?   decimal64
           +--:(redirected-signal)
           |  +--ro alt-server            string
           |  +--ro alt-server-record*    inet:ip-address
           +--:(heartbeat)
              +--rw peer-hb-status              boolean

5.2. IANA DOTS Signal Channel YANG Module 🦋

here's the IANA-maintained module, which is basically the box of shared data types the signal channel borrows from. it's giving organised, no notes 📦

   <CODE BEGINS> file "iana-dots-signal-channel@2020-05-28.yang"
   module iana-dots-signal-channel {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:iana-dots-signal-channel";
     prefix iana-signal;

     organization
       "IANA";
     contact
       "Internet Assigned Numbers Authority

        Postal: ICANN
             12025 Waterfront Drive, Suite 300
             Los Angeles, CA  90094-2536
             United States of America
        Tel:    +1 310 301 5800
        <mailto:iana@iana.org>";
     description
       "This module contains a collection of YANG data types defined
        by IANA and used for DOTS signal channel protocol.

        Copyright (c) 2020 IETF Trust and the persons identified as
        authors of the code.  All rights reserved.

        Redistribution and use in source and binary forms, with or
        without modification, is permitted pursuant to, and subject
        to the license terms contained in, the Simplified BSD License
        set forth in Section 4.c of the IETF Trust's Legal Provisions
        Relating to IETF Documents
        (http://trustee.ietf.org/license-info).

        This version of this YANG module is part of RFC 8782; see
        the RFC itself for full legal notices.";

     revision 2020-05-28 {
       description
         "Initial revision.";
       reference
         "RFC 8782: Distributed Denial-of-Service Open Threat
                    Signaling (DOTS) Signal Channel Specification";
     }

     typedef status {
       type enumeration {
         enum attack-mitigation-in-progress {
           value 1;
           description
             "Attack mitigation setup is in progress (e.g., changing
              the network path to reroute the inbound traffic
              to DOTS mitigator).";
         }
         enum attack-successfully-mitigated {
           value 2;
           description
             "Attack is being successfully mitigated (e.g., traffic
              is redirected to a DDoS mitigator and attack
              traffic is dropped or blackholed).";
         }
         enum attack-stopped {
           value 3;
           description
             "Attack has stopped and the DOTS client can
              withdraw the mitigation request.";
         }
         enum attack-exceeded-capability {
           value 4;
           description
             "Attack has exceeded the mitigation provider
              capability.";
         }
         enum dots-client-withdrawn-mitigation {
           value 5;
           description
             "DOTS client has withdrawn the mitigation
              request and the mitigation is active but
              terminating.";
         }
         enum attack-mitigation-terminated {
           value 6;
           description
             "Attack mitigation is now terminated.";
         }
         enum attack-mitigation-withdrawn {
           value 7;
           description
             "Attack mitigation is withdrawn.";
         }
         enum attack-mitigation-signal-loss {
           value 8;
           description
             "Attack mitigation will be triggered
              for the mitigation request only when
              the DOTS signal channel session is lost.";
         }
       }
       description
         "Enumeration for status reported by the DOTS server.";
     }

     typedef conflict-status {
       type enumeration {
         enum request-inactive-other-active {
           value 1;
           description
             "DOTS Server has detected conflicting mitigation
              requests from different DOTS clients.
              This mitigation request is currently inactive
              until the conflicts are resolved. Another
              mitigation request is active.";
         }
         enum request-active {
           value 2;
           description
             "DOTS Server has detected conflicting mitigation
              requests from different DOTS clients.
              This mitigation request is currently active.";
         }
         enum all-requests-inactive {
           value 3;
           description
             "DOTS Server has detected conflicting mitigation
              requests from different DOTS clients.  All
              conflicting mitigation requests are inactive.";
         }
       }
       description
         "Enumeration for conflict status.";
     }

     typedef conflict-cause {
       type enumeration {
         enum overlapping-targets {
           value 1;
           description
             "Overlapping targets. conflict-scope provides
              more details about the exact conflict.";
         }
         enum conflict-with-acceptlist {
           value 2;
           description
             "Conflicts with an existing accept-list.

              This code is returned when the DDoS mitigation
              detects that some of the source addresses/prefixes
              listed in the accept-list ACLs are actually
              attacking the target.";
         }
         enum cuid-collision {
           value 3;
           description
             "Conflicts with the cuid used by another
              DOTS client.";
         }
       }
       description
         "Enumeration for conflict causes.";
     }

     typedef attack-status {
       type enumeration {
         enum under-attack {
           value 1;
           description
             "The DOTS client determines that it is still under
              attack.";
         }
         enum attack-successfully-mitigated {
           value 2;
           description
             "The DOTS client determines that the attack is
              successfully mitigated.";
         }
       }
       description
         "Enumeration for attack status codes.";
     }
   }
   <CODE ENDS>

5.3. IETF DOTS Signal Channel YANG Module 🎀

this is the main event, the module that actually defines the signal channel. it pulls in the common YANG types from [RFC6991] and some types from [RFC8783], so it's basically a group project with two other RFCs 🫶

   <CODE BEGINS> file "ietf-dots-signal-channel@2020-05-28.yang"
   module ietf-dots-signal-channel {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-dots-signal-channel";
     prefix signal;

okay the YANG module is still going and it's giving a lot 🦋💅 this next chunk is all about the mitigation scope and the heartbeat config parameters, so grab a snack bestie 🍓✨

     import ietf-inet-types {
       prefix inet;
       reference
         "Section 4 of RFC 6991";
     }
     import ietf-yang-types {
       prefix yang;
       reference
         "Section 3 of RFC 6991";
     }
     import ietf-dots-data-channel {
       prefix ietf-data;
       reference
         "RFC 8783: Distributed Denial-of-Service Open Threat Signaling
                    (DOTS) Data Channel Specification";
     }
     import iana-dots-signal-channel {
       prefix iana-signal;
     }

     organization
       "IETF DDoS Open Threat Signaling (DOTS) Working Group";
     contact
       "WG Web:   <https://datatracker.ietf.org/wg/dots/>
        WG List:  <mailto:dots@ietf.org>

        Editor:  Konda, Tirumaleswar Reddy.K
                 <mailto:TirumaleswarReddy_Konda@McAfee.com>

        Editor:  Mohamed Boucadair
                 <mailto:mohamed.boucadair@orange.com>

        Author:  Prashanth Patil
                 <mailto:praspati@cisco.com>

        Author:  Andrew Mortensen
                 <mailto:amortensen@arbor.net>

        Author:  Nik Teague
                 <mailto:nteague@ironmountain.co.uk>";
     description
       "This module contains YANG definition for the signaling
        messages exchanged between a DOTS client and a DOTS server.

        Copyright (c) 2020 IETF Trust and the persons identified as
        authors of the code.  All rights reserved.

        Redistribution and use in source and binary forms, with or
        without modification, is permitted pursuant to, and subject
        to the license terms contained in, the Simplified BSD License
        set forth in Section 4.c of the IETF Trust's Legal Provisions
        Relating to IETF Documents
        (http://trustee.ietf.org/license-info).

        This version of this YANG module is part of RFC 8782; see
        the RFC itself for full legal notices.";

     revision 2020-05-28 {
       description
         "Initial revision.";
       reference
         "RFC 8782: Distributed Denial-of-Service Open Threat
                    Signaling (DOTS) Signal Channel Specification";
     }

     /*
      * Groupings
      */

     grouping mitigation-scope {
       description
         "Specifies the scope of the mitigation request.";
       list scope {
         key "cuid mid";
         description
           "The scope of the request.";
         leaf cdid {
           type string;
           description
             "The cdid should be included by a server-domain
              DOTS gateway to propagate the client domain
              identification information from the
              gateway's client-facing side to the gateway's
              server-facing side, and from the gateway's
              server-facing side to the DOTS server.

              It may be used by the final DOTS server
              for policy enforcement purposes.";
         }
         leaf cuid {
           type string;
           description
             "A unique identifier that is
              generated by a DOTS client to prevent
              request collisions.  It is expected that the
              cuid will remain consistent throughout the
              lifetime of the DOTS client.";
         }
         leaf mid {
           type uint32;
           description
             "Mitigation request identifier.

              This identifier must be unique for each mitigation
              request bound to the DOTS client.";
         }
         uses ietf-data:target;
         leaf-list alias-name {
           type string;
           description
             "An alias name that points to a resource.";
         }
         leaf lifetime {
           type int32;
           units "seconds";
           default "3600";
           description
             "Indicates the lifetime of the mitigation request.

              A lifetime of '0' in a mitigation request is an
              invalid value.

              A lifetime of negative one (-1) indicates indefinite
              lifetime for the mitigation request.";
         }
         leaf trigger-mitigation {
           type boolean;
           default "true";
           description
             "If set to 'false', DDoS mitigation will not be
              triggered unless the DOTS signal channel
              session is lost.";
         }
         leaf mitigation-start {
           type uint64;
           config false;
           description
             "Mitigation start time is represented in seconds
              relative to 1970-01-01T00:00:00Z in UTC time.";
         }
         leaf status {
           type iana-signal:status;
           config false;
           description
             "Indicates the status of a mitigation request.
              It must be included in responses only.";
         }
         container conflict-information {
           config false;
           description
             "Indicates that a conflict is detected.
              Must only be used for responses.";
           leaf conflict-status {
             type iana-signal:conflict-status;
             description
               "Indicates the conflict status.";
           }
           leaf conflict-cause {
             type iana-signal:conflict-cause;
             description
               "Indicates the cause of the conflict.";
           }
           leaf retry-timer {
             type uint32;
             units "seconds";
             description
               "The DOTS client must not resend the
                same request that has a conflict before the expiry of
                this timer.";
           }
           container conflict-scope {
             description
               "Provides more information about the conflict scope.";
             uses ietf-data:target {
               when "/dots-signal/scope/conflict-information/"
                  + "conflict-cause = 'overlapping-targets'";
             }
             leaf-list alias-name {
               when "../../conflict-cause = 'overlapping-targets'";
               type string;
               description
                 "Conflicting alias-name.";
             }
             list acl-list {
               when "../../conflict-cause = 'conflict-with-acceptlist'";
               key "acl-name";
               description
                 "List of conflicting ACLs as defined in the DOTS data
                  channel.  These ACLs are uniquely defined by
                  cuid and acl-name.";
               leaf acl-name {
                 type leafref {
                   path "/ietf-data:dots-data/ietf-data:dots-client/"
                      + "ietf-data:acls/ietf-data:acl/ietf-data:name";
                 }
                 description
                   "Reference to the conflicting ACL name bound to
                    a DOTS client.";
               }
               leaf acl-type {
                 type leafref {
                   path "/ietf-data:dots-data/ietf-data:dots-client/"
                      + "ietf-data:acls/ietf-data:acl/ietf-data:type";
                 }
                 description
                   "Reference to the conflicting ACL type bound to
                    a DOTS client.";
               }
             }
             leaf mid {
               when "../../conflict-cause = 'overlapping-targets'";
               type leafref {
                 path "../../../mid";
               }
               description
                 "Reference to the conflicting 'mid' bound to
                  the same DOTS client.";
             }
           }
         }
         leaf bytes-dropped {
           type yang:zero-based-counter64;
           units "bytes";
           config false;
           description
             "The total dropped byte count for the mitigation
              request since the attack mitigation was triggered.
              The count wraps around when it reaches the maximum value
              of counter64 for dropped bytes.";
         }
         leaf bps-dropped {
           type yang:gauge64;
           config false;
           description
             "The average number of dropped bits per second for
              the mitigation request since the attack
              mitigation was triggered.  This should be over
              five-minute intervals (that is, measuring bytes
              into five-minute buckets and then averaging these
              buckets over the time since the mitigation was
              triggered).";
         }
         leaf pkts-dropped {
           type yang:zero-based-counter64;
           config false;
           description
             "The total number of dropped packet count for the
              mitigation request since the attack mitigation was
              triggered.  The count wraps around when it reaches
              the maximum value of counter64 for dropped packets.";
         }
         leaf pps-dropped {
           type yang:gauge64;
           config false;
           description
             "The average number of dropped packets per second
              for the mitigation request since the attack
              mitigation was triggered.  This should be over
              five-minute intervals (that is, measuring packets
              into five-minute buckets and then averaging these
              buckets over the time since the mitigation was
              triggered).";
         }
         leaf attack-status {
           type iana-signal:attack-status;
           description
             "Indicates the status of an attack as seen by the
              DOTS client.";
         }
       }
     }

     grouping config-parameters {
       description
         "Subset of DOTS signal channel session configuration.";
       container heartbeat-interval {
         description
           "DOTS agents regularly send heartbeats to each other
            after mutual authentication is successfully
            completed in order to keep the DOTS signal channel
            open.";
         leaf max-value {
           type uint16;
           units "seconds";
           config false;
           description
             "Maximum acceptable heartbeat-interval value.";
         }
         leaf min-value {
           type uint16;
           units "seconds";
           config false;
           description
             "Minimum acceptable heartbeat-interval value.";
         }
         leaf current-value {
           type uint16;
           units "seconds";
           default "30";
           description
             "Current heartbeat-interval value.

the next bit picks up right where this description leaves off, so no cliffhanger drama, I promise 🎀💜

              '0' means that heartbeat mechanism is deactivated.";
         }
       }
       container missing-hb-allowed {
         description
           "Maximum number of missing heartbeats allowed.";
         leaf max-value {
           type uint16;
           config false;
           description
             "Maximum acceptable missing-hb-allowed value.";
         }
         leaf min-value {
           type uint16;
           config false;
           description
             "Minimum acceptable missing-hb-allowed value.";
         }
         leaf current-value {
           type uint16;
           default "15";
           description
             "Current missing-hb-allowed value.";
         }
       }
       container probing-rate {
         description
           "The limit for sending Non-confirmable messages with
            no response.";
         leaf max-value {
           type uint16;
           units "byte/second";
           config false;
           description
             "Maximum acceptable probing-rate value.";
         }
         leaf min-value {
           type uint16;
           units "byte/second";
           config false;
           description
             "Minimum acceptable probing-rate value.";
         }
         leaf current-value {
           type uint16;
           units "byte/second";
           default "5";
           description
             "Current probing-rate value.";
         }
       }
       container max-retransmit {
         description
           "Maximum number of retransmissions of a Confirmable
            message.";
         leaf max-value {
           type uint16;
           config false;
           description
             "Maximum acceptable max-retransmit value.";
         }
         leaf min-value {
           type uint16;
           config false;
           description
             "Minimum acceptable max-retransmit value.";
         }
         leaf current-value {
           type uint16;
           default "3";
           description
             "Current max-retransmit value.";
         }
       }
       container ack-timeout {
         description
           "Initial retransmission timeout value.";
         leaf max-value-decimal {
           type decimal64 {
             fraction-digits 2;
           }
           units "seconds";
           config false;
           description
             "Maximum ack-timeout value.";
         }
         leaf min-value-decimal {
           type decimal64 {
             fraction-digits 2;
           }
           units "seconds";
           config false;
           description
             "Minimum ack-timeout value.";
         }
         leaf current-value-decimal {
           type decimal64 {
             fraction-digits 2;
           }
           units "seconds";
           default "2";
           description
             "Current ack-timeout value.";
         }
       }
       container ack-random-factor {
         description
           "Random factor used to influence the timing of
            retransmissions.";
         leaf max-value-decimal {
           type decimal64 {
             fraction-digits 2;
           }
           config false;
           description
             "Maximum acceptable ack-random-factor value.";
         }
         leaf min-value-decimal {
           type decimal64 {
             fraction-digits 2;
           }
           config false;
           description
             "Minimum acceptable ack-random-factor value.";
         }
         leaf current-value-decimal {
           type decimal64 {
             fraction-digits 2;
           }
           default "1.5";
           description
             "Current ack-random-factor value.";
         }
       }
     }

     grouping signal-config {
       description
         "DOTS signal channel session configuration.";
       leaf sid {
         type uint32;
         mandatory true;
         description
           "An identifier for the DOTS signal channel
            session configuration data.";
       }
       container mitigating-config {
         description
           "Configuration parameters to use when a mitigation
            is active.";
         uses config-parameters;
       }
       container idle-config {
         description
           "Configuration parameters to use when no mitigation
            is active.";
         uses config-parameters;
       }
     }

     grouping redirected-signal {
       description
         "Grouping for the redirected signaling.";
       leaf alt-server {
         type string;
         config false;
         mandatory true;
         description
           "FQDN of an alternate server.";
       }
       leaf-list alt-server-record {
         type inet:ip-address;
         config false;
         description
           "List of records for the alternate server.";
       }
     }

     /*
      * Main Container for DOTS Signal Channel
      */

     container dots-signal {
       description
         "Main container for DOTS signal message.

          A DOTS signal message can be a mitigation, a configuration,
          or a redirected signal message.";
       choice message-type {
         description
           "Can be a mitigation, a configuration, or a redirect
            message.";
         case mitigation-scope {
           description
             "Mitigation scope of a mitigation message.";
           uses mitigation-scope;
         }
         case signal-config {
           description
             "Configuration message.";
           uses signal-config;
         }
         case redirected-signal {
           description
             "Redirected signaling.";
           uses redirected-signal;
         }
         case heartbeat {
           description
             "DOTS heartbeats.";
           leaf peer-hb-status {
             type boolean;
             mandatory true;
             description
               "Indicates whether a DOTS agent receives heartbeats
                from its peer.  The value is set to 'true' if the
                DOTS agent is receiving heartbeat messages
                from its peer.";
           }
         }
       }
     }
   }
   <CODE ENDS>

6. YANG/JSON Mapping Parameters to CBOR ✨

Okay, bestie, this part is so important 🫶 Every parameter in the payload of the DOTS signal channel MUST be mapped to a CBOR type exactly the way Table 5 shows 🎀. Each parameter also gets an integer key so the messages stay small and cute 🧚.

Note: Implementers really need to double-check that what their YANG-to-CBOR encoding scheme spits out lines up with Table 5 💅. Some CBOR and JSON types for enumerations and the 64-bit quantities can come out differently depending on which encoder you use, so don't skip this step 😭.

Now the key values. They come in two flavours: comprehension-required and comprehension-optional 🌈. DOTS agents can safely ignore any comprehension-optional values they don't understand, which is very chill 💖. But if a request includes comprehension-required values they don't understand, they cannot successfully process it 💀. The 4.00 response SHOULD include a diagnostic payload that describes the unknown comprehension-required CBOR key values 🔥. Also, the initial set of CBOR key values defined in this specification are all of type comprehension-required 👑.

okay so the big CBOR key table is up next, and it's literally the cheat sheet for every DOTS Signal Channel message 🧚💖

   +---------------------+--------------+------+-------------+--------+
   | Parameter Name      | YANG Type    | CBOR | CBOR Major  | JSON   |
   |                     |              | Key  | Type &      | Type   |
   |                     |              |      | Information |        |
   +=====================+==============+======+=============+========+
   | ietf-dots-signal-   | container    | 1    | 5 map       | Object |
   | channel:mitigation- |              |      |             |        |
   | scope               |              |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | scope               | list         | 2    | 4 array     | Array  |
   +---------------------+--------------+------+-------------+--------+
   | cdid                | string       | 3    | 3 text      | String |
   |                     |              |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | cuid                | string       | 4    | 3 text      | String |
   |                     |              |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | mid                 | uint32       | 5    | 0 unsigned  | Number |
   +---------------------+--------------+------+-------------+--------+
   | target-prefix       | leaf-list    | 6    | 4 array     | Array  |
   |                     +--------------+------+-------------+--------+
   |                     | inet:ip-     |      | 3 text      | String |
   |                     | prefix       |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | target-port-range   | list         | 7    | 4 array     | Array  |
   +---------------------+--------------+------+-------------+--------+
   | lower-port          | inet:port-   | 8    | 0 unsigned  | Number |
   |                     | number       |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | upper-port          | inet:port-   | 9    | 0 unsigned  | Number |
   |                     | number       |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | target-protocol     | leaf-list    | 10   | 4 array     | Array  |
   |                     +--------------+------+-------------+--------+
   |                     | uint8        |      | 0 unsigned  | Number |
   +---------------------+--------------+------+-------------+--------+
   | target-fqdn         | leaf-list    | 11   | 4 array     | Array  |
   |                     +--------------+------+-------------+--------+
   |                     | inet:domain- |      | 3 text      | String |
   |                     | name         |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | target-uri          | leaf-list    | 12   | 4 array     | Array  |
   |                     +--------------+------+-------------+--------+
   |                     | inet:uri     |      | 3 text      | String |
   |                     |              |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | alias-name          | leaf-list    | 13   | 4 array     | Array  |
   |                     +--------------+------+-------------+--------+
   |                     | string       |      | 3 text      | String |
   |                     |              |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | lifetime            | int32        | 14   | 0 unsigned  | Number |
   |                     |              |      +-------------+--------+
   |                     |              |      | 1 negative  | Number |
   +---------------------+--------------+------+-------------+--------+
   | mitigation-start    | uint64       | 15   | 0 unsigned  | String |
   +---------------------+--------------+------+-------------+--------+
   | status              | enumeration  | 16   | 0 unsigned  | String |
   +---------------------+--------------+------+-------------+--------+
   | conflict-           | container    | 17   | 5 map       | Object |
   | information         |              |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | conflict-status     | enumeration  | 18   | 0 unsigned  | String |
   +---------------------+--------------+------+-------------+--------+
   | conflict-cause      | enumeration  | 19   | 0 unsigned  | String |
   +---------------------+--------------+------+-------------+--------+
   | retry-timer         | uint32       | 20   | 0 unsigned  | String |
   +---------------------+--------------+------+-------------+--------+
   | conflict-scope      | container    | 21   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | acl-list            | list         | 22   | 4 array     | Array  |
   +---------------------+--------------+------+-------------+--------+
   | acl-name            | leafref      | 23   | 3 text      | String |
   |                     |              |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | acl-type            | leafref      | 24   | 3 text      | String |
   |                     |              |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | bytes-dropped       | yang:zero-   | 25   | 0 unsigned  | String |
   |                     | based-       |      |             |        |
   |                     | counter64    |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | bps-dropped         | yang:gauge64 | 26   | 0 unsigned  | String |
   +---------------------+--------------+------+-------------+--------+
   | pkts-dropped        | yang:zero-   | 27   | 0 unsigned  | String |
   |                     | based-       |      |             |        |
   |                     | counter64    |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | pps-dropped         | yang:gauge64 | 28   | 0 unsigned  | String |
   +---------------------+--------------+------+-------------+--------+
   | attack-status       | enumeration  | 29   | 0 unsigned  | String |
   +---------------------+--------------+------+-------------+--------+
   | ietf-dots-signal-   | container    | 30   | 5 map       | Object |
   | channel:signal-     |              |      |             |        |
   | config              |              |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | sid                 | uint32       | 31   | 0 unsigned  | Number |
   +---------------------+--------------+------+-------------+--------+
   | mitigating-config   | container    | 32   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | heartbeat-interval  | container    | 33   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | max-value           | uint16       | 34   | 0 unsigned  | Number |
   +---------------------+--------------+------+-------------+--------+
   | min-value           | uint16       | 35   | 0 unsigned  | Number |
   +---------------------+--------------+------+-------------+--------+
   | current-value       | uint16       | 36   | 0 unsigned  | Number |
   +---------------------+--------------+------+-------------+--------+
   | missing-hb-allowed  | container    | 37   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | max-retransmit      | container    | 38   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | ack-timeout         | container    | 39   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | ack-random-factor   | container    | 40   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | max-value-decimal   | decimal64    | 41   | 6 tag 4     | String |
   |                     |              |      | [-2,        |        |
   |                     |              |      | integer]    |        |
   +---------------------+--------------+------+-------------+--------+
   | min-value-decimal   | decimal64    | 42   | 6 tag 4     | String |
   |                     |              |      | [-2,        |        |
   |                     |              |      | integer]    |        |
   +---------------------+--------------+------+-------------+--------+
   | current-value-      | decimal64    | 43   | 6 tag 4     | String |
   | decimal             |              |      | [-2,        |        |
   |                     |              |      | integer]    |        |
   +---------------------+--------------+------+-------------+--------+
   | idle-config         | container    | 44   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | trigger-mitigation  | boolean      | 45   | 7 bits 20   | False  |
   |                     |              |      +-------------+--------+
   |                     |              |      | 7 bits 21   | True   |
   +---------------------+--------------+------+-------------+--------+
   | ietf-dots-signal-   | container    | 46   | 5 map       | Object |
   | channel:redirected- |              |      |             |        |
   | signal              |              |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | alt-server          | string       | 47   | 3 text      | String |
   |                     |              |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | alt-server-record   | leaf-list    | 48   | 4 array     | Array  |
   |                     +--------------+------+-------------+--------+
   |                     | inet:ip-     |      | 3 text      | String |
   |                     | address      |      | string      |        |
   +---------------------+--------------+------+-------------+--------+
   | ietf-dots-signal-   | container    | 49   | 5 map       | Object |
   | channel:heartbeat   |              |      |             |        |
   +---------------------+--------------+------+-------------+--------+
   | probing-rate        | container    | 50   | 5 map       | Object |
   +---------------------+--------------+------+-------------+--------+
   | peer-hb-status      | boolean      | 51   | 7 bits 20   | False  |
   |                     |              |      +-------------+--------+
   |                     |              |      | 7 bits 21   | True   |
   +---------------------+--------------+------+-------------+--------+

     Table 5: CBOR Key Values Used in DOTS Signal Channel Messages &
                     Their Mappings to JSON and YANG

7. (D)TLS Protocol Profile and Performance Considerations ✨

7.1. (D)TLS Protocol Profile ✨

Okay bestie, this section sets out the (D)TLS protocol profile for the DOTS signal channel over (D)TLS and the DOTS data channel over TLS 🎀

There are known attacks on (D)TLS, like man-in-the-middle and protocol downgrade attacks 😭 These are general attacks on (D)TLS, so they aren't specific to DOTS over (D)TLS. Check the (D)TLS RFCs for the full discussion of these security issues 🔥 DOTS agents MUST adhere to the (D)TLS implementation recommendations and security considerations of [RFC7525], except with respect to (D)TLS version. Because DOTS signal channel encryption relying upon (D)TLS is basically a greenfield deployment, DOTS agents MUST implement only (D)TLS 1.2 or later 💅

When a DOTS client is configured with a domain name of the DOTS server and connects to that server, the server may present it with a PKIX certificate 🦋 To make sure authentication actually works, a DOTS client MUST verify the entire certification path per [RFC5280]. The DOTS client MUST also use [RFC6125] validation techniques to compare the domain name with the certificate provided. Certification authorities that issue DOTS server certificates SHOULD support the DNS-ID and SRV-ID identifier types. DOTS servers SHOULD prefer DNS-ID and SRV-ID over CN-ID identifier types in certificate requests (as described in Section 2.3 of [RFC6125]), and the wildcard character '*' SHOULD NOT be included in the presented identifier. DOTS doesn't use URI-IDs for server identity verification 🙈

A big challenge with DOTS is provisioning DOTS clients, including getting keying material to them so the DOTS agents can mutually authenticate 🔑 Enrollment over Secure Transport (EST) [RFC7030] is a method of certificate enrollment where domains running DOTS servers can give DOTS clients all the cryptographic keying material they need, including a private key and a certificate, to authenticate themselves 🌸 One option is for DOTS clients to act as EST clients, enrolling with an EST server provisioned by the mitigation provider. This document doesn't specify which EST or other mechanism the DOTS client uses for initial enrollment.

The Server Name Indication (SNI) extension [RFC6066] defines a way for a client to tell a (D)TLS server the name of the server it wants to reach 🧚 This is super useful in hosting environments where lots of virtual servers sit behind a single IP address. A DOTS client might not know whether it's talking to a DOTS server in a virtual hosting setup, so the DOTS client SHOULD include the DOTS server FQDN in the SNI extension 💜

Implementations compliant with this profile MUST implement all of the following items:

  • DTLS record replay detection (Section 3.3 of [RFC6347]) or an equivalent mechanism to protect against replay attacks.
  • DTLS session resumption without server-side state to resume the session and convey the DOTS signal.
  • At least one of raw public keys [RFC7250] or PSK handshake [RFC4279] with (EC)DHE key exchange. This shrinks the size of the ServerHello, and DOTS agents that can't obtain certificates can use it too 🌈

Implementations compliant with this profile SHOULD implement all of the following items to cut down the delay before a DOTS signal channel message gets delivered ⚡

  • TLS False Start [RFC7918], which saves round-trips by letting the TLS client's second flight of messages (ChangeCipherSpec) also carry the DOTS signal. TLS False Start is formally defined for TLS, but the same technique works for DTLS too 🫶
  • Cached Information Extension [RFC7924], which skips sending the server's certificate and certificate chain if the client already cached that info from a previous TLS handshake 🧠

Compared to UDP, DOTS signal channel over TCP needs an extra round-trip time (RTT) of latency to set up the TCP connection 😩 DOTS implementations are encouraged to implement TCP Fast Open [RFC7413] to get rid of that RTT 👑

7.2. (D)TLS 1.3 Considerations 🌷

TLS 1.3 brings critical latency improvements for connection establishment over TLS 1.2 ✨ The DTLS 1.3 protocol [DTLS] is based on the TLS 1.3 protocol and gives equivalent security guarantees 🔐 (D)TLS 1.3 offers two basic handshake modes that the DOTS signal channel can take advantage of:

  • A full handshake mode, where a DOTS client can send a DOTS mitigation request message after one round trip, and the DOTS server immediately responds with a DOTS mitigation response. This assumes no packet loss is experienced.
  • 0-RTT mode, where the DOTS client can authenticate itself and send DOTS mitigation request messages in the first message, which cuts handshake latency. 0-RTT only works if the DOTS client has previously talked to that DOTS server, which is very likely with the DOTS signal channel 🚀

The DOTS client has to establish a (D)TLS session with the DOTS server during 'idle' time and share a PSK 🍓

During a DDoS attack, the DOTS client can use the (D)TLS session to convey the DOTS mitigation request message. If there's no response from the server after multiple retries, the DOTS client can resume the (D)TLS session in 0-RTT mode using the PSK 🙌

DOTS servers that support (D)TLS 1.3 MAY allow DOTS clients to send early data (0-RTT). DOTS clients MUST NOT send "CoAP Ping" as early data, and such messages MUST be rejected by DOTS servers 🚫 Section 8 of [RFC8446] discusses mechanisms to implement in order to limit the impact of replay attacks on 0-RTT data. If the DOTS server accepts 0-RTT, it MUST implement one of these mechanisms to prevent replay at the TLS layer 🛡️ A DOTS server can reject 0-RTT by sending a TLS HelloRetryRequest.

The DOTS signal channel messages that the DOTS client sends as early data are idempotent requests 💖 As a reminder, the Message ID (Section 3 of [RFC7252]) changes each time a new CoAP request is sent, and the Token (Section 5.3.1 of [RFC7252]) is randomized in each CoAP request. The DOTS server(s) MUST use the Message ID and the Token in the DOTS signal channel message to detect replay of early data at the application layer, and accept 0-RTT data at most once from the same DOTS client 🔁 This anti-replay defense requires sharing the Message ID and the Token in the 0-RTT data between DOTS servers in the DOTS server domain. DOTS servers don't rely on transport coordinates to identify DOTS peers. As specified in Section 4.4.1, DOTS servers couple the DOTS signal channel sessions using the DOTS client identity and optionally the 'cdid' parameter value. The 'mid' value is monotonically increased by the DOTS client for each mitigation request, so attackers that replay mitigation requests with lower numeric 'mid' values and overlapping scopes with mitigation requests having higher numeric 'mid' values will be rejected systematically by the DOTS server 🙅‍♀️ Likewise, the 'sid' value is monotonically increased by the DOTS client for each configuration request (Section 4.5.2). Attackers replaying configuration requests with lower numeric 'sid' values will be rejected by the DOTS server if it keeps a higher numeric 'sid' value for this DOTS client 💅

Thanks to these protections, all DOTS signal channel requests are safe to transmit in TLS 1.3 as early data 🥰 Refer to [DOTS-EARLYDATA] for more details.

Here's a simplified TLS 1.3 handshake with a 0-RTT DOTS mitigation request message exchange, shown in Figure 29 📊

    DOTS Client                                    DOTS Server

    ClientHello
    (0-RTT DOTS signal message)
                              -------->
                                                    ServerHello
                                          {EncryptedExtensions}
                                                     {Finished}
                              <--------   [DOTS signal message]
    (end_of_early_data)
    {Finished}                -------->
    [DOTS signal message]     <------->   [DOTS signal message]

Note that:
    () Indicates messages protected 0-RTT keys
    {} Indicates messages protected using handshake keys
    [] Indicates messages protected using 1-RTT keys

         Figure 29: A Simplified TLS 1.3 Handshake with 0-RTT

7.3. DTLS MTU and Fragmentation 📦

To avoid DOTS signal message fragmentation and the decreased chance of delivery that comes with it, DOTS agents MUST ensure that the DTLS record fits within a single datagram 🎯 As a reminder, DTLS only handles fragmentation and reassembly for handshake messages, not for application data (Section 4.1.1 of [RFC6347]). If the path MTU (PMTU) can't be discovered, DOTS agents MUST assume a PMTU of 1280 bytes, since IPv6 requires every link in the Internet to have an MTU of 1280 octets or greater, as specified in [RFC8200] 🌐 If IPv4 support on legacy or otherwise unusual networks is a consideration and the PMTU is unknown, DOTS implementations MAY assume a PMTU of 576 bytes for IPv4 datagrams. Every IPv4 host must be able to receive a packet whose length is equal to 576 bytes, as discussed in [RFC0791] and [RFC1122] 🐣

The DOTS client needs to account for the record expansion that DTLS processing adds when it calculates the size of the CoAP message that fits within the PMTU 🧮 The PMTU MUST be greater than or equal to [CoAP message size + DTLS 1.2 overhead of 13 octets + authentication overhead of the negotiated DTLS cipher suite + block padding] (Section 4.1.1.1 of [RFC6347]). If the total request size exceeds the PMTU, the DOTS client MUST split the DOTS signal into separate messages. For example, the list of addresses in the 'target-prefix' parameter could be split into multiple lists, and each list conveyed in a new PUT request 🧩

Implementation Note: DOTS choice of message size parameters works well with IPv6 and with most of today's IPv4 paths. However, with IPv4, it's harder to safely make sure there is no IP fragmentation. If the IPv4 PMTU is unknown, implementations may want to limit themselves to more conservative IPv4 datagram sizes, such as 576 bytes, per [RFC0791] 🌟

8. Mutual Authentication of DOTS Agents & Authorization of DOTS Clients ✨

Okay so (D)TLS with client certificates can be used for mutual authentication between DOTS agents 🔐. If there's a DOTS gateway involved, DOTS clients and DOTS gateways MUST perform mutual authentication, and only authorized DOTS clients are allowed to send DOTS signals to a DOTS gateway 💅. The DOTS gateway and the DOTS server MUST perform mutual authentication too, so a DOTS server only accepts DOTS signal channel messages from an authorized DOTS gateway. That makes a two-link chain of transitive authentication between the DOTS client and the DOTS server 🔗 iconic behaviour, honestly.

The DOTS server SHOULD support certificate-based client authentication 🫶. The DOTS client SHOULD respond to the DOTS server's TLS CertificateRequest message with the PKIX certificate it holds. DOTS client certificate validation MUST be performed per [RFC5280], and the DOTS client certificate MUST conform to the [RFC5280] certificate profile. If a DOTS client doesn't support TLS client certificate authentication, it MUST support client authentication based on pre-shared key or raw public key 🙈.

+---------------------------------------------+
|       example.com domain       +---------+  |
|                                | AAA     |  |
| +---------------+              | Server  |  |
| | Application   |              +------+--+  |
| | server        +<---------------+    ^     |
| | (DOTS client) |                |    |     |
| +---------------+                |    |     |
|                                  V    V     |   example.net domain
|                            +-----+----+--+  |    +---------------+
| +--------------+           |             |  |    |               |
| |   Guest      +<----x---->+    DOTS     +<----->+    DOTS       |
| | (DOTS client)|           |    gateway  |  |    |    server     |
| +--------------+           |             |  |    |               |
|                            +----+--------+  |    +---------------+
|                                 ^           |
|                                 |           |
| +----------------+              |           |
| | DDoS detector  |              |           |
| | (DOTS client)  +<-------------+           |
| +----------------+                          |
+---------------------------------------------+

Figure 30: Example of Authentication and Authorization of DOTS Agents

In the example in Figure 30, the DOTS gateway and the DOTS clients inside 'example.com' mutually authenticate 🤝. Once the gateway has validated a DOTS client's identity, it checks with the AAA server in the 'example.com' domain to see whether that client is authorized to request DDoS mitigation. If the DOTS client isn't authorized, a 4.01 (Unauthorized) comes back in the response to it 🚫. In this example, the DOTS gateway only lets the application server and the DDoS attack detector request DDoS mitigation, while the user of type 'guest' is not allowed to ask for it. Not me denying the guest 💀

DOTS gateways and servers located in different domains MUST perform mutual authentication (e.g., using certificates). A DOTS server will only allow a DOTS gateway with a certificate for a particular domain to request mitigation for that domain. Back to Figure 30: the DOTS server only lets the DOTS gateway request mitigation for 'example.com' and not for other domains 🌸 boundaries, bestie.


9. IANA Considerations 🎀

9.1. DOTS Signal Channel UDP and TCP Port Number 🔌

IANA has assigned the port number 4646 (the ASCII decimal value for ".." (DOTS)) to the DOTS signal channel protocol for both UDP and TCP, in the "Service Name and Transport Protocol Port Number Registry" available at https://www.iana.org/assignments/service-names-port-numbers/.

   Service Name:  dots-signal
   Port Number:  4646
   Transport Protocol:  TCP
   Description:  Distributed Denial-of-Service Open Threat Signaling
      (DOTS) Signal Channel
   Assignee:  IESG
   Contact:  IETF Chair
   Registration Date:  2020-01-16
   Reference:  [RFC8782]

   Service Name:  dots-signal
   Port Number:  4646
   Transport Protocol:  UDP
   Description:  Distributed Denial-of-Service Open Threat Signaling
      (DOTS) Signal Channel
   Assignee:  IESG
   Contact:  IETF Chair
   Registration Date:  2020-01-16
   Reference:  [RFC8782]

9.2. Well-Known 'dots' URI 🌈

IANA has registered the 'dots' well-known URI (Table 6) in the Well-Known URIs registry at https://www.iana.org/assignments/well-known-uris/well-known-uris.xhtml, as defined by [RFC8615]:

+------------+------------+-----------+-----------+-------------+
| URI Suffix | Change     | Reference | Status    | Related     |
|            | Controller |           |           | information |
+============+============+===========+===========+=============+
| dots       | IETF       | [RFC8782] | permanent | None        |
+------------+------------+-----------+-----------+-------------+

Table 6: 'dots' Well-Known URI

9.3. Media Type Registration 📨

IANA has registered the "application/dots+cbor" media type in the "Media Types" registry [IANA-MediaTypes], in the manner described in [RFC6838]. It can be used to indicate that the content is a DOTS signal channel object 💖

Type name: application

Subtype name: dots+cbor

Required parameters: N/A

Optional parameters: N/A

Encoding considerations: binary

Security considerations: See the Security Considerations section of
[RFC8782].

Interoperability considerations: N/A

Published specification: [RFC8782]

Applications that use this media type: DOTS agents sending DOTS
messages over CoAP over (D)TLS.

Fragment identifier considerations: N/A

Additional information:

   Deprecated alias names for this type: N/A
   Magic number(s): N/A
   File extension(s): N/A
   Macintosh file type code(s): N/A

Person & email address to contact for further information: IESG,
iesg@ietf.org

Intended usage: COMMON

Restrictions on usage: none

Author: See Authors' Addresses section.

Change controller: IESG

Provisional registration?  No

9.4. CoAP Content-Formats Registration 🧚

IANA has registered the CoAP Content-Format ID for the "application/dots+cbor" media type in the "CoAP Content-Formats" registry [IANA-CoAP-Content-Formats]:

  • Media Type: application/dots+cbor
  • Encoding: -
  • ID: 271
  • Reference: [RFC8782]

9.5. CBOR Tag Registration 🏷️

This section defines the DOTS CBOR tag as another means for applications to declare that a CBOR data structure is a DOTS signal channel object. Its use is optional and is intended for use in cases in which this information would not otherwise be known. The DOTS CBOR tag is not required for the DOTS signal channel protocol version specified in this document. If present, the DOTS tag MUST prefix a DOTS signal channel object.

IANA has registered the DOTS signal channel CBOR tag in the "CBOR Tags" registry [IANA-CBOR-Tags]:

  • Tag: 271
  • Data Item: DDoS Open Threat Signaling (DOTS) signal channel object
  • Semantics: DDoS Open Threat Signaling (DOTS) signal channel object, as defined in [RFC8782]
  • Reference: [RFC8782]

9.6. DOTS Signal Channel Protocol Registry 🗂️

IANA has created a new registry titled the "Distributed Denial-of-Service Open Threat Signaling (DOTS) Signal Channel" registry. The following sections define subregistries.

9.6.1. DOTS Signal Channel CBOR Key Values Subregistry 🔑

IANA has created a new subregistry titled "DOTS Signal Channel CBOR Key Values".

The structure of this subregistry is provided in Section 9.6.1.1. Section 9.6.1.2 provides the registry as initially populated with the values in Table 7.

9.6.1.1. Registration Template 📝

Parameter name: Parameter name as used in the DOTS signal channel.

CBOR Key Value: Key value for the parameter. The key value MUST be an integer in the 1-65535 range. The key values of the comprehension-required range (0x0001 - 0x3FFF) and of the comprehension-optional range (0x8000 - 0xBFFF) are assigned by IETF Review (Section 4.8 of [RFC8126]). The key values of the comprehension-optional range (0x4000 - 0x7FFF) are assigned by Specification Required (Section 4.6 of [RFC8126]) and of the comprehension-optional range (0xC000 - 0xFFFF) are reserved for Private Use (Section 4.1 of [RFC8126]).

Registration requests for the 0x4000 - 0x7FFF range are evaluated after a three-week review period on the dots-signal-reg-review@ietf.org mailing list, on the advice of one or more Designated Experts. However, to allow for the allocation of values prior to publication, the Designated Experts may approve registration once they are satisfied that such a specification will be published. New registration requests should be sent in the form of an email to the review mailing list; the request should use an appropriate subject (e.g., "Request to register CBOR Key Value for DOTS: example"). IANA will only accept new registrations from the Designated Experts, and it will check that review was requested on the mailing list in accordance with these procedures.

Within the review period, the Designated Experts will either approve or deny the registration request, communicating this decision to the review list and IANA. Denials should include an explanation and, if applicable, suggestions as to how to make the request successful. Registration requests that are undetermined for a period longer than 21 days can be brought to the IESG's attention (using the iesg@ietf.org mailing list) for resolution.

Criteria that should be applied by the Designated Experts include determining whether the proposed registration duplicates existing functionality, whether it is likely to be of general applicability or whether it is useful only for a single use case, and whether the registration description is clear. IANA must only accept registry updates to the 0x4000 - 0x7FFF range from the Designated Experts and should direct all requests for registration to the review mailing list. It is suggested that multiple Designated Experts be appointed. In cases where a registration decision could be perceived as creating a conflict of interest for a particular Expert, that Expert should defer to the judgment of the other Experts.

CBOR Major Type: CBOR Major type and optional tag for the parameter.

Change Controller: For Standards Track RFCs, list the "IESG". For others, give the name of the responsible party. Other details (e.g., email address) may also be included.

Specification Document(s): Reference to the document or documents that specify the parameter, preferably including URIs that can be used to retrieve copies of the documents. An indication of the relevant sections may also be included but is not required.

9.6.1.2. Initial Subregistry Content ✨

okay so this is the starter pack for the CBOR Key Values subregistry 🎀 every row gets its own key value, CBOR major type, and change controller, and every single one points back to [RFC8782] as its spec doc. the change controller is IESG for all of them, so nobody else is adding or touching these. the table is kept exactly as-is below, cause the formatting matters 💅

   +---------------------+------------+-----+----------+---------------+
   | Parameter Name      | CBOR Key   |CBOR | Change   | Specification |
   |                     | Value      |Major|Controller| Document(s)   |
   |                     |            |Type |          |               |
   +=====================+============+=====+==========+===============+
   | Reserved            | 0          |     |          | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | ietf-dots-signal-   | 1          | 5   | IESG     | [RFC8782]     |
   | channel:mitigation- |            |     |          |               |
   | scope               |            |     |          |               |
   +---------------------+------------+-----+----------+---------------+
   | scope               | 2          | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | cdid                | 3          | 3   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | cuid                | 4          | 3   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | mid                 | 5          | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | target-prefix       | 6          | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | target-port-range   | 7          | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | lower-port          | 8          | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | upper-port          | 9          | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | target-protocol     | 10         | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | target-fqdn         | 11         | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | target-uri          | 12         | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | alias-name          | 13         | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | lifetime            | 14         | 0/1 | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | mitigation-start    | 15         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | status              | 16         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   |conflict-information | 17         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | conflict-status     | 18         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | conflict-cause      | 19         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | retry-timer         | 20         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | conflict-scope      | 21         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | acl-list            | 22         | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | acl-name            | 23         | 3   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | acl-type            | 24         | 3   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | bytes-dropped       | 25         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | bps-dropped         | 26         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | pkts-dropped        | 27         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | pps-dropped         | 28         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | attack-status       | 29         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | ietf-dots-signal-   | 30         | 5   | IESG     | [RFC8782]     |
   |channel:signal-config|            |     |          |               |
   +---------------------+------------+-----+----------+---------------+
   | sid                 | 31         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | mitigating-config   | 32         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | heartbeat-interval  | 33         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | min-value           | 34         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | max-value           | 35         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | current-value       | 36         | 0   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | missing-hb-allowed  | 37         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | max-retransmit      | 38         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | ack-timeout         | 39         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | ack-random-factor   | 40         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | min-value-decimal   | 41         |6tag4| IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | max-value-decimal   | 42         |6tag4| IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   |current-value-decimal| 43         |6tag4| IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | idle-config         | 44         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | trigger-mitigation  | 45         | 7   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | ietf-dots-signal-   | 46         | 5   | IESG     | [RFC8782]     |
   | channel:redirected- |            |     |          |               |
   | signal              |            |     |          |               |
   +---------------------+------------+-----+----------+---------------+
   | alt-server          | 47         | 3   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | alt-server-record   | 48         | 4   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | ietf-dots-signal-   | 49         | 5   | IESG     | [RFC8782]     |
   | channel:heartbeat   |            |     |          |               |
   +---------------------+------------+-----+----------+---------------+
   | probing-rate        | 50         | 5   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | peer-hb-status      | 51         | 7   | IESG     | [RFC8782]     |
   +---------------------+------------+-----+----------+---------------+
   | Unassigned          | 52-49151   |     |          |               |
   +---------------------+------------+-----+----------+---------------+
   |Reserved for Private |49152-65535 |     |          | [RFC8782]     |
   | Use                 |            |     |          |               |
   +---------------------+------------+-----+----------+---------------+

       Table 7: Initial DOTS Signal Channel CBOR Key Values Registry

that's the whole starting registry 🧚💜 ok the big thing to notice is that key values 52-49151 are just sitting there unassigned, and 49152-65535 is reserved for private use, so the upper chunk is the private-use zone 🌈

9.6.2. Status Codes Subregistry ✨

okay so IANA made a brand new subregistry called "DOTS Signal Channel Status Codes" 🎀 These codes are the valid values you can put in the status parameter, so they're basically the vibe check for where a mitigation request is at 💅

It comes pre-loaded with these values 🦋

+--------------+---------------+----------------------+-----------+
|         Code | Label         | Description          | Reference |
+==============+===============+======================+===========+
|            0 | Reserved      |                      | [RFC8782] |
+--------------+---------------+----------------------+-----------+
|            1 | attack-       | Attack mitigation    | [RFC8782] |
|              | mitigation-   | setup is in progress |           |
|              | in-progress   | (e.g., changing the  |           |
|              |               | network path to      |           |
|              |               | redirect the inbound |           |
|              |               | traffic to a DOTS    |           |
|              |               | mitigator).          |           |
+--------------+---------------+----------------------+-----------+
|            2 | attack-       | Attack is being      | [RFC8782] |
|              | successfully- | successfully         |           |
|              | mitigated     | mitigated (e.g.,     |           |
|              |               | traffic is           |           |
|              |               | redirected to a DDoS |           |
|              |               | mitigator and attack |           |
|              |               | traffic is dropped). |           |
+--------------+---------------+----------------------+-----------+
|            3 | attack-       | Attack has stopped   | [RFC8782] |
|              | stopped       | and the DOTS client  |           |
|              |               | can withdraw the     |           |
|              |               | mitigation request.  |           |
+--------------+---------------+----------------------+-----------+
|            4 | attack-       | Attack has exceeded  | [RFC8782] |
|              | exceeded-     | the mitigation       |           |
|              | capability    | provider capability. |           |
+--------------+---------------+----------------------+-----------+
|            5 | dots-client-  | DOTS client has      | [RFC8782] |
|              | withdrawn-    | withdrawn the        |           |
|              | mitigation    | mitigation request   |           |
|              |               | and the mitigation   |           |
|              |               | is active but        |           |
|              |               | terminating.         |           |
+--------------+---------------+----------------------+-----------+
|            6 | attack-       | Attack mitigation is | [RFC8782] |
|              | mitigation-   | now terminated.      |           |
|              | terminated    |                      |           |
+--------------+---------------+----------------------+-----------+
|            7 | attack-       | Attack mitigation is | [RFC8782] |
|              | mitigation-   | withdrawn.           |           |
|              | withdrawn     |                      |           |
+--------------+---------------+----------------------+-----------+
|            8 | attack-       | Attack mitigation    | [RFC8782] |
|              | mitigation-   | will be triggered    |           |
|              | signal-loss   | for the mitigation   |           |
|              |               | request only when    |           |
|              |               | the DOTS signal      |           |
|              |               | channel session is   |           |
|              |               | lost.                |           |
+--------------+---------------+----------------------+-----------+
| 9-2147483647 | Unassigned    |                      |           |
+--------------+---------------+----------------------+-----------+

         Table 8: Initial DOTS Signal Channel Status Codes

So basically the codes go from "setup in progress" 🛠️ to "attack is being successfully mitigated" 🛡️ to "attack stopped, client can withdraw" 🙌, and then there's the sad-but-necessary "attack exceeded capability" 😭 Code 8 is the one I'm obsessed with: mitigation only kicks in if the signal channel session is lost 🫶

New codes can be assigned via Standards Action [RFC8126]. 💜


9.6.3. Conflict Status Codes Subregistry 🌸

IANA also created a subregistry called "DOTS Signal Channel Conflict Status Codes" 🧚 These are the valid values for the conflict-status parameter.

Here's what it starts with 🍓

+--------------+-------------------+--------------------+-----------+
|         Code | Label             | Description        | Reference |
+==============+===================+====================+===========+
|            0 | Reserved          |                    | [RFC8782] |
+--------------+-------------------+--------------------+-----------+
|            1 | request-inactive- | DOTS server        | [RFC8782] |
|              | other-active      | has detected       |           |
|              |                   | conflicting        |           |
|              |                   | mitigation         |           |
|              |                   | requests from      |           |
|              |                   | different DOTS     |           |
|              |                   | clients.  This     |           |
|              |                   | mitigation         |           |
|              |                   | request is         |           |
|              |                   | currently          |           |
|              |                   | inactive until     |           |
|              |                   | the conflicts      |           |
|              |                   | are resolved.      |           |
|              |                   | Another            |           |
|              |                   | mitigation         |           |
|              |                   | request is         |           |
|              |                   | active.            |           |
+--------------+-------------------+--------------------+-----------+
|            2 | request-active    | DOTS server        | [RFC8782] |
|              |                   | has detected       |           |
|              |                   | conflicting        |           |
|              |                   | mitigation         |           |
|              |                   | requests from      |           |
|              |                   | different DOTS     |           |
|              |                   | clients.  This     |           |
|              |                   | mitigation         |           |
|              |                   | request is         |           |
|              |                   | currently          |           |
|              |                   | active.            |           |
+--------------+-------------------+--------------------+-----------+
|            3 | all-requests-     | DOTS server        | [RFC8782] |
|              | inactive          | has detected       |           |
|              |                   | conflicting        |           |
|              |                   | mitigation         |           |
|              |                   | requests from      |           |
|              |                   | different DOTS     |           |
|              |                   | clients.  All      |           |
|              |                   | conflicting        |           |
|              |                   | mitigation         |           |
|              |                   | requests are       |           |
|              |                   | inactive.          |           |
+--------------+-------------------+--------------------+-----------+
| 4-2147483647 | Unassigned        |                    |           |
+--------------+-------------------+--------------------+-----------+

         Table 9: Initial DOTS Signal Channel Conflict Status Codes

These are all about the server spotting conflicting mitigation requests from different DOTS clients 👀 Code 1 means this request is parked (inactive) until things get sorted and another request is the active one 💅 Code 2 means this one's the active one, and code 3 means everybody's inactive 💀

New codes can be assigned via Standards Action [RFC8126]. ✨


9.6.4. Conflict Cause Codes Subregistry 🦋

Last one, promise 🫶 IANA made a subregistry called "DOTS Signal Channel Conflict Cause Codes", and these are the valid values for the conflict-cause parameter 🌈

Here's the starter pack 🎀

+--------------+---------------------+----------------+-----------+
|         Code | Label               | Description    | Reference |
+==============+=====================+================+===========+
|            0 | Reserved            |                | [RFC8782] |
+--------------+---------------------+----------------+-----------+
|            1 | overlapping-targets | Overlapping    | [RFC8782] |
|              |                     | targets.       |           |
+--------------+---------------------+----------------+-----------+
|            2 | conflict-with-      | Conflicts with | [RFC8782] |
|              | acceptlist          | an existing    |           |
|              |                     | accept-list.   |           |
|              |                     | This code is   |           |
|              |                     | returned when  |           |
|              |                     | the DDoS       |           |
|              |                     | mitigation     |           |
|              |                     | detects source |           |
|              |                     | addresses/     |           |
|              |                     | prefixes in    |           |
|              |                     | the accept-    |           |
|              |                     | listed ACLs    |           |
|              |                     | are attacking  |           |
|              |                     | the target.    |           |
+--------------+---------------------+----------------+-----------+
|            3 | cuid-collision      | CUID           | [RFC8782] |
|              |                     | Collision.     |           |
|              |                     | This code is   |           |
|              |                     | returned when  |           |
|              |                     | a DOTS client  |           |
|              |                     | uses a 'cuid'  |           |
|              |                     | that is        |           |
|              |                     | already used   |           |
|              |                     | by another     |           |
|              |                     | DOTS client.   |           |
+--------------+---------------------+----------------+-----------+
| 4-2147483647 | Unassigned          |                |           |
+--------------+---------------------+----------------+-----------+

         Table 10: Initial DOTS Signal Channel Conflict Cause Codes

So the cause codes explain why there's a conflict 🔍 Code 1 is overlapping targets, code 2 is when the DDoS mitigation spots attacking source addresses or prefixes that are on an accept-list (iconic plot twist 😭), and code 3 is a CUID collision, which happens when a DOTS client uses a cuid that another DOTS client is already using 🙈

New codes can be assigned via Standards Action [RFC8126]. 👑

9.6.5. Attack Status Codes Subregistry 🦋

okay so IANA made a brand new subregistry called "DOTS Signal Channel Attack Status Codes" 💖 The codes in here are the valid values for the attack-status parameter, so this is the official home for every attack-status value 💅

The registry starts out with these values:

+--------------+----------------------+-----------------+-----------+
|         Code | Label                | Description     | Reference |
+==============+======================+=================+===========+
|            0 | Reserved             |                 | [RFC8782] |
+--------------+----------------------+-----------------+-----------+
|            1 | under-attack         | The DOTS        | [RFC8782] |
|              |                      | client          |           |
|              |                      | determines      |           |
|              |                      | that it is      |           |
|              |                      | still under     |           |
|              |                      | attack.         |           |
+--------------+----------------------+-----------------+-----------+
|            2 | attack-successfully- | The DOTS        | [RFC8782] |
|              | mitigated            | client          |           |
|              |                      | determines      |           |
|              |                      | that the        |           |
|              |                      | attack is       |           |
|              |                      | successfully    |           |
|              |                      | mitigated.      |           |
+--------------+----------------------+-----------------+-----------+
| 3-2147483647 | Unassigned           |                 |           |
+--------------+----------------------+-----------------+-----------+

Table 11: Initial DOTS Signal Channel Attack Status Codes

New codes can be assigned via Standards Action [RFC8126]. ✨

9.7. DOTS Signal Channel YANG Modules 🌈

IANA registered the following URIs in the "ns" subregistry within the "IETF XML Registry" [RFC3688]. 🧚

URI:  urn:ietf:params:xml:ns:yang:ietf-dots-signal-channel
Registrant Contact:  The IESG.
XML:  N/A; the requested URI is an XML namespace.

URI:  urn:ietf:params:xml:ns:yang:iana-dots-signal-channel
Registrant Contact:  IANA.
XML:  N/A; the requested URI is an XML namespace.

IANA also registered the following YANG modules in the "YANG Module Names" subregistry [RFC7950] within the "YANG Parameters" registry. 💜

Name:  ietf-dots-signal-channel
Maintained by IANA:  N
Namespace:  urn:ietf:params:xml:ns:yang:ietf-dots-signal-channel
Prefix:  signal
Reference:  RFC8782

Name:  iana-dots-signal-channel
Maintained by IANA:  Y
Namespace:  urn:ietf:params:xml:ns:yang:iana-dots-signal-channel
Prefix:  iana-signal
Reference:  RFC8782

This document defines the initial version of the IANA-maintained iana-dots-signal-channel YANG module. IANA added this note, and it is serious business 🫶

Status, conflict status, conflict cause, and attack status values
must not be directly added to the iana-dots-signal-channel YANG
module.  They must instead be respectively added to the "DOTS
Status Codes", "DOTS Conflict Status Codes", "DOTS Conflict Cause
Codes", and "DOTS Attack Status Codes" registries.

When a 'status', 'conflict-status', 'conflict-cause', or 'attack-status' value gets added to the "DOTS Status Codes", "DOTS Conflict Status Codes", "DOTS Conflict Cause Codes", or "DOTS Attack Status Codes" registry, a new "enum" statement must be added to the iana-dots-signal-channel YANG module. The following "enum" statement, and its substatements, should be defined:

  • "enum": Replicates the label from the registry.
  • "value": Contains the IANA-assigned value corresponding to the 'status', 'conflict-status', 'conflict-cause', or 'attack-status'.
  • "description": Replicates the description from the registry.
  • "reference": Replicates the reference from the registry and adds the title of the document.

When the iana-dots-signal-channel YANG module is updated, a new "revision" statement must be added in front of the existing revision statements. 📝

IANA added this note to the "DOTS Status Codes", "DOTS Conflict Status Codes", "DOTS Conflict Cause Codes", and "DOTS Attack Status Codes" registries, and it's giving very important vibes:

When this registry is modified, the YANG module iana-dots-signal-
channel must be updated as defined in [RFC8782].

10. Security Considerations 🔥

okay this section is the one you don't skip, bestie 🚨 High-level DOTS security considerations are documented in [RFC8612] and [DOTS-ARCH]. 🧐

Authenticated encryption MUST be used for data confidentiality and message integrity. 🔐 The interaction between the DOTS agents requires Datagram Transport Layer Security (DTLS) or Transport Layer Security (TLS) with a cipher suite offering confidentiality protection, and the guidance given in [RFC7525] MUST be followed to avoid attacks on (D)TLS. The (D)TLS protocol profile used for the DOTS signal channel is specified in Section 7. 🎀

If TCP is used between DOTS agents, an attacker may be able to inject RST packets, bogus application segments, etc., regardless of whether TLS authentication is used. 😭 Because the application data is TLS protected, this will not result in the application receiving bogus data, but it will constitute a DoS on the connection. This attack can be countered by using TCP Authentication Option (TCP-AO) [RFC5925]. Although not widely adopted, if TCP-AO is used, then any bogus packets injected by an attacker will be rejected by the TCP-AO integrity check and therefore will never reach the TLS layer. 🛡️

If the 'cuid' is guessable, a misbehaving DOTS client from within the client's domain can use the 'cuid' of another DOTS client of the domain to delete or alter active mitigations. 💀 For this attack vector to happen, the misbehaving client needs to pass the security validation checks by the DOTS server, and eventually the checks of a client-domain DOTS gateway.

A similar attack can be achieved by a compromised DOTS client that can sniff the TLS 1.2 handshake, use the client certificate to identify the 'cuid' used by another DOTS client. This attack is not possible if algorithms such as version 4 Universally Unique IDentifiers (UUIDs) in Section 4.4 of [RFC4122] are used to generate the 'cuid', because such UUIDs are not a deterministic function of the client certificate. Likewise, this attack is not possible with TLS 1.3 because most of the TLS handshake is encrypted and the client certificate is not visible to eavesdroppers. 🙈

A compromised DOTS client can collude with a DDoS attacker to send mitigation request for a target resource, get the mitigation efficacy from the DOTS server, and convey the mitigation efficacy to the DDoS attacker to possibly change the DDoS attack strategy. Obviously, signaling an attack by the compromised DOTS client to the DOTS server will trigger attack mitigation. This attack can be prevented by monitoring and auditing DOTS clients to detect misbehavior and to deter misuse, and by only authorizing the DOTS client to request mitigation for specific target resources (e.g., an application server is authorized to request mitigation for its IP addresses, but a DDoS mitigator can request mitigation for any target resource in the network). Furthermore, DOTS clients are typically co-located on network security services (e.g., firewall), and a compromised security service potentially can do a lot more damage to the network. 👑

Rate-limiting DOTS requests, including those with new 'cuid' values, from the same DOTS client defend against DoS attacks that would result in varying the 'cuid' to exhaust DOTS server resources. Rate-limit policies SHOULD be enforced on DOTS gateways (if deployed) and DOTS servers. 🚦

In order to prevent leaking internal information outside a client's domain, DOTS gateways located in the client domain SHOULD NOT reveal the identification information that pertains to internal DOTS clients (e.g., source IP address, client's hostname) unless explicitly configured to do so. 🤐

DOTS servers MUST verify that requesting DOTS clients are entitled to trigger actions on a given IP prefix. That is, only actions on IP resources that belong to the DOTS client's domain MUST be authorized by a DOTS server. The exact mechanism for the DOTS servers to validate that the target prefixes are within the scope of the DOTS client domain is deployment specific. 🫡

The presence of DOTS gateways may lead to infinite forwarding loops, which is undesirable. 🌀 To prevent and detect such loops, this document uses the Hop-Limit option. ♾️

When FQDNs are used as targets, the DOTS server MUST rely upon DNS privacy-enabling protocols (e.g., DNS over TLS [RFC7858] or DNS over HTTPS (DoH) [RFC8484]) to prevent eavesdroppers from possibly identifying the target resources protected by the DDoS mitigation service, to ensure the target FQDN resolution is authentic (e.g., DNSSEC [RFC4034]). 🕵️‍♀️

CoAP-specific security considerations are discussed in Section 11 of [RFC7252], while CBOR-related security considerations are discussed in Section 8 of [RFC7049]. 🌸

11. References 📚

11.1. Normative References ✨

bestie, these are the docs this spec leans on so hard that you can't really read it without them 💅📚

[RFC0791] Postel, J., "Internet Protocol", STD 5, RFC 791, DOI 10.17487/RFC0791, September 1981, <https://www.rfc-editor.org/info/rfc791>.

[RFC1122] Braden, R., Ed., "Requirements for Internet Hosts - Communication Layers", STD 3, RFC 1122, DOI 10.17487/RFC1122, October 1989, <https://www.rfc-editor.org/info/rfc1122>.

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC3688] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, DOI 10.17487/RFC3688, January 2004, <https://www.rfc-editor.org/info/rfc3688>.

[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC 3986, DOI 10.17487/RFC3986, January 2005, <https://www.rfc-editor.org/info/rfc3986>.

[RFC4279] Eronen, P., Ed. and H. Tschofenig, Ed., "Pre-Shared Key Ciphersuites for Transport Layer Security (TLS)", RFC 4279, DOI 10.17487/RFC4279, December 2005, <https://www.rfc-editor.org/info/rfc4279>.

[RFC4632] Fuller, V. and T. Li, "Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan", BCP 122, RFC 4632, DOI 10.17487/RFC4632, August 2006, <https://www.rfc-editor.org/info/rfc4632>.

[RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, <https://www.rfc-editor.org/info/rfc4648>.

[RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, DOI 10.17487/RFC5246, August 2008, <https://www.rfc-editor.org/info/rfc5246>.

[RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, R., and W. Polk, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008, <https://www.rfc-editor.org/info/rfc5280>.

[RFC6066] Eastlake 3rd, D., "Transport Layer Security (TLS) Extensions: Extension Definitions", RFC 6066, DOI 10.17487/RFC6066, January 2011, <https://www.rfc-editor.org/info/rfc6066>.

[RFC6125] Saint-Andre, P. and J. Hodges, "Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS)", RFC 6125, DOI 10.17487/RFC6125, March 2011, <https://www.rfc-editor.org/info/rfc6125>.

[RFC6347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer Security Version 1.2", RFC 6347, DOI 10.17487/RFC6347, January 2012, <https://www.rfc-editor.org/info/rfc6347>.

[RFC6991] Schoenwaelder, J., Ed., "Common YANG Data Types", RFC 6991, DOI 10.17487/RFC6991, July 2013, <https://www.rfc-editor.org/info/rfc6991>.

[RFC7049] Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", RFC 7049, DOI 10.17487/RFC7049, October 2013, <https://www.rfc-editor.org/info/rfc7049>.

[RFC7250] Wouters, P., Ed., Tschofenig, H., Ed., Gilmore, J., Weiler, S., and T. Kivinen, "Using Raw Public Keys in Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)", RFC 7250, DOI 10.17487/RFC7250, June 2014, <https://www.rfc-editor.org/info/rfc7250>.

[RFC7252] Shelby, Z., Hartke, K., and C. Bormann, "The Constrained Application Protocol (CoAP)", RFC 7252, DOI 10.17487/RFC7252, June 2014, <https://www.rfc-editor.org/info/rfc7252>.

[RFC7525] Sheffer, Y., Holz, R., and P. Saint-Andre, "Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS)", BCP 195, RFC 7525, DOI 10.17487/RFC7525, May 2015, <https://www.rfc-editor.org/info/rfc7525>.

[RFC7641] Hartke, K., "Observing Resources in the Constrained Application Protocol (CoAP)", RFC 7641, DOI 10.17487/RFC7641, September 2015, <https://www.rfc-editor.org/info/rfc7641>.

[RFC7918] Langley, A., Modadugu, N., and B. Moeller, "Transport Layer Security (TLS) False Start", RFC 7918, DOI 10.17487/RFC7918, August 2016, <https://www.rfc-editor.org/info/rfc7918>.

[RFC7924] Santesson, S. and H. Tschofenig, "Transport Layer Security (TLS) Cached Information Extension", RFC 7924, DOI 10.17487/RFC7924, July 2016, <https://www.rfc-editor.org/info/rfc7924>.

[RFC7950] Bjorklund, M., Ed., "The YANG 1.1 Data Modeling Language", RFC 7950, DOI 10.17487/RFC7950, August 2016, <https://www.rfc-editor.org/info/rfc7950>.

[RFC7959] Bormann, C. and Z. Shelby, Ed., "Block-Wise Transfers in the Constrained Application Protocol (CoAP)", RFC 7959, DOI 10.17487/RFC7959, August 2016, <https://www.rfc-editor.org/info/rfc7959>.

[RFC8085] Eggert, L., Fairhurst, G., and G. Shepherd, "UDP Usage Guidelines", BCP 145, RFC 8085, DOI 10.17487/RFC8085, March 2017, <https://www.rfc-editor.org/info/rfc8085>.

[RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 8126, DOI 10.17487/RFC8126, June 2017, <https://www.rfc-editor.org/info/rfc8126>.

[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[RFC8200] Deering, S. and R. Hinden, "Internet Protocol, Version 6 (IPv6) Specification", STD 86, RFC 8200, DOI 10.17487/RFC8200, July 2017, <https://www.rfc-editor.org/info/rfc8200>.

[RFC8305] Schinazi, D. and T. Pauly, "Happy Eyeballs Version 2: Better Connectivity Using Concurrency", RFC 8305, DOI 10.17487/RFC8305, December 2017, <https://www.rfc-editor.org/info/rfc8305>.

[RFC8323] Bormann, C., Lemay, S., Tschofenig, H., Hartke, K., Silverajan, B., and B. Raymor, Ed., "CoAP (Constrained Application Protocol) over TCP, TLS, and WebSockets", RFC 8323, DOI 10.17487/RFC8323, February 2018, <https://www.rfc-editor.org/info/rfc8323>.

[RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018, <https://www.rfc-editor.org/info/rfc8446>.

[RFC8615] Nottingham, M., "Well-Known Uniform Resource Identifiers (URIs)", RFC 8615, DOI 10.17487/RFC8615, May 2019, <https://www.rfc-editor.org/info/rfc8615>.

[RFC8768] Boucadair, M., Reddy.K, T., and J. Shallow, "Constrained Application Protocol (CoAP) Hop-Limit Option", RFC 8768, DOI 10.17487/RFC8768, March 2020, <https://www.rfc-editor.org/info/rfc8768>.

11.2. Informative References 📚

Okay so this is the extra-reading pile, bestie 🦋 Here are the background docs the spec points you to.


Appendix A. CUID Generation 🧚

Here's the vibe check on the 'cuid' 💅 The document recommends using SPKI to generate the 'cuid', and the reasons for that choice are:

  • SPKI is globally unique. 🌈
  • It is deterministic. 🔥
  • It allows the avoidance of extra cycles that may be induced by 'cuid' collision. 💜
  • DOTS clients do not need to store the 'cuid' in a persistent storage. ✨
  • It allows the detection of compromised DOTS clients that do not adhere to the 'cuid' generation algorithm. 👑

Acknowledgements 🫶

Huge thanks to Christian Jacquenet, Roland Dobbins, Roman Danyliw, Michael Richardson, Ehud Doron, Kaname Nishizuka, Dave Dolson, Liang Xia, Gilbert Clark, Xialiang Frank, Jim Schaad, Klaus Hartke, Nesredien Suleiman, Stephen Farrell, and Yoshifumi Nishida for the discussion and comments. 💖

The authors would like to give special thanks to Kaname Nishizuka and Jon Shallow for their efforts in implementing the protocol and performing interop testing at IETF Hackathons. Absolute legends 👑

Thanks to the core WG for the recommendations on Hop-Limit and redirect signaling. 🦋

Special thanks to Benjamin Kaduk for the detailed AD review. 🌸

Thanks to Alexey Melnikov, Adam Roach, Suresh Krishnan, Mirja Kühlewind, and Alissa Cooper for the review. 🍓

Thanks to Carsten Bormann for his review of the DOTS heartbeat mechanism. 🎀

Contributors ✨

these amazing people helped cook this doc, so they get a shoutout 🫶

Jon Shallow NCC Group

Email: jon.shallow@nccgroup.trust

Mike Geller Cisco Systems, Inc. FL 33309 United States of America

Email: mgeller@cisco.com

Robert Moskowitz HTT Consulting Oak Park, MI 42837 United States of America

Email: rgm@htt-consult.com

Dan Wing

Email: dwing-ietf@fuggles.com


Authors' Addresses 💅

these are the editors and authors who actually wrote the thing 💖 if you need to reach them, here's where to find them 📬

Tirumaleswar Reddy.K (editor) 👑 McAfee, Inc. Embassy Golf Link Business Park Bangalore 560071 Karnataka India

Email: kondtir@gmail.com

Mohamed Boucadair (editor) 👑 Orange 35000 Rennes France

Email: mohamed.boucadair@orange.com

Prashanth Patil Cisco Systems, Inc.

Email: praspati@cisco.com

Andrew Mortensen Arbor Networks, Inc. 2727 S. State Street Ann Arbor, MI 48104 United States of America

Email: andrew@moretension.com

Nik Teague Iron Mountain Data Centers United Kingdom

Email: nteague@ironmountain.co.uk

📦 where this page comes from