Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
127 changed files
with
15,777 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
plugins { | ||
id 'java' | ||
id 'maven' | ||
} | ||
|
||
group = 'network.bisq' | ||
version = '-SNAPSHOT' | ||
|
||
sourceCompatibility = 1.8 | ||
|
||
repositories { | ||
jcenter() | ||
maven { url 'https://jitpack.io' } | ||
maven { url 'https://raw.githubusercontent.com/JesusMcCloud/tor-binary/master/release/' } | ||
} | ||
|
||
dependencies { | ||
compile 'network.bisq:bisq-common:-SNAPSHOT' | ||
compile('com.github.JesusMcCloud.netlayer:tor.native:0.4.2') { | ||
exclude(module: 'slf4j-api') | ||
} | ||
compile('org.apache.httpcomponents:httpclient:4.5.3') { | ||
exclude(module: 'commons-logging') | ||
} | ||
compile 'net.sf.jopt-simple:jopt-simple:5.0.3' | ||
compile 'org.fxmisc.easybind:easybind:1.0.3' | ||
compileOnly 'org.projectlombok:lombok:1.16.16' | ||
annotationProcessor 'org.projectlombok:lombok:1.16.16' | ||
testCompile 'junit:junit:4.12' | ||
testCompile 'org.jmockit:jmockit:1.30' | ||
testCompileOnly 'org.projectlombok:lombok:1.16.16' | ||
testAnnotationProcessor 'org.projectlombok:lombok:1.16.16' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
systemProp.org.gradle.internal.http.connectionTimeout=120000 | ||
systemProp.org.gradle.internal.http.socketTimeout=120000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/* | ||
* This file is part of Bisq. | ||
* | ||
* Bisq is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU Affero General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or (at | ||
* your option) any later version. | ||
* | ||
* Bisq is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public | ||
* License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package bisq.network; | ||
|
||
public class DnsLookupException extends Exception { | ||
public DnsLookupException(String message) { | ||
super(message); | ||
} | ||
|
||
public DnsLookupException(Exception e) { | ||
super(e); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/* | ||
* This file is part of Bisq. | ||
* | ||
* Bisq is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU Affero General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or (at | ||
* your option) any later version. | ||
* | ||
* Bisq is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public | ||
* License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package bisq.network; | ||
|
||
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; | ||
|
||
import java.net.InetAddress; | ||
import java.net.Socket; | ||
|
||
import java.io.IOException; | ||
|
||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** | ||
* Performs DNS lookup over Socks5 proxy that implements the RESOLVE extension. | ||
* At this time, Tor is only known Socks5 proxy that supports it. | ||
* <p/> | ||
* Adapted from https://github.com/btcsuite/btcd/blob/master/connmgr/tor.go | ||
*/ | ||
public class DnsLookupTor { | ||
private static final Logger log = LoggerFactory.getLogger(DnsLookupTor.class); | ||
private static final Map<Byte, String> torStatusErrors = DnsLookupTor.createMap(); | ||
|
||
private static Map<Byte, String> createMap() { | ||
HashMap<Byte, String> map = new HashMap<>(); | ||
map.put(b('\u0000'), "tor succeeded"); | ||
map.put(b('\u0001'), "tor general error"); | ||
map.put(b('\u0002'), "tor not allowed"); | ||
map.put(b('\u0003'), "tor network is unreachable"); | ||
map.put(b('\u0004'), "tor host is unreachable"); | ||
map.put(b('\u0005'), "tor connection refused"); | ||
map.put(b('\u0006'), "tor TTL expired"); | ||
map.put(b('\u0007'), "tor command not supported"); | ||
map.put(b('\u0008'), "tor address type not supported"); | ||
return map; | ||
} | ||
|
||
/** | ||
* Performs DNS lookup and returns a single InetAddress | ||
*/ | ||
public static InetAddress lookup(Socks5Proxy proxy, String host) throws DnsLookupException { | ||
try { | ||
// note: This is creating a new connection to our proxy, without any authentication. | ||
// This works fine when connecting to bisq's internal Tor proxy, but | ||
// would fail if user has configured an external proxy that requires auth. | ||
// It would be much better to use the already connected proxy socket, but when I | ||
// tried that I get weird errors and the lookup fails. | ||
// | ||
// So this is an area for future improvement. | ||
Socket proxySocket = new Socket(proxy.getInetAddress(), proxy.getPort()); | ||
|
||
proxySocket.getOutputStream().write(new byte[]{b('\u0005'), b('\u0001'), b('\u0000')}); | ||
byte[] buf = new byte[2]; | ||
//noinspection ResultOfMethodCallIgnored | ||
proxySocket.getInputStream().read(buf); | ||
|
||
if (buf[0] != b('\u0005')) { | ||
throw new DnsLookupException("Invalid Proxy Response"); | ||
} | ||
if (buf[1] != b('\u0000')) { | ||
throw new DnsLookupException("Unrecognized Tor Auth Method"); | ||
} | ||
|
||
byte[] hostBytes = host.getBytes(); | ||
buf = new byte[7 + hostBytes.length]; | ||
buf[0] = b('\u0005'); | ||
buf[1] = b('\u00f0'); | ||
buf[2] = b('\u0000'); | ||
buf[3] = b('\u0003'); | ||
buf[4] = (byte) hostBytes.length; | ||
System.arraycopy(hostBytes, 0, buf, 5, hostBytes.length); | ||
buf[5 + hostBytes.length] = 0; | ||
|
||
proxySocket.getOutputStream().write(buf); | ||
|
||
buf = new byte[4]; | ||
//noinspection UnusedAssignment | ||
int bytesRead = proxySocket.getInputStream().read(buf); | ||
|
||
// TODO: Should not be a length check here as well? | ||
/* if (bytesRead != 4) | ||
throw new DnsLookupException("Invalid Tor Address Response");*/ | ||
|
||
|
||
if (buf[0] != b('\u0005')) | ||
throw new DnsLookupException("Invalid Tor Proxy Response"); | ||
|
||
if (buf[1] != b('\u0000')) { | ||
if (!torStatusErrors.containsKey(buf[1])) { | ||
throw new DnsLookupException("Invalid Tor Proxy Response"); | ||
} | ||
throw new DnsLookupException(torStatusErrors.get(buf[1]) + "(host=" + host + ")"); | ||
} | ||
|
||
if (buf[3] != b('\u0001')) | ||
throw new DnsLookupException(torStatusErrors.get(b('\u0001')) + "(host=" + host + ")"); | ||
|
||
buf = new byte[4]; | ||
bytesRead = proxySocket.getInputStream().read(buf); | ||
|
||
if (bytesRead != 4) | ||
throw new DnsLookupException("Invalid Tor Address Response"); | ||
|
||
return InetAddress.getByAddress(buf); | ||
} catch (IOException | DnsLookupException e) { | ||
log.warn("Error resolving " + host + ". Exception:\n" + e.toString()); | ||
throw new DnsLookupException(e); | ||
} | ||
} | ||
|
||
/** | ||
* so we can have prettier code without a bunch of casts. | ||
*/ | ||
private static byte b(char c) { | ||
return (byte) c; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* This file is part of Bisq. | ||
* | ||
* Bisq is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU Affero General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or (at | ||
* your option) any later version. | ||
* | ||
* Bisq is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public | ||
* License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package bisq.network; | ||
|
||
public class NetworkOptionKeys { | ||
public static final String TOR_DIR = "torDir"; | ||
public static final String USE_LOCALHOST_FOR_P2P = "useLocalhostForP2P"; | ||
public static final String MAX_CONNECTIONS = "maxConnections"; | ||
public static final String PORT_KEY = "nodePort"; | ||
public static final String NETWORK_ID = "networkId"; | ||
public static final String SEED_NODES_KEY = "seedNodes"; | ||
public static final String MY_ADDRESS = "myAddress"; | ||
public static final String BAN_LIST = "banList"; | ||
//SOCKS_5_PROXY_BTC_ADDRESS used in network module so dont move it to BtcOptionKeys | ||
public static final String SOCKS_5_PROXY_BTC_ADDRESS = "socks5ProxyBtcAddress"; | ||
public static final String SOCKS_5_PROXY_HTTP_ADDRESS = "socks5ProxyHttpAddress"; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/* | ||
* This file is part of Bisq. | ||
* | ||
* Bisq is free software: you can redistribute it and/or modify it | ||
* under the terms of the GNU Affero General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or (at | ||
* your option) any later version. | ||
* | ||
* Bisq is distributed in the hope that it will be useful, but WITHOUT | ||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public | ||
* License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
package bisq.network; | ||
|
||
import bisq.common.util.Utilities; | ||
|
||
import org.bitcoinj.core.NetworkParameters; | ||
import org.bitcoinj.net.discovery.DnsDiscovery; | ||
import org.bitcoinj.net.discovery.MultiplexingDiscovery; | ||
import org.bitcoinj.net.discovery.PeerDiscovery; | ||
import org.bitcoinj.net.discovery.PeerDiscoveryException; | ||
import org.bitcoinj.utils.ContextPropagatingThreadFactory; | ||
import org.bitcoinj.utils.DaemonThreadFactory; | ||
|
||
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; | ||
|
||
import java.net.InetSocketAddress; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.ExecutorService; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
|
||
/** | ||
* <p>Supports peer discovery through DNS over Socks5 proxy with RESOLVE DNS extension.</p> | ||
* <p> | ||
* (As of this writing, only Tor is known to support the RESOLVE DNS extension.) | ||
* <p> | ||
* <p>Failure to resolve individual host names will not cause an Exception to be thrown. | ||
* However, if all hosts passed fail to resolve a PeerDiscoveryException will be thrown during getPeers(). | ||
* </p> | ||
* <p> | ||
* <p>DNS seeds do not attempt to enumerate every peer on the network. {@link DnsDiscovery#getPeers(long, java.util.concurrent.TimeUnit)} | ||
* will return up to 30 random peers from the set of those returned within the timeout period. If you want more peers | ||
* to connect to, you need to discover them via other means (like addr broadcasts).</p> | ||
*/ | ||
@Slf4j | ||
public class Socks5DnsDiscovery extends MultiplexingDiscovery { | ||
|
||
/** | ||
* Supports finding peers through DNS A records. Community run DNS entry points will be used. | ||
* | ||
* @param netParams Network parameters to be used for port information. | ||
*/ | ||
public Socks5DnsDiscovery(Socks5Proxy proxy, NetworkParameters netParams) { | ||
this(proxy, netParams.getDnsSeeds(), netParams); | ||
} | ||
|
||
/** | ||
* Supports finding peers through DNS A records. | ||
* | ||
* @param dnsSeeds Host names to be examined for seed addresses. | ||
* @param params Network parameters to be used for port information. | ||
*/ | ||
public Socks5DnsDiscovery(Socks5Proxy proxy, String[] dnsSeeds, NetworkParameters params) { | ||
super(params, buildDiscoveries(proxy, params, dnsSeeds)); | ||
} | ||
|
||
private static List<PeerDiscovery> buildDiscoveries(Socks5Proxy proxy, NetworkParameters params, String[] seeds) { | ||
List<PeerDiscovery> discoveries = new ArrayList<>(seeds.length); | ||
for (String seed : seeds) | ||
discoveries.add(new Socks5DnsSeedDiscovery(proxy, params, seed)); | ||
|
||
return discoveries; | ||
} | ||
|
||
@Override | ||
protected ExecutorService createExecutor() { | ||
// Attempted workaround for reported bugs on Linux in which gethostbyname does not appear to be properly | ||
// thread safe and can cause segfaults on some libc versions. | ||
if (Utilities.isLinux()) | ||
return Executors.newSingleThreadExecutor(new ContextPropagatingThreadFactory("DNS seed lookups")); | ||
else | ||
return Executors.newFixedThreadPool(seeds.size(), new DaemonThreadFactory("DNS seed lookups")); | ||
} | ||
|
||
/** | ||
* Implements discovery from a single DNS host over Socks5 proxy with RESOLVE DNS extension. | ||
* With our DnsLookupTor (used to not leak at DNS lookup) version we only get one address instead a list of addresses like in DnsDiscovery. | ||
* We get repeated the call until we have received enough addresses. | ||
*/ | ||
public static class Socks5DnsSeedDiscovery implements PeerDiscovery { | ||
private final String hostname; | ||
private final NetworkParameters params; | ||
private final Socks5Proxy proxy; | ||
|
||
public Socks5DnsSeedDiscovery(Socks5Proxy proxy, NetworkParameters params, String hostname) { | ||
this.hostname = hostname; | ||
this.params = params; | ||
this.proxy = proxy; | ||
} | ||
|
||
/** | ||
* Returns peer addresses. The actual DNS lookup is performed here. | ||
*/ | ||
@Override | ||
public InetSocketAddress[] getPeers(long services, long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException { | ||
if (services != 0) | ||
throw new PeerDiscoveryException("DNS seeds cannot filter by services: " + services); | ||
try { | ||
InetSocketAddress addr = new InetSocketAddress(DnsLookupTor.lookup(proxy, hostname), params.getPort()); | ||
return new InetSocketAddress[]{addr}; | ||
} catch (Exception e) { | ||
throw new PeerDiscoveryException(e); | ||
} | ||
} | ||
|
||
@Override | ||
public void shutdown() { | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return hostname; | ||
} | ||
} | ||
} |
Oops, something went wrong.