<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="/feeds.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://chameth.com/">
    <title>Chameth.com - posts like a-year-of-boardgames, debugging-beyond-the-debugger, ipv6-docker-routing, why-you-should-be-using-https</title>
    <subtitle>Personal homepage of Chris Smith</subtitle>
    <link href="https://chameth.com/feeds/posts/like/a-year-of-boardgames,debugging-beyond-the-debugger,ipv6-docker-routing,why-you-should-be-using-https/" rel="self"/>
    <link href="https://chameth.com/"/>
    <icon>https://chameth.com/favicon.png</icon>
    <updated>2026-01-29T00:00:00Z</updated>
    <id>https://chameth.com/</id>
    <author>
        <name>Chris Smith</name>
    </author>
    <entry>
        <title>An interesting Tailscale + Docker gotcha</title>
        <link href="https://chameth.com/tailscale-docker-gotcha/"/>
        <updated>2026-01-29T00:00:00Z</updated>
        <id>https://chameth.com/tailscale-docker-gotcha/</id>
        <content xml:lang="en" type="html">&lt;p&gt;As I’ve &lt;a href=&#34;https://chameth.com/how-i-use-tailscale/&#34;&gt;written&lt;/a&gt; &lt;a href=&#34;https://chameth.com/avoiding-the-consequences-of-dumb-laws-with-tailscale/&#34;&gt;about&lt;/a&gt; &lt;a href=&#34;https://chameth.com/exposing-game-servers-over-tailscale/&#34;&gt;before&lt;/a&gt;, I use &lt;a href=&#34;https://tailscale.com/&#34;&gt;Tailscale&lt;/a&gt; for a lot of things. I thought I had it set up in a reasonably secure manner, but I recently noticed a problem.&lt;/p&gt;
&lt;p&gt;I use Tailscale’s ACLs to limit what each node can access, based on the tags I apply to it. So an &lt;code&gt;app&lt;/code&gt; node can’t access anything via Tailscale, while an &lt;code&gt;integration&lt;/code&gt; or &lt;code&gt;server&lt;/code&gt; node can access things tagged with either &lt;code&gt;app&lt;/code&gt; or &lt;code&gt;integration&lt;/code&gt;. This is expressed pretty simply in the Tailscale ACL JSON:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tagOwners&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-c1&#34;&gt;// Servers that can be SSH&amp;#39;d into
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tag:server&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-c1&#34;&gt;// Applications that are exposed on tailscale but never connect out
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tag:app&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-c1&#34;&gt;// Things which talk to other services over tailscale (connecting to apps etc)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tag:integration&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;grants&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-c1&#34;&gt;// Users can access everything
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;autogroup:member&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;dst&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;ip&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-c1&#34;&gt;// Servers and integrations can access integrations and apps
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:server&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:integration&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;dst&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:integration&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:app&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;ip&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Over the past week I’ve been setting up a private &lt;a href=&#34;https://forgejo.org/&#34;&gt;Forgejo&lt;/a&gt; instance behind Tailscale, complete with an actions runner that runs things using a docker-in-docker container. I didn’t want the runner knowing anything about Tailscale, so I had it configured to speak to Forgejo direct over HTTP (&lt;code&gt;forgejo:3000&lt;/code&gt;) instead of using full Tailscale HTTPS URL that I use when accessing it (&lt;code&gt;http://git.example-net.ts.net/&lt;/code&gt;)&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Everything was going fine, until I forgot to do that translation… and it worked. My Forgejo action runners could access anything on my tailnet. I run several things on Tailscale that just have authentication turned off, on the basis that only authorised devices can access them. Things like the admin interface for this website. I definitely didn’t intend for any workflow I run on my git server to have access to edit my website!&lt;/p&gt;
&lt;p&gt;This wasn’t just limited to Forgejo, either. Any docker container I was running could access the tailnet. In hindsight it’s fairly obvious why: the host is running Tailscale, connected as a node tagged with my &lt;code&gt;server&lt;/code&gt; tag. That creates a &lt;code&gt;tailscale0&lt;/code&gt; interface, and automagically sets up iptables rules to route Tailscale traffic over the interface. Docker also automagically sets up iptables rules to bridge traffic, and apparently these two sets of rules interact in such a way that traffic from Docker containers is allowed to route via the &lt;code&gt;tailscale0&lt;/code&gt; interface.&lt;/p&gt;
&lt;p&gt;I say it’s fairly obvious in hindsight — there’s no reason why Docker would special case any particular host interface after all — but it still feels pretty surprising. Because both bits of software inject their own iptables rules, I never really had a good mental model for how they interact. The host Tailscale node was a completely separate building block to Docker. It would be a pain to use either of them if they didn’t do these rules, but it’s also one of the reasons I don’t really like “magical” things&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;There are lots of ways to fix this, but none of them feel particularly great. You can configure both Tailscale and Docker to not automatically fiddle with iptables and handle the rules yourself, but I really hate dealing with iptables&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;. As a stopgap I did hold my nose and add some iptables rules to drop traffic to the &lt;code&gt;tailscale0&lt;/code&gt; interface if it originated from the IP ranges that Docker was configured to use:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;iptables -I DOCKER-USER -s 192.168.0.0/16 -o tailscale0 -j DROP
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;iptables -I DOCKER-USER -s 172.17.0.0/12 -o tailscale0 -j DROP
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;DOCKER-USER&lt;/code&gt; chain is a nice little escape hatch; it comes before the main auto-generated &lt;code&gt;DOCKER&lt;/code&gt; chain, and Docker leaves the rules in it alone.&lt;/p&gt;
&lt;p&gt;So I added these rules, and felt pretty good about myself, and then… everything started breaking in weird ways. After some debugging I realised the problem was DNS&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;. The server’s DNS resolver is &lt;code&gt;100.100.100.100&lt;/code&gt;, a special Tailscale address. This is so that it can resolve tailnet hostnames via &lt;a href=&#34;https://tailscale.com/kb/1081/magicdns&#34;&gt;MagicDNS&lt;/a&gt; (and so I don’t have to configure my custom DNS servers manually on each device; Tailscale does it for me). My new iptables rules inadvertently dropped all the DNS packets coming from docker containers. D’oh.&lt;/p&gt;
&lt;p&gt;Obviously the solution here is to double down and add MORE iptables rules:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;iptables -I DOCKER-USER -s 192.168.0.0/16 -d 100.100.100.100 -o tailscale0 -j ACCEPT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;iptables -I DOCKER-USER -s 172.17.0.0/12 -d 100.100.100.100 -o tailscale0 -j ACCEPT
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This got DNS working again, but it all feels a bit gross. Not least because to actually make these persist you need to use &lt;code&gt;iptables-save&lt;/code&gt;, and then you also get all the rules that both Docker and Tailscale have inserted. I came across &lt;a href=&#34;https://github.com/giangi/iptables-docker-filter&#34;&gt;a script&lt;/a&gt; to filter out the Docker ones, but… yuck&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:5&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I realised a cleaner idea might just be to lock down what &lt;code&gt;server&lt;/code&gt; tagged nodes could access within Tailscale itself. That way I can avoid touching iptables at all. It’s handy to be able to &lt;code&gt;curl&lt;/code&gt; services from the host when debugging, but it’s not really necessary. So I removed that access, and… stuff broke again. I’m using my Forgejo instance as a registry for some of the docker images I run, so the docker daemon needs to be able to reach it. I ended up making a new tag for &lt;code&gt;infrastructure&lt;/code&gt;, which can be accessed from &lt;code&gt;server&lt;/code&gt; devices. This does still allow all the docker containers to reach Forgejo, but I already have it set up with appropriate access controls and public/private repository splits. Forgejo is a service designed to run publicly, so this seems a reasonable trade-off for convenience. I used the &lt;code&gt;tests&lt;/code&gt; feature of Tailscale’s ACL config to make sure I’d got the rules right:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;tests&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-c1&#34;&gt;// Servers can only access infrastructure
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;src&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt;   &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:server&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;proto&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;allow&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:infrastructure:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nt&#34;&gt;&amp;#34;deny&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;100.84.16.43:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;me@example.com:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:server:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:app:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s2&#34;&gt;&amp;#34;tag:integration:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The whole situation still feels a bit messy. If I ever get around to switching to nftables I might loop back and manually craft some rules for routing traffic, instead of leaving Tailscale and Docker to do their own thing.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;I discovered later on that logging into the container registry at &lt;code&gt;forgejo:3000&lt;/code&gt; actually issued a redirect to &lt;code&gt;https://git.example-net.ts.net/&lt;/code&gt; so this was all basically for naught… &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I didn’t use Tailscale’s MagicDNS for a long time just because the word “magic” put me off. Only when I eventually got around to learning how it worked, and seeing that it wasn’t really that magical under the hood, did I change my mind. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;nftables seems far better in lots of ways, but I can’t really be bothered migrating. Maybe next time I reimage the server for whatever reason… &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;It’s always DNS… &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;Again, nftables would almost certainly help here. It actually has (gasp) configuration files. But again, I really didn’t want to spend the time migrating. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:5&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>If all you have is a hammer…</title>
        <link href="https://chameth.com/if-all-you-have-is-a-hammer/"/>
        <updated>2025-06-18T00:00:00Z</updated>
        <id>https://chameth.com/if-all-you-have-is-a-hammer/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/if-all-you-have-is-a-hammer/hammer.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/if-all-you-have-is-a-hammer/hammer.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/if-all-you-have-is-a-hammer/hammer.jpg&#34; alt=&#34;Closeup photo of a well-used hammer with a wooden handle&#34; loading=&#34;lazy&#34; width=&#34;500&#34; height=&#34;411&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;This, dear reader, is a hammer. It is almost entirely irrelevant to the article. Enjoy.&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I presume everyone is familiar with the idiom “if all you have is a hammer,
