dns解析
This commit is contained in:
@@ -32,6 +32,9 @@ libsm = {git="https://github.com/lbl8603/libsm" ,optional = true}
|
|||||||
|
|
||||||
mio = {version = "0.8.10",features = ["os-poll","net"]}
|
mio = {version = "0.8.10",features = ["os-poll","net"]}
|
||||||
crossbeam-queue = "0.3.11"
|
crossbeam-queue = "0.3.11"
|
||||||
|
anyhow = "1.0.82"
|
||||||
|
trust-dns-proto = "0.23.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
libloading = "0.8.0"
|
libloading = "0.8.0"
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -6,6 +6,7 @@ pub use conn::Vnt;
|
|||||||
use crate::channel::punch::PunchModel;
|
use crate::channel::punch::PunchModel;
|
||||||
use crate::channel::UseChannelType;
|
use crate::channel::UseChannelType;
|
||||||
use crate::cipher::CipherModel;
|
use crate::cipher::CipherModel;
|
||||||
|
use crate::util::RecordPriority;
|
||||||
|
|
||||||
mod conn;
|
mod conn;
|
||||||
|
|
||||||
@@ -16,8 +17,9 @@ pub struct Config {
|
|||||||
pub token: String,
|
pub token: String,
|
||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub server_address: SocketAddr,
|
|
||||||
pub server_address_str: String,
|
pub server_address_str: String,
|
||||||
|
pub name_servers:Vec<SocketAddr>,
|
||||||
|
pub record_priority:RecordPriority,
|
||||||
pub stun_server: Vec<String>,
|
pub stun_server: Vec<String>,
|
||||||
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
pub in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
pub out_ips: Vec<(u32, u32)>,
|
pub out_ips: Vec<(u32, u32)>,
|
||||||
@@ -48,8 +50,9 @@ impl Config {
|
|||||||
token: String,
|
token: String,
|
||||||
device_id: String,
|
device_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
server_address: SocketAddr,
|
|
||||||
server_address_str: String,
|
server_address_str: String,
|
||||||
|
name_servers:Vec<SocketAddr>,
|
||||||
|
record_priority:RecordPriority,
|
||||||
mut stun_server: Vec<String>,
|
mut stun_server: Vec<String>,
|
||||||
in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
in_ips: Vec<(u32, u32, Ipv4Addr)>,
|
||||||
out_ips: Vec<(u32, u32)>,
|
out_ips: Vec<(u32, u32)>,
|
||||||
@@ -90,8 +93,9 @@ impl Config {
|
|||||||
token,
|
token,
|
||||||
device_id,
|
device_id,
|
||||||
name,
|
name,
|
||||||
server_address,
|
|
||||||
server_address_str,
|
server_address_str,
|
||||||
|
name_servers,
|
||||||
|
record_priority,
|
||||||
stun_server,
|
stun_server,
|
||||||
in_ips,
|
in_ips,
|
||||||
out_ips,
|
out_ips,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::channel::sender::AcceptSocketSender;
|
|||||||
use crate::handle::callback::{ConnectInfo, ErrorType};
|
use crate::handle::callback::{ConnectInfo, ErrorType};
|
||||||
use crate::handle::handshaker::Handshake;
|
use crate::handle::handshaker::Handshake;
|
||||||
use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
|
use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo};
|
||||||
use crate::util::Scheduler;
|
use crate::util::{dns_query_all, Scheduler};
|
||||||
use crate::{ErrorInfo, VntCallback};
|
use crate::{ErrorInfo, VntCallback};
|
||||||
|
|
||||||
pub fn idle_route<Call: VntCallback>(
|
pub fn idle_route<Call: VntCallback>(
|
||||||
@@ -162,10 +162,18 @@ pub fn domain_request0(
|
|||||||
config: &BaseConfigInfo,
|
config: &BaseConfigInfo,
|
||||||
) -> CurrentDeviceInfo {
|
) -> CurrentDeviceInfo {
|
||||||
let mut current_dev = current_device.load();
|
let mut current_dev = current_device.load();
|
||||||
|
|
||||||
// 探测服务端地址变化
|
// 探测服务端地址变化
|
||||||
match config.server_addr.to_socket_addrs() {
|
match dns_query_all(&config.server_addr,config.name_servers.clone()) {
|
||||||
Ok(mut addr) => {
|
Ok(mut addrs) => {
|
||||||
if let Some(addr) = addr.next() {
|
for x in &addrs {
|
||||||
|
//选出一个能用的地址
|
||||||
|
if x.is_ipv4(){
|
||||||
|
}
|
||||||
|
todo!()
|
||||||
|
|
||||||
|
}
|
||||||
|
if let Some(addr) = addrs.pop() {
|
||||||
if addr != current_dev.connect_server {
|
if addr != current_dev.connect_server {
|
||||||
let mut tmp = current_dev.clone();
|
let mut tmp = current_dev.clone();
|
||||||
tmp.connect_server = addr;
|
tmp.connect_server = addr;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ pub struct BaseConfigInfo {
|
|||||||
pub server_secret: bool,
|
pub server_secret: bool,
|
||||||
pub device_id: String,
|
pub device_id: String,
|
||||||
pub server_addr: String,
|
pub server_addr: String,
|
||||||
|
pub name_servers:Vec<SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BaseConfigInfo {
|
impl BaseConfigInfo {
|
||||||
@@ -73,6 +74,7 @@ impl BaseConfigInfo {
|
|||||||
server_secret: bool,
|
server_secret: bool,
|
||||||
device_id: String,
|
device_id: String,
|
||||||
server_addr: String,
|
server_addr: String,
|
||||||
|
name_servers:Vec<SocketAddr>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
@@ -82,6 +84,7 @@ impl BaseConfigInfo {
|
|||||||
server_secret,
|
server_secret,
|
||||||
device_id,
|
device_id,
|
||||||
server_addr,
|
server_addr,
|
||||||
|
name_servers,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,228 @@
|
|||||||
|
use std::{io, thread};
|
||||||
|
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use trust_dns_proto::op::{Edns, Message, MessageType, OpCode, Query};
|
||||||
|
use trust_dns_proto::rr::{Name, RecordType};
|
||||||
|
use trust_dns_proto::xfer::DnsRequestOptions;
|
||||||
|
|
||||||
|
/// 解析记录优先级
|
||||||
|
pub enum RecordPriority{
|
||||||
|
Ipv4,
|
||||||
|
Ipv6,
|
||||||
|
}
|
||||||
|
impl FromStr for RecordPriority {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.to_lowercase().trim() {
|
||||||
|
"ipv4" => Ok(RecordPriority::Ipv4),
|
||||||
|
"ipv6" => Ok(RecordPriority::Ipv6),
|
||||||
|
_ => Err(format!("not match '{}', enum: ipv4/ipv6", s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for RecordPriority {
|
||||||
|
fn default() -> Self {
|
||||||
|
RecordPriority::Ipv6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn dns_query_all(
|
||||||
|
domain: &str,
|
||||||
|
name_servers: Vec<SocketAddr>,
|
||||||
|
) -> anyhow::Result<Vec<SocketAddr>> {
|
||||||
|
match SocketAddr::from_str(domain) {
|
||||||
|
Ok(addr) => {
|
||||||
|
return Ok(vec![addr]);
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
if name_servers.is_empty() {
|
||||||
|
Err(anyhow::anyhow!("name server is none"))?
|
||||||
|
}
|
||||||
|
let mut err: Option<anyhow::Error> = None;
|
||||||
|
for name_server in name_servers {
|
||||||
|
if let Some(domain) = domain.strip_prefix("txt:") {
|
||||||
|
return txt_dns(domain, name_server);
|
||||||
|
}
|
||||||
|
let end_index = domain
|
||||||
|
.rfind(":")
|
||||||
|
.with_context(|| format!("{:?} not port", domain))?;
|
||||||
|
let host = &domain[..end_index];
|
||||||
|
let port = u16::from_str(&domain[end_index + 1..])
|
||||||
|
.with_context(|| format!("{:?} not port", domain))?;
|
||||||
|
let th1 = {
|
||||||
|
let host = host.to_string();
|
||||||
|
thread::spawn(move || a_dns(host, name_server))
|
||||||
|
};
|
||||||
|
let th2 = {
|
||||||
|
let host = host.to_string();
|
||||||
|
thread::spawn(move || aaaa_dns(host, name_server))
|
||||||
|
};
|
||||||
|
let mut addr = Vec::new();
|
||||||
|
match th1.join().unwrap() {
|
||||||
|
Ok(rs) => {
|
||||||
|
for ip in rs {
|
||||||
|
addr.push(SocketAddr::new(ip.into(), port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
err.replace(anyhow::anyhow!("{}",e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match th2.join().unwrap() {
|
||||||
|
Ok(rs) => {
|
||||||
|
for ip in rs {
|
||||||
|
addr.push(SocketAddr::new(ip.into(), port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if addr.is_empty() {
|
||||||
|
if let Some(err) = &mut err {
|
||||||
|
*err = anyhow::anyhow!("{},{}",err,e);
|
||||||
|
} else {
|
||||||
|
err.replace(anyhow::anyhow!("{}",e));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if addr.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return Ok(addr);
|
||||||
|
}
|
||||||
|
if let Some(e) = err {
|
||||||
|
Err(e)
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!("dns query failed"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dns_query(domain: &str, name_server: SocketAddr) -> anyhow::Result<Vec<SocketAddr>> {
|
||||||
|
dns_query_all(domain, vec![name_server])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query(
|
||||||
|
udp: &UdpSocket,
|
||||||
|
domain: &str,
|
||||||
|
name_server: SocketAddr,
|
||||||
|
record_type: RecordType,
|
||||||
|
) -> anyhow::Result<Message> {
|
||||||
|
let name = Name::from_str(domain).context("domain error")?;
|
||||||
|
let query = Query::query(name.clone(), record_type);
|
||||||
|
let mut options = DnsRequestOptions::default();
|
||||||
|
options.use_edns = true;
|
||||||
|
let request = build_message(query, options);
|
||||||
|
|
||||||
|
let request = request.to_vec()?;
|
||||||
|
udp.connect(name_server)
|
||||||
|
.with_context(|| format!("name server {:?} error ", name_server));
|
||||||
|
let mut count = 0;
|
||||||
|
let mut buf = [0; 65536];
|
||||||
|
let len = loop {
|
||||||
|
udp.send(&request)?;
|
||||||
|
|
||||||
|
match udp.recv(&mut buf) {
|
||||||
|
Ok(len) => {
|
||||||
|
break len;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
if e.kind() == io::ErrorKind::TimedOut || e.kind() == io::ErrorKind::WouldBlock {
|
||||||
|
count += 1;
|
||||||
|
if count < 3 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e).with_context(|| format!("name server {:?} recv error ", name_server))?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let message = Message::from_vec(&buf[..len])
|
||||||
|
.with_context(|| format!("name server {:?} data error ", name_server))?;
|
||||||
|
if message.answers().is_empty() {
|
||||||
|
Err(anyhow::anyhow!("{:?} no {} record", domain, record_type))?
|
||||||
|
}
|
||||||
|
Ok(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn txt_dns(domain: &str, name_server: SocketAddr) -> anyhow::Result<Vec<SocketAddr>> {
|
||||||
|
let udp = bind_udp(name_server.is_ipv4())?;
|
||||||
|
let message = query(&udp, domain, name_server, RecordType::TXT)?;
|
||||||
|
let mut rs = Vec::new();
|
||||||
|
for record in message.answers() {
|
||||||
|
let txt = record
|
||||||
|
.data()
|
||||||
|
.context("data none")?
|
||||||
|
.as_txt()
|
||||||
|
.context("record type txt is none")?;
|
||||||
|
let addr = SocketAddr::from_str(&txt.to_string())?;
|
||||||
|
rs.push(addr);
|
||||||
|
}
|
||||||
|
Ok(rs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_udp(is_ipv4: bool) -> io::Result<UdpSocket> {
|
||||||
|
let udp = if is_ipv4 {
|
||||||
|
UdpSocket::bind("0.0.0.0:0")?
|
||||||
|
} else {
|
||||||
|
UdpSocket::bind("[::]:0")?
|
||||||
|
};
|
||||||
|
udp.set_read_timeout(Some(Duration::from_millis(800)))?;
|
||||||
|
Ok(udp)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn a_dns(domain: String, name_server: SocketAddr) -> anyhow::Result<Vec<Ipv4Addr>> {
|
||||||
|
let udp = bind_udp(name_server.is_ipv4())?;
|
||||||
|
let message = query(&udp, &domain, name_server, RecordType::A)?;
|
||||||
|
let mut rs = Vec::new();
|
||||||
|
for record in message.answers() {
|
||||||
|
let a = record
|
||||||
|
.data()
|
||||||
|
.context("data none")?
|
||||||
|
.as_a()
|
||||||
|
.context("record type A is none")?;
|
||||||
|
rs.push(a.0);
|
||||||
|
}
|
||||||
|
Ok(rs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn aaaa_dns(domain: String, name_server: SocketAddr) -> anyhow::Result<Vec<Ipv6Addr>> {
|
||||||
|
let udp = bind_udp(name_server.is_ipv4())?;
|
||||||
|
let message = query(&udp, &domain, name_server, RecordType::AAAA)?;
|
||||||
|
let mut rs = Vec::new();
|
||||||
|
for record in message.answers() {
|
||||||
|
let a = record
|
||||||
|
.data()
|
||||||
|
.context("data none")?
|
||||||
|
.as_aaaa()
|
||||||
|
.context("record type AAAA is none")?;
|
||||||
|
rs.push(a.0);
|
||||||
|
}
|
||||||
|
Ok(rs)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MAX_PAYLOAD_LEN: u16 = 1232;
|
||||||
|
|
||||||
|
fn build_message(query: Query, options: DnsRequestOptions) -> Message {
|
||||||
|
// build the message
|
||||||
|
let mut message: Message = Message::new();
|
||||||
|
message
|
||||||
|
.add_query(query)
|
||||||
|
.set_message_type(MessageType::Query)
|
||||||
|
.set_op_code(OpCode::Query)
|
||||||
|
.set_recursion_desired(options.recursion_desired);
|
||||||
|
// Extended dns
|
||||||
|
if options.use_edns {
|
||||||
|
message
|
||||||
|
.extensions_mut()
|
||||||
|
.get_or_insert_with(Edns::new)
|
||||||
|
.set_max_payload(MAX_PAYLOAD_LEN)
|
||||||
|
.set_version(0);
|
||||||
|
}
|
||||||
|
message
|
||||||
|
}
|
||||||
@@ -7,3 +7,6 @@ pub use scheduler::Scheduler;
|
|||||||
|
|
||||||
mod counter;
|
mod counter;
|
||||||
pub use counter::*;
|
pub use counter::*;
|
||||||
|
|
||||||
|
mod dns_query;
|
||||||
|
pub use dns_query::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user