RFC 8765

DNS Push Notifications

πŸ“… published June 2020, from ietf

DNS Push Notifications πŸŽ€

okay bestie, let's start with the header πŸ’– This is RFC 8765, titled "DNS Push Notifications." It's a Standards Track document, ISSN 2070-1721, published in June 2020 πŸ¦‹ The authors are T. Pusateri (Unaffiliated) and S. Cheshire (Apple Inc.). The header doesn't list anything it obsoletes or updates, so it's standing on its own ✨

Abstract ✨

The Domain Name System (DNS) was built to return matching records quickly when you ask for data that barely changes πŸ“ If those records change a lot, DNS still does a good job returning the updated answers when you poll for them, as long as you don't poll too often. The problem is there's no way for a client to get asynchronously notified when those changes happen 😭 This document defines a mechanism that lets a client hear about changes to DNS records. It's called DNS Push Notifications πŸ”₯

Status of This Memo πŸ“œ

This is an Internet Standards Track document.

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It went through public review and got approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check out Section 2 of RFC 7841 🧚

Info about the current status of this document, any errata, and how to send feedback is at https://www.rfc-editor.org/info/rfc8765 πŸ’…

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

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

Table of Contents πŸ—‚οΈ

1.  Introduction
  1.1.  Requirements Language
  1.2.  Fatal Errors
2.  Motivation
3.  Overview
4.  State Considerations
5.  Transport
6.  Protocol Operation
  6.1.  Discovery
  6.2.  DNS Push Notification SUBSCRIBE
    6.2.1.  SUBSCRIBE Request
    6.2.2.  SUBSCRIBE Response
  6.3.  DNS Push Notification Updates
    6.3.1.  PUSH Message
  6.4.  DNS Push Notification UNSUBSCRIBE
    6.4.1.  UNSUBSCRIBE Message
  6.5.  DNS Push Notification RECONFIRM
    6.5.1.  RECONFIRM Message
  6.6.  DNS Stateful Operations TLV Context Summary
  6.7.  Client-Initiated Termination
  6.8.  Client Fallback to Polling
7.  Security Considerations
  7.1.  Security Services
  7.2.  TLS Name Authentication
  7.3.  TLS Early Data
  7.4.  TLS Session Resumption
8.  IANA Considerations
9.  References
  9.1.  Normative References
  9.2.  Informative References
Acknowledgments
Authors' Addresses

1. Introduction ✨

DNS records can get updated through DNS Update [RFC2136] πŸ’« Other stuff like a Discovery Proxy [RFC8766] can also make changes to a DNS zone. This document specifies a protocol that lets DNS clients subscribe to asynchronous notifications about changes to the RRsets they care about πŸ¦‹ It's a big deal for DNS-based Service Discovery [RFC6763], but it's not limited to that. It's a general DNS mechanism for record change notifications, so it's giving versatile πŸ’… Being familiar with the DNS protocol and DNS packet formats is assumed [RFC1034] [RFC1035] [RFC6895].

1.1. Requirements Language

Okay so here are the BCP 14 key words πŸ”‘ The words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document get interpreted as described in BCP 14 [RFC2119] [RFC8174], but only when they show up in all capitals, exactly like this πŸŽ€

1.2. Fatal Errors

Some invalid situations are described in this spec, like a server sending a Push Notification subscription request to a client, or a client sending a Push Notification response to a server 😭 These should never happen with a correctly implemented client and server. If they do happen, that's a serious implementation error. In these extreme cases there's no reasonable expectation of a graceful recovery, so the recipient that detects the error should unilaterally abort the session, without caring about data loss πŸ’€ The fix is for an engineer to investigate what caused the failure and fix the problem in the software πŸ› οΈ

When this spec says "forcibly abort," it means sending a TCP RST to terminate the TCP connection and the TLS session running over it. In the BSD Sockets API, you do this by setting the SO_LINGER option to zero before closing the socket 🧚

2. Motivation πŸ’œ

As the domain name system keeps adapting to new uses and deployment changes, polling has the potential to burden DNS servers at many levels of the network 😩 Other network protocols have successfully deployed a publish/subscribe model that follows the Observer design pattern [OBS]. Extensible Messaging and Presence Protocol (XMPP) Publish-Subscribe [XEP0060] and Atom [RFC4287] are examples 🌸 DNS servers are usually highly tuned and can handle a high rate of query/response traffic, but adding a publish/subscribe model for tracking DNS record changes can deliver more timely notifications, with reduced CPU usage and lower network traffic ✨

The guiding design principle of DNS Push Notifications is this: clients that choose to use DNS Push Notifications, instead of repeatedly polling with DNS queries, will get the same results they would get from sufficiently rapid polling, just more efficiently πŸ‘‘ That means the rules for which records match a given DNS Push Notification subscription are the same established rules used to figure out which records match a given DNS query [RFC1034]. For example, name comparisons are case-insensitive, and a record of type CNAME in a zone matches any DNS TYPE in a query or subscription πŸ¦‹

Multicast DNS [RFC6762] implementations always listen on a well-known link-local IP multicast group address, and changes get sent to that multicast group address so all group members can receive them. So Multicast DNS already has asynchronous change notification capability πŸ’– When DNS-based Service Discovery [RFC6763] is used across a wide area network with Unicast DNS (possibly facilitated by a Discovery Proxy [RFC8766]), it would be beneficial to have an equivalent capability for Unicast DNS. That would let clients learn about DNS record changes in a timely manner without polling πŸ™Œ

The DNS Long-Lived Queries (LLQ) mechanism [RFC8764] is an existing, deployed solution for asynchronous change notifications 🌈 It was used by Apple's Back to My Mac [RFC6281] service, introduced in Mac OS X 10.5 Leopard in 2007. Back to My Mac was designed in an era when data center operations staff insisted it was impossible for a server to handle large numbers of TCP connections, even if those connections carried very little traffic and spent most of their time idle 😀 So LLQ was defined as a UDP-based protocol, which basically meant replicating much of TCP's connection state management logic in user space, and creating its own imitation of existing TCP features like flow control, reliability, and the three-way handshake 🫠

This document builds on what was learned from LLQ, with an improved design. Instead of using UDP, this specification uses DNS Stateful Operations (DSO) [RFC8490] running over TLS over TCP, so it doesn't have to reinvent existing TCP functionality 🧠 Using TCP also gives long-lived, low-traffic connections better longevity through NAT gateways. That works without depending on the gateway to support NAT Port Mapping Protocol (NAT-PMP) [RFC6886] or Port Control Protocol (PCP) [RFC6887], and without resorting to excessive keepalive traffic ✨

3. Overview ✨

okay bestie, so here's the big picture πŸ’– A DNS Push Notification client subscribes to Push Notifications for a particular RRset by connecting to the right Push Notification server for that RRset and sending DSO message(s) that name the RRset(s) it cares about πŸŽ€ When the client stops caring about updates to those records, it unsubscribes. Simple, iconic.

The DNS Push Notification server for a DNS zone is any server that can generate the correct change notifications for a name πŸ”₯ It can be a primary, a secondary, or a stealth name server [RFC8499]. It's giving "whoever can do the job, slay."

The "_dns-push-tls._tcp.<zone>" SRV record for a zone MAY reference the same target host and port as that zone's "_dns-update-tls._tcp.<zone>" SRV record πŸ¦‹ When the same target host and port is offered for both DNS Updates and DNS Push Notifications, a client MAY use a single DSO session to that server for both DNS Updates and DNS Push Notification subscriptions. Cute shortcut, right? 🧚 But DNS Updates and DNS Push Notifications may also live on different ports of the same target host. In that case they are NOT considered to be the "same server" for this specification, and communications with those two ports are handled independently. Supporting DNS Updates and DNS Push Notifications on the same server is OPTIONAL πŸ’… A DNS Push Notification server is not required to support DNS Update, so no pressure bestie.

Standard DNS Queries MAY be sent over a DNS Push Notification (i.e., DSO) session 🌸 For any zone the server is authoritative for, it MUST respond authoritatively to queries for names inside that zone (for example, the "_dns-push-tls._tcp.<zone>" SRV record), both for normal DNS queries and for DNS Push Notification subscriptions. And for names where the server is acting as a recursive resolver (for example, when the server is the local recursive resolver) for any query it supports DNS Push Notification subscriptions for, it MUST also support standard queries. Both things, every time 🫢

Now the important part, the load thing 😭 DNS Push Notifications impose less load on the responding server than rapid polling would, but Push Notifications still have a cost. So DNS Push Notification clients MUST NOT recklessly create an excessive number of Push Notification subscriptions. Specifically:

(a) A subscription should only be active when there is a valid reason to need live data (for example, an on-screen display is currently showing the results to the user), and the subscription SHOULD be canceled as soon as the need for that data ends (for example, when the user dismisses that display). Smartphone example incoming πŸ“± If a device goes to sleep after a period of inactivity or otherwise darkens its screen, it should cancel its subscriptions when the screen darkens (since the user cannot see any changes on the display anyway), and reinstate them when it wakes up from display sleep. Cancel when dark, bring back when awake, main character energy ✨

(b) A DNS Push Notification client SHOULD NOT routinely keep a DNS Push Notification subscription active 24 hours a day, 7 days a week, just to keep a list in memory up to date so that it can display really fast if the user does choose to bring up an on-screen display of that data πŸ™ˆ DNS Push Notifications are designed to be fast enough that there is no need to pre-load a "warm" list in memory just in case it might be needed later. Not paying for a list nobody's looking at, iykyk πŸ’€

Generally, as described in the DNS Stateful Operations specification [RFC8490], a client must not keep a DSO session to a server open indefinitely if it has no subscriptions (or other operations) active on that session. A client should begin closing a DSO session immediately after it becomes idle, and then open a new session later when it's needed. Alternatively, a client may speculatively keep an idle DSO session open for some time, subject to the constraint that it must not keep a session open that has been idle for more than the session's idle timeout (15 seconds by default) [RFC8490] ⏰

Note that a DSO session with an active DNS Push Notification subscription is not considered idle, even if no traffic flows for a long stretch πŸ¦‹ In that case the DSO inactivity timeout doesn't apply, because the session isn't inactive. But the keepalive interval still applies, so enough messages get generated to keep state alive in middleboxes (such as NAT gateways or firewalls) and so the client and server can periodically check that they still have connectivity to each other. This is described in Section 6.2 of the DSO specification [RFC8490] 🌈


4. State Considerations

Each DNS Push Notification server can handle some finite number of Push Notification subscriptions πŸ’… That number varies from server to server and depends on physical machine characteristics, network capacity, and operating system resource allocation. After a client establishes a session to a DNS server, each subscription is individually accepted or rejected. Servers may use various techniques to keep subscriptions at a manageable level. So the client is free to set up simultaneous sessions to alternate DNS servers that support DNS Push Notifications for the zone, and spread its subscriptions across them at its own discretion 🧚 That way, both clients and servers can react to resource constraints. Everybody gets to be chill about it 🫢


5. Transport

Other DNS operations, like DNS Update [RFC2136], MAY use either DNS over User Datagram Protocol (UDP) [RFC0768] or DNS over Transmission Control Protocol (TCP) [RFC0793] as the transport protocol, provided they follow the historical precedent that DNS queries must first be sent using DNS over UDP and only switch to DNS over TCP if needed [RFC1123]. That UDP-first rule has since been relaxed [RFC7766], so the vibes have shifted a bit 🌸

In keeping with the more recent precedent, DNS Push Notification is defined ONLY for TCP πŸŽ€ DNS Push Notification clients MUST use DNS Stateful Operations [RFC8490] running over TLS over TCP [RFC7858].

Connection setup over TCP ensures return reachability and eases worries about state overload at the server, which can be a problem with connectionless protocols. Those can be more vulnerable to attackers using spoofed source addresses πŸ‘€ All subscribers are guaranteed to be reachable by the server thanks to the TCP three-way handshake. Flooding attacks are possible with any protocol, but TCP has a perk here: there are already established industry best practices to guard against SYN flooding and similar attacks [SYN] [RFC4953]. Safety in numbers, bestie πŸ›‘οΈ

Using TCP also lets DNS Push Notifications take advantage of current and future TCP developments, like Multipath TCP (MPTCP) [RFC8684], TCP Fast Open (TFO) [RFC7413], the TCP RACK fast loss detection algorithm [TCPRACK], and so on πŸš€ Future-proof era.

Transport Layer Security (TLS) [RFC8446] is well understood and is used by many application-layer protocols running over TCP ✨ TLS is designed to prevent eavesdropping, tampering, and message forgery. In this protocol specification, TLS is REQUIRED for every connection between a client subscriber and a server πŸ”’ Additional security measures, like client authentication during TLS negotiation, may also be employed to increase the trust relationship between client and server. Trust is the whole aesthetic πŸ’œ


6. Protocol Operation

The DNS Push Notification protocol is a session-oriented protocol and makes use of DNS Stateful Operations (DSO) [RFC8490] 🧚

For the details of the DSO message format, refer to the DNS Stateful Operations specification [RFC8490]. Those details aren't repeated here, so go read the source if you want the full tea β˜•

DNS Push Notification clients and servers MUST support DSO πŸ’– A single server can support DNS Queries, DNS Updates, and DNS Push Notifications (using DSO) on the same TCP port. Multitasking queen πŸ‘‘

A DNS Push Notification exchange begins with the client discovering the appropriate server, using the procedure described in Section 6.1, and then making a TLS/TCP connection to it πŸŽ€

After making the TLS/TCP connection, a typical DNS Push Notification client will immediately issue a DSO Keepalive operation to establish the DSO session and request a session timeout and/or keepalive interval longer than the 15-second default values. But this is not required 🌸 A DNS Push Notification client MAY issue other requests on the session first, and only issue a DSO Keepalive operation later if it determines that to be necessary. Either way, sending a DSO Keepalive operation or a Push Notification subscription request over the TLS/TCP connection signals the client's support of DSO and serves to establish a DSO session. Two ways to say "hi, I speak DSO" πŸ¦‹

In accordance with the current set of active subscriptions, the server sends relevant asynchronous Push Notifications to the client πŸ“¬ Now here's a plot twist 😭 A client MUST be prepared to receive (and silently ignore) Push Notifications for subscriptions it has previously removed. Why? Because there's no way to prevent the situation where a Push Notification is in flight from server to client at the same time that the client's UNSUBSCRIBE message canceling that subscription is in flight from client to server. Race conditions, the ultimate plot twist 🌈

6.1. Discovery πŸ”Ž

Okay bestie, step one before a client can subscribe to anything is finding the right DNS server that actually does DNS Push Notifications for the zone it cares about πŸ’–

The client starts by opening a DSO session to its normal configured DNS recursive resolver and asking for a Push Notification subscription. That connection goes to TCP port 853, the default port for DNS over TLS [RFC7858] πŸ” If the request works, and the resolver doesn't already have an active subscription for that name, type, and class, then the resolver makes its own matching subscription on the client's behalf ✨ Whatever results come back get relayed to the client. This is giving the same energy as a normal DNS query: the client asks its resolver, and if the resolver doesn't have the answer in its cache, it goes upstream to get it πŸ¦‹

In a lot of setups, the recursive resolver can handle Push Notifications for every name the client might want to follow, so you're set 🌸 VPN tunnels and Private DNS [RFC8499] can add some extra complexity on the client side, ngl. The good news is the techniques for handling VPN tunnels and Private DNS with DNS Push Notifications are the same ones already used for normal DNS queries, so nothing new to learn 🧚

If the recursive resolver doesn't support DNS over TLS, or supports it but isn't listening on TCP port 853, or supports DNS over TLS on TCP port 853 but doesn't support DSO on that port, then the DSO session setup fails [RFC8490] πŸ’€

If the recursive resolver does support DSO on TCP port 853 but doesn't support Push Notification subscriptions, the server will hit back with the DSO error code DSOTYPENI (11) when the client tries to make a subscription πŸ™ˆ

Sometimes the resolver supports DSO and Push Notification subscriptions but still can't subscribe for a particular name. In that case the recursive resolver should return SERVFAIL to the client. This includes not being able to connect to the zone's DNS Push Notification server, or connecting but getting a response code that isn't success. If the client already has a trust relationship with the zone owner (one that isn't handled through the usual VPN software mechanisms), it may handle these failures by contacting the zone's DNS Push Notification server directly 🀝

Whenever the client fails to set up a subscription through its configured recursive resolver, it should go ahead and discover the right server for direct communication. The client MUST also figure out which TCP port the server is listening on. Spoiler: it's not always TCP port 53 (the traditional conventional DNS port) or TCP port 853 (the traditional DNS over TLS port), so don't assume πŸ‘€

