RFC 9868

Transport Options for UDP

๐Ÿ“… published October 2025, from ietf

Transport Options for UDP ๐ŸŽ€

RFC 9868 โœจ (October 2025)

  • Authors: J. Touch (Independent Consultant) and C. Heard, Ed. (Unaffiliated) ๐Ÿ’–
  • Category: Standards Track ๐Ÿ”ฅ
  • Stream: Internet Engineering Task Force (IETF) ๐ŸŒธ
  • ISSN: 2070-1721
  • Updates: RFC 768 (UDP) ๐Ÿฆ‹

Abstract

okay so the big idea here is that transport protocols get extended with transport header options ๐Ÿงš this doc updates RFC 768 (UDP) by saying where UDP options live, what they look like, and what they mean. the spot is the surplus area after the end of the UDP user data but before the end of the IP datagram ๐Ÿ’…


Status of This Memo

this is an Internet Standards Track document ๐Ÿซถ

it's a product of the Internet Engineering Task Force (IETF) and it represents the consensus of the IETF community. 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 give feedback, go to https://www.rfc-editor.org/info/rfc9868 ๐ŸŒˆ


Copyright (c) 2025 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) in effect on the date of publication. please actually read those, bestie, because they describe your rights and restrictions for this doc ๐Ÿ™ˆ also, Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions, and they're provided without warranty as described in the Revised BSD License โš–๏ธ


Table of Contents

1.  Introduction
2.  Conventions Used in This Document
3.  Terminology
4.  Background
5.  UDP Option Intended Uses
6.  UDP Option Design Principles
7.  The UDP Option Area
8.  The UDP Surplus Area Structure
9.  The Option Checksum (OCS)
10. UDP Options
11. SAFE UDP Options
  11.1.  End of Options List (EOL)
  11.2.  No Operation (NOP)
  11.3.  Additional Payload Checksum (APC)
  11.4.  Fragmentation (FRAG)
  11.5.  Maximum Datagram Size (MDS)
  11.6.  Maximum Reassembled Datagram Size (MRDS)
  11.7.  Echo Request (REQ) and Echo Response (RES)
  11.8.  Timestamp (TIME)
  11.9.  Authentication (AUTH), RESERVED Only
  11.10. Experimental (EXP)
12. UNSAFE Options
  12.1.  UNSAFE Compression (UCMP)
  12.2.  UNSAFE Encryption (UENC)
  12.3.  UNSAFE Experimental (UEXP)
13. Rules for Designing New Options
14. Option Inclusion and Processing
15. UDP API Extensions
16. UDP Options Are for Transport, Not Transit
17. UDP Options vs. UDP-Lite
18. Interactions with Legacy Devices
19. Options in a Stateless, Unreliable Transport Protocol
20. UDP Option State Caching
21. Updates to RFC 768
22. Interactions with Other RFCs
23. Multicast and Broadcast Considerations
24. Network Management Considerations
25. Security Considerations
  25.1.  General Considerations Regarding the Use of Options
  25.2.  Considerations Regarding On-Path Attacks
  25.3.  Considerations Regarding Option Processing
  25.4.  Considerations for Fragmentation
  25.5.  Considerations for Providing UDP Security
  25.6.  Considerations Regarding Middleboxes
26. IANA Considerations
27. References
  27.1.  Normative References
  27.2.  Informative References
Appendix A.  Implementation Information
Acknowledgments
Authors' Addresses

1. Introduction โœจ

transport protocols use options to level up their capabilities ๐Ÿ’… TCP [RFC9293], the Stream Control Transmission Protocol (SCTP) [RFC9260], and the Datagram Congestion Control Protocol (DCCP) [RFC4340] all have room for these options, but UDP [RFC0768] doesn't, and it's kind of the odd one out ๐Ÿ™ˆ this document updates RFC 768 with an extension that gives UDP space for transport options. it covers their generic syntax and how they're used in UDP's stateless, unreliable message protocol ๐Ÿฆ‹ the details of what this does to RFC 768 are in Section 21. and this extension does not apply to UDP-Lite, which Section 17 explains more ๐Ÿงš

2. Conventions Used in This Document ๐Ÿ“š

the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here ๐Ÿซถ so the caps are doing the heavy lifting, periodt ๐Ÿ’€

also, the characters >> at the beginning of a paragraph mean that paragraph is making a statement with one of those key words ๐Ÿ‘‘ it's there so reviewers can spot the important parts fast, which is honestly iconic of them ๐ŸŒธ

3. Terminology ๐Ÿ’œ

here's the vocab we're using ๐Ÿ“

  • IP datagram [RFC0791] [RFC8200]: an IP packet made of the IP header (including any IPv4 options) and an IP payload area (including any IPv6 extension headers or other shim headers) ๐Ÿ“ฆ
  • Must-support options: UDP Options that all implementations are required to support. their use in individual UDP packets is optional ๐ŸŒˆ
  • SAFE Options: UDP Options that are designed to be safe to ignore for a receiver that doesn't understand them. they don't alter the UDP user data or signal a change in what its contents represent ๐Ÿซง
  • Socket pair: a pair of sockets defining a UDP exchange, made of a remote socket and a local socket, each one an IP address plus a UDP port number (most widely known from TCP [RFC0793], which has been obsoleted by [RFC9293]) ๐Ÿ”Œ
  • Surplus area: the area of an IP payload that follows a UDP packet. this area is used for UDP Options in this document โœจ
  • UDP packet: the more contemporary term used here to refer to a user datagram [RFC0768] ๐Ÿฆ‹
  • UDP fragment: one or more components of a UDP packet and its UDP Options that enable transmission over multiple IP payloads, larger than the maximum size of a single IP packet allows. each UDP fragment is itself transmitted as a UDP packet with its own options ๐Ÿงฉ
  • (UDP) User data: the user data field of a UDP packet [RFC0768] ๐Ÿ’Œ
  • UDP Length: the length field of a UDP header [RFC0768] ๐Ÿ“
  • UNSAFE Options: UDP Options that are not designed to be safely ignored by a receiver that doesn't understand them. they could alter the UDP user data or signal a change in what its contents represent, but there are restrictions on how they can be transmitted. those restrictions are noted in Sections 10 and 12 โš ๏ธ
  • User: the upper layer application, protocol, or service that produces and consumes the content UDP transfers ๐Ÿง‘โ€๐Ÿ’ป
  • User datagram: a UDP packet made of a UDP header and UDP payload. as discussed here, the UDP payload doesn't have to reach the end of the IP datagram. this document redefines the original idea that a UDP datagram matches the user portion of a single IP datagram, because a UDP datagram can now span more than one IP datagram through UDP fragmentation ๐ŸŒŸ

4. Background ๐ŸŒธ

lots of protocols come with a default, invariant header and an area for header options that changes from packet to packet ๐Ÿ’– those options let a protocol get extended for particular environments, or in ways the original designers never saw coming ๐Ÿงš examples include TCP's Maximum Segment Size (MSS), Window Scale, Timestamp, and Authentication Options [RFC9293] [RFC5925] [RFC7323] ๐ŸŽ€

header options show up in both stateful (connection-oriented, e.g., TCP [RFC9293], SCTP [RFC9260], and DCCP [RFC4340]) and stateless (connectionless, e.g., IPv4 [RFC0791] and IPv6 [RFC8200]) protocols ๐ŸŒˆ in stateful protocols, they can help extend how state gets managed. in stateless protocols, their effect is usually limited to individual packets, but they can add up to an aggregate effect across a sequence of packets too ๐Ÿฆ‹

UDP is one of the most popular protocols that has no space for header options [RFC0768] ๐Ÿ˜ญ its header was meant to be a minimal addition to IP, giving only port numbers and a checksum for error detection ๐Ÿ’… this document extends UDP with a trailer area for those options, sitting after the UDP user data ๐Ÿซถ

UDP Options are possible because UDP has its own length field, separate from the IP header's. other transport protocols infer their transport payload length from the IP datagram length (TCP, DCCP, and SCTP) ๐Ÿ“ historians have floated a few reasons why UDP has this field, like supporting multiple UDP packets within the same IP datagram, or marking the length of the UDP user data apart from zero padding that some systems needed because they couldn't write an arbitrary number of bytes ๐Ÿค” those ideas don't line up with earlier versions of UDP or with the concurrent design of multi-segment, multiplexing protocols, though, so the real reason is still unknown ๐Ÿ™ˆ either way, this field gives us a chance to tell the UDP user data apart from the implied transport payload length, and this document uses that to support a trailer options field ๐Ÿ‘‘

there are other ways to add header fields or options to protocols that otherwise can't be extended. in particular, in-band encoding can tell transport payload apart from extra fields, like what was proposed in [Hi15] ๐Ÿงฉ that approach can cause complications with legacy devices, so this document doesn't consider it further ๐Ÿšซ

IPv6 Teredo extensions [RFC4380] [RFC6081] use a similar mismatch between UDP and IPv6 packet lengths to support trailers โœจ but here the values differ between the UDP header and an IPv6 length carried as the payload of the UDP user data. that allows IPv6 trailers in the UDP user data, and it has nothing to do with the surplus area this document talks about ๐Ÿฆ‹ so, as a result, Teredo extensions are compatible with UDP Options ๐Ÿ’œ

5. UDP Option Intended Uses โœจ

UDP Options give UDP a soft control plane ๐Ÿงš Bestie, that's the whole vibe. They bring back capabilities that other transport protocols already have, like fragmentation and reassembly. That means UDP frames bigger than the IP MTU can get through devices that look at transport ports, such as Network Address Translations (NATs), with no extra mechanisms or state needed ๐Ÿ™Œ It's giving efficiency.

They also add features that could someday protect transport integrity and validate source identity (authentication). Some could even encrypt the user payload while the UDP transport header stays protected, which is not something Datagram Transport Layer Security (DTLS) [RFC9147] does ๐Ÿ’… Then there's PLPMTUD over UDP, known as Datagram Packetization Layer Path Maximum Transmission Unit Discovery (DPLPMTUD) [RFC9869]. It gives a way to validate probe packets without touching the user data plane, and it provides an explicit indication of the receiver transport reassembly size. Iconic. ๐Ÿ˜ญ

UDP originally assumed that the user or a layer above UDP [RFC0768] would provide these capabilities. But enough protocols now use UDP directly that an intermediate layer would be hard to deploy for legacy applications ๐Ÿ’€ So UDP Options use that surplus area to enable these extensions inside the UDP transport layer itself โœจ One use case that could benefit is request-response protocols, like DNS over UDP [He24] ๐Ÿซถ


6. UDP Option Design Principles ๐ŸŒธ

UDP Options are built on the following core principles. Each one is either an observation about how UDP [RFC0768] already behaves without these extensions, which this document does not intend to change, or a lesson learned from other protocol designs. Main character energy, honestly ๐Ÿ‘‘

  1. UDP is stateless; UDP Options do not change that fact.

The state required or maintained by the endpoints is intended to be managed either by the application or by a layer or library acting on the application's behalf. Reassembly of fragments is the only limited exception where this document introduces a notion of state to UDP. ๐Ÿง 

  1. UDP is unidirectional; UDP Options do not change that fact.

Responses to options are initiated by the application or by a layer or library acting on the application's behalf. A mechanism that requires bidirectionality needs to be defined in a separate document ๐Ÿฆ‹

  1. UDP Options have no length limit separate from that of the UDP packet itself.

Past experience with other protocols confirms that static length limits will always need to be exceeded. TCP options and IPv4 addresses are a good example of that ๐Ÿ˜ญ Each implementation can limit how long or how many options there are, but a specification is more robust when it does not introduce such a limit. โœจ

  1. UDP Options are not intended to replace or replicate other protocols.

This includes NTP, ICMP (notably echo), and so on. UDP Options are meant to introduce features that are useful for applications. They are not meant to replace these other protocols, and they are not meant to instrument UDP so that it replaces the need for network testing devices ๐Ÿ™ˆ

  1. UDP Options are a framework, not a protocol.

Options can be defined in this initial document even when the details are not enough to specify a complete protocol. Uses of those options can then be described or supplemented in other documents. Examples here include REQ/RES and TIME. In both cases the option format is defined. The protocol that uses REQ/RES is specified elsewhere (for DPLPMTUD [RFC9869]), while the protocol that uses TIME is left undefined ๐Ÿงš

  1. The UDP Option mechanism and UDP Options themselves are intended to default to the same behavior experienced by a legacy receiver.

By default, even when option checksums (OCS, APC), authentication, or decryption fail, all received packets are passed to the user application, possibly with an empty data payload. The exception is UDP fragments, which are not passed. Options that do not modify user data are intended to result in the user data also being passed by default, even if option checksums or authentication fail, for example. It is always the user's or application's obligation to override this default behavior explicitly ๐Ÿ”ฅ

These principles are meant to enable the design and use of UDP Options with minimal impact on legacy UDP endpoints, ideally none at all. UDP is, and remains, a minimal transport protocol. Any extra capability is explicitly activated by user applications or by libraries acting on their behalf ๐Ÿ’œ

Last thing, and this one is important ๐Ÿ‘€ UDP Options do not try to match the number of zero-length UDP datagrams that legacy and option-aware receivers get from a source using UDP fragmentation (see Section 11.4). Legacy receivers interpret every UDP fragment as a zero-length packet, because they do not perform reassembly. Option-aware receivers, however, would reassemble the packet as a non-zero-length packet. Zero-length UDP packets have been used as "liveness" indicators (see Section 5 of [RFC8085]), but that use is dangerous because they lack unique identifiers. The IPv6 base header has none, and the IPv4 ID field is deprecated for such use [RFC6864]. Not it ๐Ÿ™…โ€โ™€๏ธ


7. The UDP Option Area ๐ŸŽ€

The UDP transport header includes demultiplexing and service identification (port numbers), an error detection checksum, and a field that indicates the UDP datagram length, including the UDP header. The UDP Length field is typically redundant with the size of the maximum space available as a transport protocol payload, which is determined by the IP header (see details in Section 18). The UDP Option area is created when the UDP Length indicates a smaller transport payload than the IP header implies ๐Ÿฆ‹

For IPv4, the IP Total Length field indicates the total IP datagram length, including the IP header. The size of the IP options is indicated in the IP header, in 4-byte words, as the "Internet Header Length" (IHL) [RFC0791], as shown in Figure 1. In exceptional cases the Protocol field in IPv4 might not indicate UDP (that is, 17). This can happen when intervening shim headers are present, such as IP Security (IPsec) [RFC4301] or IP Payload Compression (IPComp) [RFC3173] ๐ŸŒˆ

The upper bound for UDP Length when Protocol = 17 is given by:

   UDP_Length <= IPv4_Total_Length - IPv4_IHL * 4

