I'm porting an Android device's VPN App to iOS (using NEPacketTunnelProvider).
Android provides a mechanism to bypass VPN for some tcp/udp connections, using the following API:
class VpnService {
// ...
public boolean protect(int socket) { /* ... */ }
I don't see equivalent API in iOS. How do I implement something equivalent for iOS?
Coming from Android and knowing nothing of Apple API (except Swift and ObjC++ languages), I will try to point out what a normal developer would like to know.
An iOS App's life ends the moment the views are closed, hence a permanent VPN-Service is ONLY possible in an extension, which is a completely different target than that of your views (because iOS has no Service concept).
In addition to knowing above, learn the fact that any connection (aka Socket) created from within your extension is magically excluded (aka protected) from going through packetFlow (aka Tunnel), no matter if it's a Raw-socket made by C/C++ or OOP-Wrapped class in Swift5.
Surprisingly enough, actually making your extension's socket go through tunnel is much harder,
and you would need to use NEPacketTunnelProvider class's methods:
- createTCPConnectionThroughTunnelToEndpoint:enableTLS:TLSParameters:delegate:
- createUDPSessionThroughTunnelToEndpoint:fromEndpoint:
Note that above are instance methods, which is what minus sign in ObjC means,
so only available in extension context (but there is no escaping from the tunnel for App-targets anyway).
See also: https://developer.apple.com/forums/thread/94430
Related
I'm developing a framework for iOS apps that allows interfacing with custom BLE devices made by my company. We're planning to distribute the framework binary with public headers to clients. I've already designed the client facing interface, but it's lacking a major feature: notification on various different status conditions. That is, when the framework starts scanning for devices, connects to a device, reads data, uploads to our backend, etc, there is currently no way for client apps to know.
This has been fine for local testing, but before releasing, it would be best to add some functionality to allow clients to build a UI that updates based on these various status conditions. I'm not entirely sure of what the current, best way to do this is. I'm aware I can create an NSNotificationCenter and post notifications for each of these status changes, but I'm not sure if there is some better way of doing this? Should I accept a user callback? Expose some sort of listener protocol and ability register listeners? I'm sure others have solved this problem before, what have you found works well for iOS?
Use NSNotificationCenter for one to many communication, it notifies all the objects, which register to event, without knowing who throws it.
Use protocol and delegates for one to one object communication.
As per my experience you should go with delegates, it will be clean implementation and you can also define optional and required protocol.The the global class on client side can use this delegates, and update.
Let's say I want to build a SDK that communicates with a server. I don't want any one (not even the app that implements the SDK) to intercept and look at my requests/responses.
If I'd use a common lib like AFNetworking it would be possible to look at all requests i.e by registering a NSURLProtocol.
I'm assuming that this would be harder to do if I would use i.e CFNetworking to perform my request/response handling? Or am I missing something? Would it be possible to intercept that traffic as well?
Using non NSURLConnection based classes, especially C low level classes (because NSIn/OutStream can be swizzled) like CFNetwork's CFStream, would make life harder for a potential curious developer. However, it will never stop a determined one. Your framework could, for example, be decompiled, although that's not a trivial task, which means many will quit even before starting, if the information is not worthwhile.
I wonder if I have remote iOS device, with any custom solution I can preload on it (written myself), is there a way to make it execute any custom code, like a block?
Here is what I mean:
// establish connection with remote device
[self connectToDevice:remoteDevice];
// send arbitary block of code and data to execute on remote device
[myDevice executeBlock:^(void)(BOOL result, NSData *data) {
// here I can write any code that uses the data
// I want this code to run on remote machine
}];
// I might get results via network, or any other way, not related
I do not mean run any malicious code, or my program, or something like that. I mean that I have my program already running and waiting for task to execute.
The problems I might see - Objective-c is compiled language, so having code sent does not help.
Is it possible to use some scripting language or solution to overcome this?
In a word, no. Apple's terms of service forbid you from executing code you receive over the network.
Plus, Objective C is compiled and needs to be linked into your project. There is no facility for installing dynamically linked libraries at runtime in iOS.
You might be able to figure out a way to deliver dynamically linked libraries on a jailbroken device, but that's out of the scope of this board.
There is a piece of code that does DNS lookups using CFHostStartInfoResolution(). However this is synchronously and thus blocks anything before it returns - it's bad and I also think it causes crashes due to timeouts when connection is weak (when its bad it fails out safely directly)
So I want to do this asynchronously, as it's supposed to in the docs https://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFHostRef/Reference/reference.html
New docs URL 20190227: https://developer.apple.com/documentation/cfnetwork/cfhostref
Specifically it says:
If you want to resolve the host asynchronously. call CFHostSetClient
to associate your client context and user-defined callback function
with the host. Then call CFHostScheduleWithRunLoop to schedule the
host on a run loop.
However this put me off because I haven't coded C in ages and can't get callbacks and runloops/threading right.
How am I supposed to call CFHostSetClient, CFHostScheduleWithRunLoop, and how do I implement those callbacks? Do I need to start a new thread?
Actually CFHost has a bug since on macOS since 10.7. Up to 10.7 it was possible to cancel a synchronous lookup calling CFHostCancelInfoResolution() on a second thread but since 10.7 this is not possible any longer (it just won't cancel the lookup). I reported that to Apple in 2013 (bug number is 13672880) but despite confirming it, Apple has never fixed it up to today.
Yet the more interesting part was what Apple suggested in their reply:
The best API for host name resolution is DNSServiceGetAddrInfo
and that's asynchronous and cancelable.
This API is documented to exist on macOS since 10.11.4, on iOS since 9.3, on tvOS since 9.2 and on watchOS since 2.2 - yet I think this cannot be correct, it must have existed, otherwise how could Apple recommend it in 2013 (10.11 was released 2015). I can confirm that this API also existed on iOS 8 and on macOS 10.9 and probably even earlier on both systems.
This API is internally using an undocumented asynchronous version of the otherwise synchronous C call getaddrinfo() which is found on all POSIX like systems today.
One advantage over other APIs is that you can choose if you only want to retrieve IPv4, IPv6, or both kind of addresses or you can let the system decide to pick the address family for you, depending on which addresses the system considers reachable at the moment (this is the default for most other resolving APIs).
Also in case a system has multiple active network interfaces (e.g. cable + WiFi or WiFi + mobile), you can pick the interface to use as different DNS settings may be set on different interfaces (and different DNS servers can deliver different results for the same domain name). If you don't pick one, the system will always use the current default server (this is the default for most other resolving APIs).
Should be something like this
CFHostSetClient(host, callbackFunction, hostContext);
CFHostScheduleWithRunLoop(host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFHostStartInfoResolution(host, kCFHostAddresses, 0);
And callbackFunction
void callbackFunction(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, void *info) {
// Do something
}
You don't need to start a new thread, system will do it for you.
I am learning C and Objective-C so am still dependent on examples...
I found AsyncUDPSocket which has a lot of example code in the Google Code repository, but I'm not far enough along to understand it all yet.
I'm trying to build an iPhone app that uses UDP for communication to another device (Arduino). I have the device end working (testing with the UDP Tool app). I just need help with the iOS side of it...
An example with more explanation would really help (that is, a tutorial)... Is there one or what would some example code with good comments be?
https://github.com/robbiehanson/CocoaAsyncSocket
GCDAsyncUdpSocket and AsyncUdpSocket are UDP/IP socket networking libraries. Here are the key features available in both:
Native objective-c, fully self-contained in one class. No need to
muck around with low-level sockets. This class handles everything for
you.
Full delegate support.
Errors, send completions, receive completions, and disconnections all result in a call to your delegate method.
Queued non-blocking send and receive operations, with optional
timeouts.
You tell it what to send or receive, and it handles everything for you. Queueing, buffering, waiting and checking errno - all
handled for you automatically.
Support for IPv4 and IPv6.
Automatically send/recv using IPv4 and/or IPv6. No more worrying about multiple sockets.