Merge remote-tracking branch 'refs/remotes/origin/1.2.x'

This commit is contained in:
lbl
2025-09-23 09:11:24 +08:00
12 changed files with 137 additions and 2760 deletions

View File

@@ -220,8 +220,9 @@ jobs:
else
cargo build --package vnt-cli --release --target $TARGET --features $FEATURES
fi
- name: Compress artifacts
- name: List target
run: find ./target
- name: Compress
run: |
mkdir -p ./artifacts
if [[ $OS =~ ^windows.*$ ]]; then
@@ -259,7 +260,8 @@ jobs:
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: List
run: find ./artifacts
- name: Release
uses: svenstaro/upload-release-action@v2
with:

2714
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,9 @@ common = { path = "../common", default-features = false }
tokio = { version = "1.37.0", features = ["full"] }
log = "0.4.17"
[target.'cfg(windows)'.build-dependencies]
thunk-rs = { version = "0.3.3", features = ["win7"] }
[features]
default = ["default-feature"]
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4", "ws"]

5
vn-link-cli/build.rs Normal file
View File

@@ -0,0 +1,5 @@
fn main() {
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
#[cfg(target_os = "windows")]
thunk::thunk();
}

View File

@@ -19,6 +19,7 @@ signal-hook = "0.3.17"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
[features]
default = ["default-feature"]
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "ip_proxy", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
@@ -45,3 +46,6 @@ file_config = ["common/file_config"]
[build-dependencies]
rand = "0.8.5"
chrono = "0.4.23"
[target.'cfg(windows)'.build-dependencies]
thunk-rs = { version = "0.3.3", features = ["win7"] }

5
vnt-cli/build.rs Normal file
View File

@@ -0,0 +1,5 @@
fn main() {
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
#[cfg(target_os = "windows")]
thunk::thunk();
}

View File

@@ -6,8 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
http_req = { git = "https://github.com/lmq8267/http_req.git", default-features = false, features = ["rust-tls"] }
tun-rs = { version = "2", optional = true, features = ["experimental"] }
tun-rs = { version = "2.5.0", optional = true, features = ["interruptible"] }
packet = { path = "./packet" }
bytes = "1.5.0"
log = "0.4.17"
@@ -32,13 +31,14 @@ rsa = { version = "0.9.2", features = [], optional = true }
spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], optional = true }
openssl-sys = { git = "https://github.com/vnt-dev/rust-openssl", optional = true }
libsm = { git = "https://github.com/vnt-dev/libsm", optional = true }
http_req = { git = "https://github.com/lmq8267/http_req.git", default-features = false, features = ["rust-tls"] }
mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] }
crossbeam-queue = "0.3.11"
anyhow = "1.0.82"
dns-parser = "0.8.0"
tokio = { version = "1.37.0", features = ["full"] }
tokio = { version = "1.46.1", features = ["full"] }
lz4_flex = { version = "0.11", default-features = false, optional = true }
zstd = { version = "0.13.1", optional = true }
@@ -52,8 +52,9 @@ network-interface = "2.0.0"
futures-util = "0.3.30"
[target.'cfg(target_os = "windows")'.dependencies]
winreg = "0.55.0"
libloading = "0.8.0"
windows-sys = { version = "0.59.0", features = ["Win32_Foundation",
windows-sys = { version = "0.60.2", features = ["Win32_Foundation",
"Win32_NetworkManagement",
"Win32_NetworkManagement_IpHelper",
"Win32_Networking_WinSock",

View File

@@ -141,12 +141,28 @@ impl Config {
server_address_str = s.to_string();
protocol = ConnectProtocol::TCP;
}
server_address = address_choose(dns_query_all(
let address_result = dns_query_all(
&server_address_str,
name_servers.clone(),
&LocalInterface::default(),
)?)?;
);
match address_result {
Ok(address) => match address_choose(address) {
Ok(resolved_address) => {
server_address = resolved_address;
}
Err(e) => {
log::error!("Failed to choose address: {}", e);
println!("Failed to choose address: {}", e);
}
},
Err(e) => {
log::error!("DNS query failed: {}", e);
println!("DNS query failed: {}", e);
}
}
}
#[cfg(feature = "port_mapping")]
let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?;

View File

@@ -390,26 +390,18 @@ impl<Call: VntCallback, Device: DeviceWrite> ServerPacketHandler<Call, Device> {
"device_fd == 0".into(),
));
} else {
match tun_rs::platform::Device::from_fd(device_fd as _) {
Ok(device) => {
if let Err(e) = self.tun_device_helper.start(
Arc::new(device),
self.config_info.allow_wire_guard,
) {
let device =
unsafe { tun_rs::SyncDevice::from_fd(device_fd as _) };
if let Err(e) = self
.tun_device_helper
.start(Arc::new(device), self.config_info.allow_wire_guard)
{
self.callback.error(ErrorInfo::new_msg(
ErrorType::FailedToCrateDevice,
format!("{:?}", e),
));
}
}
Err(e) => {
self.callback.error(ErrorInfo::new_msg(
ErrorType::FailedToCrateDevice,
format!("{:?}", e),
));
}
}
}
}
}
}

View File

