From 613bca6f9dfcb6cdbfcaa9191db817c4ba96bcbb Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 2 Feb 2015 22:17:09 +0000 Subject: [PATCH] Implement oNCP reconnect Signed-off-by: David Woodhouse --- cstp.c | 37 +------------------------------------ esp.c | 3 ++- oncp.c | 20 ++++++++++++-------- openconnect-internal.h | 2 +- ssl.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/cstp.c b/cstp.c index 2f5dfc37..99fdbd0f 100644 --- a/cstp.c +++ b/cstp.c @@ -632,12 +632,6 @@ int cstp_connect(struct openconnect_info *vpninfo) static int cstp_reconnect(struct openconnect_info *vpninfo) { - int ret; - int timeout; - int interval; - - openconnect_close_https(vpninfo, 0); - if (vpninfo->cstp_compr == COMPR_DEFLATE) { /* Requeue the original packet that was deflated */ if (vpninfo->current_ssl_pkt == vpninfo->deflate_pkt) { @@ -648,37 +642,8 @@ static int cstp_reconnect(struct openconnect_info *vpninfo) inflateEnd(&vpninfo->inflate_strm); deflateEnd(&vpninfo->deflate_strm); } - timeout = vpninfo->reconnect_timeout; - interval = vpninfo->reconnect_interval; - free(vpninfo->dtls_pkt); - vpninfo->dtls_pkt = NULL; - free(vpninfo->tun_pkt); - vpninfo->tun_pkt = NULL; - - while ((ret = openconnect_make_cstp_connection(vpninfo))) { - if (timeout <= 0) - return ret; - if (ret == -EPERM) { - vpn_progress(vpninfo, PRG_ERR, - _("Cookie is no longer valid, ending session\n")); - return ret; - } - vpn_progress(vpninfo, PRG_INFO, - _("sleep %ds, remaining timeout %ds\n"), - interval, timeout); - poll_cmd_fd(vpninfo, interval); - if (vpninfo->got_cancel_cmd) - return -EINTR; - if (vpninfo->got_pause_cmd) - return 0; - timeout -= interval; - interval += vpninfo->reconnect_interval; - if (interval > RECONNECT_INTERVAL_MAX) - interval = RECONNECT_INTERVAL_MAX; - } - script_config_tun(vpninfo, "reconnect"); - return 0; + return ssl_reconnect(vpninfo); } int decompress_and_queue_packet(struct openconnect_info *vpninfo, diff --git a/esp.c b/esp.c index 6e76a7ec..f8890f42 100644 --- a/esp.c +++ b/esp.c @@ -230,7 +230,7 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout) if (vpninfo->dtls_state == DTLS_SLEEPING) { int when = vpninfo->new_dtls_started + vpninfo->dtls_attempt_period - time(NULL); - if (when <= 0) { + if (when <= 0 || vpninfo->dtls_need_reconnect) { vpn_progress(vpninfo, PRG_DEBUG, _("Send ESP probes\n")); esp_send_probes(vpninfo); when = vpninfo->dtls_attempt_period; @@ -410,6 +410,7 @@ void esp_close(struct openconnect_info *vpninfo) unmonitor_read_fd(vpninfo, dtls); unmonitor_write_fd(vpninfo, dtls); unmonitor_except_fd(vpninfo, dtls); + vpninfo->dtls_fd = -1; } vpninfo->dtls_state = DTLS_SLEEPING; } diff --git a/oncp.c b/oncp.c index e220ccef..f0b79155 100644 --- a/oncp.c +++ b/oncp.c @@ -1606,16 +1606,20 @@ int oncp_mainloop(struct openconnect_info *vpninfo, int *timeout) vpninfo->current_ssl_pkt->oncp.hdr, vpninfo->current_ssl_pkt->len + 22); if (ret < 0) { -#if 0 - goto do_reconnect; -#else do_reconnect: - vpn_progress(vpninfo, PRG_ERR, _("Reconnect not implemented yet for oNCP\n")); - vpninfo->quit_reason = "Need reconnect"; + /* XXX: Do we have to do this or can we leave it open? + * Perhaps we could even reconnect asynchronously while + * the ESP is still running? */ + esp_shutdown(vpninfo); + ret = ssl_reconnect(vpninfo); + if (ret) { + vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n")); + vpninfo->quit_reason = "oNCP reconnect failed"; + return ret; + } + vpninfo->dtls_need_reconnect = 1; return 1; -#endif - } - else if (!ret) { + } else if (!ret) { #if 0 /* Not for Juniper yet */ /* -EAGAIN: ssl_nonblock_write() will have added the SSL fd to ->select_wfds if appropriate, so we can just diff --git a/openconnect-internal.h b/openconnect-internal.h index d1c73425..a71211f6 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -801,7 +801,7 @@ FILE *openconnect_fopen_utf8(struct openconnect_info *vpninfo, const char *fname, const char *mode); int udp_sockaddr(struct openconnect_info *vpninfo, int port); int udp_connect(struct openconnect_info *vpninfo); - +int ssl_reconnect(struct openconnect_info *vpninfo); void openconnect_clear_cookies(struct openconnect_info *vpninfo); /* openssl-pkcs11.c */ diff --git a/ssl.c b/ssl.c index e8c57893..84e32a8e 100644 --- a/ssl.c +++ b/ssl.c @@ -884,3 +884,45 @@ int udp_connect(struct openconnect_info *vpninfo) return fd; } + +int ssl_reconnect(struct openconnect_info *vpninfo) +{ + int ret; + int timeout; + int interval; + + openconnect_close_https(vpninfo, 0); + + + timeout = vpninfo->reconnect_timeout; + interval = vpninfo->reconnect_interval; + + free(vpninfo->dtls_pkt); + vpninfo->dtls_pkt = NULL; + free(vpninfo->tun_pkt); + vpninfo->tun_pkt = NULL; + + while ((ret = vpninfo->proto.tcp_connect(vpninfo))) { + if (timeout <= 0) + return ret; + if (ret == -EPERM) { + vpn_progress(vpninfo, PRG_ERR, + _("Cookie is no longer valid, ending session\n")); + return ret; + } + vpn_progress(vpninfo, PRG_INFO, + _("sleep %ds, remaining timeout %ds\n"), + interval, timeout); + poll_cmd_fd(vpninfo, interval); + if (vpninfo->got_cancel_cmd) + return -EINTR; + if (vpninfo->got_pause_cmd) + return 0; + timeout -= interval; + interval += vpninfo->reconnect_interval; + if (interval > RECONNECT_INTERVAL_MAX) + interval = RECONNECT_INTERVAL_MAX; + } + script_config_tun(vpninfo, "reconnect"); + return 0; +}