Compare commits
2 commits
main
...
ck/streaml
| 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]": {
|
||||
"editor.defaultFormatter": "rust-lang.rust-analyzer",
|
||||
}
|
||||
},
|
||||
"rust-analyzer.inlayHints.typeHints.enable": false
|
||||
}
|
||||
|
|
@ -39,10 +39,10 @@ extension Tunnel {
|
|||
var isOn: Binding<Bool> {
|
||||
Binding {
|
||||
switch self.status {
|
||||
case .unknown, .disabled, .disconnecting, .disconnected, .invalid, .permissionRequired, .configurationReadWriteFailed:
|
||||
return false
|
||||
case .connecting, .reasserting, .connected:
|
||||
return true
|
||||
true
|
||||
default:
|
||||
false
|
||||
}
|
||||
} set: { newValue in
|
||||
switch (self.status, newValue) {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import Combine
|
||||
import BurrowShared
|
||||
import NetworkExtension
|
||||
import SwiftUI
|
||||
|
||||
@Observable class Tunnel {
|
||||
@Observable
|
||||
class Tunnel {
|
||||
private(set) var status: Status = .unknown
|
||||
private var error: NEVPNError?
|
||||
|
||||
private let logger = Logger.logger(for: Tunnel.self)
|
||||
private let bundleIdentifier: String
|
||||
private let configure: (NETunnelProviderManager, NETunnelProviderProtocol) -> Void
|
||||
private var tasks: [Task<Void, Error>] = []
|
||||
|
|
@ -49,33 +51,34 @@ import SwiftUI
|
|||
self.bundleIdentifier = bundleIdentifier
|
||||
self.configure = configure
|
||||
|
||||
listenForUpdates()
|
||||
Task { await update() }
|
||||
}
|
||||
|
||||
private func listenForUpdates() {
|
||||
let center = NotificationCenter.default
|
||||
let statusTask = Task {
|
||||
for try await _ in center.notifications(named: .NEVPNStatusDidChange).map({ _ in () }) {
|
||||
status = currentStatus
|
||||
}
|
||||
}
|
||||
let configurationTask = Task {
|
||||
let configurationChanged = Task {
|
||||
for try await _ in center.notifications(named: .NEVPNConfigurationChange).map({ _ in () }) {
|
||||
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 {
|
||||
do {
|
||||
let updated = try await NETunnelProviderManager.managers
|
||||
await MainActor.run { managers = updated }
|
||||
await MainActor.run {
|
||||
managers = updated
|
||||
}
|
||||
} catch let vpnError as NEVPNError {
|
||||
error = vpnError
|
||||
} catch {
|
||||
print(error)
|
||||
logger.error("Failed to update VPN configurations: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,9 +120,7 @@ import SwiftUI
|
|||
}
|
||||
|
||||
deinit {
|
||||
for task in tasks {
|
||||
task.cancel()
|
||||
}
|
||||
tasks.forEach { $0.cancel() }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,19 +128,19 @@ extension NEVPNConnection {
|
|||
var tunnelStatus: Tunnel.Status {
|
||||
switch status {
|
||||
case .connected:
|
||||
return .connected(connectedDate!)
|
||||
.connected(connectedDate!)
|
||||
case .connecting:
|
||||
return .connecting
|
||||
.connecting
|
||||
case .disconnecting:
|
||||
return .disconnecting
|
||||
.disconnecting
|
||||
case .disconnected:
|
||||
return .disconnected
|
||||
.disconnected
|
||||
case .reasserting:
|
||||
return .reasserting
|
||||
.reasserting
|
||||
case .invalid:
|
||||
return .invalid
|
||||
.invalid
|
||||
@unknown default:
|
||||
return .unknown
|
||||
.unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,20 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
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 */; };
|
||||
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 */; };
|
||||
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, ); }; };
|
||||
D05B9F7629E39EEC008CB1F9 /* BurrowApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7529E39EEC008CB1F9 /* BurrowApp.swift */; };
|
||||
D05B9F7829E39EEC008CB1F9 /* TunnelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D05B9F7729E39EEC008CB1F9 /* TunnelView.swift */; };
|
||||
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 */; };
|
||||
D0BCC5FF2A086E1C00AD070D /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BCC5FE2A086E1C00AD070D /* Status.swift */; };
|
||||
D0BCC6082A0981FE00AD070D /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B98FC629FDC5B5004E7149 /* Tunnel.swift */; };
|
||||
|
|
@ -24,6 +30,20 @@
|
|||
/* End PBXBuildFile 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 */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D05B9F6A29E39EEC008CB1F9 /* Project object */;
|
||||
|
|
@ -49,8 +69,14 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
|
@ -70,6 +96,8 @@
|
|||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
|
@ -80,10 +108,18 @@
|
|||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
D00117352B30341C00D87C25 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D020F65029E4A697002790F6 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D00117442B30372900D87C25 /* libBurrowShared.a in Frameworks */,
|
||||
D0BCC6092A09A03E00AD070D /* libburrow.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -92,6 +128,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D00117452B30372C00D87C25 /* libBurrowShared.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -106,6 +143,33 @@
|
|||
path = Menu;
|
||||
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 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -122,12 +186,14 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D020F65729E4A697002790F6 /* PacketTunnelProvider.swift */,
|
||||
0B46E8DF2AC918CA00BA2A3C /* Client.swift */,
|
||||
0B28F1552ABF463A000D44B0 /* DataTypes.swift */,
|
||||
D00117322B3001A400D87C25 /* NewlineProtocolFramer.swift */,
|
||||
D00117302B2FFFC900D87C25 /* NWConnection+Async.swift */,
|
||||
D020F65929E4A697002790F6 /* Info.plist */,
|
||||
D020F66729E4A95D002790F6 /* NetworkExtension-iOS.entitlements */,
|
||||
D020F66629E4A95D002790F6 /* NetworkExtension-macOS.entitlements */,
|
||||
D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */,
|
||||
0B28F1552ABF463A000D44B0 /* DataTypes.swift */,
|
||||
0B46E8DF2AC918CA00BA2A3C /* BurrowIpc.swift */,
|
||||
D0B98FD729FDDB57004E7149 /* libburrow */,
|
||||
);
|
||||
path = NetworkExtension;
|
||||
|
|
@ -138,8 +204,10 @@
|
|||
children = (
|
||||
D05B9F7429E39EEC008CB1F9 /* App */,
|
||||
D020F65629E4A697002790F6 /* NetworkExtension */,
|
||||
D00117392B30341C00D87C25 /* Shared */,
|
||||
D020F63C29E4A1FF002790F6 /* Configuration */,
|
||||
D05B9F7329E39EEC008CB1F9 /* Products */,
|
||||
D00117432B30372900D87C25 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
|
@ -148,6 +216,7 @@
|
|||
children = (
|
||||
D05B9F7229E39EEC008CB1F9 /* Burrow.app */,
|
||||
D020F65329E4A697002790F6 /* BurrowNetworkExtension.appex */,
|
||||
D00117382B30341C00D87C25 /* libBurrowShared.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -184,6 +253,23 @@
|
|||
/* End PBXGroup 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 */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D020F65E29E4A697002790F6 /* Build configuration list for PBXNativeTarget "NetworkExtension" */;
|
||||
|
|
@ -196,7 +282,8 @@
|
|||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D08252712B5C3E2E005DA378 /* PBXTargetDependency */,
|
||||
D08252792B5DEB78005DA378 /* PBXTargetDependency */,
|
||||
D00117492B30373500D87C25 /* PBXTargetDependency */,
|
||||
);
|
||||
name = NetworkExtension;
|
||||
productName = BurrowNetworkExtension;
|
||||
|
|
@ -215,7 +302,8 @@
|
|||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D08252732B5C3E33005DA378 /* PBXTargetDependency */,
|
||||
D082527B2B5DEB7D005DA378 /* PBXTargetDependency */,
|
||||
D00117472B30373100D87C25 /* PBXTargetDependency */,
|
||||
D020F65C29E4A697002790F6 /* PBXTargetDependency */,
|
||||
);
|
||||
name = App;
|
||||
|
|
@ -230,9 +318,12 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1430;
|
||||
LastUpgradeCheck = 1510;
|
||||
LastSwiftUpdateCheck = 1510;
|
||||
LastUpgradeCheck = 1430;
|
||||
TargetAttributes = {
|
||||
D00117372B30341C00D87C25 = {
|
||||
CreatedOnToolsVersion = 15.1;
|
||||
};
|
||||
D020F65229E4A697002790F6 = {
|
||||
CreatedOnToolsVersion = 14.3;
|
||||
};
|
||||
|
|
@ -251,7 +342,7 @@
|
|||
);
|
||||
mainGroup = D05B9F6929E39EEC008CB1F9;
|
||||
packageReferences = (
|
||||
D082526F2B5C3E23005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */,
|
||||
D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */,
|
||||
);
|
||||
productRefGroup = D05B9F7329E39EEC008CB1F9 /* Products */;
|
||||
projectDirPath = "";
|
||||
|
|
@ -259,6 +350,7 @@
|
|||
targets = (
|
||||
D05B9F7129E39EEC008CB1F9 /* App */,
|
||||
D020F65229E4A697002790F6 /* NetworkExtension */,
|
||||
D00117372B30341C00D87C25 /* Shared */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
|
@ -306,12 +398,23 @@
|
|||
/* End PBXShellScriptBuildPhase 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 */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D00117332B3001A400D87C25 /* NewlineProtocolFramer.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 */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -333,22 +436,50 @@
|
|||
/* End PBXSourcesBuildPhase 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 */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D020F65229E4A697002790F6 /* NetworkExtension */;
|
||||
targetProxy = D020F65B29E4A697002790F6 /* PBXContainerItemProxy */;
|
||||
};
|
||||
D08252712B5C3E2E005DA378 /* PBXTargetDependency */ = {
|
||||
D08252792B5DEB78005DA378 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
productRef = D08252702B5C3E2E005DA378 /* SwiftLintPlugin */;
|
||||
productRef = D08252782B5DEB78005DA378 /* SwiftLintPlugin */;
|
||||
};
|
||||
D08252732B5C3E33005DA378 /* PBXTargetDependency */ = {
|
||||
D082527B2B5DEB7D005DA378 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
productRef = D08252722B5C3E33005DA378 /* SwiftLintPlugin */;
|
||||
productRef = D082527A2B5DEB7D005DA378 /* SwiftLintPlugin */;
|
||||
};
|
||||
D082527D2B5DEB80005DA378 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
productRef = D082527C2B5DEB80005DA378 /* SwiftLintPlugin */;
|
||||
};
|
||||
/* End PBXTargetDependency 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 */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = D020F66229E4A6E5002790F6 /* NetworkExtension.xcconfig */;
|
||||
|
|
@ -394,6 +525,15 @@
|
|||
/* End XCBuildConfiguration 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" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
@ -424,7 +564,7 @@
|
|||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
D082526F2B5C3E23005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */ = {
|
||||
D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/realm/SwiftLint.git";
|
||||
requirement = {
|
||||
|
|
@ -435,14 +575,19 @@
|
|||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
D08252702B5C3E2E005DA378 /* SwiftLintPlugin */ = {
|
||||
D08252782B5DEB78005DA378 /* SwiftLintPlugin */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D082526F2B5C3E23005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
||||
package = D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
||||
productName = "plugin:SwiftLintPlugin";
|
||||
};
|
||||
D08252722B5C3E33005DA378 /* SwiftLintPlugin */ = {
|
||||
D082527A2B5DEB7D005DA378 /* SwiftLintPlugin */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D082526F2B5C3E23005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
||||
package = D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
||||
productName = "plugin:SwiftLintPlugin";
|
||||
};
|
||||
D082527C2B5DEB80005DA378 /* SwiftLintPlugin */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D08252772B5DEB6E005DA378 /* XCRemoteSwiftPackageReference "SwiftLint" */;
|
||||
productName = "plugin:SwiftLintPlugin";
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
SKIP_INSTALL = NO
|
||||
MERGED_BINARY_TYPE = manual
|
||||
|
||||
LD_RUNPATH_SEARCH_PATHS[sdk=iphone*] = $(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
|
||||
GENERATE_INFOPLIST_FILE = YES
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023 Hack Club
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2023-2024 Hack Club
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Burrow
|
||||
|
||||
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[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
|
||||
}
|
||||
|
||||
protocol Request: Codable where CommandT: Codable {
|
||||
associatedtype CommandT
|
||||
protocol Request: Codable where Command: Codable {
|
||||
associatedtype Command
|
||||
|
||||
var id: UInt { get set }
|
||||
var command: CommandT { get set }
|
||||
var command: Command { get set }
|
||||
}
|
||||
|
||||
struct BurrowSingleCommand: Request {
|
||||
|
|
@ -38,13 +39,6 @@ struct BurrowStartRequest: Codable {
|
|||
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 {
|
||||
var id: UInt
|
||||
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">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>$(APP_GROUP_IDENTIFIER)</string>
|
||||
</array>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.server</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ PRODUCT_BUNDLE_IDENTIFIER = $(NETWORK_EXTENSION_BUNDLE_IDENTIFIER)
|
|||
INFOPLIST_FILE = NetworkExtension/Info.plist
|
||||
|
||||
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
|
||||
|
|
|
|||
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 NetworkExtension
|
||||
import os
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
let logger = Logger(subsystem: "com.hackclub.burrow", category: "frontend")
|
||||
var client: BurrowIpc?
|
||||
var osInitialized = false
|
||||
private let logger = Logger.logger(for: PacketTunnelProvider.self)
|
||||
|
||||
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 {
|
||||
let command = BurrowSingleCommand(id: 0, command: "ServerConfig")
|
||||
guard let data = try await client?.request(command, type: Response<BurrowResult<ServerConfigData>>.self)
|
||||
else {
|
||||
throw BurrowError.cantParseResult
|
||||
}
|
||||
libburrow.spawnInProcess(socketPath: try Constants.socketURL.path)
|
||||
|
||||
let client = try Client()
|
||||
|
||||
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)
|
||||
self.logger.log("Received final data: \(String(decoding: encoded, as: UTF8.self))")
|
||||
guard let serverconfig = data.result.Ok else {
|
||||
throw BurrowError.resultIsError
|
||||
}
|
||||
guard let tunNs = self.generateTunSettings(from: serverconfig) else {
|
||||
guard let tunNs = generateTunSettings(from: serverconfig) else {
|
||||
throw BurrowError.addrDoesntExist
|
||||
}
|
||||
try await self.setTunnelNetworkSettings(tunNs)
|
||||
self.logger.info("Set remote tunnel address to \(tunNs.tunnelRemoteAddress)")
|
||||
|
||||
// let tunFd = self.packetFlow.value(forKeyPath: "socket.fileDescriptor") as! Int;
|
||||
// self.logger.info("Found File Descriptor: \(tunFd)")
|
||||
let startCommand = start_req_fd(id: 1)
|
||||
guard let data = try await client?.request(startCommand, type: Response<BurrowResult<String>>.self)
|
||||
else {
|
||||
throw BurrowError.cantParseResult
|
||||
}
|
||||
let encodedStartRes = try JSONEncoder().encode(data.result)
|
||||
self.logger.log("Received start server response: \(String(decoding: encodedStartRes, as: UTF8.self))")
|
||||
let startRequest = BurrowRequest(
|
||||
id: .random(in: (.min)..<(.max)),
|
||||
command: BurrowStartRequest(
|
||||
Start: BurrowStartRequest.StartOptions(
|
||||
tun: BurrowStartRequest.TunOptions(
|
||||
name: nil, no_pi: false, tun_excl: false, tun_retrieve: true, address: nil
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
let response = try await client.request(startRequest, type: Response<BurrowResult<String>>.self)
|
||||
self.logger.log("Received start server response: \(String(describing: response.result))")
|
||||
} catch {
|
||||
self.logger.error("An error occurred: \(error)")
|
||||
self.logger.error("Failed to start tunnel: \(error)")
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
private func generateTunSettings(from: ServerConfigData) -> NETunnelNetworkSettings? {
|
||||
let cfig = from.ServerConfig
|
||||
guard let addr = cfig.address else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let settings = NEIPv4Settings(addresses: [addr], subnetMasks: ["255.255.255.0"])
|
||||
settings.includedRoutes = [.default()]
|
||||
|
||||
// Using a makeshift remote tunnel address
|
||||
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)")
|
||||
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();
|
||||
void initialize_oslog();
|
||||
__attribute__((__swift_name__("spawnInProcess(socketPath:)")))
|
||||
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"
|
||||
tokio = { version = "1.21", features = ["rt", "macros", "sync", "io-util", "rt-multi-thread", "time", "tracing"] }
|
||||
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-log = "0.1"
|
||||
tracing-journald = "0.3"
|
||||
tracing-oslog = {git = "https://github.com/Stormshield-robinc/tracing-oslog"}
|
||||
tracing-subscriber = { version = "0.3" , features = ["std", "env-filter"]}
|
||||
env_logger = "0.10"
|
||||
tracing-oslog = { git = "https://github.com/Stormshield-robinc/tracing-oslog" }
|
||||
tracing-subscriber = { version = "0.3" , features = ["std", "env-filter"] }
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
blake2 = "0.10.6"
|
||||
chacha20poly1305 = "0.10.1"
|
||||
rand = "0.8.5"
|
||||
rand_core = "0.6.4"
|
||||
aead = "0.5.2"
|
||||
x25519-dalek = { version = "2.0.0", features = ["reusable_secrets", "static_secrets"] }
|
||||
ring = "0.17.7"
|
||||
parking_lot = "0.12.1"
|
||||
serde_json = "1.0"
|
||||
blake2 = "0.10"
|
||||
chacha20poly1305 = "0.10"
|
||||
rand = "0.8"
|
||||
rand_core = "0.6"
|
||||
aead = "0.5"
|
||||
x25519-dalek = { version = "2.0", features = ["reusable_secrets", "static_secrets"] }
|
||||
ring = "0.17"
|
||||
parking_lot = "0.12"
|
||||
hmac = "0.12"
|
||||
ipnet = { version = "2.8.0", features = ["serde"] }
|
||||
base64 = "0.21.4"
|
||||
fehler = "1.0.0"
|
||||
ip_network_table = "0.2.0"
|
||||
ip_network = "0.4.0"
|
||||
async-channel = "2.1.1"
|
||||
base64 = "0.21"
|
||||
fehler = "1.0"
|
||||
ip_network_table = "0.2"
|
||||
ip_network = "0.4"
|
||||
async-channel = "2.1"
|
||||
schemars = "0.8"
|
||||
futures = "0.3.28"
|
||||
uuid = { version = "1.6.1", features = ["v4"] }
|
||||
console-subscriber = { version = "0.2.0" , optional = true}
|
||||
once_cell = "1.19"
|
||||
console-subscriber = { version = "0.2.0" , optional = true }
|
||||
console = "0.15.8"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
caps = "0.5.5"
|
||||
libsystemd = "0.6"
|
||||
caps = "0.5"
|
||||
libsystemd = "0.7"
|
||||
tracing-journald = "0.3"
|
||||
|
||||
[target.'cfg(target_vendor = "apple")'.dependencies]
|
||||
nix = { version = "0.26.2" }
|
||||
nix = { version = "0.27" }
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.32.0", features = ["yaml"] }
|
||||
etherparse = "0.12"
|
||||
insta = { version = "1.32", features = ["yaml"] }
|
||||
|
||||
[package.metadata.generate-rpm]
|
||||
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 instance;
|
||||
mod net;
|
||||
|
|
@ -8,44 +9,52 @@ mod response;
|
|||
use anyhow::Result;
|
||||
pub use command::{DaemonCommand, DaemonStartOptions};
|
||||
use instance::DaemonInstance;
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub use net::start_srv;
|
||||
pub use net::DaemonClient;
|
||||
pub use net::{DaemonClient, Listener};
|
||||
pub use response::{DaemonResponse, DaemonResponseData, ServerInfo};
|
||||
use tokio::sync::{Notify, RwLock};
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::{
|
||||
daemon::net::listen,
|
||||
wireguard::{Config, Interface},
|
||||
};
|
||||
use crate::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 (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 iface: Interface = config.try_into()?;
|
||||
let mut instance = DaemonInstance::new(commands_rx, response_tx, Arc::new(RwLock::new(iface)));
|
||||
|
||||
let mut inst: DaemonInstance =
|
||||
DaemonInstance::new(commands_rx, response_tx, Arc::new(RwLock::new(iface)));
|
||||
info!("Starting daemon...");
|
||||
|
||||
tracing::info!("Starting daemon jobs...");
|
||||
|
||||
let inst_job = tokio::spawn(async move {
|
||||
let res = inst.run().await;
|
||||
if let Err(e) = res {
|
||||
tracing::error!("Error when running instance: {}", e);
|
||||
let main_job = tokio::spawn(async move {
|
||||
let result = instance.run().await;
|
||||
if let Err(e) = result.as_ref() {
|
||||
error!("Instance exited: {}", e);
|
||||
}
|
||||
result
|
||||
});
|
||||
|
||||
let listen_job = tokio::spawn(async move {
|
||||
let res = listen(commands_tx, response_rx, notify_ready).await;
|
||||
if let Err(e) = res {
|
||||
tracing::error!("Error when listening: {}", e);
|
||||
let listener_job = tokio::spawn(async move {
|
||||
let result = listener.run().await;
|
||||
if let Err(e) = result.as_ref() {
|
||||
error!("Listener exited: {}", e);
|
||||
}
|
||||
result
|
||||
});
|
||||
|
||||
tokio::try_join!(inst_job, listen_job)
|
||||
tokio::try_join!(main_job, listener_job)
|
||||
.map(|_| ())
|
||||
.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")]
|
||||
mod unix;
|
||||
#[cfg(all(target_family = "unix", not(target_os = "linux")))]
|
||||
pub use unix::{listen, DaemonClient};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod systemd;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use systemd::{listen, DaemonClient};
|
||||
#[cfg(target_family = "unix")]
|
||||
pub use unix::{DaemonClient, Listener};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use windows::{listen, DaemonClient};
|
||||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
mod apple;
|
||||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub use apple::start_srv;
|
||||
pub use windows::{DaemonClient, Listener};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct DaemonRequest {
|
||||
pub id: u32,
|
||||
pub id: u64,
|
||||
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::{
|
||||
io,
|
||||
os::{
|
||||
fd::{FromRawFd, RawFd},
|
||||
unix::net::UnixListener as StdUnixListener,
|
||||
},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::fd::{IntoRawFd, RawFd};
|
||||
use std::{ffi::OsStr, io, path::Path};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use fehler::throws;
|
||||
use tokio::{
|
||||
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
|
||||
net::{UnixListener, UnixStream},
|
||||
};
|
||||
use tracing::{debug, info};
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
use tokio::sync::Notify;
|
||||
use super::*;
|
||||
use crate::daemon::{DaemonCommand, DaemonResponse, DaemonResponseData};
|
||||
|
||||
|
|
@ -25,141 +19,178 @@ const UNIX_SOCKET_PATH: &str = "/run/burrow.sock";
|
|||
#[cfg(target_vendor = "apple")]
|
||||
const UNIX_SOCKET_PATH: &str = "burrow.sock";
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn fetch_socket_path() -> Option<PathBuf> {
|
||||
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(
|
||||
#[derive(Debug)]
|
||||
pub struct Listener {
|
||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||
notify: Option<Arc<Notify>>
|
||||
) -> Result<()> {
|
||||
listen_with_optional_fd(cmd_tx, rsp_rx, None, notify).await
|
||||
inner: UnixListener,
|
||||
}
|
||||
|
||||
pub(crate) async fn listen_with_optional_fd(
|
||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||
raw_fd: Option<RawFd>,
|
||||
notify: Option<Arc<Notify>>
|
||||
) -> Result<()> {
|
||||
let path = Path::new(UNIX_SOCKET_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();
|
||||
impl Listener {
|
||||
#[throws]
|
||||
pub fn new(
|
||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||
) -> Self {
|
||||
let path = Path::new(OsStr::new(UNIX_SOCKET_PATH));
|
||||
Self::new_with_path(cmd_tx, rsp_rx, path)?
|
||||
}
|
||||
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,
|
||||
// `lines` will return Err during dropping, and this task should exit
|
||||
// gracefully.
|
||||
let rsp_rxc = rsp_rx.clone();
|
||||
tokio::task::spawn(async move {
|
||||
let cmd_tx = cmd_tx;
|
||||
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!("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');
|
||||
#[throws]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn new_with_path(
|
||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||
path: &Path,
|
||||
) -> Self {
|
||||
let inner = listener_from_path_or_fd(&path, raw_fd())?;
|
||||
Self { cmd_tx, rsp_rx, inner }
|
||||
}
|
||||
|
||||
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();
|
||||
#[throws]
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub fn new_with_path(
|
||||
cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||
rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||
path: &Path,
|
||||
) -> Self {
|
||||
let inner = listener_from_path(path)?;
|
||||
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)]
|
||||
pub struct DaemonClient {
|
||||
connection: UnixStream,
|
||||
stream: UnixStream,
|
||||
}
|
||||
|
||||
impl DaemonClient {
|
||||
pub async fn new() -> Result<Self> {
|
||||
let path = fetch_socket_path().ok_or(anyhow!("Failed to find socket path"))?;
|
||||
// debug!("found path: {:?}", path);
|
||||
let connection = UnixStream::connect(path).await?;
|
||||
debug!("connected to socket");
|
||||
Ok(Self { connection })
|
||||
let path = Path::new(OsStr::new(UNIX_SOCKET_PATH));
|
||||
Self::new_with_path(path).await
|
||||
}
|
||||
|
||||
pub async fn new_with_path(path: &str) -> Result<Self> {
|
||||
let path = Path::new(path);
|
||||
let connection = UnixStream::connect(path).await?;
|
||||
|
||||
Ok(Self { connection })
|
||||
pub async fn new_with_path(path: &Path) -> Result<Self> {
|
||||
let stream = UnixStream::connect(path).await?;
|
||||
Ok(Self { stream })
|
||||
}
|
||||
|
||||
pub async fn send_command(&mut self, command: DaemonCommand) -> Result<DaemonResponse> {
|
||||
let mut command = serde_json::to_string(&DaemonRequest { id: 0, command })?;
|
||||
command.push('\n');
|
||||
|
||||
self.connection.write_all(command.as_bytes()).await?;
|
||||
let buf_reader = BufReader::new(&mut self.connection);
|
||||
self.stream.write_all(command.as_bytes()).await?;
|
||||
let buf_reader = BufReader::new(&mut self.stream);
|
||||
let mut lines = buf_reader.lines();
|
||||
let response = lines
|
||||
.next_line()
|
||||
|
|
|
|||
|
|
@ -1,23 +1,34 @@
|
|||
use anyhow::Result;
|
||||
use fehler::throws;
|
||||
|
||||
use super::*;
|
||||
use super::DaemonCommand;
|
||||
use crate::daemon::DaemonResponse;
|
||||
|
||||
pub async fn listen(
|
||||
_cmd_tx: async_channel::Sender<DaemonCommand>,
|
||||
_rsp_rx: async_channel::Receiver<DaemonResponse>,
|
||||
) -> Result<()> {
|
||||
unimplemented!("This platform does not currently support daemon mode.")
|
||||
pub struct Listener;
|
||||
|
||||
impl Listener {
|
||||
pub fn new_with_path(
|
||||
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;
|
||||
|
||||
impl DaemonClient {
|
||||
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.")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use tun::TunInterface;
|
|||
pub struct DaemonResponse {
|
||||
// Error types can't be serialized, so this is the second best option.
|
||||
pub result: Result<DaemonResponseData, String>,
|
||||
pub id: u32,
|
||||
pub id: u64,
|
||||
}
|
||||
|
||||
impl DaemonResponse {
|
||||
|
|
@ -25,7 +25,7 @@ impl From<DaemonResponseData> for DaemonResponse {
|
|||
}
|
||||
|
||||
impl DaemonResponse {
|
||||
pub fn with_id(self, id: u32) -> Self {
|
||||
pub fn with_id(self, id: u64) -> Self {
|
||||
Self { id, ..self }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ pub mod wireguard;
|
|||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
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"))]
|
||||
pub use daemon::{
|
||||
DaemonClient,
|
||||
|
|
@ -12,9 +16,3 @@ pub use daemon::{
|
|||
DaemonStartOptions,
|
||||
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 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"))]
|
||||
mod daemon;
|
||||
pub(crate) mod tracing;
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
mod wireguard;
|
||||
|
||||
|
|
@ -39,8 +34,6 @@ struct Cli {
|
|||
enum Commands {
|
||||
/// Start Burrow
|
||||
Start(StartArgs),
|
||||
/// Retrieve the file descriptor of the tun interface
|
||||
Retrieve(RetrieveArgs),
|
||||
/// Stop Burrow daemon
|
||||
Stop,
|
||||
/// Start Burrow daemon
|
||||
|
|
@ -54,9 +47,6 @@ enum Commands {
|
|||
#[derive(Args)]
|
||||
struct StartArgs {}
|
||||
|
||||
#[derive(Args)]
|
||||
struct RetrieveArgs {}
|
||||
|
||||
#[derive(Args)]
|
||||
struct DaemonArgs {}
|
||||
|
||||
|
|
@ -71,57 +61,6 @@ async fn try_start() -> Result<()> {
|
|||
.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"))]
|
||||
async fn try_stop() -> Result<()> {
|
||||
let mut client = DaemonClient::new().await?;
|
||||
|
|
@ -176,11 +115,6 @@ async fn try_start() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
async fn try_retrieve() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
|
||||
async fn try_stop() -> Result<()> {
|
||||
Ok(())
|
||||
|
|
@ -195,26 +129,17 @@ async fn try_serverinfo() -> Result<()> {
|
|||
async fn try_serverconfig() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> Result<()> {
|
||||
initialize_tracing().await?;
|
||||
tracing::info!("Platform: {}", std::env::consts::OS);
|
||||
tracing::initialize();
|
||||
|
||||
let cli = Cli::parse();
|
||||
match &cli.command {
|
||||
Commands::Start(..) => {
|
||||
try_start().await?;
|
||||
tracing::info!("FINISHED");
|
||||
}
|
||||
Commands::Retrieve(..) => {
|
||||
try_retrieve().await?;
|
||||
tracing::info!("FINISHED");
|
||||
}
|
||||
Commands::Stop => {
|
||||
try_stop().await?;
|
||||
}
|
||||
Commands::Daemon(_) => daemon::daemon_main(None).await?,
|
||||
Commands::Start(..) => try_start().await?,
|
||||
Commands::Stop => try_stop().await?,
|
||||
Commands::Daemon(_) => daemon::daemon_main(None, None).await?,
|
||||
Commands::ServerInfo => try_serverinfo().await?,
|
||||
Commands::ServerConfig => try_serverconfig().await?,
|
||||
}
|
||||
|
|
@ -222,23 +147,6 @@ async fn main() -> Result<()> {
|
|||
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")))]
|
||||
pub fn main() {
|
||||
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];
|
||||
loop {
|
||||
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![
|
||||
tokio::spawn(main_tsk),
|
||||
tokio::spawn(update_timers_tsk),
|
||||
tokio::spawn(reset_rate_limiter_tsk)
|
||||
tokio::spawn(reset_rate_limiter_tsk),
|
||||
]);
|
||||
debug!("task made..");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,4 +8,3 @@ pub use config::Config;
|
|||
pub use iface::Interface;
|
||||
pub use pcb::PeerPcb;
|
||||
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;
|
||||
|
||||
pub mod x25519 {
|
||||
pub use x25519_dalek::{
|
||||
EphemeralSecret,
|
||||
PublicKey,
|
||||
ReusableSecret,
|
||||
SharedSecret,
|
||||
StaticSecret,
|
||||
};
|
||||
pub use x25519_dalek::{PublicKey, ReusableSecret, SharedSecret, StaticSecret};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
use std::{net::SocketAddr, sync::Arc};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{Error, Result};
|
||||
use fehler::throws;
|
||||
use ip_network::IpNetwork;
|
||||
use rand::random;
|
||||
use tokio::{net::UdpSocket, sync::RwLock, task::JoinHandle, time::timeout};
|
||||
use tokio::io::AsyncWrite;
|
||||
use tokio::{net::UdpSocket, sync::RwLock, task::JoinHandle};
|
||||
use tun::tokio::TunInterface;
|
||||
use crate::wireguard::noise::errors::WireGuardError;
|
||||
|
||||
use super::{
|
||||
noise::{TunnResult, Tunnel},
|
||||
Peer,
|
||||
};
|
||||
use crate::wireguard::noise::errors::WireGuardError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PeerPcb {
|
||||
|
|
@ -95,7 +93,13 @@ impl PeerPcb {
|
|||
TunnResult::WriteToNetwork(packet) => {
|
||||
tracing::debug!("WriteToNetwork: {:?}", packet);
|
||||
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");
|
||||
res_dat = &[];
|
||||
continue
|
||||
|
|
@ -143,8 +147,7 @@ impl PeerPcb {
|
|||
pub async fn update_timers(&self, dst: &mut [u8]) -> Result<(), Error> {
|
||||
match self.tunnel.write().await.update_timers(dst) {
|
||||
TunnResult::Done => {}
|
||||
TunnResult::Err(WireGuardError::ConnectionExpired) => {
|
||||
}
|
||||
TunnResult::Err(WireGuardError::ConnectionExpired) => {}
|
||||
TunnResult::Err(e) => {
|
||||
tracing::error!(message = "Update timers error", error = ?e)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ pub mod sys;
|
|||
|
||||
use kern_control::SysControlSocket;
|
||||
|
||||
pub use super::queue::TunQueue;
|
||||
use super::{ifname_to_string, string_to_ifname};
|
||||
use crate::TunOptions;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue