Compare commits

..

6 Commits

Author SHA1 Message Date
Jason A. Donenfeld 68d928192b Version bump
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-11-05 17:25:24 +08:00
Roopesh Chander 028e76eb3f [REVERT ME SOON] TunnelsManager: Workaround for macOS Catalina deleting tunnels arbitrarily
In macOS Catalina, for some users, the tunnels get deleted arbitrarily
by the OS. It's not clear what triggers that.

As a workaround, in macOS Catalina, when we realize that tunnels have
been deleted outside the app, we reinstate those tunnels using the
information in the keychain.

Signed-off-by: Roopesh Chander <roop@roopc.net>
2019-11-05 17:25:21 +08:00
Jason A. Donenfeld cb0c965294 wireguard-go-bridge: update to 1.13.4
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-11-05 17:20:31 +08:00
Jason A. Donenfeld d7ce621cb2 UI: iOS: more dark mode fixes
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-25 10:59:16 +02:00
Jason A. Donenfeld a1ca4f6eb5 wireguard-go-bridge: work around Go 1.13.3 regression
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-25 10:36:58 +02:00
Jason A. Donenfeld 437f0dc46d Revert "NetworkExtension: don't use exit(0) hack on Catalina"
This reverts commit 3619279a65d9a506fb13d7f24909b38a5202fa8f.

