do socks5 connect manually

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/Account.java       | 20 
src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 52 +
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java    | 48 +
3 files changed, 69 insertions(+), 51 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/Account.java 🔗

@@ -2,8 +2,6 @@ package eu.siacs.conversations.entities;
 
 import android.content.ContentValues;
 import android.database.Cursor;
-import android.os.Bundle;
-import android.os.Parcelable;
 import android.os.SystemClock;
 
 import eu.siacs.conversations.crypto.PgpDecryptionService;
@@ -15,7 +13,6 @@ import org.json.JSONObject;
 
 import java.security.PublicKey;
 import java.security.interfaces.DSAPublicKey;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -72,19 +69,6 @@ public class Account extends AbstractEntity {
 		}
 	}
 
-	public ArrayList<Parcelable> getHostnamePortBundles() {
-		ArrayList<Parcelable> values = new ArrayList<>();
-		Bundle hostPort = new Bundle();
-		if (hostname != null && !hostname.isEmpty()) {
-			hostPort.putString("name", hostname);
-		} else {
-			hostPort.putString("name", getServer().toString());
-		}
-		hostPort.putInt("port", port);
-		values.add(hostPort);
-		return values;
-	}
-
 	public enum State {
 		DISABLED,
 		OFFLINE,
@@ -268,6 +252,10 @@ public class Account extends AbstractEntity {
 		return this.hostname == null ? "" : this.hostname;
 	}
 
+	public boolean isOnion() {
+		return getServer().toString().toLowerCase().endsWith(".onion");
+	}
+
 	public void setPort(int port) {
 		this.port = port;
 	}

src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -129,6 +129,31 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 				mAccountJid.requestFocus();
 				return;
 			}
+			String hostname = null;
+			int numericPort = 5222;
+			if (mUseTor) {
+				hostname = mHostname.getText().toString();
+				final String port = mPort.getText().toString();
+				if (hostname.contains(" ")) {
+					mHostname.setError(getString(R.string.not_valid_hostname));
+					mHostname.requestFocus();
+					return;
+				}
+				try {
+					numericPort = Integer.parseInt(port);
+					if (numericPort < 0 || numericPort > 65535) {
+						mPort.setError(getString(R.string.not_a_valid_port));
+						mPort.requestFocus();
+						return;
+					}
+
+				} catch (NumberFormatException e) {
+					mPort.setError(getString(R.string.not_a_valid_port));
+					mPort.requestFocus();
+					return;
+				}
+			}
+
 			if (jid.isDomainJid()) {
 				if (Config.DOMAIN_LOCK != null) {
 					mAccountJid.setError(getString(R.string.invalid_username));
@@ -140,8 +165,6 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			}
 			final String password = mPassword.getText().toString();
 			final String passwordConfirm = mPasswordConfirm.getText().toString();
-			final String hostname = mHostname.getText().toString();
-			final String port = mPort.getText().toString();
 			if (registerNewAccount) {
 				if (!password.equals(passwordConfirm)) {
 					mPasswordConfirm.setError(getString(R.string.passwords_do_not_match));
@@ -151,29 +174,12 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 			}
 			if (mAccount != null) {
 				mAccount.setJid(jid);
+				mAccount.setPort(numericPort);
+				mAccount.setHostname(hostname);
 				mAccountJid.setError(null);
 				mPasswordConfirm.setError(null);
 				mAccount.setPassword(password);
 				mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
-				if (hostname.contains(" ")) {
-					mHostname.setError(getString(R.string.not_valid_hostname));
-					mHostname.requestFocus();
-					return;
-				}
-				mAccount.setHostname(hostname);
-				try {
-					int numericPort = Integer.parseInt(port);
-					if (numericPort < 0 || numericPort > 65535) {
-						mPort.setError(getString(R.string.not_a_valid_port));
-						mPort.requestFocus();
-						return;
-					}
-					mAccount.setPort(numericPort);
-				} catch (NumberFormatException e) {
-					mPort.setError(getString(R.string.not_a_valid_port));
-					mPort.requestFocus();
-					return;
-				}
 				xmppConnectionService.updateAccount(mAccount);
 			} else {
 				if (xmppConnectionService.findAccountByJid(jid) != null) {
@@ -182,11 +188,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
 					return;
 				}
 				mAccount = new Account(jid.toBareJid(), password);
+				mAccount.setPort(numericPort);
+				mAccount.setHostname(hostname);
 				mAccount.setOption(Account.OPTION_USETLS, true);
 				mAccount.setOption(Account.OPTION_USECOMPRESSION, true);
 				mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount);
 				xmppConnectionService.createAccount(mAccount);
 			}
+			mHostname.setError(null);
+			mPort.setError(null);
 			if (!mAccount.isOptionSet(Account.OPTION_DISABLED)
 					&& !registerNewAccount
 					&& !mInitMode) {

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

@@ -13,7 +13,6 @@ import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
 
-import org.apache.http.conn.ssl.StrictHostnameVerifier;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.xmlpull.v1.XmlPullParserException;
@@ -27,10 +26,10 @@ import java.net.ConnectException;
 import java.net.IDN;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
-import java.net.Proxy;
 import java.net.Socket;
 import java.net.UnknownHostException;
 import java.net.URL;
+import java.nio.ByteBuffer;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
@@ -234,23 +233,44 @@ public class XmppConnection implements Runnable {
 			tagReader = new XmlReader(wakeLock);
 			tagWriter = new TagWriter();
 			this.changeStatus(Account.State.CONNECTING);
-			final boolean useTor = mXmppConnectionService.useTorToConnect();
-			final Proxy TOR_PROXY = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(InetAddress.getLocalHost(), 9050));
-			if (DNSHelper.isIp(account.getServer().toString())) {
-				socket = useTor ? new Socket(TOR_PROXY) : new Socket();
+			final boolean useTor = mXmppConnectionService.useTorToConnect() || account.isOnion();
+			if (useTor) {
+				InetSocketAddress proxyAddress = new InetSocketAddress(InetAddress.getLocalHost(), 9050);
+				byte[] destination;
+				if (account.getHostname() == null || account.getHostname().isEmpty()) {
+					destination = account.getServer().toString().getBytes();
+				} 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();
+				}
+			} else if (DNSHelper.isIp(account.getServer().toString())) {
+				socket = new Socket();
 				try {
 					socket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000);
 				} catch (IOException e) {
 					throw new UnknownHostException();
 				}
 			} else {
-				final ArrayList<Parcelable> values;
-				if (useTor) {
-					values = account.getHostnamePortBundles();
-				} else {
-					final Bundle result = DNSHelper.getSRVRecord(account.getServer(),mXmppConnectionService);
-					values = result.getParcelableArrayList("values");
-				}
+				final Bundle result = DNSHelper.getSRVRecord(account.getServer(),mXmppConnectionService);
+				final ArrayList<Parcelable>values = result.getParcelableArrayList("values");
 				int i = 0;
 				boolean socketError = true;
 				while (socketError && values.size() > i) {
@@ -277,7 +297,7 @@ public class XmppConnection implements Runnable {
 									+ ": using values from dns "
 									+ srvRecordServer + ":" + srvRecordPort);
 						}
-						socket = useTor ? new Socket(TOR_PROXY) : new Socket();
+						socket = new Socket();
 						socket.connect(addr, Config.SOCKET_TIMEOUT * 1000);
 						socketError = false;
 					} catch (final Throwable e) {