everything looks like a nail”. If not, well, there it is. It’s generally
used pejoratively about being single-minded, but I think it also gives a glimpse
into something more interesting: mental and perceptual sets.&lt;/p&gt;
&lt;p&gt;Before I explain, let me tell you a story about a person who bought a 3D printer&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.
When they were first thinking about getting one, they weren’t sure if it was
worth it. They could print a few board game accessories, but then what? After
they got it, though, a whole new world opened up: everywhere they looked there
were opportunities to improve things by adding 3D printed plastic. Broken
appliances were repaired with 3D printed parts, all sorts of shelves,
organisers, hooks and other things were made. But when they talked about this
to other people, most often the response was “That’s nice, but I don’t think
I’d use one”. How could they not see the truth in all its glorious layer lines?!&lt;/p&gt;
&lt;p&gt;The answer is in the concept of a ‘set’&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;, and instead of trying to explain it,
I’m just going to quote &lt;a href=&#34;https://en.wikipedia.org/wiki/Set_(psychology)&#34;&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In psychology, a set is a group of expectations that shape experience by making
people especially sensitive to specific kinds of information. A perceptual set,
also called perceptual expectancy, is a predisposition to perceive things in a
certain way. […] A mental set is a framework for thinking about a problem.
It can be shaped by habit or by desire. Mental sets can make it easy to solve
a class of problem, but attachment to the wrong mental set can inhibit
problem-solving and creativity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This perfectly captures what happened. They’d developed a ‘3D printing mental set’:
a predisposition to see problems that can be solved with their &lt;del&gt;hammer&lt;/del&gt; 3D
printer. Once I started noticing this pattern, I started seeing it all over
the place.&lt;/p&gt;
&lt;!--more--&gt;
&lt;h3 id=&#34;sets-at-work&#34;&gt;Sets at work&lt;/h3&gt;
&lt;p&gt;Aside from the “could this be improved with some 3D printed plastic” perceptual
set, I’ve noticed a couple of other sets: DIY, and writing puzzles.&lt;/p&gt;
&lt;p&gt;DIY is probably the most obvious one. Once you become a little familiar with the
basics of what you can fix and how, it seems like you start noticing the
opportunities more. Before, you might have ignored that loose door handle, but
now you notice it and realise with a screwdriver and a sex bolt&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; you can
fix it and stop it coming loose again anytime soon.&lt;/p&gt;
&lt;p&gt;As you do more things, you build up your set of mental sets as well. You learn
how to attach things to different types of walls, how to safely work with
electricity, and so on, and suddenly installing a new outside light goes from
a seemingly complex job to just exercising some of those concepts you’re already
familiar with.&lt;/p&gt;
&lt;p&gt;This works across ‘disciplines’ as well: I wanted to automatically cool
a room down, using a fan in the window to blow in cool air. The 3D printing
mental set gave me a way to make it physically go where I wanted it to, the
home automation set gave me a plan for how to automate it, and the electricity
set helped me figure out how to wire in the relay. It sounds a bit stilted when
I spell it out like that, but the catch is I didn’t have to sit down and work
any of this out. I was already primed to think in a certain way. I had a whole
selection of hammers, and could pick the right combination of them to beat
this particular nail&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Puzzles are a bit different. I enjoy taking part in puzzle hunts&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:5&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;, and at
first I was bewildered at how the authors came up with all the puzzles. After
I started thinking about writing some myself, though, I began to notice all
kinds of things that could maybe be turned into a puzzle: a specialised
database, or a song with repetitive lyrics, or set of things with unique ID
numbers. Writing the actual puzzles is still tricky, but once you’ve equipped
the “look out for puzzle material” perceptual set it’s much easier to gather
a range of ideas.&lt;/p&gt;
&lt;p&gt;For example, one puzzle I wrote came about because I stumbled upon
&lt;a href=&#34;https://archive.org/details/patrick-stewarts-cowboy-classic-sampler&#34;&gt;Sir Patrick Stewart’s Cowboy Classic Sampler&lt;/a&gt;&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:6&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;.
I think everyone will agree that it’s a fairly unique collection. I tied some
samples of the songs together with some screen captures of Sir Patrick as Picard
in Star Trek: The Next Generation, and puzzlers had to find the season and
episode numbers of the pictures, then use those numbers to select a track and a
word from that track in the audio mix. Those words spell out a question, and the
answer to that question is the answer to the puzzle.&lt;/p&gt;
&lt;p&gt;There were other hints mixed in to point you in the right direction, it wasn’t
quite as opaque as it might sound! But the point is without being in that
“puzzle finding” mindset when I came across the album, there’s no way I could
have come up with that puzzle. Like with the fan, I was primed to think a
certain way, and managed to create something I otherwise would have struggled
with.&lt;/p&gt;
&lt;h3 id=&#34;the-curse-of-noticing-things&#34;&gt;The curse of noticing things&lt;/h3&gt;
&lt;p&gt;Figuring out how to make stuff isn’t the only place sets appear, though.
Perceptual sets are about how we perceive things. When you read something
with lots of bullet points, em-dashes, and the word “delve” do you automatically
think it’s LLM generated?&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:7&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; Then you have an LLM text perceptual set! It’s
kind of annoying, as it’s difficult to “turn off” and stop noticing these
things once you’ve seen them. Similarly, I think I have a “bad grammar” set.
I know it doesn’t bother a lot of people, but if I’m reading a book and there’s
a rogue apostrophe it will throw me right out of the moment. It’s like tripping
up when walking and being torn out of a daydream. There’s some use to these —
being able to notice grammar errors easily helps with my writing — but for
the most part they’re a negative input: they point out things are broken or
bad.&lt;/p&gt;
&lt;p&gt;The “edge case set” takes this to another level. After about 20 years of writing
software&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:8&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; I have a finely honed ability to spot problems. Give me something to
implement and my brain will immediately rattle off all the different edge cases
and under-specified parts. Then some other bit of my brain gets the job of
deciding which we actually care about, which are worth raising, and so on.
It’s definitely useful to spot them up-front, rather than when you’re deep in
the weeds implementing something, and tends to make everything go a lot smoother
if you can hammer the major ones out when planning work. It doesn’t turn off
after work though; it comes up when reading board game rule books, or
descriptions of the magic system in fantasy novels, or news reports, and so on.
It’s a lot less useful then.&lt;/p&gt;
&lt;p&gt;Speaking of news reports, here’s a fun one: Gell-Mann amnesia is a cognitive
bias where even when you critically assess media reports about something you’re
knowledgeable about (say, technology), you continue to trust similar reporting
in other areas (say, medicine). But once you know about Gell-Mann amnesia, you
might start to actively notice when it happens. You scoff at the article about
how the Internet is a “series of tubes” and then start reading the next one
about a cancer treatment, but — wait a minute — your Gell-Mann amnesia set
kicks in. I’m not sure what you then do with this information. Dismiss basically
all the media and news as useless? It’s honestly pretty annoying.&lt;/p&gt;
&lt;h3 id=&#34;the-meta-set&#34;&gt;The meta set&lt;/h3&gt;
&lt;p&gt;I’ve had this blog post on my ideas list since I first noticed the “3D printing
mindset”. I didn’t know sets were an actual thing, and I didn’t have most of
the examples I do now. As time went on with this idea rattling around in the
back of my head, I started noticing the patterns come up more and more. There’s
lots of more examples I didn’t include because I didn’t want to just write a
listicle of mental patterns. But the fact that I noticed them all seems to mean
that I’ve developed a set set, or a meta-set, if you will. It’s fascinating
to think about how all this happens inside our mushy bag of neurons, but
also a bit terrifying. If thought processes are that malleable, what stops you
accidentally breaking them? Actually, thinking about things like Q-Anon, flat
earthers, and a lot of contemporary “politics”, maybe that’s quite easy to do?&lt;/p&gt;
&lt;hr/&gt;
&lt;h3 id=&#34;image-credits&#34;&gt;Image credits&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Photo&lt;/th&gt;
&lt;th&gt;Creator&lt;/th&gt;
&lt;th&gt;Licence&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hammer&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://unsplash.com/@iantalmacs&#34;&gt;Ian Talmacs&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Unsplash License&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://unsplash.com/photos/a-close-up-of-a-hammer-with-a-black-background-4kuAvNfHEzI&#34;&gt;Unsplash&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Surprise! I am that person. Bet you didn’t see that coming! &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;I feel like they should have consulted the mathematicians and/or computer scientists before they picked a name. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;Yes, that’s a real thing. No, I won’t ever use any of the alternative names for it. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;OK, I’ve strained the metaphor enough. I’m sorry. I’ll stop. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;If you’re not familiar, a puzzle hunt is a competition where you try to solve puzzles faster than other teams. The sort of puzzles involved are perfectly described by this quote from Mike Develin: “Imagine a word search. Now imagine you aren’t told what words to look for. Now imagine you aren’t told it’s a word search. Now imagine it isn’t a word search.” &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:5&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;Go and give it a listen. I’ll wait. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:6&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;I hereby certify all my em-dashes are hand-crafted. Relatedly, Claude Code keeps writing comments that use hyphens when they should actually be em-dashes. Maybe they’ve trained it to avoid them? &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:7&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;I just made myself sad by working this out. I still feel young at heart! … Or maybe that’s cholesterol? &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:8&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>A year of boardgames</title>
        <link href="https://chameth.com/a-year-of-boardgames/"/>
        <updated>2024-07-26T00:00:00Z</updated>
        <id>https://chameth.com/a-year-of-boardgames/</id>
        <content xml:lang="en" type="html">&lt;p&gt;I realised the other day that it’s a little over a year since I started building
