Skip to content

Commit

Permalink
expose proxy url config on the endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
dignifiedquire committed May 22, 2024
1 parent ae970cd commit f856b2b
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 59 deletions.
68 changes: 68 additions & 0 deletions iroh-net/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use derive_more::Debug;
use futures_lite::{Stream, StreamExt};
use tokio_util::sync::{CancellationToken, WaitForCancellationFuture};
use tracing::{debug, info_span, trace, warn};
use url::Url;

use crate::{
config,
Expand Down Expand Up @@ -58,6 +59,7 @@ pub struct Builder {
concurrent_connections: Option<u32>,
keylog: bool,
discovery: Option<Box<dyn Discovery>>,
proxy_url: Option<Url>,
/// Path for known peers. See [`Builder::peers_data_path`].
peers_path: Option<PathBuf>,
dns_resolver: Option<DnsResolver>,
Expand All @@ -75,6 +77,7 @@ impl Default for Builder {
concurrent_connections: Default::default(),
keylog: Default::default(),
discovery: Default::default(),
proxy_url: None,
peers_path: None,
dns_resolver: None,
#[cfg(any(test, feature = "test-utils"))]
Expand All @@ -100,6 +103,23 @@ impl Builder {
self
}

/// Set an explicit proxy url to proxy all HTTP(S) traffic through.
pub fn proxy_url(mut self, url: Url) -> Self {
self.proxy_url.replace(url);
self
}

/// Set the proxy url from the environment, in this order:
///
/// - `HTTP_PROXY`
/// - `http_proxy`
/// - `HTTPS_PROXY`
/// - `https_proxy`
pub fn proxy_from_env(mut self) -> Self {
self.proxy_url = proxy_url_from_env();
self
}

/// If *keylog* is `true` and the KEYLOGFILE environment variable is present it will be
/// considered a filename to which the TLS pre-master keys are logged. This can be useful
/// to be able to decrypt captured traffic for debugging purposes.
Expand Down Expand Up @@ -225,6 +245,7 @@ impl Builder {
relay_map,
nodes_path: self.peers_path,
discovery: self.discovery,
proxy_url: self.proxy_url,
dns_resolver,
#[cfg(any(test, feature = "test-utils"))]
insecure_skip_relay_cert_verify: self.insecure_skip_relay_cert_verify,
Expand Down Expand Up @@ -831,6 +852,53 @@ fn try_send_rtt_msg(conn: &quinn::Connection, magic_ep: &Endpoint) {
}
}

/// Read a proxy url from the environemnt, in this order
///
/// - `HTTP_PROXY`
/// - `http_proxy`
/// - `HTTPS_PROXY`
/// - `https_proxy`
fn proxy_url_from_env() -> Option<Url> {
if let Some(url) = std::env::var("HTTP_PROXY")
.ok()
.and_then(|s| s.parse::<Url>().ok())
{
if is_cgi() {
warn!("HTTP_PROXY environment variable ignored in CGI");
} else {
return Some(url);
}
}
if let Some(url) = std::env::var("http_proxy")
.ok()
.and_then(|s| s.parse::<Url>().ok())
{
return Some(url);
}
if let Some(url) = std::env::var("HTTPS_PROXY")
.ok()
.and_then(|s| s.parse::<Url>().ok())
{
return Some(url);
}
if let Some(url) = std::env::var("https_proxy")
.ok()
.and_then(|s| s.parse::<Url>().ok())
{
return Some(url);
}

None
}

/// Check if we are being executed in a CGI context.
///
/// If so, a malicious client can send the `Proxy:` header, and it will
/// be in the `HTTP_PROXY` env var. So we don't use it :)
fn is_cgi() -> bool {
std::env::var_os("REQUEST_METHOD").is_some()
}

// TODO: These tests could still be flaky, lets fix that:
// https://github.com/n0-computer/iroh/issues/1183
#[cfg(test)]
Expand Down
15 changes: 15 additions & 0 deletions iroh-net/src/magicsock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use tokio_util::sync::CancellationToken;
use tracing::{
debug, error, error_span, info, info_span, instrument, trace, trace_span, warn, Instrument,
};
use url::Url;
use watchable::Watchable;

use crate::{
Expand Down Expand Up @@ -117,6 +118,9 @@ pub(super) struct Options {
/// configuration.
pub dns_resolver: DnsResolver,

/// Proxy configuration.
pub proxy_url: Option<Url>,

/// Skip verification of SSL certificates from relay servers
///
/// May only be used in tests.
Expand All @@ -132,6 +136,7 @@ impl Default for Options {
relay_map: RelayMap::empty(),
nodes_path: None,
discovery: None,
proxy_url: None,
dns_resolver: crate::dns::default_resolver().clone(),
#[cfg(any(test, feature = "test-utils"))]
insecure_skip_relay_cert_verify: false,
Expand Down Expand Up @@ -170,6 +175,9 @@ pub(super) struct MagicSock {
relay_actor_sender: mpsc::Sender<RelayActorMessage>,
/// String representation of the node_id of this node.
me: String,
/// Proxy
proxy_url: Option<Url>,

/// Used for receiving relay messages.
relay_recv_receiver: flume::Receiver<RelayRecvResult>,
/// Stores wakers, to be called when relay_recv_ch receives new data.
Expand Down Expand Up @@ -249,6 +257,11 @@ impl MagicSock {
self.my_relay.get()
}

/// Get the current proxy configuration.
pub fn proxy_url(&self) -> Option<&Url> {
self.proxy_url.as_ref()
}

/// Sets the relay node with the best latency.
///
/// If we are not connected to any relay nodes, set this to `None`.
Expand Down Expand Up @@ -1283,6 +1296,7 @@ impl Handle {
discovery,
nodes_path,
dns_resolver,
proxy_url,
#[cfg(any(test, feature = "test-utils"))]
insecure_skip_relay_cert_verify,
} = opts;
Expand Down Expand Up @@ -1341,6 +1355,7 @@ impl Handle {
me,
port: AtomicU16::new(port),
secret_key,
proxy_url,
local_addrs: std::sync::RwLock::new((ipv4_addr, ipv6_addr)),
closing: AtomicBool::new(false),
closed: AtomicBool::new(false),
Expand Down
6 changes: 5 additions & 1 deletion iroh-net/src/magicsock/relay_actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,11 @@ impl RelayActor {
let url1 = url.clone();

// building a client dials the relay
let builder = relay::http::ClientBuilder::new(url1.clone())
let mut builder = relay::http::ClientBuilder::new(url1.clone());
if let Some(url) = self.msock.proxy_url() {
builder = builder.proxy_url(url.clone());
}
let builder = builder
.address_family_selector(move || {
let ipv6_reported = ipv6_reported.clone();
Box::pin(async move { ipv6_reported.load(Ordering::Relaxed) })
Expand Down
58 changes: 0 additions & 58 deletions iroh-net/src/relay/http/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,17 +297,6 @@ impl ClientBuilder {
self
}

/// Set the proxy url from the environment, in this order:
///
/// - `HTTP_PROXY`
/// - `http_proxy`
/// - `HTTPS_PROXY`
/// - `https_proxy`
pub fn proxy_from_env(mut self) -> Self {
self.proxy_url = proxy_url_from_env();
self
}

/// Disable http proxy entirely, no matter the environment variables.
pub fn no_proxy(mut self) -> Self {
self.no_proxy = true;
Expand Down Expand Up @@ -1045,53 +1034,6 @@ fn url_port(url: &Url) -> Option<u16> {
}
}

/// Read a proxy url from the environemnt, in this order
///
/// - `HTTP_PROXY`
/// - `http_proxy`
/// - `HTTPS_PROXY`
/// - `https_proxy`
fn proxy_url_from_env() -> Option<Url> {
if let Some(url) = std::env::var("HTTP_PROXY")
.ok()
.and_then(|s| s.parse::<Url>().ok())
{
if is_cgi() {
warn!("HTTP_PROXY environment variable ignored in CGI");
} else {
return Some(url);
}
}
if let Some(url) = std::env::var("http_proxy")
.ok()
.and_then(|s| s.parse::<Url>().ok())
{
return Some(url);
}
if let Some(url) = std::env::var("HTTPS_PROXY")
.ok()
.and_then(|s| s.parse::<Url>().ok())
{
return Some(url);
}
if let Some(url) = std::env::var("https_proxy")
.ok()
.and_then(|s| s.parse::<Url>().ok())
{
return Some(url);
}

None
}

/// Check if we are being executed in a CGI context.
///
/// If so, a malicious client can send the `Proxy:` header, and it will
/// be in the `HTTP_PROXY` env var. So we don't use it :)
fn is_cgi() -> bool {
std::env::var_os("REQUEST_METHOD").is_some()
}

#[cfg(test)]
mod tests {
use anyhow::{bail, Result};
Expand Down

0 comments on commit f856b2b

Please sign in to comment.