mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 12:19:54 +01:00
Cleaned up address selection code for LAN and WAN plugins.
The LAN plugin only accepts IPv4 link-local or site-local addresses. This rules out LANs that use globally routable addresses (such as UCL), but also reduces the chances of the LAN plugin making observable connections across the WAN, which could reveal the social graph. Both plugins will attempt to reuse the previous address and port only if there's currently an interface with that address; this will avoid unnecessary attempts to bind to nonexistent addresses.
This commit is contained in:
@@ -2,15 +2,15 @@ package org.briarproject.plugins.tcp;
|
|||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -20,7 +20,7 @@ import org.briarproject.api.TransportProperties;
|
|||||||
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
import org.briarproject.api.plugins.duplex.DuplexPluginCallback;
|
||||||
import org.briarproject.util.StringUtils;
|
import org.briarproject.util.StringUtils;
|
||||||
|
|
||||||
/** A socket plugin that supports exchanging invitations over a LAN. */
|
/** A TCP plugin that supports exchanging invitations over a LAN. */
|
||||||
class LanTcpPlugin extends TcpPlugin {
|
class LanTcpPlugin extends TcpPlugin {
|
||||||
|
|
||||||
static final TransportId ID = new TransportId("lan");
|
static final TransportId ID = new TransportId("lan");
|
||||||
@@ -40,23 +40,23 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<SocketAddress> getLocalSocketAddresses() {
|
protected List<SocketAddress> getLocalSocketAddresses() {
|
||||||
List<SocketAddress> addrs = new ArrayList<SocketAddress>();
|
// Use the same address and port as last time if available
|
||||||
// Prefer a previously used address and port if available
|
|
||||||
TransportProperties p = callback.getLocalProperties();
|
TransportProperties p = callback.getLocalProperties();
|
||||||
String addrString = p.get("address");
|
String addressString = p.get("address");
|
||||||
String portString = p.get("port");
|
String portString = p.get("port");
|
||||||
InetAddress addr = null;
|
InetAddress oldAddress = null;
|
||||||
if(!StringUtils.isNullOrEmpty(addrString) &&
|
int oldPort = 0;
|
||||||
|
if(!StringUtils.isNullOrEmpty(addressString) &&
|
||||||
!StringUtils.isNullOrEmpty(portString)) {
|
!StringUtils.isNullOrEmpty(portString)) {
|
||||||
try {
|
try {
|
||||||
addr = InetAddress.getByName(addrString);
|
oldAddress = InetAddress.getByName(addressString);
|
||||||
int port = Integer.parseInt(portString);
|
oldPort = Integer.parseInt(portString);
|
||||||
addrs.add(new InetSocketAddress(addr, port));
|
|
||||||
addrs.add(new InetSocketAddress(addr, 0));
|
|
||||||
} catch(NumberFormatException e) {
|
} catch(NumberFormatException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.warning("Invalid port: " + portString);
|
||||||
} catch(UnknownHostException e) {
|
} catch(UnknownHostException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.warning("Invalid address: " + addressString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
List<NetworkInterface> ifaces;
|
List<NetworkInterface> ifaces;
|
||||||
@@ -64,30 +64,23 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||||
} catch(SocketException e) {
|
} catch(SocketException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
return addrs;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
// Prefer interfaces with link-local or site-local addresses
|
List<SocketAddress> addresses = new LinkedList<SocketAddress>();
|
||||||
|
// Accept interfaces with link-local or site-local addresses
|
||||||
for(NetworkInterface iface : ifaces) {
|
for(NetworkInterface iface : ifaces) {
|
||||||
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
||||||
if(addr != null && a.equals(addr)) continue;
|
boolean ipv4 = a instanceof Inet4Address;
|
||||||
if(a instanceof Inet6Address) continue;
|
boolean loop = a.isLoopbackAddress();
|
||||||
if(a.isLoopbackAddress()) continue;
|
|
||||||
boolean link = a.isLinkLocalAddress();
|
boolean link = a.isLinkLocalAddress();
|
||||||
boolean site = a.isSiteLocalAddress();
|
boolean site = a.isSiteLocalAddress();
|
||||||
if(link || site) addrs.add(new InetSocketAddress(a, 0));
|
if(ipv4 && !loop && (link || site)) {
|
||||||
|
if(a.equals(oldAddress))
|
||||||
|
addresses.add(0, new InetSocketAddress(a, oldPort));
|
||||||
|
addresses.add(new InetSocketAddress(a, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Accept interfaces without link-local or site-local addresses
|
return addresses;
|
||||||
for(NetworkInterface iface : ifaces) {
|
|
||||||
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
|
||||||
if(addr != null && a.equals(addr)) continue;
|
|
||||||
if(a instanceof Inet6Address) continue;
|
|
||||||
if(a.isLoopbackAddress()) continue;
|
|
||||||
boolean link = a.isLinkLocalAddress();
|
|
||||||
boolean site = a.isSiteLocalAddress();
|
|
||||||
if(!link && !site) addrs.add(new InetSocketAddress(a, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return addrs;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,15 +2,15 @@ package org.briarproject.plugins.tcp;
|
|||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -45,24 +45,23 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<SocketAddress> getLocalSocketAddresses() {
|
protected List<SocketAddress> getLocalSocketAddresses() {
|
||||||
List<SocketAddress> addrs = new ArrayList<SocketAddress>();
|
// Use the same address and port as last time if available
|
||||||
// Prefer a previously used address and port if available
|
|
||||||
TransportProperties p = callback.getLocalProperties();
|
TransportProperties p = callback.getLocalProperties();
|
||||||
String addrString = p.get("address");
|
String addressString = p.get("address");
|
||||||
String portString = p.get("port");
|
String portString = p.get("port");
|
||||||
InetAddress addr = null;
|
InetAddress oldAddress = null;
|
||||||
int port = 0;
|
int oldPort = 0;
|
||||||
if(!StringUtils.isNullOrEmpty(addrString) &&
|
if(!StringUtils.isNullOrEmpty(addressString) &&
|
||||||
!StringUtils.isNullOrEmpty(portString)) {
|
!StringUtils.isNullOrEmpty(portString)) {
|
||||||
try {
|
try {
|
||||||
addr = InetAddress.getByName(addrString);
|
oldAddress = InetAddress.getByName(addressString);
|
||||||
port = Integer.parseInt(portString);
|
oldPort = Integer.parseInt(portString);
|
||||||
addrs.add(new InetSocketAddress(addr, port));
|
|
||||||
addrs.add(new InetSocketAddress(addr, 0));
|
|
||||||
} catch(NumberFormatException e) {
|
} catch(NumberFormatException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.warning("Invalid port: " + portString);
|
||||||
} catch(UnknownHostException e) {
|
} catch(UnknownHostException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if(LOG.isLoggable(WARNING))
|
||||||
|
LOG.warning("Invalid address: " + addressString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get a list of the device's network interfaces
|
// Get a list of the device's network interfaces
|
||||||
@@ -71,27 +70,31 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
ifaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||||
} catch(SocketException e) {
|
} catch(SocketException e) {
|
||||||
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
return addrs;
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
List<SocketAddress> addresses = new LinkedList<SocketAddress>();
|
||||||
// Accept interfaces without link-local or site-local addresses
|
// Accept interfaces without link-local or site-local addresses
|
||||||
for(NetworkInterface iface : ifaces) {
|
for(NetworkInterface iface : ifaces) {
|
||||||
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
||||||
if(addr != null && a.equals(addr)) continue;
|
boolean ipv4 = a instanceof Inet4Address;
|
||||||
if(a instanceof Inet6Address) continue;
|
boolean loop = a.isLoopbackAddress();
|
||||||
if(a.isLoopbackAddress()) continue;
|
|
||||||
boolean link = a.isLinkLocalAddress();
|
boolean link = a.isLinkLocalAddress();
|
||||||
boolean site = a.isSiteLocalAddress();
|
boolean site = a.isSiteLocalAddress();
|
||||||
if(!link && !site) addrs.add(new InetSocketAddress(a, 0));
|
if(ipv4 && !loop && !link && !site) {
|
||||||
|
if(a.equals(oldAddress))
|
||||||
|
addresses.add(0, new InetSocketAddress(a, oldPort));
|
||||||
|
addresses.add(new InetSocketAddress(a, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Accept interfaces with local addresses that can be port-mapped
|
// Accept interfaces with local addresses that can be port-mapped
|
||||||
if(port == 0) port = chooseEphemeralPort();
|
if(oldPort == 0) oldPort = chooseEphemeralPort();
|
||||||
mappingResult = portMapper.map(port);
|
mappingResult = portMapper.map(oldPort);
|
||||||
if(mappingResult != null && mappingResult.isUsable()) {
|
if(mappingResult != null && mappingResult.isUsable()) {
|
||||||
InetSocketAddress a = mappingResult.getInternal();
|
InetSocketAddress a = mappingResult.getInternal();
|
||||||
if(!(a.getAddress() instanceof Inet6Address)) addrs.add(a);
|
if(a.getAddress() instanceof Inet4Address) addresses.add(a);
|
||||||
}
|
}
|
||||||
return addrs;
|
return addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int chooseEphemeralPort() {
|
private int chooseEphemeralPort() {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package org.briarproject.plugins.tcp;
|
|||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
@@ -29,24 +31,25 @@ public class LanTcpPluginTest extends BriarTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testIncomingConnection() throws Exception {
|
public void testIncomingConnection() throws Exception {
|
||||||
Callback callback = new Callback();
|
Callback callback = new Callback();
|
||||||
callback.local.put("address", "127.0.0.1");
|
|
||||||
callback.local.put("port", "0");
|
|
||||||
Executor executor = Executors.newCachedThreadPool();
|
Executor executor = Executors.newCachedThreadPool();
|
||||||
DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0);
|
DuplexPlugin plugin = new LanTcpPlugin(executor, callback, 0, 0, 0);
|
||||||
plugin.start();
|
plugin.start();
|
||||||
// The plugin should have bound a socket and stored the port number
|
// The plugin should have bound a socket and stored the port number
|
||||||
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
assertTrue(callback.propertiesLatch.await(5, SECONDS));
|
||||||
String host = callback.local.get("address");
|
String addrString = callback.local.get("address");
|
||||||
assertNotNull(host);
|
assertNotNull(addrString);
|
||||||
assertEquals("127.0.0.1", host);
|
InetAddress addr = InetAddress.getByName(addrString);
|
||||||
|
assertTrue(addr instanceof Inet4Address);
|
||||||
|
assertFalse(addr.isLoopbackAddress());
|
||||||
|
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
|
||||||
String portString = callback.local.get("port");
|
String portString = callback.local.get("port");
|
||||||
assertNotNull(portString);
|
assertNotNull(portString);
|
||||||
int port = Integer.parseInt(portString);
|
int port = Integer.parseInt(portString);
|
||||||
assertTrue(port > 0 && port < 65536);
|
assertTrue(port > 0 && port < 65536);
|
||||||
// The plugin should be listening on the port
|
// The plugin should be listening on the port
|
||||||
InetSocketAddress addr = new InetSocketAddress(host, port);
|
InetSocketAddress socketAddr = new InetSocketAddress(addr, port);
|
||||||
Socket s = new Socket();
|
Socket s = new Socket();
|
||||||
s.connect(addr, 100);
|
s.connect(socketAddr, 100);
|
||||||
assertTrue(callback.connectionsLatch.await(5, SECONDS));
|
assertTrue(callback.connectionsLatch.await(5, SECONDS));
|
||||||
s.close();
|
s.close();
|
||||||
// Stop the plugin
|
// Stop the plugin
|
||||||
|
|||||||
Reference in New Issue
Block a user