From 440a832ace6931fdc155d83522748489dbb54198 Mon Sep 17 00:00:00 2001
From: lbl8603 <49143209+lbl8603@users.noreply.github.com>
Date: Wed, 15 May 2024 20:30:42 +0800
Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9D=A1=E4=BB=B6=E7=BC=96?=
=?UTF-8?q?=E8=AF=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Cargo.lock | 1 +
README.md | 16 +++
vnt-cli/Cargo.toml | 8 +-
vnt-cli/src/config/mod.rs | 173 ++-------------------------------
vnt-cli/src/main.rs | 107 +++++++++++---------
vnt/src/core/conn.rs | 10 +-
vnt/src/core/mod.rs | 30 ++++++
vnt/src/ip_proxy/icmp_proxy.rs | 56 +++++------
vnt/src/util/dns_query.rs | 17 ++--
9 files changed, 156 insertions(+), 262 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index b785879..cd67c2e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1625,6 +1625,7 @@ dependencies = [
name = "vnt-cli"
version = "1.2.9"
dependencies = [
+ "anyhow",
"chrono",
"common",
"console",
diff --git a/README.md b/README.md
index aa14b66..7017090 100644
--- a/README.md
+++ b/README.md
@@ -85,24 +85,33 @@ features说明
| server_encrypt | 支持服务端加密 | 是 |
| ip_proxy | 内置ip代理 | 是 |
| port_mapping | 端口映射 | 是 |
+| log | 日志 | 是 |
+| command | list、route等命令 | 是 |
+| file_config | yaml配置文件 | 是 |
### ip转发/代理
+
如果编译时去除了内置的ip代理(或使用--no-proxy关闭了代理),则可以使用网卡NAT转发来实现点对网,
一般来说使用网卡NAT转发会比内置的ip代理性能更好
NAT配置可参考如下示例,点击展开
### 在出口一端做如下配置
+
注意原有的-i(入口)和-o(出口)的参数不能少
### windows
+
参考 https://learn.microsoft.com/zh-cn/virtualization/hyper-v-on-windows/user-guide/setup-nat-network
+
```shell
#设置nat,名字可以自己取,网段是vnt的网段
New-NetNat -Name vntnat -InternalIPInterfaceAddressPrefix 10.26.0.0/24
#查看设置
Get-NetNat
```
+
### linux
+
```shell
# 开启ip转发
sudo sysctl -w net.ipv4.ip_forward=1
@@ -145,6 +154,7 @@ sudo iptables-restore iptables.rules
```
### macos
+
```shell
# 开启ip转发
sudo sysctl -w net.ipv4.ip_forward=1
@@ -154,6 +164,7 @@ nat on en0 from 10.26.0.0/24 to any -> (en0)
# 加载规则
sudo pfctl -f /etc/pf.conf -e
```
+
### 支持平台
@@ -256,10 +267,15 @@ vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
2. 如果p2p后效果很差,可以选择禁用p2p(vnt-cli增加--use-channel relay 参数)
#### 问题4:重启后虚拟IP发生变化,或指定了IP不能启动
+
##### 可能原因:
+
设备重启后程序自动获取的id值改变,导致注册时重新分配了新的IP,或是IP冲突
+
##### 解决方法:
+
1. 命令行启动增加-d参数(使用配置文件启动则在配置文件中增加device_id参数),要保证每个设备的值都不一样,取值可以任意64位以内字符串
+
### 交流群
diff --git a/vnt-cli/Cargo.toml b/vnt-cli/Cargo.toml
index 80eede1..e591254 100644
--- a/vnt-cli/Cargo.toml
+++ b/vnt-cli/Cargo.toml
@@ -14,7 +14,8 @@ os_info = "3.7.0"
serde = "1.0"
serde_yaml = "0.9.32"
log = "0.4.17"
-log4rs = "1.2.0"
+log4rs = { version = "1.2.0", optional = true }
+anyhow = "1.0.82"
[dependencies.uuid]
version = "1.4.1"
features = [
@@ -28,7 +29,7 @@ sudo = "0.6.0"
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
[features]
-default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "ip_proxy", "port_mapping"]
+default = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "ip_proxy", "port_mapping", "log", "command", "file_config"]
openssl = ["vnt/openssl"]
openssl-vendored = ["vnt/openssl-vendored"]
ring-cipher = ["vnt/ring-cipher"]
@@ -39,6 +40,9 @@ aes_gcm = ["vnt/aes_gcm"]
server_encrypt = ["vnt/server_encrypt"]
ip_proxy = ["vnt/ip_proxy"]
port_mapping = ["vnt/port_mapping"]
+log = ["log4rs"]
+command = []
+file_config = []
[build-dependencies]
embed-manifest = "1.4.0"
rand = "0.8.5"
diff --git a/vnt-cli/src/config/mod.rs b/vnt-cli/src/config/mod.rs
index 0cbe330..4472e71 100644
--- a/vnt-cli/src/config/mod.rs
+++ b/vnt-cli/src/config/mod.rs
@@ -1,171 +1,12 @@
-use std::io;
-use std::net::Ipv4Addr;
-use std::str::FromStr;
+#[cfg(feature = "file_config")]
+mod file_config;
-use serde::{Deserialize, Serialize};
+#[cfg(feature = "file_config")]
+pub use file_config::read_config;
-use vnt::channel::punch::PunchModel;
-use vnt::channel::UseChannelType;
-use vnt::cipher::CipherModel;
-use vnt::core::Config;
-
-#[derive(Serialize, Deserialize, Debug)]
-#[serde(default)]
-pub struct FileConfig {
- #[cfg(target_os = "windows")]
- pub tap: bool,
- pub token: String,
- pub device_id: String,
- 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,
- pub mtu: Option,
- pub tcp: bool,
- pub ip: Option,
- pub use_channel: String,
- #[cfg(feature = "ip_proxy")]
- pub no_proxy: bool,
- pub server_encrypt: bool,
- pub parallel: usize,
- pub cipher_model: String,
- pub finger: bool,
- pub punch_model: String,
- pub ports: Option>,
- pub cmd: bool,
- pub first_latency: bool,
- pub device_name: Option,
- pub packet_loss: Option,
- pub packet_delay: u32,
- #[cfg(feature = "port_mapping")]
- pub mapping: Vec,
-}
-
-impl Default for FileConfig {
- fn default() -> Self {
- Self {
- #[cfg(target_os = "windows")]
- tap: false,
- token: "".to_string(),
- device_id: get_device_id(),
- name: os_info::get().to_string(),
- server_address: "nat1.wherewego.top:29872".to_string(),
- stun_server: vec![
- "stun1.l.google.com:19302".to_string(),
- "stun2.l.google.com:19302".to_string(),
- "stun.miwifi.com:3478".to_string(),
- ],
- dns: vec![],
- in_ips: vec![],
- out_ips: vec![],
- password: None,
- mtu: None,
- tcp: false,
- ip: None,
- use_channel: "all".to_string(),
- #[cfg(feature = "ip_proxy")]
- no_proxy: false,
- server_encrypt: false,
- parallel: 1,
- cipher_model: "aes_gcm".to_string(),
- finger: false,
- punch_model: "all".to_string(),
- ports: None,
- cmd: false,
- first_latency: false,
- device_name: None,
- packet_loss: None,
- packet_delay: 0,
- #[cfg(feature = "port_mapping")]
- mapping: vec![],
- }
- }
-}
-
-pub fn read_config(file_path: &str) -> io::Result<(Config, bool)> {
- let conf = std::fs::read_to_string(file_path)?;
- let file_conf = match serde_yaml::from_str::(&conf) {
- Ok(val) => val,
- Err(e) => {
- log::error!("{:?}", e);
- return Err(io::Error::new(io::ErrorKind::Other, format!("{}", e)));
- }
- };
- if file_conf.token.is_empty() {
- return Err(io::Error::new(io::ErrorKind::Other, "token is_empty"));
- }
-
- let in_ips = match common::args_parse::ips_parse(&file_conf.in_ips) {
- Ok(in_ips) => in_ips,
- Err(e) => {
- return Err(io::Error::new(
- io::ErrorKind::Other,
- format!("in_ips {:?} error:{}", &file_conf.in_ips, e),
- ));
- }
- };
- let out_ips = match common::args_parse::out_ips_parse(&file_conf.out_ips) {
- Ok(out_ips) => out_ips,
- Err(e) => {
- return Err(io::Error::new(
- io::ErrorKind::Other,
- format!("out_ips {:?} error:{}", &file_conf.out_ips, e),
- ));
- }
- };
- let virtual_ip = match file_conf.ip.clone().map(|v| Ipv4Addr::from_str(&v)) {
- None => None,
- Some(r) => Some(r.map_err(|e| {
- io::Error::new(
- io::ErrorKind::Other,
- format!("ip {:?} error:{}", &file_conf.ip, e),
- )
- })?),
- };
-
- let cipher_model = CipherModel::from_str(&file_conf.cipher_model)
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
-
- let punch_model = PunchModel::from_str(&file_conf.punch_model)
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
- let use_channel_type = UseChannelType::from_str(&file_conf.use_channel)
- .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
- let config = Config::new(
- #[cfg(target_os = "windows")]
- file_conf.tap,
- file_conf.token,
- file_conf.device_id,
- file_conf.name,
- file_conf.server_address,
- file_conf.dns,
- file_conf.stun_server,
- in_ips,
- out_ips,
- file_conf.password,
- file_conf.mtu,
- file_conf.tcp,
- virtual_ip,
- #[cfg(feature = "ip_proxy")]
- file_conf.no_proxy,
- file_conf.server_encrypt,
- file_conf.parallel,
- cipher_model,
- file_conf.finger,
- punch_model,
- file_conf.ports,
- file_conf.first_latency,
- file_conf.device_name,
- use_channel_type,
- file_conf.packet_loss,
- file_conf.packet_delay,
- #[cfg(feature = "port_mapping")]
- file_conf.mapping,
- )
- .unwrap();
- Ok((config, file_conf.cmd))
+#[cfg(not(feature = "file_config"))]
+pub fn read_config(_file_path: &str) -> anyhow::Result<(vnt::core::Config, bool)> {
+ unimplemented!()
}
pub fn get_device_id() -> String {
diff --git a/vnt-cli/src/main.rs b/vnt-cli/src/main.rs
index e3611c6..9ad1521 100644
--- a/vnt-cli/src/main.rs
+++ b/vnt-cli/src/main.rs
@@ -1,7 +1,7 @@
+use std::io;
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::str::FromStr;
-use std::{io, thread};
use console::style;
use getopts::Options;
@@ -12,8 +12,10 @@ use vnt::channel::UseChannelType;
use vnt::cipher::CipherModel;
use vnt::core::{Config, Vnt};
+#[cfg(feature = "command")]
mod command;
mod config;
+#[cfg(feature = "command")]
mod console_out;
mod generated_serial_number;
mod root_check;
@@ -41,6 +43,7 @@ pub fn app_home() -> io::Result {
}
fn main() {
+ #[cfg(feature = "log")]
let _ = log4rs::init_file("log4rs.yaml", Default::default());
let args: Vec = std::env::args().collect();
let program = args[0].clone();
@@ -100,6 +103,7 @@ fn main() {
sudo::escalate_if_needed().unwrap();
return;
}
+ #[cfg(feature = "command")]
if matches.opt_present("list") {
command::command(command::CommandEnum::List);
return;
@@ -342,7 +346,7 @@ fn main() {
mod callback;
-fn main0(config: Config, show_cmd: bool) {
+fn main0(config: Config, _show_cmd: bool) {
#[cfg(feature = "port_mapping")]
for (is_tcp, addr, dest) in config.port_mapping_list.iter() {
if *is_tcp {
@@ -352,36 +356,40 @@ fn main0(config: Config, show_cmd: bool) {
}
}
let vnt_util = Vnt::new(config, callback::VntHandler {}).unwrap();
- let vnt_c = vnt_util.clone();
- thread::Builder::new()
- .name("CommandServer".into())
- .spawn(move || {
- if let Err(e) = command::server::CommandServer::new().start(vnt_c) {
- log::warn!("cmd:{:?}", e);
- }
- })
- .expect("CommandServer");
- if show_cmd {
- let mut cmd = String::new();
- loop {
- cmd.clear();
- println!("======== input:list,info,route,all,stop ========");
- match io::stdin().read_line(&mut cmd) {
- Ok(len) => {
- if !command(&cmd[..len], &vnt_util) {
+ #[cfg(feature = "command")]
+ {
+ let vnt_c = vnt_util.clone();
+ std::thread::Builder::new()
+ .name("CommandServer".into())
+ .spawn(move || {
+ if let Err(e) = command::server::CommandServer::new().start(vnt_c) {
+ log::warn!("cmd:{:?}", e);
+ }
+ })
+ .expect("CommandServer");
+ if _show_cmd {
+ let mut cmd = String::new();
+ loop {
+ cmd.clear();
+ println!("======== input:list,info,route,all,stop ========");
+ match io::stdin().read_line(&mut cmd) {
+ Ok(len) => {
+ if !command(&cmd[..len], &vnt_util) {
+ break;
+ }
+ }
+ Err(e) => {
+ println!("input err:{}", e);
break;
}
}
- Err(e) => {
- println!("input err:{}", e);
- break;
- }
}
}
}
+
vnt_util.wait()
}
-
+#[cfg(feature = "command")]
fn command(cmd: &str, vnt: &Vnt) -> bool {
if cmd.is_empty() {
return false;
@@ -427,10 +435,11 @@ fn print_usage(program: &str, _opts: Options) {
println!(" -s 注册和中继服务器地址,以'TXT:'开头表示解析TXT记录");
println!(" -e stun服务器,用于探测NAT类型,可使用多个地址,如-e stun1.l.google.com -e stun2.l.google.com");
#[cfg(target_os = "windows")]
- println!(" -a 使用tap模式,默认使用tun模式");
+ println!(
+ " -a 使用tap模式,默认使用tun模式,使用tap时需要配合'--nic'参数指定tap网卡"
+ );
println!(" -i 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
println!(" 并转发到10.26.0.3,可指定多个网段");
- #[cfg(feature = "ip_proxy")]
println!(" -o 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
#[cfg(not(any(
feature = "aes_gcm",
@@ -462,6 +471,7 @@ fn print_usage(program: &str, _opts: Options) {
#[cfg(feature = "server_encrypt")]
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
println!(" -u 自定义mtu(不加密默认为1450,加密默认为1410)");
+ #[cfg(feature = "file_config")]
println!(" -f 读取配置文件中的配置");
println!(" --tcp 和服务端使用tcp通信,默认使用udp,遇到udp qos时可指定使用tcp");
@@ -478,6 +488,7 @@ fn print_usage(program: &str, _opts: Options) {
}
println!(" --punch 取值ipv4/ipv6/all,ipv4表示仅使用ipv4打洞");
println!(" --ports 取值0~65535,指定本地监听的一组端口,默认监听两个随机端口,使用过多端口会增加网络负担");
+ #[cfg(feature = "command")]
println!(" --cmd 开启交互式命令,使用此参数开启控制台输入");
#[cfg(feature = "ip_proxy")]
println!(" --no-proxy 关闭内置代理,如需点对网则需要配置网卡NAT转发");
@@ -493,26 +504,29 @@ fn print_usage(program: &str, _opts: Options) {
println!(" --mapping 端口映射,例如 --mapping udp:0.0.0.0:80->10.26.0.10:80 --mapping tcp:0.0.0.0:80->10.26.0.10:80");
println!();
- println!(
- " --list {}",
- yellow("后台运行时,查看其他设备列表".to_string())
- );
- println!(
- " --all {}",
- yellow("后台运行时,查看其他设备完整信息".to_string())
- );
- println!(
- " --info {}",
- yellow("后台运行时,查看当前设备信息".to_string())
- );
- println!(
- " --route {}",
- yellow("后台运行时,查看数据转发路径".to_string())
- );
- println!(
- " --stop {}",
- yellow("停止后台运行".to_string())
- );
+ #[cfg(feature = "command")]
+ {
+ println!(
+ " --list {}",
+ yellow("后台运行时,查看其他设备列表".to_string())
+ );
+ println!(
+ " --all {}",
+ yellow("后台运行时,查看其他设备完整信息".to_string())
+ );
+ println!(
+ " --info {}",
+ yellow("后台运行时,查看当前设备信息".to_string())
+ );
+ println!(
+ " --route {}",
+ yellow("后台运行时,查看数据转发路径".to_string())
+ );
+ println!(
+ " --stop {}",
+ yellow("停止后台运行".to_string())
+ );
+ }
println!(" -h, --help 帮助");
}
@@ -520,6 +534,7 @@ fn green(str: String) -> impl std::fmt::Display {
style(str).green()
}
+#[cfg(feature = "command")]
fn yellow(str: String) -> impl std::fmt::Display {
style(str).yellow()
}
diff --git a/vnt/src/core/conn.rs b/vnt/src/core/conn.rs
index 960b7d6..411e9f6 100644
--- a/vnt/src/core/conn.rs
+++ b/vnt/src/core/conn.rs
@@ -6,7 +6,6 @@ use std::time::Duration;
use crossbeam_utils::atomic::AtomicCell;
use parking_lot::{Mutex, RwLock};
use rand::Rng;
-use sha2::Digest;
#[cfg(not(target_os = "android"))]
use tun::device::IFace;
@@ -80,14 +79,7 @@ impl Vnt {
config.name.clone(),
config.token.clone(),
config.ip,
- config.password.as_ref().map(|v| {
- let mut hasher = sha2::Sha256::new();
- hasher.update(config.cipher_model.to_string().as_bytes());
- hasher.update(v.as_bytes());
- hasher.update(config.token.as_bytes());
- let key: [u8; 32] = hasher.finalize().into();
- key[16..].try_into().unwrap()
- }),
+ config.password_hash(),
config.server_encrypt,
config.device_id.clone(),
config.server_address_str.clone(),
diff --git a/vnt/src/core/mod.rs b/vnt/src/core/mod.rs
index bd1da8e..9ade95b 100644
--- a/vnt/src/core/mod.rs
+++ b/vnt/src/core/mod.rs
@@ -143,3 +143,33 @@ impl Config {
})
}
}
+impl Config {
+ #[cfg(any(
+ feature = "aes_gcm",
+ feature = "server_encrypt",
+ feature = "aes_cbc",
+ feature = "aes_ecb",
+ feature = "sm4_cbc"
+ ))]
+ pub fn password_hash(&self) -> Option<[u8; 16]> {
+ self.password.as_ref().map(|v| {
+ use sha2::Digest;
+ let mut hasher = sha2::Sha256::new();
+ hasher.update(self.cipher_model.to_string().as_bytes());
+ hasher.update(v.as_bytes());
+ hasher.update(self.token.as_bytes());
+ let key: [u8; 32] = hasher.finalize().into();
+ key[16..].try_into().unwrap()
+ })
+ }
+ #[cfg(not(any(
+ feature = "aes_gcm",
+ feature = "server_encrypt",
+ feature = "aes_cbc",
+ feature = "aes_ecb",
+ feature = "sm4_cbc"
+ )))]
+ pub fn password_hash(&self) -> Option<[u8; 16]> {
+ None
+ }
+}
diff --git a/vnt/src/ip_proxy/icmp_proxy.rs b/vnt/src/ip_proxy/icmp_proxy.rs
index df7d6e3..93557cf 100644
--- a/vnt/src/ip_proxy/icmp_proxy.rs
+++ b/vnt/src/ip_proxy/icmp_proxy.rs
@@ -87,38 +87,36 @@ async fn icmp_proxy(
client_cipher: Cipher,
) -> io::Result<()> {
let mut buf = [0u8; 65535 - 20 - 8];
+ #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
+ let start = 12;
+ #[cfg(target_os = "android")]
+ let start = 12 + 20;
loop {
- #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
- let start = 12;
- #[cfg(target_os = "android")]
- let start = 12 + 20;
- loop {
- let (len, addr) = icmp_socket.recv_from(&mut buf[start..]).await?;
- if let IpAddr::V4(peer_ip) = addr.ip() {
- #[cfg(target_os = "android")]
- {
- let buf = &mut buf[12..];
- // ipv4 头部20字节
- buf[0] = 0b0100_0110;
- //写入总长度
- buf[2..4].copy_from_slice(&((20 + len) as u16).to_be_bytes());
+ let (len, addr) = icmp_socket.recv_from(&mut buf[start..]).await?;
+ if let IpAddr::V4(peer_ip) = addr.ip() {
+ #[cfg(target_os = "android")]
+ {
+ let buf = &mut buf[12..];
+ // ipv4 头部20字节
+ buf[0] = 0b0100_0110;
+ //写入总长度
+ buf[2..4].copy_from_slice(&((20 + len) as u16).to_be_bytes());
- let mut ipv4 = IpV4Packet::unchecked(buf);
- ipv4.set_flags(2);
- ipv4.set_ttl(1);
- ipv4.set_protocol(packet::ip::ipv4::protocol::Protocol::Icmp);
- ipv4.set_source_ip(peer_ip);
- }
- recv_handle(
- &mut buf,
- start + len,
- peer_ip,
- &nat_map,
- &context,
- ¤t_device,
- &client_cipher,
- );
+ let mut ipv4 = IpV4Packet::unchecked(buf);
+ ipv4.set_flags(2);
+ ipv4.set_ttl(1);
+ ipv4.set_protocol(packet::ip::ipv4::protocol::Protocol::Icmp);
+ ipv4.set_source_ip(peer_ip);
}
+ recv_handle(
+ &mut buf,
+ start + len,
+ peer_ip,
+ &nat_map,
+ &context,
+ ¤t_device,
+ &client_cipher,
+ );
}
}
}
diff --git a/vnt/src/util/dns_query.rs b/vnt/src/util/dns_query.rs
index cd4f77a..3104e2b 100644
--- a/vnt/src/util/dns_query.rs
+++ b/vnt/src/util/dns_query.rs
@@ -41,8 +41,8 @@ pub fn address_choose(addrs: Vec) -> anyhow::Result {
/// 后续实现选择延迟最低的可用地址,需要服务端配合
/// 现在是选择第一个地址,优先ipv6
fn address_choose0(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 v4: Vec = addrs.iter().filter(|v| v.is_ipv4()).copied().collect();
+ let v6: Vec = addrs.iter().filter(|v| v.is_ipv6()).copied().collect();
let check_addr = |addrs: &Vec| -> anyhow::Result {
if !addrs.is_empty() {
let udp = if addrs[0].is_ipv6() {
@@ -78,9 +78,7 @@ pub fn dns_query_all(
mut name_servers: Vec,
) -> anyhow::Result> {
match SocketAddr::from_str(domain) {
- Ok(addr) => {
- return Ok(vec![addr]);
- }
+ Ok(addr) => Ok(vec![addr]),
Err(_) => {
let txt_domain = domain
.to_lowercase()
@@ -94,7 +92,6 @@ pub fn dns_query_all(
return Ok(domain
.to_socket_addrs()
.with_context(|| format!("DNS query failed {:?}", domain))?
- .into_iter()
.collect());
}
}
@@ -119,7 +116,7 @@ pub fn dns_query_all(
continue;
}
let end_index = domain
- .rfind(":")
+ .rfind(':')
.with_context(|| format!("{:?} not port", domain))?;
let host = &domain[..end_index];
let port = u16::from_str(&domain[end_index + 1..])
@@ -219,7 +216,7 @@ fn query<'a>(
domain
));
}
- if pkt.answers.len() == 0 {
+ if pkt.answers.is_empty() {
return Err(anyhow::anyhow!(
"No records received DNS {:?} domain {:?}",
name_server,
@@ -240,8 +237,8 @@ pub fn txt_dns(domain: &str, name_server: String) -> anyhow::Result