If shim headers are present, this upper bound must be reduced by the sum of the lengths of the shim headers that precede the UDP header.

   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version|  IHL  |   DSCP    |ECN|          Total Length         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Identification        |Flags|      Fragment Offset    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Time to Live | Proto=17 (UDP)|        Header Checksum        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                       Source Address                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Destination Address                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   ... zero or more IP options (using space as indicated by IHL) ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   ...     zero or more shim headers (each indicating size)      ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         UDP Source Port       |     UDP Destination Port      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          UDP Length           |         UDP Checksum          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  Figure 1: IPv4 Datagram with UDP Header

For IPv6, the IP Payload Length field indicates the transport payload after the base IPv6 header. That payload includes the IPv6 extension headers and the space available for the transport protocol, as shown in Figure 2 [RFC8200]. The Next Header field in IPv6 might not indicate UDP (that is, 17), for example when intervening IP extension headers are present. For IPv6, the lengths of any additional IP extensions are indicated within each extension [RFC8200], so the upper bound for UDP Length is given by:

     UDP_Length <= IPv6_Payload_Length - sum(extension header lengths)
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Version| Traffic Class |             Flow Label                |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         Payload Length        |  Next Header  |   Hop Limit   |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   ...
   |                       Source Address (128 bits)               |
   ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   ...
   |                    Destination Address (128 bits)             |
   ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   ... zero or more IP Extension headers (each indicating size)  ...
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |         UDP Source Port       |     UDP Destination Port      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          UDP Length           |         UDP Checksum          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                  Figure 2: IPv6 Datagram with UDP Header

In both cases, IP indicates the space available for the UDP packet, either directly in the base header or by adding information in the shim headers or extensions. Either way, this document refers to that available space as the "IP transport payload" ๐Ÿง

Because of this redundancy, the UDP Length field can be used to split the IP transport payload into two areas. One is the UDP user data. The other is an additional "surplus area" (as shown in Figure 3) ๐Ÿ’–

                            IP transport payload
             <------------------------------------------------->
   +--------+---------+----------------------+------------------+
   | IP Hdr | UDP Hdr |     UDP user data    |   surplus area   |
   +--------+---------+----------------------+------------------+
             <------------------------------>
                        UDP Length

               Figure 3: IP Transport Payload vs. UDP Length

In most cases, the IP transport payload and UDP Length point to the same location, which means there is no surplus area. That is not a requirement of UDP [RFC0768], and Section 18 has more on it. This document uses the surplus area for UDP Options ๐Ÿซถ

The surplus area can start at any valid byte offset. It does not need to be 16-bit or 32-bit aligned. In effect, this document redefines the UDP Length field as a "trailer options offset" ๐ŸŒŸ

8. The UDP Surplus Area Structure ๐ŸŽ€

Okay so UDP Options take over the entire surplus area ๐Ÿฆ‹, which is everything in the IP payload after the last byte of the UDP payload ๐Ÿ’…. They kick off with a 2-byte Option Checksum (OCS) field, lined up on the first 2-byte boundary of that area (counting from the start of the IP datagram). You add zeroes right before the OCS if you need padding to get there โœจ. The UDP Option area works with any UDP payload length, even zero (so a UDP Length of 8 is totally valid, bestie ๐Ÿ™ˆ), as long as there's room for the aligned OCS plus whatever options you're using ๐Ÿ’–.

Here's the tea: UDP Options MAY begin at any UDP Length offset ๐ŸŒธ.

Any option area bytes used for alignment before the OCS MUST be zero ๐Ÿงš. If that's not the case, all options MUST be ignored and the surplus area silently discarded ๐Ÿ’€.

Those alignment bytes, plus the OCS computed over the rest of the surplus area, make sure the one's complement sum of the whole surplus area comes out to zero ๐Ÿ”ฅ. The OCS sits on a half-word (2-byte) boundary so implementers don't have to byte-swap it in their code ๐Ÿ‘‘.

The OCS holds an optional one's complement sum that catches errors in the surplus area. The UDP checksum doesn't cover that area, so this is the extra safety net, as detailed in Section 9 ๐ŸŒˆ.

The rest of the surplus area is made of options. All of them except two use TLV (type, length, and optional value) syntax, kinda like TCP [RFC9293], as detailed in Section 10. The No Operation (NOP) and End of Options List (EOL) types are the two exceptions, since they have an implicit length of one byte ๐Ÿ“. The options keep going until the end of the surplus area, or you can stop early with an EOL Option followed by zeroes (more on that in Section 10) โญ.


9. The Option Checksum (OCS) ๐Ÿ’œ

The Option Checksum (OCS) Option is a conventional Internet checksum [RFC0791] that detects errors in the surplus area ๐Ÿ’–. It holds a 16-bit checksum that's lined up on the first 2-byte boundary, with zero padding in front if it's needed. Check out Figure 4 ๐Ÿ‘‡

                   +--------+--------+--------+--------+
                   |         UDP data         |    0   |
                   +--------+--------+--------+--------+
                   |       OCS       |  UDP Options... |
                   +--------+--------+--------+--------+

Figure 4: UDP OCS Format, Here Using One Zero Byte for Alignment

