mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Support IPv6 SLAAC addresses.
This commit is contained in:
@@ -83,7 +83,12 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<InetAddress> getUsableLocalInetAddresses() {
|
protected List<InetAddress> getUsableLocalInetAddresses(boolean ipv4) {
|
||||||
|
if (ipv4) return getUsableLocalIpv4Addresses();
|
||||||
|
else return getUsableLocalIpv6Addresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InetAddress> getUsableLocalIpv4Addresses() {
|
||||||
// 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, return its address
|
// If we're connected to a wifi network, return its address
|
||||||
@@ -100,6 +105,17 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
return emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<InetAddress> getUsableLocalIpv6Addresses() {
|
||||||
|
// If the device doesn't have wifi, don't open any sockets
|
||||||
|
if (wifiManager == null) return emptyList();
|
||||||
|
// If we have a SLAAC address, return it
|
||||||
|
for (InetAddress addr : getLocalInetAddresses()) {
|
||||||
|
if (isSlaacAddress(addr)) return singletonList(addr);
|
||||||
|
}
|
||||||
|
// No suitable addresses
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
private InetAddress intToInetAddress(int ip) {
|
private InetAddress intToInetAddress(int ip) {
|
||||||
byte[] ipBytes = new byte[4];
|
byte[] ipBytes = new byte[4];
|
||||||
ipBytes[0] = (byte) (ip & 0xFF);
|
ipBytes[0] = (byte) (ip & 0xFF);
|
||||||
@@ -150,12 +166,13 @@ class AndroidLanTcpPlugin extends LanTcpPlugin {
|
|||||||
} else if (addrs.isEmpty()) {
|
} else if (addrs.isEmpty()) {
|
||||||
LOG.info("Not connected to wifi");
|
LOG.info("Not connected to wifi");
|
||||||
socketFactory = SocketFactory.getDefault();
|
socketFactory = SocketFactory.getDefault();
|
||||||
// Server socket may not have been closed automatically when
|
// Server sockets may not have been closed automatically when
|
||||||
// interface was taken down. Socket will be cleared and state
|
// interface was taken down. Sockets will be cleared and state
|
||||||
// updated in acceptContactConnections()
|
// updated in acceptContactConnections()
|
||||||
if (s == ACTIVE) {
|
if (s == ACTIVE) {
|
||||||
LOG.info("Closing server socket");
|
LOG.info("Closing server sockets");
|
||||||
tryToClose(state.getServerSocket(), LOG, WARNING);
|
tryToClose(state.getServerSocket(true), LOG, WARNING);
|
||||||
|
tryToClose(state.getServerSocket(false), LOG, WARNING);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.info("Connected to wifi");
|
LOG.info("Connected to wifi");
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ public interface LanTcpConstants {
|
|||||||
// Transport properties (shared with contacts)
|
// Transport properties (shared with contacts)
|
||||||
String PROP_IP_PORTS = "ipPorts";
|
String PROP_IP_PORTS = "ipPorts";
|
||||||
String PROP_PORT = "port";
|
String PROP_PORT = "port";
|
||||||
|
String PROP_SLAAC = "slaac";
|
||||||
|
|
||||||
// A local setting
|
// A local setting
|
||||||
String PREF_LAN_IP_PORTS = "ipPorts";
|
String PREF_LAN_IP_PORTS = "ipPorts";
|
||||||
|
|||||||
@@ -2,13 +2,17 @@ package org.briarproject.bramble.util;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
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.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.isValidMac;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class PrivacyUtils {
|
public class PrivacyUtils {
|
||||||
|
|
||||||
@@ -19,7 +23,7 @@ public class PrivacyUtils {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static String scrubMacAddress(@Nullable String address) {
|
public static String scrubMacAddress(@Nullable String address) {
|
||||||
if (address == null || address.length() == 0) return null;
|
if (isNullOrEmpty(address) || !isValidMac(address)) return address;
|
||||||
// this is a fake address we need to know about
|
// this is a fake address we need to know about
|
||||||
if (address.equals("02:00:00:00:00:00")) return address;
|
if (address.equals("02:00:00:00:00:00")) return address;
|
||||||
// keep first and last octet of MAC address
|
// keep first and last octet of MAC address
|
||||||
@@ -27,39 +31,37 @@ public class PrivacyUtils {
|
|||||||
+ address.substring(14, 17);
|
+ address.substring(14, 17);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static String scrubInetAddress(InetAddress address) {
|
public static String scrubInetAddress(InetAddress address) {
|
||||||
// don't scrub link and site local addresses
|
if (address instanceof Inet4Address) {
|
||||||
if (address.isLinkLocalAddress() || address.isSiteLocalAddress())
|
// Don't scrub local IPv4 addresses
|
||||||
return address.toString();
|
if (address.isLoopbackAddress() || address.isLinkLocalAddress() ||
|
||||||
// completely scrub IPv6 addresses
|
address.isSiteLocalAddress()) {
|
||||||
if (address instanceof Inet6Address) return "[scrubbed]";
|
return address.getHostAddress();
|
||||||
// keep first and last octet of IPv4 addresses
|
}
|
||||||
return scrubInetAddress(address.toString());
|
// Keep first and last octet of non-local IPv4 addresses
|
||||||
|
return scrubIpv4Address(address.getAddress());
|
||||||
|
} else {
|
||||||
|
// Keep first and last octet of IPv6 addresses
|
||||||
|
return scrubIpv6Address(address.getAddress());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private static String scrubIpv4Address(byte[] ipv4) {
|
||||||
public static String scrubInetAddress(@Nullable String address) {
|
return (ipv4[0] & 0xFF) + ".[scrubbed]." + (ipv4[3] & 0xFF);
|
||||||
if (address == null) return null;
|
}
|
||||||
|
|
||||||
int firstDot = address.indexOf(".");
|
private static String scrubIpv6Address(byte[] ipv6) {
|
||||||
if (firstDot == -1) return "[scrubbed]";
|
String hex = toHexString(ipv6).toLowerCase();
|
||||||
String prefix = address.substring(0, firstDot + 1);
|
return hex.substring(0, 2) + "[scrubbed]" + hex.substring(30);
|
||||||
int lastDot = address.lastIndexOf(".");
|
|
||||||
String suffix = address.substring(lastDot, address.length());
|
|
||||||
return prefix + "[scrubbed]" + suffix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static String scrubSocketAddress(InetSocketAddress address) {
|
public static String scrubSocketAddress(InetSocketAddress address) {
|
||||||
InetAddress inetAddress = address.getAddress();
|
return scrubInetAddress(address.getAddress());
|
||||||
return scrubInetAddress(inetAddress);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static String scrubSocketAddress(SocketAddress address) {
|
public static String scrubSocketAddress(SocketAddress address) {
|
||||||
if (address instanceof InetSocketAddress)
|
if (address instanceof InetSocketAddress)
|
||||||
return scrubSocketAddress((InetSocketAddress) address);
|
return scrubSocketAddress((InetSocketAddress) address);
|
||||||
return scrubInetAddress(address.toString());
|
return "[scrubbed]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.settings.Settings;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.InterfaceAddress;
|
import java.net.InterfaceAddress;
|
||||||
@@ -22,7 +23,6 @@ import java.net.Socket;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -30,6 +30,8 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import static java.lang.Integer.parseInt;
|
import static java.lang.Integer.parseInt;
|
||||||
import static java.util.Collections.addAll;
|
import static java.util.Collections.addAll;
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.Collections.sort;
|
import static java.util.Collections.sort;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
@@ -39,11 +41,14 @@ import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID;
|
|||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IP_PORTS;
|
||||||
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_PORT;
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_PORT;
|
||||||
|
import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_SLAAC;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
import static org.briarproject.bramble.util.ByteUtils.MAX_16_BIT_UNSIGNED;
|
||||||
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
||||||
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
import static org.briarproject.bramble.util.PrivacyUtils.scrubSocketAddress;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.fromHexString;
|
||||||
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
|
||||||
import static org.briarproject.bramble.util.StringUtils.join;
|
import static org.briarproject.bramble.util.StringUtils.join;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class LanTcpPlugin extends TcpPlugin {
|
class LanTcpPlugin extends TcpPlugin {
|
||||||
@@ -53,6 +58,13 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
private static final int MAX_ADDRESSES = 4;
|
private static final int MAX_ADDRESSES = 4;
|
||||||
private static final String SEPARATOR = ",";
|
private static final String SEPARATOR = ",";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The network prefix of a SLAAC IPv6 address. See
|
||||||
|
* https://tools.ietf.org/html/rfc4862#section-5.3
|
||||||
|
*/
|
||||||
|
private static final byte[] SLAAC_PREFIX =
|
||||||
|
new byte[] {(byte) 0xFE, (byte) 0x80, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IP address of an Android device providing a wifi access point.
|
* The IP address of an Android device providing a wifi access point.
|
||||||
*/
|
*/
|
||||||
@@ -99,22 +111,22 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
protected void initialisePortProperty() {
|
protected void initialisePortProperty() {
|
||||||
TransportProperties p = callback.getLocalProperties();
|
TransportProperties p = callback.getLocalProperties();
|
||||||
if (isNullOrEmpty(p.get(PROP_PORT))) {
|
if (isNullOrEmpty(p.get(PROP_PORT))) {
|
||||||
int port = new Random().nextInt(32768) + 32768;
|
int port = chooseEphemeralPort();
|
||||||
p.put(PROP_PORT, String.valueOf(port));
|
p.put(PROP_PORT, String.valueOf(port));
|
||||||
callback.mergeLocalProperties(p);
|
callback.mergeLocalProperties(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<InetSocketAddress> getLocalSocketAddresses() {
|
protected List<InetSocketAddress> getLocalSocketAddresses(boolean ipv4) {
|
||||||
TransportProperties p = callback.getLocalProperties();
|
TransportProperties p = callback.getLocalProperties();
|
||||||
int preferredPort = 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 = parseIpv4SocketAddresses(oldIpPorts);
|
||||||
|
|
||||||
List<InetSocketAddress> locals = new ArrayList<>();
|
List<InetSocketAddress> locals = new ArrayList<>();
|
||||||
List<InetSocketAddress> fallbacks = new ArrayList<>();
|
List<InetSocketAddress> fallbacks = new ArrayList<>();
|
||||||
for (InetAddress local : getUsableLocalInetAddresses()) {
|
for (InetAddress local : getUsableLocalInetAddresses(ipv4)) {
|
||||||
// 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
|
||||||
int port = preferredPort;
|
int port = preferredPort;
|
||||||
for (InetSocketAddress old : olds) {
|
for (InetSocketAddress old : olds) {
|
||||||
@@ -140,17 +152,17 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<InetSocketAddress> parseSocketAddresses(String ipPorts) {
|
private List<InetSocketAddress> parseIpv4SocketAddresses(String ipPorts) {
|
||||||
List<InetSocketAddress> addresses = new ArrayList<>();
|
List<InetSocketAddress> addresses = new ArrayList<>();
|
||||||
if (isNullOrEmpty(ipPorts)) return addresses;
|
if (isNullOrEmpty(ipPorts)) return addresses;
|
||||||
for (String ipPort : ipPorts.split(SEPARATOR)) {
|
for (String ipPort : ipPorts.split(SEPARATOR)) {
|
||||||
InetSocketAddress a = parseSocketAddress(ipPort);
|
InetSocketAddress a = parseIpv4SocketAddress(ipPort);
|
||||||
if (a != null) addresses.add(a);
|
if (a != null) addresses.add(a);
|
||||||
}
|
}
|
||||||
return addresses;
|
return addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<InetAddress> getUsableLocalInetAddresses() {
|
protected List<InetAddress> getUsableLocalInetAddresses(boolean ipv4) {
|
||||||
List<InterfaceAddress> ifAddrs =
|
List<InterfaceAddress> ifAddrs =
|
||||||
new ArrayList<>(getLocalInterfaceAddresses());
|
new ArrayList<>(getLocalInterfaceAddresses());
|
||||||
// Prefer longer network prefixes
|
// Prefer longer network prefixes
|
||||||
@@ -159,13 +171,18 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
List<InetAddress> addrs = new ArrayList<>();
|
List<InetAddress> addrs = new ArrayList<>();
|
||||||
for (InterfaceAddress ifAddr : ifAddrs) {
|
for (InterfaceAddress ifAddr : ifAddrs) {
|
||||||
InetAddress addr = ifAddr.getAddress();
|
InetAddress addr = ifAddr.getAddress();
|
||||||
if (isAcceptableAddress(addr)) addrs.add(addr);
|
if (isAcceptableAddress(addr, ipv4)) addrs.add(addr);
|
||||||
}
|
}
|
||||||
return addrs;
|
return addrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setLocalSocketAddress(InetSocketAddress a) {
|
protected void setLocalSocketAddress(InetSocketAddress a, boolean ipv4) {
|
||||||
|
if (ipv4) setLocalIpv4SocketAddress(a);
|
||||||
|
else setLocalIpv6SocketAddress(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLocalIpv4SocketAddress(InetSocketAddress a) {
|
||||||
String ipPort = getIpPortString(a);
|
String ipPort = getIpPortString(a);
|
||||||
// Get the list of recently used addresses
|
// Get the list of recently used addresses
|
||||||
String setting = callback.getSettings().get(PREF_LAN_IP_PORTS);
|
String setting = callback.getSettings().get(PREF_LAN_IP_PORTS);
|
||||||
@@ -198,11 +215,38 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
callback.mergeSettings(settings);
|
callback.mergeSettings(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setLocalIpv6SocketAddress(InetSocketAddress a) {
|
||||||
|
if (isSlaacAddress(a.getAddress())) {
|
||||||
|
String property = toHexString(a.getAddress().getAddress());
|
||||||
|
TransportProperties properties = new TransportProperties();
|
||||||
|
properties.put(PROP_SLAAC, property);
|
||||||
|
callback.mergeLocalProperties(properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://tools.ietf.org/html/rfc4862#section-5.3
|
||||||
|
protected boolean isSlaacAddress(InetAddress a) {
|
||||||
|
if (!(a instanceof Inet6Address)) return false;
|
||||||
|
byte[] ip = a.getAddress();
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (ip[i] != SLAAC_PREFIX[i]) return false;
|
||||||
|
}
|
||||||
|
return (ip[8] & 0x02) == 0x02
|
||||||
|
&& ip[11] == (byte) 0xFF
|
||||||
|
&& ip[12] == (byte) 0xFE;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
||||||
|
TransportProperties p, boolean ipv4) {
|
||||||
|
if (ipv4) return getRemoteIpv4SocketAddresses(p);
|
||||||
|
else return getRemoteIpv6SocketAddresses(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<InetSocketAddress> getRemoteIpv4SocketAddresses(
|
||||||
TransportProperties p) {
|
TransportProperties p) {
|
||||||
String ipPorts = p.get(PROP_IP_PORTS);
|
String ipPorts = p.get(PROP_IP_PORTS);
|
||||||
List<InetSocketAddress> remotes = parseSocketAddresses(ipPorts);
|
List<InetSocketAddress> remotes = parseIpv4SocketAddresses(ipPorts);
|
||||||
int port = parsePortProperty(p.get(PROP_PORT));
|
int port = parsePortProperty(p.get(PROP_PORT));
|
||||||
// If the contact has a preferred port, we can guess their IP:port when
|
// If the contact has a preferred port, we can guess their IP:port when
|
||||||
// they're providing a wifi access point
|
// they're providing a wifi access point
|
||||||
@@ -217,20 +261,48 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
return remotes;
|
return remotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAcceptableAddress(InetAddress a) {
|
private List<InetSocketAddress> getRemoteIpv6SocketAddresses(
|
||||||
// Accept link-local and site-local IPv4 addresses
|
TransportProperties p) {
|
||||||
boolean ipv4 = a instanceof Inet4Address;
|
InetAddress slaac = parseSlaacProperty(p.get(PROP_SLAAC));
|
||||||
boolean loop = a.isLoopbackAddress();
|
int port = parsePortProperty(p.get(PROP_PORT));
|
||||||
boolean link = a.isLinkLocalAddress();
|
if (slaac == null || port == 0) return emptyList();
|
||||||
boolean site = a.isSiteLocalAddress();
|
return singletonList(new InetSocketAddress(slaac, port));
|
||||||
return ipv4 && !loop && (link || site);
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private InetAddress parseSlaacProperty(String slaacProperty) {
|
||||||
|
if (isNullOrEmpty(slaacProperty)) return null;
|
||||||
|
try {
|
||||||
|
byte[] ip = fromHexString(slaacProperty);
|
||||||
|
if (ip.length != 16) return null;
|
||||||
|
InetAddress a = InetAddress.getByAddress(ip);
|
||||||
|
return isSlaacAddress(a) ? a : null;
|
||||||
|
} catch (IllegalArgumentException | UnknownHostException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAcceptableAddress(InetAddress a, boolean ipv4) {
|
||||||
|
if (ipv4) {
|
||||||
|
// Accept link-local and site-local IPv4 addresses
|
||||||
|
boolean isIpv4 = a instanceof Inet4Address;
|
||||||
|
boolean loop = a.isLoopbackAddress();
|
||||||
|
boolean link = a.isLinkLocalAddress();
|
||||||
|
boolean site = a.isSiteLocalAddress();
|
||||||
|
return isIpv4 && !loop && (link || site);
|
||||||
|
} else {
|
||||||
|
// Accept IPv6 SLAAC addresses
|
||||||
|
return isSlaacAddress(a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isConnectable(InterfaceAddress local,
|
protected boolean isConnectable(InterfaceAddress local,
|
||||||
InetSocketAddress remote) {
|
InetSocketAddress remote) {
|
||||||
if (remote.getPort() == 0) return false;
|
if (remote.getPort() == 0) return false;
|
||||||
if (!isAcceptableAddress(remote.getAddress())) return false;
|
InetAddress remoteAddress = remote.getAddress();
|
||||||
|
boolean ipv4 = local.getAddress() instanceof Inet4Address;
|
||||||
|
if (!isAcceptableAddress(remoteAddress, ipv4)) 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
|
||||||
byte[] localIp = local.getAddress().getAddress();
|
byte[] localIp = local.getAddress().getAddress();
|
||||||
byte[] remoteIp = remote.getAddress().getAddress();
|
byte[] remoteIp = remote.getAddress().getAddress();
|
||||||
@@ -262,7 +334,7 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
public KeyAgreementListener createKeyAgreementListener(byte[] commitment) {
|
||||||
ServerSocket ss = null;
|
ServerSocket ss = null;
|
||||||
for (InetSocketAddress addr : getLocalSocketAddresses()) {
|
for (InetSocketAddress addr : getLocalSocketAddresses(true)) {
|
||||||
// Don't try to reuse the same port we use for contact connections
|
// Don't try to reuse the same port we use for contact connections
|
||||||
addr = new InetSocketAddress(addr.getAddress(), 0);
|
addr = new InetSocketAddress(addr.getAddress(), 0);
|
||||||
try {
|
try {
|
||||||
@@ -291,7 +363,7 @@ class LanTcpPlugin extends TcpPlugin {
|
|||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createKeyAgreementConnection(
|
public DuplexTransportConnection createKeyAgreementConnection(
|
||||||
byte[] commitment, BdfList descriptor) {
|
byte[] commitment, BdfList descriptor) {
|
||||||
ServerSocket ss = state.getServerSocket();
|
ServerSocket ss = state.getServerSocket(true);
|
||||||
if (ss == null) return null;
|
if (ss == null) return null;
|
||||||
InterfaceAddress local = getLocalInterfaceAddress(ss.getInetAddress());
|
InterfaceAddress local = getLocalInterfaceAddress(ss.getInetAddress());
|
||||||
if (local == null) {
|
if (local == null) {
|
||||||
|
|||||||
@@ -54,11 +54,13 @@ class PortMapperImpl implements PortMapper {
|
|||||||
shutdownManager.addShutdownHook(() -> deleteMapping(port));
|
shutdownManager.addShutdownHook(() -> deleteMapping(port));
|
||||||
}
|
}
|
||||||
String externalString = gateway.getExternalIPAddress();
|
String externalString = gateway.getExternalIPAddress();
|
||||||
if (LOG.isLoggable(INFO))
|
if (externalString == null) {
|
||||||
LOG.info(
|
LOG.info("External address not available");
|
||||||
"External address " + scrubInetAddress(externalString));
|
} else {
|
||||||
if (externalString != null)
|
|
||||||
external = InetAddress.getByName(externalString);
|
external = InetAddress.getByName(externalString);
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("External address " + scrubInetAddress(external));
|
||||||
|
}
|
||||||
} catch (IOException | SAXException e) {
|
} catch (IOException | SAXException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import javax.annotation.Nullable;
|
|||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import javax.annotation.concurrent.ThreadSafe;
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
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;
|
||||||
@@ -78,20 +79,22 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
* Returns zero or more socket addresses on which the plugin should listen,
|
* Returns zero or more socket addresses on which the plugin should listen,
|
||||||
* in order of preference. At most one of the addresses will be bound.
|
* in order of preference. At most one of the addresses will be bound.
|
||||||
*/
|
*/
|
||||||
protected abstract List<InetSocketAddress> getLocalSocketAddresses();
|
protected abstract List<InetSocketAddress> getLocalSocketAddresses(
|
||||||
|
boolean ipv4);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the address on which the plugin is listening to the transport
|
* Adds the address on which the plugin is listening to the transport
|
||||||
* properties.
|
* properties.
|
||||||
*/
|
*/
|
||||||
protected abstract void setLocalSocketAddress(InetSocketAddress a);
|
protected abstract void setLocalSocketAddress(InetSocketAddress a,
|
||||||
|
boolean ipv4);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns zero or more socket addresses for connecting to a contact with
|
* Returns zero or more socket addresses for connecting to a contact with
|
||||||
* the given transport properties.
|
* the given transport properties.
|
||||||
*/
|
*/
|
||||||
protected abstract List<InetSocketAddress> getRemoteSocketAddresses(
|
protected abstract List<InetSocketAddress> getRemoteSocketAddresses(
|
||||||
TransportProperties p);
|
TransportProperties p, boolean ipv4);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if connections to the given address can be attempted.
|
* Returns true if connections to the given address can be attempted.
|
||||||
@@ -136,37 +139,43 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
protected void bind() {
|
protected void bind() {
|
||||||
bindExecutor.execute(() -> {
|
bindExecutor.execute(() -> {
|
||||||
if (getState() != INACTIVE) return;
|
if (getState() != INACTIVE) return;
|
||||||
ServerSocket ss = null;
|
bind(true);
|
||||||
for (InetSocketAddress addr : getLocalSocketAddresses()) {
|
bind(false);
|
||||||
try {
|
|
||||||
ss = new ServerSocket();
|
|
||||||
ss.bind(addr);
|
|
||||||
break;
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Failed to bind " + scrubSocketAddress(addr));
|
|
||||||
tryToClose(ss, LOG, WARNING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ss == null) {
|
|
||||||
LOG.info("Could not bind server socket");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!state.setServerSocket(ss)) {
|
|
||||||
LOG.info("Closing redundant server socket");
|
|
||||||
tryToClose(ss, LOG, WARNING);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
backoff.reset();
|
|
||||||
InetSocketAddress local =
|
|
||||||
(InetSocketAddress) ss.getLocalSocketAddress();
|
|
||||||
setLocalSocketAddress(local);
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Listening on " + scrubSocketAddress(local));
|
|
||||||
acceptContactConnections(ss);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void bind(boolean ipv4) {
|
||||||
|
ServerSocket ss = null;
|
||||||
|
for (InetSocketAddress addr : getLocalSocketAddresses(ipv4)) {
|
||||||
|
try {
|
||||||
|
ss = new ServerSocket();
|
||||||
|
ss.bind(addr);
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Failed to bind " + scrubSocketAddress(addr));
|
||||||
|
tryToClose(ss, LOG, WARNING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ss == null) {
|
||||||
|
LOG.info("Could not bind server socket");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!state.setServerSocket(ss, ipv4)) {
|
||||||
|
LOG.info("Closing redundant server socket");
|
||||||
|
tryToClose(ss, LOG, WARNING);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backoff.reset();
|
||||||
|
InetSocketAddress local =
|
||||||
|
(InetSocketAddress) ss.getLocalSocketAddress();
|
||||||
|
setLocalSocketAddress(local, ipv4);
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Listening on " + scrubSocketAddress(local));
|
||||||
|
ServerSocket finalSocket = ss;
|
||||||
|
ioExecutor.execute(() -> acceptContactConnections(finalSocket, ipv4));
|
||||||
|
}
|
||||||
|
|
||||||
String getIpPortString(InetSocketAddress a) {
|
String getIpPortString(InetSocketAddress a) {
|
||||||
String addr = a.getAddress().getHostAddress();
|
String addr = a.getAddress().getHostAddress();
|
||||||
int percent = addr.indexOf('%');
|
int percent = addr.indexOf('%');
|
||||||
@@ -174,7 +183,7 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
return addr + ":" + a.getPort();
|
return addr + ":" + a.getPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void acceptContactConnections(ServerSocket ss) {
|
private void acceptContactConnections(ServerSocket ss, boolean ipv4) {
|
||||||
while (true) {
|
while (true) {
|
||||||
Socket s;
|
Socket s;
|
||||||
try {
|
try {
|
||||||
@@ -183,12 +192,13 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// This is expected when the server socket is closed
|
// This is expected when the server socket is closed
|
||||||
LOG.info("Server socket closed");
|
LOG.info("Server socket closed");
|
||||||
state.clearServerSocket(ss);
|
state.clearServerSocket(ss, ipv4);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Connection from " +
|
LOG.info("Connection from " +
|
||||||
scrubSocketAddress(s.getRemoteSocketAddress()));
|
scrubSocketAddress(s.getRemoteSocketAddress()));
|
||||||
|
}
|
||||||
backoff.reset();
|
backoff.reset();
|
||||||
callback.handleConnection(new TcpTransportConnection(this, s));
|
callback.handleConnection(new TcpTransportConnection(this, s));
|
||||||
}
|
}
|
||||||
@@ -196,8 +206,9 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
ServerSocket ss = state.setStopped();
|
for (@Nullable ServerSocket ss : state.setStopped()) {
|
||||||
tryToClose(ss, LOG, WARNING);
|
tryToClose(ss, LOG, WARNING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -242,14 +253,22 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DuplexTransportConnection createConnection(TransportProperties p) {
|
public DuplexTransportConnection createConnection(TransportProperties p) {
|
||||||
ServerSocket ss = state.getServerSocket();
|
DuplexTransportConnection c = createConnection(p, true);
|
||||||
|
if (c != null) return c;
|
||||||
|
return createConnection(p, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private DuplexTransportConnection createConnection(TransportProperties p,
|
||||||
|
boolean ipv4) {
|
||||||
|
ServerSocket ss = state.getServerSocket(ipv4);
|
||||||
if (ss == null) return null;
|
if (ss == null) return null;
|
||||||
InterfaceAddress local = getLocalInterfaceAddress(ss.getInetAddress());
|
InterfaceAddress local = getLocalInterfaceAddress(ss.getInetAddress());
|
||||||
if (local == null) {
|
if (local == null) {
|
||||||
LOG.warning("No interface for server socket");
|
LOG.warning("No interface for server socket");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for (InetSocketAddress remote : getRemoteSocketAddresses(p)) {
|
for (InetSocketAddress remote : getRemoteSocketAddresses(p, ipv4)) {
|
||||||
// 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(ss.getInetAddress())) {
|
remote.getAddress().equals(ss.getInetAddress())) {
|
||||||
@@ -274,9 +293,10 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
LOG.info("Connected to " + scrubSocketAddress(remote));
|
LOG.info("Connected to " + scrubSocketAddress(remote));
|
||||||
return new TcpTransportConnection(this, s);
|
return new TcpTransportConnection(this, s);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Could not connect to " +
|
LOG.info("Could not connect to " +
|
||||||
scrubSocketAddress(remote));
|
scrubSocketAddress(remote));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -299,8 +319,12 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
return new Socket();
|
return new Socket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int chooseEphemeralPort() {
|
||||||
|
return 32768 + (int) (Math.random() * 32768);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
InetSocketAddress parseSocketAddress(String ipPort) {
|
InetSocketAddress parseIpv4SocketAddress(String ipPort) {
|
||||||
if (isNullOrEmpty(ipPort)) return null;
|
if (isNullOrEmpty(ipPort)) return null;
|
||||||
String[] split = ipPort.split(":");
|
String[] split = ipPort.split(":");
|
||||||
if (split.length != 2) return null;
|
if (split.length != 2) return null;
|
||||||
@@ -311,14 +335,7 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
InetAddress a = InetAddress.getByName(addr);
|
InetAddress a = InetAddress.getByName(addr);
|
||||||
int p = Integer.parseInt(port);
|
int p = Integer.parseInt(port);
|
||||||
return new InetSocketAddress(a, p);
|
return new InetSocketAddress(a, p);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException | NumberFormatException e) {
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
// not scrubbing to enable us to find the problem
|
|
||||||
LOG.warning("Invalid address: " + addr);
|
|
||||||
return null;
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.warning("Invalid port: " + port);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -389,13 +406,15 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
@IoExecutor
|
@IoExecutor
|
||||||
private void onSettingsUpdated(Settings settings) {
|
private void onSettingsUpdated(Settings settings) {
|
||||||
boolean enabledByUser = settings.getBoolean(PREF_PLUGIN_ENABLE, false);
|
boolean enabledByUser = settings.getBoolean(PREF_PLUGIN_ENABLE, false);
|
||||||
ServerSocket ss = state.setEnabledByUser(enabledByUser);
|
List<ServerSocket> toClose = state.setEnabledByUser(enabledByUser);
|
||||||
State s = getState();
|
State s = getState();
|
||||||
if (ss != null) {
|
if (!toClose.isEmpty()) {
|
||||||
LOG.info("Disabled by user, closing server socket");
|
LOG.info("Disabled by user, closing server sockets");
|
||||||
tryToClose(ss, LOG, WARNING);
|
for (@Nullable ServerSocket ss : toClose) {
|
||||||
|
tryToClose(ss, LOG, WARNING);
|
||||||
|
}
|
||||||
} else if (s == INACTIVE) {
|
} else if (s == INACTIVE) {
|
||||||
LOG.info("Enabled by user, opening server socket");
|
LOG.info("Enabled by user, opening server sockets");
|
||||||
bind();
|
bind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,7 +428,7 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
|
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
@Nullable
|
@Nullable
|
||||||
private ServerSocket serverSocket = null;
|
private ServerSocket serverSocketV4 = null, serverSocketV6 = null;
|
||||||
|
|
||||||
synchronized void setStarted(boolean enabledByUser) {
|
synchronized void setStarted(boolean enabledByUser) {
|
||||||
started = true;
|
started = true;
|
||||||
@@ -417,48 +436,62 @@ abstract class TcpPlugin implements DuplexPlugin, EventListener {
|
|||||||
callback.pluginStateChanged(getState());
|
callback.pluginStateChanged(getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
synchronized List<ServerSocket> setStopped() {
|
||||||
synchronized ServerSocket setStopped() {
|
|
||||||
stopped = true;
|
stopped = true;
|
||||||
ServerSocket ss = serverSocket;
|
List<ServerSocket> toClose = clearServerSockets();
|
||||||
serverSocket = null;
|
|
||||||
callback.pluginStateChanged(getState());
|
callback.pluginStateChanged(getState());
|
||||||
return ss;
|
return toClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@GuardedBy("this")
|
||||||
synchronized ServerSocket setEnabledByUser(boolean enabledByUser) {
|
private List<ServerSocket> clearServerSockets() {
|
||||||
|
List<ServerSocket> toClose = asList(serverSocketV4, serverSocketV6);
|
||||||
|
serverSocketV4 = null;
|
||||||
|
serverSocketV6 = null;
|
||||||
|
return toClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized List<ServerSocket> setEnabledByUser(
|
||||||
|
boolean enabledByUser) {
|
||||||
this.enabledByUser = enabledByUser;
|
this.enabledByUser = enabledByUser;
|
||||||
ServerSocket ss = null;
|
List<ServerSocket> toClose = enabledByUser
|
||||||
if (!enabledByUser) {
|
? emptyList() : clearServerSockets();
|
||||||
ss = serverSocket;
|
|
||||||
serverSocket = null;
|
|
||||||
}
|
|
||||||
callback.pluginStateChanged(getState());
|
callback.pluginStateChanged(getState());
|
||||||
return ss;
|
return toClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
synchronized ServerSocket getServerSocket() {
|
synchronized ServerSocket getServerSocket(boolean ipv4) {
|
||||||
return serverSocket;
|
return ipv4 ? serverSocketV4 : serverSocketV6;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized boolean setServerSocket(ServerSocket ss) {
|
synchronized boolean setServerSocket(ServerSocket ss, boolean ipv4) {
|
||||||
if (stopped || serverSocket != null) return false;
|
if (stopped) return false;
|
||||||
serverSocket = ss;
|
if (ipv4) {
|
||||||
|
if (serverSocketV4 != null) return false;
|
||||||
|
serverSocketV4 = ss;
|
||||||
|
} else {
|
||||||
|
if (serverSocketV6 != null) return false;
|
||||||
|
serverSocketV6 = ss;
|
||||||
|
}
|
||||||
callback.pluginStateChanged(getState());
|
callback.pluginStateChanged(getState());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void clearServerSocket(ServerSocket ss) {
|
synchronized void clearServerSocket(ServerSocket ss, boolean ipv4) {
|
||||||
if (serverSocket == ss) serverSocket = null;
|
if (ipv4) {
|
||||||
|
if (serverSocketV4 == ss) serverSocketV4 = null;
|
||||||
|
} else {
|
||||||
|
if (serverSocketV6 == ss) serverSocketV6 = null;
|
||||||
|
}
|
||||||
callback.pluginStateChanged(getState());
|
callback.pluginStateChanged(getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized State getState() {
|
synchronized State getState() {
|
||||||
if (!started || stopped) return STARTING_STOPPING;
|
if (!started || stopped) return STARTING_STOPPING;
|
||||||
if (!enabledByUser) return DISABLED;
|
if (!enabledByUser) return DISABLED;
|
||||||
return serverSocket == null ? INACTIVE : ACTIVE;
|
if (serverSocketV4 != null || serverSocketV6 != null) return ACTIVE;
|
||||||
|
return INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized int getReasonsDisabled() {
|
synchronized int getReasonsDisabled() {
|
||||||
|
|||||||
@@ -43,10 +43,11 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<InetSocketAddress> getLocalSocketAddresses() {
|
protected List<InetSocketAddress> getLocalSocketAddresses(boolean ipv4) {
|
||||||
|
if (!ipv4) return emptyList();
|
||||||
// Use the same address and port as last time if available
|
// Use the same address and port as last time if available
|
||||||
TransportProperties p = callback.getLocalProperties();
|
TransportProperties p = callback.getLocalProperties();
|
||||||
InetSocketAddress old = parseSocketAddress(p.get(PROP_IP_PORT));
|
InetSocketAddress old = parseIpv4SocketAddress(p.get(PROP_IP_PORT));
|
||||||
List<InetSocketAddress> addrs = new LinkedList<>();
|
List<InetSocketAddress> addrs = new LinkedList<>();
|
||||||
for (InetAddress a : getLocalInetAddresses()) {
|
for (InetAddress a : getLocalInetAddresses()) {
|
||||||
if (isAcceptableAddress(a)) {
|
if (isAcceptableAddress(a)) {
|
||||||
@@ -76,14 +77,11 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
return ipv4 && !loop && !link && !site;
|
return ipv4 && !loop && !link && !site;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int chooseEphemeralPort() {
|
|
||||||
return 32768 + (int) (Math.random() * 32768);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
protected List<InetSocketAddress> getRemoteSocketAddresses(
|
||||||
TransportProperties p) {
|
TransportProperties p, boolean ipv4) {
|
||||||
InetSocketAddress parsed = parseSocketAddress(p.get(PROP_IP_PORT));
|
if (!ipv4) return emptyList();
|
||||||
|
InetSocketAddress parsed = parseIpv4SocketAddress(p.get(PROP_IP_PORT));
|
||||||
if (parsed == null) return emptyList();
|
if (parsed == null) return emptyList();
|
||||||
return singletonList(parsed);
|
return singletonList(parsed);
|
||||||
}
|
}
|
||||||
@@ -96,7 +94,8 @@ class WanTcpPlugin extends TcpPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setLocalSocketAddress(InetSocketAddress a) {
|
protected void setLocalSocketAddress(InetSocketAddress a, boolean ipv4) {
|
||||||
|
if (!ipv4) throw new AssertionError();
|
||||||
if (mappingResult != null && mappingResult.isUsable()) {
|
if (mappingResult != null && mappingResult.isUsable()) {
|
||||||
// Advertise the external address to contacts
|
// Advertise the external address to contacts
|
||||||
if (a.equals(mappingResult.getInternal())) {
|
if (a.equals(mappingResult.getInternal())) {
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import org.briarproject.briar.android.logging.BriefLogFormatter;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
@@ -185,12 +187,18 @@ public class BriarReportPrimer implements ReportPrimer {
|
|||||||
WifiInfo wifiInfo = wm.getConnectionInfo();
|
WifiInfo wifiInfo = wm.getConnectionInfo();
|
||||||
if (wifiInfo != null) {
|
if (wifiInfo != null) {
|
||||||
int ip = wifiInfo.getIpAddress(); // Nice API, Google
|
int ip = wifiInfo.getIpAddress(); // Nice API, Google
|
||||||
int ip1 = ip & 0xFF;
|
byte[] ipBytes = new byte[4];
|
||||||
int ip2 = (ip >> 8) & 0xFF;
|
ipBytes[0] = (byte) (ip & 0xFF);
|
||||||
int ip3 = (ip >> 16) & 0xFF;
|
ipBytes[1] = (byte) ((ip >> 8) & 0xFF);
|
||||||
int ip4 = (ip >> 24) & 0xFF;
|
ipBytes[2] = (byte) ((ip >> 16) & 0xFF);
|
||||||
String address = ip1 + "." + ip2 + "." + ip3 + "." + ip4;
|
ipBytes[3] = (byte) ((ip >> 24) & 0xFF);
|
||||||
customData.put("Wi-Fi address", scrubInetAddress(address));
|
try {
|
||||||
|
InetAddress address = InetAddress.getByAddress(ipBytes);
|
||||||
|
customData.put("Wi-Fi address",
|
||||||
|
scrubInetAddress(address));
|
||||||
|
} catch (UnknownHostException ignored) {
|
||||||
|
// Should only be thrown if address has illegal length
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user