use of org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy in project Smack by igniterealtime.
the class Socks5ByteStreamTest method testSocks5BytestreamWithLocalSocks5Proxy.
/**
* Socks5 bytestream should be successfully established using the local Socks5 proxy.
*
* @throws Exception should not happen
*/
public void testSocks5BytestreamWithLocalSocks5Proxy() throws Exception {
// setup port for local socks5 proxy
SmackConfiguration.setLocalSocks5ProxyEnabled(true);
SmackConfiguration.setLocalSocks5ProxyPort(7778);
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
socks5Proxy.start();
assertTrue(socks5Proxy.isRunning());
XMPPConnection initiatorConnection = getConnection(0);
XMPPConnection targetConnection = getConnection(1);
// test data
final byte[] data = new byte[] { 1, 2, 3 };
final SynchronousQueue<byte[]> queue = new SynchronousQueue<byte[]>();
Socks5BytestreamManager targetByteStreamManager = Socks5BytestreamManager.getBytestreamManager(targetConnection);
Socks5BytestreamListener incomingByteStreamListener = new Socks5BytestreamListener() {
public void incomingBytestreamRequest(Socks5BytestreamRequest request) {
InputStream inputStream;
try {
Socks5BytestreamSession session = request.accept();
inputStream = session.getInputStream();
byte[] receivedData = new byte[3];
inputStream.read(receivedData);
queue.put(receivedData);
} catch (Exception e) {
fail(e.getMessage());
}
}
};
targetByteStreamManager.addIncomingBytestreamListener(incomingByteStreamListener);
Socks5BytestreamManager initiatorByteStreamManager = Socks5BytestreamManager.getBytestreamManager(initiatorConnection);
Socks5BytestreamSession session = initiatorByteStreamManager.establishSession(targetConnection.getUser());
OutputStream outputStream = session.getOutputStream();
assertTrue(session.isDirect());
// verify stream
outputStream.write(data);
outputStream.flush();
outputStream.close();
assertEquals("received data not equal to sent data", data, queue.take());
// reset default configuration
SmackConfiguration.setLocalSocks5ProxyPort(7777);
}
use of org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy in project Smack by igniterealtime.
the class Socks5BytestreamManager method getLocalStreamHost.
/**
* Returns the stream host information of the local SOCKS5 proxy containing the IP address and
* the port or null if local SOCKS5 proxy is not running.
*
* @return the stream host information of the local SOCKS5 proxy or null if local SOCKS5 proxy
* is not running
*/
private 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<StreamHost>();
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) {
// ie. the part after the '%' sign.
if (address.startsWith(loopbackAddress)) {
continue outerloop;
}
}
streamHosts.add(new StreamHost(connection.getUser(), address, port));
}
return streamHosts;
}
use of org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy in project Smack by igniterealtime.
the class Socks5BytestreamManager method establishSession.
/**
* Establishes a SOCKS5 Bytestream with the given user using the given session ID and returns
* the Socket to send/receive data to/from the user.
*
* @param targetJID the JID of the user a SOCKS5 Bytestream should be established
* @param sessionID the session ID for the SOCKS5 Bytestream request
* @return the Socket to send/receive data to/from the user
* @throws IOException if the bytestream could not be established
* @throws InterruptedException if the current thread was interrupted while waiting
* @throws NoResponseException
* @throws SmackException if the target does not support SOCKS5.
* @throws XMPPException
*/
@Override
public Socks5BytestreamSession establishSession(Jid targetJID, String sessionID) throws IOException, InterruptedException, NoResponseException, SmackException, XMPPException {
XMPPConnection connection = connection();
XMPPErrorException discoveryException = null;
// check if target supports SOCKS5 Bytestream
if (!supportsSocks5(targetJID)) {
throw new FeatureNotSupportedException("SOCKS5 Bytestream", targetJID);
}
List<Jid> proxies = new ArrayList<>();
// determine SOCKS5 proxies from XMPP-server
try {
proxies.addAll(determineProxies());
} catch (XMPPErrorException e) {
// don't abort here, just remember the exception thrown by determineProxies()
// determineStreamHostInfos() will at least add the local Socks5 proxy (if enabled)
discoveryException = e;
}
// determine address and port of each proxy
List<StreamHost> streamHosts = determineStreamHostInfos(proxies);
if (streamHosts.isEmpty()) {
if (discoveryException != null) {
throw discoveryException;
} else {
throw new SmackException("no SOCKS5 proxies available");
}
}
// compute digest
String digest = Socks5Utils.createDigest(sessionID, connection.getUser(), targetJID);
// prioritize last working SOCKS5 proxy if exists
if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) {
StreamHost selectedStreamHost = null;
for (StreamHost streamHost : streamHosts) {
if (streamHost.getJID().equals(this.lastWorkingProxy)) {
selectedStreamHost = streamHost;
break;
}
}
if (selectedStreamHost != null) {
streamHosts.remove(selectedStreamHost);
streamHosts.add(0, selectedStreamHost);
}
}
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
try {
// add transfer digest to local proxy to make transfer valid
socks5Proxy.addTransfer(digest);
// create initiation packet
Bytestream initiation = createBytestreamInitiation(sessionID, targetJID, streamHosts);
// send initiation packet
Stanza response = connection.createStanzaCollectorAndSend(initiation).nextResultOrThrow(getTargetResponseTimeout());
// extract used stream host from response
StreamHostUsed streamHostUsed = ((Bytestream) response).getUsedHost();
StreamHost usedStreamHost = initiation.getStreamHost(streamHostUsed.getJID());
if (usedStreamHost == null) {
throw new SmackException("Remote user responded with unknown host");
}
// build SOCKS5 client
Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest, connection, sessionID, targetJID);
// establish connection to proxy
Socket socket = socks5Client.getSocket(getProxyConnectionTimeout());
// remember last working SOCKS5 proxy to prioritize it for next request
this.lastWorkingProxy = usedStreamHost.getJID();
// negotiation successful, return the output stream
return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals(connection.getUser()));
} catch (TimeoutException e) {
throw new IOException("Timeout while connecting to SOCKS5 proxy");
} finally {
// remove transfer digest if output stream is returned or an exception
// occurred
socks5Proxy.removeTransfer(digest);
}
}
use of org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy in project Smack by igniterealtime.
the class Socks5ByteStreamRequestTest method shouldAcceptSocks5BytestreamRequestAndReceiveData.
/**
* Accepting the SOCKS5 Bytestream request should be successfully.
*
* @throws Exception should not happen
*/
@Test
public void shouldAcceptSocks5BytestreamRequestAndReceiveData() throws Exception {
// start a local SOCKS5 proxy
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778);
// build SOCKS5 Bytestream initialization request
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(initiatorJID, targetJID, sessionID);
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7778);
// create test data for stream
byte[] data = new byte[] { 1, 2, 3 };
// get SOCKS5 Bytestream manager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager, bytestreamInitialization);
// accept the stream (this is the call that is tested here)
InputStream inputStream = byteStreamRequest.accept().getInputStream();
// create digest to get the socket opened by target
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
// test stream by sending some data
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
outputStream.write(data);
// 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());
}
use of org.jivesoftware.smackx.bytestreams.socks5.Socks5Proxy in project Smack by igniterealtime.
the class Socks5ByteStreamRequestTest method shouldBlacklistInvalidProxyAfter2Failures.
/**
* Target should not try to connect to SOCKS5 proxies that already failed twice.
*
* @throws Exception should not happen
*/
@Test
public void shouldBlacklistInvalidProxyAfter2Failures() throws Exception {
// build SOCKS5 Bytestream initialization request
Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation(initiatorJID, targetJID, sessionID);
bytestreamInitialization.addStreamHost(JidCreate.from("invalid." + proxyJID), "127.0.0.2", 7778);
// get SOCKS5 Bytestream manager for connection
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
// try to connect several times
for (int i = 0; i < 2; i++) {
try {
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager, bytestreamInitialization);
// set timeouts
byteStreamRequest.setTotalConnectTimeout(600);
byteStreamRequest.setMinimumConnectTimeout(300);
// accept the stream (this is the call that is tested here)
byteStreamRequest.accept();
fail("exception should be thrown");
} catch (XMPPErrorException e) {
assertTrue(e.getXMPPError().getDescriptiveText("en").contains("Could not establish socket with any provided host"));
}
// verify targets response
assertEquals(1, protocol.getRequests().size());
Stanza targetResponse = protocol.getRequests().remove(0);
assertTrue(IQ.class.isInstance(targetResponse));
assertEquals(initiatorJID, targetResponse.getTo());
assertEquals(IQ.Type.error, ((IQ) targetResponse).getType());
assertEquals(XMPPError.Condition.item_not_found, ((IQ) targetResponse).getError().getCondition());
}
// create test data for stream
byte[] data = new byte[] { 1, 2, 3 };
Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7779);
assertTrue(socks5Proxy.isRunning());
// add a valid SOCKS5 proxy
bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7779);
// build SOCKS5 Bytestream request with the bytestream initialization
Socks5BytestreamRequest byteStreamRequest = new Socks5BytestreamRequest(byteStreamManager, bytestreamInitialization);
// set timeouts
byteStreamRequest.setTotalConnectTimeout(600);
byteStreamRequest.setMinimumConnectTimeout(300);
// accept the stream (this is the call that is tested here)
InputStream inputStream = byteStreamRequest.accept().getInputStream();
// create digest to get the socket opened by target
String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID);
// test stream by sending some data
OutputStream outputStream = socks5Proxy.getSocket(digest).getOutputStream();
outputStream.write(data);
// 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());
}
Aggregations