The OCS is a 16-bit Internet checksum [RFC1071], computed over the surplus area and including the length of the surplus area as an unsigned 16-bit value. It protects the surplus area from errors in pretty much the same way the UDP checksum protects the UDP user data (when that checksum isn't zero) ๐Ÿซถ.

The main job of the OCS is to catch existing nonstandard (aka non-option) uses of that area, plus accidental errors ๐Ÿ˜ญ. It is not intended to detect attacks, as discussed further in Section 25 ๐Ÿ™ˆ. OCS isn't meant to stop future nonstandard uses of the surplus area, and it doesn't allow sharing that area with mechanisms that don't comply with UDP Options ๐Ÿ’….

This design lets packets get through errant middleboxes that wrongly compute the UDP checksum over the entire IP payload [Fa18] [Zu20], instead of only the UDP header and UDP payload (based on the UDP header length) ๐Ÿฆ‹. Because the OCS is computed over the surplus area and its length, and then inverted, it cancels out the effect the surplus has on the UDP checksum when it's wrongly included. So when the OCS is non-zero, the UDP checksum comes out the same either way โœจ.

The OCS MUST be non-zero when the UDP checksum is non-zero ๐Ÿ”ฅ.

When the UDP checksum is zero, the OCS MAY be unused, and it's then indicated by a zero OCS value ๐ŸŒธ.

UDP Option implementations MUST default to using the OCS (i.e., as a non-zero value). Users who override that default take the risk of not detecting nonstandard uses of the option area, of which there are none currently known ๐Ÿ‘‘.

Like the UDP checksum, the OCS is optional in certain situations, and it holds zero when it's not used ๐Ÿ“. UDP checksums can be zero for IPv4 [RFC0791] and for IPv6 [RFC8200] when the UDP payload is already covered by another checksum, as might happen with tunnels [RFC6935]. The same exceptions apply to the OCS when it's used to detect bit errors. There's an extra exception for its use in the UDP datagram prior to fragmentation or after reassembly (see Section 11.4) ๐Ÿงš.

The benefits are similar to letting UDP checksums be zero, but the risks are different ๐ŸŒˆ. The OCS is extra important for making sure packets with UDP Options can traverse errant middleboxes [Zu20]. When computing an OCS costs basically nothing, it's better to use the OCS to ensure that traversal โญ. In cases where those traversal risks can safely be ignored, like in controlled environments, over paths where traversal has been validated, or where upper layer protocols (applications, libraries, etc.) can adapt by enabling the OCS when packet exchange fails, the OCS can be disabled. The same goes for when bit errors at the UDP layer would be detected by other layers (as with the UDP checksum). You might disable it to conserve energy or processing resources, or when performance can be improved ๐Ÿ’œ. This is why zeroing the OCS is only safe when the UDP checksum is also zero, and why the OCS might still be used in that case ๐Ÿ’….

The OCS covers the surplus area as formatted for transmission, and it's processed immediately upon reception ๐ŸŽ€.

If the receiver's validation of the OCS fails, all options MUST be ignored and the surplus area silently discarded ๐Ÿ’€.

UDP user data that's validated by a correct UDP checksum MUST by default be delivered to the application layer, even if the OCS fails, unless the endpoints have negotiated otherwise for this UDP packet's socket pair ๐Ÿซถ.

When it's not used (i.e., it contains zero), the OCS is assumed to be "correct" for the purpose of accepting UDP datagrams at a receiver (see Section 14) โœจ.

10. UDP Options ๐ŸŽ€

okay bestie, so every UDP Option is at least two bytes long ๐Ÿซถ the only exceptions are the one-byte ones, No Operation (NOP) and End of Options List (EOL), which I'll explain below ๐Ÿ’…

                   +--------+--------+------------~~------------+
                   |  Kind  | Length | (remainder of option...) |
                   +--------+--------+------------~~------------+

                    Figure 5: UDP Option Default Format

The Kind field is always one byte, and it's named after the matching TCP field. Other protocols just call it "Type" ๐Ÿฆ‹ The Length field counts the whole option in bytes, including the Kind and Length bytes themselves. For any length below 255, it's just one byte. If the length is exactly 255, that's the signal to switch to the extended format in Figure 6 โœจ In that case, the Extended Length field is 16 bits, sent in network standard byte order. Whichever field applies, that's the one the option's length is measured by ๐Ÿ“

                   +--------+--------+--------+--------+
                   |  Kind  |  255   | Extended Length |
                   +--------+--------+--------+--------+
                   | (remainder of option...)          |
                   +--------+--------+--------+--------+

                    Figure 6: UDP Option Extended Format

The UDP Length MUST be at least as big as the UDP header (8) and no bigger than the IP transport payload. If a datagram's length falls outside that range, it MUST be silently dropped as invalid, and it MUST be logged ๐Ÿ™ˆ

All logging SHOULD be rate limited ๐Ÿ’– if there's a flood of log events, you can bundle them up and report a count, or quietly drop them if you need to protect your resources ๐ŸŒˆ

If an option's Length (or Extended Length, where that applies) is smaller than the minimum for its Kind, that's an error, and it MUST be treated that way. Those errors make the rest of the surplus area sus ๐Ÿ’€ so all UDP Options MUST be silently discarded as a result ๐Ÿ˜ญ

Any UDP Option other than NOP or EOL whose length is 254 or less MUST use the default format from Figure 5. NOP and EOL never use either length format, so they're the odd ones out ๐Ÿงš

Any UDP Option whose length is larger than 254 MUST use the extended format from Figure 6 ๐Ÿ‘‘

For compactness, UDP Options SHOULD use the smallest format they can ๐Ÿ’…

UDP Options MUST be interpreted in the order they show up in the surplus area. If they're part of UDP fragments, the order is the one they appear in within the UDP fragment option area instead (see Section 11.4) ๐Ÿ”ฅ

These are the UDP Options that are currently defined, so check the table, bestie โœจ

  +=========+==========+==========================================+
  | Kind    | Length   | Meaning                                  |
  +=========+==========+==========================================+
  | 0*      | -        | End of Options List (EOL)                |
  +---------+----------+------------------------------------------+
  | 1*      | -        | No Operation (NOP)                       |
  +---------+----------+------------------------------------------+
  | 2*      | 6        | Additional Payload Checksum (APC)        |
  +---------+----------+------------------------------------------+
  | 3*      | 10/12    | Fragmentation (FRAG)                     |
  +---------+----------+------------------------------------------+
  | 4*      | 4        | Maximum Datagram Size (MDS)              |
  +---------+----------+------------------------------------------+
  | 5*      | 5        | Maximum Reassembled Datagram Size (MRDS) |
  +---------+----------+------------------------------------------+
  | 6*      | 6        | Request (REQ)                            |
  +---------+----------+------------------------------------------+
  | 7*      | 6        | Response (RES)                           |
  +---------+----------+------------------------------------------+
  | 8       | 10       | Timestamp (TIME)                         |
  +---------+----------+------------------------------------------+
  | 9       | (varies) | RESERVED for Authentication (AUTH)       |
  +---------+----------+------------------------------------------+
  | 10-126  | (varies) | Unassigned (assignable by IANA)          |
  +---------+----------+------------------------------------------+
  | 127     | (varies) | RFC3692-style experiments (EXP)          |
  +---------+----------+------------------------------------------+
  | 128-191 |          | Reserved                                 |
  +---------+----------+------------------------------------------+
  | 192     | (varies) | Reserved for UNSAFE Compression (UCMP)   |
  +---------+----------+------------------------------------------+
  | 193     | (varies) | Reserved for UNSAFE Encryption (UENC)    |
  +---------+----------+------------------------------------------+
  | 194-253 |          | Unassigned-UNSAFE (assignable by IANA)   |
  +---------+----------+------------------------------------------+
  | 254     | (varies) | RFC3692-style UNSAFE experiments (UEXP)  |
  +---------+----------+------------------------------------------+
  | 255     |          | Reserved-UNSAFE                          |
  +---------+----------+------------------------------------------+

                               Table 1

Kinds 0 through 191 are called SAFE Options, because they don't get in the way of legacy endpoints using the UDP user data, even when an option isn't supported ๐Ÿฆ‹ Kinds 192 through 255 are UNSAFE Options, because they could mess with legacy receiving endpoints, like an option that changes the UDP data payload ๐Ÿ˜ฌ

UNSAFE Option nicknames are supposed to start with a capital "U", so SAFE Option nicknames have to avoid that letter (see Section 26) ๐Ÿ’… RESERVED and RESERVED-UNSAFE aren't assignable by IANA, and they aren't defined yet either ๐Ÿ™ˆ AUTH, UCMP, and UENC are held for future options covering authentication, compression, and encryption, and they stay reserved until they're assigned to those jobs โœจ

Okay, so FRAG technically changes the original UDP payload, which makes it UNSAFE in theory ๐Ÿ™ƒ but it only ever shows up on later fragments that carry zero-length UDP user data, so in actual use it's SAFE. More on that in Section 11.4 ๐ŸŽ€

These options get their own subsections below. Options 0 and 1 use the same values as they do for TCP ๐ŸŒธ

An endpoint that supports UDP Options MUST support every option marked with an "" above: EOL, NOP, APC, FRAG, MDS, MRDS, REQ, and RES. That means it has to be able to recognize them *and generate them when it's set up to do so. These are the "must-support" options ๐Ÿ’œ

The must-support set is fixed in this document. New options can't be added to it ๐Ÿ”’

Every other SAFE Option (the ones without an "*") MAY be implemented. Whether they get used SHOULD be decided out-of-band or negotiated, especially if you need to figure out when a legacy receiver is silently ignoring them ๐Ÿงš

Receivers that support UDP Options MUST silently ignore unknown or malformed SAFE Options, the same way a legacy receiver would ignore every UDP Option ๐Ÿซ  An option counts as malformed when its length doesn't match one of the values in that option's spec. The FRAG Option is the exception to this, because a malformed FRAG Option SHALL be treated as an unsupported UNSAFE Option ๐Ÿ”ฅ

Options with an inherently invalid Length, meaning they either underrun themselves or overrun the surplus area by pointing past the end of the IP payload, MUST be treated as a sign that the surplus area is malformed. When that happens, all options MUST be silently discarded ๐Ÿ’€

Receivers can't really treat unexpected Option Lengths as invalid in general, because that would box in future revisions of options. For example, someone might define a new APC with a different length ๐ŸŒˆ

When UNSAFE Options are present, the UDP user data MUST be empty, and any transport payload MUST be carried inside a FRAG Option (see Section 11.4) ๐ŸŽ€ Remember, these options can change the transport payload or signal that its contents mean something different. Following this rule keeps them safe in environments that might have legacy receivers (see Section 12), since the transport payload sits inside the FRAG Option area and legacy receivers just throw it away ๐Ÿซถ

Receivers that support UDP Options and get an unsupported option in the UNSAFE range MUST stop all option processing, and they MUST silently drop every UDP Option in that datagram. Section 12 has more on UNSAFE Options ๐Ÿ›‘

Apart from FRAG, NOP, EXP, and UEXP, each option SHOULD NOT show up more than once in a single UDP datagram ๐Ÿ™…โ€โ™€๏ธ If any option outside those four repeats, the receiver MUST only interpret the first instance and MUST ignore the later ones. Section 25 has extra advice on Denial of Service (DoS) issues that come from big numbers of options, whether they're valid, unknown, or repeated ๐Ÿ›ก๏ธ

NOP MAY appear multiple times, either back to back or in between other options, to keep things aligned ๐ŸŒธ Section 11.2 lists any extra repetition rules.

If FRAG shows up more than once, the options area MUST be treated as malformed and MUST NOT be processed ๐Ÿšซ

EXP and UEXP MAY appear more than once, but they SHOULD NOT repeat using the same Experimental ID (ExID) (see Sections 11.10 and 12.3) ๐Ÿงช

Options other than OCS, AUTH, and UENC MUST NOT include fields whose values depend on what's in the surplus area ๐Ÿ™…โ€โ™€๏ธ

AUTH and UENC are always computed as if their hash and the OCS are zero. The OCS is always computed as if its own contents are zero, and it's done after the AUTH or UENC hash has been computed ๐Ÿงฎ

Future options MUST NOT be defined so that an option field depends on the content or presence of other options, or on the rest of the surplus area (meaning the area after the last option, which is presumably EOL) ๐Ÿšซ

If future options depended on other options, the values, the OCS, and the AUTH and UENC Options could start interacting in unpredictable ways ๐Ÿ˜ตโ€๐Ÿ’ซ That doesn't rule out options that modify later options (in the order they appear in a packet), which is what compression (UCMP) would typically do ๐Ÿ—œ๏ธ

There's no need to save space after the last UDP Option for future use, since any future need can be handled by defining a new UDP Option over that area instead ๐Ÿงฉ Using an option for this is also safer than treating that region as an exception, because you can verify its use from the option's Kind and Length ๐Ÿ”

AUTH and UENC MUST NOT be used at the same time ๐Ÿ™…โ€โ™€๏ธ

They never go together anyway, because UENC would cover both jobs ๐Ÿ”

Must-support options other than NOP and EOL MUST be placed by the transmitter before any other SAFE UDP Options. If that ordering isn't honored, a receiver MAY drop all UDP Options. When that happens, the event MAY be logged for diagnostics ๐Ÿ“‹

The reason must-support options go first is so endpoints can add DoS protection, which Section 25 covers in more detail ๐Ÿ›ก๏ธ๐Ÿ’–

11. SAFE UDP Options ๐Ÿ’–

Okay bestie, SAFE UDP Options are the chill ones ๐Ÿซถ Legacy receivers can silently ignore them without changing what the UDP user data means. They're the total opposite of UNSAFE Options, which change the user data in ways that make it unusable for legacy receivers (see Section 12) ๐Ÿ’€ The subsections below cover the SAFE Options defined in this document โœจ

11.1. End of Options List (EOL) ๐Ÿ›‘

The End of Options List (EOL, Kind=0) Option says "that's all, folks" ๐ŸŽฌ It marks the end of the options list, so you don't have to pad the rest of the option space with NOP Options (more on those in the next section) ๐Ÿ™…โ€โ™€๏ธ

Figure 7: UDP EOL Option Format

                                  +--------+
                                  | Kind=0 |
                                  +--------+

Okay, rules time ๐Ÿ“‹ When the UDP Options don't eat up the whole surplus area or the options area of a UDP fragment, the last non-NOP Option MUST be EOL. No skipping this one ๐Ÿ’…

NOPs SHOULD NOT be used as padding before the EOL Option. EOL is only one byte, so it doesn't need any other alignment ๐Ÿงš

All bytes after EOL in the surplus area or the options area of a UDP fragment MUST be set to zero when you send them ๐Ÿ“

Bytes after EOL in the surplus area or the options area of a UDP fragment MAY be checked to be zero when you receive them. But they MUST NOT be processed in any other way (the OCS calculation is the one exception, since zeros wouldn't change it anyway) and they MUST NOT be passed to the user ๐Ÿ™ˆ

If a receiver decides to check the bytes after EOL and finds that they aren't all zero, it MUST silently discard the options area. In that case the UDP user data MUST be delivered to the application layer, unless the socket was explicitly configured to do something different, either by the upper layer or by agreement with the other endpoint ๐ŸŒธ

Why all the zero drama? Requiring the post-option surplus area to be zero blocks side-channel sneakiness ๐Ÿ•ต๏ธโ€โ™€๏ธ It means any real use of the surplus area has to be UDP Options that both endpoints actually support. Zero padding is also handy for growing the UDP datagram length without changing the UDP user data length, for example during UDP DPLPMTUD (Section 4.4 of [RFC9869]) โœจ

11.2. No Operation (NOP) ๐ŸŒˆ

The No Operation (NOP, Kind=1) Option is a one-byte placeholder ๐Ÿงธ It's meant for padding, like lining up multi-byte options on 16-bit, 32-bit, or 64-bit boundaries ๐Ÿ“

Figure 8: UDP NOP Option Format

                               +--------+
                               | Kind=1 |
                               +--------+

UDP packets SHOULD NOT use more than seven consecutive NOPs. That's enough to line things up to 8-byte boundaries, and anything more is overkill ๐Ÿ™ƒ UDP packets also SHOULD NOT use NOPs at the end of the options area as a stand-in for EOL followed by zero-fill. NOPs are for alignment only, not for random padding or filler ๐Ÿ’…

Receivers that keep seeing packets with more than seven consecutive NOPs SHOULD log those events, at least now and then, since it could be a potential DoS indicator ๐Ÿšจ

NOPs are never reported to the user, whether they're used per-datagram or per-fragment (as defined in Section 11.4) ๐Ÿซฅ

This issue gets more attention in Section 25 ๐Ÿ”

11.3. Additional Payload Checksum (APC) ๐Ÿ”

The Additional Payload Checksum (APC, Kind=2) Option is like a stronger backup for the checksum in the UDP header ๐Ÿ’ช It uses a 32-bit Cyclic Redundancy Check (CRC) that only covers the usual UDP user data payload. It skips the IP pseudoheader, the UDP header, and the surplus area. APC is not a replacement for the UDP checksum, because it doesn't cover the IP pseudoheader or the UDP header. It also isn't a supplement to the OCS, since the OCS only covers the surplus area. Its whole job is catching user data errors the UDP checksum might miss โœจ

CRC32c was picked because it's everywhere already, including Internet Small Computer System Interface (iSCSI) [RFC3385] and SCTP ๐ŸŒŸ The option carries the CRC32c in network standard byte order, the same way iSCSI does ๐Ÿงš

Figure 9: UDP APC Option Format

                   +--------+--------+--------+--------+
                   | Kind=2 | Len=6  |    CRC32c...    |
                   +--------+--------+--------+--------+
                   |  CRC32c (cont.) |
                   +--------+--------+

When APC is present, it always holds a valid CRC checksum. There are no reserved values, and that includes zero. A CRC value of zero is a perfectly valid checksum ๐Ÿ™Œ So a zero does NOT mean "APC isn't being used." If you don't want APC, you just leave the option out entirely ๐Ÿซถ

APC doesn't protect the UDP pseudoheader. Only the current UDP checksum does that (when it's in use) ๐Ÿ›ก๏ธ APC can't do this job because it would have to be recalculated every time the UDP pseudoheader changed, like during NAT address and port translation (see [RFC1141]) ๐Ÿ”

UDP packets with incorrect APC Option checksum fields SHOULD be passed to the application with an indication of an APC Option checksum failure. That's the default behavior for APC ๐Ÿ’…

Like all SAFE UDP Options, APC MUST be silently ignored when it fails, unless the receiver has been explicitly configured to do otherwise ๐Ÿคซ

Okay so here's the reasoning ๐Ÿง  Every UDP Option aware endpoint supports APC, since it's in the required set. But silently ignoring it on failure means option-aware receivers act exactly like legacy receivers, unless someone overrides that. There's another reason too: the APC check can fail even when the user data is totally fine, like when a middlebox intentionally rewrites embedded port numbers or IP addresses. Those rewrites might be deliberate and not widely known. Defaulting to silent ignore means option-aware endpoints don't change how users or apps behave unless they're explicitly told to ๐ŸŒธ

UDP packets with unrecognized APC lengths MUST get the same treatment as UDP packets with incorrect APC Option checksum fields ๐Ÿ”„

Treating unrecognized APC lengths as incorrect checksums means future versions of APC can be handled the same way, which is honestly iconic of them ๐Ÿ‘‘

APC is reported to the user, and it's only useful per-datagram, since fragments don't have any UDP user data ๐Ÿ“ฆ

11.4. Fragmentation (FRAG) ๐Ÿงฉ

The Fragmentation (FRAG, Kind=3) Option handles UDP fragmentation and reassembly. That's how you send UDP messages bigger than the IP Effective MTU for Receiving (EMTU_R) allows [RFC1122] ๐Ÿš€ FRAG puts a copy of the same UDP transport ports in each fragment. That lets fragments get through stateless Network Address (and port) Translation (NAT) devices, which regular IP fragments can't do [RFC4787] ๐Ÿฆ‹ FRAG is usually paired with the UDP MDS and MRDS Options to make large messages more efficient at both the UDP and IP layers โœจ The design is similar to the IPv6 Fragmentation Header [RFC8200], with one difference: the UDP version uses a 16-bit Offset measured in bytes, while IPv6 uses a 13-bit Fragment Offset measured in 8-byte units. This UDP variant also avoids creating reserved fields ๐Ÿงผ

FRAG also lets you use options that change the UDP payload, like encryption (UENC, see Section 12.2) ๐Ÿ”’ Just like FRAG, those options wouldn't be safe on UDP payloads by themselves, since legacy receivers would misread them. FRAG allows them to be used either on fragments or on a whole, unfragmented message. That second case is an "atomic" fragment at the UDP layer, similar to atomic IP datagrams [RFC6864]. It's safe because FRAG hides the payload from legacy receivers by tucking it inside the surplus area ๐Ÿซฃ

When FRAG is present, it SHOULD come as early as possible in the UDP Options list ๐Ÿฅ‡

Putting FRAG first makes life easier for some implementations, especially hardware-accelerated ones that expect FRAG to sit in a fixed spot ๐ŸŽ๏ธ But sometimes FRAG just can't go first. For example, when it's combined with per-fragment UENC or UCMP. In those cases, encryption or compression (or both) comes before FRAG if they also encrypt or compress the fragment option itself. Recoding could be another case, like supporting Forward Error Correction (FEC) across a group of fragments. If FRAG isn't first, software ("slow path") option processing might happen, or a small set of known cases might be handled another way ๐Ÿข

When FRAG is present, the UDP user data MUST be empty. If the user data isn't empty, all UDP Options MUST be silently ignored and the user data received MUST be sent to the user. Plot twist, but it's still a rule ๐Ÿ˜ญ

Legacy receivers read FRAG messages as zero-length user data UDP packets (the UDP Length field is 8, which is just the UDP header). That doesn't bother the receiver unless the mere presence of the UDP packet is a signal (see Section 5 of [RFC8085]) ๐Ÿ‘€ So FRAG also helps hide UNSAFE Options, which makes them safer to use around legacy receivers ๐Ÿ™ˆ

The FRAG Option comes in two formats. Non-terminal fragments use the shorter one (Figure 10), and terminal fragments use the longer one (Figure 11). The longer format also covers stand-alone fragments, where data is inside the FRAG Option but no reassembly is needed โœจ

Figure 10: UDP Non-Terminal FRAG Option Format

                   +--------+--------+--------+--------+
                   | Kind=3 | Len=10 |   Frag. Start   |
                   +--------+--------+--------+--------+
                   |           Identification          |
                   +--------+--------+--------+--------+
                   |  Frag. Offset   |
                   +--------+--------+

Most fields are shared by both FRAG formats. The option's Len field tells you whether more fragments are coming (Len=10) or whether this is the last one (Len=12) ๐Ÿ’œ

The Frag. Start field points to where the fragment data begins, measured from the start of this fragment's UDP header. The fragment data comes after the rest of the UDP Options and runs to the end of the IP datagram (which is the end of the surplus area) ๐ŸŽ€ Any options before or after FRAG are applied to this UDP fragment ๐Ÿงš

The Frag. Offset field shows where this fragment sits relative to the original UDP datagram (before fragmentation or after reassembly). It's measured from the start of the original UDP datagram's header ๐Ÿ“

The Identification field is a 32-bit value. Together with the IP source address, UDP source port, IP destination address, and UDP destination port, it uniquely identifies the original UDP datagram ๐Ÿชช

Figure 11: UDP Non-Terminal FRAG Option Format

                  +--------+--------+--------+--------+
                  | Kind=3 | Len=12 |   Frag. Start   |
                  +--------+--------+--------+--------+
                  |           Identification          |
                  +--------+--------+--------+--------+
                  |  Frag. Offset   |Reass DgOpt Start|
                  +--------+--------+--------+--------+

Okay bestie, the terminal FRAG Option ๐ŸŽ€ gets a Reassembled Datagram Option Start (RDOS) pointer โœจ. It's measured from the start of the original UDP datagram header, and it marks where the reassembled data ends and the surplus area begins. UDP Options that apply to the reassembled datagram live in that reassembled surplus area, and RDOS tells you where it starts. UDP Options sitting inside a fragment get processed on that fragment. So you can do pre-reassembly or post-reassembly stuff, like using UENC on every fragment while also using TIME on the reassembled datagram for round-trip latency measurements ๐Ÿงš.

Figure 12 shows how the fragments map onto the original datagram ๐Ÿฆ‹. In this example the trailer with the per-datagram options sits entirely inside the terminal fragment, but that doesn't have to be true every time ๐ŸŒธ.

          Constituent UDP Fragments         Original UDP Datagram

        +-------------+------------+
        | Src Port    | Dst Port   |
        +-------------+------------+
        | UDP Len (8) | UDP Chksum |
        +-------------+------------+
        |     OCS     | K=3   L=10 |      +-------------+------------+
        +-------------+------------+      | Src Port    | Dst Port   |
     ,--| Frag. Start | Identifi-  ~      +-------------+------------+
     |  +-------------+------------+      | UDP L.(RDOS)| UDP Chksum |
     |  ~ cation      | Frag. Off. |----->+-------------+------------+
     |  +-------------+------------+      | Frag Data from 1st Frag. |
     |  ~ Per-Fragment Options     ~      |             .            |
     '->+-------------+------------+      ~             .            ~
        ~      Fragment Data       ~      |             .            |
        +-------------+------------+  ,-->+-------------+------------+
                                      |   | Frag Data from 2nd Frag. |
        +-------------+------------+  |   |             .            |
        | Src Port    | Dst Port   |  |   ~             .            ~
        +-------------+------------+  |   |             .            |
        | UDP Len (8) | UDP Chksum |  | ,>+-------------+------------+
        +-------------+------------+  | | |     OCS     | UDP Options|
        |     OCS     | K=3   L=12 |  | | +-------------+            +
        +-------------+------------+  | | ~             .            ~
     ,--| Frag. Start | Identifi-  ~  | | +-------------+------------+
     |  +-------------+------------+  | |
     |  ~ cation      | Frag. Off. |--' |
     |  +-------------+------------+    |
     |  |  RDOS       | Frag.Opts. |    |
     '->+--|----------+------------+    |
        ~  |   Fragment Data       ~    |
        +--|----------+------------+    |
           |                            |
           '----------------------------'

Figure 12: UDP Fragments and Original UDP Datagram

The FRAG Option doesn't need a "more fragments" bit (the kind IP fragmentation uses) ๐Ÿ’…, because the longer 12-byte variant, shown in Figure 11, already tells the receiver the same thing.

The FRAG Option MAY be used on a single fragment ๐Ÿซถ. In that case the Frag. Offset is zero and the option uses the 12-byte format.

Endpoints supporting UDP Options MUST be capable of fragmenting and reassembling at least two fragments, and each one has to fit within the standard Ethernet MTU of 1,500 bytes โœจ. For more details, check out Section 11.6.

Using the single-fragment variant can be really helpful when you want UNSAFE Options without causing trouble for receivers that don't support UDP Options or those specific UNSAFE Options ๐ŸŒˆ.

During fragmentation, the UDP header checksum of each fragment stays constant ๐Ÿ”’. It doesn't depend on the fragment data (which lives in the surplus area), because every fragment has a zero-length user data field.

The Identification field is a 32-bit value that MUST be unique over the expected fragment reassembly timeout ๐Ÿ†”. It SHOULD be generated in a way that's similar to the IPv6 Fragment ID [RFC8200] ๐Ÿ’œ.

UDP fragments MUST NOT overlap ๐Ÿšซ.

Just like IPv6 reassembly [RFC8200], if any fragments being reassembled overlap with other fragments for the same UDP packet, the reassembly of that UDP packet MUST be abandoned. All the fragments received for that UDP packet MUST be discarded, and no ICMP error messages are to be sent in this case. This stops a potential DoS attack from turning into an ICMP storm in the reverse direction ๐Ÿ™ˆ.

Fragments can be duplicated in the network, so note that ๐Ÿ“. Instead of treating exact duplicate fragments as overlapping fragments, an implementation MAY choose to detect them and drop the exact duplicates while keeping the other fragments that belong to the same UDP packet.

UDP fragmentation relies on a fragment expiration timer. It can be preset, or it can use a value computed from the UDP Timestamp Option โฐ.

The default UDP reassembly expiration timeout SHOULD be no more than 2 minutes โณ.

UDP reassembly expiration MUST NOT generate an ICMP error. These events aren't IP errors, and the user/application layer can deal with them if it wants to ๐Ÿซง.

UDP reassembly space SHOULD be limited, so DoS attacks have less impact on resource use ๐Ÿ›ก๏ธ.

UDP reassembly space limits SHOULD NOT be computed as a shared resource across multiple sockets, so that cross-socket pair DoS attacks are avoided ๐Ÿšง.

Individual UDP fragments MUST NOT be forwarded to the user ๐Ÿ™…โ€โ™€๏ธ. The reassembled datagram only gets delivered after complete reassembly, checksum validation, and continued processing of the remaining UDP Options.

Per-fragment UDP Options, if used alongside FRAG, occur before the fragment data ๐ŸŽ€. They typically come after the FRAG Option, except when they modify the FRAG Option itself (for example, UENC or UCMP). Per-fragment options are processed before the fragment is added to the reassembled datagram. They're handy for protecting the reassembly process itself, like keeping the reassembly cache from getting polluted (using AUTH or UENC) ๐Ÿ›ก๏ธ.

Fragments of a single datagram MAY use different sets of options ๐ŸŒŸ. Checking that every fragment matches would be computationally expensive, and there could be legit reasons to put options on some fragments but not others (like MDS and MRDS).

If an option is used per-fragment but is defined as not usable per-fragment, it gets treated like any other unknown option ๐Ÿคทโ€โ™€๏ธ.

Per-datagram UDP Options, if used, live in the surplus area of the original UDP datagram. They get processed after reassembly is complete, which makes it safe to use UNSAFE Options. Those are required to get the entire UDP datagram discarded if the receiver doesn't know them or they otherwise fail (see Section 12) ๐Ÿ‘‘.

In general, UDP packets get fragmented like this:

  1. Create a UDP packet with data and UDP Options. This is the original UDP datagram, which we'll call "D" ๐Ÿฐ. The UDP Options follow the UDP user data and sit in the surplus area, just like in an unfragmented UDP datagram with UDP Options.

The UDP Options for the original packet MUST be fully prepared before you do the rest of the fragmentation steps below ๐Ÿ’….

The UDP checksum of the original packet SHOULD be set to zero, because it's never transmitted. You still get equivalent protection if each fragment has a non-zero OCS value, which will be the case if each fragment's UDP checksum is non-zero. Similarly, the OCS value of the original packet SHOULD be zero if each fragment will have a non-zero OCS value, which again happens when each fragment's UDP checksum is non-zero โœจ.

  1. Pick the desired fragment size, which we'll call "S" ๐Ÿ“. This value takes the path MTU into account (if it's known) and leaves room for per-fragment options.
  2. Split "D" into chunks no larger than "S"-12 each (10 for the non-terminal FRAG Option and 2 for OCS), with one final chunk no larger than "S"-14 (12 for the terminal FRAG Option and 2 for OCS). The per-datagram options from step 1 don't all need to sit in the terminal fragment, though. The RDOS pointer can mark the start of the original surplus area anywhere in the reassembled datagram ๐Ÿงฉ.
  3. For each chunk of "D" from step 3, create a UDP packet with no user data (UDP Length=8). Follow it with the word-aligned OCS, the FRAG Option, any extra per-fragment UDP Options, and then the FRAG data chunk ๐Ÿ“ฆ.
  4. Finish the processing that goes with creating those extra per-fragment UDP Options for each fragment ๐ŸŽ‰.

Receivers basically run that sequence in reverse ๐Ÿ”. They process all the options in each fragment. When they hit the FRAG Option, the FRAG data gets used in reassembly. Once every fragment has arrived, the whole UDP packet is processed, with any trailing UDP Options applying to the reassembled user data.

Reassembly failures at the receiver mean any per-fragment options and fragment contents get silently discarded ๐Ÿคซ. Those failures SHOULD NOT generate zero-length frames to the user.

Last but not least, fragmentation processing can get expensive ๐Ÿ’ธ, so the FRAG Option SHOULD be avoided unless the original datagram needs fragmentation or the FRAG Option is needed for "safe" use of UNSAFE Options.

The FRAG Option MAY also give limited support for UDP Options in systems that can only see the initial portion of the data in incoming or outgoing packets ๐Ÿ‘€, since those systems could potentially access per-fragment options. Of course, legacy receivers that don't support UDP Options will just silently ignore those packets ๐Ÿซ .

The presence of the FRAG Option is not reported to the user ๐Ÿ™ˆ.

11.5. Maximum Datagram Size (MDS) ๐Ÿ“ฆ

okay so the Maximum Datagram Size (MDS, Kind=4) Option is a 16-bit hint about the biggest UDP packet or UDP fragment an endpoint thinks it can receive without IP fragmentation ๐Ÿ‘€. It helps UDP apps keep their packets small enough to avoid UDP fragmentation, and it helps UDP fragmentation pick the biggest fragment to send. Both are about dodging IP fragmentation ๐Ÿ’….

It's giving the same energy as the TCP Maximum Segment Size (MSS) Option [RFC9293]. The number is the IP layer MTU minus only the fixed IP and UDP headers [RFC9293]. The sender has to adjust for the space that IP and UDP Options take up when it uses the value ๐Ÿงš. The number that gets sent is based on EMTU_R, the biggest IP datagram that can be received (aka reassembled at the receiver) [RFC1122]. BUT, just like TCP, it's only a hint of what the receiver thinks, especially when it's used with PLPMTUD at the UDP layer, which we'll get to later in this section ๐Ÿซถ.

MDS does not indicate a known path MTU and thus MUST NOT be used to limit transmissions. ๐Ÿ˜ญ not me reading that and still wanting to use it anyway ๐Ÿ™ˆ

                   +--------+--------+--------+--------+
                   | Kind=4 | Len=4  |    MDS size     |
                   +--------+--------+--------+--------+

                      Figure 13: UDP MDS Option Format

The UDP MDS Option MAY be used as a hint for path MTU discovery [RFC1191] [RFC8201], but this could be difficult because of known issues with ICMP blocking [RFC2923] and the fact that UDP doesn't have automatic retransmission. ๐ŸŒธ

MDS is more likely to be useful when it's paired with IP source fragmentation or UDP fragmentation to limit the largest reassembled UDP message, as indicated by MRDS (see Section 11.6). This is especially true when EMTU_R is larger than the required minimums (576 for IPv4 [RFC0791] and 1500 for IPv6 [RFC8200]) โœจ.

MDS can be used with DPLPMTUD [RFC8899] to give a hint to the Packetization Layer Path MTU (PLPMTU) value, though it MUST NOT prohibit transmission of larger UDP packets used as DPLPMTUD probes. ๐Ÿฆ‹

MDS is reported to the user, whether it's used per-datagram or per-fragment (as defined in Section 11.4). When it's used per-fragment, the reported value is the minimum of the MDS values received per-fragment ๐Ÿ“Š.

11.6. Maximum Reassembled Datagram Size (MRDS) ๐Ÿงฉ

The Maximum Reassembled Datagram Size (MRDS, Kind=5) Option is a 16-bit indicator of the largest reassembled UDP datagram that can be received, including the UDP header and any per-datagram UDP Options. It comes with an 8-bit indication of how many UDP fragments can be reassembled ๐Ÿ’–. The MRDS size field is the UDP version of IP's EMTU_R, but the two aren't related [RFC1122]. With the FRAG Option (Section 11.4), UDP packets can be sent as transport fragments, each in its own (presumably not fragmented) IP datagram, and then reassembled at the UDP layer. MRDS segs is the number of UDP fragments that can be reassembled ๐ŸŽ€.

               +--------+--------+--------+--------+---------+
               | Kind=5 | Len=5  |    MRDS size    |MRDS segs|
               +--------+--------+--------+--------+---------+

                     Figure 14: UDP MRDS Option Format

Endpoints supporting UDP Options MUST support a local MRDS size of at least 2,926 bytes for IPv4 and 2,886 bytes for IPv6. Support for larger values is encouraged ๐ŸŒˆ.

Endpoints supporting UDP Options MUST support a local MRDS segs value of at least 2. Support for larger values is encouraged ๐Ÿซถ.

These parameters, plus the Path MTU (PMTU), let a sender figure out the size of the largest pre-fragmentation UDP packet that a receiver will guarantee to accept ๐Ÿงฎ. MMS_S is defined as the PMTU minus the size of the IP header and the UDP header. In other words, it's the maximum UDP message size that can be successfully sent in a single UDP datagram if there are no IP options or extension headers and no UDP per-fragment options. With those size definitions in place, the size of the largest pre-fragmentation UDP packet that the receiver will guarantee to accept is the smaller of the MRDS size and the following:

(MMS_S - 12) * (MRDS segs) - 2 - (Total Per-Frag IP/UDP Options) + 8

In the expression above, Total Per-Frag IP/UDP Options includes the size of all IP options and extension headers, plus all per-fragment UDP Options (except for OCS and FRAG) that are in the sequence of UDP fragments ๐Ÿง .

If no MRDS Option has been received, a sender MUST assume that MRDS size is 2,926 bytes for IPv4 and 2,886 bytes for IPv6, and that MRDS segs is 2. Those are the minimum values allowed ๐Ÿ“.

MRDS is reported to the user, whether it's used per-datagram or per-fragment (as defined in Section 11.4). When it's used per-fragment, the reported value is the minimum of the MRDS values received per-fragment ๐Ÿ’œ.

11.7. Echo Request (REQ) and Echo Response (RES) ๐Ÿ“

The echo Request (REQ, Kind=6) and echo Response (RES, Kind=7) Options give you UDP packet-level acknowledgments as a capability for upper layer protocols to use, like user applications, libraries, operating systems, and so on ๐Ÿ’…. Both REQ and RES are controlled by these upper layers. In other words, UDP Option support described in this document never automatically responds to a REQ with a RES. Instead, the REQ gets delivered to the upper layer, and that layer decides whether and when to send a RES ๐Ÿ‘‘.

One such use is described as part of DPLPMTUD [RFC9869]. This use case is described as part of UDP Options, but it's logically considered a capability of an upper layer that uses UDP Options ๐Ÿฆ‹. Both options have the format shown in Figure 15, where the token has no internal structure or meaning.

                   +--------+--------+-----------------+
                   |  Kind  | Len=6  |      token      |
                   +--------+--------+-----------------+
                     1 byte   1 byte       4 bytes

                 Figure 15: UDP REQ and RES Options Format

As advice for upper layer protocol and library designers: when you support REQ/RES and respond with a RES, the upper layer SHOULD respond with the most recently received REQ token. Think of it as the main character move ๐ŸŽ€.

If the implementation includes a layer or library that produces and consumes REQ/RES on behalf of the user or application, then that layer MUST be disabled by default. In that case, REQ/RES are simply sent when the user or application asks for them, and passed up to it when received, just like most other UDP Options ๐Ÿ™ˆ.

For example, an application needs to explicitly enable the generation of a RES Option by DPLPMTUD when using UDP Options [RFC9869] ๐Ÿ”ฅ.

