diff --git a/Casks/vpn-bypass.rb b/Casks/vpn-bypass.rb index 181b161..59d1665 100644 --- a/Casks/vpn-bypass.rb +++ b/Casks/vpn-bypass.rb @@ -3,7 +3,7 @@ # Or if using local tap: brew install --cask --no-quarantine ./Casks/vpn-bypass.rb cask "vpn-bypass" do - version "1.7.0" + version "1.7.1" sha256 "37b127a55aec0bdb80e824e59e840ce5b529c09086aac7fc24dc4616abb817bd" url "https://github.com/GeiserX/VPN-Bypass/releases/download/v#{version}/VPN-Bypass-#{version}.dmg" diff --git a/Info.plist b/Info.plist index a3f1f59..b573d25 100644 --- a/Info.plist +++ b/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.7.0 + 1.7.1 CFBundleVersion 19 LSMinimumSystemVersion diff --git a/README.md b/README.md index 643312b..2b26e7a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

macOS 13+ Swift 5.9 - Version + Version

## Why? diff --git a/Sources/RouteManager.swift b/Sources/RouteManager.swift index 4cd1d55..fbd801e 100644 --- a/Sources/RouteManager.swift +++ b/Sources/RouteManager.swift @@ -712,7 +712,7 @@ final class RouteManager: ObservableObject { var vpnCandidates: [(name: String, ip: String, isValid: Bool)] = [] for i in interfaces.indices { - let isValid = await isCorporateVPNIP(interfaces[i].ip) + let isValid = await isCorporateVPNIP(interfaces[i].ip, hintType: hintType) interfaces[i].isValidCorporateIP = isValid // Track VPN candidates for debugging @@ -765,7 +765,8 @@ final class RouteManager: ObservableObject { } /// Check if IP is likely a corporate VPN (not Tailscale mesh, not localhost, etc.) - private func isCorporateVPNIP(_ ip: String) async -> Bool { + /// hintType comes from process detection -- used to distinguish Zscaler/WARP from Tailscale in the shared CGNAT range. + private func isCorporateVPNIP(_ ip: String, hintType: VPNType?) async -> Bool { let parts = ip.components(separatedBy: ".") guard parts.count == 4, let first = Int(parts[0]), @@ -779,29 +780,20 @@ final class RouteManager: ObservableObject { // Skip link-local if first == 169 && second == 254 { return false } - // Tailscale CGNAT range (100.64.0.0/10 = 100.64-127.x.x) - // Only consider Tailscale as VPN if it's using an exit node (routing all traffic) + // CGNAT range (100.64.0.0/10 = 100.64-127.x.x) + // Shared by Tailscale, Zscaler, Cloudflare WARP, and other VPNs. + // If a known non-Tailscale VPN process was detected, trust it. + // Otherwise fall back to Tailscale exit-node check. if first == 100 && second >= 64 && second <= 127 { + if let hint = hintType, hint != .tailscale, hint != .unknown { + return true + } return await isTailscaleExitNodeActive() } - // Cloudflare WARP range (check for WARP-specific IPs) - // WARP uses 100.96.0.0/12 range - if first == 100 && second >= 96 && second <= 111 { - return true // WARP is active - } - - // Zscaler typically uses 100.64.x.x or custom ranges - // Already covered by CGNAT check above - // Corporate VPNs typically use private ranges - // 10.0.0.0/8 - Most corporate VPNs use this if first == 10 { return true } - - // 172.16.0.0/12 (172.16-31.x.x) if first == 172 && second >= 16 && second <= 31 { return true } - - // 192.168.0.0/16 - Less common for VPN but possible if first == 192 && second == 168 { return true } return false diff --git a/Sources/SettingsView.swift b/Sources/SettingsView.swift index 1b0f920..78a7ffa 100644 --- a/Sources/SettingsView.swift +++ b/Sources/SettingsView.swift @@ -1263,7 +1263,7 @@ struct GeneralTab: View { HStack { VStack(alignment: .leading, spacing: 2) { BrandedAppName(fontSize: 13) - Text("Version 1.7.0") + Text("Version 1.7.1") .font(.system(size: 11)) .foregroundColor(Color(hex: "6B7280")) } @@ -1721,7 +1721,7 @@ struct InfoTab: View { // App name with branded colors BrandedAppName(fontSize: 24) - Text("v1.7.0") + Text("v1.7.1") .font(.system(size: 12, design: .monospaced)) .foregroundColor(Color(hex: "6B7280")) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 742e915..92b520f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to VPN Bypass will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.7.1] - 2026-02-24 + +### Fixed +- **Zscaler Detection** - Zscaler (and Cloudflare WARP) use CGNAT IPs (`100.64.x.x`) which were incorrectly treated as Tailscale-only, causing `valid=false` rejection. Now trusts the process-detection hint to distinguish Zscaler/WARP from Tailscale in the shared CGNAT range. + ## [1.7.0] - 2026-02-22 ### Added