/** * Returns a list of stream hosts containing the IP address an the port for the given list of * SOCKS5 proxy JIDs. The order of the returned list is the same as the given list of JIDs * excluding all SOCKS5 proxies who's network settings could not be determined. If a local * SOCKS5 proxy is running it will be the first item in the list returned. * * @param proxies a list of SOCKS5 proxy JIDs * @return a list of stream hosts containing the IP address an the port */ private List<StreamHost> determineStreamHostInfos(List<String> proxies) { List<StreamHost> streamHosts = new ArrayList<StreamHost>(); // add local proxy on first position if exists List<StreamHost> localProxies = getLocalStreamHost(); if (localProxies != null) { streamHosts.addAll(localProxies); } // query SOCKS5 proxies for network settings for (String proxy : proxies) { Bytestream streamHostRequest = createStreamHostRequest(proxy); try { Bytestream response = (Bytestream) SyncPacketSend.getReply(this.connection, streamHostRequest); streamHosts.addAll(response.getStreamHosts()); } catch (XMPPException e) { // blacklist errornous proxies this.proxyBlacklist.add(proxy); } } return streamHosts; }
/** * 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() { // get local proxy singleton Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy(); if (socks5Server.isRunning()) { List<String> addresses = socks5Server.getLocalAddresses(); int port = socks5Server.getPort(); if (addresses.size() >= 1) { List<StreamHost> streamHosts = new ArrayList<StreamHost>(); for (String address : addresses) { StreamHost streamHost = new StreamHost(this.connection.getUser(), address); streamHost.setPort(port); streamHosts.add(streamHost); } return streamHosts; } } // server is not running or local address could not be determined return null; }
/** * Returns a list of stream hosts containing the IP address an the port for * the given list of SOCKS5 proxy JIDs. The order of the returned list is * the same as the given list of JIDs excluding all SOCKS5 proxies who's * network settings could not be determined. If a local SOCKS5 proxy is * running it will be the first item in the list returned. * * @param proxies * a list of SOCKS5 proxy JIDs * @return a list of stream hosts containing the IP address an the port */ private List<StreamHost> determineStreamHostInfos(List<String> proxies) { List<StreamHost> streamHosts = new ArrayList<StreamHost>(); // add local proxy on first position if exists List<StreamHost> localProxies = getLocalStreamHost(); if (localProxies != null) { streamHosts.addAll(localProxies); } // query SOCKS5 proxies for network settings for (String proxy : proxies) { Bytestream streamHostRequest = createStreamHostRequest(proxy); try { Bytestream response = (Bytestream) SyncPacketSend.getReply( this.connection, streamHostRequest); streamHosts.addAll(response.getStreamHosts()); } catch (XMPPException e) { // blacklist errornous proxies this.proxyBlacklist.add(proxy); } } return streamHosts; }
/** * 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() { // get local proxy singleton Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy(); if (socks5Server.isRunning()) { List<String> addresses = socks5Server.getLocalAddresses(); int port = socks5Server.getPort(); if (addresses.size() >= 1) { List<StreamHost> streamHosts = new ArrayList<StreamHost>(); for (String address : addresses) { StreamHost streamHost = new StreamHost( this.connection.getUser(), address); streamHost.setPort(port); streamHosts.add(streamHost); } return streamHosts; } } // server is not running or local address could not be determined return null; }
/** * Returns the response to the SOCKS5 Bytestream request containing the SOCKS5 proxy used. * * @param selectedHost the used SOCKS5 proxy * @return the response to the SOCKS5 Bytestream request */ private Bytestream createUsedHostResponse(StreamHost selectedHost) { Bytestream response = new Bytestream(this.bytestreamRequest.getSessionID()); response.setTo(this.bytestreamRequest.getFrom()); response.setType(IQ.Type.result); response.setStanzaId(this.bytestreamRequest.getStanzaId()); response.setUsedHost(selectedHost.getJID()); return response; }
/** * Returns a list of stream hosts containing the IP address an the port for the given list of * SOCKS5 proxy JIDs. The order of the returned list is the same as the given list of JIDs * excluding all SOCKS5 proxies who's network settings could not be determined. If a local * SOCKS5 proxy is running it will be the first item in the list returned. * * @param proxies a list of SOCKS5 proxy JIDs * @return a list of stream hosts containing the IP address an the port */ private List<StreamHost> determineStreamHostInfos(List<String> proxies) { XMPPConnection connection = connection(); List<StreamHost> streamHosts = new ArrayList<StreamHost>(); // add local proxy on first position if exists List<StreamHost> localProxies = getLocalStreamHost(); if (localProxies != null) { streamHosts.addAll(localProxies); } // query SOCKS5 proxies for network settings for (String proxy : proxies) { Bytestream streamHostRequest = createStreamHostRequest(proxy); try { Bytestream response = (Bytestream) connection.createPacketCollectorAndSend( streamHostRequest).nextResultOrThrow(); streamHosts.addAll(response.getStreamHosts()); } catch (Exception e) { // blacklist errornous proxies this.proxyBlacklist.add(proxy); } } return streamHosts; }
/** * 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) { // 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(connection.getUser(), address, port)); } return streamHosts; }
/** * Returns a SOCKS5 Bytestream initialization request stanza(/packet) with the given session ID * containing the given stream hosts for the given target JID. * * @param sessionID the session ID for the SOCKS5 Bytestream * @param targetJID the target JID of SOCKS5 Bytestream request * @param streamHosts a list of SOCKS5 proxies the target should connect to * @return a SOCKS5 Bytestream initialization request packet */ private Bytestream createBytestreamInitiation(String sessionID, String targetJID, List<StreamHost> streamHosts) { Bytestream initiation = new Bytestream(sessionID); // add all stream hosts for (StreamHost streamHost : streamHosts) { initiation.addStreamHost(streamHost); } initiation.setType(IQ.Type.set); initiation.setTo(targetJID); return initiation; }
/** * If the target is not connected to the local SOCKS5 proxy an exception should be thrown. * * @throws Exception should not happen */ @Test public void shouldFailIfTargetIsNotConnectedToLocalSocks5Proxy() throws Exception { // start a local SOCKS5 proxy Socks5Proxy.setLocalSocks5ProxyPort(proxyPort); Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy(); socks5Proxy.start(); // build stream host information for local SOCKS5 proxy StreamHost streamHost = new StreamHost(connection.getUser(), socks5Proxy.getLocalAddresses().get(0), 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 { socks5Client.getSocket(10000); 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 } socks5Proxy.stop(); }
/** * If the initiator can connect to a SOCKS5 proxy but activating the stream fails an exception * should be thrown. * * @throws Exception should not happen */ @Test public void shouldFailIfActivateSocks5ProxyFails() throws Exception { // build error response as reply to the stream activation XMPPError xmppError = new XMPPError(XMPPError.Condition.internal_server_error); IQ error = new ErrorIQ(xmppError); error.setFrom(proxyJID); error.setTo(initiatorJID); protocol.addResponse(error, Verification.correspondingSenderReceiver, Verification.requestTypeSET); // start a local SOCKS5 proxy Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(proxyPort); socks5Proxy.start(); StreamHost streamHost = new StreamHost(proxyJID, socks5Proxy.getAddress(), 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 { socks5Client.getSocket(10000); fail("exception should be thrown"); } catch (XMPPErrorException e) { assertTrue(XMPPError.Condition.internal_server_error.equals(e.getXMPPError().getCondition())); protocol.verifyAll(); } socks5Proxy.stop(); }
/** * Returns the response to the SOCKS5 Bytestream request containing the SOCKS5 proxy used. * * @param selectedHost the used SOCKS5 proxy * @return the response to the SOCKS5 Bytestream request */ private Bytestream createUsedHostResponse(StreamHost selectedHost) { Bytestream response = new Bytestream(this.bytestreamRequest.getSessionID()); response.setTo(this.bytestreamRequest.getFrom()); response.setType(IQ.Type.RESULT); response.setPacketID(this.bytestreamRequest.getPacketID()); response.setUsedHost(selectedHost.getJID()); return response; }
/** * Returns a SOCKS5 Bytestream initialization request packet with the given session ID * containing the given stream hosts for the given target JID. * * @param sessionID the session ID for the SOCKS5 Bytestream * @param targetJID the target JID of SOCKS5 Bytestream request * @param streamHosts a list of SOCKS5 proxies the target should connect to * @return a SOCKS5 Bytestream initialization request packet */ private Bytestream createBytestreamInitiation(String sessionID, String targetJID, List<StreamHost> streamHosts) { Bytestream initiation = new Bytestream(sessionID); // add all stream hosts for (StreamHost streamHost : streamHosts) { initiation.addStreamHost(streamHost); } initiation.setType(IQ.Type.SET); initiation.setTo(targetJID); return initiation; }
/** * Returns the response to the SOCKS5 Bytestream request containing the * SOCKS5 proxy used. * * @param selectedHost * the used SOCKS5 proxy * @return the response to the SOCKS5 Bytestream request */ private Bytestream createUsedHostResponse(StreamHost selectedHost) { Bytestream response = new Bytestream( this.bytestreamRequest.getSessionID()); response.setTo(this.bytestreamRequest.getFrom()); response.setType(IQ.Type.RESULT); response.setPacketID(this.bytestreamRequest.getPacketID()); response.setUsedHost(selectedHost.getJID()); return response; }
/** * Returns a SOCKS5 Bytestream initialization request packet with the given * session ID containing the given stream hosts for the given target JID. * * @param sessionID * the session ID for the SOCKS5 Bytestream * @param targetJID * the target JID of SOCKS5 Bytestream request * @param streamHosts * a list of SOCKS5 proxies the target should connect to * @return a SOCKS5 Bytestream initialization request packet */ private Bytestream createBytestreamInitiation(String sessionID, String targetJID, List<StreamHost> streamHosts) { Bytestream initiation = new Bytestream(sessionID); // add all stream hosts for (StreamHost streamHost : streamHosts) { initiation.addStreamHost(streamHost); } initiation.setType(IQ.Type.SET); initiation.setTo(targetJID); return initiation; }
/** * Target and initiator should successfully connect to a "remote" SOCKS5 proxy and the initiator * activates the bytestream. * * @throws Exception should not happen */ @Test public void shouldSuccessfullyEstablishConnectionAndActivateSocks5Proxy() throws Exception { // build activation confirmation response IQ activationResponse = new EmptyResultIQ(); activationResponse.setFrom(proxyJID); activationResponse.setTo(initiatorJID); protocol.addResponse(activationResponse, Verification.correspondingSenderReceiver, Verification.requestTypeSET, new Verification<Bytestream, IQ>() { public void verify(Bytestream request, IQ response) { // verify that the correct stream should be activated assertNotNull(request.getToActivate()); assertEquals(targetJID, request.getToActivate().getTarget()); } }); // start a local SOCKS5 proxy Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(proxyPort); socks5Proxy.start(); StreamHost streamHost = new StreamHost(proxyJID, socks5Proxy.getAddress(), 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); Socket initiatorSocket = socks5Client.getSocket(10000); InputStream in = initiatorSocket.getInputStream(); Socket targetSocket = socks5Proxy.getSocket(digest); OutputStream out = targetSocket.getOutputStream(); // verify test data for (int i = 0; i < 10; i++) { out.write(i); assertEquals(i, in.read()); } protocol.verifyAll(); initiatorSocket.close(); targetSocket.close(); socks5Proxy.stop(); }
/** * Creates a new SOCKS5 client for the initiators side. * * @param streamHost containing network settings of the SOCKS5 proxy * @param digest identifying the SOCKS5 Bytestream * @param connection the XMPP connection * @param sessionID the session ID of the SOCKS5 Bytestream * @param target the target JID of the SOCKS5 Bytestream */ public Socks5ClientForInitiator(StreamHost streamHost, String digest, XMPPConnection connection, String sessionID, String target) { super(streamHost, digest); this.connection = new WeakReference<>(connection); this.sessionID = sessionID; this.target = target; }
/** * Creates a new SOCKS5 client for the initiators side. * * @param streamHost containing network settings of the SOCKS5 proxy * @param digest identifying the SOCKS5 Bytestream * @param connection the XMPP connection * @param sessionID the session ID of the SOCKS5 Bytestream * @param target the target JID of the SOCKS5 Bytestream */ public Socks5ClientForInitiator(StreamHost streamHost, String digest, Connection connection, String sessionID, String target) { super(streamHost, digest); this.connection = connection; this.sessionID = sessionID; this.target = target; }
/** * Creates a new SOCKS5 client for the initiators side. * * @param streamHost * containing network settings of the SOCKS5 proxy * @param digest * identifying the SOCKS5 Bytestream * @param connection * the XMPP connection * @param sessionID * the session ID of the SOCKS5 Bytestream * @param target * the target JID of the SOCKS5 Bytestream */ public Socks5ClientForInitiator(StreamHost streamHost, String digest, Connection connection, String sessionID, String target) { super(streamHost, digest); this.connection = connection; this.sessionID = sessionID; this.target = target; }
/** * Constructor for a SOCKS5 client. * * @param streamHost containing network settings of the SOCKS5 proxy * @param digest identifying the SOCKS5 Bytestream */ public Socks5Client(StreamHost streamHost, String digest) { this.streamHost = streamHost; this.digest = digest; }
/** * Invoking {@link Socks5BytestreamManager#establishSession(String, String)} the first time * should successfully negotiate a SOCKS5 Bytestream via the second SOCKS5 proxy. The second * negotiation should run in the same manner if prioritization is disabled. * * @throws Exception should not happen */ @Test public void shouldNotPrioritizeSocks5ProxyIfPrioritizationDisabled() throws Exception { // disable clients local SOCKS5 proxy Socks5Proxy.setLocalSocks5ProxyEnabled(false); // get Socks5ByteStreamManager for connection Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection); byteStreamManager.setProxyPrioritizationEnabled(false); assertFalse(byteStreamManager.isProxyPrioritizationEnabled()); Verification<Bytestream, Bytestream> streamHostUsedVerification = new Verification<Bytestream, Bytestream>() { public void verify(Bytestream request, Bytestream response) { assertEquals(response.getSessionID(), request.getSessionID()); assertEquals(2, request.getStreamHosts().size()); // verify that the used stream host is the second in list StreamHost streamHost = (StreamHost) request.getStreamHosts().toArray()[1]; assertEquals(response.getUsedHost().getJID(), streamHost.getJID()); } }; createResponses(streamHostUsedVerification); // start a local SOCKS5 proxy Socks5TestProxy socks5Proxy = Socks5TestProxy.getProxy(7778); socks5Proxy.start(); // create digest to get the socket opened by target String digest = Socks5Utils.createDigest(sessionID, initiatorJID, targetJID); // call the method that should be tested OutputStream outputStream = byteStreamManager.establishSession(targetJID, sessionID).getOutputStream(); // test the established bytestream InputStream inputStream = socks5Proxy.getSocket(digest).getInputStream(); byte[] data = new byte[] { 1, 2, 3 }; outputStream.write(data); byte[] result = new byte[3]; inputStream.read(result); assertArrayEquals(data, result); 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); }
/** * Constructor for a SOCKS5 client. * * @param streamHost * containing network settings of the SOCKS5 proxy * @param digest * identifying the SOCKS5 Bytestream */ public Socks5Client(StreamHost streamHost, String digest) { this.streamHost = streamHost; this.digest = digest; }