Skip to content

Conversation

lexnv
Copy link
Collaborator

@lexnv lexnv commented Jul 8, 2025

This PR exposes an option to forbid or allow dialing private IP addresses.

For test networks started locally, it is recommended to use private IP addresses to establish connections.

However, for running production validators, the validator node should never attempt to dial a private IP address.
This behavior can be detected by some cloud providers as port scanning. The downstream effect of that depends on the cloud provider, but most likely, the node will become unreachable or the instance will be terminated.

Before this PR, litep2p might receive a local (private) IP address on either the Kademlia or the Identify protocol from a libp2p node. Now, the transport manager will not forward the dialing request to the installed protocols if the private IP option is disabled.

This may be the case of paritytech/polkadot-sdk#8915, where a node operator running a validator using litep2p on the Polkadot network loses connectivity after a few days.

Closes: paritytech/polkadot-sdk#8631

Next Steps

  • Wait for further information to be provided by the node operator
  • Ensure the PR is properly tested locally, in versi-net and on kusama validators

@lexnv lexnv self-assigned this Jul 8, 2025
@dmitry-markin
Copy link
Collaborator

One consequence might be that mDNS won't work with IpDialingMode::GlobalOnly, because multicast addresses are not considered global.

Actually, this brings us back to the discussion of Kademlia manual routing table update mode — ideally, private IPs should not be added to the local routing table (and distributed further) in the first place, and this can be done completely in client code (polkadot-sdk) like it's done with libp2p backend. Just one thing to consider is we should also ensure we don't add private addresses to the transport manager. This way we will "fail early" and not even try to dial such peers.

@dmitry-markin
Copy link
Collaborator

One consequence might be that mDNS won't work with IpDialingMode::GlobalOnly, because multicast addresses are not considered global.

This is not the case luckily — mDNS directly uses UDP sockets instead of relying on TransportManager:

let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;

keep_alive_timeout: Duration,

/// True if litep2p should attempt to dial local addresses.
use_private_ip: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
use_private_ip: bool,
dial_global_ips_only: bool,

?

private_ip != !global_ip

Comment on lines +217 to +218
Some(Protocol::Dns(_)) | Some(Protocol::Dns4(_)) | Some(Protocol::Dns6(_)) =>
return true,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will leak addresses like /dns4/10.10.10.10/tcp/30333/..., and also dns records can point to local IP addresses.

Comment on lines 263 to 268
/// Similar to [`Self::addresses`], but returns an iterator over the addresses.
pub fn addresses_iter(&self) -> impl Iterator<Item = &Multiaddr> {
let mut records = self.addresses.values().collect::<Vec<_>>();
records.sort_by(|lhs, rhs| rhs.score.cmp(&lhs.score));
records.into_iter().map(|record| &record.address)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Returning an iterator after allocating a vector "hides" the cost of calling this function. IMO having addresses() should be enough.

Comment on lines +291 to +294
let has_dialable_address = address_store
.addresses
.iter()
.any(|(address, _record)| self.ip_dialing_mode.allows_address(address));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Currently we check if the address is global two times — in TransportManagerHandle, and later in TransportManager. May be it's enough to keep the check only in one place?

@la10736
Copy link

la10736 commented Sep 24, 2025

What about this PR? This issue is still present on polkadot nodes.

@lexnv
Copy link
Collaborator Author

lexnv commented Oct 1, 2025

Hey @la10736, we reprioritized the efforts towards a high-priority objective. I'll handle this in the following few weeks as this is still important 🙏

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.

Kusama node sends P2P requests to RFC1918 (10/8) networks despite --no-private-ip and --no-mdns args

3 participants