Closed whyrusleeping closed 8 years ago
The good news is I found a very promising approach for nat traversal, which takes its ICE implementation directly from the chromium src (like i want to do in https://github.com/jbenet/random-ideas/issues/13). It's https://github.com/getlantern/natty with go bindings at https://github.com/getlantern/go-natty.
I can get OSX processes to connect to each other using their https://github.com/getlantern/waddell signaling server, and the https://github.com/getlantern/nattywad client, using a very crappy test script: https://gist.github.com/jbenet/632d9459414b996e9457 i wrote (but when I went to test linux I got https://github.com/getlantern/nattywad/issues/1).
Pros:
Cons
Got farther with natty: https://github.com/jbenet/go-netcatnat/
Ok the roadmap for NAT traversal is:
Service
to ipfs nodes, to do what waddell
does.[1] this is a convoluted example, and there's probably simpler ways, but maybe:
<multiaddr of signaler used>/ipfsstun/<peer.ID>/ipfs/<peer.ID>`
// or something nicer than ipfsstun
// the peer.ID is repeated because encapsulation. ipfsstun could use arbitrary identifiers
This says "connect to <multiaddr of signaler used>
and ask for connection to /ipfsstun/<peer.ID>
, it will give you addresses, attempt to connect to those. behind them is an /ipfs/<peer.ID>
.
pwnat
I reiterate here that we cannot rely on others' systems for nat traversal. It's an important enough piece and should not rely on public stun servers, as our traffic needs to not depend on pieces of infrastructure that might {fail, rate limit, block ipfs} unexpectedly. ipfs must sustain itself.
Where do you put UDP on our priority list?
@whyrusleeping ah right, natty is currently for udp only, so i guess we're switching now. We can find the simplest reliability protocol on top of udp, and aim for uTP or SCTP, and then QUIC once its implementations settle.
Update: now that we have UDT (#58), I can move ahead on this. My next thing will be adding Natty and UDT. these are two C++ libs, that will add significant size (and noise) to the binary. These are stopgaps to get the right functionality, in the end native Go impls, or Cgo compiled things will probably be less problematic to use.
this makes me kinda sad, since now we cant just distribute binaries...
@whyrusleeping oh we can. cross compilation :)
ehhh, not quite what i was hoping for though, with pure go, you can build once for each system and go. Once you mix in cgo and other linking stuff, you have to worry more about the specific system and their version of libc
@whyrusleeping yeah, it's painful. Pure Go impl of {UTP, UDT, SCTP, and QUIC} in the horizon. in due time. For now, I much prefer my ipfs node able to talk yours, (almost) no matter where it is.
Oh yeah, im much more happy about UDP and NAT working than i am sad about not being pure Go
NAT traversal is non trivial, the roadmap looks like this:
(*IpfsDht).FindPeersConnectedToPeer
)natty
, which gives us only UDPAddr
pairs) The blocker is reliable transport. Our options so far have been:
utp
- needs to be implemented robustly. h2so5/utp
is not yet working, could go-wrap libutp
.udt
- go-wrapped, needs some ARM assembly sctp
- needs go-wrapping, should not have assembly.quic
- needs lib-izing, and go-wrapping. Of these, quic
is my favorite option for the future. It is a truly phenmenal transport, with tons of things done very, very well. However, though the dragon is ready to hatch from its egg, it must still be unearthed from the enormous Code Caverns, of the Chromium Mountains, a quest not to be taken lightly.
Reliable transport a really big deal for us, and hard to get right:
@whyrusleeping pre-empting your call for "Lets Implement UTP!", we should not roll our own right now-- it will take us weeks to get reasonable robustness, speed, flow control, memory consumption, etc. We are good hackers, but it's taken the broader community years to make the few implementations there are. this is not to be underestimated. I totally want to have native go implementations of these transports (see my related emails to go-nuts mailing list), but we cannot afford the implementation cost right now.
And, frankly, I'm seriously considering doing the following horrible hack that might actually work robustly and be much quicker to pull off that
UDPAddr
pairs from natty, BUT! A-TCPConn <---> IPConn <---> UDPConn <--IPConn--> TCPConn-B
This is a mad science(tm) hack that gets around the awful realities of the network and the awful realities of software: simple things outside of specific rails is too fucking hard to do.
Looking at http://golang.org/pkg/net/#IPConn -- it should be possible, my concern is making sure DialIP
doesn't interfere with other traffic:
Resources:
The easiest thing to do for now is to just relay all traffic. Would get us around NAT, but would certainly increase load of nodes.
We'll have to relay some traffic, as not all NAT is hole punching. Sometimes we do have to use relaying. This could actually be done with Bitswap in mind, and be governed by the standard bitswap decision engine: relay for those nodes who are useful to us.
In lieu of using natty and hole-punching, we could start with the big guns (which will work for everything and we have to do anyway) and optimize later. My Knuth VM is telling me to optimize later.
I think a combination of relays, and NAT hole punching (NAT-PMP, uPnP) could be our best option (at least short term). I found a PMP library: https://github.com/jackpal/go-nat-pmp, and there was a few promising uPnP libraries around, which should get us through a decent number of networks, and the rest can be relayed.
we could start with the big guns
the big guns being relay?
the big guns being relay?
yeah
Since I don't think I've seen this mentioned yet, and it's good overview:
https://tools.ietf.org/html/rfc5128 State of Peer-to-Peer (P2P) Communication across Network Address Translators (NATs)
Any update on where you're at on this issue?
closing this for now, basic NAT traversal has been implemented as well as utp in dev0.4.0. Further discussion on relays and more advanced traversal should start a new issue
Awesome, well done guys!
Hey @whyrusleeping and @jbenet can you describe the NAT traversal implementation in 0.4.0 or link to more details? Exciting stuff.
@myleshorton @whyrusleeping @jbenet Yes, I am interested in how it works for the purposes of my own decentralized application. My application would require IPFS anyway, and I am wondering if I can just piggyback on the NAT traversal that IPFS uses, and then just specify a different a different port?
I just came back to this link again. Does anyone have an answer?
@Cole128 check https://libp2p.io, the networking layer of IPFS that, among other things, provides solutions for NAT Traversal. If you need support, ask at http://discuss.ipfs.io (it has bigger reach than a github issue)
@lidel libp2p led me here which seems to say it is only kind of implemented now.
@Cole128 there are two implementations of libp2p, one in js and one in go (and a work in progress one in rust). The issue you linked was for js. NAT traversal works pretty well in go (although we're still missing a few pieces).
If you just want to piggyback on ipfs's NAT traversal, you may be interested in https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md#ipfs-p2p
There's some improved documentation in #4894 but it's blocked on actually making this feature behave according to that documentation... (i.e., how one would expect).
If you're still having trouble with NAT traversal, you may also be interested in the circuit relay feature: https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md#circuit-relay
@Stebalien thanks a lot, I'll check all those links out.
Peers behind nats need a way for other peers in the network to connect to them. It would be nice to also have webrtc, but until a go library for that exists, this will have to do.