Skip to content

Commit

Permalink
Merge branch 'delay_tunnel_and_close' into 'master'
Browse files Browse the repository at this point in the history
delay_tunnel_reason and delay_close

See merge request openconnect/openconnect!117
  • Loading branch information
dlenski committed Nov 17, 2020
2 parents cc98dc5 + 41b3e29 commit e2c5b73
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 81 deletions.
2 changes: 2 additions & 0 deletions cstp.c
Expand Up @@ -348,6 +348,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
buf_free(dtls12_cl);
}
append_compr_types(reqbuf, "DTLS", vpninfo->req_compr & ~COMPR_DEFLATE);

vpninfo->delay_tunnel_reason = "DTLS MTU detection";
}
#endif
buf_append(reqbuf, "\r\n");
Expand Down
2 changes: 1 addition & 1 deletion dtls.c
Expand Up @@ -287,6 +287,7 @@ int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)

if (vpninfo->dtls_state == DTLS_CONNECTING) {
dtls_try_handshake(vpninfo);
vpninfo->delay_tunnel_reason = "DTLS MTU detection";
return 0;
}

Expand Down Expand Up @@ -712,4 +713,3 @@ void dtls_detect_mtu(struct openconnect_info *vpninfo)
skip_mtu:
free(buf);
}

8 changes: 6 additions & 2 deletions gpst.c
Expand Up @@ -567,9 +567,11 @@ static int gpst_parse_config_xml(struct openconnect_info *vpninfo, xmlNode *xml_
}
if (openconnect_setup_esp_keys(vpninfo, 0))
vpn_progress(vpninfo, PRG_ERR, "Failed to setup ESP keys.\n");
else
else {
/* prevent race condition between esp_mainloop() and gpst_mainloop() timers */
vpninfo->dtls_times.last_rekey = time(&vpninfo->new_dtls_started);
vpninfo->delay_tunnel_reason = "awaiting GPST ESP connection";
}
}
#else
vpn_progress(vpninfo, PRG_DEBUG, _("Ignoring ESP keys since ESP support not available in this build\n"));
Expand Down Expand Up @@ -1077,8 +1079,10 @@ int gpst_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
case DTLS_SECRET:
case DTLS_SLEEPING:
/* Allow 5 seconds after configuration for ESP to start */
if (!ka_check_deadline(timeout, time(NULL), vpninfo->new_dtls_started + 5))
if (!ka_check_deadline(timeout, time(NULL), vpninfo->new_dtls_started + 5)) {
vpninfo->delay_tunnel_reason = "awaiting GPST ESP connection";
return 0;
}

/* ... before we switch to HTTPS instead */
vpn_progress(vpninfo, PRG_ERR,
Expand Down
146 changes: 97 additions & 49 deletions main.c
Expand Up @@ -80,7 +80,11 @@ static void init_token(struct openconnect_info *vpninfo,

static int verbose = PRG_INFO;
static int timestamp;
int background;
#ifndef _WIN32
static int background;
static FILE *pid_fp = NULL;
static char *pidfile = NULL;
#endif
static int do_passphrase_from_fsid;
static int non_inter;
static int cookieonly;
Expand Down Expand Up @@ -1379,20 +1383,98 @@ static int autocomplete(int argc, char **argv)
return 0;
}

static void print_connection_info(struct openconnect_info *vpninfo)
{
const struct oc_ip_info *ip_info;
const char *ssl_compr, *udp_compr, *dtls_state;

openconnect_get_ip_info(vpninfo, &ip_info, NULL, NULL);

switch (vpninfo->dtls_state) {
case DTLS_NOSECRET:
dtls_state = _("unsuccessful");
break;
case DTLS_SLEEPING:
case DTLS_SECRET:
dtls_state = _("in progress");
break;
case DTLS_DISABLED:
dtls_state = _("disabled");
break;
default:
dtls_state = _("connected");
}

ssl_compr = openconnect_get_cstp_compression(vpninfo);
udp_compr = openconnect_get_dtls_compression(vpninfo);
vpn_progress(vpninfo, PRG_INFO,
_("Connected as %s%s%s, using SSL%s%s, with %s%s%s %s\n"),
ip_info->addr?:"",
(ip_info->netmask6 && ip_info->addr) ? " + " : "",
ip_info->netmask6 ? : "",
ssl_compr ? " + " : "", ssl_compr ? : "",
vpninfo->proto->udp_protocol ? : "UDP", udp_compr ? " + " : "", udp_compr ? : "",
dtls_state);
}

#ifndef _WIN32
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);
}
}
pid = fork();
if (pid == -1) {
vpn_perror(vpninfo, "Failed to continue in background\n");
exit(1);
} else if (pid > 0) {
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;
}
#endif /* _WIN32 */

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;
char *urlpath = NULL;
struct oc_vpn_option *gai;
char *ip;
const char *ssl_compr, *udp_compr;
char *proxy = getenv("https_proxy");
char *vpnc_script = NULL;
const struct oc_ip_info *ip_info;
int autoproxy = 0;
int opt;
char *pidfile = NULL;
FILE *fp = NULL;
char *config_arg;
char *config_filename;
char *token_str = NULL;
Expand Down Expand Up @@ -1534,9 +1616,11 @@ int main(int argc, char **argv)
case OPT_CAFILE:
openconnect_set_cafile(vpninfo, dup_config_arg());
break;
#ifndef _WIN32
case OPT_PIDFILE:
pidfile = keep_config_arg();
break;
#endif
case OPT_PFS:
openconnect_set_pfs(vpninfo, 1);
break;
Expand Down Expand Up @@ -1932,7 +2016,6 @@ int main(int argc, char **argv)
fprintf(stderr, _("Set up UDP failed; using SSL instead\n"));
}

