rfc9267xml2.original.xml   rfc9267.xml 
<?xml version='1.0' encoding='utf-8'?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
<!ENTITY RFC1035 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RF
C.1035.xml">
<!ENTITY RFC5625 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RF
C.5625.xml">
<!ENTITY I-D.ietf-dnsind-local-compression SYSTEM "https://xml2rfc.ietf.org/publ
ic/rfc/bibxml3/reference.I-D.ietf-dnsind-local-compression.xml">
<!ENTITY RFC6895 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RF
C.6895.xml">
<!ENTITY RFC8484 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RF
C.8484.xml">
<!ENTITY RFC7858 SYSTEM "https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RF
C.7858.xml">
]>
<rfc submissionType="independent" docName="draft-dashevskyi-dnsrr-antipatterns-0 <!DOCTYPE rfc [
6" category="info" ipr="trust200902"> <!ENTITY nbsp "&#160;">
<!ENTITY zwsp "&#8203;">
<!ENTITY nbhy "&#8209;">
<!ENTITY wj "&#8288;">
]>
<!-- Generated by id2xml 1.5.0 on 2022-05-24T23:44:10Z --> <rfc xmlns:xi="http://www.w3.org/2001/XInclude" submissionType="independent" cat
<?rfc strict="yes"?> egory="info"
<?rfc compact="yes"?> docName="draft-dashevskyi-dnsrr-antipatterns-06" number="9267" ipr="trust200902"
<?rfc subcompact="no"?> obsoletes=""
<?rfc symrefs="yes"?> updates="" xml:lang="en" symRefs="true" sortRefs="true" tocInclude="true" versio
<?rfc sortrefs="no"?> n="3">
<?rfc text-list-symbols="o*+-"?>
<?rfc toc="yes"?>
<!-- xml2rfc v2v3 conversion 3.12.7 -->
<!-- Generated by id2xml 1.5.0 on 2022-05-24T23:44:10Z -->
<front> <front>
<title abbrev="Common implementation anti-patterns rela">Common implement <title abbrev="Vulnerabilities in DNS RR Processing">Common Implementation A
ation anti-patterns related to Domain Name System (DNS) resource record (RR) pro nti-Patterns Related to Domain Name System (DNS) Resource Record (RR) Processing
cessing</title> </title>
<author initials="S." surname="Dashevskyi" fullname="Stanislav Dashevskyi
">
<organization>Forescout Technologies</organization>
<address><postal>
<street>John F. Kennedylaan, 2</street>
<city>Eindhoven</city>
<code>5612AB</code>
<country>The Netherlands</country>
</postal>
<email>stanislav.dashevskyi@forescout.com</email>
</address>
</author>
<author initials="D." surname="dos Santos" fullname="Daniel dos Santos">
<organization>Forescout Technologies</organization>
<address><postal>
<street>John F. Kennedylaan, 2</street>
<city>Eindhoven</city>
<code>5612AB</code>
<country>The Netherlands</country>
</postal>
<email>daniel.dossantos@forescout.com</email>
</address>
</author>
<author initials="J." surname="Wetzels" fullname="Jos Wetzels">
<organization>Forescout Technologies</organization>
<address><postal>
<street>John F. Kennedylaan, 2</street>
<city>Eindhoven</city>
<code>5612AB</code>
<country>The Netherlands</country>
</postal>
<email>jos.wetzels@forescout.com</email>
</address>
</author>
<author initials="A." surname="Amri" fullname="Amine Amri">
<organization>Forescout Technologies</organization>
<address><postal>
<street>John F. Kennedylaan, 2</street>
<city>Eindhoven</city>
<code>5612AB</code>
<country>The Netherlands</country>
</postal>
<email>amine.amri@forescout.com</email>
</address>
</author>
<date year="2022" month="May"/>
<!-- [rfced] Please insert any keywords (beyond those that appear in the title) <seriesInfo name="RFC" value="9267"/>
for use on https://www.rfc-editor.org/search. --> <author initials="S." surname="Dashevskyi" fullname="Stanislav Dashevskyi">
<organization>Forescout Technologies</organization>
<address>
<postal>
<street>John F. Kennedylaan, 2</street>
<city>Eindhoven</city>
<code>5612AB</code>
<country>Netherlands</country>
</postal>
<email>stanislav.dashevskyi@forescout.com</email>
</address>
</author>
<author initials="D." surname="dos Santos" fullname="Daniel dos Santos">
<organization>Forescout Technologies</organization>
<address>
<postal>
<street>John F. Kennedylaan, 2</street>
<city>Eindhoven</city>
<code>5612AB</code>
<country>Netherlands</country>
</postal>
<email>daniel.dossantos@forescout.com</email>
</address>
</author>
<author initials="J." surname="Wetzels" fullname="Jos Wetzels">
<organization>Forescout Technologies</organization>
<address>
<postal>
<street>John F. Kennedylaan, 2</street>
<city>Eindhoven</city>
<code>5612AB</code>
<country>Netherlands</country>
</postal>
<email>jos.wetzels@forescout.com</email>
</address>
</author>
<author initials="A." surname="Amri" fullname="Amine Amri">
<organization>Forescout Technologies</organization>
<address>
<postal>
<street>John F. Kennedylaan, 2</street>
<city>Eindhoven</city>
<code>5612AB</code>
<country>Netherlands</country>
</postal>
<email>amine.amri@forescout.com</email>
</address>
</author>
<date year="2022" month="July"/>
<keyword>example</keyword> <keyword>vulnerabilities</keyword>
<keyword>vulnerability</keyword>
<abstract><t> <abstract>
<t>
This memo describes common vulnerabilities related to Domain Name This memo describes common vulnerabilities related to Domain Name
System (DNS) response record (RR) processing as seen in several DNS System (DNS) resource record (RR) processing as seen in several DNS
client implementations. These vulnerabilities may lead to successful client implementations. These vulnerabilities may lead to successful
Denial-of-Service and Remote Code Execution attacks against the Denial-of-Service and Remote Code Execution attacks against the
affected software. Where applicable, violations of RFC 1035 are affected software. Where applicable, violations of RFC 1035 are
mentioned.</t> mentioned.</t>
</abstract>
</abstract> </front>
</front> <middle>
<section anchor="sect-1" numbered="true" toc="default">
<middle> <name>Introduction</name>
<section title="Introduction" anchor="sect-1"><t> <t>
Recently, there have been major vulnerabilities on DNS Major vulnerabilities in DNS implementations recently became evident and rais
implementations that raised attention to this protocol as an ed attention to this protocol as an important attack vector, as discussed in <xr
important attack vector, such as <xref target="SIGRED"/>, <xref target="SADDN ef target="SIGRED" format="default"/>, <xref target="SADDNS" format="default"/>,
S"/>, and and
<xref target="DNSPOOQ"/> - a set of 7 critical issues affecting the DNS <xref target="DNSPOOQ" format="default"/>, the latter being a set of 7 critic
al issues affecting the DNS
forwarder "dnsmasq".</t> forwarder "dnsmasq".</t>
<t>
<t>
The authors of this memo have analyzed the DNS client implementations The authors of this memo have analyzed the DNS client implementations
of several major TCP/IP protocol stacks and found a set of of several major TCP/IP protocol stacks and found a set of
vulnerabilities that share common implementation flaws vulnerabilities that share common implementation flaws
(anti-patterns). These flaws are related to processing DNS RRs (anti-patterns). These flaws are related to processing DNS resource records (
(discussed in <xref target="RFC1035"/>) and may lead to critical security RRs)
(discussed in <xref target="RFC1035" format="default"/>) and may lead to crit
ical security
vulnerabilities.</t> vulnerabilities.</t>
<t>
<t>
While implementation flaws may differ from one software project to While implementation flaws may differ from one software project to
another, these anti-patterns are highly likely to span across another, these anti-patterns are highly likely to span
multiple implementations. In fact, one of the first CVEs related to multiple implementations. In fact, one of the first "Common Vulnerabilities a
one of the anti-patterns <xref target="CVE-2000-0333"/> dates back to the yea nd Exposures" (CVE) documents related to
r 2000. one of the anti-patterns <xref target="CVE-2000-0333" format="default"/> date
s back to the year 2000.
The observations are not limited to DNS client implementations. The observations are not limited to DNS client implementations.
Any software that processes DNS RRs may be affected, such as Any software that processes DNS RRs may be affected, such as
firewalls, intrusion detection systems, or general purpose DNS packet firewalls, intrusion detection systems, or general-purpose DNS packet
dissectors (e.g., <xref target="CVE-2017-9345"/> in Wireshark). Similar issue dissectors (e.g., the DNS dissector in Wireshark; see <xref target="CVE-2017-
s may 9345" format="default"/>). Similar issues may
also occur in DNS-over-HTTPS <xref target="RFC8484"/> and DNS-over-TLS <xref also occur in DNS-over-HTTPS <xref target="RFC8484" format="default"/> and DN
target="RFC7858"/> S-over-TLS <xref target="RFC7858" format="default"/>
implementations. However, any implementation that deals with the DNS implementations. However, any implementation that deals with the DNS
wire format is subject to the considerations discussed in this draft.</t> wire format is subject to the considerations discussed in this document.</t>
<t>
<t> <xref target="I-D.ietf-dnsind-local-compression" format="default"/> and <xref
<xref target="I-D.ietf-dnsind-local-compression"/> and <xref target="RFC5625" target="RFC5625" format="default"/> briefly mention some of these
/> briefly mention some of these
anti-patterns, but the main purpose of this memo is to provide anti-patterns, but the main purpose of this memo is to provide
technical details behind these anti-patterns, so that the common technical details behind these anti-patterns, so that the common
mistakes can be eradicated.</t> mistakes can be eradicated.</t>
<t>
<t>
We provide general recommendations on mitigating the anti-patterns. We provide general recommendations on mitigating the anti-patterns.
We also suggest that all implementations should drop We also suggest that all implementations should drop
malicious/malformed DNS replies and log them (optionally).</t> malicious/malformed DNS replies and (optionally) log them.</t>
</section>
</section> <section anchor="sect-2" numbered="true" toc="default">
<name>Compression Pointer and Offset Validation</name>
<section title="Compression Pointer and Offset Validation" anchor="sect-2 <t>
"><t> <xref target="RFC1035" format="default"/> defines the DNS message compression
<xref target="RFC1035"/> defines the DNS message compression scheme that can scheme that can be used
be used
to reduce the size of messages. When it is used, an entire domain to reduce the size of messages. When it is used, an entire domain
name or several name labels are replaced with a (compression) pointer name or several name labels are replaced with a (compression) pointer
to a prior occurrence of the same name.</t> to a prior occurrence of the same name.</t>
<t>
<t>
The compression pointer is a combination of two octets: the two most The compression pointer is a combination of two octets: the two most
significant bits are set to 1, and the remaining 14 bits are the significant bits are set to 1, and the remaining 14 bits are the
OFFSET field. This field specifies the offset from the beginning of OFFSET field. This field specifies the offset from the beginning of
the DNS header, at which another domain name or label is located:</t> the DNS header, at which another domain name or label is located:</t>
<artwork name="" type="" align="left" alt=""><![CDATA[
<figure><artwork><![CDATA[
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| 1 1| OFFSET | | 1 1| OFFSET |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
]]></artwork> ]]></artwork>
</figure> <t>
<t>
The message compression scheme explicitly allows a domain name to be The message compression scheme explicitly allows a domain name to be
represented as: (1) a sequence of unpacked labels ending with a zero represented as one of the following: (1) a sequence of unpacked labels ending
octet; (2) a pointer; (3) a sequence of labels ending with a pointer.</t> with a zero
octet, (2) a pointer, or (3) a sequence of labels ending with a pointer.</t>
<t> <t>
However, <xref target="RFC1035"/> does not explicitly state that blindly foll However, <xref target="RFC1035" format="default"/> does not explicitly state
owing that blindly following
compression pointers of any kind can be harmful <xref target="I-D.ietf-dnsind compression pointers of any kind can be harmful <xref target="I-D.ietf-dnsind
-local-compression"/>, as we -local-compression" format="default"/>, as we
could not have had any assumptions about various implementations could not have had any assumptions about various implementations
that would follow.</t> that would follow.</t>
<t>
<t>
Yet, any DNS packet parser that attempts to decompress domain names Yet, any DNS packet parser that attempts to decompress domain names
without validating the value of OFFSET is likely susceptible to without validating the value of OFFSET is likely susceptible to
memory corruption bugs and buffer overruns. These bugs allow for easy memory corruption bugs and buffer overruns. These bugs make it easier to perf
Denial-of-Service attacks, and may result in successful Remote Code orm
Denial-of-Service attacks and may result in successful Remote Code
Execution attacks.</t> Execution attacks.</t>
<t>
<t>
Pseudocode that illustrates a typical example of a broken domain name Pseudocode that illustrates a typical example of a broken domain name
parsing implementation is shown below (Snippet 1):</t> parsing implementation is shown below (<xref target="snippet_1"/>):</t>
<figure><artwork><![CDATA[ <figure anchor="snippet_1">
1:decompress_domain_name(*name, *dns_payload) { <name>A Broken Implementation of a Function That Is Used for Decompressing DNS D
omain Names (Pseudocode)</name>
<sourcecode name="" type="pseudocode"><![CDATA[
1: decompress_domain_name(*name, *dns_payload) {
2: 2:
3: name_buffer[255]; 3: name_buffer[255];
4: copy_offset = 0; 4: copy_offset = 0;
5: 5:
6: label_len_octet = name; 6: label_len_octet = name;
7: dest_octet = name_buffer; 7: dest_octet = name_buffer;
8: 8:
9: while (*label_len_octet != 0x00) { 9: while (*label_len_octet != 0x00) {
10: 10:
11: if (is_compression_pointer(*label_len_octet)) { 11: if (is_compression_pointer(*label_len_octet)) {
12: ptr_offset = get_offset(label_len_octet, 12: ptr_offset = get_offset(label_len_octet,
label_len_octet+1); label_len_octet+1);
13: label_len_octet = dns_payload + ptr_offset + 1; 13: label_len_octet = dns_payload + ptr_offset + 1;
14: } 14: }
15: 15:
16: else { 16: else {
17: length = *label_len_octet; 17: length = *label_len_octet;
18: copy(dest_octet + copy_offset, 18: copy(dest_octet + copy_offset,
label_len_octet+1, *length); label_len_octet+1, *length);
19: 19:
20: copy_offset += length; 20: copy_offset += length;
21: label_len_octet += length + 1; 21: label_len_octet += length + 1;
22: } 22: }
23: 23:
24: } 24: }
25:} 25: }
Snippet 1 - A broken implementation of a function that is used for ]]></sourcecode>
decompressing DNS domain names (pseudocode) </figure>
]]></artwork> <t>
</figure>
<t>
Such implementations typically have a dedicated function for Such implementations typically have a dedicated function for
decompressing domain names (for example, see <xref target="CVE-2020-24338"/> decompressing domain names (for example, see <xref target="CVE-2020-24338" fo
and rmat="default"/> and
<xref target="CVE-2020-27738"/>). Among other parameters, these functions may <xref target="CVE-2020-27738" format="default"/>). Among other parameters, th
accept a pointer to the beginning of the first name label within a ese functions may
accept a pointer to the beginning of the first name label within an
RR ("name") and a pointer to the beginning of the DNS payload to be RR ("name") and a pointer to the beginning of the DNS payload to be
used as a starting point for the compression pointer used as a starting point for the compression pointer
("dns_payload"). The destination buffer for the domain name ("dns_payload"). The destination buffer for the domain name
("name_buffer") is typically limited to 255 bytes as per ("name_buffer") is typically limited to 255 bytes as per
<xref target="RFC1035"/> and can be allocated either in the stack or in the h eap <xref target="RFC1035" format="default"/> and can be allocated either in the stack or in the heap
memory region.</t> memory region.</t>
<t>
<t> The code of the function in <xref target="snippet_1"/> reads the domain name
The code of the function at Snippet 1 reads the domain name label by label from an RR until it reaches the NUL octet ("0x00") that
label-by-label from a RR until it reaches the NUL octet ("0x00") that
signifies the end of a domain name. If the current label length octet signifies the end of a domain name. If the current label length octet
("label_len_octet") is a compression pointer, the code extracts the ("label_len_octet") is a compression pointer, the code extracts the
value of the compression offset and uses it to "jump" to another value of the compression offset and uses it to "jump" to another
label length octet. If the current label length octet is not a label length octet. If the current label length octet is not a
compression pointer, the label bytes will be copied into the name compression pointer, the label bytes will be copied into the name
buffer, and the number of bytes copied will correspond to the value buffer, and the number of bytes copied will correspond to the value
of the current label length octet. After the copy operation, the code of the current label length octet. After the copy operation, the code
will move on to the next label length octet.</t> will move on to the next label length octet.</t>
<t>
<t>
The first issue with this implementation is due to unchecked The first issue with this implementation is due to unchecked
compression offset values. The second issue is due to the absence of compression offset values. The second issue is due to the absence of
checks that ensure that a pointer will eventually arrive at an checks that ensure that a pointer will eventually arrive at a
decompressed domain label. We describe these issues in more detail decompressed domain label. We describe these issues in more detail
below.</t> below.</t>
<t>
<t> <!-- DNE; fixed -->
<xref target="RFC1035"/> states that "... [compression pointer is] a pointer <xref target="RFC1035" format="default"/> states that a compression pointer i
to a prior occurrence of the same name". Also, according to <xref target="RFC103 s "a pointer to a prior occurance [sic] of the same name." Also, according to <x
5"/>, ref target="RFC1035" format="default"/>,
the maximum size of DNS packets that can be sent over the UDP the maximum size of DNS packets that can be sent over UDP
protocol is limited to 512 octets.</t> is limited to 512 octets.</t>
<t>
<t> The pseudocode in <xref target="snippet_1"/> violates these constraints, as
The pseudocode at Snippet 1 violates these constraints, as it will it will
accept a compression pointer that forces the code to read out of the accept a compression pointer that forces the code to read outside the
bounds of a DNS packet. For instance, the compression pointer of bounds of a DNS packet. For instance, a compression pointer set to
"0xffff" will produce the offset of 16383 octets, which is most "0xffff" will produce an offset of 16383 octets, which is most
definitely pointing to a label length octet somewhere past the definitely pointing to a label length octet somewhere past the bounds of the
original DNS packet. Supplying such offset values will most likely original DNS packet. Supplying such offset values will most likely
cause memory corruption issues and may lead to Denial-of-Service cause memory corruption issues and may lead to Denial-of-Service
conditions (e.g., a Null pointer dereference after "label_len_octet" conditions (e.g., a Null pointer dereference after "label_len_octet"
is set to an invalid address in memory). As an additional example, is set to an invalid address in memory). For additional examples,
see <xref target="CVE-2020-25767"/>, <xref target="CVE-2020-24339"/>, and <xr see <xref target="CVE-2020-25767" format="default"/>, <xref target="CVE-2020-
ef target="CVE-2020-24335"/>.</t> 24339" format="default"/>, and <xref target="CVE-2020-24335" format="default"/>.
</t>
<t> <t>
The pseudocode at Snippet 1 allows for jumping from a compression The pseudocode in <xref target="snippet_1"/> allows jumping from a compressio
pointer to another compression pointer and it does not restrict the n
number of such jumps. That is, if a label length octet which is pointer to another compression pointer and does not restrict the
number of such jumps. That is, if a label length octet that is
currently being parsed is a compression pointer, the code will currently being parsed is a compression pointer, the code will
perform a jump to another label, and if that other label is a perform a jump to another label, and if that other label is a
compression pointer as well, the code will perform another jump, and compression pointer as well, the code will perform another jump, and
so forth until it reaches an decompressed label. This may lead to so forth until it reaches a decompressed label. This may lead to
unforeseen side-effects that result in security issues.</t> unforeseen side effects that result in security issues.</t>
<t>Consider the DNS packet excerpt illustrated below:</t>
<t>Consider the excerpt from a DNS packet illustrated below:</t> <artwork name="" type="" align="left" alt=""><![CDATA[
<figure><artwork><![CDATA[
+----+----+----+----+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+----+----+----+----+
+0x00 | ID | FLAGS | QCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | +0x00 | ID | FLAGS | QDCOUNT | ANCOUNT | NSCOUNT | ARCOUNT |
+----+----+----+----+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+----+----+----+----+
->+0x0c |0xc0|0x0c| TYPE | CLASS |0x04| t | e | s | t |0x03| ->+0x0c |0xc0|0x0c| TYPE | CLASS |0x04| t | e | s | t |0x03|
| +----+--|-+----+----+----+----+----+----+----+----+----+----+ | +----+--|-+----+----+----+----+----+----+----+----+----+----+
| +0x18 | c | o| | m |0x00| TYPE | CLASS | ................ | | +0x18 | c | o| | m |0x00| TYPE | CLASS | ................ |
| +----+--|-+----+----+----+----+----+----+----+----+----+----+ | +----+--|-+----+----+----+----+----+----+----+----+----+----+
| | | |
-----------------
]]></artwork> ]]></artwork>
</figure> <t>
<t> The packet begins with a DNS header at offset +0x00, and its DNS
The packet begins with a DNS header at the offset +0x00, and its DNS payload contains several RRs. The first RR begins at an offset of
payload contains several RRs. The first RR begins at the offset of 12 octets (+0x0c); its first label length octet is set to the
12 octets (+0xc0) and its first label length octet is set to the
value "0xc0", which indicates that it is a compression pointer. The value "0xc0", which indicates that it is a compression pointer. The
compression pointer offset is computed from the two octets "0xc00c" compression pointer offset is computed from the two octets "0xc00c"
and it is equal to 12. Since the broken implementation at Snippet 1 and is equal to 12. Since the broken implementation in <xref target="snippet_ 1"/>
follows this offset value blindly, the pointer will jump back to follows this offset value blindly, the pointer will jump back to
the first octet of the first RR (+0xc0) over and over again. The the first octet of the first RR (+0x0c) over and over again. The
code at Snippet 1 will enter an infinite loop state, since it will code in <xref target="snippet_1"/> will enter an infinite-loop state, since i
t will
never leave the "TRUE" branch of the "while" loop.</t> never leave the "TRUE" branch of the "while" loop.</t>
<t>
<t> Apart from achieving infinite loops, the implementation flaws in
Apart from achieving infinite loops, the implementation flaws at <xref target="snippet_1"/> make it possible to achieve various pointer loops
Snippet 1 make it possible to achieve various pointer loops that have that have
other effects. For instance, consider the DNS packet excerpt shown other undesirable effects. For instance, consider the DNS packet excerpt show
n
below:</t> below:</t>
<artwork name="" type="" align="left" alt=""><![CDATA[
<figure><artwork><![CDATA[
+----+----+----+----+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+----+----+----+----+
+0x00 | ID | FLAGS | QCOUNT | ANCOUNT | NSCOUNT | ARCOUNT | +0x00 | ID | FLAGS | QDCOUNT | ANCOUNT | NSCOUNT | ARCOUNT |
+----+----+----+----+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+----+----+----+----+
->+0x0c |0x04| t | e | s | t |0xc0|0x0c| ...................... | ->+0x0c |0x04| t | e | s | t |0xc0|0x0c| ...................... |
| +----+----+----+----+----+----+--|-+----+----+----+----+----+ | +----+----+----+----+----+----+--|-+----+----+----+----+----+
| | | |
------------------------------------------
]]></artwork> ]]></artwork>
</figure> <t>
<t> With such a domain name, the implementation in <xref target="snippet_1"/> wil
With such a domain name, the implementation at Snippet 1 will first l first
copy the domain label at the offset "0xc0" ("test"), then it will copy the domain label at offset "0xc0" ("test"); it will then
fetch the next label length octet, which is a compression pointer fetch the next label length octet, which happens to be a compression pointer
("0xc0"). The compression pointer offset is computed from the two ("0xc0"). The compression pointer offset is computed from the two
octets "0xc00c" and is equal to 12 octets. The code will jump back octets "0xc00c" and is equal to 12 octets. The code will jump back
at the offset "0xc0" where the first label "test" is located. The to offset "0xc0" where the first label "test" is located. The
code will again copy the "test" label, and jump back to it, code will again copy the "test" label and then jump back to it,
following the compression pointer, over and over again.</t> following the compression pointer, over and over again.</t>
<t>
<t> <xref target="snippet_1"/> does not contain any logic that restricts multiple
Snippet 1 does not contain any logic that restricts multiple jumps jumps
from the same compression pointer and does not ensure that no more from the same compression pointer and does not ensure that no more
than 255 octets are copied into the name buffer ("name_buffer"). In than 255 octets are copied into the name buffer ("name_buffer"). In
fact, the code will continue to write the label "test" into it, fact,</t>
overwriting the name buffer and the stack of the heap metadata. In
fact, attackers would have a significant degree of freedom in
constructing shell-code, since they can create arbitrary copy chains
with various combinations of labels and compression pointers.</t>
<t> <ul spacing="normal">
<li>the code will continue to write the label "test" into it,
overwriting the name buffer and the stack of the heap metadata.</li>
<li>attackers would have a significant degree of freedom in
constructing shell code, since they can create arbitrary copy chains
with various combinations of labels and compression pointers.</li>
</ul>
Therefore, blindly following compression pointers may not only lead to <t>Therefore, blindly following compression pointers may lead not only to
Denial-of-Service as pointed by <xref Denial-of-Service conditions, as pointed out by <xref target="I-D.ietf-dnsind
target="I-D.ietf-dnsind-local-compression"/>, but also to successful Remote -local-compression" format="default"/>, but also to successful Remote
Code Execution attacks, as there may be other implementation issues present Code Execution attacks, as there may be other implementation issues present
within the corresponding code.</t> within the corresponding code.</t>
<t>
Some implementations may not follow <xref target="RFC1035" format="default"/>
, which states:
<!-- DNE; fixed -->
</t>
<blockquote>The first two bits are ones. This allows a pointer to be distinguis
hed
from a label, since the label must begin with two zero bits because
labels are restricted to 63 octets or less. (The 10 and 01 combinations
are reserved for future use.)</blockquote>
<t>
Figures&nbsp;<xref target="snippet_2" format="counter"/> and <xref target="snipp
et_3" format="counter"/> show pseudocode that implements two functions that chec
k whether a given octet is a compression pointer; <xref target="snippet_2"/> sho
ws a correct implementation, and <xref target="snippet_3"/> shows an incorrect (
broken) implementation.</t>
<t> <figure anchor="snippet_2">
Some implementations may not follow <xref target="RFC1035"/>, which states: " <name>Correct Compression Pointer Check</name>
the first two bits [of a compression pointer octet] are ones; this allows a poin <sourcecode name="" type="pseudocode" ><![CDATA[
ter to be distinguished from a label, the label must begin with two zero bits b
ecause labels are restricted to 63 octets or less (the 10 and 01 combinations ar
e reserved for future use)". Snippets 2
and 3 show pseudocode that implements two functions that check
whether a given octet is a compression pointer: correct and incorrect
implementations respectively.</t>
<figure><artwork><![CDATA[
1: unsigned char is_compression_pointer(*octet) { 1: unsigned char is_compression_pointer(*octet) {
2: if ((*octet & 0xc0) == 0xc0) 2: if ((*octet & 0xc0) == 0xc0)
3: return true; 3: return true;
4: } else { 4: } else {
5: return false; 5: return false;
6: } 6: }
7: } 7: }
Snippet 2 - Correct compression pointer check ]]></sourcecode>
</figure>
<figure anchor="snippet_3">
<name>Broken Compression Pointer Check</name>
<sourcecode name="" type="pseudocode"><![CDATA[
1: unsigned char is_compression_pointer(*octet) { 1: unsigned char is_compression_pointer(*octet) {
2: if (*octet & 0xc0) { 2: if (*octet & 0xc0) {
3: return true; 3: return true;
4: } else { 4: } else {
5: return false; 5: return false;
6: } 6: }
7: } 7: }
]]></sourcecode>
Snippet 3 - Broken compression pointer check </figure>
]]></artwork> <t>
</figure> The correct implementation (<xref target="snippet_2"/>) ensures that the two mos
t
<t>
The correct implementation (Snippet 2) ensures that the two most
significant bits of an octet are both set, while the broken significant bits of an octet are both set, while the broken
implementation (Snippet 3) would consider an octet with only one of implementation (<xref target="snippet_3"/>) would consider an octet with only on
the two bits set as a compression pointer. This is likely an e of
the two bits set to be a compression pointer. This is likely an
implementation mistake rather than an intended violation of implementation mistake rather than an intended violation of
[RFC1035], because there are no benefits in supporting such <xref target="RFC1035" format="default"/>, because there are no benefits in supp orting such
compression pointer values. The implementations related to compression pointer values. The implementations related to
[CVE-2020-24338] and [CVE-2020-24335] had a broken <xref target="CVE-2020-24338" format="default"/> and <xref target="CVE-2020-2433
compression pointer check illustrated on Snippet 3.</t> 5" format="default"/> had a broken
compression pointer check, similar to the code shown in <xref target="snippet_3"
<t> />.</t>
<t>
While incorrect implementations alone do not lead to vulnerabilities, While incorrect implementations alone do not lead to vulnerabilities,
they may have unforeseen side-effects when combined with other they may have unforeseen side effects when combined with other
vulnerabilities. For instance, the first octet of the value "0x4130" vulnerabilities. For instance, the first octet of the value "0x4130"
may be incorrectly interpreted as a label length by a broken may be incorrectly interpreted as a label length by a broken
implementation. Such label length (65) is invalid, and is larger implementation. Such a label length (65) is invalid and is larger
than 63 (as per <xref target="RFC1035"/>), and a packet that has this value s than 63 (as per <xref target="RFC1035" format="default"/>); a packet that has
hould this value should
be discarded. However, the function shown on Snippet 3 will be discarded. However, the function shown in <xref target="snippet_3"/> will
consider "0x41" to be a valid compression pointer, and the packet consider "0x41" to be a valid compression pointer, and the packet
may pass the validation steps.</t> may pass the validation steps.</t>
<t>
<t> This might give attackers additional leverage for constructing
This might give an additional leverage for attackers in constructing
payloads and circumventing the existing DNS packet validation payloads and circumventing the existing DNS packet validation
mechanisms.</t> mechanisms.</t>
<t>
<t> The first occurrence of a compression pointer in an RR (an octet with
The first occurrence of a compression pointer in a RR (an octet with the two highest bits set to 1) must resolve to an octet within a DNS
the 2 highest bits set to 1) must resolve to an octet within a DNS record with a value that is greater than 0 (i.e., it must not be a
record with the value that is greater than 0 (i.e., it must not be a
Null-terminator) and less than 64. The offset at which this octet is Null-terminator) and less than 64. The offset at which this octet is
located must be smaller than the offset at which the compression located must be smaller than the offset at which the compression
pointer is located - once an implementation makes sure of that, pointer is located; once an implementation makes sure of that,
compression pointer loops can never occur.</t> compression pointer loops can never occur.</t>
<t>
<t> In small DNS implementations (e.g., embedded TCP/IP stacks),
In small DNS implementations (e.g., embedded TCP/IP stacks) the
support for nested compression pointers (pointers that point to a support for nested compression pointers (pointers that point to a
compressed name) should be discouraged: there is very little to be compressed name) should be discouraged: there is very little to be
gained in terms of performance versus the high possibility of gained in terms of performance versus the high probability of
introducing errors, such as the ones discussed above.</t> introducing errors such as those discussed above.</t>
<t>
<t>
The code that implements domain name parsing should check the offset The code that implements domain name parsing should check the offset
not only with respect to the bounds of a packet, but also its with respect to not only the bounds of a packet but also its
position with respect to the compression pointer in question. A position with respect to the compression pointer in question. A
compression pointer must not be "followed" more than once. We have compression pointer must not be "followed" more than once. We have
seen several implementations using a check that ensures that seen several implementations using a check that ensures that
a compression pointer is not followed more than several times. A a compression pointer is not followed more than several times. A
better alternative may be to ensure that the target of a compression better alternative may be to ensure that the target of a compression
pointer is always located before the location of the pointer in the pointer is always located before the location of the pointer in the
packet.</t> packet.</t>
</section>
</section> <section anchor="sect-3" numbered="true" toc="default">
<name>Label and Name Length Validation</name>
<section title="Label and Name Length Validation" anchor="sect-3"><t> <t>
<xref target="RFC1035"/> restricts the length of name labels to 63 octets, an <xref target="RFC1035" format="default"/> restricts the length of name labels
d to 63 octets and
lengths of domain names to 255 octets (i.e., label octets and label lengths of domain names to 255 octets (i.e., label octets and label
length octets). Some implementations do not explicitly enforce these length octets). Some implementations do not explicitly enforce these
restrictions.</t> restrictions.</t>
<t>
<t> Consider the function "copy_domain_name()" shown in <xref target="snippet_4"/
Consider the function "copy_domain_name()" shown on Snippet 4 below. > below.
The function is a variant of the "decompress_domain_name()" function The function is a variant of the "decompress_domain_name()" function
(Snippet 1), with the difference that it does not support compressed (<xref target="snippet_1"/>), with the difference that it does not support co
labels, and copies only decompressed labels into the name buffer.</t> mpressed
labels and only copies decompressed labels into the name buffer.</t>
<figure><artwork><![CDATA[ <figure anchor="snippet_4">
1:copy_domain_name(*name, *dns_payload) { <name>A Broken Implementation of a Function That Is Used for Copying Non-&w
j;compressed Domain Names</name>
<sourcecode name="" type="pseudocode" ><![CDATA[
1: copy_domain_name(*name, *dns_payload) {
2: 2:
3: name_buffer[255]; 3: name_buffer[255];
4: copy_offset = 0; 4: copy_offset = 0;
5: 5:
6: label_len_octet = name; 6: label_len_octet = name;
7: dest_octet = name_buffer; 7: dest_octet = name_buffer;
8: 8:
9: while (*label_len_octet != 0x00) { 9: while (*label_len_octet != 0x00) {
10: 10:
11: if (is_compression_pointer(*label_len_octet)) { 11: if (is_compression_pointer(*label_len_octet)) {
12: length = 2; 12: length = 2;
13: label_len_octet += length + 1; 13: label_len_octet += length + 1;
14: } 14: }
15: 15:
16: else { 16: else {
17: length = *label_len_octet; 17: length = *label_len_octet;
18: copy(dest_octet + copy_offset, 18: copy(dest_octet + copy_offset,
label_len_octet+1, *length); label_len_octet+1, *length);
19: 19:
20: copy_offset += length; 20: copy_offset += length;
21: label_len_octet += length + 1; 21: label_len_octet += length + 1;
22: } 22: }
23: 23:
24: } 24: }
25:} 25: }
Snippet 4 - A broken implementation of a function ]]></sourcecode>
that is used for copying non-compressed domain names </figure>
]]></artwork> <t>
</figure>
<t>
This implementation does not explicitly check for the value of the This implementation does not explicitly check for the value of the
label length octet: this value can be up to 255 octets, and a single label length octet: this value can be up to 255 octets, and a single
label can fill the name buffer. Depending on the memory layout of the label can fill the name buffer. Depending on the memory layout of the
target, how the name buffer is allocated, and the size of the target, how the name buffer is allocated, and the size of the
malformed packet, it is possible to trigger various memory corruption malformed packet, it is possible to trigger various memory corruption
issues.</t> issues.</t>
<t>
<t> Both Figures&nbsp;<xref target="snippet_1" format="counter"/> and <xref targe
Both Snippets 1 and 4 restrict the size of the name buffer to 255 t="snippet_4"
octets, however there are no restrictions on the actual number of format="counter"/> restrict the size of the name buffer to 255
octets; however, there are no restrictions on the actual number of
octets that will be copied into this buffer. In this particular case, octets that will be copied into this buffer. In this particular case,
a subsequent copy operation (if another label is present in the a subsequent copy operation (if another label is present in the
packet) will write past the name buffer, allowing to overwrite heap packet) will write past the name buffer, allowing heap
or stack metadata in a controlled manner.</t> or stack metadata to be overwritten in a controlled manner.</t>
<t>
<t>
Similar examples of vulnerable implementations can be found in the Similar examples of vulnerable implementations can be found in the
code relevant to <xref target="CVE-2020-25110"/>, <xref target="CVE-2020-1579 code relevant to <xref target="CVE-2020-25110" format="default"/>, <xref targ
5"/>, and et="CVE-2020-15795" format="default"/>, and
<xref target="CVE-2020-27009"/>.</t> <xref target="CVE-2020-27009" format="default"/>.</t>
<t>
<t> As a general recommendation, a domain label length octet must have a
As a general recommendation, a domain label length octet must have the value of more than 0 and less than 64 <xref target="RFC1035" format="default"
value of more than 0 and less than 64 (<xref target="RFC1035"/>). If this is />. If this is not the case,
not the case,
an invalid value has been provided within the packet, or a value at an an invalid value has been provided within the packet, or a value at an
invalid position might be interpreted as a domain name length due to other invalid position might be interpreted as a domain name length due to other
errors in the packet (e.g., misplaced Null-terminator or invalid errors in the packet (e.g., misplaced Null-terminator or invalid
compression pointer).</t> compression pointer).</t>
<t>
<t>
The number of domain label characters must correspond to the value of The number of domain label characters must correspond to the value of
the domain label octet. To avoid possible errors when interpreting the domain label octet. To avoid possible errors when interpreting
the characters of a domain label, developers may consider the characters of a domain label, developers may consider
recommendations for the preferred domain name syntax outlined in recommendations for the preferred domain name syntax outlined in
<xref target="RFC1035"/>.</t> <xref target="RFC1035" format="default"/>.</t>
<t>
<t>
The domain name length must not be more than 255 octets, including The domain name length must not be more than 255 octets, including
the size of decompressed domain names. The NUL octet ("0x00") must the size of decompressed domain names. The NUL octet ("0x00") must
be present at the end of the domain name, and within the maximum name be present at the end of the domain name and must be within the maximum name
length (255 octets).</t> length (255 octets).</t>
</section>
</section> <section anchor="sect-4" numbered="true" toc="default">
<name>Null-Terminator Placement Validation</name>
<section title="Null-terminator Placement Validation" anchor="sect-4"><t> <t>
A domain name must end with a NUL ("0x00") octet, as per <xref target="RFC103 A domain name must end with a NUL ("0x00") octet, as per <xref target="RFC103
5"/>. 5" format="default"/>.
The implementations shown at Snippets 1 and 4 assume that this is the The implementations shown in Figures&nbsp;<xref target="snippet_1" format="co
case for the RRs that they process, however names that do not have a unter"/> and <xref
NUL octet placed at the proper position within a RR are not target="snippet_4" format="counter"/> assume that this is the
case for the RRs that they process; however, names that do not have a
NUL octet placed at the proper position within an RR are not
discarded.</t> discarded.</t>
<t>
<t>
This issue is closely related to the absence of label and name length This issue is closely related to the absence of label and name length
checks. For example, the logic behind Snippets 1 and 4 will continue checks. For example, the logic behind Figures&nbsp;<xref target="snippet_1" f
to copy octets into the name buffer, until a NUL octet is ormat="counter"/> and <xref target="snippet_4"
format="counter"/> will continue
to copy octets into the name buffer until a NUL octet is
encountered. This octet can be placed at an arbitrary position encountered. This octet can be placed at an arbitrary position
within a RR, or not placed at all.</t> within an RR or not placed at all.</t>
<t>
<t> Consider the pseudocode function shown in <xref target="snippet_5"/>. The fun
Consider a pseudocode function shown on Snippet 5. The function ction
returns the length of a domain name ("name") in octets to be used returns the length of a domain name ("name") in octets to be used
elsewhere (e.g., to allocate a name buffer of a certain size): for elsewhere (e.g., to allocate a name buffer of a certain size): for
compressed domain names the function returns 2, for decompressed compressed domain names, the function returns 2; for decompressed
names it returns their true length using the "strlen(3)" function.</t> names, it returns their true length using the "strlen(3)" function.</t>
<figure anchor="snippet_5">
<figure><artwork><![CDATA[ <name>A Broken Implementation of a Function That Returns the Length of a Do
main Name</name>
<sourcecode name="" type="pseudocode"><![CDATA[
1: get_name_length(*name) { 1: get_name_length(*name) {
2: 2:
3: if (is_compression_pointer(name)) 3: if (is_compression_pointer(name))
4: return 2; 4: return 2;
5: 5:
6: name_len = strlen(name) + 1; 6: name_len = strlen(name) + 1;
7: return name_len; 7: return name_len;
8: } 8: }
Snippet 5 - A broken implementation of a function that ]]></sourcecode>
returns the length of a domain name </figure>
]]></artwork></figure> <t>
<t>
"strlen(3)" is a standard C library function that returns the length "strlen(3)" is a standard C library function that returns the length
of a given sequence of characters terminated by the NUL ("0x00") of a given sequence of characters terminated by the NUL ("0x00")
octet. Since this function also expects names to be explicitly octet. Since this function also expects names to be explicitly
Null-terminated, the return value "strlen(3)" may be also controlled Null-terminated, the return value "strlen(3)" may also be controlled
by attackers. Through the value of "name_len" attackers may control by attackers. Through the value of "name_len", attackers may control
the allocation of internal buffers, or specify the number by octets the allocation of internal buffers or specify the number by octets
copied into these buffers, or other operations depending on the copied into these buffers, or they may perform other operations, depending on
the
implementation specifics.</t> implementation specifics.</t>
<t>
<t> The absence of explicit checks for placement of the NUL octet may also
The absence of explicit checks for the NUL octet placement may also
facilitate controlled memory reads and writes. An example of facilitate controlled memory reads and writes. An example of
vulnerable implementations can be found in the code relevant to vulnerable implementations can be found in the code relevant to
<xref target="CVE-2020-25107"/>, <xref target="CVE-2020-17440"/>, <xref targe <xref target="CVE-2020-25107" format="default"/>, <xref target="CVE-2020-1744
t="CVE-2020-24383"/>, and 0" format="default"/>, <xref target="CVE-2020-24383" format="default"/>, and
<xref target="CVE-2020-27736"/>.</t> <xref target="CVE-2020-27736" format="default"/>.</t>
<t>
<t>
As a general recommendation for mitigating such issues, developers As a general recommendation for mitigating such issues, developers
should never trust user data to be Null-terminated. For example, to should never trust user data to be Null-terminated. For example, to
fix/mitigate the issue in the code Snippet 5, developers should use fix/mitigate the issue shown in the code in <xref target="snippet_5"/>, devel
the function "strnlen(3)" that reads at most X characters(the second opers should use
the function "strnlen(3)", which reads at most X characters (the second
argument of the function), and ensure that X is not larger than the argument of the function), and ensure that X is not larger than the
buffer allocated for the name.</t> buffer allocated for the name.</t>
</section>
</section> <section anchor="sect-5" numbered="true" toc="default">
<name>Response Data Length Validation</name>
<section title="Response Data Length Validation" anchor="sect-5"><t> <t>
As stated in <xref target="RFC1035"/>, every RR contains a variable length st As stated in <xref target="RFC1035" format="default"/>, every RR contains a v
ring of ariable-length string of
octets that contains the retrieved resource data (RDATA) (e.g., an IP octets that contains the retrieved resource data (RDATA) (e.g., an IP
address that corresponds to a domain name in question). The length of address that corresponds to a domain name in question). The length of
the RDATA field is regulated by the resource data length field the RDATA field is regulated by the resource data length field
(RDLENGTH), that is also present in an RR.</t> (RDLENGTH), which is also present in an RR.</t>
<t>
<t>
Implementations that process RRs may not check for the validity of Implementations that process RRs may not check for the validity of
the RDLENGTH field value, when retrieving RDATA. Failing to do so may the RDLENGTH field value when retrieving RDATA. Failing to do so may
lead to out-of-bound read issues (similarly to the label and name lead to out-of-bound read issues, whose impact may
length validation issues discussed in <xref target="sect-3"/>), whose impact vary significantly, depending on the implementation specifics. We have
may
vary significantly depending on the implementation specifics. We have
observed instances of Denial-of-Service conditions and information observed instances of Denial-of-Service conditions and information
leaks.</t> leaks.</t>
<t>
<t>
Therefore, the value of the data length byte in response DNS records Therefore, the value of the data length byte in response DNS records
(RDLENGTH) must reflect the number of bytes available in the field (RDLENGTH) must reflect the number of bytes available in the field
that describes the resource (RDATA). The format of RDATA must that describes the resource (RDATA). The format of RDATA must
conform to the TYPE and CLASS fields of the RR.</t> conform to the TYPE and CLASS fields of the RR.</t>
<t>
<t>
Examples of vulnerable implementations can be found in the code Examples of vulnerable implementations can be found in the code
relevant to <xref target="CVE-2020-25108"/>, <xref target="CVE-2020-24336"/>, relevant to <xref target="CVE-2020-25108" format="default"/>, <xref target="C
and <xref target="CVE-2020-27009"/>.</t> VE-2020-24336" format="default"/>, and <xref target="CVE-2020-27009" format="def
ault"/>.</t>
</section> </section>
<section anchor="sect-6" numbered="true" toc="default">
<section title="Record Count Validation" anchor="sect-6"><t> <name>Record Count Validation</name>
According to <xref target="RFC1035"/>, the DNS header contains four two-octet <t>
According to <xref target="RFC1035" format="default"/>, the DNS header contai
ns four two-octet
fields that specify the amount of question records (QDCOUNT), answer fields that specify the amount of question records (QDCOUNT), answer
records (ANCOUNT), authority records (NSCOUNT), and additional records (ANCOUNT), authority records (NSCOUNT), and additional
records (ARCOUNT).</t> records (ARCOUNT).</t>
<t>
<xref target="snippet_6"/> illustrates a recurring implementation anti-patter
n for a
function that processes DNS RRs. The function "process_dns_records()"
extracts the value of ANCOUNT ("num_answers") and the pointer to the
DNS data payload ("data_ptr"). The function processes answer records
in a loop, decrementing the "num_answers" value after processing each
record until the value of "num_answers" becomes zero. For
simplicity, we assume that there is only one domain name per answer.
Inside the loop, the code calculates the domain name length
("name_length") and adjusts the data payload pointer ("data_ptr") by the
offset that corresponds to "name_length + 1", so that the pointer
lands on the first answer record. Next, the answer record is
retrieved and processed, and the "num_answers" value is decremented.</t>
<figure><artwork><![CDATA[ <figure anchor="snippet_6">
<name>A Broken Implementation of a Function That Processes RRs</name>
<sourcecode name="" type="pseudocode" ><![CDATA[
1: process_dns_records(dns_header, ...) { 1: process_dns_records(dns_header, ...) {
// ... // ...
2: num_answers = dns_header->ancount 2: num_answers = dns_header->ancount
3: data_ptr = dns_header->data 3: data_ptr = dns_header->data
4: 4:
5: while (num_answers > 0) { 5: while (num_answers > 0) {
6: name_length = get_name_length(data_ptr); 6: name_length = get_name_length(data_ptr);
7: data_ptr += name_length + 1; 7: data_ptr += name_length + 1;
8: 8:
9: answer = (struct dns_answer_record *)data_ptr; 9: answer = (struct dns_answer_record *)data_ptr;
10: 10:
11: // process the answer record 11: // process the answer record
12: 12:
13: --num_answers; 13: --num_answers;
14: } 14: }
// ... // ...
15: } 15: }
]]></sourcecode>
Snippet 6 - A broken implementation of a RR processing function </figure>
]]></artwork> <t>
</figure>
<t>
Snippet 6 illustrates a recurring implementation anti-pattern for a
function that processes DNS RRs. The function "process_dns_records()"
extracts the value of ANCOUNT ("num_answers") and the pointer to the
DNS data payload ("data_ptr"). The function processes answer records
in a loop decrementing the "num_answers" value after processing each
record, until the value of "num_answers" becomes zero. For
simplicity, we assume that there is only one domain name per answer.
Inside the loop, the code calculates the domain name length
"name_length", and adjusts the data payload pointer "data_ptr" by the
offset that corresponds to "name_length + 1", so that the pointer
lands on the first answer record. Next, the answer record is
retrieved and processed, and the "num_answers" value is decremented.</t>
<t>
If the ANCOUNT number retrieved from the header If the ANCOUNT number retrieved from the header
("dns_header-&gt;ancount") is not checked against the amount of data ("dns_header-&gt;ancount") is not checked against the amount of data
available in the packet and it is, e.g., larger than the number of available in the packet and it is, for example, larger than the number of
answer records available, the data pointer "data_ptr" will read out answer records available, the data pointer ("data_ptr") will read outside
of the bounds of the packet. This may result in Denial-of-Service the bounds of the packet. This may result in Denial-of-Service
conditions.</t> conditions.</t>
<t>
<t>
In this section, we used an example of processing answer records. In this section, we used an example of processing answer records.
However, the same logic is often reused for implementing the However, the same logic is often reused for implementing the
processing of other types of records: e.g., the number of Question processing of other types of records, e.g., the number of question
(QCOUNT), Authority (NSCOUNT), and Additional (ARCOUNT) records. The (QDCOUNT), authority (NSCOUNT), and additional (ARCOUNT) records. The
number of these records specified must correspond to the actual data specified numbers of these records must correspond to the actual data
present within the packet. Therefore, all record count fields must present within the packet. Therefore, all record count fields must
be checked before fully parsing the contents of a packet. be checked before fully parsing the contents of a packet.
Specifically, Section 6.3 of<xref target="RFC5625"/> recommends that such mal Specifically, <xref target="RFC5625" sectionFormat="of" section="6.3"/> recom
formed mends that such malformed
DNS packets should be dropped, and (optionally) logged.</t> DNS packets should be dropped and (optionally) logged.</t>
<t>
<t>
Examples of vulnerable implementations can be found in the code Examples of vulnerable implementations can be found in the code
relevant to <xref target="CVE-2020-25109"/>, <xref target="CVE-2020-24340"/>, relevant to <xref target="CVE-2020-25109" format="default"/>, <xref target="C
<xref target="CVE-2020-24334"/>, and VE-2020-24340" format="default"/>, <xref target="CVE-2020-24334" format="default
<xref target="CVE-2020-27737"/>.</t> "/>, and
<xref target="CVE-2020-27737" format="default"/>.</t>
</section> </section>
<section anchor="sect-7" numbered="true" toc="default">
<section title="Security Considerations" anchor="sect-7"><t> <name>Security Considerations</name>
Security issues are discussed throughout this memo. The document <t>
Security issues are discussed throughout this memo; it
discusses implementation flaws (anti-patterns) that affect the discusses implementation flaws (anti-patterns) that affect the
functionality of processing DNS RRs. The presence of such functionality of processing DNS RRs. The presence of such
anti-patterns leads to bugs causing buffer overflows, anti-patterns leads to bugs that cause buffer overflows,
read-out-of-bounds, and infinite loop issues. These issues have the read-out-of-bounds, and infinite-loop issues. These issues have the
following security impact: Information Leak, Denial-of-Service, and following security impacts: information leaks, Denial-of-Service attacks, and
Remote Code Execution.</t> Remote Code Execution attacks.</t>
<t>
<t> This document lists general recommendations for the developers of DNS
The document lists general recommendation for the developers of DNS record parsing functionality that allow those developers to prevent such
record parsing functionality that allow to prevent such
implementation flaws, e.g., by rigorously checking the data received implementation flaws, e.g., by rigorously checking the data received
over the wire before processing it.</t> over the wire before processing it.</t>
</section>
</section> <section anchor="sect-8" numbered="true" toc="default">
<name>IANA Considerations</name>
<section title="IANA Considerations" anchor="sect-8"><t> <t>
This document introduces no new IANA considerations. Please see This document has no IANA actions. Please see
<xref target="RFC6895"/> for a complete review of the IANA considerations <xref target="RFC6895" format="default"/> for a complete review of the IANA c
onsiderations
introduced by DNS.</t> introduced by DNS.</t>
</section>
</middle>
<back>
</section> <displayreference target="I-D.ietf-dnsind-local-compression" to="DNS-COMPRESSION
"/>
</middle>
<back>
<references title="Normative References">
&RFC1035;
&RFC5625;
</references>
<references title="Informative References">
<reference anchor="SIGRED" target="https://cve.mitre.org/cgi-bin/cvename.
cgi?name=CVE-2020-1350"><front>
<title>CVE-2020-1350: A remote code execution vulnerability in Windows Do
main Name System servers</title>
<author>
<organization>Common Vulnerabilities and Exposures</organization>
</author>
<date month="July" year="2020"/>
</front>
</reference>
<reference anchor="SADDNS" target="https://dl.acm.org/doi/pdf/10.1145/3372 <references>
297.3417280"> <name>References</name>
<front> <references>
<title>DNS Cache Poisoning Attack Reloaded: Revolutions with Side Chann <name>Normative References</name>
els</title> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
<author initials="K." surname="Man" fullname="Keyu Man"> FC.1035.xml"/>
<organization/> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
</author> FC.5625.xml"/>
<author initials="Z." surname="Qian" fullname="Zhiyun Qian"> </references>
<organization/> <references>
</author>
<author initials="Z." surname="Wang" fullname="Zhongjie Wang">
<organization/>
</author>
<author initials="X." surname="Zheng" fullname="Xiaofeng Zheng">
<organization/>
</author>
<author initials="Y." surname="Huang" fullname="Youjun Huang">
<organization/>
</author>
<author initials="H." surname="Duan" fullname="Haixin Duan">
<organization/>
</author>
<date month="November" year="2020"/>
</front>
<seriesInfo name="Proc. of ACM CCS'20" value=""/>
</reference>
<reference anchor="DNSPOOQ" target="https://www.jsof-tech.com/wp-content/u <name>Informative References</name>
ploads/2021/01/DNSpooq-Technical-WP.pdf"> <reference anchor="SIGRED" target="https://cve.mitre.org/cgi-bin/cvename
<front> .cgi?name=CVE-2020-1350">
<title>DNSpooq: Cache Poisoning and RCE in popular DNS Forwarder dnsmas <front>
q</title> <title>CVE-2020-1350: A remote code execution vulnerability in Windo
<author initials="M." surname="Kol" fullname="Moshe Kol"> ws Domain Name System servers</title>
<organization/> <author>
</author> <organization>Common Vulnerabilities and Exposures</organization>
<author initials="S." surname="Oberma" fullname="Shlomi Oberma"> </author>
<organization/> <date year="2020"/>
</author> </front>
<date month="January" year="2021"/> </reference>
</front>
<seriesInfo name="technical report" value=""/>
</reference>
<reference anchor="CVE-2000-0333" target="https://cve.mitre.org/cgi-bin/c <reference anchor="SADDNS" target="https://dl.acm.org/doi/pdf/10.1145/33
vename.cgi?name=CVE-2000-0333"><front> 72297.3417280">
<title>CVE-2000-0333: A denial-of-service vulnerability in tcpdump, Ether <front>
eal, and other sniffer packages via malformed DNS packets</title> <title>DNS Cache Poisoning Attack Reloaded: Revolutions with Side Ch
<author> annels</title>
<organization>Common Vulnerabilities and Exposures</organization> <author initials="K." surname="Man" fullname="Keyu Man">
</author> <organization/>
<date year="2000"/> </author>
</front> <author initials="Z." surname="Qian" fullname="Zhiyun Qian">
<organization/>
</author>
<author initials="Z." surname="Wang" fullname="Zhongjie Wang">
<organization/>
</author>
<author initials="X." surname="Zheng" fullname="Xiaofeng Zheng">
<organization/>
</author>
<author initials="Y." surname="Huang" fullname="Youjun Huang">
<organization/>
</author>
<author initials="H." surname="Duan" fullname="Haixin Duan">
<organization/>
</author>
<date month="November" year="2020"/>
</front>
<refcontent>Proc. 2020 ACM SIGSAC Conference on Computer and Communica
tions Security, CCS '20</refcontent>
<seriesInfo name="DOI" value="10.1145/3372297.3417280"/>
</reference>
</reference> <reference anchor="DNSPOOQ" target="https://www.jsof-tech.com/wp-content
<reference anchor="CVE-2020-24338" target="https://cve.mitre.org/cgi-bin/ /uploads/2021/01/DNSpooq-Technical-WP.pdf">
cvename.cgi?name=CVE-2020-24338"><front> <front>
<title>CVE-2020-24338: A denial-of-service and remote code execution vuln <title>DNSpooq: Cache Poisoning and RCE in Popular DNS Forwarder dns
erability in the DNS domain name record decompression functionality of picoTCP</ masq</title>
title> <author initials="M." surname="Kol" fullname="Moshe Kol">
<author> <organization/>
<organization>Common Vulnerabilities and Exposures</organization> </author>
</author> <author initials="S." surname="Oberman" fullname="Shlomi Oberman">
<date month="December" year="2020"/> <organization/>
</front> </author>
<date month="January" year="2021"/>
</front>
<refcontent>JSOF Technical Report</refcontent>
</reference>
</reference> <reference anchor="CVE-2000-0333" target="https://cve.mitre.org/cgi-bin/
<reference anchor="CVE-2020-27738" target="https://cve.mitre.org/cgi-bin/ cvename.cgi?name=CVE-2000-0333">
cvename.cgi?name=CVE-2020-27738"><front> <front>
<title>CVE-2020-27738: A denial-of-service and remote code execution vuln <title>CVE-2000-0333: A denial-of-service vulnerability in tcpdump,
erability DNS domain name record decompression functionality of Nucleus NET</tit Ethereal, and other sniffer packages via malformed DNS packets</title>
le> <author>
<author> <organization>Common Vulnerabilities and Exposures</organization>
<organization>Common Vulnerabilities and Exposures</organization> </author>
</author> <date year="2000"/>
<date month="April" year="2021"/> </front>
</front> </reference>
</reference> <reference anchor="CVE-2020-24338" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-25767" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-24338">
cvename.cgi?name=CVE-2020-25767"><front> <front>
<title>CVE-2020-25767: An out-of-bounds read and denial-of-service vulner <title>CVE-2020-24338: A denial-of-service and remote code execution
ability in the DNS name parsing routine of HCC Embedded NicheStack</title> vulnerability in the DNS domain name record decompression functionality of pico
<author> TCP</title>
<organization>Common Vulnerabilities and Exposures</organization> <author>
</author> <organization>Common Vulnerabilities and Exposures</organization>
<date month="August" year="2021"/> </author>
</front> <date year="2020"/>
</front>
</reference>
</reference> <reference anchor="CVE-2020-27738" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-24339" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-27738">
cvename.cgi?name=CVE-2020-24339"><front> <front>
<title>CVE-2020-24339: An out-of-bounds read and denial-of-service vulner <title>CVE-2020-27738: A denial-of-service and remote code execution
ability in the DNS domain name record decompression functionality of picoTCP</ti vulnerability DNS domain name record decompression functionality of Nucleus NET
tle> </title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="December" year="2020"/> <date year="2021"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-25767" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-24335" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-25767">
cvename.cgi?name=CVE-2020-24335"><front> <front>
<title>CVE-2020-24335: A memory corruption vulnerability in domain name p <title>CVE-2020-25767: An out-of-bounds read and denial-of-service v
arsing routines of uIP</title> ulnerability in the DNS name parsing routine of HCC Embedded NicheStack</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="December" year="2020"/> <date year="2021"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-24339" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-25110" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-24339">
cvename.cgi?name=CVE-2020-25110"><front> <front>
<title>CVE-2020-25110: A denial-of-service and remote code execution vuln <title>CVE-2020-24339: An out-of-bounds read and denial-of-service v
erability in the DNS implementation of Ethernut Nut/OS</title> ulnerability in the DNS domain name record decompression functionality of picoTC
<author> P</title>
<organization>Common Vulnerabilities and Exposures</organization> <author>
</author> <organization>Common Vulnerabilities and Exposures</organization>
<date month="December" year="2020"/> </author>
</front> <date year="2020"/>
</front>
</reference>
</reference> <reference anchor="CVE-2020-24335" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-15795" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-24335">
cvename.cgi?name=CVE-2020-15795"><front> <front>
<title>CVE-2020-15795: A denial-of-service and remote code execution vuln <title>CVE-2020-24335: A memory corruption vulnerability in domain n
erability DNS domain name label parsing functionality of Nucleus NET</title> ame parsing routines of uIP</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="April" year="2021"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-25110" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-27009" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-25110">
cvename.cgi?name=CVE-2020-27009"><front> <front>
<title>CVE-2020-27009: A denial-of-service and remote code execution vuln <title>CVE-2020-25110: A denial-of-service and remote code execution
erability DNS domain name record decompression functionality of Nucleus NET</tit vulnerability in the DNS implementation of Ethernut Nut/OS</title>
le> <author>
<author> <organization>Common Vulnerabilities and Exposures</organization>
<organization>Common Vulnerabilities and Exposures</organization> </author>
</author> <date year="2020"/>
<date month="April" year="2021"/> </front>
</front> </reference>
</reference> <reference anchor="CVE-2020-15795" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-25107" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-15795">
cvename.cgi?name=CVE-2020-25107"><front> <front>
<title>CVE-2020-25107: A denial-of-service and remote code execution vuln <title>CVE-2020-15795: A denial-of-service and remote code execution
erability in the DNS implementation of Ethernut Nut/OS</title> vulnerability DNS domain name label parsing functionality of Nucleus NET</title
<author> >
<organization>Common Vulnerabilities and Exposures</organization> <author>
</author> <organization>Common Vulnerabilities and Exposures</organization>
<date month="December" year="2020"/> </author>
</front> <date year="2021"/>
</front>
</reference>
</reference> <reference anchor="CVE-2020-27009" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-17440" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-27009">
cvename.cgi?name=CVE-2020-17440"><front> <front>
<title>CVE-2020-17440 A denial-of-service vulnerability in the DNS name p <title>CVE-2020-27009: A denial-of-service and remote code execution
arsing implementation of uIP</title> vulnerability DNS domain name record decompression functionality of Nucleus NET
<author> </title>
<organization>Common Vulnerabilities and Exposures</organization> <author>
</author> <organization>Common Vulnerabilities and Exposures</organization>
<date month="December" year="2020"/> </author>
</front> <date year="2021"/>
</front>
</reference>
</reference> <reference anchor="CVE-2020-25107" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-24383" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-25107">
cvename.cgi?name=CVE-2020-24383"><front> <front>
<title>CVE-2020-24383: An information leak and denial-of-service vulnerab <title>CVE-2020-25107: A denial-of-service and remote code execution
ility while parsing mDNS resource records in FNET</title> vulnerability in the DNS implementation of Ethernut Nut/OS</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="December" year="2020"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-17440" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-27736" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-17440">
cvename.cgi?name=CVE-2020-27736"><front> <front>
<title>CVE-2020-27736: An information leak and denial-of-service vulnerab <title>CVE-2020-17440 A denial-of-service vulnerability in the DNS n
ility in the DNS name parsing functionality of Nucleus NET</title> ame parsing implementation of uIP</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="April" year="2021"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-24383" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-25108" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-24383">
cvename.cgi?name=CVE-2020-25108"><front> <front>
<title>CVE-2020-25108: A denial-of-service and remote code execution vuln <title>CVE-2020-24383: An information leak and denial-of-service vul
erability in the DNS implementation of Ethernut Nut/OS</title> nerability while parsing mDNS resource records in FNET</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="December" year="2020"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-27736" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-24336" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-27736">
cvename.cgi?name=CVE-2020-24336"><front> <front>
<title>CVE-2020-24336: A buffer overflow vulnerability in the DNS impleme <title>CVE-2020-27736: An information leak and denial-of-service vul
ntation of Contiki and Contiki-NG</title> nerability in the DNS name parsing functionality of Nucleus NET</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="December" year="2020"/> <date year="2021"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-25108" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-25109" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-25108">
cvename.cgi?name=CVE-2020-25109"><front> <front>
<title>CVE-2020-25109: A denial-of-service and remote code execution vuln <title>CVE-2020-25108: A denial-of-service and remote code execution
erability in the DNS implementation of Ethernut Nut/OS</title> vulnerability in the DNS implementation of Ethernut Nut/OS</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="December" year="2020"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-24336" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-24340" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-24336">
cvename.cgi?name=CVE-2020-24340"><front> <front>
<title>CVE-2020-24340: An out-of-bounds read and denial-of-service vulner <title>CVE-2020-24336: A buffer overflow vulnerability in the DNS im
ability in the DNS response parsing functionality of picoTCP</title> plementation of Contiki and Contiki-NG</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="December" year="2020"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-25109" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-24334" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-25109">
cvename.cgi?name=CVE-2020-24334"><front> <front>
<title>CVE-2020-24334: An out-of-bounds read and denial-of-service vulner <title>CVE-2020-25109: A denial-of-service and remote code execution
ability in the DNS response parsing functionality of uIP</title> vulnerability in the DNS implementation of Ethernut Nut/OS</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="December" year="2020"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-24340" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2020-27737" target="https://cve.mitre.org/cgi-bin/ /cvename.cgi?name=CVE-2020-24340">
cvename.cgi?name=CVE-2020-27737"><front> <front>
<title>CVE-2020-27737: An information leak and denial-of-service vulnerab <title>CVE-2020-24340: An out-of-bounds read and denial-of-service v
ility in the DNS response parsing functionality of Nucleus NET</title> ulnerability in the DNS response parsing functionality of picoTCP</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date month="April" year="2021"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-24334" target="https://cve.mitre.org/cgi-bin
<reference anchor="CVE-2017-9345" target="https://cve.mitre.org/cgi-bin/c /cvename.cgi?name=CVE-2020-24334">
vename.cgi?name=CVE-2017-9345"><front> <front>
<title>CVE-2017-9345: An infinite loop in the DNS dissector of Wireshark< <title>CVE-2020-24334: An out-of-bounds read and denial-of-service v
/title> ulnerability in the DNS response parsing functionality of uIP</title>
<author> <author>
<organization>Common Vulnerabilities and Exposures</organization> <organization>Common Vulnerabilities and Exposures</organization>
</author> </author>
<date year="2017"/> <date year="2020"/>
</front> </front>
</reference>
</reference> <reference anchor="CVE-2020-27737" target="https://cve.mitre.org/cgi-bin
&I-D.ietf-dnsind-local-compression; /cvename.cgi?name=CVE-2020-27737">
&RFC6895; <front>
&RFC8484; <title>CVE-2020-27737: An information leak and denial-of-service vul
&RFC7858; nerability in the DNS response parsing functionality of Nucleus NET</title>
</references> <author>
<section title="Acknowledgements" numbered="no" anchor="acknowledgements" <organization>Common Vulnerabilities and Exposures</organization>
><t> </author>
We would like to thank Shlomi Oberman, who has greatly contributed to <date year="2021"/>
the research that led to the creation of this document.</t> </front>
</reference>
</section> <reference anchor="CVE-2017-9345" target="https://cve.mitre.org/cgi-bin/
cvename.cgi?name=CVE-2017-9345">
<front>
<title>CVE-2017-9345: An infinite loop in the DNS dissector of Wires
hark</title>
<author>
<organization>Common Vulnerabilities and Exposures</organization>
</author>
<date year="2017"/>
</front>
</reference>
</back> <!-- draft-ietf-dnsind-local-compression (Expired) -->
<xi:include href="https://datatracker.ietf.org/doc/bibxml3/reference.I-D
.ietf-dnsind-local-compression.xml"/>
</rfc> <xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
FC.6895.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
FC.8484.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.R
FC.7858.xml"/>
</references>
</references>
<section numbered="false" anchor="acknowledgements" toc="default">
<name>Acknowledgements</name>
<t>
We would like to thank <contact fullname="Shlomi Oberman"/>, who has greatly
contributed to
the research that led to the creation of this document.</t>
</section>
</back>
</rfc>
 End of changes. 144 change blocks. 
748 lines changed or deleted 760 lines changed or added

This html diff was produced by rfcdiff 1.48.