From b1a8d944bf8e3561a79802c055d8325716b09983 Mon Sep 17 00:00:00 2001 From: jmacxx <47253594+jmacxx@users.noreply.github.com> Date: Tue, 10 Mar 2020 22:56:40 -0500 Subject: [PATCH] Allow IPv6 connections to Bitcoin nodes Currently bisq desktop does not accept IPv6 addresses in the settings for custom nodes or via the --btcNodes command line option. The separation of address and port is handled incorrectly in core / BtcNodes::fromFullAddress. This results in IPv6 addresses being ignored. Where Tor is enabled for Bitcoin connections, we need to handle the IPv6 address response from Tor DNS lookup. Fixes #3990 --- .../java/bisq/core/btc/nodes/BtcNodes.java | 29 +++++++++++++++---- .../main/java/bisq/network/DnsLookupTor.java | 19 +++++++----- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/bisq/core/btc/nodes/BtcNodes.java b/core/src/main/java/bisq/core/btc/nodes/BtcNodes.java index e5d16ed9701..4f998500542 100644 --- a/core/src/main/java/bisq/core/btc/nodes/BtcNodes.java +++ b/core/src/main/java/bisq/core/btc/nodes/BtcNodes.java @@ -113,13 +113,32 @@ public static class BtcNode { * @return BtcNode instance */ public static BtcNode fromFullAddress(String fullAddress) { - String[] parts = fullAddress.split(":"); + String[] parts = fullAddress.split("]"); checkArgument(parts.length > 0); - final String host = parts[0]; + String host = ""; int port = DEFAULT_PORT; - if (parts.length == 2) - port = Integer.valueOf(parts[1]); - + if (parts[0].contains("[") && parts[0].contains(":")) { + // IPv6 address and optional port number + // address part delimited by square brackets e.g. [2a01:123:456:789::2]:8333 + host = parts[0].replace("[", "").replace("]", ""); + if (parts.length == 2) + port = Integer.parseInt(parts[1].replace(":", "")); + } + else if (parts[0].contains(":") && !parts[0].contains(".")) { + // IPv6 address only; not delimited by square brackets + host = parts[0]; + } + else if (parts[0].contains(".")) { + // address and an optional port number + // e.g. 127.0.0.1:8333 or abcdef123xyz.onion:9999 + parts = fullAddress.split(":"); + checkArgument(parts.length > 0); + host = parts[0]; + if (parts.length == 2) + port = Integer.parseInt(parts[1]); + } + + checkArgument(host.length()>0, "BtcNode address format not recognised"); return host.contains(".onion") ? new BtcNode(null, host, null, port, null) : new BtcNode(null, null, host, port, null); } diff --git a/p2p/src/main/java/bisq/network/DnsLookupTor.java b/p2p/src/main/java/bisq/network/DnsLookupTor.java index c74b5ed6a73..37318d6df88 100644 --- a/p2p/src/main/java/bisq/network/DnsLookupTor.java +++ b/p2p/src/main/java/bisq/network/DnsLookupTor.java @@ -84,10 +84,10 @@ public static InetAddress lookup(Socks5Proxy proxy, String host) throws DnsLooku byte[] hostBytes = host.getBytes(Charsets.UTF_8); buf = new byte[7 + hostBytes.length]; - buf[0] = b('\u0005'); - buf[1] = b('\u00f0'); - buf[2] = b('\u0000'); - buf[3] = b('\u0003'); + buf[0] = b('\u0005'); // version SOCKS5 + buf[1] = b('\u00f0'); // CMD_RESOLVE + buf[2] = b('\u0000'); // (reserved) + buf[3] = b('\u0003'); // SOCKS5_ATYPE_HOSTNAME buf[4] = (byte) hostBytes.length; System.arraycopy(hostBytes, 0, buf, 5, hostBytes.length); buf[5 + hostBytes.length] = 0; @@ -113,13 +113,16 @@ public static InetAddress lookup(Socks5Proxy proxy, String host) throws DnsLooku throw new DnsLookupException(torStatusErrors.get(buf[1]) + "(host=" + host + ")"); } - if (buf[3] != b('\u0001')) + final char SOCKS5_ATYPE_IPV4 = '\u0001'; + final char SOCKS5_ATYPE_IPV6 = '\u0004'; + final byte atype = buf[3]; + if (atype != b(SOCKS5_ATYPE_IPV4) && atype != b(SOCKS5_ATYPE_IPV6)) throw new DnsLookupException(torStatusErrors.get(b('\u0001')) + "(host=" + host + ")"); - buf = new byte[4]; + final int octets = (atype == SOCKS5_ATYPE_IPV4 ? 4 : 16); + buf = new byte[octets]; bytesRead = proxySocket.getInputStream().read(buf); - - if (bytesRead != 4) + if (bytesRead != octets) throw new DnsLookupException("Invalid Tor Address Response"); return InetAddress.getByAddress(buf);