From 8d2013577951d75720eb16c20ff5dc3f60bec199 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Tue, 8 Sep 2015 21:08:27 +0200 Subject: [PATCH 1/4] swap: close resources reported by StrictMode This required rebuilding the zipsigner.jar, since there was once issue to be fixed in kellingwood.security.zipsigner.ZipSigner. Here are the stacktraces: StrictMode E A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. E java.lang.Throwable: Explicit termination method 'close' not called E at dalvik.system.CloseGuard.open(CloseGuard.java:184) E at java.io.FileOutputStream.(FileOutputStream.java:90) E at java.io.FileOutputStream.(FileOutputStream.java:73) E at java.io.FileWriter.(FileWriter.java:42) E at org.fdroid.fdroid.localrepo.LocalRepoManager.writeIndexJar(LocalRepoManager.java:488) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:698) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:645) E at android.os.AsyncTask$2.call(AsyncTask.java:288) E at java.util.concurrent.FutureTask.run(FutureTask.java:237) E at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) E at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) E at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) E at java.lang.Thread.run(Thread.java:841) E A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. E java.lang.Throwable: Explicit termination method 'close' not called E at dalvik.system.CloseGuard.open(CloseGuard.java:184) E at java.io.RandomAccessFile.(RandomAccessFile.java:128) E at kellinwood.zipio.ZipInput.(ZipInput.java:57) E at kellinwood.zipio.ZipInput.read(ZipInput.java:75) E at kellinwood.security.zipsigner.ZipSigner.signZip(ZipSigner.java:646) E at org.fdroid.fdroid.localrepo.LocalRepoKeyStore.signZip(LocalRepoKeyStore.java:218) E at org.fdroid.fdroid.localrepo.LocalRepoManager.writeIndexJar(LocalRepoManager.java:515) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:698) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:645) E at android.os.AsyncTask$2.call(AsyncTask.java:288) E at java.util.concurrent.FutureTask.run(FutureTask.java:237) E at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) E at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) E at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) E at java.lang.Thread.run(Thread.java:841) E A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. E java.lang.Throwable: Explicit termination method 'end' not called E at dalvik.system.CloseGuard.open(CloseGuard.java:184) E at java.util.zip.Inflater.(Inflater.java:82) E at kellinwood.zipio.ZioEntry.getInputStream(ZioEntry.java:475) E at kellinwood.zipio.ZioEntry.getInputStream(ZioEntry.java:445) E at kellinwood.security.zipsigner.ZipSigner.addDigestsToManifest(ZipSigner.java:418) E at kellinwood.security.zipsigner.ZipSigner.signZip(ZipSigner.java:713) E at kellinwood.security.zipsigner.ZipSigner.signZip(ZipSigner.java:647) E at org.fdroid.fdroid.localrepo.LocalRepoKeyStore.signZip(LocalRepoKeyStore.java:218) E at org.fdroid.fdroid.localrepo.LocalRepoManager.writeIndexJar(LocalRepoManager.java:515) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:698) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:645) E at android.os.AsyncTask$2.call(AsyncTask.java:288) E at java.util.concurrent.FutureTask.run(FutureTask.java:237) E at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) E at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) E at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) E at java.lang.Thread.run(Thread.java:841) StrictMode E A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. E java.lang.Throwable: Explicit termination method 'close' not called E at dalvik.system.CloseGuard.open(CloseGuard.java:184) E at java.io.FileOutputStream.(FileOutputStream.java:90) E at java.io.FileOutputStream.(FileOutputStream.java:73) E at java.io.FileWriter.(FileWriter.java:42) E at org.fdroid.fdroid.localrepo.LocalRepoManager.writeIndexJar(LocalRepoManager.java:488) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:698) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:645) E at android.os.AsyncTask$2.call(AsyncTask.java:288) E at java.util.concurrent.FutureTask.run(FutureTask.java:237) E at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) E at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) E at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) E at java.lang.Thread.run(Thread.java:841) E A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. E java.lang.Throwable: Explicit termination method 'close' not called E at dalvik.system.CloseGuard.open(CloseGuard.java:184) E at java.io.RandomAccessFile.(RandomAccessFile.java:128) E at kellinwood.zipio.ZipInput.(ZipInput.java:57) E at kellinwood.zipio.ZipInput.read(ZipInput.java:75) E at kellinwood.security.zipsigner.ZipSigner.signZip(ZipSigner.java:646) E at org.fdroid.fdroid.localrepo.LocalRepoKeyStore.signZip(LocalRepoKeyStore.java:218) E at org.fdroid.fdroid.localrepo.LocalRepoManager.writeIndexJar(LocalRepoManager.java:515) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:698) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:645) E at android.os.AsyncTask$2.call(AsyncTask.java:288) E at java.util.concurrent.FutureTask.run(FutureTask.java:237) E at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) E at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) E at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) E at java.lang.Thread.run(Thread.java:841) E A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. E java.lang.Throwable: Explicit termination method 'end' not called E at dalvik.system.CloseGuard.open(CloseGuard.java:184) E at java.util.zip.Inflater.(Inflater.java:82) E at kellinwood.zipio.ZioEntry.getInputStream(ZioEntry.java:475) E at kellinwood.zipio.ZioEntry.getInputStream(ZioEntry.java:445) E at kellinwood.security.zipsigner.ZipSigner.addDigestsToManifest(ZipSigner.java:418) E at kellinwood.security.zipsigner.ZipSigner.signZip(ZipSigner.java:713) E at kellinwood.security.zipsigner.ZipSigner.signZip(ZipSigner.java:647) E at org.fdroid.fdroid.localrepo.LocalRepoKeyStore.signZip(LocalRepoKeyStore.java:218) E at org.fdroid.fdroid.localrepo.LocalRepoManager.writeIndexJar(LocalRepoManager.java:515) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:698) E at org.fdroid.fdroid.views.swap.SwapWorkflowActivity$PrepareSwapRepo.doInBackground(SwapWorkflowActivity.java:645) E at android.os.AsyncTask$2.call(AsyncTask.java:288) E at java.util.concurrent.FutureTask.run(FutureTask.java:237) E at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) E at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) E at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) E at java.lang.Thread.run(Thread.java:841) --- F-Droid/build.gradle | 4 +++- F-Droid/libs/binaryDeps/zipsigner.jar | Bin 74924 -> 74958 bytes .../fdroid/localrepo/LocalRepoManager.java | 6 ++++-- .../security/zipsigner/ZipSigner.java | 5 ++++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/F-Droid/build.gradle b/F-Droid/build.gradle index ef1fc2593..0e26dca10 100644 --- a/F-Droid/build.gradle +++ b/F-Droid/build.gradle @@ -36,7 +36,9 @@ if (!hasProperty('sourceDeps')) { // yet (seems to be a little unsupported as of late), so not using mavenCentral/jcenter. compile(name: 'nanohttpd-2.1.0') - // Upstream doesn't have a binary on mavenCentral. Looks discontinued. + // Upstream doesn't have a binary on mavenCentral, and it is an SVN repo on + // Google Code. We include this code directly in this repo, and have made + // modifications that should be pushed to anyone who wants to maintain it. compile(name: 'zipsigner') // Project semi-abandoned, 3.4.1 is from 2011 and we use trunk from 2013 diff --git a/F-Droid/libs/binaryDeps/zipsigner.jar b/F-Droid/libs/binaryDeps/zipsigner.jar index 1e741d75876633a6bd72bf31d8bd14dbef9f9559..1a870774e8e17ac48d863981216a0df5c4eaa936 100644 GIT binary patch delta 15133 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 delta 15228 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

S72+oM8a~R}2s`5*U3=^KlI9pYajft^B{U zC73%{Z~p9sY;649dt3>Ic%4i*VGmO~0RR9VU;x1Tc>O;58tWspzaW)9^tXQw%HPyr z{#jA9Q~wcYfI6EZbcb5Vbk;%%iE|KMq4-v1qja8#fLf0YCyHqSu-2LQHS z<|gRkeHAd{%{AZF%qS83or=kk3j7*Ww`u~Oq=e!JlyaSD3gCYE3UB(8( zf;bkQ{yh%@!p8Z}wk!b{7G%C38d$u2Em1r{1rD8}%)gP1o1fQmzL;nJQh1jCN&o=) zel3uoSUfP&_|V3;DF6Q{&^X>Ju?XBN@u@is2m}9R=XcPcGThg9cSwKVp@Dwk{wE;j z->7^)<+s1zfo$->NQi!)nKqaX8+uXKed!$5f10_%~i;5Ff$cSi4RJ zANyaTzM7o(f-AqcY4JkC^)a zz+QUfU+ZrpUK5le1H<^!@^nP6W>)0ArlZ@A^*@H5=Zjt9z1UR$(ro`4x>WYc!iNO* z_Wx+#TYdyFy|mK<;{R{1eD&)oS>nIu{?6n-B}e;jTE9!a))?=nfB~Ar{7=aR-n~YN z*7Uk>_wKKaC0Vu&M=#}ReKDQFwE`Nf8Epsp7I{}%z;f1onZ zU?4vXFs@e^5zmhwB`=VX|8whofPaPI#KVHU#Z;7mda(uoV1D^mc=1pI?WHP!{|D<& BQNREI diff --git a/F-Droid/src/org/fdroid/fdroid/localrepo/LocalRepoManager.java b/F-Droid/src/org/fdroid/fdroid/localrepo/LocalRepoManager.java index e404db88d..c23278e83 100644 --- a/F-Droid/src/org/fdroid/fdroid/localrepo/LocalRepoManager.java +++ b/F-Droid/src/org/fdroid/fdroid/localrepo/LocalRepoManager.java @@ -345,11 +345,13 @@ public class LocalRepoManager { serializer = XmlPullParserFactory.newInstance().newSerializer(); } - public void build(Writer output) throws IOException, LocalRepoKeyStore.InitException { + public void build(File file) throws IOException, LocalRepoKeyStore.InitException { + Writer output = new FileWriter(file); serializer.setOutput(output); serializer.startDocument(null, null); tagFdroid(); serializer.endDocument(); + output.close(); } private void tagFdroid() throws IOException, LocalRepoKeyStore.InitException { @@ -485,7 +487,7 @@ public class LocalRepoManager { public void writeIndexJar() throws IOException { try { - new IndexXmlBuilder(context, apps).build(new FileWriter(xmlIndex)); + new IndexXmlBuilder(context, apps).build(xmlIndex); } catch (Exception e) { Log.e(TAG, "Could not write index jar", e); Toast.makeText(context, R.string.failed_to_create_index, Toast.LENGTH_LONG).show(); diff --git a/extern/zipsigner/src/main/java/kellinwood/security/zipsigner/ZipSigner.java b/extern/zipsigner/src/main/java/kellinwood/security/zipsigner/ZipSigner.java index d5c0604b2..8bc9aea5c 100644 --- a/extern/zipsigner/src/main/java/kellinwood/security/zipsigner/ZipSigner.java +++ b/extern/zipsigner/src/main/java/kellinwood/security/zipsigner/ZipSigner.java @@ -378,8 +378,10 @@ public class ZipSigner Manifest input = null; ZioEntry manifestEntry = entries.get(JarFile.MANIFEST_NAME); if (manifestEntry != null) { + InputStream is = manifestEntry.getInputStream(); input = new Manifest(); - input.read( manifestEntry.getInputStream()); + input.read(is); + is.close(); } Manifest output = new Manifest(); Attributes main = output.getMainAttributes(); @@ -645,6 +647,7 @@ public class ZipSigner ZipInput input = ZipInput.read( inputZipFilename); signZip( input.getEntries(), new FileOutputStream( outputZipFilename), outputZipFilename); + input.close(); } /** Sign the From 0f44fcb8fdfd14b83d879811935df8b2e89af225 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 10 Sep 2015 09:51:52 +0200 Subject: [PATCH 2/4] swap: remove useless text that used to be a link It is not helpful to the user to tell them they can download from the web when they are using swap, since a) they should use F-Droid since its safer, and b) they are probably using swap because they can't access the web reliably. --- F-Droid/assets/index.template.html | 5 ----- 1 file changed, 5 deletions(-) diff --git a/F-Droid/assets/index.template.html b/F-Droid/assets/index.template.html index fd77b404b..f2f9cee82 100644 --- a/F-Droid/assets/index.template.html +++ b/F-Droid/assets/index.template.html @@ -105,10 +105,5 @@ Not done -

- - Or, download apps from the web - -
From 1654443b00902152861b3cffb7b8ef744e382f63 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 10 Sep 2015 16:49:13 +0200 Subject: [PATCH 3/4] StrictMode only works in android-9 and above --- F-Droid/src/org/fdroid/fdroid/FDroidApp.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/F-Droid/src/org/fdroid/fdroid/FDroidApp.java b/F-Droid/src/org/fdroid/fdroid/FDroidApp.java index 0c140a5d5..b10d43932 100644 --- a/F-Droid/src/org/fdroid/fdroid/FDroidApp.java +++ b/F-Droid/src/org/fdroid/fdroid/FDroidApp.java @@ -153,9 +153,10 @@ public class FDroidApp extends Application { c.getResources().updateConfiguration(cfg, null); } + @TargetApi(9) @Override public void onCreate() { - if (BuildConfig.DEBUG) { + if (Build.VERSION.SDK_INT >= 9 && BuildConfig.DEBUG) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyLog() From a69488b32fdfcfebbc4ce6f5bdbb2ed24add4839 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 10 Sep 2015 17:54:49 +0200 Subject: [PATCH 4/4] HttpDownloader bypasses proxy when accessing a swap repo Proxying are basically always for internet access, and swap repos are by definition only on the local network. This adds a pretty strict check for whether a given download URL is for a swap repo, and if so, the proxy settings are ignored. fixes https://dev.guardianproject.info/issues/3421 --- F-Droid/build.gradle | 2 ++ F-Droid/src/org/fdroid/fdroid/FDroidApp.java | 3 ++ .../org/fdroid/fdroid/net/HttpDownloader.java | 10 ++++++- .../fdroid/net/WifiStateChangeService.java | 29 +++++++++++++++---- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/F-Droid/build.gradle b/F-Droid/build.gradle index 0e26dca10..270be4936 100644 --- a/F-Droid/build.gradle +++ b/F-Droid/build.gradle @@ -27,6 +27,7 @@ if (!hasProperty('sourceDeps')) { compile 'com.madgag.spongycastle:pkix:1.51.0.0' compile 'com.madgag.spongycastle:prov:1.51.0.0' compile 'com.madgag.spongycastle:core:1.51.0.0' + compile 'commons-net:commons-net:3.3' // Upstream doesn't have a binary on mavenCentral/jcenter yet: // https://github.com/kolavar/android-support-v4-preferencefragment/issues/13 @@ -70,6 +71,7 @@ if (!hasProperty('sourceDeps')) { compile 'eu.chainfire:libsuperuser:1.0.0.201504231659' compile 'cc.mvdan.accesspoint:library:0.1.1' compile 'info.guardianproject.netcipher:netcipher:1.2' + compile 'commons-net:commons-net:3.3' compile(project(':extern:support-v4-preferencefragment')) { exclude module: 'support-v4' diff --git a/F-Droid/src/org/fdroid/fdroid/FDroidApp.java b/F-Droid/src/org/fdroid/fdroid/FDroidApp.java index b10d43932..554722e15 100644 --- a/F-Droid/src/org/fdroid/fdroid/FDroidApp.java +++ b/F-Droid/src/org/fdroid/fdroid/FDroidApp.java @@ -44,6 +44,7 @@ import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import com.nostra13.universalimageloader.utils.StorageUtils; +import org.apache.commons.net.util.SubnetUtils; import org.fdroid.fdroid.Preferences.ChangeListener; import org.fdroid.fdroid.compat.PRNGFixes; import org.fdroid.fdroid.data.AppProvider; @@ -68,6 +69,7 @@ public class FDroidApp extends Application { // for the local repo on this device, all static since there is only one public static int port; public static String ipAddressString; + public static SubnetUtils.SubnetInfo subnetInfo; public static String ssid; public static String bssid; public static final Repo repo = new Repo(); @@ -135,6 +137,7 @@ public class FDroidApp extends Application { public static void initWifiSettings() { port = 8888; ipAddressString = null; + subnetInfo = (new SubnetUtils("0.0.0.0/32").getInfo()); ssid = ""; bssid = ""; } diff --git a/F-Droid/src/org/fdroid/fdroid/net/HttpDownloader.java b/F-Droid/src/org/fdroid/fdroid/net/HttpDownloader.java index dcdf7c683..241a73cee 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/HttpDownloader.java +++ b/F-Droid/src/org/fdroid/fdroid/net/HttpDownloader.java @@ -5,6 +5,7 @@ import android.util.Log; import com.nostra13.universalimageloader.core.download.BaseImageDownloader; +import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Utils; @@ -84,11 +85,18 @@ public class HttpDownloader extends Downloader { } } + boolean isSwapUrl() { + String host = sourceUrl.getHost(); + return sourceUrl.getPort() > 1023 // only root can use <= 1023, so never a swap repo + && host.matches("[0-9.]+") // host must be an IP address + && FDroidApp.subnetInfo.isInRange(host); // on the same subnet as we are + } + protected void setupConnection() throws IOException { if (connection != null) return; Preferences prefs = Preferences.get(); - if (prefs.isProxyEnabled()) { + if (prefs.isProxyEnabled() && ! isSwapUrl()) { SocketAddress sa = new InetSocketAddress(prefs.getProxyHost(), prefs.getProxyPort()); Proxy proxy = new Proxy(Proxy.Type.HTTP, sa); NetCipher.setProxy(proxy); diff --git a/F-Droid/src/org/fdroid/fdroid/net/WifiStateChangeService.java b/F-Droid/src/org/fdroid/fdroid/net/WifiStateChangeService.java index 88eeeda11..ed058d7ab 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/WifiStateChangeService.java +++ b/F-Droid/src/org/fdroid/fdroid/net/WifiStateChangeService.java @@ -1,5 +1,6 @@ package org.fdroid.fdroid.net; +import android.annotation.TargetApi; import android.app.Service; import android.content.ComponentName; import android.content.Context; @@ -9,10 +10,13 @@ import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.AsyncTask; +import android.os.Build; import android.os.IBinder; import android.support.v4.content.LocalBroadcastManager; +import android.text.TextUtils; import android.util.Log; +import org.apache.commons.net.util.SubnetUtils; import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Preferences; @@ -23,6 +27,7 @@ import org.fdroid.fdroid.localrepo.SwapService; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.security.cert.Certificate; @@ -80,14 +85,17 @@ public class WifiStateChangeService extends Service { if (wifiState == WifiManager.WIFI_STATE_ENABLED) { wifiInfo = wifiManager.getConnectionInfo(); FDroidApp.ipAddressString = formatIpAddress(wifiInfo.getIpAddress()); + String netmask = formatIpAddress(wifiManager.getDhcpInfo().netmask); + if (!TextUtils.isEmpty(FDroidApp.ipAddressString)) + FDroidApp.subnetInfo = new SubnetUtils(FDroidApp.ipAddressString, netmask).getInfo(); } else if (wifiState == WifiManager.WIFI_STATE_DISABLED || wifiState == WifiManager.WIFI_STATE_DISABLING) { // try once to see if its a hotspot - FDroidApp.ipAddressString = getIpAddressFromNetworkInterface(); + setIpInfoFromNetworkInterface(); if (FDroidApp.ipAddressString == null) return null; } else { // a hotspot can be active during WIFI_STATE_UNKNOWN - FDroidApp.ipAddressString = getIpAddressFromNetworkInterface(); + setIpInfoFromNetworkInterface(); } if (FDroidApp.ipAddressString == null) { @@ -179,7 +187,8 @@ public class WifiStateChangeService extends Service { return null; } - public String getIpAddressFromNetworkInterface() { + @TargetApi(9) + public void setIpInfoFromNetworkInterface() { try { for (Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); networkInterfaces.hasMoreElements(); ) { NetworkInterface netIf = networkInterfaces.nextElement(); @@ -191,15 +200,23 @@ public class WifiStateChangeService extends Service { } else if (netIf.getDisplayName().contains("wlan0") || netIf.getDisplayName().contains("eth0") || netIf.getDisplayName().contains("ap0")) { - return inetAddress.getHostAddress(); + FDroidApp.ipAddressString = inetAddress.getHostAddress(); + if (Build.VERSION.SDK_INT < 9) + return; + // the following methods were not added until android-9/Gingerbread + for (InterfaceAddress address : netIf.getInterfaceAddresses()) { + if (inetAddress.equals(address.getAddress()) && ! TextUtils.isEmpty(FDroidApp.ipAddressString)) { + String cidr = String.format("%s/%i", FDroidApp.ipAddressString, address.getNetworkPrefixLength()); + FDroidApp.subnetInfo = (new SubnetUtils(cidr)).getInfo(); + break; + } + } } } } } catch (SocketException e) { Log.e(TAG, "Could not get ip address", e); } - - return null; } private String formatIpAddress(int ipAddress) {