From badc6da6499aeaffe911eafa9bca98b3730c1878 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 10 Mar 2020 14:04:26 +0000 Subject: [PATCH] Accept any link-local IPv6 address. This allows IPv6 to be used when providing an access point. --- .../plugin/tcp/AndroidLanTcpPlugin.java | 8 +- .../bramble/api/plugin/LanTcpConstants.java | 5 +- .../bramble/plugin/tcp/LanTcpPlugin.java | 117 +++++++++--------- 3 files changed, 63 insertions(+), 67 deletions(-) diff --git a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java index bddc94cc4..ec6c83e62 100644 --- a/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java +++ b/bramble-android/src/main/java/org/briarproject/bramble/plugin/tcp/AndroidLanTcpPlugin.java @@ -93,8 +93,8 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { Pair wifi = getWifiIpv4Address(); if (wifi == null) return emptyList(); if (ipv4) return singletonList(wifi.getFirst()); - InetAddress slaac = getSlaacAddressForInterface(wifi.getFirst()); - return slaac == null ? emptyList() : singletonList(slaac); + InetAddress ipv6 = getIpv6AddressForInterface(wifi.getFirst()); + return ipv6 == null ? emptyList() : singletonList(ipv6); } /** @@ -159,12 +159,12 @@ class AndroidLanTcpPlugin extends LanTcpPlugin { } @Nullable - private InetAddress getSlaacAddressForInterface(InetAddress wifi) { + private InetAddress getIpv6AddressForInterface(InetAddress wifi) { try { NetworkInterface iface = NetworkInterface.getByInetAddress(wifi); if (iface == null) return null; for (InetAddress addr : list(iface.getInetAddresses())) { - if (isSlaacAddress(addr)) return addr; + if (isIpv6LinkLocalAddress(addr)) return addr; } // No suitable address return null; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/LanTcpConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/LanTcpConstants.java index 835d67b5a..69880b4ab 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/LanTcpConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/plugin/LanTcpConstants.java @@ -7,8 +7,9 @@ public interface LanTcpConstants { // Transport properties (shared with contacts) String PROP_IP_PORTS = "ipPorts"; String PROP_PORT = "port"; - String PROP_SLAAC = "slaac"; + String PROP_IPV6 = "ipv6"; - // A local setting + // Local settings (not shared with contacts) String PREF_LAN_IP_PORTS = "ipPorts"; + String PREF_IPV6 = "ipv6"; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java index 27ceddbaa..98b077b3f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/plugin/tcp/LanTcpPlugin.java @@ -22,6 +22,8 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.Executor; import java.util.logging.Logger; @@ -31,17 +33,18 @@ import javax.annotation.Nullable; import static java.lang.Integer.parseInt; 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.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.keyagreement.KeyAgreementConstants.TRANSPORT_ID_LAN; import static org.briarproject.bramble.api.plugin.LanTcpConstants.ID; +import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_IPV6; import static org.briarproject.bramble.api.plugin.LanTcpConstants.PREF_LAN_IP_PORTS; +import static org.briarproject.bramble.api.plugin.LanTcpConstants.PROP_IPV6; 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_SLAAC; +import static org.briarproject.bramble.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH; 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.PrivacyUtils.scrubSocketAddress; @@ -49,22 +52,15 @@ import static org.briarproject.bramble.util.StringUtils.fromHexString; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; import static org.briarproject.bramble.util.StringUtils.join; import static org.briarproject.bramble.util.StringUtils.toHexString; +import static org.briarproject.bramble.util.StringUtils.utf8IsTooLong; @NotNullByDefault class LanTcpPlugin extends TcpPlugin { private static final Logger LOG = getLogger(LanTcpPlugin.class.getName()); - private static final int MAX_ADDRESSES = 4; 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. *

@@ -187,56 +183,48 @@ class LanTcpPlugin extends TcpPlugin { private void setLocalIpv4SocketAddress(InetSocketAddress a) { String ipPort = getIpPortString(a); + updateRecentAddresses(PREF_LAN_IP_PORTS, PROP_IP_PORTS, ipPort); + } + + private void setLocalIpv6SocketAddress(InetSocketAddress a) { + String hex = toHexString(a.getAddress().getAddress()); + updateRecentAddresses(PREF_IPV6, PROP_IPV6, hex); + } + + private void updateRecentAddresses(String settingKey, String propertyKey, + String item) { // Get the list of recently used addresses - String setting = callback.getSettings().get(PREF_LAN_IP_PORTS); - List recent = new ArrayList<>(); - if (!isNullOrEmpty(setting)) + String setting = callback.getSettings().get(settingKey); + Deque recent = new LinkedList<>(); + if (!isNullOrEmpty(setting)) { addAll(recent, setting.split(SEPARATOR)); - // Is the address already in the list? - if (recent.remove(ipPort)) { - // Move the address to the start of the list - recent.add(0, ipPort); + } + if (recent.remove(item)) { + // Move the item to the start of the list + recent.addFirst(item); setting = join(recent, SEPARATOR); } else { - // Add the address to the start of the list - recent.add(0, ipPort); - // Drop the least recently used address if the list is full - if (recent.size() > MAX_ADDRESSES) - recent = recent.subList(0, MAX_ADDRESSES); + // Add the item to the start of the list + recent.addFirst(item); + // Drop items from the end of the list if it's too long to encode setting = join(recent, SEPARATOR); + while (utf8IsTooLong(setting, MAX_PROPERTY_LENGTH)) { + recent.removeLast(); + setting = join(recent, SEPARATOR); + } // Update the list of addresses shared with contacts - List shared = new ArrayList<>(recent); - sort(shared); - String property = join(shared, SEPARATOR); TransportProperties properties = new TransportProperties(); - properties.put(PROP_IP_PORTS, property); + properties.put(propertyKey, setting); callback.mergeLocalProperties(properties); } // Save the setting Settings settings = new Settings(); - settings.put(PREF_LAN_IP_PORTS, setting); + settings.put(settingKey, setting); 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; + protected boolean isIpv6LinkLocalAddress(InetAddress a) { + return a instanceof Inet6Address && a.isLinkLocalAddress(); } @Override @@ -266,22 +254,30 @@ class LanTcpPlugin extends TcpPlugin { private List getRemoteIpv6SocketAddresses( TransportProperties p) { - InetAddress slaac = parseSlaacProperty(p.get(PROP_SLAAC)); + List addrs = parseIpv6Addresses(p.get(PROP_IPV6)); int port = parsePortProperty(p.get(PROP_PORT)); - if (slaac == null || port == 0) return emptyList(); - return singletonList(new InetSocketAddress(slaac, port)); + if (addrs.isEmpty() || port == 0) return emptyList(); + List remotes = new ArrayList<>(); + for (InetAddress addr : addrs) { + remotes.add(new InetSocketAddress(addr, port)); + } + return remotes; } - @Nullable - private InetAddress parseSlaacProperty(String slaacProperty) { - if (isNullOrEmpty(slaacProperty)) return null; + private List parseIpv6Addresses(String property) { + if (isNullOrEmpty(property)) return emptyList(); try { - byte[] ip = fromHexString(slaacProperty); - if (ip.length != 16) return null; - InetAddress a = InetAddress.getByAddress(ip); - return isSlaacAddress(a) ? a : null; + List addrs = new ArrayList<>(); + for (String hex : property.split(SEPARATOR)) { + byte[] ip = fromHexString(hex); + if (ip.length == 16) { + InetAddress addr = InetAddress.getByAddress(ip); + if (isIpv6LinkLocalAddress(addr)) addrs.add(addr); + } + } + return addrs; } catch (IllegalArgumentException | UnknownHostException e) { - return null; + return emptyList(); } } @@ -289,13 +285,12 @@ class LanTcpPlugin extends TcpPlugin { 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); + return isIpv4 && (link || site); } else { - // Accept IPv6 SLAAC addresses - return isSlaacAddress(a); + // Accept link-local IPv6 addresses + return isIpv6LinkLocalAddress(a); } }