Node: multiple ipv6 request not working

Created on 19 Jun 2017  路  17Comments  路  Source: nodejs/node

  • Version:
    8.1.2
  • Platform:
    linux
  • Subsystem:
    mint 18.2


With curl it works:

root@server:~/server-scripts# curl --interface enp1s0 https://v6.ident.me/ && echo && echo
2001:470:1f1b:5b5:9ade:d0ff:fe04:23c3

root@server:~/server-scripts# curl --interface enp2s0 https://v6.ident.me/ && echo && echo 
2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84

With Nodejs, just one request, it works:

/* The request
{ url: 'https://v6.ident.me/.json',
  localAddress: '2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84' }
*/

 utils.http.request(getRequest({
                    url: 'https://v6.ident.me/.json',
                    //family: 6,
                    localAddress: getIpV6(interfaces.enp2s0).address
                })),

result:

{ address: '2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84' }

With 2 request, it is stuck:

/* 2 Request - 2 different functions
{ url: 'https://v6.ident.me/.json',
  localAddress: '2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84' }
{ url: 'https://v6.ident.me/.json',
  localAddress: '2001:470:1f1b:5b5:9ade:d0ff:fe04:23c3' }
*/

I get no results. If i change 2nd with IPV4, it works of works.

http invalid

All 17 comments

Can you post a complete test case with no third-party dependencies? I.e., no dependencies on npm packages.

The error :-1:

{ message: 'connect ETIMEDOUT 2a01:7e00::f03c:91ff:fe70:2b9d:443',
  stack: 'Error: connect ETIMEDOUT 2a01:7e00::f03c:91ff:fe70:2b9d:443\n    at Object.exports._errnoException (util.js:1016:11)\n    at exports._exceptionWithHostPort (util.js:1039:20)\n    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1138:14)' }

No idea where this 2a01:7e00::f03c:91ff:fe70:2b9d:443' comes from. But it is a NodeJs issue, because I have to revert to curl for now.

there is no thrid party dependencies, a simple request, a wrapper. pure node request.

Then please post that complete test case I asked for. If I can't run it, I'm not going to look at it.

#!/usr/bin/env node
const os = require('os');
const interfaces = os.networkInterfaces();
const https = require('https');
const url = require('url');

const getIpV6 = (items) => {
    const result = items.find(item => {
        return item.family === 'IPv6' && !item.address.startsWith('f');
    })
    return result;
}

const parsed = url.parse('https://v6.ident.me/.json');
const option1 = Object.assign({
    localAddress: getIpV6(interfaces.enp2s0).address,
}, parsed)
const option2 = Object.assign({
    localAddress: getIpV6(interfaces.enp1s0).address,
}, parsed)


console.log(`start options1 ${option1.localAddress}`);
https.get(option1 , (res) => {
    console.log();
    console.log('got option1 result');
    console.log('option1 local address', option1.localAddress);
    res.on('data', (chunk) => {
        console.log(`${option1.localAddress} option1 chunk`, chunk.toString());
    });
})

console.log(`start options2 ${option2.localAddress}`);
https.get(option2, (res) => {
    console.log();
    console.log('got option2 result');
    console.log('option2 local address', option2.localAddress);
    res.on('data', (chunk) => {
        console.log(`${option2.localAddress} option2 chunk`, chunk.toString());
    });
})

const exec = require('child_process').exec
exec('curl -ssk --interface enp2s0 https://v6.ident.me/.json', (err, stdout, stderr) => {
    console.log();
    console.log('curl enp2s0 stderr', stderr)
    console.log('curl enp2s0 stdout', stdout)
    console.log('curl enp2s0 stderr', stderr)
});

exec('curl -ssk --interface enp1s0 https://v6.ident.me/.json', (err, stdout, stderr) => {
    console.log();
    console.log('curl enp1s0 stderr', stderr)
    console.log('curl enp1s0 stdout', stdout)
    console.log('curl enp1s0 stderr', stderr)
});

Output:

root@server:~/server-scripts# ./test.js
start options1 2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84
start options2 2001:470:1f1b:5b5:9ade:d0ff:fe04:23c3

got option1 result
option1 local address 2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84
2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84 option1 chunk {"address": "2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84"}

curl enp2s0 stderr 
curl enp2s0 stdout {"address": "2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84"}
curl enp2s0 stderr 

