Only bind to the SLAAC address of the wifi interface.

This is just a precaution - on all devices I've tested, the wifi
interface is the only one with a SLAAC address.
This commit is contained in:
akwizgran
2020-03-06 11:24:12 +00:00
parent e1084ffadd
commit d0c53f1310

View File

@@ -8,6 +8,7 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import org.briarproject.bramble.PoliteExecutor; import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.network.event.NetworkStatusEvent; import org.briarproject.bramble.api.network.event.NetworkStatusEvent;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -17,7 +18,9 @@ import org.briarproject.bramble.api.settings.Settings;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -31,12 +34,14 @@ import static android.content.Context.WIFI_SERVICE;
import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.os.Build.VERSION.SDK_INT; import static android.os.Build.VERSION.SDK_INT;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.list;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE;
import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE;
import static org.briarproject.bramble.util.IoUtils.tryToClose; import static org.briarproject.bramble.util.IoUtils.tryToClose;
import static org.briarproject.bramble.util.LogUtils.logException;
@NotNullByDefault @NotNullByDefault
class AndroidLanTcpPlugin extends LanTcpPlugin { class AndroidLanTcpPlugin extends LanTcpPlugin {
@@ -84,36 +89,58 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
@Override @Override
protected List<InetAddress> getUsableLocalInetAddresses(boolean ipv4) { protected List<InetAddress> getUsableLocalInetAddresses(boolean ipv4) {
if (ipv4) return getUsableLocalIpv4Addresses(); Pair<InetAddress, Boolean> wifi = getWifiIpv4Address();
else return getUsableLocalIpv6Addresses(); if (wifi == null) return emptyList();
if (ipv4) return singletonList(wifi.getFirst());
InetAddress slaac = getSlaacAddressForInterface(wifi.getFirst());
return slaac == null ? emptyList() : singletonList(slaac);
} }
private List<InetAddress> getUsableLocalIpv4Addresses() { /**
// If the device doesn't have wifi, don't open any sockets * Returns a {@link Pair} where the first element is the IPv4 address of
if (wifiManager == null) return emptyList(); * the wifi interface and the second element is true if this device is
* providing an access point, or false if this device is a client. Returns
* null if this device isn't connected to wifi as an access point or client.
*/
@Nullable
private Pair<InetAddress, Boolean> getWifiIpv4Address() {
if (wifiManager == null) return null;
// If we're connected to a wifi network, return its address // If we're connected to a wifi network, return its address
WifiInfo info = wifiManager.getConnectionInfo(); WifiInfo info = wifiManager.getConnectionInfo();
if (info != null && info.getIpAddress() != 0) { if (info != null && info.getIpAddress() != 0) {
return singletonList(intToInetAddress(info.getIpAddress())); return new Pair<>(intToInetAddress(info.getIpAddress()), false);
} }
// If we're running an access point, return its address List<InetAddress> addrs = getLocalInetAddresses();
for (InetAddress addr : getLocalInetAddresses()) { // If we're providing a normal access point, return its address
if (addr.equals(WIFI_AP_ADDRESS)) return singletonList(addr); for (InetAddress addr : addrs) {
if (addr.equals(WIFI_DIRECT_AP_ADDRESS)) return singletonList(addr); if (WIFI_AP_ADDRESS.equals(addr)) {
return new Pair<>(addr, true);
}
} }
// No suitable addresses // If we're providing a wifi direct access point, return its address
return emptyList(); for (InetAddress addr : addrs) {
if (WIFI_DIRECT_AP_ADDRESS.equals(addr)) {
return new Pair<>(addr, true);
}
}
// Not connected to wifi
return null;
} }
private List<InetAddress> getUsableLocalIpv6Addresses() { @Nullable
// If the device doesn't have wifi, don't open any sockets private InetAddress getSlaacAddressForInterface(InetAddress wifi) {
if (wifiManager == null) return emptyList(); try {
// If we have a SLAAC address, return it NetworkInterface iface = NetworkInterface.getByInetAddress(wifi);
for (InetAddress addr : getLocalInetAddresses()) { if (iface == null) return null;
if (isSlaacAddress(addr)) return singletonList(addr); for (InetAddress addr : list(iface.getInetAddresses())) {
if (isSlaacAddress(addr)) return addr;
}
// No suitable address
return null;
} catch (SocketException e) {
logException(LOG, WARNING, e);
return null;
} }
// No suitable addresses
return emptyList();
} }
private InetAddress intToInetAddress(int ip) { private InetAddress intToInetAddress(int ip) {
@@ -153,9 +180,20 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
connectionStatusExecutor.execute(() -> { connectionStatusExecutor.execute(() -> {
State s = getState(); State s = getState();
if (s != ACTIVE && s != INACTIVE) return; if (s != ACTIVE && s != INACTIVE) return;
List<InetAddress> addrs = getLocalInetAddresses(); Pair<InetAddress, Boolean> wifi = getWifiIpv4Address();
if (addrs.contains(WIFI_AP_ADDRESS) if (wifi == null) {
|| addrs.contains(WIFI_DIRECT_AP_ADDRESS)) { LOG.info("Not connected to wifi");
socketFactory = SocketFactory.getDefault();
// Server sockets may not have been closed automatically when
// interface was taken down. If any sockets are open, closing
// them here will cause the sockets to be cleared and the state
// to be updated in acceptContactConnections()
if (s == ACTIVE) {
LOG.info("Closing server sockets");
tryToClose(state.getServerSocket(true), LOG, WARNING);
tryToClose(state.getServerSocket(false), LOG, WARNING);
}
} else if (wifi.getSecond()) {
LOG.info("Providing wifi hotspot"); LOG.info("Providing wifi hotspot");
// There's no corresponding Network object and thus no way // There's no corresponding Network object and thus no way
// to get a suitable socket factory, so we won't be able to // to get a suitable socket factory, so we won't be able to
@@ -163,17 +201,6 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
// has internet access // has internet access
socketFactory = SocketFactory.getDefault(); socketFactory = SocketFactory.getDefault();
if (s == INACTIVE) bind(); if (s == INACTIVE) bind();
} else if (addrs.isEmpty()) {
LOG.info("Not connected to wifi");
socketFactory = SocketFactory.getDefault();
// Server sockets may not have been closed automatically when
// interface was taken down. Sockets will be cleared and state
// updated in acceptContactConnections()
if (s == ACTIVE) {
LOG.info("Closing server sockets");
tryToClose(state.getServerSocket(true), LOG, WARNING);
tryToClose(state.getServerSocket(false), LOG, WARNING);
}
} else { } else {
LOG.info("Connected to wifi"); LOG.info("Connected to wifi");
socketFactory = getSocketFactory(); socketFactory = getSocketFactory();