Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

daemon chokes on ip4 and ip6 on same port #228

Closed
hackergrrl opened this issue May 17, 2016 · 23 comments
Closed

daemon chokes on ip4 and ip6 on same port #228

hackergrrl opened this issue May 17, 2016 · 23 comments
Labels
exp/novice Someone with a little familiarity can pick up help wanted Seeking public contribution on this issue kind/bug A bug in existing code (including security flaws)

Comments

@hackergrrl
Copy link
Contributor

given my go-ipfs generated config:

  "Addresses": {
    "Swarm": [
      "/ip4/0.0.0.0/tcp/4001",
      "/ip6/::/tcp/4001"
    ],
    "API": "/ip4/127.0.0.1/tcp/5001",
    "Gateway": "/ip4/127.0.0.1/tcp/8080"
  },

running the js-ipfs daemon will die with

Initializing daemon...
Starting at /home/noffle/.ipfs
Finished loading
error   listen EADDRINUSE :::4001

Works fine if I remove the /ip6 address.

@ghost
Copy link

ghost commented May 17, 2016

What if you remove the /ip4? :::4001 doesn't look right

@daviddias
Copy link
Member

It is true because we start a listener per multiaddr. Node.js TCP implementation starts a listener automatically on an IPV6 addr and IPV4, so the second time you listen, you are trying to listen on the same port.

Possible solution: Do addr matching and avoid trying to listen on equivalent addresses.
Workaround: We've been removing the ipv6 addr since we don't need it. It would be good to not have to worry about it though.

@daviddias daviddias added kind/bug A bug in existing code (including security flaws) exp/novice Someone with a little familiarity can pick up help wanted Seeking public contribution on this issue labels May 17, 2016
@dignifiedquire
Copy link
Member

can we stop/disable node from auto listening on ip6? I think that would be the best solution

@daviddias
Copy link
Member

@dignifiedquire not that I know or managed to find somewhere how to do it.

@ghost
Copy link

ghost commented May 17, 2016

There are unix socket options for that, I don't recall the exact name (SOL_SOMETHING) or how to set socket options in nodejs.

@shamb0t
Copy link

shamb0t commented May 25, 2016

@noffle is this issue still happening for you? I have the same config but the js-ipfs daemon isn't choking

@hackergrrl
Copy link
Contributor Author

@shamb0t yup, still happening

@deltab
Copy link

deltab commented May 26, 2016

It's the IPv6 socket binding to IPv4:

IPV6_V6ONLY (since Linux 2.4.21 and 2.6)

If this flag is set to true (non-zero), then the socket is restricted to sending and receiving IPv6 packets only. In this case, an IPv4 and an IPv6 application can bind to a single port at the same time.

If this flag is set to false (zero), then the socket can be used to send and receive packets to and from an IPv6 address or an IPv4-mapped IPv6 address.

Using it in Node seems to require the use of ffi or a compiled extension.

@daviddias
Copy link
Member

@shamb0t here is more input: You are not seeing the error now cause I removed the IPV6 port from the default config to avoid new users getting hit by that -> e98368e#diff-ce4bf744aff5c27c180e317f04bedab0L5

What @noffle is seeing, is that if you do an ipfs init with go-ipfs and then use that repo with js-ipfs, it will choke.

We still need a fix for this on the js-libp2p-tcp transport where we filter the 'equivalent' IP addrs. Note that IPV6 has a bunch of possible combinations that result to the one of listening in any interface (0.0.0.0)

@shamb0t
Copy link

shamb0t commented May 26, 2016

@diasdavid config file is generated from (go)ipfs init and the jsipfs daemon isn't choking. I added the line you removed from the default-config and still no choking. Should it choke if I regenerate the config with jsipfs init? Seems to be working fine for me...Im on osx 10.10

@daviddias
Copy link
Member

@shamb0t @noffle would you like to handle this one?

@daviddias
Copy link
Member

@shamb0t as we talked offline, this is only visible in Linux. Can you verify with a test and CI? (CI is Linux)

@dignifiedquire
Copy link
Member

@diasdavid what's the actual plan of action here?

@daviddias
Copy link
Member

@dignifiedquire Making sure that having both IPv6 and IPv4 addresses for the same port doesn't crash on Linux. To achieve this, what I've been think through is that, since this is a net module implementation detail, the libp2p-tcp transport instance should keep a tab of the listeners that it started, so that if it started a listener in IPv4 and then tries to start a listener in IPv6 on the same mapped addr, it will just return the same listener.

@SidHarder
Copy link
Member

I thought I would tackle this issue but I am unable to reproduce the problem. I'm running on a MAC with the following config:

"Addresses": {
"Swarm": [
"/ip4/0.0.0.0/tcp/4001",
"/ip6/::/tcp/4001"
],
"API": "/ip4/127.0.0.1/tcp/5001",
"Gateway": "/ip4/127.0.0.1/tcp/8080"
},

I start the daemon with the following code:

var IPFS = require ('../../git/js-ipfs/src/index.js');
var node = new IPFS();

node.goOnline(function(){});

I receive the following message:

Sids-MacBook-Pro:js-ipfs sidharder$ node index.js
Promise { { version: '0.17.0', repo: '', commit: '' } }
Swarm listening on /ip4/127.0.0.1/tcp/4001
Swarm listening on /ip4/10.1.4.129/tcp/4001
Swarm listening on /ip6/::/tcp/4001

@victorb
Copy link
Member

victorb commented Oct 18, 2016

@SidHarder seems the problem only affects Linux. Maybe you could try it in a VM or in a Docker container based on some Linux dist?

@SidHarder
Copy link
Member

@diasdavid I was able to reproduce this problem on an Ubuntu server. One solution that I implemented that seems to work was to add a distinctMultiaddr method to the peerInfo object which creates a new array of multiaddrs that doesn't contain any duplicate IP/Ports. I then called this method in the transport object when it's time to build the multiaddrs array just before the createListeners method is called. The distinctMultiaddr function will choose the first distinct addresses/ports and drop others as it loops through the addresses. The filter code is a bit messy. Does this sound like a reasonable approach or did you have something else in mind.

@daviddias
Copy link
Member

@SidHarder it sounds that what you build is what we need, just a couple of questions:

  • Does your distinct multiaddrs favour IPV6 or IPV4? I'm actually not 100% sure if Node.js favours one or the other (I do know that listening on IPV4 will also make it listen on IPV6, but not sure if the reverse happens)
  • Are you filtering for all the transports? As far as we know, this only happens for the TCP implementation from Node.js core, it might not hold true for other transports.

@SidHarder
Copy link
Member

@diasdavid The distinctMultiaddrs method doesn't favor either ipv4 or ipv6, it simply keeps the first equivalent IP and port and ignores any subsequent with same IP/Port. So the addresses that will be listened on can be modified by changing the order of addresses in the config file. I'm afraid I don't know how Node favors IPV4 vs IPV6.

I'm not sure how to answer the question "Are you filtering for all the transports". I'm simply taking the multiaddrs array and making sure there are no duplicate ip/ports. Am I missing something here?

Question?? So basically what I did was clone the master js-ipfs repo and then ran npm install which installed all the additional modules. I then went into the node_modules folder and made the following changes:

  1. In /peerInfo/lib/index.js I added the distinctMultiaddrs functio.
  2. In /libp2p-swarm/lib/transport.js I changed it to use the above method when appropriate.

To submit theses changes I will clone the two repositories that these files are in, make the changes and then create two separate pr's. What I don't feel comfortable with is that in this scenario I haven't exactly test the code that I'm submitting. Do you see a problem with this? How would you approach this?

@Kubuxu
Copy link
Member

Kubuxu commented Oct 25, 2016

I haven't read full thread here but here is how IPv6 sockets work on linux:

When you call open on a IPv6 socket fd with address: localhost, anybind or special addresses that is mapping IPv4 space to IPv6 it will open both IPv4 and v6 endpoints in kernel.

There is special flag (IPV6_V6ONLY ) for socket syscall that blocks binding IPv4 address when socket with corresponding IPv6 address is bound. For more see: https://linux.die.net/man/7/ipv6

@SidHarder
Copy link
Member

I just finished testing js-ipfs on ubuntu with ipv4 and ipv6 on port 5001, daemon is not choking any more.

@victorb
Copy link
Member

victorb commented Nov 23, 2016

I can verify that it's working for me as well now, I'm on Ubuntu 16.04.1 LTS

@daviddias
Copy link
Member

Wohooo! :D thank you @SidHarder !

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
exp/novice Someone with a little familiarity can pick up help wanted Seeking public contribution on this issue kind/bug A bug in existing code (including security flaws)
Projects
None yet
Development

No branches or pull requests

8 participants