Skip to content

Commit

Permalink
Delay tun device creation until DTLS has been negotiated
Browse files Browse the repository at this point in the history
Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
  • Loading branch information
Nikos Mavrogiannopoulos authored and nmav committed Dec 5, 2015
1 parent 8b041c7 commit 8b137a2
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 34 deletions.
41 changes: 9 additions & 32 deletions main.c
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -1053,19 +1053,19 @@ 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) {
fprintf(stderr, _("Invalid user \"%s\"\n"),
config_arg);
exit(1);
}
uid = pw->pw_uid;
vpninfo->uid = pw->pw_uid;
}
break;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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))
Expand All @@ -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 ? : "",
Expand Down
70 changes: 69 additions & 1 deletion mainloop.c
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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 */
Expand Down
8 changes: 7 additions & 1 deletion openconnect-internal.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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); \
Expand Down

0 comments on commit 8b137a2

Please sign in to comment.