Skip to content

Commit 3563eb4

Browse files
committed
chore: add dylib downloader and validator
1 parent e9f5c6f commit 3563eb4

23 files changed

+1143
-385
lines changed

Coder Desktop/Coder Desktop.xcodeproj/project.pbxproj

+305-76
Large diffs are not rendered by default.

Coder Desktop/Coder Desktop.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"originHash" : "aa8dd97dc6e28dedc4a5c45c435467a247486474bf3c1caf5e67085d52325132",
2+
"originHash" : "0dee63153808d20a73f823faee354b1c4e55e5f9258a2831fa6074ed154cd0bc",
33
"pins" : [
44
{
55
"identity" : "alamofire",
@@ -36,6 +36,15 @@
3636
"version" : "1.28.2"
3737
}
3838
},
39+
{
40+
"identity" : "swifter",
41+
"kind" : "remoteSourceControl",
42+
"location" : "https://github.com/httpswift/swifter",
43+
"state" : {
44+
"revision" : "9483a5d459b45c3ffd059f7b55f9638e268632fd",
45+
"version" : "1.5.0"
46+
}
47+
},
3948
{
4049
"identity" : "swiftlintplugins",
4150
"kind" : "remoteSourceControl",

Coder Desktop/Coder Desktop.xcodeproj/xcshareddata/xcschemes/Coder Desktop.xcscheme

+14-3
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,20 @@
6262
parallelizable = "YES">
6363
<BuildableReference
6464
BuildableIdentifier = "primary"
65-
BlueprintIdentifier = "961679D82D030E1D00B2B6DF"
66-
BuildableName = "ProtoTests.xctest"
67-
BlueprintName = "ProtoTests"
65+
BlueprintIdentifier = "AA3B3DA02D2D23860099996A"
66+
BuildableName = "VPNLib.framework"
67+
BlueprintName = "VPNLib"
68+
ReferencedContainer = "container:Coder Desktop.xcodeproj">
69+
</BuildableReference>
70+
</TestableReference>
71+
<TestableReference
72+
skipped = "NO"
73+
parallelizable = "YES">
74+
<BuildableReference
75+
BuildableIdentifier = "primary"
76+
BlueprintIdentifier = "AA3B3DA72D2D23860099996A"
77+
BuildableName = "VPNLibTests.xctest"
78+
BlueprintName = "VPNLibTests"
6879
ReferencedContainer = "container:Coder Desktop.xcodeproj">
6980
</BuildableReference>
7081
</TestableReference>

Coder Desktop/Coder Desktop.xcodeproj/xcshareddata/xcschemes/ProtoTests.xcscheme renamed to Coder Desktop/Coder Desktop.xcodeproj/xcshareddata/xcschemes/VPN.xcscheme

+19-26
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,29 @@
66
parallelizeBuildables = "YES"
77
buildImplicitDependencies = "YES"
88
buildArchitectures = "Automatic">
9+
<BuildActionEntries>
10+
<BuildActionEntry
11+
buildForTesting = "YES"
12+
buildForRunning = "YES"
13+
buildForProfiling = "YES"
14+
buildForArchiving = "YES"
15+
buildForAnalyzing = "YES">
16+
<BuildableReference
17+
BuildableIdentifier = "primary"
18+
BlueprintIdentifier = "9616792F2CFF117300B2B6DF"
19+
BuildableName = "com.coder.Coder-Desktop.VPN.systemextension"
20+
BlueprintName = "VPN"
21+
ReferencedContainer = "container:Coder Desktop.xcodeproj">
22+
</BuildableReference>
23+
</BuildActionEntry>
24+
</BuildActionEntries>
925
</BuildAction>
1026
<TestAction
1127
buildConfiguration = "Debug"
1228
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
1329
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
1430
shouldUseLaunchSchemeArgsEnv = "YES"
1531
shouldAutocreateTestPlan = "YES">
16-
<Testables>
17-
<TestableReference
18-
skipped = "NO"
19-
parallelizable = "YES">
20-
<BuildableReference
21-
BuildableIdentifier = "primary"
22-
BlueprintIdentifier = "961679D82D030E1D00B2B6DF"
23-
BuildableName = "ProtoTests.xctest"
24-
BlueprintName = "ProtoTests"
25-
ReferencedContainer = "container:Coder Desktop.xcodeproj">
26-
</BuildableReference>
27-
</TestableReference>
28-
</Testables>
2932
</TestAction>
3033
<LaunchAction
3134
buildConfiguration = "Debug"
@@ -37,16 +40,6 @@
3740
debugDocumentVersioning = "YES"
3841
debugServiceExtension = "internal"
3942
allowLocationSimulation = "YES">
40-
<BuildableProductRunnable
41-
runnableDebuggingMode = "0">
42-
<BuildableReference
43-
BuildableIdentifier = "primary"
44-
BlueprintIdentifier = "961678FB2CFF100D00B2B6DF"
45-
BuildableName = "Coder Desktop.app"
46-
BlueprintName = "Coder Desktop"
47-
ReferencedContainer = "container:Coder Desktop.xcodeproj">
48-
</BuildableReference>
49-
</BuildableProductRunnable>
5043
</LaunchAction>
5144
<ProfileAction
5245
buildConfiguration = "Release"
@@ -57,9 +50,9 @@
5750
<MacroExpansion>
5851
<BuildableReference
5952
BuildableIdentifier = "primary"
60-
BlueprintIdentifier = "961678FB2CFF100D00B2B6DF"
61-
BuildableName = "Coder Desktop.app"
62-
BlueprintName = "Coder Desktop"
53+
BlueprintIdentifier = "9616792F2CFF117300B2B6DF"
54+
BuildableName = "com.coder.Coder-Desktop.VPN.systemextension"
55+
BlueprintName = "VPN"
6356
ReferencedContainer = "container:Coder Desktop.xcodeproj">
6457
</BuildableReference>
6558
</MacroExpansion>

Coder Desktop/Coder Desktop.xctestplan

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
{
2020
"target" : {
2121
"containerPath" : "container:Coder Desktop.xcodeproj",
22-
"identifier" : "961679D82D030E1D00B2B6DF",
23-
"name" : "ProtoTests"
22+
"identifier" : "9616790E2CFF100E00B2B6DF",
23+
"name" : "Coder DesktopTests"
2424
}
2525
},
2626
{
2727
"target" : {
2828
"containerPath" : "container:Coder Desktop.xcodeproj",
29-
"identifier" : "9616790E2CFF100E00B2B6DF",
30-
"name" : "Coder DesktopTests"
29+
"identifier" : "AA3B3DA72D2D23860099996A",
30+
"name" : "VPNLibTests"
3131
}
3232
},
3333
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>com.apple.developer.networking.networkextension</key>
6+
<array>
7+
<string>packet-tunnel-provider</string>
8+
</array>
9+
<key>com.apple.security.app-sandbox</key>
10+
<true/>
11+
<key>com.apple.security.files.user-selected.read-only</key>
12+
<true/>
13+
<key>com.apple.security.network.client</key>
14+
<true/>
15+
</dict>
16+
</plist>

Coder Desktop/Coder Desktop/Coder_Desktop.entitlements

+2
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@
1212
<true/>
1313
<key>com.apple.security.network.client</key>
1414
<true/>
15+
<key>com.apple.security.network.server</key>
16+
<true/>
1517
</dict>
1618
</plist>

Coder Desktop/Coder Desktop/SDK/Client.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Alamofire
22
import Foundation
33

4-
protocol Client {
4+
protocol Client: Sendable {
55
init(url: URL, token: String?)
66
func user(_ ident: String) async throws(ClientError) -> User
77
}
@@ -114,10 +114,10 @@ struct APIError: Decodable {
114114
struct Response: Decodable {
115115
let message: String
116116
let detail: String?
117-
let validations: [ValidationError]?
117+
let validations: [FieldValidation]?
118118
}
119119

120-
struct ValidationError: Decodable {
120+
struct FieldValidation: Decodable {
121121
let field: String
122122
let detail: String
123123
}

Coder Desktop/VPN/Manager.swift

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import NetworkExtension
2+
import os
3+
import VPNLib
4+
5+
actor Manager {
6+
let ptp: PacketTunnelProvider
7+
let downloader: Downloader
8+
9+
var tunnelHandle: TunnelHandle? = nil
10+
var speaker: Speaker<Vpn_TunnelMessage, Vpn_ManagerMessage>? = nil
11+
// TODO: XPC Speaker
12+
13+
private let dest = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
14+
.first!.appending(path: "coder-vpn.dylib")
15+
16+
init(with: PacketTunnelProvider) {
17+
ptp = with
18+
self.downloader = Downloader()
19+
}
20+
}

Coder Desktop/VPN/PacketTunnelProvider.swift

+54-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,62 @@
11
import NetworkExtension
2+
import os
23

3-
class PacketTunnelProvider: NEPacketTunnelProvider {
4-
override func startTunnel(options _: [String: NSObject]?, completionHandler _: @escaping (Error?) -> Void) {
5-
// Add code here to start the process of connecting the tunnel.
4+
/* From <sys/kern_control.h> */
5+
let CTLIOCGINFO: UInt = 0xC064_4E03
6+
7+
class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
8+
private let logger = Logger(subsystem: "com.coder.Coder.CoderPacketTunnelProvider", category: "network-extension")
9+
private var manager: Manager?
10+
11+
private var tunnelFileDescriptor: Int32? {
12+
var ctlInfo = ctl_info()
13+
withUnsafeMutablePointer(to: &ctlInfo.ctl_name) {
14+
$0.withMemoryRebound(to: CChar.self, capacity: MemoryLayout.size(ofValue: $0.pointee)) {
15+
_ = strcpy($0, "com.apple.net.utun_control")
16+
}
17+
}
18+
for fd: Int32 in 0 ... 1024 {
19+
var addr = sockaddr_ctl()
20+
var ret: Int32 = -1
21+
var len = socklen_t(MemoryLayout.size(ofValue: addr))
22+
withUnsafeMutablePointer(to: &addr) {
23+
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
24+
ret = getpeername(fd, $0, &len)
25+
}
26+
}
27+
if ret != 0 || addr.sc_family != AF_SYSTEM {
28+
continue
29+
}
30+
if ctlInfo.ctl_id == 0 {
31+
ret = ioctl(fd, CTLIOCGINFO, &ctlInfo)
32+
if ret != 0 {
33+
continue
34+
}
35+
}
36+
if addr.sc_id == ctlInfo.ctl_id {
37+
return fd
38+
}
39+
}
40+
return nil
41+
}
42+
43+
override func startTunnel(options _: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
44+
guard manager == nil else {
45+
logger.error("startTunnel called with non-nil Manager")
46+
completionHandler(nil)
47+
return
48+
}
49+
manager = Manager(with: self)
50+
completionHandler(nil)
651
}
752

853
override func stopTunnel(with _: NEProviderStopReason, completionHandler: @escaping () -> Void) {
9-
// Add code here to start the process of stopping the tunnel.
54+
guard manager == nil else {
55+
logger.error("stopTunnel called with nil Manager")
56+
completionHandler()
57+
return
58+
}
59+
manager = nil
1060
completionHandler()
1161
}
1262

Coder Desktop/VPN/TunnelHandle.swift

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import Foundation
2+
import os
3+
4+
let startSymbol = "OpenTunnel"
5+
6+
actor TunnelHandle {
7+
private let logger = Logger(subsystem: "com.coder.Coder.CoderPacketTunnelProvider", category: "tunnel-handle")
8+
9+
private var openTunnelFn: OpenTunnel!
10+
private var tunnelPipe: Pipe!
11+
private var dylibHandle: UnsafeMutableRawPointer!
12+
13+
init(dylibPath: URL) throws(TunnelHandleError) {
14+
dylibHandle = dlopen(dylibPath.path, RTLD_NOW | RTLD_LOCAL)
15+
16+
guard dylibHandle != nil else {
17+
var errStr = "UNKNOWN"
18+
let e = dlerror()
19+
if e != nil {
20+
errStr = String(cString: e!)
21+
}
22+
throw TunnelHandleError.dylib(errStr)
23+
}
24+
25+
let startSym = dlsym(dylibHandle, startSymbol)
26+
guard startSym != nil else {
27+
var errStr = "UNKNOWN"
28+
let e = dlerror()
29+
if e != nil {
30+
errStr = String(cString: e!)
31+
}
32+
throw TunnelHandleError.symbol(startSymbol, errStr)
33+
}
34+
openTunnelFn = unsafeBitCast(startSym, to: OpenTunnel.self)
35+
tunnelPipe = Pipe()
36+
let res = openTunnelFn(tunnelPipe.fileHandleForReading.fileDescriptor,
37+
tunnelPipe.fileHandleForWriting.fileDescriptor)
38+
guard res == 0 else {
39+
throw TunnelHandleError.openTunnel(OpenTunnelError(rawValue: res) ?? .unknown)
40+
}
41+
}
42+
43+
func close() throws {
44+
dlclose(dylibHandle)
45+
}
46+
}
47+
48+
enum TunnelHandleError: Error {
49+
case dylib(String)
50+
case symbol(String, String)
51+
case openTunnel(OpenTunnelError)
52+
53+
var description: String {
54+
switch self {
55+
case let .dylib(d): return d
56+
case let .symbol(symbol, message): return "\(symbol): \(message)"
57+
case let .openTunnel(error): return "OpenTunnel: \(error.message)"
58+
}
59+
}
60+
}
61+
62+
enum OpenTunnelError: Int32 {
63+
case errDupReadFD = -2
64+
case errDupWriteFD = -3
65+
case errOpenPipe = -4
66+
case errNewTunnel = -5
67+
case unknown = -99
68+
69+
var message: String {
70+
switch self {
71+
case .errDupReadFD: return "Failed to duplicate read file descriptor"
72+
case .errDupWriteFD: return "Failed to duplicate write file descriptor"
73+
case .errOpenPipe: return "Failed to open the pipe"
74+
case .errNewTunnel: return "Failed to create a new tunnel"
75+
case .unknown: return "Unknown error code"
76+
}
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef CoderPacketTunnelProvider_Bridging_Header_h
2+
#define CoderPacketTunnelProvider_Bridging_Header_h
3+
4+
// GoInt32 OpenTunnel(GoInt32 cReadFD, GoInt32 cWriteFD);
5+
typedef int(*OpenTunnel)(int, int);
6+
7+
#endif /* CoderPacketTunnelProvider_Bridging_Header_h */

0 commit comments

Comments
 (0)