mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-06-08 07:37:41 +00:00
Support multiple DNS queries with DNS over TCP
This commit is contained in:
parent
3b5f803da8
commit
edb775941e
1 changed files with 38 additions and 20 deletions
|
@ -8,7 +8,7 @@ use smoltcp::{
|
||||||
wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket, UDP_HEADER_LEN},
|
wire::{IpCidr, IpProtocol, Ipv4Packet, Ipv6Packet, TcpPacket, UdpPacket, UDP_HEADER_LEN},
|
||||||
};
|
};
|
||||||
use socks5_impl::protocol::{Address, StreamOperation, UdpHeader, UserKey};
|
use socks5_impl::protocol::{Address, StreamOperation, UdpHeader, UserKey};
|
||||||
use std::{collections::LinkedList, convert::TryInto};
|
use std::collections::LinkedList;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
convert::{From, TryFrom},
|
convert::{From, TryFrom},
|
||||||
|
@ -185,6 +185,7 @@ struct TcpConnectState {
|
||||||
udp_data_cache: LinkedList<Vec<u8>>,
|
udp_data_cache: LinkedList<Vec<u8>>,
|
||||||
udp_over_tcp_expiry: Option<::std::time::Instant>,
|
udp_over_tcp_expiry: Option<::std::time::Instant>,
|
||||||
udp_over_tcp_data_cache: LinkedList<Vec<u8>>,
|
udp_over_tcp_data_cache: LinkedList<Vec<u8>>,
|
||||||
|
is_tcp_dns: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait TcpProxy {
|
pub(crate) trait TcpProxy {
|
||||||
|
@ -461,15 +462,7 @@ impl<'a> TunToProxy<'a> {
|
||||||
fn preprocess_origin_connection_info(&mut self, info: ConnectionInfo) -> Result<ConnectionInfo> {
|
fn preprocess_origin_connection_info(&mut self, info: ConnectionInfo) -> Result<ConnectionInfo> {
|
||||||
let origin_dst = SocketAddr::try_from(&info.dst)?;
|
let origin_dst = SocketAddr::try_from(&info.dst)?;
|
||||||
let connection_info = match &mut self.options.virtual_dns {
|
let connection_info = match &mut self.options.virtual_dns {
|
||||||
None => {
|
None => info,
|
||||||
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
|
|
||||||
info.dst = Address::from(dns_addr);
|
|
||||||
}
|
|
||||||
info
|
|
||||||
}
|
|
||||||
Some(virtual_dns) => {
|
Some(virtual_dns) => {
|
||||||
let dst_ip = origin_dst.ip();
|
let dst_ip = origin_dst.ip();
|
||||||
virtual_dns.touch_ip(&dst_ip);
|
virtual_dns.touch_ip(&dst_ip);
|
||||||
|
@ -485,17 +478,25 @@ impl<'a> TunToProxy<'a> {
|
||||||
fn process_incoming_udp_packets_dns_over_tcp(
|
fn process_incoming_udp_packets_dns_over_tcp(
|
||||||
&mut self,
|
&mut self,
|
||||||
manager: &Rc<dyn ConnectionManager>,
|
manager: &Rc<dyn ConnectionManager>,
|
||||||
info: &ConnectionInfo,
|
original_info: &ConnectionInfo,
|
||||||
origin_dst: SocketAddr,
|
origin_dst: SocketAddr,
|
||||||
payload: &[u8],
|
payload: &[u8],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
_ = dns::parse_data_to_dns_message(payload, false)?;
|
_ = dns::parse_data_to_dns_message(payload, false)?;
|
||||||
|
let mut new_info = original_info.clone();
|
||||||
|
let dns_addr: SocketAddr = "8.8.8.8:53".parse()?;
|
||||||
|
new_info.dst = Address::from(dns_addr);
|
||||||
|
|
||||||
|
let info = &new_info;
|
||||||
|
|
||||||
if !self.connection_map.contains_key(info) {
|
if !self.connection_map.contains_key(info) {
|
||||||
log::info!("DNS over TCP {} ({})", info, origin_dst);
|
log::info!("DNS over TCP {} ({})", info, origin_dst);
|
||||||
|
|
||||||
let tcp_proxy_handler = manager.new_tcp_proxy(info, false)?;
|
let tcp_proxy_handler = manager.new_tcp_proxy(info, false)?;
|
||||||
let server_addr = manager.get_server_addr();
|
let server_addr = manager.get_server_addr();
|
||||||
let state = self.create_new_tcp_connection_state(server_addr, origin_dst, tcp_proxy_handler, false)?;
|
let mut state = self.create_new_tcp_connection_state(server_addr, origin_dst, tcp_proxy_handler, false)?;
|
||||||
|
state.is_tcp_dns = true;
|
||||||
|
state.udp_origin_dst = Some(SocketAddr::try_from(original_info.dst.clone())?);
|
||||||
self.connection_map.insert(info.clone(), state);
|
self.connection_map.insert(info.clone(), state);
|
||||||
|
|
||||||
self.expect_smoltcp_send()?;
|
self.expect_smoltcp_send()?;
|
||||||
|
@ -538,20 +539,33 @@ impl<'a> TunToProxy<'a> {
|
||||||
assert!(state.udp_over_tcp_expiry.is_some());
|
assert!(state.udp_over_tcp_expiry.is_some());
|
||||||
state.udp_over_tcp_expiry = Some(Self::common_udp_life_timeout());
|
state.udp_over_tcp_expiry = Some(Self::common_udp_life_timeout());
|
||||||
|
|
||||||
let mut buf = Vec::<u8>::new();
|
// Code similar to the code in parent function. TODO: Cleanup.
|
||||||
let read = match state.mio_stream.read_to_end(&mut buf) {
|
let mut vecbuf = Vec::<u8>::new();
|
||||||
|
let read_result = state.mio_stream.read_to_end(&mut vecbuf);
|
||||||
|
let read = match read_result {
|
||||||
Ok(read_result) => read_result,
|
Ok(read_result) => read_result,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
if error.kind() != std::io::ErrorKind::WouldBlock {
|
if error.kind() != std::io::ErrorKind::WouldBlock {
|
||||||
log::error!("{} Read from proxy: {}", info.dst, error);
|
log::error!("{} Read from proxy: {}", info.dst, error);
|
||||||
}
|
}
|
||||||
buf.len()
|
vecbuf.len()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if read == 0 {
|
|
||||||
|
let data = vecbuf.as_slice();
|
||||||
|
let data_event = IncomingDataEvent {
|
||||||
|
direction: IncomingDirection::FromServer,
|
||||||
|
buffer: &data[0..read],
|
||||||
|
};
|
||||||
|
if let Err(error) = state.tcp_proxy_handler.push_data(data_event) {
|
||||||
|
log::error!("{}", error);
|
||||||
|
self.remove_connection(&info.clone())?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let mut buf = buf[..read].to_vec();
|
|
||||||
|
let dns_event = state.tcp_proxy_handler.peek_data(OutgoingDirection::ToClient);
|
||||||
|
|
||||||
|
let mut buf = dns_event.buffer.to_vec();
|
||||||
let mut to_send: LinkedList<Vec<u8>> = LinkedList::new();
|
let mut to_send: LinkedList<Vec<u8>> = LinkedList::new();
|
||||||
loop {
|
loop {
|
||||||
if buf.len() < 2 {
|
if buf.len() < 2 {
|
||||||
|
@ -566,8 +580,10 @@ impl<'a> TunToProxy<'a> {
|
||||||
let message = dns::parse_data_to_dns_message(&data, false)?;
|
let message = dns::parse_data_to_dns_message(&data, false)?;
|
||||||
let name = dns::extract_domain_from_dns_message(&message)?;
|
let name = dns::extract_domain_from_dns_message(&message)?;
|
||||||
let ip = dns::extract_ipaddr_from_dns_message(&message)?;
|
let ip = dns::extract_ipaddr_from_dns_message(&message)?;
|
||||||
log::trace!("DNS over TCP ======== {} -> {}", name, ip);
|
log::info!("DNS over TCP ======== {} -> {}", name, ip);
|
||||||
|
state
|
||||||
|
.tcp_proxy_handler
|
||||||
|
.consume_data(OutgoingDirection::ToClient, len + 2);
|
||||||
to_send.push_back(data);
|
to_send.push_back(data);
|
||||||
if len + 2 == buf.len() {
|
if len + 2 == buf.len() {
|
||||||
break;
|
break;
|
||||||
|
@ -576,7 +592,7 @@ impl<'a> TunToProxy<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to client
|
// Write to client
|
||||||
let src = info.dst.clone().try_into()?;
|
let src = state.udp_origin_dst.ok_or("Expected UDP addr")?;
|
||||||
while let Some(packet) = to_send.pop_front() {
|
while let Some(packet) = to_send.pop_front() {
|
||||||
self.send_udp_packet_to_client(src, info.src, &packet)?;
|
self.send_udp_packet_to_client(src, info.src, &packet)?;
|
||||||
}
|
}
|
||||||
|
@ -767,6 +783,7 @@ impl<'a> TunToProxy<'a> {
|
||||||
udp_data_cache: LinkedList::new(),
|
udp_data_cache: LinkedList::new(),
|
||||||
udp_over_tcp_expiry: None,
|
udp_over_tcp_expiry: None,
|
||||||
udp_over_tcp_data_cache: LinkedList::new(),
|
udp_over_tcp_data_cache: LinkedList::new(),
|
||||||
|
is_tcp_dns: false,
|
||||||
};
|
};
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
@ -980,6 +997,7 @@ impl<'a> TunToProxy<'a> {
|
||||||
.connection_established();
|
.connection_established();
|
||||||
if self.options.dns_over_tcp && conn_info.dst.port() == DNS_PORT && established {
|
if self.options.dns_over_tcp && conn_info.dst.port() == DNS_PORT && established {
|
||||||
self.receive_dns_over_tcp_packet_and_write_to_client(&conn_info)?;
|
self.receive_dns_over_tcp_packet_and_write_to_client(&conn_info)?;
|
||||||
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
let e = "connection state not found";
|
let e = "connection state not found";
|
||||||
let state = self.connection_map.get_mut(&conn_info).ok_or(e)?;
|
let state = self.connection_map.get_mut(&conn_info).ok_or(e)?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue