mirror of
https://github.com/lbl8603/vnt.git
synced 2025-09-27 04:26:25 +08:00
91
.github/workflows/rust.yml
vendored
91
.github/workflows/rust.yml
vendored
@@ -7,14 +7,12 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
# necessary for windows
|
# necessary for windows
|
||||||
shell: bash
|
shell: bash
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# test:
|
# test:
|
||||||
@@ -44,7 +42,7 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- TARGET: i686-unknown-linux-musl # test in an alpine container on a mac
|
- TARGET: i686-unknown-linux-musl # test in an alpine container on a mac
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: default
|
FEATURES: ring-cipher,openssl-vendored,wss
|
||||||
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
|
- TARGET: x86_64-unknown-linux-musl # test in an alpine container on a mac
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: ring-cipher,wss
|
FEATURES: ring-cipher,wss
|
||||||
@@ -81,11 +79,6 @@ jobs:
|
|||||||
- TARGET: mips-unknown-linux-musl # openwrt
|
- TARGET: mips-unknown-linux-musl # openwrt
|
||||||
OS: ubuntu-latest
|
OS: ubuntu-latest
|
||||||
FEATURES: ring-cipher,wss
|
FEATURES: ring-cipher,wss
|
||||||
# - TARGET: x86_64-unknown-freebsd
|
|
||||||
# OS: ubuntu-latest
|
|
||||||
# ARTIFACT_NAME: freebsd-13.2-x86_64
|
|
||||||
# FEATURES: default
|
|
||||||
# BSD_VERSION: 13.2
|
|
||||||
# needs: test
|
# needs: test
|
||||||
runs-on: ${{ matrix.OS }}
|
runs-on: ${{ matrix.OS }}
|
||||||
env:
|
env:
|
||||||
@@ -98,7 +91,7 @@ jobs:
|
|||||||
- name: Init submodules
|
- name: Init submodules
|
||||||
uses: snickerbockers/submodules-init@v4
|
uses: snickerbockers/submodules-init@v4
|
||||||
- name: Cargo cache
|
- name: Cargo cache
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cargo/registry
|
~/.cargo/registry
|
||||||
@@ -109,38 +102,7 @@ jobs:
|
|||||||
run: echo OPENSSL_SRC_PERL=C:/Strawberry/perl/bin/perl >> $GITHUB_ENV
|
run: echo OPENSSL_SRC_PERL=C:/Strawberry/perl/bin/perl >> $GITHUB_ENV
|
||||||
- name: List
|
- name: List
|
||||||
run: find ./
|
run: find ./
|
||||||
- name: Build NetLink X86_64-FreeBSD
|
|
||||||
uses: cross-platform-actions/action@v0.23.0
|
|
||||||
if: ${{ endsWith(matrix.TARGET, 'freebsd') }}
|
|
||||||
env:
|
|
||||||
TARGET: ${{ matrix.TARGET }}
|
|
||||||
with:
|
|
||||||
operating_system: freebsd
|
|
||||||
environment_variables: TARGET
|
|
||||||
architecture: x86-64
|
|
||||||
version: ${{ matrix.BSD_VERSION }}
|
|
||||||
shell: bash
|
|
||||||
memory: 5G
|
|
||||||
cpu_count: 4
|
|
||||||
run: |
|
|
||||||
uname -a
|
|
||||||
echo $SHELL
|
|
||||||
pwd
|
|
||||||
ls -lah
|
|
||||||
whoami
|
|
||||||
env | sort
|
|
||||||
sudo pkg install -y git protobuf
|
|
||||||
curl --proto 'https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
|
||||||
source $HOME/.cargo/env
|
|
||||||
rustup set auto-self-update disable
|
|
||||||
rustup install 1.77
|
|
||||||
rustup default 1.77
|
|
||||||
export CC=clang
|
|
||||||
export CXX=clang++
|
|
||||||
export CARGO_TERM_COLOR=always
|
|
||||||
cargo build --release --verbose --target $TARGET
|
|
||||||
- name: Install and configure dependencies
|
- name: Install and configure dependencies
|
||||||
if: ${{ ! endsWith(matrix.TARGET, 'freebsd') }}
|
|
||||||
run: |
|
run: |
|
||||||
# dependencies are only needed on ubuntu as that's the only place where
|
# dependencies are only needed on ubuntu as that's the only place where
|
||||||
# we make cross-compilation
|
# we make cross-compilation
|
||||||
@@ -162,7 +124,7 @@ jobs:
|
|||||||
;;
|
;;
|
||||||
armv7-unknown-linux-musleabi)
|
armv7-unknown-linux-musleabi)
|
||||||
MUSL_URI=armv7m-linux-musleabi-cross
|
MUSL_URI=armv7m-linux-musleabi-cross
|
||||||
;;
|
;;
|
||||||
arm-unknown-linux-musleabihf)
|
arm-unknown-linux-musleabihf)
|
||||||
MUSL_URI=arm-linux-musleabihf-cross
|
MUSL_URI=arm-linux-musleabihf-cross
|
||||||
;;
|
;;
|
||||||
@@ -173,28 +135,34 @@ jobs:
|
|||||||
MUSL_URI=mips-linux-muslsf-cross
|
MUSL_URI=mips-linux-muslsf-cross
|
||||||
URL=mips-linux-muslsf
|
URL=mips-linux-muslsf
|
||||||
;;
|
;;
|
||||||
|
i686-unknown-linux-musl)
|
||||||
|
MUSL_URI=i686-linux-musl-cross
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ -n "$MUSL_URI" ]; then
|
if [ -n "$MUSL_URI" ]; then
|
||||||
mkdir -p /opt/musl_gcc
|
mkdir -p /opt/musl_gcc
|
||||||
wget -c https://musl.cc/$MUSL_URI.tgz -P /opt/musl_gcc/
|
wget -c https://musl.cc/$MUSL_URI.tgz -P /opt/musl_gcc/
|
||||||
tar zxf /opt/musl_gcc/$MUSL_URI.tgz -C /opt/musl_gcc/
|
tar zxf /opt/musl_gcc/$MUSL_URI.tgz -C /opt/musl_gcc/
|
||||||
sudo ln -s /opt/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/
|
sudo ln -s /opt/musl_gcc/$MUSL_URI/bin/*gcc /usr/bin/
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
rustup install 1.77
|
||||||
|
rustup default 1.77
|
||||||
fi
|
fi
|
||||||
if [[ $TARGET =~ ^mips.*$ ]]; then
|
if [[ $TARGET =~ ^mips.*$ ]]; then
|
||||||
cd /opt/musl_gcc/${URL}-cross/lib/gcc/${URL}/11.2.1
|
# mips平台使用nightly版本
|
||||||
cp libgcc_eh.a libunwind.a
|
cd /opt/musl_gcc/${URL}-cross/lib/gcc/${URL}/11.2.1
|
||||||
rustup toolchain install nightly-x86_64-unknown-linux-gnu
|
cp libgcc_eh.a libunwind.a
|
||||||
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
rustup toolchain install nightly-x86_64-unknown-linux-gnu
|
||||||
RUST_LIB_SRC=$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/
|
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
|
||||||
if [[ -f $RUST_LIB_SRC/library/Cargo.lock && ! -f $RUST_LIB_SRC/Cargo.lock ]]; then
|
RUST_LIB_SRC=$HOME/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/
|
||||||
cp -f $RUST_LIB_SRC/library/Cargo.lock $RUST_LIB_SRC/Cargo.lock
|
if [[ -f $RUST_LIB_SRC/library/Cargo.lock && ! -f $RUST_LIB_SRC/Cargo.lock ]]; then
|
||||||
fi
|
cp -f $RUST_LIB_SRC/library/Cargo.lock $RUST_LIB_SRC/Cargo.lock
|
||||||
elif [[ $OS =~ ^windows.*$ ]]; then
|
fi
|
||||||
# Windows 平台使用 1.77 版本
|
else
|
||||||
rustup install 1.77.0
|
rustup install 1.77
|
||||||
rustup default 1.77.0
|
rustup default 1.77
|
||||||
fi
|
fi
|
||||||
rustup -V
|
rustup -V
|
||||||
|
|
||||||
@@ -238,13 +206,13 @@ jobs:
|
|||||||
[target.aarch64-apple-darwin]
|
[target.aarch64-apple-darwin]
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
||||||
[target.i686-unknown-linux-musl]
|
[target.i686-unknown-linux-musl]
|
||||||
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
linker = "i686-linux-musl-gcc"
|
||||||
|
rustflags = ["-C", "target-feature=+crt-static","-C", "strip=symbols"]
|
||||||
EOF
|
EOF
|
||||||
- name: Install rust target
|
- name: Install rust target
|
||||||
if: ${{ ! endsWith(matrix.TARGET, 'freebsd') && ! startsWith(matrix.TARGET, 'mips') }}
|
if: ${{ ! startsWith(matrix.TARGET, 'mips') }}
|
||||||
run: rustup target add $TARGET
|
run: rustup target add $TARGET
|
||||||
- name: Run build vn-link-cli
|
- name: Run build vn-link-cli
|
||||||
if: ${{ ! endsWith(matrix.TARGET, 'freebsd') }}
|
|
||||||
run: |
|
run: |
|
||||||
if [[ $TARGET =~ ^mips.*$ ]]; then
|
if [[ $TARGET =~ ^mips.*$ ]]; then
|
||||||
cargo +nightly build --package vn-link-cli --release --verbose --target $TARGET -Z build-std=std,panic_abort --features $FEATURES
|
cargo +nightly build --package vn-link-cli --release --verbose --target $TARGET -Z build-std=std,panic_abort --features $FEATURES
|
||||||
@@ -252,7 +220,6 @@ jobs:
|
|||||||
cargo build --package vn-link-cli --release --verbose --target $TARGET --features $FEATURES
|
cargo build --package vn-link-cli --release --verbose --target $TARGET --features $FEATURES
|
||||||
fi
|
fi
|
||||||
- name: Run build vnt-cli
|
- name: Run build vnt-cli
|
||||||
if: ${{ ! endsWith(matrix.TARGET, 'freebsd') }}
|
|
||||||
run: |
|
run: |
|
||||||
if [[ $TARGET =~ ^mips.*$ ]]; then
|
if [[ $TARGET =~ ^mips.*$ ]]; then
|
||||||
cargo +nightly build --package vnt-cli --release --verbose --target $TARGET -Z build-std=std,panic_abort --features $FEATURES
|
cargo +nightly build --package vnt-cli --release --verbose --target $TARGET -Z build-std=std,panic_abort --features $FEATURES
|
||||||
@@ -305,8 +272,8 @@ jobs:
|
|||||||
- name: Release
|
- name: Release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
file: ./artifacts/**/*.tar.gz
|
file: ./artifacts/**/*.tar.gz
|
||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
overwrite: true
|
overwrite: true
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
@@ -9,6 +9,9 @@ common = { path = "../common", default-features = false }
|
|||||||
tokio = { version = "1.37.0", features = ["full"] }
|
tokio = { version = "1.37.0", features = ["full"] }
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.build-dependencies]
|
||||||
|
thunk-rs = { version = "0.3.3", features = ["win7"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["default-feature"]
|
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"]
|
default-feature = ["server_encrypt", "aes_gcm", "aes_cbc", "aes_ecb", "sm4_cbc", "chacha20_poly1305", "port_mapping", "log", "command", "file_config", "lz4", "ws"]
|
||||||
|
6
vn-link-cli/build.rs
Normal file
6
vn-link-cli/build.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
fn main() {
|
||||||
|
// 配置 thunk-rs 来链接 Windows 7 兼容库,并自动设置链接参数
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
thunk::thunk();
|
||||||
|
}
|
@@ -19,6 +19,9 @@ signal-hook = "0.3.17"
|
|||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.build-dependencies]
|
||||||
|
thunk-rs = { version = "0.3.3", features = ["win7"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["default-feature"]
|
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"]
|
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 +47,4 @@ command = ["common/command"]
|
|||||||
file_config = ["common/file_config"]
|
file_config = ["common/file_config"]
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
|
@@ -31,6 +31,7 @@ rsa = { version = "0.9.2", features = [], optional = true }
|
|||||||
spki = { version = "0.7.2", features = ["fingerprint", "alloc", "base64"], 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 }
|
openssl-sys = { git = "https://github.com/vnt-dev/rust-openssl", optional = true }
|
||||||
libsm = { git = "https://github.com/vnt-dev/libsm", 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"] }
|
mio = { version = "=0.8.11", features = ["os-poll", "net", "os-ext"] }
|
||||||
crossbeam-queue = "0.3.11"
|
crossbeam-queue = "0.3.11"
|
||||||
@@ -84,4 +85,4 @@ zstd_compress = ["zstd"]
|
|||||||
integrated_tun = ["tun-rs"]
|
integrated_tun = ["tun-rs"]
|
||||||
upnp = ["igd"]
|
upnp = ["igd"]
|
||||||
ws = ["tokio-tungstenite"]
|
ws = ["tokio-tungstenite"]
|
||||||
wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/rustls-tls-webpki-roots", "rustls"]
|
wss = ["ws", "tokio-tungstenite/rustls-tls-native-roots", "tokio-tungstenite/rustls-tls-webpki-roots", "rustls"]
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
use cfg_aliases::cfg_aliases;
|
use cfg_aliases::cfg_aliases;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
thunk::thunk();
|
||||||
|
|
||||||
cfg_aliases! {
|
cfg_aliases! {
|
||||||
cipher: {
|
cipher: {
|
||||||
any(feature = "aes_gcm",
|
any(feature = "aes_gcm",
|
||||||
|
@@ -103,7 +103,16 @@ where
|
|||||||
if let Ok(redirect) = v.to_str() {
|
if let Ok(redirect) = v.to_str() {
|
||||||
log::info!("url重定向响应头 {:?}", res.headers());
|
log::info!("url重定向响应头 {:?}", res.headers());
|
||||||
log::info!("url重定向地址 {}", redirect);
|
log::info!("url重定向地址 {}", redirect);
|
||||||
url = redirect.to_string();
|
// 替换协议前缀
|
||||||
|
if redirect.starts_with("http://") {
|
||||||
|
url = redirect.replacen("http://", "ws://", 1);
|
||||||
|
} else if redirect.starts_with("https://") {
|
||||||
|
url = redirect.replacen("https://", "wss://", 1);
|
||||||
|
} else {
|
||||||
|
url = redirect.to_string();
|
||||||
|
}
|
||||||
|
println!("Location:{}", url);
|
||||||
|
log::info!("最终地址: {}", url);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -141,12 +141,30 @@ impl Config {
|
|||||||
server_address_str = s.to_string();
|
server_address_str = s.to_string();
|
||||||
protocol = ConnectProtocol::TCP;
|
protocol = ConnectProtocol::TCP;
|
||||||
}
|
}
|
||||||
server_address = address_choose(dns_query_all(
|
let address_result = dns_query_all(
|
||||||
&server_address_str,
|
&server_address_str,
|
||||||
name_servers.clone(),
|
name_servers.clone(),
|
||||||
&LocalInterface::default(),
|
&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")]
|
#[cfg(feature = "port_mapping")]
|
||||||
let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?;
|
let port_mapping_list = crate::port_mapping::convert(port_mapping_list)?;
|
||||||
|
|
||||||
|
@@ -4,7 +4,8 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket};
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{io, thread};
|
use std::{io, thread};
|
||||||
|
use http_req::request::{Request, RedirectPolicy};
|
||||||
|
use http_req::uri::Uri;
|
||||||
use crate::channel::socket::LocalInterface;
|
use crate::channel::socket::LocalInterface;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use dns_parser::{Builder, Packet, QueryClass, QueryType, RData, ResponseCode};
|
use dns_parser::{Builder, Packet, QueryClass, QueryType, RData, ResponseCode};
|
||||||
@@ -82,21 +83,48 @@ pub fn dns_query_all(
|
|||||||
mut name_servers: Vec<String>,
|
mut name_servers: Vec<String>,
|
||||||
default_interface: &LocalInterface,
|
default_interface: &LocalInterface,
|
||||||
) -> anyhow::Result<Vec<SocketAddr>> {
|
) -> anyhow::Result<Vec<SocketAddr>> {
|
||||||
match SocketAddr::from_str(domain) {
|
let mut current_domain = domain.to_string(); // 引入可变变量存储当前域名
|
||||||
|
match SocketAddr::from_str(¤t_domain) {
|
||||||
Ok(addr) => Ok(vec![addr]),
|
Ok(addr) => Ok(vec![addr]),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let txt_domain = domain
|
// 重定向判断 http:
|
||||||
|
let current_domain_lower = current_domain.to_lowercase();
|
||||||
|
let redirect_domain = current_domain_lower
|
||||||
|
.strip_prefix("http:")
|
||||||
|
.or_else(|| current_domain_lower.strip_prefix("https:"))
|
||||||
|
.map(|v| v.to_string());
|
||||||
|
|
||||||
|
// 执行重定向检查
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 检查是否为 IP 和端口组合
|
||||||
|
if let Ok(socket_addr) = SocketAddr::from_str(&final_domain) {
|
||||||
|
// 如果是 IP 和端口格式,直接返回结果
|
||||||
|
return Ok(vec![socket_addr]);
|
||||||
|
} else {
|
||||||
|
// 如果不是 IP 和端口格式,则更新为重定向地址
|
||||||
|
current_domain = final_domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let txt_domain = current_domain
|
||||||
.to_lowercase()
|
.to_lowercase()
|
||||||
.strip_prefix("txt:")
|
.strip_prefix("txt:")
|
||||||
.map(|v| v.to_string());
|
.map(|v| v.to_string());
|
||||||
if name_servers.is_empty() {
|
if name_servers.is_empty() {
|
||||||
if txt_domain.is_some() {
|
if txt_domain.is_some() {
|
||||||
name_servers.push("223.5.5.5:53".into());
|
name_servers.push("223.5.5.5:53".into());
|
||||||
|
name_servers.push("119.29.29.29:53".into());
|
||||||
name_servers.push("114.114.114.114:53".into());
|
name_servers.push("114.114.114.114:53".into());
|
||||||
} else {
|
} else {
|
||||||
return Ok(domain
|
return Ok(current_domain
|
||||||
.to_socket_addrs()
|
.to_socket_addrs()
|
||||||
.with_context(|| format!("DNS query failed {:?}", domain))?
|
.with_context(|| format!("DNS query failed {:?}", current_domain))?
|
||||||
.collect());
|
.collect());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,6 +135,7 @@ pub fn dns_query_all(
|
|||||||
match txt_dns(domain, name_server, default_interface) {
|
match txt_dns(domain, name_server, default_interface) {
|
||||||
Ok(addr) => {
|
Ok(addr) => {
|
||||||
if !addr.is_empty() {
|
if !addr.is_empty() {
|
||||||
|
println!("TXT: {:?}", addr);
|
||||||
return Ok(addr);
|
return Ok(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,12 +149,13 @@ pub fn dns_query_all(
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let end_index = domain
|
|
||||||
|
let end_index = current_domain
|
||||||
.rfind(':')
|
.rfind(':')
|
||||||
.with_context(|| format!("{:?} not port", domain))?;
|
.with_context(|| format!("{:?} not port", current_domain))?;
|
||||||
let host = &domain[..end_index];
|
let host = &domain[..end_index];
|
||||||
let port = u16::from_str(&domain[end_index + 1..])
|
let port = u16::from_str(&domain[end_index + 1..])
|
||||||
.with_context(|| format!("{:?} not port", domain))?;
|
.with_context(|| format!("{:?} not port", current_domain))?;
|
||||||
let th1 = {
|
let th1 = {
|
||||||
let host = host.to_string();
|
let host = host.to_string();
|
||||||
let name_server = name_server.clone();
|
let name_server = name_server.clone();
|
||||||
@@ -174,12 +204,96 @@ pub fn dns_query_all(
|
|||||||
if let Some(e) = err {
|
if let Some(e) = err {
|
||||||
Err(e)
|
Err(e)
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::anyhow!("DNS query failed {:?}", domain))
|
Err(anyhow::anyhow!("DNS query failed {:?}", current_domain))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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..]; // 提取端口部分
|
||||||
|
return !port.is_empty() && port.chars().all(|c| c.is_numeric());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 处理 IPv4 和普通域名(格式为 example.com:443 或 192.168.1.1:8080)
|
||||||
|
if let Some((_host, port)) = addr.rsplit_once(':') {
|
||||||
|
return !port.is_empty() && port.chars().all(|c| c.is_numeric());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_for_redirect(domain: &String) -> anyhow::Result<Option<String>> {
|
||||||
|
// 确保域名有 http:// 或 https:// 前缀
|
||||||
|
let mut url = if domain.starts_with("http://") || domain.starts_with("https://") {
|
||||||
|
domain.clone()
|
||||||
|
} else {
|
||||||
|
format!("http://{}", domain)
|
||||||
|
};
|
||||||
|
// 解析 URL
|
||||||
|
let uri = match Uri::try_from(url.as_str()) {
|
||||||
|
Ok(u) => u,
|
||||||
|
Err(e) => {
|
||||||
|
println!("解析地址失败: {}", e);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut response_body = Vec::new();
|
||||||
|
|
||||||
|
// 发送 HTTP 请求
|
||||||
|
let response = match Request::new(&uri)
|
||||||
|
.timeout(Duration::from_secs(20))
|
||||||
|
.redirect_policy(RedirectPolicy::Limit(0))
|
||||||
|
.send(&mut response_body)
|
||||||
|
{
|
||||||
|
Ok(resp) => {
|
||||||
|
println!("HTTP Status Code: {}", resp.status_code());
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let body_str = String::from_utf8_lossy(&response_body);
|
||||||
|
let cleaned_body = body_str.replace('\n', "").replace('\r', "");
|
||||||
|
println!("Response Body: {}", cleaned_body);
|
||||||
|
// 处理 3XX 重定向
|
||||||
|
if response.status_code().is_redirect() {
|
||||||
|
if let Some(location) = response.headers().get("Location") {
|
||||||
|
url = location.to_string().trim_end_matches('/').to_string();
|
||||||
|
println!("Location: {}", url);
|
||||||
|
return Ok(Some(url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理 200 响应
|
||||||
|
if response.status_code().is_success() {
|
||||||
|
for line in body_str.lines() {
|
||||||
|
let trimmed = line.trim();
|
||||||
|
if parse_host_port(trimmed) {
|
||||||
|
println!("text: {}", trimmed);
|
||||||
|
return Ok(Some(trimmed.to_string()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 去掉 http:// 或 https:// 前缀
|
||||||
|
fn remove_http_prefix(url: &str) -> String {
|
||||||
|
url.trim_start_matches("http://")
|
||||||
|
.trim_start_matches("https://")
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn query<'a>(
|
fn query<'a>(
|
||||||
udp: &UdpSocket,
|
udp: &UdpSocket,
|
||||||
domain: &str,
|
domain: &str,
|
||||||
|
Reference in New Issue
Block a user