NPM work only in old IPV4 World.

cli
help-wanted
good-first-patch
priority:low
triaged

(Valentin Ouvrard) #1

What I Wanted to Do

Use NPM install in IPv6 networks.

What Happened Instead

NPM resolve the IPv4 of the registry and try to reach directly the IPv4.

Reproduction Steps

Get an IPv6 machine,
NPM install anything

Details

It’s a design problem, because NPM talk directly to the IPv4, which is really bad.

If NPM talk to the hostname instead, it will work on IPv4/v6 and if the registry exist in IPv4-only, you can reach it out using NAT64 mechanisms.

This issue seem ignored from more than 3 years, and issue related to this bug are close by the Bot on Github.

It would be awesome (or normal ) to fix that with high priority…


(Kat Marchán) #2

I’m not sure where you’re getting your assessment. npm hands node the hostnames themselves. If you’re having IPv6 issues, that’s at least partially due to Node itself.

We do have a separate issue, which might be what you’re actually running into, in which case this is a duplicate: Installs fail behind proxy.

You can see how Node itself selects between IPv4 vs IPv6 in this stackoverflow post. tl;dr it uses your operating system’s own settings, and npm doesn’t change anything about that.

If you can be more specific about how and why your failure is happening, that’d be useful, but for the most part, I don’t really get why you’re having problems at all, and you’d need to do a lot more debugging and add more detail to this report before I can help you.


(Valentin Ouvrard) #3

Thanks for your answer zkat,

Here is what happen when I want install a npm package in IPv6-only Linux host :

npm verb Linux 4.9.0-7-amd64
npm verb argv "/usr/bin/node" "/usr/bin/npm" "--verbose" "install" "uglify-js"
npm verb node v8.11.3
npm verb npm  v5.6.0
npm ERR! code ENETUNREACH
npm ERR! errno ENETUNREACH
npm ERR! request to https://registry.npmjs.org/uglify-js failed, reason: connect ENETUNREACH 104.16.20.35:443 - Local (0.0.0.0:0)
npm verb exit [ 1, true ]

As you see, the IPv4 is resolved (even if registry.npmjs.org got IPv6 address) and try to connect directly to this IPv4, which fail, cause of IPv4 absence).

Some people say to me that the request package of node is involved to do that.

Can you confirm me is that true ?

Otherwize, I find that on npm’s cli repo :

:slight_smile:


(Kat Marchán) #4

package downloads don’t use request anymore. We use node-fetch-npm, which is a fork of node-fetch. We don’t touch dns directly, and that module just hands the package URL straight to Node’s own http and https.

Try this script and see what it does for you. If this breaks, then you’ll have to talk to the Node folks to figure it out:

const https = require('https');

https.get('https://registry.npmjs.org/uglify-js', (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });

}).on('error', (e) => {
  console.error(e);
});

EDIT: ohhhh, you edited your message while I was typing mine. Ignore the above. I didn’t realize we were doing this. Hang on, I’m digging into this.


(Kat Marchán) #5

Ahaha wow ok, so… looking into this.

That section was originally added to npmconf, the old config package we used, in this PR by @bmeck. There, he references an old Node bug which was closed back in 2015 and fixed sometime before that (no one seems to know when and how, but perhaps it has to do with this old libuv issue.

tl;dr I think we can probably lift this restriction and stop doing this. Thanks for taking the time to push on this! I think just removing the special-case patches here and letting Node do its default IP family stuff is probably Good Enough as far as any supported Node version goes. So if anyone’s interested in sending such a patch in, it’ll be most welcome.


(Valentin Ouvrard) #6

Thanks a lot for your investigation @zkat :smile:

You think, this should work ?

function getLocalAddresses () {
  var interfaces
  // #8094: some environments require elevated permissions to enumerate
  // interfaces, and synchronously throw EPERM when run without
  // elevated privileges
  try {
    interfaces = os.networkInterfaces()
  } catch (e) {
    interfaces = {}
  }

  return Object.keys(interfaces).map(function (nic) {
    return interfaces[nic].filter()
      .map(function (addr) {
        return addr.address
      })
  }).reduce(function (curr, next) {
    return curr.concat(next)
  }, []).concat(undefined)
}



(Kat Marchán) #7

You can probably remove the .filter() call altogether here :slight_smile:


(Kat Marchán) #8

This has been fixed as of npm@6.4.0-next.0.


(system) #9

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.