Still broken!

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
2019-10-15 16:51:50 +02:00
10 changed files with 213 additions and 28 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
VERSION_NAME = 0.0.20191015
VERSION_ID = 15
VERSION_NAME = 0.0.20191105
VERSION_ID = 16
+161 -2
View File
@@ -20,17 +20,23 @@ protocol TunnelsManagerActivationDelegate: class {
}
class TunnelsManager {
private var tunnels: [TunnelContainer]
fileprivate var tunnels: [TunnelContainer]
weak var tunnelsListDelegate: TunnelsManagerListDelegate?
weak var activationDelegate: TunnelsManagerActivationDelegate?
private var statusObservationToken: AnyObject?
private var waiteeObservationToken: AnyObject?
private var configurationsObservationToken: AnyObject?
private var catalinaWorkaround: Any?
init(tunnelProviders: [NETunnelProviderManager]) {
tunnels = tunnelProviders.map { TunnelContainer(tunnel: $0) }.sorted { TunnelsManager.tunnelNameIsLessThan($0.name, $1.name) }
startObservingTunnelStatuses()
startObservingTunnelConfigurations()
#if os(macOS)
if #available(macOS 10.15, *) {
self.catalinaWorkaround = CatalinaWorkaround(tunnelsManager: self)
}
#endif
}
static func create(completionHandler: @escaping (Result<TunnelsManager, TunnelsManagerError>) -> Void) {
@@ -75,7 +81,15 @@ class TunnelsManager {
tunnelManagers.remove(at: index)
}
}
#if os(macOS)
if #available(macOS 10.15, *) {
// Don't delete orphaned keychain refs. We need them to restore tunnels as a workaround.
} else {
Keychain.deleteReferences(except: refs)
}
#else
Keychain.deleteReferences(except: refs)
#endif
#if os(iOS)
RecentTunnelsTracker.cleanupTunnels(except: tunnelNames)
#endif
@@ -622,7 +636,7 @@ class TunnelContainer: NSObject {
}
extension NETunnelProviderManager {
private static var cachedConfigKey: UInt8 = 0
fileprivate static var cachedConfigKey: UInt8 = 0
var tunnelConfiguration: TunnelConfiguration? {
if let cached = objc_getAssociatedObject(self, &NETunnelProviderManager.cachedConfigKey) as? TunnelConfiguration {
@@ -645,3 +659,148 @@ extension NETunnelProviderManager {
return localizedDescription == tunnel.name && tunnelConfiguration == tunnel.tunnelConfiguration
}
}
#if os(macOS)
@available(macOS 10.15, *)
class CatalinaWorkaround {
// In macOS Catalina, for some users, the tunnels get deleted arbitrarily
// by the OS. It's not clear what triggers that.
// As a workaround, in macOS Catalina, when we realize that tunnels have been
// deleted outside the app, we reinstate those tunnels using the information
// in the keychain.
unowned let tunnelsManager: TunnelsManager
private var configChangeSubscriber: Any?
struct ReinstationData {
let tunnelConfiguration: TunnelConfiguration
let keychainPasswordRef: Data
}
init(tunnelsManager: TunnelsManager) {
self.tunnelsManager = tunnelsManager
// Attempt reinstation when there's a change in tunnel configurations,
// which indicates that tunnels may have been deleted outside the app.
// We use debounce to wait for all change notifications to arrive
// before attempting to reinstate, so that we don't have saveToPreferences
// being called while another saveToPreferences is in progress.
self.configChangeSubscriber = NotificationCenter.default
.publisher(for: .NEVPNConfigurationChange, object: nil)
.debounce(for: .seconds(1), scheduler: RunLoop.main)
.subscribe(on: RunLoop.main)
.sink { [weak self] _ in
self?.reinstateTunnelsDeletedOutsideApp()
}
// Attempt reinstation on app launch
reinstateTunnelsDeletedOutsideApp()
}
func reinstateTunnelsDeletedOutsideApp() {
let rd = reinstationDataForTunnelsDeletedOutsideApp()
reinstateTunnels(ArraySlice(rd), completionHandler: nil)
}
private func reinstateTunnels(_ rdArray: ArraySlice<ReinstationData>, completionHandler: (() -> Void)?) {
guard let head = rdArray.first else {
completionHandler?()
return
}
let tail = rdArray.dropFirst()
self.tunnelsManager.reinstateTunnel(reinstationData: head) { _ in
DispatchQueue.main.async {
self.reinstateTunnels(tail, completionHandler: completionHandler)
}
}
}
private func reinstationDataForTunnelsDeletedOutsideApp() -> [ReinstationData] {
let knownRefs: [Data] = self.tunnelsManager.tunnels
.compactMap { $0.tunnelProvider.protocolConfiguration as? NETunnelProviderProtocol }
.compactMap { $0.passwordReference }
let knownRefsSet: Set<Data> = Set(knownRefs)
var result: CFTypeRef?
let ret = SecItemCopyMatching([kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: Bundle.main.bundleIdentifier as Any,
kSecMatchLimit as String: kSecMatchLimitAll,
kSecReturnAttributes as String: true,
kSecReturnPersistentRef as String: true] as CFDictionary,
&result)
guard ret == errSecSuccess, let resultDicts = result as? [[String: Any]] else { return [] }
let labelPrefix = "WireGuard Tunnel: "
var reinstationData: [ReinstationData] = []
for resultDict in resultDicts {
guard let ref = resultDict[kSecValuePersistentRef as String] as? Data else { continue }
guard let label = resultDict[kSecAttrLabel as String] as? String else { continue }
guard label.hasPrefix(labelPrefix) else { continue }
if !knownRefsSet.contains(ref) {
let tunnelName = String(label.dropFirst(labelPrefix.count))
if let configStr = Keychain.openReference(called: ref),
let config = try? TunnelConfiguration(fromWgQuickConfig: configStr, called: tunnelName) {
reinstationData.append(ReinstationData(tunnelConfiguration: config, keychainPasswordRef: ref))
}
}
}
return reinstationData
}
}
#endif
#if os(macOS)
@available(macOS 10.15, *)
extension TunnelsManager {
fileprivate func reinstateTunnel(reinstationData: CatalinaWorkaround.ReinstationData, completionHandler: @escaping (Bool) -> Void) {
let tunnelName = reinstationData.tunnelConfiguration.name ?? ""
if tunnelName.isEmpty {
completionHandler(false)
return
}
if tunnels.contains(where: { $0.name == tunnelName }) {
completionHandler(false)
return
}
let tunnelProviderProtocol = NETunnelProviderProtocol()
guard let appId = Bundle.main.bundleIdentifier else { fatalError() }
tunnelProviderProtocol.providerBundleIdentifier = "\(appId).network-extension"
tunnelProviderProtocol.passwordReference = reinstationData.keychainPasswordRef
tunnelProviderProtocol.providerConfiguration = ["UID": getuid()]
tunnelProviderProtocol.serverAddress = {
let endpoints = reinstationData.tunnelConfiguration.peers.compactMap { $0.endpoint }
if endpoints.count == 1 {
return endpoints[0].stringRepresentation
} else if endpoints.isEmpty {
return "Unspecified"
} else {
return "Multiple endpoints"
}
}()
let tunnelProvider = NETunnelProviderManager()
tunnelProvider.localizedDescription = tunnelName
tunnelProvider.protocolConfiguration = tunnelProviderProtocol
objc_setAssociatedObject(tunnelProvider, &NETunnelProviderManager.cachedConfigKey, reinstationData.tunnelConfiguration, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
tunnelProvider.isEnabled = true
tunnelProvider.saveToPreferences { [weak self] error in
guard error == nil else {
wg_log(.error, message: "Reinstate: Saving configuration failed: \(error!)")
completionHandler(false)
return
}
guard let self = self else { return }
let tunnel = TunnelContainer(tunnel: tunnelProvider)
self.tunnels.append(tunnel)
self.tunnels.sort { TunnelsManager.tunnelNameIsLessThan($0.name, $1.name) }
self.tunnelsListDelegate?.tunnelAdded(at: self.tunnels.firstIndex(of: tunnel)!)
completionHandler(true)
}
}
}
#endif
+5 -1
View File
@@ -21,7 +21,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
let window = UIWindow(frame: UIScreen.main.bounds)
window.backgroundColor = .white
if #available(iOS 13.0, *) {
window.backgroundColor = .systemBackground
} else {
window.backgroundColor = .white
}
self.window = window
let mainVC = MainViewController()
@@ -41,7 +41,11 @@ class LogViewController: UIViewController {
override func loadView() {
view = UIView()
view.backgroundColor = .white
if #available(iOS 13.0, *) {
view.backgroundColor = .systemBackground
} else {
view.backgroundColor = .white
}
view.addSubview(textView)
textView.translatesAutoresizingMaskIntoConstraints = false
@@ -87,12 +91,18 @@ class LogViewController: UIViewController {
let richText = NSMutableAttributedString()
let bodyFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.body)
let captionFont = UIFont.preferredFont(forTextStyle: UIFont.TextStyle.caption1)
let lightGrayColor = UIColor(white: 0.88, alpha: 1.0)
for logEntry in fetchedLogEntries {
let bgColor = self.isNextLineHighlighted ? lightGrayColor : UIColor.white
let timestampText = NSAttributedString(string: logEntry.timestamp + "\n", attributes: [.font: captionFont, .backgroundColor: bgColor, .paragraphStyle: self.paragraphStyle])
let messageText = NSAttributedString(string: logEntry.message + "\n", attributes: [.font: bodyFont, .backgroundColor: bgColor, .paragraphStyle: self.paragraphStyle])
var bgColor: UIColor
var fgColor: UIColor
if #available(iOS 13.0, *) {
bgColor = self.isNextLineHighlighted ? .systemGray3 : .systemBackground
fgColor = .label
} else {
bgColor = self.isNextLineHighlighted ? UIColor(white: 0.88, alpha: 1.0) : UIColor.white
fgColor = .black
}
let timestampText = NSAttributedString(string: logEntry.timestamp + "\n", attributes: [.font: captionFont, .backgroundColor: bgColor, .foregroundColor: fgColor, .paragraphStyle: self.paragraphStyle])
let messageText = NSAttributedString(string: logEntry.message + "\n", attributes: [.font: bodyFont, .backgroundColor: bgColor, .foregroundColor: fgColor, .paragraphStyle: self.paragraphStyle])
richText.append(timestampText)
richText.append(messageText)
self.isNextLineHighlighted.toggle()
@@ -11,7 +11,11 @@ class MainViewController: UISplitViewController {
init() {
let detailVC = UIViewController()
detailVC.view.backgroundColor = .white
if #available(iOS 13.0, *) {
detailVC.view.backgroundColor = .systemBackground
} else {
detailVC.view.backgroundColor = .white
}
let detailNC = UINavigationController(rootViewController: detailVC)
let masterVC = TunnelsListTableViewController()
@@ -52,7 +52,11 @@ class TunnelsListTableViewController: UIViewController {
override func loadView() {
view = UIView()
view.backgroundColor = .white
if #available(iOS 13.0, *) {
view.backgroundColor = .systemBackground
} else {
view.backgroundColor = .white
}
tableView.dataSource = self
tableView.delegate = self
@@ -395,7 +399,11 @@ extension TunnelsListTableViewController: TunnelsManagerListDelegate {
(splitViewController.viewControllers[0] as? UINavigationController)?.popToRootViewController(animated: false)
} else {
let detailVC = UIViewController()
detailVC.view.backgroundColor = .white
if #available(iOS 13.0, *) {
detailVC.view.backgroundColor = .systemBackground
} else {
detailVC.view.backgroundColor = .white
}
let detailNC = UINavigationController(rootViewController: detailVC)
splitViewController.showDetailViewController(detailNC, sender: self)
}
@@ -99,10 +99,7 @@ class PacketTunnelProvider: NEPacketTunnelProvider {
// HACK: This is a filthy hack to work around Apple bug 32073323 (dup'd by us as 47526107).
// Remove it when they finally fix this upstream and the fix has been rolled out to
// sufficient quantities of users.
let osVersion = ProcessInfo.processInfo.operatingSystemVersion
if osVersion.majorVersion <= 10 && osVersion.minorVersion <= 14 {
exit(0)
}
exit(0)
#endif
}
+1 -1
View File
@@ -28,7 +28,7 @@ $(GOROOT)/.prepared:
[ -n "$(REAL_GOROOT)" ]
mkdir -p "$(GOROOT)"
rsync -a --delete --exclude=pkg/obj/go-build "$(REAL_GOROOT)/" "$(GOROOT)/"
patch -p1 -f -N -r- -d "$(GOROOT)" < goruntime-boottime-over-monotonic.diff
cat goruntime-*.diff | patch -p1 -f -N -r- -d "$(GOROOT)"
touch "$@"
define libwg-go-a
+4 -3
View File
@@ -3,7 +3,8 @@ module golang.zx2c4.com/wireguard/ios
go 1.13
require (
golang.org/x/net v0.0.0-20191007182048-72f939374954 // indirect
golang.org/x/sys v0.0.0-20191008105621-543471e840be
golang.zx2c4.com/wireguard v0.0.20190909-0.20191008144818-222f0f8000e8
golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59 // indirect
golang.org/x/net v0.0.0-20191105084925-a882066a44e0 // indirect
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6
golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1
)
+8 -6
View File
@@ -1,20 +1,22 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4=
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59 h1:PyXRxSVbvzDGuqYXjHndV7xDzJ7w2K8KD9Ef8GB7KOE=
golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823 h1:Ypyv6BNJh07T1pUSrehkLemqPKXhus2MkfktJ91kRh4=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954 h1:JGZucVF/L/TotR719NbujzadOZ2AgnYlqphQGHDCKaU=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191105084925-a882066a44e0 h1:QPlSTtPE2k6PZPasQUbzuK3p9JbS+vMXYVto8g/yrsg=
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c h1:6Zx7DRlKXf79yfxuQ/7GqV3w2y7aDsk6bGg0MzF5RVU=
golang.org/x/sys v0.0.0-20191003212358-c178f38b412c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 h1:ZJUmhYTp8GbGC0ViZRc2U+MIYQ8xx9MscsdXnclfIhw=
golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.zx2c4.com/wireguard v0.0.20190909-0.20191008144818-222f0f8000e8 h1:BqfQHKZLrdq0j5Z/R9coISbr1nYcSE+3BdyF5LidO+g=
golang.zx2c4.com/wireguard v0.0.20190909-0.20191008144818-222f0f8000e8/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=
golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1 h1:KxtBKNgJUQG8vwZzJKkwBGOcqp95xLu6A6KIMde1kl0=
golang.zx2c4.com/wireguard v0.0.20191013-0.20191030132932-4cdf805b29b1/go.mod h1:P2HsVp8SKwZEufsnezXZA4GRX/T49/HlU7DGuelXsU4=