The discovery algorithm is iterative. It starts with the full name of the record the client wants to subscribe to, then keeps sending SOA queries, trimming one label each time, until it finds the closest enclosing authoritative server. There's also a shortcut so the client can jump straight to the SOA record of the closest enclosing authoritative server in lots of cases ⚑

  1. The client kicks things off by sending a DNS query to its local resolver with record type SOA [RFC1035] for the record name it wants to subscribe to. Example time: say the client wants PTR records named "_ipp._tcp.headoffice.example.com" (to find Internet Printing Protocol (IPP) printers [RFC8010] [RFC8011] advertised at Example Company's head office). It sends an SOA query for "_ipp._tcp.headoffice.example.com" to the local recursive resolver. The goal is to find the server authoritative for "_ipp._tcp.headoffice.example.com". The closest enclosing zone could be "example.com", "headoffice.example.com", "_tcp.headoffice.example.com", or even "_ipp._tcp.headoffice.example.com" itself. The client doesn't know in advance where the zone cut is, which is exactly why it uses this iterative approach to figure it out πŸ•΅οΈβ€β™€οΈ
  2. If the requested SOA record exists, it comes back in the Answer Section with a NOERROR response code, and the client has what it needs πŸŽ‰

(This language isn't adding any new requirements on DNS recursive resolvers. It just describes how DNS already works [RFC1034] [RFC1035].)

  1. If the requested SOA record doesn't exist, the client gets back either a NOERROR/NODATA response or an NXDOMAIN/Name Error response. Either way, the local resolver would normally include the SOA record for the closest enclosing zone of the requested name in the Authority Section. If that SOA shows up in the Authority Section, the client has what it needs πŸ’…

(This language isn't adding any new requirements on DNS recursive resolvers. It just describes how negative responses already work [RFC2308].)

  1. If the response has no SOA record at all, the client keeps going iteratively. It strips the leading label off the current query name. If the new name still has at least two labels, the client sends an SOA query for it and goes back to step 2, repeating until it gets an SOA or the query name is down to a single label, i.e., a Top-Level Domain (TLD). A single-label name means something's wrong with the network configuration, which should not happen, so the client gives up 😭 It can try again later, at a time of its choosing, like after a change in network attachment.
  2. Once the SOA is known (whether it showed up in the Answer Section or the Authority Section), the client sends a DNS query with type SRV [RFC2782] for the record name "_dns-push-tls._tcp.<zone>", where <zone> is the owner name of the discovered SOA record 🧩
  3. If the zone is set up to offer DNS Push Notifications, this SRV record MUST exist. (If it doesn't, the zone isn't configured correctly for DNS Push Notifications as this document describes.) The SRV "target" names the server providing DNS Push Notifications for the zone, and the port to contact it on is in the SRV record's "port" field. The target host's address(es) MAY be included in the Additional Section. Even so, the address records SHOULD be authenticated before use, as described in Section 7.2 and, where it applies, in the specification for using DNS-Based Authentication of Named Entities (DANE) TLSA Records with SRV Records [RFC7673] πŸ”’
  4. You might get more than one SRV record back. In that case, the "priority" and "weight" values decide the order for sending subscription requests. As the SRV specification [RFC2782] explains, the server with the lowest "priority" gets contacted first. If several servers share the same "priority", "weight" tells you the weighted probability of picking each one, and higher weights are more likely to be picked 🎲 If a server won't accept the subscription request, or isn't reachable in a reasonable time (as the client decides), the client moves on to the next server πŸƒβ€β™€οΈ

Each time a client makes a new DNS Push Notification subscription, it SHOULD repeat the discovery process to find the preferred DNS server for that subscription at that moment πŸ” If the client already has a DSO session with that server, it SHOULD reuse that existing session for the new subscription. Otherwise, a new DSO session gets set up. While it's discovering, the client MUST respect the DNS TTL values on the records it receives and store them in its local cache for that lifetime (which it'll usually do for every DNS query anyway) ⏳ So as long as the DNS TTL values on the authoritative records are set to reasonable values, repeating discovery can finish practically instantly, using only locally stored cached data. Iconic efficiency πŸ¦‹


6.2. DNS Push Notification SUBSCRIBE πŸŽ€

After connecting, and asking for a longer idle timeout and/or keepalive interval if needed, a DNS Push Notification client tells the server it wants Push Notifications for a given domain name by sending a SUBSCRIBE request. A SUBSCRIBE request gets encoded in a DSO message [RFC8490]. This spec defines a DSO Primary TLV for DNS Push Notification SUBSCRIBE Requests, with DSO Type Code 0x0040 🧁

DSO messages with the SUBSCRIBE TLV as the Primary TLV are allowed in TLS early data, as long as the precautions in Section 7.3 are followed ⚠️

The entity that starts a SUBSCRIBE request is, by definition, the client. A server MUST NOT send a SUBSCRIBE request over an existing session from a client. If a server does send a SUBSCRIBE request over a DSO session the client started, that's a fatal error, and the client MUST forcibly abort the connection immediately 🚨

Every SUBSCRIBE request gets exactly one SUBSCRIBE response from the server. The entity that starts a SUBSCRIBE response is, by definition, the server. A client MUST NOT send a SUBSCRIBE response. If a client does send one, that's a fatal error, and the server MUST forcibly abort the connection immediately πŸ’œ

6.2.1. SUBSCRIBE Request ✨

okay so a SUBSCRIBE request starts with the standard 12-byte DSO header [RFC8490], and then the SUBSCRIBE Primary TLV shows up πŸ’…. Figure 1 shows the whole look.

The MESSAGE ID field MUST be set to a unique value that the client is not using for any other active operation on this DSO session. no repeats, bestie πŸ™…β€β™€οΈ

a MESSAGE ID counts as in use on the session if the client sent it in a request that hasn't gotten a response yet, OR if the client used it for a subscription it hasn't canceled with UNSUBSCRIBE yet. so in the SUBSCRIBE response, the server MUST echo back the MESSAGE ID value unchanged πŸ” (same ID, no glow-up).

the other header fields MUST be set as described in the DSO specification [RFC8490]. the DNS OPCODE field holds the OPCODE value for DNS Stateful Operations (6) 🧚. the four count fields must be zero, and the corresponding four sections must be empty (i.e., absent). iykyk 🌸

the DSO-TYPE is SUBSCRIBE (0x0040) πŸ’–. the DSO-LENGTH is the length of the DSO-DATA that follows, and that DSO-DATA is where the name, type, and class of the record(s) being sought live πŸ“.

                                      1  1  1  1  1  1
        0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
      |                  MESSAGE ID                   |   \
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |QR| OPCODE(6) |         Z          |   RCODE   |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             QDCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     > HEADER
      |             ANCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             NSCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             ARCOUNT (MUST BE ZERO)            |   /
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /
      |         DSO-TYPE = SUBSCRIBE (0x0040)         |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |   DSO-LENGTH (number of octets in DSO-DATA)   |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
      \                     NAME                      \   \
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |                     TYPE                      |     > DSO-DATA
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |                     CLASS                     |   /
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /

                        Figure 1: SUBSCRIBE Request

the DSO-DATA for a SUBSCRIBE request MUST contain exactly one NAME, TYPE, and CLASS πŸŽ€. since SUBSCRIBE requests go over TCP, you can concatenate multiple SUBSCRIBE DSO request messages in a single TCP stream and pack them nicely into TCP segments. so efficient, it's giving πŸ¦‹

if it's accepted, the subscription stays in effect until the client cancels it using UNSUBSCRIBE, or until the DSO session between the client and the server gets closed πŸ”’.


SUBSCRIBE requests on a given session MUST be unique. A client MUST NOT send a SUBSCRIBE message that duplicates the name, type and class of an existing active subscription on that DSO session. for this matching, the established DNS case insensitivity for US-ASCII letters [RFC0020] applies, so "example.com" and "Example.com" are the same bestie πŸ™ˆ. and if a server gets a duplicate SUBSCRIBE message, that's a fatal error, and the server MUST forcibly abort the connection immediately πŸ’€. no mercy, no second chances.

DNS wildcarding is not supported 🚫. an asterisk character (*) in a SUBSCRIBE message only matches a literal asterisk character (*) in a name, and nothing else. similarly, a CNAME in a SUBSCRIBE message only matches a CNAME record with that name in the zone, and no other records with that name πŸ’.

a client may SUBSCRIBE to records that are unknown to the server at the time of the request (providing that the name falls within one of the zone(s) the server is responsible for), and that is not an error 🌈. the server MUST NOT return NXDOMAIN in this case. the server MUST accept these requests and send Push Notifications if and when matching records are found in the future 🧚✨. patience is a virtue, and so is this server.

if neither TYPE nor CLASS are ANY (255), then it's a specific subscription to changes for the given name, type, and class 🎯. if one or both of TYPE or CLASS are ANY (255), then the subscription matches all types and/or all classes as appropriate 🌸.

NOTE: A little-known quirk of DNS is that in DNS QUERY requests, QTYPE and QCLASS 255 mean "ANY", not "ALL". They indicate that the server should respond with ANY matching records of its choosing, not necessarily ALL matching records. This can lead to some surprising and unexpected results, where a query returns some valid answers, but not all of them, and makes QTYPE = 255 (ANY) queries less useful than people sometimes imagine. πŸ™ƒ

when it's used with SUBSCRIBE, TYPE 255 and CLASS 255 should be interpreted to mean "ALL", not "ANY" πŸ‘‘. after accepting a subscription where one or both of TYPE or CLASS are 255, the server MUST send Push Notification Updates for ALL record changes that match the subscription, not just some of them. ALL of them, no leaving anyone on read πŸ’…πŸŒˆ

6.2.2. SUBSCRIBE Response ✨

Okay so every SUBSCRIBE response starts with the standard DSO 12-byte header [RFC8490] πŸŽ€. The QR bit gets set, which just means "hey, this is a response" πŸ’…. The header MAY be followed by one or more optional Additional TLVs, like a Retry Delay Additional TLV 🧚. Figure 2 shows the whole look.

The MESSAGE ID field MUST echo the value from the SUBSCRIBE request 🫢. That's how the client knows which request the reply is for, so it's literally the main character link πŸ”—.

The other header fields MUST be set the way the DSO spec [RFC8490] describes πŸ“–. The DNS OPCODE field holds the OPCODE value for DNS Stateful Operations (6). The four count fields must be zero, and the matching four sections must be empty (i.e., absent) πŸ™ˆ.

A SUBSCRIBE response message MUST NOT include a SUBSCRIBE TLV 🚫. If a client gets one anyway, the response still gets processed, but that SUBSCRIBE TLV MUST be silently ignored 🀫.

                                   1  1  1  1  1  1
     0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
   |                  MESSAGE ID                   |   \
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
   |QR| OPCODE(6) |         Z          |   RCODE   |    |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
   |             QDCOUNT (MUST BE ZERO)            |    |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     > HEADER
   |             ANCOUNT (MUST BE ZERO)            |    |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
   |             NSCOUNT (MUST BE ZERO)            |    |
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
   |             ARCOUNT (MUST BE ZERO)            |   /
   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /

Figure 2: SUBSCRIBE Response

In the SUBSCRIBE response, the RCODE tells you whether the subscription got accepted 🎟. These are the supported RCODEs:

+-----------+-------+-----------------------------------+
| Mnemonic  | Value | Description                       |
+===========+=======+===================================+
| NOERROR   |   0   | SUBSCRIBE successful.             |
+-----------+-------+-----------------------------------+
| FORMERR   |   1   | Server failed to process request  |
|           |       | due to a malformed request.       |
+-----------+-------+-----------------------------------+
| SERVFAIL  |   2   | Server failed to process request  |
|           |       | due to a problem with the server. |
+-----------+-------+-----------------------------------+
| NOTIMP    |   4   | Server does not implement DSO.    |
+-----------+-------+-----------------------------------+
| REFUSED   |   5   | Server refuses to process request |
|           |       | for policy or security reasons.   |
+-----------+-------+-----------------------------------+
| NOTAUTH   |   9   | Server is not authoritative for   |
|           |       | the requested name.               |
+-----------+-------+-----------------------------------+
| DSOTYPENI |   11  | SUBSCRIBE operation not           |
|           |       | supported.                        |
+-----------+-------+-----------------------------------+

Table 1: SUBSCRIBE Response Codes

This doc only specifies these RCODE values for SUBSCRIBE Responses πŸ“. Servers sending SUBSCRIBE Responses SHOULD use one of these values. Also, NXDOMAIN is not a valid RCODE in response to a SUBSCRIBE Request, so don't go there πŸ™…. Future situations might make other RCODE values make sense, so clients MUST be prepared to accept and handle SUBSCRIBE Responses with any other nonzero RCODE error values πŸ’œ.

If the server sends a nonzero RCODE in the SUBSCRIBE response, that means:

  • a. the client is (at least partially) misconfigured, or
  • b. the server resources are exhausted, or
  • c. there is some other unknown failure on the server.

In any case, the client shouldn't retry the subscription to this server right away πŸ™ƒ. If multiple SRV records were returned as described in Section 6.1, Paragraph 9, Item 7, a subsequent server MAY be tried immediately.

If the client has other successful subscriptions to this server, those stay put even though new subscriptions might get refused 🌸. Neither the client nor the server is required to close the connection, although either end may choose to do so.

If the server sends a nonzero RCODE, then it SHOULD append a Retry Delay Additional TLV [RFC8490] to the response, specifying a delay before the client tries this operation again ⏳. Recommended values for the delay, based on the RCODE, are below. These recommended values cover both the defaults a server should put in the Retry Delay Additional TLV and the defaults a client should assume if the server doesn't send one.

For RCODE = 1 (FORMERR): the delay may be any value the implementer picks. A value of five minutes is RECOMMENDED to reduce the risk of high load from defective clients 🫠.

For RCODE = 2 (SERVFAIL): the delay should match the level of server overload and how long that overload is expected to last. By default, a value of one minute is RECOMMENDED. If a more serious server failure happens, the delay may be longer, depending on the specific problem πŸ› .

For RCODE = 4 (NOTIMP): this one shows up on a server that doesn't implement DNS Stateful Operations [RFC8490]. It's unlikely that the server will start supporting DSO in the next few minutes, so the retry delay SHOULD be one hour ⏰. A server that doesn't implement DSO is also unlikely to send a Retry Delay Additional TLV, so this recommended value especially applies to what a client should assume by default πŸ’….

For RCODE = 5 (REFUSED): this happens on a server that implements DNS Push Notifications but is currently set up to disallow them. The retry delay may be any value the implementer picks and/or the operator configures πŸ”§.

If the server being queried is listed in a _dns-push-tls._tcp.<zone> SRV record for the zone, that's a misconfiguration 😬. The server is being advertised as supporting DNS Push Notifications for this zone, but it isn't currently configured to do that. Since the misconfiguration could be fixed at any time, the retry delay should not be set too high. By default, a value of 5 minutes is RECOMMENDED.

For RCODE = 9 (NOTAUTH): this happens on a server that implements DNS Push Notifications but isn't configured to be authoritative for the requested name. The retry delay may be any value the implementer picks and/or the operator configures 🌈.

If the server being queried is listed in a _dns-push-tls._tcp.<zone> SRV record for the zone, that's a misconfiguration 😬. The server is being advertised as supporting DNS Push Notifications for this zone, but it isn't currently configured to do that. Since the misconfiguration could be fixed at any time, the retry delay should not be set too high. By default, a value of 5 minutes is RECOMMENDED.

For RCODE = 11 (DSOTYPENI): this happens on a server that implements DSO but doesn't implement DNS Push Notifications. It's unlikely that the server will start supporting DNS Push Notifications in the next few minutes, so the retry delay SHOULD be one hour πŸ•.

For other RCODE values: the retry delay should be set by the server as appropriate for that error condition. By default, a value of 5 minutes is RECOMMENDED.

For RCODE = 9 (NOTAUTH), the time delay applies to requests for other names within the same zone πŸ—Ί. Requests for names in other zones aren't subject to the delay. For all other RCODEs, the time delay applies to all subsequent requests to this server ⭐.

After sending an error response, the server MAY allow the session to stay open, or MAY follow it with a DSO Retry Delay operation (using the Retry Delay Primary TLV) telling the client to close the session, as described in the DSO specification [RFC8490] πŸ‘‹. Clients MUST correctly handle both cases. Note that the DSO Retry Delay operation (using the Retry Delay Primary TLV) is different from the Retry Delay Additional TLV mentioned above, so don't mix them up πŸ™.


6.3. DNS Push Notification Updates πŸ¦‹

Once a subscription has been successfully established, the server generates PUSH messages to send to the client as appropriate πŸ“£. If the answer set was already non-empty when the subscription was set up, an initial PUSH message gets sent right after the SUBSCRIBE Response. Any later changes to the answer set are then shared with the client in subsequent PUSH messages.

A client MUST NOT send a PUSH message πŸ™…. If a client does send one, or a PUSH message shows up with the QR bit set (meaning it's a response), that's a fatal error, and the receiver MUST forcibly abort the connection immediately πŸ’€.

6.3.1. PUSH Message πŸ“¬

A PUSH unidirectional message starts with the standard DSO 12-byte header [RFC8490], followed by the PUSH Primary TLV. Figure 3 shows what a PUSH message looks like πŸ–Ό.

Since this is a DSO unidirectional message, the MESSAGE ID field MUST be zero 0️⃣. There's no client response to a PUSH message, so nobody's replying to this one 🀐.

The other header fields MUST be set as described in the DSO specification [RFC8490]. The DNS OPCODE field holds the OPCODE value for DNS Stateful Operations (6). The four count fields must be zero, and the matching four sections must be empty (i.e., absent) πŸ™ˆ.

The DSO-TYPE is PUSH (0x0041) πŸ’œ.

The DSO-LENGTH is the length of the DSO-DATA that follows, and that DSO-DATA is what specifies the changes being communicated πŸ“.

The DSO-DATA contains one or more change notifications. A PUSH Message MUST contain at least one change notification. If a PUSH Message comes in with no change notifications, that's a fatal error, and the client MUST forcibly abort the connection immediately 🚨.

The change notification records are formatted similarly to how DNS Resource Records are usually written in DNS messages, as Figure 3 illustrates, and they're interpreted as described below 🧁.

The TTL field holds an unsigned 32-bit integer [RFC2181]. If the TTL is in the range 0 to 2,147,483,647 seconds (0 to 2^(31) - 1, or 0x7FFFFFFF), then a new DNS Resource Record with the given name, type, class, and RDATA gets added βž•. Type and class MUST NOT be 255 (ANY). If either type or class is 255 (ANY), that's a fatal error, and the client MUST forcibly abort the connection immediately 😱. A TTL of 0 means this record should be kept for as long as the subscription is active, and it should be discarded the moment the subscription is canceled πŸŽ€.

Okay so the TTL is doing a LOT of work here πŸ’… If it's 0xFFFFFFFF, that's a remove βœ‚οΈ and the DNS Resource Record with that name, type, class, and RDATA is gone 🫢 Type and class MUST NOT be 255 (ANY). If either one is 255 (ANY), that's a fatal error and the client MUST forcibly abort the connection immediately πŸ’€

If the TTL is 0xFFFFFFFE, it's a "collective" remove notification ✨ For these, RDLEN MUST be zero, which means RDATA MUST be empty too. If a change notification shows up with TTL = 0xFFFFFFFE and RDLEN isn't zero, that's a fatal error and the client MUST forcibly abort the connection immediately 😭

There are three kinds of collective remove notification 🧚 For them:

  • If CLASS is not 255 (ANY) and TYPE is not 255 (ANY), then for the given name, this removes all records of the specified type in the specified class.
  • If CLASS is not 255 (ANY) and TYPE is 255 (ANY), then for the given name, this removes all records of all types in the specified class.
  • If CLASS is 255 (ANY), then for the given name, this removes all records of all types in all classes. In this case, TYPE MUST be set to zero on transmission and MUST be silently ignored on reception.

Summary of change notification types, because I know you're going to want a cheat sheet πŸ“

  • Remove all RRsets from a name in all classes: TTL = 0xFFFFFFFE, RDLEN = 0, CLASS = 255 (ANY).
  • Remove all RRsets from a name in given class: TTL = 0xFFFFFFFE, RDLEN = 0, CLASS gives class, TYPE = 255 (ANY).
  • Remove specified RRset from a name in given class: TTL = 0xFFFFFFFE, RDLEN = 0, CLASS and TYPE specify the RRset being removed.
  • Remove an individual RR from a name: TTL = 0xFFFFFFFF, CLASS, TYPE, RDLEN, and RDATA specify the RR being removed.
  • Add individual RR to a name: TTL >= 0 and TTL <= 0x7FFFFFFF, CLASS, TYPE, RDLEN, RDATA, and TTL specify the RR being added.

Now this part is a little plot twist πŸ‘‘ It's valid for the RDATA of an added or removed DNS Resource Record to be empty (zero length). For example, an Address Prefix List Resource Record [RFC3123] may have empty RDATA. So a change notification with RDLEN = 0 does NOT automatically mean "remove" πŸ™ˆ If RDLEN = 0 and TTL is in the range 0 to 0x7FFFFFFF, that's an addition of a record with the given name, type, class, and empty RDATA. If RDLEN = 0 and TTL = 0xFFFFFFFF, it's the removal of that single record with the given name, type, class, and empty RDATA.

If the TTL is any value other than 0xFFFFFFFF, 0xFFFFFFFE, or a value in the range 0 to 0x7FFFFFFF, the receiver SHOULD silently ignore that particular change notification record. The connection is not terminated, and the other valid change notification records in this PUSH message still get processed as usual πŸ¦‹

When one change affects more than one active subscription, only one PUSH message gets sent 🌸 For example, a PUSH message adding a given record might match both a SUBSCRIBE request with the same TYPE and a different SUBSCRIBE request with TYPE = 255 (ANY). It is not the case that two PUSH messages get sent just because the new record matches two active subscriptions.

The server SHOULD encode change notifications in the most efficient manner possible. For example, when three AAAA records are removed from a given name, and no other AAAA records exist for that name, the server SHOULD send a "Remove specified RRset from a name in given class" PUSH message, not three separate "Remove an individual RR from a name" PUSH messages. Similarly, when both an SRV and a TXT record are removed from a given name, and no other records of any kind exist for that name in that class, the server SHOULD send a "Remove all RRsets from a name in given class" PUSH message, not two separate "Remove specified RRset from a name in given class" PUSH messages πŸ’–

For efficiency, when generating a PUSH message, the server SHOULD include as many change notifications as it has immediately available to send to that client, instead of sending each one as its own DSO message ✨ That's true even if those notifications apply to different subscriptions from that client. Conceptually, a PUSH message is a session-level mechanism, not a subscription-level one πŸŽ€ Once it has used up the change notifications immediately available for that client, the server SHOULD send the PUSH message right away, rather than waiting around speculatively to see if more notifications show up.

For efficiency, when generating a PUSH message, the server SHOULD use standard DNS name compression, with offsets relative to the beginning of the DNS message [RFC1035]. When multiple change notifications in a single PUSH message have the same owner name, this name compression can yield significant savings πŸ”₯ Name compression should be performed as specified in Section 18.14 of the Multicast DNS specification [RFC6762]. Namely, owner names should always be compressed, and names appearing within RDATA should be compressed for only the RR types listed below:

NS, CNAME, PTR, DNAME, SOA, MX, AFSDB, RT, KX, RP, PX, SRV, NSEC

Servers MAY generate PUSH messages up to a maximum DNS message length of 16,382 bytes, counting from the start of the DSO 12-byte header. Including the two-byte length prefix used to frame DNS over a byte stream like TLS, that makes a total of 16,384 bytes. Servers MUST NOT generate PUSH messages larger than this. Where the immediately available change notifications are enough to exceed a DNS message length of 16,382 bytes, the change notifications MUST be communicated in separate PUSH messages of up to 16,382 bytes each. DNS name compression gets less effective for messages larger than 16,384 bytes, so there's very little efficiency benefit in sending anything bigger than this 🌈

If a client receives a PUSH message with a DNS message length larger than 16,382 bytes, that's a fatal error and the client MUST forcibly abort the connection immediately 🚨

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
    |           MESSAGE ID (MUST BE ZERO)           |   \
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    |QR| OPCODE(6) |         Z          |   RCODE   |    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    |             QDCOUNT (MUST BE ZERO)            |    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     > HEADER
    |             ANCOUNT (MUST BE ZERO)            |    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    |             NSCOUNT (MUST BE ZERO)            |    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    |             ARCOUNT (MUST BE ZERO)            |   /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /
    |            DSO-TYPE = PUSH (0x0041)           |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |   DSO-LENGTH (number of octets in DSO-DATA)   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
    \                     NAME                      \   \
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    |                     TYPE                      |    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    |                     CLASS                     |    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    |                      TTL                      |    |
    |     (32-bit unsigned big-endian integer)      |     > DSO-DATA
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    |  RDLEN (16-bit unsigned big-endian integer)   |    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    \           RDATA (sized as necessary)          \    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
    :     NAME, TYPE, CLASS, TTL, RDLEN, RDATA      :    |
    :             Repeated As Necessary             :   /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /

Figure 3: PUSH Message 🧁

When processing the records received in a PUSH message, the receiving client MUST validate that the records being added or removed correspond with at least one currently active subscription on that session πŸ” Specifically, the record name MUST match the name given in the SUBSCRIBE request, subject to the usual established DNS case-insensitivity for US-ASCII letters. For individual additions and removals, if the TYPE in the SUBSCRIBE request was not ANY (255), then the TYPE of the record must either be CNAME or match the TYPE given in the SUBSCRIBE request. And if the CLASS in the SUBSCRIBE request was not ANY (255), then the CLASS of the record MUST match the CLASS given in the SUBSCRIBE request. For collective removals, at least one of the records being removed MUST match an active subscription. If there's no matching active subscription on that session, that particular addition or removal record is silently ignored. The processing of the other additions and removal records in this message is not affected, and the DSO session is not closed. This is to allow for the unavoidable race condition where a client sends an outbound UNSUBSCRIBE while inbound PUSH messages for that subscription from the server are still in flight ✈️

The TTL of an added record is stored by the client. While the subscription is active, the TTL is NOT decremented, because a change to the TTL would produce a new update πŸ•°οΈ For as long as a relevant subscription remains active, the client SHOULD assume that when a record goes away, the server will notify it of that fact. So a client doesn't have to poll to check that the record is still there πŸ™Œ Once a subscription is canceled (individually, or because the DSO session was closed), record aging for records covered by the subscription resumes, and records are removed from the local cache when their TTL reaches zero.


6.4. DNS Push Notification UNSUBSCRIBE ✨

To cancel an individual subscription without closing the entire DSO session, the client sends an UNSUBSCRIBE message over the established DSO session to the server πŸ¦‹

The entity that initiates an UNSUBSCRIBE message is, by definition, the client πŸ’œ A server MUST NOT send an UNSUBSCRIBE message over an existing session from a client. If a server does send an UNSUBSCRIBE message over a DSO session initiated by a client, or if an UNSUBSCRIBE message is sent with the QR bit set (indicating that it's a response), that's a fatal error and the receiver MUST forcibly abort the connection immediately πŸ›‘

6.4.1. UNSUBSCRIBE Message πŸ’Œ

Okay so an UNSUBSCRIBE is a unidirectional message πŸ’… It starts with the standard DSO 12-byte header [RFC8490], then the UNSUBSCRIBE Primary TLV goes right after it. Figure 4 shows the whole thing πŸ¦‹

Because that's how DSO unidirectional messages work, the MESSAGE ID field MUST be zero πŸ™ˆ And the server never replies to an UNSUBSCRIBE, so there's no response to wait around for ✨

All the other header fields MUST be set the way the DSO specification [RFC8490] describes πŸŽ€ The DNS OPCODE field holds the OPCODE value for DNS Stateful Operations, which is 6. The four count fields must be zero, and their four sections must be empty (aka absent) πŸ“

The DSO-TYPE is UNSUBSCRIBE (0x0042) πŸ’œ

The DSO-LENGTH field is 2, which is just the size of the 2-octet MESSAGE ID sitting in the DSO-DATA 🌸

The DSO-DATA holds the value that was previously in the MESSAGE ID field of an active SUBSCRIBE request. That's how the server knows which SUBSCRIBE is getting canceled πŸ”₯ Once the UNSUBSCRIBE arrives, that SUBSCRIBE request is no longer active πŸ’€

Clients are allowed to send an UNSUBSCRIBE for a SUBSCRIBE they haven't gotten a response to yet πŸ‘‘ This is for when a client starts and stops a subscription in less time than the round-trip to the server. The client is NOT required to wait for the SUBSCRIBE response before sending the UNSUBSCRIBE 🫢

So a server can totally receive an UNSUBSCRIBE that doesn't match any active subscription πŸ™ˆ That can happen when a client sends a SUBSCRIBE, it fails and returns an error code, but the client already sent an UNSUBSCRIBE before it found out the SUBSCRIBE had failed. Because of this, servers MUST silently ignore UNSUBSCRIBE messages that do not match any currently active subscription 😭

                                      1  1  1  1  1  1
        0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
      |           MESSAGE ID (MUST BE ZERO)           |   \
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |QR| OPCODE(6) |         Z          |   RCODE   |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             QDCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     > HEADER
      |             ANCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             NSCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             ARCOUNT (MUST BE ZERO)            |   /
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /
      |         DSO-TYPE = UNSUBSCRIBE (0x0042)       |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |                DSO-LENGTH (2)                 |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
      |              SUBSCRIBE MESSAGE ID             |   > DSO-DATA
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /

Figure 4: UNSUBSCRIBE Message


6.5. DNS Push Notification RECONFIRM ✨

Sometimes, especially when a Discovery Proxy [RFC8766] is involved, a DNS Zone can hold stale data πŸ₯Ί When a client runs into data it thinks might be stale (like an SRV record pointing at a target host+port that isn't answering connection requests), the client can send a RECONFIRM message to ask the server to re-check that the data is still valid πŸ” For a Discovery Proxy, that means it issues new Multicast DNS queries to find out whether the target device is still around. How the Discovery Proxy kicks off those queries depends on the details of the Multicast DNS implementation underneath it πŸ› οΈ For example, a Discovery Proxy built on Apple's dns_sd.h API [SD-API] answers a DNS Push Notification RECONFIRM message by calling the underlying API's DNSServiceReconfirmRecord() routine 🍎

For other types of DNS server, the RECONFIRM operation is currently undefined. It SHOULD result in a NOERROR response, but it doesn't need to trigger any other action πŸ€·β€β™€οΈ

Lots of RECONFIRM operations can be a sign of network unreliability or some kind of misconfiguration 🚨 So RECONFIRM operations MAY be logged or otherwise passed along to a human administrator, to help catch and fix those network problems πŸ§‘β€πŸ’»

If, after getting a valid RECONFIRM message, the server decides the disputed records really aren't valid anymore, then subsequent DNS PUSH Messages will go out to inform interested clients πŸ“£ So when one client finds out a previously advertised device (like a network printer) is gone, it has the side effect of letting every other interested client know that the device is now gone too πŸ–¨οΈπŸ’¨

The entity that starts a RECONFIRM message is, by definition, the client πŸ‘‘ A server MUST NOT send a RECONFIRM message over an existing session from a client. If a server does send a RECONFIRM message over a DSO session that a client initiated, or a RECONFIRM message comes in with the QR bit set (meaning it's a response), that's a fatal error and the receiver MUST forcibly abort the connection immediately 🚫πŸ’₯

6.5.1. RECONFIRM Message πŸŽ€

A RECONFIRM unidirectional message starts with the standard DSO 12-byte header [RFC8490], then the RECONFIRM Primary TLV follows. Figure 5 shows what a RECONFIRM message looks like πŸ¦‹

Because of the DSO unidirectional message rules, the MESSAGE ID field MUST be zero. And there's no server response to a RECONFIRM message either πŸ™…β€β™€οΈ

The other header fields MUST be set as the DSO specification [RFC8490] describes. The DNS OPCODE field holds the OPCODE value for DNS Stateful Operations, 6. The four count fields must be zero, and the matching four sections must be empty (aka absent) πŸ’–

The DSO-TYPE is RECONFIRM (0x0043) πŸ’œ

The DSO-LENGTH is the length of the data that comes after it, and that data spells out the name, type, class, and content of the record being disputed 🧾

A DNS Push Notifications RECONFIRM message holds exactly one RECONFIRM Primary TLV 🎯 The DSO-DATA in a RECONFIRM Primary TLV MUST contain exactly one record. It has no count field, so it can't specify more than one record πŸ™…β€β™€οΈ Since RECONFIRM messages go over TCP, several of them can be stacked up in a single TCP stream and packed nicely into TCP segments πŸ§ƒ But that also means DNS name compression can't be used between different RECONFIRM messages πŸ˜΅β€πŸ’« Still, a client only sends a bunch of RECONFIRM messages when there are serious network problems, and that's not expected to happen often enough that making this case more efficient is important πŸ€·β€β™€οΈ

TYPE MUST NOT be the value ANY (255), and CLASS MUST NOT be the value ANY (255) 🚫

DNS wildcarding isn't supported πŸ™…β€β™€οΈ An asterisk character ("") in a RECONFIRM message only matches a literal asterisk character ("") in a name, and nothing else. Same deal for a CNAME in a RECONFIRM message: it only matches a CNAME record with that name in the zone, and no other records with that name 🌡

There's no RDLEN field, because the length of the RDATA can be worked out from DSO-LENGTH, so an extra RDLEN field would be redundant 🧠

Following the same rules as for PUSH messages, DNS name compression SHOULD be used within the RDATA of the RECONFIRM message, with offsets relative to the beginning of the DNS message [RFC1035] πŸ—œοΈ

                                      1  1  1  1  1  1
        0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
      |           MESSAGE ID (MUST BE ZERO)           |   \
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |QR| OPCODE(6) |         Z          |   RCODE   |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             QDCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     > HEADER
      |             ANCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             NSCOUNT (MUST BE ZERO)            |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |             ARCOUNT (MUST BE ZERO)            |   /
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /
      |         DSO-TYPE = RECONFIRM (0x0043)         |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      |   DSO-LENGTH (number of octets in DSO-DATA)   |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  \
      \                     NAME                      \   \
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      |                     TYPE                      |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     > DSO-DATA
      |                     CLASS                     |    |
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+    |
      \                     RDATA                     \   /
      +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+  /

Figure 5: RECONFIRM Message


6.6. DNS Stateful Operations TLV Context Summary πŸ—‚οΈ

This document defines four new DSO TLVs. As recommended in Section 8.2 of the DNS Stateful Operations specification [RFC8490], the valid contexts for these new TLV types are summarized below πŸ’•

The client TLV contexts are:

  • C-P: Client request message, Primary TLV
  • C-U: Client Unidirectional message, primary TLV
  • C-A: Client request or unidirectional message, Additional TLV
  • CRP: Response back to client, Primary TLV
  • CRA: Response back to client, Additional TLV
           +-------------+-----+-----+-----+-----+-----+
           |    TLV Type | C-P | C-U | C-A | CRP | CRA |
           +=============+=====+=====+=====+=====+=====+
           |   SUBSCRIBE |  X  |     |     |     |     |
           +-------------+-----+-----+-----+-----+-----+
           |        PUSH |     |     |     |     |     |
           +-------------+-----+-----+-----+-----+-----+
           | UNSUBSCRIBE |     |  X  |     |     |     |
           +-------------+-----+-----+-----+-----+-----+
           |   RECONFIRM |     |  X  |     |     |     |
           +-------------+-----+-----+-----+-----+-----+

Table 2: DSO TLV Client Context Summary

The server TLV contexts are:

  • S-P: Server request message, Primary TLV
  • S-U: Server Unidirectional message, primary TLV
  • S-A: Server request or unidirectional message, Additional TLV
  • SRP: Response back to server, Primary TLV
  • SRA: Response back to server, Additional TLV
           +-------------+-----+-----+-----+-----+-----+
           |    TLV Type | S-P | S-U | S-A | SRP | SRA |
           +=============+=====+=====+=====+=====+=====+
           |   SUBSCRIBE |     |     |     |     |     |
           +-------------+-----+-----+-----+-----+-----+
           |        PUSH |     |  X  |     |     |     |
           +-------------+-----+-----+-----+-----+-----+
           | UNSUBSCRIBE |     |     |     |     |     |
           +-------------+-----+-----+-----+-----+-----+
           |   RECONFIRM |     |     |     |     |     |
           +-------------+-----+-----+-----+-----+-----+

Table 3: DSO TLV Server Context Summary

6.7. Client-Initiated Termination πŸ¦‹

okay so ending a subscription is giving "bye, I'm out" πŸ‘‹. You can shut down one specific subscription by sending an UNSUBSCRIBE TLV for it, or you can cancel every subscription at once by closing the whole DSO session πŸ’…. When a client drops one subscription (via UNSUBSCRIBE) or all of them on a session (by ending the session), it's basically telling the server "I'm no longer interested in those updates," and the server is allowed to free up any state it's been holding for them ✨.

After a client terminates its last subscription on a session via UNSUBSCRIBE, it MAY close the session right away, or it can keep the session open if it's expecting to do more stuff on it later 🌸. If a client wants to keep an idle session open, it MUST respect the maximum idle time that the server requires [RFC8490] ⏰.

If a client is done with one or more subscriptions on a session and doesn't plan to keep the session open, it MAY take the efficiency shortcut and just close the session, which automatically ends every subscription on it 🧚. This can happen when the client computer is shutting down or going to sleep, when the app that needed the subscriptions has quit, or just because the last active subscription on that session got canceled πŸ’œ.

When closing a session, a client should do an orderly close of the TLS session πŸŽ€. Most APIs have a session close method that sends a TLS close_notify alert, as described in Section 6.1 of the TLS 1.3 specification [RFC8446]. That alert tells the other side that the sender won't send any more data over the session 🫢. After sending the TLS close_notify alert, the client MUST gracefully close the underlying connection with a TCP FIN so the TLS close_notify actually gets delivered reliably 😭. How you send a TCP FIN depends on your networking API. For example, in the BSD Sockets API, you send one by calling shutdown(s,SHUT_WR) and then keeping the socket open until all the remaining data has been read from it πŸ“.

If the session gets forcibly closed at the TCP level by sending a RST from either end of the connection, data may be lost. πŸ’€

6.8. Client Fallback to Polling 🌈

sometimes a client tries every single route to set up a DNS Push Notification subscription and it just... doesn't work 😀. That can happen if the client's configured recursive resolver doesn't support DNS over TLS, or supports it but isn't listening on TCP port 853, or supports DNS over TLS on TCP port 853 but doesn't support DSO on that port, or is just unable to provide a subscription for some other reason πŸ™ˆ. In that situation, the client will try to talk directly to an appropriate server, and maybe the zone apex discovery fails, or there's no "_dns-push-tls._tcp.<zone>" SRV record, or the server named in the SRV record is misconfigured, overloaded, or unresponsive for some other reason πŸ’”.

Whatever the reason it failed, the client still probably wants the answer it was after, even if it can't get it with the real-time change notifications that DNS Push Notifications provide πŸ‘€. So the client will most likely get its answer with a regular DNS query instead, repeated at some interval to spot when the answer RRset changes πŸ”.

If a client falls back to polling with conventional DNS queries after failing to set up a DNS Push Notification subscription, it needs to keep the polling rate under control so it doesn't dump excessive load on the server 🫠. The interval between successive DNS queries for the same name, type, and class SHOULD be at least the minimum of 900 seconds (15 minutes) or two seconds more than the TTL of the answer RRset πŸ•°οΈ.

The reason that, for TTLs up to 898 seconds, the query shouldn't be reissued until two seconds after the answer RRset has expired is to make sure the answer RRset has also expired from the cache on the client's configured recursive resolver 🧠. Otherwise (especially if the clocks on the client and the recursive resolver don't tick at exactly the same rate), you can get a race condition 😬. The client queries its recursive resolver just as the answer RRset has one second left in that resolver's cache. The client gets a reply saying one second remains, so it requeries one second later. If the answer RRset has actually expired from the recursive resolver's cache by then, the recursive resolver issues a new query to fetch fresh data from the authoritative server. Waiting until the answer RRset has definitely expired from the cache on the client's configured recursive resolver avoids this race condition and any extra unnecessary queries it would cause πŸ™Œ.

Each time a client is about to reissue its query to find changes to the answer RRset, it should first try again to set up a DNS Push Notification subscription, using previously cached DNS answers where appropriate πŸ”„. Once a temporary misconfiguration has been fixed, this lets a polling client switch back to DNS Push Notifications for asynchronous notification of changes πŸŽ‰.

7. Security Considerations πŸ”

The Strict Privacy profile for DNS over TLS is REQUIRED for DNS Push Notifications [RFC8310] πŸ›‘οΈ. Cleartext connections for DNS Push Notifications are not permissible. Since this is a brand-new protocol, there's no need for transition mechanisms from the Opportunistic Privacy profile πŸ™…β€β™€οΈ.

Also, check out Section 9 of the document Usage Profiles for DNS over (D)TLS [RFC8310] for extra recommendations on the various versions of TLS usage πŸ“–.

Because TLS is required, the server may also enforce client certificate authentication and verification, for stronger client-server security or end-to-end security πŸͺͺ. Recommendations for security in specific deployment scenarios are outside the scope of this document πŸ€·β€β™€οΈ.

DNSSEC is RECOMMENDED for authenticating DNS Push Notification servers πŸ”‘. TLS on its own does not provide complete security 😳. TLS certificate verification can give reasonable assurance that the client is really talking to the server tied to the desired host name. But because the desired host name is learned through a DNS SRV query, if that SRV query gets subverted, the client might have a secure connection to a rogue server πŸ‘Ύ. DNSSEC can add confidence that the SRV query hasn't been subverted πŸ’….

7.1. Security Services πŸ’œ

Using TLS is meant to provide the following security services ✨:

  • Confidentiality: All application-layer communication is encrypted, with the goal that no party should be able to decrypt it except the intended receiver πŸ”’.
  • Data integrity protection: Any changes made to the communication in transit are detectable by the receiver πŸ•΅οΈβ€β™€οΈ.
  • Authentication: An endpoint of the TLS communication is authenticated as the intended entity to communicate with πŸͺͺ.
  • Anti-replay protection: TLS provides for the detection of, and prevention against, messages sent previously over a TLS connection (such as DNS Push Notifications). If prior messages are re-sent later as a man-in-the-middle attack, the receiver will detect this and reject the replayed messages 🚫.

Deployment recommendations on appropriate key lengths and cipher suites are beyond the scope of this document. For best current practices, please refer to the current TLS Recommendations [BCP195] πŸ“š. Keep in mind that best practices only exist for a snapshot in time, and recommendations will keep changing. Updated versions or errata may exist for these recommendations πŸ”„.

7.2. TLS Name Authentication 🏷️

As described in Section 6.1, the client discovers the DNS Push Notification server with an SRV lookup for the record name "_dns-push-tls._tcp.<zone>". The server connection endpoint SHOULD then be authenticated using DANE TLSA records for the associated SRV record πŸ”. This ties the target's name and port number to a trusted TLS certificate [RFC7673] πŸŽ€.

This procedure uses the TLS Server Name Indication (SNI) extension [RFC6066] to tell the server which name the client has authenticated through TLSA records πŸ“£. So if the SRV record passes DNSSEC validation and a usable TLSA record matches the target name, an SNI extension must be used for the target name, so the client knows it's connecting to the server it authenticated 🫢. If the target name doesn't have a usable TLSA record, then using SNI is optional πŸ™‚. For more on authenticating domain names, see Usage Profiles for DNS over TLS and DNS over DTLS [RFC8310] πŸ“–.

7.3. TLS Early Data ⏩

DSO messages with the SUBSCRIBE TLV as the Primary TLV are permitted in TLS early data πŸƒβ€β™€οΈ. Using TLS early data can save one network round trip and can get the client its results faster ⚑.

There are some factors to think about before using TLS early data πŸ€”.

TLS early data is not forward secret. If forward secrecy of DNS Push Notification subscriptions is required, the client should not use TLS early data πŸ”.

With TLS early data, there are no guarantees of non-replay between connections. If packets are duplicated and delayed in the network, the later arrivals could be mistaken for new subscription requests πŸŒ€. Generally this isn't a major concern, since the amount of state the server creates for these spurious subscriptions is small and short-lived, because the TCP connection will never complete the three-way handshake πŸ€“. Servers MAY choose to implement rate-limiting measures that activate when the server detects an excessive number of spurious subscription requests 🚦.

For more guidance on TLS early data, check out the discussion of zero round-trip data in Sections 2.3 and 8, and Appendix E.5, of the TLS 1.3 specification [RFC8446] πŸ“š.

7.4. TLS Session Resumption πŸ”

TLS session resumption [RFC8446] is permissible on DNS Push Notification servers. However, closing the TLS connection terminates the DSO session 🫣. When the TLS session is resumed, the DNS Push Notification server won't have any subscription state, and it will proceed as it would with any other new DSO session πŸ†•. Session resumption may let a TLS connection get set up more quickly, but the client will still have to recreate any subscriptions it wants πŸ’–.

8. IANA Considerations ✨

okay bestie, so this section is basically the paperwork bit πŸ“‹πŸ’… It's where the IANA (the folks who keep the official registries) gets told what's been added. Two main things are getting registered here: one new service name, and four new DSO TLV types πŸŽ€

This document defines a new service name, and it only applies to the TCP protocol πŸ¦‹ It has been recorded in the IANA "Service Name and Transport Protocol Port Number Registry" [RFC6335] [SRVTYPE]. Iconic, honestly.

Here's the service name entry:

     +-----------------------+------+----------------------+---------+
     | Name                  | Port |        Value         | Section |
     +=======================+======+======================+=========+
     | DNS Push Notification | None | "_dns-push-tls._tcp" |   6.1   |
     | Service Type          |      |                      |         |
     +-----------------------+------+----------------------+---------+

                   Table 4: IANA Service Type Assignments

This document defines four new DNS Stateful Operation TLV types 🌸 These have been recorded in the IANA "DSO Type Codes" registry [RFC8490] [DSOTYPE]. Main character energy for the DSO world, no cap πŸ‘‘

And here are the four TLVs, with their values, early data status, and status (all Standards Track, slay):

     +-------------+--------+------------+-----------------+---------+
     | Name        | Value  | Early Data |      Status     | Section |
     +=============+========+============+=================+=========+
     | SUBSCRIBE   | 0x0040 |     OK     | Standards Track |   6.2   |
     +-------------+--------+------------+-----------------+---------+
     | PUSH        | 0x0041 |     NO     | Standards Track |   6.3   |
     +-------------+--------+------------+-----------------+---------+
     | UNSUBSCRIBE | 0x0042 |     NO     | Standards Track |   6.4   |
     +-------------+--------+------------+-----------------+---------+
     | RECONFIRM   | 0x0043 |     NO     | Standards Track |   6.5   |
     +-------------+--------+------------+-----------------+---------+

                Table 5: IANA DSO TLV Type Code Assignments

This document defines no new DNS OPCODEs or RCODEs πŸ™ˆ So nothing new there, bestie. Just the service name and the four TLVs.


9. References πŸ“š

9.1. Normative References πŸ’œ

These are the must-read ones, the foundations everything else sits on:

   [DSOTYPE]  IANA, "Domain Name System (DNS) Parameters",
              <https://www.iana.org/assignments/dns-parameters/>.

   [RFC0020]  Cerf, V., "ASCII format for network interchange", STD 80,
              RFC 20, DOI 10.17487/RFC0020, October 1969,
              <https://www.rfc-editor.org/info/rfc20>.

   [RFC0768]  Postel, J., "User Datagram Protocol", STD 6, RFC 768,
              DOI 10.17487/RFC0768, August 1980,
              <https://www.rfc-editor.org/info/rfc768>.

   [RFC0793]  Postel, J., "Transmission Control Protocol", STD 7,
              RFC 793, DOI 10.17487/RFC0793, September 1981,
              <https://www.rfc-editor.org/info/rfc793>.

   [RFC1034]  Mockapetris, P., "Domain names - concepts and facilities",
              STD 13, RFC 1034, DOI 10.17487/RFC1034, November 1987,
              <https://www.rfc-editor.org/info/rfc1034>.

   [RFC1035]  Mockapetris, P., "Domain names - implementation and
              specification", STD 13, RFC 1035, DOI 10.17487/RFC1035,
              November 1987, <https://www.rfc-editor.org/info/rfc1035>.

   [RFC1123]  Braden, R., Ed., "Requirements for Internet Hosts -
              Application and Support", STD 3, RFC 1123,
              DOI 10.17487/RFC1123, October 1989,
              <https://www.rfc-editor.org/info/rfc1123>.

   [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>.

   [RFC2136]  Vixie, P., Ed., Thomson, S., Rekhter, Y., and J. Bound,
              "Dynamic Updates in the Domain Name System (DNS UPDATE)",
              RFC 2136, DOI 10.17487/RFC2136, April 1997,
              <https://www.rfc-editor.org/info/rfc2136>.

   [RFC2181]  Elz, R. and R. Bush, "Clarifications to the DNS
              Specification", RFC 2181, DOI 10.17487/RFC2181, July 1997,
              <https://www.rfc-editor.org/info/rfc2181>.

   [RFC2782]  Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for
              specifying the location of services (DNS SRV)", RFC 2782,
              DOI 10.17487/RFC2782, February 2000,
              <https://www.rfc-editor.org/info/rfc2782>.

   [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>.

   [RFC6335]  Cotton, M., Eggert, L., Touch, J., Westerlund, M., and S.
              Cheshire, "Internet Assigned Numbers Authority (IANA)
              Procedures for the Management of the Service Name and
              Transport Protocol Port Number Registry", BCP 165,
              RFC 6335, DOI 10.17487/RFC6335, August 2011,
              <https://www.rfc-editor.org/info/rfc6335>.

   [RFC6895]  Eastlake 3rd, D., "Domain Name System (DNS) IANA
              Considerations", BCP 42, RFC 6895, DOI 10.17487/RFC6895,
              April 2013, <https://www.rfc-editor.org/info/rfc6895>.

   [RFC7673]  Finch, T., Miller, M., and P. Saint-Andre, "Using DNS-
              Based Authentication of Named Entities (DANE) TLSA Records
              with SRV Records", RFC 7673, DOI 10.17487/RFC7673, October
              2015, <https://www.rfc-editor.org/info/rfc7673>.

   [RFC7766]  Dickinson, J., Dickinson, S., Bellis, R., Mankin, A., and
              D. Wessels, "DNS Transport over TCP - Implementation
              Requirements", RFC 7766, DOI 10.17487/RFC7766, March 2016,
              <https://www.rfc-editor.org/info/rfc7766>.

   [RFC7858]  Hu, Z., Zhu, L., Heidemann, J., Mankin, A., Wessels, D.,
              and P. Hoffman, "Specification for DNS over Transport
              Layer Security (TLS)", RFC 7858, DOI 10.17487/RFC7858, May
              2016, <https://www.rfc-editor.org/info/rfc7858>.

   [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>.

   [RFC8310]  Dickinson, S., Gillmor, D., and T. Reddy, "Usage Profiles
              for DNS over TLS and DNS over DTLS", RFC 8310,
              DOI 10.17487/RFC8310, March 2018,
              <https://www.rfc-editor.org/info/rfc8310>.

   [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>.

   [RFC8490]  Bellis, R., Cheshire, S., Dickinson, J., Dickinson, S.,
              Lemon, T., and T. Pusateri, "DNS Stateful Operations",
              RFC 8490, DOI 10.17487/RFC8490, March 2019,
              <https://www.rfc-editor.org/info/rfc8490>.

   [SRVTYPE]  IANA, "Service Name and Transport Protocol Port Number
              Registry", <https://www.iana.org/assignments/service-
              names-port-numbers/>.

9.2. Informative References 🧚

And these are the extra-credit reads, the "ooh tell me more" section:

   [BCP195]   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, May 2015,
              <https://www.rfc-editor.org/info/bcp195>.

   [OBS]      Wikipedia, "Observer pattern", February 2020,
              <https://en.wikipedia.org/w/
              index.php?title=Observer_pattern&oldid=939702131>.

   [RFC2308]  Andrews, M., "Negative Caching of DNS Queries (DNS
              NCACHE)", RFC 2308, DOI 10.17487/RFC2308, March 1998,
              <https://www.rfc-editor.org/info/rfc2308>.

   [RFC3123]  Koch, P., "A DNS RR Type for Lists of Address Prefixes
              (APL RR)", RFC 3123, DOI 10.17487/RFC3123, June 2001,
              <https://www.rfc-editor.org/info/rfc3123>.

   [RFC4287]  Nottingham, M., Ed. and R. Sayre, Ed., "The Atom
              Syndication Format", RFC 4287, DOI 10.17487/RFC4287,
              December 2005, <https://www.rfc-editor.org/info/rfc4287>.

   [RFC4953]  Touch, J., "Defending TCP Against Spoofing Attacks",
              RFC 4953, DOI 10.17487/RFC4953, July 2007,
              <https://www.rfc-editor.org/info/rfc4953>.

   [RFC6281]  Cheshire, S., Zhu, Z., Wakikawa, R., and L. Zhang,
              "Understanding Apple's Back to My Mac (BTMM) Service",
              RFC 6281, DOI 10.17487/RFC6281, June 2011,
              <https://www.rfc-editor.org/info/rfc6281>.

   [RFC6762]  Cheshire, S. and M. Krochmal, "Multicast DNS", RFC 6762,
              DOI 10.17487/RFC6762, February 2013,
              <https://www.rfc-editor.org/info/rfc6762>.

   [RFC6763]  Cheshire, S. and M. Krochmal, "DNS-Based Service
              Discovery", RFC 6763, DOI 10.17487/RFC6763, February 2013,
              <https://www.rfc-editor.org/info/rfc6763>.

   [RFC6886]  Cheshire, S. and M. Krochmal, "NAT Port Mapping Protocol
              (NAT-PMP)", RFC 6886, DOI 10.17487/RFC6886, April 2013,
              <https://www.rfc-editor.org/info/rfc6886>.

   [RFC6887]  Wing, D., Ed., Cheshire, S., Boucadair, M., Penno, R., and
              P. Selkirk, "Port Control Protocol (PCP)", RFC 6887,
              DOI 10.17487/RFC6887, April 2013,
              <https://www.rfc-editor.org/info/rfc6887>.

   [RFC7413]  Cheng, Y., Chu, J., Radhakrishnan, S., and A. Jain, "TCP
              Fast Open", RFC 7413, DOI 10.17487/RFC7413, December 2014,
              <https://www.rfc-editor.org/info/rfc7413>.

   [RFC8010]  Sweet, M. and I. McDonald, "Internet Printing
              Protocol/1.1: Encoding and Transport", STD 92, RFC 8010,
              DOI 10.17487/RFC8010, January 2017,
              <https://www.rfc-editor.org/info/rfc8010>.

   [RFC8011]  Sweet, M. and I. McDonald, "Internet Printing
              Protocol/1.1: Model and Semantics", STD 92, RFC 8011,
              DOI 10.17487/RFC8011, January 2017,
              <https://www.rfc-editor.org/info/rfc8011>.

   [RFC8499]  Hoffman, P., Sullivan, A., and K. Fujiwara, "DNS
              Terminology", BCP 219, RFC 8499, DOI 10.17487/RFC8499,
              January 2019, <https://www.rfc-editor.org/info/rfc8499>.

   [RFC8684]  Ford, A., Raiciu, C., Handley, M., Bonaventure, O., and C.
              Paasch, "TCP Extensions for Multipath Operation with
              Multiple Addresses", RFC 8684, DOI 10.17487/RFC8684, March
              2020, <https://www.rfc-editor.org/info/rfc8684>.

   [RFC8764]  Cheshire, S. and M. Krochmal, "Apple's DNS Long-Lived
              Queries Protocol", RFC 8764, DOI 10.17487/RFC8764, June
              2020, <https://www.rfc-editor.org/info/rfc8764>.

   [RFC8766]  Cheshire, S., "Discovery Proxy for Multicast DNS-Based
              Service Discovery", RFC 8766, DOI 10.17487/RFC8766, June
              2020, <https://www.rfc-editor.org/info/rfc8766>.

   [SD-API]   Apple Inc., "dns_sd.h",
              <https://opensource.apple.com/source/mDNSResponder/
              mDNSResponder-878.70.2/mDNSShared/dns_sd.h.auto.html>.

   [SYN]      Eddy, W., "Defenses Against TCP SYN Flooding Attacks", The
              Internet Protocol Journal, Cisco Systems, Volume 9, Number
              4, December 2006,
              <https://www.cisco.com/web/about/ac123/ac147/
              archived_issues/ipj_9-4/ipj_9-4.pdf>.

   [TCPRACK]  Cheng, Y., Cardwell, N., Dukkipati, N., and P. Jha, "RACK:
              a time-based fast loss detection algorithm for TCP", Work
              in Progress, Internet-Draft, draft-ietf-tcpm-rack-08, 9
              March 2020,
              <https://tools.ietf.org/html/draft-ietf-tcpm-rack-08>.

   [XEP0060]  Millard, P., Saint-Andre, P., and R. Meijer, "Publish-
              Subscribe", XSF XEP 0060, October 2019,
              <https://xmpp.org/extensions/xep-0060.html>.

Acknowledgments ✨

Okay bestie, first things first: the authors want to thank Kiren Sekar and Marc Krochmal 🫢 for the earlier work they did in this field. Without that groundwork, this whole spec would not exist, and we honor the people who came before us πŸ’œ.

This document got way better thanks to comments from Ran Atkinson, Tim Chown, Sara Dickinson, Mark Delany, Ralph Droms, Jan Komissar, Eric Rescorla, Michael Richardson, David Schinazi, Manju Shankar Rao, Robert Sparks, Markus Stenberg, Andrew Sullivan, Michael Sweet, Dave Thaler, Brian Trammell, Bernie Volz, Γ‰ric Vyncke, Christopher Wood, Liang Xia, and Soraia Zlatkovic. Absolutely iconic reviewers, the whole squad πŸ‘‘πŸ”₯. Ted Lemon also gave some clarifying text that was genuinely appreciated 🌸.


Authors' Addresses ✨

Tom Pusateri πŸ¦‹ Unaffiliated Raleigh, NC 27608 United States of America

Phone: +1 919 867 1330 Email: pusateri@bangj.com

Stuart Cheshire πŸŽ€ Apple Inc. One Apple Park Way Cupertino, CA 95014 United States of America

Phone: +1 (408) 996-1010 Email: cheshire@apple.com

πŸ“¦ where this page comes from