mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 14:22:05 +01:00
Rework SOCKS5 unit tests so that they can be run in parallel
As result it is now also possible to start multiple local SOCKS5 proxies with different port, which is usually not necessary in real life but useful for unit tests.
This commit is contained in:
parent
d337474a86
commit
9352225f44
10 changed files with 653 additions and 709 deletions
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Copyright 2016 Florian Schmaus
|
* Copyright 2016-2019 Florian Schmaus
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -27,7 +27,7 @@ public class NetworkUtil {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(NetworkUtil.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(NetworkUtil.class.getName());
|
||||||
|
|
||||||
public static ServerSocket getSocketOnLoopback() {
|
public static ServerSocket getSocketOnLoopback() throws IOException {
|
||||||
final InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
|
final InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
|
||||||
final int portMin = 1024;
|
final int portMin = 1024;
|
||||||
final int portMax = (1 << 16) - 1;
|
final int portMax = (1 << 16) - 1;
|
||||||
|
@ -40,13 +40,12 @@ public class NetworkUtil {
|
||||||
break;
|
break;
|
||||||
} catch (BindException e) {
|
} catch (BindException e) {
|
||||||
LOGGER.log(Level.FINEST, "Could not bind port " + port + ", trying next", e);
|
LOGGER.log(Level.FINEST, "Could not bind port " + port + ", trying next", e);
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serverSocket == null) {
|
if (serverSocket == null) {
|
||||||
throw new IllegalStateException();
|
throw new IOException("Could not bind any port between " + portMin + " and " + portMax
|
||||||
|
+ " on loopback address" + loopbackAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
return serverSocket;
|
return serverSocket;
|
||||||
|
|
|
@ -56,6 +56,7 @@ import org.jivesoftware.smackx.disco.packet.DiscoverItems;
|
||||||
import org.jivesoftware.smackx.disco.packet.DiscoverItems.Item;
|
import org.jivesoftware.smackx.disco.packet.DiscoverItems.Item;
|
||||||
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
|
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
|
||||||
|
|
||||||
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
import org.jxmpp.jid.Jid;
|
import org.jxmpp.jid.Jid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,6 +150,8 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream
|
||||||
/* flag to enable/disable prioritization of last working proxy */
|
/* flag to enable/disable prioritization of last working proxy */
|
||||||
private boolean proxyPrioritizationEnabled = true;
|
private boolean proxyPrioritizationEnabled = true;
|
||||||
|
|
||||||
|
private boolean annouceLocalStreamHost = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* list containing session IDs of SOCKS5 Bytestream initialization packets that should be
|
* list containing session IDs of SOCKS5 Bytestream initialization packets that should be
|
||||||
* ignored by the InitiationListener
|
* ignored by the InitiationListener
|
||||||
|
@ -375,6 +378,30 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream
|
||||||
this.proxyPrioritizationEnabled = proxyPrioritizationEnabled;
|
this.proxyPrioritizationEnabled = proxyPrioritizationEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the bytestream manager will announce the local stream host(s), i.e. the local SOCKS5 proxy.
|
||||||
|
* <p>
|
||||||
|
* Local stream hosts will be announced if this option is enabled and at least one is running.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if
|
||||||
|
* @since 4.4.0
|
||||||
|
*/
|
||||||
|
public boolean isAnnouncingLocalStreamHostEnabled() {
|
||||||
|
return annouceLocalStreamHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether or not the bytestream manager will annouce the local stream host(s), i.e. the local SOCKS5 proxy.
|
||||||
|
*
|
||||||
|
* @param announceLocalStreamHost
|
||||||
|
* @see #isAnnouncingLocalStreamHostEnabled()
|
||||||
|
* @since 4.4.0
|
||||||
|
*/
|
||||||
|
public void setAnnounceLocalStreamHost(boolean announceLocalStreamHost) {
|
||||||
|
this.annouceLocalStreamHost = announceLocalStreamHost;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establishes a SOCKS5 Bytestream with the given user and returns the Socket to send/receive
|
* Establishes a SOCKS5 Bytestream with the given user and returns the Socket to send/receive
|
||||||
* data to/from the user.
|
* data to/from the user.
|
||||||
|
@ -592,10 +619,12 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream
|
||||||
XMPPConnection connection = connection();
|
XMPPConnection connection = connection();
|
||||||
List<StreamHost> streamHosts = new ArrayList<>();
|
List<StreamHost> streamHosts = new ArrayList<>();
|
||||||
|
|
||||||
// add local proxy on first position if exists
|
if (annouceLocalStreamHost) {
|
||||||
List<StreamHost> localProxies = getLocalStreamHost();
|
// add local proxy on first position if exists
|
||||||
if (localProxies != null) {
|
List<StreamHost> localProxies = getLocalStreamHost();
|
||||||
streamHosts.addAll(localProxies);
|
if (localProxies != null) {
|
||||||
|
streamHosts.addAll(localProxies);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// query SOCKS5 proxies for network settings
|
// query SOCKS5 proxies for network settings
|
||||||
|
@ -636,34 +665,33 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream
|
||||||
* is not running
|
* is not running
|
||||||
*/
|
*/
|
||||||
public List<StreamHost> getLocalStreamHost() {
|
public List<StreamHost> getLocalStreamHost() {
|
||||||
XMPPConnection connection = connection();
|
|
||||||
// get local proxy singleton
|
|
||||||
Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
|
|
||||||
|
|
||||||
if (!socks5Server.isRunning()) {
|
|
||||||
// server is not running
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<String> addresses = socks5Server.getLocalAddresses();
|
|
||||||
if (addresses.isEmpty()) {
|
|
||||||
// local address could not be determined
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final int port = socks5Server.getPort();
|
|
||||||
|
|
||||||
List<StreamHost> streamHosts = new ArrayList<>();
|
List<StreamHost> streamHosts = new ArrayList<>();
|
||||||
outerloop: for (String address : addresses) {
|
|
||||||
// Prevent loopback addresses from appearing as streamhost
|
XMPPConnection connection = connection();
|
||||||
final String[] loopbackAddresses = { "127.0.0.1", "0:0:0:0:0:0:0:1", "::1" };
|
EntityFullJid myJid = connection.getUser();
|
||||||
for (String loopbackAddress : loopbackAddresses) {
|
|
||||||
// Use 'startsWith' here since IPv6 addresses may have scope ID,
|
for (Socks5Proxy socks5Server : Socks5Proxy.getRunningProxies()) {
|
||||||
// ie. the part after the '%' sign.
|
List<String> addresses = socks5Server.getLocalAddresses();
|
||||||
if (address.startsWith(loopbackAddress)) {
|
if (addresses.isEmpty()) {
|
||||||
continue outerloop;
|
// local address could not be determined
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
final int port = socks5Server.getPort();
|
||||||
|
|
||||||
|
outerloop: for (String address : addresses) {
|
||||||
|
// Prevent loopback addresses from appearing as streamhost
|
||||||
|
final String[] loopbackAddresses = { "127.0.0.1", "0:0:0:0:0:0:0:1", "::1" };
|
||||||
|
for (String loopbackAddress : loopbackAddresses) {
|
||||||
|
// Use 'startsWith' here since IPv6 addresses may have scope ID,
|
||||||
|
// ie. the part after the '%' sign.
|
||||||
|
if (address.startsWith(loopbackAddress)) {
|
||||||
|
continue outerloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
streamHosts.add(new StreamHost(myJid, address, port));
|
||||||
}
|
}
|
||||||
streamHosts.add(new StreamHost(connection.getUser(), address, port));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return streamHosts;
|
return streamHosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,12 +57,14 @@ public class Socks5BytestreamRequest implements BytestreamRequest {
|
||||||
private static final Cache<String, Integer> ADDRESS_BLACKLIST = new ExpirationCache<String, Integer>(
|
private static final Cache<String, Integer> ADDRESS_BLACKLIST = new ExpirationCache<String, Integer>(
|
||||||
BLACKLIST_MAX_SIZE, BLACKLIST_LIFETIME);
|
BLACKLIST_MAX_SIZE, BLACKLIST_LIFETIME);
|
||||||
|
|
||||||
|
private static int DEFAULT_CONNECTION_FAILURE_THRESHOLD = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The number of connection failures it takes for a particular SOCKS5 proxy to be blacklisted.
|
* The number of connection failures it takes for a particular SOCKS5 proxy to be blacklisted.
|
||||||
* When a proxy is blacklisted no more connection attempts will be made to it for a period of 2
|
* When a proxy is blacklisted no more connection attempts will be made to it for a period of 2
|
||||||
* hours.
|
* hours.
|
||||||
*/
|
*/
|
||||||
private static int CONNECTION_FAILURE_THRESHOLD = 2;
|
private int connectionFailureThreshold = DEFAULT_CONNECTION_FAILURE_THRESHOLD;
|
||||||
|
|
||||||
/* the bytestream initialization request */
|
/* the bytestream initialization request */
|
||||||
private Bytestream bytestreamRequest;
|
private Bytestream bytestreamRequest;
|
||||||
|
@ -76,6 +78,28 @@ public class Socks5BytestreamRequest implements BytestreamRequest {
|
||||||
/* minimum timeout to connect to one SOCKS5 proxy */
|
/* minimum timeout to connect to one SOCKS5 proxy */
|
||||||
private int minimumConnectTimeout = 2000;
|
private int minimumConnectTimeout = 2000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default connection failure threshold.
|
||||||
|
*
|
||||||
|
* @return the default connection failure threshold.
|
||||||
|
* @see #setConnectFailureThreshold(int)
|
||||||
|
* @since 4.4.0
|
||||||
|
*/
|
||||||
|
public static int getDefaultConnectFailureThreshold() {
|
||||||
|
return DEFAULT_CONNECTION_FAILURE_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default connection failure threshold.
|
||||||
|
*
|
||||||
|
* @param defaultConnectFailureThreshold the default connection failure threshold.
|
||||||
|
* @see #setConnectFailureThreshold(int)
|
||||||
|
* @since 4.4.0
|
||||||
|
*/
|
||||||
|
public static void setDefaultConnectFailureThreshold(int defaultConnectFailureThreshold) {
|
||||||
|
DEFAULT_CONNECTION_FAILURE_THRESHOLD = defaultConnectFailureThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of connection failures it takes for a particular SOCKS5 proxy to be
|
* Returns the number of connection failures it takes for a particular SOCKS5 proxy to be
|
||||||
* blacklisted. When a proxy is blacklisted no more connection attempts will be made to it for a
|
* blacklisted. When a proxy is blacklisted no more connection attempts will be made to it for a
|
||||||
|
@ -84,8 +108,8 @@ public class Socks5BytestreamRequest implements BytestreamRequest {
|
||||||
* @return the number of connection failures it takes for a particular SOCKS5 proxy to be
|
* @return the number of connection failures it takes for a particular SOCKS5 proxy to be
|
||||||
* blacklisted
|
* blacklisted
|
||||||
*/
|
*/
|
||||||
public static int getConnectFailureThreshold() {
|
public int getConnectFailureThreshold() {
|
||||||
return CONNECTION_FAILURE_THRESHOLD;
|
return connectionFailureThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,8 +122,8 @@ public class Socks5BytestreamRequest implements BytestreamRequest {
|
||||||
* @param connectFailureThreshold the number of connection failures it takes for a particular
|
* @param connectFailureThreshold the number of connection failures it takes for a particular
|
||||||
* SOCKS5 proxy to be blacklisted
|
* SOCKS5 proxy to be blacklisted
|
||||||
*/
|
*/
|
||||||
public static void setConnectFailureThreshold(int connectFailureThreshold) {
|
public void setConnectFailureThreshold(int connectFailureThreshold) {
|
||||||
CONNECTION_FAILURE_THRESHOLD = connectFailureThreshold;
|
connectionFailureThreshold = connectFailureThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -234,7 +258,7 @@ public class Socks5BytestreamRequest implements BytestreamRequest {
|
||||||
|
|
||||||
// check to see if this address has been blacklisted
|
// check to see if this address has been blacklisted
|
||||||
int failures = getConnectionFailures(address);
|
int failures = getConnectionFailures(address);
|
||||||
if (CONNECTION_FAILURE_THRESHOLD > 0 && failures >= CONNECTION_FAILURE_THRESHOLD) {
|
if (connectionFailureThreshold > 0 && failures >= connectionFailureThreshold) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||||
import org.jivesoftware.smack.SmackException.SmackMessageException;
|
import org.jivesoftware.smack.SmackException.SmackMessageException;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.util.Async;
|
||||||
import org.jivesoftware.smack.util.CloseableUtil;
|
import org.jivesoftware.smack.util.CloseableUtil;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
|
||||||
|
@ -111,27 +112,14 @@ public class Socks5Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
Thread executor = new Thread(futureTask);
|
Async.go(futureTask, "SOCKS5 client connecting to " + streamHost);
|
||||||
executor.start();
|
|
||||||
|
|
||||||
// get connection to initiator with timeout
|
// get connection to initiator with timeout
|
||||||
try {
|
try {
|
||||||
return futureTask.get(timeout, TimeUnit.MILLISECONDS);
|
return futureTask.get(timeout, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
catch (ExecutionException e) {
|
catch (ExecutionException e) {
|
||||||
Throwable cause = e.getCause();
|
throw new IOException("ExecutionException while SOCKS5 client attempting to connect to " + streamHost, e);
|
||||||
if (cause != null) {
|
|
||||||
// case exceptions to comply with method signature
|
|
||||||
if (cause instanceof IOException) {
|
|
||||||
throw (IOException) cause;
|
|
||||||
}
|
|
||||||
if (cause instanceof SmackMessageException) {
|
|
||||||
throw (SmackMessageException) cause;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// throw generic Smack exception if unexpected exception was thrown
|
|
||||||
throw new IllegalStateException("Error while connecting to SOCKS5 proxy", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,7 @@ public class Socks5ClientForInitiator extends Socks5Client {
|
||||||
|
|
||||||
// check if stream host is the local SOCKS5 proxy
|
// check if stream host is the local SOCKS5 proxy
|
||||||
if (this.streamHost.getJID().equals(this.connection.get().getUser())) {
|
if (this.streamHost.getJID().equals(this.connection.get().getUser())) {
|
||||||
Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy();
|
socket = Socks5Proxy.getSocketForDigest(this.digest);
|
||||||
socket = socks5Server.getSocket(this.digest);
|
|
||||||
if (socket == null) {
|
if (socket == null) {
|
||||||
throw new SmackException.SmackMessageException("target is not connected to SOCKS5 proxy");
|
throw new SmackException.SmackMessageException("target is not connected to SOCKS5 proxy");
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@ -73,6 +74,8 @@ import org.jivesoftware.smack.util.CloseableUtil;
|
||||||
public final class Socks5Proxy {
|
public final class Socks5Proxy {
|
||||||
private static final Logger LOGGER = Logger.getLogger(Socks5Proxy.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(Socks5Proxy.class.getName());
|
||||||
|
|
||||||
|
private static final List<Socks5Proxy> RUNNING_PROXIES = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
/* SOCKS5 proxy singleton */
|
/* SOCKS5 proxy singleton */
|
||||||
private static Socks5Proxy socks5Server;
|
private static Socks5Proxy socks5Server;
|
||||||
|
|
||||||
|
@ -104,7 +107,7 @@ public final class Socks5Proxy {
|
||||||
/**
|
/**
|
||||||
* Private constructor.
|
* Private constructor.
|
||||||
*/
|
*/
|
||||||
private Socks5Proxy() {
|
Socks5Proxy() {
|
||||||
this.serverProcess = new Socks5ServerProcess();
|
this.serverProcess = new Socks5ServerProcess();
|
||||||
|
|
||||||
Enumeration<NetworkInterface> networkInterfaces;
|
Enumeration<NetworkInterface> networkInterfaces;
|
||||||
|
@ -188,9 +191,9 @@ public final class Socks5Proxy {
|
||||||
/**
|
/**
|
||||||
* Starts the local SOCKS5 proxy server. If it is already running, this method does nothing.
|
* Starts the local SOCKS5 proxy server. If it is already running, this method does nothing.
|
||||||
*/
|
*/
|
||||||
public synchronized void start() {
|
public synchronized ServerSocket start() {
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
return;
|
return this.serverSocket;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (getLocalSocks5ProxyPort() < 0) {
|
if (getLocalSocks5ProxyPort() < 0) {
|
||||||
|
@ -213,6 +216,8 @@ public final class Socks5Proxy {
|
||||||
this.serverThread = new Thread(this.serverProcess);
|
this.serverThread = new Thread(this.serverProcess);
|
||||||
this.serverThread.setName("Smack Local SOCKS5 Proxy [" + this.serverSocket + ']');
|
this.serverThread.setName("Smack Local SOCKS5 Proxy [" + this.serverSocket + ']');
|
||||||
this.serverThread.setDaemon(true);
|
this.serverThread.setDaemon(true);
|
||||||
|
|
||||||
|
RUNNING_PROXIES.add(this);
|
||||||
this.serverThread.start();
|
this.serverThread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,6 +225,8 @@ public final class Socks5Proxy {
|
||||||
// couldn't setup server
|
// couldn't setup server
|
||||||
LOGGER.log(Level.SEVERE, "couldn't setup local SOCKS5 proxy on port " + getLocalSocks5ProxyPort(), e);
|
LOGGER.log(Level.SEVERE, "couldn't setup local SOCKS5 proxy on port " + getLocalSocks5ProxyPort(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.serverSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,6 +237,8 @@ public final class Socks5Proxy {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RUNNING_PROXIES.remove(this);
|
||||||
|
|
||||||
CloseableUtil.maybeClose(this.serverSocket, LOGGER);
|
CloseableUtil.maybeClose(this.serverSocket, LOGGER);
|
||||||
|
|
||||||
if (this.serverThread != null && this.serverThread.isAlive()) {
|
if (this.serverThread != null && this.serverThread.isAlive()) {
|
||||||
|
@ -483,4 +492,17 @@ public final class Socks5Proxy {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Socket getSocketForDigest(String digest) {
|
||||||
|
for (Socks5Proxy socks5Proxy : RUNNING_PROXIES) {
|
||||||
|
Socket socket = socks5Proxy.getSocket(digest);
|
||||||
|
if (socket != null) {
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Socks5Proxy> getRunningProxies() {
|
||||||
|
return RUNNING_PROXIES;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.ConnectException;
|
import java.net.ConnectException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.SmackException.FeatureNotSupportedException;
|
import org.jivesoftware.smack.SmackException.FeatureNotSupportedException;
|
||||||
|
@ -37,6 +39,7 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
import org.jivesoftware.smack.packet.ErrorIQ;
|
import org.jivesoftware.smack.packet.ErrorIQ;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.StanzaError;
|
import org.jivesoftware.smack.packet.StanzaError;
|
||||||
|
import org.jivesoftware.smack.util.NetworkUtil;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
|
||||||
|
@ -49,8 +52,6 @@ import org.jivesoftware.smackx.disco.packet.DiscoverItems.Item;
|
||||||
import org.jivesoftware.util.ConnectionUtils;
|
import org.jivesoftware.util.ConnectionUtils;
|
||||||
import org.jivesoftware.util.Protocol;
|
import org.jivesoftware.util.Protocol;
|
||||||
import org.jivesoftware.util.Verification;
|
import org.jivesoftware.util.Verification;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.jxmpp.jid.DomainBareJid;
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
|
@ -71,30 +72,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
private static final DomainBareJid xmppServer = initiatorJID.asDomainBareJid();
|
private static final DomainBareJid xmppServer = initiatorJID.asDomainBareJid();
|
||||||
private static final DomainBareJid proxyJID = JidTestUtil.MUC_EXAMPLE_ORG;
|
private static final DomainBareJid proxyJID = JidTestUtil.MUC_EXAMPLE_ORG;
|
||||||
private static final String proxyAddress = "127.0.0.1";
|
private static final String proxyAddress = "127.0.0.1";
|
||||||
private static final String sessionID = "session_id";
|
|
||||||
|
|
||||||
// protocol verifier
|
|
||||||
private Protocol protocol;
|
|
||||||
|
|
||||||
// mocked XMPP connection
|
|
||||||
private XMPPConnection connection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize fields used in the tests.
|
|
||||||
* @throws XMPPException
|
|
||||||
* @throws SmackException
|
|
||||||
* @throws InterruptedException
|
|
||||||
*/
|
|
||||||
@Before
|
|
||||||
public void setup() throws XMPPException, SmackException, InterruptedException {
|
|
||||||
|
|
||||||
// build protocol verifier
|
|
||||||
protocol = new Protocol();
|
|
||||||
|
|
||||||
// create mocked XMPP connection
|
|
||||||
connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that {@link Socks5BytestreamManager#getBytestreamManager(XMPPConnection)} returns one
|
* Test that {@link Socks5BytestreamManager#getBytestreamManager(XMPPConnection)} returns one
|
||||||
|
@ -102,7 +79,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldHaveOneManagerForEveryConnection() {
|
public void shouldHaveOneManagerForEveryConnection() {
|
||||||
|
|
||||||
// mock two connections
|
// mock two connections
|
||||||
XMPPConnection connection1 = mock(XMPPConnection.class);
|
XMPPConnection connection1 = mock(XMPPConnection.class);
|
||||||
XMPPConnection connection2 = mock(XMPPConnection.class);
|
XMPPConnection connection2 = mock(XMPPConnection.class);
|
||||||
|
@ -124,15 +100,21 @@ public class Socks5ByteStreamManagerTest {
|
||||||
// assertions
|
// assertions
|
||||||
assertEquals(conn1ByteStreamManager1, conn1ByteStreamManager2);
|
assertEquals(conn1ByteStreamManager1, conn1ByteStreamManager2);
|
||||||
assertNotSame(conn1ByteStreamManager1, conn2ByteStreamManager1);
|
assertNotSame(conn1ByteStreamManager1, conn2ByteStreamManager1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SOCKS5 Bytestream feature should be removed form the service discovery manager if Socks5
|
* The SOCKS5 Bytestream feature should be removed form the service discovery manager if Socks5
|
||||||
* bytestream feature is disabled.
|
* bytestream feature is disabled.
|
||||||
|
*
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPErrorException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldDisableService() {
|
public void shouldDisableService() throws XMPPErrorException, SmackException, InterruptedException {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
ServiceDiscoveryManager discoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
|
ServiceDiscoveryManager discoveryManager = ServiceDiscoveryManager.getInstanceFor(connection);
|
||||||
|
|
||||||
|
@ -147,9 +129,15 @@ public class Socks5ByteStreamManagerTest {
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid)} should throw an exception
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid)} should throw an exception
|
||||||
* if the given target does not support SOCKS5 Bytestream.
|
* if the given target does not support SOCKS5 Bytestream.
|
||||||
* @throws XMPPException
|
* @throws XMPPException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfTargetDoesNotSupportSocks5() throws XMPPException {
|
public void shouldFailIfTargetDoesNotSupportSocks5()
|
||||||
|
throws XMPPException, SmackException, InterruptedException, IOException {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -165,24 +153,27 @@ public class Socks5ByteStreamManagerTest {
|
||||||
catch (FeatureNotSupportedException e) {
|
catch (FeatureNotSupportedException e) {
|
||||||
assertTrue(e.getFeature().equals("SOCKS5 Bytestream"));
|
assertTrue(e.getFeature().equals("SOCKS5 Bytestream"));
|
||||||
assertTrue(e.getJid().equals(targetJID));
|
assertTrue(e.getJid().equals(targetJID));
|
||||||
} catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if XMPP
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if XMPP
|
||||||
* server doesn't return any proxies.
|
* server doesn't return any proxies.
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfNoSocks5ProxyFound1() {
|
public void shouldFailIfNoSocks5ProxyFound1()
|
||||||
|
throws SmackException, InterruptedException, IOException, XMPPException {
|
||||||
// disable clients local SOCKS5 proxy
|
final Protocol protocol = new Protocol();
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
final String sessionID = "session_id_shouldFailIfNoSocks5ProxyFound1";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create responses in the order they should be queried specified by the XEP-0065
|
* create responses in the order they should be queried specified by the XEP-0065
|
||||||
|
@ -206,7 +197,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
Verification.requestTypeGET);
|
Verification.requestTypeGET);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// start SOCKS5 Bytestream
|
// start SOCKS5 Bytestream
|
||||||
byteStreamManager.establishSession(targetJID, sessionID);
|
byteStreamManager.establishSession(targetJID, sessionID);
|
||||||
|
|
||||||
|
@ -216,24 +206,27 @@ public class Socks5ByteStreamManagerTest {
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
assertTrue(e.getMessage().contains("no SOCKS5 proxies available"));
|
assertTrue(e.getMessage().contains("no SOCKS5 proxies available"));
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if no
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if no
|
||||||
* proxy is a SOCKS5 proxy.
|
* proxy is a SOCKS5 proxy.
|
||||||
|
*
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfNoSocks5ProxyFound2() {
|
public void shouldFailIfNoSocks5ProxyFound2()
|
||||||
|
throws SmackException, InterruptedException, IOException, XMPPException {
|
||||||
// disable clients local SOCKS5 proxy
|
final Protocol protocol = new Protocol();
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
final String sessionID = "session_id_shouldFailIfNoSocks5ProxyFound2";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create responses in the order they should be queried specified by the XEP-0065
|
* create responses in the order they should be queried specified by the XEP-0065
|
||||||
|
@ -269,7 +262,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
Verification.requestTypeGET);
|
Verification.requestTypeGET);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// start SOCKS5 Bytestream
|
// start SOCKS5 Bytestream
|
||||||
byteStreamManager.establishSession(targetJID, sessionID);
|
byteStreamManager.establishSession(targetJID, sessionID);
|
||||||
|
|
||||||
|
@ -279,25 +271,26 @@ public class Socks5ByteStreamManagerTest {
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
assertTrue(e.getMessage().contains("no SOCKS5 proxies available"));
|
assertTrue(e.getMessage().contains("no SOCKS5 proxies available"));
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if no
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if no
|
||||||
* SOCKS5 proxy can be found. If it turns out that a proxy is not a SOCKS5 proxy it should not
|
* SOCKS5 proxy can be found. If it turns out that a proxy is not a SOCKS5 proxy it should not
|
||||||
* be queried again.
|
* be queried again.
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldBlacklistNonSocks5Proxies() {
|
public void shouldBlacklistNonSocks5Proxies() throws SmackException, InterruptedException, IOException, XMPPException {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
// disable clients local SOCKS5 proxy
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final String sessionID = "session_id_shouldBlacklistNonSocks5Proxies";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create responses in the order they should be queried specified by the XEP-0065
|
* create responses in the order they should be queried specified by the XEP-0065
|
||||||
|
@ -333,7 +326,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
Verification.requestTypeGET);
|
Verification.requestTypeGET);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// start SOCKS5 Bytestream
|
// start SOCKS5 Bytestream
|
||||||
byteStreamManager.establishSession(targetJID, sessionID);
|
byteStreamManager.establishSession(targetJID, sessionID);
|
||||||
|
|
||||||
|
@ -343,9 +335,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
assertTrue(e.getMessage().contains("no SOCKS5 proxies available"));
|
assertTrue(e.getMessage().contains("no SOCKS5 proxies available"));
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* retry to establish SOCKS5 Bytestream */
|
/* retry to establish SOCKS5 Bytestream */
|
||||||
|
|
||||||
|
@ -356,7 +345,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
Verification.requestTypeGET);
|
Verification.requestTypeGET);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// start SOCKS5 Bytestream
|
// start SOCKS5 Bytestream
|
||||||
byteStreamManager.establishSession(targetJID, sessionID);
|
byteStreamManager.establishSession(targetJID, sessionID);
|
||||||
|
|
||||||
|
@ -370,25 +358,26 @@ public class Socks5ByteStreamManagerTest {
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
assertTrue(e.getMessage().contains("no SOCKS5 proxies available"));
|
assertTrue(e.getMessage().contains("no SOCKS5 proxies available"));
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if the
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if the
|
||||||
* target does not accept a SOCKS5 Bytestream. See <a
|
* target does not accept a SOCKS5 Bytestream. See <a
|
||||||
* href="http://xmpp.org/extensions/xep-0065.html#usecase-alternate">XEP-0065 Section 5.2 A2</a>
|
* href="http://xmpp.org/extensions/xep-0065.html#usecase-alternate">XEP-0065 Section 5.2 A2</a>
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfTargetDoesNotAcceptSocks5Bytestream() {
|
public void shouldFailIfTargetDoesNotAcceptSocks5Bytestream() throws SmackException, InterruptedException, IOException, XMPPException {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
// disable clients local SOCKS5 proxy
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final String sessionID = "session_id_shouldFailIfTargetDoesNotAcceptSocks5Bytestream";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create responses in the order they should be queried specified by the XEP-0065
|
* create responses in the order they should be queried specified by the XEP-0065
|
||||||
|
@ -443,7 +432,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
Verification.requestTypeSET);
|
Verification.requestTypeSET);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// start SOCKS5 Bytestream
|
// start SOCKS5 Bytestream
|
||||||
byteStreamManager.establishSession(targetJID, sessionID);
|
byteStreamManager.establishSession(targetJID, sessionID);
|
||||||
|
|
||||||
|
@ -453,25 +441,28 @@ public class Socks5ByteStreamManagerTest {
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
assertEquals(rejectPacket.getError(), e.getStanzaError());
|
assertEquals(rejectPacket.getError(), e.getStanzaError());
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if the
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if the
|
||||||
* proxy used by target is invalid.
|
* proxy used by target is invalid.
|
||||||
* @throws XmppStringprepException
|
*
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfTargetUsesInvalidSocks5Proxy() throws XmppStringprepException {
|
public void shouldFailIfTargetUsesInvalidSocks5Proxy()
|
||||||
|
throws SmackException, InterruptedException, IOException, XMPPException {
|
||||||
// disable clients local SOCKS5 proxy
|
final Protocol protocol = new Protocol();
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
final String sessionID = "session_id_shouldFailIfTargetUsesInvalidSocks5Proxy";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
// TODO: It appears that it is not required to disable the local stream host for this unit test.
|
||||||
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create responses in the order they should be queried specified by the XEP-0065
|
* create responses in the order they should be queried specified by the XEP-0065
|
||||||
|
@ -526,7 +517,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
Verification.requestTypeSET);
|
Verification.requestTypeSET);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// start SOCKS5 Bytestream
|
// start SOCKS5 Bytestream
|
||||||
byteStreamManager.establishSession(targetJID, sessionID);
|
byteStreamManager.establishSession(targetJID, sessionID);
|
||||||
|
|
||||||
|
@ -536,24 +526,26 @@ public class Socks5ByteStreamManagerTest {
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
assertTrue(e.getMessage().contains("Remote user responded with unknown host"));
|
assertTrue(e.getMessage().contains("Remote user responded with unknown host"));
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should fail if
|
||||||
* initiator can not connect to the SOCKS5 proxy used by target.
|
* initiator can not connect to the SOCKS5 proxy used by target.
|
||||||
|
*
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfInitiatorCannotConnectToSocks5Proxy() {
|
public void shouldFailIfInitiatorCannotConnectToSocks5Proxy()
|
||||||
|
throws SmackException, InterruptedException, XMPPException {
|
||||||
// disable clients local SOCKS5 proxy
|
final Protocol protocol = new Protocol();
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
final String sessionID = "session_id_shouldFailIfInitiatorCannotConnectToSocks5Proxy";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create responses in the order they should be queried specified by the XEP-0065
|
* create responses in the order they should be queried specified by the XEP-0065
|
||||||
|
@ -618,7 +610,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
}, Verification.correspondingSenderReceiver, Verification.requestTypeSET);
|
}, Verification.correspondingSenderReceiver, Verification.requestTypeSET);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// start SOCKS5 Bytestream
|
// start SOCKS5 Bytestream
|
||||||
byteStreamManager.establishSession(targetJID, sessionID);
|
byteStreamManager.establishSession(targetJID, sessionID);
|
||||||
|
|
||||||
|
@ -627,28 +618,30 @@ public class Socks5ByteStreamManagerTest {
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
// initiator can't connect to proxy because it is not running
|
// initiator can't connect to proxy because it is not running
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
assertEquals(ConnectException.class, e.getClass());
|
Throwable actualCause = e.getCause().getCause();
|
||||||
|
assertEquals(ConnectException.class, actualCause.getClass());
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should successfully
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} should successfully
|
||||||
* negotiate and return a SOCKS5 Bytestream connection.
|
* negotiate and return a SOCKS5 Bytestream connection.
|
||||||
*
|
*
|
||||||
* @throws Exception should not happen
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldNegotiateSocks5BytestreamAndTransferData() throws Exception {
|
public void shouldNegotiateSocks5BytestreamAndTransferData()
|
||||||
|
throws SmackException, InterruptedException, IOException, XMPPException {
|
||||||
// disable clients local SOCKS5 proxy
|
final Protocol protocol = new Protocol();
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
final String sessionID = "session_id_shouldNegotiateSocks5BytestreamAndTransferData";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create responses in the order they should be queried specified by the XEP-0065
|
* create responses in the order they should be queried specified by the XEP-0065
|
||||||
|
@ -684,9 +677,10 @@ public class Socks5ByteStreamManagerTest {
|
||||||
|
|
||||||
// build a socks5 stream host info containing the address and the port of the
|
// build a socks5 stream host info containing the address and the port of the
|
||||||
// proxy
|
// proxy
|
||||||
|
ServerSocket proxyServerSocket = NetworkUtil.getSocketOnLoopback();
|
||||||
Bytestream streamHostInfo = Socks5PacketUtils.createBytestreamResponse(proxyJID,
|
Bytestream streamHostInfo = Socks5PacketUtils.createBytestreamResponse(proxyJID,
|
||||||
initiatorJID);
|
initiatorJID);
|
||||||
streamHostInfo.addStreamHost(proxyJID, proxyAddress, 7778);
|
streamHostInfo.addStreamHost(proxyJID, proxyAddress, proxyServerSocket.getLocalPort());
|
||||||
|
|
||||||
// return stream host info if it is queried
|
// return stream host info if it is queried
|
||||||
protocol.addResponse(streamHostInfo, Verification.correspondingSenderReceiver,
|
protocol.addResponse(streamHostInfo, Verification.correspondingSenderReceiver,
|
||||||
|
@ -726,143 +720,146 @@ public class Socks5ByteStreamManagerTest {
|
||||||
}, Verification.correspondingSenderReceiver, Verification.requestTypeSET);
|
}, Verification.correspondingSenderReceiver, Verification.requestTypeSET);
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778);
|
try (Socks5TestProxy socks5Proxy = new Socks5TestProxy(proxyServerSocket)) {
|
||||||
socks5Proxy.start();
|
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
// create digest to get the socket opened by target
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
// finally call the method that should be tested
|
// finally call the method that should be tested
|
||||||
OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
||||||
|
|
||||||
// test the established bytestream
|
// test the established bytestream
|
||||||
InputStream inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
InputStream inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
||||||
|
|
||||||
byte[] data = new byte[] { 1, 2, 3 };
|
byte[] data = new byte[] { 1, 2, 3 };
|
||||||
outputStream.write(data);
|
outputStream.write(data);
|
||||||
|
|
||||||
byte[] result = new byte[3];
|
byte[] result = new byte[3];
|
||||||
inputStream.read(result);
|
inputStream.read(result);
|
||||||
|
|
||||||
assertArrayEquals(data, result);
|
assertArrayEquals(data, result);
|
||||||
|
}
|
||||||
|
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If multiple network addresses are added to the local SOCKS5 proxy, all of them should be
|
* If multiple network addresses are added to the local SOCKS5 proxy, all of them should be
|
||||||
* contained in the SOCKS5 Bytestream request.
|
* contained in the SOCKS5 Bytestream request.
|
||||||
*
|
*
|
||||||
* @throws Exception should not happen
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws XMPPException
|
||||||
|
* @throws TimeoutException
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldUseMultipleAddressesForLocalSocks5Proxy() throws Exception {
|
public void shouldUseMultipleAddressesForLocalSocks5Proxy()
|
||||||
|
throws SmackException, InterruptedException, IOException, TimeoutException, XMPPException {
|
||||||
// enable clients local SOCKS5 proxy on port 7778
|
final Protocol protocol = new Protocol();
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(true);
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
Socks5Proxy.setLocalSocks5ProxyPort(7778);
|
final String sessionID = "session_id_shouldUseMultipleAddressesForLocalSocks5Proxy";
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
|
Socks5Proxy socks5Proxy = new Socks5Proxy();
|
||||||
socks5Proxy.start();
|
socks5Proxy.start();
|
||||||
assertTrue(socks5Proxy.isRunning());
|
try {
|
||||||
|
assertTrue(socks5Proxy.isRunning());
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create responses in the order they should be queried specified by the XEP-0065
|
* create responses in the order they should be queried specified by the XEP-0065
|
||||||
* specification
|
* specification
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// build discover info that supports the SOCKS5 feature
|
// build discover info that supports the SOCKS5 feature
|
||||||
DiscoverInfo discoverInfo = Socks5PacketUtils.createDiscoverInfo(targetJID, initiatorJID);
|
DiscoverInfo discoverInfo = Socks5PacketUtils.createDiscoverInfo(targetJID, initiatorJID);
|
||||||
discoverInfo.addFeature(Bytestream.NAMESPACE);
|
discoverInfo.addFeature(Bytestream.NAMESPACE);
|
||||||
|
|
||||||
// return that SOCKS5 is supported if target is queried
|
// return that SOCKS5 is supported if target is queried
|
||||||
protocol.addResponse(discoverInfo, Verification.correspondingSenderReceiver,
|
protocol.addResponse(discoverInfo, Verification.correspondingSenderReceiver,
|
||||||
Verification.requestTypeGET);
|
Verification.requestTypeGET);
|
||||||
|
|
||||||
// build discover items containing no proxy item
|
// build discover items containing no proxy item
|
||||||
DiscoverItems discoverItems = Socks5PacketUtils.createDiscoverItems(xmppServer,
|
DiscoverItems discoverItems = Socks5PacketUtils.createDiscoverItems(xmppServer,
|
||||||
initiatorJID);
|
initiatorJID);
|
||||||
|
|
||||||
// return the discover item if XMPP server is queried
|
// return the discover item if XMPP server is queried
|
||||||
protocol.addResponse(discoverItems, Verification.correspondingSenderReceiver,
|
protocol.addResponse(discoverItems, Verification.correspondingSenderReceiver,
|
||||||
Verification.requestTypeGET);
|
Verification.requestTypeGET);
|
||||||
|
|
||||||
// build used stream host response
|
// build used stream host response
|
||||||
Bytestream streamHostUsedPacket = Socks5PacketUtils.createBytestreamResponse(targetJID,
|
Bytestream streamHostUsedPacket = Socks5PacketUtils.createBytestreamResponse(targetJID,
|
||||||
initiatorJID);
|
initiatorJID);
|
||||||
streamHostUsedPacket.setSessionID(sessionID);
|
streamHostUsedPacket.setSessionID(sessionID);
|
||||||
streamHostUsedPacket.setUsedHost(initiatorJID); // local proxy used
|
streamHostUsedPacket.setUsedHost(initiatorJID); // local proxy used
|
||||||
|
|
||||||
// return used stream host info as response to the bytestream initiation
|
// return used stream host info as response to the bytestream initiation
|
||||||
protocol.addResponse(streamHostUsedPacket, new Verification<Bytestream, Bytestream>() {
|
protocol.addResponse(streamHostUsedPacket, new Verification<Bytestream, Bytestream>() {
|
||||||
|
@Override
|
||||||
|
public void verify(Bytestream request, Bytestream response) {
|
||||||
|
assertEquals(response.getSessionID(), request.getSessionID());
|
||||||
|
StreamHost streamHost1 = request.getStreamHosts().get(0);
|
||||||
|
assertEquals(response.getUsedHost().getJID(), streamHost1.getJID());
|
||||||
|
StreamHost streamHost2 = request.getStreamHosts().get(request.getStreamHosts().size() - 1);
|
||||||
|
assertEquals(response.getUsedHost().getJID(), streamHost2.getJID());
|
||||||
|
assertEquals("localAddress", streamHost2.getAddress());
|
||||||
|
}
|
||||||
|
}, Verification.correspondingSenderReceiver, Verification.requestTypeSET);
|
||||||
|
|
||||||
@Override
|
// create digest to get the socket opened by target
|
||||||
public void verify(Bytestream request, Bytestream response) {
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
assertEquals(response.getSessionID(), request.getSessionID());
|
|
||||||
StreamHost streamHost1 = request.getStreamHosts().get(0);
|
// connect to proxy as target
|
||||||
assertEquals(response.getUsedHost().getJID(), streamHost1.getJID());
|
socks5Proxy.addTransfer(digest);
|
||||||
StreamHost streamHost2 = request.getStreamHosts().get(request.getStreamHosts().size() - 1);
|
StreamHost streamHost = new StreamHost(targetJID,
|
||||||
assertEquals(response.getUsedHost().getJID(), streamHost2.getJID());
|
socks5Proxy.getLocalAddresses().get(0),
|
||||||
assertEquals("localAddress", streamHost2.getAddress());
|
socks5Proxy.getPort());
|
||||||
|
Socks5Client socks5Client = new Socks5Client(streamHost, digest);
|
||||||
|
InputStream inputStream = socks5Client.getSocket(2000).getInputStream();
|
||||||
|
|
||||||
|
// add another network address before establishing SOCKS5 Bytestream
|
||||||
|
socks5Proxy.addLocalAddress("localAddress");
|
||||||
|
|
||||||
|
// finally call the method that should be tested
|
||||||
|
OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
||||||
|
|
||||||
|
// test the established bytestream
|
||||||
|
byte[] data = new byte[] { 1, 2, 3 };
|
||||||
|
outputStream.write(data);
|
||||||
|
|
||||||
|
byte[] result = new byte[3];
|
||||||
|
inputStream.read(result);
|
||||||
|
|
||||||
|
assertArrayEquals(data, result);
|
||||||
|
|
||||||
|
protocol.verifyAll();
|
||||||
|
} finally {
|
||||||
|
socks5Proxy.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
}, Verification.correspondingSenderReceiver, Verification.requestTypeSET);
|
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
|
||||||
|
|
||||||
// connect to proxy as target
|
|
||||||
socks5Proxy.addTransfer(digest);
|
|
||||||
StreamHost streamHost = new StreamHost(targetJID,
|
|
||||||
socks5Proxy.getLocalAddresses().get(0),
|
|
||||||
socks5Proxy.getPort());
|
|
||||||
Socks5Client socks5Client = new Socks5Client(streamHost, digest);
|
|
||||||
InputStream inputStream = socks5Client.getSocket(2000).getInputStream();
|
|
||||||
|
|
||||||
// add another network address before establishing SOCKS5 Bytestream
|
|
||||||
socks5Proxy.addLocalAddress("localAddress");
|
|
||||||
|
|
||||||
// finally call the method that should be tested
|
|
||||||
OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
|
||||||
|
|
||||||
// test the established bytestream
|
|
||||||
byte[] data = new byte[] { 1, 2, 3 };
|
|
||||||
outputStream.write(data);
|
|
||||||
|
|
||||||
byte[] result = new byte[3];
|
|
||||||
inputStream.read(result);
|
|
||||||
|
|
||||||
assertArrayEquals(data, result);
|
|
||||||
|
|
||||||
protocol.verifyAll();
|
|
||||||
|
|
||||||
// reset proxy settings
|
|
||||||
socks5Proxy.stop();
|
|
||||||
socks5Proxy.removeLocalAddress("localAddress");
|
|
||||||
Socks5Proxy.setLocalSocks5ProxyPort(7777);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} the first time
|
* Invoking {@link Socks5BytestreamManager#establishSession(org.jxmpp.jid.Jid, String)} the first time
|
||||||
* should successfully negotiate a SOCKS5 Bytestream via the second SOCKS5 proxy and should
|
* should successfully negotiate a SOCKS5 Bytestream via the second SOCKS5 proxy and should
|
||||||
* prioritize this proxy for a second SOCKS5 Bytestream negotiation.
|
* prioritize this proxy for a second SOCKS5 Bytestream negotiation.
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
|
* @throws IOException
|
||||||
*
|
*
|
||||||
* @throws Exception should not happen
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldPrioritizeSecondSocks5ProxyOnSecondAttempt() throws Exception {
|
public void shouldPrioritizeSecondSocks5ProxyOnSecondAttempt() throws SmackException, InterruptedException, IOException, XMPPException {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
// disable clients local SOCKS5 proxy
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final String sessionID = "session_id_shouldPrioritizeSecondSocks5ProxyOnSecondAttempt";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
assertTrue(byteStreamManager.isProxyPrioritizationEnabled());
|
assertTrue(byteStreamManager.isProxyPrioritizationEnabled());
|
||||||
|
|
||||||
|
@ -878,59 +875,58 @@ public class Socks5ByteStreamManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
createResponses(streamHostUsedVerification1);
|
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778);
|
try (Socks5TestProxy socks5Proxy = new Socks5TestProxy()) {
|
||||||
socks5Proxy.start();
|
createResponses(protocol, sessionID, streamHostUsedVerification1, socks5Proxy);
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
// create digest to get the socket opened by target
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
// call the method that should be tested
|
// call the method that should be tested
|
||||||
OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
||||||
|
|
||||||
// test the established bytestream
|
// test the established bytestream
|
||||||
InputStream inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
InputStream inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
||||||
|
|
||||||
byte[] data = new byte[] { 1, 2, 3 };
|
byte[] data = new byte[] { 1, 2, 3 };
|
||||||
outputStream.write(data);
|
outputStream.write(data);
|
||||||
|
|
||||||
byte[] result = new byte[3];
|
byte[] result = new byte[3];
|
||||||
inputStream.read(result);
|
inputStream.read(result);
|
||||||
|
|
||||||
assertArrayEquals(data, result);
|
assertArrayEquals(data, result);
|
||||||
|
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
|
|
||||||
Verification<Bytestream, Bytestream> streamHostUsedVerification2 = new Verification<Bytestream, Bytestream>() {
|
Verification<Bytestream, Bytestream> streamHostUsedVerification2 = new Verification<Bytestream, Bytestream>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void verify(Bytestream request, Bytestream response) {
|
public void verify(Bytestream request, Bytestream response) {
|
||||||
assertEquals(response.getSessionID(), request.getSessionID());
|
assertEquals(response.getSessionID(), request.getSessionID());
|
||||||
assertEquals(2, request.getStreamHosts().size());
|
assertEquals(2, request.getStreamHosts().size());
|
||||||
// verify that the used stream host is the first in list
|
// verify that the used stream host is the first in list
|
||||||
StreamHost streamHost = (StreamHost) request.getStreamHosts().toArray()[0];
|
StreamHost streamHost = (StreamHost) request.getStreamHosts().toArray()[0];
|
||||||
assertEquals(response.getUsedHost().getJID(), streamHost.getJID());
|
assertEquals(response.getUsedHost().getJID(), streamHost.getJID());
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
createResponses(streamHostUsedVerification2);
|
createResponses(protocol, sessionID, streamHostUsedVerification2, socks5Proxy);
|
||||||
|
|
||||||
// call the method that should be tested again
|
// call the method that should be tested again
|
||||||
outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
||||||
|
|
||||||
// test the established bytestream
|
// test the established bytestream
|
||||||
inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
||||||
|
|
||||||
outputStream.write(data);
|
outputStream.write(data);
|
||||||
|
|
||||||
inputStream.read(result);
|
inputStream.read(result);
|
||||||
|
|
||||||
assertArrayEquals(data, result);
|
assertArrayEquals(data, result);
|
||||||
|
|
||||||
protocol.verifyAll();
|
|
||||||
|
|
||||||
|
protocol.verifyAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -938,18 +934,23 @@ public class Socks5ByteStreamManagerTest {
|
||||||
* should successfully negotiate a SOCKS5 Bytestream via the second SOCKS5 proxy. The second
|
* should successfully negotiate a SOCKS5 Bytestream via the second SOCKS5 proxy. The second
|
||||||
* negotiation should run in the same manner if prioritization is disabled.
|
* negotiation should run in the same manner if prioritization is disabled.
|
||||||
*
|
*
|
||||||
* @throws Exception should not happen
|
* @throws IOException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws SmackException
|
||||||
|
* @throws XMPPException
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotPrioritizeSocks5ProxyIfPrioritizationDisabled() throws Exception {
|
public void shouldNotPrioritizeSocks5ProxyIfPrioritizationDisabled() throws IOException, SmackException, InterruptedException, XMPPException {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
// disable clients local SOCKS5 proxy
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
|
final String sessionID = "session_id_shouldNotPrioritizeSocks5ProxyIfPrioritizationDisabled";
|
||||||
|
|
||||||
// get Socks5ByteStreamManager for connection
|
// get Socks5ByteStreamManager for connection
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
byteStreamManager.setProxyPrioritizationEnabled(false);
|
byteStreamManager.setAnnounceLocalStreamHost(false);
|
||||||
|
|
||||||
|
byteStreamManager.setProxyPrioritizationEnabled(false);
|
||||||
assertFalse(byteStreamManager.isProxyPrioritizationEnabled());
|
assertFalse(byteStreamManager.isProxyPrioritizationEnabled());
|
||||||
|
|
||||||
Verification<Bytestream, Bytestream> streamHostUsedVerification = new Verification<Bytestream, Bytestream>() {
|
Verification<Bytestream, Bytestream> streamHostUsedVerification = new Verification<Bytestream, Bytestream>() {
|
||||||
|
@ -964,52 +965,51 @@ public class Socks5ByteStreamManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
createResponses(streamHostUsedVerification);
|
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778);
|
try (Socks5TestProxy socks5Proxy = new Socks5TestProxy()) {
|
||||||
socks5Proxy.start();
|
createResponses(protocol, sessionID, streamHostUsedVerification, socks5Proxy);
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
// create digest to get the socket opened by target
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
// call the method that should be tested
|
// call the method that should be tested
|
||||||
OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
||||||
|
|
||||||
// test the established bytestream
|
// test the established bytestream
|
||||||
InputStream inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
InputStream inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
||||||
|
|
||||||
byte[] data = new byte[] { 1, 2, 3 };
|
byte[] data = new byte[] { 1, 2, 3 };
|
||||||
outputStream.write(data);
|
outputStream.write(data);
|
||||||
|
|
||||||
byte[] result = new byte[3];
|
byte[] result = new byte[3];
|
||||||
inputStream.read(result);
|
inputStream.read(result);
|
||||||
|
|
||||||
assertArrayEquals(data, result);
|
assertArrayEquals(data, result);
|
||||||
|
|
||||||
|
protocol.verifyAll();
|
||||||
|
|
||||||
|
createResponses(protocol, sessionID, streamHostUsedVerification, socks5Proxy);
|
||||||
|
|
||||||
|
// call the method that should be tested again
|
||||||
|
outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
||||||
|
|
||||||
|
// test the established bytestream
|
||||||
|
inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
||||||
|
|
||||||
|
outputStream.write(data);
|
||||||
|
|
||||||
|
inputStream.read(result);
|
||||||
|
|
||||||
|
assertArrayEquals(data, result);
|
||||||
|
}
|
||||||
|
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
|
|
||||||
createResponses(streamHostUsedVerification);
|
|
||||||
|
|
||||||
// call the method that should be tested again
|
|
||||||
outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream();
|
|
||||||
|
|
||||||
// test the established bytestream
|
|
||||||
inputStream = socks5Proxy.getSocket(digest).getInputStream();
|
|
||||||
|
|
||||||
outputStream.write(data);
|
|
||||||
|
|
||||||
inputStream.read(result);
|
|
||||||
|
|
||||||
assertArrayEquals(data, result);
|
|
||||||
|
|
||||||
protocol.verifyAll();
|
|
||||||
|
|
||||||
byteStreamManager.setProxyPrioritizationEnabled(true);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createResponses(Verification<Bytestream, Bytestream> streamHostUsedVerification) throws XmppStringprepException {
|
private static void createResponses(Protocol protocol, String sessionID,
|
||||||
|
Verification<Bytestream, Bytestream> streamHostUsedVerification, Socks5TestProxy socks5TestProxy)
|
||||||
|
throws XmppStringprepException {
|
||||||
// build discover info that supports the SOCKS5 feature
|
// build discover info that supports the SOCKS5 feature
|
||||||
DiscoverInfo discoverInfo = Socks5PacketUtils.createDiscoverInfo(targetJID, initiatorJID);
|
DiscoverInfo discoverInfo = Socks5PacketUtils.createDiscoverInfo(targetJID, initiatorJID);
|
||||||
discoverInfo.addFeature(Bytestream.NAMESPACE);
|
discoverInfo.addFeature(Bytestream.NAMESPACE);
|
||||||
|
@ -1056,7 +1056,7 @@ public class Socks5ByteStreamManagerTest {
|
||||||
*/
|
*/
|
||||||
Bytestream streamHostInfo1 = Socks5PacketUtils.createBytestreamResponse(
|
Bytestream streamHostInfo1 = Socks5PacketUtils.createBytestreamResponse(
|
||||||
JidCreate.from("proxy2.xmpp-server"), initiatorJID);
|
JidCreate.from("proxy2.xmpp-server"), initiatorJID);
|
||||||
streamHostInfo1.addStreamHost(JidCreate.from("proxy2.xmpp-server"), proxyAddress, 7778);
|
streamHostInfo1.addStreamHost(JidCreate.from("proxy2.xmpp-server"), proxyAddress, socks5TestProxy.getPort());
|
||||||
|
|
||||||
// return stream host info if it is queried
|
// return stream host info if it is queried
|
||||||
protocol.addResponse(streamHostInfo1, Verification.correspondingSenderReceiver,
|
protocol.addResponse(streamHostInfo1, Verification.correspondingSenderReceiver,
|
||||||
|
@ -1065,7 +1065,7 @@ public class Socks5ByteStreamManagerTest {
|
||||||
// build a SOCKS5 stream host info containing the address and the port of the proxy
|
// build a SOCKS5 stream host info containing the address and the port of the proxy
|
||||||
Bytestream streamHostInfo2 = Socks5PacketUtils.createBytestreamResponse(proxyJID,
|
Bytestream streamHostInfo2 = Socks5PacketUtils.createBytestreamResponse(proxyJID,
|
||||||
initiatorJID);
|
initiatorJID);
|
||||||
streamHostInfo2.addStreamHost(proxyJID, proxyAddress, 7778);
|
streamHostInfo2.addStreamHost(proxyJID, proxyAddress, socks5TestProxy.getPort());
|
||||||
|
|
||||||
// return stream host info if it is queried
|
// return stream host info if it is queried
|
||||||
protocol.addResponse(streamHostInfo2, Verification.correspondingSenderReceiver,
|
protocol.addResponse(streamHostInfo2, Verification.correspondingSenderReceiver,
|
||||||
|
@ -1094,16 +1094,6 @@ public class Socks5ByteStreamManagerTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
}, Verification.correspondingSenderReceiver, Verification.requestTypeSET);
|
}, Verification.correspondingSenderReceiver, Verification.requestTypeSET);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop eventually started local SOCKS5 test proxy.
|
|
||||||
*/
|
|
||||||
@After
|
|
||||||
public void cleanUp() {
|
|
||||||
Socks5TestProxy.stopProxy();
|
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,19 +27,16 @@ import java.io.OutputStream;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.Stanza;
|
import org.jivesoftware.smack.packet.Stanza;
|
||||||
import org.jivesoftware.smack.packet.StanzaError;
|
import org.jivesoftware.smack.packet.StanzaError;
|
||||||
|
import org.jivesoftware.smack.util.NetworkUtil;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
||||||
|
|
||||||
import org.jivesoftware.util.ConnectionUtils;
|
import org.jivesoftware.util.ConnectionUtils;
|
||||||
import org.jivesoftware.util.Protocol;
|
import org.jivesoftware.util.Protocol;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.jxmpp.jid.DomainBareJid;
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
|
@ -60,27 +57,6 @@ public class Socks5ByteStreamRequestTest {
|
||||||
private static final String proxyAddress = "127.0.0.1";
|
private static final String proxyAddress = "127.0.0.1";
|
||||||
private static final String sessionID = "session_id";
|
private static final String sessionID = "session_id";
|
||||||
|
|
||||||
private Protocol protocol;
|
|
||||||
|
|
||||||
private XMPPConnection connection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize fields used in the tests.
|
|
||||||
* @throws XMPPException
|
|
||||||
* @throws SmackException
|
|
||||||
* @throws InterruptedException
|
|
||||||
*/
|
|
||||||
@Before
|
|
||||||
public void setup() throws XMPPException, SmackException, InterruptedException {
|
|
||||||
|
|
||||||
// build protocol verifier
|
|
||||||
protocol = new Protocol();
|
|
||||||
|
|
||||||
// create mocked XMPP connection
|
|
||||||
connection = ConnectionUtils.createMockedConnection(protocol, targetJID);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepting a SOCKS5 Bytestream request should fail if the request doesn't contain any Socks5
|
* Accepting a SOCKS5 Bytestream request should fail if the request doesn't contain any Socks5
|
||||||
* proxies.
|
* proxies.
|
||||||
|
@ -89,6 +65,9 @@ public class Socks5ByteStreamRequestTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfRequestHasNoStreamHosts() throws Exception {
|
public void shouldFailIfRequestHasNoStreamHosts() throws Exception {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, targetJID);
|
||||||
|
|
||||||
assertThrows(Socks5Exception.NoSocks5StreamHostsProvided.class, () -> {
|
assertThrows(Socks5Exception.NoSocks5StreamHostsProvided.class, () -> {
|
||||||
// build SOCKS5 Bytestream initialization request with no SOCKS5 proxies
|
// build SOCKS5 Bytestream initialization request with no SOCKS5 proxies
|
||||||
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
||||||
|
@ -113,7 +92,6 @@ public class Socks5ByteStreamRequestTest {
|
||||||
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
||||||
assertEquals(StanzaError.Condition.item_not_found,
|
assertEquals(StanzaError.Condition.item_not_found,
|
||||||
targetResponse.getError().getCondition());
|
targetResponse.getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,6 +102,9 @@ public class Socks5ByteStreamRequestTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfRequestHasInvalidStreamHosts() throws Exception {
|
public void shouldFailIfRequestHasInvalidStreamHosts() throws Exception {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, targetJID);
|
||||||
|
|
||||||
assertThrows(Socks5Exception.CouldNotConnectToAnyProvidedSocks5Host.class, () -> {
|
assertThrows(Socks5Exception.CouldNotConnectToAnyProvidedSocks5Host.class, () -> {
|
||||||
// build SOCKS5 Bytestream initialization request
|
// build SOCKS5 Bytestream initialization request
|
||||||
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
||||||
|
@ -150,7 +131,6 @@ public class Socks5ByteStreamRequestTest {
|
||||||
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
|
||||||
assertEquals(StanzaError.Condition.item_not_found,
|
assertEquals(StanzaError.Condition.item_not_found,
|
||||||
targetResponse.getError().getCondition());
|
targetResponse.getError().getCondition());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,10 +140,13 @@ public class Socks5ByteStreamRequestTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldBlacklistInvalidProxyAfter2Failures() throws Exception {
|
public void shouldBlacklistInvalidProxyAfter2Failures() throws Exception {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, targetJID);
|
||||||
|
|
||||||
// build SOCKS5 Bytestream initialization request
|
// build SOCKS5 Bytestream initialization request
|
||||||
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
||||||
initiatorJID, targetJID, sessionID);
|
initiatorJID, targetJID, sessionID);
|
||||||
|
// Add an unreachable stream host.
|
||||||
bytestreamInitialization.addStreamHost(JidCreate.from("invalid." + proxyJID), "127.0.0.2", 7778);
|
bytestreamInitialization.addStreamHost(JidCreate.from("invalid." + proxyJID), "127.0.0.2", 7778);
|
||||||
|
|
||||||
// get SOCKS5 Bytestream manager for connection
|
// get SOCKS5 Bytestream manager for connection
|
||||||
|
@ -196,44 +179,44 @@ public class Socks5ByteStreamRequestTest {
|
||||||
|
|
||||||
// create test data for stream
|
// create test data for stream
|
||||||
byte[] data = new byte[] { 1, 2, 3 };
|
byte[] data = new byte[] { 1, 2, 3 };
|
||||||
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7779);
|
|
||||||
|
|
||||||
assertTrue(socks5Proxy.isRunning());
|
try (Socks5TestProxy socks5Proxy = new Socks5TestProxy()) {
|
||||||
|
assertTrue(socks5Proxy.isRunning());
|
||||||
|
|
||||||
// add a valid SOCKS5 proxy
|
// add a valid SOCKS5 proxy
|
||||||
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7779);
|
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, socks5Proxy.getPort());
|
||||||
|
|
||||||
// build SOCKS5 Bytestream request with the bytestream initialization
|
// build SOCKS5 Bytestream request with the bytestream initialization
|
||||||
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
|
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
|
||||||
bytestreamInitialization);
|
bytestreamInitialization);
|
||||||
|
|
||||||
// set timeouts
|
// set timeouts
|
||||||
byteStreamRequest.setTotalConnectTimeout(600);
|
byteStreamRequest.setTotalConnectTimeout(600);
|
||||||
byteStreamRequest.setMinimumConnectTimeout(300);
|
byteStreamRequest.setMinimumConnectTimeout(300);
|
||||||
|
|
||||||
// accept the stream (this is the call that is tested here)
|
// accept the stream (this is the call that is tested here)
|
||||||
InputStream inputStream = byteStreamRequest.accept().getInputStream();
|
InputStream inputStream = byteStreamRequest.accept().getInputStream();
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
// create digest to get the socket opened by target
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
// test stream by sending some data
|
// test stream by sending some data
|
||||||
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
|
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
|
||||||
outputStream.write(data);
|
outputStream.write(data);
|
||||||
|
|
||||||
// verify that data is transferred correctly
|
// verify that data is transferred correctly
|
||||||
byte[] result = new byte[3];
|
byte[] result = new byte[3];
|
||||||
inputStream.read(result);
|
inputStream.read(result);
|
||||||
assertArrayEquals(data, result);
|
assertArrayEquals(data, result);
|
||||||
|
|
||||||
// verify targets response
|
|
||||||
assertEquals(1, protocol.getRequests().size());
|
|
||||||
Stanza targetResponse = protocol.getRequests().remove(0);
|
|
||||||
assertEquals(Bytestream.class, targetResponse.getClass());
|
|
||||||
assertEquals(initiatorJID, targetResponse.getTo());
|
|
||||||
assertEquals(IQ.Type.result, ((Bytestream) targetResponse).getType());
|
|
||||||
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
|
|
||||||
|
|
||||||
|
// verify targets response
|
||||||
|
assertEquals(1, protocol.getRequests().size());
|
||||||
|
Stanza targetResponse = protocol.getRequests().remove(0);
|
||||||
|
assertEquals(Bytestream.class, targetResponse.getClass());
|
||||||
|
assertEquals(initiatorJID, targetResponse.getTo());
|
||||||
|
assertEquals(IQ.Type.result, ((Bytestream) targetResponse).getType());
|
||||||
|
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,9 +226,8 @@ public class Socks5ByteStreamRequestTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotBlacklistInvalidProxy() throws Exception {
|
public void shouldNotBlacklistInvalidProxy() throws Exception {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
// disable blacklisting
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, targetJID);
|
||||||
Socks5BytestreamRequest.setConnectFailureThreshold(0);
|
|
||||||
|
|
||||||
// build SOCKS5 Bytestream initialization request
|
// build SOCKS5 Bytestream initialization request
|
||||||
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
||||||
|
@ -265,6 +247,7 @@ public class Socks5ByteStreamRequestTest {
|
||||||
// set timeouts
|
// set timeouts
|
||||||
byteStreamRequest.setTotalConnectTimeout(600);
|
byteStreamRequest.setTotalConnectTimeout(600);
|
||||||
byteStreamRequest.setMinimumConnectTimeout(300);
|
byteStreamRequest.setMinimumConnectTimeout(300);
|
||||||
|
byteStreamRequest.setConnectFailureThreshold(0);
|
||||||
|
|
||||||
// accept the stream (this is the call that is tested here)
|
// accept the stream (this is the call that is tested here)
|
||||||
byteStreamRequest.accept();
|
byteStreamRequest.accept();
|
||||||
|
@ -279,10 +262,6 @@ public class Socks5ByteStreamRequestTest {
|
||||||
assertEquals(StanzaError.Condition.item_not_found,
|
assertEquals(StanzaError.Condition.item_not_found,
|
||||||
targetResponse.getError().getCondition());
|
targetResponse.getError().getCondition());
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable blacklisting
|
|
||||||
Socks5BytestreamRequest.setConnectFailureThreshold(2);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -294,62 +273,65 @@ public class Socks5ByteStreamRequestTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotTimeoutIfFirstSocks5ProxyDoesNotRespond() throws Exception {
|
public void shouldNotTimeoutIfFirstSocks5ProxyDoesNotRespond() throws Exception {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, targetJID);
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778);
|
try (Socks5TestProxy socks5Proxy = new Socks5TestProxy()) {
|
||||||
|
// create a fake SOCKS5 proxy that doesn't respond to a request
|
||||||
|
ServerSocket unresponsiveSocks5Socket = NetworkUtil.getSocketOnLoopback();
|
||||||
|
|
||||||
// create a fake SOCKS5 proxy that doesn't respond to a request
|
try {
|
||||||
ServerSocket serverSocket = new ServerSocket(7779);
|
// build SOCKS5 Bytestream initialization request
|
||||||
|
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
||||||
|
initiatorJID, targetJID, sessionID);
|
||||||
|
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, unresponsiveSocks5Socket.getLocalPort());
|
||||||
|
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, socks5Proxy.getPort());
|
||||||
|
|
||||||
// build SOCKS5 Bytestream initialization request
|
// create test data for stream
|
||||||
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
byte[] data = new byte[] { 1, 2, 3 };
|
||||||
initiatorJID, targetJID, sessionID);
|
|
||||||
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7779);
|
|
||||||
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7778);
|
|
||||||
|
|
||||||
// create test data for stream
|
// get SOCKS5 Bytestream manager for connection
|
||||||
byte[] data = new byte[] { 1, 2, 3 };
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
|
||||||
// get SOCKS5 Bytestream manager for connection
|
// build SOCKS5 Bytestream request with the bytestream initialization
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
|
||||||
|
bytestreamInitialization);
|
||||||
|
|
||||||
// build SOCKS5 Bytestream request with the bytestream initialization
|
// set timeouts
|
||||||
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
|
byteStreamRequest.setTotalConnectTimeout(2000);
|
||||||
bytestreamInitialization);
|
byteStreamRequest.setMinimumConnectTimeout(1000);
|
||||||
|
|
||||||
// set timeouts
|
// accept the stream (this is the call that is tested here)
|
||||||
byteStreamRequest.setTotalConnectTimeout(2000);
|
InputStream inputStream = byteStreamRequest.accept().getInputStream();
|
||||||
byteStreamRequest.setMinimumConnectTimeout(1000);
|
|
||||||
|
|
||||||
// accept the stream (this is the call that is tested here)
|
// assert that client tries to connect to dumb SOCKS5 proxy
|
||||||
InputStream inputStream = byteStreamRequest.accept().getInputStream();
|
Socket socket = unresponsiveSocks5Socket.accept();
|
||||||
|
assertNotNull(socket);
|
||||||
|
|
||||||
// assert that client tries to connect to dumb SOCKS5 proxy
|
// create digest to get the socket opened by target
|
||||||
Socket socket = serverSocket.accept();
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
assertNotNull(socket);
|
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
// test stream by sending some data
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
|
||||||
|
outputStream.write(data);
|
||||||
|
|
||||||
// test stream by sending some data
|
// verify that data is transferred correctly
|
||||||
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
|
byte[] result = new byte[3];
|
||||||
outputStream.write(data);
|
inputStream.read(result);
|
||||||
|
assertArrayEquals(data, result);
|
||||||
// verify that data is transferred correctly
|
|
||||||
byte[] result = new byte[3];
|
|
||||||
inputStream.read(result);
|
|
||||||
assertArrayEquals(data, result);
|
|
||||||
|
|
||||||
// verify targets response
|
|
||||||
assertEquals(1, protocol.getRequests().size());
|
|
||||||
Stanza targetResponse = protocol.getRequests().remove(0);
|
|
||||||
assertEquals(Bytestream.class, targetResponse.getClass());
|
|
||||||
assertEquals(initiatorJID, targetResponse.getTo());
|
|
||||||
assertEquals(IQ.Type.result, ((Bytestream) targetResponse).getType());
|
|
||||||
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
|
|
||||||
|
|
||||||
serverSocket.close();
|
|
||||||
|
|
||||||
|
// verify targets response
|
||||||
|
assertEquals(1, protocol.getRequests().size());
|
||||||
|
Stanza targetResponse = protocol.getRequests().remove(0);
|
||||||
|
assertEquals(Bytestream.class, targetResponse.getClass());
|
||||||
|
assertEquals(initiatorJID, targetResponse.getTo());
|
||||||
|
assertEquals(IQ.Type.result, ((Bytestream) targetResponse).getType());
|
||||||
|
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
|
||||||
|
} finally {
|
||||||
|
unresponsiveSocks5Socket.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -359,57 +341,48 @@ public class Socks5ByteStreamRequestTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldAcceptSocks5BytestreamRequestAndReceiveData() throws Exception {
|
public void shouldAcceptSocks5BytestreamRequestAndReceiveData() throws Exception {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, targetJID);
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778);
|
try (Socks5TestProxy socks5Proxy = new Socks5TestProxy()) {
|
||||||
|
// build SOCKS5 Bytestream initialization request
|
||||||
|
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
||||||
|
initiatorJID, targetJID, sessionID);
|
||||||
|
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, socks5Proxy.getPort());
|
||||||
|
|
||||||
// build SOCKS5 Bytestream initialization request
|
// create test data for stream
|
||||||
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(
|
byte[] data = new byte[] { 1, 2, 3 };
|
||||||
initiatorJID, targetJID, sessionID);
|
|
||||||
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7778);
|
|
||||||
|
|
||||||
// create test data for stream
|
// get SOCKS5 Bytestream manager for connection
|
||||||
byte[] data = new byte[] { 1, 2, 3 };
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
|
||||||
// get SOCKS5 Bytestream manager for connection
|
// build SOCKS5 Bytestream request with the bytestream initialization
|
||||||
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
|
||||||
|
bytestreamInitialization);
|
||||||
|
|
||||||
// build SOCKS5 Bytestream request with the bytestream initialization
|
// accept the stream (this is the call that is tested here)
|
||||||
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager,
|
InputStream inputStream = byteStreamRequest.accept().getInputStream();
|
||||||
bytestreamInitialization);
|
|
||||||
|
|
||||||
// accept the stream (this is the call that is tested here)
|
// create digest to get the socket opened by target
|
||||||
InputStream inputStream = byteStreamRequest.accept().getInputStream();
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
// test stream by sending some data
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
|
||||||
|
outputStream.write(data);
|
||||||
|
|
||||||
// test stream by sending some data
|
// verify that data is transferred correctly
|
||||||
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
|
byte[] result = new byte[3];
|
||||||
outputStream.write(data);
|
inputStream.read(result);
|
||||||
|
assertArrayEquals(data, result);
|
||||||
// verify that data is transferred correctly
|
|
||||||
byte[] result = new byte[3];
|
|
||||||
inputStream.read(result);
|
|
||||||
assertArrayEquals(data, result);
|
|
||||||
|
|
||||||
// verify targets response
|
|
||||||
assertEquals(1, protocol.getRequests().size());
|
|
||||||
Stanza targetResponse = protocol.getRequests().remove(0);
|
|
||||||
assertEquals(Bytestream.class, targetResponse.getClass());
|
|
||||||
assertEquals(initiatorJID, targetResponse.getTo());
|
|
||||||
assertEquals(IQ.Type.result, ((Bytestream) targetResponse).getType());
|
|
||||||
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
|
|
||||||
|
|
||||||
|
// verify targets response
|
||||||
|
assertEquals(1, protocol.getRequests().size());
|
||||||
|
Stanza targetResponse = protocol.getRequests().remove(0);
|
||||||
|
assertEquals(Bytestream.class, targetResponse.getClass());
|
||||||
|
assertEquals(initiatorJID, targetResponse.getTo());
|
||||||
|
assertEquals(IQ.Type.result, ((Bytestream) targetResponse).getType());
|
||||||
|
assertEquals(proxyJID, ((Bytestream) targetResponse).getUsedHost().getJID());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop eventually started local SOCKS5 test proxy.
|
|
||||||
*/
|
|
||||||
@After
|
|
||||||
public void cleanUp() {
|
|
||||||
Socks5TestProxy.stopProxy();
|
|
||||||
Socks5Proxy.setLocalSocks5ProxyEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,12 @@ import java.net.Socket;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
|
||||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||||
import org.jivesoftware.smack.packet.EmptyResultIQ;
|
import org.jivesoftware.smack.packet.EmptyResultIQ;
|
||||||
import org.jivesoftware.smack.packet.ErrorIQ;
|
import org.jivesoftware.smack.packet.ErrorIQ;
|
||||||
import org.jivesoftware.smack.packet.IQ;
|
import org.jivesoftware.smack.packet.IQ;
|
||||||
import org.jivesoftware.smack.packet.StanzaError;
|
import org.jivesoftware.smack.packet.StanzaError;
|
||||||
|
import org.jivesoftware.smack.util.CloseableUtil;
|
||||||
|
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
|
||||||
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
|
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
|
||||||
|
@ -41,8 +41,6 @@ import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost;
|
||||||
import org.jivesoftware.util.ConnectionUtils;
|
import org.jivesoftware.util.ConnectionUtils;
|
||||||
import org.jivesoftware.util.Protocol;
|
import org.jivesoftware.util.Protocol;
|
||||||
import org.jivesoftware.util.Verification;
|
import org.jivesoftware.util.Verification;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.jxmpp.jid.DomainBareJid;
|
import org.jxmpp.jid.DomainBareJid;
|
||||||
import org.jxmpp.jid.EntityFullJid;
|
import org.jxmpp.jid.EntityFullJid;
|
||||||
|
@ -63,31 +61,8 @@ public class Socks5ClientForInitiatorTest {
|
||||||
|
|
||||||
private static final int GET_SOCKET_TIMEOUT = 90 * 1000;
|
private static final int GET_SOCKET_TIMEOUT = 90 * 1000;
|
||||||
|
|
||||||
private static final int proxyPort = 7890;
|
|
||||||
private static final String sessionID = "session_id";
|
private static final String sessionID = "session_id";
|
||||||
|
|
||||||
// protocol verifier
|
|
||||||
private Protocol protocol;
|
|
||||||
|
|
||||||
// mocked XMPP connection
|
|
||||||
private XMPPConnection connection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize fields used in the tests.
|
|
||||||
* @throws XMPPException
|
|
||||||
* @throws SmackException
|
|
||||||
* @throws InterruptedException
|
|
||||||
*/
|
|
||||||
@Before
|
|
||||||
public void setup() throws XMPPException, SmackException, InterruptedException {
|
|
||||||
|
|
||||||
// build protocol verifier
|
|
||||||
protocol = new Protocol();
|
|
||||||
|
|
||||||
// create mocked XMPP connection
|
|
||||||
connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the target is not connected to the local SOCKS5 proxy an exception should be thrown.
|
* If the target is not connected to the local SOCKS5 proxy an exception should be thrown.
|
||||||
*
|
*
|
||||||
|
@ -95,35 +70,36 @@ public class Socks5ClientForInitiatorTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfTargetIsNotConnectedToLocalSocks5Proxy() throws Exception {
|
public void shouldFailIfTargetIsNotConnectedToLocalSocks5Proxy() throws Exception {
|
||||||
|
Protocol protocol = new Protocol();
|
||||||
|
XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5Proxy.setLocalSocks5ProxyPort(proxyPort);
|
Socks5Proxy socks5Proxy = new Socks5Proxy();
|
||||||
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
|
|
||||||
socks5Proxy.start();
|
socks5Proxy.start();
|
||||||
|
|
||||||
// build stream host information for local SOCKS5 proxy
|
|
||||||
StreamHost streamHost = new StreamHost(connection.getUser(),
|
|
||||||
loopbackAddress,
|
|
||||||
socks5Proxy.getPort());
|
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
|
||||||
|
|
||||||
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
|
|
||||||
connection, sessionID, targetJID);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
socks5Client.getSocket(GET_SOCKET_TIMEOUT);
|
// build stream host information for local SOCKS5 proxy
|
||||||
|
StreamHost streamHost = new StreamHost(connection.getUser(),
|
||||||
|
loopbackAddress,
|
||||||
|
socks5Proxy.getPort());
|
||||||
|
|
||||||
fail("exception should be thrown");
|
// create digest to get the socket opened by target
|
||||||
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
|
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
|
||||||
|
connection, sessionID, targetJID);
|
||||||
|
|
||||||
|
try {
|
||||||
|
socks5Client.getSocket(GET_SOCKET_TIMEOUT);
|
||||||
|
|
||||||
|
fail("exception should be thrown");
|
||||||
|
}
|
||||||
|
catch (SmackException e) {
|
||||||
|
assertTrue(e.getMessage().contains("target is not connected to SOCKS5 proxy"));
|
||||||
|
protocol.verifyAll(); // assert no XMPP messages were sent
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
socks5Proxy.stop();
|
||||||
}
|
}
|
||||||
catch (SmackException e) {
|
|
||||||
assertTrue(e.getMessage().contains("target is not connected to SOCKS5 proxy"));
|
|
||||||
protocol.verifyAll(); // assert no XMPP messages were sent
|
|
||||||
}
|
|
||||||
|
|
||||||
socks5Proxy.stop();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,65 +109,67 @@ public class Socks5ClientForInitiatorTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldSuccessfullyConnectThroughLocalSocks5Proxy() throws Exception {
|
public void shouldSuccessfullyConnectThroughLocalSocks5Proxy() throws Exception {
|
||||||
|
Protocol protocol = new Protocol();
|
||||||
|
XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5Proxy.setLocalSocks5ProxyPort(proxyPort);
|
Socks5Proxy socks5Proxy = new Socks5Proxy();
|
||||||
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
|
|
||||||
socks5Proxy.start();
|
socks5Proxy.start();
|
||||||
|
try {
|
||||||
|
// test data
|
||||||
|
final byte[] data = new byte[] { 1, 2, 3 };
|
||||||
|
|
||||||
// test data
|
// create digest
|
||||||
final byte[] data = new byte[] { 1, 2, 3 };
|
final String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
// create digest
|
// allow connection of target with this digest
|
||||||
final String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
socks5Proxy.addTransfer(digest);
|
||||||
|
|
||||||
// allow connection of target with this digest
|
// build stream host information
|
||||||
socks5Proxy.addTransfer(digest);
|
final StreamHost streamHost = new StreamHost(connection.getUser(),
|
||||||
|
loopbackAddress,
|
||||||
|
socks5Proxy.getPort());
|
||||||
|
|
||||||
// build stream host information
|
// target connects to local SOCKS5 proxy
|
||||||
final StreamHost streamHost = new StreamHost(connection.getUser(),
|
Thread targetThread = new Thread() {
|
||||||
loopbackAddress,
|
@Override
|
||||||
socks5Proxy.getPort());
|
public void run() {
|
||||||
|
try {
|
||||||
// target connects to local SOCKS5 proxy
|
Socks5Client targetClient = new Socks5Client(streamHost, digest);
|
||||||
Thread targetThread = new Thread() {
|
Socket socket = targetClient.getSocket(10000);
|
||||||
|
socket.getOutputStream().write(data);
|
||||||
@Override
|
}
|
||||||
public void run() {
|
catch (Exception e) {
|
||||||
try {
|
// TODO: This does not work.
|
||||||
Socks5Client targetClient = new Socks5Client(streamHost, digest);
|
fail(e.getMessage());
|
||||||
Socket socket = targetClient.getSocket(10000);
|
}
|
||||||
socket.getOutputStream().write(data);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
fail(e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
targetThread.start();
|
||||||
|
|
||||||
|
// TODO: Replace this Thread.sleep().
|
||||||
|
Thread.sleep(200);
|
||||||
|
|
||||||
|
// initiator connects
|
||||||
|
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
|
||||||
|
connection, sessionID, targetJID);
|
||||||
|
|
||||||
|
Socket socket = socks5Client.getSocket(GET_SOCKET_TIMEOUT);
|
||||||
|
|
||||||
|
// verify test data
|
||||||
|
InputStream in = socket.getInputStream();
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
assertEquals(data[i], in.read());
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
targetThread.join();
|
||||||
targetThread.start();
|
|
||||||
|
|
||||||
Thread.sleep(200);
|
protocol.verifyAll(); // assert no XMPP messages were sent
|
||||||
|
|
||||||
// initiator connects
|
socks5Proxy.removeTransfer(digest);
|
||||||
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
|
} finally {
|
||||||
connection, sessionID, targetJID);
|
socks5Proxy.stop();
|
||||||
|
|
||||||
Socket socket = socks5Client.getSocket(GET_SOCKET_TIMEOUT);
|
|
||||||
|
|
||||||
// verify test data
|
|
||||||
InputStream in = socket.getInputStream();
|
|
||||||
for (int i = 0; i < data.length; i++) {
|
|
||||||
assertEquals(data[i], in.read());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
targetThread.join();
|
|
||||||
|
|
||||||
protocol.verifyAll(); // assert no XMPP messages were sent
|
|
||||||
|
|
||||||
socks5Proxy.removeTransfer(digest);
|
|
||||||
socks5Proxy.stop();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,6 +180,8 @@ public class Socks5ClientForInitiatorTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldFailIfActivateSocks5ProxyFails() throws Exception {
|
public void shouldFailIfActivateSocks5ProxyFails() throws Exception {
|
||||||
|
Protocol protocol = new Protocol();
|
||||||
|
XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
|
||||||
// build error response as reply to the stream activation
|
// build error response as reply to the stream activation
|
||||||
IQ error = new ErrorIQ(StanzaError.getBuilder(StanzaError.Condition.internal_server_error));
|
IQ error = new ErrorIQ(StanzaError.getBuilder(StanzaError.Condition.internal_server_error));
|
||||||
|
@ -212,30 +192,25 @@ public class Socks5ClientForInitiatorTest {
|
||||||
Verification.requestTypeSET);
|
Verification.requestTypeSET);
|
||||||
|
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(proxyPort);
|
try (Socks5TestProxy socks5Proxy = new Socks5TestProxy()) {
|
||||||
socks5Proxy.start();
|
StreamHost streamHost = new StreamHost(proxyJID, loopbackAddress, socks5Proxy.getPort());
|
||||||
|
|
||||||
StreamHost streamHost = new StreamHost(proxyJID,
|
// create digest to get the socket opened by target
|
||||||
loopbackAddress, socks5Proxy.getPort());
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest, connection,
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
sessionID, targetJID);
|
||||||
|
|
||||||
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
|
try {
|
||||||
connection, sessionID, targetJID);
|
|
||||||
|
|
||||||
try {
|
socks5Client.getSocket(GET_SOCKET_TIMEOUT);
|
||||||
|
|
||||||
socks5Client.getSocket(GET_SOCKET_TIMEOUT);
|
fail("exception should be thrown");
|
||||||
|
} catch (XMPPErrorException e) {
|
||||||
fail("exception should be thrown");
|
assertTrue(StanzaError.Condition.internal_server_error.equals(e.getStanzaError().getCondition()));
|
||||||
|
protocol.verifyAll();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (XMPPErrorException e) {
|
|
||||||
assertTrue(StanzaError.Condition.internal_server_error.equals(e.getStanzaError().getCondition()));
|
|
||||||
protocol.verifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
socks5Proxy.stop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -246,6 +221,8 @@ public class Socks5ClientForInitiatorTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void shouldSuccessfullyEstablishConnectionAndActivateSocks5Proxy() throws Exception {
|
public void shouldSuccessfullyEstablishConnectionAndActivateSocks5Proxy() throws Exception {
|
||||||
|
Protocol protocol = new Protocol();
|
||||||
|
XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
|
||||||
// build activation confirmation response
|
// build activation confirmation response
|
||||||
IQ activationResponse = new EmptyResultIQ();
|
IQ activationResponse = new EmptyResultIQ();
|
||||||
|
@ -265,45 +242,34 @@ public class Socks5ClientForInitiatorTest {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Socket initiatorSocket = null, targetSocket = null;
|
||||||
// start a local SOCKS5 proxy
|
// start a local SOCKS5 proxy
|
||||||
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(proxyPort);
|
try (Socks5TestProxy socks5Proxy = new Socks5TestProxy()) {
|
||||||
socks5Proxy.start();
|
StreamHost streamHost = new StreamHost(proxyJID, loopbackAddress, socks5Proxy.getPort());
|
||||||
|
|
||||||
StreamHost streamHost = new StreamHost(proxyJID,
|
// create digest to get the socket opened by target
|
||||||
loopbackAddress, socks5Proxy.getPort());
|
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
||||||
|
|
||||||
// create digest to get the socket opened by target
|
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest, connection,
|
||||||
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
|
sessionID, targetJID);
|
||||||
|
|
||||||
Socks5ClientForInitiator socks5Client = new Socks5ClientForInitiator(streamHost, digest,
|
initiatorSocket = socks5Client.getSocket(10000);
|
||||||
connection, sessionID, targetJID);
|
InputStream in = initiatorSocket.getInputStream();
|
||||||
|
|
||||||
Socket initiatorSocket = socks5Client.getSocket(10000);
|
targetSocket = socks5Proxy.getSocket(digest);
|
||||||
InputStream in = initiatorSocket.getInputStream();
|
OutputStream out = targetSocket.getOutputStream();
|
||||||
|
|
||||||
Socket targetSocket = socks5Proxy.getSocket(digest);
|
// verify test data
|
||||||
OutputStream out = targetSocket.getOutputStream();
|
for (int i = 0; i < 10; i++) {
|
||||||
|
out.write(i);
|
||||||
|
assertEquals(i, in.read());
|
||||||
|
}
|
||||||
|
|
||||||
// verify test data
|
protocol.verifyAll();
|
||||||
for (int i = 0; i < 10; i++) {
|
} finally {
|
||||||
out.write(i);
|
CloseableUtil.maybeClose(initiatorSocket);
|
||||||
assertEquals(i, in.read());
|
CloseableUtil.maybeClose(targetSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol.verifyAll();
|
|
||||||
|
|
||||||
initiatorSocket.close();
|
|
||||||
targetSocket.close();
|
|
||||||
socks5Proxy.stop();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset default port for local SOCKS5 proxy.
|
|
||||||
*/
|
|
||||||
@After
|
|
||||||
public void cleanup() {
|
|
||||||
Socks5Proxy.setLocalSocks5ProxyPort(7777);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.jivesoftware.smack.SmackException;
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.util.CloseableUtil;
|
||||||
|
import org.jivesoftware.smack.util.NetworkUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple SOCKS5 proxy for testing purposes. It is almost the same as the Socks5Proxy class but the
|
* Simple SOCKS5 proxy for testing purposes. It is almost the same as the Socks5Proxy class but the
|
||||||
|
@ -38,12 +40,9 @@ import org.jivesoftware.smack.SmackException;
|
||||||
*
|
*
|
||||||
* @author Henning Staib
|
* @author Henning Staib
|
||||||
*/
|
*/
|
||||||
public final class Socks5TestProxy {
|
public final class Socks5TestProxy implements AutoCloseable {
|
||||||
private static final Logger LOGGER = Logger.getLogger(Socks5TestProxy.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(Socks5TestProxy.class.getName());
|
||||||
|
|
||||||
/* SOCKS5 proxy singleton */
|
|
||||||
private static Socks5TestProxy socks5Server;
|
|
||||||
|
|
||||||
/* reusable implementation of a SOCKS5 proxy server process */
|
/* reusable implementation of a SOCKS5 proxy server process */
|
||||||
private Socks5ServerProcess serverProcess;
|
private Socks5ServerProcess serverProcess;
|
||||||
|
|
||||||
|
@ -51,64 +50,22 @@ public final class Socks5TestProxy {
|
||||||
private Thread serverThread;
|
private Thread serverThread;
|
||||||
|
|
||||||
/* server socket to accept SOCKS5 connections */
|
/* server socket to accept SOCKS5 connections */
|
||||||
private ServerSocket serverSocket;
|
private final ServerSocket serverSocket;
|
||||||
|
|
||||||
/* assigns a connection to a digest */
|
/* assigns a connection to a digest */
|
||||||
private final Map<String, Socket> connectionMap = new ConcurrentHashMap<String, Socket>();
|
private final Map<String, Socket> connectionMap = new ConcurrentHashMap<String, Socket>();
|
||||||
|
|
||||||
/* port of the test proxy */
|
|
||||||
private int port = 7777;
|
|
||||||
|
|
||||||
private boolean startupComplete;
|
private boolean startupComplete;
|
||||||
|
|
||||||
/**
|
Socks5TestProxy() throws IOException {
|
||||||
* Private constructor.
|
this(NetworkUtil.getSocketOnLoopback());
|
||||||
*/
|
}
|
||||||
private Socks5TestProxy(int port) {
|
|
||||||
|
Socks5TestProxy(ServerSocket serverSocket) {
|
||||||
|
this.serverSocket = serverSocket;
|
||||||
this.serverProcess = new Socks5ServerProcess();
|
this.serverProcess = new Socks5ServerProcess();
|
||||||
this.port = port;
|
this.serverThread = new Thread(this.serverProcess);
|
||||||
}
|
this.serverThread.start();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the local SOCKS5 proxy server.
|
|
||||||
*
|
|
||||||
* @param port of the test proxy
|
|
||||||
* @return the local SOCKS5 proxy server
|
|
||||||
*/
|
|
||||||
public static synchronized Socks5TestProxy getProxy(int port) {
|
|
||||||
if (socks5Server == null) {
|
|
||||||
socks5Server = new Socks5TestProxy(port);
|
|
||||||
socks5Server.start();
|
|
||||||
}
|
|
||||||
return socks5Server;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the test proxy.
|
|
||||||
*/
|
|
||||||
public static synchronized void stopProxy() {
|
|
||||||
if (socks5Server != null) {
|
|
||||||
socks5Server.stop();
|
|
||||||
socks5Server = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the local SOCKS5 proxy server. If it is already running, this method does nothing.
|
|
||||||
*/
|
|
||||||
public synchronized void start() {
|
|
||||||
if (isRunning()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
this.serverSocket = new ServerSocket(this.port);
|
|
||||||
this.serverThread = new Thread(this.serverProcess);
|
|
||||||
this.serverThread.start();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
LOGGER.log(Level.SEVERE, "exception", e);
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,8 +95,6 @@ public final class Socks5TestProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.serverThread = null;
|
this.serverThread = null;
|
||||||
this.serverSocket = null;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,16 +128,15 @@ public final class Socks5TestProxy {
|
||||||
*
|
*
|
||||||
* @param digest identifying the connection
|
* @param digest identifying the connection
|
||||||
* @return socket or null if there is no socket for the given digest
|
* @return socket or null if there is no socket for the given digest
|
||||||
|
* @throws InterruptedException
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("WaitNotInLoop")
|
public Socket getSocket(String digest) throws InterruptedException {
|
||||||
public Socket getSocket(String digest) {
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!startupComplete) {
|
long now = System.currentTimeMillis();
|
||||||
try {
|
final long deadline = now + 5000;
|
||||||
wait(5000);
|
while (!startupComplete && now < deadline) {
|
||||||
} catch (InterruptedException e) {
|
wait(deadline - now);
|
||||||
LOGGER.log(Level.SEVERE, "exception", e);
|
now = System.currentTimeMillis();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!startupComplete) {
|
if (!startupComplete) {
|
||||||
|
@ -197,7 +151,7 @@ public final class Socks5TestProxy {
|
||||||
* @return true if the local SOCKS5 proxy server is running, otherwise false
|
* @return true if the local SOCKS5 proxy server is running, otherwise false
|
||||||
*/
|
*/
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return this.serverSocket != null;
|
return !this.serverSocket.isClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -213,7 +167,7 @@ public final class Socks5TestProxy {
|
||||||
Socket socket = null;
|
Socket socket = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// TODO: Add !serverSocket.isClosed() into the while condition and remove the following lines.
|
||||||
if (Socks5TestProxy.this.serverSocket.isClosed()
|
if (Socks5TestProxy.this.serverSocket.isClosed()
|
||||||
|| Thread.currentThread().isInterrupted()) {
|
|| Thread.currentThread().isInterrupted()) {
|
||||||
return;
|
return;
|
||||||
|
@ -227,20 +181,16 @@ public final class Socks5TestProxy {
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
startupComplete = true;
|
startupComplete = true;
|
||||||
notify();
|
notifyAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (SocketException e) {
|
catch (SocketException e) {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
|
LOGGER.log(Level.FINE, "Socket exception in Socks5TestProxy " + this, e);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
try {
|
LOGGER.log(Level.SEVERE, "exception", e);
|
||||||
LOGGER.log(Level.SEVERE, "exception", e);
|
CloseableUtil.maybeClose(socket, LOGGER);
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
catch (IOException e1) {
|
|
||||||
/* Do Nothing */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,4 +259,9 @@ public final class Socks5TestProxy {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue