openrtc 2.9.8

OpenRTC: a Rust-first P2P runtime for device discovery, signaling, and iroh/QUIC networking.
Documentation
//! Native IP policy input into the existing Iroh endpoint owner.
use super::Client;

impl Client {
    /// Whether this host compiled the pinned native Iroh UDP/candidate exclusion
    /// mechanism. This does not imply relay/custom DNS, TCP or ICE exclusion, or
    /// permission to install OS routes.
    pub fn supports_native_ip_exclusions(&self) -> bool {
        cfg!(feature = "native-ip-exclusions")
    }

    /// Commit native UDP/candidate exclusions on this client's one endpoint.
    /// Await success before creating overlay routes and retain the exclusions
    /// until the host has verified removal of its owned routes. Empty input
    /// restores ordinary native Iroh UDP behavior. Unspecified constructor
    /// input preserves a host-built endpoint's existing native IP policy.
    /// An explicit update replaces that policy.
    ///
    /// Updates, bind and adoption share the existing endpoint initialization
    /// guard. Desired input is retained before dispatch so cancellation cannot
    /// leave a future endpoint bind using older host policy. A dropped future
    /// is not an acknowledgement; callers must not install routes on that basis.
    /// This method never creates/closes a peer or schedules recovery.
    pub async fn set_native_ip_exclusions(
        &self,
        networks: Vec<ipnet::IpNet>,
    ) -> anyhow::Result<()> {
        anyhow::ensure!(
            self.supports_native_ip_exclusions(),
            "native IP exclusions are unsupported by this build"
        );
        let _init_lock = self.iroh_init_guard.lock().await;
        *self.native_ip_exclusions.write().await = Some(networks.clone());
        #[cfg(feature = "native-ip-exclusions")]
        if let Some(endpoint) = self.iroh_endpoint.read().await.as_ref() {
            endpoint.set_excluded_ip_networks(networks).await?;
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use crate::client::ClientBuilder;
    #[cfg(not(feature = "native-ip-exclusions"))]
    use crate::client::TransportConfig;

    #[cfg(not(feature = "native-ip-exclusions"))]
    #[tokio::test]
    async fn unsupported_native_ip_input_refuses_endpoint_creation() {
        for networks in [vec!["127.0.0.0/8".parse().unwrap()], Vec::new()] {
            let client =
                ClientBuilder::new_provider_neutral("ip-policy-test".into(), Box::new(|| None))
                    .transport_config(TransportConfig {
                        relay: false,
                        ..Default::default()
                    })
                    .native_ip_exclusions(networks.clone())
                    .build();
            let live_update = client.set_native_ip_exclusions(networks).await;
            assert!(
                live_update.is_err(),
                "an unsupported policy update cannot be acknowledged, including explicit clear"
            );
            let result = client
                .init_iroh_without_internal_router(None, Vec::new())
                .await;
            assert!(
                result.is_err(),
                "an explicitly configured unsupported policy cannot bind an endpoint"
            );
            assert!(client.iroh_endpoint.read().await.is_none());
            assert!(client.current_node_id().await.is_none());
        }
    }

    #[cfg(feature = "native-ip-exclusions")]
    #[tokio::test]
    async fn native_ip_constructor_and_live_updates_use_the_same_endpoint() {
        for supplied_by_sdk in [true, false] {
            let networks = vec!["127.0.0.0/8".parse().unwrap()];
            let builder =
                ClientBuilder::new_provider_neutral("ip-policy-test".into(), Box::new(|| None));
            let client = if supplied_by_sdk {
                builder.native_ip_exclusions(networks.clone()).build()
            } else {
                builder.build()
            };
            let builder = iroh::Endpoint::builder(iroh::endpoint::presets::Minimal)
                .bind_addr("127.0.0.1:0")
                .unwrap()
                .bind_addr("[::1]:0")
                .unwrap();
            let builder = if supplied_by_sdk {
                builder
            } else {
                builder.excluded_ip_networks(networks)
            };
            let endpoint = builder.bind().await.unwrap();
            assert_eq!(
                endpoint
                    .addr()
                    .ip_addrs()
                    .any(|addr| addr.ip().to_canonical().is_ipv4()),
                supplied_by_sdk,
                "verify the fixture's initial candidate policy"
            );
            let node = endpoint.id();
            client
                .adopt_endpoint_with_router_mode(endpoint.clone(), false)
                .await
                .unwrap();
            assert!(endpoint.addr().ip_addrs().all(|addr| !addr.ip().to_canonical().is_ipv4()),
                "constructor input must be committed before publishing; unspecified input must preserve a host exclusion");
            client.set_native_ip_exclusions(Vec::new()).await.unwrap();
            assert!(
                endpoint
                    .addr()
                    .ip_addrs()
                    .any(|addr| addr.ip().to_canonical().is_ipv4()),
                "clearing policy must refresh native candidates on the retained endpoint"
            );
            client
                .set_native_ip_exclusions(vec!["127.0.0.0/8".parse().unwrap()])
                .await
                .unwrap();
            assert!(endpoint
                .addr()
                .ip_addrs()
                .all(|addr| !addr.ip().to_canonical().is_ipv4()));
            assert_eq!(
                client.iroh_endpoint.read().await.as_ref().unwrap().id(),
                node
            );
            assert!(!endpoint.is_closed());
            endpoint.close().await;
        }
    }
}