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

protocols/autonat: optionally use only global IPs #2618

Merged
merged 21 commits into from
May 22, 2022

Conversation

elenaf9
Copy link
Contributor

@elenaf9 elenaf9 commented Apr 17, 2022

Description

Optionally only perform dial-backs on peers that are observed at a global ip-address.
This is relevant when multiple peers are in the same local network, in which case a peer could incorrectly assume themself to be public because a peer in the same local network was able to dial them. Thus servers should reject dial-back requests from clients with a non-global IP address, and at the same time clients should only pick connected peers as servers if they are global.
Behind a config flag (enabled by default) to also allow use-cases where AutoNAT is needed within a private network.
Continuation/ alternative to #2526 (cc @hamamo). Opened as a draft for now because of the open questions below.

Links to any relevant issues

Fixes #2514.

Open Questions

The is_global check for Ipv4 and Ipv6 addresses currently implements the same logic as std::net::Ipv4Addr::is_global, std::net::Ipv6Addr::is_global, which are at the time of writing unstable behind the ip flag.
(See rust-lang/rust#27709 and rust-lang/rust#85604.)

For Ipv4 most of the internally called methods are stable, apart from the checks for is_shared, is_reserved and is_benchmarking. Could we just remove those checks? In case of is_shared the peer is still eligible for a dial-back and the other two cases should never occur in practice, no? In general, would it be enough to just check for is_private, is_loopback and is_link_local? I am not sure, but since we only use this check for observed addresses, can any of the other cases even happen?

For Ipv6 there is still some ongoing discussion around the is_global check, because is currently checks for the (global) scope of the address rather than global reachability (See rust-lang/rust#86634 and rust-lang/rust#85604). There are ongoing efforts to fix this (and eventually stabilize all ip methods), but they seem to be inactive since last year. Is this something that we could / should help push to completion?

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

Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

This looks good to me overall. Just two comments:

protocols/autonat/src/behaviour.rs Outdated Show resolved Hide resolved
protocols/autonat/src/behaviour.rs Outdated Show resolved Hide resolved
@elenaf9 elenaf9 marked this pull request as ready for review May 8, 2022 18:51
let status_text = "no dial-request over relayed connections".to_string();
(status_text, ResponseError::DialError)
let status_text = "refusing to dial peer with blocked observed address".to_string();
(status_text, ResponseError::DialRefused)
Copy link
Contributor Author

@elenaf9 elenaf9 May 8, 2022

Choose a reason for hiding this comment

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

Note: the go implementation returns a ResponseError::DialError here (but with the same status text). I decided to change it here because imo a DialRefused makes more sense. A client should not flip their status to private or reduce the confidence in their public status just because they accidentally picked a server that rejects them because of the observed address (though if the client also enabled only_global_ips this should not happen in practice).
Edit: should it be part of the spec to list the cases in which a server returns DialError?

Copy link
Member

Choose a reason for hiding this comment

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

Edit: should it be part of the spec to list the cases in which a server returns DialError?

Yes. I think this is worth consolidating on. Mind driving it on libp2p/specs?

Copy link
Contributor Author

@elenaf9 elenaf9 May 10, 2022

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also added 7035422, which does the same change for the case that filter_valid_addrs filters out all addresses send from the client.

protocols/autonat/CHANGELOG.md Outdated Show resolved Hide resolved
let status_text = "no dial-request over relayed connections".to_string();
(status_text, ResponseError::DialError)
let status_text = "refusing to dial peer with blocked observed address".to_string();
(status_text, ResponseError::DialRefused)
Copy link
Member

Choose a reason for hiding this comment

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

Edit: should it be part of the spec to list the cases in which a server returns DialError?

Yes. I think this is worth consolidating on. Mind driving it on libp2p/specs?

Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

This is good to go from my end. Just a small nit above.

elenaf9 and others added 5 commits May 10, 2022 22:12
We only add an observed addresses for a peer to Behaviour.connected
if the address is not relayed. Hence there is no need to check the
address again in `filter_valid_addrs`.
Copy link
Member

@mxinden mxinden left a comment

Choose a reason for hiding this comment

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

Latest changes look good to me. Feel free to merge once ready.

@elenaf9 elenaf9 merged commit ef2afcd into libp2p:master May 22, 2022
@elenaf9 elenaf9 deleted the autonat/config-global-ips branch May 22, 2022 20:04
@elenaf9 elenaf9 mentioned this pull request Jan 6, 2023
4 tasks
mergify bot pushed a commit that referenced this pull request Jan 10, 2023
Fix AutoNAT examples that became outdated due to #2959 and #2618.
umgefahren pushed a commit to umgefahren/rust-libp2p that referenced this pull request Mar 8, 2024
Optionally only perform dial-backs on peers that are observed at a global ip-address.
This is relevant when multiple peers are in the same local network, in which case a peer could incorrectly assume themself to be public because a peer in the same local network was able to dial them. Thus servers should reject dial-back requests from clients with a non-global IP address, and at the same time clients should only pick connected peers as servers if they are global.
Behind a config flag (enabled by default) to also allow use-cases where AutoNAT is needed within a private network.
umgefahren pushed a commit to umgefahren/rust-libp2p that referenced this pull request Mar 8, 2024
Fix AutoNAT examples that became outdated due to libp2p#2959 and libp2p#2618.
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.

AutoNAT: how to handle non-global IP addresses?
3 participants