The token transmitted in a RES Option MUST be a token received in a REQ Option by the transmitter. This makes sure the response is to a request that was actually received ๐Ÿซถ.

REQ and RES Option kinds each appear at most once in each UDP packet, just like most other options. A single packet can include both options, though they'd otherwise be unrelated to each other. Also, the FRAG Option is not used when sending DPLPMTUD probes to determine a PLPMTU [RFC9869] โœจ.

REQ and RES are reported to the user, whether they're used per-datagram or per-fragment (as defined in Section 11.4). When they're used per-fragment, the reported value indicates the most recently received token ๐Ÿ“Š.

11.8. Timestamp (TIME) โฐ

Timestamps are provided as a capability for applications and other upper layer protocols to use ๐ŸŒธ. They're based on a notion of time as a monotonically non-decreasing unsigned integer, with wraparound. They're defined the same way as TCP Protection Against Wrapped Sequence (PAWS) numbers, meaning "without any connection to [real-world, classical physics wall-clock] time" [RFC7323]. They're pretty similar to relativistic time or the individual scalars of Lamport clocks [La78]. Still, if you want, they can correspond to real-world time, for example for round-trip time (RTT) estimation. This option makes no assertions about which is the case. The decision is up to the application layer using this option ๐Ÿงš.

The Timestamp (TIME, Kind=8) Option exchanges two four-byte unsigned timestamp fields. It serves a similar purpose to TCP's Timestamp (TS) Option [RFC7323], letting UDP estimate the RTT between hosts. For UDP, this RTT can be useful for setting UDP fragment reassembly timeouts or transport-layer rate limiting [RFC8085] ๐Ÿ’–.

        +--------+--------+------------------+------------------+
        | Kind=8 | Len=10 |      TSval       |      TSecr       |
        +--------+--------+------------------+------------------+
          1 byte   1 byte       4 bytes            4 bytes

                     Figure 16: UDP TIME Option Format

TS Value (TSval) and TS Echo Reply (TSecr) are used in a similar way to the TCP TS Option [RFC7323]. On transmitted UDP packets that use the option, TSval is always set based on the local "time" value. Received TSval and TSecr field contents are passed to the application, which can pass the received TSval along to be used as TSecr in UDP messages sent back (in other words, to echo the received TSval). A received TSecr of zero means the TSval wasn't echoed by the transmitter, i.e., from a previously received UDP packet ๐Ÿ™ˆ.

TIME MAY use an RTT estimate based on non-zero Timestamp values as a hint for fragmentation reassembly, rate limiting, or other mechanisms that benefit from that kind of estimate ๐ŸŒˆ.

An application MAY use TIME to compute this RTT estimate for further use by the user ๐Ÿ’….

UDP timestamps are modeled after TCP timestamps and have similar expectations. Specifically, they're supposed to follow these guidelines:

  • Values are monotonic and non-decreasing, except for anticipated number-space rollover events.
  • Values "increase" (allowing for rollover, i.e., modulo the field size except zero) according to a typical 'tick' time.
  • A request is defined as TSval being non-zero, and a reply is defined as TSecr being non-zero.
  • A receiver always responds to a request with the highest TSval received (allowing for rollover), which is not necessarily the most recently received.

Rollover can be handled as a special case, or more completely using sequence number extension [RFC9187]. Either way, zero values need to be avoided explicitly ๐Ÿฆ‹.

TIME values MUST NOT use zeros as valid time values, because zeros are used as indicators of requests and responses. โš ๏ธ

TIME is reported to the user, whether it's used per-datagram or per-fragment (as defined in Section 11.4). When it's used per-fragment, the reported value is the minimum and maximum of each of the timestamp values received per-fragment ๐Ÿ‘‘.

Use of TIME per-fragment is NOT RECOMMENDED. The exceptions are supporting diagnostics on the reassembly process itself, which could be more appropriate to handle within the UDP Option processing implementation ๐ŸŒŸ.

11.9. Authentication (AUTH), RESERVED Only ๐Ÿ”

Okay so the Authentication (AUTH, Kind=9) Option is basically reserved for all UDP authentication mechanisms [To24]. ๐Ÿฆ‹ AUTH is expected to cover the UDP user data and UDP Options, with possible extra coverage of the IP pseudoheader and UDP header, and potentially even support for NAT traversal. That NAT traversal would work by zeroing the remote socket (the source IP address and UDP port) before computing the check, kind of like how the TCP Authentication Option (TCP-AO) NAT traversal does it [RFC6978]. ๐ŸŒธ

Like APC, AUTH is a SAFE Option because it doesn't modify the UDP user data. ๐Ÿ’… Still, AUTH could fail even when the user data hasn't been corrupted, like when its contents have been overwritten. Those overwrites could be intentional and not widely known, so the default is silent ignore. That way option-aware endpoints don't change how users or applications operate unless they're explicitly told to. ๐Ÿ™ˆ

When a socket pair relies on AUTH (for example, after a security policy gets configured), this default is expected to be overridden. Incoming packets without AUTH, or with a failed AUTH check, would then be silently dropped, so only authenticated packets would reach the user. โœจ This lets the AUTH security checks happen above UDP, in a separate shim layer or application library. ๐Ÿ”’

A specification for using AUTH is expected to define how the AUTH security parameters get coordinated, and how the socket pair gets configured when those parameters are installed. ๐Ÿ“ That specification is expected to address the rules for when AUTH is required on transmission, and when the presence and correct validation of AUTH is required on reception. ๐Ÿซถ

11.10. Experimental (EXP) ๐Ÿงช

The Experimental (EXP, Kind=127) Option is allocated for experiments [RFC3692]. Only one value is allocated, because experiments are expected to use an Experimental ID (ExID) to tell apart concurrent use for different purposes. Those UDP ExIDs get registered with IANA, following the approach developed for TCP experimental options [RFC6994]. ๐ŸŒˆ

               +----------+----------+----------+----------+
               | Kind=127 |   Len    |      UDP ExID       |
               +----------+----------+----------+----------+
               |  (option contents, as defined)...         |
               +----------+----------+----------+----------+

Figure 17: UDP EXP Option Format

The length of the Experimental Option MUST be at least 4 to account for the Kind, Len, and 16-bit UDP ExID (similar to TCP ExIDs [RFC6994]). ๐Ÿ’œ

The UDP EXP Option uses only 16-bit ExIDs, unlike TCP ExIDs. ๐ŸŽ€ In TCP, the first 16 bits of the ExID are unique, and the additional 16 bits, where present, are used to decrease the chance of the entire ExID occurring in legacy use of the TCP EXP Option. This extended variant gives UDP EXP no similar use, because ExIDs are required. ๐Ÿ™ƒ

The UDP EXP Option also has an Extended Length format, where the option Len is 255, followed by two bytes of Extended Length. ๐Ÿ“

               +----------+----------+----------+----------+
               | Kind=127 |   255    |   Extended Length   |
               +----------+----------+----------+----------+
               |      UDP ExID       |(option contents...) |
               +----------+----------+----------+----------+

Figure 18: UDP EXP Extended Option Format

UDP Experimental IDs (ExIDs) are assigned from a combined TCP/UDP ExID registry managed by IANA (see Section 26). ๐Ÿ—‚๏ธ Assigned ExIDs can be used in either the EXP or UEXP Options (see Section 12.3 for the latter). ๐Ÿ‘‘


12. UNSAFE Options โš ๏ธ

UNSAFE Options are not safe to ignore, and they can be used unidirectionally or without soft-state confirmation of UDP Option capability. ๐Ÿ”ฅ They are only ever used when the user data occurs inside a reassembled set of one or more UDP fragments. That way, if UDP fragmentation isn't supported, the enclosed UDP user data would be silently dropped anyway. ๐Ÿซ 

Applications using UNSAFE Options SHOULD NOT also use zero-length UDP packets as signals, because they will arrive when UNSAFE Options fail. Those that choose to allow such packets MUST account for such events. ๐Ÿ’€
UNSAFE Options MUST be used only as part of UDP fragments, used either per-fragment or after reassembly. ๐Ÿงฉ
Receivers supporting UDP Options MUST silently drop the UDP user data of the reassembled datagram if any fragment or the entire datagram includes an UNSAFE Option whose Kind is not supported, or if an UNSAFE Option appears outside the context of a fragment or reassembled fragments. ๐Ÿšซ

12.1. UNSAFE Compression (UCMP) ๐Ÿ—œ๏ธ

The UNSAFE Compression (UCMP, Kind=192) Option is reserved for all UDP compression mechanisms. ๐Ÿ’œ UCMP is expected to cover the UDP user data and some (e.g., later, in sequence) UDP Options. ๐ŸŒธ

12.2. UNSAFE Encryption (UENC) ๐Ÿ”

The UNSAFE Encryption (UENC, Kind=193) Option is reserved for all UDP encryption mechanisms. ๐Ÿฆ‹ UENC is expected to provide all of the services of the AUTH Option (Section 11.9), and in addition to encrypt the UDP user data and some (e.g., later or in sequence) UDP Options, in a similar manner as the TCP Authentication Option Extension for Payload Encryption (TCP-AO-ENC) [To18]. ๐Ÿ™ˆ

12.3. UNSAFE Experimental (UEXP) ๐Ÿงช

The UNSAFE Experimental (UEXP, Kind=254) Option is reserved for experiments [RFC3692]. Just like EXP, only one such UEXP value is reserved, because experiments are expected to use an Experimental ID (ExIDs) to tell apart concurrent use for different purposes. Those UDP ExIDs are registered with IANA, following the approach developed for TCP experimental options [RFC6994]. โœจ

Assigned ExIDs can be used with either the UEXP or EXP Options. ๐ŸŽ€


13. Rules for Designing New Options ๐Ÿ“œ

The UDP Option Kind space allows for the definition of new options. ๐ŸŒฑ However, the currently defined options (including AUTH, UENC, and UCMP) do not allow for arbitrary new options. Here's a summary of the rules for new options and their rationales, bestie. ๐Ÿซถ

New options MUST NOT be defined as "must-implement", i.e., they are not eligible for the asterisk ("*") designation used in Section 10. ๐Ÿšซ

This document defines the minimum set of "must-implement" UDP Options. ๐Ÿ’… All new options are included at the discretion of a given implementation. ๐Ÿ“

New options MUST NOT modify the content of options that precede them (in order of appearance and thus processing). ๐Ÿ™…โ€โ™€๏ธ
The fields of new options MUST NOT depend on the content of other options. ๐Ÿง 

UNSAFE Options can both depend on and vary user data content, because they are contained only inside UDP fragments and thus are processed only by receivers capable of handling UDP Options. ๐Ÿ”ฅ

New options MUST NOT declare their order relative to other options, whether new or old, even as a preference. ๐Ÿšซ
At the sender, new options MUST NOT modify UDP packet content anywhere outside their option field, excepting only UNSAFE Options. Areas that need to remain unmodified include the IP header, IP options, UDP user data, and surplus area (i.e., other options). ๐Ÿ›ก๏ธ
Options MUST NOT be modified in transit. This includes those already defined as well as new options. ๐Ÿšง
New options MUST NOT require or allow that any UDP Options (including themselves) or the remaining surplus area be modified in transit. ๐ŸŒŠ
All options MUST indicate whether they can be used per-fragment and, if so, MUST also indicate how their success or failure is reported to the user. It is RECOMMENDED that new options be designed to support per-fragment use. It is also RECOMMENDED that options used per-fragment be reported to the user as a finite aggregate (e.g., a sum, a flag, etc.) rather than individually. ๐Ÿ“Š

With one exception, UNSAFE Options are used when UDP user data needs to be modified: ๐Ÿฆ„

The FRAG Option modifies UDP user data, splitting it across multiple IP packets. UNSAFE Options MAY modify the UDP user data, e.g., by encryption, compression, or other transformations. All other (SAFE) options MUST NOT modify the UDP user data. ๐Ÿ’–

14. Option Inclusion and Processing โœจ

okay bestie, this section is all about who gets to decide what ๐Ÿ’… senders pick which options get added, and receivers pick which ones they actually handle. it's giving teamwork ๐Ÿซถ

Senders MAY add any option, as configured by the API.

All "must-support" options MUST be processed by receivers, if present (presuming UDP Options are supported at that receiver).

Options that are not "must-support" options MAY, if present, be ignored by receivers, based, e.g., on API settings.

All options MUST be processed by receivers in the order encountered in the options area.

Unless configuration settings direct otherwise, all options except UNSAFE Options MUST result in the UDP user data being passed to the upper layer protocol or application, regardless of whether all options are processed, are supported, or succeed.

The basic premise is that, for options-aware endpoints, the sender decides what options to add and the receiver decides what options to handle. ngl this is so fair ๐Ÿฆ‹ simply adding an option doesn't force any work onto a receiver, except for the "must-support" options.

Upon receipt, the receiver checks various properties of the UDP packet and its options to decide whether to accept or drop the UDP packet, and whether to accept or ignore some of its options. It goes in this order:

        if the UDP checksum fails then
            silently drop the entire UDP packet (per RFC 1122)
        if the UDP checksum passes or is zero then
            if (OCS != 0 and OCS fails) or
               (OCS == 0 and UDP CS != 0) then
                deliver the UDP user data but ignore other options
                (this is required to emulate legacy behavior)
            if (OCS != 0 and OCS passes) or
               (OCS == 0 and UDP CS == 0) then
                deliver the UDP user data after parsing
                and processing the rest of the options,
                regardless of whether each is supported or succeeds
                (again, this is required to emulate legacy behavior)

The design of the UNSAFE Options makes sure the resulting UDP data gets silently dropped in both legacy receivers and options-aware receivers that don't recognize those options. Again, note that this still results in the delivery of a zero-length UDP packet ๐Ÿ™ˆ

Options-aware receivers can drop UDP packets with option processing errors, either through an override of the default UDP processing or at the application layer.

Put another way, every option gets treated the same way: the transmitter can add each option as desired, and the receiver has the choice to require a given option or not. Only if a receiver marks a particular option as mandatory (e.g., through API configuration) does it need to confirm that the option is present and correct.

Here's the summary for all options:

  • if the option is not required by the receiver, then UDP packets missing the option are accepted.
  • if the option is required (e.g., by override of the default behavior at the receiver) and missing or incorrectly formed, silently drop the UDP packet.
  • if the UDP packet is accepted (either because the option is not required or because it was required and correct), then pass the option with the UDP packet via the API. Note that FRAG, NOP, and EOL are not passed to the user (see Section 15).

Any options whose length exceeds that of the UDP packet (i.e., intending to use data that would have been beyond the surplus area) SHOULD be silently ignored (again to model legacy behavior) ๐Ÿ“


15. UDP API Extensions

