mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-06-06 14:50:14 +00:00
trust-dns-proto import
This commit is contained in:
parent
4ebd019cb5
commit
5ce2e85919
4 changed files with 128 additions and 2 deletions
|
@ -25,6 +25,7 @@ prctl = "1.0"
|
||||||
smoltcp = { version = "0.10.0", features = ["std", "phy-tuntap_interface"] }
|
smoltcp = { version = "0.10.0", features = ["std", "phy-tuntap_interface"] }
|
||||||
socks5-impl = { version = "0.5", default-features = false }
|
socks5-impl = { version = "0.5", default-features = false }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
trust-dns-proto = "0.22"
|
||||||
unicase = "2.6.0"
|
unicase = "2.6.0"
|
||||||
url = "2.4"
|
url = "2.4"
|
||||||
|
|
||||||
|
|
104
src/dns.rs
Normal file
104
src/dns.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::{net::IpAddr, str::FromStr};
|
||||||
|
use trust_dns_proto::{
|
||||||
|
op::{Message, ResponseCode},
|
||||||
|
rr::{record_type::RecordType, Name, RData, Record},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "use-rand")]
|
||||||
|
pub fn build_dns_request(
|
||||||
|
domain: &str,
|
||||||
|
query_type: RecordType,
|
||||||
|
used_by_tcp: bool,
|
||||||
|
) -> Result<Vec<u8>, String> {
|
||||||
|
// [dependencies]
|
||||||
|
// rand = "0.8"
|
||||||
|
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||||
|
use trust_dns_proto::op::{header::MessageType, op_code::OpCode, query::Query};
|
||||||
|
let name = Name::from_str(domain).map_err(|e| e.to_string())?;
|
||||||
|
let query = Query::query(name, query_type);
|
||||||
|
let mut msg = Message::new();
|
||||||
|
msg.add_query(query)
|
||||||
|
.set_id(StdRng::from_entropy().gen())
|
||||||
|
.set_op_code(OpCode::Query)
|
||||||
|
.set_message_type(MessageType::Query)
|
||||||
|
.set_recursion_desired(true);
|
||||||
|
let mut msg_buf = msg.to_vec().map_err(|e| e.to_string())?;
|
||||||
|
if used_by_tcp {
|
||||||
|
let mut buf = (msg_buf.len() as u16).to_be_bytes().to_vec();
|
||||||
|
buf.append(&mut msg_buf);
|
||||||
|
Ok(buf)
|
||||||
|
} else {
|
||||||
|
Ok(msg_buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_dns_response(
|
||||||
|
mut request: Message,
|
||||||
|
domain: &str,
|
||||||
|
ip: IpAddr,
|
||||||
|
ttl: u32,
|
||||||
|
) -> Result<Message, String> {
|
||||||
|
let record = match ip {
|
||||||
|
IpAddr::V4(ip) => {
|
||||||
|
let mut record = Record::with(Name::from_str(domain)?, RecordType::A, ttl);
|
||||||
|
record.set_data(Some(RData::A(ip)));
|
||||||
|
record
|
||||||
|
}
|
||||||
|
IpAddr::V6(ip) => {
|
||||||
|
let mut record = Record::with(Name::from_str(domain)?, RecordType::AAAA, ttl);
|
||||||
|
record.set_data(Some(RData::AAAA(ip)));
|
||||||
|
record
|
||||||
|
}
|
||||||
|
};
|
||||||
|
request.add_answer(record);
|
||||||
|
Ok(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_ipaddr_from_dns_message(message: &Message) -> Result<IpAddr, String> {
|
||||||
|
if message.response_code() != ResponseCode::NoError {
|
||||||
|
return Err(format!("{:?}", message.response_code()));
|
||||||
|
}
|
||||||
|
let mut cname = None;
|
||||||
|
for answer in message.answers() {
|
||||||
|
match answer
|
||||||
|
.data()
|
||||||
|
.ok_or("DNS response not contains answer data")?
|
||||||
|
{
|
||||||
|
RData::A(addr) => {
|
||||||
|
return Ok(IpAddr::V4(*addr));
|
||||||
|
}
|
||||||
|
RData::AAAA(addr) => {
|
||||||
|
return Ok(IpAddr::V6(*addr));
|
||||||
|
}
|
||||||
|
RData::CNAME(name) => {
|
||||||
|
cname = Some(name.to_utf8());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(cname) = cname {
|
||||||
|
return Err(cname);
|
||||||
|
}
|
||||||
|
Err(format!("{:?}", message.answers()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_domain_from_dns_message(message: &Message) -> Result<String, String> {
|
||||||
|
let query = message.queries().get(0).ok_or("DnsRequest no query body")?;
|
||||||
|
let name = query.name().to_string();
|
||||||
|
Ok(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_data_to_dns_message(data: &[u8], used_by_tcp: bool) -> Result<Message, String> {
|
||||||
|
if used_by_tcp {
|
||||||
|
if data.len() < 2 {
|
||||||
|
return Err("invalid dns data".into());
|
||||||
|
}
|
||||||
|
let len = u16::from_be_bytes([data[0], data[1]]) as usize;
|
||||||
|
let data = data.get(2..len + 2).ok_or("invalid dns data")?;
|
||||||
|
return parse_data_to_dns_message(data, false);
|
||||||
|
}
|
||||||
|
let message = Message::from_vec(data).map_err(|e| e.to_string())?;
|
||||||
|
Ok(message)
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ use std::{
|
||||||
use tun2proxy::ConnectionManager;
|
use tun2proxy::ConnectionManager;
|
||||||
|
|
||||||
mod android;
|
mod android;
|
||||||
|
mod dns;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod http;
|
mod http;
|
||||||
pub mod setup;
|
pub mod setup;
|
||||||
|
|
|
@ -8,7 +8,6 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
const DNS_TTL: u8 = 30; // TTL in DNS replies in seconds
|
|
||||||
const MAPPING_TIMEOUT: u64 = 60; // Mapping timeout in seconds
|
const MAPPING_TIMEOUT: u64 = 60; // Mapping timeout in seconds
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Debug)]
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
|
@ -57,6 +56,23 @@ impl VirtualDns {
|
||||||
VirtualDns::default()
|
VirtualDns::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// /*
|
||||||
|
pub fn receive_query(&mut self, data: &[u8]) -> Option<Vec<u8>> {
|
||||||
|
use crate::dns;
|
||||||
|
let mut dns_block = || {
|
||||||
|
let message = dns::parse_data_to_dns_message(data, false)?;
|
||||||
|
let qname = dns::extract_domain_from_dns_message(&message)?;
|
||||||
|
if let Some(ip) = self.allocate_ip(qname.clone()) {
|
||||||
|
let message = dns::build_dns_response(message, &qname, ip, 5)?;
|
||||||
|
message.to_vec()
|
||||||
|
} else {
|
||||||
|
Err("Virtual IP space for DNS exhausted".into())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dns_block().ok()
|
||||||
|
}
|
||||||
|
// */
|
||||||
|
/*
|
||||||
pub fn receive_query(&mut self, data: &[u8]) -> Option<Vec<u8>> {
|
pub fn receive_query(&mut self, data: &[u8]) -> Option<Vec<u8>> {
|
||||||
if data.len() < 17 {
|
if data.len() < 17 {
|
||||||
return None;
|
return None;
|
||||||
|
@ -109,6 +125,8 @@ impl VirtualDns {
|
||||||
response[8] = 0;
|
response[8] = 0;
|
||||||
response[9] = 0;
|
response[9] = 0;
|
||||||
|
|
||||||
|
const DNS_TTL: u8 = 30; // TTL in DNS replies in seconds
|
||||||
|
|
||||||
// additional section
|
// additional section
|
||||||
response[10] = 0;
|
response[10] = 0;
|
||||||
response[11] = 0;
|
response[11] = 0;
|
||||||
|
@ -138,7 +156,7 @@ impl VirtualDns {
|
||||||
}
|
}
|
||||||
Some(response)
|
Some(response)
|
||||||
}
|
}
|
||||||
|
// */
|
||||||
fn increment_ip(addr: IpAddr) -> Option<IpAddr> {
|
fn increment_ip(addr: IpAddr) -> Option<IpAddr> {
|
||||||
let mut ip_bytes = match addr as IpAddr {
|
let mut ip_bytes = match addr as IpAddr {
|
||||||
IpAddr::V4(ip) => Vec::<u8>::from(ip.octets()),
|
IpAddr::V4(ip) => Vec::<u8>::from(ip.octets()),
|
||||||
|
@ -239,6 +257,7 @@ impl VirtualDns {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Parse a non-root DNS qname at a specific offset and return the name along with its size.
|
/// Parse a non-root DNS qname at a specific offset and return the name along with its size.
|
||||||
/// DNS packet parsing should be continued after the name.
|
/// DNS packet parsing should be continued after the name.
|
||||||
fn parse_qname(data: &[u8], mut offset: usize) -> Option<(String, usize)> {
|
fn parse_qname(data: &[u8], mut offset: usize) -> Option<(String, usize)> {
|
||||||
|
@ -277,4 +296,5 @@ impl VirtualDns {
|
||||||
|
|
||||||
Some((qname, offset))
|
Some((qname, offset))
|
||||||
}
|
}
|
||||||
|
// */
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue