0
0
mirror of https://github.com/schwabe/ics-openvpn.git synced 2024-09-19 19:42:29 +02:00

Make lastTunConfiguration an object

This commit is contained in:
Arne Schwabe 2023-09-05 00:36:20 +02:00
parent 58cbe1ec52
commit 173f36fe51

View File

@ -87,17 +87,27 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
private static final int PRIORITY_DEFAULT = 0;
private static final int PRIORITY_MAX = 2;
private static boolean mNotificationAlwaysVisible = false;
private final Vector<String> mDnslist = new Vector<>();
private final NetworkSpace mRoutes = new NetworkSpace();
private final NetworkSpace mRoutesv6 = new NetworkSpace();
static class TunConfig {
private final Vector<String> mDnslist = new Vector<>();
private final NetworkSpace mRoutes = new NetworkSpace();
private final NetworkSpace mRoutesv6 = new NetworkSpace();
private String mDomain = null;
private CIDRIP mLocalIP = null;
private int mMtu;
private String mLocalIPv6 = null;
private ProxyInfo mProxyInfo;
};
private TunConfig tunConfig = new TunConfig();
private final Object mProcessLock = new Object();
private String lastChannel;
private Thread mProcessThread = null;
private VpnProfile mProfile;
private String mDomain = null;
private CIDRIP mLocalIP = null;
private int mMtu;
private String mLocalIPv6 = null;
private DeviceStateReceiver mDeviceStateReceiver;
private boolean mDisplayBytecount = false;
private boolean mStarting = false;
@ -138,12 +148,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
};
private String mLastTunCfg;
private TunConfig mLastTunCfg;
private String mRemoteGW;
private Handler guiHandler;
private Toast mlastToast;
private Runnable mOpenVPNThread;
private ProxyInfo mProxyInfo;
private HandlerThread mCommandHandlerThread;
private Handler mCommandHandler;
@ -747,27 +756,35 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
VpnStatus.flushLog();
}
private String getTunConfigString() {
private static String getTunConfigString(TunConfig tc) {
// The format of the string is not important, only that
// two identical configurations produce the same result
String cfg = "TUNCFG UNQIUE STRING ips:";
if (mLocalIP != null)
cfg += mLocalIP.toString();
if (mLocalIPv6 != null)
cfg += mLocalIPv6;
if (tc.mLocalIP != null)
cfg += tc.mLocalIP.toString();
if (tc.mLocalIPv6 != null)
cfg += tc.mLocalIPv6;
cfg += "routes: " + TextUtils.join("|", mRoutes.getNetworks(true)) + TextUtils.join("|", mRoutesv6.getNetworks(true));
cfg += "excl. routes:" + TextUtils.join("|", mRoutes.getNetworks(false)) + TextUtils.join("|", mRoutesv6.getNetworks(false));
cfg += "dns: " + TextUtils.join("|", mDnslist);
cfg += "domain: " + mDomain;
cfg += "mtu: " + mMtu;
cfg += "proxyInfo: " + mProxyInfo;
cfg += "routes: " + TextUtils.join("|", tc.mRoutes.getNetworks(true)) + TextUtils.join("|", tc.mRoutesv6.getNetworks(true));
cfg += "excl. routes:" + TextUtils.join("|", tc.mRoutes.getNetworks(false)) + TextUtils.join("|", tc.mRoutesv6.getNetworks(false));
cfg += "dns: " + TextUtils.join("|", tc.mDnslist);
cfg += "domain: " + tc.mDomain;
cfg += "mtu: " + tc.mMtu;
cfg += "proxyInfo: " + tc.mProxyInfo;
return cfg;
}
public ParcelFileDescriptor openTun() {
ParcelFileDescriptor pfd = openTun(tunConfig);
// Reset information
mLastTunCfg = tunConfig;
tunConfig = new TunConfig();
return pfd;
}
private ParcelFileDescriptor openTun(TunConfig tc) {
//Debug.startMethodTracing(getExternalFilesDir(null).toString() + "/opentun.trace", 40* 1024 * 1024);
@ -786,36 +803,36 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
allowAllAFFamilies(builder);
}
if (mLocalIP == null && mLocalIPv6 == null) {
if (tc.mLocalIP == null && tc.mLocalIPv6 == null) {
VpnStatus.logError(getString(R.string.opentun_no_ipaddr));
return null;
}
if (mLocalIP != null) {
if (tc.mLocalIP != null) {
// OpenVPN3 manages excluded local networks by callback
if (!VpnProfile.doUseOpenVPN3(this))
addLocalNetworksToRoutes();
addLocalNetworksToRoutes(tc);
try {
builder.addAddress(mLocalIP.mIp, mLocalIP.len);
builder.addAddress(tc.mLocalIP.mIp, tc.mLocalIP.len);
} catch (IllegalArgumentException iae) {
VpnStatus.logError(R.string.dns_add_error, mLocalIP, iae.getLocalizedMessage());
VpnStatus.logError(R.string.dns_add_error, tc.mLocalIP, iae.getLocalizedMessage());
return null;
}
}
if (mLocalIPv6 != null) {
String[] ipv6parts = mLocalIPv6.split("/");
if (tc.mLocalIPv6 != null) {
String[] ipv6parts = tc.mLocalIPv6.split("/");
try {
builder.addAddress(ipv6parts[0], Integer.parseInt(ipv6parts[1]));
} catch (IllegalArgumentException iae) {
VpnStatus.logError(R.string.ip_add_error, mLocalIPv6, iae.getLocalizedMessage());
VpnStatus.logError(R.string.ip_add_error, tc.mLocalIPv6, iae.getLocalizedMessage());
return null;
}
}
for (String dns : mDnslist) {
for (String dns : tc.mDnslist) {
try {
builder.addDnsServer(dns);
} catch (IllegalArgumentException iae) {
@ -824,15 +841,15 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
String release = Build.VERSION.RELEASE;
builder.setMtu(mMtu);
builder.setMtu(tc.mMtu);
Collection<IpAddress> positiveIPv4Routes = mRoutes.getPositiveIPList();
Collection<IpAddress> positiveIPv6Routes = mRoutesv6.getPositiveIPList();
Collection<IpAddress> positiveIPv4Routes = tc.mRoutes.getPositiveIPList();
Collection<IpAddress> positiveIPv6Routes = tc.mRoutesv6.getPositiveIPList();
if ("samsung".equals(Build.BRAND) && mDnslist.size() >= 1) {
if ("samsung".equals(Build.BRAND) && tc.mDnslist.size() >= 1) {
// Check if the first DNS Server is in the VPN range
try {
IpAddress dnsServer = new IpAddress(new CIDRIP(mDnslist.get(0), 32), true);
IpAddress dnsServer = new IpAddress(new CIDRIP(tc.mDnslist.get(0), 32), true);
boolean dnsIncluded = false;
for (IpAddress net : positiveIPv4Routes) {
if (net.containsNet(dnsServer)) {
@ -840,28 +857,28 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
}
if (!dnsIncluded) {
String samsungwarning = String.format("Warning Samsung Android 5.0+ devices ignore DNS servers outside the VPN range. To enable DNS resolution a route to your DNS Server (%s) has been added.", mDnslist.get(0));
String samsungwarning = String.format("Warning Samsung Android 5.0+ devices ignore DNS servers outside the VPN range. To enable DNS resolution a route to your DNS Server (%s) has been added.", tc.mDnslist.get(0));
VpnStatus.logWarning(samsungwarning);
positiveIPv4Routes.add(dnsServer);
}
} catch (Exception e) {
// If it looks like IPv6 ignore error
if (!mDnslist.get(0).contains(":"))
VpnStatus.logError("Error parsing DNS Server IP: " + mDnslist.get(0));
if (!tc.mDnslist.get(0).contains(":"))
VpnStatus.logError("Error parsing DNS Server IP: " + tc.mDnslist.get(0));
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
installRoutesExcluded(builder, mRoutes);
installRoutesExcluded(builder, mRoutesv6);
installRoutesExcluded(builder, tc.mRoutes);
installRoutesExcluded(builder, tc.mRoutesv6);
} else {
installRoutesPostiveOnly(builder, positiveIPv4Routes, positiveIPv6Routes);
}
if (mDomain != null)
builder.addSearchDomain(mDomain);
if (tc.mDomain != null)
builder.addSearchDomain(tc.mDomain);
String ipv4info;
String ipv6info;
@ -874,27 +891,27 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
int ipv4len;
if (mLocalIP != null) {
ipv4len = mLocalIP.len;
ipv4info = mLocalIP.mIp;
if (tc.mLocalIP != null) {
ipv4len = tc.mLocalIP.len;
ipv4info = tc.mLocalIP.mIp;
} else {
ipv4len = -1;
}
if (mLocalIPv6 != null) {
ipv6info = mLocalIPv6;
if (tc.mLocalIPv6 != null) {
ipv6info = tc.mLocalIPv6;
}
if ((!mRoutes.getNetworks(false).isEmpty() || !mRoutesv6.getNetworks(false).isEmpty()) && isLockdownEnabledCompat()) {
if ((!tc.mRoutes.getNetworks(false).isEmpty() || !tc.mRoutesv6.getNetworks(false).isEmpty()) && isLockdownEnabledCompat()) {
VpnStatus.logInfo("VPN lockdown enabled (do not allow apps to bypass VPN) enabled. Route exclusion will not allow apps to bypass VPN (e.g. bypass VPN for local networks)");
}
VpnStatus.logInfo(R.string.local_ip_info, ipv4info, ipv4len, ipv6info, mMtu);
VpnStatus.logInfo(R.string.dns_server_info, TextUtils.join(", ", mDnslist), mDomain);
VpnStatus.logInfo(R.string.routes_info_incl, TextUtils.join(", ", mRoutes.getNetworks(true)), TextUtils.join(", ", mRoutesv6.getNetworks(true)));
VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", mRoutes.getNetworks(false)), TextUtils.join(", ", mRoutesv6.getNetworks(false)));
if (mProxyInfo != null) {
VpnStatus.logInfo(R.string.proxy_info, mProxyInfo.getHost(), mProxyInfo.getPort());
VpnStatus.logInfo(R.string.local_ip_info, ipv4info, ipv4len, ipv6info, tc.mMtu);
VpnStatus.logInfo(R.string.dns_server_info, TextUtils.join(", ", tc.mDnslist), tc.mDomain);
VpnStatus.logInfo(R.string.routes_info_incl, TextUtils.join(", ", tc.mRoutes.getNetworks(true)), TextUtils.join(", ", tc.mRoutesv6.getNetworks(true)));
VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", tc.mRoutes.getNetworks(false)), TextUtils.join(", ", tc.mRoutesv6.getNetworks(false)));
if (tc.mProxyInfo != null) {
VpnStatus.logInfo(R.string.proxy_info, tc.mProxyInfo.getHost(), tc.mProxyInfo.getPort());
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
/* On Tiramisu we install the routes exactly like promised */
@ -915,31 +932,20 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
String session = mProfile.mName;
if (mLocalIP != null && mLocalIPv6 != null)
session = getString(R.string.session_ipv6string, session, mLocalIP, mLocalIPv6);
else if (mLocalIP != null)
session = getString(R.string.session_ipv4string, session, mLocalIP);
if (tc.mLocalIP != null && tc.mLocalIPv6 != null)
session = getString(R.string.session_ipv6string, session, tc.mLocalIP, tc.mLocalIPv6);
else if (tc.mLocalIP != null)
session = getString(R.string.session_ipv4string, session, tc.mLocalIP);
else
session = getString(R.string.session_ipv4string, session, mLocalIPv6);
session = getString(R.string.session_ipv4string, session, tc.mLocalIPv6);
builder.setSession(session);
// No DNS Server, log a warning
if (mDnslist.size() == 0)
if (tc.mDnslist.size() == 0)
VpnStatus.logInfo(R.string.warn_no_dns);
setHttpProxy(builder);
mLastTunCfg = getTunConfigString();
// Reset information
mDnslist.clear();
mRoutes.clear();
mRoutesv6.clear();
mLocalIP = null;
mLocalIPv6 = null;
mDomain = null;
mProxyInfo = null;
setHttpProxy(builder, tc);
builder.setConfigureIntent(getGraphPendingIntent());
@ -1000,10 +1006,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
}
private void setHttpProxy(Builder builder) {
if (mProxyInfo != null && Build.VERSION.SDK_INT >= 29) {
builder.setHttpProxy(mProxyInfo);
} else if (mProxyInfo != null) {
private void setHttpProxy(Builder builder, TunConfig tc) {
if (tc.mProxyInfo != null && Build.VERSION.SDK_INT >= 29) {
builder.setHttpProxy(tc.mProxyInfo);
} else if (tc.mProxyInfo != null) {
VpnStatus.logWarning("HTTP Proxy needs Android 10 or later.");
}
}
@ -1023,16 +1029,16 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
builder.allowFamily(OsConstants.AF_INET6);
}
private void addLocalNetworksToRoutes() {
private void addLocalNetworksToRoutes(TunConfig tc) {
for (String net : NetworkUtils.getLocalNetworks(this, false)) {
String[] netparts = net.split("/");
String ipAddr = netparts[0];
int netMask = Integer.parseInt(netparts[1]);
if (ipAddr.equals(mLocalIP.mIp))
if (ipAddr.equals(tc.mLocalIP.mIp))
continue;
if(mProfile.mAllowLocalLAN)
mRoutes.addIP(new CIDRIP(ipAddr, netMask), false);
tc.mRoutes.addIP(new CIDRIP(ipAddr, netMask), false);
}
if (mProfile.mAllowLocalLAN) {
@ -1103,12 +1109,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
public void addDNS(String dns) {
mDnslist.add(dns);
tunConfig.mDnslist.add(dns);
}
public void setDomain(String domain) {
if (mDomain == null) {
mDomain = domain;
if (tunConfig.mDomain == null) {
tunConfig.mDomain = domain;
}
}
@ -1116,12 +1122,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
* Route that is always included, used by the v3 core
*/
public void addRoute(CIDRIP route, boolean include) {
mRoutes.addIP(route, include);
tunConfig.mRoutes.addIP(route, include);
}
public boolean addHttpProxy(String proxy, int port) {
try {
mProxyInfo = ProxyInfo.buildDirectProxy(proxy, port);
tunConfig.mProxyInfo = ProxyInfo.buildDirectProxy(proxy, port);
} catch (Exception e) {
VpnStatus.logError("Could not set proxy" + e.getLocalizedMessage());
return false;
@ -1135,11 +1141,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
IpAddress gatewayIP = new IpAddress(new CIDRIP(gateway, 32), false);
if (mLocalIP == null) {
if (tunConfig.mLocalIP == null) {
VpnStatus.logError("Local IP address unset and received. Neither pushed server config nor local config specifies an IP addresses. Opening tun device is most likely going to fail.");
return;
}
IpAddress localNet = new IpAddress(mLocalIP, true);
IpAddress localNet = new IpAddress(tunConfig.mLocalIP, true);
if (localNet.containsNet(gatewayIP))
include = true;
@ -1155,7 +1161,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
if (route.normalise())
VpnStatus.logWarning(R.string.route_not_netip, dest, route.len, route.mIp);
mRoutes.addIP(route, include);
tunConfig.mRoutes.addIP(route, include);
}
public void addRoutev6(String network, String device) {
@ -1170,7 +1176,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
try {
Inet6Address ip = (Inet6Address) InetAddress.getAllByName(v6parts[0])[0];
int mask = Integer.parseInt(v6parts[1]);
mRoutesv6.addIPv6(ip, mask, included);
tunConfig.mRoutesv6.addIPv6(ip, mask, included);
} catch (UnknownHostException e) {
VpnStatus.logException(e);
@ -1185,21 +1191,21 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
public void setMtu(int mtu) {
mMtu = mtu;
tunConfig.mMtu = mtu;
}
public void setLocalIP(CIDRIP cdrip) {
mLocalIP = cdrip;
tunConfig.mLocalIP = cdrip;
}
public void setLocalIP(String local, String netmask, int mtu, String mode) {
mLocalIP = new CIDRIP(local, netmask);
mMtu = mtu;
tunConfig.mLocalIP = new CIDRIP(local, netmask);
tunConfig.mMtu = mtu;
mRemoteGW = null;
long netMaskAsInt = CIDRIP.getInt(netmask);
if (mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) {
if (tunConfig.mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) {
// get the netmask as IP
int masklen;
@ -1213,22 +1219,22 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
// Netmask is Ip address +/-1, assume net30/p2p with small net
if ((netMaskAsInt & mask) == (mLocalIP.getInt() & mask)) {
mLocalIP.len = masklen;
if ((netMaskAsInt & mask) == (tunConfig.mLocalIP.getInt() & mask)) {
tunConfig.mLocalIP.len = masklen;
} else {
mLocalIP.len = 32;
tunConfig.mLocalIP.len = 32;
if (!"p2p".equals(mode))
VpnStatus.logWarning(R.string.ip_not_cidr, local, netmask, mode);
}
}
if (("p2p".equals(mode) && mLocalIP.len < 32) || ("net30".equals(mode) && mLocalIP.len < 30)) {
if (("p2p".equals(mode) && tunConfig.mLocalIP.len < 32) || ("net30".equals(mode) && tunConfig.mLocalIP.len < 30)) {
VpnStatus.logWarning(R.string.ip_looks_like_subnet, local, netmask, mode);
}
/* Workaround for Lollipop and higher, it does not route traffic to the VPNs own network mask */
if (mLocalIP.len <= 31) {
CIDRIP interfaceRoute = new CIDRIP(mLocalIP.mIp, mLocalIP.len);
if (tunConfig.mLocalIP.len <= 31) {
CIDRIP interfaceRoute = new CIDRIP(tunConfig.mLocalIP.mIp, tunConfig.mLocalIP.len);
interfaceRoute.normalise();
addRoute(interfaceRoute, true);
}
@ -1239,7 +1245,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
public void setLocalIPv6(String ipv6addr) {
mLocalIPv6 = ipv6addr;
tunConfig.mLocalIPv6 = ipv6addr;
}
@Override
@ -1317,8 +1323,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
public String getTunReopenStatus() {
String currentConfiguration = getTunConfigString();
if (currentConfiguration.equals(mLastTunCfg)) {
String currentConfiguration = getTunConfigString(mLastTunCfg);
if (currentConfiguration.equals(getTunConfigString(mLastTunCfg))) {
return "NOACTION";
} else {
return "OPEN_BEFORE_CLOSE";