curl enp1s0 stderr 
curl enp1s0 stdout {"address": "2001:470:1f1b:5b5:9ade:d0ff:fe04:23c3"}
curl enp1s0 stderr 

You can see, the 2nd interface is not working wiith NodeJs, but everywhere it is working wget and curl.

Here are the interfaces, but it is only with NodeJs. C, PHP works.

```
{ lo:
[ { address: '127.0.0.1',
netmask: '255.0.0.0',
family: 'IPv4',
mac: '00:00:00:00:00:00',
internal: true },
{ address: '::1',
netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
family: 'IPv6',
mac: '00:00:00:00:00:00',
scopeid: 0,
internal: true } ],
enp1s0:
[ { address: '192.168.81.20',
netmask: '255.255.255.0',
family: 'IPv4',
mac: '00:00:00:00:9a:de',
internal: false },
{ address: '2001:470:1f1b:5b5:9ade:d0ff:fe04:23c3',
netmask: 'ffff:ffff:ffff:ffff::',
family: 'IPv6',
mac: '00:00:00:00:9a:de',
scopeid: 0,
internal: false },
{ address: 'fe80::9ade:d0ff:fe04:23c3',
netmask: 'ffff:ffff:ffff:ffff::',
family: 'IPv6',
mac: '00:00:00:00:9a:de',
scopeid: 2,
internal: false } ],
enp2s0:
[ { address: '192.168.78.20',
netmask: '255.255.255.0',
family: 'IPv4',
mac: '00:00:00:00:ee:aa',
internal: false },
{ address: '2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84',
netmask: 'ffff:ffff:ffff:ffff::',
family: 'IPv6',
mac: '00:00:00:00:ee:aa',
scopeid: 0,
internal: false },
{ address: 'fe80::eeaa:a0ff:fe1b:4d84',
netmask: 'ffff:ffff:ffff:ffff::',
family: 'IPv6',
mac: '00:00:00:00:ee:aa',
scopeid: 3,
internal: false } ] }

````

thanks for helping!

Seems to be working for me locally. Does it make a difference if you pass in a link-local address, like 2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84%enp2s0? (Note the %enps20 suffix.)

Ciao!
How are you?
Do you have 2 interfaces? I use 2 interfaces for the server. How do you make it to work with NodeJS?
I tested, but the same result. And only with NodeJs. PHP is good. Look the settings. they seem good.

Code:'

#!/usr/bin/env node
const os = require('os');
const https = require('https');
const url = require('url');
const exec = require('child_process').exec

const interfaces = os.networkInterfaces();
delete interfaces.lo;

console.log('interfaces')
console.log(interfaces);

const parsedUrl = url.parse('https://v6.ident.me/.json');

Object.keys(interfaces).forEach(_interface => {
    const curlUrl = `curl -ssk --interface ${_interface} https://v6.ident.me/.json`;
    console.log()
    console.log('CURL', curlUrl);
    exec(curlUrl, (err, stdout, stderr) => {
        console.log();
        console.log(`CURL RESULT ${_interface} err`, err)
        console.log(`CURL RESULT ${_interface} stdout`, stdout)
        console.log(`CURL RESULT ${_interface} stderr`, stderr)
    });

    const ipv6 = interfaces[_interface].find(info => {
        return info.family === 'IPv6' && !info.address.startsWith('f');
    });
    const httpRequest = Object.assign({
        localAddress: `${ipv6.address}%${_interface}`,
        family: 6,
    }, parsedUrl);

    Object.keys(httpRequest).forEach((key) => (httpRequest[key] == null) && delete httpRequest[key]);

    console.log();
    console.log('NODE Request', httpRequest);
    const req = https.get(httpRequest, (res) => {
        res.on('data', (chunk) => {
            console.log();
            console.log(`NODE RESULT ${ipv6.address}` + '%%' + `${_interface}`, chunk.toString());
        });
    })
    req.end();
})

Result;