UDP currently specifies an Application Programming Interface (API), summarized as follows (with a Unix-style command as an example) [RFC0768]:

  • Method to create new receive ports
    • e.g., bind(handle, recvaddr(optional), recvport)
  • Receive, which returns data octets, source port, and source address
    • e.g., recvfrom(handle, srcaddr, srcport, data)
  • Send, which specifies data, source and destination addresses, and source and destination ports
    • e.g., sendto(handle, destaddr, destport, data)

This API gets extended to support options, like so โœจ

  • Extend the method to create receive ports to include per-packet and per-fragment receive options that are required or omitted as indicated by the application.

Datagrams not containing these required options MUST be silently dropped and SHOULD be logged.

  • Extend the method to create receive ports to have a means to indicate that all packets containing UDP Options that are received on a particular socket pair are to be discarded.

The default value for the setting to drop all packets containing UDP Options MUST be to process packets containing UDP Options normally (i.e., not to discard them).

  • Extend the receive function to indicate the per-packet options and their parameters as received with the corresponding received datagram. Note that per-fragment options are handled within the processing of each fragment.

Options and their processing status (success/fail) MUST be available to the user (i.e., application layer or upper layer protocol/service), both for the packet and for the fragment set, except for FRAG, NOP, and EOL. Those three options are handled within UDP Option processing only. As a reminder (from Section 14), all options except UNSAFE Options MUST result in the UDP user data being passed to the application layer (unless overridden in the API), regardless of whether all options are processed, supported, or succeed.

  • For fragments, success for an option is reported only when all fragments succeed for that option.

Per-fragment option status reporting SHOULD default as needed (e.g., not computed and/or not passed up to the upper layers) to minimize overhead, unless actively requested (e.g., by the user or application layer).

SAFE Options associated with fragments are accumulated when associated with the reassembled packet. Values MAY be coalesced, e.g., to indicate that only an AUTH failure of a fragment occurred, rather than not indicating the AUTH status of each fragment.

  • Extend the send function to indicate the options to be added to the corresponding sent datagram. This includes indicating which options apply to individual fragments versus which apply to the UDP packet prior to fragmentation, if fragmentation is enabled. It also includes a minimum datagram length, such that the options list ends in EOL and additional space is zero-filled as needed. Finally, it includes a maximum fragment size, e.g., as discovered by DPLPMTUD, whether implemented at the application layer per [RFC8899] or in conjunction with other UDP Options [RFC9869].

Examples of API instances for Linux and FreeBSD are provided in Appendix A to encourage uniform cross-platform implementations ๐ŸŒˆ

APIs are not intended to provide user control over option order, especially on a per-packet basis, as this could create a covert channel (see Section 25). Similarly, APIs are not intended to provide user or application control over UDP fragment boundaries on a per-packet basis. They are, however, expected to allow control over which options, including fragmentation, are enabled (or disabled) on a per-packet basis. Such control over fragmentation is critical to DPLPMTUD ๐Ÿ‘‘


16. UDP Options Are for Transport, Not Transit

UDP Options are indicated in the surplus area of the IP payload that is not used by UDP. That area is really part of the IP payload, not the UDP payload, so it might be tempting to wonder whether this is a generally useful approach for extending IP ๐Ÿค”

Unfortunately, the surplus area only exists for transports that include their own transport layer payload length indicator. TCP and SCTP include header length fields that already provide space for transport options, by indicating the total length of the header area, so the entire remaining area indicated in the network layer (IP) is the transport payload. UDP-Lite already uses the UDP Length field to indicate the boundary between data covered by the transport checksum and data not covered, so there is no remaining area where the length of the UDP-Lite payload as a whole can be indicated [RFC3828]. no room, no surplus ๐Ÿ˜ญ

UDP Options are transport options. They are no more (or less) appropriate to be modified in transit than any other portion of the transport datagram.

Generally, transport headers, options, and data are not intended to be modified in transit. UDP Options are no exception, and are specified here as "MUST NOT be altered in transit".

However, note that the UDP Option mechanism provides no specific protection against in-transit modification of the UDP header, UDP payload, or surplus area, except as provided by the OCS or the options selected (e.g., AUTH or UENC).

Unless protected by encryption (e.g., UENC, or via other layers like IPsec), UDP Options remain visible to devices on the network path. The decision not to require mandatory encryption for UDP Options, to prevent that visibility, was made because the key distribution and management infrastructure needed to support such encryption doesn't exist in many of the deployment scenarios of interest. That's especially true for those that use UDP directly as a stateless and connectionless transport protocol (e.g., see [He24]). so yeah, visible by design ๐Ÿงš


17. UDP Options vs. UDP-Lite

UDP-Lite provides partial checksum coverage, so UDP packets with errors in some locations can be delivered to the user [RFC3828]. It uses a different transport protocol number (136) than UDP (17), so that it can interpret the UDP Length field as the prefix covered by the UDP checksum.

UDP (protocol 17) already defines the UDP Length field as the limit of the UDP checksum, but by default it also limits the data provided to the application to whatever precedes the UDP Length. A goal of UDP-Lite is to deliver data beyond UDP Length by default, which is why a separate transport protocol number was required ๐Ÿฆ‹

UDP Options don't use or need a separate transport protocol number, because the data beyond the UDP Length offset (surplus data) isn't provided to the application by default. That data is interpreted exclusively within the UDP transport layer ๐Ÿ’–

UDP-Lite cannot support UDP Options, either as proposed here or in any other form, because the entire payload of the UDP packet is already defined as user data, and there's no additional field in which to indicate a surplus area for options. The UDP Length field in UDP-Lite is already used to mark the boundary between user data covered by the checksum and user data not covered. no spare field, no options, periodt ๐Ÿ’…

18. Interactions with Legacy Devices ๐ŸŽ€

okay so it has always been totally fine for the UDP Length to not match the IP transport payload length [RFC0768]. UDP-Lite actually used that inconsistency with a different transport number [RFC3828] ๐Ÿฆ‹. There are no known systems using this trick for UDP, ngl. But it's possible it could interact with UDP Options, like a legacy system might send datagrams that look like they have UDP Options ๐Ÿ‘€. The OCS protects against that way better than a static "magic number" ๐Ÿ’….

UDP Options have been tested as interoperable with Linux, macOS, and Windows Cygwin, and they worked through NAT devices ๐ŸŒˆ. These systems only delivered the user data that the UDP Length field indicated, and they quietly discarded the surplus area ๐Ÿ™ˆ.

One embedded device was reported to pass the entire IP datagram to the UDP application layer ๐Ÿ˜ณ. This could enable application-layer UDP Option processing, but it would require conventional UDP user applications to examine only the UDP user data. It's also inconsistent with the UDP application interface [RFC0768] [RFC1122], so it's a no from me ๐Ÿ’€.

It has been noted that Alcatel-Lucent's "Brick" Intrusion Detection System has a default configuration that treats inconsistencies between UDP Length and IP Length as an attack to be reported ๐Ÿšจ. Other firewall systems, e.g., Check Point, use a default "relaxed UDP Length verification" so they don't falsely flag this inconsistency as an attack ๐Ÿซถ.

There are known uses of UDP exchanges of zero-length UDP user data packets, notably in the TIME protocol [RFC0868] โฐ. The need to support such packets is also noted in the UDP usage guidelines [RFC8085]. Some mechanisms in this document can generate more zero-length UDP packets for a UDP Option aware endpoint than for a legacy endpoint (e.g., based on some error conditions), and some can generate fewer (e.g., fragment reassembly) โœจ. Because such packets inherently carry no unique transport header or transport content, endpoints are already expected to be tolerant of their (inadvertent) replication or loss by the network, so such variations are not expected to be problematic ๐Ÿฅฐ.

19. Options in a Stateless, Unreliable Transport Protocol ๐Ÿงš

there are two ways to interpret options for a stateless, unreliable protocol. An option is either local to the message, or it's intended to affect a stream of messages in a soft-state manner ๐ŸŒŠ. Either interpretation is valid for defined UDP Options โœ….

It is impossible to know in advance whether an endpoint supports a UDP Option ๐Ÿคทโ€โ™€๏ธ.

>> All UDP Options other than UNSAFE ones MUST be ignored if not supported or upon failure (e.g., APC).

>> All UDP Options that fail MUST result in the UDP data still being sent to the application layer by default to ensure equivalence with legacy devices.

UDP Options that rely on soft-state exchange need to allow message reordering and loss, in the same way as UDP applications [RFC8085] ๐Ÿซ .

The above requirements prevent using any option that cannot be safely ignored, unless it is hidden inside the FRAG area (i.e., UNSAFE Options) ๐Ÿšซ. Legacy systems also always need to be able to interpret the transport fragments as individual UDP packets ๐Ÿ’–.

20. UDP Option State Caching ๐Ÿ’œ

Some TCP connection parameters, stored in the TCP Control Block (TCB), can be usefully shared either among concurrent connections or between connections in sequence. This is known as TCB sharing [RFC9040] ๐Ÿ”. Although UDP is stateless, some of the options proposed herein could have similar benefits in being shared or cached. We call this UCB sharing, or UDP Control Block sharing, by analogy ๐Ÿซง. Just as TCB sharing is not a standard because it is consistent with existing TCP specifications, UCB sharing would be consistent with existing UDP specifications, including this one. Both are implementation issues that are outside the scope of their respective specifications, so UCB sharing is outside the scope of this document ๐Ÿ“ฆ.

21. Updates to RFC 768 ๐Ÿ“

This document updates [RFC0768] as follows:

  • This document defines the meaning of the IP payload area beyond the UDP Length but within the IP Length as the surplus area used herein for UDP Options ๐ŸŽ.
  • This document extends the UDP API to support the use of UDP Options ๐Ÿ’….

22. Interactions with Other RFCs ๐Ÿฆ‹

This document clarifies the interaction between UDP Length and IP Length, which is not explicitly constrained in either UDP or the host requirements [RFC0768] [RFC1122] ๐Ÿ“.

Teredo extensions define use of a similar difference between these lengths for trailers [RFC4380] [RFC6081]. In [RFC6081], Teredo extensions define the length of an IPv6 payload inside UDP as pointing to less than the end of the UDP payload, which enables trailing options for that IPv6 packet ๐ŸŒ€:

   |  ...the IPv6 packet length (i.e., the Payload Length value in the
   |  IPv6 header plus the IPv6 header size) is less than or equal to
   |  the UDP payload length (i.e., the Length value in the UDP header
   |  minus the UDP header size)

UDP Options are not affected by the difference between the UDP user payload end and the payload IPv6 end. Both would end at the UDP user payload, which could end before the enclosing IPv4 or IPv6 header indicates. That allows UDP Options in addition to the trailer options of the IPv6 payload ๐Ÿง. The result, if UDP Options were used, is shown in Figure 19 ๐Ÿ‘‡.

                            Outer IP Length
       <---------------------------------------------------------->
      +--------+---------+------------------------------+----------+
      | IP Hdr | UDP Hdr | IPv6 packet/len | TE trailer | surplus  |
      +--------+---------+------------------------------+----------+
                          <--------------->
                          Inner IPv6 Length
                <-------------------------------------->
                              UDP Length

          Figure 19: TE Trailers and UDP Options Used Concurrently

UDP Options cannot be supported when a UDP packet has no independent UDP Length. One such case is when UDP Length==0 in IPv6, intended for (but not limited to) IPv6 Jumbograms [RFC2675] ๐Ÿ‹. Note that although this technique is "Standard", the specification did not "update" UDP [RFC0768]. Another such case arises when UDP is proxied via HTTP [RFC9298], as the UDP header is omitted and only the UDP user data is transported ๐ŸŒ.

This document is consistent with the UDP profile for RObust Header Compression (ROHC) [RFC3095], noted here ๐Ÿ—œ๏ธ:

   |  The Length field of the UDP header MUST match the Length field(s)
   |  of the preceding subheaders, i.e., there must not be any padding
   |  after the UDP payload that is covered by the IP Length.

ROHC compresses UDP headers only when this match succeeds. It does not prohibit UDP headers where the match fails. In those cases, ROHC default rules (Section 5.10 of [RFC3095]) would cause the UDP header to remain uncompressed. Upon receipt of a compressed UDP header, Appendix A.1.3 of [RFC3095] indicates that the UDP Length is "INFERRED"; in uncompressed packets, it would simply be explicitly provided ๐Ÿงฉ.

This issue of handling UDP header compression is more explicitly described in more recent specifications, e.g., Section 10.10 of [RFC8724] ๐Ÿ“š.

23. Multicast and Broadcast Considerations ๐Ÿ“ก

UDP Options are primarily intended for unicast use ๐Ÿ’Œ. Using these options over multicast or broadcast IP requires careful consideration. For example, you need to make sure the options used are safe for different endpoints to interpret differently (e.g., either to support or silently ignore), or make sure that all receivers of a multicast or broadcast group confirm support for the options in use ๐Ÿ‘ฏ.

24. Network Management Considerations ๐ŸŒธ

UDP Options use and configuration may be useful to track and manage remotely ๐Ÿ›ฐ๏ธ. IP Flow Information Export (IPFIX) [RFC7011] Information Elements for UDP Options have been defined in [RFC9870]. Similar to what has been done for TCP [RFC9648], a YANG model [RFC7950] for use by network management protocols (e.g., NETCONF [RFC6241] or RESTCONF [RFC8040]) may be developed. Development of these models is outside the scope of this document ๐Ÿงธ.

25. Security Considerations ๐Ÿ”’

๐Ÿšจ Bestie, this is the serious part, so read it carefully! ๐Ÿšจ

There are a number of security issues raised by the introduction of options to UDP ๐Ÿ’€. Some are specific to this variant, but others are associated with any packet processing mechanism. All are discussed further in this section.

25.1. General Considerations Regarding the Use of Options

Note that any user application that considers UDP Options to adversely affect security need not enable them ๐Ÿ™…โ€โ™€๏ธ. However, their use does not impact security in a substantially different way than TCP options. Both enable the use of a control channel that has the potential for abuse. Similar to TCP, there are many options that, if unprotected, could be used by an attacker to interfere with communication ๐Ÿ˜ค.

UDP Options are not covered by DTLS [RFC9147]. Neither TLS [RFC8446] (Transport Layer Security for TCP) nor DTLS (TLS for UDP) protect the transport layer. Both operate as a shim layer solely on the user data of transport packets, protecting only their contents ๐Ÿ›ก๏ธ.

Just as TLS does not protect the TCP header or its options, DTLS does not protect the UDP header or the new options introduced by this document. Transport security is provided in TCP by the TCP Authentication Option (TCP-AO) [RFC5925] and, when defined, in UDP by the Authentication (AUTH) Option (Section 11.9) and, when defined, the UNSAFE Encryption (UENC) Option (Section 12). Transport headers are also protected as payload when using IP security (IPsec) [RFC4301] ๐Ÿ”.

