Compare commits
2 commits
9e03c9680c
...
f34fb10922
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f34fb10922 | ||
|
|
b462f3fb6c |
40 changed files with 1349 additions and 1158 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
|
@ -13,5 +13,6 @@
|
||||||
],
|
],
|
||||||
"[rust]": {
|
"[rust]": {
|
||||||
"editor.defaultFormatter": "rust-lang.rust-analyzer",
|
"editor.defaultFormatter": "rust-lang.rust-analyzer",
|
||||||
}
|
},
|
||||||
|
"rust-analyzer.inlayHints.typeHints.enable": false
|
||||||
}
|
}
|
||||||
|
|
@ -39,10 +39,10 @@ extension Tunnel {
|
||||||
var isOn: Binding<Bool> {
|
var isOn: Binding<Bool> {
|
||||||
Binding {
|
Binding {
|
||||||
switch self.status {
|
switch self.status {
|
||||||
case .unknown, .disabled, .disconnecting, .disconnected, .invalid, .permissionRequired, .configurationReadWriteFailed:
|
|
||||||
return false
|
|
||||||
case .connecting, .reasserting, .connected:
|
case .connecting, .reasserting, .connected:
|
||||||
return true
|
true
|
||||||
|
default:
|
||||||
|
false
|
||||||
}
|
}
|
||||||
} set: { newValue in
|
} set: { newValue in
|
||||||
switch (self.status, newValue) {
|
switch (self.status, newValue) {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import Combine
|
import BurrowShared
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@Observable class Tunnel {
|
@Observable
|
||||||
|
class Tunnel {
|
||||||
private(set) var status: Status = .unknown
|
private(set) var status: Status = .unknown
|
||||||
private var error: NEVPNError?
|
private var error: NEVPNError?
|
||||||
|
|
||||||
|
private let logger = Logger.logger(for: Tunnel.self)
|
||||||
private let bundleIdentifier: String
|
private let bundleIdentifier: String
|
||||||
private let configure: (NETunnelProviderManager, NETunnelProviderProtocol) -> Void
|
private let configure: (NETunnelProviderManager, NETunnelProviderProtocol) -> Void
|
||||||
private var tasks: [Task<Void, Error>] = []
|
private var tasks: [Task<Void, Error>] = []
|
||||||
|
|
@ -49,33 +51,34 @@ import SwiftUI
|
||||||
self.bundleIdentifier = bundleIdentifier
|
self.bundleIdentifier = bundleIdentifier
|
||||||
self.configure = configure
|
self.configure = configure
|
||||||
|
|
||||||
listenForUpdates()
|
|
||||||
Task { await update() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private func listenForUpdates() {
|
|
||||||
let center = NotificationCenter.default
|
let center = NotificationCenter.default
|
||||||
let statusTask = Task {
|
let configurationChanged = Task {
|
||||||
for try await _ in center.notifications(named: .NEVPNStatusDidChange).map({ _ in () }) {
|
|
||||||
status = currentStatus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let configurationTask = Task {
|
|
||||||
for try await _ in center.notifications(named: .NEVPNConfigurationChange).map({ _ in () }) {
|
for try await _ in center.notifications(named: .NEVPNConfigurationChange).map({ _ in () }) {
|
||||||
await update()
|
await update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tasks = [statusTask, configurationTask]
|
let statusChanged = Task {
|
||||||
|
for try await _ in center.notifications(named: .NEVPNStatusDidChange).map({ _ in () }) {
|
||||||
|
await MainActor.run {
|
||||||
|
status = currentStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks = [configurationChanged, statusChanged]
|
||||||
|
|
||||||
|
Task { await update() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private func update() async {
|
private func update() async {
|
||||||
do {
|
do {
|
||||||
let updated = try await NETunnelProviderManager.managers
|
let updated = try await NETunnelProviderManager.managers
|
||||||
await MainActor.run { managers = updated }
|
await MainActor.run {
|
||||||
|
managers = updated
|
||||||
|
}
|
||||||
} catch let vpnError as NEVPNError {
|
} catch let vpnError as NEVPNError {
|
||||||
error = vpnError
|
error = vpnError
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
logger.error("Failed to update VPN configurations: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,9 +120,7 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
for task in tasks {
|
tasks.forEach { $0.cancel() }
|
||||||
task.cancel()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,19 +128,19 @@ extension NEVPNConnection {
|
||||||
var tunnelStatus: Tunnel.Status {
|
var tunnelStatus: Tunnel.Status {
|
||||||
switch status {
|
switch status {
|
||||||
case .connected:
|
case .connected:
|
||||||
return .connected(connectedDate!)
|
.connected(connectedDate!)
|
||||||
case .connecting:
|
case .connecting:
|
||||||
return .connecting
|
.connecting
|
||||||
case .disconnecting:
|
case .disconnecting:
|
||||||
return .disconnecting
|
.disconnecting
|
||||||
case .disconnected:
|
case .disconnected:
|
||||||
return .disconnected
|
.disconnected
|
||||||
case .reasserting:
|
case .reasserting:
|
||||||
return .reasserting
|
.reasserting
|
||||||
case .invalid:
|
case .invalid:
|
||||||
return .invalid
|
.invalid
|
||||||
@unknown default:
|
@unknown default:
|
||||||
return .unknown
|
.unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,20 @@
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
0B28F1562ABF463A000D44B0 /* DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B28F1552ABF463A000D44B0 /* DataTypes.swift */; };
|
0B28F1562ABF463A000D44B0 /* DataTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B28F1552ABF463A000D44B0 /* DataTypes.swift */; };
|
||||||
0B46E8E02AC918CA00BA2A3C /* BurrowIpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B46E8DF2AC918CA00BA2A3C /* BurrowIpc.swift */; };
|
0B46E8E02AC918CA00BA2A3C /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B46E8DF2AC918CA00BA2A3C /* Client.swift */; };
|
||||||
43AA26D82A10004900F14CE6 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuView.swift */; };
|
43AA26D82A10004900F14CE6 /* MenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43AA26D72A10004900F14CE6 /* MenuView.swift */; };
|
||||||
|
D00117312B2FFFC900D87C25 /* NWConnection+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */; };
|
||||||
|
D00117332B3001A400D87C25 /* NewlineProtocolFramer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */; };
|
||||||
|
D001173B2B30341C00D87C25 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = D001173A2B30341C00D87C25 /* Logging.swift */; };
|
||||||
|
D00117442B30372900D87C25 /* libBurrowShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D00117382B30341C00D87C25 /* libBurrowShared.a */; };
|
||||||
|
D00117452B30372C00D87C25 /* libBurrowShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D00117382B30341C00D87C25 /* libBurrowShared.a */; };
|
||||||
D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00AA8962A4669BC005C8102 /* AppDelegate.swift */; };
|
D00AA8972A4669BC005C8102 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D00AA8962A4669BC005C8102 /* AppDelegate.swift */; };
|
||||||
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; };
|
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */; };
|
||||||
D020F65D29E4A697002790F6 /* BurrowNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
D020F65D29E4A697002790F6 /* BurrowNetworkExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */; };
|
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */; };
|
||||||
D05B9F7829E39EEC008CB1F9 /* TunnelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */; };
|
D05B9F7829E39EEC008CB1F9 /* TunnelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */; };
|
||||||
D05B9F7A29E39EED008CB1F9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D05B9F7929E39EED008CB1F9 /* Assets.xcassets */; };
|
D05B9F7A29E39EED008CB1F9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D05B9F7929E39EED008CB1F9 /* Assets.xcassets */; };
|
||||||
|
D08252762B5C9FC4005DA378 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08252752B5C9FC4005DA378 /* Constants.swift */; };
|
||||||
D0BCC5FD2A086D4700AD070D /* NetworkExtension+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */; };
|
D0BCC5FD2A086D4700AD070D /* NetworkExtension+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FC2A086D4700AD070D /* NetworkExtension+Async.swift */; };
|
||||||
D0BCC5FF2A086E1C00AD070D /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FE2A086E1C00AD070D /* Status.swift */; };
|
D0BCC5FF2A086E1C00AD070D /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FE2A086E1C00AD070D /* Status.swift */; };
|
||||||
D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B98FC629FDC5B5004E7149 /* Tunnel.swift */; };
|
D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B98FC629FDC5B5004E7149 /* Tunnel.swift */; };
|
||||||
|
|
@ -24,6 +30,20 @@
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
D00117462B30373100D87C25 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = D00117372B30341C00D87C25;
|
||||||
|
remoteInfo = Shared;
|
||||||
|
};
|
||||||
|
D00117482B30373500D87C25 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = D00117372B30341C00D87C25;
|
||||||
|
remoteInfo = Shared;
|
||||||
|
};
|
||||||
D020F65B29E4A697002790F6 /* PBXContainerItemProxy */ = {
|
D020F65B29E4A697002790F6 /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */;
|
containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */;
|
||||||
|
|
@ -49,8 +69,14 @@
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
0B28F1552ABF463A000D44B0 /* DataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTypes.swift; sourceTree = "<group>"; };
|
0B28F1552ABF463A000D44B0 /* DataTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataTypes.swift; sourceTree = "<group>"; };
|
||||||
0B46E8DF2AC918CA00BA2A3C /* BurrowIpc.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowIpc.swift; sourceTree = "<group>"; };
|
0B46E8DF2AC918CA00BA2A3C /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
|
||||||
43AA26D72A10004900F14CE6 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = "<group>"; };
|
43AA26D72A10004900F14CE6 /* MenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuView.swift; sourceTree = "<group>"; };
|
||||||
|
D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NWConnection+Async.swift"; sourceTree = "<group>"; };
|
||||||
|
D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewlineProtocolFramer.swift; sourceTree = "<group>"; };
|
||||||
|
D00117382B30341C00D87C25 /* libBurrowShared.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBurrowShared.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D001173A2B30341C00D87C25 /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
|
||||||
|
D00117412B30347800D87C25 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||||
|
D00117422B30348D00D87C25 /* Shared.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
||||||
D00AA8962A4669BC005C8102 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
D00AA8962A4669BC005C8102 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = "<group>"; };
|
D020F63D29E4A1FF002790F6 /* Identity.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Identity.xcconfig; sourceTree = "<group>"; };
|
||||||
D020F64029E4A1FF002790F6 /* Compiler.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Compiler.xcconfig; sourceTree = "<group>"; };
|
D020F64029E4A1FF002790F6 /* Compiler.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Compiler.xcconfig; sourceTree = "<group>"; };
|
||||||
|
|
@ -70,6 +96,8 @@
|
||||||
D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowApp.swift; sourceTree = "<group>"; };
|
D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurrowApp.swift; sourceTree = "<group>"; };
|
||||||
D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelView.swift; sourceTree = "<group>"; };
|
D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelView.swift; sourceTree = "<group>"; };
|
||||||
D05B9F7929E39EED008CB1F9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
D05B9F7929E39EED008CB1F9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
D08252742B5C9DEB005DA378 /* Constants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = "<group>"; };
|
||||||
|
D08252752B5C9FC4005DA378 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||||
D0B98FBF29FD8072004E7149 /* build-rust.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-rust.sh"; sourceTree = "<group>"; };
|
D0B98FBF29FD8072004E7149 /* build-rust.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "build-rust.sh"; sourceTree = "<group>"; };
|
||||||
D0B98FC629FDC5B5004E7149 /* Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = "<group>"; };
|
D0B98FC629FDC5B5004E7149 /* Tunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = "<group>"; };
|
||||||
D0B98FD829FDDB6F004E7149 /* libburrow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libburrow.h; sourceTree = "<group>"; };
|
D0B98FD829FDDB6F004E7149 /* libburrow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libburrow.h; sourceTree = "<group>"; };
|
||||||
|
|
@ -80,10 +108,18 @@
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
D00117352B30341C00D87C25 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
D020F65029E4A697002790F6 /* Frameworks */ = {
|
D020F65029E4A697002790F6 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D00117442B30372900D87C25 /* libBurrowShared.a in Frameworks */,
|
||||||
D0BCC6092A09A03E00AD070D /* libburrow.a in Frameworks */,
|
D0BCC6092A09A03E00AD070D /* libburrow.a in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
@ -92,6 +128,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D00117452B30372C00D87C25 /* libBurrowShared.a in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -106,6 +143,33 @@
|
||||||
path = Menu;
|
path = Menu;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D00117392B30341C00D87C25 /* Shared */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D001173A2B30341C00D87C25 /* Logging.swift */,
|
||||||
|
D08252752B5C9FC4005DA378 /* Constants.swift */,
|
||||||
|
D00117422B30348D00D87C25 /* Shared.xcconfig */,
|
||||||
|
D001173F2B30347800D87C25 /* Constants */,
|
||||||
|
);
|
||||||
|
path = Shared;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D001173F2B30347800D87C25 /* Constants */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D08252742B5C9DEB005DA378 /* Constants.h */,
|
||||||
|
D00117412B30347800D87C25 /* module.modulemap */,
|
||||||
|
);
|
||||||
|
path = Constants;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D00117432B30372900D87C25 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D020F63C29E4A1FF002790F6 /* Configuration */ = {
|
D020F63C29E4A1FF002790F6 /* Configuration */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
|
@ -122,12 +186,14 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */,
|
D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */,
|
||||||
|
0B46E8DF2AC918CA00BA2A3C /* Client.swift */,
|
||||||
|
0B28F1552ABF463A000D44B0 /* DataTypes.swift */,
|
||||||
|
D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */,
|
||||||
|
D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */,
|
||||||
D020F65929E4A697002790F6 /* Info.plist */,
|
D020F65929E4A697002790F6 /* Info.plist */,
|
||||||
D020F66729E4A95D002790F6 /* NetworkExtension-iOS.entitlements */,
|
D020F66729E4A95D002790F6 /* NetworkExtension-iOS.entitlements */,
|
||||||
D020F66629E4A95D002790F6 /* NetworkExtension-macOS.entitlements */,
|
D020F66629E4A95D002790F6 /* NetworkExtension-macOS.entitlements */,
|
||||||
D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */,
|
D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */,
|
||||||
0B28F1552ABF463A000D44B0 /* DataTypes.swift */,
|
|
||||||
0B46E8DF2AC918CA00BA2A3C /* BurrowIpc.swift */,
|
|
||||||
D0B98FD729FDDB57004E7149 /* libburrow */,
|
D0B98FD729FDDB57004E7149 /* libburrow */,
|
||||||
);
|
);
|
||||||
path = NetworkExtension;
|
path = NetworkExtension;
|
||||||
|
|
@ -138,8 +204,10 @@
|
||||||
children = (
|
children = (
|
||||||
D05B9F7429E39EEC008CB1F9 /* App */,
|
D05B9F7429E39EEC008CB1F9 /* App */,
|
||||||
D020F65629E4A697002790F6 /* NetworkExtension */,
|
D020F65629E4A697002790F6 /* NetworkExtension */,
|
||||||
|
D00117392B30341C00D87C25 /* Shared */,
|
||||||
D020F63C29E4A1FF002790F6 /* Configuration */,
|
D020F63C29E4A1FF002790F6 /* Configuration */,
|
||||||
D05B9F7329E39EEC008CB1F9 /* Products */,
|
D05B9F7329E39EEC008CB1F9 /* Products */,
|
||||||
|
D00117432B30372900D87C25 /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
|
@ -148,6 +216,7 @@
|
||||||
children = (
|
children = (
|
||||||
D05B9F7229E39EEC008CB1F9 /* Burrow.app */,
|
D05B9F7229E39EEC008CB1F9 /* Burrow.app */,
|
||||||
D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */,
|
D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */,
|
||||||
|
D00117382B30341C00D87C25 /* libBurrowShared.a */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -184,6 +253,23 @@
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
D00117372B30341C00D87C25 /* Shared */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = D001173C2B30341C00D87C25 /* Build configuration list for PBXNativeTarget "Shared" */;
|
||||||
|
buildPhases = (
|
||||||
|
D00117342B30341C00D87C25 /* Sources */,
|
||||||
|
D00117352B30341C00D87C25 /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
D082527D2B5DEB80005DA378 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = Shared;
|
||||||
|
productName = Shared;
|
||||||
|
productReference = D00117382B30341C00D87C25 /* libBurrowShared.a */;
|
||||||
|
productType = "com.apple.product-type.library.static";
|
||||||
|
};
|
||||||
D020F65229E4A697002790F6 /* NetworkExtension */ = {
|
D020F65229E4A697002790F6 /* NetworkExtension */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = D020F65E29E4A697002790F6 /* Build configuration list for PBXNativeTarget "NetworkExtension" */;
|
buildConfigurationList = D020F65E29E4A697002790F6 /* Build configuration list for PBXNativeTarget "NetworkExtension" */;
|
||||||
|
|
@ -196,7 +282,8 @@
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
D08252712B5C3E2E005DA378 /* PBXTargetDependency */,
|
D08252792B5DEB78005DA378 /* PBXTargetDependency */,
|
||||||
|
D00117492B30373500D87C25 /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = NetworkExtension;
|
name = NetworkExtension;
|
||||||
productName = BurrowNetworkExtension;
|
productName = BurrowNetworkExtension;
|
||||||
|
|
@ -215,7 +302,8 @@
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
D08252732B5C3E33005DA378 /* PBXTargetDependency */,
|
D082527B2B5DEB7D005DA378 /* PBXTargetDependency */,
|
||||||
|
D00117472B30373100D87C25 /* PBXTargetDependency */,
|
||||||
D020F65C29E4A697002790F6 /* PBXTargetDependency */,
|
D020F65C29E4A697002790F6 /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = App;
|
name = App;
|
||||||
|
|
@ -230,9 +318,12 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = 1;
|
BuildIndependentTargetsInParallel = 1;
|
||||||
LastSwiftUpdateCheck = 1430;
|
LastSwiftUpdateCheck = 1510;
|
||||||
LastUpgradeCheck = 1510;
|
LastUpgradeCheck = 1430;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
|
D00117372B30341C00D87C25 = {
|
||||||
|
CreatedOnToolsVersion = 15.1;
|
||||||
|
};
|
||||||
D020F65229E4A697002790F6 = {
|
D020F65229E4A697002790F6 = {
|
||||||
CreatedOnToolsVersion = 14.3;
|
CreatedOnToolsVersion = 14.3;
|
||||||
};
|
};
|
||||||
|
|
@ -251,7 +342,7 @@
|
||||||
);
|
);
|
||||||
mainGroup = D05B9F6929E39EEC008CB1F9;
|
mainGroup = D05B9F6929E39EEC008CB1F9;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
D082526F2B5C3E23005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */,
|
D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */,
|
||||||
);
|
);
|
||||||
productRefGroup = D05B9F7329E39EEC008CB1F9 /* Products */;
|
productRefGroup = D05B9F7329E39EEC008CB1F9 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
|
@ -259,6 +350,7 @@
|
||||||
targets = (
|
targets = (
|
||||||
D05B9F7129E39EEC008CB1F9 /* App */,
|
D05B9F7129E39EEC008CB1F9 /* App */,
|
||||||
D020F65229E4A697002790F6 /* NetworkExtension */,
|
D020F65229E4A697002790F6 /* NetworkExtension */,
|
||||||
|
D00117372B30341C00D87C25 /* Shared */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
|
|
@ -306,12 +398,23 @@
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
D00117342B30341C00D87C25 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
D001173B2B30341C00D87C25 /* Logging.swift in Sources */,
|
||||||
|
D08252762B5C9FC4005DA378 /* Constants.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
D020F64F29E4A697002790F6 /* Sources */ = {
|
D020F64F29E4A697002790F6 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D00117332B3001A400D87C25 /* NewlineProtocolFramer.swift in Sources */,
|
||||||
0B28F1562ABF463A000D44B0 /* DataTypes.swift in Sources */,
|
0B28F1562ABF463A000D44B0 /* DataTypes.swift in Sources */,
|
||||||
0B46E8E02AC918CA00BA2A3C /* BurrowIpc.swift in Sources */,
|
D00117312B2FFFC900D87C25 /* NWConnection+Async.swift in Sources */,
|
||||||
|
0B46E8E02AC918CA00BA2A3C /* Client.swift in Sources */,
|
||||||
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */,
|
D020F65829E4A697002790F6 /* PacketTunnelProvider.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
@ -333,22 +436,50 @@
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
/* Begin PBXTargetDependency section */
|
||||||
|
D00117472B30373100D87C25 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = D00117372B30341C00D87C25 /* Shared */;
|
||||||
|
targetProxy = D00117462B30373100D87C25 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
D00117492B30373500D87C25 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = D00117372B30341C00D87C25 /* Shared */;
|
||||||
|
targetProxy = D00117482B30373500D87C25 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
D020F65C29E4A697002790F6 /* PBXTargetDependency */ = {
|
D020F65C29E4A697002790F6 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = D020F65229E4A697002790F6 /* NetworkExtension */;
|
target = D020F65229E4A697002790F6 /* NetworkExtension */;
|
||||||
targetProxy = D020F65B29E4A697002790F6 /* PBXContainerItemProxy */;
|
targetProxy = D020F65B29E4A697002790F6 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
D08252712B5C3E2E005DA378 /* PBXTargetDependency */ = {
|
D08252792B5DEB78005DA378 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
productRef = D08252702B5C3E2E005DA378 /* SwiftLintPlugin */;
|
productRef = D08252782B5DEB78005DA378 /* SwiftLintPlugin */;
|
||||||
};
|
};
|
||||||
D08252732B5C3E33005DA378 /* PBXTargetDependency */ = {
|
D082527B2B5DEB7D005DA378 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
productRef = D08252722B5C3E33005DA378 /* SwiftLintPlugin */;
|
productRef = D082527A2B5DEB7D005DA378 /* SwiftLintPlugin */;
|
||||||
|
};
|
||||||
|
D082527D2B5DEB80005DA378 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
productRef = D082527C2B5DEB80005DA378 /* SwiftLintPlugin */;
|
||||||
};
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
|
D001173D2B30341C00D87C25 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = D00117422B30348D00D87C25 /* Shared.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
D001173E2B30341C00D87C25 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = D00117422B30348D00D87C25 /* Shared.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
D020F65F29E4A697002790F6 /* Debug */ = {
|
D020F65F29E4A697002790F6 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */;
|
baseConfigurationReference = D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */;
|
||||||
|
|
@ -394,6 +525,15 @@
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
|
D001173C2B30341C00D87C25 /* Build configuration list for PBXNativeTarget "Shared" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
D001173D2B30341C00D87C25 /* Debug */,
|
||||||
|
D001173E2B30341C00D87C25 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
D020F65E29E4A697002790F6 /* Build configuration list for PBXNativeTarget "NetworkExtension" */ = {
|
D020F65E29E4A697002790F6 /* Build configuration list for PBXNativeTarget "NetworkExtension" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|
@ -424,7 +564,7 @@
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCRemoteSwiftPackageReference section */
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
D082526F2B5C3E23005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */ = {
|
D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/realm/SwiftLint.git";
|
repositoryURL = "https://github.com/realm/SwiftLint.git";
|
||||||
requirement = {
|
requirement = {
|
||||||
|
|
@ -435,14 +575,19 @@
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
D08252702B5C3E2E005DA378 /* SwiftLintPlugin */ = {
|
D08252782B5DEB78005DA378 /* SwiftLintPlugin */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = D082526F2B5C3E23005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
package = D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
||||||
productName = "plugin:SwiftLintPlugin";
|
productName = "plugin:SwiftLintPlugin";
|
||||||
};
|
};
|
||||||
D08252722B5C3E33005DA378 /* SwiftLintPlugin */ = {
|
D082527A2B5DEB7D005DA378 /* SwiftLintPlugin */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = D082526F2B5C3E23005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
package = D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
||||||
|
productName = "plugin:SwiftLintPlugin";
|
||||||
|
};
|
||||||
|
D082527C2B5DEB80005DA378 /* SwiftLintPlugin */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
||||||
productName = "plugin:SwiftLintPlugin";
|
productName = "plugin:SwiftLintPlugin";
|
||||||
};
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
SKIP_INSTALL = NO
|
SKIP_INSTALL = NO
|
||||||
|
MERGED_BINARY_TYPE = manual
|
||||||
|
|
||||||
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks
|
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(inherited) @executable_path/Frameworks
|
||||||
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks
|
LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) @executable_path/../Frameworks
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ CODE_SIGN_IDENTITY = Apple Development
|
||||||
|
|
||||||
INFOPLIST_FILE = Configuration/Info.plist
|
INFOPLIST_FILE = Configuration/Info.plist
|
||||||
GENERATE_INFOPLIST_FILE = YES
|
GENERATE_INFOPLIST_FILE = YES
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 Hack Club
|
INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023-2024 Hack Club
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Burrow
|
INFOPLIST_KEY_CFBundleDisplayName = Burrow
|
||||||
|
|
||||||
ENABLE_BITCODE = NO
|
ENABLE_BITCODE = NO
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,4 @@
|
||||||
|
MERGED_BINARY_TYPE = manual
|
||||||
|
|
||||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @executable_path/../../Frameworks
|
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @executable_path/../../Frameworks
|
||||||
LD_RUNPATH_SEARCH_PATHS[sdk=macos*] = $(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks
|
LD_RUNPATH_SEARCH_PATHS[sdk=macos*] = $(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks
|
||||||
|
|
|
||||||
|
|
@ -1,133 +0,0 @@
|
||||||
import Foundation
|
|
||||||
import Network
|
|
||||||
import os
|
|
||||||
|
|
||||||
final class LineProtocol: NWProtocolFramerImplementation {
|
|
||||||
static let definition = NWProtocolFramer.Definition(implementation: LineProtocol.self)
|
|
||||||
static let label = "Lines"
|
|
||||||
init(framer: NWProtocolFramer.Instance) { }
|
|
||||||
func start(framer: NWProtocolFramer.Instance) -> NWProtocolFramer.StartResult { .ready }
|
|
||||||
func stop(framer: NWProtocolFramer.Instance) -> Bool { true }
|
|
||||||
func wakeup(framer: NWProtocolFramer.Instance) { }
|
|
||||||
func cleanup(framer: NWProtocolFramer.Instance) { }
|
|
||||||
func lines(from buffer: UnsafeMutableRawBufferPointer?) -> (lines: [Data], size: Int)? {
|
|
||||||
guard let buffer = buffer else { return nil }
|
|
||||||
let lines = buffer
|
|
||||||
.split(separator: 10)
|
|
||||||
guard !lines.isEmpty else { return nil }
|
|
||||||
let size = lines
|
|
||||||
.lazy
|
|
||||||
.map(\.count)
|
|
||||||
.reduce(0, +) + lines.count
|
|
||||||
let strings = lines
|
|
||||||
.lazy
|
|
||||||
.map { Data($0) }
|
|
||||||
return (lines: Array(strings), size: size)
|
|
||||||
}
|
|
||||||
func handleInput(framer: NWProtocolFramer.Instance) -> Int {
|
|
||||||
var result: [Data] = []
|
|
||||||
_ = framer.parseInput(minimumIncompleteLength: 1, maximumLength: 16_000) { buffer, _ in
|
|
||||||
guard let (lines, size) = lines(from: buffer) else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
result = lines
|
|
||||||
return size
|
|
||||||
}
|
|
||||||
for line in result {
|
|
||||||
framer.deliverInput(data: line, message: .init(instance: framer), isComplete: true)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
func handleOutput(
|
|
||||||
framer: NWProtocolFramer.Instance,
|
|
||||||
message: NWProtocolFramer.Message,
|
|
||||||
messageLength: Int,
|
|
||||||
isComplete: Bool
|
|
||||||
) {
|
|
||||||
do {
|
|
||||||
try framer.writeOutputNoCopy(length: messageLength)
|
|
||||||
} catch {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NWConnection {
|
|
||||||
func receiveMessage() async throws -> (Data?, NWConnection.ContentContext?, Bool) {
|
|
||||||
try await withUnsafeThrowingContinuation { continuation in
|
|
||||||
receiveMessage { completeContent, contentContext, isComplete, error in
|
|
||||||
if let error = error {
|
|
||||||
continuation.resume(throwing: error)
|
|
||||||
}
|
|
||||||
continuation.resume(returning: (completeContent, contentContext, isComplete))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func send_raw(_ request: Data) async throws -> Data {
|
|
||||||
try await withCheckedThrowingContinuation { continuation in
|
|
||||||
let comp: NWConnection.SendCompletion = .contentProcessed {error in
|
|
||||||
if let error = error {
|
|
||||||
continuation.resume(with: .failure(error))
|
|
||||||
} else {
|
|
||||||
continuation.resume(with: .success(request))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.send(content: request, completion: comp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final class BurrowIpc {
|
|
||||||
let connection: NWConnection
|
|
||||||
private var generator = SystemRandomNumberGenerator()
|
|
||||||
private var logger: Logger
|
|
||||||
init(logger: Logger) {
|
|
||||||
let params = NWParameters.tcp
|
|
||||||
params.defaultProtocolStack
|
|
||||||
.applicationProtocols
|
|
||||||
.insert(NWProtocolFramer.Options(definition: LineProtocol.definition), at: 0)
|
|
||||||
let connection = NWConnection(to: .unix(path: "burrow.sock"), using: params)
|
|
||||||
connection.start(queue: .global())
|
|
||||||
self.connection = connection
|
|
||||||
self.logger = logger
|
|
||||||
}
|
|
||||||
func send<T: Request, U: Decodable>(_ request: T) async throws -> U {
|
|
||||||
do {
|
|
||||||
let id: UInt = generator.next(upperBound: UInt.max)
|
|
||||||
var copy = request
|
|
||||||
copy.id = id
|
|
||||||
var data = try JSONEncoder().encode(request)
|
|
||||||
data.append(contentsOf: [10])
|
|
||||||
_ = try await self.connection.send_raw(data)
|
|
||||||
return try JSONDecoder().decode(Response<U>.self, from: data).result
|
|
||||||
} catch {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func receive_raw() async throws -> Data {
|
|
||||||
let (completeContent, _, _) = try await connection.receiveMessage()
|
|
||||||
self.logger.info("Received raw message response")
|
|
||||||
guard let data = completeContent else {
|
|
||||||
throw BurrowError.resultIsNone
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
func request<U: Decodable>(_ request: any Request, type: U.Type) async throws -> U {
|
|
||||||
do {
|
|
||||||
var data: Data = try JSONEncoder().encode(request)
|
|
||||||
data.append(contentsOf: [10])
|
|
||||||
_ = try await self.connection.send_raw(data)
|
|
||||||
self.logger.debug("message sent")
|
|
||||||
let receivedData = try await receive_raw()
|
|
||||||
self.logger.info("Received result: \(String(decoding: receivedData, as: UTF8.self))")
|
|
||||||
return try self.parse_response(receivedData)
|
|
||||||
} catch {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse_response<U: Decodable>(_ response: Data) throws -> U {
|
|
||||||
try JSONDecoder().decode(U.self, from: response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
60
Apple/NetworkExtension/Client.swift
Normal file
60
Apple/NetworkExtension/Client.swift
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import BurrowShared
|
||||||
|
import Foundation
|
||||||
|
import Network
|
||||||
|
|
||||||
|
final class Client {
|
||||||
|
let connection: NWConnection
|
||||||
|
|
||||||
|
private let logger: Logger = Logger.logger(for: Client.self)
|
||||||
|
private var generator = SystemRandomNumberGenerator()
|
||||||
|
|
||||||
|
convenience init() throws {
|
||||||
|
self.init(url: try Constants.socketURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(url: URL) {
|
||||||
|
let endpoint: NWEndpoint
|
||||||
|
if url.isFileURL {
|
||||||
|
endpoint = .unix(path: url.path(percentEncoded: false))
|
||||||
|
} else {
|
||||||
|
endpoint = .url(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
let parameters = NWParameters.tcp
|
||||||
|
parameters.defaultProtocolStack
|
||||||
|
.applicationProtocols
|
||||||
|
.insert(NWProtocolFramer.Options(definition: NewlineProtocolFramer.definition), at: 0)
|
||||||
|
connection = NWConnection(to: endpoint, using: parameters)
|
||||||
|
connection.start(queue: .global())
|
||||||
|
}
|
||||||
|
|
||||||
|
func request<U: Decodable>(_ request: any Request, type: U.Type = U.self) async throws -> U {
|
||||||
|
do {
|
||||||
|
var copy = request
|
||||||
|
copy.id = generator.next(upperBound: UInt.max)
|
||||||
|
let content = try JSONEncoder().encode(copy)
|
||||||
|
logger.debug("> \(String(decoding: content, as: UTF8.self))")
|
||||||
|
|
||||||
|
try await self.connection.send(content: content)
|
||||||
|
let (response, _, _) = try await connection.receiveMessage()
|
||||||
|
|
||||||
|
logger.debug("< \(String(decoding: response, as: UTF8.self))")
|
||||||
|
return try JSONDecoder().decode(U.self, from: response)
|
||||||
|
} catch {
|
||||||
|
logger.error("\(error, privacy: .public)")
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
connection.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Constants {
|
||||||
|
static var socketURL: URL {
|
||||||
|
get throws {
|
||||||
|
try groupContainerURL.appending(component: "burrow.sock", directoryHint: .notDirectory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,10 +8,11 @@ enum BurrowError: Error {
|
||||||
case resultIsNone
|
case resultIsNone
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol Request: Codable where CommandT: Codable {
|
protocol Request: Codable where Command: Codable {
|
||||||
associatedtype CommandT
|
associatedtype Command
|
||||||
|
|
||||||
var id: UInt { get set }
|
var id: UInt { get set }
|
||||||
var command: CommandT { get set }
|
var command: Command { get set }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BurrowSingleCommand: Request {
|
struct BurrowSingleCommand: Request {
|
||||||
|
|
@ -38,13 +39,6 @@ struct BurrowStartRequest: Codable {
|
||||||
let Start: StartOptions
|
let Start: StartOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
func start_req_fd(id: UInt) -> BurrowRequest<BurrowStartRequest> {
|
|
||||||
let command = BurrowStartRequest(Start: BurrowStartRequest.StartOptions(
|
|
||||||
tun: BurrowStartRequest.TunOptions(name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: nil)
|
|
||||||
))
|
|
||||||
return BurrowRequest(id: id, command: command)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Response<T>: Decodable where T: Decodable {
|
struct Response<T>: Decodable where T: Decodable {
|
||||||
var id: UInt
|
var id: UInt
|
||||||
var result: T
|
var result: T
|
||||||
|
|
|
||||||
32
Apple/NetworkExtension/NWConnection+Async.swift
Normal file
32
Apple/NetworkExtension/NWConnection+Async.swift
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Foundation
|
||||||
|
import Network
|
||||||
|
|
||||||
|
extension NWConnection {
|
||||||
|
// swiftlint:disable:next large_tuple
|
||||||
|
func receiveMessage() async throws -> (Data, NWConnection.ContentContext?, Bool) {
|
||||||
|
try await withUnsafeThrowingContinuation { continuation in
|
||||||
|
receiveMessage { completeContent, contentContext, isComplete, error in
|
||||||
|
if let error {
|
||||||
|
continuation.resume(throwing: error)
|
||||||
|
} else {
|
||||||
|
guard let completeContent = completeContent else {
|
||||||
|
fatalError("Both error and completeContent were nil")
|
||||||
|
}
|
||||||
|
continuation.resume(returning: (completeContent, contentContext, isComplete))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func send(content: Data) async throws {
|
||||||
|
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
|
||||||
|
send(content: content, completion: .contentProcessed { error in
|
||||||
|
if let error {
|
||||||
|
continuation.resume(throwing: error)
|
||||||
|
} else {
|
||||||
|
continuation.resume(returning: ())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,17 +2,19 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.security.network.client</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.network.server</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.developer.networking.networkextension</key>
|
<key>com.apple.developer.networking.networkextension</key>
|
||||||
<array>
|
<array>
|
||||||
<string>packet-tunnel-provider</string>
|
<string>packet-tunnel-provider</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>com.apple.security.app-sandbox</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.security.application-groups</key>
|
<key>com.apple.security.application-groups</key>
|
||||||
<array>
|
<array>
|
||||||
<string>$(APP_GROUP_IDENTIFIER)</string>
|
<string>$(APP_GROUP_IDENTIFIER)</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.server</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,6 @@ PRODUCT_BUNDLE_IDENTIFIER = $(NETWORK_EXTENSION_BUNDLE_IDENTIFIER)
|
||||||
INFOPLIST_FILE = NetworkExtension/Info.plist
|
INFOPLIST_FILE = NetworkExtension/Info.plist
|
||||||
|
|
||||||
CODE_SIGN_ENTITLEMENTS = NetworkExtension/NetworkExtension-iOS.entitlements
|
CODE_SIGN_ENTITLEMENTS = NetworkExtension/NetworkExtension-iOS.entitlements
|
||||||
CODE_SIGN_ENTITLEMENTS[sdk=macos*] = NetworkExtension/NetworkExtension-macOS.entitlements
|
CODE_SIGN_ENTITLEMENTS[sdk=macosx*] = NetworkExtension/NetworkExtension-macOS.entitlements
|
||||||
|
|
||||||
SWIFT_INCLUDE_PATHS = $(inherited) $(PROJECT_DIR)/NetworkExtension
|
SWIFT_INCLUDE_PATHS = $(inherited) $(PROJECT_DIR)/NetworkExtension
|
||||||
|
|
|
||||||
54
Apple/NetworkExtension/NewlineProtocolFramer.swift
Normal file
54
Apple/NetworkExtension/NewlineProtocolFramer.swift
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import Foundation
|
||||||
|
import Network
|
||||||
|
|
||||||
|
final class NewlineProtocolFramer: NWProtocolFramerImplementation {
|
||||||
|
private static let delimeter: UInt8 = 10 // `\n`
|
||||||
|
|
||||||
|
static let definition = NWProtocolFramer.Definition(implementation: NewlineProtocolFramer.self)
|
||||||
|
static let label = "Lines"
|
||||||
|
|
||||||
|
init(framer: NWProtocolFramer.Instance) { }
|
||||||
|
|
||||||
|
func start(framer: NWProtocolFramer.Instance) -> NWProtocolFramer.StartResult { .ready }
|
||||||
|
func stop(framer: NWProtocolFramer.Instance) -> Bool { true }
|
||||||
|
|
||||||
|
func wakeup(framer: NWProtocolFramer.Instance) { }
|
||||||
|
func cleanup(framer: NWProtocolFramer.Instance) { }
|
||||||
|
|
||||||
|
func handleInput(framer: NWProtocolFramer.Instance) -> Int {
|
||||||
|
while true {
|
||||||
|
var result: [Data] = []
|
||||||
|
let parsed = framer.parseInput(minimumIncompleteLength: 1, maximumLength: 16_000) { buffer, _ in
|
||||||
|
guard let buffer else { return 0 }
|
||||||
|
var lines = buffer
|
||||||
|
.split(separator: Self.delimeter, omittingEmptySubsequences: false)
|
||||||
|
.map { Data($0) }
|
||||||
|
guard lines.count > 1 else { return 0 }
|
||||||
|
_ = lines.popLast()
|
||||||
|
|
||||||
|
result = lines
|
||||||
|
return lines.reduce(lines.count) { $0 + $1.count }
|
||||||
|
}
|
||||||
|
|
||||||
|
guard parsed && !result.isEmpty else { break }
|
||||||
|
|
||||||
|
for line in result {
|
||||||
|
framer.deliverInput(data: line, message: .init(instance: framer), isComplete: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleOutput(
|
||||||
|
framer: NWProtocolFramer.Instance,
|
||||||
|
message: NWProtocolFramer.Message,
|
||||||
|
messageLength: Int,
|
||||||
|
isComplete: Bool
|
||||||
|
) {
|
||||||
|
do {
|
||||||
|
try framer.writeOutputNoCopy(length: messageLength)
|
||||||
|
framer.writeOutput(data: [Self.delimeter])
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,69 +1,63 @@
|
||||||
|
import BurrowShared
|
||||||
import libburrow
|
import libburrow
|
||||||
import NetworkExtension
|
import NetworkExtension
|
||||||
import os
|
import os
|
||||||
|
|
||||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||||
let logger = Logger(subsystem: "com.hackclub.burrow", category: "frontend")
|
private let logger = Logger.logger(for: PacketTunnelProvider.self)
|
||||||
var client: BurrowIpc?
|
|
||||||
var osInitialized = false
|
|
||||||
override func startTunnel(options: [String: NSObject]? = nil) async throws {
|
override func startTunnel(options: [String: NSObject]? = nil) async throws {
|
||||||
logger.log("Starting tunnel")
|
|
||||||
if !osInitialized {
|
|
||||||
libburrow.initialize_oslog()
|
|
||||||
osInitialized = true
|
|
||||||
}
|
|
||||||
libburrow.start_srv()
|
|
||||||
client = BurrowIpc(logger: logger)
|
|
||||||
logger.info("Started server")
|
|
||||||
do {
|
do {
|
||||||
let command = BurrowSingleCommand(id: 0, command: "ServerConfig")
|
libburrow.spawnInProcess(socketPath: try Constants.socketURL.path)
|
||||||
guard let data = try await client?.request(command, type: Response<BurrowResult<ServerConfigData>>.self)
|
|
||||||
else {
|
let client = try Client()
|
||||||
throw BurrowError.cantParseResult
|
|
||||||
}
|
let command = BurrowRequest(id: 0, command: "ServerConfig")
|
||||||
|
let data = try await client.request(command, type: Response<BurrowResult<ServerConfigData>>.self)
|
||||||
|
|
||||||
let encoded = try JSONEncoder().encode(data.result)
|
let encoded = try JSONEncoder().encode(data.result)
|
||||||
self.logger.log("Received final data: \(String(decoding: encoded, as: UTF8.self))")
|
self.logger.log("Received final data: \(String(decoding: encoded, as: UTF8.self))")
|
||||||
guard let serverconfig = data.result.Ok else {
|
guard let serverconfig = data.result.Ok else {
|
||||||
throw BurrowError.resultIsError
|
throw BurrowError.resultIsError
|
||||||
}
|
}
|
||||||
guard let tunNs = self.generateTunSettings(from: serverconfig) else {
|
guard let tunNs = generateTunSettings(from: serverconfig) else {
|
||||||
throw BurrowError.addrDoesntExist
|
throw BurrowError.addrDoesntExist
|
||||||
}
|
}
|
||||||
try await self.setTunnelNetworkSettings(tunNs)
|
try await self.setTunnelNetworkSettings(tunNs)
|
||||||
self.logger.info("Set remote tunnel address to \(tunNs.tunnelRemoteAddress)")
|
self.logger.info("Set remote tunnel address to \(tunNs.tunnelRemoteAddress)")
|
||||||
|
|
||||||
// let tunFd = self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int;
|
let startRequest = BurrowRequest(
|
||||||
// self.logger.info("Found File Descriptor: \(tunFd)")
|
id: .random(in: (.min)..<(.max)),
|
||||||
let startCommand = start_req_fd(id: 1)
|
command: BurrowStartRequest(
|
||||||
guard let data = try await client?.request(startCommand, type: Response<BurrowResult<String>>.self)
|
Start: BurrowStartRequest.StartOptions(
|
||||||
else {
|
tun: BurrowStartRequest.TunOptions(
|
||||||
throw BurrowError.cantParseResult
|
name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: nil
|
||||||
}
|
)
|
||||||
let encodedStartRes = try JSONEncoder().encode(data.result)
|
)
|
||||||
self.logger.log("Received start server response: \(String(decoding: encodedStartRes, as: UTF8.self))")
|
)
|
||||||
|
)
|
||||||
|
let response = try await client.request(startRequest, type: Response<BurrowResult<String>>.self)
|
||||||
|
self.logger.log("Received start server response: \(String(describing: response.result))")
|
||||||
} catch {
|
} catch {
|
||||||
self.logger.error("An error occurred: \(error)")
|
self.logger.error("Failed to start tunnel: \(error)")
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? {
|
private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? {
|
||||||
let cfig = from.ServerConfig
|
let cfig = from.ServerConfig
|
||||||
guard let addr = cfig.address else {
|
guard let addr = cfig.address else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let settings = NEIPv4Settings(addresses: [addr], subnetMasks: ["255.255.255.0"])
|
||||||
|
settings.includedRoutes = [.default()]
|
||||||
|
|
||||||
// Using a makeshift remote tunnel address
|
// Using a makeshift remote tunnel address
|
||||||
let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
|
let nst = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "1.1.1.1")
|
||||||
nst.ipv4Settings = NEIPv4Settings(addresses: [addr], subnetMasks: ["255.255.255.0"])
|
nst.ipv4Settings = settings
|
||||||
|
nst.dnsSettings = .init(servers: ["1.1.1.1"])
|
||||||
logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)")
|
logger.log("Initialized ipv4 settings: \(nst.ipv4Settings)")
|
||||||
return nst
|
return nst
|
||||||
}
|
}
|
||||||
override func stopTunnel(with reason: NEProviderStopReason) async {
|
|
||||||
}
|
|
||||||
override func handleAppMessage(_ messageData: Data) async -> Data? {
|
|
||||||
messageData
|
|
||||||
}
|
|
||||||
override func sleep() async {
|
|
||||||
}
|
|
||||||
override func wake() {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
void start_srv();
|
__attribute__((__swift_name__("spawnInProcess(socketPath:)")))
|
||||||
void initialize_oslog();
|
extern void spawn_in_process(const char * __nullable path);
|
||||||
|
|
|
||||||
22
Apple/Shared/Constants.swift
Normal file
22
Apple/Shared/Constants.swift
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
@_implementationOnly import Constants
|
||||||
|
|
||||||
|
public enum Constants {
|
||||||
|
enum Error: Swift.Error {
|
||||||
|
case invalidAppGroupIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
public static let bundleIdentifier = AppBundleIdentifier
|
||||||
|
public static let appGroupIdentifier = AppGroupIdentifier
|
||||||
|
|
||||||
|
public static var groupContainerURL: URL {
|
||||||
|
get throws { try _groupContainerURL.get() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static let _groupContainerURL: Result<URL, Error> = {
|
||||||
|
guard let groupContainerURL = FileManager.default
|
||||||
|
.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier) else {
|
||||||
|
return .failure(.invalidAppGroupIdentifier)
|
||||||
|
}
|
||||||
|
return .success(groupContainerURL)
|
||||||
|
}()
|
||||||
|
}
|
||||||
11
Apple/Shared/Constants/Constants.h
Normal file
11
Apple/Shared/Constants/Constants.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#define MACRO_STRING_(m) #m
|
||||||
|
#define MACRO_STRING(m) @MACRO_STRING_(m)
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
static NSString * const AppBundleIdentifier = MACRO_STRING(APP_BUNDLE_IDENTIFIER);
|
||||||
|
static NSString * const AppGroupIdentifier = MACRO_STRING(APP_GROUP_IDENTIFIER);
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
4
Apple/Shared/Constants/module.modulemap
Normal file
4
Apple/Shared/Constants/module.modulemap
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
module Constants {
|
||||||
|
header "Constants.h"
|
||||||
|
export *
|
||||||
|
}
|
||||||
19
Apple/Shared/Logging.swift
Normal file
19
Apple/Shared/Logging.swift
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import os
|
||||||
|
@_exported import OSLog
|
||||||
|
|
||||||
|
extension Logger {
|
||||||
|
private static let loggers: OSAllocatedUnfairLock<[String: Logger]> = OSAllocatedUnfairLock(initialState: [:])
|
||||||
|
|
||||||
|
public static let subsystem = Constants.bundleIdentifier
|
||||||
|
|
||||||
|
public static func logger(for type: Any.Type) -> Logger {
|
||||||
|
let category = String(describing: type)
|
||||||
|
let logger = loggers.withLock { loggers in
|
||||||
|
if let logger = loggers[category] { return logger }
|
||||||
|
let logger = Logger(subsystem: subsystem, category: category)
|
||||||
|
loggers[category] = logger
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
}
|
||||||
5
Apple/Shared/Shared.xcconfig
Normal file
5
Apple/Shared/Shared.xcconfig
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
PRODUCT_NAME = BurrowShared
|
||||||
|
MERGEABLE_LIBRARY = YES
|
||||||
|
|
||||||
|
SWIFT_INCLUDE_PATHS = $(PROJECT_DIR)/Shared/Constants
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = APP_BUNDLE_IDENTIFIER=$(APP_BUNDLE_IDENTIFIER) APP_GROUP_IDENTIFIER=$(APP_GROUP_IDENTIFIER)
|
||||||
1040
Cargo.lock
generated
1040
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -12,46 +12,44 @@ crate-type = ["lib", "staticlib"]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
tokio = { version = "1.21", features = ["rt", "macros", "sync", "io-util", "rt-multi-thread", "time", "tracing"] }
|
tokio = { version = "1.21", features = ["rt", "macros", "sync", "io-util", "rt-multi-thread", "time", "tracing"] }
|
||||||
tun = { version = "0.1", path = "../tun", features = ["serde", "tokio"] }
|
tun = { version = "0.1", path = "../tun", features = ["serde", "tokio"] }
|
||||||
clap = { version = "4.3.2", features = ["derive"] }
|
clap = { version = "4.4", features = ["derive"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-log = "0.1"
|
tracing-log = "0.1"
|
||||||
tracing-journald = "0.3"
|
tracing-oslog = { git = "https://github.com/Stormshield-robinc/tracing-oslog" }
|
||||||
tracing-oslog = {git = "https://github.com/Stormshield-robinc/tracing-oslog"}
|
tracing-subscriber = { version = "0.3" , features = ["std", "env-filter"] }
|
||||||
tracing-subscriber = { version = "0.3" , features = ["std", "env-filter"]}
|
|
||||||
env_logger = "0.10"
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1.0"
|
||||||
blake2 = "0.10.6"
|
blake2 = "0.10"
|
||||||
chacha20poly1305 = "0.10.1"
|
chacha20poly1305 = "0.10"
|
||||||
rand = "0.8.5"
|
rand = "0.8"
|
||||||
rand_core = "0.6.4"
|
rand_core = "0.6"
|
||||||
aead = "0.5.2"
|
aead = "0.5"
|
||||||
x25519-dalek = { version = "2.0.0", features = ["reusable_secrets", "static_secrets"] }
|
x25519-dalek = { version = "2.0", features = ["reusable_secrets", "static_secrets"] }
|
||||||
ring = "0.17.7"
|
ring = "0.17"
|
||||||
parking_lot = "0.12.1"
|
parking_lot = "0.12"
|
||||||
hmac = "0.12"
|
hmac = "0.12"
|
||||||
ipnet = { version = "2.8.0", features = ["serde"] }
|
base64 = "0.21"
|
||||||
base64 = "0.21.4"
|
fehler = "1.0"
|
||||||
fehler = "1.0.0"
|
ip_network_table = "0.2"
|
||||||
ip_network_table = "0.2.0"
|
ip_network = "0.4"
|
||||||
ip_network = "0.4.0"
|
async-channel = "2.1"
|
||||||
async-channel = "2.1.1"
|
|
||||||
schemars = "0.8"
|
schemars = "0.8"
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
uuid = { version = "1.6.1", features = ["v4"] }
|
once_cell = "1.19"
|
||||||
console-subscriber = { version = "0.2.0" , optional = true}
|
console-subscriber = { version = "0.2.0" , optional = true }
|
||||||
|
console = "0.15.8"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
caps = "0.5.5"
|
caps = "0.5"
|
||||||
libsystemd = "0.6"
|
libsystemd = "0.7"
|
||||||
|
tracing-journald = "0.3"
|
||||||
|
|
||||||
[target.'cfg(target_vendor = "apple")'.dependencies]
|
[target.'cfg(target_vendor = "apple")'.dependencies]
|
||||||
nix = { version = "0.26.2" }
|
nix = { version = "0.27" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
insta = { version = "1.32.0", features = ["yaml"] }
|
insta = { version = "1.32", features = ["yaml"] }
|
||||||
etherparse = "0.12"
|
|
||||||
|
|
||||||
[package.metadata.generate-rpm]
|
[package.metadata.generate-rpm]
|
||||||
assets = [
|
assets = [
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
use tracing::debug;
|
|
||||||
use tracing_oslog::OsLogger;
|
|
||||||
use tracing_subscriber::layer::SubscriberExt;
|
|
||||||
|
|
||||||
pub use crate::daemon::start_srv;
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn initialize_oslog() {
|
|
||||||
let collector =
|
|
||||||
tracing_subscriber::registry().with(OsLogger::new("com.hackclub.burrow", "backend"));
|
|
||||||
tracing::subscriber::set_global_default(collector).unwrap();
|
|
||||||
debug!("Initialized oslog tracing in libburrow rust FFI");
|
|
||||||
}
|
|
||||||
55
burrow/src/daemon/apple.rs
Normal file
55
burrow/src/daemon/apple.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
use std::{
|
||||||
|
ffi::{c_char, CStr},
|
||||||
|
path::PathBuf,
|
||||||
|
sync::Arc,
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use tokio::{
|
||||||
|
runtime::{Builder, Handle},
|
||||||
|
sync::Notify,
|
||||||
|
};
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use crate::daemon::daemon_main;
|
||||||
|
|
||||||
|
static BURROW_NOTIFY: OnceCell<Arc<Notify>> = OnceCell::new();
|
||||||
|
static BURROW_HANDLE: OnceCell<Handle> = OnceCell::new();
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn spawn_in_process(path: *const c_char) {
|
||||||
|
crate::tracing::initialize();
|
||||||
|
|
||||||
|
let notify = BURROW_NOTIFY.get_or_init(|| Arc::new(Notify::new()));
|
||||||
|
let handle = BURROW_HANDLE.get_or_init(|| {
|
||||||
|
let path_buf = if path.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(PathBuf::from(CStr::from_ptr(path).to_str().unwrap()))
|
||||||
|
};
|
||||||
|
let sender = notify.clone();
|
||||||
|
|
||||||
|
let (handle_tx, handle_rx) = tokio::sync::oneshot::channel();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let runtime = Builder::new_multi_thread()
|
||||||
|
.worker_threads(4)
|
||||||
|
.enable_all()
|
||||||
|
.thread_name("burrow-worker")
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
handle_tx.send(runtime.handle().clone()).unwrap();
|
||||||
|
runtime.block_on(async {
|
||||||
|
let result = daemon_main(path_buf.as_deref(), Some(sender.clone())).await;
|
||||||
|
if let Err(error) = result.as_ref() {
|
||||||
|
error!("Burrow thread exited: {}", error);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
})
|
||||||
|
});
|
||||||
|
handle_rx.blocking_recv().unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let receiver = notify.clone();
|
||||||
|
handle.block_on(async move { receiver.notified().await });
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
|
pub mod apple;
|
||||||
mod command;
|
mod command;
|
||||||
mod instance;
|
mod instance;
|
||||||
mod net;
|
mod net;
|
||||||
|
|
@ -8,44 +9,52 @@ mod response;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
pub use command::{DaemonCommand, DaemonStartOptions};
|
pub use command::{DaemonCommand, DaemonStartOptions};
|
||||||
use instance::DaemonInstance;
|
use instance::DaemonInstance;
|
||||||
#[cfg(target_vendor = "apple")]
|
pub use net::{DaemonClient, Listener};
|
||||||
pub use net::start_srv;
|
|
||||||
pub use net::DaemonClient;
|
|
||||||
pub use response::{DaemonResponse, DaemonResponseData, ServerInfo};
|
pub use response::{DaemonResponse, DaemonResponseData, ServerInfo};
|
||||||
use tokio::sync::{Notify, RwLock};
|
use tokio::sync::{Notify, RwLock};
|
||||||
|
use tracing::{error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::wireguard::{Config, Interface};
|
||||||
daemon::net::listen,
|
|
||||||
wireguard::{Config, Interface},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub async fn daemon_main(notify_ready: Option<Arc<Notify>>) -> Result<()> {
|
pub async fn daemon_main(path: Option<&Path>, notify_ready: Option<Arc<Notify>>) -> Result<()> {
|
||||||
let (commands_tx, commands_rx) = async_channel::unbounded();
|
let (commands_tx, commands_rx) = async_channel::unbounded();
|
||||||
let (response_tx, response_rx) = async_channel::unbounded();
|
let (response_tx, response_rx) = async_channel::unbounded();
|
||||||
|
|
||||||
|
let listener = if let Some(path) = path {
|
||||||
|
info!("Creating listener... {:?}", path);
|
||||||
|
Listener::new_with_path(commands_tx, response_rx, path)
|
||||||
|
} else {
|
||||||
|
info!("Creating listener...");
|
||||||
|
Listener::new(commands_tx, response_rx)
|
||||||
|
};
|
||||||
|
if let Some(n) = notify_ready {
|
||||||
|
n.notify_one()
|
||||||
|
}
|
||||||
|
let listener = listener?;
|
||||||
|
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let iface: Interface = config.try_into()?;
|
let iface: Interface = config.try_into()?;
|
||||||
|
let mut instance = DaemonInstance::new(commands_rx, response_tx, Arc::new(RwLock::new(iface)));
|
||||||
|
|
||||||
let mut inst: DaemonInstance =
|
info!("Starting daemon...");
|
||||||
DaemonInstance::new(commands_rx, response_tx, Arc::new(RwLock::new(iface)));
|
|
||||||
|
|
||||||
tracing::info!("Starting daemon jobs...");
|
let main_job = tokio::spawn(async move {
|
||||||
|
let result = instance.run().await;
|
||||||
let inst_job = tokio::spawn(async move {
|
if let Err(e) = result.as_ref() {
|
||||||
let res = inst.run().await;
|
error!("Instance exited: {}", e);
|
||||||
if let Err(e) = res {
|
|
||||||
tracing::error!("Error when running instance: {}", e);
|
|
||||||
}
|
}
|
||||||
|
result
|
||||||
});
|
});
|
||||||
|
|
||||||
let listen_job = tokio::spawn(async move {
|
let listener_job = tokio::spawn(async move {
|
||||||
let res = listen(commands_tx, response_rx, notify_ready).await;
|
let result = listener.run().await;
|
||||||
if let Err(e) = res {
|
if let Err(e) = result.as_ref() {
|
||||||
tracing::error!("Error when listening: {}", e);
|
error!("Listener exited: {}", e);
|
||||||
}
|
}
|
||||||
|
result
|
||||||
});
|
});
|
||||||
|
|
||||||
tokio::try_join!(inst_job, listen_job)
|
tokio::try_join!(main_job, listener_job)
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
use std::sync::Arc;
|
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
use tokio::sync::Notify;
|
|
||||||
use tracing::{error, info};
|
|
||||||
|
|
||||||
use crate::daemon::{daemon_main, DaemonClient};
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn start_srv() {
|
|
||||||
info!("Starting server");
|
|
||||||
let start_notify = Arc::new(Notify::new());
|
|
||||||
let start_recv = start_notify.clone();
|
|
||||||
let _handle = thread::spawn(move || {
|
|
||||||
let rt = Runtime::new().unwrap();
|
|
||||||
rt.block_on(async {
|
|
||||||
if let Err(e) = daemon_main(Some(start_notify.clone())).await {
|
|
||||||
error!("Error when starting rpc server: {}", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
start_notify.notify_one();
|
|
||||||
});
|
|
||||||
let rt = Runtime::new().unwrap();
|
|
||||||
rt.block_on(async {
|
|
||||||
start_recv.notified().await;
|
|
||||||
match DaemonClient::new().await {
|
|
||||||
Ok(..) => info!("Server successfully started"),
|
|
||||||
Err(e) => error!("Could not connect to server: {}", e)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -4,28 +4,18 @@ use super::DaemonCommand;
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
mod unix;
|
mod unix;
|
||||||
#[cfg(all(target_family = "unix", not(target_os = "linux")))]
|
|
||||||
pub use unix::{listen, DaemonClient};
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_family = "unix")]
|
||||||
mod systemd;
|
pub use unix::{DaemonClient, Listener};
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub use systemd::{listen, DaemonClient};
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
mod windows;
|
mod windows;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub use windows::{listen, DaemonClient};
|
pub use windows::{DaemonClient, Listener};
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
|
||||||
mod apple;
|
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
|
||||||
pub use apple::start_srv;
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct DaemonRequest {
|
pub struct DaemonRequest {
|
||||||
pub id: u32,
|
pub id: u64,
|
||||||
pub command: DaemonCommand,
|
pub command: DaemonCommand,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
use std::os::fd::IntoRawFd;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use tokio::sync::Notify;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::daemon::DaemonResponse;
|
|
||||||
|
|
||||||
pub async fn listen(
|
|
||||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
|
||||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
|
||||||
notify: Option<Arc<Notify>>
|
|
||||||
) -> Result<()> {
|
|
||||||
if !libsystemd::daemon::booted()
|
|
||||||
|| listen_with_systemd(cmd_tx.clone(), rsp_rx.clone())
|
|
||||||
.await
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
unix::listen(cmd_tx, rsp_rx, notify).await?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn listen_with_systemd(
|
|
||||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
|
||||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let fds = libsystemd::activation::receive_descriptors(false)?;
|
|
||||||
super::unix::listen_with_optional_fd(cmd_tx, rsp_rx, Some(fds[0].clone().into_raw_fd()), None).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type DaemonClient = unix::DaemonClient;
|
|
||||||
|
|
@ -1,21 +1,15 @@
|
||||||
use std::{
|
#[cfg(target_os = "linux")]
|
||||||
io,
|
use std::os::fd::{IntoRawFd, RawFd};
|
||||||
os::{
|
use std::{ffi::OsStr, io, path::Path};
|
||||||
fd::{FromRawFd, RawFd},
|
|
||||||
unix::net::UnixListener as StdUnixListener,
|
|
||||||
},
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Error, Result};
|
||||||
|
use fehler::throws;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
|
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
|
||||||
net::{UnixListener, UnixStream},
|
net::{UnixListener, UnixStream},
|
||||||
};
|
};
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use tokio::sync::Notify;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::daemon::{DaemonCommand, DaemonResponse, DaemonResponseData};
|
use crate::daemon::{DaemonCommand, DaemonResponse, DaemonResponseData};
|
||||||
|
|
||||||
|
|
@ -25,141 +19,178 @@ const UNIX_SOCKET_PATH: &str = "/run/burrow.sock";
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
const UNIX_SOCKET_PATH: &str = "burrow.sock";
|
const UNIX_SOCKET_PATH: &str = "burrow.sock";
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[derive(Debug)]
|
||||||
fn fetch_socket_path() -> Option<PathBuf> {
|
pub struct Listener {
|
||||||
let tries = vec![
|
|
||||||
"burrow.sock".to_string(),
|
|
||||||
format!(
|
|
||||||
"{}/Library/Containers/com.hackclub.burrow.network/Data/burrow.sock",
|
|
||||||
std::env::var("HOME").unwrap_or_default()
|
|
||||||
)
|
|
||||||
.to_string(),
|
|
||||||
];
|
|
||||||
for path in tries {
|
|
||||||
let path = PathBuf::from(path);
|
|
||||||
if path.exists() {
|
|
||||||
return Some(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
fn fetch_socket_path() -> Option<PathBuf> {
|
|
||||||
Some(Path::new(UNIX_SOCKET_PATH).to_path_buf())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn listen(
|
|
||||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||||
notify: Option<Arc<Notify>>
|
inner: UnixListener,
|
||||||
) -> Result<()> {
|
|
||||||
listen_with_optional_fd(cmd_tx, rsp_rx, None, notify).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn listen_with_optional_fd(
|
impl Listener {
|
||||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
#[throws]
|
||||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
pub fn new(
|
||||||
raw_fd: Option<RawFd>,
|
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||||
notify: Option<Arc<Notify>>
|
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||||
) -> Result<()> {
|
) -> Self {
|
||||||
let path = Path::new(UNIX_SOCKET_PATH);
|
let path = Path::new(OsStr::new(UNIX_SOCKET_PATH));
|
||||||
|
Self::new_with_path(cmd_tx, rsp_rx, path)?
|
||||||
let listener = if let Some(raw_fd) = raw_fd {
|
|
||||||
let listener = unsafe { StdUnixListener::from_raw_fd(raw_fd) };
|
|
||||||
listener.set_nonblocking(true)?;
|
|
||||||
UnixListener::from_std(listener)
|
|
||||||
} else {
|
|
||||||
UnixListener::bind(path)
|
|
||||||
};
|
|
||||||
let listener = if let Ok(listener) = listener {
|
|
||||||
listener
|
|
||||||
} else {
|
|
||||||
// Won't help all that much, if we use the async version of fs.
|
|
||||||
if let Some(par) = path.parent() {
|
|
||||||
std::fs::create_dir_all(par)?;
|
|
||||||
}
|
|
||||||
match std::fs::remove_file(path) {
|
|
||||||
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()),
|
|
||||||
stuff => stuff,
|
|
||||||
}?;
|
|
||||||
info!("Relative path: {}", path.to_string_lossy());
|
|
||||||
UnixListener::bind(path)?
|
|
||||||
};
|
|
||||||
if let Some(notify) = notify {
|
|
||||||
notify.notify_one();
|
|
||||||
}
|
}
|
||||||
loop {
|
|
||||||
let (stream, _) = listener.accept().await?;
|
|
||||||
let cmd_tx = cmd_tx.clone();
|
|
||||||
|
|
||||||
// I'm pretty sure we won't need to manually join / shut this down,
|
#[throws]
|
||||||
// `lines` will return Err during dropping, and this task should exit
|
#[cfg(target_os = "linux")]
|
||||||
// gracefully.
|
pub fn new_with_path(
|
||||||
let rsp_rxc = rsp_rx.clone();
|
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||||
tokio::task::spawn(async move {
|
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||||
let cmd_tx = cmd_tx;
|
path: &Path,
|
||||||
let mut stream = stream;
|
) -> Self {
|
||||||
let (mut read_stream, mut write_stream) = stream.split();
|
let inner = listener_from_path_or_fd(&path, raw_fd())?;
|
||||||
let buf_reader = BufReader::new(&mut read_stream);
|
Self { cmd_tx, rsp_rx, inner }
|
||||||
let mut lines = buf_reader.lines();
|
}
|
||||||
while let Ok(Some(line)) = lines.next_line().await {
|
|
||||||
info!("Got line: {}", line);
|
|
||||||
debug!("Line raw data: {:?}", line.as_bytes());
|
|
||||||
let mut res: DaemonResponse = DaemonResponseData::None.into();
|
|
||||||
let req = match serde_json::from_str::<DaemonRequest>(&line) {
|
|
||||||
Ok(req) => Some(req),
|
|
||||||
Err(e) => {
|
|
||||||
res.result = Err(e.to_string());
|
|
||||||
tracing::error!("Failed to parse request: {}", e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut res = serde_json::to_string(&res).unwrap();
|
|
||||||
res.push('\n');
|
|
||||||
|
|
||||||
if let Some(req) = req {
|
#[throws]
|
||||||
cmd_tx.send(req.command).await.unwrap();
|
#[cfg(not(target_os = "linux"))]
|
||||||
let res = rsp_rxc.recv().await.unwrap().with_id(req.id);
|
pub fn new_with_path(
|
||||||
let mut retres = serde_json::to_string(&res).unwrap();
|
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||||
retres.push('\n');
|
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||||
info!("Sending response: {}", retres);
|
path: &Path,
|
||||||
write_stream.write_all(retres.as_bytes()).await.unwrap();
|
) -> Self {
|
||||||
} else {
|
let inner = listener_from_path(path)?;
|
||||||
write_stream.write_all(res.as_bytes()).await.unwrap();
|
Self { cmd_tx, rsp_rx, inner }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(&self) -> Result<()> {
|
||||||
|
info!("Waiting for connections...");
|
||||||
|
loop {
|
||||||
|
let (stream, _) = self.inner.accept().await?;
|
||||||
|
let cmd_tx = self.cmd_tx.clone();
|
||||||
|
let rsp_rxc = self.rsp_rx.clone();
|
||||||
|
tokio::task::spawn(async move {
|
||||||
|
info!("Got connection: {:?}", stream);
|
||||||
|
Self::stream(stream, cmd_tx, rsp_rxc).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn stream(
|
||||||
|
stream: UnixStream,
|
||||||
|
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||||
|
rsp_rxc: async_channel::Receiver<DaemonResponse>,
|
||||||
|
) {
|
||||||
|
let mut stream = stream;
|
||||||
|
let (mut read_stream, mut write_stream) = stream.split();
|
||||||
|
let buf_reader = BufReader::new(&mut read_stream);
|
||||||
|
let mut lines = buf_reader.lines();
|
||||||
|
while let Ok(Some(line)) = lines.next_line().await {
|
||||||
|
info!("Line: {}", line);
|
||||||
|
let mut res: DaemonResponse = DaemonResponseData::None.into();
|
||||||
|
let req = match serde_json::from_str::<DaemonRequest>(&line) {
|
||||||
|
Ok(req) => Some(req),
|
||||||
|
Err(e) => {
|
||||||
|
res.result = Err(e.to_string());
|
||||||
|
error!("Failed to parse request: {}", e);
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
let mut res = serde_json::to_string(&res).unwrap();
|
||||||
|
res.push('\n');
|
||||||
|
|
||||||
|
if let Some(req) = req {
|
||||||
|
cmd_tx.send(req.command).await.unwrap();
|
||||||
|
let res = rsp_rxc.recv().await.unwrap().with_id(req.id);
|
||||||
|
let mut retres = serde_json::to_string(&res).unwrap();
|
||||||
|
retres.push('\n');
|
||||||
|
info!("Sending response: {}", retres);
|
||||||
|
write_stream.write_all(retres.as_bytes()).await.unwrap();
|
||||||
|
} else {
|
||||||
|
write_stream.write_all(res.as_bytes()).await.unwrap();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn raw_fd() -> Option<RawFd> {
|
||||||
|
if !libsystemd::daemon::booted() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match libsystemd::activation::receive_descriptors(false) {
|
||||||
|
Ok(descriptors) => descriptors.into_iter().map(|d| d.into_raw_fd()).next(),
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("Failed to receive descriptors: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[throws]
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn listener_from_path_or_fd(path: &Path, raw_fd: Option<RawFd>) -> UnixListener {
|
||||||
|
match raw_fd.map(listener_from_fd) {
|
||||||
|
Some(Ok(listener)) => listener,
|
||||||
|
_ => listener_from_path(path)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[throws]
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn listener_from_fd(fd: RawFd) -> UnixListener {
|
||||||
|
use std::os::fd::FromRawFd;
|
||||||
|
|
||||||
|
let listener = unsafe { std::os::unix::net::UnixListener::from_raw_fd(fd) };
|
||||||
|
listener.set_nonblocking(true)?;
|
||||||
|
UnixListener::from_std(listener)?
|
||||||
|
}
|
||||||
|
|
||||||
|
#[throws]
|
||||||
|
fn listener_from_path(path: &Path) -> UnixListener {
|
||||||
|
let error = match UnixListener::bind(path) {
|
||||||
|
Ok(listener) => return listener,
|
||||||
|
Err(e) => e,
|
||||||
|
};
|
||||||
|
|
||||||
|
match error.kind() {
|
||||||
|
io::ErrorKind::NotFound => {
|
||||||
|
if let Some(parent) = path.parent() {
|
||||||
|
info!("Creating parent directory {:?}", parent);
|
||||||
|
std::fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
io::ErrorKind::AddrInUse => {
|
||||||
|
info!("Removing existing file");
|
||||||
|
match std::fs::remove_file(path) {
|
||||||
|
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()),
|
||||||
|
stuff => stuff,
|
||||||
|
}?;
|
||||||
|
}
|
||||||
|
_ => error!("Failed to bind to {:?}: {}", path, error),
|
||||||
|
}
|
||||||
|
|
||||||
|
UnixListener::bind(path)?
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DaemonClient {
|
pub struct DaemonClient {
|
||||||
connection: UnixStream,
|
stream: UnixStream,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DaemonClient {
|
impl DaemonClient {
|
||||||
pub async fn new() -> Result<Self> {
|
pub async fn new() -> Result<Self> {
|
||||||
let path = fetch_socket_path().ok_or(anyhow!("Failed to find socket path"))?;
|
let path = Path::new(OsStr::new(UNIX_SOCKET_PATH));
|
||||||
// debug!("found path: {:?}", path);
|
Self::new_with_path(path).await
|
||||||
let connection = UnixStream::connect(path).await?;
|
|
||||||
debug!("connected to socket");
|
|
||||||
Ok(Self { connection })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new_with_path(path: &str) -> Result<Self> {
|
pub async fn new_with_path(path: &Path) -> Result<Self> {
|
||||||
let path = Path::new(path);
|
let stream = UnixStream::connect(path).await?;
|
||||||
let connection = UnixStream::connect(path).await?;
|
Ok(Self { stream })
|
||||||
|
|
||||||
Ok(Self { connection })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_command(&mut self, command: DaemonCommand) -> Result<DaemonResponse> {
|
pub async fn send_command(&mut self, command: DaemonCommand) -> Result<DaemonResponse> {
|
||||||
let mut command = serde_json::to_string(&DaemonRequest { id: 0, command })?;
|
let mut command = serde_json::to_string(&DaemonRequest { id: 0, command })?;
|
||||||
command.push('\n');
|
command.push('\n');
|
||||||
|
|
||||||
self.connection.write_all(command.as_bytes()).await?;
|
self.stream.write_all(command.as_bytes()).await?;
|
||||||
let buf_reader = BufReader::new(&mut self.connection);
|
let buf_reader = BufReader::new(&mut self.stream);
|
||||||
let mut lines = buf_reader.lines();
|
let mut lines = buf_reader.lines();
|
||||||
let response = lines
|
let response = lines
|
||||||
.next_line()
|
.next_line()
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,34 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use fehler::throws;
|
||||||
|
|
||||||
use super::*;
|
use super::DaemonCommand;
|
||||||
use crate::daemon::DaemonResponse;
|
use crate::daemon::DaemonResponse;
|
||||||
|
|
||||||
pub async fn listen(
|
pub struct Listener;
|
||||||
_cmd_tx: async_channel::Sender<DaemonCommand>,
|
|
||||||
_rsp_rx: async_channel::Receiver<DaemonResponse>,
|
impl Listener {
|
||||||
) -> Result<()> {
|
pub fn new_with_path(
|
||||||
unimplemented!("This platform does not currently support daemon mode.")
|
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||||
|
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||||
|
path: &Path,
|
||||||
|
) -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(&self) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct DaemonClient;
|
pub struct DaemonClient;
|
||||||
|
|
||||||
impl DaemonClient {
|
impl DaemonClient {
|
||||||
pub async fn new() -> Result<Self> {
|
pub async fn new() -> Result<Self> {
|
||||||
unimplemented!("This platform does not currently support daemon mode.")
|
Ok(Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_command(&mut self, _: DaemonCommand) -> Result<()> {
|
pub async fn send_command(&mut self, command: DaemonCommand) -> Result<DaemonResponse> {
|
||||||
unimplemented!("This platform does not currently support daemon mode.")
|
unimplemented!("This platform does not currently support daemon mode.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use tun::TunInterface;
|
||||||
pub struct DaemonResponse {
|
pub struct DaemonResponse {
|
||||||
// Error types can't be serialized, so this is the second best option.
|
// Error types can't be serialized, so this is the second best option.
|
||||||
pub result: Result<DaemonResponseData, String>,
|
pub result: Result<DaemonResponseData, String>,
|
||||||
pub id: u32,
|
pub id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DaemonResponse {
|
impl DaemonResponse {
|
||||||
|
|
@ -25,7 +25,7 @@ impl From<DaemonResponseData> for DaemonResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DaemonResponse {
|
impl DaemonResponse {
|
||||||
pub fn with_id(self, id: u32) -> Self {
|
pub fn with_id(self, id: u64) -> Self {
|
||||||
Self { id, ..self }
|
Self { id, ..self }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@ pub mod wireguard;
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
mod daemon;
|
mod daemon;
|
||||||
|
pub(crate) mod tracing;
|
||||||
|
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
pub use daemon::apple::spawn_in_process;
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
pub use daemon::{
|
pub use daemon::{
|
||||||
DaemonClient,
|
DaemonClient,
|
||||||
|
|
@ -12,9 +16,3 @@ pub use daemon::{
|
||||||
DaemonStartOptions,
|
DaemonStartOptions,
|
||||||
ServerInfo,
|
ServerInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
|
||||||
mod apple;
|
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
|
||||||
pub use apple::*;
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,9 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use tracing::instrument;
|
|
||||||
use tracing_log::LogTracer;
|
|
||||||
use tracing_oslog::OsLogger;
|
|
||||||
use tracing_subscriber::{prelude::*, EnvFilter, FmtSubscriber};
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
|
||||||
use tun::TunInterface;
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
mod daemon;
|
mod daemon;
|
||||||
|
pub(crate) mod tracing;
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
mod wireguard;
|
mod wireguard;
|
||||||
|
|
||||||
|
|
@ -39,8 +34,6 @@ struct Cli {
|
||||||
enum Commands {
|
enum Commands {
|
||||||
/// Start Burrow
|
/// Start Burrow
|
||||||
Start(StartArgs),
|
Start(StartArgs),
|
||||||
/// Retrieve the file descriptor of the tun interface
|
|
||||||
Retrieve(RetrieveArgs),
|
|
||||||
/// Stop Burrow daemon
|
/// Stop Burrow daemon
|
||||||
Stop,
|
Stop,
|
||||||
/// Start Burrow daemon
|
/// Start Burrow daemon
|
||||||
|
|
@ -54,9 +47,6 @@ enum Commands {
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
struct StartArgs {}
|
struct StartArgs {}
|
||||||
|
|
||||||
#[derive(Args)]
|
|
||||||
struct RetrieveArgs {}
|
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
struct DaemonArgs {}
|
struct DaemonArgs {}
|
||||||
|
|
||||||
|
|
@ -71,57 +61,6 @@ async fn try_start() -> Result<()> {
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
|
||||||
#[instrument]
|
|
||||||
async fn try_retrieve() -> Result<()> {
|
|
||||||
LogTracer::init()
|
|
||||||
.context("Failed to initialize LogTracer")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if cfg!(target_os = "linux") || cfg!(target_vendor = "apple") {
|
|
||||||
let maybe_layer = system_log().unwrap();
|
|
||||||
if let Some(layer) = maybe_layer {
|
|
||||||
let logger = layer.with_subscriber(FmtSubscriber::new());
|
|
||||||
tracing::subscriber::set_global_default(logger)
|
|
||||||
.context("Failed to set the global tracing subscriber")
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let iface2 = TunInterface::retrieve().ok_or(anyhow::anyhow!("No interface found"))?;
|
|
||||||
tracing::info!("{:?}", iface2);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn initialize_tracing() -> Result<()> {
|
|
||||||
LogTracer::init().context("Failed to initialize LogTracer")?;
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
|
||||||
{
|
|
||||||
let maybe_layer = system_log()?;
|
|
||||||
if let Some(layer) = maybe_layer {
|
|
||||||
let registry = tracing_subscriber::registry()
|
|
||||||
.with(layer)
|
|
||||||
.with(tracing_subscriber::fmt::layer()
|
|
||||||
.with_line_number(true)
|
|
||||||
.with_filter(EnvFilter::from_default_env())
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "tokio-console")]
|
|
||||||
let registry = registry.with(
|
|
||||||
console_subscriber::spawn()
|
|
||||||
.with_filter(EnvFilter::from_default_env()
|
|
||||||
.add_directive("tokio=trace".parse()?)
|
|
||||||
.add_directive("runtime=trace".parse()?)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
tracing::subscriber::set_global_default(registry).context("Failed to set the global tracing subscriber")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
async fn try_stop() -> Result<()> {
|
async fn try_stop() -> Result<()> {
|
||||||
let mut client = DaemonClient::new().await?;
|
let mut client = DaemonClient::new().await?;
|
||||||
|
|
@ -176,11 +115,6 @@ async fn try_start() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_vendor = "apple"))]
|
|
||||||
async fn try_retrieve() -> Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
||||||
async fn try_stop() -> Result<()> {
|
async fn try_stop() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -195,26 +129,17 @@ async fn try_serverinfo() -> Result<()> {
|
||||||
async fn try_serverconfig() -> Result<()> {
|
async fn try_serverconfig() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
initialize_tracing().await?;
|
tracing::initialize();
|
||||||
tracing::info!("Platform: {}", std::env::consts::OS);
|
|
||||||
|
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
match &cli.command {
|
match &cli.command {
|
||||||
Commands::Start(..) => {
|
Commands::Start(..) => try_start().await?,
|
||||||
try_start().await?;
|
Commands::Stop => try_stop().await?,
|
||||||
tracing::info!("FINISHED");
|
Commands::Daemon(_) => daemon::daemon_main(None, None).await?,
|
||||||
}
|
|
||||||
Commands::Retrieve(..) => {
|
|
||||||
try_retrieve().await?;
|
|
||||||
tracing::info!("FINISHED");
|
|
||||||
}
|
|
||||||
Commands::Stop => {
|
|
||||||
try_stop().await?;
|
|
||||||
}
|
|
||||||
Commands::Daemon(_) => daemon::daemon_main(None).await?,
|
|
||||||
Commands::ServerInfo => try_serverinfo().await?,
|
Commands::ServerInfo => try_serverinfo().await?,
|
||||||
Commands::ServerConfig => try_serverconfig().await?,
|
Commands::ServerConfig => try_serverconfig().await?,
|
||||||
}
|
}
|
||||||
|
|
@ -222,23 +147,6 @@ async fn main() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn system_log() -> Result<Option<tracing_journald::Layer>> {
|
|
||||||
let maybe_journald = tracing_journald::layer();
|
|
||||||
match maybe_journald {
|
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
|
||||||
tracing::trace!("journald not found");
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
_ => Ok(Some(maybe_journald?)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
|
||||||
fn system_log() -> Result<Option<OsLogger>> {
|
|
||||||
Ok(Some(OsLogger::new("com.hackclub.burrow", "burrow-cli")))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
eprintln!("This platform is not supported currently.")
|
eprintln!("This platform is not supported currently.")
|
||||||
|
|
|
||||||
63
burrow/src/tracing.rs
Normal file
63
burrow/src/tracing.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
use std::sync::Once;
|
||||||
|
|
||||||
|
use tracing::{error, info};
|
||||||
|
use tracing_subscriber::{
|
||||||
|
layer::{Layer, SubscriberExt},
|
||||||
|
EnvFilter,
|
||||||
|
Registry,
|
||||||
|
};
|
||||||
|
|
||||||
|
static TRACING: Once = Once::new();
|
||||||
|
|
||||||
|
pub fn initialize() {
|
||||||
|
TRACING.call_once(|| {
|
||||||
|
if let Err(e) = tracing_log::LogTracer::init() {
|
||||||
|
error!("Failed to initialize LogTracer: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let system_log = Some(tracing_subscriber::fmt::layer());
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
let system_log = match tracing_journald::layer() {
|
||||||
|
Ok(layer) => Some(layer),
|
||||||
|
Err(e) => {
|
||||||
|
if e.kind() != std::io::ErrorKind::NotFound {
|
||||||
|
error!("Failed to initialize journald: {}", e);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(target_vendor = "apple")]
|
||||||
|
let system_log = Some(tracing_oslog::OsLogger::new(
|
||||||
|
"com.hackclub.burrow",
|
||||||
|
"tracing",
|
||||||
|
));
|
||||||
|
|
||||||
|
let stderr = (console::user_attended_stderr() || system_log.is_none()).then(|| {
|
||||||
|
tracing_subscriber::fmt::layer()
|
||||||
|
.with_level(true)
|
||||||
|
.with_writer(std::io::stderr)
|
||||||
|
.compact()
|
||||||
|
.with_filter(EnvFilter::from_default_env())
|
||||||
|
});
|
||||||
|
|
||||||
|
let subscriber = Registry::default().with(stderr).with(system_log);
|
||||||
|
|
||||||
|
#[cfg(feature = "tokio-console")]
|
||||||
|
let subscriber = subscriber.with(
|
||||||
|
console_subscriber::spawn().with_filter(
|
||||||
|
EnvFilter::from_default_env()
|
||||||
|
.add_directive("tokio=trace".parse().unwrap())
|
||||||
|
.add_directive("runtime=trace".parse().unwrap()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = tracing::subscriber::set_global_default(subscriber) {
|
||||||
|
error!("Failed to initialize logging: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Initialized logging")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -153,7 +153,13 @@ impl Interface {
|
||||||
let mut buf = [0u8; 65535];
|
let mut buf = [0u8; 65535];
|
||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(250)).await;
|
tokio::time::sleep(tokio::time::Duration::from_millis(250)).await;
|
||||||
pcb.update_timers(&mut buf).await;
|
match pcb.update_timers(&mut buf).await {
|
||||||
|
Ok(..) => (),
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to update timers: {}", e);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -167,7 +173,7 @@ impl Interface {
|
||||||
tsks.extend(vec![
|
tsks.extend(vec![
|
||||||
tokio::spawn(main_tsk),
|
tokio::spawn(main_tsk),
|
||||||
tokio::spawn(update_timers_tsk),
|
tokio::spawn(update_timers_tsk),
|
||||||
tokio::spawn(reset_rate_limiter_tsk)
|
tokio::spawn(reset_rate_limiter_tsk),
|
||||||
]);
|
]);
|
||||||
debug!("task made..");
|
debug!("task made..");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,3 @@ pub use config::Config;
|
||||||
pub use iface::Interface;
|
pub use iface::Interface;
|
||||||
pub use pcb::PeerPcb;
|
pub use pcb::PeerPcb;
|
||||||
pub use peer::Peer;
|
pub use peer::Peer;
|
||||||
pub use x25519_dalek::{PublicKey, StaticSecret};
|
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,7 @@ const MAX_QUEUE_DEPTH: usize = 256;
|
||||||
const N_SESSIONS: usize = 8;
|
const N_SESSIONS: usize = 8;
|
||||||
|
|
||||||
pub mod x25519 {
|
pub mod x25519 {
|
||||||
pub use x25519_dalek::{
|
pub use x25519_dalek::{PublicKey, ReusableSecret, SharedSecret, StaticSecret};
|
||||||
EphemeralSecret,
|
|
||||||
PublicKey,
|
|
||||||
ReusableSecret,
|
|
||||||
SharedSecret,
|
|
||||||
StaticSecret,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
use std::{net::SocketAddr, sync::Arc};
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use fehler::throws;
|
use fehler::throws;
|
||||||
use ip_network::IpNetwork;
|
use ip_network::IpNetwork;
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use tokio::{net::UdpSocket, sync::RwLock, task::JoinHandle, time::timeout};
|
use tokio::{net::UdpSocket, sync::RwLock, task::JoinHandle};
|
||||||
use tokio::io::AsyncWrite;
|
|
||||||
use tun::tokio::TunInterface;
|
use tun::tokio::TunInterface;
|
||||||
use crate::wireguard::noise::errors::WireGuardError;
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
noise::{TunnResult, Tunnel},
|
noise::{TunnResult, Tunnel},
|
||||||
Peer,
|
Peer,
|
||||||
};
|
};
|
||||||
|
use crate::wireguard::noise::errors::WireGuardError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PeerPcb {
|
pub struct PeerPcb {
|
||||||
|
|
@ -95,7 +93,13 @@ impl PeerPcb {
|
||||||
TunnResult::WriteToNetwork(packet) => {
|
TunnResult::WriteToNetwork(packet) => {
|
||||||
tracing::debug!("WriteToNetwork: {:?}", packet);
|
tracing::debug!("WriteToNetwork: {:?}", packet);
|
||||||
self.open_if_closed().await?;
|
self.open_if_closed().await?;
|
||||||
self.socket.read().await.as_ref().unwrap().send(packet).await?;
|
self.socket
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.send(packet)
|
||||||
|
.await?;
|
||||||
tracing::debug!("WriteToNetwork done");
|
tracing::debug!("WriteToNetwork done");
|
||||||
res_dat = &[];
|
res_dat = &[];
|
||||||
continue
|
continue
|
||||||
|
|
@ -143,8 +147,7 @@ impl PeerPcb {
|
||||||
pub async fn update_timers(&self, dst: &mut [u8]) -> Result<(), Error> {
|
pub async fn update_timers(&self, dst: &mut [u8]) -> Result<(), Error> {
|
||||||
match self.tunnel.write().await.update_timers(dst) {
|
match self.tunnel.write().await.update_timers(dst) {
|
||||||
TunnResult::Done => {}
|
TunnResult::Done => {}
|
||||||
TunnResult::Err(WireGuardError::ConnectionExpired) => {
|
TunnResult::Err(WireGuardError::ConnectionExpired) => {}
|
||||||
}
|
|
||||||
TunnResult::Err(e) => {
|
TunnResult::Err(e) => {
|
||||||
tracing::error!(message = "Update timers error", error = ?e)
|
tracing::error!(message = "Update timers error", error = ?e)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ pub mod sys;
|
||||||
|
|
||||||
use kern_control::SysControlSocket;
|
use kern_control::SysControlSocket;
|
||||||
|
|
||||||
pub use super::queue::TunQueue;
|
|
||||||
use super::{ifname_to_string, string_to_ifname};
|
use super::{ifname_to_string, string_to_ifname};
|
||||||
use crate::TunOptions;
|
use crate::TunOptions;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue