commit 8db5c3a0b4ebaf0bc5f1cf67fb8f2cea590f53fe Author: bim dsnake@protonmail.com Date: Sat Apr 24 20:55:52 2021 -0400
Fix bug where Orbot couldn't host multiple onion services of the same version (v2 or v3) off the same local port --- .../ui/hiddenservices/database/HSDatabase.java | 11 ++-- .../ui/v3onionservice/OnionServiceDatabase.java | 8 ++- .../torproject/android/service/OrbotService.java | 61 +++++++++++++++++----- 3 files changed, 60 insertions(+), 20 deletions(-)
diff --git a/app/src/main/java/org/torproject/android/ui/hiddenservices/database/HSDatabase.java b/app/src/main/java/org/torproject/android/ui/hiddenservices/database/HSDatabase.java index 18bc7aa0..d9a398bd 100644 --- a/app/src/main/java/org/torproject/android/ui/hiddenservices/database/HSDatabase.java +++ b/app/src/main/java/org/torproject/android/ui/hiddenservices/database/HSDatabase.java @@ -9,7 +9,7 @@ public class HSDatabase extends SQLiteOpenHelper {
public static final String HS_DATA_TABLE_NAME = "hs_data"; public static final String HS_CLIENT_COOKIE_TABLE_NAME = "hs_client_cookie"; - private static final int DATABASE_VERSION = 2; + private static final int DATABASE_VERSION = 4; private static final String DATABASE_NAME = "hidden_services"; private static final String HS_DATA_TABLE_CREATE = "CREATE TABLE " + HS_DATA_TABLE_NAME + " (" + @@ -21,7 +21,8 @@ public class HSDatabase extends SQLiteOpenHelper { "auth_cookie_value TEXT, " + "created_by_user INTEGER DEFAULT 0, " + "enabled INTEGER DEFAULT 1, " + - "port INTEGER);"; + "port INTEGER, " + + "filepath TEXT);";
private static final String HS_CLIENT_COOKIE_TABLE_CREATE = "CREATE TABLE " + HS_CLIENT_COOKIE_TABLE_NAME + " (" + @@ -42,6 +43,8 @@ public class HSDatabase extends SQLiteOpenHelper {
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (newVersion > oldVersion) { + db.execSQL("ALTER TABLE " + HS_DATA_TABLE_NAME + " ADD COLUMN filepath TEXT"); + } } -} - +} \ No newline at end of file diff --git a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDatabase.java b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDatabase.java index 558babac..d2c62a9d 100644 --- a/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDatabase.java +++ b/app/src/main/java/org/torproject/android/ui/v3onionservice/OnionServiceDatabase.java @@ -8,7 +8,7 @@ public class OnionServiceDatabase extends SQLiteOpenHelper {
static final String DATABASE_NAME = "onion_service", ONION_SERVICE_TABLE_NAME = "onion_services"; - private static final int DATABASE_VERSION = 1; + private static final int DATABASE_VERSION = 2;
private static final String ONION_SERVICES_CREATE_SQL = "CREATE TABLE " + ONION_SERVICE_TABLE_NAME + " (" + @@ -18,7 +18,8 @@ public class OnionServiceDatabase extends SQLiteOpenHelper { "onion_port INTEGER, " + "created_by_user INTEGER DEFAULT 0, " + "enabled INTEGER DEFAULT 1, " + - "port INTEGER);"; + "port INTEGER, " + + "filepath TEXT);";
OnionServiceDatabase(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -31,6 +32,9 @@ public class OnionServiceDatabase extends SQLiteOpenHelper {
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (newVersion > oldVersion) { + db.execSQL("ALTER TABLE " + ONION_SERVICE_TABLE_NAME + " ADD COLUMN filepath text"); + } }
diff --git a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java index 5d5eb3fd..6808f088 100644 --- a/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java +++ b/orbotservice/src/main/java/org/torproject/android/service/OrbotService.java @@ -72,6 +72,7 @@ import java.util.HashMap; import java.util.Objects; import java.util.Random; import java.util.StringTokenizer; +import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; @@ -98,7 +99,8 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb OnionService.AUTH_COOKIE, OnionService.AUTH_COOKIE_VALUE, OnionService.ONION_PORT, - OnionService.ENABLED}; + OnionService.ENABLED, + OnionService.PATH}; private static final String[] V3_ONION_SERVICE_PROJECTION = new String[]{ OnionService._ID, OnionService.NAME, @@ -106,6 +108,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb OnionService.PORT, OnionService.ONION_PORT, OnionService.ENABLED, + OnionService.PATH }; private static final String[] LEGACY_COOKIE_PROJECTION = new String[]{ ClientCookie._ID, @@ -841,16 +844,16 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb try { while (onionServices.moveToNext()) { String domain = onionServices.getString(onionServices.getColumnIndex(OnionService.DOMAIN)); - int localPort = onionServices.getInt(onionServices.getColumnIndex(OnionService.PORT)); - if (domain == null || TextUtils.isEmpty(domain)) { - String v3OnionDirPath = new File(mV3OnionBasePath.getAbsolutePath(), "v3" + localPort).getCanonicalPath(); + String path = onionServices.getString(onionServices.getColumnIndex(OnionService.PATH)); + String v3OnionDirPath = new File(mV3OnionBasePath.getAbsolutePath(), path).getCanonicalPath(); File hostname = new File(v3OnionDirPath, "hostname"); if (hostname.exists()) { + int id = onionServices.getInt(onionServices.getColumnIndex(OnionService._ID)); domain = Utils.readString(new FileInputStream(hostname)).trim(); ContentValues fields = new ContentValues(); fields.put(OnionService.DOMAIN, domain); - contentResolver.update(V3_ONION_SERVICES_CONTENT_URI, fields, "port=" + localPort, null); + contentResolver.update(V3_ONION_SERVICES_CONTENT_URI, fields, OnionService._ID + "=" + id, null); } }
@@ -870,19 +873,18 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb try { while (hidden_services.moveToNext()) { String HSDomain = hidden_services.getString(hidden_services.getColumnIndex(OnionService.DOMAIN)); - Integer HSLocalPort = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.PORT)); - Integer HSAuthCookie = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.AUTH_COOKIE)); + int HSAuthCookie = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.AUTH_COOKIE)); String HSAuthCookieValue = hidden_services.getString(hidden_services.getColumnIndex(OnionService.AUTH_COOKIE_VALUE)); - // Update only new domains or restored from backup with auth cookie if ((HSDomain == null || HSDomain.length() < 1) || (HSAuthCookie == 1 && (HSAuthCookieValue == null || HSAuthCookieValue.length() < 1))) { - String hsDirPath = new File(mHSBasePath.getAbsolutePath(), "hs" + HSLocalPort).getCanonicalPath(); + String hsDirPath = new File(mHSBasePath.getAbsolutePath(), hidden_services.getString(hidden_services.getColumnIndex(OnionService.PATH))).getCanonicalPath(); File file = new File(hsDirPath, "hostname");
if (file.exists()) { ContentValues fields = new ContentValues();
try { + int id = hidden_services.getInt(hidden_services.getColumnIndex(OnionService._ID)); String onionHostname = Utils.readString(new FileInputStream(file)).trim(); if (HSAuthCookie == 1) { String[] aux = onionHostname.split(" "); @@ -890,14 +892,13 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb fields.put(OnionService.AUTH_COOKIE_VALUE, aux[1]); } fields.put(OnionService.DOMAIN, onionHostname); - mCR.update(V2_HS_CONTENT_URI, fields, "port=" + HSLocalPort, null); + mCR.update(V2_HS_CONTENT_URI, fields, OnionService._ID + "=" + id, null); } catch (FileNotFoundException e) { logException("unable to read onion hostname file", e); showToolbarNotification(getString(R.string.unable_to_read_hidden_service_name), HS_NOTIFY_ID, R.drawable.ic_stat_notifyerr); } } else { showToolbarNotification(getString(R.string.unable_to_read_hidden_service_name), HS_NOTIFY_ID, R.drawable.ic_stat_notifyerr); - } } } @@ -1390,9 +1391,22 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb Cursor onionServices = contentResolver.query(V3_ONION_SERVICES_CONTENT_URI, V3_ONION_SERVICE_PROJECTION, OnionService.ENABLED + "=1", null, null); if (onionServices != null) { while (onionServices.moveToNext()) { + int id = onionServices.getInt(onionServices.getColumnIndex(OnionService._ID)); int localPort = onionServices.getInt(onionServices.getColumnIndex(OnionService.PORT)); int onionPort = onionServices.getInt(onionServices.getColumnIndex(OnionService.ONION_PORT)); - String v3DirPath = new File(mV3OnionBasePath.getAbsolutePath(), "v3" + localPort).getCanonicalPath(); + String path = onionServices.getString(onionServices.getColumnIndex(OnionService.PATH)); + String domain = onionServices.getString(onionServices.getColumnIndex(OnionService.DOMAIN)); + if (path == null) { + path = "v3"; + if (domain == null) + path += UUID.randomUUID().toString(); + else + path += localPort; + ContentValues cv = new ContentValues(); + cv.put(OnionService.PATH, path); + contentResolver.update(V3_ONION_SERVICES_CONTENT_URI, cv, OnionService._ID + "=" + id, null); + } + String v3DirPath = new File(mV3OnionBasePath.getAbsolutePath(), path).getCanonicalPath(); torrc.append("HiddenServiceDir ").append(v3DirPath).append("\n"); torrc.append("HiddenServiceVersion 3").append("\n"); torrc.append("HiddenServicePort ").append(onionPort).append(" 127.0.0.1:").append(localPort).append("\n"); @@ -1404,18 +1418,36 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb } }
- // todo needs modifications to set hidden service version back after doing v3 stuff... private void addV2HiddenServicesToTorrc(StringBuffer torrc, ContentResolver contentResolver) { try { Cursor hidden_services = contentResolver.query(V2_HS_CONTENT_URI, LEGACY_V2_ONION_SERVICE_PROJECTION, OnionService.ENABLED + "=1", null, null); if (hidden_services != null) { try { while (hidden_services.moveToNext()) { + int id = hidden_services.getInt(hidden_services.getColumnIndex(OnionService._ID)); String HSname = hidden_services.getString(hidden_services.getColumnIndex(OnionService.NAME)); + String domain = hidden_services.getString(hidden_services.getColumnIndex(OnionService.DOMAIN)); int HSLocalPort = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.PORT)); int HSOnionPort = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.ONION_PORT)); int HSAuthCookie = hidden_services.getInt(hidden_services.getColumnIndex(OnionService.AUTH_COOKIE)); - String hsDirPath = new File(mHSBasePath.getAbsolutePath(), "hs" + HSLocalPort).getCanonicalPath(); + String path = hidden_services.getString(hidden_services.getColumnIndex(OnionService.PATH)); + + // logic to fix bug where you can't have 2+ hidden services on same local port without breaking services that were configured before the bug fix + if (path == null) { + String newPath = "hs"; + if (domain == null) + newPath +=UUID.randomUUID().toString(); + else + newPath += HSLocalPort; + + ContentValues cv = new ContentValues(); + cv.put(OnionService.PATH, newPath); + contentResolver.update(V2_HS_CONTENT_URI, cv, OnionService._ID + "=" + id, null); + path = newPath; + } + + String hsDirPath = new File(mHSBasePath.getAbsolutePath(), path).getCanonicalPath(); +
debug("Adding hidden service on port: " + HSLocalPort);
@@ -1656,6 +1688,7 @@ public class OrbotService extends VpnService implements TorServiceConstants, Orb public static final String AUTH_COOKIE = "auth_cookie"; public static final String AUTH_COOKIE_VALUE = "auth_cookie_value"; public static final String ENABLED = "enabled"; + public static final String PATH = "filepath"; }
public static final class V3ClientAuth implements BaseColumns {
tor-commits@lists.torproject.org