[PATCH] openconnect: add initial support for openconnect ssl vpn.

openconnect at lakedaemon.net openconnect at lakedaemon.net
Thu Jul 14 21:38:54 EDT 2011


From: Jason Cooper <cyanogen at lakedaemon.net>


Signed-off-by: Jason Cooper <cyanogen at lakedaemon.net>
---
 core/res/res/values/strings.xml                    |    1 +
 .../com/android/server/vpn/OpenconnectService.java |  132 +++++++++++++++++
 .../com/android/server/vpn/VpnServiceBinder.java   |    6 +
 vpn/java/android/net/vpn/OpenconnectProfile.java   |  148 ++++++++++++++++++++
 vpn/java/android/net/vpn/VpnType.java              |    3 +-
 5 files changed, 289 insertions(+), 1 deletions(-)
 create mode 100644 packages/VpnServices/src/com/android/server/vpn/OpenconnectService.java
 create mode 100644 vpn/java/android/net/vpn/OpenconnectProfile.java

diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 967457d..b743825 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2358,6 +2358,7 @@
     <string name="l2tp_ipsec_psk_vpn_description">Pre-shared key based L2TP/IPSec VPN</string>
     <string name="l2tp_ipsec_crt_vpn_description">Certificate based L2TP/IPSec VPN</string>
     <string name="openvpn_vpn_description">OpenVPN SSL VPN</string>
+    <string name="openconnect_vpn_description">OpenConnect SSL VPN</string>
 
     <!-- Localized strings for WebView -->
     <!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
diff --git a/packages/VpnServices/src/com/android/server/vpn/OpenconnectService.java b/packages/VpnServices/src/com/android/server/vpn/OpenconnectService.java
new file mode 100644
index 0000000..e32a4c8
--- /dev/null
+++ b/packages/VpnServices/src/com/android/server/vpn/OpenconnectService.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011, Jason Cooper <cyanogen at lakedaemon.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * copied from OpenvpnService.java which was (same license):
+ *
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vpn;
+
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.net.vpn.OpenconnectProfile;
+import android.net.vpn.VpnManager;
+import android.security.Credentials;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * The service that manages the openconnect VPN connection.
+ */
+class OpenconnectService extends VpnService<OpenconnectProfile> {
+
+    private static final String OPENCONNECT_DAEMON = "openconnect";
+
+    private static final String MTPD = "mtpd";
+
+    private static final String USE_INLINE = "[[INLINE]]";
+
+    private static final String USE_KEYSTORE = "[[ANDROID]]";
+
+    private static final String TAG = OpenconnectService.class.getSimpleName();
+
+    private static int count = 0;
+
+    private transient String mPassword;
+
+    private transient String mUsername;
+
+    private synchronized static String getCount() {
+        return Integer.toString(count++);
+    }
+
+    @Override
+    protected void connect(String serverIp, String username, String password) throws IOException {
+        OpenconnectProfile p = getProfile();
+        ArrayList<String> args = new ArrayList<String>();
+	String url = "https://" + p.getServerName() + ":" + p.getPort();
+
+        mUsername = username;
+        mPassword = password;
+
+        args.add(OPENCONNECT_DAEMON);
+
+        if (p.getCAName() != null) {
+            args.add("--cafile");
+            args.add(USE_INLINE);
+            args.add(USE_KEYSTORE + Credentials.CA_CERTIFICATE + p.getCAName());
+        }
+        if (p.getCertName() != null) {
+            args.add("--certificate");
+            args.add(USE_INLINE);
+            args.add(USE_KEYSTORE + Credentials.USER_CERTIFICATE + p.getCertName());
+            args.add("--sslkey");
+            args.add(USE_INLINE);
+            args.add(USE_KEYSTORE + Credentials.USER_PRIVATE_KEY + p.getCertName());
+	    args.add("--key-type");
+	    args.add("PKCS#12");
+        }
+        if (! p.getUseCompression()) {
+            args.add("--no-deflate");
+        }
+        if (p.getUserAuth()) {
+            args.add("-u");
+            args.add(mUsername);
+            args.add("--passwd-on-stdin");
+            args.add(mPassword);
+        }
+        if (p.getExtra() != null && !p.getExtra().equals("")) {
+            Scanner s = new Scanner(p.getExtra());
+            while (s.hasNext())
+                args.add(s.next());
+        }
+	args.add(url);
+        DaemonProxy mtpd = getDaemons().startDaemon(MTPD);
+        mtpd.sendCommand(args.toArray(new String[args.size()]));
+    }
+
+    @Override
+    void waitUntilConnectedOrTimedout() throws IOException {
+        setVpnStateUp(true);
+    }
+
+    void startConnectivityMonitor() {
+        /*
+         * Openconnect is completely event driven, so we don't need a polling
+         * monitor at all, so do nothing here
+         */
+    }
+
+}
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
index 990da63..2c13a93 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
@@ -23,6 +23,7 @@ import android.net.vpn.L2tpIpsecProfile;
 import android.net.vpn.L2tpIpsecPskProfile;
 import android.net.vpn.L2tpProfile;
 import android.net.vpn.OpenvpnProfile;
