From d3f76c0e265c3177de3796279473c18a1adc6a0d Mon Sep 17 00:00:00 2001 From: Stuart McLaren Date: Wed, 5 Apr 2023 12:37:00 +0100 Subject: [PATCH] Basic support for freebsd ipfw firewall FreeBSD's ipfw firewall does not rewrite the destination IP address when forwarding using rules such as: 00100 fwd 127.0.0.1,2080 tcp from me to not me 80,443 This commit adds ipfw support by assuming transparent redirection on freebsd. If you create the above rule and point moproxy at a http proxy at IP address 1.2.3.4 $ moproxy -b 127.0.0.1 -p 2080 -t 1.2.3.4:8080 You can fetch remote 443 or 80 ports without setting proxy environment variables, eg: $ curl https://example.com:443 ... --- README.md | 4 ++++ src/client/mod.rs | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/README.md b/README.md index 311708d..e8fc29e 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,12 @@ nft add rule nat prerouting tcp dport {80, 443} redirect to 2080 # or the legacy iptables equivalent iptables -t nat -A OUTPUT -p tcp -m multiport --dports 80,443 -j REDIRECT --to-port 2080 iptables -t nat -A PREROUTING -p tcp -m multiport --dports 80,443 -j REDIRECT --to-port 2080 + +# or ipfw (FreeBSD) +ipfw add 100 fwd 127.0.0.1,2080 tcp from me to not me dst-port 80,443 ``` + SOCKSv5 server is also launched alongs with transparent proxy on the same port: ```bash http_proxy=socks5h://localhost:2080 curl ifconfig.co diff --git a/src/client/mod.rs b/src/client/mod.rs index ba6e970..862a6fb 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -134,6 +134,12 @@ async fn accept_socks5(client: &mut TcpStream) -> io::Result { Ok((addr, port).into()) } +async fn transparent_dest(client: &mut TcpStream) -> io::Result { + // Transparent firewall redirection (unmodified destination address) + // (for example, ipfw firewall with 'fwd' rule) + Ok((client.local_addr()?).into()) +} + impl NewClient { #[instrument(name = "retrieve_dest", skip_all)] pub async fn from_socket(mut left: TcpStream, list: ServerList) -> io::Result { @@ -152,6 +158,9 @@ impl NewClient { #[cfg(not(target_os = "linux"))] let dest: Option = None; + #[cfg(target_os = "freebsd")] + let dest = (transparent_dest(&mut left).await?).into(); + let dest = if let Some(dest) = dest { debug!(?dest, "Retrived destination via NAT info"); dest.into()