mirror of
https://github.com/lbl8603/vnt.git
synced 2025-09-26 20:21:20 +08:00
Merge remote-tracking branch 'refs/remotes/origin/1.2.x'
This commit is contained in:
8
.github/workflows/rust.yml
vendored
8
.github/workflows/rust.yml
vendored
@@ -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
2714
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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
5
vn-link-cli/build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
|
||||
#[cfg(target_os = "windows")]
|
||||
thunk::thunk();
|
||||
}
|
@@ -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"]
|
||||
@@ -44,4 +45,7 @@ command = ["common/command"]
|
||||
file_config = ["common/file_config"]
|
||||
[build-dependencies]
|
||||
rand = "0.8.5"
|
||||
chrono = "0.4.23"
|
||||
chrono = "0.4.23"
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
thunk-rs = { version = "0.3.3", features = ["win7"] }
|
||||
|
5
vnt-cli/build.rs
Normal file
5
vnt-cli/build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
|
||||
#[cfg(target_os = "windows")]
|
||||
thunk::thunk();
|
||||
}
|
@@ -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",
|
||||
|
@@ -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)?;
|
||||
|
||||
|
@@ -390,24 +390,16 @@ 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,
|
||||
) {
|
||||
self.callback.error(ErrorInfo::new_msg(
|
||||
ErrorType::FailedToCrateDevice,
|
||||
format!("{:?}", e),
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
self.callback.error(ErrorInfo::new_msg(
|
||||
ErrorType::FailedToCrateDevice,
|
||||
format!("{:?}", e),
|
||||
));
|
||||
}
|
||||
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),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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(
|
||||
|
@@ -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<()> {
|
||||
|
@@ -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);
|
||||
@@ -149,7 +148,7 @@ pub fn dns_query_all(
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
let end_index = current_domain
|
||||
.rfind(':')
|
||||
.with_context(|| format!("{:?} not port", current_domain))?;
|
||||
@@ -214,8 +213,8 @@ fn parse_host_port(addr: &str) -> bool {
|
||||
// 处理 IPv6 地址(格式为 [::1]:8080)
|
||||
if addr.starts_with('[') {
|
||||
if let Some(idx) = addr.rfind(']') {
|
||||
if let Some(port_idx) = addr[idx+1..].find(':') {
|
||||
let port = &addr[idx+1+port_idx+1..]; // 提取端口部分
|
||||
if let Some(port_idx) = addr[idx + 1..].find(':') {
|
||||
let port = &addr[idx + 1 + port_idx + 1..]; // 提取端口部分
|
||||
return !port.is_empty() && port.chars().all(|c| c.is_numeric());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -275,7 +272,7 @@ fn check_for_redirect(domain: &String) -> anyhow::Result<Option<String>> {
|
||||
};
|
||||
|
||||
let body_str = String::from_utf8_lossy(&response_body);
|
||||
let cleaned_body = body_str.replace('\n', "").replace('\r', "");
|
||||
let cleaned_body = body_str.replace('\n', "").replace('\r', "");
|
||||
println!("Response Body: {}", cleaned_body);
|
||||
// 处理 3XX 重定向
|
||||
if response.status_code().is_redirect() {
|
||||
@@ -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() {
|
||||
|
Reference in New Issue
Block a user