From c95a21a736fadb46685e051064b0ec1efdae667a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 31 Jan 2015 01:19:49 +0100 Subject: Updated ics-openvpn to rev 1020. Improved build.gradle script. --- .../java/de/blinkt/openvpn/core/ConfigParser.java | 1030 ++++++++++---------- .../java/de/blinkt/openvpn/core/NetworkSpace.java | 13 +- .../de/blinkt/openvpn/core/OpenVPNService.java | 34 +- 3 files changed, 543 insertions(+), 534 deletions(-) (limited to 'app/src/main/java/de/blinkt') diff --git a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java index 5dc96bbc..5f5d486c 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java +++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java @@ -28,11 +28,11 @@ import de.blinkt.openvpn.VpnProfile; public class ConfigParser { - public static final String CONVERTED_PROFILE = "converted Profile"; - private HashMap>> options = new HashMap>>(); - private HashMap> meta = new HashMap>(); + public static final String CONVERTED_PROFILE = "converted Profile"; + private HashMap>> options = new HashMap>>(); + private HashMap> meta = new HashMap>(); - public void parseConfig(Reader reader) throws IOException, ConfigParseError { + public void parseConfig(Reader reader) throws IOException, ConfigParseError { BufferedReader br = new BufferedReader(reader); @@ -75,192 +75,176 @@ public class ConfigParser { } catch (java.lang.OutOfMemoryError memoryError) { throw new ConfigParseError("File too large to parse: " + memoryError.getLocalizedMessage()); } - } + } - private Vector parsemeta(String line) { - String meta = line.split("#\\sOVPN_ACCESS_SERVER_", 2)[1]; - String[] parts = meta.split("=",2); - Vector rval = new Vector(); + private Vector parsemeta(String line) { + String meta = line.split("#\\sOVPN_ACCESS_SERVER_", 2)[1]; + String[] parts = meta.split("=", 2); + Vector rval = new Vector(); Collections.addAll(rval, parts); - return rval; - - } - - private void checkinlinefile(Vector args, BufferedReader br) throws IOException, ConfigParseError { - String arg0 = args.get(0).trim(); - // CHeck for - if(arg0.startsWith("<") && arg0.endsWith(">")) { - String argname = arg0.substring(1, arg0.length()-1); - String inlinefile = VpnProfile.INLINE_TAG; - - String endtag = String.format("",argname); - do { - String line = br.readLine(); - if(line==null){ - throw new ConfigParseError(String.format("No endtag for starttag <%s> found",argname,argname)); - } - if(line.trim().equals(endtag)) - break; - else { - inlinefile+=line; - inlinefile+= "\n"; - } - } while(true); - - args.clear(); - args.add(argname); - args.add(inlinefile); - } - - } - - enum linestate { - initial, - readin_single_quote - , reading_quoted, reading_unquoted, done} - - private boolean space(char c) { - // I really hope nobody is using zero bytes inside his/her config file - // to sperate parameter but here we go: - return Character.isWhitespace(c) || c == '\0'; - - } - - public class ConfigParseError extends Exception { - private static final long serialVersionUID = -60L; - - public ConfigParseError(String msg) { - super(msg); - } - } - - - // adapted openvpn's parse function to java - private Vector parseline(String line) throws ConfigParseError { - Vector parameters = new Vector(); - - if (line.length()==0) - return parameters; - - - linestate state = linestate.initial; - boolean backslash = false; - char out=0; - - int pos=0; - String currentarg=""; - - do { - // Emulate the c parsing ... - char in; - if(pos < line.length()) - in = line.charAt(pos); - else - in = '\0'; - - if (!backslash && in == '\\' && state != linestate.readin_single_quote) - { - backslash = true; - } - else - { - if (state == linestate.initial) - { - if (!space (in)) - { - if (in == ';' || in == '#') /* comment */ - break; - if (!backslash && in == '\"') - state = linestate.reading_quoted; - else if (!backslash && in == '\'') - state = linestate.readin_single_quote; - else - { - out = in; - state = linestate.reading_unquoted; - } - } - } - else if (state == linestate.reading_unquoted) - { - if (!backslash && space (in)) - state = linestate.done; - else - out = in; - } - else if (state == linestate.reading_quoted) - { - if (!backslash && in == '\"') - state = linestate.done; - else - out = in; - } - else if (state == linestate.readin_single_quote) - { - if (in == '\'') - state = linestate.done; - else - out = in; - } - - if (state == linestate.done) - { - /* ASSERT (parm_len > 0); */ - state = linestate.initial; - parameters.add(currentarg); - currentarg = ""; - out =0; - } - - if (backslash && out!=0) - { - if (!(out == '\\' || out == '\"' || space (out))) - { - throw new ConfigParseError("Options warning: Bad backslash ('\\') usage"); - } - } - backslash = false; - } + return rval; + + } + + private void checkinlinefile(Vector args, BufferedReader br) throws IOException, ConfigParseError { + String arg0 = args.get(0).trim(); + // CHeck for + if (arg0.startsWith("<") && arg0.endsWith(">")) { + String argname = arg0.substring(1, arg0.length() - 1); + String inlinefile = VpnProfile.INLINE_TAG; + + String endtag = String.format("", argname); + do { + String line = br.readLine(); + if (line == null) { + throw new ConfigParseError(String.format("No endtag for starttag <%s> found", argname, argname)); + } + if (line.trim().equals(endtag)) + break; + else { + inlinefile += line; + inlinefile += "\n"; + } + } while (true); + + args.clear(); + args.add(argname); + args.add(inlinefile); + } + + } + + enum linestate { + initial, + readin_single_quote, reading_quoted, reading_unquoted, done + } + + private boolean space(char c) { + // I really hope nobody is using zero bytes inside his/her config file + // to sperate parameter but here we go: + return Character.isWhitespace(c) || c == '\0'; + + } + + public class ConfigParseError extends Exception { + private static final long serialVersionUID = -60L; + + public ConfigParseError(String msg) { + super(msg); + } + } + + + // adapted openvpn's parse function to java + private Vector parseline(String line) throws ConfigParseError { + Vector parameters = new Vector(); + + if (line.length() == 0) + return parameters; + + + linestate state = linestate.initial; + boolean backslash = false; + char out = 0; + + int pos = 0; + String currentarg = ""; + + do { + // Emulate the c parsing ... + char in; + if (pos < line.length()) + in = line.charAt(pos); + else + in = '\0'; + + if (!backslash && in == '\\' && state != linestate.readin_single_quote) { + backslash = true; + } else { + if (state == linestate.initial) { + if (!space(in)) { + if (in == ';' || in == '#') /* comment */ + break; + if (!backslash && in == '\"') + state = linestate.reading_quoted; + else if (!backslash && in == '\'') + state = linestate.readin_single_quote; + else { + out = in; + state = linestate.reading_unquoted; + } + } + } else if (state == linestate.reading_unquoted) { + if (!backslash && space(in)) + state = linestate.done; + else + out = in; + } else if (state == linestate.reading_quoted) { + if (!backslash && in == '\"') + state = linestate.done; + else + out = in; + } else if (state == linestate.readin_single_quote) { + if (in == '\'') + state = linestate.done; + else + out = in; + } + + if (state == linestate.done) { + /* ASSERT (parm_len > 0); */ + state = linestate.initial; + parameters.add(currentarg); + currentarg = ""; + out = 0; + } + + if (backslash && out != 0) { + if (!(out == '\\' || out == '\"' || space(out))) { + throw new ConfigParseError("Options warning: Bad backslash ('\\') usage"); + } + } + backslash = false; + } /* store parameter character */ - if (out!=0) - { - currentarg+=out; - } - } while (pos++ < line.length()); - - return parameters; - } - - - final String[] unsupportedOptions = { "config", - "tls-server" - - }; - - // Ignore all scripts - // in most cases these won't work and user who wish to execute scripts will - // figure out themselves - final String[] ignoreOptions = { "tls-client", - "askpass", - "auth-nocache", - "up", - "down", - "route-up", - "ipchange", - "route-up", - "route-pre-down", - "auth-user-pass-verify", - "dhcp-release", - "dhcp-renew", - "dh", + if (out != 0) { + currentarg += out; + } + } while (pos++ < line.length()); + + return parameters; + } + + + final String[] unsupportedOptions = {"config", + "tls-server" + + }; + + // Ignore all scripts + // in most cases these won't work and user who wish to execute scripts will + // figure out themselves + final String[] ignoreOptions = {"tls-client", + "askpass", + "auth-nocache", + "up", + "down", + "route-up", + "ipchange", + "route-up", + "route-pre-down", + "auth-user-pass-verify", + "dhcp-release", + "dhcp-renew", + "dh", "group", "ip-win32", "management-hold", "management", "management-client", "management-query-remote", - "management-query-passwords", + "management-query-passwords", "management-query-proxy", "management-external-key", "management-forget-disconnect", @@ -269,32 +253,32 @@ public class ConfigParser { "management-up-down", "management-client-user", "management-client-group", - "pause-exit", + "pause-exit", "plugin", "machine-readable-output", - "persist-key", - "register-dns", - "route-delay", - "route-gateway", - "route-metric", - "route-method", - "status", - "script-security", - "show-net-up", - "suppress-timestamps", - "tmp-dir", - "tun-ipv6", - "topology", + "persist-key", + "register-dns", + "route-delay", + "route-gateway", + "route-metric", + "route-method", + "status", + "script-security", + "show-net-up", + "suppress-timestamps", + "tmp-dir", + "tun-ipv6", + "topology", "user", "win-sys", - }; final String[][] ignoreOptionsWithArg = - { - {"setenv", "IV_GUI_VER"}, - {"setenv", "IV_OPENVPN_GUI_VERSION"} - }; + { + {"setenv", "IV_GUI_VER"}, + {"setenv", "IV_OPENVPN_GUI_VERSION"}, + {"engine", "dynamic"} + }; final String[] connectionOptions = { "local", @@ -326,70 +310,67 @@ public class ConfigParser { // This method is far too long - @SuppressWarnings("ConstantConditions") + @SuppressWarnings("ConstantConditions") public VpnProfile convertProfile() throws ConfigParseError, IOException { - boolean noauthtypeset=true; - VpnProfile np = new VpnProfile(CONVERTED_PROFILE); - // Pull, client, tls-client - np.clearDefaults(); - - if(options.containsKey("client") || options.containsKey("pull")) { - np.mUsePull=true; - options.remove("pull"); - options.remove("client"); - } - - Vector secret = getOption("secret", 1, 2); - if(secret!=null) - { - np.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; - noauthtypeset=false; - np.mUseTLSAuth=true; - np.mTLSAuthFilename=secret.get(1); - if(secret.size()==3) - np.mTLSAuthDirection=secret.get(2); - - } - - Vector> routes = getAllOption("route", 1, 4); - if(routes!=null) { - String routeopt = ""; + boolean noauthtypeset = true; + VpnProfile np = new VpnProfile(CONVERTED_PROFILE); + // Pull, client, tls-client + np.clearDefaults(); + + if (options.containsKey("client") || options.containsKey("pull")) { + np.mUsePull = true; + options.remove("pull"); + options.remove("client"); + } + + Vector secret = getOption("secret", 1, 2); + if (secret != null) { + np.mAuthenticationType = VpnProfile.TYPE_STATICKEYS; + noauthtypeset = false; + np.mUseTLSAuth = true; + np.mTLSAuthFilename = secret.get(1); + if (secret.size() == 3) + np.mTLSAuthDirection = secret.get(2); + + } + + Vector> routes = getAllOption("route", 1, 4); + if (routes != null) { + String routeopt = ""; String routeExcluded = ""; - for(Vector route:routes){ - String netmask = "255.255.255.255"; + for (Vector route : routes) { + String netmask = "255.255.255.255"; String gateway = "vpn_gateway"; - if(route.size() >= 3) - netmask = route.get(2); + if (route.size() >= 3) + netmask = route.get(2); if (route.size() >= 4) gateway = route.get(3); - String net = route.get(1); - try { - CIDRIP cidr = new CIDRIP(net, netmask); + String net = route.get(1); + try { + CIDRIP cidr = new CIDRIP(net, netmask); if (gateway.equals("net_gateway")) routeExcluded += cidr.toString() + " "; else - routeopt+=cidr.toString() + " "; - } catch (ArrayIndexOutOfBoundsException aioob) { - throw new ConfigParseError("Could not parse netmask of route " + netmask); - } catch (NumberFormatException ne) { - - + routeopt += cidr.toString() + " "; + } catch (ArrayIndexOutOfBoundsException aioob) { + throw new ConfigParseError("Could not parse netmask of route " + netmask); + } catch (NumberFormatException ne) { - throw new ConfigParseError("Could not parse netmask of route " + netmask); - } + throw new ConfigParseError("Could not parse netmask of route " + netmask); + } - } - np.mCustomRoutes=routeopt; - np.mExcludedRoutes=routeExcluded; - } + } + np.mCustomRoutes = routeopt; + np.mExcludedRoutes = routeExcluded; + } Vector> routesV6 = getAllOption("route-ipv6", 1, 4); - if (routesV6!=null) { + if (routesV6 != null) { String customIPv6Routes = ""; - for (Vector route:routesV6){ + for (Vector route : routesV6) { customIPv6Routes += route.get(1) + " "; } @@ -397,39 +378,36 @@ public class ConfigParser { } // Also recognize tls-auth [inline] direction ... - Vector> tlsauthoptions = getAllOption("tls-auth", 1, 2); - if(tlsauthoptions!=null) { - for(Vector tlsauth:tlsauthoptions) { - if(tlsauth!=null) - { - if(!tlsauth.get(1).equals("[inline]")) { - np.mTLSAuthFilename=tlsauth.get(1); - np.mUseTLSAuth=true; - } - if(tlsauth.size()==3) - np.mTLSAuthDirection=tlsauth.get(2); - } - } - } - - Vector direction = getOption("key-direction", 1, 1); - if(direction!=null) - np.mTLSAuthDirection=direction.get(1); + Vector> tlsauthoptions = getAllOption("tls-auth", 1, 2); + if (tlsauthoptions != null) { + for (Vector tlsauth : tlsauthoptions) { + if (tlsauth != null) { + if (!tlsauth.get(1).equals("[inline]")) { + np.mTLSAuthFilename = tlsauth.get(1); + np.mUseTLSAuth = true; + } + if (tlsauth.size() == 3) + np.mTLSAuthDirection = tlsauth.get(2); + } + } + } + + Vector direction = getOption("key-direction", 1, 1); + if (direction != null) + np.mTLSAuthDirection = direction.get(1); Vector> defgw = getAllOption("redirect-gateway", 0, 5); - if(defgw != null) - { - np.mUseDefaultRoute=true; + if (defgw != null) { + np.mUseDefaultRoute = true; checkRedirectParameters(np, defgw); } - Vector> redirectPrivate = getAllOption("redirect-private",0,5); - if (redirectPrivate != null) - { - checkRedirectParameters(np,redirectPrivate); + Vector> redirectPrivate = getAllOption("redirect-private", 0, 5); + if (redirectPrivate != null) { + checkRedirectParameters(np, redirectPrivate); } - Vector dev =getOption("dev",1,1); - Vector devtype =getOption("dev-type",1,1); + Vector dev = getOption("dev", 1, 1); + Vector devtype = getOption("dev-type", 1, 1); if ((devtype != null && devtype.get(1).equals("tun")) || (dev != null && dev.get(1).startsWith("tun")) || @@ -437,15 +415,15 @@ public class ConfigParser { //everything okay } else { throw new ConfigParseError("Sorry. Only tun mode is supported. See the FAQ for more detail"); - } + } - Vector mssfix = getOption("mssfix",0,1); + Vector mssfix = getOption("mssfix", 0, 1); - if (mssfix!=null) { - if (mssfix.size()>=2) { + if (mssfix != null) { + if (mssfix.size() >= 2) { try { - np.mMssFix=Integer.parseInt(mssfix.get(1)); - } catch(NumberFormatException e) { + np.mMssFix = Integer.parseInt(mssfix.get(1)); + } catch (NumberFormatException e) { throw new ConfigParseError("Argument to --mssfix has to be an integer"); } } else { @@ -454,172 +432,171 @@ public class ConfigParser { } - Vector mode =getOption("mode",1,1); - if (mode != null){ - if(!mode.get(1).equals("p2p")) - throw new ConfigParseError("Invalid mode for --mode specified, need p2p"); - } - - - - Vector> dhcpoptions = getAllOption("dhcp-option", 2, 2); - if(dhcpoptions!=null) { - for(Vector dhcpoption:dhcpoptions) { - String type=dhcpoption.get(1); - String arg = dhcpoption.get(2); - if(type.equals("DOMAIN")) { - np.mSearchDomain=dhcpoption.get(2); - } else if(type.equals("DNS")) { - np.mOverrideDNS=true; - if(np.mDNS1.equals(VpnProfile.DEFAULT_DNS1)) - np.mDNS1=arg; - else - np.mDNS2=arg; - } - } - } - - Vector ifconfig = getOption("ifconfig", 2, 2); - if(ifconfig!=null) { - try { - CIDRIP cidr = new CIDRIP(ifconfig.get(1), ifconfig.get(2)); - np.mIPv4Address=cidr.toString(); - } catch (NumberFormatException nfe) { - throw new ConfigParseError("Could not pase ifconfig IP address: " + nfe.getLocalizedMessage()); - } - - } - - if(getOption("remote-random-hostname", 0, 0)!=null) - np.mUseRandomHostname=true; - - if(getOption("float", 0, 0)!=null) - np.mUseFloat=true; - - if(getOption("comp-lzo", 0, 1)!=null) - np.mUseLzo=true; - - Vector cipher = getOption("cipher", 1, 1); - if(cipher!=null) - np.mCipher= cipher.get(1); - - Vector auth = getOption("auth", 1, 1); - if(auth!=null) - np.mAuth = auth.get(1); - - - Vector ca = getOption("ca",1,1); - if(ca!=null){ - np.mCaFilename = ca.get(1); - } - - Vector cert = getOption("cert",1,1); - if(cert!=null){ - np.mClientCertFilename = cert.get(1); - np.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; - noauthtypeset=false; - } - Vector key= getOption("key",1,1); - if(key!=null) - np.mClientKeyFilename=key.get(1); - - Vector pkcs12 = getOption("pkcs12",1,1); - if(pkcs12!=null) { - np.mPKCS12Filename = pkcs12.get(1); - np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; - noauthtypeset=false; - } - - Vector cryptoapicert = getOption("cryptoapicert",1,1); - if(cryptoapicert!=null) { + Vector mode = getOption("mode", 1, 1); + if (mode != null) { + if (!mode.get(1).equals("p2p")) + throw new ConfigParseError("Invalid mode for --mode specified, need p2p"); + } + + + Vector> dhcpoptions = getAllOption("dhcp-option", 2, 2); + if (dhcpoptions != null) { + for (Vector dhcpoption : dhcpoptions) { + String type = dhcpoption.get(1); + String arg = dhcpoption.get(2); + if (type.equals("DOMAIN")) { + np.mSearchDomain = dhcpoption.get(2); + } else if (type.equals("DNS")) { + np.mOverrideDNS = true; + if (np.mDNS1.equals(VpnProfile.DEFAULT_DNS1)) + np.mDNS1 = arg; + else + np.mDNS2 = arg; + } + } + } + + Vector ifconfig = getOption("ifconfig", 2, 2); + if (ifconfig != null) { + try { + CIDRIP cidr = new CIDRIP(ifconfig.get(1), ifconfig.get(2)); + np.mIPv4Address = cidr.toString(); + } catch (NumberFormatException nfe) { + throw new ConfigParseError("Could not pase ifconfig IP address: " + nfe.getLocalizedMessage()); + } + + } + + if (getOption("remote-random-hostname", 0, 0) != null) + np.mUseRandomHostname = true; + + if (getOption("float", 0, 0) != null) + np.mUseFloat = true; + + if (getOption("comp-lzo", 0, 1) != null) + np.mUseLzo = true; + + Vector cipher = getOption("cipher", 1, 1); + if (cipher != null) + np.mCipher = cipher.get(1); + + Vector auth = getOption("auth", 1, 1); + if (auth != null) + np.mAuth = auth.get(1); + + + Vector ca = getOption("ca", 1, 1); + if (ca != null) { + np.mCaFilename = ca.get(1); + } + + Vector cert = getOption("cert", 1, 1); + if (cert != null) { + np.mClientCertFilename = cert.get(1); + np.mAuthenticationType = VpnProfile.TYPE_CERTIFICATES; + noauthtypeset = false; + } + Vector key = getOption("key", 1, 1); + if (key != null) + np.mClientKeyFilename = key.get(1); + + Vector pkcs12 = getOption("pkcs12", 1, 1); + if (pkcs12 != null) { + np.mPKCS12Filename = pkcs12.get(1); np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; - noauthtypeset=false; + noauthtypeset = false; } - Vector compatnames = getOption("compat-names",1,2); - Vector nonameremapping = getOption("no-name-remapping",1,1); - Vector tlsremote = getOption("tls-remote",1,1); - if(tlsremote!=null){ - np.mRemoteCN = tlsremote.get(1); - np.mCheckRemoteCN=true; - np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE; + Vector cryptoapicert = getOption("cryptoapicert", 1, 1); + if (cryptoapicert != null) { + np.mAuthenticationType = VpnProfile.TYPE_KEYSTORE; + noauthtypeset = false; + } - if((compatnames!=null && compatnames.size() > 2) || - (nonameremapping!=null)) - np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING; - } + Vector compatnames = getOption("compat-names", 1, 2); + Vector nonameremapping = getOption("no-name-remapping", 1, 1); + Vector tlsremote = getOption("tls-remote", 1, 1); + if (tlsremote != null) { + np.mRemoteCN = tlsremote.get(1); + np.mCheckRemoteCN = true; + np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE; + + if ((compatnames != null && compatnames.size() > 2) || + (nonameremapping != null)) + np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_COMPAT_NOREMAPPING; + } - Vector verifyx509name = getOption("verify-x509-name",1,2); - if(verifyx509name!=null){ - np.mRemoteCN = verifyx509name.get(1); - np.mCheckRemoteCN=true; - if(verifyx509name.size()>2) { - if (verifyx509name.get(2).equals("name")) - np.mX509AuthType=VpnProfile.X509_VERIFY_TLSREMOTE_RDN; - else if (verifyx509name.get(2).equals("name-prefix")) - np.mX509AuthType=VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX; - else - throw new ConfigParseError("Unknown parameter to x509-verify-name: " + verifyx509name.get(2) ); - } else { - np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_DN; - } + Vector verifyx509name = getOption("verify-x509-name", 1, 2); + if (verifyx509name != null) { + np.mRemoteCN = verifyx509name.get(1); + np.mCheckRemoteCN = true; + if (verifyx509name.size() > 2) { + if (verifyx509name.get(2).equals("name")) + np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_RDN; + else if (verifyx509name.get(2).equals("name-prefix")) + np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_RDN_PREFIX; + else + throw new ConfigParseError("Unknown parameter to x509-verify-name: " + verifyx509name.get(2)); + } else { + np.mX509AuthType = VpnProfile.X509_VERIFY_TLSREMOTE_DN; + } - } + } - Vector verb = getOption("verb",1,1); - if(verb!=null){ - np.mVerb=verb.get(1); - } + Vector verb = getOption("verb", 1, 1); + if (verb != null) { + np.mVerb = verb.get(1); + } - if(getOption("nobind", 0, 0) != null) - np.mNobind=true; + if (getOption("nobind", 0, 0) != null) + np.mNobind = true; - if(getOption("persist-tun", 0,0) != null) - np.mPersistTun=true; + if (getOption("persist-tun", 0, 0) != null) + np.mPersistTun = true; - Vector connectretry = getOption("connect-retry", 1, 1); - if(connectretry!=null) - np.mConnectRetry =connectretry.get(1); + Vector connectretry = getOption("connect-retry", 1, 1); + if (connectretry != null) + np.mConnectRetry = connectretry.get(1); - Vector connectretrymax = getOption("connect-retry-max", 1, 1); - if(connectretrymax!=null) - np.mConnectRetryMax =connectretrymax.get(1); + Vector connectretrymax = getOption("connect-retry-max", 1, 1); + if (connectretrymax != null) + np.mConnectRetryMax = connectretrymax.get(1); Vector> remotetls = getAllOption("remote-cert-tls", 1, 1); - if(remotetls!=null) - if(remotetls.get(0).get(1).equals("server")) - np.mExpectTLSCert=true; - else - options.put("remotetls",remotetls); - - Vector authuser = getOption("auth-user-pass",0,1); - if(authuser !=null){ - if(noauthtypeset) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS; - } else if(np.mAuthenticationType==VpnProfile.TYPE_CERTIFICATES) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS_CERTIFICATES; - } else if(np.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) { - np.mAuthenticationType=VpnProfile.TYPE_USERPASS_KEYSTORE; - } - if(authuser.size()>1) { - // Set option value to password get to embed later. - np.mUsername=null; - useEmbbedUserAuth(np, authuser.get(1)); - } - } + if (remotetls != null) + if (remotetls.get(0).get(1).equals("server")) + np.mExpectTLSCert = true; + else + options.put("remotetls", remotetls); + + Vector authuser = getOption("auth-user-pass", 0, 1); + if (authuser != null) { + if (noauthtypeset) { + np.mAuthenticationType = VpnProfile.TYPE_USERPASS; + } else if (np.mAuthenticationType == VpnProfile.TYPE_CERTIFICATES) { + np.mAuthenticationType = VpnProfile.TYPE_USERPASS_CERTIFICATES; + } else if (np.mAuthenticationType == VpnProfile.TYPE_KEYSTORE) { + np.mAuthenticationType = VpnProfile.TYPE_USERPASS_KEYSTORE; + } + if (authuser.size() > 1) { + // Set option value to password get to embed later. + np.mUsername = null; + useEmbbedUserAuth(np, authuser.get(1)); + } + } Pair conns = parseConnectionOptions(null); - np.mConnections =conns.second; + np.mConnections = conns.second; Vector> connectionBlocks = getAllOption("connection", 1, 1); - if (np.mConnections.length > 0 && connectionBlocks !=null ) { - throw new ConfigParseError("Using a block and --remote is not allowed."); + if (np.mConnections.length > 0 && connectionBlocks != null) { + throw new ConfigParseError("Using a block and --remote is not allowed."); } - if (connectionBlocks!=null) { + if (connectionBlocks != null) { np.mConnections = new Connection[connectionBlocks.size()]; int connIndex = 0; @@ -633,43 +610,43 @@ public class ConfigParser { connIndex++; } } - if(getOption("remote-random", 0, 0) != null) - np.mRemoteRandom=true; + if (getOption("remote-random", 0, 0) != null) + np.mRemoteRandom = true; Vector protoforce = getOption("proto-force", 1, 1); - if(protoforce!=null) { + if (protoforce != null) { boolean disableUDP; String protoToDisable = protoforce.get(1); if (protoToDisable.equals("udp")) - disableUDP=true; + disableUDP = true; else if (protoToDisable.equals("tcp")) - disableUDP=false; + disableUDP = false; else throw new ConfigParseError(String.format("Unknown protocol %s in proto-force", protoToDisable)); - for (Connection conn:np.mConnections) - if(conn.mUseUdp==disableUDP) - conn.mEnabled=false; + for (Connection conn : np.mConnections) + if (conn.mUseUdp == disableUDP) + conn.mEnabled = false; } // Parse OpenVPN Access Server extra - Vector friendlyname = meta.get("FRIENDLY_NAME"); - if(friendlyname !=null && friendlyname.size() > 1) - np.mName=friendlyname.get(1); + Vector friendlyname = meta.get("FRIENDLY_NAME"); + if (friendlyname != null && friendlyname.size() > 1) + np.mName = friendlyname.get(1); - Vector ocusername = meta.get("USERNAME"); - if(ocusername !=null && ocusername.size() > 1) - np.mUsername=ocusername.get(1); + Vector ocusername = meta.get("USERNAME"); + if (ocusername != null && ocusername.size() > 1) + np.mUsername = ocusername.get(1); checkIgnoreAndInvalidOptions(np); - fixup(np); + fixup(np); - return np; - } + return np; + } private Pair parseConnection(String connection, Connection defaultValues) throws IOException, ConfigParseError { - // Parse a connection Block as a new configuration file + // Parse a connection Block as a new configuration file ConfigParser connectionParser = new ConfigParser(); @@ -683,7 +660,7 @@ public class ConfigParser { private Pair parseConnectionOptions(Connection connDefault) throws ConfigParseError { Connection conn; - if (connDefault!=null) + if (connDefault != null) try { conn = connDefault.clone(); } catch (CloneNotSupportedException e) { @@ -693,28 +670,28 @@ public class ConfigParser { else conn = new Connection(); - Vector port = getOption("port", 1,1); - if(port!=null){ + Vector port = getOption("port", 1, 1); + if (port != null) { conn.mServerPort = port.get(1); } - Vector rport = getOption("rport", 1,1); - if(rport!=null){ + Vector rport = getOption("rport", 1, 1); + if (rport != null) { conn.mServerPort = rport.get(1); } - Vector proto = getOption("proto", 1,1); - if(proto!=null){ - conn.mUseUdp=isUdpProto(proto.get(1)); + Vector proto = getOption("proto", 1, 1); + if (proto != null) { + conn.mUseUdp = isUdpProto(proto.get(1)); } // Parse remote config - Vector> remotes = getAllOption("remote",1,3); + Vector> remotes = getAllOption("remote", 1, 3); // Assume that we need custom options if connectionDefault are set - if(connDefault!=null) { + if (connDefault != null) { for (Vector> option : options.values()) { conn.mCustomConfiguration += getOptionStrings(option); @@ -724,14 +701,14 @@ public class ConfigParser { conn.mUseCustomConfig = true; } // Make remotes empty to simplify code - if (remotes==null) + if (remotes == null) remotes = new Vector>(); Connection[] connections = new Connection[remotes.size()]; - int i=0; - for (Vector remote: remotes) { + int i = 0; + for (Vector remote : remotes) { try { connections[i] = conn.clone(); } catch (CloneNotSupportedException e) { @@ -739,7 +716,7 @@ public class ConfigParser { } switch (remote.size()) { case 4: - connections[i].mUseUdp=isUdpProto(remote.get(3)); + connections[i].mUseUdp = isUdpProto(remote.get(3)); case 3: connections[i].mServerPort = remote.get(2); case 2: @@ -752,63 +729,60 @@ public class ConfigParser { } private void checkRedirectParameters(VpnProfile np, Vector> defgw) { - for (Vector redirect: defgw) - for (int i=1;i redirect : defgw) + for (int i = 1; i < redirect.size(); i++) { if (redirect.get(i).equals("block-local")) - np.mAllowLocalLAN=false; + np.mAllowLocalLAN = false; else if (redirect.get(i).equals("unblock-local")) - np.mAllowLocalLAN=true; + np.mAllowLocalLAN = true; } } - private boolean isUdpProto(String proto) throws ConfigParseError { - boolean isudp; - if(proto.equals("udp") || proto.equals("udp6")) - isudp=true; - else if (proto.equals("tcp-client") || - proto.equals("tcp") || - proto.equals("tcp6") || - proto.endsWith("tcp6-client")) - isudp =false; - else - throw new ConfigParseError("Unsupported option to --proto " + proto); - return isudp; - } - - static public void useEmbbedUserAuth(VpnProfile np, String inlinedata) - { - String data = VpnProfile.getEmbeddedContent(inlinedata); - String[] parts = data.split("\n"); - if(parts.length >= 2) { - np.mUsername=parts[0]; - np.mPassword=parts[1]; - } - } - - private void checkIgnoreAndInvalidOptions(VpnProfile np) throws ConfigParseError { - for(String option:unsupportedOptions) - if(options.containsKey(option)) - throw new ConfigParseError(String.format("Unsupported Option %s encountered in config file. Aborting",option)); + private boolean isUdpProto(String proto) throws ConfigParseError { + boolean isudp; + if (proto.equals("udp") || proto.equals("udp6")) + isudp = true; + else if (proto.equals("tcp-client") || + proto.equals("tcp") || + proto.equals("tcp6") || + proto.endsWith("tcp6-client")) + isudp = false; + else + throw new ConfigParseError("Unsupported option to --proto " + proto); + return isudp; + } - for(String option:ignoreOptions) - // removing an item which is not in the map is no error - options.remove(option); + static public void useEmbbedUserAuth(VpnProfile np, String inlinedata) { + String data = VpnProfile.getEmbeddedContent(inlinedata); + String[] parts = data.split("\n"); + if (parts.length >= 2) { + np.mUsername = parts[0]; + np.mPassword = parts[1]; + } + } + private void checkIgnoreAndInvalidOptions(VpnProfile np) throws ConfigParseError { + for (String option : unsupportedOptions) + if (options.containsKey(option)) + throw new ConfigParseError(String.format("Unsupported Option %s encountered in config file. Aborting", option)); + for (String option : ignoreOptions) + // removing an item which is not in the map is no error + options.remove(option); - if(options.size()> 0) { - np.mCustomConfigOptions += "# These Options were found in the config file do not map to config settings:\n"; + if (options.size() > 0) { + np.mCustomConfigOptions += "# These Options were found in the config file do not map to config settings:\n"; - for(Vector> option:options.values()) { + for (Vector> option : options.values()) { - np.mCustomConfigOptions += getOptionStrings(option); + np.mCustomConfigOptions += getOptionStrings(option); - } - np.mUseCustomConfig=true; + } + np.mUseCustomConfig = true; - } - } + } + } boolean ignoreThisOption(Vector option) { @@ -843,35 +817,35 @@ public class ConfigParser { private void fixup(VpnProfile np) { - if(np.mRemoteCN.equals(np.mServerName)) { - np.mRemoteCN=""; - } - } - - private Vector getOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector> alloptions = getAllOption(option, minarg, maxarg); - if(alloptions==null) - return null; - else - return alloptions.lastElement(); - } - - - private Vector> getAllOption(String option, int minarg, int maxarg) throws ConfigParseError { - Vector> args = options.get(option); - if(args==null) - return null; - - for(Vector optionline:args) - - if(optionline.size()< (minarg+1) || optionline.size() > maxarg+1) { - String err = String.format(Locale.getDefault(),"Option %s has %d parameters, expected between %d and %d", - option,optionline.size()-1,minarg,maxarg ); - throw new ConfigParseError(err); - } - options.remove(option); - return args; - } + if (np.mRemoteCN.equals(np.mServerName)) { + np.mRemoteCN = ""; + } + } + + private Vector getOption(String option, int minarg, int maxarg) throws ConfigParseError { + Vector> alloptions = getAllOption(option, minarg, maxarg); + if (alloptions == null) + return null; + else + return alloptions.lastElement(); + } + + + private Vector> getAllOption(String option, int minarg, int maxarg) throws ConfigParseError { + Vector> args = options.get(option); + if (args == null) + return null; + + for (Vector optionline : args) + + if (optionline.size() < (minarg + 1) || optionline.size() > maxarg + 1) { + String err = String.format(Locale.getDefault(), "Option %s has %d parameters, expected between %d and %d", + option, optionline.size() - 1, minarg, maxarg); + throw new ConfigParseError(err); + } + options.remove(option); + return args; + } } diff --git a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java index 26354689..c86f9e44 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java +++ b/app/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java @@ -172,8 +172,16 @@ public class NetworkSpace { } public boolean containsNet(ipAddress network) { - return getFirstAddress().compareTo(network.getFirstAddress()) != 1 && - getLastAddress().compareTo(network.getLastAddress()) != -1; + // this.first >= net.first && this.last <= net.last + BigInteger ourFirst = getFirstAddress(); + BigInteger ourLast = getLastAddress(); + BigInteger netFirst = network.getFirstAddress(); + BigInteger netLast = network.getLastAddress(); + + boolean a = ourFirst.compareTo(netFirst) != 1; + boolean b = ourLast.compareTo(netLast) != -1; + return a && b; + } } @@ -320,6 +328,7 @@ public class NetworkSpace { boolean skipIp=false; // If there is any smaller net that is excluded we may not add the positive route back + for (ipAddress calculatedIp: ipsSorted) { if(!calculatedIp.included && origIp.containsNet(calculatedIp)) { skipIp=true; diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 3cb5527b..3c1ec064 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -51,6 +51,8 @@ import static de.blinkt.openvpn.core.NetworkSpace.ipAddress; import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTED; import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; +import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NOTCONNECTED; +import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_NONETWORK; import se.leap.bitmaskclient.Dashboard; @@ -174,7 +176,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac mNotificationManager.notify(OPENVPN_STATUS, notification); - startForeground(OPENVPN_STATUS, notification); + //startForeground(OPENVPN_STATUS, notification); } private int getIconByConnectionStatus(ConnectionStatus level) { @@ -552,9 +554,15 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac Collection positiveIPv4Routes = mRoutes.getPositiveIPList(); Collection positiveIPv6Routes = mRoutesv6.getPositiveIPList(); + ipAddress multicastRange = new ipAddress(new CIDRIP("224.0.0.0", 3), true); + for (NetworkSpace.ipAddress route : positiveIPv4Routes) { try { - builder.addRoute(route.getIPv4Address(), route.networkMask); + + if (multicastRange.containsNet(route)) + VpnStatus.logDebug(R.string.ignore_multicast_route, route.toString()); + else + builder.addRoute(route.getIPv4Address(), route.networkMask); } catch (IllegalArgumentException ia) { VpnStatus.logError(getString(R.string.route_rejected) + route + " " + ia.getLocalizedMessage()); } @@ -607,7 +615,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac try { //Debug.stopMethodTracing(); - return builder.establish(); + ParcelFileDescriptor tun = builder.establish(); + if (tun==null) + throw new NullPointerException("Android establish() method returned null (Really broken network configuration?)"); + return tun; } catch (Exception e) { VpnStatus.logError(R.string.tun_open_error); VpnStatus.logError(getString(R.string.error) + e.getLocalizedMessage()); @@ -843,6 +854,21 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac mDisplayBytecount = true; mConnecttime = System.currentTimeMillis(); lowpriority = true; + if(mProfile.mPersistTun) { + NotificationManager ns = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + ns.cancel(OPENVPN_STATUS); + return; + } + } else if (level == LEVEL_NONETWORK || level == LEVEL_NOTCONNECTED) { + NotificationManager ns = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + ns.cancel(OPENVPN_STATUS); + return; + } else if (level != LEVEL_NOTCONNECTED && mConnecttime > 0) { + mDisplayBytecount = false; + String msg = "Traffic is blocked until the VPN becomes active."; + String ticker = msg; + showNotification(msg, ticker, lowpriority , 0, level); + return; } else { mDisplayBytecount = false; } @@ -876,7 +902,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac humanReadableByteCount(diffOut / OpenVPNManagement.mBytecountInterval, true)); boolean lowpriority = !mNotificationAlwaysVisible; - showNotification(netstat, null, lowpriority, mConnecttime, LEVEL_CONNECTED); + //showNotification(netstat, null, lowpriority, mConnecttime, LEVEL_CONNECTED); } } -- cgit v1.2.3