Skip to content
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

Ping protocol closes connection if other party doesn't support /ping #2109

Closed
thomaseizinger opened this issue Jun 24, 2021 · 7 comments · Fixed by #2149
Closed

Ping protocol closes connection if other party doesn't support /ping #2109

thomaseizinger opened this issue Jun 24, 2021 · 7 comments · Fixed by #2149

Comments

@thomaseizinger
Copy link
Contributor

thomaseizinger commented Jun 24, 2021

Issue as per title. Is this intentional? I would have expected a more graceful behaviour where the implementation just ignores a particular connection if the other party doesn't support /ping. In particular, I am talking about ProtocolsHandlerUpgrErr::Upgrade(UpgradeError::Select(NegotiationError::Failed)).

If this shouldn't be the default behaviour (IMO it should be), would you accept a PR with a config option that at least makes this configurable? Something like no_close_on_unsupported?

@mxinden
Copy link
Member

mxinden commented Jun 24, 2021

Is this intentional?

I don't know whether this was intentional when first implemented. Either way say a user depends on libp2p-ping to close idle connections. Connections to a node that does not support libp2p-ping would never close when idle without this feature.

no_close_on_UNsupported

Adding this to PingConfig is fine by me. Off the top of my head, with the above in mind, I don't think we should make it the default behavior. Do you feel strongly about this @thomaseizinger?

Out of curiosity, what is your reasoning for not running ping on one of your nodes?

@thomaseizinger
Copy link
Contributor Author

no_close_on_UNsupported

Typo corrected, thanks!

I don't know whether this was intentional when first implemented. Either way say a user depends on libp2p-ping to close idle connections. Connections to a node that does not support libp2p-ping would never close when idle without this feature.

I think there is a difference between how we implement connection_keep_alive based on the idle state of the connection and actively closing the connection because we run into an error.

I am suggesting to not make the handler of /ping do anything if it detects that the other party doesn't support /ping.
We can still have the handler close idle connections by returning KeepAlive::No.

Out of curiosity, what is your reasoning for not running ping on one of your nodes?

I ran into this when writing the examples of rendezvous. I was trying to build the following setup:

  • Party A with /ping and /rendezvous, discovers services via rendezvous point
  • rendezvous-point with /rendezvous and /identify
  • Party B with /ping, /rendezvous and /identify, registers itself on startup based on observed external address from rendezvous point

The idea was for /ping to represent the protocol that party A and B would like to speak and they use the rendezvous-point to find each other. However, if you compose the behaviours like this, the rendezvous node always actively force-closes the connection to either node - disallowing the /rendezvous protocol to do its job - because it runs into the negotiation error with the /ping protocol.

@mxinden
Copy link
Member

mxinden commented Jun 28, 2021

I don't know whether this was intentional when first implemented. Either way say a user depends on libp2p-ping to close idle connections. Connections to a node that does not support libp2p-ping would never close when idle without this feature.

I think there is a difference between how we implement connection_keep_alive based on the idle state of the connection and actively closing the connection because we run into an error.

I am suggesting to not make the handler of /ping do anything if it detects that the other party doesn't support /ping.
We can still have the handler close idle connections by returning KeepAlive::No.

Mistake on my end. I should have written dead instead of idle connections. There might be situations where users depend on libp2p-ping to close dead connections while one of their other protocols always returns KeepAlive::Yes. Say libp2p-ping does not close connections to peers that don't support the Ping protocol. An attacker could try to DOS a node by opening up a lot of connections, not supporting the Ping protocol, killing them on their side only, using up memory on the victims side.

The above is only problematic if another protocol always returns KeepAlive::Yes. I think that is problematic in itself.

Long story short: I am fine with either way, not closing connections when Ping is unsupported by default or as an option. Only requirement would be for this to be well documented.

@thomaseizinger
Copy link
Contributor Author

Right, that makes sense. I wonder what a sane default is then. If we end up landing #2110 then we could change the protocol to emit an event instead (i.e. PingUnsupported) and let the application decide what to do. Some applications might want to close the connection as a result whereas others (my examples) wouldn't care too much.

On the other hand, it is less convenient if everyone has to write that line of code themselves.

I have to say, I am tempted to emit an event here and not make a decision on what should happen with dead connections. I think that ideal behaviour will depend on the overall usecase of the application and emitting an event allows us to keep the config of Ping simple.

@mxinden
Copy link
Member

mxinden commented Jun 30, 2021

An additional PingFailure variant, e.g. ProtocolUnsupported, leaving it up to the user what to do, sounds good to me.

@thomaseizinger
Copy link
Contributor Author

An additional PingFailure variant, e.g. ProtocolUnsupported, leaving it up to the user what to do, sounds good to me.

Copy that.

To reiterate:

  • Remove behaviour of closing connections on unsupported protocol
  • Emit an event to let the swarm / parent behaviour know about it

da-kami added a commit to comit-network/rendezvous-server that referenced this issue Jul 1, 2021
Unfortunately we have to compose Ping into the mox until libp2p/rust-libp2p#2109 is fixed.
The ping interval is set to a very large value (roughly 100 years), so we don't spam nodes from the rendezvous node, but react to incoming pings.
I opted to not print the ping events because they spam the logs.
@mxinden
Copy link
Member

mxinden commented Jul 1, 2021

Sounds good to me @thomaseizinger! Plus a changelog entry please :)

rishflab pushed a commit to comit-network/rendezvous-server that referenced this issue Jul 2, 2021
Unfortunately we have to compose Ping into the mox until libp2p/rust-libp2p#2109 is fixed.
The ping interval is set to a very large value (roughly 100 years), so we don't spam nodes from the rendezvous node, but react to incoming pings.
I opted to not print the ping events because they spam the logs.
thomaseizinger added a commit to thomaseizinger/rust-libp2p that referenced this issue Jul 20, 2021
thomaseizinger added a commit to thomaseizinger/rust-libp2p that referenced this issue Jul 20, 2021
thomaseizinger added a commit to thomaseizinger/rust-libp2p that referenced this issue Jul 20, 2021
thomaseizinger added a commit to thomaseizinger/rust-libp2p that referenced this issue Jul 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants