Merge branch 'network-prefix-length' into 'master'

Use network prefix length to determine which addresses are connectable

Closes #1178

See merge request briar/briar!1230
This commit is contained in:
Torsten Grote
2020-02-19 13:11:24 +00:00
5 changed files with 170 additions and 193 deletions

View File

@@ -19,7 +19,7 @@ import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Collection; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -84,19 +84,19 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
} }
@Override @Override
protected Collection<InetAddress> getLocalIpAddresses() { protected List<InetAddress> getUsableLocalInetAddresses() {
// If the device doesn't have wifi, don't open any sockets // If the device doesn't have wifi, don't open any sockets
if (wifiManager == null) return emptyList(); if (wifiManager == null) return emptyList();
// If we're connected to a wifi network, use that network // 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 singletonList(intToInetAddress(info.getIpAddress()));
}
// If we're running an access point, return its address // If we're running an access point, return its address
Collection<InetAddress> all = super.getLocalIpAddresses(); for (InetAddress addr : getLocalInetAddresses()) {
if (all.contains(WIFI_AP_ADDRESS)) if (addr.equals(WIFI_AP_ADDRESS)) return singletonList(addr);
return singletonList(WIFI_AP_ADDRESS); if (addr.equals(WIFI_DIRECT_AP_ADDRESS)) return singletonList(addr);
if (all.contains(WIFI_DIRECT_AP_ADDRESS)) }
return singletonList(WIFI_DIRECT_AP_ADDRESS);
// No suitable addresses // No suitable addresses
return emptyList(); return emptyList();
} }
@@ -136,7 +136,7 @@ class AndroidLanTcpPlugin extends LanTcpPlugin implements EventListener {
private void updateConnectionStatus() { private void updateConnectionStatus() {
connectionStatusExecutor.execute(() -> { connectionStatusExecutor.execute(() -> {
if (!running) return; if (!running) return;
Collection<InetAddress> addrs = getLocalIpAddresses(); List<InetAddress> addrs = getLocalInetAddresses();
if (addrs.contains(WIFI_AP_ADDRESS) if (addrs.contains(WIFI_AP_ADDRESS)
|| addrs.contains(WIFI_DIRECT_AP_ADDRESS)) { || addrs.contains(WIFI_DIRECT_AP_ADDRESS)) {
LOG.info("Providing wifi hotspot"); LOG.info("Providing wifi hotspot");

View File

@@ -17,12 +17,11 @@ import java.io.IOException;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -51,9 +50,6 @@ class LanTcpPlugin extends TcpPlugin {
private static final Logger LOG = getLogger(LanTcpPlugin.class.getName()); private static final Logger LOG = getLogger(LanTcpPlugin.class.getName());
private static final LanAddressComparator ADDRESS_COMPARATOR =
new LanAddressComparator();
private static final int MAX_ADDRESSES = 4; private static final int MAX_ADDRESSES = 4;
private static final String SEPARATOR = ","; private static final String SEPARATOR = ",";
@@ -111,28 +107,26 @@ class LanTcpPlugin extends TcpPlugin {
@Override @Override
protected List<InetSocketAddress> getLocalSocketAddresses() { protected List<InetSocketAddress> getLocalSocketAddresses() {
TransportProperties p = callback.getLocalProperties(); TransportProperties p = callback.getLocalProperties();
int port = parsePortProperty(p.get(PROP_PORT)); int preferredPort = parsePortProperty(p.get(PROP_PORT));
String oldIpPorts = p.get(PROP_IP_PORTS); String oldIpPorts = p.get(PROP_IP_PORTS);
List<InetSocketAddress> olds = parseSocketAddresses(oldIpPorts); List<InetSocketAddress> olds = parseSocketAddresses(oldIpPorts);
List<InetSocketAddress> locals = new ArrayList<>(); List<InetSocketAddress> locals = new ArrayList<>();
for (InetAddress local : getLocalIpAddresses()) { List<InetSocketAddress> fallbacks = new ArrayList<>();
if (isAcceptableAddress(local)) { for (InetAddress local : getUsableLocalInetAddresses()) {
// If we've used this address before, try to use the same port // If we've used this address before, try to use the same port
boolean reused = false; int port = preferredPort;
for (InetSocketAddress old : olds) { for (InetSocketAddress old : olds) {
if (old.getAddress().equals(local)) { if (old.getAddress().equals(local)) {
locals.add(new InetSocketAddress(local, old.getPort())); port = old.getPort();
reused = true; break;
break;
}
} }
// Otherwise try to use our preferred port
if (!reused) locals.add(new InetSocketAddress(local, port));
// Fall back to any available port
locals.add(new InetSocketAddress(local, 0));
} }
locals.add(new InetSocketAddress(local, port));
// Fall back to any available port
fallbacks.add(new InetSocketAddress(local, 0));
} }
sort(locals, ADDRESS_COMPARATOR); locals.addAll(fallbacks);
return locals; return locals;
} }
@@ -155,6 +149,20 @@ class LanTcpPlugin extends TcpPlugin {
return addresses; return addresses;
} }
protected List<InetAddress> getUsableLocalInetAddresses() {
List<InterfaceAddress> ifAddrs =
new ArrayList<>(getLocalInterfaceAddresses());
// Prefer longer network prefixes
sort(ifAddrs, (a, b) ->
b.getNetworkPrefixLength() - a.getNetworkPrefixLength());
List<InetAddress> addrs = new ArrayList<>();
for (InterfaceAddress ifAddr : ifAddrs) {
InetAddress addr = ifAddr.getAddress();
if (isAcceptableAddress(addr)) addrs.add(addr);
}
return addrs;
}
@Override @Override
protected void setLocalSocketAddress(InetSocketAddress a) { protected void setLocalSocketAddress(InetSocketAddress a) {
String ipPort = getIpPortString(a); String ipPort = getIpPortString(a);
@@ -218,55 +226,31 @@ class LanTcpPlugin extends TcpPlugin {
} }
@Override @Override
protected boolean isConnectable(InetSocketAddress remote) { protected boolean isConnectable(InterfaceAddress local,
InetSocketAddress remote) {
if (remote.getPort() == 0) return false; if (remote.getPort() == 0) return false;
if (!isAcceptableAddress(remote.getAddress())) return false; if (!isAcceptableAddress(remote.getAddress())) return false;
// Try to determine whether the address is on the same LAN as us // Try to determine whether the address is on the same LAN as us
if (socket == null) return false; byte[] localIp = local.getAddress().getAddress();
byte[] localIp = socket.getInetAddress().getAddress();
byte[] remoteIp = remote.getAddress().getAddress(); byte[] remoteIp = remote.getAddress().getAddress();
return addressesAreOnSameLan(localIp, remoteIp); int prefixLength = local.getNetworkPrefixLength();
return areAddressesInSameNetwork(localIp, remoteIp, prefixLength);
} }
// Package access for testing // Package access for testing
boolean addressesAreOnSameLan(byte[] localIp, byte[] remoteIp) { static boolean areAddressesInSameNetwork(byte[] localIp, byte[] remoteIp,
// 10.0.0.0/8 int prefixLength) {
if (isSlash8SiteLocal(localIp)) return isSlash8SiteLocal(remoteIp); if (localIp.length != remoteIp.length) return false;
// 172.16.0.0/12 // Compare the first prefixLength bits of the addresses
if (isSlash12SiteLocal(localIp)) return isSlash12SiteLocal(remoteIp); for (int i = 0; i < prefixLength; i++) {
// 192.168.0.0/16 int byteIndex = i >> 3;
if (isSlash16SiteLocal(localIp)) return isSlash16SiteLocal(remoteIp); int bitIndex = i & 7; // 0 to 7
// 169.254.0.0/16 int mask = 128 >> bitIndex; // Select the bit at bitIndex
if (isSlash16LinkLocal(localIp)) return isSlash16LinkLocal(remoteIp); if ((localIp[byteIndex] & mask) != (remoteIp[byteIndex] & mask)) {
// Unrecognised prefix return false; // Addresses differ at bit i
return false; }
} }
return true;
private static boolean isSlash8SiteLocal(byte[] ipv4) {
return ipv4[0] == 10;
}
private static boolean isSlash12SiteLocal(byte[] ipv4) {
return ipv4[0] == (byte) 172 && (ipv4[1] & 0xF0) == 16;
}
private static boolean isSlash16SiteLocal(byte[] ipv4) {
return ipv4[0] == (byte) 192 && ipv4[1] == (byte) 168;
}
private static boolean isSlash16LinkLocal(byte[] ipv4) {
return ipv4[0] == (byte) 169 && ipv4[1] == (byte) 254;
}
// Returns the prefix length for a link-local or site-local address, or 0
// for any other address
private static int getPrefixLengthIfKnown(InetAddress addr) {
if (!(addr instanceof Inet4Address)) return 0;
byte[] ipv4 = addr.getAddress();
if (isSlash8SiteLocal(ipv4)) return 8;
if (isSlash12SiteLocal(ipv4)) return 12;
if (isSlash16SiteLocal(ipv4) || isSlash16LinkLocal(ipv4)) return 16;
return 0;
} }
@Override @Override
@@ -307,6 +291,12 @@ class LanTcpPlugin extends TcpPlugin {
public DuplexTransportConnection createKeyAgreementConnection( public DuplexTransportConnection createKeyAgreementConnection(
byte[] commitment, BdfList descriptor) { byte[] commitment, BdfList descriptor) {
if (!isRunning()) return null; if (!isRunning()) return null;
ServerSocket ss = socket;
InterfaceAddress local = getLocalInterfaceAddress(ss.getInetAddress());
if (local == null) {
LOG.warning("No interface for key agreement server socket");
return null;
}
InetSocketAddress remote; InetSocketAddress remote;
try { try {
remote = parseSocketAddress(descriptor); remote = parseSocketAddress(descriptor);
@@ -314,12 +304,11 @@ class LanTcpPlugin extends TcpPlugin {
LOG.info("Invalid IP/port in key agreement descriptor"); LOG.info("Invalid IP/port in key agreement descriptor");
return null; return null;
} }
if (!isConnectable(remote)) { if (!isConnectable(local, remote)) {
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
SocketAddress local = socket.getLocalSocketAddress();
LOG.info(scrubSocketAddress(remote) + LOG.info(scrubSocketAddress(remote) +
" is not connectable from " + " is not connectable from " +
scrubSocketAddress(local)); scrubSocketAddress(ss.getLocalSocketAddress()));
} }
return null; return null;
} }
@@ -327,7 +316,7 @@ class LanTcpPlugin extends TcpPlugin {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubSocketAddress(remote)); LOG.info("Connecting to " + scrubSocketAddress(remote));
Socket s = createSocket(); Socket s = createSocket();
s.bind(new InetSocketAddress(socket.getInetAddress(), 0)); s.bind(new InetSocketAddress(ss.getInetAddress(), 0));
s.connect(remote, connectionTimeout); s.connect(remote, connectionTimeout);
s.setSoTimeout(socketTimeout); s.setSoTimeout(socketTimeout);
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
@@ -377,19 +366,4 @@ class LanTcpPlugin extends TcpPlugin {
IoUtils.tryToClose(ss, LOG, WARNING); IoUtils.tryToClose(ss, LOG, WARNING);
} }
} }
static class LanAddressComparator implements Comparator<InetSocketAddress> {
@Override
public int compare(InetSocketAddress a, InetSocketAddress b) {
// Prefer addresses with non-zero ports
int aPort = a.getPort(), bPort = b.getPort();
if (aPort > 0 && bPort == 0) return -1;
if (aPort == 0 && bPort > 0) return 1;
// Prefer addresses with longer prefixes
int aPrefix = getPrefixLengthIfKnown(a.getAddress());
int bPrefix = getPrefixLengthIfKnown(b.getAddress());
return bPrefix - aPrefix;
}
}
} }

View File

@@ -19,10 +19,10 @@ import org.briarproject.bramble.util.IoUtils;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface; import java.net.NetworkInterface;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
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.ArrayList;
@@ -36,7 +36,6 @@ import java.util.regex.Pattern;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static java.net.NetworkInterface.getNetworkInterfaces;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.list; import static java.util.Collections.list;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
@@ -88,7 +87,8 @@ abstract class TcpPlugin implements DuplexPlugin {
* Returns true if connections to the given address can be attempted. * Returns true if connections to the given address can be attempted.
*/ */
@SuppressWarnings("BooleanMethodIsAlwaysInverted") @SuppressWarnings("BooleanMethodIsAlwaysInverted")
protected abstract boolean isConnectable(InetSocketAddress remote); protected abstract boolean isConnectable(InterfaceAddress local,
InetSocketAddress remote);
TcpPlugin(Executor ioExecutor, Backoff backoff, PluginCallback callback, TcpPlugin(Executor ioExecutor, Backoff backoff, PluginCallback callback,
int maxLatency, int maxIdleTime, int connectionTimeout) { int maxLatency, int maxIdleTime, int connectionTimeout) {
@@ -233,18 +233,23 @@ abstract class TcpPlugin implements DuplexPlugin {
@Override @Override
public DuplexTransportConnection createConnection(TransportProperties p) { public DuplexTransportConnection createConnection(TransportProperties p) {
if (!isRunning()) return null; if (!isRunning()) return null;
ServerSocket ss = socket;
InterfaceAddress local = getLocalInterfaceAddress(ss.getInetAddress());
if (local == null) {
LOG.warning("No interface for server socket");
return null;
}
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) { for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
// Don't try to connect to our own address // Don't try to connect to our own address
if (!canConnectToOwnAddress() && if (!canConnectToOwnAddress() &&
remote.getAddress().equals(socket.getInetAddress())) { remote.getAddress().equals(ss.getInetAddress())) {
continue; continue;
} }
if (!isConnectable(remote)) { if (!isConnectable(local, remote)) {
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
SocketAddress local = socket.getLocalSocketAddress();
LOG.info(scrubSocketAddress(remote) + LOG.info(scrubSocketAddress(remote) +
" is not connectable from " + " is not connectable from " +
scrubSocketAddress(local)); scrubSocketAddress(ss.getLocalSocketAddress()));
} }
continue; continue;
} }
@@ -252,7 +257,7 @@ abstract class TcpPlugin implements DuplexPlugin {
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
LOG.info("Connecting to " + scrubSocketAddress(remote)); LOG.info("Connecting to " + scrubSocketAddress(remote));
Socket s = createSocket(); Socket s = createSocket();
s.bind(new InetSocketAddress(socket.getInetAddress(), 0)); s.bind(new InetSocketAddress(ss.getInetAddress(), 0));
s.connect(remote, connectionTimeout); s.connect(remote, connectionTimeout);
s.setSoTimeout(socketTimeout); s.setSoTimeout(socketTimeout);
if (LOG.isLoggable(INFO)) if (LOG.isLoggable(INFO))
@@ -267,6 +272,14 @@ abstract class TcpPlugin implements DuplexPlugin {
return null; return null;
} }
@Nullable
InterfaceAddress getLocalInterfaceAddress(InetAddress a) {
for (InterfaceAddress ifAddr : getLocalInterfaceAddresses()) {
if (ifAddr.getAddress().equals(a)) return ifAddr;
}
return null;
}
// Override for testing // Override for testing
protected boolean canConnectToOwnAddress() { protected boolean canConnectToOwnAddress() {
return false; return false;
@@ -327,14 +340,27 @@ abstract class TcpPlugin implements DuplexPlugin {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
Collection<InetAddress> getLocalIpAddresses() { List<InterfaceAddress> getLocalInterfaceAddresses() {
List<InterfaceAddress> addrs = new ArrayList<>();
for (NetworkInterface iface : getNetworkInterfaces()) {
addrs.addAll(iface.getInterfaceAddresses());
}
return addrs;
}
List<InetAddress> getLocalInetAddresses() {
List<InetAddress> addrs = new ArrayList<>();
for (NetworkInterface iface : getNetworkInterfaces()) {
addrs.addAll(list(iface.getInetAddresses()));
}
return addrs;
}
private List<NetworkInterface> getNetworkInterfaces() {
try { try {
Enumeration<NetworkInterface> ifaces = getNetworkInterfaces(); Enumeration<NetworkInterface> ifaces =
if (ifaces == null) return emptyList(); NetworkInterface.getNetworkInterfaces();
List<InetAddress> addrs = new ArrayList<>(); return ifaces == null ? emptyList() : list(ifaces);
for (NetworkInterface iface : list(ifaces))
addrs.addAll(list(iface.getInetAddresses()));
return addrs;
} catch (SocketException e) { } catch (SocketException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
return emptyList(); return emptyList();

View File

@@ -10,6 +10,7 @@ import org.briarproject.bramble.api.properties.TransportProperties;
import java.net.Inet4Address; import java.net.Inet4Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.InterfaceAddress;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -47,7 +48,7 @@ class WanTcpPlugin extends TcpPlugin {
TransportProperties p = callback.getLocalProperties(); TransportProperties p = callback.getLocalProperties();
InetSocketAddress old = parseSocketAddress(p.get(PROP_IP_PORT)); InetSocketAddress old = parseSocketAddress(p.get(PROP_IP_PORT));
List<InetSocketAddress> addrs = new LinkedList<>(); List<InetSocketAddress> addrs = new LinkedList<>();
for (InetAddress a : getLocalIpAddresses()) { for (InetAddress a : getLocalInetAddresses()) {
if (isAcceptableAddress(a)) { if (isAcceptableAddress(a)) {
// If this is the old address, try to use the same port // If this is the old address, try to use the same port
if (old != null && old.getAddress().equals(a)) if (old != null && old.getAddress().equals(a))
@@ -88,7 +89,8 @@ class WanTcpPlugin extends TcpPlugin {
} }
@Override @Override
protected boolean isConnectable(InetSocketAddress remote) { protected boolean isConnectable(InterfaceAddress local,
InetSocketAddress remote) {
if (remote.getPort() == 0) return false; if (remote.getPort() == 0) return false;
return isAcceptableAddress(remote.getAddress()); return isAcceptableAddress(remote.getAddress());
} }

View File

@@ -10,7 +10,6 @@ import org.briarproject.bramble.api.plugin.TransportConnectionWriter;
import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.settings.Settings; import org.briarproject.bramble.api.settings.Settings;
import org.briarproject.bramble.plugin.tcp.LanTcpPlugin.LanAddressComparator;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -22,7 +21,6 @@ import java.net.InetSocketAddress;
import java.net.NetworkInterface; import java.net.NetworkInterface;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.util.Comparator;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -33,6 +31,7 @@ import static java.util.concurrent.Executors.newCachedThreadPool;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.COMMIT_LENGTH;
import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN;
import static org.briarproject.bramble.plugin.tcp.LanTcpPlugin.areAddressesInSameNetwork;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@@ -59,44 +58,62 @@ public class LanTcpPluginTest extends BrambleTestCase {
} }
@Test @Test
public void testAddressesAreOnSameLan() { public void testAreAddressesInSameNetwork() {
// Local and remote in 10.0.0.0/8 should return true // Local and remote in 10.0.0.0/8
assertTrue(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0), assertTrue(areAddressesInSameNetwork(makeAddress(10, 0, 0, 0),
makeAddress(10, 255, 255, 255))); makeAddress(10, 255, 255, 255), 8));
// Local and remote in 172.16.0.0/12 should return true assertFalse(areAddressesInSameNetwork(makeAddress(10, 0, 0, 0),
assertTrue(plugin.addressesAreOnSameLan(makeAddress(172, 16, 0, 0), makeAddress(10, 255, 255, 255), 9));
makeAddress(172, 31, 255, 255)));
// Local and remote in 192.168.0.0/16 should return true // Local and remote in 172.16.0.0/12
assertTrue(plugin.addressesAreOnSameLan(makeAddress(192, 168, 0, 0), assertTrue(areAddressesInSameNetwork(makeAddress(172, 16, 0, 0),
makeAddress(192, 168, 255, 255))); makeAddress(172, 31, 255, 255), 12));
// Local and remote in 169.254.0.0/16 (link-local) should return true assertFalse(areAddressesInSameNetwork(makeAddress(172, 16, 0, 0),
assertTrue(plugin.addressesAreOnSameLan(makeAddress(169, 254, 0, 0), makeAddress(172, 31, 255, 255), 13));
makeAddress(169, 254, 255, 255)));
// Local and remote in different recognised prefixes should return false // Local and remote in 192.168.0.0/16
assertFalse(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0), assertTrue(areAddressesInSameNetwork(makeAddress(192, 168, 0, 0),
makeAddress(172, 31, 255, 255))); makeAddress(192, 168, 255, 255), 16));
assertFalse(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0), assertFalse(areAddressesInSameNetwork(makeAddress(192, 168, 0, 0),
makeAddress(192, 168, 255, 255))); makeAddress(192, 168, 255, 255), 17));
assertFalse(plugin.addressesAreOnSameLan(makeAddress(172, 16, 0, 0),
makeAddress(10, 255, 255, 255))); // Local and remote in 169.254.0.0/16
assertFalse(plugin.addressesAreOnSameLan(makeAddress(172, 16, 0, 0), assertTrue(areAddressesInSameNetwork(makeAddress(169, 254, 0, 0),
makeAddress(192, 168, 255, 255))); makeAddress(169, 254, 255, 255), 16));
assertFalse(plugin.addressesAreOnSameLan(makeAddress(192, 168, 0, 0), assertFalse(areAddressesInSameNetwork(makeAddress(169, 254, 0, 0),
makeAddress(10, 255, 255, 255))); makeAddress(169, 254, 255, 255), 17));
assertFalse(plugin.addressesAreOnSameLan(makeAddress(192, 168, 0, 0),
makeAddress(172, 31, 255, 255))); // Local in 10.0.0.0/8, remote in a different network
assertFalse(plugin.addressesAreOnSameLan(makeAddress(169, 254, 0, 0), assertFalse(areAddressesInSameNetwork(makeAddress(10, 0, 0, 0),
makeAddress(192, 168, 255, 255))); makeAddress(172, 31, 255, 255), 8));
// Remote prefix unrecognised should return false assertFalse(areAddressesInSameNetwork(makeAddress(10, 0, 0, 0),
assertFalse(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0), makeAddress(192, 168, 255, 255), 8));
makeAddress(1, 2, 3, 4))); assertFalse(areAddressesInSameNetwork(makeAddress(10, 0, 0, 0),
assertFalse(plugin.addressesAreOnSameLan(makeAddress(172, 16, 0, 0), makeAddress(169, 254, 255, 255), 8));
makeAddress(1, 2, 3, 4)));
assertFalse(plugin.addressesAreOnSameLan(makeAddress(192, 168, 0, 0), // Local in 172.16.0.0/12, remote in a different network
makeAddress(1, 2, 3, 4))); assertFalse(areAddressesInSameNetwork(makeAddress(172, 16, 0, 0),
// Both prefixes unrecognised should return false makeAddress(10, 255, 255, 255), 12));
assertFalse(plugin.addressesAreOnSameLan(makeAddress(1, 2, 3, 4), assertFalse(areAddressesInSameNetwork(makeAddress(172, 16, 0, 0),
makeAddress(5, 6, 7, 8))); makeAddress(192, 168, 255, 255), 12));
assertFalse(areAddressesInSameNetwork(makeAddress(172, 16, 0, 0),
makeAddress(169, 254, 255, 255), 12));
// Local in 192.168.0.0/16, remote in a different network
assertFalse(areAddressesInSameNetwork(makeAddress(192, 168, 0, 0),
makeAddress(10, 255, 255, 255), 16));
assertFalse(areAddressesInSameNetwork(makeAddress(192, 168, 0, 0),
makeAddress(172, 31, 255, 255), 16));
assertFalse(areAddressesInSameNetwork(makeAddress(192, 168, 0, 0),
makeAddress(169, 254, 255, 255), 16));
// Local in 169.254.0.0/16, remote in a different network
assertFalse(areAddressesInSameNetwork(makeAddress(169, 254, 0, 0),
makeAddress(10, 255, 255, 255), 16));
assertFalse(areAddressesInSameNetwork(makeAddress(169, 254, 0, 0),
makeAddress(172, 31, 255, 255), 16));
assertFalse(areAddressesInSameNetwork(makeAddress(169, 254, 0, 0),
makeAddress(192, 168, 255, 255), 16));
} }
private byte[] makeAddress(int... parts) { private byte[] makeAddress(int... parts) {
@@ -266,54 +283,12 @@ public class LanTcpPluginTest extends BrambleTestCase {
plugin.stop(); plugin.stop();
} }
@Test
public void testComparatorPrefersNonZeroPorts() {
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
InetSocketAddress nonZero = new InetSocketAddress("1.2.3.4", 1234);
InetSocketAddress zero = new InetSocketAddress("1.2.3.4", 0);
assertEquals(0, comparator.compare(nonZero, nonZero));
assertTrue(comparator.compare(nonZero, zero) < 0);
assertTrue(comparator.compare(zero, nonZero) > 0);
assertEquals(0, comparator.compare(zero, zero));
}
@Test
public void testComparatorPrefersLongerPrefixes() {
Comparator<InetSocketAddress> comparator = new LanAddressComparator();
InetSocketAddress prefix169 = new InetSocketAddress("169.254.0.1", 0);
InetSocketAddress prefix192 = new InetSocketAddress("192.168.0.1", 0);
InetSocketAddress prefix172 = new InetSocketAddress("172.16.0.1", 0);
InetSocketAddress prefix10 = new InetSocketAddress("10.0.0.1", 0);
assertEquals(0, comparator.compare(prefix169, prefix169));
assertEquals(0, comparator.compare(prefix169, prefix192));
assertTrue(comparator.compare(prefix169, prefix172) < 0);
assertTrue(comparator.compare(prefix169, prefix10) < 0);
assertEquals(0, comparator.compare(prefix192, prefix192));
assertEquals(0, comparator.compare(prefix192, prefix169));
assertTrue(comparator.compare(prefix192, prefix172) < 0);
assertTrue(comparator.compare(prefix192, prefix10) < 0);
assertTrue(comparator.compare(prefix172, prefix169) > 0);
assertTrue(comparator.compare(prefix172, prefix192) > 0);
assertEquals(0, comparator.compare(prefix172, prefix172));
assertTrue(comparator.compare(prefix172, prefix10) < 0);
assertTrue(comparator.compare(prefix10, prefix169) > 0);
assertTrue(comparator.compare(prefix10, prefix192) > 0);
assertTrue(comparator.compare(prefix10, prefix172) > 0);
assertEquals(0, comparator.compare(prefix10, prefix10));
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean systemHasLocalIpv4Address() throws Exception { private boolean systemHasLocalIpv4Address() throws Exception {
for (NetworkInterface i : list(getNetworkInterfaces())) { for (NetworkInterface i : list(getNetworkInterfaces())) {
for (InetAddress a : list(i.getInetAddresses())) { for (InetAddress a : list(i.getInetAddresses())) {
if (a instanceof Inet4Address) if (a instanceof Inet4Address) {
return a.isLinkLocalAddress() || a.isSiteLocalAddress(); return a.isLinkLocalAddress() || a.isSiteLocalAddress();
}
} }
} }
return false; return false;