[tor-commits] [orbot/master] Fix bug where Orbot couldn't host multiple onion services of the same version (v2 or v3) off the same local port

n8fr8 at torproject.org n8fr8 at torproject.org
Wed Dec 22 21:55:07 UTC 2021


commit 8db5c3a0b4ebaf0bc5f1cf67fb8f2cea590f53fe
Author: bim <dsnake at 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 {





More information about the tor-commits mailing list