<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet href="/feed_style.xsl" type="text/xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="https://www.rssboard.org/media-rss">
  <channel>
    <title>musl on Tony&#39;s personal blog</title>
    <link>https://www.antoninotarantino.com/tags/musl/</link>
    <description>Recent content in musl on Tony&#39;s personal blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <lastBuildDate>Thu, 09 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.antoninotarantino.com/tags/musl/index.xml" rel="self" type="application/rss+xml" /><icon>https://www.antoninotarantino.com/img/icon.svg</icon>
    
    
    <item>
      <title>Finding out musl&#39;s DNS resolution implementation</title>
      <link>https://www.antoninotarantino.com/posts/musl-dns/</link>
      <pubDate>Thu, 09 Jul 2026 00:00:00 +0000</pubDate>
      
      <guid>https://www.antoninotarantino.com/posts/musl-dns/</guid>
      <description><![CDATA[<p>There are moments you can hardly explain yourself what&rsquo;s going on, especially when dealing with vastly known, solid tools like <code>ping</code>, <code>dig</code> and <code>curl</code>. This was literally me while trying to understand <em>unexpected</em> <strong>local</strong> DNS resolution issues on a containerised application based on <a href="https://alpinelinux.org/">Alpine</a>.</p>
<p>I took the opportunity to debug further and share what, imo, is a pretty known scenario to those who carefully and consciously pick one technology over another. I did not and many other respected collaborators of mine did not either, apparently.</p>
<p>In a scenario where your system uses <a href="https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html">dnsmasq</a> and the setup includes the <code>-A, --address=</code> in its configuration, it becomes possible that this address will not be correctly translated on a container running on Alpine, and that&rsquo;s because you&rsquo;re likely going to miss something in <code>/etc/dnsmasq.conf</code>. In short, this happens as <code>getaddrinfo()</code> in musl is <a href="https://git.musl-libc.org/cgit/musl/tree/src/network/getaddrinfo.c">implemented differently</a> than the glibc implementation. An <a href="https://bell-sw.com/blog/how-to-deal-with-alpine-dns-issues/">interesting article</a> treats the same topic with good depth, while <a href="https://jvns.ca/blog/2022/01/15/some-ways-dns-can-break/">this article</a> also shares a similar experience to mine. The <a href="https://wiki.musl-libc.org/functional-differences-from-glibc.html#:~:text=Name%20Resolver%2FDNS,-Traditional">musl wiki</a> explains the differences between both implementations. Spoiler, you need to also enter a (NULL, if you want) IPv6 address (<code>::</code>) along with the specified IPv4. You can even stop reading here.</p>
<p>Let&rsquo;s reproduce with containers. <code>docker</code>, <code>docker-compose</code>, <code>dnsmasq</code>, <code>tcpdump</code> (on host) will be needed for this.</p>
<p><code>/etc/dnsmasq.conf</code>:</p>
<pre tabindex="0"><code class="language-conf" data-lang="conf">bind-interfaces
domain-needed
bogus-priv
address=/custom-address/10.0.0.1
user=dnsmasq
group=dnsmasq
interface=*
server=1.0.0.1
server=1.1.1.1
</code></pre><p><code>docker-compose.yaml</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">dnsmasq</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">dockurr/dnsmasq</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">container_name</span>: <span style="color:#ae81ff">dnsmasq</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">DNS1</span>: <span style="color:#e6db74">&#34;1.0.0.1&#34;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">DNS2</span>: <span style="color:#e6db74">&#34;1.1.1.1&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;192.168.1.18:53:53/udp&#34;</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;192.168.1.18:53:53/tcp&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">cap_add</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">NET_RAW</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">NET_ADMIN</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">restart</span>: <span style="color:#ae81ff">always</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./dnsmasq.conf:/etc/dnsmasq.conf:Z</span>
</span></span></code></pre></div><p>Explicitly set the local IP listening on 53 in case of port conflict, as mentioned in <a href="https://hub.docker.com/r/dockurr/dnsmasq">dockurr/dnsmasq</a>.</p>
<p>Start <code>docker compose</code> and wait for <code>dnsmasq</code> to run on a container.</p>
<p><code>docker compose up</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[dnsmasq] | dnsmasq: started, version 2.93 cachesize 150
</span></span><span style="display:flex;"><span>[dnsmasq] | dnsmasq: compile time options: IPv6 GNU-getopt no-DBus no-UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP no-conntrack ipset no-nftset auth DNSSEC loop-detect inotify dumpfile
</span></span><span style="display:flex;"><span>[dnsmasq] | dnsmasq: using nameserver 1.0.0.1#53
</span></span><span style="display:flex;"><span>[dnsmasq] | dnsmasq: using nameserver 1.1.1.1#53
</span></span><span style="display:flex;"><span>[dnsmasq] | dnsmasq: read /etc/hosts - 14 names
</span></span></code></pre></div><p>Also start an Alpine container, I will use Node 22.22.0 as this was the one I was working with while troubleshooting.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>docker run -it --dns<span style="color:#f92672">=</span>192.168.1.18 node:22.22.0
</span></span><span style="display:flex;"><span><span style="color:#75715e"># / apk update &amp;&amp; apk add bind-tools</span>
</span></span></code></pre></div><p>Perhaps install <code>dig</code> to see a working and a non-working DNS resolution. <code>dig</code> uses its own mechanism for resolving DNS, while <code>ping</code> (pre-installed) uses musl routines. From inside the Node container:</p>
<p><code>dig custom-address</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Dig successful response:
</span></span><span style="display:flex;"><span>; &lt;&lt;&gt;&gt; DiG 9.20.23 &lt;&lt;&gt;&gt; custom-address
</span></span><span style="display:flex;"><span>;; global options: +cmd
</span></span><span style="display:flex;"><span>;; Got answer:
</span></span><span style="display:flex;"><span>;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 24967
</span></span><span style="display:flex;"><span>;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; OPT PSEUDOSECTION:
</span></span><span style="display:flex;"><span>; EDNS: version: 0, flags:; udp: 1232
</span></span><span style="display:flex;"><span>;; QUESTION SECTION:
</span></span><span style="display:flex;"><span>;custom-address.            IN  A
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; ANSWER SECTION:
</span></span><span style="display:flex;"><span>custom-address.     0    IN  A    10.0.0.1
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>;; Query time: 1 msec
</span></span><span style="display:flex;"><span>;; SERVER: 192.168.1.18#53(192.168.1.18) (UDP)
</span></span><span style="display:flex;"><span>;; WHEN: Wed Jul 08 21:51:43 UTC 2026
</span></span><span style="display:flex;"><span>;; MSG SIZE  rcvd: 58
</span></span></code></pre></div><p><code>ping custom-address</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>ping: bad address &#39;custom-address&#39;
</span></span></code></pre></div><p>Let&rsquo;s bring some more information from the container before starting analyzing the traffic with <code>tcpdump</code> on the host. If you do not already know the network interface from your app container (not dnsmasq):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>cat /sys/class/net/eth0/iflink
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">36</span>
</span></span></code></pre></div><p>Note <code>36</code> and then, from the host where your containers are running:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>ip link | grep <span style="color:#e6db74">&#39;^36:&#39;</span>
</span></span></code></pre></div><p>Note the interface ID, in my case <code>veth1</code>. Start <code>tcpdump</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>tcpdump -i veth1 -n -vv port <span style="color:#ae81ff">53</span>
</span></span></code></pre></div><p>Recap:</p>
<ul>
<li><code>dnsmasq</code> running as a container, mapping to the host as <code>191.168.1.18:53</code></li>
<li>App (<code>node:22.22.0</code>) running and using <code>dnsmasq</code> as its own resovler/forwarder (via <code>--dns=192.168.1.18</code> directive in <code>docker</code> command)</li>
<li><code>tcpdump</code> on host listening on the Docker&rsquo;s virtual network interface</li>
</ul>
<p>From the node container run <code>ping custom-address</code> and observe in <code>tcpdump</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>23:51:11.841250 IP (tos 0x0, ttl 64, id 45117, offset 0, flags [DF], proto UDP (17), length 59)
</span></span><span style="display:flex;"><span>    10.88.0.7.37992 &gt; 192.168.1.18.domain: [bad udp cksum 0xcc51 -&gt; 0xf88a!] 4254+ A? custom-address. (31)
</span></span><span style="display:flex;"><span>23:51:11.841402 IP (tos 0x0, ttl 64, id 45118, offset 0, flags [DF], proto UDP (17), length 59)
</span></span><span style="display:flex;"><span>    10.88.0.7.37992 &gt; 192.168.1.18.domain: [bad udp cksum 0xcc51 -&gt; 0xda01!] 5159+ AAAA? custom-address. (31)
</span></span><span style="display:flex;"><span>23:51:11.841609 IP (tos 0x0, ttl 63, id 30246, offset 0, flags [DF], proto UDP (17), length 75)
</span></span><span style="display:flex;"><span>    192.168.1.18.domain &gt; 10.88.0.7.37992: [bad udp cksum 0xcc61 -&gt; 0x601f!] 4254* q: A? custom-address. 1/0/0 custom-address. A 10.0.0.1 (47)
</span></span><span style="display:flex;"><span>23:51:11.841744 IP (tos 0x0, ttl 63, id 30247, offset 0, flags [DF], proto UDP (17), length 59)
</span></span><span style="display:flex;"><span>    192.168.1.18.domain &gt; 10.88.0.7.37992: [bad udp cksum 0xcc51 -&gt; 0x597e!] 5159 NXDomain q: AAAA? custom-address. 0/0/0 (31)
</span></span></code></pre></div><p>Last line above is the problem to the <code>ping: bad address 'custom-address'</code> (<code>NXDOMAIN</code>). Let&rsquo;s retry with <code>dig custom-address</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>23:52:07.635969 IP (tos 0x0, ttl 64, id 58182, offset 0, flags [none], proto UDP (17), length 82)
</span></span><span style="display:flex;"><span>    10.88.0.7.59643 &gt; 192.168.1.18.domain: [bad udp cksum 0xcc68 -&gt; 0x9e7b!] 57293+ [1au] A? custom-address. ar: . OPT UDPsize=1232 [COOKIE bcf4899c1135d91f] (54)
</span></span><span style="display:flex;"><span>23:52:07.636125 IP (tos 0x0, ttl 63, id 50946, offset 0, flags [DF], proto UDP (17), length 86)
</span></span><span style="display:flex;"><span>    192.168.1.18.domain &gt; 10.88.0.7.59643: [bad udp cksum 0xcc6c -&gt; 0x374c!] 57293* q: A? custom-address. 1/0/1 custom-address. A 10.0.0.1 ar: . OPT UDPsize=1232 (58)
</span></span></code></pre></div><p>No problem with <code>dig</code>, there is no reference to IPv6. It resolves the local IPv4 address fine.</p>
<p>Adding <code>address=/custom-address/::</code> to <code>/etc/dnsmasq.conf</code> should be enough to fix <code>ping</code>. So:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>docker compose down
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#39;address=/custom-address/::&#39;</span> &gt;&gt; ./dnsmasq.conf
</span></span><span style="display:flex;"><span>docker compose up
</span></span></code></pre></div><p>Retry <code>ping</code> from the app container:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>PING custom-address (10.0.0.1): 56 data bytes
</span></span></code></pre></div><p>From <code>tcpdump</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>23:49:18.644383 IP (tos 0x0, ttl 64, id 18878, offset 0, flags [DF], proto UDP (17), length 59)
</span></span><span style="display:flex;"><span>    10.88.0.7.60943 &gt; 192.168.1.18.domain: [bad udp cksum 0xcc51 -&gt; 0x9ab4!] 5325+ A? custom-address. (31)
</span></span><span style="display:flex;"><span>23:49:18.644527 IP (tos 0x0, ttl 64, id 18879, offset 0, flags [DF], proto UDP (17), length 59)
</span></span><span style="display:flex;"><span>    10.88.0.7.60943 &gt; 192.168.1.18.domain: [bad udp cksum 0xcc51 -&gt; 0x7c5a!] 6183+ AAAA? custom-address. (31)
</span></span><span style="display:flex;"><span>23:49:18.644682 IP (tos 0x0, ttl 63, id 55552, offset 0, flags [DF], proto UDP (17), length 75)
</span></span><span style="display:flex;"><span>    192.168.1.18.domain &gt; 10.88.0.7.60943: [bad udp cksum 0xcc61 -&gt; 0x0249!] 5325* q: A? custom-address. 1/0/0 custom-address. A 10.0.0.1 (47)
</span></span><span style="display:flex;"><span>23:49:18.644841 IP (tos 0x0, ttl 63, id 55553, offset 0, flags [DF], proto UDP (17), length 87)
</span></span><span style="display:flex;"><span>    192.168.1.18.domain &gt; 10.88.0.7.60943: [bad udp cksum 0xcc6d -&gt; 0xbde0!] 6183* q: AAAA? custom-address. 1/0/0 custom-address. AAAA :: (59)
</span></span></code></pre></div><p>There&rsquo;s no more <code>NXDOMAIN</code> when querying for <code>AAAA</code>.
It finally resolves.</p>
<h2 id="links">Links</h2>
<ul>
<li><a href="https://alpinelinux.org/">https://alpinelinux.org/</a></li>
<li><a href="https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html">https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html</a></li>
<li><a href="https://hub.docker.com/r/dockurr/dnsmasq">https://hub.docker.com/r/dockurr/dnsmasq</a></li>
<li><a href="https://wiki.musl-libc.org/functional-differences-from-glibc.html">https://wiki.musl-libc.org/functional-differences-from-glibc.html</a></li>
<li><a href="https://bell-sw.com/blog/how-to-deal-with-alpine-dns-issues/">https://bell-sw.com/blog/how-to-deal-with-alpine-dns-issues/</a></li>
<li><a href="https://git.musl-libc.org/cgit/musl/tree/src/network/getaddrinfo.c">https://git.musl-libc.org/cgit/musl/tree/src/network/getaddrinfo.c</a></li>
</ul>
]]></description>
      
    </item>
    
    
  </channel>
</rss>
