From 8b137a2031f75f57552dd12919894646d22e6f97 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 14 Oct 2015 13:30:10 +0200 Subject: [PATCH] Delay tun device creation until DTLS has been negotiated Signed-off-by: Nikos Mavrogiannopoulos --- main.c | 41 ++++++------------------- mainloop.c | 70 +++++++++++++++++++++++++++++++++++++++++- openconnect-internal.h | 8 ++++- 3 files changed, 85 insertions(+), 34 deletions(-) diff --git a/main.c b/main.c index f853afe4..9dd295ac 100644 --- a/main.c +++ b/main.c @@ -971,7 +971,7 @@ int main(int argc, char **argv) char *ip; const char *compr = ""; char *proxy = getenv("https_proxy"); - char *vpnc_script = NULL, *ifname = NULL; + char *vpnc_script = NULL; const struct oc_ip_info *ip_info; int autoproxy = 0; int opt; @@ -989,9 +989,7 @@ int main(int argc, char **argv) #ifndef _WIN32 struct sigaction sa; struct utsname utsbuf; - uid_t uid = getuid(); int use_syslog = 0; - int script_tun = 0; #endif #ifdef ENABLE_NLS @@ -1033,6 +1031,8 @@ int main(int argc, char **argv) #ifdef _WIN32 set_default_vpncscript(); #else + vpninfo->use_tun_script = 0; + vpninfo->uid = getuid(); if (!uname(&utsbuf)) { free(vpninfo->localname); vpninfo->localname = xstrdup(utsbuf.nodename); @@ -1053,11 +1053,11 @@ int main(int argc, char **argv) use_syslog = 1; break; case 'S': - script_tun = 1; + vpninfo->use_tun_script = 1; break; case 'U': { char *strend; - uid = strtol(config_arg, &strend, 0); + vpninfo->uid = strtol(config_arg, &strend, 0); if (strend[0]) { struct passwd *pw = getpwnam(config_arg); if (!pw) { @@ -1065,7 +1065,7 @@ int main(int argc, char **argv) config_arg); exit(1); } - uid = pw->pw_uid; + vpninfo->uid = pw->pw_uid; } break; } @@ -1220,7 +1220,7 @@ int main(int argc, char **argv) case 'h': usage(); case 'i': - ifname = dup_config_arg(); + vpninfo->ifname = dup_config_arg(); break; case 'm': { int mtu = atol(config_arg); @@ -1475,31 +1475,8 @@ int main(int argc, char **argv) if (!vpnc_script) vpnc_script = xstrdup(default_vpncscript); -#ifndef _WIN32 - if (script_tun) { - if (openconnect_setup_tun_script(vpninfo, vpnc_script)) { - fprintf(stderr, _("Set up tun script failed\n")); - openconnect_vpninfo_free(vpninfo); - exit(1); - } - } else -#endif - if (openconnect_setup_tun_device(vpninfo, vpnc_script, ifname)) { - fprintf(stderr, _("Set up tun device failed\n")); - openconnect_vpninfo_free(vpninfo); - exit(1); - } -#ifndef _WIN32 - if (uid != getuid()) { - if (setuid(uid)) { - fprintf(stderr, _("Failed to set uid %ld\n"), - (long)uid); - openconnect_vpninfo_free(vpninfo); - exit(1); - } - } -#endif + STRDUP(vpninfo->vpnc_script, vpnc_script); if (vpninfo->dtls_state != DTLS_DISABLED && openconnect_setup_dtls(vpninfo, 60)) @@ -1523,7 +1500,7 @@ int main(int argc, char **argv) compr = " + lz4"; } vpn_progress(vpninfo, PRG_INFO, - _("Connected %s as %s%s%s, using %s%s\n"), openconnect_get_ifname(vpninfo), + _("Connected as %s%s%s, using %s%s\n"), ip_info->addr?:"", (ip_info->netmask6 && ip_info->addr) ? " + " : "", ip_info->netmask6 ? : "", diff --git a/mainloop.c b/mainloop.c index 1bd3bc8b..78485021 100644 --- a/mainloop.c +++ b/mainloop.c @@ -45,6 +45,12 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout) struct pkt *this; int work_done = 0; + if (!vpninfo->tun_is_up) { + /* no tun yet, clear any queued packets */ + while ((this = dequeue_packet(&vpninfo->incoming_queue))); + return 0; + } + if (read_fd_monitored(vpninfo, tun)) { struct pkt *out_pkt = vpninfo->tun_pkt; while (1) { @@ -95,6 +101,37 @@ int tun_mainloop(struct openconnect_info *vpninfo, int *timeout) return work_done; } +static int setup_tun_device(struct openconnect_info *vpninfo) +{ + int ret; + +#ifndef _WIN32 + if (vpninfo->use_tun_script) { + ret = openconnect_setup_tun_script(vpninfo, vpninfo->vpnc_script); + if (ret) { + fprintf(stderr, _("Set up tun script failed\n")); + return ret; + } + } else +#endif + ret = openconnect_setup_tun_device(vpninfo, vpninfo->vpnc_script, vpninfo->ifname); + if (ret) { + fprintf(stderr, _("Set up tun device failed\n")); + return ret; + } + +#ifndef _WIN32 + if (vpninfo->uid != getuid()) { + if (setuid(vpninfo->uid)) { + fprintf(stderr, _("Failed to set uid %ld\n"), + (long)vpninfo->uid); + return -EPERM; + } + } +#endif + return 0; +} + /* Return value: * = 0, when successfully paused (may call again) * = -EINTR, if aborted locally via OC_CMD_CANCEL @@ -109,6 +146,7 @@ int openconnect_mainloop(struct openconnect_info *vpninfo, { int ret = 0; + vpninfo->tun_is_up = 0; vpninfo->reconnect_timeout = reconnect_timeout; vpninfo->reconnect_interval = reconnect_interval; @@ -119,7 +157,7 @@ int openconnect_mainloop(struct openconnect_info *vpninfo, while (!vpninfo->quit_reason) { int did_work = 0; - int timeout = INT_MAX; + int timeout; #ifdef _WIN32 HANDLE events[4]; int nr_events = 0; @@ -128,11 +166,40 @@ int openconnect_mainloop(struct openconnect_info *vpninfo, fd_set rfds, wfds, efds; #endif + /* If tun is not up, loop more often to detect + * a DTLS timeout (due to a firewall block) as soon. */ + if (vpninfo->tun_is_up) + timeout = INT_MAX; + 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 (vpninfo->tun_is_up == 0 && (vpninfo->dtls_state == DTLS_CONNECTED || + vpninfo->dtls_state == DTLS_SLEEPING)) { + ret = setup_tun_device(vpninfo); + if (ret) { + break; + } + + vpninfo->tun_is_up = 1; + } + ret = vpninfo->proto.udp_mainloop(vpninfo, &timeout); if (vpninfo->quit_reason) break; did_work += ret; + + } else if (vpninfo->tun_is_up == 0) { + /* No DTLS - setup TUN device unconditionally */ + ret = setup_tun_device(vpninfo); + if (ret) + break; + + vpninfo->tun_is_up = 1; } ret = vpninfo->proto.tcp_mainloop(vpninfo, &timeout); @@ -156,6 +223,7 @@ int openconnect_mainloop(struct openconnect_info *vpninfo, } break; } + if (vpninfo->got_pause_cmd) { /* close all connections and wait for the user to call openconnect_mainloop() again */ diff --git a/openconnect-internal.h b/openconnect-internal.h index b7a2b0ec..93b18400 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -536,8 +536,14 @@ struct openconnect_info { char *dtls_cipher; char *vpnc_script; +#ifndef _WIN32 + uid_t uid; +#endif + int tun_is_up; /* whether the tun device is setup */ + int use_tun_script; int script_tun; char *ifname; + char *cmd_ifname; int reqmtu, basemtu; const char *banner; @@ -1000,7 +1006,7 @@ static inline int strprefix_match(const char *str, int len, const char *match) } #define STRDUP(res, arg) \ - do { \ + if (res != arg) { \ free(res); \ if (arg) { \ res = strdup(arg); \