out a collection of board games&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:1&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, and thought it’d be fun to go through the
collection and what I think about the games in hindsight.&lt;/p&gt;
&lt;h3 id=&#34;the-beginning&#34;&gt;The beginning&lt;/h3&gt;
&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/ticket-to-ride.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/ticket-to-ride.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/a-year-of-boardgames/ticket-to-ride.jpg&#34; alt=&#34;A picture of the board from Ticket to Ride: Europe&#34; loading=&#34;lazy&#34; width=&#34;800&#34; height=&#34;533&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Ticket to Ride: Europe&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I don’t remember how I discovered the concept of “modern” boardgames, but
just over a year ago I purchased &lt;a href=&#34;https://boardgamegeek.com/boardgame/14996/ticket-to-ride-europe&#34;&gt;Ticket to Ride: Europe&lt;/a&gt;
as my first. Prior to that I thought board games were like Scrabble,
Monopoly, Trivial Pursuit, etc: they might provide a distraction occasionally,
but didn’t amount to actual &lt;em&gt;fun&lt;/em&gt; in the same way a video game might. I’d
characterise those “classic” games as generally being extremely dependent on
luck, not presenting many interesting choices, and generally being punishing if you’re behind.&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:2&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Ticket to Ride came as a breath of fresh air. You get to decide where to route
your lines, whether you want to take on more cards, how aggressive to be in
blocking the other players, and more. There’s still some luck involved, but
it’s managed by being able to draw from a pool of visible cards, or being
able to select which route cards you keep.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Shortly after I also picked up &lt;a href=&#34;https://boardgamegeek.com/boardgame/822/carcassonne&#34;&gt;Carcassonne&lt;/a&gt;,
and was similarly enamoured. I’ve not played either of them recently, though:
they both fall into a weird little gap for me. While I enjoy the games, I don’t
like playing them with certain groups&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:3&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;, but I don’t love them enough to
prioritise them over other games when playing with other groups.&lt;/p&gt;
&lt;h3 id=&#34;pandemic&#34;&gt;Pandemic&lt;/h3&gt;
&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/pandemic.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/pandemic.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/a-year-of-boardgames/pandemic.jpg&#34; alt=&#34;The box of Pandemic&#34; loading=&#34;lazy&#34; width=&#34;291&#34; height=&#34;400&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Pandemic&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The next “gateway” game I picked up was &lt;a href=&#34;https://boardgamegeek.com/boardgame/30549/pandemic&#34;&gt;Pandemic&lt;/a&gt;,
which was my first co-operative game. I loved everything about it, and still do.
The feeling when you managed to claw back a victory after setback after setback
is great, but so is the shock when everything goes even worse than you thought
possible!&lt;/p&gt;
&lt;p&gt;Pandemic was also the first game where one of the mechanics caught my attention.
The way epidemics work is that you take the bottom card from the infection deck,
which becomes the center of the new outbreak, then shuffle that and all the
discards back onto the top of the deck. It sounds simple, but it has big
implications: everywhere that was previously infected can now be re-infected,
and you’re guaranteed some tense rounds while you work back through those
cards. It still blows my mind a little how shuffling and re-adding some card
can mix up the game so much.&lt;/p&gt;
&lt;p&gt;I still play Pandemic when I can, and it generally has a spot in my board game
bag when I’m going away. I’ve since picked up the &lt;a href=&#34;https://boardgamegeek.com/boardgameexpansion/40849/pandemic-on-the-brink&#34;&gt;On the Brink&lt;/a&gt;
expansion which adds some fun new twists&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:4&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt; to the base game, and
&lt;a href=&#34;https://boardgamegeek.com/boardgame/329670/pandemic-hot-zone-europe&#34;&gt;Pandemic: Hotzone – Europe&lt;/a&gt;
which plays similarly but is a bit quicker and smaller. I’ve also recently
ordered &lt;a href=&#34;https://boardgamegeek.com/boardgame/198928/iberia&#34;&gt;Iberia&lt;/a&gt;, but it
hasn’t materialised yet.&lt;/p&gt;
&lt;h3 id=&#34;more-gateway-games&#34;&gt;More gateway games&lt;/h3&gt;
&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/quacks.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/quacks.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/a-year-of-boardgames/quacks.jpg&#34; alt=&#34;The box of The Quacks of Quedlinburg&#34; loading=&#34;lazy&#34; width=&#34;600&#34; height=&#34;600&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;The Quacks of Quedlinburg&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Over the next few months I picked up &lt;a href=&#34;https://boardgamegeek.com/boardgame/244521/the-quacks-of-quedlinburg&#34;&gt;The Quacks of Quedlinburg&lt;/a&gt;,
&lt;a href=&#34;https://boardgamegeek.com/boardgame/230802/azul&#34;&gt;Azul&lt;/a&gt; (the mini variant),
and &lt;a href=&#34;https://boardgamegeek.com/boardgame/148228/splendor&#34;&gt;Splendor&lt;/a&gt;. Quacks
is probably my least favourite out of all the games so far: it’s not terrible,
but it straddles deck-building and push-your-luck in a way that I don’t find
particularly satisfying. It’s fun to play the combos you’ve invested in, and
it’s fun to try and push your luck, but it’s not really fun when failing at the
luck element means you don’t get to use the stuff you were building.&lt;/p&gt;
&lt;p&gt;Quacks does bear the distinction of being the first game I customised, though:
it got a little plastic organiser to hold all the ingredients instead of having
to sort through a massive plastic bag with them all mixed in. My appreciation
for game boxes with good built-in storage has gradually increased over the year,
as have the tools I have for fixing those that don’t. But we’ll get back to
that…&lt;/p&gt;
&lt;p&gt;Azul is fun when you’re in the right mood; I’m not terribly into abstract
strategy games, but Azul is light enough that it’s enjoyable. Splendor, on the
other hand, I really like. So much so that I wrote a digital re-implementation
of it. Both Azul and Splendor allow you to mess with your opponent a little, but
not too much, which keeps it interesting but also means it still plays well in
groups that don’t like too much head-on confrontation.&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:5&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I think the thing that really caught my attention in Splendor, though, is the
quasi-engine building you do. It’s not actually classed as an engine builder
on BoardGameGeek, but as you collect cards you get discounts on other cards,
which lets you get better cards and further discounts, and so on. I love that
kind of positive feedback loop in video games, and I apparently love it in
board games as well.&lt;/p&gt;
&lt;h3 id=&#34;terraforming-mars&#34;&gt;Terraforming Mars&lt;/h3&gt;
&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/tfm.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/tfm.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/a-year-of-boardgames/tfm.jpg&#34; alt=&#34;Terraforming Mars board, covered with tiles and player cubes&#34; loading=&#34;lazy&#34; width=&#34;400&#34; height=&#34;225&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;A recent game of Terraforming Mars&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I’d heard lots of good things about &lt;a href=&#34;https://boardgamegeek.com/boardgame/167791/terraforming-mars&#34;&gt;Terraforming Mars&lt;/a&gt;,
but I was worried it sounded a bit too complicated so put off buying it for a while.
I mean, its weight on BoardGameGeek is orange. That’s scary, right?! Well… no.
Terraforming Mars is easily my favourite board game, and I’ve played it pretty
consistently since buying it. It has such a huge stock of cards that no two
games feel the same: one game you might have an arsenal of cards that generate
and use microbes; another you might have a plethora of science tags that let
you play some of the most powerful project cards; next you might be spamming
forests on Mars, or drowning in credits because you have too much income. It
has the engine building element that I love, but I also really enjoy that it’s
not always obvious who’s doing well and who’s not until the final score is
tallied; that keeps everyone engaged and working on things for the entire game.&lt;/p&gt;
&lt;p&gt;I’ve added in the &lt;a href=&#34;https://boardgamegeek.com/boardgameexpansion/247030/terraforming-mars-prelude&#34;&gt;Prelude&lt;/a&gt;
expansion, which I wouldn’t play the game without now, and the &lt;a href=&#34;https://boardgamegeek.com/boardgameexpansion/231965/terraforming-mars-venus-next&#34;&gt;Venus Next&lt;/a&gt;
expansion, which adds some interesting bits but is nowhere close to being a hard
requirement. I’ll probably pick up &lt;a href=&#34;https://boardgamegeek.com/boardgameexpansion/255681/terraforming-mars-colonies&#34;&gt;Colonies&lt;/a&gt;
next. Prelude adds a new type of card that you take at the start of the game,
which gives you a fairly hefty boost; these help you get off to a faster start,
and may also affect what strategies you try to run with for the rest of the
game. Venus Next adds another resource track, but you don’t have to complete it
to end the game; it also adds a bunch of project cards that have “floater”
resources, but they don’t feel that much different to the base game microbes&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:6&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt;.
One interesting thing that Venus Next adds, though, is a “solar phase” where
one of the global parameters is increased at the end of each generation. The
active player decides which parameter, but gets none of the benefits for it, so
you get to decide entirely tactically.&lt;/p&gt;
&lt;p&gt;There are two drawbacks to Terraforming Mars: it’s a little lengthy, and some
of the components are a bit rubbish. Timing-wise, I find it takes a good
hour and a half for a two player game, while adding a third player can almost
double that. Obviously it depends who you’re playing with and what’s happening
in the game, but that’s enough of a commitment that you more-or-less have to plan
when to play instead of just spontaneously bringing it to the table. Component-wise,
the game comes with basically no storage for anything other than little plastic
bags that slosh around in the box; horrible plastic cubes for resource tracking
that somehow jump out of your hand constantly, and flimsy printed sheets for
putting those cubes on.&lt;/p&gt;
&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/tfm-board.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/tfm-board.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/a-year-of-boardgames/tfm-board.png&#34; alt=&#34;Custom Terraforming Mars player board&#34; loading=&#34;lazy&#34; width=&#34;400&#34; height=&#34;300&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;My custom player boards&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The reason I &lt;a href=&#34;https://chameth.com/adventures-in-3d-printing/&#34;&gt;got a 3D printer&lt;/a&gt; was in part so that I could make my own upgraded
player boards that actually held the pieces in place instead of letting them fly
everywhere if the table was slightly knocked. You can buy third party ones but
I figured it was a teach-a-man-to-fish kind of situation, and dropping £200 on
a 3D printer would save me money in the long run vs buying £50 of player boards
someone else had made.&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:7&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt; About seven versions later, I have some boards which
I think look and feel great. It’s 3D printed in two halves, then has a laminated
2D print sandwiched in the middle for all the markings and artwork.&lt;/p&gt;
&lt;p&gt;As well as the player mats, I 3D printed some boxes, card holders, and
so on, but have since replaced them with an insert from &lt;a href=&#34;https://www.foldedspace.com/&#34;&gt;Folded Space&lt;/a&gt;.
These are made of foam, and are perfectly sized to the game box and all the
components in it. I could have eventually got to that point with 3D prints, but
it would have taken a lot of time to design and print everything. Terraforming
Mars was also the game that I first sleeved, as trying to shuffle the huge decks
was an exercise in frustration. With all of the cards sleeved, not only are they
more protected against wear and tear, you can now shuffle the deck just by
gently mashing stacks of cards together. It makes shuffling so easy I now sleeve
basically all my games as I hate having to riffle shuffle unsleeved cards.&lt;/p&gt;
&lt;h3 id=&#34;marrakech-and-heroquest&#34;&gt;Marrakech and HeroQuest&lt;/h3&gt;
&lt;p&gt;Later in the year I bought &lt;a href=&#34;https://boardgamegeek.com/boardgame/29223/marrakech&#34;&gt;Marrakech&lt;/a&gt;
after playing a giant version of it at a games expo. It sits somewhere between
Azul and Splendor for me: it’s fun, and good when you want a short game, but
it’s not high enough on my list to want to take it away with me. Playing with
felt rugs does make a nice change from flipping cards or dealing with plastic
components, though.&lt;/p&gt;
&lt;p&gt;I also picked up &lt;a href=&#34;https://boardgamegeek.com/boardgame/699/heroquest&#34;&gt;HeroQuest&lt;/a&gt; at one
point when it was on offer. It’s a good concept, and I felt like I would like it, but
it was a bit of a let-down. The biggest problem for me is that you either need one
player to basically be the DM, and manage the board, or you use an app to do that
and have to deal with a bunch of admin and duplicating things because you’re half
playing on the board and half in the app. I also don’t like relying on an
app because I’ve been around long enough to know how easily computer software can
become defunct, get removed from stores, get “updated” to remove features you need,
and so on. I feel like the game would work well with five
people: one to DM, and four to control the four heroes. But if you’ve got five people
who want to play a dungeon crawler why aren’t you just playing D&amp;amp;D or a similar TTRPG?
I’ll probably sell this at some point.&lt;/p&gt;
&lt;h3 id=&#34;party-games&#34;&gt;Party games&lt;/h3&gt;
&lt;figure class=&#34;image left&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/codenames.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/codenames.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/a-year-of-boardgames/codenames.jpg&#34; alt=&#34;Codenames components&#34; loading=&#34;lazy&#34; width=&#34;400&#34; height=&#34;246&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Codenames&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;These are all smaller games, and with most of them I’d played them before and
decided I wanted my own copy. &lt;a href=&#34;https://boardgamegeek.com/boardgame/178900/codenames&#34;&gt;Codenames&lt;/a&gt;
is my favourite party game, and I also picked up &lt;a href=&#34;https://boardgamegeek.com/boardgame/224037/codenames-duet&#34;&gt;Codenames: Duet&lt;/a&gt;
and they now live in the same box with a nice 3D printed insert. Codenames seems
to just naturally produce fun moments: when an obscure clue is understood
completely it feels amazing, but when it’s totally misunderstood it’s also
generally hilarious. There’s also a great tension as the spymaster when you
give a clue, then immediately realise it can be misinterpreted in a way that
points straight at the assassin.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://boardgamegeek.com/boardgame/312786/poetry-for-neanderthals&#34;&gt;Poetry for Neanderthals&lt;/a&gt;
is fun in the same party-word-game sort of way, but basically has no replayability.
There are few enough cards that if you play a few times you can remember the
“harder” word and just immediately guess it once you get the “easier” one being
hinted (you can also sometimes just do this outright, which feels great but it
kind of sucks from a gameplay point of view). The best bits are the inflatable
“no stick” you get to bop people with, and how everyone speaks like a neanderthal
for a little bit out of habit even after the game has ended. I seem to be weirdly
good at this game, and I’m not sure what that says about me.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://boardgamegeek.com/boardgame/277085/love-letter&#34;&gt;Love Letter&lt;/a&gt; has to
take the spot of best game per cubic centimeter. It’s basically just a small
set of cards, but it enables some really fun emergent gameplay. I really love
how small the game is, and how easy it is to set up and play. It’s the perfect
time filler. I’ve also played &lt;a href=&#34;https://boardgamegeek.com/boardgame/198740/lovecraft-letter&#34;&gt;Lovecraft Letter&lt;/a&gt;,
which adds a lot more complexity and was great fun, but is sadly out of print
and I haven’t been able to find a copy at a sensible price.&lt;/p&gt;
&lt;h3 id=&#34;fluxx&#34;&gt;Fluxx&lt;/h3&gt;
&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/fluxx.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/a-year-of-boardgames/fluxx.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/a-year-of-boardgames/fluxx.jpg&#34; alt=&#34;A game of Star Trek mega-Fluxx, with three transporter cards in play&#34; loading=&#34;lazy&#34; width=&#34;400&#34; height=&#34;239&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Star Trek mega-Fluxx&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;My arbitrary 12 month period ends not long after I went to a tabletop event
and played, amongst other things, &lt;a href=&#34;https://boardgamegeek.com/boardgame/122159/cthulhu-fluxx&#34;&gt;Cthulu Fluxx&lt;/a&gt;,
&lt;a href=&#34;https://boardgamegeek.com/boardgame/235365/doctor-who-fluxx&#34;&gt;Doctor Who Fluxx&lt;/a&gt;, and
&lt;a href=&#34;https://boardgamegeek.com/boardgame/246530/star-trek-the-next-generation-fluxx&#34;&gt;Star Trek: The Next Generation Fluxx&lt;/a&gt;.
Each game has the same core Fluxx elements, but adds slight twists along with
the unique themes. I ordered a copy of &lt;a href=&#34;https://boardgamegeek.com/boardgame/102104/star-fluxx&#34;&gt;Star Fluxx&lt;/a&gt;,
but then found out that you can combine the four Star Trek variants (TOS, TNG, DS9 and VOY) together
with some expansions to make a mega game so ordered all of those as well. While
putting together my mega-Fluxx order I noticed they had a &lt;a href=&#34;https://boardgamegeek.com/boardgame/183896/firefly-fluxx&#34;&gt;Firefly Fluxx&lt;/a&gt;
that was out of print so I snapped up one of the last copies of that, too.&lt;/p&gt;
&lt;p&gt;I ordered most of the games direct from Looney Labs, as the out of print ones
weren’t readily available anywhere else. Unfortunately, UK Border Force managed
to misread the import label&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a class=&#34;footnote-ref&#34; href=&#34;#fn:8&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt; and demanded £300 of VAT and import duties on
them! They refunded it eventually, but this small set of tiny games were for
a little while the most expensive things in my collection.&lt;/p&gt;
&lt;p&gt;Fluxx is fun enough, but the mega-deck version is brilliant. It gets much more
chaotic, with multiple captains, teleporters, and other doodads in play to steal
cards back and forth. I was worried it wouldn’t play well with non-Trekkies, but
the cards from each series use a different font and the weird people that can’t
identify Star Trek series based on uniform variations seem happy enough relying
on that.&lt;/p&gt;
&lt;h3 id=&#34;future&#34;&gt;Future&lt;/h3&gt;
&lt;p&gt;A few more months have passed since then, and my collection is still growing.
Board game stores have summer sales, it turns out! If my physical wallet was
in any way involved in the purchasing flow I’m sure it’d be crying.&lt;/p&gt;
&lt;p&gt;I’ve recently started logging my plays with &lt;a href=&#34;https://www.bgstatsapp.com/&#34;&gt;BG Stats&lt;/a&gt;
(which synchronises the information up to Board Game Geek). I’m interested to
see if the hard numbers actually align with my conceptions of how often I play
certain games. If I do another roundup in a year’s time, expect it to have a
lot more stats in…&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr/&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Other words that may be appropriate here: “hoarding”;
“compulsively obtaining”; “spending all my money on”, etc &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:1&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:2&#34;&gt;
&lt;p&gt;Think about a game of Monopoly: what do you actually get to decide? It
basically comes down to “buy or not” if you land on an available property, then
later on “buy more houses or not”. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:2&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:3&#34;&gt;
&lt;p&gt;e.g. a family member doesn’t like the farmer mechanic in Carcassonne, and
I don’t find the game interesting enough without them. Nothing wrong with the
game or the people, we’re just not going to both enjoy it the way we like when
playing together. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:3&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:4&#34;&gt;
&lt;p&gt;Which is definitely why I bought it. Not because it comes with amazing
little petri dishes to keep the disease cubes in. Certainly not. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:4&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:5&#34;&gt;
&lt;p&gt;There’s a different edge to taking a card that someone else wanted in
Splendor — there’s twelve others they can pick from, or they can take a face
down one, etc; it might be an inconvenience but you haven’t totally upended
their plans — versus blocking a really long train line they were trying to
build in Ticket to Ride. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:5&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:6&#34;&gt;
&lt;p&gt;Floaters are meant to be big pieces of infrastructure that float in the
atmosphere of Venus. The fact that they feel exactly the same way as tiny little
microbes when played seems wrong. &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:6&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:7&#34;&gt;
&lt;p&gt;Having since bought a more expensive printer, I think I’m past the point
of convincing myself it’s “cheaper”. It’s a lot more fun, though, and if you
design parts yourself you end up with exactly what you want! &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:7&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&#34;fn:8&#34;&gt;
&lt;p&gt;Turns out the “weight (lbs)” column is not the “quantity” column. Who knew? &lt;a class=&#34;footnote-backref&#34; href=&#34;#fnref:8&#34; role=&#34;doc-backlink&#34;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    <entry>
        <title>Adventures in IPv6 routing in Docker</title>
        <link href="https://chameth.com/ipv6-docker-routing/"/>
        <updated>2022-10-24T00:00:00Z</updated>
        <id>https://chameth.com/ipv6-docker-routing/</id>
        <content xml:lang="en" type="html">&lt;p&gt;One of the biggest flaws in Docker’s design is that it wasn’t created with IPv6 in mind. Out of the box Docker assigns
