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

feat(transport): Implement dial_with_new_port to prevent port reuse #3910

Closed
wants to merge 1 commit into from

Conversation

b-zee
Copy link
Contributor

@b-zee b-zee commented May 11, 2023

This is useful in case of AutoNAT, whereby we do not want to reuse the same port when probing.

A new dial_with_new_port is added, that TCP and QUIC can use to create a new source socket (port). This is called when DialOpts has the option enabled to use a new port, which can be used by AutoNAT.

Description

This is a draft to see what options there are to implement a fix for both #3889 and #3900. Please bear with me as I try to figure out the right way to maneuver the APIs and concepts here.

The AutoNAT client uses request_response to send a request, so that has to have an option added for using a new port too. For the AutoNAT server, I observed that secondary probes will still cause a dial to error with AddrNotAvailable if not using the new with_new_port. For this reason the AutoNAT server also has to create a new socket (TCP). However, this is probably because I am not getting rid of the sockets after AutoNAT is done. I am not sure how to do that.

For TCP the 'fix' is to ignore port reuse if enabled. And for QUIC we should create a new dialer. What I am trying to understand is how these sockets/dialers are handled and can be managed properly.

Notes & open questions

Change checklist

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • A changelog entry has been made in the appropriate crates

@b-zee b-zee changed the title Implement dial_with_new_port to prevent port reuse feat(transport): Implement dial_with_new_port to prevent port reuse May 11, 2023
This is useful in case of AutoNAT, whereby we do not want to reuse the
same port when probing.
@b-zee b-zee force-pushed the feat/dial-with-new-port branch from 217ae9e to 2b2f5f5 Compare May 11, 2023 08:11
Copy link
Contributor

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for getting started on this! I've left an initial thought.

@@ -396,6 +396,33 @@ where
request_id
}

/// TODO: Document
pub fn send_request_with_new_port(
Copy link
Contributor

@thomaseizinger thomaseizinger May 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't really work unfortunately. libp2p-request-response hides the idea of connections and streams from the user. At the moment, there is no guarantee that a certain messages is actually going to be sent over a specific connection.

I think to effectively utilize this API in AutoNAT, we will have to rewrite it to not use libp2p-request-response.

The flow would something like:

  • Issue a new ToSwarm::Dial that uses the new_port option
  • Grab the (future) ConnectionId from DialOpts
  • Remember it in the behaviour, together with the request that we want to send on that connection
  • Wait for handle_established_outbound_connection with this new ConnectionId
  • Initialize the handler with that connection

This is quite specific to AutoNAT and I am not sure we should extend libp2p-request-response to be able to do this. We could make libp2p-request-response do such kind of things as well. But, I think it is a bad fit for the abstraction because it gets too leaky. To me, libp2p-request-response is all about providing convenience when you just want to declare a message type and send it back and forth between two peers. If we don't hide certain details about the internals of libp2p with it, then the complexity for the user doesn't actually go away.

Another thing that bothers me is that we expose functions such as add_address. Those should go away in my opinion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite specific to AutoNAT and I am not sure we should extend libp2p-request-response to be able to do this.

Agreed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that even with rewriting it, the issue of "don't run other protocols over that connection" is not solved although I am not entirely convinced it is actually a problem.

Comment on lines +138 to +143
fn dial_with_new_port(
&mut self,
_addr: Multiaddr,
) -> Result<Self::Dial, TransportError<Self::Error>> {
unimplemented!()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of this API at all but I also don't have a better idea in the short-term. Long-term, I'd like to get rid of the Dial associated type (see #3436).

@b-zee
Copy link
Contributor Author

b-zee commented Jul 21, 2023

Closing this PR in anticipation of a more thought out perspective in #4226

@b-zee b-zee closed this Jul 21, 2023
@b-zee b-zee deleted the feat/dial-with-new-port branch July 21, 2023 07:32
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 this pull request may close these issues.

3 participants