use crate::args::TransparentAction;
#[cfg(target_os = "macos")]
use std::process::Command;
#[cfg(target_os = "macos")]
use anyhow::{Result, Context};
#[cfg(target_os = "macos")]
use std::io::Write;
#[cfg(target_os = "macos")]
pub fn handle_transparent_command(action: TransparentAction) -> Result<()> {
match action {
TransparentAction::Generate { port, output, interface } => {
let config = generate_pf_config(port, &interface);
if let Some(path) = output {
std::fs::write(&path, &config)
.with_context(|| format!("Failed to write PF config to {:?}", path))?;
println!("PF configuration written to {:?}", path);
} else {
println!("{}", config);
}
}
TransparentAction::Load { port, interface } => {
if !is_root() {
anyhow::bail!("This command requires root privileges. Please run with sudo.");
}
let config = generate_pf_config(port, &interface);
let mut temp = tempfile::Builder::new()
.prefix("relay_pf_")
.suffix(".conf")
.tempfile()?;
temp.write_all(config.as_bytes())?;
let temp_path = temp.path().to_owned();
let status = Command::new("pfctl")
.args(["-a", "relaycraft", "-f", temp_path.to_str().unwrap()])
.status()
.context("Failed to execute pfctl")?;
if !status.success() {
anyhow::bail!("pfctl failed to load rules");
}
let _ = Command::new("pfctl")
.arg("-e")
.output();
println!("Transparent proxy rules loaded (redirecting TCP to port {} on {}).", port, interface);
}
TransparentAction::Unload => {
if !is_root() {
anyhow::bail!("This command requires root privileges. Please run with sudo.");
}
let status = Command::new("pfctl")
.args(["-a", "relaycraft", "-F", "all"])
.status()
.context("Failed to execute pfctl")?;
if !status.success() {
anyhow::bail!("pfctl failed to unload rules");
}
println!("Transparent proxy rules unloaded.");
}
TransparentAction::Status => {
let output = Command::new("pfctl")
.args(["-a", "relaycraft", "-s", "rules"])
.output()
.context("Failed to execute pfctl")?;
if output.status.success() {
let rules = String::from_utf8_lossy(&output.stdout);
if rules.trim().is_empty() {
println!("No active rules for relaycraft anchor.");
} else {
println!("Active rules for relaycraft anchor:");
println!("{}", rules);
}
} else {
println!("Failed to check status. Are you root?");
}
}
}
Ok(())
}
#[cfg(not(target_os = "macos"))]
pub fn handle_transparent_command(_action: TransparentAction) -> anyhow::Result<()> {
anyhow::bail!("Transparent proxy management is only supported on macOS.");
}
#[cfg(target_os = "macos")]
fn generate_pf_config(port: u16, interface: &str) -> String {
format!(
"# relaycraft transparent proxy rules for {0}
rdr pass on {0} inet proto tcp from any to any port 80 -> 127.0.0.1 port {1}
rdr pass on {0} inet proto tcp from any to any port 443 -> 127.0.0.1 port {1}
",
interface, port
)
}
#[cfg(target_os = "macos")]
fn is_root() -> bool {
Command::new("id")
.arg("-u")
.output()
.map(|output| {
String::from_utf8_lossy(&output.stdout).trim() == "0"
})
.unwrap_or(false)
}