oot@server:~/server-scripts# ./test.js 
interfaces
{ enp1s0: 
   [ { address: '192.168.81.20',
       netmask: '255.255.255.0',
       family: 'IPv4',
       mac: '00:00:00:00:9a:de',
       internal: false },
     { address: '2001:470:1f1b:5b5:9ade:d0ff:fe04:23c3',
       netmask: 'ffff:ffff:ffff:ffff::',
       family: 'IPv6',
       mac: '00:00:00:00:9a:de',
       scopeid: 0,
       internal: false },
     { address: 'fe80::9ade:d0ff:fe04:23c3',
       netmask: 'ffff:ffff:ffff:ffff::',
       family: 'IPv6',
       mac: '00:00:00:00:9a:de',
       scopeid: 2,
       internal: false } ],
  enp2s0: 
   [ { address: '192.168.78.20',
       netmask: '255.255.255.0',
       family: 'IPv4',
       mac: '00:00:00:00:ee:aa',
       internal: false },
     { address: '2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84',
       netmask: 'ffff:ffff:ffff:ffff::',
       family: 'IPv6',
       mac: '00:00:00:00:ee:aa',
       scopeid: 0,
       internal: false },
     { address: 'fe80::eeaa:a0ff:fe1b:4d84',
       netmask: 'ffff:ffff:ffff:ffff::',
       family: 'IPv6',
       mac: '00:00:00:00:ee:aa',
       scopeid: 3,
       internal: false } ] }

CURL curl -ssk --interface enp1s0 https://v6.ident.me/.json

NODE Request { localAddress: '2001:470:1f1b:5b5:9ade:d0ff:fe04:23c3%enp1s0',
  family: 6,
  protocol: 'https:',
  slashes: true,
  host: 'v6.ident.me',
  hostname: 'v6.ident.me',
  pathname: '/.json',
  path: '/.json',
  href: 'https://v6.ident.me/.json' }

CURL curl -ssk --interface enp2s0 https://v6.ident.me/.json

NODE Request { localAddress: '2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84%enp2s0',
  family: 6,
  protocol: 'https:',
  slashes: true,
  host: 'v6.ident.me',
  hostname: 'v6.ident.me',
  pathname: '/.json',
  path: '/.json',
  href: 'https://v6.ident.me/.json' }

NODE RESULT 2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84%enp2s0 {"address": "2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84"}

CURL RESULT enp1s0 err null
CURL RESULT enp1s0 stdout {"address": "2001:470:1f1b:5b5:9ade:d0ff:fe04:23c3"}
CURL RESULT enp1s0 stderr 

CURL RESULT enp2s0 err null
CURL RESULT enp2s0 stdout {"address": "2001:470:1f1b:5b3:eeaa:a0ff:fe1b:4d84"}
CURL RESULT enp2s0 stderr 

events.js:182
      throw er; // Unhandled 'error' event
      ^

Error: connect ETIMEDOUT 2a01:7e00::f03c:91ff:fe70:2b9d:443
    at Object.exports._errnoException (util.js:1016:11)
    at exports._exceptionWithHostPort (util.js:1039:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1138:14)

There is a timeout, I waited, but I have no idea this IPv6 address comes, because it only with NodeJs.
Do you know how can do it? The routes are good, nothing like that anywere.
PHP, CURL, working.

Yes, two interfaces. I didn't need to do anything special (except use the right interface names), it just worked.

Perhaps try strace'ing node and curl to see what they do differently. Look for bind, connect, ioctl, setsockopt, etc. system calls. If I had to venture a guess, it's that curl binds to the interface (with an ioctl) while node binds to the address.

I'm going to close this for now because so far it seems to be an issue with your local environment. I can reopen if it does turn out to be a bug in node.

If you want to debug this further, open an issue over at https://github.com/nodejs/help/issues and we'll take it from there.

can you show works with 2 interfaces? you code, please! where i am doing something wrong and you already got it.

please you are using 2 ipv6, 1ipv6 works, it is deffirent ndoejs error, since with work it works!
how can my entirvonrnemt bad is everything works (mail server, https,)
only in nodejs not working with 2 ipv6 adress.
curl works!!!
why is my entinvornment bad!!!!
this weird!

The only changes I made to your script were the interface names.

i see, end nodejs cannot select the interface? only bind to an address?

Correct. Node calls bind(2). I suspect curl calls an ioctl or setsockopt(SO_BINDTODEVICE).

proposal to solve this issue #35769

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Brekmister picture Brekmister  路  3Comments

dfahlander picture dfahlander  路  3Comments

willnwhite picture willnwhite  路  3Comments

sandeepks1 picture sandeepks1  路  3Comments

mcollina picture mcollina  路  3Comments