From d617e670063f0703382eed4eee5d69f541466d65 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jul 2020 16:51:36 +0100 Subject: [PATCH 1/4] Add method for plugins to get remote properties. --- .../bramble/api/plugin/PluginCallback.java | 7 +++++++ .../bramble/plugin/PluginManagerImpl.java | 14 ++++++++++++++ .../bramble/plugin/tcp/LanTcpPluginTest.java | 7 +++++++ .../bramble/plugin/tor/TestPluginCallback.java | 9 +++++++++ 4 files changed, 37 insertions(+) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java index 1b149cde1..3c0f3ca4d 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/PluginCallback.java @@ -8,6 +8,8 @@ import org.briarproject.bramble.api.plugin.event.TransportStateEvent; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.settings.Settings; +import java.util.Collection; + /** * An interface through which a transport plugin interacts with the rest of * the application. @@ -25,6 +27,11 @@ public interface PluginCallback extends ConnectionHandler { */ TransportProperties getLocalProperties(); + /** + * Returns the plugin's remote transport properties. + */ + Collection getRemoteProperties(); + /** * Merges the given settings with the plugin's settings */ diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java index f2d0d6a72..3b9479565 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/PluginManagerImpl.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.plugin; import org.briarproject.bramble.api.connection.ConnectionManager; +import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.lifecycle.IoExecutor; @@ -44,6 +45,7 @@ import java.util.logging.Logger; import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; +import static java.util.Collections.emptyList; import static java.util.logging.Level.FINE; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; @@ -303,6 +305,18 @@ class PluginManagerImpl implements PluginManager, Service { } } + @Override + public Collection getRemoteProperties() { + try { + Map remote = + transportPropertyManager.getRemoteProperties(id); + return remote.values(); + } catch (DbException e) { + logException(LOG, WARNING, e); + return emptyList(); + } + } + @Override public void mergeSettings(Settings s) { PluginManagerImpl.this.mergeSettings(s, id.getString()); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/plugin/tcp/LanTcpPluginTest.java b/bramble-core/src/test/java/org/briarproject/bramble/plugin/tcp/LanTcpPluginTest.java index 1ae844f7b..909a2f858 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/plugin/tcp/LanTcpPluginTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/plugin/tcp/LanTcpPluginTest.java @@ -22,11 +22,13 @@ import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.Socket; +import java.util.Collection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import static java.net.NetworkInterface.getNetworkInterfaces; +import static java.util.Collections.emptyList; import static java.util.Collections.list; import static java.util.concurrent.Executors.newCachedThreadPool; import static java.util.concurrent.TimeUnit.SECONDS; @@ -320,6 +322,11 @@ public class LanTcpPluginTest extends BrambleTestCase { return local; } + @Override + public Collection getRemoteProperties() { + return emptyList(); + } + @Override public void mergeSettings(Settings s) { } diff --git a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/TestPluginCallback.java b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/TestPluginCallback.java index aeb5a9ee9..b25038bc8 100644 --- a/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/TestPluginCallback.java +++ b/bramble-java/src/test/java/org/briarproject/bramble/plugin/tor/TestPluginCallback.java @@ -9,6 +9,10 @@ import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.settings.Settings; +import java.util.Collection; + +import static java.util.Collections.emptyList; + @NotNullByDefault public class TestPluginCallback implements PluginCallback { @@ -22,6 +26,11 @@ public class TestPluginCallback implements PluginCallback { return new TransportProperties(); } + @Override + public Collection getRemoteProperties() { + return emptyList(); + } + @Override public void mergeSettings(Settings s) { } From 49f06402781e44997360e34cb00803efbf35f981 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Thu, 16 Jul 2020 16:56:14 +0100 Subject: [PATCH 2/4] Use reflected Bluetooth address if we don't know our own address. --- .../api/plugin/BluetoothConstants.java | 3 + .../plugin/bluetooth/BluetoothPlugin.java | 61 +++++++++++++++++-- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/BluetoothConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/BluetoothConstants.java index 6b8a654bd..ce8930f38 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/BluetoothConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/BluetoothConstants.java @@ -10,6 +10,9 @@ public interface BluetoothConstants { String PROP_ADDRESS = "address"; String PROP_UUID = "uuid"; + // Local settings (not shared with contacts) + String PREF_ADDRESS_IS_REFLECTED = "addressIsReflected"; + // Default value for PREF_PLUGIN_ENABLE boolean DEFAULT_PREF_PLUGIN_ENABLE = false; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index 643af4608..2902d3751 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.plugin.bluetooth; import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.Multiset; import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.event.Event; @@ -25,6 +26,7 @@ import org.briarproject.bramble.api.plugin.event.BluetoothEnabledEvent; import org.briarproject.bramble.api.plugin.event.DisableBluetoothEvent; import org.briarproject.bramble.api.plugin.event.EnableBluetoothEvent; import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.properties.event.RemoteTransportPropertiesUpdatedEvent; import org.briarproject.bramble.api.rendezvous.KeyMaterialSource; import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint; import org.briarproject.bramble.api.settings.Settings; @@ -48,6 +50,7 @@ import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH; import static org.briarproject.bramble.api.plugin.BluetoothConstants.DEFAULT_PREF_PLUGIN_ENABLE; import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID; +import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_ADDRESS_IS_REFLECTED; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID; import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES; @@ -55,6 +58,7 @@ import static org.briarproject.bramble.api.plugin.Plugin.State.ACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.DISABLED; import static org.briarproject.bramble.api.plugin.Plugin.State.INACTIVE; import static org.briarproject.bramble.api.plugin.Plugin.State.STARTING_STOPPING; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.REFLECTED_PROPERTY_PREFIX; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.PrivacyUtils.scrubMacAddress; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; @@ -205,25 +209,64 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { TransportProperties p = callback.getLocalProperties(); String address = p.get(PROP_ADDRESS); String uuid = p.get(PROP_UUID); + Settings s = callback.getSettings(); + boolean isReflected = s.getBoolean(PREF_ADDRESS_IS_REFLECTED, false); boolean changed = false; - if (address == null) { + if (address == null || isReflected) { address = getBluetoothAddress(); - if (LOG.isLoggable(INFO)) + if (LOG.isLoggable(INFO)) { LOG.info("Local address " + scrubMacAddress(address)); - if (!isNullOrEmpty(address)) { - p.put(PROP_ADDRESS, address); + } + if (address == null) { + address = getReflectedAddress(); + if (LOG.isLoggable(INFO)) { + LOG.info("Reflected address " + scrubMacAddress(address)); + } + if (address != null) { + changed = true; + isReflected = true; + } + } else { changed = true; + isReflected = false; } } if (uuid == null) { byte[] random = new byte[UUID_BYTES]; secureRandom.nextBytes(random); uuid = UUID.nameUUIDFromBytes(random).toString(); - p.put(PROP_UUID, uuid); changed = true; } contactConnectionsUuid = uuid; - if (changed) callback.mergeLocalProperties(p); + if (changed) { + p = new TransportProperties(); + // If we previously used a reflected address and there's no longer + // a reflected address with enough votes to be used, we'll continue + // to use the old reflected address until there's a new winner + if (address != null) p.put(PROP_ADDRESS, address); + p.put(PROP_UUID, uuid); + callback.mergeLocalProperties(p); + s = new Settings(); + s.putBoolean(PREF_ADDRESS_IS_REFLECTED, isReflected); + callback.mergeSettings(s); + } + } + + @Nullable + private String getReflectedAddress() { + // Count the number of votes for each reflected address + String key = REFLECTED_PROPERTY_PREFIX + PROP_ADDRESS; + Multiset votes = new Multiset<>(); + for (TransportProperties p : callback.getRemoteProperties()) { + String address = p.get(key); + if (address != null && isValidAddress(address)) votes.add(address); + } + // If an address gets more than half of the votes, accept it + int total = votes.getTotal(); + for (String address : votes.keySet()) { + if (votes.getCount(address) * 2 > total) return address; + } + return null; } private void acceptContactConnections(SS ss) { @@ -429,6 +472,12 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { ioExecutor.execute(connectionLimiter::keyAgreementStarted); } else if (e instanceof KeyAgreementStoppedListeningEvent) { ioExecutor.execute(connectionLimiter::keyAgreementEnded); + } else if (e instanceof RemoteTransportPropertiesUpdatedEvent) { + RemoteTransportPropertiesUpdatedEvent r = + (RemoteTransportPropertiesUpdatedEvent) e; + if (r.getTransportId().equals(ID)) { + ioExecutor.execute(this::updateProperties); + } } } From a4091be6f73daa9603be0106173a812d54d2fb06 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Mon, 20 Jul 2020 16:18:25 +0100 Subject: [PATCH 3/4] Ignore reflected address until we've made a Bluetooth connection. This reduces the opportunities for contacts to reflect a false address. --- .../api/plugin/BluetoothConstants.java | 5 +++- .../plugin/bluetooth/BluetoothPlugin.java | 30 +++++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/BluetoothConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/BluetoothConstants.java index ce8930f38..284f1143d 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/BluetoothConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/BluetoothConstants.java @@ -12,7 +12,10 @@ public interface BluetoothConstants { // Local settings (not shared with contacts) String PREF_ADDRESS_IS_REFLECTED = "addressIsReflected"; + String PREF_EVER_CONNECTED = "everConnected"; - // Default value for PREF_PLUGIN_ENABLE + // Default values for local settings boolean DEFAULT_PREF_PLUGIN_ENABLE = false; + boolean DEFAULT_PREF_ADDRESS_IS_REFLECTED = false; + boolean DEFAULT_PREF_EVER_CONNECTED = false; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java index 2902d3751..9a5ff6b74 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/bluetooth/BluetoothPlugin.java @@ -48,9 +48,12 @@ import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_BLUETOOTH; +import static org.briarproject.bramble.api.plugin.BluetoothConstants.DEFAULT_PREF_ADDRESS_IS_REFLECTED; +import static org.briarproject.bramble.api.plugin.BluetoothConstants.DEFAULT_PREF_EVER_CONNECTED; import static org.briarproject.bramble.api.plugin.BluetoothConstants.DEFAULT_PREF_PLUGIN_ENABLE; import static org.briarproject.bramble.api.plugin.BluetoothConstants.ID; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_ADDRESS_IS_REFLECTED; +import static org.briarproject.bramble.api.plugin.BluetoothConstants.PREF_EVER_CONNECTED; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_ADDRESS; import static org.briarproject.bramble.api.plugin.BluetoothConstants.PROP_UUID; import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES; @@ -81,6 +84,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { private final PluginCallback callback; private final int maxLatency, maxIdleTime; private final AtomicBoolean used = new AtomicBoolean(false); + private final AtomicBoolean everConnected = new AtomicBoolean(false); protected final PluginState state = new PluginState(); @@ -171,6 +175,8 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { Settings settings = callback.getSettings(); boolean enabledByUser = settings.getBoolean(PREF_PLUGIN_ENABLE, DEFAULT_PREF_PLUGIN_ENABLE); + everConnected.set(settings.getBoolean(PREF_EVER_CONNECTED, + DEFAULT_PREF_EVER_CONNECTED)); state.setStarted(enabledByUser); try { initialiseAdapter(); @@ -210,14 +216,15 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { String address = p.get(PROP_ADDRESS); String uuid = p.get(PROP_UUID); Settings s = callback.getSettings(); - boolean isReflected = s.getBoolean(PREF_ADDRESS_IS_REFLECTED, false); + boolean isReflected = s.getBoolean(PREF_ADDRESS_IS_REFLECTED, + DEFAULT_PREF_ADDRESS_IS_REFLECTED); boolean changed = false; if (address == null || isReflected) { address = getBluetoothAddress(); if (LOG.isLoggable(INFO)) { LOG.info("Local address " + scrubMacAddress(address)); } - if (address == null) { + if (address == null && everConnected.get()) { address = getReflectedAddress(); if (LOG.isLoggable(INFO)) { LOG.info("Reflected address " + scrubMacAddress(address)); @@ -283,10 +290,23 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { LOG.info("Connection received"); connectionLimiter.connectionOpened(conn); backoff.reset(); + setEverConnected(); callback.handleConnection(conn); } } + private void setEverConnected() { + if (!everConnected.getAndSet(true)) { + ioExecutor.execute(() -> { + Settings s = new Settings(); + s.putBoolean(PREF_EVER_CONNECTED, true); + callback.mergeSettings(s); + // Contacts may already have sent a reflected address + updateProperties(); + }); + } + } + @Override public void stop() { SS ss = state.setStopped(); @@ -333,6 +353,7 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { DuplexTransportConnection d = createConnection(p); if (d != null) { backoff.reset(); + setEverConnected(); h.handleConnection(d); } }); @@ -435,7 +456,10 @@ abstract class BluetoothPlugin implements DuplexPlugin, EventListener { LOG.info("Connecting to key agreement UUID " + uuid); conn = connect(address, uuid); } - if (conn != null) connectionLimiter.connectionOpened(conn); + if (conn != null) { + connectionLimiter.connectionOpened(conn); + setEverConnected(); + } return conn; } From e9f78bc4861987bbd40fb48fbcf3f42720dd0f64 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 21 Jul 2020 10:38:30 +0100 Subject: [PATCH 4/4] Avoid redundantly storing unchanged properties and settings. --- .idea/codeStyles/Project.xml | 3 --- .../plugin/bluetooth/BluetoothPlugin.java | 19 +++++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 78dfd234a..011a1a146 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -1,8 +1,5 @@ - -