mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 11:19:04 +01:00
Don't try to connect to unreachable IP addresses.
This commit is contained in:
@@ -50,14 +50,9 @@ class LanTcpPlugin extends TcpPlugin {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<SocketAddress> addrs = new LinkedList<SocketAddress>();
|
||||
// Accept interfaces with local IPv4 addresses
|
||||
for(NetworkInterface iface : ifaces) {
|
||||
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
||||
boolean ipv4 = a instanceof Inet4Address;
|
||||
boolean loop = a.isLoopbackAddress();
|
||||
boolean link = a.isLinkLocalAddress();
|
||||
boolean site = a.isSiteLocalAddress();
|
||||
if(ipv4 && !loop && (link || site)) {
|
||||
if(isAcceptableAddress(a)) {
|
||||
// If this is the old address, try to use the same port
|
||||
if(old != null && old.getAddress().equals(a))
|
||||
addrs.add(0, new InetSocketAddress(a, old.getPort()));
|
||||
@@ -67,4 +62,38 @@ class LanTcpPlugin extends TcpPlugin {
|
||||
}
|
||||
return addrs;
|
||||
}
|
||||
|
||||
private boolean isAcceptableAddress(InetAddress a) {
|
||||
// Accept link-local and site-local IPv4 addresses
|
||||
boolean ipv4 = a instanceof Inet4Address;
|
||||
boolean loop = a.isLoopbackAddress();
|
||||
boolean link = a.isLinkLocalAddress();
|
||||
boolean site = a.isSiteLocalAddress();
|
||||
return ipv4 && !loop && (link || site);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConnectable(InetSocketAddress remote) {
|
||||
if(remote.getPort() == 0) return false;
|
||||
if(!isAcceptableAddress(remote.getAddress())) return false;
|
||||
// Try to determine whether the address is on the same LAN as us
|
||||
if(socket == null) return true;
|
||||
byte[] localIp = socket.getInetAddress().getAddress();
|
||||
byte[] remoteIp = remote.getAddress().getAddress();
|
||||
return addressesAreOnSameLan(localIp, remoteIp);
|
||||
}
|
||||
|
||||
// Package access for testing
|
||||
boolean addressesAreOnSameLan(byte[] localIp, byte[] remoteIp) {
|
||||
// 10.0.0.0/8
|
||||
if(localIp[0] == 10) return remoteIp[0] == 10;
|
||||
// 172.16.0.0/12
|
||||
if(localIp[0] == (byte) 172 && (localIp[1] & 0xF0) == 16)
|
||||
return remoteIp[0] == (byte) 172 && (remoteIp[1] & 0xF0) == 16;
|
||||
// 192.168.0.0/16
|
||||
if(localIp[0] == (byte) 192 && localIp[1] == (byte) 168)
|
||||
return remoteIp[0] == (byte) 192 && remoteIp[1] == (byte) 168;
|
||||
// Unrecognised prefix - may be compatible
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ import java.net.SocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -46,6 +45,9 @@ abstract class TcpPlugin implements DuplexPlugin {
|
||||
*/
|
||||
protected abstract List<SocketAddress> getLocalSocketAddresses();
|
||||
|
||||
/** Returns true if connections to the given address can be attempted. */
|
||||
protected abstract boolean isConnectable(InetSocketAddress remote);
|
||||
|
||||
protected TcpPlugin(Executor pluginExecutor, DuplexPluginCallback callback,
|
||||
int maxFrameLength, long maxLatency, long pollingInterval) {
|
||||
this.pluginExecutor = pluginExecutor;
|
||||
@@ -162,40 +164,40 @@ abstract class TcpPlugin implements DuplexPlugin {
|
||||
|
||||
public void poll(Collection<ContactId> connected) {
|
||||
if(!isRunning()) return;
|
||||
Map<ContactId, TransportProperties> remote =
|
||||
callback.getRemoteProperties();
|
||||
for(final ContactId c : remote.keySet()) {
|
||||
if(connected.contains(c)) continue;
|
||||
pluginExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
connectAndCallBack(c);
|
||||
}
|
||||
});
|
||||
}
|
||||
for(ContactId c : callback.getRemoteProperties().keySet())
|
||||
if(!connected.contains(c)) connectAndCallBack(c);
|
||||
}
|
||||
|
||||
private void connectAndCallBack(ContactId c) {
|
||||
DuplexTransportConnection d = createConnection(c);
|
||||
if(d != null) callback.outgoingConnectionCreated(c, d);
|
||||
private void connectAndCallBack(final ContactId c) {
|
||||
pluginExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
DuplexTransportConnection d = createConnection(c);
|
||||
if(d != null) callback.outgoingConnectionCreated(c, d);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public DuplexTransportConnection createConnection(ContactId c) {
|
||||
if(!isRunning()) return null;
|
||||
SocketAddress addr = getRemoteSocketAddress(c);
|
||||
if(addr == null) return null;
|
||||
InetSocketAddress remote = getRemoteSocketAddress(c);
|
||||
if(remote == null) return null;
|
||||
if(!isConnectable(remote)) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info(remote + " is not connectable");
|
||||
return null;
|
||||
}
|
||||
Socket s = new Socket();
|
||||
try {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Connecting to " + addr);
|
||||
s.connect(addr);
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Connected to " + addr);
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Connecting to " + remote);
|
||||
s.connect(remote);
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Connected to " + remote);
|
||||
return new TcpTransportConnection(this, s);
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Could not connect to " + addr);
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Could not connect to " + remote);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private SocketAddress getRemoteSocketAddress(ContactId c) {
|
||||
private InetSocketAddress getRemoteSocketAddress(ContactId c) {
|
||||
TransportProperties p = callback.getRemoteProperties().get(c);
|
||||
if(p == null) return null;
|
||||
return parseSocketAddress(p.get("address"), p.get("port"));
|
||||
|
||||
@@ -56,14 +56,9 @@ class WanTcpPlugin extends TcpPlugin {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<SocketAddress> addrs = new LinkedList<SocketAddress>();
|
||||
// Accept interfaces without global IPv4 addresses
|
||||
for(NetworkInterface iface : ifaces) {
|
||||
for(InetAddress a : Collections.list(iface.getInetAddresses())) {
|
||||
boolean ipv4 = a instanceof Inet4Address;
|
||||
boolean loop = a.isLoopbackAddress();
|
||||
boolean link = a.isLinkLocalAddress();
|
||||
boolean site = a.isSiteLocalAddress();
|
||||
if(ipv4 && !loop && !link && !site) {
|
||||
if(isAcceptableAddress(a)) {
|
||||
// If this is the old address, try to use the same port
|
||||
if(old != null && old.getAddress().equals(a))
|
||||
addrs.add(0, new InetSocketAddress(a, old.getPort()));
|
||||
@@ -81,10 +76,25 @@ class WanTcpPlugin extends TcpPlugin {
|
||||
return addrs;
|
||||
}
|
||||
|
||||
private boolean isAcceptableAddress(InetAddress a) {
|
||||
// Accept global IPv4 addresses
|
||||
boolean ipv4 = a instanceof Inet4Address;
|
||||
boolean loop = a.isLoopbackAddress();
|
||||
boolean link = a.isLinkLocalAddress();
|
||||
boolean site = a.isSiteLocalAddress();
|
||||
return ipv4 && !loop && !link && !site;
|
||||
}
|
||||
|
||||
private int chooseEphemeralPort() {
|
||||
return 32768 + (int) (Math.random() * 32768);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConnectable(InetSocketAddress remote) {
|
||||
if(remote.getPort() == 0) return false;
|
||||
return isAcceptableAddress(remote.getAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setLocalSocketAddress(InetSocketAddress a) {
|
||||
if(mappingResult != null && mappingResult.isUsable()) {
|
||||
|
||||
@@ -28,6 +28,49 @@ public class LanTcpPluginTest extends BriarTestCase {
|
||||
|
||||
private final ContactId contactId = new ContactId(234);
|
||||
|
||||
@Test
|
||||
public void testAddressesAreOnSameLan() {
|
||||
LanTcpPlugin plugin = new LanTcpPlugin(null, null, 0, 0, 0);
|
||||
// Local and remote in 10.0.0.0/8 should return true
|
||||
assertTrue(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0),
|
||||
makeAddress(10, 255, 255, 255)));
|
||||
// Local and remote in 172.16.0.0/12 should return true
|
||||
assertTrue(plugin.addressesAreOnSameLan(makeAddress(172, 16, 0, 0),
|
||||
makeAddress(172, 31, 255, 255)));
|
||||
// Local and remote in 192.168.0.0/16 should return true
|
||||
assertTrue(plugin.addressesAreOnSameLan(makeAddress(192, 168, 0, 0),
|
||||
makeAddress(192, 168, 255, 255)));
|
||||
// Local and remote in different recognised prefixes should return false
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0),
|
||||
makeAddress(172, 31, 255, 255)));
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0),
|
||||
makeAddress(192, 168, 255, 255)));
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(172, 16, 0, 0),
|
||||
makeAddress(10, 255, 255, 255)));
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(172, 16, 0, 0),
|
||||
makeAddress(192, 168, 255, 255)));
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(192, 168, 0, 0),
|
||||
makeAddress(10, 255, 255, 255)));
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(192, 168, 0, 0),
|
||||
makeAddress(172, 31, 255, 255)));
|
||||
// Remote prefix unrecognised should return false
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(10, 0, 0, 0),
|
||||
makeAddress(1, 2, 3, 4)));
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(172, 16, 0, 0),
|
||||
makeAddress(1, 2, 3, 4)));
|
||||
assertFalse(plugin.addressesAreOnSameLan(makeAddress(192, 168, 0, 0),
|
||||
makeAddress(1, 2, 3, 4)));
|
||||
// Both prefixes unrecognised should return true (could be link-local)
|
||||
assertTrue(plugin.addressesAreOnSameLan(makeAddress(1, 2, 3, 4),
|
||||
makeAddress(5, 6, 7, 8)));
|
||||
}
|
||||
|
||||
private byte[] makeAddress(int... parts) {
|
||||
byte[] b = new byte[parts.length];
|
||||
for(int i = 0; i < parts.length; i++) b[i] = (byte) parts[i];
|
||||
return b;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncomingConnection() throws Exception {
|
||||
Callback callback = new Callback();
|
||||
|
||||
Reference in New Issue
Block a user