n0-computer / iroh

A toolkit for building distributed applications
https://iroh.computer
Apache License 2.0
2.55k stars 158 forks source link

The client is unable to successfully holepunching when using RelayMode::Disabled #2567

Open zh522130 opened 3 months ago

zh522130 commented 3 months ago

My client should not be connected by other nodes, so it will not publish any information or add a relay address. The relay address and configuration on the server side may change at any time in the future, and the client should obtain the server connection information from a discovery service.

Therefore, I have set the client's relay mode to RelayMode::Disabled. Currently, the client can communicate with the server through a relay, but it is unable to successfully holepunching.

If the client can obtain sufficient information from the discovery service, I only need to maintain the server for changes in relay configuration.

flub commented 3 months ago

I'm not sure I fully follow the network setup you are trying to use.

The relay address and configuration on the server side may change at any time in the future, and the client should obtain the server connection information from a discovery service.

The idea of the relay servers is that they are more stable and reachable from anywhere. So that they can help in establishing connections and support holepunching. Without a relay server you will not be able to holepunch. The RelayMode::Disabled is for when you can establish a direct connection without holepunching.

In the abstract a discovery service is a mapping from a NodeId to the RelayUrl and/or direct addresses. Practically the built-in DnsDiscovery services only maps to a RelayUrl. The pkarr discovery also handles direct addresses. So if you have nodes on an isolated network that need to reach each other then they could use a suitable discovery service on that network and work without relay server if they can establish direct connections without holepunching. But if they need holepunching they will need a relay server, which you could run on an isolated network. (I'm not sure if you're trying to run on an isolated network or not though)

matheus23 commented 3 months ago

It seems like there's multiple points in here:

  1. My client should not be connected by other nodes, so it will not publish any information or add a relay address. [...] Therefore, I have set the client's relay mode to RelayMode::Disabled[...], but it is unable to successfully holepunching.

  2. The relay address and configuration on the server side may change at any time in the future, and the client should obtain the server connection information from a discovery service.

The requirement for (1), holepunching to work while RelayMode is disabled, possibly goes against how iroh-net is designed as a whole. When sending messages to another node, you actually need to connect to the home relay for the destination, while when you receive messages from the other side, it connects to your home relay. This asymmetry is part of the design, so if one side doesn't have a home relay, holepunching won't work.

(2) is a sort of feature requestion. I see how it would possibly be desirable to have a system that doesn't depend on a possibly hard-coded relay map. One could think of a relay map directory that is fetched initially and populates the relay map on startup. I suggest experimenting with something like that in the application level first.

flub commented 3 months ago

Oh, I understand better now what the question is.

You have a node which you do not want to have a home relay, so use RelayMode::Disabled. This node uses discovery to discover the RelayUrl of other nodes it wants to connect to. This connection works over the relay server but does not manage to holepunch. Is that correct?

I suspect this is because without a relay map the netcheck report to discover STUN information for the node itself is not being run. So when holepunching happens the node without home relay is not sending useful addresses in the call-me-maybe message (the message to start holepunching) to establish a connection with, and thus holepunching fails.

So this would be a feature request to somehow make this work. You could certainly use the relay server of the peer node to run STUN again, but would not want to mark this as your home relay. This would require some changes to make it work.

However, be aware that relay servers are pretty dumb and will forward traffic between any nodes connected to them. So once you connect to a relay server, even if it is not your home relay, you will be able to be contacted via this relay. As soon as someone asks that relay to send something to your NodeId it will. They would somehow have to find our your NodeId is connected to that relay though.

zh522130 commented 3 months ago

The idea of the relay servers is that they are more stable and reachable from anywhere. So that they can help in establishing connections and support holepunching. Without a relay server you will not be able to holepunch. The RelayMode::Disabled is for when you can establish a direct connection without holepunching.

Yes, punching through requires a relay server. Perhaps it is unrealistic to expect successful hole punching with RelayMode::Disabled. Instead, there should be a mode similar to RelayMode::FromNode (just a placeholder name) that allows the client to obtain hole punching information from the server. The server can also choose whether to publish its tunnel port information. For clients that cannot be connected directly, I believe obtaining information from a discovery service will be more convenient for future maintenance. Of course, this can also be achieved by modifying the code ourselves.Yes

flub commented 3 months ago

What is the aim of not having a home relay? If you do not tell anyone that you can be reached by that relay the routing behaviour of it is the same as it would be for an other relay server you are connected to.

If you do not want to accept connections on the node then don't call Endpoint::accept. At least if you're using iroh-net directly, if using a full iroh::Node I'm not sure how that would work yet.

zh522130 commented 3 months ago

You have a node which you do not want to have a home relay, so use RelayMode::Disabled. This node uses discovery to discover the RelayUrl of other nodes it wants to connect to. This connection works over the relay server but does not manage to holepunch. Is that correct?

Sorry, my previous explanation wasn't very clear. Let me clarify:

  1. The client cannot be connected by other nodes, so it should not publish its own information.
  2. Since it cannot publish information, there is no need to send relay information either, as the relay information of peer nodes can be obtained from the discovery service.
  3. Currently, the peer node information obtained only allows the client node to communicate with it through a relay, but it cannot be used for hole punching.
  4. If it is possible to use the obtained information for hole punching, any future changes in the relay would only require changes on the server side.

I hope this makes my requirements clearer.

zh522130 commented 3 months ago

If you do not want to accept connections on the node then don't call Endpoint::accept. At least if you're using iroh-net directly, if using a full iroh::Node I'm not sure how that would work yet.

Yes, I am currently not calling Endpoint::accept in the client.

For me, The biggest advantage for me is that when I update the relay configuration, I only need to update the server.

zh522130 commented 3 months ago

(2) is a sort of feature requestion. I see how it would possibly be desirable to have a system that doesn't depend on a possibly hard-coded relay map. One could think of a relay map directory that is fetched initially and populates the relay map on startup. I suggest experimenting with something like that in the application level first.

Yes, if this does not conform to the iroh-net specifications, I will have to implement it myself, as this is just my personal requirement for now.