cernekee / ics-openconnect

Android UI for OpenConnect VPN client
GNU General Public License v2.0
369 stars 130 forks source link

Support non-AnyConnect protocols via libopenconnect API #28

Open dlenski opened 6 years ago

dlenski commented 6 years ago

As of dlenski/openconnect@40802e459873e55eefbe64f05b9475821f761b8e (not yet in an official openconnect release) there is a new API to get the list of supported protocols, along with their descriptions and supporting features.

int openconnect_get_supported_protocols(struct oc_vpn_proto **protos);
void openconnect_free_supported_protocols(struct oc_vpn_proto *protos);
int openconnect_set_protocol(struct openconnect_info *vpninfo, const char *protocol);

The next OpenConnect release should include this API along with (optimistically :grinning:) support for GlobalProtect VPNs (gp) in addition to AnyConnect and Juniper (nc).

In the NetworkManagerOpenconnect frontend, it was quite straightforward (https://git.gnome.org/browse/network-manager-openconnect/commit/?id=1ed6de801a398887277fbb9c35d9f5f5d6c4d5c3) to add multiprotocol support using this API, and it's underway on the Windows openconnect-gui as well (openconnect/openconnect-gui#158).

Are you interested in adding multiprotocol support the Android front-end as well?

From my perusal of your code, it appears that it's clean and only interfaces with libopenconnect using the public API :+1: :+1:. One minor exception that I see is that you use the AnyConnect-specific X-CSTP-Idle-Timeout option as a hint for how often the keepalive function should run.

cernekee commented 6 years ago

How does the auth-dialog flow look on those protocols? That's the part of the app I've been most reluctant to touch, since it's so hairy.

I would have figured that the configuration options (like CSD) would vary per-protocol, too? Any other UI changes?

dlenski commented 6 years ago

How does the auth-dialog flow look on those protocols? That's the part of the app I've been most reluctant to touch, since it's so hairy.

Yeah, that code is hairy in all the front-ends :frowning_face:. Fortunately, the auth-dialog flow is essentially identical, building up a form structure that's the same as what is used for AnyConnect. After adding multi-protocol support to the NM plugin, Juniper and GlobalProtect login forms "just worked." (username/password fields may be named differently, but this shouldn't affect the behavior of the front-ends, because the field types, e.g. OC_FORM_OPT_TEXT, are named similarly.)

CSD is similar. Juniper uses a mechanism called TNCC and GlobalProtect uses one called HIP, which are essentially equivalent to CSD and can similarly be invoked by wrapper scripts. One tricky detail is that, for GlobalProtect, the HIP script has to be executed during the connection phase, rather than the authentication phase… I mentioned this on the official mailing list a few months ago, and wrote a quick-and-dirty patch for the NM plugin to support it.

Other than that, the non-AnyConnect protocols pretty much work identically. They set the routing environment variables identically, etc.

dlenski commented 6 years ago

One tricky detail is that, for GlobalProtect, the HIP script has to be executed during the connection phase, rather than the authentication phase… I mentioned this on the official mailing list a few months ago, and wrote a quick-and-dirty patch for the NM plugin to support it.

Actually, I don't think this will cause any problems at all for the Android plugin, because you're doing both the authentication and the connection phase in a single process, so all the required configuration variables will be there. :+1:

cernekee commented 6 years ago

For AnyConnect, the Android client uses a static CSD script that posts the right incantation to the Cisco-specific URL. It's not configurable.

If we skip TNCC/HIP for now, what is the expected impact on users?

dlenski commented 6 years ago

Ah, interesting. An equally simple shell script works for GP (it literally does nothing but output an XML blob to stdout, filled in with a few environment variables).

In my experience, few Juniper VPNs use TNCC, so even without TNCC support I think it would be useful.

dlenski commented 6 years ago

tl;dr If you just openconnect_set_protocol, almost everything will Just Work.

The only expected exception is CSD/HIP/TNCC.

dlenski commented 6 years ago

I added support for the multi-protocol API to the Java bindings and test application… also sent this to the mailing list.

See this diff: https://github.com/dlenski/openconnect/compare/2f270d251800a0a7a3beecc27990ca06d66a300f...master

    public static final int OC_PROTO_PROXY = 1;
    public static final int OC_PROTO_CSD = 2;
    public static final int OC_PROTO_AUTH_CERT = 4;
    public static final int OC_PROTO_AUTH_OTP = 8;
    public static final int OC_PROTO_AUTH_STOKEN = 16;

    public static class VPNProto {
        public String name;
        public String prettyName;
        public String description;
        public int flags;
    };

    public static native VPNProto[] getSupportedProtocols();
    public synchronized native String getProtocol();
    public synchronized native int setProtocol(String protocol);

I can now connect to a GlobalProtect or Juniper server using the Java test application. :grinning: :beer:

If we skip TNCC/HIP for now, what is the expected impact on users?

At least for GlobalProtect, adding support for HIP to the Android application should now be as simple as putting hipreport.sh into the Android application as csd-gp.sh (alongside csd-anyconnect.sh).

        String csd_wrapper = "./csd-" + lib.getProtocol() + ".sh";