feat(network): Configurable external address for Version network messages (#8488)
* add configurable external address for Version network messages * apply suggestions from code review Co-authored-by: Arya <aryasolhi@gmail.com> --------- Co-authored-by: Arya <aryasolhi@gmail.com>
This commit is contained in:
parent
8a786fe6ce
commit
239fcc85ba
|
@ -72,6 +72,14 @@ pub struct Config {
|
|||
/// their address books.
|
||||
pub listen_addr: SocketAddr,
|
||||
|
||||
/// The external address of this node if any.
|
||||
///
|
||||
/// Zebra bind to `listen_addr` but this can be an internal address if the node
|
||||
/// is behind a firewall, load balancer or NAT. This field can be used to
|
||||
/// advertise a different address to peers making it possible to receive inbound
|
||||
/// connections and contribute to the P2P network from behind a firewall, load balancer, or NAT.
|
||||
pub external_addr: Option<SocketAddr>,
|
||||
|
||||
/// The network to connect to.
|
||||
pub network: Network,
|
||||
|
||||
|
@ -601,6 +609,7 @@ impl Default for Config {
|
|||
listen_addr: "0.0.0.0:8233"
|
||||
.parse()
|
||||
.expect("Hardcoded address should be parseable"),
|
||||
external_addr: None,
|
||||
network: Network::Mainnet,
|
||||
initial_mainnet_peers: mainnet_peers,
|
||||
initial_testnet_peers: testnet_peers,
|
||||
|
@ -635,6 +644,7 @@ impl<'de> Deserialize<'de> for Config {
|
|||
#[serde(deny_unknown_fields, default)]
|
||||
struct DConfig {
|
||||
listen_addr: String,
|
||||
external_addr: Option<String>,
|
||||
network: NetworkKind,
|
||||
testnet_parameters: Option<DTestnetParameters>,
|
||||
initial_mainnet_peers: IndexSet<String>,
|
||||
|
@ -651,6 +661,7 @@ impl<'de> Deserialize<'de> for Config {
|
|||
let config = Config::default();
|
||||
Self {
|
||||
listen_addr: "0.0.0.0".to_string(),
|
||||
external_addr: None,
|
||||
network: Default::default(),
|
||||
testnet_parameters: None,
|
||||
initial_mainnet_peers: config.initial_mainnet_peers,
|
||||
|
@ -665,6 +676,7 @@ impl<'de> Deserialize<'de> for Config {
|
|||
|
||||
let DConfig {
|
||||
listen_addr,
|
||||
external_addr,
|
||||
network: network_kind,
|
||||
testnet_parameters,
|
||||
initial_mainnet_peers,
|
||||
|
@ -737,6 +749,20 @@ impl<'de> Deserialize<'de> for Config {
|
|||
},
|
||||
}?;
|
||||
|
||||
let external_socket_addr = if let Some(address) = &external_addr {
|
||||
match address.parse::<SocketAddr>() {
|
||||
Ok(socket) => Ok(Some(socket)),
|
||||
Err(_) => match address.parse::<IpAddr>() {
|
||||
Ok(ip) => Ok(Some(SocketAddr::new(ip, network.default_port()))),
|
||||
Err(err) => Err(de::Error::custom(format!(
|
||||
"{err}; Hint: addresses can be a IPv4, IPv6 (with brackets), or a DNS name, the port is optional"
|
||||
))),
|
||||
},
|
||||
}?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let [max_connections_per_ip, peerset_initial_target_size] = [
|
||||
("max_connections_per_ip", max_connections_per_ip, DEFAULT_MAX_CONNS_PER_IP),
|
||||
// If we want Zebra to operate with no network,
|
||||
|
@ -756,6 +782,7 @@ impl<'de> Deserialize<'de> for Config {
|
|||
|
||||
Ok(Config {
|
||||
listen_addr: canonical_socket_addr(listen_addr),
|
||||
external_addr: external_socket_addr,
|
||||
network,
|
||||
initial_mainnet_peers,
|
||||
initial_testnet_peers,
|
||||
|
|
|
@ -654,7 +654,17 @@ where
|
|||
let their_addr = connected_addr
|
||||
.get_transient_addr()
|
||||
.expect("non-Isolated connections have a remote addr");
|
||||
(their_addr, our_services, config.listen_addr)
|
||||
|
||||
// Include the configured external address in our version message, if any, otherwise, include our listen address.
|
||||
let advertise_addr = match config.external_addr {
|
||||
Some(external_addr) => {
|
||||
info!(?their_addr, ?config.listen_addr, "using external address for Version messages");
|
||||
external_addr
|
||||
}
|
||||
None => config.listen_addr,
|
||||
};
|
||||
|
||||
(their_addr, our_services, advertise_addr)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -184,7 +184,8 @@ use common::{
|
|||
check::{is_zebrad_version, EphemeralCheck, EphemeralConfig},
|
||||
config::random_known_rpc_port_config,
|
||||
config::{
|
||||
config_file_full_path, configs_dir, default_test_config, persistent_test_config, testdir,
|
||||
config_file_full_path, configs_dir, default_test_config, external_address_test_config,
|
||||
persistent_test_config, testdir,
|
||||
},
|
||||
launch::{
|
||||
spawn_zebrad_for_rpc, spawn_zebrad_without_rpc, ZebradTestDirExt, BETWEEN_NODES_DELAY,
|
||||
|
@ -3128,6 +3129,33 @@ async fn validate_regtest_genesis_block() {
|
|||
)
|
||||
}
|
||||
|
||||
/// Test that Version messages are sent with the external address when configured to do so.
|
||||
#[test]
|
||||
fn external_address() -> Result<()> {
|
||||
let _init_guard = zebra_test::init();
|
||||
let testdir = testdir()?.with_config(&mut external_address_test_config(&Mainnet)?)?;
|
||||
let mut child = testdir.spawn_child(args!["start"])?;
|
||||
|
||||
// Give enough time to start connecting to some peers.
|
||||
std::thread::sleep(Duration::from_secs(10));
|
||||
|
||||
child.kill(false)?;
|
||||
|
||||
let output = child.wait_with_output()?;
|
||||
let output = output.assert_failure()?;
|
||||
|
||||
// Zebra started
|
||||
output.stdout_line_contains("Starting zebrad")?;
|
||||
|
||||
// Make sure we are using external address for Version messages.
|
||||
output.stdout_line_contains("using external address for Version messages")?;
|
||||
|
||||
// Make sure the command was killed.
|
||||
output.assert_was_killed()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test successful `getblocktemplate` and `submitblock` RPC calls on Regtest on Canopy.
|
||||
///
|
||||
/// See [`common::regtest::submit_blocks`] for more information.
|
||||
|
|
|
@ -119,6 +119,12 @@ pub fn persistent_test_config(network: &Network) -> Result<ZebradConfig> {
|
|||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn external_address_test_config(network: &Network) -> Result<ZebradConfig> {
|
||||
let mut config = default_test_config(network)?;
|
||||
config.network.external_addr = Some("127.0.0.1:0".parse()?);
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn testdir() -> Result<TempDir> {
|
||||
tempfile::Builder::new()
|
||||
.prefix("zebrad_tests")
|
||||
|
|
Loading…
Reference in New Issue