refactored socks5 connection code. make jingle transport use that new code

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/Config.java                            |  2 
src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java          | 52 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java               | 29 
src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java | 42 
4 files changed, 72 insertions(+), 53 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/Config.java 🔗

@@ -42,7 +42,7 @@ public final class Config {
 	public static final int REFRESH_UI_INTERVAL = 500;
 
 	public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb
-	public static final boolean DISABLE_HTTP_UPLOAD = false;
+	public static final boolean DISABLE_HTTP_UPLOAD = true;
 	public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance
 	public static final boolean EXTENDED_SM_LOGGING = true; // log stanza counts
 	public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption

src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java 🔗

@@ -0,0 +1,52 @@
+package eu.siacs.conversations.utils;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+
+import eu.siacs.conversations.Config;
+
+public class SocksSocketFactory {
+
+	public static void createSocksConnection(Socket socket, String destination, int port) throws IOException {
+		InputStream proxyIs = socket.getInputStream();
+		OutputStream proxyOs = socket.getOutputStream();
+		proxyOs.write(new byte[]{0x05, 0x01, 0x00});
+		byte[] response = new byte[2];
+		proxyIs.read(response);
+		byte[] dest = destination.getBytes();
+		ByteBuffer request = ByteBuffer.allocate(7 + dest.length);
+		request.put(new byte[]{0x05, 0x01, 0x00, 0x03});
+		request.put((byte) dest.length);
+		request.put(dest);
+		request.putShort((short) port);
+		proxyOs.write(request.array());
+		response = new byte[7 + dest.length];
+		proxyIs.read(response);
+		if (response[1] != 0x00) {
+			throw new SocksConnectionException();
+		}
+	}
+
+	public static Socket createSocket(InetSocketAddress address, String destination, int port) throws IOException {
+		Socket socket = new Socket();
+		socket.connect(address, Config.CONNECT_TIMEOUT * 1000);
+		createSocksConnection(socket, destination, port);
+		return socket;
+	}
+
+	public static Socket createSocketOverTor(String destination, int port) throws IOException {
+		return createSocket(new InetSocketAddress(InetAddress.getLocalHost(), 9050), destination, port);
+	}
+
+	static class SocksConnectionException extends IOException {
+
+	}
+}

src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -67,6 +67,7 @@ import eu.siacs.conversations.generator.IqGenerator;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.utils.CryptoHelper;
 import eu.siacs.conversations.utils.DNSHelper;
+import eu.siacs.conversations.utils.SocksSocketFactory;
 import eu.siacs.conversations.utils.Xmlns;
 import eu.siacs.conversations.xml.Element;
 import eu.siacs.conversations.xml.Tag;
@@ -235,32 +236,14 @@ public class XmppConnection implements Runnable {
 			this.changeStatus(Account.State.CONNECTING);
 			final boolean useTor = mXmppConnectionService.useTorToConnect() || account.isOnion();
 			if (useTor) {
-				InetSocketAddress proxyAddress = new InetSocketAddress(InetAddress.getLocalHost(), 9050);
-				byte[] destination;
+				String destination;
 				if (account.getHostname() == null || account.getHostname().isEmpty()) {
-					destination = account.getServer().toString().getBytes();
+					destination = account.getServer().toString();
 				} else {
-					destination = account.getHostname().getBytes();
-				}
-				Log.d(Config.LOGTAG,"connecting via tor to "+new String(destination));
-				socket = new Socket();
-				socket.connect(proxyAddress, Config.CONNECT_TIMEOUT * 1000);
-				InputStream proxyIs = socket.getInputStream();
-				OutputStream proxyOs = socket.getOutputStream();
-				proxyOs.write(new byte[]{0x05, 0x01, 0x00});
-				byte[] response = new byte[2];
-				proxyIs.read(response);
-				ByteBuffer request = ByteBuffer.allocate(7 + destination.length);
-				request.put(new byte[]{0x05, 0x01, 0x00, 0x03});
-				request.put((byte) destination.length);
-				request.put(destination);
-				request.putShort((short) account.getPort());
-				proxyOs.write(request.array());
-				response = new byte[7 + destination.length];
-				proxyIs.read(response);
-				if (response[1] != 0x00) {
-					throw new UnknownHostException();
+					destination = account.getHostname();
 				}
+				Log.d(Config.LOGTAG,account.getJid().toBareJid()+": connect to "+destination+" via TOR");
+				socket = SocksSocketFactory.createSocketOverTor(destination,account.getPort());
 			} else if (DNSHelper.isIp(account.getServer().toString())) {
 				socket = new Socket();
 				try {

src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java 🔗

@@ -21,6 +21,7 @@ import eu.siacs.conversations.Config;
 import eu.siacs.conversations.entities.DownloadableFile;
 import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.utils.CryptoHelper;
+import eu.siacs.conversations.utils.SocksSocketFactory;
 
 public class JingleSocks5Transport extends JingleTransport {
 	private JingleCandidate candidate;
@@ -61,36 +62,19 @@ public class JingleSocks5Transport extends JingleTransport {
 			@Override
 			public void run() {
 				try {
-					final boolean useTor = connection.getConnectionManager().getXmppConnectionService().useTorToConnect();
-					final Proxy TOR_PROXY = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(InetAddress.getLocalHost(), 9050));
-					socket = useTor ? new Socket(TOR_PROXY) : new Socket();
-					SocketAddress address = new InetSocketAddress(candidate.getHost(),candidate.getPort());
-					socket.connect(address,Config.SOCKET_TIMEOUT * 1000);
-					inputStream = socket.getInputStream();
-					outputStream = socket.getOutputStream();
-					byte[] login = { 0x05, 0x01, 0x00 };
-					byte[] expectedReply = { 0x05, 0x00 };
-					byte[] reply = new byte[2];
-					outputStream.write(login);
-					inputStream.read(reply);
-					final String connect = Character.toString('\u0005')
-							+ '\u0001' + '\u0000' + '\u0003' + '\u0028'
-							+ destination + '\u0000' + '\u0000';
-					if (Arrays.equals(reply, expectedReply)) {
-						outputStream.write(connect.getBytes());
-						byte[] result = new byte[2];
-						inputStream.read(result);
-						int status = result[1];
-						if (status == 0) {
-							isEstablished = true;
-							callback.established();
-						} else {
-							callback.failed();
-						}
+					final boolean useTor = connection.getAccount().isOnion() || connection.getConnectionManager().getXmppConnectionService().useTorToConnect();
+					if (useTor) {
+						socket = SocksSocketFactory.createSocketOverTor(candidate.getHost(),candidate.getPort());
 					} else {
-						socket.close();
-						callback.failed();
+						socket = new Socket();
+						SocketAddress address = new InetSocketAddress(candidate.getHost(),candidate.getPort());
+						socket.connect(address,Config.SOCKET_TIMEOUT * 1000);
 					}
+					inputStream = socket.getInputStream();
+					outputStream = socket.getOutputStream();
+					SocksSocketFactory.createSocksConnection(socket,destination,0);
+					isEstablished = true;
+					callback.established();
 				} catch (UnknownHostException e) {
 					callback.failed();
 				} catch (IOException e) {
@@ -162,7 +146,7 @@ public class JingleSocks5Transport extends JingleTransport {
 					wakeLock.acquire();
 					MessageDigest digest = MessageDigest.getInstance("SHA-1");
 					digest.reset();
-					inputStream.skip(45);
+					//inputStream.skip(45);
 					socket.setSoTimeout(30000);
 					file.getParentFile().mkdirs();
 					file.createNewFile();