Some UDP Options are never passed to the receiving application, notably FRAG, NOP, and EOL ๐Ÿซฅ. They are not intended to convey information, either by their presence (FRAG, EOL) or by their number (NOP). It could also be useful to provide the options received in a reference order (e.g., sorted by option number) to avoid the order of options being used as a covert channel ๐Ÿ•ต๏ธโ€โ™€๏ธ.

All logging is rate limited to avoid logging itself becoming a resource vulnerability ๐Ÿชต๐Ÿ’….

25.2. Considerations Regarding On-Path Attacks โœจ

okay so UDP Options are like any other options: they can expose option information to on-path attackers ๐Ÿ‘€, unless the options are encrypted (which might happen with some configurations of UENC, when it gets defined). Application protocol designers are expected to make sure nobody treats information in UDP Options as private unless UENC actually provides that privacy ๐Ÿ™ˆ. Designers who use secure payloads (say, via DTLS) need to know that UDP Options add information that sits outside the UDP payload ๐Ÿ’…, so it isn't protected by that same mechanism. Alternate mechanisms (again, maybe some UENC configurations) could be needed too, to guard against information disclosure ๐Ÿ”.

>> Implementations worried about UDP Options being used as a covert channel MAY consider limiting use of some or all options ๐Ÿ•ต๏ธโ€โ™€๏ธ. Those implementations SHOULD return options in an order that isn't related to their sequence in the received packet ๐Ÿ”€.

Ngl, UDP Options also open up new chances for Distributed DoS (DDoS) attacks ๐Ÿ˜ญ, especially through fragmentation ๐Ÿ’ฅ. When they're enabled, UDP Options add extra work at the receiver ๐Ÿฅต. Of the "must-support" options, only REQ (for example, when used with DPLPMTUD [RFC9869]) will make the upper layer start a UDP response when the user hasn't transmitted anything ๐Ÿซข.

>> Implementations concerned about DoS attacks that use large numbers of UDP Options (implemented or unknown), or long runs of repeating valid options (like NOPs), SHOULD detect excessive occurrences and limit the resources they use, for instance through silent packet drops ๐Ÿ›‘. Such responses SHOULD be logged ๐Ÿ“. The specific thresholds depend on the implementation, so they aren't included here ๐Ÿคทโ€โ™€๏ธ.

25.3. Considerations Regarding Option Processing ๐Ÿงฉ

UDP Options use a TLV syntax that's similar to TCP's ๐ŸŽ€. That syntax is known to need serial processing, and it could be a DoS risk. For example, an attacker could add lots of unknown options that have to be parsed in full, which is also the case for IPv6 [RFC8504] ๐Ÿ˜ค.

Using UDP packets with inconsistent IP and UDP Length fields can trigger a buffer overflow if it isn't handled properly ๐Ÿšจ. That happens if space is allocated based on the smaller field but copying is based on the larger one. There have been no reports of this vulnerability though ๐Ÿ™Œ, and it would depend on inconsistent use of the two fields for memory allocation and copying.

Required options come first and appear at most once each ๐Ÿ’–. The exception is NOPs, which never need to come in runs of more than seven in a row โœจ. That's why their DoS impact is limited ๐Ÿ’…. TLV formats for options do need serial processing, but any format that allows future options (whether they're ignored or not) could bring a similar DoS vulnerability ๐Ÿฅบ.

>> Implementations concerned that UDP Options could introduce a vulnerability MAY implement only the required UDP Options, and SHOULD also limit TLV processing by number of non-padding options, total length, or both ๐Ÿšง. The number of non-zero TLVs allowed in that case MUST be at least as many as the number of concurrent options supported, plus a few extra to handle unexpected unknown options ๐Ÿงฎ. It SHOULD also consider being adaptive and based on the implementation, so the limit isn't locked in globally ๐Ÿ”“.

For example, if a system supports 10 different option types that could be used at the same time, it's expected to allow up to around 13-14 different options in the same packet ๐ŸŒˆ. This document doesn't specify a fixed minimum ๐Ÿ™…โ€โ™€๏ธ, but it does recognize that a given system might not expect more than a few unknown option types per packet ๐Ÿ“.

25.4. Considerations for Fragmentation ๐Ÿงต

UDP fragmentation brings its own set of security concerns ๐Ÿ˜ฌ. They can be handled in a way similar to IP reassembly or TCP segment reordering [CERT18] ๐Ÿ› ๏ธ. In particular, the number of UDP packets pending reassembly, and the effort used for reassembly, is typically limited ๐Ÿ“‰. It could also be useful to assume a reasonable minimum fragment size, for example that non-terminal fragments are never smaller than 500 bytes ๐Ÿ“.

>> Implementations concerned that UDP fragmentation could introduce a vulnerability SHOULD implement limits on the number of pending fragments ๐Ÿšฆ.

25.5. Considerations for Providing UDP Security ๐Ÿ”

UDP security is not meant to rely only on transport layer processing of options ๐Ÿ’ญ. UNSAFE Options are the only type that share fate with the UDP data ๐Ÿซฑ๐Ÿซฒ, because the data is hidden in the surplus area until those options are processed ๐Ÿ™ˆ. All other options default to being silently ignored at the transport layer ๐Ÿคซ. They could still be dropped if that default is overridden (for example, by configuration) or discarded at the application layer (for example, using information about the processed options that is passed along with the UDP packet) ๐Ÿ—‘๏ธ.

Options that provide UDP security, like AUTH and UENC, need endpoint key and security parameter coordination ๐Ÿ”‘. UDP Options are stateless, so they don't facilitate that coordination ๐Ÿ˜ต. These parameters include whether and when to override the defaults described here ๐ŸŽ›๏ธ. That matters especially at the transmitter, for deciding when emitted packets need to include AUTH ๐Ÿ“ค, and at the receiver, for deciding whether (and when) packets with failed AUTH, or without AUTH (or that fail the AUTH checks), are not forwarded to the user or application ๐Ÿšซ.

25.6. Considerations Regarding Middleboxes ๐Ÿฐ

Some middleboxes act as UDP relays ๐Ÿ”. They forward data between a UDP socket and another transport socket by modifying the IP and/or UDP headers, without properly acting as a protocol endpoint (that is, an application layer proxy) ๐Ÿ˜ณ. In those cases, a sender might add UDP Options that get stripped by the middlebox before the packet is forwarded to the second socket ๐Ÿช„. The remote application won't receive the options ๐Ÿ™…โ€โ™€๏ธ. For SAFE Options, the payload data will be received ๐Ÿ“ฌ. For UNSAFE Options, the payload data will not be received ๐Ÿ’€. The application then functions as it would when talking to a remote endpoint that doesn't support UDP Options ๐Ÿซ .

Also, [Zu20] reports that packets containing UDP Options don't traverse certain Internet paths ๐Ÿ—บ๏ธ. Most likely, those options were stripped (for example, by resetting the IP Length to match the UDP Length, which truncates the surplus area) or the packets with options were dropped ๐Ÿฅ€. UDP Options do not function over those paths ๐Ÿ˜ญ.

26. IANA Considerations ๐Ÿ“‹

IANA has created the "User Datagram Protocol (UDP)" registry group ๐ŸŽ€. It consists of the "UDP Option Kind Numbers" registry and a pointer to the unified "TCP/UDP Experimental Option Experiment Identifiers (TCP/UDP ExIDs)" registry ๐Ÿงพ. The "TCP experimental IDs (ExIDs)" registry has been renamed to the "TCP/UDP Experimental Option Experiment Identifiers (TCP/UDP ExIDs)" registry, and it's now a unified registry for both TCP and UDP ExIDs ๐Ÿค. IANA has added the following note to the unified TCP/UDP ExID registry:

|  16-bit ExIDs can be used with either TCP or UDP; 32-bit ExIDs can
|  be used with TCP or their first 16 bits can be used with UDP.  Use
|  with each transport (TCP, UDP) is indicated in the protocol
|  column, as defined in RFC 9868.

Initial values of the "UDP Option Kind Numbers" registry are as listed in Section 10, including those both assigned and reserved ๐Ÿ“š. Additional values in this registry are to be assigned from the Unassigned values in Section 10 by IESG Approval or Standards Action [RFC8126] โœ…. Those assignments are subject to the conditions set forth in this document, particularly (but not limited to) those in Section 13 ๐Ÿ”’.

>> Although option nicknames are not used in-band, new UNSAFE Option names MUST commence with the capital letter "U", and new SAFE Options MUST NOT commence with either uppercase or lowercase "U" ๐Ÿ”ค.

IANA has added the following note to the "UDP Option Kind Numbers" registry, indicating that entries are mandatory to implement when UDP Options are supported ๐Ÿ“Œ. No new options may be created that are mandatory to implement in all UDP Options implementations ๐Ÿšซ.

|  Codepoints 0-7 MUST be supported on any implementation supporting
|  UDP Options.  All others are supported at the discretion of each
|  implementation.

UDP Experimental Option Experiment Identifiers (UDP ExIDs) are meant to be used in a similar way to TCP ExIDs [RFC6994] ๐Ÿงช. Both TCP and UDP ExIDs are managed as a single, unified registry ๐Ÿ—‚๏ธ. That's because such options could be used for both transport protocols, and the option space is large enough that there's no clear need to maintain them separately ๐ŸŒŒ. This TCP/UDP ExIDs registry has entries for both transports ๐ŸšŒ, but each codepoint needs to be explicitly defined for each transport protocol where it's used ๐Ÿ™‹โ€โ™€๏ธ. In other words, defining a codepoint in TCP doesn't imply it has a similar use in UDP ๐Ÿ™…โ€โ™€๏ธ. IANA has added a "Protocol" field to the registry and updated the current TCP ExIDs to be indicated as defined for TCP ๐Ÿท๏ธ. New assignments are to indicate the transport they're defined for ๐Ÿ’œ.

TCP/UDP ExIDs can be used in either or both of the UDP EXP (Section 11.10) or UEXP (Section 12.3) Options ๐ŸŽ. TCP/UDP ExID entries for use in UDP consist of a 16-bit ExID (in network-standard order) and, as with the original TCP ExIDs, will preferably also include a short description and acronym for use in documentation ๐Ÿ“. TCP/UDP ExIDs used for UDP are always 16 bits ๐Ÿ”ข. Their use in EXP and UEXP Options is required, so they don't need a larger codepoint value to decrease the probability of accidental occurrence with non-ExID uses of the experimental options ๐ŸŽฒ. That's the case with TCP ExIDs, for example when using 32-bit ExIDs ๐Ÿง. ExIDs defined solely for TCP options could be either 16 or 32 bits ๐ŸŒ—. All ExIDs, including UDP ones now, need to be unique in their first 16 bits, as originally described for TCP [RFC6994] ๐Ÿ”‘.

Values in the TCP/UDP ExID registry are to be assigned by IANA using the First Come First Served (FCFS) policy [RFC8126] ๐Ÿ. That policy applies to both the ExID value and the acronym ๐Ÿ”ค. UDP Options using these ExIDs are subject to the same conditions as new UDP Options ๐Ÿ’…. In other words, they too are subject to the conditions set forth in this document, particularly (but not limited to) those in Section 13 ๐Ÿ“œ.

27. References ๐Ÿ“š

27.1. Normative References โœจ

okay bestie, these are the docs you NEED to have open before you touch the spec ๐Ÿ“š๐Ÿ’… they're the foundation, so you can't skip them ๐Ÿซถ

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

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

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

[RFC9869] Fairhurst, G. and T. Jones, "Datagram Packetization Layer Path MTU Discovery (DPLPMTUD) for UDP Options", RFC 9869, DOI 10.17487/RFC9869, October 2025, https://www.rfc-editor.org/info/rfc9869.


27.2. Informative References ๐ŸŒธ

these ones are the extra-cozy reading list ๐Ÿงš the drafts, the old classics, and the wild side quests that give you the full story ๐Ÿ’œ they're not required reading, but ngl they're iconic and you'll want them ๐Ÿ”ฅ

[CERT18] CERT Coordination Center, "TCP implementations vulnerable to Denial of Service", Vulnerability Note VU#962459, Software Engineering Institute, CMU, 2018, https://www.kb.cert.org/vuls/id/962459.

[Fa18] Fairhurst, G., Jones, T., and R. Zullo, "Checksum Compensation Options for UDP Options", Work in Progress, Internet-Draft, draft-fairhurst-udp-options-cco-00, 19 October 2018, https://datatracker.ietf.org/doc/html/draft-fairhurst-udp-options-cco-00.

[He24] Heard, C. M., "Use of UDP Options for Transmission of Large DNS Responses", Work in Progress, Internet-Draft, draft-heard-dnsop-udp-opt-large-dns-responses-00, 28 April 2024, https://datatracker.ietf.org/doc/html/draft-heard-dnsop-udp-opt-large-dns-responses-00.

[Hi15] Hildebrand, J. and B. Trammell, "Substrate Protocol for User Datagrams (SPUD) Prototype", Work in Progress, Internet-Draft, draft-hildebrand-spud-prototype-03, 9 March 2015, https://datatracker.ietf.org/doc/html/draft-hildebrand-spud-prototype-03.

[La78] Lamport, L., "Time, clocks, and the ordering of events in a distributed system", Communications of the ACM, vol. 21, no. 7, pp. 558-565, DOI 10.1145/359545.359563, July 1978, https://doi.org/10.1145/359545.359563.

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

[RFC0868] Postel, J. and K. Harrenstien, "Time Protocol", STD 26, RFC 868, DOI 10.17487/RFC0868, May 1983, https://www.rfc-editor.org/info/rfc868.

[RFC1071] Braden, R., Borman, D., and C. Partridge, "Computing the Internet checksum", RFC 1071, DOI 10.17487/RFC1071, September 1988, https://www.rfc-editor.org/info/rfc1071.

[RFC1141] Mallory, T. and A. Kullberg, "Incremental updating of the Internet checksum", RFC 1141, DOI 10.17487/RFC1141, January 1990, https://www.rfc-editor.org/info/rfc1141.

[RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191, DOI 10.17487/RFC1191, November 1990, https://www.rfc-editor.org/info/rfc1191.

[RFC2675] Borman, D., Deering, S., and R. Hinden, "IPv6 Jumbograms", RFC 2675, DOI 10.17487/RFC2675, August 1999, https://www.rfc-editor.org/info/rfc2675.

[RFC2923] Lahey, K., "TCP Problems with Path MTU Discovery", RFC 2923, DOI 10.17487/RFC2923, September 2000, https://www.rfc-editor.org/info/rfc2923.

[RFC3095] Bormann, C., Burmeister, C., Degermark, M., Fukushima, H., Hannu, H., Jonsson, L., Hakenberg, R., Koren, T., Le, K., Liu, Z., Martensson, A., Miyazaki, A., Svanbro, K., Wiebke, T., Yoshimura, T., and H. Zheng, "RObust Header Compression (ROHC): Framework and four profiles: RTP, UDP, ESP, and uncompressed", RFC 3095, DOI 10.17487/RFC3095, July 2001, https://www.rfc-editor.org/info/rfc3095.

[RFC3173] Shacham, A., Monsour, B., Pereira, R., and M. Thomas, "IP Payload Compression Protocol (IPComp)", RFC 3173, DOI 10.17487/RFC3173, September 2001, https://www.rfc-editor.org/info/rfc3173.

[RFC3385] Sheinwald, D., Satran, J., Thaler, P., and V. Cavanna, "Internet Protocol Small Computer System Interface (iSCSI) Cyclic Redundancy Check (CRC)/Checksum Considerations", RFC 3385, DOI 10.17487/RFC3385, September 2002, https://www.rfc-editor.org/info/rfc3385.

[RFC3692] Narten, T., "Assigning Experimental and Testing Numbers Considered Useful", BCP 82, RFC 3692, DOI 10.17487/RFC3692, January 2004, https://www.rfc-editor.org/info/rfc3692.

[RFC3828] Larzon, L., Degermark, M., Pink, S., Jonsson, L., Ed., and G. Fairhurst, Ed., "The Lightweight User Datagram Protocol (UDP-Lite)", RFC 3828, DOI 10.17487/RFC3828, July 2004, https://www.rfc-editor.org/info/rfc3828.

[RFC4301] Kent, S. and K. Seo, "Security Architecture for the Internet Protocol", RFC 4301, DOI 10.17487/RFC4301, December 2005, https://www.rfc-editor.org/info/rfc4301.

[RFC4340] Kohler, E., Handley, M., and S. Floyd, "Datagram Congestion Control Protocol (DCCP)", RFC 4340, DOI 10.17487/RFC4340, March 2006, https://www.rfc-editor.org/info/rfc4340.

[RFC4380] Huitema, C., "Teredo: Tunneling IPv6 over UDP through Network Address Translations (NATs)", RFC 4380, DOI 10.17487/RFC4380, February 2006, https://www.rfc-editor.org/info/rfc4380.

[RFC4787] Audet, F., Ed. and C. Jennings, "Network Address Translation (NAT) Behavioral Requirements for Unicast UDP", BCP 127, RFC 4787, DOI 10.17487/RFC4787, January 2007, https://www.rfc-editor.org/info/rfc4787.

[RFC5925] Touch, J., Mankin, A., and R. Bonica, "The TCP Authentication Option", RFC 5925, DOI 10.17487/RFC5925, June 2010, https://www.rfc-editor.org/info/rfc5925.

[RFC6081] Thaler, D., "Teredo Extensions", RFC 6081, DOI 10.17487/RFC6081, January 2011, https://www.rfc-editor.org/info/rfc6081.

[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., "Network Configuration Protocol (NETCONF)", RFC 6241, DOI 10.17487/RFC6241, June 2011, https://www.rfc-editor.org/info/rfc6241.

[RFC6864] Touch, J., "Updated Specification of the IPv4 ID Field", RFC 6864, DOI 10.17487/RFC6864, February 2013, https://www.rfc-editor.org/info/rfc6864.

[RFC6935] Eubanks, M., Chimento, P., and M. Westerlund, "IPv6 and UDP Checksums for Tunneled Packets", RFC 6935, DOI 10.17487/RFC6935, April 2013, https://www.rfc-editor.org/info/rfc6935.

[RFC6978] Touch, J., "A TCP Authentication Option Extension for NAT Traversal", RFC 6978, DOI 10.17487/RFC6978, July 2013, https://www.rfc-editor.org/info/rfc6978.

[RFC6994] Touch, J., "Shared Use of Experimental TCP Options", RFC 6994, DOI 10.17487/RFC6994, August 2013, https://www.rfc-editor.org/info/rfc6994.

[RFC7011] Claise, B., Ed., Trammell, B., Ed., and P. Aitken, "Specification of the IP Flow Information Export (IPFIX) Protocol for the Exchange of Flow Information", STD 77, RFC 7011, DOI 10.17487/RFC7011, September 2013, https://www.rfc-editor.org/info/rfc7011.

[RFC7323] Borman, D., Braden, B., Jacobson, V., and R. Scheffenegger, Ed., "TCP Extensions for High Performance", RFC 7323, DOI 10.17487/RFC7323, September 2014, https://www.rfc-editor.org/info/rfc7323.

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

[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, "RESTCONF Protocol", RFC 8040, DOI 10.17487/RFC8040, January 2017, https://www.rfc-editor.org/info/rfc8040.

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

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

[RFC8201] McCann, J., Deering, S., Mogul, J., and R. Hinden, Ed., "Path MTU Discovery for IP version 6", STD 87, RFC 8201, DOI 10.17487/RFC8201, July 2017, https://www.rfc-editor.org/info/rfc8201.

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

[RFC8504] Chown, T., Loughney, J., and T. Winters, "IPv6 Node Requirements", BCP 220, RFC 8504, DOI 10.17487/RFC8504, January 2019, https://www.rfc-editor.org/info/rfc8504.

[RFC8724] Minaburo, A., Toutain, L., Gomez, C., Barthel, D., and JC. Zuniga, "SCHC: Generic Framework for Static Context Header Compression and Fragmentation", RFC 8724, DOI 10.17487/RFC8724, April 2020, https://www.rfc-editor.org/info/rfc8724.

[RFC8899] Fairhurst, G., Jones, T., Tรผxen, M., Rรผngeler, I., and T. Vรถlker, "Packetization Layer Path MTU Discovery for Datagram Transports", RFC 8899, DOI 10.17487/RFC8899, September 2020, https://www.rfc-editor.org/info/rfc8899.

[RFC9040] Touch, J., Welzl, M., and S. Islam, "TCP Control Block Interdependence", RFC 9040, DOI 10.17487/RFC9040, July 2021, https://www.rfc-editor.org/info/rfc9040.

[RFC9147] Rescorla, E., Tschofenig, H., and N. Modadugu, "The Datagram Transport Layer Security (DTLS) Protocol Version 1.3", RFC 9147, DOI 10.17487/RFC9147, April 2022, https://www.rfc-editor.org/info/rfc9147.

[RFC9187] Touch, J., "Sequence Number Extension for Windowed Protocols", RFC 9187, DOI 10.17487/RFC9187, January 2022, https://www.rfc-editor.org/info/rfc9187.

[RFC9260] Stewart, R., Tรผxen, M., and K. Nielsen, "Stream Control Transmission Protocol", RFC 9260, DOI 10.17487/RFC9260, June 2022, https://www.rfc-editor.org/info/rfc9260.

27.2. Informative References (continued) ๐Ÿฆ‹

[RFC9293] Eddy, W., Ed., "Transmission Control Protocol (TCP)", STD 7, RFC 9293, DOI 10.17487/RFC9293, August 2022, https://www.rfc-editor.org/info/rfc9293. Okay, this is the TCP spec, the OG that basically runs the internet's reliable-delivery vibes ๐Ÿ’–

[RFC9298] Schinazi, D., "Proxying UDP in HTTP", RFC 9298, DOI 10.17487/RFC9298, August 2022, https://www.rfc-editor.org/info/rfc9298. This one is about tunneling UDP through HTTP, which is such a glow-up for UDP ๐ŸŒˆ

[RFC9648] Scharf, M., Jethanandani, M., and V. Murgai, "YANG Data Model for TCP", RFC 9648, DOI 10.17487/RFC9648, October 2024, https://www.rfc-editor.org/info/rfc9648. A YANG data model for TCP, so yes, it's giving structured config ๐Ÿ“‹

[RFC9870] Boucadair, M. and T. Reddy.K, "Export of UDP Options Information in IP Flow Information Export (IPFIX)", RFC 9870, DOI 10.17487/RFC9870, October 2025, https://www.rfc-editor.org/info/rfc9870. This is the one that lets you export UDP Options info over IPFIX, very useful and very on-brand for this whole doc ๐Ÿซถ

[To18] Touch, J. D., "A TCP Authentication Option Extension for Payload Encryption", Work in Progress, Internet-Draft, draft-touch-tcp-ao-encrypt-09, 19 July 2018, https://datatracker.ietf.org/doc/html/draft-touch-tcp-ao-encrypt-09. A draft (so, still cooking) about encrypting the payload with the TCP Authentication Option ๐Ÿ”ฅ

[To24] Touch, J. D., "The UDP Authentication Option", Work in Progress, Internet-Draft, draft-touch-tsvwg-udp-auth-opt-00, 3 March 2024, https://datatracker.ietf.org/doc/html/draft-touch-tsvwg-udp-auth-opt-00. Same author, but for UDP auth, and it's also a work in progress ๐Ÿ‘‘

[Zu20] Zullo, R., Jones, T., and G. Fairhurst, "Overcoming the Sorrows of the Young UDP Options", 4th Network Traffic Measurement and Analysis Conference (TMA), 2020, https://dl.ifip.org/db/conf/tma/tma2020/tma2020-camera-paper70.pdf. The title alone is iconic ๐Ÿ˜ญ It's a conference paper about the challenges UDP Options run into.


Appendix A. Implementation Information โœจ

Okay, this is the part for implementers who want their API names to match up ๐Ÿ’… The following info is here to encourage consistent naming across API implementations, so everyone's on the same page.

System-level variables (sysctl) are listed in Table 2 below:

     +=======================+=========+=======================+
     | Name                  | Default | Meaning               |
     +=======================+=========+=======================+
     | net.ipv4.udp_opt      | 0       | UDP Options available |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_ocs  | 1       | Use OCS               |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_apc  | 0       | Include APC           |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_frag | 0       | Fragment              |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_mds  | 0       | Include MDS           |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_mrds | 0       | Include MRDS          |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_req  | 0       | Include REQ           |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_resp | 0       | Include RES           |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_time | 0       | Include TIME          |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_auth | 0       | Include AUTH          |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_exp  | 0       | Include EXP           |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_ucmp | 0       | Include UCMP          |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_uenc | 0       | Include UENC          |
     +-----------------------+---------+-----------------------+
     | net.ipv4.udp_opt_uexp | 0       | Include UEXP          |
     +-----------------------+---------+-----------------------+

                               Table 2

Next up are the socket options (sockopt), which are cached for outgoing datagrams. That's Table 3 ๐ŸŒธ

           +==============+=============================+
           | Name         | Meaning                     |
           +==============+=============================+
           | UDP_OPT      | Enable UDP Options (at all) |
           +--------------+-----------------------------+
           | UDP_OPT_OCS  | Use UDP OCS                 |
           +--------------+-----------------------------+
           | UDP_OPT_APC  | Enable UDP APC Option       |
           +--------------+-----------------------------+
           | UDP_OPT_FRAG | Enable UDP fragmentation    |
           +--------------+-----------------------------+
           | UDP OPT MDS  | Enable UDP MDS Option       |
           +--------------+-----------------------------+
           | UDP OPT MRDS | Enable UDP MRDS Option      |
           +--------------+-----------------------------+
           | UDP OPT REQ  | Enable UDP REQ Option       |
           +--------------+-----------------------------+
           | UDP OPT RES  | Enable UDP RES Option       |
           +--------------+-----------------------------+
           | UDP_OPT_TIME | Enable UDP TIME Option      |
           +--------------+-----------------------------+
           | UDP OPT AUTH | Enable UDP AUTH Option      |
           +--------------+-----------------------------+
           | UDP OPT EXP  | Enable UDP EXP Option       |
           +--------------+-----------------------------+
           | UDP_OPT_UCMP | Enable UDP UCMP Option      |
           +--------------+-----------------------------+
           | UDP_OPT_UENC | Enable UDP UENC Option      |
           +--------------+-----------------------------+
           | UDP OPT UEXP | Enable UDP UEXP Option      |
           +--------------+-----------------------------+

                              Table 3

For send/sendto parameters, it's the same as the sysctl stuff, just with different prefixes:

  • (Same as sysctl, with different prefixes)

Connection parameters (per-socket pair cached state, part UCB) are in Table 4 ๐Ÿ’œ

              +==============+======================+
              | Name         | Initial Value        |
              +==============+======================+
              | opts_enabled | net.ipv4.udp_opt     |
              +--------------+----------------------+
              | ocs_enabled  | net.ipv4.udp_opt_ocs |
              +--------------+----------------------+

                               Table 4
NB: The JUNK Option is included for debugging purposes and is not intended to be enabled otherwise. So, bestie, this is a debugging-only vibe. Please don't turn it on in prod ๐Ÿ™ˆ

The JUNK system variable is set like this:

System variables:

net.ipv4.udp_opt_junk 0

The JUNK sysctl table is Table 5:

       +=======================+=========+=====================+
       | Name                  | Default | Meaning             |
       +=======================+=========+=====================+
       | net.ipv4.udp_opt_junk | 0       | Default use of junk |
       +-----------------------+---------+---------------------+

                                Table 5

The JUNK socket options are Table 6 ๐Ÿงš

      +==============+=========+=================================+
      | Name         | Params  | Meaning                         |
      +==============+=========+=================================+
      | UDP_JUNK     | -       | Enable UDP junk option          |
      +--------------+---------+---------------------------------+
      | UDP_JUNK_VAL | fillval | Value to use as junk fill       |
      +--------------+---------+---------------------------------+
      | UDP_JUNK_LEN | length  | Length of junk payload in bytes |
      +--------------+---------+---------------------------------+

                                Table 6

And the connection parameters for JUNK are Table 7:

                +==============+=======================+
                | Name         | Initial Value         |
                +==============+=======================+
                | junk_enabled | net.ipv4.udp_opt_junk |
                +--------------+-----------------------+
                | junk_value   | 0xABCD                |
                +--------------+-----------------------+
                | junk_len     | 4                     |
                +--------------+-----------------------+

                                Table 7

Acknowledgments ๐Ÿซถ

This work got so much help from Erik Auerswald, Bob Briscoe, Ken Calvert, Ted Faber, and Gorry Fairhurst (who contributed OCS for errant middlebox traversal). C. M. Heard, the editor of this doc, also gets a huge shoutout ๐Ÿ‘‘ They did the work of combining the previous FRAG and LITE Options into the new FRAG, plus Figure 12. Tom Herbert, Tom Jones, Mark Smith, Carl Williams, and Raffaele Zullo were also a massive help, and so were the discussions on the IETF TSVWG and SPUD email lists. Literally so many brilliant people ๐Ÿ˜ญ

This work was partly supported by USC/ISI's Postel Center. Thank you, Postel Center ๐ŸŒˆ


Authors' Addresses ๐Ÿ’Œ

Joe Touch Independent Consultant Manhattan Beach, CA 90266 United States of America Phone: +1 (310) 560-0334 Email: touch@strayalpha.com

C. M. (Mike) Heard (editor) Unaffiliated PO Box 2667 Redwood City, CA 94064-2667 United States of America Phone: +1 (408) 499-7257 Email: heard@pobox.com

๐Ÿ“ฆ where this page comes from