+import android.net.vpn.OpenconnectProfile;
 import android.net.vpn.PptpProfile;
 import android.net.vpn.VpnManager;
 import android.net.vpn.VpnProfile;
@@ -168,6 +169,11 @@ public class VpnServiceBinder extends Service {
                 ovpn.setContext(this, (OpenvpnProfile)p );
                 return ovpn;
 
+            case OPENCONNECT:
+                OpenconnectService oconn = new OpenconnectService();
+                oconn.setContext(this, (OpenconnectProfile)p );
+                return oconn;
+
             case PPTP:
                 PptpService pptp = new PptpService();
                 pptp.setContext(this, (PptpProfile) p);
diff --git a/vpn/java/android/net/vpn/OpenconnectProfile.java b/vpn/java/android/net/vpn/OpenconnectProfile.java
new file mode 100644
index 0000000..f544354
--- /dev/null
+++ b/vpn/java/android/net/vpn/OpenconnectProfile.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011, Jason Cooper <cyanogen at lakedaemon.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * copied from OpenvpnProfile.java which was (same license):
+ *
+ * Copyright (C) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.vpn;
+
+import android.os.Parcel;
+
+/**
+ * The profile for OpenConnect type of VPN.
+ * {@hide}
+ */
+public class OpenconnectProfile extends VpnProfile {
+    private static final long serialVersionUID = 1L;
+
+    // Standard Settings
+    private boolean mUserAuth = true;
+
+    private String mCA;
+
+    private String mCert;
+
+    private String mSVRCert;
+
+    // Advanced Settings
+    private int mPort = 443;
+
+    private boolean mUseCompression = true;
+
+    private String mExtra;
+
+    @Override
+    public VpnType getType() {
+        return VpnType.OPENCONNECT;
+    }
+
+    public void setPort(String port) {
+        try {
+            mPort = Integer.parseInt(port);
+        } catch (NumberFormatException e) {
+            // no update
+        }
+    }
+
+    public String getPort() {
+        return Integer.toString(mPort);
+    }
+
+    public boolean getUserAuth() {
+        return mUserAuth;
+    }
+
+    public void setUserAuth(boolean auth) {
+        mUserAuth = auth;
+    }
+
+    public String getCAName() {
+        return mCA;
+    }
+
+    public void setCAName(String name) {
+        mCA = name;
+    }
+
+    public String getCertName() {
+        return mCert;
+    }
+
+    public void setCertName(String name) {
+        mCert = name;
+    }
+
+    public String getSVRCertName() {
+        return mSVRCert;
+    }
+
+    public void setSVRCertName(String name) {
+        mSVRCert = name;
+    }
+
+    public void setUseCompression(boolean b) {
+        mUseCompression = b;
+    }
+
+    public boolean getUseCompression() {
+        return mUseCompression;
+    }
+
+    public void setExtra(String extra) {
+        mExtra = extra;
+    }
+
+    public String getExtra() {
+        return mExtra;
+    }
+
+    @Override
+    protected void readFromParcel(Parcel in) {
+        super.readFromParcel(in);
+        mPort = in.readInt();
+        mCA = in.readString();
+        mCert = in.readString();
+        mSVRCert = in.readString();
+        mUseCompression = in.readInt() == 1;
+        mExtra = in.readString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        super.writeToParcel(parcel, flags);
+        parcel.writeInt(mPort);
+        parcel.writeString(mCA);
+        parcel.writeString(mCert);
+        parcel.writeString(mSVRCert);
+        parcel.writeInt(mUseCompression ? 1 : 0);
+        parcel.writeString(mExtra);
+    }
+}
diff --git a/vpn/java/android/net/vpn/VpnType.java b/vpn/java/android/net/vpn/VpnType.java
index 2157067..a486318 100644
--- a/vpn/java/android/net/vpn/VpnType.java
+++ b/vpn/java/android/net/vpn/VpnType.java
@@ -29,7 +29,8 @@ public enum VpnType {
             L2tpIpsecPskProfile.class),
     L2TP_IPSEC("L2TP/IPSec CRT", R.string.l2tp_ipsec_crt_vpn_description,
             L2tpIpsecProfile.class),
-    OPENVPN("OpenVPN", R.string.openvpn_vpn_description, OpenvpnProfile.class);
+    OPENVPN("OpenVPN", R.string.openvpn_vpn_description, OpenvpnProfile.class),
+    OPENCONNECT("OpenConnect", R.string.openconnect_vpn_description, OpenconnectProfile.class);
 
     private String mDisplayName;
     private int mDescriptionId;
-- 
1.7.0.4




More information about the openconnect-devel mailing list