]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
use setup_tun callback to defer printing connection status AND backgrounding until...
authorDaniel Lenski <dlenski@gmail.com>
Wed, 20 May 2020 05:06:34 +0000 (22:06 -0700)
committerDaniel Lenski <dlenski@gmail.com>
Wed, 20 May 2020 06:31:30 +0000 (23:31 -0700)
This will make scripted use of OpenConnect a lot less sensitive to timing of the tunnel
coming up, if a script is trying to use the tunnel as soon as the main process exits.
(See https://gitlab.com/openconnect/openconnect/-/issues/117 for examples.)

Here's a log of OpenConnect connecting to a GlobalProtect server where ESP
fails to start succesfully due to a firewall blocking UDP. With this
change, it doesn't print the connection status or go to background until after the
attempt to connect ESP has failed, and the tunnel has been started.

    $ echo PASSWORD | sudo ./openconnect -u USERNAME vpn.company.com/gateway --prot=gp --passwd-on-stdin -b \
                           -s echo +++ vpnc-script called with reason $reason
    POST https://vpn.company.com/ssl-vpn/prelogin.esp?tmp=tmp&clientVer=4100&clientos=Linux
    Connected to 1.2.3.4:443
    SSL negotiation with vpn.company.com
    Connected to HTTPS on vpn.company.com with ciphersuite (TLS1.2)-(RSA)-(AES-256-GCM)
    Enter login credentials
    POST https://vpn.company.com/ssl-vpn/login.esp
    POST https://vpn.company.com/ssl-vpn/getconfig.esp
    Session will expire after 1440 minutes.
    Tunnel timeout (rekey interval) is 180 minutes.
    Idle timeout is 180 minutes.
    No MTU received. Calculated 1214 for ESP tunnel
    POST https://vpn.company.com/ssl-vpn/hipreportcheck.esp
    Delaying tunnel for 1000 ms with reason: awaiting GPST ESP connection
    Delaying tunnel for 1000 ms with reason: awaiting GPST ESP connection
    Delaying tunnel for 1000 ms with reason: awaiting GPST ESP connection
    Delaying tunnel for 1000 ms with reason: awaiting GPST ESP connection
    Delaying tunnel for 1000 ms with reason: awaiting GPST ESP connection
    Delaying tunnel for 1000 ms with reason: awaiting GPST ESP connection
    Failed to connect ESP tunnel; using HTTPS instead.
    Connected as 10.0.1.2, using SSL, with ESP unsuccessful
    Continuing in background; pid 1234
    +++ vpnc-script called with reason pre-init
    +++ vpnc-script called with reason connect
    $

Here's an example of attempted DTLS connecting on an AnyConnect VPN, where DTLS
never succeeds. This right away gives us some good feedback that we could probably
reduce the duration of the loop:

    Connected to 1.2.3.4:443
    SSL negotiation with vpn.company.com
    Server certificate verify failed: signer not found
    Connected to HTTPS on vpn.company.com with ciphersuite (TLS1.2)-(ECDHE-RSA-SECP384R1)-(AES-256-GCM)
    Got CONNECT response: HTTP/1.1 200 OK
    CSTP connected. DPD 30, Keepalive 20
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    DTLS handshake failed: Resource temporarily unavailable, try again.
    Delaying tunnel for 1000 ms with reason: DTLS MTU detection
    Connected as 10.0.1.2, using SSL, with DTLS in progress

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
main.c
openconnect.h

diff --git a/main.c b/main.c
index 8080defb53cfe67e9cda09c258578519e9ccd6c6..cf60cd665df0cdbd589f36cef209d225123e0c2d 100644 (file)
--- a/main.c
+++ b/main.c
@@ -80,7 +80,9 @@ static void init_token(struct openconnect_info *vpninfo,
 
 static int verbose = PRG_INFO;
 static int timestamp;
-int background;
+static int background;
+static FILE *pid_fp = NULL;
+static char *pidfile = NULL;
 static int do_passphrase_from_fsid;
 static int non_inter;
 static int cookieonly;
@@ -1410,6 +1412,48 @@ static void print_connection_info(struct openconnect_info *vpninfo)
                     dtls_state);
 }
 
