<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title> - Keenan&#x27;s Blog</title>
      <link>https://kgugeler.ca/blog/</link>
      <description></description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://kgugeler.ca/blog/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Tue, 03 Jun 2025 00:00:00 +0000</lastBuildDate>
      <item>
          <title>A Really Stupid DNS Server</title>
          <pubDate>Tue, 03 Jun 2025 00:00:00 +0000</pubDate>
          <author>Keenan Gugeler</author>
          <link>https://kgugeler.ca/blog/a-really-stupid-dns-server/</link>
          <guid>https://kgugeler.ca/blog/a-really-stupid-dns-server/</guid>
          <description xml:base="https://kgugeler.ca/blog/a-really-stupid-dns-server/">&lt;p&gt;I manage my certificates with Let&#x27;s Encrypt, and for a while now I&#x27;ve been
using the DNS challenge for its ability to get wildcard certificates. This
makes it easy for me to set up a new subdomain, without having to reconfigure
my certificate.&lt;&#x2F;p&gt;
&lt;p&gt;I used to use Cloudflare&#x27;s API to manage the TXT records, but I swapped some
time ago to having a NS record for &lt;code&gt;_acme-challenge.kgugeler.ca&lt;&#x2F;code&gt; point to my
VPS, and when I want to renew my certificate, I spawn a public BIND instance.
This method is mentioned by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;letsencrypt.org&#x2F;docs&#x2F;challenge-types&#x2F;#dns-01-challenge&quot;&gt;Let&#x27;s
Encrypt&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Recently I had a bad idea. BIND is a complex DNS server, right? What if I could
replace it with a small server. After all, it&#x27;s not doing much. What could go
wrong?&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dns&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#dns&quot; aria-label=&quot;Anchor link for: dns&quot;&gt;DNS&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Ok, so I know that DNS uses UDP over port 53, and I know it has a recursive
structure, and I know about the different record types but... how do I make a
DNS query? What does it look like on the wire?&lt;&#x2F;p&gt;
&lt;p&gt;Thankfully
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Domain_Name_System#DNS_message_format&quot;&gt;Wikipedia&lt;&#x2F;a&gt;
has me covered. We&#x27;ve got a short header, and then a list of questions,
answers, authority records, and additional records. The questions are sent in
queries and repeated in responses. The answers are records that are answers to
the questions. Authority records are what we get when the server redirects us
to other name servers, and Additional records &quot;relate to the query but are not
strictly answers for the question&quot;. Let&#x27;s look at a simple DNS query to the
root name servers:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; dig @a.root-servers.net kgugeler.ca&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;; &amp;lt;&amp;lt;&amp;gt;&amp;gt; DiG 9.20.9 &amp;lt;&amp;lt;&amp;gt;&amp;gt; @a.root-servers.net kgugeler.ca&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;; (2 servers found)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; global options: +cmd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; Got answer:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; -&amp;gt;&amp;gt;HEADER&amp;lt;&amp;lt;- opcode: QUERY, status: NOERROR, id: 65458&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; WARNING: recursion requested but not available&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; OPT PSEUDOSECTION:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;; EDNS: version: 0, flags:; udp: 4096&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; QUESTION SECTION:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;kgugeler.ca.			IN	A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; AUTHORITY SECTION:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ca.			172800	IN	NS	d.ca-servers.ca.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ca.			172800	IN	NS	any.ca-servers.ca.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ca.			172800	IN	NS	c.ca-servers.ca.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ca.			172800	IN	NS	j.ca-servers.ca.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; ADDITIONAL SECTION:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;d.ca-servers.ca.	172800	IN	A	45.142.220.101&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;d.ca-servers.ca.	172800	IN	AAAA	2a0e:dbc0::101&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;any.ca-servers.ca.	172800	IN	A	199.4.144.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;any.ca-servers.ca.	172800	IN	AAAA	2001:500:a7::2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;c.ca-servers.ca.	172800	IN	A	185.159.196.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;c.ca-servers.ca.	172800	IN	AAAA	2620:10a:8053::2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;j.ca-servers.ca.	172800	IN	A	198.182.167.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;j.ca-servers.ca.	172800	IN	AAAA	2001:500:83::1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We see that there are 4 authority records to point us to the nameservers for
the CA TLD - any of the four records will do. We don&#x27;t have any way of knowing
their IPs, which is why those IPs appear in the additional section&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-extra_rr-1&quot;&gt;&lt;a href=&quot;#fn-extra_rr&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also worth noting that &lt;code&gt;dig&lt;&#x2F;code&gt; requested recursion, meaning it requested
the root nameserver to walk the DNS hierarchy for it, and the root nameserver
(naturally) declined - doing recursive DNS processing safely is hard.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;question&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#question&quot; aria-label=&quot;Anchor link for: question&quot;&gt;Question&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;A question in the question section is simple enough: we need a name, a type of
record, and a class. For our purposes the class will always be IN, the internet
class.&lt;&#x2F;p&gt;
&lt;p&gt;Err, hold on, how is that name encoded?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The domain name is broken into discrete labels which are concatenated; each
label is prefixed by the length of that label.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;That&#x27;s not very specific... thankfully the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.rfc-editor.org&#x2F;rfc&#x2F;rfc1035&quot;&gt;RFC&lt;&#x2F;a&gt; has me covered. Each component of
the domain is encoded by adding a single byte for the length, and then the
content. Don&#x27;t forget about root domain &lt;code&gt;.&lt;&#x2F;code&gt;! So &lt;code&gt;kgugeler.ca&lt;&#x2F;code&gt; becomes &lt;code&gt;08 6b 67 75 67 65 6c 65 72 02 63 61 00&lt;&#x2F;code&gt;, where the last zero byte indicates a component
of length zero, the root&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-dns_root-1&quot;&gt;&lt;a href=&quot;#fn-dns_root&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;resource-records&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#resource-records&quot; aria-label=&quot;Anchor link for: resource-records&quot;&gt;Resource Records&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;These are pretty similar - we need a name, type, and class, just like
questions. Then, we need a TTL and the actual data: which is also encoded with
length + value. The actual value format is type-specific.&lt;&#x2F;p&gt;
&lt;p&gt;For the purposes of this post, only TXT records matter, and they are encoded as
length + value. This means that a TXT record for kgugeler.ca looks like the
following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; kgugeler.ca.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;08 6b 67 75 67 65 6c 65 72 02 63 61 00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; TXT is type 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; IN is class 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00 01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; TTL of one minute = 60 seconds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00 00 00 3c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Our data has length 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00 04&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Our data is encoded as one length byte + value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; This says &amp;quot;DNS&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;03 44 4e 53&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that the TXT records ends up having two length fields, one outer, one inner.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;name-compression&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#name-compression&quot; aria-label=&quot;Anchor link for: name-compression&quot;&gt;Name Compression&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;So far, the protocol seems simple to parse and generate, right? Sure, there are
a lot of resource record types, but other than that, super easy!&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In order to reduce the size of messages, the domain system utilizes a
compression scheme which eliminates the repetition of domain names in a
message. In this scheme, an entire domain name or a list of labels at the end
of a domain name is replaced with a pointer to a prior occurance of the same
name.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Uh, what?&lt;&#x2F;p&gt;
&lt;p&gt;So it turns out that by enforcing that the lengths of domain name components
are at most 63 bytes, we can use the upper two bits to signal some other thing.
In this case, if the upper two bits are both one, then the next 14 bits (two
bytes total) are used as a &quot;pointer&quot; into the message. Any other upper bit
pattern is reserved.&lt;&#x2F;p&gt;
&lt;p&gt;The pointer is just an offset from message start. The idea is that if we have a
question &lt;code&gt;kgugeler.ca IN TXT&lt;&#x2F;code&gt;, we have to spell out &lt;code&gt;kgugeler.ca&lt;&#x2F;code&gt;. But in the
answer, when we need to put the name down again, we can use a pointer:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Question&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; kgugeler.ca.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;08 6b 67 75 67 65 6c 65 72 02 63 61 00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Answer: this is a pointer to offset 16 from message start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;c0 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can also have only some suffix be a pointer:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; hi + pointer to offset 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;02 68 69 c0 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a useful feature! Unfortunately, the RFC does not make any suggestions
on how to restrict this to ease processing. For instance, if pointers always
had to point to smaller offsets, then termination is guaranteed. Or if pointers
couldn&#x27;t point at other pointers, then termination is guaranteed since each
pointer will always point to something that increases the length of the domain
name, and the domain name has a limit of 255.&lt;&#x2F;p&gt;
&lt;p&gt;I decided to assume that pointers won&#x27;t point at other pointers, which seems
reasonable.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;parsing&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#parsing&quot; aria-label=&quot;Anchor link for: parsing&quot;&gt;Parsing&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Okay, now we can finally parse messages! Here&#x27;s the segment of the parsing code
that actually handles names. The rest is pretty boring, but you can see it
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git.sr.ht&#x2F;~riolku&#x2F;acme-dns-01-responder&#x2F;tree&#x2F;5e9ed863758618cda85be53d81f909ed96b2a045&#x2F;item&#x2F;main.py&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F9E2AF;font-style: italic;&quot;&gt; Consumer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89DCEB;font-style: italic;&quot;&gt; __init__&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt; packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;font-style: italic;&quot;&gt; bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; packet&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;font-style: italic;&quot;&gt; consume_bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt; size&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;font-style: italic;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;) -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;font-style: italic;&quot;&gt; bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;        assert&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; size&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;font-style: italic;&quot;&gt; len&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt;packet&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt; size&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span&gt; size&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span&gt; data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;font-style: italic;&quot;&gt; consume_ubyte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;) -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;font-style: italic;&quot;&gt; int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;unpack&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E3A1;&quot;&gt;&amp;quot;&amp;gt;B&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;consume_bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;))[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;font-style: italic;&quot;&gt; consume_name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;) -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; Name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        components&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        total_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        label_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;consume_ubyte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;        while&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; label_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;3F&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            total_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span&gt; label_length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;            assert&lt;&#x2F;span&gt;&lt;span&gt; total_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            components&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;consume_bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;label_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            label_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;consume_ubyte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span&gt; label_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;            assert&lt;&#x2F;span&gt;&lt;span&gt; label_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;C0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;C0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;label_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;3F&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;consume_ubyte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            components&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;extend&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;resolve_label_pointer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; total_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt; Name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt;components&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;components&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;font-style: italic;&quot;&gt; resolve_label_pointer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt; offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt; total_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;) -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #EBA0AC;font-style: italic;&quot;&gt; list&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;font-style: italic;&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;]:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9399B2;font-style: italic;&quot;&gt;        # Store global offset for restoring later&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        components&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9399B2;font-style: italic;&quot;&gt;        # Disallow double pointer to avoid DoS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        allow_pointer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;        while&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; True&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            first_byte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;consume_ubyte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span&gt; first_byte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;                break&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;            elif&lt;&#x2F;span&gt;&lt;span&gt; first_byte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;3F&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                total_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span&gt; first_byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;                assert&lt;&#x2F;span&gt;&lt;span&gt; total_length&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                components&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;consume_bytes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;first_byte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                allow_pointer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;            else&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;                assert&lt;&#x2F;span&gt;&lt;span&gt; allow_pointer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A6E3A1;&quot;&gt; &amp;quot;Pointer to pointer in message&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;                assert&lt;&#x2F;span&gt;&lt;span&gt; first_byte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;C0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;C0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9399B2;font-style: italic;&quot;&gt;                # Set the global offset and continue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;                self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;first_byte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt;3F&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #FAB387;&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #89B4FA;&quot;&gt;consume_ubyte&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #9399B2;font-style: italic;&quot;&gt;        # Restore global offset&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #94E2D5;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; offset&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #F38BA8;font-style: italic;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span style=&quot;color: #9399B2;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;offset&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #CBA6F7;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span&gt; components&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Debugging this code wasn&#x27;t too bad, since we can send a request to the server
with &lt;code&gt;dig&lt;&#x2F;code&gt; and look through it with either python or Wireshark.&lt;&#x2F;p&gt;
&lt;p&gt;Serialization is even easier, since we aren&#x27;t obligated to output pointers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;flags&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#flags&quot; aria-label=&quot;Anchor link for: flags&quot;&gt;Flags&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;One thing I neglected to mention earlier are the message flags. This is a
16-bit field that contains several flags, including whether the message is a
query or reply, the OPCODE, whether recursion is desired by the client, whether
recursion is available on the server, and the response code. This isn&#x27;t too
important for parsing, but we need to know this format for generating our
responses. I didn&#x27;t bother to check the flags sent much.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;rewriting-it-in-rust&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rewriting-it-in-rust&quot; aria-label=&quot;Anchor link for: rewriting-it-in-rust&quot;&gt;Rewriting it in Rust&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;For some insane reason, I thought that it would be easier to write this parser
in Rust&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-rust_impl-1&quot;&gt;&lt;a href=&quot;#fn-rust_impl&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, since Rust has helpers for dealing with conversions to&#x2F;from binary
data. It was about the same. I don&#x27;t know what I expected... but I did make a
fun realization while writing it in Rust.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;throwing-the-parser-out-the-window&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#throwing-the-parser-out-the-window&quot; aria-label=&quot;Anchor link for: throwing-the-parser-out-the-window&quot;&gt;Throwing the Parser out the Window&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Wait, why are we writing a DNS server again?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;acme&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#acme&quot; aria-label=&quot;Anchor link for: acme&quot;&gt;ACME&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Automatic_Certificate_Management_Environment&quot;&gt;Automated Certificate Management
Environment&lt;&#x2F;a&gt;
protocol is used to request a certificate. Let&#x27;s Encrypt then issues a
challenge, in our case, a DNS challenge: we have to prove that we control the
domain by placing a TXT record in the domain DNS records.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;who-needs-a-parser&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#who-needs-a-parser&quot; aria-label=&quot;Anchor link for: who-needs-a-parser&quot;&gt;Who needs a Parser&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Hold on, if all we need to do is serve a record from a single domain name, why
do we need a parser? We can just ignore what clients ask entirely!&lt;&#x2F;p&gt;
&lt;p&gt;Well, okay, not entirely. The first two bytes of the query are a transaction
ID, and if that&#x27;s different in our reply, DNS clients won&#x27;t recognize our
response&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-dig_id_mismatch-1&quot;&gt;&lt;a href=&quot;#fn-dig_id_mismatch&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;What happens if a client asks a different question?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #CDD6F4; background-color: #1E1E2E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; dig @127.0.0.1 sourcehut.org&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;;; ;; Question section mismatch: got kgugeler.ca&#x2F;TXT&#x2F;IN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dig is not happy&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-dig_unhappy-1&quot;&gt;&lt;a href=&quot;#fn-dig_unhappy&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;does-it-work&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#does-it-work&quot; aria-label=&quot;Anchor link for: does-it-work&quot;&gt;Does it work?&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Yes, it works! I can actually get a certificate provisioned this way. It&#x27;s not
pretty, since there&#x27;s no easy way to dynamically add a new record yet, but it
works!&lt;&#x2F;p&gt;
&lt;p&gt;One interesting thing I found out while doing this is that Let&#x27;s Encrypt
queries the DNS server from multiple locations, in order to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;community.letsencrypt.org&#x2F;t&#x2F;why-does-lets-encrypt-send-a-large-number-of-dns-tcp-requests-to-authoritative-resolution&#x2F;221099&#x2F;3&quot;&gt;prevent BGP
hijacking&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;automating-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#automating-it&quot; aria-label=&quot;Anchor link for: automating-it&quot;&gt;Automating it&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Naturally, my first thought here is to use Certbot hooks to spawn the server. There are two main issues here:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I need to spawn the server in the background and wait for the cleanup hook
to stop it. A natural choice is to use OpenRC since I&#x27;m on Alpine, but then
the service needs to know the challenge token to serve.&lt;&#x2F;li&gt;
&lt;li&gt;I want a certificate for &lt;code&gt;kgugeler.ca&lt;&#x2F;code&gt; and &lt;code&gt;*.kgugeler.ca&lt;&#x2F;code&gt;... but that means
I need to put two records on &lt;code&gt;_acme-challenge.kgugeler.ca&lt;&#x2F;code&gt;, so I need to
support that.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;rewriting-it-in-go&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rewriting-it-in-go&quot; aria-label=&quot;Anchor link for: rewriting-it-in-go&quot;&gt;Rewriting it in Go??&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I was briefly tempted to write the server in Go and integrate with
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;go-acme.github.io&#x2F;lego&quot;&gt;lego&lt;&#x2F;a&gt;, since it has a Go Library. I eventually
decided not to, since then I&#x27;d have to remember to rebuild everytime lego
updates, and I&#x27;m lazy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;control-socket&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#control-socket&quot; aria-label=&quot;Anchor link for: control-socket&quot;&gt;Control Socket&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;An easier solution is to simply spawn the server without any TXT records
configured. Then, use a control socket to add challenges to the domain.&lt;&#x2F;p&gt;
&lt;p&gt;I was initially going to use a TCP socket with a simple length + value
encoding, but it&#x27;s even easier to just use a UDP socket and have the whole
packet be the record to add. Dead simple.&lt;&#x2F;p&gt;
&lt;p&gt;Now the flow goes like this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Certbot hook runs, the server is started if it hasn&#x27;t been already. A record gets added.&lt;&#x2F;li&gt;
&lt;li&gt;The hook is run again, adding another record via the control socket.&lt;&#x2F;li&gt;
&lt;li&gt;Let&#x27;s Encrypt verifies the record.&lt;&#x2F;li&gt;
&lt;li&gt;The cleanup hook stops the server.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is much nicer to package and script!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;but-why&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#but-why&quot; aria-label=&quot;Anchor link for: but-why&quot;&gt;But... why?&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;One reason Let&#x27;s Encrypt gives for having a separate nameserver for the
&lt;code&gt;_acme-challenge&lt;&#x2F;code&gt; subdomain is security: no need to have a DNS API credential
on your VPS. And indeed, this is a benefit. The primary reason I swapped to
BIND in the first place though was speed: it&#x27;s instantaneous to verify records,
since I can simply set a TTL of 1 second, and they deploy immediately.&lt;&#x2F;p&gt;
&lt;p&gt;But why write this server? It&#x27;s way simpler than BIND - the entire server is 86
lines of python code. It doesn&#x27;t do any parsing or validation or anything on
untrusted input: it reads two bytes and dumps a pregenerated response.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;limitations&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#limitations&quot; aria-label=&quot;Anchor link for: limitations&quot;&gt;Limitations&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Uh... basically every limitation you can think of?&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s no way this server is close to standards compliant, it can&#x27;t handle
multiple domains at once, it&#x27;s not supported by any existing tools...&lt;&#x2F;p&gt;
&lt;p&gt;This kind of idea isn&#x27;t new though - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;joohoi&#x2F;acme-dns&quot;&gt;Joohoi&#x27;s
ACME-DNS&lt;&#x2F;a&gt; is a simple DNS server for
handling ACME DNS-01 challenges, and is supported by Lego. I haven&#x27;t looked at
the code much, but it&#x27;s probably what I&#x27;d recommend to people looking for a
similar setup... there&#x27;s no way this hack is something I can recommend.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s very amusing to me that this project works at all, and it&#x27;s cool how
simple the code ends up being. Of course all the ACME work is being done
elsewhere, but the fact that we can solve a DNS challenge in such a stupid
fashion is both hilarious and satisfying.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-extra_rr&quot;&gt;
&lt;p&gt;If you&#x27;re paying really close attention, you&#x27;ll see that we got 9
additional records. The last one is for DNS extensions, which I didn&#x27;t have
to look into, so I can&#x27;t explain it to you. &lt;a href=&quot;#fr-extra_rr-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-dns_root&quot;&gt;
&lt;p&gt;All domain names technically &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Domain_name&quot;&gt;end with a
dot&lt;&#x2F;a&gt;, that is almost always
omitted. &lt;a href=&quot;#fr-dns_root-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-rust_impl&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git.sr.ht&#x2F;~riolku&#x2F;acme-dns-01-responder&#x2F;tree&#x2F;ea18fde11c5e606f80c50b08ea2b4f838487781a&#x2F;item&#x2F;src&quot;&gt;If you&#x27;re curious&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-rust_impl-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-dig_id_mismatch&quot;&gt;
&lt;p&gt;Dig gives &lt;code&gt;;; Warning: ID mismatch: expected ID 54268, got 26729&lt;&#x2F;code&gt;. &lt;a href=&quot;#fr-dig_id_mismatch-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-dig_unhappy&quot;&gt;
&lt;p&gt;&quot;Hello please give me the IP of sourcehut.org&quot; &quot;HELLO HAVE A
TXT RECORD FOR AN UNRELATED DOMAIN&quot; &quot;what&quot; &lt;a href=&quot;#fr-dig_unhappy-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</description>
      </item>
    </channel>
</rss>
