... | ... | @@ -31,6 +31,9 @@ The base layer of any mesh networking protocol is the individual direct connecti |
|
|
|
|
|
Some of the transport layers covered by this research are already used in the Briar messaging app, but by removing the constraint that devices only connect to contacts, we change the ways in which familiar transports can be used, so we need to look at them again with the public mesh strategy in mind.
|
|
|
|
|
|
In particular, the public mesh strategy allows devices to advertise the fact that they are participating in the mesh, so that nearby devices can discover and connect to them.
|
|
|
Several of the transports discussed below have advertising and discovery mechanisms suitable for this purpose.
|
|
|
|
|
|
## Prologue
|
|
|
|
|
|
### Evaluation Criteria
|
... | ... | @@ -192,11 +195,10 @@ On a mobile device, a public mesh Bluetooth service needs to be able to run unin |
|
|
<uses-permission
|
|
|
android:name="android.permission.ACCESS_FINE_LOCATION"
|
|
|
android:maxSdkVersion="30" />
|
|
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
|
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
|
|
<!-- The BLUETOOTH permission was supposed to be removed in API 31 but is still needed on some Xiaomi/Redmi/POCO devices running API 31 and Nubia devices running API 32 -->
|
|
|
<uses-permission
|
|
|
android:name="android.permission.BLUETOOTH"
|
|
|
android:maxSdkVersion="30" />
|
|
|
android:maxSdkVersion="32" />
|
|
|
<uses-permission
|
|
|
android:name="android.permission.BLUETOOTH_ADMIN"
|
|
|
android:maxSdkVersion="30" />
|
... | ... | @@ -206,10 +208,6 @@ On a mobile device, a public mesh Bluetooth service needs to be able to run unin |
|
|
android:name="android.permission.BLUETOOTH_SCAN"
|
|
|
android:usesPermissionFlags="neverForLocation"
|
|
|
tools:targetApi="31" />
|
|
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
|
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
|
|
|
|
|
Depending on the API level, various permissions must be granted by the user. On API level 31, the following permissions require user confirmation:
|
|
|
|
... | ... | @@ -219,6 +217,8 @@ Depending on the API level, various permissions must be granted by the user. On |
|
|
|
|
|
On API levels 30 and earlier, access to some Bluetooth APIs requires location-related permissions, and access to these APIs while the app is in the background may result in a warning being shown about the app accessing the user's location. This creates a UX hurdle for future public mesh applications because it could cause users to believe their locations are being tracked.
|
|
|
|
|
|
On Android versions 6 and later (API level >= 23), the device's location services must be enabled in order for apps to receive BLE discovery results.
|
|
|
|
|
|
### BLESSED
|
|
|
|
|
|
We have found that the open source Bluetooth library [BLESSED](https://github.com/weliem/blessed-android) is useful for working with BLE on Android. The project's README.md offers an introduction to the library for new users, and they also offer a number of [example projects](https://github.com/weliem/blessed-android/tree/master/app/src/main/java/com/welie/blessedexample) to help developers get started with BLESSED.
|
... | ... | @@ -387,7 +387,6 @@ TODO find code snippets from blechat impl |
|
|
#### Peer Connectivity
|
|
|
|
|
|
#### Notes
|
|
|
test note
|
|
|
|
|
|
While the library has methods built to enable auto-peering, our attempt to enable auto-peering with this framework proved unsuccessful.
|
|
|
|
... | ... | @@ -603,11 +602,7 @@ Connecting to a specific network is possible on any API level, but on Android 10 |
|
|
If the network doesn't have internet access, some devices show a warning dialog or notification.
|
|
|
If the device is currently connected to a network with internet access, the device may reconnect to that network instead of connecting to the requested network.
|
|
|
|
|
|
#### Security Concerns
|
|
|
|
|
|
The authors of [Nearby Threats: Reversing, Analyzing, and Attacking Google’s ‘Nearby Connections’ on Android](https://francozappa.github.io/publication/rearby/) noted that when a device connects to a Wi-Fi access point, all of the device's traffic is routed through the access point, even if the app that requested the connection didn't expect the access point to provide internet access.
|
|
|
|
|
|
This security concern is relevant for mesh applications that connect to access points without user interaction, even if they don't use Google Nearby.
|
|
|
The [soft AP attack](#soft-ap-attack) applies to all of these methods of connecting to access points.
|
|
|
|
|
|
### Wi-Fi Access Point
|
|
|
|
... | ... | @@ -619,7 +614,7 @@ Some devices require a SIM card to be inserted before this feature can be used. |
|
|
On Android versions 5.1 and earlier (API level <= 22), applications can use reflection to access a hidden API for enabling an access point, including specifying the network name and password.
|
|
|
|
|
|
Android versions 8 and later (API level >= 26) have an API for creating a "local-only hotspot", which is an access point that doesn't provide internet access to connected clients.
|
|
|
The application can't choose the hotspot's network name or password.
|
|
|
The application receives the hotspot's network name and password via a callback, but cannot choose the network name or password.
|
|
|
|
|
|
<https://developer.android.com/reference/android/net/wifi/WifiManager#startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback,%20android.os.Handler)>
|
|
|
|
... | ... | @@ -632,19 +627,145 @@ We still need to test whether LAN multicast and the NSD API can be used (by clie |
|
|
|
|
|
Some devices can provide an access point while simultaneously being a client of another Wi-Fi network, which might make it possible to create a mesh in which each device would act as a client, an access point, or both.
|
|
|
|
|
|
Once a device has created an access point, it could make the network name and password available via other transport layers (such as BLE or Wi-Fi Direct service discovery) to enable nearby devices to discover the access point, recognise that it belongs to the mesh, and connect to it.
|
|
|
|
|
|
### Wi-Fi Direct
|
|
|
|
|
|
Wi-Fi Direct is a Wi-Fi standard that enables devices to discover and connect to each other without the need for an access point.
|
|
|
The standard includes a "legacy mode" that allows interoperability with ordinary Wi-Fi clients that don't implement the Wi-Fi Direct standard.
|
|
|
|
|
|
#### Peer Advertisement
|
|
|
* <https://www.wi-fi.org/discover-wi-fi/wi-fi-direct>
|
|
|
* <https://www.wi-fi.org/download.php?file=/sites/default/files/private/Wi-Fi_Direct_Specification_v1.9.pdf>
|
|
|
* <https://developer.android.com/guide/topics/connectivity/wifip2p>
|
|
|
|
|
|
Wi-Fi Direct has two overlapping mechanisms for discovering nearby devices: "peer discovery" and "service discovery".
|
|
|
The `wifi-direct-rebased` branch of the testbed app demonstrates how these mechanisms can be used.
|
|
|
|
|
|
On most Android devices, apps can use Wi-Fi Direct whenever the device's Wi-Fi is enabled, but some devices (eg Moto E3) can't act as Wi-Fi Direct peers and ordinary Wi-Fi clients at the same time: whenever an app asks to create or join a Wi-Fi Direct group, the system UI asks the user to confirm that the device will disconnect from the Wi-Fi network.
|
|
|
|
|
|
Some other devices (eg Huawei P8 Lite 2015) require the user to activate Wi-Fi Direct in the system settings before it can be used.
|
|
|
|
|
|
#### Peer Discovery
|
|
|
|
|
|
Peer discovery is used to discover nearby Wi-Fi Direct devices that are also performing peer discovery, service discovery or service advertisement.
|
|
|
|
|
|
Android provides an API for starting and stopping peer discovery.
|
|
|
Once started, peer discovery remains active until it's explicitly stopped, or until a Wi-Fi Direct connection is initiated or a group is formed.
|
|
|
|
|
|
<https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager#discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel,%20android.net.wifi.p2p.WifiP2pManager.ActionListener)>
|
|
|
|
|
|
Android versions 13 and later (API >= 33) provide an API for listening and responding to peer discovery requests without sending requests:
|
|
|
|
|
|
<https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager#startListening(android.net.wifi.p2p.WifiP2pManager.Channel,%20android.net.wifi.p2p.WifiP2pManager.ActionListener)>
|
|
|
|
|
|
The peer discovery mechanism does not enable devices to advertise any information other than a device name.
|
|
|
This may be the model name (eg "HUAWEI P8 Lite 2017") or a meaningless name like "Android_a1b2".
|
|
|
On Android versions 10 and earlier (API level <= 29), applications can set the local device's name by using reflection to access a hidden API.
|
|
|
|
|
|
#### Service Discovery
|
|
|
|
|
|
Service discovery is used to advertise and discover services provided by Wi-Fi Direct devices, and can also be used as a way of advertising and discovering small amounts of information (such as ways to contact a device over various transport layers) without opening a connection.
|
|
|
|
|
|
<https://developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct>
|
|
|
|
|
|
Android supports two protocols for Wi-Fi Direct service discovery: DNS Service Discovery (DNS-SD) and Universal Plug and Play (UPnP).
|
|
|
|
|
|
With DNS-SD, the advertisement contains an "instance name" (device name), a service type, and a record containing key-value pairs.
|
|
|
Discovery can search for all services, all services of a specific type, or a specific instance name and service type.
|
|
|
|
|
|
With UPnP, the advertisement contains a UUID and a set of URNs describing the device and the available services.
|
|
|
Discovery can search for all services, or services of a specific type.
|
|
|
|
|
|
DNS-SD is likely to be the more useful protocol because of the ability to advertise arbitrary key-value pairs.
|
|
|
|
|
|
Service discovery stops automatically after two minutes.
|
|
|
There is no callback to inform the app that service discovery has stopped.
|
|
|
|
|
|
* <https://issuetracker.google.com/issues/37092481>
|
|
|
* <https://cs.android.com/android/platform/superproject/+/master:packages/modules/Wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java;drc=69cce4cb58a66b09a3d3e1e6c7de65aa169d44d0;l=241>
|
|
|
|
|
|
The developers of Thali reported some performance and stability issues when repeatedly performing Wi-Fi Direct service discovery, and we also saw some evidence to support this.
|
|
|
The following Stack Overflow answer has some tips for making service discovery more reliable:
|
|
|
|
|
|
<https://stackoverflow.com/a/31641302>
|
|
|
|
|
|
#### Peer Connectivity
|
|
|
|
|
|
When Wi-Fi Direct devices connect to each other they always form a group, even if only two devices are involved.
|
|
|
One device is chosen as the group owner and the devices connect in a star topology with the group owner at the centre.
|
|
|
|
|
|
Android provides an API for connecting to a Wi-Fi Direct device discovered via peer discovery or service discovery:
|
|
|
|
|
|
<https://developer.android.com/training/connect-devices-wirelessly/wifi-direct>
|
|
|
|
|
|
During the connection process, one or both of the devices will show a dialog or notification asking the user whether they want to accept the connection.
|
|
|
The name of the other device is shown in the dialog.
|
|
|
This may be the model name (eg "HUAWEI P8 Lite 2017") or a meaningless name like "Android_a1b2".
|
|
|
As mentioned in the peer discovery section, on Android versions 10 and earlier (API level <= 29), applications can set the local device's name by using reflection to access a hidden API.
|
|
|
|
|
|
The dialog is usually shown on the device accepting the connection and not on the other device, but this seems to depend on which device is chosen as group owner, whether the devices have connected before, and whether the group information was stored persistently on each device.
|
|
|
|
|
|
The need for user confirmation prevents Wi-Fi Direct connections from being made automatically in the background.
|
|
|
Even if the connection is initiated by the user while the app is in the foreground, the user experience is poor because confirmation may be requested on either device (or both) and the device names may not be meaningful.
|
|
|
|
|
|
#### Legacy Mode
|
|
|
|
|
|
The Wi-Fi Direct standard includes a "legacy mode" for interoperating with ordinary Wi-Fi clients that don't support Wi-Fi Direct.
|
|
|
|
|
|
In this mode, a Wi-Fi Direct device creates an access point that legacy clients can connect to.
|
|
|
This device also functions as the group owner for a Wi-Fi Direct group.
|
|
|
Clients connected to the access point can communicate with devices in the group.
|
|
|
|
|
|
<https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager#createGroup(android.net.wifi.p2p.WifiP2pManager.Channel,%20android.net.wifi.p2p.WifiP2pManager.ActionListener)>
|
|
|
|
|
|
The app receives the network name and password via a callback. On Android versions 10 and later (API level >= 29), the app can specify the network name and password:
|
|
|
|
|
|
<https://developer.android.com/reference/android/net/wifi/p2p/WifiP2pManager#createGroup(android.net.wifi.p2p.WifiP2pManager.Channel,%20android.net.wifi.p2p.WifiP2pConfig,%20android.net.wifi.p2p.WifiP2pManager.ActionListener)>
|
|
|
|
|
|
On Android versions 10 and later (API level >= 29), the `WifiP2pManager` API can also be used for connecting to a legacy mode group with a given network name and password.
|
|
|
This is a useful alternative to the methods described in the [Wi-Fi Client section](#wi-fi-client), as it doesn't expose the device to the [soft AP attack](#soft-ap-attack).
|
|
|
|
|
|
The `wifi-direct-service-discovery` branch of the testbed app demonstrates how an app can create a legacy mode access point and advertise its network name and password via Wi-Fi Direct service discovery.
|
|
|
Peers running Android 10 or later can connect to the access point via the Wi-Fi Direct API without being exposed to the soft AP attack.
|
|
|
|
|
|
We couldn't find any devices that could perform service discovery while providing a legacy mode access point, but advertising a service while providing a legacy mode access point seemed to work.
|
|
|
|
|
|
#### Android Permissions
|
|
|
|
|
|
Wi-Fi Direct requires various permissions on different Android API levels:
|
|
|
|
|
|
<uses-permission
|
|
|
android:name="android.permission.ACCESS_FINE_LOCATION"
|
|
|
android:maxSdkVersion="32" />
|
|
|
<uses-permission
|
|
|
android:name="android.permission.ACCESS_WIFI_STATE"/>
|
|
|
<uses-permission
|
|
|
android:name="android.permission.CHANGE_WIFI_STATE"/>
|
|
|
<uses-permission
|
|
|
android:name="android.permission.INTERNET"/>
|
|
|
<uses-permission
|
|
|
android:name="android.permission.NEARBY_WIFI_DEVICES"
|
|
|
android:usesPermissionFlags="neverForLocation" />
|
|
|
|
|
|
Depending on the API level, the user must grant either the location permission or the nearby Wi-Fi devices permission.
|
|
|
In practice, the system UI for requesting the `NEARBY_WIFI_DEVICES` permission also seems to grant the `BLUETOOTH_ADVERTISE`, `BLUETOOTH_CONNECT` and `BLUETOOTH_SCAN` permissions, and vice versa, but apps should probably not depend on this.
|
|
|
|
|
|
The device's location services must be enabled in order for apps to use the Wi-Fi Direct API.
|
|
|
|
|
|
#### Notes
|
|
|
|
|
|
* Some devices can perform peer discovery while providing a legacy mode access point, but others fail to discover any peers.
|
|
|
* Group info is persisted and may be returned by `requestGroupInfo()` even after closing and reopening the Wi-Fi Direct channel, or exiting and relaunching the process. Persisted group info can be removed by calling `removeGroup()`.
|
|
|
* If the user authorises a connection between two devices, this is also persisted and isn't removed even if the app is uninstalled. Persisted authorisations aren't removed by calling `removeGroup()`. This could be a privacy issue and can also cause some pain for testing. Resetting network settings seems to remove the authorisations without requiring a full factory reset.
|
|
|
* The first WPS (ie not legacy mode) connection between two devices requires authorisation by one or both of the users. Either device may become the group owner. If the device receiving the connection already belongs to another group, it may leave the other group and form a new group rather than adding the new device to the existing group.
|
|
|
* Stopping peer discovery by calling `stopPeerDiscovery()` doesn't work on the Samsung Galaxy A21s (the callback is never called). Closing and reopening the Wi-Fi Direct channel allows peer discovery to be started again.
|
|
|
* Unlike normal Wi-Fi networks, it seems to be possible to make TCP connections across a Wi-Fi Direct network on API level >= 21 when the device has internet access via another network, without needing to find the network's `SocketFactory`. (Which is just as well, because `ConnectionManager#getAllNetworks()` doesn't seem to return any network that's recognisable as a Wi-Fi Direct network, eg via the capability `NET_CAPABILITY_WIFI_P2P`.) However, I've only tested this with internet access via Wi-Fi. It's possible that it would be a different story if the device had internet access via mobile data.
|
|
|
* On the Moto G 4G, creating a legacy mode access point or connecting to a peer via WPS shows a system confirmation dialog if the device is connected to a Wi-Fi network, but no dialog is shown for peer discovery or service discovery.
|
|
|
* On the Huawei P8 Lite 2015, Wi-Fi Direct has to be enabled in the system Wi-Fi settings, which turns off regular Wi-Fi. Without this it's possible to initialise a Wi-Fi Direct channel but all operations on the channel return `ERROR`.
|
|
|
* Stopping peer discovery doesn't work on the Samsung Galaxy J5 2016 (looks like the same issue as the much newer Samsung Galaxy A21s).
|
|
|
* On the J5, connecting to a peer via WPS doesn't always cause the connection info or group info to be updated (it does seem to get updated if the J5 is the group owner).
|
|
|
* The Nokia 1.3 can sometimes get into a state where all Wi-Fi Direct operations fail with error code `BUSY`. Closing and reinitialising the Wi-Fi Direct channel doesn't help. Nor does turning the device's Wi-Fi off and on again. Rebooting the device fixes the issue.
|
|
|
|
|
|
### Ad Hoc Mode
|
|
|
|
|
|
The original Wi-Fi standard defines two modes of operation: infrastructure mode, in which stations communicate via an access point, and ad hoc mode, in which stations communicate directly with each other.
|
... | ... | @@ -730,8 +851,7 @@ The system may trigger a scan when the screen is turned on, resulting in the dev |
|
|
|
|
|
On Android versions 10 and later (API level >= 29), we did not manage to trigger automatic reconnection to a network requested via the `WifiNetworkSpecifier` API, regardless of whether the client was reconnecting to the same access point or a second access point with the same network name and password.
|
|
|
|
|
|
We have not yet tested whether the `WifiP2pManager` (Wi-Fi Direct) API can be used to roam between legacy mode access points with the same network name and password on Android versions 10 and later.
|
|
|
However, the tests described above for reconnecting to the same access point would seem to suggest that periodically trying to connect via the `WifiP2pManager` API is likely to work also for the case of roaming between access points.
|
|
|
However, the `WifiP2pManager` (Wi-Fi Direct) API can be used to roam between legacy mode access points with the same network name and password on Android versions 10 and later, by periodically retrying until the connection attempt succeeds.
|
|
|
|
|
|
#### Creating an Access Point with Predefined Credentials
|
|
|
|
... | ... | @@ -751,7 +871,7 @@ On Android versions 10 and later (API level >= 29) it was done via the `WifiP2pM |
|
|
Devices varied in their behaviour when connecting to an access point without internet access, and when roaming between access points with the same network name and password.
|
|
|
This could make it challenging to create a consistent user experience.
|
|
|
|
|
|
Android versions 9 and earlier (API level <= 28) would be vulnerable to the ["soft AP attack"]{#soft-ap-attack) when acting as clients.
|
|
|
Android versions 9 and earlier (API level <= 28) would be vulnerable to the [soft AP attack]{#soft-ap-attack) when acting as clients.
|
|
|
|
|
|
Not all devices would be able to act as access points, and users would not be able to control which of the available access points their devices would connect to, so this technique would need to be used in combination with other transport layers.
|
|
|
|
... | ... | @@ -787,6 +907,8 @@ The advertiser may then tell the discoverer to switch from Bluetooth to Wi-Fi. W |
|
|
The "Nearby Threats" researchers identified several attacks against Nearby, including the "soft AP attack", in which a malicious advertiser instructs the discoverer to switch to an access point that has internet access.
|
|
|
This unexpectedly causes the discoverer's device to route all its traffic through that access point.
|
|
|
|
|
|
This attack is relevant to mesh applications that connect to Wi-Fi access points without user interaction, even if they don't use Google Nearby.
|
|
|
|
|
|
Due to this attack, it is not safe to use the Wi-Fi client (`WifiManager`) API for connecting to an access point provided by another device, including a Wi-Fi Direct legacy mode access point.
|
|
|
However, it appears to be safe to use the Wi-Fi Direct (`WifiP2pManager`) API for connecting to a legacy mode access point, as in this case the client will not route all its traffic through the access point even if the access point unexpectedly provides internet access.
|
|
|
|
... | ... | |