+static FILE *background_self(struct openconnect_info *vpninfo, char *pidfile) {
+       FILE *fp = NULL;
+       int pid;
+
+       /* Open the pidfile before forking, so we can report errors
+          more sanely. It's *possible* that we'll fail to write to
+          it, but very unlikely. */
+       if (pidfile != NULL) {
+               fp = openconnect_fopen_utf8(vpninfo, pidfile, "w");
+               if (!fp) {
+                       fprintf(stderr, _("Failed to open '%s' for write: %s\n"),
+                               pidfile, strerror(errno));
+                       openconnect_vpninfo_free(vpninfo);
+                       exit(1);
+               }
+       }
+       if ((pid = fork())) {
+               if (fp) {
+                       fprintf(fp, "%d\n", pid);
+                       fclose(fp);
+               }
+               vpn_progress(vpninfo, PRG_INFO,
+                            _("Continuing in background; pid %d\n"),
+                            pid);
+               openconnect_vpninfo_free(vpninfo);
+               exit(0);
+       }
+       if (fp)
+               fclose(fp);
+       return fp;
+}
+
+static void fully_up_cb(void *_vpninfo) {
+       struct openconnect_info *vpninfo = _vpninfo;
+
+       print_connection_info(vpninfo);
+#ifndef _WIN32
+       if (background)
+               pid_fp = background_self(vpninfo, pidfile);
+#endif
+}
+
 int main(int argc, char **argv)
 {
        struct openconnect_info *vpninfo;
@@ -1420,8 +1464,6 @@ int main(int argc, char **argv)
        char *vpnc_script = NULL;
        int autoproxy = 0;
        int opt;
-       char *pidfile = NULL;
-       FILE *fp = NULL;
        char *config_arg;
        char *config_filename;
        char *token_str = NULL;
@@ -1964,7 +2006,6 @@ int main(int argc, char **argv)
                fprintf(stderr, _("Set up UDP failed; using SSL instead\n"));
        }
 
-       print_connection_info(vpninfo);
 
        if (!vpninfo->vpnc_script) {
                vpn_progress(vpninfo, PRG_INFO,
@@ -1973,39 +2014,9 @@ int main(int argc, char **argv)
                             _("See http://www.infradead.org/openconnect/vpnc-script.html\n"));
        }
 
-#ifndef _WIN32
-       if (background) {
-               int pid;
-
-               /* Open the pidfile before forking, so we can report errors
-                  more sanely. It's *possible* that we'll fail to write to
-                  it, but very unlikely. */
-               if (pidfile != NULL) {
-                       fp = openconnect_fopen_utf8(vpninfo, pidfile, "w");
-                       if (!fp) {
-                               fprintf(stderr, _("Failed to open '%s' for write: %s\n"),
-                                       pidfile, strerror(errno));
-                               openconnect_vpninfo_free(vpninfo);
-                               exit(1);
-                       }
-               }
-               if ((pid = fork())) {
-                       if (fp) {
-                               fprintf(fp, "%d\n", pid);
-                               fclose(fp);
-                       }
-                       vpn_progress(vpninfo, PRG_INFO,
-                                    _("Continuing in background; pid %d\n"),
-                                    pid);
-                       openconnect_vpninfo_free(vpninfo);
-                       exit(0);
-               }
-               if (fp)
-                       fclose(fp);
-       }
-#endif
 
        openconnect_set_loglevel(vpninfo, verbose);
+       openconnect_set_setup_tun_handler(vpninfo, fully_up_cb);
 
        while (1) {
                ret = openconnect_mainloop(vpninfo, reconnect_timeout, RECONNECT_INTERVAL_MIN);
@@ -2015,7 +2026,7 @@ int main(int argc, char **argv)
                vpn_progress(vpninfo, PRG_INFO, _("User requested reconnect\n"));
        }
 
-       if (fp)
+       if (pid_fp)
                unlink(pidfile);
 
        switch (ret) {
index 2dbce891d2734b6c00b7e03053c4c1051b55a7e6..375d411f0464434d91cfda52ef34598cb85c5114 100644 (file)
@@ -691,7 +691,7 @@ typedef int (*openconnect_getaddrinfo_vfn) (void *privdata, const char *node, co
                                            const struct addrinfo *hints, struct addrinfo **res);
 void openconnect_override_getaddrinfo(struct openconnect_info *vpninfo, openconnect_getaddrinfo_vfn gai_fn);
 
-/* Callback for configuring the interface after MTU detection finishes. */
+/* Callback for configuring the interface after tunnel is fully up. */
 typedef void (*openconnect_setup_tun_vfn) (void *privdata);
 void openconnect_set_setup_tun_handler(struct openconnect_info *vpninfo,
                                       openconnect_setup_tun_vfn setup_tun);