each container a private IPv4 address, and they won’t be able to reach IPv6-only services. While incoming connections
might work, the containers won’t know the correct remote IP address which can cause problems for some applications.
This situation is obviously suboptimal in the current day and age. It’s a bit like not supporting HTTPS on a website —
you might not have any issues because of it immediately, but you’re fighting against the currents of progress and are
making life worse for your users.&lt;/p&gt;
&lt;p&gt;Thankfully, it’s now relatively easy to make Docker behave a lot nicer. The
&lt;a href=&#34;https://github.com/robbertkl/docker-ipv6nat&#34;&gt;docker-ipv6nat&lt;/a&gt; project has been around since 2016, and uses an IPv6
overlay network and some iptables magic to route traffic to and from containers in a sensible fashion. It uses NAT
to emulate the behaviour Docker employs for IPv4 traffic; while using NAT with IPv6 is an anathema, I think it makes
sense for containers. You could give each container a publicly routable IPv6 address, but that brings with it a lot
of headaches: you’re basically going to be forced to implement service discovery and some kind of DNS management to
deal with the fact that your containers will be popping up on randomly assigned IP addresses. That is completely
overkill for people running a small number of services on one or two physical boxes; and if it’s not overkill for you
then you’re probably already looking at more complicated orchestration solutions like Kubernetes.&lt;/p&gt;
&lt;p&gt;More recently, similar functionality has been built into the Docker daemon itself. You can now
&lt;a href=&#34;https://docs.docker.com/config/daemon/ipv6/&#34;&gt;edit the config file to enable ipv6&lt;/a&gt; and each container will be
assigned an address in the range specified when it uses the default bridge network. This gives more-or-less the same
functionality of docker-ipv6nat — you lose a little flexibility as you can’t disable IPv6 on the default bridge, but
that’s a very worthy trade for having the functionality built-in.&lt;/p&gt;
&lt;p&gt;So far this all seems very simple. Hardly worthy of being called an “adventure”. Enter stage left: the wicked witch of
destination address selection…&lt;/p&gt;
&lt;!--more--&gt;
&lt;h3 id=&#34;destination-address-selection-and-you&#34;&gt;Destination address selection and you&lt;/h3&gt;
&lt;p&gt;When a computer program tries to connect to an address such as &lt;code&gt;google.com&lt;/code&gt;, it first resolves it in to an IP address.
That’s DNS 101, but what happens if the address resolves to multiple IP addresses? For example, &lt;code&gt;google.com&lt;/code&gt; resolves
to both &lt;code&gt;142.250.74.206&lt;/code&gt; and &lt;code&gt;2a00:1450:4001:82b::200e&lt;/code&gt;. You might just assume there’s a simple
“prefer IPv4 / prefer IPv6” toggle somewhere that decides, but it’s actually a lot more complicated. With IPv6, devices
are likely to have many addresses - a link-local address, a unique local address, a normal public address, various
privacy addresses, and so on. To deal with this, a number of RFCs define a series of rules that most implementations
follow. These are called the &lt;em&gt;destination address selection rules&lt;/em&gt;. &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc6724&#34;&gt;RFC6724&lt;/a&gt;
gives the rules as:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Avoid unusable destinations&lt;/li&gt;
&lt;li&gt;Prefer matching scope&lt;/li&gt;
&lt;li&gt;Avoid deprecated addresses&lt;/li&gt;
&lt;li&gt;Prefer home addresses&lt;/li&gt;
&lt;li&gt;Prefer matching label&lt;/li&gt;
&lt;li&gt;Prefer higher precedence&lt;/li&gt;
&lt;li&gt;Prefer native transport&lt;/li&gt;
&lt;li&gt;Prefer smaller scope&lt;/li&gt;
&lt;li&gt;Use the longest matching prefix&lt;/li&gt;
&lt;li&gt;Otherwise, leave the order unchanged&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Applying these rules will re-order the list of IP addresses such that (in theory) the most likely one to work will be
first. Most of them are fairly niche rules; the ones that do the heavy lifting are rules 5 and 6, which rely on a policy
table to make their decisions. The policy table ‘SHOULD’ be configurable by system administrators to allow them to tweak
how traffic is routed. In the absence of an admin-provided policy table, the RFC gives the following defaults:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prefix&lt;/th&gt;
&lt;th&gt;Precedence&lt;/th&gt;
&lt;th&gt;Label&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::1/128&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Loopback address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::/0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Any IPv6 address&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::ffff:0:0/96&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;IPv4 addresses mapped as v6 addresses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2002::/16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6-to-4 gateways&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2001::/32&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Toredo tunnels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fc00::/7&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;Unique Local Addresses (ULAs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::/96&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;IPv4 compatible addresses (deprecated)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fec0::/10&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Site-local addresses (deprecated)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3ffe::/16&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;6bone (deprecated)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The policy table is a bit complex, but you can see that normal IPv6 addresses are preferred (have a higher precedence)
over IPv4 addresses, which are preferred over the various tunnels, local addresses, and various deprecated ranges.&lt;/p&gt;
&lt;p&gt;We can see the result of this when I run &lt;code&gt;ping google.com&lt;/code&gt; on a box that has a native IPv6 connection as well as a
native IPv4 connection:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;PING google.com(fra07s29-in-x200e.1e100.net (2a00:1450:4001:802::200e)) 56 data bytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra24s01-in-x0e.1e100.net (2a00:1450:4001:802::200e): icmp_seq=1 ttl=119 time=5.11 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra24s01-in-x0e.1e100.net (2a00:1450:4001:802::200e): icmp_seq=2 ttl=119 time=5.28 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra07s29-in-x200e.1e100.net (2a00:1450:4001:802::200e): icmp_seq=3 ttl=119 time=5.31 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;^C
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;--- google.com ping statistics ---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;3 packets transmitted, 3 received, 0% packet loss, time 2003ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;rtt min/avg/max/mdev = 5.114/5.235/5.311/0.086 ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The address selection in this instance has been a result of rule 6: the IPv6 address has a higher precedence (40) than
the IPv4 address (35).&lt;/p&gt;
&lt;p&gt;However, if I run the same command in an IPv6-enabled Ubuntu container then it seems to prefer the IPv4 address:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;PING google.com (172.217.16.206) 56(84) bytes of data.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra16s08-in-f206.1e100.net (172.217.16.206): icmp_seq=1 ttl=59 time=4.86 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra16s08-in-f14.1e100.net (172.217.16.206): icmp_seq=2 ttl=59 time=4.86 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra16s08-in-f14.1e100.net (172.217.16.206): icmp_seq=3 ttl=59 time=5.03 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;^C
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;--- google.com ping statistics ---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;3 packets transmitted, 3 received, 0% packet loss, time 2003ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;rtt min/avg/max/mdev = 4.860/4.916/5.027/0.078 ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If I force &lt;code&gt;ping&lt;/code&gt; to use IPv6 with the &lt;code&gt;-6&lt;/code&gt; flag then it works the same as on the host, but when left to its own devices
it prefers IPv4. What’s going on there? The key difference between the Docker container and the host is that the host’s
network interfaces have public addresses, but the container has a private IPv4 address (&lt;code&gt;172.19.0.7&lt;/code&gt;) and a private
IPv6 address (&lt;code&gt;fd00:dead:beef::7&lt;/code&gt;). My first reaction to this was to think “Ah yes, fc00::/7 has a lower precedence
than native IPv4, that makes sense”, but that’s not quite right. These are the &lt;em&gt;destination&lt;/em&gt; address selection rules;
rule 6 doesn’t care about the source addresses. This is actually rule 5 at work: the label of source IPv6 address is
&lt;code&gt;13&lt;/code&gt;, but the label of the destination address is &lt;code&gt;1&lt;/code&gt;; meanwhile both the source and destination IPv4 addresses are &lt;code&gt;4&lt;/code&gt;.
This sorts the IPv4 address before the IPv6 one, and rule 6 becomes irrelevant.&lt;/p&gt;
&lt;h3 id=&#34;adjusting-the-policy-table&#34;&gt;Adjusting the policy table&lt;/h3&gt;
&lt;p&gt;Thankfully, the RFC says the policy table should be configurable by system administrators, so those of us who are doing
unorthodox things like NAT’ing IPv6 can customise the behaviour to fit our weird environments. The configuration is
done via the &lt;a href=&#34;https://man.archlinux.org/man/gai.conf.5.en&#34;&gt;/etc/gai.conf&lt;/a&gt; file (‘gai’ standing for &lt;code&gt;getaddrinfo&lt;/code&gt;, the
function in the standard library responsible for dealing with all these rules). The &lt;code&gt;gai.conf&lt;/code&gt; file by default (if it
exists) will likely just contain comments and examples; if there are no uncommented “label” or “precedence” lines then
the library will use its built-in defaults based on the RFC requirements.&lt;/p&gt;
&lt;p&gt;To make our container happy, we need to cause &lt;code&gt;fd00::/8&lt;/code&gt; to have the same label as a public IPv6 address. To do this we
can uncomment the default labels in &lt;code&gt;gai.conf&lt;/code&gt; and then add a single extra line, like so:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label ::1/128       0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label ::/0          1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label 2002::/16     2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label ::/96         3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label ::ffff:0:0/96 4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label fec0::/10     5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label fc00::/7      6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; label 2001:0::/32   7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-gi&#34;&gt;+label fd00::/8      1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because &lt;code&gt;fd00::/8&lt;/code&gt; has a longer prefix than &lt;code&gt;fc00::/7&lt;/code&gt; it will match our addresses and give them a label of &lt;code&gt;1&lt;/code&gt;, the
same as a public IPv6 address would get. This makes rule 5 leave it alone, and the default precedence table used by
the standard library will put the IPv6 address above the IPv4 address. (They don’t bother giving &lt;code&gt;fc00::/7&lt;/code&gt; a separate
precedence as listed in the RFC because rule 5 would have already de-prioritised those addresses, as we discovered.)&lt;/p&gt;
&lt;p&gt;Making this small change to the &lt;code&gt;gai.conf&lt;/code&gt; file in our Ubuntu container makes it start preferring the IPv6 address
for &lt;code&gt;google.com&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;PING google.com(fra16s65-in-x0e.1e100.net (2a00:1450:4001:806::200e)) 56 data bytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra15s29-in-x0e.1e100.net (2a00:1450:4001:806::200e): icmp_seq=1 ttl=118 time=5.00 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra15s29-in-x0e.1e100.net (2a00:1450:4001:806::200e): icmp_seq=2 ttl=118 time=5.10 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;64 bytes from fra16s65-in-x0e.1e100.net (2a00:1450:4001:806::200e): icmp_seq=3 ttl=118 time=5.08 ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;^C
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;--- google.com ping statistics ---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;3 packets transmitted, 3 received, 0% packet loss, time 2004ms
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;rtt min/avg/max/mdev = 5.002/5.058/5.098/0.040 ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A fairly complicated problem, but a simple fix!&lt;/p&gt;
&lt;h3 id=&#34;but-wait-theres-more&#34;&gt;But wait, there’s more…&lt;/h3&gt;
&lt;p&gt;Unfortunately, this fix won’t work on containers that use alpine. And that is a &lt;em&gt;lot&lt;/em&gt; of containers. Alpine uses
&lt;a href=&#34;https://musl.libc.org/&#34;&gt;musl&lt;/a&gt; as its standard library, rather than the much more common
&lt;a href=&#34;https://www.gnu.org/software/libc/&#34;&gt;glibc&lt;/a&gt;. There is very little documentation on the subject, but if you browse
the source code for musl you will see that it doesn’t implement any way at all to configure the policy tables. In
&lt;a href=&#34;https://git.musl-libc.org/cgit/musl/tree/src/network/lookup_name.c?id=63402be229facae2d0de9c5943a6ed25246fd021&#34;&gt;network/lookup_name.c&lt;/a&gt;
we can see the sorting logic:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-cm&#34;&gt;/* The following implements a subset of RFC 3484/6724 destination
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cm&#34;&gt;	 * address selection by generating a single 31-bit sort key for
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cm&#34;&gt;	 * each address. Rules 3, 4, and 7 are omitted for having
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cm&#34;&gt;	 * excessive runtime and code size cost and dubious benefit.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cm&#34;&gt;	 * So far the label/precedence table cannot be customized. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;cnt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sockaddr_in6&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;AF_INET6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_scope_id&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;scopeid&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_port&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;65535&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sockaddr_in&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa4&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da4&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin_family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin_port&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;65535&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;socklen_t&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;salen&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dalen&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;AF_INET6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-n&#34;&gt;da&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dalen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-n&#34;&gt;sa&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;salen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\0\0\0\0\0\0\0\0\0\0\xff\xff&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\0\0\0\0\0\0\0\0\0\0\xff\xff&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-n&#34;&gt;da&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dalen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-n&#34;&gt;sa&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;salen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;dpolicy&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;policyof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dscope&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;scopeof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dlabel&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dpolicy&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dprec&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dpolicy&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;prec&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;prefixlen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;socket&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;SOCK_DGRAM&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;SOCK_CLOEXEC&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;IPPROTO_UDP&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;connect&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;da&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dalen&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_USABLE&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;getsockname&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;sa&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;salen&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;					&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;family&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;AF_INET&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;memcpy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;					&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;dscope&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;scopeof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_MATCHINGSCOPE&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;					&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;dlabel&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;labelof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_MATCHINGLABEL&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;					&lt;span class=&#34;chroma-n&#34;&gt;prefixlen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-nf&#34;&gt;prefixmatch&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sa6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;						&lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;da6&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sin6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;				&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-nf&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;fd&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;dprec&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_PREC_SHIFT&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;dscope&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_SCOPE_SHIFT&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;prefixlen&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_PREFIX_SHIFT&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;|=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;MAXADDRS&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;DAS_ORDER_SHIFT&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;sortkey&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-nf&#34;&gt;qsort&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;cnt&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;sizeof&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;buf&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;addrcmp&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see if the address labels match, the sort key is adjusted using the &lt;code&gt;DAS_MATCHINGLABEL&lt;/code&gt; constant. But where
do the labels come from? For that we need to investigate the &lt;code&gt;policyof&lt;/code&gt; func:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;chroma-kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;chroma-kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;chroma-kt&#34;&gt;char&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;prec&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;label&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;50&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\0\0\0\0\0\0\0\0\0\0\xff\xff&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;35&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\x20\2&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\x20\1&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xff&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-se&#34;&gt;\xfc&lt;/span&gt;&lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mh&#34;&gt;0xfe&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;13&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cp&#34;&gt;#if 0&lt;/span&gt;&lt;span class=&#34;chroma-c&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	/* These are deprecated and/or returned to the address
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	 * pool, so despite the RFC, treating them as special
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	 * is probably wrong. */
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	{ &amp;#34;&amp;#34;, 11, 0xff, 1, 3 },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	{ &amp;#34;\xfe\xc0&amp;#34;, 1, 0xc0, 1, 11 },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-c&#34;&gt;	{ &amp;#34;\x3f\xfe&amp;#34;, 1, 0xff, 1, 12 },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-cp&#34;&gt;#endif
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-cm&#34;&gt;/* Last rule must match all addresses to stop loop. */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;chroma-s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;40&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-k&#34;&gt;static&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;policy&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;policyof&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;chroma-k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;in6_addr&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;chroma-mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-nf&#34;&gt;memcmp&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;chroma-p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;s6_addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;chroma-o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;mask&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		    &lt;span class=&#34;chroma-o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;addr&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;			&lt;span class=&#34;chroma-k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;		&lt;span class=&#34;chroma-k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;chroma-n&#34;&gt;defpolicy&lt;/span&gt;&lt;span class=&#34;chroma-o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;chroma-n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;chroma-p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;	&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&lt;span class=&#34;chroma-p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So the &lt;code&gt;policyof&lt;/code&gt; func simply uses the &lt;code&gt;defpolicy&lt;/code&gt; array to find the policy that applies to an address. This &lt;code&gt;defpolicy&lt;/code&gt;
array contains a number of hardcoded entries which correspond exactly to the ones provided in the RFC. The one causing
us problems is &lt;code&gt;{ &amp;#34;\xfc&amp;#34;, 0, 0xfe, 3, 13 }&lt;/code&gt; which matches &lt;code&gt;fc00::/7&lt;/code&gt; addresses.&lt;/p&gt;
&lt;p&gt;Unfortunately, without recompiling musl from source there’s not much we can do to address this directly. The only way
we can make the containers work as desired is to give them a different address range. Ideally this would be a range
that you control and that is otherwise not used, but there’s a good chance you won’t have such a range. One possible
alternative is the &lt;code&gt;2001:db8::/32&lt;/code&gt; range which is reserved for documentation purposes. This doesn’t feature in any of
the policy tables, so is treated like a normal public IPv6 address. It doesn’t feel great to misuse a reserved range
like that, but it’s probably the least of all evils, at least until musl allows configuring the policy table.&lt;/p&gt;
</content>
    </entry>
    <entry>
        <title>Debugging beyond the debugger</title>
        <link href="https://chameth.com/debugging-beyond-the-debugger/"/>
        <updated>2019-05-08T00:00:00Z</updated>
        <id>https://chameth.com/debugging-beyond-the-debugger/</id>
        <content xml:lang="en" type="html">&lt;figure class=&#34;image right&#34;&gt;
  &lt;picture&gt;
      &lt;source srcset=&#34;https://chameth.com/debugging-beyond-the-debugger/tools.avif&#34; type=&#34;image/avif&#34;/&gt;
      &lt;source srcset=&#34;https://chameth.com/debugging-beyond-the-debugger/tools.webp&#34; type=&#34;image/webp&#34;/&gt;
      &lt;img src=&#34;https://chameth.com/debugging-beyond-the-debugger/tools.jpg&#34; alt=&#34;Collection of tools hanging on a wall&#34; loading=&#34;lazy&#34; width=&#34;300&#34; height=&#34;396&#34;/&gt;
  &lt;/picture&gt;
  &lt;figcaption&gt;&lt;p&gt;Real-life debugging tools&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Most programming — and sysadmin — problems can be debugged in a
fairly straight forward manner using logs, print statements,
educated guesses, or an actual debugger. Sometimes, though, the
problem is more elusive. There’s a wider box of tricks that can
be employed in these cases but I’ve not managed to find a nice
overview of them, so here’s mine. I’m mainly focusing on Linux
and similar systems, but there tend to be alternatives available
for other Operating Systems or VMs if you seek them out.&lt;/p&gt;
&lt;h3 id=&#34;networking&#34;&gt;Networking&lt;/h3&gt;
&lt;h4 id=&#34;tcpdump&#34;&gt;tcpdump&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;tcpdump&lt;/code&gt; prints out descriptions of packets on a network interface. You can
apply filters to limit which packets are displayed, chose to dump the entire
content of the packet, and so forth.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Typical usage might look something like:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# tcpdump -nSi eth0 port 80
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;16:03:35.577781 IP6 2001:db8::1.54742 &amp;gt; 2001:db8::2.80: Flags [S], seq 2815779044, win 64800, options [mss 1440,sackOK,TS val 2378811665 ecr 0,nop,wscale 7], length 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;16:03:35.586853 IP6 2001:db8::2.80 &amp;gt; 2001:db8::1.54742: Flags [S.], seq 1522609102, ack 2815779045, win 28560, options [mss 1440,sackOK,TS val 3063610173 ecr 2378811665,nop,wscale 7], length 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;16:03:35.586877 IP6 2001:db8::1.54742 &amp;gt; 2001:db8::2.80: Flags [.], ack 1522609103, win 507, options [nop,nop,TS val 2378811674 ecr 3063610173], length 0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;16:03:35.620678 IP6 2001:db8::1.54742 &amp;gt; 2001:db8::2.80: Flags [P.], seq 2815779045:2815779399, ack 1522609103, win 507, options [nop,nop,TS val 2378811708 ecr 3063610173], length 354: HTTP: GET / HTTP/1.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here you can see the start of a plaintext HTTP request: the three-way
handshake as the TCP connection is established followed by a GET request.
Even if the data is encrypted as it will be in most cases, it’s often useful
to see the “shape” of the transmissions: did the client start sending data
when it connected, did the server ever respond, etc.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://danielmiessler.com/study/tcpdump/&#34;&gt;Daniel Miessler has a good tutorial on tcpdump&lt;/a&gt;
if you’re not familiar with it and don’t want to jump straight into the man
page.&lt;/p&gt;
&lt;h5 id=&#34;-with-docker&#34;&gt;… with Docker&lt;/h5&gt;
&lt;p&gt;Docker sets up separate network namespaces for each container. To see the
traffic across the interfaces of a single container you can &lt;code&gt;nsenter&lt;/code&gt; the
container’s network namespace:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# nsenter -t $(docker inspect --format &amp;#39;{{.State.Pid}}&amp;#39; my_container) -n tcpdump -nS port 80
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This retrieves the PID for the container, and tells &lt;code&gt;nsenter&lt;/code&gt; to enter the
network (&lt;code&gt;-n&lt;/code&gt;) namespace from the given target (&lt;code&gt;-t&lt;/code&gt;) PID, and then run the
given command (in this case &lt;code&gt;tcpdump ...&lt;/code&gt;).&lt;/p&gt;
&lt;h4 id=&#34;openssl-s-client--s-server&#34;&gt;openssl s_client / s_server&lt;/h4&gt;
&lt;p&gt;When a connection is using TLS it’s often useful to try connecting to the
server and see what certificate it presents, algorithms it negotiates, and
so forth. OpenSSL offers two useful subcommands which can help with this:
&lt;code&gt;s_client&lt;/code&gt; for connecting as a client, and &lt;code&gt;s_server&lt;/code&gt; for listening to
connections.&lt;/p&gt;
&lt;p&gt;For example, using &lt;code&gt;s_client&lt;/code&gt; to connect to &lt;code&gt;google.com&lt;/code&gt; on the standard
HTTPS port shows us details about the server cert and its verification
status:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ openssl s_client -connect google.com:443
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;CONNECTED(00000003)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;depth=2 OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;verify return:1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;depth=1 C = US, O = Google Trust Services, CN = Google Internet Authority G3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;verify return:1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;depth=0 C = US, ST = California, L = Mountain View, O = Google LLC, CN = *.google.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;verify return:1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Certificate chain
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; 0 s:C = US, ST = California, L = Mountain View, O = Google LLC, CN = *.google.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;   i:C = US, O = Google Trust Services, CN = Google Internet Authority G3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; 1 s:C = US, O = Google Trust Services, CN = Google Internet Authority G3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;   i:OU = GlobalSign Root CA - R2, O = GlobalSign, CN = GlobalSign
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Whereas connecting to my webserver and providing an unknown host in the SNI
field results in an SSL alert 112 (“The server name sent was not recognized”)
and no server certificate is sent:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ openssl s_client -connect chameth.com:443 -servername example.com
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;CONNECTED(00000003)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;140384831313024:error:14094458:SSL routines:ssl3_read_bytes:tlsv1 unrecognized name:../ssl/record/rec_layer_s3.c:1536:SSL alert number 112
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;no peer certificate available
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Often if you hit this kind of alert in an application the exact error will be
lost somewhere in the many layers between the SSL library and the logs, so
being able to directly connect and test can help diagnose a lot of issues.&lt;/p&gt;
&lt;p&gt;Once a connection is established you can read and write plain text and it
will be encrypted and decrypted automatically.&lt;/p&gt;
&lt;h4 id=&#34;java-apps&#34;&gt;Java apps&lt;/h4&gt;
&lt;p&gt;If a Java app is involved in the connection, you can enable a lot of built-in
debugging with a simple JVM property: &lt;code&gt;javax.net.debug&lt;/code&gt;. You can tweak
what exactly gets logged, but the easiest thing to do is just set the property
to &lt;code&gt;all&lt;/code&gt; and you’ll see information about certificate chains, verification,
and packet dumps:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ java -Djavax.net.debug=all -jar ....
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;found key for : duke
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;chain [0] = [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  Version: V1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  Subject: CN=Duke, OU=Java Software, O=&amp;#34;Sun Microsystems, Inc.&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  L=Cupertino, ST=CA, C=US
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;More information about Java’s debugging options is available on
&lt;a href=&#34;https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/ReadDebug.html&#34;&gt;docs.oracle.com&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;thread-and-core-dumps&#34;&gt;Thread and core dumps&lt;/h3&gt;
&lt;p&gt;Higher-level languages frequently provide an interactive way to dump the
current execution state of all of their threads (a “thread dump”). This
is useful to spot deadlocks, some types of race conditions, and as a
quick and dirty method of investigating hangs or excessive CPU usage.&lt;/p&gt;
&lt;p&gt;With both Java and Go applications you can send a QUIT signal to have a
thread dump printed out; Go applications will quit after doing so, Java
ones will carry on running. At most terminals you can hit &lt;code&gt;Ctrl&lt;/code&gt; and &lt;code&gt;\&lt;/code&gt; to
send a QUIT signal.&lt;/p&gt;
&lt;p&gt;For Java you can also use the &lt;code&gt;jstack&lt;/code&gt; tool from the JDK to dump threads
by PID; this can be useful if the application is running in the background
or has redirected sysout:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ jstack 8321
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Attaching to process ID 8321, please wait...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Debugger attached successfully.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Client compiler detected.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Thread t@5: (state = BLOCKED)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; - java.lang.Object.wait(long) @bci=-1107318896 (Interpreted frame)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; - java.lang.Object.wait(long) @bci=0 (Interpreted frame)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; - java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=116 (Interpreted frame)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; - java.lang.ref.ReferenceQueue.remove() @bci=2, line=132 (Interpreted frame)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt; - java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A core dump provides more complete information about the state of a process,
but is often more complex to interpret. The &lt;code&gt;gcore&lt;/code&gt; utility from GDB will
create a core dump of a process with a given PID. You can then generally
load the core file using your normal debugger, depending on the language
in question.&lt;/p&gt;
&lt;h3 id=&#34;system-calls&#34;&gt;System calls&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;strace&lt;/code&gt; is the swiss army knife for seeing what a process is doing. It
details each system call made by a program (you can filter them down, of
course). For example:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ strace -e read curl https://google.com/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;read(3, &amp;#34;\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0&amp;gt;\0\1\0\0\0 \236\0\0\0\0\0\0&amp;#34;..., 832) = 832
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;read(3, &amp;#34;\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0&amp;gt;\0\1\0\0\0P!\0\0\0\0\0\0&amp;#34;..., 832) = 832
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;read(3, &amp;#34;\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0&amp;gt;\0\1\0\0\0\200l\2\0\0\0\0\0&amp;#34;..., 832) = 832
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;read(3, &amp;#34;\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0&amp;gt;\0\1\0\0\0\20Q\0\0\0\0\0\0&amp;#34;..., 832) = 832
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;read(3, &amp;#34;\0\0\0\0\0\0\0\4\25\345\366\302\273sE6\365wI\225\321|\3435Z\362\216\372\215\251aO&amp;#34;..., 253) = 253
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta http-equiv=&amp;#34;content-type&amp;#34; content=&amp;#34;text/html;charset=utf-8&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&amp;lt;TITLE&amp;gt;301 Moved&amp;lt;/TITLE&amp;gt;&amp;lt;/HEAD&amp;gt;&amp;lt;BODY&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&amp;lt;H1&amp;gt;301 Moved&amp;lt;/H1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;The document has moved
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&amp;lt;A HREF=&amp;#34;https://www.google.com/&amp;#34;&amp;gt;here&amp;lt;/A&amp;gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;&amp;lt;/BODY&amp;gt;&amp;lt;/HTML&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;read(3, &amp;#34;\27\3\3\0!&amp;#34;, 5)                = 5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;a href=&#34;http://www.brendangregg.com/blog/2014-05-12/strace-wow-much-syscall.html&#34;&gt;Brendan Gregg&lt;/a&gt;
has a nice guide on &lt;code&gt;strace&lt;/code&gt; and alternatives.&lt;/p&gt;
&lt;h4 id=&#34;-with-docker-1&#34;&gt;… with docker&lt;/h4&gt;
&lt;p&gt;When the application is running in docker you can usually just &lt;code&gt;strace&lt;/code&gt; it
from the host with the correct PID
(from e.g. &lt;code&gt;docker inspect --format &amp;#39;{{.State.Pid}}&amp;#39; my_container&lt;/code&gt;).
Sometimes you may need to trace the startup of an application though, which is
a bit trickier. Instead you can run a new container using the same PID
namespace as your target, and the permissions needed to &lt;code&gt;strace&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ docker run --rm -it --pid=container:my_container \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  --net=container:my_container \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  --cap-add sys_admin \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  --cap-add sys_ptrace \
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;  alpine
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;From within the new container you can install strace, and trace any running
program within the target container using &lt;code&gt;strace -p&lt;/code&gt; as normal. To start a
new program you need access to the target container’s filesystem, which you
can get to via &lt;code&gt;/proc/1/root&lt;/code&gt; (PID &lt;code&gt;1&lt;/code&gt; being the main process that docker
started in the target container).&lt;/p&gt;
&lt;h3 id=&#34;files&#34;&gt;Files&lt;/h3&gt;
&lt;p&gt;Sometimes the problem might relate to file access. There are a couple of
straight forward — but nonetheless useful — tools which might help here.
&lt;code&gt;inotifywait&lt;/code&gt; uses the Linux &lt;code&gt;inotify&lt;/code&gt; subsystem to watch files or directories
for operations. For example:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ inotifywait -mr site/content
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Setting up watches.  Beware: since -r was given, this may take a while!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;Watches established.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;site/content/post/ MODIFY 2019-05-08-debugging-beyond-the-debugger.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;site/content/post/ OPEN 2019-05-08-debugging-beyond-the-debugger.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;site/content/post/ MODIFY 2019-05-08-debugging-beyond-the-debugger.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;site/content/post/ MODIFY 2019-05-08-debugging-beyond-the-debugger.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;site/content/post/ CLOSE_WRITE,CLOSE 2019-05-08-debugging-beyond-the-debugger.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here the &lt;code&gt;-m&lt;/code&gt; switch makes &lt;code&gt;inotifywait&lt;/code&gt; monitor the files forever (instead
of exiting on the first modification, which is the normal behaviour) and &lt;code&gt;r&lt;/code&gt;
makes it recurse into the directory and monitor each file and subdirectory in
there.&lt;/p&gt;
&lt;p&gt;If you want to see what processes currently have a file open, &lt;code&gt;fuser&lt;/code&gt; is the
go-to tool. For example:&lt;/p&gt;
&lt;pre class=&#34;chroma-chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;$ fuser -v /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;                     USER PID ACCESS COMMAND
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;/:                   root     kernel mount /
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;                     chris      2961 .rc.. systemd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;                     chris      2986 .r... gdm-x-session
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;                     chris      2994 .r... dbus-daemon
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;                     chris      3001 .r... gnome-session-b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;chroma-line&#34;&gt;&lt;span class=&#34;chroma-cl&#34;&gt;# ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;honourable-mentions&#34;&gt;Honourable mentions&lt;/h3&gt;
&lt;p&gt;These aren’t really debugging tools, but I feel it’s worth mentioning as
they often feature somewhere along the debugging-of-weird-problems journey.&lt;/p&gt;
&lt;p&gt;I’ve seen some weird and wonderful problems happen
because a disk is full, so a quick &lt;code&gt;df&lt;/code&gt; early on in the debugging process
never hurts. Some apps may hang, some may corrupt their config, some may
fall over and die; sometimes the manner in which they fail doesn’t obviously
point to a disk space issue.&lt;/p&gt;
&lt;p&gt;Another issue that comes up now and then — especially inside VMs or
other environment that don’t have a decent amount of “noise” happening —
is entropy exhaustion. A quick look at &lt;code&gt;/proc/sys/kernel/random/entropy_avail&lt;/code&gt;
should be enough to confirm that everything is ticking along nicely. If it’s
exceedingly low then you may find that anything involving random number
generation stalls (TLS connections for example).&lt;/p&gt;
</content>
    </entry>
</feed>
