diff --git a/src/lib.rs b/src/lib.rs index bdbf7a0..d21d99b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,6 +98,7 @@ impl std::fmt::Display for ProxyType { pub struct Options { virtual_dns: Option, mtu: Option, + dns_over_tcp: bool, } impl Options { @@ -107,6 +108,13 @@ impl Options { pub fn with_virtual_dns(mut self) -> Self { self.virtual_dns = Some(virtdns::VirtualDns::new()); + self.dns_over_tcp = false; + self + } + + pub fn with_dns_over_tcp(mut self) -> Self { + self.dns_over_tcp = true; + self.virtual_dns = None; self } diff --git a/src/main.rs b/src/main.rs index 1502599..6047dd9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,6 +40,10 @@ struct Args { /// Verbosity level #[arg(short, long, value_name = "level", value_enum, default_value = "info")] verbosity: ArgVerbosity, + + /// DNS over TCP + #[arg(long)] + dns_over_tcp: bool, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] @@ -79,6 +83,10 @@ fn main() -> ExitCode { options = options.with_virtual_dns(); } + if args.dns_over_tcp { + options = options.with_dns_over_tcp(); + } + let interface = match args.tun_fd { None => NetworkInterface::Named(args.tun.clone()), Some(fd) => { diff --git a/src/tun2proxy.rs b/src/tun2proxy.rs index c405486..67574c7 100644 --- a/src/tun2proxy.rs +++ b/src/tun2proxy.rs @@ -527,6 +527,30 @@ impl<'a> TunToProxy<'a> { self.send_udp_packet_to_client(origin_dst, connection_info.src, response.as_slice())?; } else { // Another UDP packet + if self.options.dns_over_tcp && port == DNS_PORT { + if !self.connection_map.contains_key(&connection_info) { + log::info!("DNS over TCP {} ({})", connection_info, origin_dst); + let tcp_proxy_handler = manager.new_tcp_proxy(&connection_info, false)?; + #[rustfmt::skip] + let state = self.create_new_tcp_connection_state(server_addr, origin_dst, tcp_proxy_handler, false)?; + self.connection_map.insert(connection_info.clone(), state); + } else { + log::trace!("Subsequent dns over tcp packet {} ({})", connection_info, origin_dst); + } + + let len = payload.len() as u16; + let mut buf = Vec::with_capacity(2 + len as usize); + buf.extend_from_slice(&len.to_be_bytes()); + buf.extend_from_slice(payload); + + // TODO: Build an IP packet and inject it into the device. + self.device.inject_packet(&buf); + + self.expect_smoltcp_send()?; + self.tunsocket_read_and_forward(&connection_info)?; + self.write_to_server(&connection_info)?; + return Ok(()); + } if !self.connection_map.contains_key(&connection_info) { log::info!("UDP associate session {} ({})", connection_info, origin_dst); let tcp_proxy_handler = manager.new_tcp_proxy(&connection_info, true)?;