Muxun_programs/python/tun.ps1
Galaxy 907bd5af0e mx init
the muxun is not operated by git,now init
2025-11-09 20:06:06 +08:00

203 lines
6.7 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#Requires -RunAsAdministrator
[CmdletBinding()]
param(
[switch]$Stop,
[string]$Socks = "127.0.0.1:59999",
[string[]]$Direct = @("117.143.9.6"),
[string]$Dns = "127.0.0.1",
[switch]$EnableDoH # 可选:为 $Dns 启用 DoHWin11+
)
# --- 全局设置 ---
$ErrorActionPreference = "Stop"
$TunIP = "192.168.123.1"
$TunMask = "255.255.255.0"
$State = Join-Path $PSScriptRoot ".wintun-state.json"
# --- 常量:防火墙规则名 ---
$FwNames = @(
"Block NonTUN DNS TCPv4",
"Block NonTUN DNS UDPv4",
"Block NonTUN DNS TCPv6",
"Block NonTUN DNS UDPv6"
)
function Get-Uplink {
<#
选一个物理上行(默认路由优先,排除虚拟网卡)
Returns: [pscustomobject] @{ Alias; Index; Gateway }
#>
$bad = "wintun|wireguard|tap|vEthernet|Hyper-V|VirtualBox|VMware|Npcap|Loopback|Docker|Tailscale|ZeroTier|Hamachi"
$routes = Get-NetRoute -DestinationPrefix "0.0.0.0/0" -AddressFamily IPv4 |
Sort-Object RouteMetric, InterfaceMetric
foreach ($r in $routes) {
$if = Get-NetIPInterface -InterfaceIndex $r.InterfaceIndex -ErrorAction SilentlyContinue |
Where-Object { $_.AddressFamily -eq 2 } # 2 means IPv4
if ($null -ne $if -and ($if.InterfaceAlias -notmatch $bad)) {
return [pscustomobject]@{ Alias = $if.InterfaceAlias; Index = $if.InterfaceIndex; Gateway = $r.NextHop }
}
}
throw "No physical uplink found."
}
function Remove-DnsEnforcement {
<#
清理NRPT + 防火墙规则
#>
try {
Get-DnsClientNrptRule -ErrorAction SilentlyContinue |
Where-Object { $_.Namespace -eq "." } |
Remove-DnsClientNrptRule -ErrorAction SilentlyContinue -Force | Out-Null
} catch {}
foreach ($n in $FwNames) {
Get-NetFirewallRule -DisplayName $n -ErrorAction SilentlyContinue | Remove-NetFirewallRule -ErrorAction SilentlyContinue
}
}
function Apply-DnsEnforcement {
param(
[Parameter(Mandatory=$true)][string[]]$DnsServers,
[Parameter(Mandatory=$true)][int]$TunIfIndex
)
<#
强制 DNS
1) NRPT "." 指向 $DnsServers
2) (已禁用) 封非 TUN 的 53 (TCP/UDP, v4/v6)
#>
# 清理旧 NRPT
Remove-DnsEnforcement
# NRPT所有域名都走指定 DNS
Add-DnsClientNrptRule -Namespace "." -NameServers $DnsServers -Comment "Force all DNS via TUN" | Out-Null
# --- 防火墙规则部分已移除,以解决兼容性问题 ---
}
function Enable-DoHIfRequested {
param(
[Parameter(Mandatory=$true)][string]$Server
)
<#
为指定 IPv4 DNS 启用 DoHWin11+)。失败时静默跳过。
#>
if (-not $EnableDoH) { return }
if ($Server -match '^\d{1,3}(\.\d{1-3}){3}$') {
try {
# Cloudflare 模板示例;如换 DNS请替换模板
netsh dns add encryption server=$Server dohtemplate=https://cloudflare-dns.com/dns-query autoupgrade=yes udpfallback=no | Out-Null
} catch {}
}
}
function Start-Tun {
<#
启动 tun2socks创建 TUN设置地址与 DNS 强制策略,添加默认路由与直连例外
#>
$t2s = Join-Path $PSScriptRoot "tun2socks.exe"
$dll = Join-Path $PSScriptRoot "wintun.dll"
if (-not (Test-Path $t2s)) { throw "Missing tun2socks.exe" }
if (-not (Test-Path $dll)) { throw "Missing wintun.dll (same folder as script)" }
# 先清掉历史 tun2socks
Get-Process tun2socks -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
$uplink = Get-Uplink
Write-Host ("Uplink: {0} Gateway: {1}" -f $uplink.Alias, $uplink.Gateway)
$before = (Get-NetIPInterface | Where-Object { $_.AddressFamily -eq 2 }).InterfaceIndex
# 启动 tun2socks
Start-Process -FilePath $t2s -ArgumentList @(
"-device","wintun",
"-proxy",("socks5://{0}" -f $Socks),
"-interface",$uplink.Alias
) -WindowStyle Hidden | Out-Null
# 识别新出现的 TUN 接口
$tun = $null
for ($i=0; $i -lt 60; $i++) {
Start-Sleep -Milliseconds 200
$after = Get-NetIPInterface | Where-Object { $_.AddressFamily -eq 2 }
$new = $after | Where-Object { $before -notcontains $_.InterfaceIndex }
if ($new) { $tun = $new | Sort-Object InterfaceMetric | Select-Object -First 1; break }
}
if (-not $tun) {
$tun = Get-NetIPInterface | Where-Object { $_.AddressFamily -eq 2 } |
Where-Object { $_.InterfaceAlias -match "wintun|tun|wireguard" } |
Sort-Object InterfaceMetric | Select-Object -First 1
}
if (-not $tun) { throw "Wintun interface not found." }
# 配置 TUN 地址
netsh interface ipv4 set address name="$($tun.InterfaceAlias)" source=static addr=$TunIP mask=$TunMask
# 设 TUN 的 DNS (使用 netsh 以增强兼容性)
$dnsServers = @($Dns)
netsh interface ipv4 set dnsservers name="$($tun.InterfaceAlias)" static $($dnsServers[0]) primary
# 可选启用 DoH
Enable-DoHIfRequested -Server $Dns
# 强制NRPT + 防火墙
Apply-DnsEnforcement -DnsServers $dnsServers -TunIfIndex $tun.InterfaceIndex
# 把默认路由指向 TUN所有流量含 DNS 都从隧道走)
route -p add 0.0.0.0 mask 0.0.0.0 $TunIP metric 1 if $($tun.InterfaceIndex) | Out-Null
# 直连例外(这些目标直接走物理上行)
foreach ($ip in $Direct) {
route -p add $ip mask 255.255.255.255 $($uplink.Gateway) if $($uplink.Index) metric 5 | Out-Null
}
# 降低 TUN 接口度量 (已注释掉,以解决兼容性问题)
# try { Set-NetIPInterface -InterfaceIndex $tun.InterfaceIndex -InterfaceMetric 5 -ErrorAction SilentlyContinue } catch {}
# 记录状态
@{
TunAlias = $tun.InterfaceAlias
TunIndex = $tun.InterfaceIndex
TunIP = $TunIP
Direct = $Direct
Dns = $dnsServers
} | ConvertTo-Json | Set-Content -Path $State -Encoding UTF8
Write-Host ("TUN ready: {0} -> SOCKS {1}; DNS {2}; direct: {3}" -f $tun.InterfaceAlias, $Socks, ($dnsServers -join ","), ($Direct -join ", ")) -ForegroundColor Green
}
function Stop-Tun {
<#
清理默认路由、直连路由、NRPT、防火墙、进程与状态
#>
$tunIPLocal = $TunIP
$directLocal = $Direct
if (Test-Path $State) {
try {
$s = Get-Content $State | ConvertFrom-Json
if ($s.TunIP) { $tunIPLocal = $s.TunIP }
if ($s.Direct) { $directLocal = $s.Direct }
} catch {}
}
# 路由清理
route delete 0.0.0.0 mask 0.0.0.0 $tunIPLocal | Out-Null
foreach ($ip in $directLocal) { route delete $ip | Out-Null }
# 清理 DNS 强制策略
Remove-DnsEnforcement
# 结束进程与状态文件
Get-Process tun2socks -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
Remove-Item $State -ErrorAction SilentlyContinue | Out-Null
Write-Host "Stopped and cleaned routes & DNS policies." -ForegroundColor Yellow
}
# --- 入口 ---
try {
if ($Stop) { Stop-Tun } else { Start-Tun }
} catch {
Write-Host ("Error: {0}" -f $_.Exception.Message) -ForegroundColor Red
exit 1
}