Add relayed-only mode

This commit is contained in:
neequ57 2025-06-13 13:10:41 +00:00 committed by Christien Rioux
parent d742171aa7
commit 87708d4b3e
18 changed files with 205 additions and 135 deletions

View file

@ -136,4 +136,6 @@ core:
max_connections: 16 max_connections: 16
listen_address: ':5150' listen_address: ':5150'
path: 'ws' path: 'ws'
# url: '' # url: ''
privacy:
require_inbound_relay: false

View file

@ -29,6 +29,7 @@ pub const ADDRESS_CHECK_CACHE_SIZE: usize = 10;
pub struct AddressCheckConfig { pub struct AddressCheckConfig {
pub detect_address_changes: bool, pub detect_address_changes: bool,
pub ip6_prefix_size: usize, pub ip6_prefix_size: usize,
pub require_inbound_relay: bool,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
@ -70,15 +71,18 @@ impl AddressCheck {
pub fn new(net: Network) -> Self { pub fn new(net: Network) -> Self {
let registry = net.registry(); let registry = net.registry();
let (detect_address_changes, ip6_prefix_size) = registry.config().with(|c| { let (detect_address_changes, ip6_prefix_size, require_inbound_relay) =
( registry.config().with(|c| {
c.network.detect_address_changes, (
c.network.max_connections_per_ip6_prefix_size as usize, c.network.detect_address_changes,
) c.network.max_connections_per_ip6_prefix_size as usize,
}); c.network.privacy.require_inbound_relay,
)
});
let config = AddressCheckConfig { let config = AddressCheckConfig {
detect_address_changes, detect_address_changes,
ip6_prefix_size, ip6_prefix_size,
require_inbound_relay,
}; };
Self { Self {
@ -202,6 +206,11 @@ impl AddressCheck {
return; return;
} }
// Configured to only use relays for inbound connections. Thus, skip address detection.
if self.config.require_inbound_relay {
return;
}
// Process the state of the address checker and see if we need to // Process the state of the address checker and see if we need to
// perform a full address check for this routing domain // perform a full address check for this routing domain
let needs_address_detection = match peer_info.signed_node_info().node_info().network_class() let needs_address_detection = match peer_info.signed_node_info().node_info().network_class()
@ -225,7 +234,7 @@ impl AddressCheck {
}; };
if needs_address_detection { if needs_address_detection {
if self.config.detect_address_changes { if self.config.detect_address_changes && !self.config.require_inbound_relay {
// Reset the address check cache now so we can start detecting fresh // Reset the address check cache now so we can start detecting fresh
veilid_log!(self info veilid_log!(self info
"{:?} address has changed, detecting dial info", "{:?} address has changed, detecting dial info",

View file

@ -17,7 +17,7 @@ const NEW_CONNECTION_RETRY_DELAY_MS: u32 = 500;
#[derive(Debug)] #[derive(Debug)]
enum ConnectionManagerEvent { enum ConnectionManagerEvent {
Accepted(ProtocolNetworkConnection), Accepted(ProtocolNetworkConnection),
Dead(NetworkConnection), Dead(Box<NetworkConnection>),
} }
#[derive(Debug)] #[derive(Debug)]
@ -330,12 +330,16 @@ impl ConnectionManager {
// Send it to be terminated // Send it to be terminated
#[cfg(feature = "verbose-tracing")] #[cfg(feature = "verbose-tracing")]
veilid_log!(self debug "== LRU kill connection due to limit: {:?}", conn.debug_print(Timestamp::now())); veilid_log!(self debug "== LRU kill connection due to limit: {:?}", conn.debug_print(Timestamp::now()));
let _ = inner.sender.send(ConnectionManagerEvent::Dead(conn)); let _ = inner
.sender
.send(ConnectionManagerEvent::Dead(Box::new(conn)));
} }
Err(ConnectionTableAddError::AddressFilter(conn, e)) => { Err(ConnectionTableAddError::AddressFilter(conn, e)) => {
// Connection filtered // Connection filtered
let desc = conn.flow(); let desc = conn.flow();
let _ = inner.sender.send(ConnectionManagerEvent::Dead(conn)); let _ = inner
.sender
.send(ConnectionManagerEvent::Dead(Box::new(conn)));
return Ok(NetworkResult::no_connection_other(format!( return Ok(NetworkResult::no_connection_other(format!(
"connection filtered: {:?} ({})", "connection filtered: {:?} ({})",
desc, e desc, e
@ -345,7 +349,9 @@ impl ConnectionManager {
// Connection already exists // Connection already exists
let desc = conn.flow(); let desc = conn.flow();
veilid_log!(self debug "== Connection already exists: {:?}", conn.debug_print(Timestamp::now())); veilid_log!(self debug "== Connection already exists: {:?}", conn.debug_print(Timestamp::now()));
let _ = inner.sender.send(ConnectionManagerEvent::Dead(conn)); let _ = inner
.sender
.send(ConnectionManagerEvent::Dead(Box::new(conn)));
return Ok(NetworkResult::no_connection_other(format!( return Ok(NetworkResult::no_connection_other(format!(
"connection already exists: {:?}", "connection already exists: {:?}",
desc desc
@ -355,7 +361,9 @@ impl ConnectionManager {
// Connection table is full // Connection table is full
let desc = conn.flow(); let desc = conn.flow();
veilid_log!(self debug "== Connection table full: {:?}", conn.debug_print(Timestamp::now())); veilid_log!(self debug "== Connection table full: {:?}", conn.debug_print(Timestamp::now()));
let _ = inner.sender.send(ConnectionManagerEvent::Dead(conn)); let _ = inner
.sender
.send(ConnectionManagerEvent::Dead(Box::new(conn)));
return Ok(NetworkResult::no_connection_other(format!( return Ok(NetworkResult::no_connection_other(format!(
"connection table is full: {:?}", "connection table is full: {:?}",
desc desc
@ -687,7 +695,7 @@ impl ConnectionManager {
} }
} }
} }
let _ = sender.send(ConnectionManagerEvent::Dead(conn)); let _ = sender.send(ConnectionManagerEvent::Dead(Box::new(conn)));
} }
} }

View file

@ -884,7 +884,9 @@ impl DiscoveryContext {
// UPNP Automatic Mapping // UPNP Automatic Mapping
/////////// ///////////
let enable_upnp = self.config().with(|c| c.network.upnp); let enable_upnp = self
.config()
.with(|c| c.network.upnp && !c.network.privacy.require_inbound_relay);
if enable_upnp { if enable_upnp {
// Attempt a port mapping via all available and enabled mechanisms // Attempt a port mapping via all available and enabled mechanisms
// Try this before the direct mapping in the event that we are restarting // Try this before the direct mapping in the event that we are restarting

View file

@ -768,7 +768,9 @@ impl Network {
true, true,
); );
let confirmed_public_internet = !self.config().with(|c| c.network.detect_address_changes); let confirmed_public_internet = self
.config()
.with(|c| !c.network.detect_address_changes || c.network.privacy.require_inbound_relay);
editor_public_internet.setup_network( editor_public_internet.setup_network(
network_state.protocol_config.outbound, network_state.protocol_config.outbound,
network_state.protocol_config.inbound, network_state.protocol_config.inbound,
@ -836,9 +838,18 @@ impl Network {
self.trigger_update_network_class(RoutingDomain::PublicInternet); self.trigger_update_network_class(RoutingDomain::PublicInternet);
} else { } else {
// Warn if we have no public dialinfo, because we're not going to magically find some // Warn if we have no public dialinfo, because we're not going to magically find some
// with detect address changes turned off // with detect_address_changes turned off. Skip the warning if require_inbound_relay is
// enabled, this option intentionally disables publishing any dialinfo.
let pi = routing_table.get_current_peer_info(RoutingDomain::PublicInternet); let pi = routing_table.get_current_peer_info(RoutingDomain::PublicInternet);
if !pi.signed_node_info().has_any_dial_info() { if !pi.signed_node_info().has_any_dial_info()
&& !self
.registry
.config()
.get()
.network
.privacy
.require_inbound_relay
{
veilid_log!(self warn veilid_log!(self warn
"This node has no valid public dial info.\nConfigure this node with a static public IP address and correct firewall rules." "This node has no valid public dial info.\nConfigure this node with a static public IP address and correct firewall rules."
); );

View file

@ -140,13 +140,15 @@ impl Network {
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
pub(super) async fn bind_udp_protocol_handlers(&self) -> EyreResult<StartupDisposition> { pub(super) async fn bind_udp_protocol_handlers(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "UDP: binding protocol handlers"); veilid_log!(self trace "UDP: binding protocol handlers");
let (listen_address, public_address, detect_address_changes) = self.config().with(|c| { let (listen_address, public_address, detect_address_changes, require_inbound_relay) =
( self.config().with(|c| {
c.network.protocol.udp.listen_address.clone(), (
c.network.protocol.udp.public_address.clone(), c.network.protocol.udp.listen_address.clone(),
c.network.detect_address_changes, c.network.protocol.udp.public_address.clone(),
) c.network.detect_address_changes,
}); c.network.privacy.require_inbound_relay,
)
});
// Get the binding parameters from the user-specified listen address // Get the binding parameters from the user-specified listen address
let bind_set = self let bind_set = self
@ -175,7 +177,7 @@ impl Network {
{ {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
if public_address.is_some() && !detect_address_changes { if public_address.is_some() && !detect_address_changes && !require_inbound_relay {
inner.static_public_dial_info.insert(ProtocolType::UDP); inner.static_public_dial_info.insert(ProtocolType::UDP);
} }
} }
@ -191,12 +193,14 @@ impl Network {
) -> EyreResult<()> { ) -> EyreResult<()> {
veilid_log!(self trace "UDP: registering dial info"); veilid_log!(self trace "UDP: registering dial info");
let (public_address, detect_address_changes) = self.config().with(|c| { let (public_address, detect_address_changes, require_inbound_relay) =
( self.config().with(|c| {
c.network.protocol.udp.public_address.clone(), (
c.network.detect_address_changes, c.network.protocol.udp.public_address.clone(),
) c.network.detect_address_changes,
}); c.network.privacy.require_inbound_relay,
)
});
let local_dial_info_list = { let local_dial_info_list = {
let mut out = vec![]; let mut out = vec![];
@ -220,7 +224,7 @@ impl Network {
}; };
// Add static public dialinfo if it's configured // Add static public dialinfo if it's configured
if let Some(public_address) = public_address.as_ref() { if let (Some(public_address), false) = (public_address.as_ref(), require_inbound_relay) {
// Resolve statically configured public dialinfo // Resolve statically configured public dialinfo
let mut public_sockaddrs = public_address let mut public_sockaddrs = public_address
.to_socket_addrs() .to_socket_addrs()
@ -247,7 +251,11 @@ impl Network {
for di in &local_dial_info_list { for di in &local_dial_info_list {
// If the local interface address is global, then register global dial info // If the local interface address is global, then register global dial info
// if no other public address is specified // if no other public address is specified
if !detect_address_changes && public_address.is_none() && di.address().is_global() { if !detect_address_changes
&& !require_inbound_relay
&& public_address.is_none()
&& di.address().is_global()
{
editor_public_internet.add_dial_info(di.clone(), DialInfoClass::Direct); editor_public_internet.add_dial_info(di.clone(), DialInfoClass::Direct);
} }
@ -261,13 +269,15 @@ impl Network {
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
pub(super) async fn start_ws_listeners(&self) -> EyreResult<StartupDisposition> { pub(super) async fn start_ws_listeners(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "WS: binding protocol handlers"); veilid_log!(self trace "WS: binding protocol handlers");
let (listen_address, url, detect_address_changes) = self.config().with(|c| { let (listen_address, url, detect_address_changes, require_inbound_relay) =
( self.config().with(|c| {
c.network.protocol.ws.listen_address.clone(), (
c.network.protocol.ws.url.clone(), c.network.protocol.ws.listen_address.clone(),
c.network.detect_address_changes, c.network.protocol.ws.url.clone(),
) c.network.detect_address_changes,
}); c.network.privacy.require_inbound_relay,
)
});
// Get the binding parameters from the user-specified listen address // Get the binding parameters from the user-specified listen address
let bind_set = self let bind_set = self
@ -299,7 +309,7 @@ impl Network {
{ {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
if url.is_some() && !detect_address_changes { if url.is_some() && !detect_address_changes && !require_inbound_relay {
inner.static_public_dial_info.insert(ProtocolType::WS); inner.static_public_dial_info.insert(ProtocolType::WS);
} }
} }
@ -314,11 +324,12 @@ impl Network {
editor_local_network: &mut RoutingDomainEditorLocalNetwork<'_>, editor_local_network: &mut RoutingDomainEditorLocalNetwork<'_>,
) -> EyreResult<()> { ) -> EyreResult<()> {
veilid_log!(self trace "WS: registering dial info"); veilid_log!(self trace "WS: registering dial info");
let (url, path, detect_address_changes) = self.config().with(|c| { let (url, path, detect_address_changes, require_inbound_relay) = self.config().with(|c| {
( (
c.network.protocol.ws.url.clone(), c.network.protocol.ws.url.clone(),
c.network.protocol.ws.path.clone(), c.network.protocol.ws.path.clone(),
c.network.detect_address_changes, c.network.detect_address_changes,
c.network.privacy.require_inbound_relay,
) )
}); });
@ -389,7 +400,11 @@ impl Network {
let local_di = let local_di =
DialInfo::try_ws(*socket_address, local_url).wrap_err("try_ws failed")?; DialInfo::try_ws(*socket_address, local_url).wrap_err("try_ws failed")?;
if !detect_address_changes && url.is_none() && local_di.address().is_global() { if !detect_address_changes
&& !require_inbound_relay
&& url.is_none()
&& local_di.address().is_global()
{
// Register public dial info // Register public dial info
editor_public_internet.add_dial_info(local_di.clone(), DialInfoClass::Direct); editor_public_internet.add_dial_info(local_di.clone(), DialInfoClass::Direct);
} }
@ -405,13 +420,15 @@ impl Network {
pub(super) async fn start_wss_listeners(&self) -> EyreResult<StartupDisposition> { pub(super) async fn start_wss_listeners(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "WSS: binding protocol handlers"); veilid_log!(self trace "WSS: binding protocol handlers");
let (listen_address, url, detect_address_changes) = self.config().with(|c| { let (listen_address, url, detect_address_changes, require_inbound_relay) =
( self.config().with(|c| {
c.network.protocol.wss.listen_address.clone(), (
c.network.protocol.wss.url.clone(), c.network.protocol.wss.listen_address.clone(),
c.network.detect_address_changes, c.network.protocol.wss.url.clone(),
) c.network.detect_address_changes,
}); c.network.privacy.require_inbound_relay,
)
});
// Get the binding parameters from the user-specified listen address // Get the binding parameters from the user-specified listen address
let bind_set = self let bind_set = self
@ -444,7 +461,7 @@ impl Network {
{ {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
if url.is_some() && !detect_address_changes { if url.is_some() && !detect_address_changes && !require_inbound_relay {
inner.static_public_dial_info.insert(ProtocolType::WSS); inner.static_public_dial_info.insert(ProtocolType::WSS);
} }
} }
@ -514,13 +531,15 @@ impl Network {
pub(super) async fn start_tcp_listeners(&self) -> EyreResult<StartupDisposition> { pub(super) async fn start_tcp_listeners(&self) -> EyreResult<StartupDisposition> {
veilid_log!(self trace "TCP: binding protocol handlers"); veilid_log!(self trace "TCP: binding protocol handlers");
let (listen_address, public_address, detect_address_changes) = self.config().with(|c| { let (listen_address, public_address, detect_address_changes, require_inbound_relay) =
( self.config().with(|c| {
c.network.protocol.tcp.listen_address.clone(), (
c.network.protocol.tcp.public_address.clone(), c.network.protocol.tcp.listen_address.clone(),
c.network.detect_address_changes, c.network.protocol.tcp.public_address.clone(),
) c.network.detect_address_changes,
}); c.network.privacy.require_inbound_relay,
)
});
// Get the binding parameters from the user-specified listen address // Get the binding parameters from the user-specified listen address
let bind_set = self let bind_set = self
@ -552,7 +571,7 @@ impl Network {
{ {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
if public_address.is_some() && !detect_address_changes { if public_address.is_some() && !detect_address_changes && !require_inbound_relay {
inner.static_public_dial_info.insert(ProtocolType::TCP); inner.static_public_dial_info.insert(ProtocolType::TCP);
} }
} }
@ -568,12 +587,14 @@ impl Network {
) -> EyreResult<()> { ) -> EyreResult<()> {
veilid_log!(self trace "TCP: registering dialinfo"); veilid_log!(self trace "TCP: registering dialinfo");
let (public_address, detect_address_changes) = self.config().with(|c| { let (public_address, detect_address_changes, require_inbound_relay) =
( self.config().with(|c| {
c.network.protocol.tcp.public_address.clone(), (
c.network.detect_address_changes, c.network.protocol.tcp.public_address.clone(),
) c.network.detect_address_changes,
}); c.network.privacy.require_inbound_relay,
)
});
let mut registered_addresses: HashSet<IpAddr> = HashSet::new(); let mut registered_addresses: HashSet<IpAddr> = HashSet::new();
@ -602,7 +623,7 @@ impl Network {
}; };
// Add static public dialinfo if it's configured // Add static public dialinfo if it's configured
if let Some(public_address) = public_address.as_ref() { if let (Some(public_address), false) = (public_address.as_ref(), require_inbound_relay) {
// Resolve statically configured public dialinfo // Resolve statically configured public dialinfo
let mut public_sockaddrs = public_address let mut public_sockaddrs = public_address
.to_socket_addrs() .to_socket_addrs()
@ -629,7 +650,11 @@ impl Network {
let di = DialInfo::tcp(*socket_address); let di = DialInfo::tcp(*socket_address);
// Register global dial info if no public address is specified // Register global dial info if no public address is specified
if !detect_address_changes && public_address.is_none() && di.address().is_global() { if !detect_address_changes
&& !require_inbound_relay
&& public_address.is_none()
&& di.address().is_global()
{
editor_public_internet.add_dial_info(di.clone(), DialInfoClass::Direct); editor_public_internet.add_dial_info(di.clone(), DialInfoClass::Direct);
} }
// Register interface dial info // Register interface dial info

View file

@ -87,12 +87,22 @@ impl Network {
return Ok(()); return Ok(());
} }
let (detect_address_changes, upnp) = { let (detect_address_changes, upnp, require_inbound_relay) = {
let config = self.network_manager().config(); let config = self.network_manager().config();
let c = config.get(); let c = config.get();
(c.network.detect_address_changes, c.network.upnp) (
c.network.detect_address_changes,
c.network.upnp,
c.network.privacy.require_inbound_relay,
)
}; };
if require_inbound_relay {
// Configured to only use relays for inbound connections.
// This implicitly turns off address detection and upnp.
return Ok(());
}
// If we need to figure out our network class, tick the task for it // If we need to figure out our network class, tick the task for it
if detect_address_changes { if detect_address_changes {
// Check our network interfaces to see if they have changed // Check our network interfaces to see if they have changed

View file

@ -287,60 +287,46 @@ impl RouteSpecStore {
let geolocation_info = let geolocation_info =
sni.get_geolocation_info(RoutingDomain::PublicInternet); sni.get_geolocation_info(RoutingDomain::PublicInternet);
// Since denylist is used, consider nodes with unknown countries to be automatically // Since denylist is used, consider nodes with unknown countries to be automatically excluded
// excluded as well let Some(node_country_code) = geolocation_info.country_code() else {
if geolocation_info.country_code().is_none() {
veilid_log!(self veilid_log!(self
debug "allocate_route_inner: skipping node {} from unknown country", debug "allocate_route_inner: skipping node {:?} from unknown country",
e.best_node_id() e.best_node_id()
); );
return false; return false;
} };
// Same thing applies to relays used by the node // The same thing applies to relays used by the node
if geolocation_info // They must all be from a known country
.relay_country_codes() let relay_country_codes: Option<Vec<CountryCode>> = geolocation_info.relay_country_codes().iter().cloned().collect();
.iter() let Some(relay_country_codes) = relay_country_codes else {
.any(Option::is_none)
{
veilid_log!(self veilid_log!(self
debug "allocate_route_inner: skipping node {} using relay from unknown country", debug "allocate_route_inner: skipping node {:?} using relay from unknown country",
e.best_node_id() e.best_node_id()
); );
return false; return false;
} };
// Ensure that node is not excluded // Ensure that node is not excluded
// Safe to unwrap here, checked above if country_code_denylist.contains(&node_country_code)
if country_code_denylist.contains(&geolocation_info.country_code().unwrap())
{ {
veilid_log!(self veilid_log!(self
debug "allocate_route_inner: skipping node {} from excluded country {}", debug "allocate_route_inner: skipping node {:?} from excluded country {}",
e.best_node_id(), e.best_node_id(),
geolocation_info.country_code().unwrap() node_country_code
); );
return false; return false;
} }
// Ensure that node relays are not excluded // Ensure that node relays are not excluded
// Safe to unwrap here, checked above if let Some(cc) = relay_country_codes
if geolocation_info
.relay_country_codes()
.iter() .iter()
.cloned() .filter(|cc| country_code_denylist.contains(cc))
.map(Option::unwrap) .next()
.any(|cc| country_code_denylist.contains(&cc))
{ {
veilid_log!(self veilid_log!(self
debug "allocate_route_inner: skipping node {} using relay from excluded country {:?}", debug "allocate_route_inner: skipping node {:?} using relay from excluded country {}",
e.best_node_id(), e.best_node_id(),
geolocation_info cc
.relay_country_codes()
.iter()
.cloned()
.map(Option::unwrap)
.filter(|cc| country_code_denylist.contains(&cc))
.next()
.unwrap()
); );
return false; return false;
} }

View file

@ -178,11 +178,9 @@ impl TableDB {
&Nonce::try_from(&data[0..NONCE_LENGTH]).unwrap(), &Nonce::try_from(&data[0..NONCE_LENGTH]).unwrap(),
&di.typed_key.value, &di.typed_key.value,
); );
decompress_size_prepended(&out, None) decompress_size_prepended(&out, None).map_err(|e| std::io::Error::other(e.to_string()))
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
} else { } else {
decompress_size_prepended(data, None) decompress_size_prepended(data, None).map_err(|e| std::io::Error::other(e.to_string()))
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
} }
} }

View file

@ -289,6 +289,7 @@ pub fn config_callback(key: String) -> ConfigCallbackReturn {
"network.protocol.wss.listen_address" => Ok(Box::new("".to_owned())), "network.protocol.wss.listen_address" => Ok(Box::new("".to_owned())),
"network.protocol.wss.path" => Ok(Box::new(String::from("ws"))), "network.protocol.wss.path" => Ok(Box::new(String::from("ws"))),
"network.protocol.wss.url" => Ok(Box::new(Option::<String>::None)), "network.protocol.wss.url" => Ok(Box::new(Option::<String>::None)),
"network.privacy.require_inbound_relay" => Ok(Box::new(false)),
#[cfg(feature = "geolocation")] #[cfg(feature = "geolocation")]
"network.privacy.country_code_denylist" => Ok(Box::new(Vec::<CountryCode>::new())), "network.privacy.country_code_denylist" => Ok(Box::new(Vec::<CountryCode>::new())),
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]
@ -436,6 +437,7 @@ pub fn test_config() {
assert_eq!(inner.network.protocol.wss.path, "ws"); assert_eq!(inner.network.protocol.wss.path, "ws");
assert_eq!(inner.network.protocol.wss.url, None); assert_eq!(inner.network.protocol.wss.url, None);
assert!(!inner.network.privacy.require_inbound_relay);
#[cfg(feature = "geolocation")] #[cfg(feature = "geolocation")]
assert_eq!(inner.network.privacy.country_code_denylist, Vec::new()); assert_eq!(inner.network.privacy.country_code_denylist, Vec::new());
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]

View file

@ -280,8 +280,9 @@ pub fn fix_veilidconfig() -> VeilidConfig {
url: Some("https://veilid.com/wss".to_string()), url: Some("https://veilid.com/wss".to_string()),
}, },
}, },
#[cfg(feature = "geolocation")]
privacy: VeilidConfigPrivacy { privacy: VeilidConfigPrivacy {
require_inbound_relay: false,
#[cfg(feature = "geolocation")]
country_code_denylist: vec![CountryCode::from_str("NZ").unwrap()], country_code_denylist: vec![CountryCode::from_str("NZ").unwrap()],
}, },
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]

View file

@ -285,25 +285,18 @@ pub struct VeilidConfigProtocol {
/// ///
/// ```yaml /// ```yaml
/// privacy: /// privacy:
/// country_code_denylist: [] /// require_inbound_relay: false
/// country_code_denylist: [] # only with `--features=geolocation`
/// ``` /// ```
#[cfg(feature = "geolocation")] #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(target_arch = "wasm32", derive(Tsify))] #[cfg_attr(target_arch = "wasm32", derive(Tsify))]
#[must_use] #[must_use]
pub struct VeilidConfigPrivacy { pub struct VeilidConfigPrivacy {
pub require_inbound_relay: bool,
#[cfg(feature = "geolocation")]
pub country_code_denylist: Vec<CountryCode>, pub country_code_denylist: Vec<CountryCode>,
} }
#[cfg(feature = "geolocation")]
impl Default for VeilidConfigPrivacy {
fn default() -> Self {
Self {
country_code_denylist: Vec::new(),
}
}
}
/// Virtual networking client support for testing/simulation purposes /// Virtual networking client support for testing/simulation purposes
/// ///
/// ```yaml /// ```yaml
@ -568,7 +561,6 @@ pub struct VeilidConfigNetwork {
pub tls: VeilidConfigTLS, pub tls: VeilidConfigTLS,
pub application: VeilidConfigApplication, pub application: VeilidConfigApplication,
pub protocol: VeilidConfigProtocol, pub protocol: VeilidConfigProtocol,
#[cfg(feature = "geolocation")]
pub privacy: VeilidConfigPrivacy, pub privacy: VeilidConfigPrivacy,
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]
pub virtual_network: VeilidConfigVirtualNetwork, pub virtual_network: VeilidConfigVirtualNetwork,
@ -596,7 +588,6 @@ impl Default for VeilidConfigNetwork {
tls: VeilidConfigTLS::default(), tls: VeilidConfigTLS::default(),
application: VeilidConfigApplication::default(), application: VeilidConfigApplication::default(),
protocol: VeilidConfigProtocol::default(), protocol: VeilidConfigProtocol::default(),
#[cfg(feature = "geolocation")]
privacy: VeilidConfigPrivacy::default(), privacy: VeilidConfigPrivacy::default(),
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]
virtual_network: VeilidConfigVirtualNetwork::default(), virtual_network: VeilidConfigVirtualNetwork::default(),
@ -1049,6 +1040,7 @@ impl VeilidStartupOptions {
get_config!(inner.network.protocol.wss.listen_address); get_config!(inner.network.protocol.wss.listen_address);
get_config!(inner.network.protocol.wss.path); get_config!(inner.network.protocol.wss.path);
get_config!(inner.network.protocol.wss.url); get_config!(inner.network.protocol.wss.url);
get_config!(inner.network.privacy.require_inbound_relay);
#[cfg(feature = "geolocation")] #[cfg(feature = "geolocation")]
get_config!(inner.network.privacy.country_code_denylist); get_config!(inner.network.privacy.country_code_denylist);
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]

View file

@ -189,6 +189,11 @@ class VeilidConfigProtocol(ConfigBase):
wss: VeilidConfigWSS wss: VeilidConfigWSS
@dataclass
class VeilidConfigPrivacy(ConfigBase):
require_inbound_relay: bool
@dataclass @dataclass
class VeilidConfigNetwork(ConfigBase): class VeilidConfigNetwork(ConfigBase):
connection_initial_timeout_ms: int connection_initial_timeout_ms: int
@ -210,6 +215,7 @@ class VeilidConfigNetwork(ConfigBase):
tls: VeilidConfigTLS tls: VeilidConfigTLS
application: VeilidConfigApplication application: VeilidConfigApplication
protocol: VeilidConfigProtocol protocol: VeilidConfigProtocol
privacy: VeilidConfigPrivacy
@dataclass @dataclass

View file

@ -4267,6 +4267,7 @@
"max_connections_per_ip4", "max_connections_per_ip4",
"max_connections_per_ip6_prefix", "max_connections_per_ip6_prefix",
"max_connections_per_ip6_prefix_size", "max_connections_per_ip6_prefix_size",
"privacy",
"protocol", "protocol",
"restricted_nat_retries", "restricted_nat_retries",
"reverse_connection_receipt_time_ms", "reverse_connection_receipt_time_ms",
@ -4331,6 +4332,9 @@
"null" "null"
] ]
}, },
"privacy": {
"$ref": "#/definitions/VeilidConfigPrivacy"
},
"protocol": { "protocol": {
"$ref": "#/definitions/VeilidConfigProtocol" "$ref": "#/definitions/VeilidConfigProtocol"
}, },
@ -4358,6 +4362,18 @@
} }
} }
}, },
"VeilidConfigPrivacy": {
"description": "Privacy preferences for routes.\n\n```yaml privacy: require_inbound_relay: false country_code_denylist: [] # only with `--features=geolocation` ```",
"type": "object",
"required": [
"require_inbound_relay"
],
"properties": {
"require_inbound_relay": {
"type": "boolean"
}
}
},
"VeilidConfigProtectedStore": { "VeilidConfigProtectedStore": {
"type": "object", "type": "object",
"required": [ "required": [

View file

@ -35,10 +35,9 @@ pub const PROGRAM_NAME: &str = "veilid-server";
pub fn load_default_config() -> EyreResult<config::Config> { pub fn load_default_config() -> EyreResult<config::Config> {
#[cfg(not(feature = "geolocation"))] #[cfg(not(feature = "geolocation"))]
let privacy_section = ""; let privacy_geolocation_section = "";
#[cfg(feature = "geolocation")] #[cfg(feature = "geolocation")]
let privacy_section = r#" let privacy_geolocation_section = r#"
privacy:
country_code_denylist: [] country_code_denylist: []
"#; "#;
@ -224,8 +223,10 @@ core:
listen_address: ':5150' listen_address: ':5150'
path: 'ws' path: 'ws'
# url: '' # url: ''
privacy:
require_inbound_relay: false
%PRIVACY_GEOLOCATION_SECTION%
%VIRTUAL_NETWORK_SECTION% %VIRTUAL_NETWORK_SECTION%
%PRIVACY_SECTION%
"#, "#,
) )
.replace( .replace(
@ -256,7 +257,7 @@ core:
"%REMOTE_MAX_SUBKEY_CACHE_MEMORY_MB%", "%REMOTE_MAX_SUBKEY_CACHE_MEMORY_MB%",
&Settings::get_default_remote_max_subkey_cache_memory_mb().to_string(), &Settings::get_default_remote_max_subkey_cache_memory_mb().to_string(),
) )
.replace("%PRIVACY_SECTION%", privacy_section) .replace("%PRIVACY_GEOLOCATION_SECTION%", privacy_geolocation_section)
.replace("%VIRTUAL_NETWORK_SECTION%", virtual_network_section) .replace("%VIRTUAL_NETWORK_SECTION%", virtual_network_section)
.replace( .replace(
"%VIRTUAL_NETWORK_SERVER_SECTION%", "%VIRTUAL_NETWORK_SERVER_SECTION%",
@ -646,9 +647,10 @@ pub struct Protocol {
pub wss: Wss, pub wss: Wss,
} }
#[cfg(feature = "geolocation")]
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
pub struct Privacy { pub struct Privacy {
pub require_inbound_relay: bool,
#[cfg(feature = "geolocation")]
pub country_code_denylist: Vec<CountryCode>, pub country_code_denylist: Vec<CountryCode>,
} }
@ -730,7 +732,6 @@ pub struct Network {
pub tls: Tls, pub tls: Tls,
pub application: Application, pub application: Application,
pub protocol: Protocol, pub protocol: Protocol,
#[cfg(feature = "geolocation")]
pub privacy: Privacy, pub privacy: Privacy,
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]
pub virtual_network: VirtualNetwork, pub virtual_network: VirtualNetwork,
@ -1252,6 +1253,7 @@ impl Settings {
set_config_value!(inner.core.network.protocol.wss.listen_address, value); set_config_value!(inner.core.network.protocol.wss.listen_address, value);
set_config_value!(inner.core.network.protocol.wss.path, value); set_config_value!(inner.core.network.protocol.wss.path, value);
set_config_value!(inner.core.network.protocol.wss.url, value); set_config_value!(inner.core.network.protocol.wss.url, value);
set_config_value!(inner.core.network.privacy.require_inbound_relay, value);
#[cfg(feature = "geolocation")] #[cfg(feature = "geolocation")]
set_config_value!(inner.core.network.privacy.country_code_denylist, value); set_config_value!(inner.core.network.privacy.country_code_denylist, value);
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]
@ -1689,6 +1691,9 @@ impl Settings {
None => None, None => None,
})) }))
} }
"network.privacy.require_inbound_relay" => {
Ok(Box::new(inner.core.network.privacy.require_inbound_relay))
}
#[cfg(feature = "geolocation")] #[cfg(feature = "geolocation")]
"network.privacy.country_code_denylist" => Ok(Box::new( "network.privacy.country_code_denylist" => Ok(Box::new(
inner.core.network.privacy.country_code_denylist.clone(), inner.core.network.privacy.country_code_denylist.clone(),
@ -1981,6 +1986,7 @@ mod tests {
); );
assert_eq!(s.core.network.protocol.wss.url, None); assert_eq!(s.core.network.protocol.wss.url, None);
// //
assert_eq!(s.core.network.privacy.require_inbound_relay, false);
#[cfg(feature = "geolocation")] #[cfg(feature = "geolocation")]
assert_eq!(s.core.network.privacy.country_code_denylist, &[]); assert_eq!(s.core.network.privacy.country_code_denylist, &[]);
#[cfg(feature = "virtual-network")] #[cfg(feature = "virtual-network")]

View file

@ -157,11 +157,7 @@ impl AsyncRead for AsyncPeekStream {
// //
let buflen = buf.len(); let buflen = buf.len();
let bufcopylen = core::cmp::min(buflen, inner.peekbuf_len); let bufcopylen = core::cmp::min(buflen, inner.peekbuf_len);
let bufreadlen = if buflen > inner.peekbuf_len { let bufreadlen = buflen.saturating_sub(inner.peekbuf_len);
buflen - inner.peekbuf_len
} else {
0
};
if bufreadlen > 0 { if bufreadlen > 0 {
match Pin::new(&mut inner.stream).poll_read(cx, &mut buf[bufcopylen..buflen]) { match Pin::new(&mut inner.stream).poll_read(cx, &mut buf[bufcopylen..buflen]) {

View file

@ -131,7 +131,7 @@ impl<T> NetworkResult<T> {
Self::NoConnection(e) Self::NoConnection(e)
} }
pub fn no_connection_other<S: ToString>(s: S) -> Self { pub fn no_connection_other<S: ToString>(s: S) -> Self {
Self::NoConnection(io::Error::new(io::ErrorKind::Other, s.to_string())) Self::NoConnection(io::Error::other(s.to_string()))
} }
pub fn invalid_message<S: ToString>(s: S) -> Self { pub fn invalid_message<S: ToString>(s: S) -> Self {
Self::InvalidMessage(s.to_string()) Self::InvalidMessage(s.to_string())

View file

@ -22,7 +22,7 @@ macro_rules! io_error_other {
} }
pub fn to_io_error_other<E: std::error::Error + Send + Sync + 'static>(x: E) -> io::Error { pub fn to_io_error_other<E: std::error::Error + Send + Sync + 'static>(x: E) -> io::Error {
io::Error::new(io::ErrorKind::Other, x) io::Error::other(x)
} }
#[macro_export] #[macro_export]