From 77020ccf7bf3a58b27c427a67706f945da213784 Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Fri, 25 Dec 2015 03:38:48 +0100
Subject: [PATCH 01/33] Define the floating button at the end of the
 RelativeLayout, to put it over all the others widgets. Thanks to @0MazaHacka0
 for reporting it.

---
 cSploit/res/layout/plugin_inspector.xml | 30 ++++++++++++++-----------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/cSploit/res/layout/plugin_inspector.xml b/cSploit/res/layout/plugin_inspector.xml
index 1c9ee175ef..026735c44a 100644
--- a/cSploit/res/layout/plugin_inspector.xml
+++ b/cSploit/res/layout/plugin_inspector.xml
@@ -6,19 +6,6 @@
     android:paddingTop="16sp"
     android:id="@+id/whatever">
 
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/inspectToggleButton"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:padding="20dp"
-        android:src="@drawable/ic_play_arrow_24dp"
-        android:checked="false"
-        android:translationZ="8dp"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentRight="true"
-        android:layout_margin="20dp"
-        android:focusableInTouchMode="true" />
-
     <ProgressBar
         android:id="@+id/inspectActivity"
         android:layout_width="wrap_content"
@@ -156,4 +143,21 @@
         android:gravity="center_vertical"
         />
     </ScrollView>
+
+    <!--
+    Later children in a RelativeLayout tend to float over earlier children in a RelativeLayout.
+    https://www.stackoverflow.com/a/28651543
+    -->
+    <android.support.design.widget.FloatingActionButton
+        android:id="@+id/inspectToggleButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="20dp"
+        android:src="@drawable/ic_play_arrow_24dp"
+        android:checked="false"
+        android:translationZ="8dp"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentRight="true"
+        android:layout_margin="20dp"
+        android:focusableInTouchMode="true" />
 </RelativeLayout>
\ No newline at end of file

From 8c5a9cc5048b30a2e1a1809711b623861375e56d Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Fri, 25 Dec 2015 03:41:15 +0100
Subject: [PATCH 02/33] version bump

---
 cSploit/build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cSploit/build.gradle b/cSploit/build.gradle
index ffa986128a..d719669179 100644
--- a/cSploit/build.gradle
+++ b/cSploit/build.gradle
@@ -52,8 +52,8 @@ android {
     defaultConfig {
         minSdkVersion 9
         targetSdkVersion 22
-        versionCode 4
-        versionName "1.6.2"
+        versionCode 5
+        versionName "1.6.3"
         if(System.getenv("NIGHTLY_BUILD")) {
             versionName += "+" + System.getenv("NIGHTLY_BUILD_COMMIT").substring(0, 7)
         }

From 539f98252a35a1be8718233b5d1d2b66e897360f Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Fri, 25 Dec 2015 03:43:57 +0100
Subject: [PATCH 03/33] use stable version of gradle android plugin

---
 build.gradle         | 2 +-
 cSploit/build.gradle | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/build.gradle b/build.gradle
index c0bd27756b..dea94eb99c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
         mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.4.0-beta6'
+        classpath 'com.android.tools.build:gradle:1.5.0'
     }
 }
 
diff --git a/cSploit/build.gradle b/cSploit/build.gradle
index d719669179..dcbe82d686 100644
--- a/cSploit/build.gradle
+++ b/cSploit/build.gradle
@@ -4,7 +4,7 @@ buildscript {
         mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.4.0-beta6'
+        classpath 'com.android.tools.build:gradle:1.5.0'
     }
 }
 

From d29597b91cbb6493abdd153544657587b88bc315 Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Thu, 7 Jan 2016 14:26:26 +0100
Subject: [PATCH 04/33] fixes #555

---
 .../services/receivers/MsfRpcdServiceReceiver.java     | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/cSploit/src/org/csploit/android/services/receivers/MsfRpcdServiceReceiver.java b/cSploit/src/org/csploit/android/services/receivers/MsfRpcdServiceReceiver.java
index d832e90f62..63dacf81ac 100644
--- a/cSploit/src/org/csploit/android/services/receivers/MsfRpcdServiceReceiver.java
+++ b/cSploit/src/org/csploit/android/services/receivers/MsfRpcdServiceReceiver.java
@@ -2,6 +2,7 @@
 
 import android.app.Activity;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -68,7 +69,7 @@ private void showToastForStatus(Context context, MsfRpcdService.Status status) {
   }
 
   private void updateNotificationForStatus(Context context, MsfRpcdService.Status status) {
-    NotificationCompat.Builder mBuilder =
+    NotificationCompat.Builder builder =
             new NotificationCompat.Builder(context)
             .setSmallIcon(R.drawable.exploit_msf)
             .setContentTitle(context.getString(R.string.msf_status))
@@ -76,8 +77,13 @@ private void updateNotificationForStatus(Context context, MsfRpcdService.Status
             .setContentText(context.getString(status.getText()))
             .setColor(ContextCompat.getColor(context, status.getColor()));
 
+    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
+            new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
+
+    builder.setContentIntent(pendingIntent);
+
     NotificationManager mNotificationManager =
             (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-    mNotificationManager.notify(MSF_NOTIFICATION, mBuilder.build());
+    mNotificationManager.notify(MSF_NOTIFICATION, builder.build());
   }
 }

From 5a120d732171938f8bc5342bf2711ef4e18eb146 Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Thu, 7 Jan 2016 14:33:18 +0100
Subject: [PATCH 05/33] version bump

---
 cSploit/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cSploit/build.gradle b/cSploit/build.gradle
index dcbe82d686..5475b4df46 100644
--- a/cSploit/build.gradle
+++ b/cSploit/build.gradle
@@ -53,7 +53,7 @@ android {
         minSdkVersion 9
         targetSdkVersion 22
         versionCode 5
-        versionName "1.6.3"
+        versionName "1.6.4"
         if(System.getenv("NIGHTLY_BUILD")) {
             versionName += "+" + System.getenv("NIGHTLY_BUILD_COMMIT").substring(0, 7)
         }

From f92cde5420828df24788009b1ae5b4ca2fe759c5 Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sat, 16 Jan 2016 08:16:01 +0100
Subject: [PATCH 06/33] force user to choose empty or old directories.

---
 cSploit/res/values/strings.xml                |   1 +
 .../org/csploit/android/SettingsActivity.java | 107 +++++++++++++-----
 2 files changed, 81 insertions(+), 27 deletions(-)

diff --git a/cSploit/res/values/strings.xml b/cSploit/res/values/strings.xml
index d03780c5c9..43af23b7c5 100644
--- a/cSploit/res/values/strings.xml
+++ b/cSploit/res/values/strings.xml
@@ -529,4 +529,5 @@
     <string name="mitm_ss_select_target_prompt">Select %s ?</string>
     <string name="github_issues_url" translatable="false">https://github.com/cSploit/android/issues</string>
     <string name="issue_message"><![CDATA[<p>Before opening a new issue, please, take the time to read the already <a href="%1$s">open issues</a>, probably it\' s already open. If it\' s not open we\'ll need as much information as you can get, so please, read <a href="%2$s">this guide</a> in order to know how to report a bug properly.</p>]]></string>
+    <string name="pref_err_empty_or_old">must be empty or an old installation directory.</string>
 </resources>
diff --git a/cSploit/src/org/csploit/android/SettingsActivity.java b/cSploit/src/org/csploit/android/SettingsActivity.java
index 4a64f9787a..dbb71f2026 100644
--- a/cSploit/src/org/csploit/android/SettingsActivity.java
+++ b/cSploit/src/org/csploit/android/SettingsActivity.java
@@ -214,14 +214,84 @@ public void onEnd(int exitCode) {
       }
     }
 
+    private boolean isDirectoryEmptyOrWithVersion(File folder) {
+      String[] files = folder.list();
+
+      if(files.length > 0) {
+        for(String fname : files) {
+          if("VERSION".equals(fname)) {
+            return true;
+          }
+        }
+        return false;
+      }
+
+      return true;
+    }
+
+    private ExecChecker getCheckerForKey(String key) {
+      switch (key) {
+        case "RUBY_DIR":
+          return ExecChecker.ruby();
+        case "MSF_DIR":
+          return ExecChecker.msf();
+      }
+      return null;
+    }
+
+    private String getCurrentPathForKey(String key) {
+      switch (key) {
+        case "RUBY_DIR":
+          return System.getRubyPath();
+        case "MSF_DIR":
+          return System.getMsfPath();
+      }
+      return null;
+    }
+
+    private boolean shallAskForDelete(String key) {
+      return key.equals("RUBY_DIR") || key.equals("MSF_DIR");
+    }
+
+    /**
+     * check if selected directory is valid for the given key.
+     * @param key to be updated
+     * @param path of the chosen directory
+     * @return true if {@code path} is valid, false otherwise
+     */
+    private boolean canChangeDirectoryTo(String key, String path) {
+      File folder = new File(path);
+      ExecChecker checker = getCheckerForKey(key);
+      String oldPath = getCurrentPathForKey(key);
+      String toastMessage = null;
+      boolean valid = false;
+      boolean checkEmptyOrVersion = shallAskForDelete(key);
+
+      if (!folder.exists()) {
+        toastMessage = getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_exists);
+      } else if (!folder.canWrite()) {
+        toastMessage = getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_writable);
+      } else if (checker != null && !checker.canExecuteInDir(path)) {
+        toastMessage = getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_executable);
+      } else if (checkEmptyOrVersion && !isDirectoryEmptyOrWithVersion(folder)) {
+        toastMessage = getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_empty_or_old);
+      } else if (oldPath == null || !oldPath.equals(path)) {
+        valid = true;
+      }
+
+      if(toastMessage != null) {
+        Toast.makeText(getContext(), toastMessage, Toast.LENGTH_LONG).show();
+      }
+
+      return valid;
+    }
+
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent intent) {
       if (requestCode == DirectoryPicker.PICK_DIRECTORY && resultCode != RESULT_CANCELED) {
         Bundle extras = intent.getExtras();
         String path;
         String key;
-        File folder;
-        String oldPath = null;
 
         if (extras == null) {
           Logger.debug("null extra: " + intent);
@@ -236,35 +306,18 @@ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
           return;
         }
 
-        folder = new File(path);
-        ExecChecker checker = null;
-
-
-        if (key.equals("RUBY_DIR")) {
-          oldPath = System.getRubyPath();
-          checker = ExecChecker.ruby();
-        } else if (key.equals("MSF_DIR")) {
-          oldPath = System.getMsfPath();
-          checker = ExecChecker.msf();
-        }
-
-        if (!folder.exists())
-          Toast.makeText(getActivity(), getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_exists), Toast.LENGTH_SHORT).show();
-
-        else if (!folder.canWrite())
-          Toast.makeText(getActivity(), getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_writable), Toast.LENGTH_SHORT).show();
+        if(canChangeDirectoryTo(key, path)) {
 
-        else if (checker != null && !checker.canExecuteInDir(path))
-          Toast.makeText(getActivity(), getString(R.string.pref_folder) + " " + path + " " + getString(R.string.pref_err_executable), Toast.LENGTH_LONG).show();
 
-        else {
-          //noinspection ConstantConditions
           getPreferenceManager().getSharedPreferences().edit().putString(key, path).commit();
-          if (oldPath != null && !oldPath.equals(path)) {
-            File current = new File(oldPath);
 
-            if (current.exists() && current.isDirectory() && current.listFiles().length > 2) {
-              wipe_prompt_older(current);
+          if(shallAskForDelete(key)) {
+            String oldPath = getCurrentPathForKey(key);
+            if(oldPath != null) {
+              File current = new File(oldPath);
+              if(current.exists() && current.isDirectory() && current.list().length > 0) {
+                wipe_prompt_older(current);
+              }
             }
           }
         }

From cc505266783be1296c7b9b77d51b8e1fce46c879 Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sat, 16 Jan 2016 08:17:14 +0100
Subject: [PATCH 07/33] version bump

---
 cSploit/build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cSploit/build.gradle b/cSploit/build.gradle
index 5475b4df46..2c5d5117ed 100644
--- a/cSploit/build.gradle
+++ b/cSploit/build.gradle
@@ -52,8 +52,8 @@ android {
     defaultConfig {
         minSdkVersion 9
         targetSdkVersion 22
-        versionCode 5
-        versionName "1.6.4"
+        versionCode 6
+        versionName "1.6.5"
         if(System.getenv("NIGHTLY_BUILD")) {
             versionName += "+" + System.getenv("NIGHTLY_BUILD_COMMIT").substring(0, 7)
         }

From 014b6419599d8687288d35262a1092e0ef75f648 Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sun, 27 Mar 2016 23:49:47 +0200
Subject: [PATCH 08/33] [ExploitFinder] fix #612

---
 cSploit/src/org/csploit/android/net/datasource/Rapid7.java | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/datasource/Rapid7.java b/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
index fe5b1202a4..1c043828cb 100644
--- a/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
+++ b/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
@@ -308,9 +308,11 @@ private void parseSearchResults(String html) {
     private void parseExploit(String html) {
       MsfExploit exploit = ExploitReceiver.parsePage(html);
 
-      exploit.setPort(port);
+      if(exploit != null) {
+        exploit.setPort(port);
 
-      receiver.onItemFound(exploit);
+        receiver.onItemFound(exploit);
+      }
     }
 
     @Override

From 1144ea692f50459c1fbbc66cc6af6813d5a8d43e Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sun, 27 Mar 2016 23:59:17 +0200
Subject: [PATCH 09/33] [ExploitFinder] parsed paged may return null

---
 cSploit/src/org/csploit/android/net/datasource/Rapid7.java | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/cSploit/src/org/csploit/android/net/datasource/Rapid7.java b/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
index 1c043828cb..4562e3b6c5 100644
--- a/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
+++ b/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
@@ -211,6 +211,10 @@ public static void beginFetchReferences(RemoteReader.Job job, Target.Exploit exp
     public void onContentFetched(byte[] content) {
 
       MsfExploit result = parsePage(new String(content));
+
+      if(result == null)
+        return;
+
       result.copyTo(exploit);
 
       receiver.onFoundItemChanged(exploit);

From 1860d4fadd1cdffa83735a009065fc688c643113 Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Wed, 14 Oct 2015 14:22:47 +0200
Subject: [PATCH 10/33] partially fixes #428

---
 cSploit/src/org/csploit/android/MainActivity.java |  1 -
 cSploit/src/org/csploit/android/core/System.java  | 11 ++++++++---
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/cSploit/src/org/csploit/android/MainActivity.java b/cSploit/src/org/csploit/android/MainActivity.java
index 0d1a076b98..19deaf369f 100644
--- a/cSploit/src/org/csploit/android/MainActivity.java
+++ b/cSploit/src/org/csploit/android/MainActivity.java
@@ -612,7 +612,6 @@ public void onInputEntered(String input) {
                         @Override
                         public void run() {
                           System.addOrderedTarget(target);
-                          mTargetAdapter.update(null, null);
                         }
                       });
                     } else
diff --git a/cSploit/src/org/csploit/android/core/System.java b/cSploit/src/org/csploit/android/core/System.java
index 2c144bb62d..028539112c 100644
--- a/cSploit/src/org/csploit/android/core/System.java
+++ b/cSploit/src/org/csploit/android/core/System.java
@@ -1031,16 +1031,21 @@ public static boolean addOrderedTarget(Target target){
         return false;
       }
 
+      boolean inserted = false;
+
       for (int i = 0; i < mTargets.size(); i++) {
         if (mTargets.get(i).comesAfter(target)) {
           mTargets.add(i, target);
-          Services.getNetworkRadar().onNewTargetFound(target);
-          return true;
+          inserted = true;
+          break;
         }
       }
 
-      mTargets.add(target);
+      if(!inserted)
+        mTargets.add(target);
+
       Services.getNetworkRadar().onNewTargetFound(target);
+      notifyTargetListChanged();
       return true;
     }
   }

From cdfd4ead6d48dd818efcc841eb41ea5b3f625438 Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sun, 18 Oct 2015 18:02:40 +0200
Subject: [PATCH 11/33] fixes #429

---
 .../src/org/csploit/android/MainActivity.java |  2 ++
 .../src/org/csploit/android/core/System.java  | 28 ++++++++++++-------
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/cSploit/src/org/csploit/android/MainActivity.java b/cSploit/src/org/csploit/android/MainActivity.java
index 19deaf369f..970eb002d9 100644
--- a/cSploit/src/org/csploit/android/MainActivity.java
+++ b/cSploit/src/org/csploit/android/MainActivity.java
@@ -280,6 +280,8 @@ private void onCoreBeating() {
   }
 
   private void onCoreUpdated() {
+    System.onCoreInstalled();
+
     if (startCore()) {
       onCoreBeating();
     } else if (isRootMissing) {
diff --git a/cSploit/src/org/csploit/android/core/System.java b/cSploit/src/org/csploit/android/core/System.java
index 028539112c..24a91efcef 100644
--- a/cSploit/src/org/csploit/android/core/System.java
+++ b/cSploit/src/org/csploit/android/core/System.java
@@ -195,22 +195,30 @@ public static void init(Context context) throws Exception{
 
       uncaughtReloadNetworkMapping();
 
-      ThreadHelper.getSharedExecutor().execute(new Runnable() {
-        @Override
-        public void run() {
-          preloadServices();
-          preloadVendors();
-        }
-      });
-    }
-    catch(Exception e){
-      if(!(e instanceof NoRouteToHostException))
+      if(isCoreInstalled())
+        beginLoadServicesAndVendors();
+    } catch (Exception e) {
+      if (!(e instanceof NoRouteToHostException))
         errorLogging(e);
 
       throw e;
     }
   }
 
+  private static void beginLoadServicesAndVendors() {
+    ThreadHelper.getSharedExecutor().execute(new Runnable() {
+      @Override
+      public void run() {
+        preloadVendors();
+        preloadServices();
+      }
+    });
+  }
+
+  public static void onCoreInstalled() {
+    beginLoadServicesAndVendors();
+  }
+
   public static void reloadTools() {
     getTools().reload();
   }

From ccda98040ffb518266807114fb5e9aab3e378514 Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sun, 18 Oct 2015 18:19:07 +0200
Subject: [PATCH 12/33] fixes #437

---
 .../src/org/csploit/android/MainActivity.java | 61 ++++++++++++-------
 1 file changed, 39 insertions(+), 22 deletions(-)

diff --git a/cSploit/src/org/csploit/android/MainActivity.java b/cSploit/src/org/csploit/android/MainActivity.java
index 970eb002d9..6d1e400cde 100644
--- a/cSploit/src/org/csploit/android/MainActivity.java
+++ b/cSploit/src/org/csploit/android/MainActivity.java
@@ -888,16 +888,20 @@ public View getView(int position, View convertView, ViewGroup parent) {
     }
 
     public void clearSelection() {
-      for (Target t : list)
-        t.setSelected(false);
+      synchronized (this) {
+        for (Target t : list)
+          t.setSelected(false);
+      }
       notifyDataSetChanged();
       if (mActionMode != null)
         mActionMode.finish();
     }
 
     public void toggleSelection(int position) {
-      Target t = list.get(position);
-      t.setSelected(!t.isSelected());
+      synchronized (this) {
+        Target t = list.get(position);
+        t.setSelected(!t.isSelected());
+      }
       notifyDataSetChanged();
       if (mActionMode != null) {
         if (getSelectedCount() > 0)
@@ -909,27 +913,34 @@ public void toggleSelection(int position) {
 
     public int getSelectedCount() {
       int i = 0;
-      for (Target t : list)
-        if (t.isSelected())
-          i++;
+      synchronized (this) {
+        for (Target t : list)
+          if (t.isSelected())
+            i++;
+      }
       return i;
     }
 
     public ArrayList<Target> getSelected() {
       ArrayList<Target> result = new ArrayList<Target>();
-      for (Target t : list)
-        if (t.isSelected())
-          result.add(t);
+      synchronized (this) {
+        for (Target t : list)
+          if (t.isSelected())
+            result.add(t);
+      }
       return result;
     }
 
     public int[] getSelectedPositions() {
-      int[] res = new int[getSelectedCount()];
+      int[] res;
       int j = 0;
 
-      for (int i = 0; i < list.size(); i++)
-        if (list.get(i).isSelected())
-          res[j++] = i;
+      synchronized (this) {
+        res = new int[getSelectedCount()];
+        for (int i = 0; i < list.size(); i++)
+          if (list.get(i).isSelected())
+            res[j++] = i;
+      }
       return res;
     }
 
@@ -949,13 +960,17 @@ public void update(Observable observable, Object data) {
         public void run() {
           if(lv == null)
             return;
-          int start = lv.getFirstVisiblePosition();
-          for(int i=start, j=lv.getLastVisiblePosition();i<=j;i++)
-            if(target==list.get(i)){
-              View view = lv.getChildAt(i-start);
-              getView(i, view, lv);
-              break;
-            }
+
+          synchronized (this) {
+            int start = lv.getFirstVisiblePosition();
+            int end = Math.min(lv.getLastVisiblePosition(), list.size());
+            for (int i = start; i <= end; i++)
+              if (target == list.get(i)) {
+                View view = lv.getChildAt(i - start);
+                getView(i, view, lv);
+                break;
+              }
+          }
         }
       });
 
@@ -963,7 +978,9 @@ public void run() {
 
     @Override
     public void run() {
-      list = System.getTargets();
+      synchronized (this) {
+        list = System.getTargets();
+      }
       notifyDataSetChanged();
     }
 

From b157c2484fc72a846a71ae8092ac7b1b4ff89f93 Mon Sep 17 00:00:00 2001
From: ga <gainan@users.noreply.github.com>
Date: Fri, 16 Oct 2015 22:14:16 +0200
Subject: [PATCH 13/33] display activity when dumping traffic to a pcap file.

---
 .../csploit/android/plugins/mitm/Sniffer.java | 121 +++++++++++++++---
 1 file changed, 102 insertions(+), 19 deletions(-)

diff --git a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
index 0a3ab1f76b..f5280f93a5 100644
--- a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
+++ b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
+import android.os.FileObserver;
 import android.support.v7.app.AppCompatActivity;
 import android.text.Html;
 import android.view.LayoutInflater;
@@ -50,6 +51,7 @@
 import org.csploit.android.tools.TcpDump;
 
 import java.io.File;
+import java.io.IOException;
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -79,6 +81,7 @@ public class Sniffer extends AppCompatActivity implements AdapterView.OnItemClic
   private boolean mDumpToFile = false;
   private String mPcapFileName = null;
   private Child mTcpdumpProcess = null;
+  private FileObserver mFileActivity = null;
 
   public class AddressStats implements Comparable<AddressStats>{
     public String mAddress = "";
@@ -402,6 +405,14 @@ private void setStoppedState(){
       mTcpdumpProcess.kill();
       mTcpdumpProcess = null;
     }
+
+    if(mDumpToFile) {
+      if (mFileActivity != null) {
+        mFileActivity.stopWatching();
+        mFileActivity = null;
+      }
+    }
+
     Sniffer.this.runOnUiThread(new Runnable() {
       @Override
       public void run() {
@@ -415,6 +426,44 @@ public void run() {
     });
   }
 
+  private void addNewTarget (final AddressStats stats){
+    Sniffer.this.runOnUiThread(new Runnable() {
+      @Override
+      public void run() {
+        mAdapter.addStats(stats);
+        mAdapter.notifyDataSetChanged();
+      }
+    });
+  }
+
+  private void updateStats (final AddressStats stats, final long len){
+    Sniffer.this.runOnUiThread(new Runnable() {
+      @Override
+      public void run() {
+        long deltat;
+        stats.mBytes += len;
+
+        deltat = (java.lang.System.currentTimeMillis() - stats.mSampledTime);
+
+        if (deltat >= mSampleTime) {
+          stats.mBandwidth = (stats.mBytes - stats.mSampledBytes) / deltat;
+          stats.mSampledTime = java.lang.System.currentTimeMillis();
+          stats.mSampledBytes = stats.mBytes;
+        }
+        mAdapter.notifyDataSetChanged();
+      }
+    });
+  }
+
+  private void showMessage (final String text){
+    Sniffer.this.runOnUiThread(new Runnable() {
+      @Override
+      public void run() {
+        Toast.makeText(Sniffer.this, text, Toast.LENGTH_LONG).show();
+      }
+    });
+  }
+
   private void setSpoofErrorState(final String error){
     Sniffer.this.runOnUiThread(new Runnable(){
       @Override
@@ -425,10 +474,59 @@ public void run(){
     });
   }
 
+  /**
+   * Monitor a pcap file for changes, in order to let the user know that the capture is running.
+   */
+  private void startMonitoringPcapFile(){
+    final String str_address = (System.getCurrentTarget().getType() == Target.Type.NETWORK) ? System.getCurrentTarget().getDisplayAddress().split("/")[0] : System.getCurrentTarget().getDisplayAddress();
+
+    final File pcapfile = new File(mPcapFileName);
+    try{
+      pcapfile.createNewFile();
+    }catch(IOException io)
+    {
+      Toast.makeText(this, "File not created: " + io.getLocalizedMessage(), Toast.LENGTH_LONG).show();
+      return;
+    }
+
+    mFileActivity = new FileObserver(mPcapFileName) {
+      @Override
+      public void onEvent(int event, String s) {
+        switch (event){
+          case FileObserver.CLOSE_WRITE:
+            showMessage(getString(R.string.saved) + ":\n" + mPcapFileName);
+            break;
+          case FileObserver.MODIFY:
+
+            AddressStats stats = mAdapter.getStats(str_address);
+            updateStats(stats, pcapfile.length());
+            break;
+          case FileObserver.OPEN:
+            showMessage(getString(R.string.dumping_traffic_to) + mPcapFileName);
+            break;
+          default:
+            break;
+        }
+      }
+    };
+    final AddressStats stats = new AddressStats(str_address);
+    stats.mBytes = 0;
+    stats.mSampledTime = java.lang.System.currentTimeMillis();
+    addNewTarget(stats);
+    // android docs: The monitored file or directory must exist at this time,or else no events will be reported
+    mFileActivity.startWatching();
+  }
+
   private void setStartedState(){
+    if (mRunning)
+      setStoppedState();
 
-    if(mDumpToFile)
-      Toast.makeText(Sniffer.this, getString(R.string.dumping_traffic_to) + mPcapFileName, Toast.LENGTH_SHORT).show();
+    if(mDumpToFile) {
+      mSampleTime = 100;
+      startMonitoringPcapFile();
+    }
+    else
+      mSampleTime = 1000;
 
     try {
       mSpoofSession.start(new OnSessionReadyListener(){
@@ -453,7 +551,6 @@ public void onSessionReady(){
               @Override
               public void onPacket(InetAddress src, InetAddress dst, int len) {
               long now = java.lang.System.currentTimeMillis();
-              long deltat;
               AddressStats stats = null;
               String stringAddress = null;
 
@@ -472,25 +569,11 @@ public void onPacket(InetAddress src, InetAddress dst, int len) {
                 stats.mBytes = len;
                 stats.mSampledTime = now;
               } else {
-                stats.mBytes += len;
-
-                deltat = (now - stats.mSampledTime);
-
-                if (deltat >= mSampleTime) {
-                  stats.mBandwidth = (stats.mBytes - stats.mSampledBytes) / deltat;
-                  stats.mSampledTime = java.lang.System.currentTimeMillis();
-                  stats.mSampledBytes = stats.mBytes;
-                }
+                updateStats(stats, len);
               }
 
               final AddressStats fstats = stats;
-              Sniffer.this.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                  mAdapter.addStats(fstats);
-                  mAdapter.notifyDataSetChanged();
-                }
-              });
+              addNewTarget(fstats);
               }
             });
           } catch( ChildManager.ChildNotStartedException e ) {

From 4339b93fb14460883301ed8058d05448fdb2129a Mon Sep 17 00:00:00 2001
From: fattire <f4ttire@gmail.com>
Date: Fri, 30 Oct 2015 01:34:14 -0700
Subject: [PATCH 14/33] Update gradle to 2.8

---
 gradle/wrapper/gradle-wrapper.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 714c31b24f..5460a5392c 100755
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip

From 70d9a708d7764d21f4953ecc5c5516a3a268f074 Mon Sep 17 00:00:00 2001
From: ga <gainan@users.noreply.github.com>
Date: Fri, 30 Oct 2015 22:49:16 +0100
Subject: [PATCH 15/33] Extract charset encoding from HTTP headers or html
 headers.

workaround for #451 and #50.
---
 .../android/net/http/RequestParser.java       | 44 +++++++++++++++++++
 .../android/net/http/proxy/StreamThread.java  | 26 ++++++++---
 2 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/http/RequestParser.java b/cSploit/src/org/csploit/android/net/http/RequestParser.java
index f189ac0a16..cc4f6bcb0d 100644
--- a/cSploit/src/org/csploit/android/net/http/RequestParser.java
+++ b/cSploit/src/org/csploit/android/net/http/RequestParser.java
@@ -27,6 +27,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 public class RequestParser
 {
@@ -478,4 +480,46 @@ public static ArrayList<HttpCookie> getCookiesFromHeaders(ArrayList<String> head
 
     return null;
   }
+
+  /**
+   * extract the charset encoding from the HTTP response headers.
+   *
+   * @param contentType content-type header to be parsed
+   * @return returns the charset encoding if we've found it, or null.
+   */
+  public static String getCharsetFromHeaders(String contentType){
+    if (contentType != null && contentType.toLowerCase().trim().contains("charset=")){
+      String[] parts = contentType.toLowerCase().trim().split("=");
+      if (parts.length > 0)
+        return parts[1];
+    }
+
+    return null;
+  }
+
+  /**
+   * extract the charset encoding of a web site from the <meta> headers.
+   *
+   * @param body html body of the site to be parsed
+   * @return returns the charset encoding if we've found it, or null.
+   */
+  public static String getCharsetFromBody(String body) {
+    if (body != null) {
+      // match <body>, <body onLoad="">, etc...
+      int headEnd = body.toLowerCase().indexOf("</head>");
+
+      // return null if there's no head tags
+      if (headEnd == -1)
+        return null;
+
+      String body_head = body.toLowerCase().substring(0, headEnd);
+
+      Pattern p = Pattern.compile("charset=([\"a-z0-9A-Z-]+)");
+      Matcher m = p.matcher(body_head);
+      if (m.find())
+        return m.toMatchResult().group(1).replaceAll("\"", "");
+    }
+
+    return null;
+  }
 }
diff --git a/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java b/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java
index 54928d2b94..6370efdfda 100644
--- a/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java
+++ b/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java
@@ -18,16 +18,16 @@
  */
 package org.csploit.android.net.http.proxy;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
+import org.csploit.android.core.Logger;
 import org.csploit.android.core.Profiler;
 import org.csploit.android.core.System;
-import org.csploit.android.core.Logger;
 import org.csploit.android.net.ByteBuffer;
 import org.csploit.android.net.http.RequestParser;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
 public class StreamThread implements Runnable
 {
   private final static String[] FILTERED_CONTENT_TYPES = new String[]
@@ -159,7 +159,21 @@ public void run(){
 
         headers = patched;
 
-        mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes());
+        // try to get the charset encoding from the HTTP headers.
+        String charset = RequestParser.getCharsetFromHeaders(contentType);
+
+        // if we haven't found the charset encoding on the HTTP headers, try it out on the body.
+        if (charset == null) {
+          charset = RequestParser.getCharsetFromBody(body);
+        }
+
+        if (charset != null) {
+          mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes(charset));
+        }
+        else {
+          // if we haven't found the charset encoding, just handle it on ByteBuffer()
+          mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes());
+        }
 
         mWriter.write(mBuffer.getData());
         mWriter.flush();

From e755957ba5388433d9c407aba3ba28c11671ed86 Mon Sep 17 00:00:00 2001
From: ga <gainan@users.noreply.github.com>
Date: Sun, 1 Nov 2015 19:18:18 +0100
Subject: [PATCH 16/33] some websites put the charset encoding names between ''
 characters, so parse them as well.

---
 .../org/csploit/android/net/http/RequestParser.java  | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/http/RequestParser.java b/cSploit/src/org/csploit/android/net/http/RequestParser.java
index cc4f6bcb0d..3e9b2269bf 100644
--- a/cSploit/src/org/csploit/android/net/http/RequestParser.java
+++ b/cSploit/src/org/csploit/android/net/http/RequestParser.java
@@ -505,8 +505,7 @@ public static String getCharsetFromHeaders(String contentType){
    */
   public static String getCharsetFromBody(String body) {
     if (body != null) {
-      // match <body>, <body onLoad="">, etc...
-      int headEnd = body.toLowerCase().indexOf("</head>");
+      int headEnd = body.toLowerCase().trim().indexOf("</head>");
 
       // return null if there's no head tags
       if (headEnd == -1)
@@ -514,10 +513,13 @@ public static String getCharsetFromBody(String body) {
 
       String body_head = body.toLowerCase().substring(0, headEnd);
 
-      Pattern p = Pattern.compile("charset=([\"a-z0-9A-Z-]+)");
+      Pattern p = Pattern.compile("charset=([\"\'a-z0-9A-Z-]+)");
       Matcher m = p.matcher(body_head);
-      if (m.find())
-        return m.toMatchResult().group(1).replaceAll("\"", "");
+      String str_match = "";
+      if (m.find()) {
+        str_match = m.toMatchResult().group(1);
+        return str_match.replaceAll("[\"']", "");
+      }
     }
 
     return null;

From 81a014b794882561ea761721a4d3ba50614b7755 Mon Sep 17 00:00:00 2001
From: ga <gainan@users.noreply.github.com>
Date: Wed, 4 Nov 2015 14:07:43 +0100
Subject: [PATCH 17/33] if we get a not valid charset, send the request with
 the default charset encoding.

---
 .../org/csploit/android/net/http/proxy/StreamThread.java | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java b/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java
index 6370efdfda..918b0a9963 100644
--- a/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java
+++ b/cSploit/src/org/csploit/android/net/http/proxy/StreamThread.java
@@ -27,6 +27,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
 
 public class StreamThread implements Runnable
 {
@@ -168,7 +169,13 @@ public void run(){
         }
 
         if (charset != null) {
-          mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes(charset));
+          try {
+            mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes(charset));
+          }
+          catch (UnsupportedEncodingException e){
+            Logger.error("UnsupportedEncoding: " + e.getLocalizedMessage());
+            mBuffer.setData((headers + HEAD_SEPARATOR + body).getBytes());
+          }
         }
         else {
           // if we haven't found the charset encoding, just handle it on ByteBuffer()

From 7d983d552ec28e94ddb9b31e3e2db147177c3b58 Mon Sep 17 00:00:00 2001
From: ga <gainan@users.noreply.github.com>
Date: Sun, 1 Nov 2015 19:25:29 +0100
Subject: [PATCH 18/33] parse TopLevelDomains correctly.

put out of the loop the check for adding dots to the domain.

fixes #21.
---
 .../org/csploit/android/net/http/RequestParser.java  | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/http/RequestParser.java b/cSploit/src/org/csploit/android/net/http/RequestParser.java
index 3e9b2269bf..29132e28bc 100644
--- a/cSploit/src/org/csploit/android/net/http/RequestParser.java
+++ b/cSploit/src/org/csploit/android/net/http/RequestParser.java
@@ -302,15 +302,17 @@ public static String getBaseDomain(String hostname){
           tld_parts = tld.split("\\.");
         int itld = tld_parts.length,
           ihost = host_parts.length,
-          i = 0,
-          stop = ihost - 1;
+          i = 0;
+
+        if ((ihost - itld) == 0)
+          return hostname;
 
         domain = "";
-        for(i = ihost - itld; i <= stop; i++){
-          domain += host_parts[i] + (i == stop ? "" : ".");
+        for(i = ihost - itld - 1; i < ihost; i++){
+          domain += host_parts[i] + ".";
         }
 
-        return domain;
+        return domain.substring(0, domain.length() - 1);
       }
     }
 

From 319d148ee4a036480dc60b387b9fdd4520a8f984 Mon Sep 17 00:00:00 2001
From: ga <gainan@users.noreply.github.com>
Date: Fri, 6 Nov 2015 00:35:31 +0100
Subject: [PATCH 19/33] parse TopLevelDomains better. reorder TLD domains, to
 put simple domains (.us) at the end of the compounded domains of the same
 type (.com.us)

---
 .../android/net/http/RequestParser.java       | 212 +++++++++---------
 1 file changed, 106 insertions(+), 106 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/http/RequestParser.java b/cSploit/src/org/csploit/android/net/http/RequestParser.java
index 29132e28bc..f710c1038b 100644
--- a/cSploit/src/org/csploit/android/net/http/RequestParser.java
+++ b/cSploit/src/org/csploit/android/net/http/RequestParser.java
@@ -47,30 +47,30 @@ public class RequestParser
   private static final String[] TLD =
     {
       ".com.ac", ".edu.ac", ".gov.ac",
-      ".net.ac", ".mil.ac", ".org.ac", ".ad", ".nom.ad", ".ae",
+      ".net.ac", ".mil.ac", ".org.ac", ".nom.ad", ".ad",
       ".net.ae", ".gov.ae", ".org.ae", ".mil.ae", ".sch.ae", ".ac.ae",
-      ".pro.ae", ".name.ae", ".aero", ".af", ".gov.af", ".edu.af",
-      ".net.af", ".com.af", ".ag", ".com.ag", ".org.ag", ".net.ag",
-      ".co.ag", ".nom.ag", ".ai", ".off.ai", ".com.ai", ".net.ai",
-      ".org.ai", ".gov.al", ".edu.al", ".org.al", ".com.al", ".net.al",
-      ".tirana.al", ".soros.al", ".upt.al", ".am", ".an", ".com.an",
-      ".net.an", ".org.an", ".edu.an", ".co.ao", ".ed.ao", ".gv.ao",
+      ".pro.ae", ".name.ae", ".ae", ".aero", ".gov.af", ".edu.af",
+      ".net.af", ".com.af", ".af", ".com.ag", ".org.ag", ".net.ag",
+      ".co.ag", ".nom.ag", ".ag", ".off.ai", ".com.ai", ".net.ai",
+      ".org.ai", ".ai", ".gov.al", ".edu.al", ".org.al", ".com.al", ".net.al",
+      ".tirana.al", ".soros.al", ".upt.al", ".am", ".com.an",
+      ".net.an", ".org.an", ".edu.an", ".an", ".co.ao", ".ed.ao", ".gv.ao",
       ".it.ao", ".og.ao", ".pb.ao", ".com.ar", ".gov.ar", ".int.ar",
       ".mil.ar", ".net.ar", ".org.ar", ".iris.arpa", ".uri.arpa",
-      ".urn.arpa", ".as", ".at", ".gv.at", ".ac.at", ".co.at", ".or.at",
-      ".priv.at", ".asn.au", ".com.au", ".net.au", ".id.au", ".org.au",
+      ".urn.arpa", ".as", ".gv.at", ".ac.at", ".co.at", ".or.at",
+      ".priv.at", ".at", ".asn.au", ".com.au", ".net.au", ".id.au", ".org.au",
       ".csiro.au", ".oz.au", ".info.au", ".conf.au", ".act.au",
       ".nsw.au", ".nt.au", ".qld.au", ".sa.au", ".tas.au", ".vic.au",
       ".wa.auFor", ".gov.au", ".and", ".act", ".nsw", ".nt", ".qld",
-      ".sa", ".tas", ".vic", ".wa", ".aw", ".com.aw", ".ax", ".az",
+      ".sa", ".tas", ".vic", ".wa", ".com.aw", ".aw", ".ax",
       ".com.az", ".net.az", ".int.az", ".gov.az", ".biz.az", ".org.az",
-      ".edu.az", ".mil.az", ".pp.az", ".name.az", ".info.az", ".com.bb",
+      ".edu.az", ".mil.az", ".pp.az", ".name.az", ".info.az", ".az", ".com.bb",
       ".edu.bb", ".gov.bb", ".net.bb", ".org.bb", ".com.bd", ".edu.bd",
       ".net.bd", ".gov.bd", ".org.bd", ".mil.bd", ".ac.be", ".gov.bf",
       ".possibly", ".com.bm", ".edu.bm", ".org.bm", ".gov.bm", ".net.bm",
-      ".com.bn", ".edu.bn", ".org.bn", ".net.bn", ".bo", ".com.bo",
+      ".com.bn", ".edu.bn", ".org.bn", ".net.bn", ".com.bo",
       ".org.bo", ".net.bo", ".gov.bo", ".gob.bo", ".edu.bo", ".tv.bo",
-      ".mil.bo", ".int.bo", ".agr.br", ".am.br", ".art.br", ".edu.br",
+      ".mil.bo", ".int.bo", ".bo", ".agr.br", ".am.br", ".art.br", ".edu.br",
       ".com.br", ".coop.br", ".esp.br", ".far.br", ".fm.br", ".gov.br",
       ".imb.br", ".ind.br", ".inf.br", ".mil.br", ".net.br", ".org.br",
       ".psi.br", ".rec.br", ".srv.br", ".tmp.br", ".tur.br", ".tv.br",
@@ -79,71 +79,71 @@ public class RequestParser
       ".eti.br", ".fnd.br", ".fot.br", ".fst.br", ".ggf.br", ".jor.br",
       ".lel.br", ".mat.br", ".med.br", ".mus.br", ".not.br", ".ntr.br",
       ".odo.br", ".ppg.br", ".pro.br", ".psc.br", ".qsl.br", ".slg.br",
-      ".trd.br", ".vet.br", ".zlg.br", ".dpn.br", ".nom.br", ".bs",
-      ".com.bs", ".net.bs", ".org.bs", ".bt", ".com.bt", ".edu.bt",
-      ".gov.bt", ".net.bt", ".org.bt", ".bw", ".co.bw", ".org.bw",
-      ".gov.by", ".mil.by", ".ca", ".ab.ca", ".bc.ca", ".mb.ca",
+      ".trd.br", ".vet.br", ".zlg.br", ".dpn.br", ".nom.br",
+      ".com.bs", ".net.bs", ".org.bs", ".bs", ".com.bt", ".edu.bt",
+      ".gov.bt", ".net.bt", ".org.bt", ".bt", ".co.bw", ".org.bw", ".bw",
+      ".gov.by", ".mil.by", ".ab.ca", ".bc.ca", ".mb.ca",
       ".nb.ca", ".nf.ca", ".nl.ca", ".ns.ca", ".nt.ca", ".nu.ca",
-      ".on.ca", ".pe.ca", ".qc.ca", ".sk.ca", ".yk.ca", ".cc", ".co.cc",
-      ".cd", ".com.cd", ".net.cd", ".org.cd", ".ch", ".com.ch",
-      ".net.ch", ".org.ch", ".gov.ch", ".co.ck", ".others", ".cn",
+      ".on.ca", ".pe.ca", ".qc.ca", ".sk.ca", ".yk.ca", ".ca", ".co.cc", ".cc",
+      ".com.cd", ".net.cd", ".org.cd", ".cd", ".com.ch",
+      ".net.ch", ".org.ch", ".gov.ch", ".ch", ".co.ck", ".others",
       ".ac.cn", ".com.cn", ".edu.cn", ".gov.cn", ".net.cn", ".org.cn",
       ".ah.cn", ".bj.cn", ".cq.cn", ".fj.cn", ".gd.cn", ".gs.cn",
       ".gz.cn", ".gx.cn", ".ha.cn", ".hb.cn", ".he.cn", ".hi.cn",
       ".hl.cn", ".hn.cn", ".jl.cn", ".js.cn", ".jx.cn", ".ln.cn",
       ".nm.cn", ".nx.cn", ".qh.cn", ".sc.cn", ".sd.cn", ".sh.cn",
       ".sn.cn", ".sx.cn", ".tj.cn", ".xj.cn", ".xz.cn", ".yn.cn",
-      ".zj.cn", ".com.co", ".edu.co", ".org.co", ".gov.co", ".mil.co",
+      ".zj.cn", ".cn", ".com.co", ".edu.co", ".org.co", ".gov.co", ".mil.co",
       ".net.co", ".nom.co", ".ac.cr", ".co.cr", ".ed.cr", ".fi.cr",
-      ".go.cr", ".or.cr", ".sa.cr", ".cu", ".com.cu", ".edu.cu",
-      ".org.cu", ".net.cu", ".gov.cu", ".inf.cu", ".cx", ".gov.cx",
+      ".go.cr", ".or.cr", ".sa.cr", ".com.cu", ".edu.cu",
+      ".org.cu", ".net.cu", ".gov.cu", ".inf.cu", ".cu", ".gov.cx", ".cx",
       ".com.cy", ".biz.cy", ".info.cy", ".ltd.cy", ".pro.cy", ".net.cy",
       ".org.cy", ".name.cy", ".tm.cy", ".ac.cy", ".ekloges.cy",
-      ".press.cy", ".parliament.cy", ".dm", ".com.dm", ".net.dm",
-      ".org.dm", ".edu.dm", ".gov.dm", ".edu.do", ".gov.do", ".gob.do",
+      ".press.cy", ".parliament.cy", ".com.dm", ".net.dm",
+      ".org.dm", ".edu.dm", ".gov.dm", ".dm", ".edu.do", ".gov.do", ".gob.do",
       ".com.do", ".org.do", ".sld.do", ".web.do", ".net.do", ".mil.do",
-      ".art.do", ".dz", ".com.dz", ".org.dz", ".net.dz", ".gov.dz",
-      ".edu.dz", ".asso.dz", ".pol.dz", ".art.dz", ".ec", ".com.ec",
+      ".art.do", ".com.dz", ".org.dz", ".net.dz", ".gov.dz",
+      ".edu.dz", ".asso.dz", ".pol.dz", ".art.dz", ".dz", ".com.ec",
       ".info.ec", ".net.ec", ".fin.ec", ".med.ec", ".pro.ec", ".org.ec",
-      ".edu.ec", ".gov.ec", ".mil.ec", ".ee", ".com.ee", ".org.ee",
-      ".fie.ee", ".pri.ee", ".eun.eg", ".edu.eg", ".sci.eg", ".gov.eg",
-      ".com.eg", ".org.eg", ".net.eg", ".mil.eg", ".es", ".com.es",
-      ".nom.es", ".org.es", ".gob.es", ".edu.es", ".com.et", ".gov.et",
+      ".edu.ec", ".gov.ec", ".mil.ec", ".ec",".com.ee", ".org.ee",
+      ".fie.ee", ".pri.ee", ".ee", ".eun.eg", ".edu.eg", ".sci.eg", ".gov.eg",
+      ".com.eg", ".org.eg", ".net.eg", ".mil.eg", ".com.es",
+      ".nom.es", ".org.es", ".gob.es", ".edu.es", ".es", ".com.et", ".gov.et",
       ".org.et", ".edu.et", ".net.et", ".biz.et", ".name.et", ".info.et",
-      ".fi", ".aland.fi", ".biz.fj", ".com.fj", ".info.fj", ".name.fj",
+      ".aland.fi", ".fi", ".biz.fj", ".com.fj", ".info.fj", ".name.fj",
       ".net.fj", ".org.fj", ".pro.fj", ".ac.fj", ".gov.fj", ".mil.fj",
       ".school.fj", ".co.fk", ".org.fk", ".gov.fk", ".ac.fk", ".nom.fk",
-      ".net.fk", ".fr", ".tm.fr", ".asso.fr", ".nom.fr", ".prd.fr",
-      ".presse.fr", ".com.fr", ".gouv.fr", ".ge", ".com.ge", ".edu.ge",
-      ".gov.ge", ".org.ge", ".mil.ge", ".net.ge", ".pvt.ge", ".gg",
-      ".co.gg", ".net.gg", ".org.gg", ".com.gh", ".edu.gh", ".gov.gh",
-      ".org.gh", ".mil.gh", ".gi", ".com.gi", ".ltd.gi", ".gov.gi",
+      ".net.fk", ".tm.fr", ".asso.fr", ".nom.fr", ".prd.fr",
+      ".presse.fr", ".com.fr", ".gouv.fr", ".fr", ".com.ge", ".edu.ge",
+      ".gov.ge", ".org.ge", ".mil.ge", ".net.ge", ".pvt.ge", ".ge",
+      ".co.gg", ".net.gg", ".org.gg", ".gg", ".com.gh", ".edu.gh", ".gov.gh",
+      ".org.gh", ".mil.gh", ".gh", ".com.gi", ".ltd.gi", ".gov.gi",
       ".mod.gi", ".edu.gi", ".org.gi", ".com.gn", ".ac.gn", ".gov.gn",
-      ".org.gn", ".net.gn", ".gp", ".or", ".org.gp", ".gr", ".com.gr",
-      ".edu.gr", ".net.gr", ".org.gr", ".gov.gr", ".hk", ".com.hk",
-      ".edu.hk", ".gov.hk", ".idv.hk", ".net.hk", ".org.hk", ".hn",
+      ".org.gn", ".net.gn", ".gn", ".or", ".org.gp", ".gp", ".com.gr",
+      ".edu.gr", ".net.gr", ".org.gr", ".gov.gr", ".gr", ".com.hk",
+      ".edu.hk", ".gov.hk", ".idv.hk", ".net.hk", ".org.hk", ".hk",
       ".com.hn", ".edu.hn", ".org.hn", ".net.hn", ".mil.hn", ".gob.hn",
-      ".hr", ".iz.hr", ".from.hr", ".name.hr", ".com.hr", ".ht",
+      ".hn", ".iz.hr", ".from.hr", ".name.hr", ".com.hr", ".hr",
       ".com.ht", ".net.ht", ".firm.ht", ".shop.ht", ".info.ht",
       ".pro.ht", ".adult.ht", ".org.ht", ".art.ht", ".pol.ht", ".rel.ht",
       ".asso.ht", ".perso.ht", ".coop.ht", ".med.ht", ".edu.ht",
-      ".gouv.ht", ".hu", ".co.hu", ".info.hu", ".org.hu", ".priv.hu",
+      ".gouv.ht", ".ht", ".co.hu", ".info.hu", ".org.hu", ".priv.hu",
       ".sport.hu", ".tm.hu", ".agrar.hu", ".bolt.hu", ".casino.hu",
       ".city.hu", ".erotica.hu", ".erotika.hu", ".film.hu", ".forum.hu",
       ".games.hu", ".hotel.hu", ".ingatlan.hu", ".jogasz.hu",
       ".konyvelo.hu", ".lakas.hu", ".media.hu", ".news.hu", ".reklam.hu",
       ".sex.hu", ".shop.hu", ".suli.hu", ".szex.hu", ".tozsde.hu",
-      ".utazas.hu", ".video.hu", ".ac.id", ".co.id", ".or.id", ".go.id",
-      ".ie", ".gov.ie", ".ac.il", ".co.il", ".org.il", ".net.il",
+      ".utazas.hu", ".video.hu", ".hu", ".ac.id", ".co.id", ".or.id", ".go.id",
+      ".gov.ie", ".ie", ".ac.il", ".co.il", ".org.il", ".net.il",
       ".gov.il", ".muni.il", ".idf.il", ".co.im", ".ltd.co.im",
       ".plc.co.im", ".net.im", ".gov.im", ".org.im", ".nic.im", ".ac.im",
-      ".in", ".co.in", ".firm.in", ".net.in", ".org.in", ".gen.in",
+      ".co.in", ".firm.in", ".net.in", ".org.in", ".gen.in",
       ".ind.in", ".nic.in", ".ac.in", ".edu.in", ".res.in", ".gov.in",
-      ".mil.in", ".ir", ".ac.ir", ".co.ir", ".gov.ir", ".net.ir",
-      ".org.ir", ".sch.ir", ".it", ".gov.it", "...", ".je", ".co.je",
-      ".net.je", ".org.je", ".edu.jm", ".gov.jm", ".com.jm", ".net.jm",
-      ".org.jm", ".jo", ".com.jo", ".org.jo", ".net.jo", ".edu.jo",
-      ".gov.jo", ".mil.jo", ".jp", ".ac.jp", ".ad.jp", ".co.jp",
+      ".mil.in", ".in", ".ac.ir", ".co.ir", ".gov.ir", ".net.ir",
+      ".org.ir", ".sch.ir", ".ir", ".gov.it", ".it", ".co.je",
+      ".net.je", ".org.je", ".je", ".edu.jm", ".gov.jm", ".com.jm", ".net.jm",
+      ".org.jm", ".com.jo", ".org.jo", ".net.jo", ".edu.jo",
+      ".gov.jo", ".mil.jo", ".jo", ".ac.jp", ".ad.jp", ".co.jp",
       ".ed.jp", ".go.jp", ".gr.jp", ".lg.jp", ".ne.jp", ".hokkaido.jp",
       ".aomori.jp", ".iwate.jp", ".miyagi.jp", ".akita.jp",
       ".yamagata.jp", ".fukushima.jp", ".ibaraki.jp", ".tochigi.jp",
@@ -157,30 +157,30 @@ public class RequestParser
       ".kochi.jp", ".fukuoka.jp", ".saga.jp", ".nagasaki.jp",
       ".kumamoto.jp", ".oita.jp", ".miyazaki.jp", ".kagoshima.jp",
       ".okinawa.jp", ".sapporo.jp", ".sendai.jp", ".yokohama.jp",
-      ".kawasaki.jp", ".nagoya.jp", ".kobe.jp", ".kitakyushu.jp",
+      ".kawasaki.jp", ".nagoya.jp", ".kobe.jp", ".kitakyushu.jp", ".jp",
       ".per.kh", ".com.kh", ".edu.kh", ".gov.kh", ".mil.kh", ".net.kh",
-      ".org.kh", ".kr", ".co.kr", ".or.kr", ".com.kw", ".edu.kw",
-      ".gov.kw", ".net.kw", ".org.kw", ".mil.kw", ".ky", ".edu.ky",
-      ".gov.ky", ".com.ky", ".org.ky", ".net.ky", ".org.kz", ".edu.kz",
+      ".org.kh", ".co.kr", ".or.kr", ".kr", ".com.kw", ".edu.kw",
+      ".gov.kw", ".net.kw", ".org.kw", ".mil.kw", ".edu.ky",
+      ".gov.ky", ".com.ky", ".org.ky", ".net.ky", ".ky", ".org.kz", ".edu.kz",
       ".net.kz", ".gov.kz", ".mil.kz", ".com.kz", ".net.lb", ".org.lb",
       ".gov.lb", ".edu.lb", ".com.lb", ".com.lc", ".org.lc", ".edu.lc",
-      ".gov.lc", ".li", ".com.li", ".net.li", ".org.li", ".gov.li",
-      ".lk", ".gov.lk", ".sch.lk", ".net.lk", ".int.lk", ".com.lk",
+      ".gov.lc", ".com.li", ".net.li", ".org.li", ".gov.li", ".li",
+      ".gov.lk", ".sch.lk", ".net.lk", ".int.lk", ".com.lk",
       ".org.lk", ".edu.lk", ".ngo.lk", ".soc.lk", ".web.lk", ".ltd.lk",
-      ".assn.lk", ".grp.lk", ".hotel.lk", ".com.lr", ".edu.lr",
-      ".gov.lr", ".org.lr", ".net.lr", ".org.ls", ".co.ls", ".lt",
-      ".gov.lt", ".mil.lt", ".lu", ".gov.lu", ".mil.lu", ".org.lu",
-      ".net.lu", ".lv", ".com.lv", ".edu.lv", ".gov.lv", ".org.lv",
-      ".mil.lv", ".id.lv", ".net.lv", ".asn.lv", ".conf.lv", ".ly",
+      ".assn.lk", ".grp.lk", ".hotel.lk", ".lk", ".com.lr", ".edu.lr",
+      ".gov.lr", ".org.lr", ".net.lr", ".org.ls", ".co.ls",
+      ".gov.lt", ".mil.lt", ".lt", ".gov.lu", ".mil.lu", ".org.lu",
+      ".net.lu", ".lu", ".com.lv", ".edu.lv", ".gov.lv", ".org.lv",
+      ".mil.lv", ".id.lv", ".net.lv", ".asn.lv", ".conf.lv", ".lv",
       ".com.ly", ".net.ly", ".gov.ly", ".plc.ly", ".edu.ly", ".sch.ly",
-      ".med.ly", ".org.ly", ".id.ly", ".ma", ".co.ma", ".net.ma",
-      ".gov.ma", ".org.ma", ".mc", ".tm.mc", ".asso.mc", ".mg",
+      ".med.ly", ".org.ly", ".id.ly", ".ly", ".co.ma", ".net.ma",
+      ".gov.ma", ".org.ma", ".ma", ".tm.mc", ".asso.mc", ".mc",
       ".org.mg", ".nom.mg", ".gov.mg", ".prd.mg", ".tm.mg", ".com.mg",
-      ".edu.mg", ".mil.mg", ".army.mil", ".navy.mil", ".mk", ".com.mk",
-      ".org.mk", ".mo", ".com.mo", ".net.mo", ".org.mo", ".edu.mo",
-      ".gov.mo", ".weather.mobi", ".music.mobi", ".mt", ".org.mt",
-      ".com.mt", ".gov.mt", ".edu.mt", ".net.mt", ".mu", ".com.mu",
-      ".co.mu", ".aero.mv", ".biz.mv", ".com.mv", ".coop.mv", ".edu.mv",
+      ".edu.mg", ".mil.mg", ".mg", ".army.mil", ".navy.mil", ".com.mk",
+      ".org.mk", ".mk", ".com.mo", ".net.mo", ".org.mo", ".edu.mo",
+      ".gov.mo", ".mo", ".weather.mobi", ".music.mobi", ".org.mt",
+      ".com.mt", ".gov.mt", ".edu.mt", ".net.mt", ".mt", ".com.mu",
+      ".co.mu", ".mu", ".aero.mv", ".biz.mv", ".com.mv", ".coop.mv", ".edu.mv",
       ".gov.mv", ".info.mv", ".int.mv", ".mil.mv", ".museum.mv",
       ".name.mv", ".net.mv", ".org.mv", ".pro.mv", ".ac.mw", ".co.mw",
       ".com.mw", ".coop.mw", ".edu.mw", ".gov.mw", ".int.mw",
@@ -188,12 +188,12 @@ public class RequestParser
       ".org.mx", ".edu.mx", ".gob.mx", ".com.my", ".net.my", ".org.my",
       ".gov.my", ".edu.my", ".mil.my", ".name.my", ".edu.ng", ".com.ng",
       ".gov.ng", ".org.ng", ".net.ng", ".gob.ni", ".com.ni", ".edu.ni",
-      ".org.ni", ".nom.ni", ".net.ni", ".nl", ".no", ".mil.no",
+      ".org.ni", ".nom.ni", ".net.ni", ".nl", ".mil.no",
       ".stat.no", ".kommune.no", ".herad.no", ".priv.no", ".vgs.no",
       ".fhs.no", ".museum.no", ".fylkesbibl.no", ".folkebibl.no",
-      ".idrett.no", ".com.np", ".org.np", ".edu.np", ".net.np",
-      ".gov.np", ".mil.np", ".nr", ".gov.nr", ".edu.nr", ".biz.nr",
-      ".info.nr", ".org.nr", ".com.nr", ".net.nr", ".ac.nz", ".co.nz",
+      ".idrett.no", ".no", ".com.np", ".org.np", ".edu.np", ".net.np",
+      ".gov.np", ".mil.np", ".gov.nr", ".edu.nr", ".biz.nr",
+      ".info.nr", ".org.nr", ".com.nr", ".net.nr", ".nr", ".ac.nz", ".co.nz",
       ".cri.nz", ".gen.nz", ".geek.nz", ".govt.nz", ".iwi.nz",
       ".maori.nz", ".mil.nz", ".net.nz", ".org.nz", ".school.nz",
       ".com.om", ".co.om", ".edu.om", ".ac.com", ".sch.om", ".gov.om",
@@ -201,55 +201,55 @@ public class RequestParser
       ".pro.om", ".med.om", ".com.pa", ".ac.pa", ".sld.pa", ".gob.pa",
       ".edu.pa", ".org.pa", ".net.pa", ".abo.pa", ".ing.pa", ".med.pa",
       ".nom.pa", ".com.pe", ".org.pe", ".net.pe", ".edu.pe", ".mil.pe",
-      ".gob.pe", ".nom.pe", ".pf", ".com.pf", ".org.pf", ".edu.pf",
-      ".com.pg", ".net.pg", ".ph", ".com.ph", ".gov.ph", ".pk",
+      ".gob.pe", ".nom.pe", ".com.pf", ".org.pf", ".edu.pf", ".pf",
+      ".com.pg", ".net.pg", ".com.ph", ".gov.ph", ".ph",
       ".com.pk", ".net.pk", ".edu.pk", ".org.pk", ".fam.pk", ".biz.pk",
       ".web.pk", ".gov.pk", ".gob.pk", ".gok.pk", ".gon.pk", ".gop.pk",
-      ".gos.pk", ".pl", ".com.pl", ".biz.pl", ".net.pl", ".art.pl",
+      ".gos.pk", ".pk", ".com.pl", ".biz.pl", ".net.pl", ".art.pl",
       ".edu.pl", ".org.pl", ".ngo.pl", ".gov.pl", ".info.pl", ".mil.pl",
       ".waw.pl", ".warszawa.pl", ".wroc.pl", ".wroclaw.pl", ".krakow.pl",
       ".poznan.pl", ".lodz.pl", ".gda.pl", ".gdansk.pl", ".slupsk.pl",
       ".szczecin.pl", ".lublin.pl", ".bialystok.pl",
-      ".olsztyn.pl.torun.pl", ".more...", ".pr", ".biz.pr", ".com.pr",
+      ".olsztyn.pl.torun.pl", ".pl", ".biz.pr", ".com.pr",
       ".edu.pr", ".gov.pr", ".info.pr", ".isla.pr", ".name.pr",
-      ".net.pr", ".org.pr", ".pro.pr", ".law.pro", ".med.pro",
-      ".cpa.pro", ".ps", ".edu.ps", ".gov.ps", ".sec.ps", ".plo.ps",
-      ".com.ps", ".org.ps", ".net.ps", ".pt", ".com.pt", ".edu.pt",
-      ".gov.pt", ".int.pt", ".net.pt", ".nome.pt", ".org.pt", ".publ.pt",
-      ".net.py", ".org.py", ".gov.py", ".edu.py", ".com.py", ".ro",
+      ".net.pr", ".org.pr", ".pro.pr", ".pr", ".law.pro", ".med.pro",
+      ".cpa.pro", ".edu.ps", ".gov.ps", ".sec.ps", ".plo.ps",
+      ".com.ps", ".org.ps", ".net.ps", ".ps", ".com.pt", ".edu.pt",
+      ".gov.pt", ".int.pt", ".net.pt", ".nome.pt", ".org.pt", ".publ.pt", ".pt",
+      ".net.py", ".org.py", ".gov.py", ".edu.py", ".com.py",
       ".com.ro", ".org.ro", ".tm.ro", ".nt.ro", ".nom.ro", ".info.ro",
-      ".rec.ro", ".arts.ro", ".firm.ro", ".store.ro", ".www.ro", ".ru",
+      ".rec.ro", ".arts.ro", ".firm.ro", ".store.ro", ".www.ro", ".ro",
       ".com.ru", ".net.ru", ".org.ru", ".pp.ru", ".msk.ru", ".int.ru",
-      ".ac.ru", ".rw", ".gov.rw", ".net.rw", ".edu.rw", ".ac.rw",
-      ".com.rw", ".co.rw", ".int.rw", ".mil.rw", ".gouv.rw", ".com.sa",
+      ".ac.ru", ".ru", ".gov.rw", ".net.rw", ".edu.rw", ".ac.rw",
+      ".com.rw", ".co.rw", ".int.rw", ".mil.rw", ".gouv.rw", ".rw", ".com.sa",
       ".edu.sa", ".sch.sa", ".med.sa", ".gov.sa", ".net.sa", ".org.sa",
-      ".pub.sa", ".com.sb", ".gov.sb", ".net.sb", ".edu.sb", ".sc",
-      ".com.sc", ".gov.sc", ".net.sc", ".org.sc", ".edu.sc", ".sd",
+      ".pub.sa", ".com.sb", ".gov.sb", ".net.sb", ".edu.sb",
+      ".com.sc", ".gov.sc", ".net.sc", ".org.sc", ".edu.sc", ".sc",
       ".com.sd", ".net.sd", ".org.sd", ".edu.sd", ".med.sd", ".tv.sd",
-      ".gov.sd", ".info.sd", ".se", ".org.se", ".pp.se", ".tm.se",
+      ".gov.sd", ".info.sd", ".sd", ".org.se", ".pp.se", ".tm.se",
       ".brand.se", ".parti.se", ".press.se", ".komforb.se",
       ".kommunalforbund.se", ".komvux.se", ".lanarb.se", ".lanbib.se",
       ".naturbruksgymn.se", ".sshn.se", ".fhv.se", ".fhsk.se", ".fh.se",
       ".ab.se", ".c.se", ".d.se", ".e.se", ".f.se", ".g.se", ".h.se",
       ".i.se", ".k.se", ".m.se", ".n.se", ".o.se", ".s.se", ".t.se",
-      ".u.se", ".w.se", ".x.se", ".y.se", ".z.se", ".ac.se", ".bd.se",
-      ".sg", ".com.sg", ".net.sg", ".org.sg", ".gov.sg", ".edu.sg",
-      ".per.sg", ".idn.sg", ".edu.sv", ".com.sv", ".gob.sv", ".org.sv",
+      ".u.se", ".w.se", ".x.se", ".y.se", ".z.se", ".ac.se", ".bd.se", ".se",
+      ".com.sg", ".net.sg", ".org.sg", ".gov.sg", ".edu.sg",
+      ".per.sg", ".idn.sg", ".sg", ".edu.sv", ".com.sv", ".gob.sv", ".org.sv",
       ".red.sv", ".gov.sy", ".com.sy", ".net.sy", ".ac.th", ".co.th",
-      ".in.th", ".go.th", ".mi.th", ".or.th", ".net.th", ".tj", ".ac.tj",
+      ".in.th", ".go.th", ".mi.th", ".or.th", ".net.th", ".ac.tj",
       ".biz.tj", ".com.tj", ".co.tj", ".edu.tj", ".int.tj", ".name.tj",
-      ".net.tj", ".org.tj", ".web.tj", ".gov.tj", ".go.tj", ".mil.tj",
+      ".net.tj", ".org.tj", ".web.tj", ".gov.tj", ".go.tj", ".mil.tj", ".tj",
       ".com.tn", ".intl.tn", ".gov.tn", ".org.tn", ".ind.tn", ".nat.tn",
       ".tourism.tn", ".info.tn", ".ens.tn", ".fin.tn", ".net.tn", ".to",
-      ".gov.to", ".tp", ".gov.tp", ".com.tr", ".info.tr", ".biz.tr",
+      ".gov.to", ".gov.tp", ".tp", ".com.tr", ".info.tr", ".biz.tr",
       ".net.tr", ".org.tr", ".web.tr", ".gen.tr", ".av.tr", ".dr.tr",
       ".bbs.tr", ".name.tr", ".tel.tr", ".gov.tr", ".bel.tr", ".pol.tr",
-      ".mil.tr", ".edu.tr", ".tt", ".co.tt", ".com.tt", ".org.tt",
+      ".mil.tr", ".edu.tr", ".co.tt", ".com.tt", ".org.tt",
       ".net.tt", ".biz.tt", ".info.tt", ".pro.tt", ".name.tt", ".edu.tt",
-      ".gov.tt", ".tv", ".gov.tv", ".tw", ".edu.tw", ".gov.tw",
+      ".gov.tt", ".tt", ".gov.tv", ".tv", ".edu.tw", ".gov.tw",
       ".mil.tw", ".com.tw", ".net.tw", ".org.tw", ".idv.tw", ".game.tw",
-      ".ebiz.tw", ".club.tw", ".co.tz", ".ac.tz", ".go.tz", ".or.tz",
-      ".ne.tz", ".ua", ".com.ua", ".gov.ua", ".net.ua", ".edu.ua",
+      ".ebiz.tw", ".club.tw", ".tw", ".co.tz", ".ac.tz", ".go.tz", ".or.tz",
+      ".ne.tz", ".com.ua", ".gov.ua", ".net.ua", ".edu.ua",
       ".org.uaGeographical", ".cherkassy.ua", ".ck.ua", ".chernigov.ua",
       ".cn.ua", ".chernovtsy.ua", ".cv.ua", ".crimea.ua",
       ".dnepropetrovsk.ua", ".dp.ua", ".donetsk.ua", ".dn.ua", ".if.ua",
@@ -260,12 +260,12 @@ public class RequestParser
       ".poltava.ua", ".pl.ua", ".rovno.ua", ".rv.ua", ".sebastopol.ua",
       ".sumy.ua", ".ternopil.ua", ".te.ua", ".uzhgorod.ua",
       ".vinnica.ua", ".vn.ua", ".zaporizhzhe.ua", ".zp.ua",
-      ".zhitomir.ua", ".zt.ua", ".ug", ".co.ug", ".ac.ug", ".sc.ug",
-      ".go.ug", ".ne.ug", ".or.ug", ".ac.uk", ".co.uk", ".gov.uk",
+      ".zhitomir.ua", ".zt.ua", ".ua", ".co.ug", ".ac.ug", ".sc.ug",
+      ".go.ug", ".ne.ug", ".or.ug", ".ug", ".ac.uk", ".co.uk", ".gov.uk",
       ".ltd.uk", ".me.uk", ".mil.uk", ".mod.uk", ".net.uk", ".nic.uk",
       ".nhs.uk", ".org.uk", ".plc.uk", ".police.uk", ".bl.uk",
       ".icnet.uk", ".jet.uk", ".nel.uk", ".nls.uk",
-      ".parliament.uk.sch.uk", ".uses", ".level", ".domains", ".us",
+      ".parliament.uk.sch.uk", ".uses", ".level", ".domains",
       ".ak.us", ".al.us", ".ar.us", ".az.us", ".ca.us", ".co.us",
       ".ct.us", ".dc.us", ".de.us", ".dni.us", ".fed.us", ".fl.us",
       ".ga.us", ".hi.us", ".ia.us", ".id.us", ".il.us", ".in.us",
@@ -275,12 +275,12 @@ public class RequestParser
       ".nm.us", ".nsn.us", ".nv.us", ".ny.us", ".oh.us", ".ok.us",
       ".or.us", ".pa.us", ".ri.us", ".sc.us", ".sd.us", ".tn.us",
       ".tx.us", ".ut.us", ".vt.us", ".va.us", ".wa.us", ".wi.us",
-      ".wv.us", ".wy.us", ".edu.uy", ".gub.uy", ".org.uy", ".com.uy",
+      ".wv.us", ".wy.us", ".us", ".edu.uy", ".gub.uy", ".org.uy", ".com.uy",
       ".net.uy", ".mil.uy", ".vatican.va", ".com.ve", ".net.ve",
-      ".org.ve", ".info.ve", ".co.ve", ".web.ve", ".vi", ".com.vi",
-      ".org.vi", ".edu.vi", ".gov.vi", ".vn", ".com.vn", ".net.vn",
+      ".org.ve", ".info.ve", ".co.ve", ".web.ve", ".com.vi",
+      ".org.vi", ".edu.vi", ".gov.vi", ".vi", ".com.vn", ".net.vn",
       ".org.vn", ".edu.vn", ".gov.vn", ".int.vn", ".ac.vn", ".biz.vn",
-      ".info.vn", ".name.vn", ".pro.vn", ".health.vn", ".com.ye",
+      ".info.vn", ".name.vn", ".pro.vn", ".health.vn", ".vn", ".com.ye",
       ".net.ye", ".ac.yu", ".co.yu", ".org.yu", ".edu.yu", ".ac.za",
       ".city.za", ".co.za", ".edu.za", ".gov.za", ".law.za", ".mil.za",
       ".nom.za", ".org.za", ".school.za", ".alt.za", ".net.za",
@@ -304,11 +304,11 @@ public static String getBaseDomain(String hostname){
           ihost = host_parts.length,
           i = 0;
 
-        if ((ihost - itld) == 0)
+        if ((ihost - itld) == 0 || ihost == 2)
           return hostname;
 
         domain = "";
-        for(i = ihost - itld - 1; i < ihost; i++){
+        for(i = ihost - itld; i < ihost; i++){
           domain += host_parts[i] + ".";
         }
 

From 9c996cb92d4f371b89667898f05cb3a96d9040c8 Mon Sep 17 00:00:00 2001
From: ga <gainan@users.noreply.github.com>
Date: Tue, 10 Nov 2015 16:09:09 +0100
Subject: [PATCH 20/33] TLD array updated with latest domains from
 www.publicsuffix.org

added a simple cache for already resolved TLDs.
---
 .../android/net/http/RequestParser.java       | 14 ++++++--
 .../android/net/http/proxy/DNSCache.java      | 33 +++++++++++++++++--
 2 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/http/RequestParser.java b/cSploit/src/org/csploit/android/net/http/RequestParser.java
index f710c1038b..86f04837d9 100644
--- a/cSploit/src/org/csploit/android/net/http/RequestParser.java
+++ b/cSploit/src/org/csploit/android/net/http/RequestParser.java
@@ -22,6 +22,7 @@
 
 import org.csploit.android.core.Logger;
 import org.csploit.android.net.ByteBuffer;
+import org.csploit.android.net.http.proxy.DNSCache;
 
 import java.net.HttpCookie;
 import java.util.ArrayList;
@@ -296,6 +297,11 @@ public static String getBaseDomain(String hostname){
     if(Patterns.IP_ADDRESS.matcher(hostname).matches())
       return hostname;
 
+    String cached_domain = DNSCache.getInstance().getCachedRootDomain(hostname);
+    if (cached_domain != null) {
+      return cached_domain;
+    }
+
     for(String tld : TLD){
       if(hostname.endsWith(tld)){
         String[] host_parts = hostname.split("\\."),
@@ -312,6 +318,7 @@ public static String getBaseDomain(String hostname){
           domain += host_parts[i] + ".";
         }
 
+        DNSCache.getInstance().addCachedRootDomain(domain.substring(0, domain.length() - 1));
         return domain.substring(0, domain.length() - 1);
       }
     }
@@ -320,14 +327,15 @@ public static String getBaseDomain(String hostname){
       nextIndex = hostname.indexOf('.'),
       lastIndex = hostname.lastIndexOf('.');
 
-    while(nextIndex < lastIndex){
+    while(nextIndex < lastIndex) {
       startIndex = nextIndex + 1;
       nextIndex = hostname.indexOf('.', startIndex);
     }
 
-    if(startIndex > 0)
+    if(startIndex > 0) {
+      DNSCache.getInstance().addCachedRootDomain(hostname.substring(startIndex));
       return hostname.substring(startIndex);
-
+    }
     else
       return hostname;
   }
diff --git a/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java b/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
index b8f474e264..1f3419f2ba 100644
--- a/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
+++ b/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
@@ -18,20 +18,22 @@
  */
 package org.csploit.android.net.http.proxy;
 
+import org.csploit.android.core.Logger;
+
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.Socket;
+import java.util.ArrayList;
 import java.util.HashMap;
 
 import javax.net.SocketFactory;
 
-import org.csploit.android.core.Logger;
-
 public class DNSCache
 {
   private static DNSCache mInstance = null;
 
   private HashMap<String, InetAddress> mCache = null;
+  private ArrayList<String> mCachedRootDomain = null;
 
   public static DNSCache getInstance(){
     if(mInstance == null)
@@ -42,6 +44,33 @@ public static DNSCache getInstance(){
 
   public DNSCache(){
     mCache = new HashMap<String, InetAddress>();
+    mCachedRootDomain = new ArrayList<String>();
+  }
+
+  /**
+   * checks if a domain ends with an already intercepted root domain.
+   *
+   * @param hostname hostname to check
+   * @return String the root domain or null
+   */
+  public String getCachedRootDomain (String hostname){
+    for (String rootDomain : mCachedRootDomain){
+      if (hostname.endsWith(rootDomain)){
+        return rootDomain;
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Adds a root domain extracted from the domain of a request,
+   * to the list of intercepted root domains.
+   *
+   * @param rootdomain Root domain to add to the list
+   */
+  public void addCachedRootDomain (String rootdomain){
+    mCachedRootDomain.add(rootdomain);
   }
 
   private InetAddress getAddress(String server) throws IOException{

From f3f3c9532fefe0f87eec74fefed7de0f66247923 Mon Sep 17 00:00:00 2001
From: ga <gainan@users.noreply.github.com>
Date: Wed, 11 Nov 2015 17:45:46 +0100
Subject: [PATCH 21/33] put the items: network, gateway and our own device, on
 top of the hosts list.

---
 cSploit/src/org/csploit/android/core/System.java | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/cSploit/src/org/csploit/android/core/System.java b/cSploit/src/org/csploit/android/core/System.java
index 24a91efcef..88fdb5c27e 100644
--- a/cSploit/src/org/csploit/android/core/System.java
+++ b/cSploit/src/org/csploit/android/core/System.java
@@ -1041,7 +1041,9 @@ public static boolean addOrderedTarget(Target target){
 
       boolean inserted = false;
 
-      for (int i = 0; i < mTargets.size(); i++) {
+      int start_idx = 3;
+      if(!mNetwork.haveGateway()) start_idx = 2;
+      for (int i = start_idx; i < mTargets.size(); i++) {
         if (mTargets.get(i).comesAfter(target)) {
           mTargets.add(i, target);
           inserted = true;

From a7d2bec87d35afe3e3c8092d966dc45cdb888b5e Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Thu, 19 Nov 2015 17:52:27 +0100
Subject: [PATCH 22/33] use Comparable interface to sort our targets. also use
 a TreeSet to store them.

---
 .../src/org/csploit/android/core/System.java  | 62 +++++--------------
 .../android/helpers/NetworkHelper.java        | 33 ++++++++++
 .../src/org/csploit/android/net/Endpoint.java | 22 ++++---
 .../org/csploit/android/net/IP4Address.java   |  9 ++-
 .../src/org/csploit/android/net/Network.java  | 11 +++-
 .../src/org/csploit/android/net/Target.java   | 34 ++++++++--
 6 files changed, 112 insertions(+), 59 deletions(-)

diff --git a/cSploit/src/org/csploit/android/core/System.java b/cSploit/src/org/csploit/android/core/System.java
index 88fdb5c27e..a5b320aabb 100644
--- a/cSploit/src/org/csploit/android/core/System.java
+++ b/cSploit/src/org/csploit/android/core/System.java
@@ -87,6 +87,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Observer;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.zip.GZIPInputStream;
@@ -111,7 +113,7 @@ public class System
   private static WifiLock mWifiLock = null;
   private static WakeLock mWakeLock = null;
   private static Network mNetwork = null;
-  private static final List<Target> mTargets = new ArrayList<>();
+  private static final SortedSet<Target> mTargets = new TreeSet<>();
   private static Target mCurrentTarget = null;
   private static Map<String, String> mServices = null;
   private static Map<String, String> mPorts = null;
@@ -824,20 +826,11 @@ public static void loadSession(String filename) throws Exception{
 
         // read targets
         int targets = Integer.parseInt(reader.readLine());
-        for(int i = 0; i < targets; i++){
-          Target target = new Target(reader);
-
-          if(!hasTarget(target)){
-            System.addOrderedTarget(target);
-          } else{
-            synchronized (mTargets) {
-              for (int j = 0; j < mTargets.size(); j++) {
-                if (mTargets.get(j) != null && mTargets.get(j).equals(target)) {
-                  mTargets.set(j, target);
-                  break;
-                }
-              }
-            }
+
+        synchronized (mTargets) {
+          for (int i = 0; i < targets; i++) {
+            Target target = new Target(reader);
+            mTargets.add(target);
           }
         }
 
@@ -1034,30 +1027,16 @@ public static boolean addOrderedTarget(Target target){
     if(target == null)
       return false;
 
-    synchronized (mTargets) {
-      if(mTargets.contains(target)) {
-        return false;
-      }
-
-      boolean inserted = false;
+    boolean changed;
 
-      int start_idx = 3;
-      if(!mNetwork.haveGateway()) start_idx = 2;
-      for (int i = start_idx; i < mTargets.size(); i++) {
-        if (mTargets.get(i).comesAfter(target)) {
-          mTargets.add(i, target);
-          inserted = true;
-          break;
-        }
+    synchronized (mTargets) {
+      changed = mTargets.add(target);
+      if(changed) {
+        Services.getNetworkRadar().onNewTargetFound(target);
+        notifyTargetListChanged();
       }
-
-      if(!inserted)
-        mTargets.add(target);
-
-      Services.getNetworkRadar().onNewTargetFound(target);
-      notifyTargetListChanged();
-      return true;
     }
+    return changed;
   }
 
   public static boolean hasTarget(Target target){
@@ -1084,16 +1063,9 @@ public static Target getTargetByAddress(String address){
   }
 
   public static Target getTargetByAddress(InetAddress address) {
-    int i, size;
-
     synchronized (mTargets) {
-
-      size = mTargets.size();
-
-      for(i=0;i<size;i++) {
-        Target t = mTargets.get(i);
-
-        if(t != null && t.getAddress() != null && t.getAddress().equals(address)) {
+      for(Target t : mTargets) {
+        if (t != null && t.getAddress() != null && t.getAddress().equals(address)) {
           return t;
         }
       }
diff --git a/cSploit/src/org/csploit/android/helpers/NetworkHelper.java b/cSploit/src/org/csploit/android/helpers/NetworkHelper.java
index 11c8ab981f..71ef9d5735 100644
--- a/cSploit/src/org/csploit/android/helpers/NetworkHelper.java
+++ b/cSploit/src/org/csploit/android/helpers/NetworkHelper.java
@@ -1,5 +1,7 @@
 package org.csploit.android.helpers;
 
+import java.net.InetAddress;
+
 /**
  * A class that provide some useful network-related static methods
  */
@@ -21,4 +23,35 @@ public static int getOUICode(byte[] macAddress) {
   public static int getOUICode(String hexOui) {
     return Integer.parseInt(hexOui, 16);
   }
+
+  /**
+   * compare two byte[] comparing their length and each of their values.
+   * @return -1 if {@code a} is less than {@code b}, 0 if are equals, +1 if {@code a} is greater than {@code b}
+   */
+  public static int compareByteArray(byte[] a, byte[] b) {
+    int result;
+
+    result = a.length - b.length;
+
+    if(result != 0) {
+      return result;
+    }
+
+    for(int i = 0; i < a.length; i++) {
+      result = ((short) a[i] & 0xFF) - ((short) b[i] & 0xFF);
+      if(result != 0) {
+        return result;
+      }
+    }
+
+    return 0;
+  }
+
+  /**
+   * compare two {@link InetAddress}
+   * @return -1 if {@code a} is less than {@code b}, 0 if are equals, +1 if {@code a} is greater than {@code b}
+   */
+  public static int compareInetAddresses(InetAddress a, InetAddress b) {
+    return compareByteArray(a.getAddress(), b.getAddress());
+  }
 }
diff --git a/cSploit/src/org/csploit/android/net/Endpoint.java b/cSploit/src/org/csploit/android/net/Endpoint.java
index 27be5e0304..1e26e30334 100644
--- a/cSploit/src/org/csploit/android/net/Endpoint.java
+++ b/cSploit/src/org/csploit/android/net/Endpoint.java
@@ -18,14 +18,17 @@
  */
 package org.csploit.android.net;
 
+import android.support.annotation.NonNull;
+
 import java.io.BufferedReader;
 import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 
 import org.csploit.android.core.System;
+import org.csploit.android.helpers.NetworkHelper;
 
-public class Endpoint
+public class Endpoint implements Comparable<Endpoint>
 {
   private InetAddress mAddress = null;
   private byte[] mHardware = null;
@@ -99,14 +102,19 @@ else if(mHardware != null && endpoint.mHardware != null) {
       return mAddress.equals(endpoint.getAddress());
   }
 
-  public InetAddress getAddress(){
-    return mAddress;
-  }
+  @Override
+  public int compareTo(@NonNull Endpoint another) {
+    if(mHardware != null && another.mHardware != null) {
+      if(NetworkHelper.compareByteArray(mHardware, another.mHardware) == 0) {
+        return 0;
+      }
+    }
 
-  public long getAddressAsLong(){
-    byte[] baddr = mAddress.getAddress();
+    return NetworkHelper.compareInetAddresses(mAddress, another.mAddress);
+  }
 
-    return ((baddr[0] & 0xFFl) << 24) + ((baddr[1] & 0xFFl) << 16) + ((baddr[2] & 0xFFl) << 8) + (baddr[3] & 0xFFl);
+  public InetAddress getAddress(){
+    return mAddress;
   }
 
   public void setAddress(InetAddress address){
diff --git a/cSploit/src/org/csploit/android/net/IP4Address.java b/cSploit/src/org/csploit/android/net/IP4Address.java
index 8186028895..71f2f4dfb9 100644
--- a/cSploit/src/org/csploit/android/net/IP4Address.java
+++ b/cSploit/src/org/csploit/android/net/IP4Address.java
@@ -23,11 +23,11 @@
 import java.net.UnknownHostException;
 import java.nio.ByteOrder;
 
-public class IP4Address
+public class IP4Address implements Comparable<IP4Address>
 {
   private byte[] mByteArray = null;
   private String mString = "";
-  private int mInteger = 0;
+  private final int mInteger;
   private InetAddress mAddress = null;
 
   public static int ntohl(int n){
@@ -125,6 +125,11 @@ public boolean equals(InetAddress address){
     return mAddress.equals(address);
   }
 
+  @Override
+  public int compareTo(IP4Address another) {
+    return mInteger - another.mInteger;
+  }
+
   public int getPrefixLength(){
     int bits, i, n = mInteger;
 
diff --git a/cSploit/src/org/csploit/android/net/Network.java b/cSploit/src/org/csploit/android/net/Network.java
index 971948a1db..9d64cbc577 100644
--- a/cSploit/src/org/csploit/android/net/Network.java
+++ b/cSploit/src/org/csploit/android/net/Network.java
@@ -24,6 +24,7 @@
 import android.net.NetworkInfo;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.support.annotation.NonNull;
 
 import org.apache.commons.net.util.SubnetUtils;
 
@@ -36,7 +37,7 @@
 import org.csploit.android.core.Logger;
 import org.csploit.android.core.System;
 
-public class Network
+public class Network implements Comparable<Network>
 {
   public enum Protocol{
     TCP,
@@ -265,4 +266,12 @@ public InetAddress getLocalAddress(){
   public NetworkInterface getInterface(){
     return mInterface;
   }
+
+  @Override
+  public int compareTo(@NonNull Network another) {
+    if(mBase.equals(another.mBase)) {
+      return mNetmask.getPrefixLength() - another.mNetmask.getPrefixLength();
+    }
+    return mBase.compareTo(another.mBase);
+  }
 }
diff --git a/cSploit/src/org/csploit/android/net/Target.java b/cSploit/src/org/csploit/android/net/Target.java
index 6b20888b38..63f17df623 100644
--- a/cSploit/src/org/csploit/android/net/Target.java
+++ b/cSploit/src/org/csploit/android/net/Target.java
@@ -19,6 +19,7 @@
 package org.csploit.android.net;
 
 import android.os.StrictMode;
+import android.support.annotation.NonNull;
 
 import org.csploit.android.R;
 import org.csploit.android.core.Logger;
@@ -39,7 +40,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class Target
+public class Target implements Comparable<Target>
 {
 
   public enum Type{
@@ -440,8 +441,34 @@ public boolean hasAlias(){
     return mAlias != null && !mAlias.isEmpty();
   }
 
-  public boolean comesAfter(Target target){
-    return mType != Type.NETWORK && (mType != Type.ENDPOINT || target.getType() == Type.ENDPOINT && mEndpoint.getAddressAsLong() > target.getEndpoint().getAddressAsLong());
+  @Override
+  public int compareTo(@NonNull Target another) {
+    if(mType != another.mType) {
+      if(mType == Type.NETWORK) {
+        return -1;
+      } else if (mType == Type.REMOTE) {
+        return +1;
+      } else if (another.mType == Type.NETWORK){
+        return +1;
+      } else { // another is REMOTE
+        return -1;
+      }
+    }
+    if(mType == Type.NETWORK) {
+      return mNetwork.compareTo(another.mNetwork);
+    } else if(mType == Type.REMOTE){
+      return mHostname.compareTo(another.mHostname);
+    } else {
+      try {
+        if (mEndpoint.getAddress().equals(System.getNetwork().getGatewayAddress()))
+          return -1;
+        else if (mEndpoint.getAddress().equals(System.getNetwork().getLocalAddress()))
+          return +1;
+      } catch (Exception e) {
+        System.errorLogging(e);
+      }
+      return mEndpoint.compareTo(another.mEndpoint);
+    }
   }
 
   public Target(Network net){
@@ -483,7 +510,6 @@ else if(mType == Type.REMOTE)
         return mHostname.equals(target.getHostname());
     }
 
-
     return false;
   }
 

From b986abe5ef51c32cd818a852f99612e23c3305aa Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Thu, 19 Nov 2015 14:02:02 +0100
Subject: [PATCH 23/33] improved singleton pattern

---
 .../org/csploit/android/net/http/proxy/DNSCache.java  | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java b/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
index 1f3419f2ba..f46dd77abc 100644
--- a/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
+++ b/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
@@ -30,21 +30,18 @@
 
 public class DNSCache
 {
-  private static DNSCache mInstance = null;
+  private static DNSCache mInstance = new DNSCache();
 
   private HashMap<String, InetAddress> mCache = null;
   private ArrayList<String> mCachedRootDomain = null;
 
   public static DNSCache getInstance(){
-    if(mInstance == null)
-      mInstance = new DNSCache();
-
     return mInstance;
   }
 
-  public DNSCache(){
-    mCache = new HashMap<String, InetAddress>();
-    mCachedRootDomain = new ArrayList<String>();
+  private DNSCache() {
+    mCache = new HashMap<>();
+    mCachedRootDomain = new ArrayList<>();
   }
 
   /**

From fa3f672c899d1b8453e9e63a25c801b1dda7590f Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Thu, 19 Nov 2015 14:07:17 +0100
Subject: [PATCH 24/33] make cache thread safe. changed names a while.

---
 .../android/net/http/RequestParser.java       |  6 ++---
 .../android/net/http/proxy/DNSCache.java      | 22 +++++++++++--------
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/http/RequestParser.java b/cSploit/src/org/csploit/android/net/http/RequestParser.java
index 86f04837d9..3950015e7b 100644
--- a/cSploit/src/org/csploit/android/net/http/RequestParser.java
+++ b/cSploit/src/org/csploit/android/net/http/RequestParser.java
@@ -297,7 +297,7 @@ public static String getBaseDomain(String hostname){
     if(Patterns.IP_ADDRESS.matcher(hostname).matches())
       return hostname;
 
-    String cached_domain = DNSCache.getInstance().getCachedRootDomain(hostname);
+    String cached_domain = DNSCache.getInstance().getRootDomain(hostname);
     if (cached_domain != null) {
       return cached_domain;
     }
@@ -318,7 +318,7 @@ public static String getBaseDomain(String hostname){
           domain += host_parts[i] + ".";
         }
 
-        DNSCache.getInstance().addCachedRootDomain(domain.substring(0, domain.length() - 1));
+        DNSCache.getInstance().addRootDomain(domain.substring(0, domain.length() - 1));
         return domain.substring(0, domain.length() - 1);
       }
     }
@@ -333,7 +333,7 @@ public static String getBaseDomain(String hostname){
     }
 
     if(startIndex > 0) {
-      DNSCache.getInstance().addCachedRootDomain(hostname.substring(startIndex));
+      DNSCache.getInstance().addRootDomain(hostname.substring(startIndex));
       return hostname.substring(startIndex);
     }
     else
diff --git a/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java b/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
index f46dd77abc..3303ae0f5d 100644
--- a/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
+++ b/cSploit/src/org/csploit/android/net/http/proxy/DNSCache.java
@@ -32,8 +32,8 @@ public class DNSCache
 {
   private static DNSCache mInstance = new DNSCache();
 
-  private HashMap<String, InetAddress> mCache = null;
-  private ArrayList<String> mCachedRootDomain = null;
+  private final HashMap<String, InetAddress> mCache;
+  private final ArrayList<String> mRootDomainCache;
 
   public static DNSCache getInstance(){
     return mInstance;
@@ -41,7 +41,7 @@ public static DNSCache getInstance(){
 
   private DNSCache() {
     mCache = new HashMap<>();
-    mCachedRootDomain = new ArrayList<>();
+    mRootDomainCache = new ArrayList<>();
   }
 
   /**
@@ -50,10 +50,12 @@ private DNSCache() {
    * @param hostname hostname to check
    * @return String the root domain or null
    */
-  public String getCachedRootDomain (String hostname){
-    for (String rootDomain : mCachedRootDomain){
-      if (hostname.endsWith(rootDomain)){
-        return rootDomain;
+  public String getRootDomain(String hostname){
+    synchronized (mRootDomainCache) {
+      for (String rootDomain : mRootDomainCache) {
+        if (hostname.endsWith(rootDomain)) {
+          return rootDomain;
+        }
       }
     }
 
@@ -66,8 +68,10 @@ public String getCachedRootDomain (String hostname){
    *
    * @param rootdomain Root domain to add to the list
    */
-  public void addCachedRootDomain (String rootdomain){
-    mCachedRootDomain.add(rootdomain);
+  public void addRootDomain(String rootdomain){
+    synchronized (mRootDomainCache) {
+      mRootDomainCache.add(rootdomain);
+    }
   }
 
   private InetAddress getAddress(String server) throws IOException{

From 96de421a0d732acc5a339476ab8839a156e8bca2 Mon Sep 17 00:00:00 2001
From: tux_mind <massimo.dragano@gmail.com>
Date: Thu, 19 Nov 2015 15:32:39 +0100
Subject: [PATCH 25/33] little speed up

---
 .../csploit/android/net/http/RequestParser.java  | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/http/RequestParser.java b/cSploit/src/org/csploit/android/net/http/RequestParser.java
index 3950015e7b..47775edd7f 100644
--- a/cSploit/src/org/csploit/android/net/http/RequestParser.java
+++ b/cSploit/src/org/csploit/android/net/http/RequestParser.java
@@ -291,8 +291,6 @@ public class RequestParser
 
 
   public static String getBaseDomain(String hostname){
-    String domain = "";
-
     // if hostname is an IP address return that address
     if(Patterns.IP_ADDRESS.matcher(hostname).matches())
       return hostname;
@@ -313,13 +311,19 @@ public static String getBaseDomain(String hostname){
         if ((ihost - itld) == 0 || ihost == 2)
           return hostname;
 
-        domain = "";
+        StringBuilder sb = new StringBuilder();
+
         for(i = ihost - itld; i < ihost; i++){
-          domain += host_parts[i] + ".";
+          sb.append(host_parts[i]);
+          if(i < ihost - 1) {
+            sb.append(".");
+          }
         }
 
-        DNSCache.getInstance().addRootDomain(domain.substring(0, domain.length() - 1));
-        return domain.substring(0, domain.length() - 1);
+        String domain = sb.toString();
+
+        DNSCache.getInstance().addRootDomain(domain);
+        return domain;
       }
     }
 

From e4a12c878d0adb277a5c8dbc2836c6e2835e8841 Mon Sep 17 00:00:00 2001
From: fattire <f4ttire@gmail.com>
Date: Thu, 19 Nov 2015 16:10:54 -0800
Subject: [PATCH 26/33] update libraries, gradle, gradle plugin

---
 cSploit/build.gradle                     | 10 +++++-----
 gradle/wrapper/gradle-wrapper.properties |  4 ++--
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/cSploit/build.gradle b/cSploit/build.gradle
index 2c5d5117ed..bd29df0c17 100644
--- a/cSploit/build.gradle
+++ b/cSploit/build.gradle
@@ -21,10 +21,10 @@ allprojects {
 apply plugin:  'com.android.application'
 
 dependencies {
-    compile 'com.android.support:support-v4:23.0.1'
-    compile 'com.android.support:appcompat-v7:23.0.1'
-    compile 'com.android.support:design:23.0.1'
-    compile 'com.android.support:preference-v7:23.0.1'
+    compile 'com.android.support:support-v4:23.1.1'
+    compile 'com.android.support:appcompat-v7:23.1.1'
+    compile 'com.android.support:design:23.1.1'
+    compile 'com.android.support:preference-v7:23.1.1'
     compile 'org.apache.commons:commons-compress:1.10'
     compile 'commons-net:commons-net:3.3'
     compile 'com.github.zafarkhaja:java-semver:0.9.0'
@@ -37,7 +37,7 @@ dependencies {
 
 android {
     compileSdkVersion 23
-    buildToolsVersion '23.0.1'
+    buildToolsVersion '23.0.2'
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_7
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 5460a5392c..4b8a3c2dae 100755
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Thu Sep 24 21:38:44 PDT 2015
+#Thu Nov 19 16:09:54 PST 2015
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-all.zip

From 662cbd353b62b9fbd986f7b91b05fed36a03370d Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Mon, 28 Mar 2016 21:26:26 +0200
Subject: [PATCH 27/33] version bump

---
 cSploit/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cSploit/build.gradle b/cSploit/build.gradle
index bd29df0c17..becadf91f2 100644
--- a/cSploit/build.gradle
+++ b/cSploit/build.gradle
@@ -53,7 +53,7 @@ android {
         minSdkVersion 9
         targetSdkVersion 22
         versionCode 6
-        versionName "1.6.5"
+        versionName "1.6.6-rc.1"
         if(System.getenv("NIGHTLY_BUILD")) {
             versionName += "+" + System.getenv("NIGHTLY_BUILD_COMMIT").substring(0, 7)
         }

From 469a57437ae1b9bbaeea01a7b62507d2832cae39 Mon Sep 17 00:00:00 2001
From: Silur <asd@asd.asd>
Date: Sat, 2 Apr 2016 01:50:27 +0200
Subject: [PATCH 28/33] pcap storage permission fix

---
 .../csploit/android/plugins/mitm/Sniffer.java | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
index f5280f93a5..f877613c10 100644
--- a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
+++ b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
@@ -50,8 +50,7 @@
 import org.csploit.android.plugins.mitm.SpoofSession.OnSessionReadyListener;
 import org.csploit.android.tools.TcpDump;
 
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -337,7 +336,7 @@ public void onClick(View v){
       @Override
       public void onConfirm(){
         mDumpToFile = true;
-        mPcapFileName = (new File(System.getStoragePath(), "csploit-sniff-" + java.lang.System.currentTimeMillis() + ".pcap")).getAbsolutePath();
+        mPcapFileName = (new File(Sniffer.this.getCacheDir(), "csploit-sniff-" + java.lang.System.currentTimeMillis() + ".pcap")).getAbsolutePath();
       }
 
       @Override
@@ -410,6 +409,20 @@ private void setStoppedState(){
       if (mFileActivity != null) {
         mFileActivity.stopWatching();
         mFileActivity = null;
+        //copy pcap file from cache to storage
+          try {
+              InputStream in = new FileInputStream(mPcapFileName);
+              OutputStream out = new FileOutputStream(new File(System.getStoragePath(),new File(mPcapFileName).getName()));
+              byte[] buf = new byte[1024];
+              int len;
+              while ((len = in.read(buf)) > 0) {
+                  out.write(buf, 0, len);
+              }
+              in.close();
+              out.close();
+          } catch (IOException e) {
+              e.printStackTrace();
+          }
       }
     }
 

From 47714a988ae44217e16378527087d70445d8baea Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Wed, 6 Apr 2016 10:57:21 +0200
Subject: [PATCH 29/33] [Sniffer] use IOUtils for deal with cached files.

use IOUtils from apache commons to move
pcap file from cache to storage.

I've also exported those small piece of code into a separate function.
---
 .../csploit/android/plugins/mitm/Sniffer.java | 34 +++++++++++--------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
index f877613c10..5cdcee6142 100644
--- a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
+++ b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
@@ -39,10 +39,12 @@
 import android.widget.Toast;
 import android.widget.ToggleButton;
 
+import org.apache.commons.compress.utils.IOUtils;
 import org.csploit.android.ActionActivity;
 import org.csploit.android.R;
 import org.csploit.android.core.Child;
 import org.csploit.android.core.ChildManager;
+import org.csploit.android.core.Logger;
 import org.csploit.android.core.System;
 import org.csploit.android.gui.dialogs.ConfirmDialog;
 import org.csploit.android.gui.dialogs.ErrorDialog;
@@ -399,6 +401,23 @@ public boolean onOptionsItemSelected(MenuItem item){
     }
   }
 
+  private void movePcapFileFromCacheToStorage()
+  {
+    InputStream in = null;
+    OutputStream out = null;
+
+    try {
+      in = new FileInputStream(mPcapFileName);
+      out = new FileOutputStream(new File(System.getStoragePath(),new File(mPcapFileName).getName()));
+      IOUtils.copy(in, out);
+    } catch (IOException e) {
+      System.errorLogging(e);
+    } finally {
+      IOUtils.closeQuietly(in);
+      IOUtils.closeQuietly(out);
+    }
+  }
+
   private void setStoppedState(){
     if(mTcpdumpProcess != null) {
       mTcpdumpProcess.kill();
@@ -409,20 +428,7 @@ private void setStoppedState(){
       if (mFileActivity != null) {
         mFileActivity.stopWatching();
         mFileActivity = null;
-        //copy pcap file from cache to storage
-          try {
-              InputStream in = new FileInputStream(mPcapFileName);
-              OutputStream out = new FileOutputStream(new File(System.getStoragePath(),new File(mPcapFileName).getName()));
-              byte[] buf = new byte[1024];
-              int len;
-              while ((len = in.read(buf)) > 0) {
-                  out.write(buf, 0, len);
-              }
-              in.close();
-              out.close();
-          } catch (IOException e) {
-              e.printStackTrace();
-          }
+        movePcapFileFromCacheToStorage();
       }
     }
 

From 388d6cf5c3847fd0a1a8064da16c5ed254695aef Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Wed, 6 Apr 2016 11:07:48 +0200
Subject: [PATCH 30/33] [Sniffer] moving a file implies it's removal...

---
 cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
index 5cdcee6142..3599384249 100644
--- a/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
+++ b/cSploit/src/org/csploit/android/plugins/mitm/Sniffer.java
@@ -401,13 +401,13 @@ public boolean onOptionsItemSelected(MenuItem item){
     }
   }
 
-  private void movePcapFileFromCacheToStorage()
-  {
+  private void movePcapFileFromCacheToStorage() {
+    File inputFile = new File(mPcapFileName);
     InputStream in = null;
     OutputStream out = null;
 
     try {
-      in = new FileInputStream(mPcapFileName);
+      in = new FileInputStream(inputFile);
       out = new FileOutputStream(new File(System.getStoragePath(),new File(mPcapFileName).getName()));
       IOUtils.copy(in, out);
     } catch (IOException e) {
@@ -415,6 +415,7 @@ private void movePcapFileFromCacheToStorage()
     } finally {
       IOUtils.closeQuietly(in);
       IOUtils.closeQuietly(out);
+      inputFile.delete();
     }
   }
 

From 41d6e3a3dbf80879bf4d074fb9c9e018cbe63aa5 Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sat, 18 Jun 2016 02:07:00 +0200
Subject: [PATCH 31/33] [ExploitFinder] Rapid7 now force to HTTPS.

---
 cSploit/src/org/csploit/android/net/datasource/Rapid7.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cSploit/src/org/csploit/android/net/datasource/Rapid7.java b/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
index 4562e3b6c5..50df7e55ea 100644
--- a/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
+++ b/cSploit/src/org/csploit/android/net/datasource/Rapid7.java
@@ -344,7 +344,7 @@ public String toString() {
   public void beginSearch(RemoteReader.Job job, String query, Target.Port port, Search.Receiver<Target.Exploit> receiver) {
     String url;
 
-    url = "http://www.rapid7.com/db/search?q=";
+    url = "https://www.rapid7.com/db/search?q=";
 
     try {
       url += URLEncoder.encode(query, "UTF-8");

From 34092c1e92ff6d92eee06b7803be48f0bfc6a7f2 Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sat, 18 Jun 2016 02:13:50 +0200
Subject: [PATCH 32/33] [ExploitFinder] follow HTTP redirects.

 Even if we tell to Java to do this it ignore our preferences.
 We have to do this my hand.
---
 .../org/csploit/android/net/RemoteReader.java | 34 +++++++++++--------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/cSploit/src/org/csploit/android/net/RemoteReader.java b/cSploit/src/org/csploit/android/net/RemoteReader.java
index bd2954d97f..7b6ca8809f 100644
--- a/cSploit/src/org/csploit/android/net/RemoteReader.java
+++ b/cSploit/src/org/csploit/android/net/RemoteReader.java
@@ -357,7 +357,6 @@ public void run() {
     boolean isError;
     InputStream stream;
     Notifier notifier;
-    URL url;
 
     running = true;
 
@@ -385,23 +384,28 @@ public void run() {
       stream = null;
 
       try {
-        url = new URL(task.getUrl());
-      } catch (MalformedURLException e) {
-        notifiers.execute(new Notifier(task, ("Bad URL: " + task.getUrl()).getBytes(), true));
-        continue;
-      }
+        String url = task.getUrl();
 
-      if(!url.getHost().equals(host)) {
-        Logger.error(String.format("RemoteReader[%s]: URL '%s' does not belong to me", host, task.getUrl()));
-        notifiers.execute(new Notifier(task, "Host mismatch".getBytes(), true));
-        continue;
-      }
+        Logger.info("fetching '" + url + "'");
 
-      Logger.info("fetching '" + url.toString() + "'");
+        URL current = new URL(url);
 
-      try {
-        connection = url.openConnection();
-        stream = connection.getInputStream();
+        for(int i=0;i<30;i++) {
+          connection = current.openConnection();
+          stream = connection.getInputStream();
+
+          if(!(connection instanceof HttpURLConnection))
+            break;
+
+          HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
+          int code = httpURLConnection.getResponseCode();
+
+          if(code != HttpURLConnection.HTTP_MOVED_PERM && code != HttpURLConnection.HTTP_MOVED_TEMP )
+            break;
+
+          String location = connection.getHeaderField("Location");
+          current = new URL(current, location);
+        }
       } catch (IOException e) {
         if (connection != null && connection instanceof HttpURLConnection) {
           stream = ((HttpURLConnection) connection).getErrorStream();

From 0ff1883683a4256294f743602e7d2a550e720b69 Mon Sep 17 00:00:00 2001
From: tux-mind <massimo.dragano@gmail.com>
Date: Sat, 18 Jun 2016 02:20:56 +0200
Subject: [PATCH 33/33] version bump

fixed #637
fixed #651
fixed #652
fixed #675
---
 cSploit/build.gradle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/cSploit/build.gradle b/cSploit/build.gradle
index becadf91f2..e86b784a2c 100644
--- a/cSploit/build.gradle
+++ b/cSploit/build.gradle
@@ -53,7 +53,7 @@ android {
         minSdkVersion 9
         targetSdkVersion 22
         versionCode 6
-        versionName "1.6.6-rc.1"
+        versionName "1.6.6-rc.2"
         if(System.getenv("NIGHTLY_BUILD")) {
             versionName += "+" + System.getenv("NIGHTLY_BUILD_COMMIT").substring(0, 7)
         }