From efe177605eefae82aca8e097c17bf2bc29794cee Mon Sep 17 00:00:00 2001 From: Jeroen Leenarts Date: Fri, 3 Aug 2018 22:24:41 +0200 Subject: [PATCH] Finish trampoline code. Signed-off-by: Jason A. Donenfeld --- .../PacketTunnelProvider.swift | 61 ++++++++++--------- .../WireGuardGoWrapper.h | 5 +- .../WireGuardGoWrapper.m | 48 ++++++++++++--- ...ireGuardNetworkExtension-Bridging-Header.h | 1 + wireguard-go-bridge/wireguard.h | 2 +- 5 files changed, 79 insertions(+), 38 deletions(-) diff --git a/WireGuardNetworkExtension/PacketTunnelProvider.swift b/WireGuardNetworkExtension/PacketTunnelProvider.swift index f5ba60a..4b282ac 100644 --- a/WireGuardNetworkExtension/PacketTunnelProvider.swift +++ b/WireGuardNetworkExtension/PacketTunnelProvider.swift @@ -9,54 +9,57 @@ import NetworkExtension import os.log +enum PacketTunnelProviderError: Error { + case tunnelSetupFailed +} + +/// A packet tunnel provider object. class PacketTunnelProvider: NEPacketTunnelProvider { + + // MARK: Properties + + /// A reference to the WireGuard wrapper object. let wireGuardWrapper = WireGuardGoWrapper() - private let tunnelQueue = DispatchQueue(label: PacketTunnelProvider.description()) + /// The completion handler to call when the tunnel is fully established. + var pendingStartCompletion: ((Error?) -> Void)? - //TODO create a way to transfer config into extension + /// The completion handler to call when the tunnel is fully disconnected. + var pendingStopCompletion: (() -> Void)? + // MARK: NEPacketTunnelProvider + + /// Begin the process of establishing the tunnel. override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) { os_log("Starting tunnel", log: Log.general, type: .info) - // Add code here to start the process of connecting the tunnel. - //TODO get a settings string in here. - tunnelQueue.sync { - wireGuardWrapper.turnOn(withInterfaceName: "TODO", settingsString: "TODO") + //TODO tunnel settings + if wireGuardWrapper.turnOn(withInterfaceName: "test", settingsString: "") { + // Success + completionHandler(nil) + } else { + completionHandler(PacketTunnelProviderError.tunnelSetupFailed) } } + /// Begin the process of stopping the tunnel. override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) { os_log("Stopping tunnel", log: Log.general, type: .info) - // Add code here to start the process of stopping the tunnel. - tunnelQueue.sync { - wireGuardWrapper.turnOff() - } + + wireGuardWrapper.turnOff() completionHandler() } + /// Handle IPC messages from the app. override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) { - // Add code here to handle the message. - if let handler = completionHandler { - handler(messageData) + guard let messageString = NSString(data: messageData, encoding: String.Encoding.utf8.rawValue) else { + completionHandler?(nil) + return } - } - private func loopReadPackets(_ handler: @escaping ([Data]?, Error?) -> Void) { - packetFlow.readPackets { [weak self] (_, _) in - // TODO write packets into the tunnel - self?.loopReadPackets(handler) - } - } + os_log("Got a message from the app: %s", log: Log.general, type: .info, messageString) - func writePacket(_ packet: Data, completionHandler: ((Error?) -> Void)?) { - packetFlow.writePackets([packet], withProtocols: [AF_INET] as [NSNumber]) - completionHandler?(nil) - } - - func writePackets(_ packets: [Data], completionHandler: ((Error?) -> Void)?) { - let protocols = [Int32](repeating: AF_INET, count: packets.count) as [NSNumber] - packetFlow.writePackets(packets, withProtocols: protocols) - completionHandler?(nil) + let responseData = "Hello app".data(using: String.Encoding.utf8) + completionHandler?(responseData) } } diff --git a/WireGuardNetworkExtension/WireGuardGoWrapper.h b/WireGuardNetworkExtension/WireGuardGoWrapper.h index 51a88bd..b9038b4 100644 --- a/WireGuardNetworkExtension/WireGuardGoWrapper.h +++ b/WireGuardNetworkExtension/WireGuardGoWrapper.h @@ -7,10 +7,13 @@ // #import +#import @interface WireGuardGoWrapper : NSObject -- (void) turnOnWithInterfaceName: (NSString *)interfaceName settingsString: (NSString *)settingsString; +@property (nonatomic, weak) NEPacketTunnelFlow *packetFlow; + +- (BOOL) turnOnWithInterfaceName: (NSString *)interfaceName settingsString: (NSString *)settingsString; - (void) turnOff; @end diff --git a/WireGuardNetworkExtension/WireGuardGoWrapper.m b/WireGuardNetworkExtension/WireGuardGoWrapper.m index f15e34e..a24a239 100644 --- a/WireGuardNetworkExtension/WireGuardGoWrapper.m +++ b/WireGuardNetworkExtension/WireGuardGoWrapper.m @@ -6,10 +6,10 @@ // Copyright © 2018 Jason A. Donenfeld . All rights reserved. // -#import "WireGuardGoWrapper.h" - #include + #include "wireguard.h" +#import "WireGuardGoWrapper.h" /// Trampoline function static ssize_t do_read(const void *ctx, const unsigned char *buf, size_t len); @@ -24,12 +24,25 @@ static void do_log(int level, const char *tag, const char *msg); @property (nonatomic, assign) int handle; @property (nonatomic, assign) BOOL isClosed; +@property (nonatomic, strong) NSMutableArray *packets; +@property (nonatomic, strong) NSMutableArray *protocols; + +@property (nonatomic, strong) NSCondition *condition; @end @implementation WireGuardGoWrapper -- (void) turnOnWithInterfaceName: (NSString *)interfaceName settingsString: (NSString *)settingsString +- (instancetype)init +{ + self = [super init]; + if (self) { + self.condition = [NSCondition new]; + } + return self; +} + +- (BOOL) turnOnWithInterfaceName: (NSString *)interfaceName settingsString: (NSString *)settingsString { wgSetLogger(do_log); @@ -38,6 +51,8 @@ static void do_log(int level, const char *tag, const char *msg); const char * settings = [settingsString UTF8String]; self.handle = wgTurnOn((gostring_t){ .p = ifName, .n = interfaceName.length }, (gostring_t){ .p = settings, .n = settingsString.length }, do_read, do_write, (__bridge void *)(self)); + + return self.handle > 0; } - (void) turnOff @@ -61,16 +76,35 @@ static void do_log(int level, const char *tag, const char *msg); static ssize_t do_read(const void *ctx, const unsigned char *buf, size_t len) { WireGuardGoWrapper *wrapper = (__bridge WireGuardGoWrapper *)ctx; - printf("Reading from instance with ctx %p into buffer %p of length %zu\n", ctx, buf, len); - sleep(1); - // TODO received data from tunnel, write to Packetflow + if (wrapper.packets.count == 0) { + + [wrapper.packetFlow readPacketsWithCompletionHandler:^(NSArray * _Nonnull packets, NSArray * _Nonnull protocols) { + [wrapper.packets addObjectsFromArray:packets]; + [wrapper.protocols addObjectsFromArray:protocols]; + // TODO make sure that the completion handler and the do_read are not performed on the same thread. + [wrapper.condition signal]; + }]; + [wrapper.condition wait]; + } + + NSData *packet = [wrapper.packets objectAtIndex:0]; +// NSNumber *protocol = [wrapper.protocols objectAtIndex:0]; + [wrapper.packets removeObjectAtIndex:0]; + [wrapper.protocols removeObjectAtIndex:0]; + + len = [packet length]; + buf = (Byte*)malloc(len); + memcpy(buf, [packet bytes], len); + return wrapper.isClosed ? -1 : 0; } static ssize_t do_write(const void *ctx, const unsigned char *buf, size_t len) { WireGuardGoWrapper *wrapper = (__bridge WireGuardGoWrapper *)ctx; - printf("Writing from instance with ctx %p into buffer %p of length %zu\n", ctx, buf, len); + //TODO: determine IPv4 or IPv6 status. + NSData *packet = [[NSData alloc] initWithBytes:buf length:len]; + [wrapper.packetFlow writePackets:@[packet] withProtocols:@[@AF_INET]]; return len; } diff --git a/WireGuardNetworkExtension/WireGuardNetworkExtension-Bridging-Header.h b/WireGuardNetworkExtension/WireGuardNetworkExtension-Bridging-Header.h index cfbb258..c677810 100644 --- a/WireGuardNetworkExtension/WireGuardNetworkExtension-Bridging-Header.h +++ b/WireGuardNetworkExtension/WireGuardNetworkExtension-Bridging-Header.h @@ -3,3 +3,4 @@ // #import "WireGuardGoWrapper.h" +#include "wireguard.h" diff --git a/wireguard-go-bridge/wireguard.h b/wireguard-go-bridge/wireguard.h index 483d564..d009f72 100644 --- a/wireguard-go-bridge/wireguard.h +++ b/wireguard-go-bridge/wireguard.h @@ -14,6 +14,6 @@ typedef void(*logger_fn_t)(int level, const char *tag, const char *msg); extern void wgSetLogger(logger_fn_t logger_fn); extern int wgTurnOn(gostring_t ifname, gostring_t settings, read_write_fn_t read_fn, read_write_fn_t write_fn, void *ctx); extern void wgTurnOff(int handle); -extern char *wgVersion(); +extern char *wgVersion(void); #endif