@Override InputStream negotiateIncomingStream(Stanza streamInitiation) throws InterruptedException, SmackException, XMPPErrorException { // build SOCKS5 Bytestream request Socks5BytestreamRequest request = new ByteStreamRequest(this.manager, (Bytestream) streamInitiation); // always accept the request Socks5BytestreamSession session = request.accept(); // test input stream try { PushbackInputStream stream = new PushbackInputStream(session.getInputStream()); int firstByte = stream.read(); stream.unread(firstByte); return stream; } catch (IOException e) { throw new SmackException("Error establishing input stream", e); } }
/** * Enable the Jabber services related to file transfer on the particular * connection. * * @param connection The connection on which to enable or disable the services. * @param isEnabled True to enable, false to disable. */ private static void setServiceEnabled(final XMPPConnection connection, final boolean isEnabled) { ServiceDiscoveryManager manager = ServiceDiscoveryManager .getInstanceFor(connection); List<String> namespaces = new ArrayList<String>(); namespaces.addAll(Arrays.asList(NAMESPACE)); namespaces.add(DataPacketExtension.NAMESPACE); if (!IBB_ONLY) { namespaces.add(Bytestream.NAMESPACE); } for (String namespace : namespaces) { if (isEnabled) { manager.addFeature(namespace); } else { manager.removeFeature(namespace); } } }
/** * Checks to see if all file transfer related services are enabled on the * connection. * * @param connection The connection to check * @return True if all related services are enabled, false if they are not. */ public static boolean isServiceEnabled(final XMPPConnection connection) { ServiceDiscoveryManager manager = ServiceDiscoveryManager .getInstanceFor(connection); List<String> namespaces = new ArrayList<String>(); namespaces.addAll(Arrays.asList(NAMESPACE)); namespaces.add(DataPacketExtension.NAMESPACE); if (!IBB_ONLY) { namespaces.add(Bytestream.NAMESPACE); } for (String namespace : namespaces) { if (!manager.includesFeature(namespace)) { return false; } } return true; }
/** * Target should respond with not-acceptable error if no listeners for incoming Socks5 * bytestream requests are registered. * * @throws XMPPException should not happen */ public void testRespondWithErrorOnSocks5BytestreamRequest() throws XMPPException { XMPPConnection targetConnection = getConnection(0); XMPPConnection initiatorConnection = getConnection(1); Bytestream bytestreamInitiation = Socks5PacketUtils.createBytestreamInitiation( initiatorConnection.getUser(), targetConnection.getUser(), "session_id"); bytestreamInitiation.addStreamHost("proxy.localhost", "127.0.0.1", 7777); PacketCollector collector = initiatorConnection.createPacketCollector(new PacketIDFilter( bytestreamInitiation.getStanzaId())); initiatorConnection.sendStanza(bytestreamInitiation); Packet result = collector.nextResult(); assertNotNull(result.getError()); assertEquals(XMPPError.Condition.no_acceptable.toString(), result.getError().getCondition()); }
/** * 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; }
@Override InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException, InterruptedException { // build SOCKS5 Bytestream request Socks5BytestreamRequest request = new ByteStreamRequest(this.manager, (Bytestream) streamInitiation); // always accept the request Socks5BytestreamSession session = request.accept(); // test input stream try { PushbackInputStream stream = new PushbackInputStream(session.getInputStream()); int firstByte = stream.read(); stream.unread(firstByte); return stream; } catch (IOException e) { throw new XMPPException("Error establishing input stream", e); } }
/** * 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; }
@Override InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException, InterruptedException { // build SOCKS5 Bytestream request Socks5BytestreamRequest request = new ByteStreamRequest(this.manager, (Bytestream) streamInitiation); // always accept the request Socks5BytestreamSession session = request.accept(); // test input stream try { PushbackInputStream stream = new PushbackInputStream( session.getInputStream()); int firstByte = stream.read(); stream.unread(firstByte); return stream; } catch (IOException e) { throw new XMPPException("Error establishing input stream", e); } }
/** * Target should respond with not-acceptable error if no listeners for incoming Socks5 * bytestream requests are registered. * * @throws XMPPException should not happen */ public void testRespondWithErrorOnSocks5BytestreamRequest() throws XMPPException { Connection targetConnection = getConnection(0); Connection initiatorConnection = getConnection(1); Bytestream bytestreamInitiation = Socks5PacketUtils.createBytestreamInitiation( initiatorConnection.getUser(), targetConnection.getUser(), "session_id"); bytestreamInitiation.addStreamHost("proxy.localhost", "127.0.0.1", 7777); PacketCollector collector = initiatorConnection.createPacketCollector(new PacketIDFilter( bytestreamInitiation.getPacketID())); initiatorConnection.sendPacket(bytestreamInitiation); Packet result = collector.nextResult(); assertNotNull(result.getError()); assertEquals(XMPPError.Condition.no_acceptable.toString(), result.getError().getCondition()); }
private void processRequest(Stanza packet) throws NotConnectedException { Bytestream byteStreamRequest = (Bytestream) packet; StreamNegotiator.signal(byteStreamRequest.getFrom() + '\t' + byteStreamRequest.getSessionID(), byteStreamRequest); // ignore request if in ignore list if (this.manager.getIgnoredBytestreamRequests().remove(byteStreamRequest.getSessionID())) { return; } // build bytestream request from packet Socks5BytestreamRequest request = new Socks5BytestreamRequest(this.manager, byteStreamRequest); // notify listeners for bytestream initiation from a specific user BytestreamListener userListener = this.manager.getUserListener(byteStreamRequest.getFrom()); if (userListener != null) { userListener.incomingBytestreamRequest(request); } else if (!this.manager.getAllRequestListeners().isEmpty()) { /* * if there is no user specific listener inform listeners for all initiation requests */ for (BytestreamListener listener : this.manager.getAllRequestListeners()) { listener.incomingBytestreamRequest(request); } } else { /* * if there is no listener for this initiation request, reply with reject message */ this.manager.replyRejectPacket(byteStreamRequest); } }
/** * 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 SOCKS5 Bytestream activation packet. * * @return SOCKS5 Bytestream activation packet */ private Bytestream createStreamHostActivation() { Bytestream activate = new Bytestream(this.sessionID); activate.setMode(null); activate.setType(IQ.Type.set); activate.setTo(this.streamHost.getJID()); activate.setToActivate(this.target); return activate; }
/** * Disables the SOCKS5 Bytestream manager by removing the SOCKS5 Bytestream feature from the * service discovery, disabling the listener for SOCKS5 Bytestream initiation requests and * resetting its internal state, which includes removing this instance from the managers map. * <p> * To re-enable the SOCKS5 Bytestream feature invoke {@link #getBytestreamManager(XMPPConnection)}. * Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature. */ public synchronized void disableService() { XMPPConnection connection = connection(); // remove initiation packet listener connection.unregisterIQRequestHandler(initiationListener); // shutdown threads this.initiationListener.shutdown(); // clear listeners this.allRequestListeners.clear(); this.userListeners.clear(); // reset internal state this.lastWorkingProxy = null; this.proxyBlacklist.clear(); this.ignoredBytestreamRequests.clear(); // remove manager from static managers map managers.remove(connection); // shutdown local SOCKS5 proxy if there are no more managers for other connections if (managers.size() == 0) { Socks5Proxy.getSocks5Proxy().stop(); } // remove feature from service discovery ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection); // check if service discovery is not already disposed by connection shutdown if (serviceDiscoveryManager != null) { serviceDiscoveryManager.removeFeature(Bytestream.NAMESPACE); } }
/** * 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 a IQ stanza(/packet) to query a SOCKS5 proxy its network settings. * * @param proxy the proxy to query * @return IQ stanza(/packet) to query a SOCKS5 proxy its network settings */ private Bytestream createStreamHostRequest(String proxy) { Bytestream request = new Bytestream(); request.setType(IQ.Type.get); request.setTo(proxy); return request; }
/** * 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; }
/** * Returns a collection of the supported transfer protocols. * * @return Returns a collection of the supported transfer protocols. */ public static Collection<String> getSupportedProtocols() { List<String> protocols = new ArrayList<String>(); protocols.add(DataPacketExtension.NAMESPACE); if (!IBB_ONLY) { protocols.add(Bytestream.NAMESPACE); } return Collections.unmodifiableList(protocols); }
private StreamNegotiator getNegotiator(final FormField field) throws NoAcceptableTransferMechanisms { String variable; boolean isByteStream = false; boolean isIBB = false; for (FormField.Option option : field.getOptions()) { variable = option.getValue(); if (variable.equals(Bytestream.NAMESPACE) && !IBB_ONLY) { isByteStream = true; } else if (variable.equals(DataPacketExtension.NAMESPACE)) { isIBB = true; } } if (!isByteStream && !isIBB) { throw new FileTransferException.NoAcceptableTransferMechanisms(); } if (isByteStream && isIBB) { return new FaultTolerantNegotiator(connection(), byteStreamTransferManager, inbandTransferManager); } else if (isByteStream) { return byteStreamTransferManager; } else { return inbandTransferManager; } }
private StreamNegotiator getOutgoingNegotiator(final FormField field) throws NoAcceptableTransferMechanisms { boolean isByteStream = false; boolean isIBB = false; for (String variable : field.getValues()) { if (variable.equals(Bytestream.NAMESPACE) && !IBB_ONLY) { isByteStream = true; } else if (variable.equals(DataPacketExtension.NAMESPACE)) { isIBB = true; } } if (!isByteStream && !isIBB) { throw new FileTransferException.NoAcceptableTransferMechanisms(); } if (isByteStream && isIBB) { return new FaultTolerantNegotiator(connection(), byteStreamTransferManager, inbandTransferManager); } else if (isByteStream) { return byteStreamTransferManager; } else { return inbandTransferManager; } }
private DataForm createDefaultInitiationForm() { DataForm form = new DataForm(DataForm.Type.form); FormField field = new FormField(STREAM_DATA_FIELD_NAME); field.setType(FormField.Type.list_single); if (!IBB_ONLY) { field.addOption(new FormField.Option(Bytestream.NAMESPACE)); } field.addOption(new FormField.Option(DataPacketExtension.NAMESPACE)); form.addField(field); return form; }
private StreamNegotiator determineNegotiator(Stanza streamInitiation) { if (streamInitiation instanceof Bytestream) { return primaryNegotiator; } else if (streamInitiation instanceof Open){ return secondaryNegotiator; } else { throw new IllegalStateException("Unknown stream initation type"); } }
/** * The SOCKS5 Bytestream feature should be removed form the service discovery manager if Socks5 * bytestream feature is disabled. */ @Test public void shouldDisableService() { Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection); ServiceDiscoveryManager discoveryManager = ServiceDiscoveryManager.getInstanceFor(connection); assertTrue(discoveryManager.includesFeature(Bytestream.NAMESPACE)); byteStreamManager.disableService(); assertFalse(discoveryManager.includesFeature(Bytestream.NAMESPACE)); }
/** * Accepting a SOCKS5 Bytestream request should fail if the request doesn't contain any Socks5 * proxies. * * @throws Exception should not happen */ @Test public void shouldFailIfRequestHasNoStreamHosts() throws Exception { try { // build SOCKS5 Bytestream initialization request with no SOCKS5 proxies Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation( initiatorJID, targetJID, sessionID); // 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) byteStreamRequest.accept(); fail("exception should be thrown"); } catch (XMPPErrorException e) { assertTrue(e.getMessage().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()); }
/** * Accepting a SOCKS5 Bytestream request should fail if target is not able to connect to any of * the provided SOCKS5 proxies. * * @throws Exception */ @Test public void shouldFailIfRequestHasInvalidStreamHosts() throws Exception { try { // build SOCKS5 Bytestream initialization request Bytestream bytestreamInitialization = Socks5PacketUtils.createBytestreamInitiation( initiatorJID, targetJID, sessionID); // add proxy that is not running bytestreamInitialization.addStreamHost(proxyJID, proxyAddress, 7778); // 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) byteStreamRequest.accept(); fail("exception should be thrown"); } catch (XMPPErrorException e) { assertTrue(e.getMessage().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()); }
private void processRequest(Packet packet) { Bytestream byteStreamRequest = (Bytestream) packet; // ignore request if in ignore list if (this.manager.getIgnoredBytestreamRequests().remove(byteStreamRequest.getSessionID())) { return; } // build bytestream request from packet Socks5BytestreamRequest request = new Socks5BytestreamRequest(this.manager, byteStreamRequest); // notify listeners for bytestream initiation from a specific user BytestreamListener userListener = this.manager.getUserListener(byteStreamRequest.getFrom()); if (userListener != null) { userListener.incomingBytestreamRequest(request); } else if (!this.manager.getAllRequestListeners().isEmpty()) { /* * if there is no user specific listener inform listeners for all initiation requests */ for (BytestreamListener listener : this.manager.getAllRequestListeners()) { listener.incomingBytestreamRequest(request); } } else { /* * if there is no listener for this initiation request, reply with reject message */ this.manager.replyRejectPacket(byteStreamRequest); } }
/** * 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 activation packet. * * @return SOCKS5 Bytestream activation packet */ private Bytestream createStreamHostActivation() { Bytestream activate = new Bytestream(this.sessionID); activate.setMode(null); activate.setType(IQ.Type.SET); activate.setTo(this.streamHost.getJID()); activate.setToActivate(this.target); return activate; }
/** * Returns a IQ packet to query a SOCKS5 proxy its network settings. * * @param proxy the proxy to query * @return IQ packet to query a SOCKS5 proxy its network settings */ private Bytestream createStreamHostRequest(String proxy) { Bytestream request = new Bytestream(); request.setType(IQ.Type.GET); request.setTo(proxy); return request; }
/** * 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; }
public BytestreamSIDFilter(String sessionID) { super(Bytestream.class); if (sessionID == null) { throw new IllegalArgumentException("StreamID cannot be null"); } this.sessionID = sessionID; }
@Override public boolean accept(Packet packet) { if (super.accept(packet)) { Bytestream bytestream = (Bytestream) packet; // packet must by of type SET and contains the given session ID return this.sessionID.equals(bytestream.getSessionID()) && IQ.Type.SET.equals(bytestream.getType()); } return false; }