pages tagged nodejsNico Schotteliushttps://www.nico.schottelius.org//tags/nodejs/Nico Schotteliusikiwiki2021-01-23T08:48:31ZThe Nodejs in IPv6 only networks problemhttps://www.nico.schottelius.org//blog/nodejs-and-ipv6-only-networks/2021-01-23T08:48:31Z2021-01-23T08:48:31Z
<p>For some years I have been seeing problems of nodejs based
applications that do not work in IPv6 only networks.
More recently, <a href="https://twitter.com/NicoSchottelius/status/1352243030368116739">I again found a situation in which a nodejs based
application does not even
install</a>,
if you try to install it in an IPv6 only network.</p>
<p>As the situation is not just straight forward, I started to collect
information about it on this website.</p>
<h2>The starting point</h2>
<p>I wanted to install
<a href="https://github.com/ether/etherpad-lite">etherpad-lite</a> and it failed
with the following error:</p>
<pre><code>174 error request to https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz failed, reason: connect EHOSTUNREACH 104.16.25.35:443
</code></pre>
<p>The message <strong>connect EHOSTUNREACH 104.16.25.35:443</strong> already cleary
points to the problem: npm is trying to connect via IPv4 on an IPv6
only VM. This cleary cannot work.</p>
<h2>A bug in NPM?</h2>
<p>My first suspicion was that it <a href="https://github.com/npm/cli/issues/2519">must be a bug in
npm</a>. But on Twitter
<a href="https://twitter.com/A1bi/status/1352574621594300416">I was told that npm should work in IPv6 only
networks</a>. That's
strange.
However it turns out that <a href="https://github.com/npm/cli/issues/348#issuecomment-751143040">somebody else had this problem
before</a>
and it seems to be specific to using npm on <a href="https://alpinelinux.org/">Alpine
Linux</a>.</p>
<h2>A bug in Alpine Linux?</h2>
<p>Alpine Linux is currently the main distribution that I use. Not
because of the <a href="https://musl.libc.org/">small libc called musl</a>, but
because the whole system works straight forward. Correct. And easy to
use. But what does that have to do with etherpad-lite failing to
install in an IPv6 only network?</p>
<p>It turns out that there is
<a href="https://github.com/libuv/libuv/issues/2225">a difference between musl and glibc in the default behaviour of
getaddrinfo()</a>, which is
used to retrieve DNS results from the operating system.</p>
<h2>A bug in musl libc?</h2>
<p>I got in touch with the developers of musl and the statement is rather
easy: musl <a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html">is behaving according to the
spec</a>
and the caller, in this
context nodejs, cannot just use the <strong>first</strong> result, but has to
potentially try <strong>all results</strong>.</p>
<h2>A DNS or a design bug?</h2>
<p>And at this stage the problem gets tricky. Let's revise again what I
wanted to do and why we are so deep into the rabbit hole.</p>
<p>I wanted to install etherpad-lite, which uses resources from
registry.npmjs.org. So npm wants to connect via HTTPS to
registry.npmjs.org and download a file. To achieve this, npm has to
find out which IP address registry.npmjs.org has. And for this it is
doing a DNS lookup.</p>
<p>So far, so good. Now the trouble begins:</p>
<pre><code>A DNS lookup can contain 0, 1 or many answers.
</code></pre>
<p><strong>And in case of the libc call getaddrinfo, the result is a list of IPv6
and IPv4 addresses, potentially 0 to many of each.</strong></p>
<p>So an application that "just wants to connect somewhere", cannot just
take the first result.</p>
<h2>A bug in nodejs?</h2>
<p>The assumption at this point is that nodejs only takes the first
result from DNS and tries to connect to it. However so far I have not
been able to spot the exact source code location to support that
claim.</p>
<p>Stay tuned...</p>