openconnect_get_ip_info(vpninfo, &ip_info, NULL, NULL);

#if !defined(_WIN32) && !defined(__native_client__)
if (use_syslog) {
Expand All @@ -1941,57 +2024,16 @@ int main(int argc, char **argv)
}
#endif /* !_WIN32 && !__native_client__ */

ssl_compr = openconnect_get_cstp_compression(vpninfo);
udp_compr = openconnect_get_dtls_compression(vpninfo);
vpn_progress(vpninfo, PRG_INFO,
_("Connected as %s%s%s, using SSL%s%s, with %s%s%s %s\n"),
ip_info->addr?:"",
(ip_info->netmask6 && ip_info->addr) ? " + " : "",
ip_info->netmask6 ? : "",
ssl_compr ? " + " : "", ssl_compr ? : "",
vpninfo->proto->udp_protocol ? : "UDP", udp_compr ? " + " : "", udp_compr ? : "",
(vpninfo->dtls_state == DTLS_DISABLED || vpninfo->dtls_state == DTLS_NOSECRET ? _("disabled") : _("in progress")));

if (!vpninfo->vpnc_script) {
vpn_progress(vpninfo, PRG_INFO,
_("No --script argument provided; DNS and routing are not configured\n"));
vpn_progress(vpninfo, PRG_INFO,
_("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);
Expand All @@ -2001,8 +2043,10 @@ int main(int argc, char **argv)
vpn_progress(vpninfo, PRG_INFO, _("User requested reconnect\n"));
}

if (fp)
#ifndef _WIN32
if (pid_fp)
unlink(pidfile);
#endif

out:
switch (ret) {
Expand All @@ -2022,6 +2066,10 @@ int main(int argc, char **argv)
vpn_progress(vpninfo, PRG_INFO, _("User detached from session (SIGHUP); exiting.\n"));
ret = 0;
break;
case -EIO:
vpn_progress(vpninfo, PRG_INFO, _("Unrecoverable I/O error; exiting.\n"));
ret = 1;
break;
default:
vpn_progress(vpninfo, PRG_ERR, _("Unknown error; exiting.\n"));
ret = 1;
Expand Down
75 changes: 47 additions & 28 deletions mainloop.c
Expand Up @@ -132,6 +132,8 @@ static int setup_tun_device(struct openconnect_info *vpninfo)
ret = openconnect_setup_tun_device(vpninfo, vpninfo->vpnc_script, vpninfo->ifname);
if (ret) {
fprintf(stderr, _("Set up tun device failed\n"));
if (!vpninfo->quit_reason)
vpninfo->quit_reason = "Set up tun device failed";
return ret;
}

Expand Down Expand Up @@ -204,29 +206,25 @@ int openconnect_mainloop(struct openconnect_info *vpninfo,
else
timeout = 1000;

if (vpninfo->dtls_state > DTLS_DISABLED) {
/* Postpone tun device creation after DTLS is connected so
* we have a better knowledge of the link MTU. We also
* force the creation if DTLS enters sleeping mode - i.e.,
* we failed to connect on time. */
if (!tun_is_up(vpninfo) && (vpninfo->dtls_state == DTLS_CONNECTED ||
vpninfo->dtls_state == DTLS_SLEEPING)) {
if (!tun_is_up(vpninfo)) {
if (vpninfo->delay_tunnel_reason) {
vpn_progress(vpninfo, PRG_TRACE, _("Delaying tunnel with reason: %s\n"),
vpninfo->delay_tunnel_reason);
/* XX: don't let this spin forever */
vpninfo->delay_tunnel_reason = NULL;
} else {
/* No DTLS, or DTLS failed; setup TUN device unconditionally */
ret = setup_tun_device(vpninfo);
if (ret) {
if (ret)
break;
}
}
}

if (vpninfo->dtls_state > DTLS_DISABLED) {
ret = vpninfo->proto->udp_mainloop(vpninfo, &timeout, udp_r);
if (vpninfo->quit_reason)
break;
did_work += ret;

} else if (!tun_is_up(vpninfo)) {
/* No DTLS - setup TUN device unconditionally */
ret = setup_tun_device(vpninfo);
if (ret)
break;
}

ret = vpninfo->proto->tcp_mainloop(vpninfo, &timeout, tcp_r);
Expand All @@ -242,28 +240,49 @@ int openconnect_mainloop(struct openconnect_info *vpninfo,

poll_cmd_fd(vpninfo, 0);
if (vpninfo->got_cancel_cmd) {
if (vpninfo->cancel_type == OC_CMD_CANCEL) {
if (vpninfo->delay_close != NO_DELAY_CLOSE) {
if (vpninfo->delay_close == DELAY_CLOSE_IMMEDIATE_CALLBACK) {
vpn_progress(vpninfo, PRG_TRACE, _("Delaying cancel (immediate callback).\n"));
did_work++;
} else
vpn_progress(vpninfo, PRG_TRACE, _("Delaying cancel.\n"));
/* XX: don't let this spin forever */
vpninfo->delay_close = NO_DELAY_CLOSE;
} else if (vpninfo->cancel_type == OC_CMD_CANCEL) {
vpninfo->quit_reason = "Aborted by caller";
vpninfo->got_cancel_cmd = 0;
ret = -EINTR;
break;
} else {
vpninfo->got_cancel_cmd = 0;
ret = -ECONNABORTED;
break;
}
vpninfo->got_cancel_cmd = 0;
break;
}

if (vpninfo->got_pause_cmd) {
/* close all connections and wait for the user to call
openconnect_mainloop() again */
openconnect_close_https(vpninfo, 0);
if (vpninfo->dtls_state > DTLS_DISABLED) {
vpninfo->proto->udp_close(vpninfo);
vpninfo->new_dtls_started = 0;
}
if (vpninfo->delay_close != NO_DELAY_CLOSE) {
/* XX: don't let this spin forever */
if (vpninfo->delay_close == DELAY_CLOSE_IMMEDIATE_CALLBACK) {
vpn_progress(vpninfo, PRG_TRACE, _("Delaying pause (immediate callback).\n"));
did_work++;
} else
vpn_progress(vpninfo, PRG_TRACE, _("Delaying pause.\n"));
/* XX: don't let this spin forever */
vpninfo->delay_close = NO_DELAY_CLOSE;
} else {
/* close all connections and wait for the user to call
openconnect_mainloop() again */
openconnect_close_https(vpninfo, 0);
if (vpninfo->dtls_state > DTLS_DISABLED) {
vpninfo->proto->udp_close(vpninfo);
vpninfo->new_dtls_started = 0;
}

vpninfo->got_pause_cmd = 0;
vpn_progress(vpninfo, PRG_INFO, _("Caller paused the connection\n"));
return 0;
vpninfo->got_pause_cmd = 0;
vpn_progress(vpninfo, PRG_INFO, _("Caller paused the connection\n"));
return 0;
}
}

if (did_work)
Expand Down
6 changes: 6 additions & 0 deletions openconnect-internal.h
Expand Up @@ -669,6 +669,12 @@ struct openconnect_info {
char *version_string;

const char *quit_reason;
const char *delay_tunnel_reason; /* If non-null, provides a reason why protocol is not yet ready for tunnel setup */
enum {
NO_DELAY_CLOSE = 0,
DELAY_CLOSE_WAIT,
DELAY_CLOSE_IMMEDIATE_CALLBACK,
} delay_close; /* Delay close of mainloop */

int verbose;
void *cbdata;
Expand Down
2 changes: 1 addition & 1 deletion openconnect.h
Expand Up @@ -693,7 +693,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);
Expand Down

0 comments on commit e2c5b73

Please sign in to comment.