Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fallback can incorrectly fail to resolve with some /etc/hosts configurations #42

Closed
pimterry opened this issue Sep 7, 2021 · 3 comments · Fixed by #43
Closed

Fallback can incorrectly fail to resolve with some /etc/hosts configurations #42

pimterry opened this issue Sep 7, 2021 · 3 comments · Fixed by #43
Labels
bug Something isn't working external help wanted Extra attention is needed

Comments

@pimterry
Copy link
Contributor

pimterry commented Sep 7, 2021

Repro:

  • Make sure you have localhost defined as 127.0.0.1 in your /etc/hosts, but no IPv6 ::1 definition.
  • Run:
    const dns = require('dns')
    const CacheableLookup = require("cacheable-lookup");
    
    dns.lookup('localhost', { family: 6 }, (err, result) => console.log('dns', err, result));
    
    const cacheable = new CacheableLookup();
    cacheable.servers = ['1.1.1.1']; // Or any other remote DNS server
    cacheable.lookup('localhost', { family: 6 }, (err, result) => console.log('cacheableLookup', err, result));
  • dns.lookup successfully resolves, cacheable lookup returns ENOTFOUND

Having only IPv4 localhost defined but no IPv6 might seem contrived, but it's actually the default in many places, including all Ubuntu releases (see https://gist.github.com/ghoneycutt/e531984406b4b86ace687ea8958a6dc3). localhost can still be resolved to ::1 for IPv6 on these machines, it's just that it's handled elsewhere (no idea why).

This means that on most Ubuntu machines (and probably others) http.get('localhost', { family: 6, lookup: cacheableLookup.lookup }) with a DNS server configured will always incorrectly fail to resolve.

This happens because:

  • The family is set to 6
  • There's a server defined, so cacheable lookup sends a request there first
  • That returns ENOTFOUND, so cacheable lookup tries to use dns.lookup and cache the result
  • Cacheable-lookup doesn't pass the family to that call and instead always passes { all: true }, presumably to maximize the fallback caching.
  • dns.lookup({ all: true }) actually returns only the IPv4 address from /etc/hosts, with no IPv6 value, even though dns.lookup({ family: 6 }) can successfully get the IPv6 result. Presumably this is because it stops once it finds an answer in /etc/hosts?

That last step might seem like bad Node.js behaviour, but it's also true in Python apparently so I expect it's something that comes from Linux's DNS resolution itself.

I think this will affect any lookup where only an IPv4 or IPv6 address is available in the hosts file - requests for the other family will simply fail unexpectedly. Haven't tested other OS, no idea if this can happen elsewhere too.

@szmarczak szmarczak added bug Something isn't working external help wanted Extra attention is needed labels Sep 8, 2021
@szmarczak
Copy link
Owner

Good catch! Thanks for the very detailed issue, I can reproduce this locally.

I think the solution is to duplicate the dns.lookup call for now, so it gets queried separately for IPv4 and IPv6.

@szmarczak
Copy link
Owner

Released 6.0.2 🎉

@pimterry
Copy link
Contributor Author

pimterry commented Oct 5, 2021

Amazing, thanks for the quick merge & release! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working external help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants