Browse Source

Added background synchronization with android sync framework. Added country-list retrieval from the tracing API.

Alexander Brakowski 9 years ago
parent
commit
ac05133325

+ 25 - 0
AndroidManifest.xml

@@ -21,6 +21,12 @@
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.NFC" />
     <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
+    <!-- Required to register a SyncStatusObserver to display a "syncing..." progress indicator. -->
+    <uses-permission android:name="android.permission.READ_SYNC_STATS"/>
+    <!-- Required to enable our SyncAdapter after it's created. -->
+    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
+    <!-- Required because we're manually creating a new account. -->
+    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
     <!--
     	<uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
@@ -126,6 +132,25 @@
                 android:name="android.support.PARENT_ACTIVITY"
                 android:value="de.tudarmstadt.informatik.hostage.ui.activity.MainActivity" />
         </activity>
+
+        <service android:name=".sync.android.SyncService"
+                 android:exported="true">
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter" />
+            </intent-filter>
+
+            <meta-data android:name="android.content.SyncAdapter"
+                       android:resource="@xml/syncadapter" />
+        </service>
+
+        <service android:name=".sync.android.HostageAccountService">
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+
+            <meta-data android:name="android.accounts.AccountAuthenticator"
+                       android:resource="@xml/authenticator" />
+        </service>
     </application>
 
 </manifest>

+ 4 - 0
res/values-de/strings.xml

@@ -220,4 +220,8 @@
     <string name="rec_via_nfc">&#220;ber NFC</string>
     <string name="rec_via_online">&#220;ber Online Datenbank</string>
     <string name="title_activity_p2_psync">WifiDirect Synchronization</string>
+    <string name="pref_sync_countries_dialog">Länderauswahl</string>
+    <string name="pref_sync_countries_desc">Nur Angriffdaten von diesen Ländern herunterladen</string>
+    <string name="pref_sync_countries">Länder</string>
+    <string name="pref_download_server">Download server</string>
 </resources>

+ 2 - 0
res/values/arrays.xml

@@ -12,4 +12,6 @@
         <item>All</item>
     </string-array>
 
+    <string-array name="pref_sync_countries_default">
+    </string-array>
 </resources>

+ 4 - 0
res/values/strings.xml

@@ -235,4 +235,8 @@
     <string name="rec_via_nfc">Via NFC</string>
     <string name="rec_via_online">Via Online Database</string>
     <string name="title_activity_p2_psync">WifiDirect Synchronization</string>
+    <string name="pref_sync_countries_dialog">Country selection</string>
+    <string name="pref_sync_countries_desc">Only download attack data of these countries</string>
+    <string name="pref_sync_countries">Countries</string>
+    <string name="pref_download_server">Download server</string>
 </resources>

+ 23 - 0
res/xml/authenticator.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+                       android:accountType="de.tudarmstadt.informatik.hostage"
+                       android:icon="@drawable/ic_launcher"
+                       android:smallIcon="@drawable/ic_launcher"
+                       android:label="@string/app_name"
+        />

+ 16 - 2
res/xml/settings_preferences.xml

@@ -26,16 +26,30 @@
 	</PreferenceCategory>
 
 	<PreferenceCategory android:title="@string/pref_upload" >
-		<CheckBoxPreference
+		<!--<CheckBoxPreference
 			android:defaultValue="false"
 			android:key="pref_auto_synchronize"
 			android:summary="@string/pref_auto_synchronize_summ"
-			android:title="@string/pref_auto_synchronize_title" />
+			android:title="@string/pref_auto_synchronize_title" />-->
 
 		<EditTextPreference
 				android:key="pref_upload_server"
 				android:defaultValue="https://ssi.cased.de"
 				android:title="@string/pref_upload_server" />
+
+        <EditTextPreference
+            android:key="pref_download_server"
+            android:defaultValue="http://ssi.cased.de/api"
+            android:title="@string/pref_download_server" />
+
+        <MultiSelectListPreference
+            android:dialogTitle="@string/pref_sync_countries_dialog"
+            android:key="pref_sync_countries"
+            android:summary="@string/pref_sync_countries_desc"
+            android:title="@string/pref_sync_countries"
+            android:entries="@array/pref_sync_countries_default"
+            android:entryValues="@array/pref_sync_countries_default"
+            />
 	</PreferenceCategory>
 
 	<PreferenceCategory android:title="@string/advanced_settings">

+ 25 - 0
res/xml/syncadapter.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+              android:contentAuthority="de.tudarmstadt.informatik.hostage.androidsync"
+              android:accountType="de.tudarmstadt.informatik.hostage"
+              android:userVisible="true"
+              android:supportsUploading="true"
+              android:allowParallelSyncs="false"
+              android:isAlwaysSyncable="true"
+        />

+ 97 - 0
src/de/tudarmstadt/informatik/hostage/sync/android/HostageAccountService.java

@@ -0,0 +1,97 @@
+package de.tudarmstadt.informatik.hostage.sync.android;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.NetworkErrorException;
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Created by abrakowski
+ */
+public class HostageAccountService extends Service {
+    private static final String TAG = "HostageAccountService";
+    private static final String ACCOUNT_TYPE = "de.tudarmstadt.informatik.hostage";
+    public static final String ACCOUNT_NAME = "TraCINg";
+    private Authenticator mAuthenticator;
+
+
+    public static Account GetAccount() {
+        final String accountName = ACCOUNT_NAME;
+        return new Account(accountName, ACCOUNT_TYPE);
+    }
+
+    @Override
+    public void onCreate() {
+        Log.i(TAG, "Service created");
+        mAuthenticator = new Authenticator(this);
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.i(TAG, "Service destroyed");
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mAuthenticator.getIBinder();
+    }
+
+    public class Authenticator extends AbstractAccountAuthenticator {
+        public Authenticator(Context context) {
+            super(context);
+        }
+
+        @Override
+        public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                     String s) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle addAccount(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                 String s, String s2, String[] strings, Bundle bundle)
+                throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                         Account account, Bundle bundle)
+                throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                   Account account, String s, Bundle bundle)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getAuthTokenLabel(String s) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                        Account account, String s, Bundle bundle)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                  Account account, String[] strings)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+    }
+}

+ 104 - 0
src/de/tudarmstadt/informatik/hostage/sync/android/SyncAdapter.java

@@ -0,0 +1,104 @@
+package de.tudarmstadt.informatik.hostage.sync.android;
+
+import android.accounts.Account;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import de.tudarmstadt.informatik.hostage.logging.Record;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.ui.model.LogFilter;
+
+/**
+ * Created by abrakowski
+ */
+public class SyncAdapter extends AbstractThreadedSyncAdapter {
+    public static final String TAG = "SyncAdapter";
+    private final SharedPreferences pref;
+    private final SharedPreferences.Editor editor;
+    private final HostageDBOpenHelper dbh;
+
+    private Context context;
+
+    public SyncAdapter(Context context, boolean autoInitialize) {
+        this(context, autoInitialize, false);
+    }
+
+    public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
+        super(context, autoInitialize, allowParallelSyncs);
+        this.context = context;
+
+        pref = PreferenceManager.getDefaultSharedPreferences(context);
+        editor = pref.edit();
+        dbh = new HostageDBOpenHelper(context);
+    }
+
+    /**
+     * Called by the Android system in response to a request to run the sync adapter. The work
+     * required to read data from the network, parse it, and store it in the content provider is
+     * done here. Extending AbstractThreadedSyncAdapter ensures that all methods within SyncAdapter
+     * run on a background thread. For this reason, blocking I/O and other long-running tasks can be
+     * run <em>in situ</em>, and you don't have to set up a separate thread for them.
+     .
+     *
+     * <p>This is where we actually perform any work required to perform a sync.
+     * {@link AbstractThreadedSyncAdapter} guarantees that this will be called on a non-UI thread,
+     * so it is safe to peform blocking I/O here.
+     *
+     * <p>The syncResult argument allows you to pass information back to the method that triggered
+     * the sync.
+     */
+    @Override
+    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
+        // We will only do a one-direction sync. That is, only sending data to the tracing server.
+        // For bidirectional syncing, we will still have to decide how much data should be requested from the server,
+        // because the server has relatively to a mobile device almost unlimited space.
+
+        Log.i(TAG, "Beginning network synchronization");
+
+        long lastSyncTime = pref.getLong("LAST_SYNC_TIME", 0);
+
+        String serverAddress = pref.getString("pref_upload_server", "https://ssi.cased.de"); //"https://192.168.1.118:9999"
+
+        Log.i(TAG, "Connecting to " + serverAddress);
+        LogFilter filter = new LogFilter();
+        filter.setAboveTimestamp(lastSyncTime);
+
+        ArrayList<Record> records = dbh.getRecordsForFilter(filter);
+        StringWriter writer = new StringWriter();
+
+        int size = records.size();
+        int offset = 1;
+        int currOffset = 1;
+        boolean error = false;
+        for (Record record : records) {
+            SyncUtils.appendRecordToStringWriter(record, writer);
+
+            if(currOffset == 100 || offset == size){
+                boolean success = SyncUtils.uploadRecordsToServer(writer.toString(), serverAddress);
+                if(!success){
+                    syncResult.stats.numIoExceptions++;
+                    error =  true;
+                    break;
+                }
+
+                writer.getBuffer().setLength(0);
+                currOffset = 0;
+            }
+
+            offset++;
+            currOffset++;
+        }
+
+        if(!error) pref.edit().putLong("LAST_SYNC_TIME", System.currentTimeMillis()).apply();
+        Log.i(TAG, "Network synchronization complete");
+    }
+}

+ 52 - 0
src/de/tudarmstadt/informatik/hostage/sync/android/SyncService.java

@@ -0,0 +1,52 @@
+package de.tudarmstadt.informatik.hostage.sync.android;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Created by abrakowski
+ */
+public class SyncService extends Service {
+    private static final String TAG = "SyncService";
+
+    private static final Object sSyncAdapterLock = new Object();
+    private static SyncAdapter sSyncAdapter = null;
+
+    /**
+     * Thread-safe constructor, creates static {@link SyncAdapter} instance.
+     */
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.i(TAG, "Service created");
+        synchronized (sSyncAdapterLock) {
+            if (sSyncAdapter == null) {
+                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
+            }
+        }
+    }
+
+    @Override
+    /**
+     * Logging-only destructor.
+     */
+    public void onDestroy() {
+        super.onDestroy();
+        Log.i(TAG, "Service destroyed");
+    }
+
+    /**
+     * Return Binder handle for IPC communication with {@link SyncAdapter}.
+     *
+     * <p>New sync requests will be sent directly to the SyncAdapter using this channel.
+     *
+     * @param intent Calling intent
+     * @return Binder handle for {@link SyncAdapter}
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return sSyncAdapter.getSyncAdapterBinder();
+    }
+}

+ 227 - 0
src/de/tudarmstadt/informatik/hostage/sync/android/SyncUtils.java

@@ -0,0 +1,227 @@
+package de.tudarmstadt.informatik.hostage.sync.android;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Writer;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import de.tudarmstadt.informatik.hostage.logging.Record;
+import de.tudarmstadt.informatik.hostage.net.MySSLSocketFactory;
+
+/**
+ * Created by abrakowski
+ */
+public class SyncUtils {
+    private static final long SYNC_FREQUENCY = 60 * 60;  // 1 hour (in seconds)
+    public static final String CONTENT_AUTHORITY = "de.tudarmstadt.informatik.hostage.androidsync";
+    private static final String PREF_SETUP_COMPLETE = "sync_setup_complete";
+
+    private static final Map<String, Integer> protocolsTypeMap;
+
+    static {
+        protocolsTypeMap = new HashMap<String, Integer>();
+        protocolsTypeMap.put("ECHO", 10);
+        protocolsTypeMap.put("FTP", 0);
+        protocolsTypeMap.put("GHOST", 0);
+        protocolsTypeMap.put("HTTP", 0);
+        protocolsTypeMap.put("HTTPS", 0);
+        protocolsTypeMap.put("MySQL", 31);
+        protocolsTypeMap.put("SIP", 50);
+        protocolsTypeMap.put("SMB", 40);
+        protocolsTypeMap.put("TELNET", 0);
+    }
+
+    /**
+     * Create an entry for this application in the system account list, if it isn't already there.
+     *
+     * @param context Context
+     */
+    public static void CreateSyncAccount(Context context) {
+        boolean newAccount = false;
+        boolean setupComplete = PreferenceManager
+                .getDefaultSharedPreferences(context).getBoolean(PREF_SETUP_COMPLETE, false);
+
+        // Create account, if it's missing. (Either first run, or user has deleted account.)
+        Account account = HostageAccountService.GetAccount();
+        AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
+        if (accountManager.addAccountExplicitly(account, null, null)) {
+            // Inform the system that this account supports sync
+            ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
+            // Inform the system that this account is eligible for auto sync when the network is up
+            ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true);
+            // Recommend a schedule for automatic synchronization. The system may modify this based
+            // on other scheduled syncs and network utilization.
+            ContentResolver.addPeriodicSync(
+                    account, CONTENT_AUTHORITY, new Bundle(),SYNC_FREQUENCY);
+            newAccount = true;
+        }
+
+        // Schedule an initial sync if we detect problems with either our account or our local
+        // data has been deleted. (Note that it's possible to clear app data WITHOUT affecting
+        // the account list, so wee need to check both.)
+        if (newAccount || !setupComplete) {
+            TriggerRefresh();
+            PreferenceManager.getDefaultSharedPreferences(context).edit()
+                    .putBoolean(PREF_SETUP_COMPLETE, true).commit();
+        }
+    }
+
+    public static void TriggerRefresh() {
+        Bundle b = new Bundle();
+        // Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
+        b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+        ContentResolver.requestSync(
+                HostageAccountService.GetAccount(),      // Sync account
+                CONTENT_AUTHORITY,                       // Content authority
+                b);                                      // Extras
+    }
+
+    public static void appendRecordToStringWriter(Record record, Writer stream){
+        try {
+            stream.append(
+            "{" +
+                "\"sensor\":{" +
+                    "\"name\":\"HosTaGe\"," +
+                    "\"type\":\"Honeypot\"" +
+                "}," +
+                "\"src\":{" +
+                    "\"ip\":\"" + record.getRemoteIP() + "\"," +
+                    "\"port\":" + record.getRemotePort() +
+                "}," +
+                "\"dst\":{" +
+                    "\"ip\":\"" + record.getExternalIP() /*record.getLocalIP()*/ + "\"," +
+                    "\"port\":" + record.getLocalPort() +
+                "}," +
+                "\"type\":" + (protocolsTypeMap.containsKey(record.getProtocol()) ? protocolsTypeMap.get(record.getProtocol()) : 0) + "," +
+                "\"log\":\"" + record.getProtocol() + "\"," +
+                "\"md5sum\":\"\"," +
+                "\"date\":" + (int)(record.getTimestamp() / 1000) +
+             "}\n"
+            );
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static boolean uploadRecordsToServer(String entity, String serverAddress){
+        HttpPost httppost;
+        try {
+            HttpClient httpClient = createHttpClient();
+            // Create HttpPost
+            httppost = new HttpPost(serverAddress);
+
+            StringEntity se = new StringEntity(entity);
+            httppost.addHeader("content-type", "application/json+newline");
+            httppost.setEntity(se);
+
+            // Execute HttpPost
+            HttpResponse response = httpClient.execute(httppost);
+
+            if(response.getStatusLine().getStatusCode() >= 400 && response.getStatusLine().getStatusCode() < 600){
+                return false;
+            }
+            Log.i("TracingSyncService", "Status Code: " + response.getStatusLine().getStatusCode());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    public static List<String[]> getCountriesFromServer(String serverAddress){
+        HttpGet httpget;
+        List<String[]> ret = new ArrayList<String[]>();
+
+        try {
+            HttpClient httpClient = createHttpClient();
+            // Create HttpPost
+            httpget = new HttpGet(serverAddress + "/get_countries");
+            httpget.addHeader("content-type", "application/json+newline");
+
+            // Execute HttpPost
+            HttpResponse response = httpClient.execute(httpget);
+
+            if(response.getStatusLine().getStatusCode() >= 400 && response.getStatusLine().getStatusCode() < 600){
+                return null;
+            }
+
+            BufferedReader bReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+            String line;
+            StringBuilder builder = new StringBuilder();
+            while ((line = bReader.readLine()) != null) {
+                builder.append(line);
+            }
+
+            JSONArray array = new JSONArray(builder.toString());
+            for(int i = 0; i < array.length(); i++){
+                JSONObject ob = array.getJSONObject(i);
+                ret.add(new String[]{ob.getString("cc"), ob.getString("country")});
+            }
+
+            Log.i("TracingSyncService", "Status Code: " + response.getStatusLine().getStatusCode());
+            return ret;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static HttpClient createHttpClient() {
+        try {
+            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+            trustStore.load(null, null);
+
+            SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
+            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+
+            HttpParams params = new BasicHttpParams();
+            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
+
+            SchemeRegistry registry = new SchemeRegistry();
+            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+            registry.register(new Scheme("https", sf, 443));
+
+            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
+
+            return new DefaultHttpClient(ccm, params);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new DefaultHttpClient();
+        }
+    }
+}

+ 17 - 98
src/de/tudarmstadt/informatik/hostage/sync/tracing/TracingSyncService.java

@@ -46,6 +46,7 @@ import de.tudarmstadt.informatik.hostage.logging.Record;
 import de.tudarmstadt.informatik.hostage.logging.SyncInfoRecord;
 import de.tudarmstadt.informatik.hostage.net.MySSLSocketFactory;
 import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.sync.android.SyncUtils;
 import de.tudarmstadt.informatik.hostage.ui.model.LogFilter;
 
 /**
@@ -65,8 +66,7 @@ public class TracingSyncService extends IntentService {
 
 	public static final int RECORD_UPLOADED = 0x00;
 	public static final int SYNC_COMPLETE = 0x01;
-
-    public static Map<String, Integer> protocolsTypeMap;
+    public static final int SYNC_ERROR = 0x02;
 
 	private HttpClient httpClient;
 	private ResultReceiver receiver;
@@ -76,19 +76,6 @@ public class TracingSyncService extends IntentService {
 	SharedPreferences pref;
 	Editor editor;
 
-    static {
-        protocolsTypeMap = new HashMap<String, Integer>();
-        protocolsTypeMap.put("ECHO", 10);
-        protocolsTypeMap.put("FTP", 0);
-        protocolsTypeMap.put("GHOST", 0);
-        protocolsTypeMap.put("HTTP", 0);
-        protocolsTypeMap.put("HTTPS", 0);
-        protocolsTypeMap.put("MySQL", 31);
-        protocolsTypeMap.put("SIP", 50);
-        protocolsTypeMap.put("SMB", 40);
-        protocolsTypeMap.put("TELNET", 0);
-    }
-
 	public TracingSyncService() {
 		super(TracingSyncService.class.getName());
 
@@ -129,7 +116,7 @@ public class TracingSyncService extends IntentService {
 	private void syncNewRecords() {
         long lastSyncTime = pref.getLong("LAST_SYNC_TIME", 0);
 
-		String serverAddress = pref.getString("pref_upload", "https://ssi.cased.de"); //"https://192.168.1.118:9999"
+		String serverAddress = pref.getString("pref_upload_server", "https://ssi.cased.de"); //"https://192.168.1.118:9999"
 
         LogFilter filter = new LogFilter();
         filter.setAboveTimestamp(lastSyncTime);
@@ -140,12 +127,23 @@ public class TracingSyncService extends IntentService {
 		int size = records.size();
 		int offset = 1;
         int currOffset = 1;
+
+        boolean error = false;
 		for (Record record : records) {
-            appendRecordToStringWriter(record, writer);
+            SyncUtils.appendRecordToStringWriter(record, writer);
 
             if(currOffset == 5 || offset == size){
-                boolean success = uploadRecordsToServer(writer.toString(), serverAddress);
+                boolean success = SyncUtils.uploadRecordsToServer(writer.toString(), serverAddress);
                 Log.i("Tracing upload", "Upload of record: " + offset + "/" + size + ((success) ? " successful." : " failed."));
+
+                if(!success){
+                    if(receiver != null){
+                        receiver.send(SYNC_ERROR, null);
+                        error = true;
+                    }
+                    break;
+                }
+
                 if (receiver != null) {
                     Bundle data = new Bundle();
                     data.putInt(UPLOAD_SIZE, size);
@@ -161,56 +159,9 @@ public class TracingSyncService extends IntentService {
             currOffset++;
 		}
 
-        pref.edit().putLong("LAST_SYNC_TIME", System.currentTimeMillis()).apply();
+        if(!error) pref.edit().putLong("LAST_SYNC_TIME", System.currentTimeMillis()).apply();
 	}
 
-    private void appendRecordToStringWriter(Record record, Writer stream){
-        try {
-            stream.append(
-                "{" +
-                    "\"sensor\":{" +
-                        "\"name\":\"HosTaGe\"," +
-                        "\"type\":\"Honeypot\"" +
-                    "}," +
-                    "\"src\":{" +
-                        "\"ip\":\"" + record.getRemoteIP() + "\"," +
-                        "\"port\":" + record.getRemotePort() +
-                    "}," +
-                    "\"dst\":{" +
-                        "\"ip\":\"" + record.getExternalIP() /*record.getLocalIP()*/ + "\"," +
-                        "\"port\":" + record.getLocalPort() +
-                    "}," +
-                    "\"type\":" + (protocolsTypeMap.containsKey(record.getProtocol()) ? protocolsTypeMap.get(record.getProtocol()) : 0) + "," +
-                    "\"log\":\"" + record.getProtocol() + "\"," +
-                    "\"md5sum\":\"\"," +
-                    "\"date\":" + (int)(record.getTimestamp() / 1000) +
-                "}\n"
-            );
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    private boolean uploadRecordsToServer(String entity, String serverAddress){
-        HttpPost httppost;
-        try {
-            httpClient = createHttpClient();
-            // Create HttpPost
-            httppost = new HttpPost(serverAddress);
-
-            StringEntity se = new StringEntity(entity);
-            httppost.addHeader("content-type", "application/json+newline");
-            httppost.setEntity(se);
-
-            // Execute HttpPost
-            HttpResponse response = httpClient.execute(httppost);
-            Log.i("TracingSyncService", "Status Code: " + response.getStatusLine().getStatusCode());
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        }
-        return true;
-    }
 
 	/**
 	 * Gets the data from the server and updates the database.
@@ -262,36 +213,4 @@ public class TracingSyncService extends IntentService {
 			e.printStackTrace();
 		}
 	}
-
-	/**
-	 * Creates a HttpClient with an own SSL Socket.
-	 * 
-	 * @return HttpsClient who accepts accepts all certificates.
-	 * @see MySSLSocketFactory
-	 */
-	private HttpClient createHttpClient() {
-		try {
-			KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
-			trustStore.load(null, null);
-
-			SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
-			sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
-
-			HttpParams params = new BasicHttpParams();
-			HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
-			HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
-
-			SchemeRegistry registry = new SchemeRegistry();
-			registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
-			registry.register(new Scheme("https", sf, 443));
-
-			ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
-
-			return new DefaultHttpClient(ccm, params);
-		} catch (Exception e) {
-			e.printStackTrace();
-			return new DefaultHttpClient();
-		}
-	}
-
 }

+ 4 - 0
src/de/tudarmstadt/informatik/hostage/ui/activity/MainActivity.java

@@ -38,6 +38,7 @@ import de.tudarmstadt.informatik.hostage.Hostage;
 import de.tudarmstadt.informatik.hostage.R;
 import de.tudarmstadt.informatik.hostage.model.Profile;
 import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
+import de.tudarmstadt.informatik.hostage.sync.android.SyncUtils;
 import de.tudarmstadt.informatik.hostage.ui.model.LogFilter;
 import de.tudarmstadt.informatik.hostage.ui.adapter.DrawerListAdapter;
 import de.tudarmstadt.informatik.hostage.ui.fragment.AboutFragment;
@@ -186,6 +187,9 @@ public class MainActivity extends Activity {
 	public void onStart() {
 		super.onStart();
 
+        // Register syncing with android
+        SyncUtils.CreateSyncAccount(this);
+
 		if (isServiceRunning()) {
 			this.bindService();
 		}

+ 46 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/PreferenceHostageFrament.java

@@ -1,14 +1,19 @@
 package de.tudarmstadt.informatik.hostage.ui.fragment;
 
 import android.content.SharedPreferences;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.preference.EditTextPreference;
+import android.preference.MultiSelectListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.sync.android.SyncUtils;
 
 /**
  * Manages and creates the application preferences view
@@ -17,6 +22,8 @@ import de.tudarmstadt.informatik.hostage.R;
  * @created 02.03.14 21:03
  */
 public class PreferenceHostageFrament extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
+    public static CharSequence[] entries = null;
+    public static CharSequence[] entriesValues = null;
 
 	/**
 	 * Maps an text preference to an suffix string
@@ -34,6 +41,7 @@ public class PreferenceHostageFrament extends PreferenceFragment implements Shar
 		String[] textPreferences = new String[]{
 				"pref_external_location",
 				"pref_upload_server",
+                "pref_download_server",
 				"pref_max_connections",
 				"pref_timeout",
 				"pref_sleeptime",
@@ -52,8 +60,42 @@ public class PreferenceHostageFrament extends PreferenceFragment implements Shar
 		for(String k: textPreferences){
 			updatePreferenceSummary(k);
 		}
+
+        if(entries == null || entriesValues == null) {
+            refreshCountryList();
+        }
 	}
 
+    private void refreshCountryList(){
+        final SharedPreferences sharedPreferences = this.getPreferenceManager().getSharedPreferences();
+
+        Preference p = getPreferenceManager().findPreference("pref_sync_countries");
+        final MultiSelectListPreference mp = (MultiSelectListPreference) p;
+
+        AsyncTask<String, Void, List<String[]>> task = new AsyncTask<String, Void, List<String[]>>(){
+            @Override
+            protected List<String[]> doInBackground(String... params) {
+                return SyncUtils.getCountriesFromServer(sharedPreferences.getString("pref_download_server", "http://192.168.1.118:8888"));
+            }
+
+            protected void onPostExecute(List<String[]> lst) {
+                if(lst != null) {
+                    entries = new CharSequence[lst.size()];
+                    entriesValues = new CharSequence[lst.size()];
+
+                    for (int i = 0; i < lst.size(); i++) {
+                        entries[i] = lst.get(i)[1];
+                        entriesValues[i] = lst.get(i)[0];
+                    }
+
+                    mp.setEntries(entries);
+                    mp.setEntryValues(entriesValues);
+                }
+            }
+        };
+
+        task.execute();
+    }
 	/**
 	 * Updates the summary text of the given preference
 	 *
@@ -113,6 +155,10 @@ public class PreferenceHostageFrament extends PreferenceFragment implements Shar
 	 */
 	@Override
 	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+        if(key.equals("pref_download_server")){
+            refreshCountryList();
+        }
+
 		updatePreferenceSummary(key);
 	}
 }