Skip to content

chore: add dylib downloader and validator #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
381 changes: 305 additions & 76 deletions Coder Desktop/Coder Desktop.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "aa8dd97dc6e28dedc4a5c45c435467a247486474bf3c1caf5e67085d52325132",
"originHash" : "0dee63153808d20a73f823faee354b1c4e55e5f9258a2831fa6074ed154cd0bc",
"pins" : [
{
"identity" : "alamofire",
Expand Down Expand Up @@ -36,6 +36,15 @@
"version" : "1.28.2"
}
},
{
"identity" : "swifter",
"kind" : "remoteSourceControl",
"location" : "https://github.com/httpswift/swifter",
"state" : {
"revision" : "9483a5d459b45c3ffd059f7b55f9638e268632fd",
"version" : "1.5.0"
}
},
{
"identity" : "swiftlintplugins",
"kind" : "remoteSourceControl",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,20 @@
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "961679D82D030E1D00B2B6DF"
BuildableName = "ProtoTests.xctest"
BlueprintName = "ProtoTests"
BlueprintIdentifier = "AA3B3DA02D2D23860099996A"
BuildableName = "VPNLib.framework"
BlueprintName = "VPNLib"
ReferencedContainer = "container:Coder Desktop.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AA3B3DA72D2D23860099996A"
BuildableName = "VPNLibTests.xctest"
BlueprintName = "VPNLibTests"
ReferencedContainer = "container:Coder Desktop.xcodeproj">
</BuildableReference>
</TestableReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,29 @@
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "9616792F2CFF117300B2B6DF"
BuildableName = "com.coder.Coder-Desktop.VPN.systemextension"
BlueprintName = "VPN"
ReferencedContainer = "container:Coder Desktop.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "961679D82D030E1D00B2B6DF"
BuildableName = "ProtoTests.xctest"
BlueprintName = "ProtoTests"
ReferencedContainer = "container:Coder Desktop.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
Expand All @@ -37,16 +40,6 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "961678FB2CFF100D00B2B6DF"
BuildableName = "Coder Desktop.app"
BlueprintName = "Coder Desktop"
ReferencedContainer = "container:Coder Desktop.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
Expand All @@ -57,9 +50,9 @@
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "961678FB2CFF100D00B2B6DF"
BuildableName = "Coder Desktop.app"
BlueprintName = "Coder Desktop"
BlueprintIdentifier = "9616792F2CFF117300B2B6DF"
BuildableName = "com.coder.Coder-Desktop.VPN.systemextension"
BlueprintName = "VPN"
ReferencedContainer = "container:Coder Desktop.xcodeproj">
</BuildableReference>
</MacroExpansion>
Expand Down
8 changes: 4 additions & 4 deletions Coder Desktop/Coder Desktop.xctestplan
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
{
"target" : {
"containerPath" : "container:Coder Desktop.xcodeproj",
"identifier" : "961679D82D030E1D00B2B6DF",
"name" : "ProtoTests"
"identifier" : "9616790E2CFF100E00B2B6DF",
"name" : "Coder DesktopTests"
}
},
{
"target" : {
"containerPath" : "container:Coder Desktop.xcodeproj",
"identifier" : "9616790E2CFF100E00B2B6DF",
"name" : "Coder DesktopTests"
"identifier" : "AA3B3DA72D2D23860099996A",
"name" : "VPNLibTests"
}
},
{
Expand Down
16 changes: 16 additions & 0 deletions Coder Desktop/Coder Desktop/Coder DesktopRelease.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!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.developer.networking.networkextension</key>
<array>
<string>packet-tunnel-provider</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
</dict>
</plist>
2 changes: 2 additions & 0 deletions Coder Desktop/Coder Desktop/Coder_Desktop.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>
6 changes: 3 additions & 3 deletions Coder Desktop/Coder Desktop/SDK/Client.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Alamofire
import Foundation

protocol Client {
protocol Client: Sendable {
init(url: URL, token: String?)
func user(_ ident: String) async throws(ClientError) -> User
}
Expand Down Expand Up @@ -114,10 +114,10 @@ struct APIError: Decodable {
struct Response: Decodable {
let message: String
let detail: String?
let validations: [ValidationError]?
let validations: [FieldValidation]?
}

struct ValidationError: Decodable {
struct FieldValidation: Decodable {
let field: String
let detail: String
}
Expand Down
20 changes: 20 additions & 0 deletions Coder Desktop/VPN/Manager.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import NetworkExtension
import os
import VPNLib

actor Manager {
let ptp: PacketTunnelProvider
let downloader: Downloader

var tunnelHandle: TunnelHandle?
var speaker: Speaker<Vpn_TunnelMessage, Vpn_ManagerMessage>?
// TODO: XPC Speaker

private let dest = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
.first!.appending(path: "coder-vpn.dylib")

init(with: PacketTunnelProvider) {
ptp = with
downloader = Downloader()
}
}
58 changes: 54 additions & 4 deletions Coder Desktop/VPN/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,62 @@
import NetworkExtension
import os

class PacketTunnelProvider: NEPacketTunnelProvider {
override func startTunnel(options _: [String: NSObject]?, completionHandler _: @escaping (Error?) -> Void) {
// Add code here to start the process of connecting the tunnel.
/* From <sys/kern_control.h> */
let CTLIOCGINFO: UInt = 0xC064_4E03

class PacketTunnelProvider: NEPacketTunnelProvider, @unchecked Sendable {
private let logger = Logger(subsystem: "com.coder.Coder.CoderPacketTunnelProvider", category: "network-extension")
private var manager: Manager?

private var tunnelFileDescriptor: Int32? {
var ctlInfo = ctl_info()
withUnsafeMutablePointer(to: &ctlInfo.ctl_name) {
$0.withMemoryRebound(to: CChar.self, capacity: MemoryLayout.size(ofValue: $0.pointee)) {
_ = strcpy($0, "com.apple.net.utun_control")
}
}
for fd: Int32 in 0 ... 1024 {
var addr = sockaddr_ctl()
var ret: Int32 = -1
var len = socklen_t(MemoryLayout.size(ofValue: addr))
withUnsafeMutablePointer(to: &addr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
ret = getpeername(fd, $0, &len)
}
}
if ret != 0 || addr.sc_family != AF_SYSTEM {
continue
}
if ctlInfo.ctl_id == 0 {
ret = ioctl(fd, CTLIOCGINFO, &ctlInfo)
if ret != 0 {
continue
}
}
if addr.sc_id == ctlInfo.ctl_id {
return fd
}
}
return nil
}

override func startTunnel(options _: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
guard manager == nil else {
logger.error("startTunnel called with non-nil Manager")
completionHandler(nil)
return
}
manager = Manager(with: self)
completionHandler(nil)
}

override func stopTunnel(with _: NEProviderStopReason, completionHandler: @escaping () -> Void) {
// Add code here to start the process of stopping the tunnel.
guard manager == nil else {
logger.error("stopTunnel called with nil Manager")
completionHandler()
return
}
manager = nil
completionHandler()
}

Expand Down
78 changes: 78 additions & 0 deletions Coder Desktop/VPN/TunnelHandle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import Foundation
import os

let startSymbol = "OpenTunnel"

actor TunnelHandle {
private let logger = Logger(subsystem: "com.coder.Coder.CoderPacketTunnelProvider", category: "tunnel-handle")

private var openTunnelFn: OpenTunnel!
private var tunnelPipe: Pipe!
private var dylibHandle: UnsafeMutableRawPointer!

init(dylibPath: URL) throws(TunnelHandleError) {
dylibHandle = dlopen(dylibPath.path, RTLD_NOW | RTLD_LOCAL)

guard dylibHandle != nil else {
var errStr = "UNKNOWN"
let e = dlerror()
if e != nil {
errStr = String(cString: e!)
}
throw TunnelHandleError.dylib(errStr)
}

let startSym = dlsym(dylibHandle, startSymbol)
guard startSym != nil else {
var errStr = "UNKNOWN"
let e = dlerror()
if e != nil {
errStr = String(cString: e!)
}
throw TunnelHandleError.symbol(startSymbol, errStr)
}
openTunnelFn = unsafeBitCast(startSym, to: OpenTunnel.self)
tunnelPipe = Pipe()
let res = openTunnelFn(tunnelPipe.fileHandleForReading.fileDescriptor,
tunnelPipe.fileHandleForWriting.fileDescriptor)
guard res == 0 else {
throw TunnelHandleError.openTunnel(OpenTunnelError(rawValue: res) ?? .unknown)
}
}

func close() throws {
dlclose(dylibHandle)
}
}

enum TunnelHandleError: Error {
case dylib(String)
case symbol(String, String)
case openTunnel(OpenTunnelError)

var description: String {
switch self {
case let .dylib(d): return d
case let .symbol(symbol, message): return "\(symbol): \(message)"
case let .openTunnel(error): return "OpenTunnel: \(error.message)"
}
}
}

enum OpenTunnelError: Int32 {
case errDupReadFD = -2
case errDupWriteFD = -3
case errOpenPipe = -4
case errNewTunnel = -5
case unknown = -99

var message: String {
switch self {
case .errDupReadFD: return "Failed to duplicate read file descriptor"
case .errDupWriteFD: return "Failed to duplicate write file descriptor"
case .errOpenPipe: return "Failed to open the pipe"
case .errNewTunnel: return "Failed to create a new tunnel"
case .unknown: return "Unknown error code"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef CoderPacketTunnelProvider_Bridging_Header_h
#define CoderPacketTunnelProvider_Bridging_Header_h

// GoInt32 OpenTunnel(GoInt32 cReadFD, GoInt32 cWriteFD);
typedef int(*OpenTunnel)(int, int);

#endif /* CoderPacketTunnelProvider_Bridging_Header_h */
Loading