added ipv6 support

This commit is contained in:
mnbogner
2026-06-13 14:02:18 -07:00
parent 2fade0c1df
commit 27d8b2f159
3 changed files with 68 additions and 53 deletions

View File

@@ -3,6 +3,7 @@ package org.fdroid.fdroid;
import android.content.Context;
import org.apache.commons.net.util.SubnetUtils;
import org.apache.commons.net.util.SubnetUtils6;
import org.fdroid.database.Repository;
import org.fdroid.index.IndexFormatVersion;
@@ -23,6 +24,8 @@ public class FDroidApp {
@Nullable
public static volatile SubnetUtils.SubnetInfo subnetInfo;
@Nullable
public static volatile SubnetUtils6.SubnetInfo subnet6Info;
@Nullable
public static volatile String ssid;
@Nullable
public static volatile String bssid;
@@ -32,14 +35,12 @@ public class FDroidApp {
@SuppressWarnings("unused")
public static volatile String queryString;
public static final SubnetUtils.SubnetInfo UNSET_SUBNET_INFO =
new SubnetUtils("0.0.0.0/32").getInfo();
public static void initWifiSettings() {
port = generateNewPort ? (int) (Math.random() * 10000 + 8080) : port == 0 ? 8888 : port;
generateNewPort = false;
ipAddressString = null;
subnetInfo = UNSET_SUBNET_INFO;
subnetInfo = null;
subnet6Info = null;
ssid = null;
bssid = null;
}

View File

@@ -71,6 +71,10 @@ import org.fdroid.fdroid.qr.CameraCharacteristicsChecker;
import org.fdroid.settings.SettingsManager;
import org.fdroid.ui.nearby.SwapSuccessViewModel;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
@@ -478,13 +482,27 @@ public class SwapWorkflowActivity extends AppCompatActivity {
}
private static boolean isSwapUrl(Uri uri) {
return isSwapUrl(uri.getHost(), uri.getPort());
return isSwapUrl(uri.getHost());
}
private static boolean isSwapUrl(String host, int port) {
return port > 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
private static boolean isSwapUrl(String host) {
try {
InetAddress hostIp = InetAddress.getByName(host);
if (hostIp instanceof Inet4Address && FDroidApp.subnetInfo != null) {
return FDroidApp.subnetInfo.isInRange(host);
} else if (hostIp instanceof Inet6Address && FDroidApp.subnet6Info != null) {
return FDroidApp.subnet6Info.isInRange(host);
} else {
// unable to verify subnet range
return false;
}
} catch (UnknownHostException e) {
// if the host can't be parsed, it isn't a valid ip address
return false;
} catch (NullPointerException e) {
// FDroidApp.subnetInfo/subnet6Info may not have been setup
return false;
}
}
private void promptToSelectWifiNetwork() {
@@ -835,27 +853,26 @@ public class SwapWorkflowActivity extends AppCompatActivity {
private boolean checkIfNewRepoOnSameWifi(NewRepoConfig newRepo) {
// if this is a local repo, check we're on the same wifi
if (!TextUtils.isEmpty(newRepo.getBssid())) {
WifiManager wifiManager = ContextCompat.getSystemService(getApplicationContext(),
WifiManager.class);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String bssid = wifiInfo.getBSSID();
if (TextUtils.isEmpty(bssid)) {
// device may not have wifi
return false;
}
bssid = bssid.toLowerCase(Locale.ENGLISH);
String newRepoBssid = Uri.decode(newRepo.getBssid()).toLowerCase(Locale.ENGLISH);
if (!bssid.equals(newRepoBssid)) {
// repo config bssid doesn't match device bssid
return false;
}
// repo config appears to be on same wifi as device
return true;
} else {
// repo config has empty bssid
if (TextUtils.isEmpty(newRepo.getBssid())) {
// repo may not be connected to an access point
return false;
}
WifiManager wifiManager = ContextCompat.getSystemService(getApplicationContext(),
WifiManager.class);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
String bssid = wifiInfo.getBSSID();
if (TextUtils.isEmpty(bssid)) {
// device may not be connected to an access point
return false;
}
bssid = bssid.toLowerCase(Locale.ENGLISH);
String newRepoBssid = Uri.decode(newRepo.getBssid()).toLowerCase(Locale.ENGLISH);
if (!bssid.equals(newRepoBssid)) {
// repo config bssid doesn't match device bssid, check subnet
return isSwapUrl(newRepo.getRepoUri());
}
// repo config appears to be on same wifi as device
return true;
}
/**

View File

@@ -25,6 +25,7 @@ import androidx.work.Worker;
import androidx.work.WorkerParameters;
import org.apache.commons.net.util.SubnetUtils;
import org.apache.commons.net.util.SubnetUtils6;
import org.fdroid.database.Repository;
import org.fdroid.BuildConfig;
import org.fdroid.fdroid.FDroidApp;
@@ -33,6 +34,7 @@ import org.fdroid.fdroid.Preferences;
import org.fdroid.R;
import org.fdroid.fdroid.Utils;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
@@ -166,24 +168,9 @@ public class WifiStateChangeService extends Worker {
}
if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
wifiInfo = wifiManager.getConnectionInfo();
FDroidApp.ipAddressString = formatIpAddress(wifiInfo.getIpAddress());
setSsid(wifiInfo);
DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
if (dhcpInfo != null) {
String netmask = formatIpAddress(dhcpInfo.netmask);
if (!TextUtils.isEmpty(FDroidApp.ipAddressString) && netmask != null) {
try {
FDroidApp.subnetInfo = new SubnetUtils(FDroidApp.ipAddressString, netmask).getInfo();
} catch (IllegalArgumentException e) {
// catch mystery: "java.lang.IllegalArgumentException: Could not parse [null/24]"
e.printStackTrace();
}
}
}
if (FDroidApp.ipAddressString == null
|| FDroidApp.subnetInfo == FDroidApp.UNSET_SUBNET_INFO) {
setIpInfoFromNetworkInterface();
}
// WifiInfo only supports ipv4 so use network interface instead
setIpInfoFromNetworkInterface();
} else if (wifiState == WifiManager.WIFI_STATE_DISABLED
|| wifiState == WifiManager.WIFI_STATE_DISABLING
|| wifiState == WifiManager.WIFI_STATE_UNKNOWN) {
@@ -323,7 +310,7 @@ public class WifiStateChangeService extends Worker {
for (Enumeration<InetAddress> inetAddresses = netIf.getInetAddresses(); inetAddresses.hasMoreElements(); ) {
InetAddress inetAddress = inetAddresses.nextElement();
if (inetAddress.isLoopbackAddress() || inetAddress instanceof Inet6Address) {
if (inetAddress.isLoopbackAddress()) {
continue;
}
if (netIf.getDisplayName().contains("wlan0")
@@ -332,16 +319,26 @@ public class WifiStateChangeService extends Worker {
FDroidApp.ipAddressString = inetAddress.getHostAddress();
for (InterfaceAddress address : netIf.getInterfaceAddresses()) {
short networkPrefixLength = address.getNetworkPrefixLength();
if (networkPrefixLength > 32) {
// something is giving a "/64" netmask, IPv6?
// java.lang.IllegalArgumentException: Value [64] not in range [0,32]
// assume that ipv6 prefix length > 32
if ((inetAddress instanceof Inet4Address && networkPrefixLength > 32)
|| (inetAddress instanceof Inet6Address && networkPrefixLength <= 32)) {
continue;
}
// include support for both ipv4 and ipv6
try {
String cidr = String.format(Locale.ENGLISH, "%s/%d",
FDroidApp.ipAddressString, networkPrefixLength);
FDroidApp.subnetInfo = new SubnetUtils(cidr).getInfo();
break;
if (inetAddress instanceof Inet4Address) {
String cidr = String.format(Locale.ENGLISH, "%s/%d",
FDroidApp.ipAddressString, networkPrefixLength);
FDroidApp.subnetInfo = new SubnetUtils(cidr).getInfo();
break;
} else if (inetAddress instanceof Inet6Address) {
String cidr = String.format(Locale.ENGLISH, "%s/%d",
FDroidApp.ipAddressString, networkPrefixLength);
FDroidApp.subnet6Info = new SubnetUtils6(cidr).getInfo();
break;
} else {
Log.i(TAG, "Unexpected address type: " + inetAddress.getHostAddress());
}
} catch (IllegalArgumentException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();