diff --git a/conduwuit-example.toml b/conduwuit-example.toml index aee29f92..b4bce140 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -1117,6 +1117,16 @@ # #ip_range_denylist = ["127.0.0.0/8", "10.0.0.0/8", "172.16.0.0/12", +# Optional interface to bind to with SO_BINDTODEVICE for URL previews. +# If not set, it will not bind to a specific interface. +# This uses [`reqwest::ClientBuilder::interface`] under the hood. +# +# To list the interfaces on your system, use the command `ip link show` +# +# Example: `"eth0"` +# +#url_preview_bound_interface = + # Vector list of domains allowed to send requests to for URL previews. # Defaults to none. Note: this is a *contains* match, not an explicit # match. Putting "google.com" will match "https://google.com" and diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index cb8f3b87..c613c819 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -1250,6 +1250,16 @@ pub struct Config { #[serde(default = "default_ip_range_denylist")] pub ip_range_denylist: Vec, + /// Optional interface to bind to with SO_BINDTODEVICE for URL previews. + /// If not set, it will not bind to a specific interface. + /// This uses [`reqwest::ClientBuilder::interface`] under the hood. + /// + /// To list the interfaces on your system, use the command `ip link show` + /// + /// Example: `"eth0"` + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + pub url_preview_bound_interface: Option, + /// Vector list of domains allowed to send requests to for URL previews. /// Defaults to none. Note: this is a *contains* match, not an explicit /// match. Putting "google.com" will match "https://google.com" and @@ -1960,6 +1970,15 @@ impl fmt::Display for Config { line("Forbidden room aliases", { &self.forbidden_alias_names.patterns().iter().join(", ") }); + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + line( + "URL preview bound interface", + if let Some(interface) = &self.url_preview_bound_interface { + interface + } else { + "not set" + }, + ); line( "URL preview domain contains allowlist", &self.url_preview_domain_contains_allowlist.join(", "), diff --git a/src/service/client/mod.rs b/src/service/client/mod.rs index 2794efc1..bcd88158 100644 --- a/src/service/client/mod.rs +++ b/src/service/client/mod.rs @@ -25,15 +25,23 @@ impl crate::Service for Service { let config = &args.server.config; let resolver = args.require::("resolver"); + let url_preview_builder = base(config)? + .dns_resolver(resolver.resolver.clone()) + .redirect(redirect::Policy::limited(3)); + + #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] + let url_preview_builder = if let Some(interface) = &config.url_preview_bound_interface { + url_preview_builder.interface(interface) + } else { + url_preview_builder + }; + Ok(Arc::new(Self { default: base(config)? .dns_resolver(resolver.resolver.clone()) .build()?, - url_preview: base(config)? - .dns_resolver(resolver.resolver.clone()) - .redirect(redirect::Policy::limited(3)) - .build()?, + url_preview: url_preview_builder.build()?, extern_media: base(config)? .dns_resolver(resolver.resolver.clone())