@@ -13,7 +13,7 @@ use parking_lot::Mutex;
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::Arc;
use tun_rs::SyncDevice;
use tun_rs::{InterruptEvent, SyncDevice};
pub(crate) fn start_simple(
stop_manager: StopManager,
@@ -29,10 +29,11 @@ pub(crate) fn start_simple(
device_stop: DeviceStop,
allow_wire_guard: bool,
) -> anyhow::Result<()> {
let event = Arc::new(InterruptEvent::new()?);
let worker = {
let device = device.clone();
let event = event.clone();
stop_manager.add_listener("tun_device".into(), move || {
if let Err(e) = device.shutdown() {
if let Err(e) = event.trigger() {
log::warn!("{:?}", e);
}
})?
@@ -50,6 +51,7 @@ pub(crate) fn start_simple(
if let Err(e) = start_simple0(
context,
device,
event,
current_device,
ip_route,
#[cfg(feature = "ip_proxy")]
@@ -72,6 +74,7 @@ pub(crate) fn start_simple(
fn start_simple0(
context: &ChannelContext,
device: Arc<SyncDevice>,
event: Arc<InterruptEvent>,
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
ip_route: ExternalRoute,
#[cfg(feature = "ip_proxy")] ip_proxy_map: Option<IpProxyMap>,
@@ -84,7 +87,7 @@ fn start_simple0(
let mut buf = [0; BUFFER_SIZE];
let mut extend = [0; BUFFER_SIZE];
loop {
let len = device.recv(&mut buf[12..])? + 12;
let len = device.recv_intr(&mut buf[12..],&event)? + 12;
// buf是重复利用的需要重置头部
buf[..12].fill(0);
match crate::handle::tun_tap::tun_handler::handle(

View File

@@ -70,6 +70,11 @@ fn create_device0(config: &DeviceConfig) -> io::Result<Arc<SyncDevice>> {
#[cfg(target_os = "windows")]
{
let name = config
.device_name
.clone()
.unwrap_or_else(|| DEFAULT_TUN_NAME.to_string());
_ = delete_adapter_info_from_reg(&name);
tun_builder = tun_builder.metric(0).ring_capacity(4 * 1024 * 1024);
}
@@ -102,6 +107,65 @@ fn delete_device(name: &str) {
log::warn!("删除网卡失败:{:?}", delete_tun);
}
}
#[cfg(windows)]
fn delete_adapter_info_from_reg(dev_name: &str) -> std::io::Result<()> {
use std::collections::HashSet;
use winreg::{enums::HKEY_LOCAL_MACHINE, enums::KEY_ALL_ACCESS, RegKey};
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
let profiles_key = hklm.open_subkey_with_flags(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Profiles",
KEY_ALL_ACCESS,
)?;
let mut profile_guid_set = HashSet::new();
for sub_key_name in profiles_key.enum_keys().filter_map(Result::ok) {
let sub_key = profiles_key.open_subkey(&sub_key_name)?;
match sub_key.get_value::<String, _>("Description") {
Ok(profile_name) => {
if dev_name == profile_name {
match profiles_key.delete_subkey_all(&sub_key_name) {
Ok(_) => {
log::info!("deleted Profiles sub_key: {}", sub_key_name);
profile_guid_set.insert(sub_key_name);
}
Err(e) => {
log::warn!("Failed to delete Profiles sub_key {}: {}", sub_key_name, e)
}
}
}
}
Err(e) => log::warn!(
"Failed to read Description for sub_key {}: {}",
sub_key_name,
e
),
}
}
let unmanaged_key = hklm.open_subkey_with_flags(
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkList\\Signatures\\Unmanaged",
KEY_ALL_ACCESS,
)?;
for sub_key_name in unmanaged_key.enum_keys().filter_map(Result::ok) {
let sub_key = unmanaged_key.open_subkey(&sub_key_name)?;
match sub_key.get_value::<String, _>("ProfileGuid") {
Ok(profile_guid) => {
if profile_guid_set.contains(&profile_guid) {
match unmanaged_key.delete_subkey_all(&sub_key_name) {
Ok(_) => log::info!("deleted Unmanaged sub_key: {}", sub_key_name),
Err(e) => {
log::warn!("Failed to delete Unmanaged sub_key {}: {}", sub_key_name, e)
}
}
}
}
Err(e) => log::warn!(
"Failed to read Description for sub_key {}: {}",
sub_key_name,
e
),
}
}
Ok(())
}
#[cfg(target_os = "windows")]
pub fn add_route(index: u32, dest: Ipv4Addr, netmask: Ipv4Addr) -> io::Result<()> {

View File

@@ -1,14 +1,14 @@
use crate::channel::socket::LocalInterface;
use anyhow::Context;
use dns_parser::{Builder, Packet, QueryClass, QueryType, RData, ResponseCode};
use http_req::request::{RedirectPolicy, Request};
use http_req::uri::Uri;
use std::cell::RefCell;
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket};
use std::str::FromStr;
use std::time::Duration;
use std::{io, thread};
use http_req::request::{Request, RedirectPolicy};
use http_req::uri::Uri;
use crate::channel::socket::LocalInterface;
use anyhow::Context;
use dns_parser::{Builder, Packet, QueryClass, QueryType, RData, ResponseCode};
thread_local! {
static HISTORY: RefCell<HashMap<SocketAddr,usize>> = RefCell::new(HashMap::new());
@@ -97,7 +97,6 @@ pub fn dns_query_all(
// 执行重定向检查
if let Some(stripped) = redirect_domain {
if let Some(redirected_url) = check_for_redirect(&stripped)? {
// 去掉 URL 开头的协议部分
let final_domain = remove_http_prefix(&redirected_url);
println!("Server Address: {}", final_domain);
@@ -248,9 +247,7 @@ fn check_for_redirect(domain: &String) -> anyhow::Result<Option<String>> {
// 解析 URL
let uri = match Uri::try_from(url.as_str()) {
Ok(u) => {
u
}
Ok(u) => u,
Err(e) => {
println!("解析地址失败: {}", e);
return Ok(last_redirect_url);
@@ -288,7 +285,6 @@ fn check_for_redirect(domain: &String) -> anyhow::Result<Option<String>> {
return Ok(last_redirect_url);
}
}
// 处理 200 响应
else if response.status_code().is_success() {
for line in body_str.lines() {