-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Segregate routable and non-routable networks #436
Comments
Potentially a silly question, but what's the definition of "routable network" and "non-routable network" in this proposal? |
The usual interpretation is publicly routable address range -- check wikipedia for a list of private networks. |
I've been thinking about this as well in the context of libp2p/libp2p#47. One possible design is to add an API in
|
^ Identify could use this API to filter addresses. And the peerstore could use this to prune existing entries. |
Maybe after segregation we can try connecting top to down like if WAN network is same reject it and move to LAN network if that is same dial using loopback on different port. Peer A: Peer B: If A wants to connect with B: Because they are on the same LAN and WAN network they can connect using loopback:port Peer A: Peer B: WAN is same, connect on LAN. Peer A: Peer B: Totally different network. Dial on WAN. Can this work? |
@upperwal I'm having trouble parsing your first sentence. |
@Stebalien So instead of trying all the observed addresses we can segregate the addresses into different categories like PRIVATE, PUBLIC or LOOPBACK (as @raulk suggested) and then we can try connecting in the following order:
|
edit: I need to read entire comments before responding. |
Okay. Maybe it wasn't such a silly question, because I assumed a different definition. I think we should limit the distribution of non-routable addresses even more. I think that non-routable IPs should only be distributed to peers with non-routable addresses in the same subnet as the non-routable IP we want to distribute. I.e. the line in the OP could should be changed is:
Also, could the proposal be amended to say that we send only our non-routable IP to non-routable nodes in the same subnet. I.e. we don't also send the routable IP. This will avoid NAT and IP-level routing problems, and I would definitely prefer it. However, I don't know if there are edge cases, or advanced network setups, that this might be non-ideal for. I'm especially unsure about IPv6. In general, how do other protocols/software handle this problem of public/private addresses? Is there some prior art we can refer to. |
(that was actually my first thought as well) Unfortunately, that won't work on complex networks: it's entirely possible to have multiple private subnets joined into a single network. As far as I know, this is actually an extremely common setup on corporate networks. Different buildings/floors will be on different subnets and the subnets will be connected by, e.g., a VPN.
Manual configuration and service discovery through mDNS (local multicast). We have the second but the first probably isn't going to work well for us (although we could provide some kind of configuration language...). However, I'd would like to amend my original proposal:
|
@Stebalien The given approach does prioritise loopback/private addresses and it also gives you a way to check if these addresses work. Let me explain it again. Solution to this problem is, to somehow identify the location (network) of peer A and B.
This way we are checking for the subnets in which peer A and B lies and dialing accordingly. This can also work for complex networks like you described above given we can query the subnet router for it's interface address (and subnets will have different IP signatures so distinguishable). If not, a fallback strategy can be used where: If peer A and B are on different subnet within an organisation connected to a VPN with observable addresses as follows: Peer A: 1.2.3.4/24:1234 -> [some subnet X which isn't visible] -> 192.168.1.2 -> 127.0.0.1:3000 Now we will assume that they are on the same host but they are not. We can try connecting using loopback but if it fails we try private IP if that fails we goto the public one. This case is applicable only when we could not find the subnet IP. Man, I need a diagram. 😛 I hope I am much more clear this time. |
That's a very good point, but there's a few other sides to the coin:
(To be clear, I am not married to any particular proposal solution here. I just think its an interesting topic, and I hope I'm contributing to the conversation.) For what its worth, I think that your proposal is a strict improvement on the current setup, and I would be all-for it being implemented, but I'm not sure I'm convinced that its the end of the road in terms of solutions. |
Yeah, this bugs me too (related ipfs/kubo#1771). And you're right, that's bad form. Really, we should just make this configurable (to some extent). Personally, I'd start with my proposal (as you said, it's a strict improvement but is less restrictive) and we can then add configuration options for more restrictive setups.
This I'm less worried about. Yes, it can happen but oh well, a few dials fail in rare cases. IMO, the bigger issue is dialing private IP addresses on every dial. Ah. I saw the in-order part, read the headers, and completely misread your proposal. That's actually a really cool solution. There are a few drawbacks:
However, it's a really cool heuristic and we can probably just plug it into the dialer with little work. |
@upperwal want to try plugging this logic into |
@Stebalien Yeah, its a simple solution with little refactor. Sure, let me give it a try. |
I am able to order the ip list as []public, []private, []loopback by implementing
Next step would be to find the correct subnet. The only problem is that the peer dialing does not know it's observed address. |
A quick and (somehow) dirty solution would be to pass |
Unfortunately that can't work -- it would create a circular dependency. |
So some refactoring is unavoidable... |
I think identity protocol can help (with little refactoring) where destination peer can send us back our observed address during protocol negotiation. Observed address can be stored and made available by some API. Edit: Keeping our observed address can help us take intelligent and optimised decisions when it comes to routing and connectivity. |
Damn. That's annoying. I don't know of a simple fix.
We don't really need to know anything about subnets to get this to work, we just need our observed external address. |
I know. By "Next step would be to find the correct subnet.", I meant to find the shortest path to dial on and yes that would only require our observed address. @Stebalien Is #427 related to the other peer's observed addresses (the one I would be connected to)? |
i think this is reasonable, just be careful when making choices about composability. i think this is long overdue, but i'd be sure to account for the multiple wrapping layers here and try your best to tease them apart! something like: type Dialer interface {
func Dial(...) ...
}
type DialerStrategy interface {
Dialer
func Wrap(Dialer) Dialer
} then we could have var MultiaddrDialer Dialer // manet stuff
var SyncDialer DialerWrapper // lets us parallelize and cancel upon success
var ResourceLimitedDialer DialerWrapper // lets us constrict file handle usage |
one thing i'm immediately wondering about/concerned about is how "peer-to-peer friendly" an identity service is. feels like it has the potential to centralize things quite a bit if gone about wrong. perhaps a node doesn't announce until it's fully bootstrapped, which might include identifying itself by multiple peers in different subnets? furthermore, i think raul's concerns about backwards compatibility point towards a dialer-focused solution as the best steps forward. |
Regardless of how much magic this is, isn't it required? For example, lets say that Peer A and Peer B both have their own public addresses but are also on the same private network (because they're in a datacenter or VPN). Peer A and Peer B might tell eachother both their public and private IP addresses. But what happens when Peer A wants to tell Peer C (on the other side of the internet) about Peer B? Will Peer A tell Peer C the private addresses too? |
got a trivial solution. Calling |
I'd rather not make any network requests to discover this... @raulk is now working on a dialing refactor to make things like this possible. |
cool |
@raulk Any update on this? I noticed that identify already knows about This will require Lines 105 to 116 in 3e2dc09
Maybe we can have something like This is a quick fix. Let me know if you are working on something bigger and I would be happy to contribute. Edit: This will also help close libp2p/go-libp2p-pubsub#40 and resolve error |
@upperwal Here's a WIP PR for a change that modularises the swarm dialer in a way that allows applications to determine how they want to prioritise multiaddrs, plan the dials over time, and throttle each attempt based on resources: libp2p/go-libp2p-swarm#88.
We'll definitely need to expose the observed addresses on the |
Any updates to this? |
Progress:
|
Currently, we announce all IP addresses we're listening, even private ones, and will dial any address we find for a peer, even private ones. We do this intentionally so we can connect to nodes on our local network. Unfortunately, this causes issues like ipfs/kubo#5511 and really pisses off users (for obvious reasons).
One reasonable solution (IMO) is to segregate routable and non-routable networks. That is:
We'll still be able to discover and dial nodes on non-routable networks through local discovery (mDNS). Additionally, if we're running IPFS on a VPN and all peers have non-routable addresses, everything should "just work".
This will mostly require changes to the DHT and the Identify protocol.
Future work:
The text was updated successfully, but these errors were encountered: