From 5b40a9f1470f2f4d2d8edc7227ddf0ca28de5e0a Mon Sep 17 00:00:00 2001 From: lbl8603 <49143209+lbl8603@users.noreply.github.com> Date: Tue, 23 Apr 2024 08:21:01 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8C=87=E5=AE=9Adns?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnt-cli/README.md | 2 + vnt-cli/src/config/mod.rs | 25 ++---- vnt-cli/src/main.rs | 25 ++---- .../java/top/wherewego/vnt/jni/Config.java | 4 + vnt-jni/src/config.rs | 22 +---- vnt/src/core/conn.rs | 1 + vnt/src/core/mod.rs | 36 +++++--- vnt/src/handle/maintain/idle.rs | 53 ++++++------ vnt/src/handle/mod.rs | 4 +- vnt/src/util/dns_query.rs | 83 ++++++++++--------- 10 files changed, 118 insertions(+), 137 deletions(-) diff --git a/vnt-cli/README.md b/vnt-cli/README.md index 4939c2d..026bac9 100644 --- a/vnt-cli/README.md +++ b/vnt-cli/README.md @@ -121,6 +121,8 @@ first_latency: false #是否优先低延迟通道,默认为false,表示优 device_name: vnt-tun #网卡名称 packet_loss: 0 #指定丢包率 取值0~1之间的数 用于模拟弱网 packet_delay: 0 #指定延迟 单位毫秒 用于模拟弱网 +dns: + - 8.8.8.8:53 ``` 或者需要哪个配置就加哪个,当然token是必须的 diff --git a/vnt-cli/src/config/mod.rs b/vnt-cli/src/config/mod.rs index c1f8870..4c42695 100644 --- a/vnt-cli/src/config/mod.rs +++ b/vnt-cli/src/config/mod.rs @@ -1,5 +1,5 @@ use std::io; -use std::net::{Ipv4Addr, ToSocketAddrs}; +use std::net::Ipv4Addr; use std::str::FromStr; use serde::{Deserialize, Serialize}; @@ -19,6 +19,7 @@ pub struct FileConfig { pub name: String, pub server_address: String, pub stun_server: Vec, + pub dns: Vec, pub in_ips: Vec, pub out_ips: Vec, pub password: Option, @@ -55,6 +56,7 @@ impl Default for FileConfig { "stun2.l.google.com:19302".to_string(), "stun.qq.com:3478".to_string(), ], + dns: vec![], in_ips: vec![], out_ips: vec![], password: None, @@ -91,24 +93,7 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> { if file_conf.token.is_empty() { return Err(io::Error::new(io::ErrorKind::Other, "token is_empty")); } - let server_address = match file_conf.server_address.to_socket_addrs() { - Ok(mut addr) => { - if let Some(addr) = addr.next() { - addr - } else { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("server_address {:?} error", &file_conf.server_address), - )); - } - } - Err(e) => { - return Err(io::Error::new( - io::ErrorKind::Other, - format!("server_address {:?} error:{}", &file_conf.server_address, e), - )); - } - }; + let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) { Ok(in_ips) => in_ips, Err(e) => { @@ -150,8 +135,8 @@ pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> { file_conf.token, file_conf.device_id, file_conf.name, - server_address, file_conf.server_address, + file_conf.dns, file_conf.stun_server, in_ips, out_ips, diff --git a/vnt-cli/src/main.rs b/vnt-cli/src/main.rs index c7796bd..acfed5c 100644 --- a/vnt-cli/src/main.rs +++ b/vnt-cli/src/main.rs @@ -1,4 +1,4 @@ -use std::net::{Ipv4Addr, ToSocketAddrs}; +use std::net::Ipv4Addr; use std::path::PathBuf; use std::str::FromStr; use std::{io, thread}; @@ -72,6 +72,7 @@ fn main() { opts.optopt("", "use-channel", "使用通道 relay/p2p", ""); opts.optopt("", "packet-loss", "丢包率", ""); opts.optopt("", "packet-delay", "延迟", ""); + opts.optmulti("", "dns", "dns", ""); opts.optopt("f", "", "配置文件", ""); //"后台运行时,查看其他设备列表" opts.optflag("", "list", "后台运行时,查看其他设备列表"); @@ -150,27 +151,14 @@ fn main() { let server_address_str = matches .opt_get_default("s", "nat1.wherewego.top:29872".to_string()) .unwrap(); - let server_address = match server_address_str.to_socket_addrs() { - Ok(mut addr) => { - if let Some(addr) = addr.next() { - addr - } else { - println!("parameter '-s {}' error .", server_address_str); - return; - } - } - Err(e) => { - println!("parameter '-s {}' error {}.", server_address_str, e); - return; - } - }; + let mut stun_server = matches.opt_strs("e"); if stun_server.is_empty() { stun_server.push("stun1.l.google.com:19302".to_string()); stun_server.push("stun2.l.google.com:19302".to_string()); stun_server.push("stun.qq.com:3478".to_string()); } - + let dns = matches.opt_strs("dns"); let in_ip = matches.opt_strs("i"); let in_ip = match ips_parse(&in_ip) { Ok(in_ip) => in_ip, @@ -305,8 +293,8 @@ fn main() { token, device_id, name, - server_address, server_address_str, + dns, stun_server, in_ip, out_ip, @@ -423,7 +411,7 @@ fn print_usage(program: &str, _opts: Options) { ); println!(" -n 给设备一个名字,便于区分不同设备,默认使用系统版本"); println!(" -d 设备唯一标识符,不使用--ip参数时,服务端凭此参数分配虚拟ip,注意不能重复"); - println!(" -s 注册和中继服务器地址"); + println!(" -s 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录"); println!(" -e stun服务器,用于探测NAT类型,可多次指定,如-e addr1 -e addr2"); println!(" -a 使用tap模式,默认使用tun模式"); println!(" -i 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); @@ -486,6 +474,7 @@ fn print_usage(program: &str, _opts: Options) { println!( " --packet-delay <0> 模拟延迟,整数,单位毫秒(ms),程序会按设定的值延迟发包,可用于模拟弱网" ); + println!(" --dns DNS服务器地址,可使用多个dns,默认使用8.8.8.8:53"); println!(); println!( diff --git a/vnt-jni/java/top/wherewego/vnt/jni/Config.java b/vnt-jni/java/top/wherewego/vnt/jni/Config.java index 1f13eb3..97f28db 100644 --- a/vnt-jni/java/top/wherewego/vnt/jni/Config.java +++ b/vnt-jni/java/top/wherewego/vnt/jni/Config.java @@ -50,6 +50,10 @@ public class Config { * 服务端地址 */ private String server; + /** + * 服务端地址 + */ + private String[] dns; /** * stun服务地址 */ diff --git a/vnt-jni/src/config.rs b/vnt-jni/src/config.rs index 46d66e0..3854215 100644 --- a/vnt-jni/src/config.rs +++ b/vnt-jni/src/config.rs @@ -21,6 +21,7 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { let password = to_string(env, &config, "password")?; let server_address_str = to_string_not_null(env, &config, "server")?; let stun_server = to_string_array_not_null(env, &config, "stunServer")?; + let dns = to_string_array_not_null(env, &config, "dns")?; let cipher_model = to_string_not_null(env, &config, "cipherModel")?; let punch_model = to_string(env, &config, "punchModel")?; let mtu = to_integer(env, &config, "mtu")?.map(|v| v as u32); @@ -78,25 +79,6 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { vec![] }; - let server_address = match server_address_str.to_socket_addrs() { - Ok(mut rs) => { - if let Some(addr) = rs.next() { - addr - } else { - env.throw_new("java/lang/RuntimeException", "server address err") - .expect("throw"); - return Err(Error::JavaException); - } - } - Err(e) => { - env.throw_new( - "java/lang/RuntimeException", - format!("server address {}", e), - ) - .expect("throw"); - return Err(Error::JavaException); - } - }; let cipher_model = match CipherModel::from_str(&cipher_model) { Ok(cipher_model) => cipher_model, Err(e) => { @@ -113,8 +95,8 @@ pub fn new_config(env: &mut JNIEnv, config: JObject) -> Result { token, device_id, name, - server_address, server_address_str, + dns, stun_server, in_ips, out_ips, diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs index 4110a5a..a2f8020 100644 --- a/vnt/src/core/conn.rs +++ b/vnt/src/core/conn.rs @@ -92,6 +92,7 @@ impl Vnt { config.server_encrypt, config.device_id.clone(), config.server_address_str.clone(), + config.name_servers.clone(), ); let ports = config.ports.as_ref().map_or(vec![0, 0], |v| { if v.is_empty() { diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs index d20345c..daead95 100644 --- a/vnt/src/core/mod.rs +++ b/vnt/src/core/mod.rs @@ -1,12 +1,13 @@ -use std::io; -use std::net::{Ipv4Addr, SocketAddr}; +use anyhow::anyhow; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr}; +use std::str::FromStr; pub use conn::Vnt; use crate::channel::punch::PunchModel; use crate::channel::UseChannelType; use crate::cipher::CipherModel; -use crate::util::RecordPriority; +use crate::util::{address_choose, dns_query_all}; mod conn; @@ -17,9 +18,9 @@ pub struct Config { pub token: String, pub device_id: String, pub name: String, + pub server_address: SocketAddr, pub server_address_str: String, - pub name_servers:Vec, - pub record_priority:RecordPriority, + pub name_servers: Vec, pub stun_server: Vec, pub in_ips: Vec<(u32, u32, Ipv4Addr)>, pub out_ips: Vec<(u32, u32)>, @@ -51,8 +52,7 @@ impl Config { device_id: String, name: String, server_address_str: String, - name_servers:Vec, - record_priority:RecordPriority, + mut name_servers: Vec, mut stun_server: Vec, in_ips: Vec<(u32, u32, Ipv4Addr)>, out_ips: Vec<(u32, u32)>, @@ -72,30 +72,42 @@ impl Config { use_channel_type: UseChannelType, packet_loss_rate: Option, packet_delay: u32, - ) -> io::Result { + ) -> anyhow::Result { for x in stun_server.iter_mut() { if !x.contains(":") { x.push_str(":3478"); } } + for x in name_servers.iter_mut() { + if Ipv6Addr::from_str(x).is_ok() { + x.push_str(":53"); + } else if !x.contains(":") { + x.push_str(":53"); + } + } if token.is_empty() || token.len() > 128 { - return Err(io::Error::new(io::ErrorKind::Other, "token too long")); + return Err(anyhow!("token too long")); } if device_id.is_empty() || device_id.len() > 128 { - return Err(io::Error::new(io::ErrorKind::Other, "device_id too long")); + return Err(anyhow!("device_id too long")); } if name.is_empty() || name.len() > 128 { - return Err(io::Error::new(io::ErrorKind::Other, "name too long")); + return Err(anyhow!("name too long")); } + if name_servers.is_empty() { + name_servers.push("8.8.8.8:53".to_string()); + } + let server_address = + address_choose(dns_query_all(&server_address_str, name_servers.clone())?)?; Ok(Self { #[cfg(any(target_os = "windows", target_os = "linux"))] tap, token, device_id, name, + server_address, server_address_str, name_servers, - record_priority, stun_server, in_ips, out_ips, diff --git a/vnt/src/handle/maintain/idle.rs b/vnt/src/handle/maintain/idle.rs index 7ff6558..403c017 100644 --- a/vnt/src/handle/maintain/idle.rs +++ b/vnt/src/handle/maintain/idle.rs @@ -1,5 +1,5 @@ use std::io; -use std::net::{SocketAddr, ToSocketAddrs}; +use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; @@ -12,7 +12,7 @@ use crate::channel::sender::AcceptSocketSender; use crate::handle::callback::{ConnectInfo, ErrorType}; use crate::handle::handshaker::Handshake; use crate::handle::{BaseConfigInfo, ConnectStatus, CurrentDeviceInfo}; -use crate::util::{dns_query_all, Scheduler}; +use crate::util::{address_choose, dns_query_all, Scheduler}; use crate::{ErrorInfo, VntCallback}; pub fn idle_route( @@ -164,32 +164,35 @@ pub fn domain_request0( let mut current_dev = current_device.load(); // 探测服务端地址变化 - match dns_query_all(&config.server_addr,config.name_servers.clone()) { - Ok(mut addrs) => { - for x in &addrs { - //选出一个能用的地址 - if x.is_ipv4(){ - } - todo!() + match dns_query_all(&config.server_addr, config.name_servers.clone()) { + Ok(addrs) => { + log::info!( + "domain {} dns {:?} addr {:?}", + config.server_addr, + config.name_servers, + addrs + ); - } - if let Some(addr) = addrs.pop() { - if addr != current_dev.connect_server { - let mut tmp = current_dev.clone(); - tmp.connect_server = addr; - let rs = current_device.compare_exchange(current_dev, tmp); - log::info!( - "服务端地址变化,旧地址:{},新地址:{},替换结果:{}", - current_dev.connect_server, - addr, - rs.is_ok() - ); - if rs.is_ok() { - current_dev.connect_server = addr; + match address_choose(addrs) { + Ok(addr) => { + if addr != current_dev.connect_server { + let mut tmp = current_dev.clone(); + tmp.connect_server = addr; + let rs = current_device.compare_exchange(current_dev, tmp); + log::info!( + "服务端地址变化,旧地址:{},新地址:{},替换结果:{}", + current_dev.connect_server, + addr, + rs.is_ok() + ); + if rs.is_ok() { + current_dev.connect_server = addr; + } } } - } else { - log::error!("域名解析值为空,domain={}", config.server_addr); + Err(e) => { + log::error!("域名地址选择失败:{:?},domain={}", e, config.server_addr); + } } } Err(e) => { diff --git a/vnt/src/handle/mod.rs b/vnt/src/handle/mod.rs index 308f8e8..fc0c10d 100644 --- a/vnt/src/handle/mod.rs +++ b/vnt/src/handle/mod.rs @@ -62,7 +62,7 @@ pub struct BaseConfigInfo { pub server_secret: bool, pub device_id: String, pub server_addr: String, - pub name_servers:Vec, + pub name_servers: Vec, } impl BaseConfigInfo { @@ -74,7 +74,7 @@ impl BaseConfigInfo { server_secret: bool, device_id: String, server_addr: String, - name_servers:Vec, + name_servers: Vec, ) -> Self { Self { name, diff --git a/vnt/src/util/dns_query.rs b/vnt/src/util/dns_query.rs index 80155f9..f2eae37 100644 --- a/vnt/src/util/dns_query.rs +++ b/vnt/src/util/dns_query.rs @@ -1,38 +1,40 @@ -use std::{io, thread}; use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket}; use std::str::FromStr; use std::time::Duration; +use std::{io, thread}; 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 { - match s.to_lowercase().trim() { - "ipv4" => Ok(RecordPriority::Ipv4), - "ipv6" => Ok(RecordPriority::Ipv6), - _ => Err(format!("not match '{}', enum: ipv4/ipv6", s)), +/// 后续实现选择延迟最低的可用地址,需要服务端配合 +/// 现在是选择第一个地址,优先ipv6 +pub fn address_choose(addrs: Vec) -> anyhow::Result { + let v4: Vec = addrs.iter().filter(|v| v.is_ipv4()).map(|v| *v).collect(); + let v6: Vec = addrs.iter().filter(|v| v.is_ipv6()).map(|v| *v).collect(); + let check_addr = |addrs: &Vec| -> anyhow::Result { + if !addrs.is_empty() { + let udp = if addrs[0].is_ipv6() { + UdpSocket::bind("[::]:0")? + } else { + UdpSocket::bind("0.0.0.0:0")? + }; + for addr in addrs { + if udp.connect(addr).is_ok() { + return Ok(*addr); + } + } } + Err(anyhow::anyhow!("not connect address")) + }; + if let Ok(addr) = check_addr(&v6) { + return Ok(addr); } + check_addr(&v4) } -impl Default for RecordPriority { - fn default() -> Self { - RecordPriority::Ipv6 - } -} -pub fn dns_query_all( - domain: &str, - name_servers: Vec, -) -> anyhow::Result> { + +pub fn dns_query_all(domain: &str, name_servers: Vec) -> anyhow::Result> { match SocketAddr::from_str(domain) { Ok(addr) => { return Ok(vec![addr]); @@ -43,7 +45,7 @@ pub fn dns_query_all( } let mut err: Option = None; for name_server in name_servers { - if let Some(domain) = domain.strip_prefix("txt:") { + if let Some(domain) = domain.to_lowercase().strip_prefix("txt:") { return txt_dns(domain, name_server); } let end_index = domain @@ -54,10 +56,12 @@ pub fn dns_query_all( .with_context(|| format!("{:?} not port", domain))?; let th1 = { let host = host.to_string(); + let name_server = name_server.clone(); thread::spawn(move || a_dns(host, name_server)) }; let th2 = { let host = host.to_string(); + let name_server = name_server.clone(); thread::spawn(move || aaaa_dns(host, name_server)) }; let mut addr = Vec::new(); @@ -68,7 +72,7 @@ pub fn dns_query_all( } } Err(e) => { - err.replace(anyhow::anyhow!("{}",e)); + err.replace(anyhow::anyhow!("{}", e)); } } match th2.join().unwrap() { @@ -80,9 +84,9 @@ pub fn dns_query_all( Err(e) => { if addr.is_empty() { if let Some(err) = &mut err { - *err = anyhow::anyhow!("{},{}",err,e); + *err = anyhow::anyhow!("{},{}", err, e); } else { - err.replace(anyhow::anyhow!("{}",e)); + err.replace(anyhow::anyhow!("{}", e)); } continue; } @@ -102,10 +106,6 @@ pub fn dns_query_all( } } -pub fn dns_query(domain: &str, name_server: SocketAddr) -> anyhow::Result> { - dns_query_all(domain, vec![name_server]) -} - fn query( udp: &UdpSocket, domain: &str, @@ -120,7 +120,7 @@ fn query( let request = request.to_vec()?; udp.connect(name_server) - .with_context(|| format!("name server {:?} error ", name_server)); + .with_context(|| format!("name server {:?} error ", name_server))?; let mut count = 0; let mut buf = [0; 65536]; let len = loop { @@ -150,8 +150,9 @@ fn query( Ok(message) } -pub fn txt_dns(domain: &str, name_server: SocketAddr) -> anyhow::Result> { - let udp = bind_udp(name_server.is_ipv4())?; +pub fn txt_dns(domain: &str, name_server: String) -> anyhow::Result> { + let name_server: SocketAddr = name_server.parse()?; + let udp = bind_udp(name_server)?; let message = query(&udp, domain, name_server, RecordType::TXT)?; let mut rs = Vec::new(); for record in message.answers() { @@ -166,8 +167,8 @@ pub fn txt_dns(domain: &str, name_server: SocketAddr) -> anyhow::Result io::Result { - let udp = if is_ipv4 { +fn bind_udp(name_server: SocketAddr) -> anyhow::Result { + let udp = if name_server.is_ipv4() { UdpSocket::bind("0.0.0.0:0")? } else { UdpSocket::bind("[::]:0")? @@ -176,8 +177,9 @@ fn bind_udp(is_ipv4: bool) -> io::Result { Ok(udp) } -pub fn a_dns(domain: String, name_server: SocketAddr) -> anyhow::Result> { - let udp = bind_udp(name_server.is_ipv4())?; +pub fn a_dns(domain: String, name_server: String) -> anyhow::Result> { + let name_server: SocketAddr = name_server.parse()?; + let udp = bind_udp(name_server)?; let message = query(&udp, &domain, name_server, RecordType::A)?; let mut rs = Vec::new(); for record in message.answers() { @@ -191,8 +193,9 @@ pub fn a_dns(domain: String, name_server: SocketAddr) -> anyhow::Result anyhow::Result> { - let udp = bind_udp(name_server.is_ipv4())?; +pub fn aaaa_dns(domain: String, name_server: String) -> anyhow::Result> { + let name_server: SocketAddr = name_server.parse()?; + let udp = bind_udp(name_server)?; let message = query(&udp, &domain, name_server, RecordType::AAAA)?; let mut rs = Vec::new(); for record in message.answers() {