use of org.jivesoftware.smack.SmackException.SmackMessageException in project Smack by igniterealtime.
the class Socks5Client method establish.
/**
* Initializes the connection to the SOCKS5 proxy by negotiating authentication method and
* requesting a stream for the given digest. Currently only the no-authentication method is
* supported by the Socks5Client.
*
* @param socket connected to a SOCKS5 proxy
* @throws IOException if an I/O error occurred.
* @throws SmackMessageException if there was an error.
*/
protected void establish(Socket socket) throws IOException, SmackMessageException {
byte[] connectionRequest;
byte[] connectionResponse;
/*
* use DataInputStream/DataOutpuStream to assure read and write is completed in a single
* statement
*/
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
// authentication negotiation
byte[] cmd = new byte[3];
// protocol version 5
cmd[0] = (byte) 0x05;
// number of authentication methods supported
cmd[1] = (byte) 0x01;
// authentication method: no-authentication required
cmd[2] = (byte) 0x00;
out.write(cmd);
out.flush();
byte[] response = new byte[2];
in.readFully(response);
// check if server responded with correct version and no-authentication method
if (response[0] != (byte) 0x05 || response[1] != (byte) 0x00) {
throw new SmackException.SmackMessageException("Remote SOCKS5 server responded with unexpected version: " + response[0] + ' ' + response[1] + ". Should be 0x05 0x00.");
}
// request SOCKS5 connection with given address/digest
connectionRequest = createSocks5ConnectRequest();
out.write(connectionRequest);
out.flush();
// receive response
connectionResponse = Socks5Utils.receiveSocks5Message(in);
// verify response
// set expected return status to 0
connectionRequest[1] = (byte) 0x00;
if (!Arrays.equals(connectionRequest, connectionResponse)) {
throw new SmackException.SmackMessageException("Connection request does not equal connection response. Response: " + Arrays.toString(connectionResponse) + ". Request: " + Arrays.toString(connectionRequest));
}
}
use of org.jivesoftware.smack.SmackException.SmackMessageException in project Smack by igniterealtime.
the class Socks5Client method getSocket.
/**
* Returns the initialized socket that can be used to transfer data between peers via the SOCKS5
* proxy.
*
* @param timeout timeout to connect to SOCKS5 proxy in milliseconds
* @return socket the initialized socket
* @throws IOException if initializing the socket failed due to a network error
* @throws TimeoutException if connecting to SOCKS5 proxy timed out
* @throws InterruptedException if the current thread was interrupted while waiting
* @throws XMPPException if an XMPP protocol error was received.
* @throws SmackMessageException if there was an error.
* @throws NotConnectedException if the XMPP connection is not connected.
* @throws NoResponseException if there was no response from the remote entity.
*/
public Socket getSocket(int timeout) throws IOException, InterruptedException, TimeoutException, XMPPException, SmackMessageException, NotConnectedException, NoResponseException {
// wrap connecting in future for timeout
FutureTask<Socket> futureTask = new FutureTask<>(new Callable<Socket>() {
@Override
public Socket call() throws IOException, SmackMessageException {
// initialize socket
Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(streamHost.getAddress().asInetAddress(), streamHost.getPort());
socket.connect(socketAddress);
// initialize connection to SOCKS5 proxy
try {
establish(socket);
} catch (SmackMessageException e) {
if (!socket.isClosed()) {
CloseableUtil.maybeClose(socket, LOGGER);
}
throw e;
}
return socket;
}
});
Async.go(futureTask, "SOCKS5 client connecting to " + streamHost);
// get connection to initiator with timeout
try {
return futureTask.get(timeout, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw new IOException("ExecutionException while SOCKS5 client attempting to connect to " + streamHost, e);
}
}
use of org.jivesoftware.smack.SmackException.SmackMessageException 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 XMPPException if an XMPP protocol error was received.
* @throws NotConnectedException if the XMPP connection is not connected.
* @throws NoResponseException if there was no response from the remote entity.
* @throws SmackMessageException if there was an error.
* @throws FeatureNotSupportedException if a requested feature is not supported by the remote entity.
*/
@Override
public Socks5BytestreamSession establishSession(Jid targetJID, String sessionID) throws IOException, InterruptedException, XMPPException, NoResponseException, NotConnectedException, SmackMessageException, FeatureNotSupportedException {
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.SmackMessageException("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.SmackMessageException("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", e);
} finally {
// remove transfer digest if output stream is returned or an exception
// occurred
socks5Proxy.removeTransfer(digest);
}
}
Aggregations