network keying

This commit is contained in:
John Smith 2023-06-23 21:12:48 -04:00
parent bc6421acf7
commit acebcb7947
14 changed files with 119 additions and 21 deletions

View File

@ -49,6 +49,7 @@ core:
client_whitelist_timeout_ms: 300000 client_whitelist_timeout_ms: 300000
reverse_connection_receipt_time_ms: 5000 reverse_connection_receipt_time_ms: 5000
hole_punch_receipt_time_ms: 5000 hole_punch_receipt_time_ms: 5000
network_key_password: null
routing_table: routing_table:
node_id: null node_id: null
node_id_secret: null node_id_secret: null

View File

@ -188,8 +188,9 @@ network:
client_whitelist_timeout_ms: 300000 client_whitelist_timeout_ms: 300000
reverse_connection_receipt_time_ms: 5000 reverse_connection_receipt_time_ms: 5000
hole_punch_receipt_time_ms: 5000 hole_punch_receipt_time_ms: 5000
node_id: '' network_key_password: null
node_id_secret: '' node_id: null
node_id_secret: null
bootstrap: ['bootstrap.veilid.net'] bootstrap: ['bootstrap.veilid.net']
upnp: true upnp: true
detect_address_changes: true detect_address_changes: true

View File

@ -160,6 +160,8 @@ struct NetworkManagerUnlockedInner {
// Background processes // Background processes
rolling_transfers_task: TickTask<EyreReport>, rolling_transfers_task: TickTask<EyreReport>,
public_address_check_task: TickTask<EyreReport>, public_address_check_task: TickTask<EyreReport>,
// Network Key
network_key: Option<SharedSecret>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -185,6 +187,7 @@ impl NetworkManager {
#[cfg(feature="unstable-blockstore")] #[cfg(feature="unstable-blockstore")]
block_store: BlockStore, block_store: BlockStore,
crypto: Crypto, crypto: Crypto,
network_key: Option<SharedSecret>,
) -> NetworkManagerUnlockedInner { ) -> NetworkManagerUnlockedInner {
NetworkManagerUnlockedInner { NetworkManagerUnlockedInner {
config, config,
@ -199,6 +202,7 @@ impl NetworkManager {
update_callback: RwLock::new(None), update_callback: RwLock::new(None),
rolling_transfers_task: TickTask::new(ROLLING_TRANSFERS_INTERVAL_SECS), rolling_transfers_task: TickTask::new(ROLLING_TRANSFERS_INTERVAL_SECS),
public_address_check_task: TickTask::new(PUBLIC_ADDRESS_CHECK_TASK_INTERVAL_SECS), public_address_check_task: TickTask::new(PUBLIC_ADDRESS_CHECK_TASK_INTERVAL_SECS),
network_key,
} }
} }
@ -211,6 +215,34 @@ impl NetworkManager {
block_store: BlockStore, block_store: BlockStore,
crypto: Crypto, crypto: Crypto,
) -> Self { ) -> Self {
// Make the network key
let network_key = {
let c = config.get();
let network_key_password = if let Some(nkp) = c.network.network_key_password.clone() {
Some(nkp)
} else {
if c.network.routing_table.bootstrap.contains(&"bootstrap.veilid.net".to_owned()) {
None
} else {
Some(c.network.routing_table.bootstrap.join(","))
}
};
let network_key = if let Some(network_key_password) = network_key_password {
info!("Using network key");
let bcs = crypto.best();
// Yes the use of the salt this way is generally bad, but this just needs to be hashed
Some(bcs.derive_shared_secret(network_key_password.as_bytes(), network_key_password.as_bytes()).expect("failed to derive network key"))
} else {
None
};
network_key
};
let this = Self { let this = Self {
inner: Arc::new(Mutex::new(Self::new_inner())), inner: Arc::new(Mutex::new(Self::new_inner())),
unlocked_inner: Arc::new(Self::new_unlocked_inner( unlocked_inner: Arc::new(Self::new_unlocked_inner(
@ -221,6 +253,7 @@ impl NetworkManager {
#[cfg(feature="unstable-blockstore")] #[cfg(feature="unstable-blockstore")]
block_store, block_store,
crypto, crypto,
network_key,
)), )),
}; };
@ -819,7 +852,10 @@ impl NetworkManager {
}; };
// Build the envelope to send // Build the envelope to send
let out = self.build_envelope(best_node_id, envelope_version, body)?; let mut out = self.build_envelope(best_node_id, envelope_version, body)?;
// Apply network key
self.apply_network_key(&mut out);
// Send the envelope via whatever means necessary // Send the envelope via whatever means necessary
self.send_data(node_ref, out).await self.send_data(node_ref, out).await
@ -830,7 +866,7 @@ impl NetworkManager {
pub async fn send_out_of_band_receipt( pub async fn send_out_of_band_receipt(
&self, &self,
dial_info: DialInfo, dial_info: DialInfo,
rcpt_data: Vec<u8>, mut rcpt_data: Vec<u8>,
) -> EyreResult<()> { ) -> EyreResult<()> {
// Do we need to validate the outgoing receipt? Probably not // Do we need to validate the outgoing receipt? Probably not
// because it is supposed to be opaque and the // because it is supposed to be opaque and the
@ -838,6 +874,9 @@ impl NetworkManager {
// Also, in the case of an old 'version', returning the receipt // Also, in the case of an old 'version', returning the receipt
// should not be subject to our ability to decode it // should not be subject to our ability to decode it
// Apply network key
self.apply_network_key(&mut rcpt_data);
// Send receipt directly // Send receipt directly
log_net!(debug "send_out_of_band_receipt: dial_info={}", dial_info); log_net!(debug "send_out_of_band_receipt: dial_info={}", dial_info);
network_result_value_or_log!(self network_result_value_or_log!(self
@ -1081,7 +1120,7 @@ impl NetworkManager {
// If the node has had lost questions or failures to send, prefer sequencing // If the node has had lost questions or failures to send, prefer sequencing
// to improve reliability. The node may be experiencing UDP fragmentation drops // to improve reliability. The node may be experiencing UDP fragmentation drops
// or other firewalling issues and may perform better with TCP. // or other firewalling issues and may perform better with TCP.
let unreliable = target_node_ref.peer_stats().rpc_stats.failed_to_send > 0 || target_node_ref.peer_stats().rpc_stats.recent_lost_answers > 0; let unreliable = target_node_ref.peer_stats().rpc_stats.failed_to_send > 2 || target_node_ref.peer_stats().rpc_stats.recent_lost_answers > 2;
if unreliable && sequencing < Sequencing::PreferOrdered { if unreliable && sequencing < Sequencing::PreferOrdered {
sequencing = Sequencing::PreferOrdered; sequencing = Sequencing::PreferOrdered;
} }
@ -1258,7 +1297,9 @@ impl NetworkManager {
.iter() .iter()
.filter_map(|nr| nr.make_peer_info(RoutingDomain::PublicInternet)) .filter_map(|nr| nr.make_peer_info(RoutingDomain::PublicInternet))
.collect(); .collect();
let json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec(); let mut json_bytes = serialize_json(bootstrap_peerinfo).as_bytes().to_vec();
self.apply_network_key(&mut json_bytes);
// Reply with a chunk of signed routing table // Reply with a chunk of signed routing table
match self match self
@ -1281,8 +1322,12 @@ impl NetworkManager {
pub async fn boot_request(&self, dial_info: DialInfo) -> EyreResult<Vec<PeerInfo>> { pub async fn boot_request(&self, dial_info: DialInfo) -> EyreResult<Vec<PeerInfo>> {
let timeout_ms = self.with_config(|c| c.network.rpc.timeout_ms); let timeout_ms = self.with_config(|c| c.network.rpc.timeout_ms);
// Send boot magic to requested peer address // Send boot magic to requested peer address
let data = BOOT_MAGIC.to_vec(); let mut data = BOOT_MAGIC.to_vec();
let out_data: Vec<u8> = network_result_value_or_log!(self
// Apply network key
self.apply_network_key(&mut data);
let mut out_data: Vec<u8> = network_result_value_or_log!(self
.net() .net()
.send_recv_data_unbound_to_dial_info(dial_info, data, timeout_ms) .send_recv_data_unbound_to_dial_info(dial_info, data, timeout_ms)
.await? => .await? =>
@ -1290,6 +1335,9 @@ impl NetworkManager {
return Ok(Vec::new()); return Ok(Vec::new());
}); });
// Apply network key
self.apply_network_key(&mut out_data);
let bootstrap_peerinfo: Vec<PeerInfo> = let bootstrap_peerinfo: Vec<PeerInfo> =
deserialize_json(std::str::from_utf8(&out_data).wrap_err("bad utf8 in boot peerinfo")?) deserialize_json(std::str::from_utf8(&out_data).wrap_err("bad utf8 in boot peerinfo")?)
.wrap_err("failed to deserialize boot peerinfo")?; .wrap_err("failed to deserialize boot peerinfo")?;
@ -1297,13 +1345,28 @@ impl NetworkManager {
Ok(bootstrap_peerinfo) Ok(bootstrap_peerinfo)
} }
// Network isolation encryption
fn apply_network_key(&self, data: &mut [u8]) {
if let Some(network_key) = self.unlocked_inner.network_key {
let bcs = self.crypto().best();
// Nonce abuse, but this is not supposed to be cryptographically sound
// it's just here to keep networks from accidentally bridging.
// A proper nonce would increase the data length here and change the packet sizes on the wire
bcs.crypt_in_place_no_auth(
data,
&network_key.bytes[0..NONCE_LENGTH].try_into().unwrap(),
&network_key,
)
}
}
// Called when a packet potentially containing an RPC envelope is received by a low-level // Called when a packet potentially containing an RPC envelope is received by a low-level
// network protocol handler. Processes the envelope, authenticates and decrypts the RPC message // network protocol handler. Processes the envelope, authenticates and decrypts the RPC message
// and passes it to the RPC handler // and passes it to the RPC handler
#[instrument(level = "trace", ret, err, skip(self, data), fields(data.len = data.len()))] #[instrument(level = "trace", ret, err, skip(self, data), fields(data.len = data.len()))]
async fn on_recv_envelope( async fn on_recv_envelope(
&self, &self,
data: &[u8], mut data: &mut [u8],
connection_descriptor: ConnectionDescriptor, connection_descriptor: ConnectionDescriptor,
) -> EyreResult<bool> { ) -> EyreResult<bool> {
let root = span!( let root = span!(
@ -1352,6 +1415,9 @@ impl NetworkManager {
} }
}; };
// Apply network key
self.apply_network_key(&mut data);
// Is this a direct bootstrap request instead of an envelope? // Is this a direct bootstrap request instead of an envelope?
if data[0..4] == *BOOT_MAGIC { if data[0..4] == *BOOT_MAGIC {
network_result_value_or_log!(self.handle_boot_request(connection_descriptor).await? => {}); network_result_value_or_log!(self.handle_boot_request(connection_descriptor).await? => {});
@ -1445,6 +1511,10 @@ impl NetworkManager {
if let Some(relay_nr) = some_relay_nr { if let Some(relay_nr) = some_relay_nr {
// Relay the packet to the desired destination // Relay the packet to the desired destination
log_net!("relaying {} bytes to {}", data.len(), relay_nr); log_net!("relaying {} bytes to {}", data.len(), relay_nr);
// Apply network key
self.apply_network_key(&mut data);
network_result_value_or_log!(match self.send_data(relay_nr, data.to_vec()) network_result_value_or_log!(match self.send_data(relay_nr, data.to_vec())
.await { .await {
Ok(v) => v, Ok(v) => v,

View File

@ -67,7 +67,6 @@ impl Network {
{ {
Ok(Ok((size, descriptor))) => { Ok(Ok((size, descriptor))) => {
// XXX: Limit the number of packets from the same IP address? // XXX: Limit the number of packets from the same IP address?
log_net!("UDP packet: {:?}", descriptor);
// Network accounting // Network accounting
network_manager.stats_packet_rcvd( network_manager.stats_packet_rcvd(
@ -77,7 +76,7 @@ impl Network {
// Pass it up for processing // Pass it up for processing
if let Err(e) = network_manager if let Err(e) = network_manager
.on_recv_envelope(&data[..size], descriptor) .on_recv_envelope(&mut data[..size], descriptor)
.await .await
{ {
log_net!(debug "failed to process received udp envelope: {}", e); log_net!(debug "failed to process received udp envelope: {}", e);

View File

@ -301,13 +301,13 @@ impl NetworkConnection {
match res { match res {
Ok(v) => { Ok(v) => {
let message = network_result_value_or_log!(v => { let mut message = network_result_value_or_log!(v => {
return RecvLoopAction::Finish; return RecvLoopAction::Finish;
}); });
// Pass received messages up to the network manager for processing // Pass received messages up to the network manager for processing
if let Err(e) = network_manager if let Err(e) = network_manager
.on_recv_envelope(message.as_slice(), descriptor) .on_recv_envelope(message.as_mut_slice(), descriptor)
.await .await
{ {
log_net!(debug "failed to process received envelope: {}", e); log_net!(debug "failed to process received envelope: {}", e);

View File

@ -196,6 +196,7 @@ fn config_callback(key: String) -> ConfigCallbackReturn {
"network.client_whitelist_timeout_ms" => Ok(Box::new(300_000u32)), "network.client_whitelist_timeout_ms" => Ok(Box::new(300_000u32)),
"network.reverse_connection_receipt_time_ms" => Ok(Box::new(5_000u32)), "network.reverse_connection_receipt_time_ms" => Ok(Box::new(5_000u32)),
"network.hole_punch_receipt_time_ms" => Ok(Box::new(5_000u32)), "network.hole_punch_receipt_time_ms" => Ok(Box::new(5_000u32)),
"network.network_key_password" => Ok(Box::new(Option::<String>::None)),
"network.routing_table.node_id" => Ok(Box::new(TypedKeySet::new())), "network.routing_table.node_id" => Ok(Box::new(TypedKeySet::new())),
"network.routing_table.node_id_secret" => Ok(Box::new(TypedSecretSet::new())), "network.routing_table.node_id_secret" => Ok(Box::new(TypedSecretSet::new())),
"network.routing_table.bootstrap" => Ok(Box::new(Vec::<String>::new())), "network.routing_table.bootstrap" => Ok(Box::new(Vec::<String>::new())),
@ -330,6 +331,7 @@ pub async fn test_config() {
assert_eq!(inner.network.client_whitelist_timeout_ms, 300_000u32); assert_eq!(inner.network.client_whitelist_timeout_ms, 300_000u32);
assert_eq!(inner.network.reverse_connection_receipt_time_ms, 5_000u32); assert_eq!(inner.network.reverse_connection_receipt_time_ms, 5_000u32);
assert_eq!(inner.network.hole_punch_receipt_time_ms, 5_000u32); assert_eq!(inner.network.hole_punch_receipt_time_ms, 5_000u32);
assert_eq!(inner.network.network_key_password, Option::<String>::None);
assert_eq!(inner.network.rpc.concurrency, 2u32); assert_eq!(inner.network.rpc.concurrency, 2u32);
assert_eq!(inner.network.rpc.queue_size, 1024u32); assert_eq!(inner.network.rpc.queue_size, 1024u32);
assert_eq!(inner.network.rpc.timeout_ms, 5_000u32); assert_eq!(inner.network.rpc.timeout_ms, 5_000u32);

View File

@ -110,6 +110,7 @@ pub fn fix_veilidconfiginner() -> VeilidConfigInner {
client_whitelist_timeout_ms: 7000, client_whitelist_timeout_ms: 7000,
reverse_connection_receipt_time_ms: 8000, reverse_connection_receipt_time_ms: 8000,
hole_punch_receipt_time_ms: 9000, hole_punch_receipt_time_ms: 9000,
network_key_password: None,
routing_table: VeilidConfigRoutingTable { routing_table: VeilidConfigRoutingTable {
node_id: TypedKeySet::new(), node_id: TypedKeySet::new(),
node_id_secret: TypedSecretSet::new(), node_id_secret: TypedSecretSet::new(),

View File

@ -384,6 +384,7 @@ pub struct VeilidConfigNetwork {
pub client_whitelist_timeout_ms: u32, pub client_whitelist_timeout_ms: u32,
pub reverse_connection_receipt_time_ms: u32, pub reverse_connection_receipt_time_ms: u32,
pub hole_punch_receipt_time_ms: u32, pub hole_punch_receipt_time_ms: u32,
pub network_key_password: Option<String>,
pub routing_table: VeilidConfigRoutingTable, pub routing_table: VeilidConfigRoutingTable,
pub rpc: VeilidConfigRPC, pub rpc: VeilidConfigRPC,
pub dht: VeilidConfigDHT, pub dht: VeilidConfigDHT,
@ -695,6 +696,7 @@ impl VeilidConfig {
get_config!(inner.network.client_whitelist_timeout_ms); get_config!(inner.network.client_whitelist_timeout_ms);
get_config!(inner.network.reverse_connection_receipt_time_ms); get_config!(inner.network.reverse_connection_receipt_time_ms);
get_config!(inner.network.hole_punch_receipt_time_ms); get_config!(inner.network.hole_punch_receipt_time_ms);
get_config!(inner.network.network_key_password);
get_config!(inner.network.routing_table.node_id); get_config!(inner.network.routing_table.node_id);
get_config!(inner.network.routing_table.node_id_secret); get_config!(inner.network.routing_table.node_id_secret);
get_config!(inner.network.routing_table.bootstrap); get_config!(inner.network.routing_table.bootstrap);

View File

@ -703,6 +703,7 @@ class VeilidConfigNetwork {
int clientWhitelistTimeoutMs; int clientWhitelistTimeoutMs;
int reverseConnectionReceiptTimeMs; int reverseConnectionReceiptTimeMs;
int holePunchReceiptTimeMs; int holePunchReceiptTimeMs;
String? networkKeyPassword;
VeilidConfigRoutingTable routingTable; VeilidConfigRoutingTable routingTable;
VeilidConfigRPC rpc; VeilidConfigRPC rpc;
VeilidConfigDHT dht; VeilidConfigDHT dht;
@ -723,6 +724,7 @@ class VeilidConfigNetwork {
required this.clientWhitelistTimeoutMs, required this.clientWhitelistTimeoutMs,
required this.reverseConnectionReceiptTimeMs, required this.reverseConnectionReceiptTimeMs,
required this.holePunchReceiptTimeMs, required this.holePunchReceiptTimeMs,
this.networkKeyPassword,
required this.routingTable, required this.routingTable,
required this.rpc, required this.rpc,
required this.dht, required this.dht,
@ -745,6 +747,7 @@ class VeilidConfigNetwork {
'client_whitelist_timeout_ms': clientWhitelistTimeoutMs, 'client_whitelist_timeout_ms': clientWhitelistTimeoutMs,
'reverse_connection_receipt_time_ms': reverseConnectionReceiptTimeMs, 'reverse_connection_receipt_time_ms': reverseConnectionReceiptTimeMs,
'hole_punch_receipt_time_ms': holePunchReceiptTimeMs, 'hole_punch_receipt_time_ms': holePunchReceiptTimeMs,
'network_key_password': networkKeyPassword,
'routing_table': routingTable.toJson(), 'routing_table': routingTable.toJson(),
'rpc': rpc.toJson(), 'rpc': rpc.toJson(),
'dht': dht.toJson(), 'dht': dht.toJson(),
@ -770,6 +773,7 @@ class VeilidConfigNetwork {
reverseConnectionReceiptTimeMs = reverseConnectionReceiptTimeMs =
json['reverse_connection_receipt_time_ms'], json['reverse_connection_receipt_time_ms'],
holePunchReceiptTimeMs = json['hole_punch_receipt_time_ms'], holePunchReceiptTimeMs = json['hole_punch_receipt_time_ms'],
networkKeyPassword = json['network_key_password'],
routingTable = VeilidConfigRoutingTable.fromJson(json['routing_table']), routingTable = VeilidConfigRoutingTable.fromJson(json['routing_table']),
rpc = VeilidConfigRPC.fromJson(json['rpc']), rpc = VeilidConfigRPC.fromJson(json['rpc']),
dht = VeilidConfigDHT.fromJson(json['dht']), dht = VeilidConfigDHT.fromJson(json['dht']),

View File

@ -1,3 +1,4 @@
#!/bin/bash #!/bin/bash
poetry config --local virtualenvs.in-project true
export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring
poetry install poetry install

View File

@ -130,6 +130,7 @@ async def test_routing_context_app_message_loopback_big_packets():
await api.debug("purge routes") await api.debug("purge routes")
# make a routing context that uses a safety route # make a routing context that uses a safety route
#rc = await (await (await api.new_routing_context()).with_privacy()).with_sequencing(veilid.Sequencing.ENSURE_ORDERED)
rc = await (await api.new_routing_context()).with_privacy() rc = await (await api.new_routing_context()).with_privacy()
async with rc: async with rc:

View File

@ -203,6 +203,7 @@ class VeilidConfigNetwork(ConfigBase):
client_whitelist_timeout_ms: int client_whitelist_timeout_ms: int
reverse_connection_receipt_time_ms: int reverse_connection_receipt_time_ms: int
hole_punch_receipt_time_ms: int hole_punch_receipt_time_ms: int
network_key_password: Optional[str]
routing_table: VeilidConfigRoutingTable routing_table: VeilidConfigRoutingTable
rpc: VeilidConfigRPC rpc: VeilidConfigRPC
dht: VeilidConfigDHT dht: VeilidConfigDHT

View File

@ -152,6 +152,11 @@ fn do_clap_matches(default_config_path: &OsStr) -> Result<clap::ArgMatches, clap
.long("panic") .long("panic")
.help("panic on ctrl-c instead of graceful shutdown"), .help("panic on ctrl-c instead of graceful shutdown"),
) )
.arg(
Arg::new("network-key")
.long("network-key")
.help("password override to use for network isolation"),
)
; ;
#[cfg(feature = "rt-tokio")] #[cfg(feature = "rt-tokio")]
@ -258,6 +263,9 @@ pub fn process_command_line() -> EyreResult<(Settings, ArgMatches)> {
if matches.occurrences_of("new-password") != 0 { if matches.occurrences_of("new-password") != 0 {
settingsrw.core.protected_store.new_device_encryption_key_password = Some(matches.value_of("new-password").unwrap().to_owned()); settingsrw.core.protected_store.new_device_encryption_key_password = Some(matches.value_of("new-password").unwrap().to_owned());
} }
if matches.occurrences_of("network-key") != 0 {
settingsrw.core.network.network_key_password = Some(matches.value_of("new-password").unwrap().to_owned());
}
if matches.occurrences_of("dump-txt-record") != 0 { if matches.occurrences_of("dump-txt-record") != 0 {
// Turn off terminal logging so we can be interactive // Turn off terminal logging so we can be interactive

View File

@ -69,6 +69,7 @@ core:
client_whitelist_timeout_ms: 300000 client_whitelist_timeout_ms: 300000
reverse_connection_receipt_time_ms: 5000 reverse_connection_receipt_time_ms: 5000
hole_punch_receipt_time_ms: 5000 hole_punch_receipt_time_ms: 5000
network_key_password: null
routing_table: routing_table:
node_id: null node_id: null
node_id_secret: null node_id_secret: null
@ -582,6 +583,7 @@ pub struct Network {
pub client_whitelist_timeout_ms: u32, pub client_whitelist_timeout_ms: u32,
pub reverse_connection_receipt_time_ms: u32, pub reverse_connection_receipt_time_ms: u32,
pub hole_punch_receipt_time_ms: u32, pub hole_punch_receipt_time_ms: u32,
pub network_key_password: Option<String>,
pub routing_table: RoutingTable, pub routing_table: RoutingTable,
pub rpc: Rpc, pub rpc: Rpc,
pub dht: Dht, pub dht: Dht,
@ -994,6 +996,7 @@ impl Settings {
set_config_value!(inner.core.network.client_whitelist_timeout_ms, value); set_config_value!(inner.core.network.client_whitelist_timeout_ms, value);
set_config_value!(inner.core.network.reverse_connection_receipt_time_ms, value); set_config_value!(inner.core.network.reverse_connection_receipt_time_ms, value);
set_config_value!(inner.core.network.hole_punch_receipt_time_ms, value); set_config_value!(inner.core.network.hole_punch_receipt_time_ms, value);
set_config_value!(inner.core.network.network_key_password, value);
set_config_value!(inner.core.network.routing_table.node_id, value); set_config_value!(inner.core.network.routing_table.node_id, value);
set_config_value!(inner.core.network.routing_table.node_id_secret, value); set_config_value!(inner.core.network.routing_table.node_id_secret, value);
set_config_value!(inner.core.network.routing_table.bootstrap, value); set_config_value!(inner.core.network.routing_table.bootstrap, value);
@ -1174,6 +1177,9 @@ impl Settings {
"network.hole_punch_receipt_time_ms" => { "network.hole_punch_receipt_time_ms" => {
Ok(Box::new(inner.core.network.hole_punch_receipt_time_ms)) Ok(Box::new(inner.core.network.hole_punch_receipt_time_ms))
} }
"network.network_key_password" => {
Ok(Box::new(inner.core.network.network_key_password.clone()))
}
"network.routing_table.node_id" => Ok(Box::new( "network.routing_table.node_id" => Ok(Box::new(
inner inner
.core .core
@ -1575,6 +1581,7 @@ mod tests {
assert_eq!(s.core.network.client_whitelist_timeout_ms, 300_000u32); assert_eq!(s.core.network.client_whitelist_timeout_ms, 300_000u32);
assert_eq!(s.core.network.reverse_connection_receipt_time_ms, 5_000u32); assert_eq!(s.core.network.reverse_connection_receipt_time_ms, 5_000u32);
assert_eq!(s.core.network.hole_punch_receipt_time_ms, 5_000u32); assert_eq!(s.core.network.hole_punch_receipt_time_ms, 5_000u32);
assert_eq!(s.core.network.network_key_password, None);
assert_eq!(s.core.network.routing_table.node_id, None); assert_eq!(s.core.network.routing_table.node_id, None);
assert_eq!(s.core.network.routing_table.node_id_secret, None); assert_eq!(s.core.network.routing_table.node_id_secret, None);
// //