|
|
This report describes the research carried out by the OuiSync and Briar teams to explore the opportunities for peer-to-peer and device-to-device communication on iOS, including communication between iOS and other platforms.
|
|
|
|
|
|
Most of the information is based on Apple's developer documentation, with some input from experienced iOS developers.
|
|
|
|
|
|
On Android we've found that there are often differences between what's possible according to the documentation and what's possible on real devices.
|
|
|
Apple is a single vendor controlling both hardware and software, so the gap between documentation and reality may be smaller on iOS than on Android, but we don't have enough experience with iOS to confirm this.
|
|
|
|
|
|
## Push Notifications
|
|
|
|
|
|
Communication apps on iOS typically use *push notifications* to wake the app and notify the user when new content is available.
|
|
|
|
|
|
### Architecture
|
|
|
|
|
|
The iOS push notification architecture includes two centralised components: the Apple Push Notification service (APNs), which is operated by Apple, and the *provider server*, which is operated by the app publisher.
|
|
|
|
|
|
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server
|
|
|
|
|
|
Before an app running on a device can receive push notifications, the app must contact APNs and receive a *device token*.
|
|
|
The app uploads this token to the provider server, which can later present it to APNs when sending a push notification to the device.
|
|
|
This enables APNs to verify that the device has asked to receive notifications from the app publisher.
|
|
|
|
|
|
https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns
|
|
|
|
|
|
When the provider server wants to send a notification to a device, it sends a request to APNs.
|
|
|
This request must be authenticated to prove that the request comes from the app publisher, and it must include the device token to prove that the device has asked to receive notifications from the app publisher.
|
|
|
|
|
|
The provider server can authenticate itself to APNs using either a certificate issued to the app publisher by Apple, or a short-lived token generated using an authentication key issued to the app publisher by Apple.
|
|
|
|
|
|
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns
|
|
|
|
|
|
### Centralisation
|
|
|
|
|
|
The requirement for the provider server to authenticate itself to APNs using credentials issued by Apple means that the provider server must be a logically centralised entity controlled by the app publisher.
|
|
|
APNs itself is of course a logically centralised entity controlled by Apple.
|
|
|
|
|
|
Even if the app uses a P2P or federated network for all of its other communication, its push notifications must flow through these two centralised entities.
|
|
|
See, for example, the notification architecture used by Matrix, in which federated homeservers send notifications through a centralised push gateway operated by the app publisher:
|
|
|
|
|
|
https://spec.matrix.org/v1.1/push-gateway-api/
|
|
|
|
|
|
### Metadata Exposure
|
|
|
|
|
|
If push notifications are used in the typical way to wake the app when a new message is available, then the app publisher (via the provider server) and Apple (via APNs) are both in a position to see which devices are receiving messages at which times, which is a form of metadata exposure.
|
|
|
|
|
|
If the sender authenticates themselves to the provider server (or to another server controlled by the app publisher) when taking the action that triggers the notification (eg uploading a message), then the app publisher can identify both the sender and recipient of the message, which is a much stronger form of metadata exposure.
|
|
|
|
|
|
The push notification architecture does not require the sender's identity to be exposed to APNs.
|
|
|
|
|
|
### Mitigations
|
|
|
|
|
|
In a federated communication system, it may be possible to mitigate the centralisation of the push notification architecture by allowing the servers of the federated communication system to act as provider servers.
|
|
|
|
|
|
Each federated server would be responsible for delivering push notifications to its own users.
|
|
|
A device would upload its device token to its own federated server, rather than to a central server operated by the app publisher.
|
|
|
|
|
|
When a federated server wanted to send a push notification, it would authenticate itself to APNs using a short-lived token issued by a centralised *token server* operated by the app publisher.
|
|
|
The token server would generate these tokens using an authentication key obtained from Apple in the usual way, but would then issue the tokens to the federated servers rather than using them itself.
|
|
|
|
|
|
In this design, the token server would still be a centralised entity.
|
|
|
It would be responsible for deciding which federated servers were authorised to send push notifications, and for issuing fresh tokens to those servers.
|
|
|
Any federated servers that were no longer authorised by the token server to send push notifications would stop being able to send notifications when their tokens expired (APNs authentication tokens expire after one hour).
|
|
|
|
|
|
Due to the need for each APNs request to include a device token, each federated server would only be able to send notifications to its own users.
|
|
|
This would limit the damage that could be done by a misbehaving federated server.
|
|
|
|
|
|
The token server would not handle device tokens, and would not see any metadata other than the identities of the federated servers.
|
|
|
|
|
|
This approach might not scale to a large and fast-changing population of federated servers, where it would be difficult for the app publisher to prevent a misbehaving server from rejoining the network under a new identity in order to obtain a new authentication token.
|
|
|
Apple might refuse to publish an app that distributed APNs authentication tokens to servers controlled by third parties.
|
|
|
|
|
|
### Background Notifications
|
|
|
|
|
|
Push notifications are often used to wake the app and notify the user, but it's also possible to send a *background notification* that wakes the app without notifying the user.
|
|
|
|
|
|
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app
|
|
|
|
|
|
Background notifications could be sent periodically to every device in a P2P or federated network, allowing each device to wake up and connect to its peers or federated server to check for new content.
|
|
|
The app publisher's provider server could send these periodic notifications without knowing whether any content was available, and thus no metadata would need to be exposed to the provider server or to APNs.
|
|
|
|
|
|
However, iOS limits the number of background notifications that each app running on a device can receive: the documentation recommends that app publishers "don't try to send more than two or three per hour".
|
|
|
Thus there would be a delay of up to 20 or 30 minutes between new content becoming available and the recipient device(s) being notified.
|
|
|
|
|
|
Another effect of throttling background notifications is that even if the provider server were to ask APNs to send notifications to all devices simultaneously, the devices wouldn't necessarily wake up at the same time.
|
|
|
Thus background notifications wouldn't be suitable for coordinating the peers in a P2P network to come online briefly at the same time and connect to each other.
|
|
|
|
|
|
When a device receives a background notification, iOS gives the app 30 seconds to do any necessary work in response to the notification.
|
|
|
Depending on network conditions, this might not be enough time to connect to a federated server or peers in a P2P network, especially if the connections were being made via Tor.
|
|
|
|
|
|
## Background Execution
|
|
|
|
|
|
iOS is much stricter than Android about how much work apps are allowed to do while they're running in the background.
|
|
|
|
|
|
### Execution States
|
|
|
|
|
|
An iOS app can be in one of five execution states:
|
|
|
|
|
|
* Active: An app is in this state when it's running in the foreground.
|
|
|
* Inactive: This is a transitional state that the app briefly occupies when moving between other states.
|
|
|
* Background: An app is in this state when it's running in the background. This can happen because the app has recently been moved out of the foreground (Active -> Inactive -> Background), or because the app has been woken from the Suspended state by a system event (Suspended -> Background), or because the app has been launched in the background to handle a system event (Not Running -> Inactive -> Background).
|
|
|
* Suspended: An app is in this state when it's no longer running, but the system is keeping the app in memory to allow it to be relaunched quickly.
|
|
|
* Not Running: An app is in this state when it hasn't been launched yet, or when it's been removed from memory to make room for other apps.
|
|
|
|
|
|
https://medium.com/@chinthaka01/the-execution-states-of-an-ios-application-84e117132e27
|
|
|
|
|
|
https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/about_the_background_execution_sequence
|
|
|
|
|
|
When an app is moved from the foreground to the background, it has five seconds to do any necessary work before being suspended.
|
|
|
An app can request extra time for this work if needed.
|
|
|
The amount of time that will be granted isn't documented, but it can be queried by the app at runtime.
|
|
|
|
|
|
https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/extending_your_app_s_background_execution_time/
|
|
|
|
|
|
### Background Modes
|
|
|
|
|
|
iOS defines specific categories of work that apps are allowed to do in the background.
|
|
|
These are known as *background modes*.
|
|
|
An app's publisher must declare which background modes the app will use.
|
|
|
|
|
|
https://developer.apple.com/documentation/xcode/configuring-background-execution-modes/
|
|
|
|
|
|
https://developer.apple.com/documentation/backgroundtasks/choosing_background_strategies_for_your_app
|
|
|
|
|
|
The background modes most likely to be relevant for peer-to-peer or device-to-device communication are `bluetooth-central`, `bluetooth-peripheral`, `fetch` and `processing`. Each of these modes is discussed below.
|
|
|
The `voip` mode is relevant for apps that can receive voice or video calls.
|
|
|
|
|
|
#### Background Modes for Bluetooth
|
|
|
|
|
|
Although the prospects for peer-to-peer communication on iOS aren't encouraging, the prospects for device-to-device communication via Bluetooth Low Energy (BLE) are relatively good.
|
|
|
|
|
|
iOS provides two background modes, `bluetooth-central` and `bluetooth-peripheral`, corresponding to BLE's *central* and *peripheral* roles.
|
|
|
A BLE device in the central role can scan for nearby peripherals and connect to them.
|
|
|
A device in the peripheral role can advertise its presence to nearby centrals and publish *services* consisting of fields called *characteristics* that can be read and written by connected centrals.
|
|
|
|
|
|
An iOS device can operate in the central and peripheral roles simultaneously, so devices can discover each other and make device-to-device connections without having to decide their respective roles in advance.
|
|
|
BLE can potentially also be used for communicating with devices running Android or other operating systems.
|
|
|
|
|
|
When an app is terminated, it can persist the state of any ongoing Bluetooth operations so that they can be resumed when the app is relaunched into the foreground or background.
|
|
|
For example, if an app is terminated while scanning for nearby peripherals providing a specific service, the system may relaunch the app in the background when a suitable peripheral is found.
|
|
|
|
|
|
Similarly, if an app is terminated while advertising a service, the system may relaunch the app in the background when a nearby central accesses the service.
|
|
|
|
|
|
https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html
|
|
|
|
|
|
Scanning and advertising may happen less frequently when the app is in the background.
|
|
|
The identifiers of services being advertised are moved to a special "overflow area" and can only be discovered by iOS devices that are specifically scanning for them.
|
|
|
Services in the overflow can only be discovered while the scanning device's screen is turned on.
|
|
|
This means that in most cases, devices can't discover each other if the app is running in the background on both devices.
|
|
|
|
|
|
http://www.davidgyoungtech.com/2020/05/07/hacking-the-overflow-area
|
|
|
|
|
|
#### Background App Refresh Tasks
|
|
|
|
|
|
The `fetch` background mode allows an app to run in the background occasionally to refresh its content.
|
|
|
|
|
|
https://developer.apple.com/documentation/backgroundtasks
|
|
|
|
|
|
When this background mode was first introduced, the documentation said that background tasks would be allowed to run every 15 minutes.
|
|
|
This is no longer the case: iOS now takes several factors into account when deciding when to run background tasks, including the device's battery level, the app's consumption of battery and other resources, and how recently the user has interacted with the app.
|
|
|
|
|
|
https://developer.apple.com/forums/thread/685525
|
|
|
|
|
|
https://developer.apple.com/videos/play/wwdc2020/10063/
|
|
|
|
|
|
#### Background Processing Tasks
|
|
|
|
|
|
The `processing` background mode allows an app to run resource-intensive tasks in the background while the device is charging and not being used.
|
|
|
|
|
|
https://developer.apple.com/documentation/backgroundtasks
|
|
|
|
|
|
If this mode allows network access then it could potentially be useful for letting devices in a P2P network take on more resource-intensive "superpeer" roles while they're idle and connected to power and Wi-Fi.
|
|
|
|
|
|
## Bonjour
|
|
|
|
|
|
iOS provides an API for Bonjour, Apple's implementation of Multicast DNS (mDNS) and DNS Service Discovery (DNS-SD), which can be used to advertise and discover services on a local area network.
|
|
|
|
|
|
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/NetServices/Articles/programming.html#//apple_ref/doc/uid/TP40002459-SW1
|
|
|
|
|
|
http://www.multicastdns.org/
|
|
|
|
|
|
http://www.dns-sd.org/
|
|
|
|
|
|
Bonjour is compatible with implementations of mDNS and DNS-SD on other platforms (eg Network Service Discovery on Android), so it could be useful as a cross-platform service discovery mechanism.
|
|
|
|
|
|
Advertising and discovery can continue while the app is running in the background, but unlike Bluetooth there's no provision for advertising or discovery to continue when the app has been suspended or terminated.
|
|
|
Apps are expected to unregister all Bonjour services when they're suspended, as they won't be able to respond to incoming connection attempts while suspended.
|
|
|
|
|
|
Considering the limited opportunities for background execution described above, it's unlikely to be possible to discover a Bonjour service running on iOS unless the app providing the service is running in the foreground.
|
|
|
However, opportunistically discovering services running on other platforms during the iOS app's brief periods of background execution may be possible.
|
|
|
|
|
|
## Multicast
|
|
|
|
|
|
As well as Bonjour, which uses IP multicast for advertising and discovering services, iOS allows low-level access to IP multicast so that apps can implement their own multicast-based protocols.
|
|
|
|
|
|
https://developer.apple.com/news/?id=0oi77447
|
|
|
|
|
|
This API suffers from the same restrictions as Bonjour and other networking APIs: apps must release network-related resources when they're suspended, and suspended or terminated apps can't respond to incoming connection attempts. |