From d6190becb1c48ee912b11a4206116d0fd4c90772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 20 Dec 2014 20:14:23 +0100 Subject: Update ics-openvpn to 1006 --- .../java/de/blinkt/openvpn/core/ConfigParser.java | 280 +++++++++++++-------- 1 file changed, 182 insertions(+), 98 deletions(-) (limited to 'app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java') 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 0d8230b7..5dc96bbc 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java +++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java @@ -1,13 +1,17 @@ /* * Copyright (c) 2012-2014 Arne Schwabe - * Distributed under the GNU GPL v2. For full terms see the file doc/LICENSE.txt + * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt */ package de.blinkt.openvpn.core; +import android.text.TextUtils; +import android.util.Pair; + import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; +import java.io.StringReader; import java.util.Collections; import java.util.HashMap; import java.util.Locale; @@ -28,48 +32,49 @@ public class ConfigParser { private HashMap>> options = new HashMap>>(); private HashMap> meta = new HashMap>(); - - private boolean extraRemotesAsCustom=false; - public void parseConfig(Reader reader) throws IOException, ConfigParseError { - BufferedReader br =new BufferedReader(reader); + BufferedReader br = new BufferedReader(reader); - int lineno=0; - while (true){ - String line = br.readLine(); - lineno++; - if(line==null) - break; + int lineno = 0; + try { + while (true) { + String line = br.readLine(); + lineno++; + if (line == null) + break; - if (lineno==1 && (line.startsWith("PK\003\004") - || (line.startsWith("PK\007\008")))) + if (lineno == 1 && (line.startsWith("PK\003\004") + || (line.startsWith("PK\007\008")))) throw new ConfigParseError("Input looks like a ZIP Archive. Import is only possible for OpenVPN config files (.ovpn/.conf)"); - // Check for OpenVPN Access Server Meta information - if (line.startsWith("# OVPN_ACCESS_SERVER_")) { - Vector metaarg = parsemeta(line); - meta.put(metaarg.get(0),metaarg); - continue; - } - Vector args = parseline(line); + // Check for OpenVPN Access Server Meta information + if (line.startsWith("# OVPN_ACCESS_SERVER_")) { + Vector metaarg = parsemeta(line); + meta.put(metaarg.get(0), metaarg); + continue; + } + Vector args = parseline(line); - if(args.size() ==0) - continue; + if (args.size() == 0) + continue; - if(args.get(0).startsWith("--")) - args.set(0, args.get(0).substring(2)); + if (args.get(0).startsWith("--")) + args.set(0, args.get(0).substring(2)); - checkinlinefile(args,br); + checkinlinefile(args, br); - String optionname = args.get(0); - if(!options.containsKey(optionname)) { - options.put(optionname, new Vector>()); - } - options.get(optionname).add(args); - } + String optionname = args.get(0); + if (!options.containsKey(optionname)) { + options.put(optionname, new Vector>()); + } + options.get(optionname).add(args); + } + } catch (java.lang.OutOfMemoryError memoryError) { + throw new ConfigParseError("File too large to parse: " + memoryError.getLocalizedMessage()); + } } private Vector parsemeta(String line) { @@ -98,7 +103,7 @@ public class ConfigParser { break; else { inlinefile+=line; - inlinefile+= "\n"; + inlinefile+= "\n"; } } while(true); @@ -132,7 +137,7 @@ public class ConfigParser { // adapted openvpn's parse function to java private Vector parseline(String line) throws ConfigParseError { - Vector parameters = new Vector(); + Vector parameters = new Vector(); if (line.length()==0) return parameters; @@ -145,12 +150,12 @@ public class ConfigParser { int pos=0; String currentarg=""; - do { + do { // Emulate the c parsing ... char in; if(pos < line.length()) in = line.charAt(pos); - else + else in = '\0'; if (!backslash && in == '\\' && state != linestate.readin_single_quote) @@ -228,10 +233,7 @@ public class ConfigParser { } - final String[] unsupportedOptions = { "config", - "connection", - "proto-force", - "remote-random", + final String[] unsupportedOptions = { "config", "tls-server" }; @@ -299,7 +301,7 @@ public class ConfigParser { "remote", "float", "port", -// "connect-retry", + "connect-retry", "connect-timeout", "connect-retry-max", "link-mtu", @@ -325,7 +327,7 @@ public class ConfigParser { // This method is far too long @SuppressWarnings("ConstantConditions") - public VpnProfile convertProfile() throws ConfigParseError{ + public VpnProfile convertProfile() throws ConfigParseError, IOException { boolean noauthtypeset=true; VpnProfile np = new VpnProfile(CONVERTED_PROFILE); // Pull, client, tls-client @@ -338,7 +340,7 @@ public class ConfigParser { } Vector secret = getOption("secret", 1, 2); - if(secret!=null) + if(secret!=null) { np.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; noauthtypeset=false; @@ -362,7 +364,7 @@ public class ConfigParser { if (route.size() >= 4) gateway = route.get(3); - String net = route.get(1); + String net = route.get(1); try { CIDRIP cidr = new CIDRIP(net, netmask); if (gateway.equals("net_gateway")) @@ -398,7 +400,7 @@ public class ConfigParser { Vector> tlsauthoptions = getAllOption("tls-auth", 1, 2); if(tlsauthoptions!=null) { for(Vector tlsauth:tlsauthoptions) { - if(tlsauth!=null) + if(tlsauth!=null) { if(!tlsauth.get(1).equals("[inline]")) { np.mTLSAuthFilename=tlsauth.get(1); @@ -458,36 +460,6 @@ public class ConfigParser { throw new ConfigParseError("Invalid mode for --mode specified, need p2p"); } - Vector port = getOption("port", 1,1); - if(port!=null){ - np.mServerPort = port.get(1); - } - - Vector rport = getOption("rport", 1,1); - if(rport!=null){ - np.mServerPort = rport.get(1); - } - - Vector proto = getOption("proto", 1,1); - if(proto!=null){ - np.mUseUdp=isUdpProto(proto.get(1)); - } - - // Parse remote config - Vector> remotes = getAllOption("remote",1,3); - - if(remotes!=null && remotes.size()>=1 ) { - Vector remote = remotes.get(0); - switch (remote.size()) { - case 4: - np.mUseUdp=isUdpProto(remote.get(3)); - case 3: - np.mServerPort = remote.get(2); - case 2: - np.mServerName = remote.get(1); - } - } - Vector> dhcpoptions = getAllOption("dhcp-option", 2, 2); @@ -581,18 +553,18 @@ public class ConfigParser { if(verifyx509name!=null){ np.mRemoteCN = verifyx509name.get(1); np.mCheckRemoteCN=true; - if(verifyx509name.size()>2) { + 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 + 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); @@ -615,7 +587,7 @@ public class ConfigParser { if(connectretrymax!=null) np.mConnectRetryMax =connectretrymax.get(1); - Vector> remotetls = getAllOption("remote-cert-tls", 1, 1); + Vector> remotetls = getAllOption("remote-cert-tls", 1, 1); if(remotetls!=null) if(remotetls.get(0).get(1).equals("server")) np.mExpectTLSCert=true; @@ -632,14 +604,55 @@ public class ConfigParser { np.mAuthenticationType=VpnProfile.TYPE_USERPASS_KEYSTORE; } if(authuser.size()>1) { - // Set option value to password get to get cance to embed later. + // Set option value to password get to embed later. np.mUsername=null; - np.mPassword=authuser.get(1); - useEmbbedUserAuth(np,authuser.get(1)); + useEmbbedUserAuth(np, authuser.get(1)); } } - // Parse OpenVPN Access Server extra + Pair conns = parseConnectionOptions(null); + 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 (connectionBlocks!=null) { + np.mConnections = new Connection[connectionBlocks.size()]; + + int connIndex = 0; + for (Vector conn : connectionBlocks) { + Pair connectionBlockConnection = + parseConnection(conn.get(1), conns.first); + + if (connectionBlockConnection.second.length != 1) + throw new ConfigParseError("A block must have exactly one remote"); + np.mConnections[connIndex] = connectionBlockConnection.second[0]; + connIndex++; + } + } + if(getOption("remote-random", 0, 0) != null) + np.mRemoteRandom=true; + + Vector protoforce = getOption("proto-force", 1, 1); + if(protoforce!=null) { + boolean disableUDP; + String protoToDisable = protoforce.get(1); + if (protoToDisable.equals("udp")) + disableUDP=true; + else if (protoToDisable.equals("tcp")) + 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; + } + + // Parse OpenVPN Access Server extra Vector friendlyname = meta.get("FRIENDLY_NAME"); if(friendlyname !=null && friendlyname.size() > 1) np.mName=friendlyname.get(1); @@ -649,20 +662,95 @@ public class ConfigParser { if(ocusername !=null && ocusername.size() > 1) np.mUsername=ocusername.get(1); - // Check the other options - if(remotes !=null && remotes.size()>1 && extraRemotesAsCustom) { - // first is already added - remotes.remove(0); - np.mCustomConfigOptions += getOptionStrings(remotes); - np.mUseCustomConfig=true; - - } - checkIgnoreAndInvalidOptions(np); + checkIgnoreAndInvalidOptions(np); fixup(np); return np; } + private Pair parseConnection(String connection, Connection defaultValues) throws IOException, ConfigParseError { + // Parse a connection Block as a new configuration file + + + ConfigParser connectionParser = new ConfigParser(); + StringReader reader = new StringReader(connection.substring(VpnProfile.INLINE_TAG.length())); + connectionParser.parseConfig(reader); + + Pair conn = connectionParser.parseConnectionOptions(defaultValues); + + return conn; + } + + private Pair parseConnectionOptions(Connection connDefault) throws ConfigParseError { + Connection conn; + if (connDefault!=null) + try { + conn = connDefault.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + return null; + } + else + conn = new Connection(); + + Vector port = getOption("port", 1,1); + if(port!=null){ + conn.mServerPort = port.get(1); + } + + 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)); + } + + + // Parse remote config + Vector> remotes = getAllOption("remote",1,3); + + + // Assume that we need custom options if connectionDefault are set + if(connDefault!=null) { + for (Vector> option : options.values()) { + + conn.mCustomConfiguration += getOptionStrings(option); + + } + if (!TextUtils.isEmpty(conn.mCustomConfiguration)) + conn.mUseCustomConfig = true; + } + // Make remotes empty to simplify code + if (remotes==null) + remotes = new Vector>(); + + Connection[] connections = new Connection[remotes.size()]; + + + int i=0; + for (Vector remote: remotes) { + try { + connections[i] = conn.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + switch (remote.size()) { + case 4: + connections[i].mUseUdp=isUdpProto(remote.get(3)); + case 3: + connections[i].mServerPort = remote.get(2); + case 2: + connections[i].mServerName = remote.get(1); + } + i++; + } + return Pair.create(conn, connections); + + } + private void checkRedirectParameters(VpnProfile np, Vector> defgw) { for (Vector redirect: defgw) for (int i=1;i