|
| 1 | +<# |
| 2 | +.SYNOPSIS |
| 3 | + Tor Iran launcher: starts the optimized tor client, waits for bootstrap, |
| 4 | + and sets the Windows system proxy (HTTP 127.0.0.1:8118) on success. |
| 5 | +
|
| 6 | +.DESCRIPTION |
| 7 | + Layout: |
| 8 | + newway\bin\ <- tor.exe, webtunnel.exe, obfs4proxy.exe, snowflake-client.exe + DLLs |
| 9 | + newway\configs\torrc.iran |
| 10 | + newway\data\ <- bridges.txt (see fetch-bridges.ps1), tor.log, runtime torrc |
| 11 | +
|
| 12 | +.PARAMETER BinDir Folder containing the tor binaries (default: ..\bin relative to repo root) |
| 13 | +.PARAMETER BridgesFile File with 'Bridge ...' lines (default: data\bridges.txt) |
| 14 | +.PARAMETER BootstrapOnly Exit after reaching 100% bootstrap (no proxy change, no wait) |
| 15 | +.PARAMETER NewCircuit Send SIGNAL NEWNYM to a running tor and exit |
| 16 | +.PARAMETER Stop Stop the running tor managed by this launcher and reset proxy |
| 17 | +
|
| 18 | +.EXAMPLE |
| 19 | + .\launcher.ps1 |
| 20 | + .\launcher.ps1 -NewCircuit |
| 21 | +#> |
| 22 | +param( |
| 23 | + [string]$BinDir, |
| 24 | + [string]$BridgesFile, |
| 25 | + [switch]$BootstrapOnly, |
| 26 | + [switch]$NewCircuit, |
| 27 | + [switch]$Stop |
| 28 | +) |
| 29 | + |
| 30 | +$ErrorActionPreference = "Stop" |
| 31 | + |
| 32 | +$Root = Split-Path $PSScriptRoot -Parent |
| 33 | +if (-not $BinDir) { $BinDir = Join-Path $Root "bin" } |
| 34 | +$DataDir = Join-Path $Root "data" |
| 35 | +$Template = Join-Path $Root "configs\torrc.iran" |
| 36 | +$RunTorrc = Join-Path $DataDir "torrc" |
| 37 | +$TorLog = Join-Path $DataDir "tor.log" |
| 38 | +$ConsoleLog= Join-Path $DataDir "tor-console.log" |
| 39 | +if (-not $BridgesFile) { $BridgesFile = Join-Path $DataDir "bridges.txt" } |
| 40 | +New-Item -ItemType Directory -Force -Path $DataDir | Out-Null |
| 41 | + |
| 42 | +$TorExe = Join-Path $BinDir "tor.exe" |
| 43 | + |
| 44 | +# ---------- control port helper ---------- |
| 45 | +function Send-Control([string]$cmd) { |
| 46 | + try { |
| 47 | + $c = New-Object System.Net.Sockets.TcpClient("127.0.0.1", 9051) |
| 48 | + $s = $c.GetStream() |
| 49 | + $w = New-Object System.IO.StreamWriter($s) |
| 50 | + $r = New-Object System.IO.StreamReader($s) |
| 51 | + $w.NewLine = "`r`n"; $w.AutoFlush = $true |
| 52 | + $w.WriteLine("AUTHENTICATE"); $null = $r.ReadLine() |
| 53 | + $w.WriteLine($cmd); $null = $r.ReadLine() |
| 54 | + $w.WriteLine("QUIT") |
| 55 | + $c.Close() |
| 56 | + return $true |
| 57 | + } catch { return $false } |
| 58 | +} |
| 59 | + |
| 60 | +# ---------- windows system proxy ---------- |
| 61 | +function Set-SystemProxy([bool]$on) { |
| 62 | + $k = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" |
| 63 | + if ($on) { |
| 64 | + Set-ItemProperty -Path $k -Name ProxyEnable -Value 1 |
| 65 | + Set-ItemProperty -Path $k -Name ProxyServer -Value "127.0.0.1:8118" |
| 66 | + Set-ItemProperty -Path $k -Name ProxyOverride -Value "<local>" |
| 67 | + } else { |
| 68 | + Set-ItemProperty -Path $k -Name ProxyEnable -Value 0 |
| 69 | + } |
| 70 | + Add-Type @" |
| 71 | +using System; using System.Runtime.InteropServices; |
| 72 | +public static class WinINet { |
| 73 | + [DllImport("wininet.dll", SetLastError=true)] |
| 74 | + public static extern bool InternetSetOption(IntPtr h, int o, IntPtr b, int l); |
| 75 | + public static void Refresh(){ |
| 76 | + InternetSetOption(IntPtr.Zero, 39, IntPtr.Zero, 0); // SETTINGS_CHANGED |
| 77 | + InternetSetOption(IntPtr.Zero, 37, IntPtr.Zero, 0); // REFRESH |
| 78 | + } |
| 79 | +} |
| 80 | +"@ |
| 81 | + [WinINet]::Refresh() |
| 82 | +} |
| 83 | + |
| 84 | +# ---------- new circuit / stop ---------- |
| 85 | +if ($NewCircuit) { |
| 86 | + if (Send-Control "SIGNAL NEWNYM") { Write-Host "New identity requested (NEWNYM)."; exit 0 } |
| 87 | + Write-Host "No tor control port found on 127.0.0.1:9051. Is tor running?"; exit 1 |
| 88 | +} |
| 89 | + |
| 90 | +$torProc = Get-Process -Name "tor" -ErrorAction SilentlyContinue | |
| 91 | + Where-Object { $_.Path -and $_.Path -eq $TorExe } |
| 92 | +if ($Stop) { |
| 93 | + if ($torProc) { |
| 94 | + $torProc | Stop-Process -Force |
| 95 | + Start-Sleep -Seconds 1 |
| 96 | + Set-SystemProxy $false |
| 97 | + Write-Host "Tor stopped; system proxy reset." |
| 98 | + } else { Write-Host "No managed tor running." } |
| 99 | + exit 0 |
| 100 | +} |
| 101 | +if ($torProc) { |
| 102 | + Write-Host "A tor instance from this folder is already running (PID $($torProc.Id))." |
| 103 | + Write-Host "Use -Stop to stop it, or -NewCircuit to rotate circuits." |
| 104 | + exit 0 |
| 105 | +} |
| 106 | + |
| 107 | +# ---------- verify binaries ---------- |
| 108 | +if (-not (Test-Path $TorExe)) { |
| 109 | + Write-Host "[x] tor.exe not found in $BinDir" |
| 110 | + Write-Host " Put tor.exe + DLLs + webtunnel.exe + obfs4proxy.exe + snowflake-client.exe there." |
| 111 | + Write-Host " Download them from GitHub Actions artifacts (see README) or run package-release.ps1." |
| 112 | + exit 1 |
| 113 | +} |
| 114 | +foreach ($pt in "webtunnel.exe","obfs4proxy.exe","snowflake-client.exe") { |
| 115 | + if (-not (Test-Path (Join-Path $BinDir $pt))) { |
| 116 | + Write-Warning "Missing transport: $pt (bridges of that type will not work)" |
| 117 | + } |
| 118 | +} |
| 119 | + |
| 120 | +# ---------- build runtime torrc ---------- |
| 121 | +if (-not (Test-Path $Template)) { Write-Host "[x] template not found: $Template"; exit 1 } |
| 122 | +$torrc = Get-Content $Template -Raw |
| 123 | +$torrc = $torrc.Replace("%%DIR%%", $BinDir) |
| 124 | + |
| 125 | +$bridgeCount = 0 |
| 126 | +if (Test-Path $BridgesFile) { |
| 127 | + $bridgeLines = @(Get-Content $BridgesFile | Where-Object { $_ -match "^Bridge\s+(webtunnel|obfs4|snowflake)" }) |
| 128 | + $bridgeCount = $bridgeLines.Count |
| 129 | + if ($bridgeCount -gt 0) { |
| 130 | + $torrc += "`n# --- bridges (from $BridgesFile) ---`n" + ($bridgeLines -join "`n") + "`n" |
| 131 | + } |
| 132 | +} |
| 133 | +Set-Content -Path $RunTorrc -Value $torrc -Encoding UTF8 |
| 134 | +Write-Host "[i] runtime torrc written to $RunTorrc (bridges: $bridgeCount)" |
| 135 | + |
| 136 | +# ---------- start tor ---------- |
| 137 | +if (Test-Path $TorLog) { Remove-Item $TorLog -Force } |
| 138 | +if (Test-Path $ConsoleLog) { Remove-Item $ConsoleLog -Force } |
| 139 | + |
| 140 | +Write-Host "[i] starting tor.exe ..." |
| 141 | +$proc = Start-Process -FilePath $TorExe -ArgumentList "-f", $RunTorrc -PassThru -WindowStyle Hidden -RedirectStandardOutput $ConsoleLog -RedirectStandardError (Join-Path $DataDir "tor-err.log") |
| 142 | + |
| 143 | +# ---------- wait for bootstrap ---------- |
| 144 | +$deadline = (Get-Date).AddMinutes(6) |
| 145 | +$lastPct = -1 |
| 146 | +$bootstrapped = $false |
| 147 | +try { |
| 148 | + while ((Get-Date) -lt $deadline) { |
| 149 | + if ($proc.HasExited) { |
| 150 | + Write-Host "" |
| 151 | + Write-Host "[x] tor exited with code $($proc.ExitCode)" |
| 152 | + if (Test-Path $ConsoleLog) { Get-Content $ConsoleLog -Tail 20 | ForEach-Object { Write-Host " $_" } } |
| 153 | + exit 1 |
| 154 | + } |
| 155 | + if (Test-Path $TorLog) { |
| 156 | + $log = Get-Content $TorLog -ErrorAction SilentlyContinue |
| 157 | + $last = $log | Select-Object -Last 1 |
| 158 | + if ($last -match "Bootstrapped 100%") { $bootstrapped = $true; break } |
| 159 | + if ($last -match "Bootstrapped (\d+)%") { |
| 160 | + $pct = [int]$matches[1] |
| 161 | + if ($pct -ne $lastPct) { Write-Host " Bootstrapped $pct% ..."; $lastPct = $pct } |
| 162 | + } |
| 163 | + } |
| 164 | + Start-Sleep -Seconds 3 |
| 165 | + } |
| 166 | +} finally { |
| 167 | + if (-not $bootstrapped) { |
| 168 | + Write-Host "" |
| 169 | + Write-Host "[x] bootstrap did not reach 100% in time." |
| 170 | + Write-Host " Common fixes:" |
| 171 | + Write-Host " - your bridges may be blocked: re-run fetch-bridges.ps1 then launcher.ps1" |
| 172 | + Write-Host " - try a different transport (edit data\bridges.txt)" |
| 173 | + Write-Host " - check the tail of: $TorLog" |
| 174 | + if (Test-Path $TorLog) { Get-Content $TorLog -Tail 8 | ForEach-Object { Write-Host " $_" } } |
| 175 | + $proc | Stop-Process -Force |
| 176 | + Set-SystemProxy $false |
| 177 | + exit 1 |
| 178 | + } |
| 179 | +} |
| 180 | + |
| 181 | +# ---------- success ---------- |
| 182 | +if ($BootstrapOnly) { |
| 183 | + Write-Host "" |
| 184 | + Write-Host "Bootstrapped 100%. Test mode: stopping tor and resetting proxy." |
| 185 | + $proc | Stop-Process -Force |
| 186 | + Set-SystemProxy $false |
| 187 | + exit 0 |
| 188 | +} |
| 189 | + |
| 190 | +Set-SystemProxy $true |
| 191 | +Write-Host "" |
| 192 | +Write-Host "============================================================" |
| 193 | +Write-Host " Tor is UP (100% bootstrap). System proxy set to 127.0.0.1:8118" |
| 194 | +Write-Host " SOCKS5: 127.0.0.1:9050 | DNS: 127.0.0.1:5353" |
| 195 | +Write-Host " Press Enter to stop Tor and restore the system proxy." |
| 196 | +Write-Host "============================================================" |
| 197 | +[void]$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | Out-Null |
| 198 | + |
| 199 | +$proc | Stop-Process -Force |
| 200 | +Set-SystemProxy $false |
| 201 | +Write-Host "Tor stopped; system proxy restored." |
0 commit comments