diff --git a/README.md b/README.md index 4b89238..09981ec 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ A tunnel interface for HTTP and SOCKS proxies on Linux based on [smoltcp](https: - IPv4 and IPv6 support - GFW evasion mechanism for certain use cases (see [issue #35](https://github.com/blechschmidt/tun2proxy/issues/35)) - SOCKS5 UDP support +- Native support for proxying DNS over TCP ## Build Clone the repository and `cd` into the project folder. Then run the following: @@ -122,6 +123,3 @@ asked to open connections to IPv6 destinations. In such a case, you can disable either through `sysctl -w net.ipv6.conf.all.disable_ipv6=1` and `sysctl -w net.ipv6.conf.default.disable_ipv6=1` or through `ip -6 route del default`, which causes the `libc` resolver (and other software) to not issue DNS AAAA requests for IPv6 addresses. - -## TODO -- Native support for proxying DNS over TCP or TLS diff --git a/src/lib.rs b/src/lib.rs index eac2bbf..4cbffa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,6 +100,7 @@ pub struct Options { virtual_dns: Option, mtu: Option, dns_over_tcp: bool, + dns_addr: Option, ipv6_enabled: bool, } @@ -120,6 +121,11 @@ impl Options { self } + pub fn with_dns_addr(mut self, addr: Option) -> Self { + self.dns_addr = addr; + self + } + pub fn with_ipv6_enabled(mut self) -> Self { self.ipv6_enabled = true; self diff --git a/src/main.rs b/src/main.rs index e579f06..c513d1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,13 +25,13 @@ struct Args { #[arg(short, long, value_parser = Proxy::from_url, value_name = "URL")] proxy: Proxy, - /// DNS handling - #[arg(short, long, value_name = "method", value_enum, default_value = "virtual")] + /// DNS handling strategy + #[arg(short, long, value_name = "strategy", value_enum, default_value = "virtual")] dns: ArgDns, - /// Enable DNS over TCP - #[arg(long)] - dns_over_tcp: bool, + /// DNS resolver address + #[arg(long, value_name = "IP", default_value = "8.8.8.8")] + dns_addr: IpAddr, /// IPv6 enabled #[arg(short = '6', long)] @@ -50,10 +50,15 @@ struct Args { verbosity: ArgVerbosity, } +/// DNS query handling strategy +/// - Virtual: Intercept DNS queries and resolve them locally with a fake IP address +/// - OverTcp: Use TCP to send DNS queries to the DNS server +/// - Direct: Looks as general UDP traffic but change the destination to the DNS server #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] enum ArgDns { Virtual, - None, + OverTcp, + Direct, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] @@ -83,13 +88,17 @@ fn main() -> ExitCode { log::info!("Proxy {proxy_type} server: {addr}"); let mut options = Options::new(); - if args.dns == ArgDns::Virtual { - options = options.with_virtual_dns(); + match args.dns { + ArgDns::Virtual => { + options = options.with_virtual_dns(); + } + ArgDns::OverTcp => { + options = options.with_dns_over_tcp(); + } + _ => {} } - if args.dns_over_tcp { - options = options.with_dns_over_tcp(); - } + options = options.with_dns_addr(Some(args.dns_addr)); if args.ipv6_enabled { options = options.with_ipv6_enabled(); diff --git a/src/tun2proxy.rs b/src/tun2proxy.rs index 88c6fbc..b540053 100644 --- a/src/tun2proxy.rs +++ b/src/tun2proxy.rs @@ -505,7 +505,7 @@ impl<'a> TunToProxy<'a> { let mut info = info; let port = origin_dst.port(); if port == DNS_PORT && info.protocol == IpProtocol::Udp && dns::addr_is_private(&origin_dst) { - let dns_addr: SocketAddr = "8.8.8.8:53".parse()?; // TODO: Configurable + let dns_addr: SocketAddr = (self.options.dns_addr.ok_or("dns_addr")?, DNS_PORT).into(); info.dst = Address::from(dns_addr); } info