Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Invoke vpnc-script with "pre-init" to load tun module if necessary
Shift the os-specific tun setup out into a separate function, just because
it declares local variables and the pre-init script call is now happening
before that in the code block.

Clean up script invocation a little too, and fix the fact that we'd run the
script with "reconnect" reason even if there wasn't a script at all.

Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  • Loading branch information
David Woodhouse authored and David Woodhouse committed Apr 10, 2012
1 parent 6668456 commit 9186ea2
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 122 deletions.
2 changes: 1 addition & 1 deletion cstp.c
Expand Up @@ -443,7 +443,7 @@ int cstp_reconnect(struct openconnect_info *vpninfo)
if (interval > RECONNECT_INTERVAL_MAX)
interval = RECONNECT_INTERVAL_MAX;
}
script_reconnect(vpninfo);
script_config_tun(vpninfo, "reconnect");
return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion openconnect-internal.h
Expand Up @@ -244,7 +244,7 @@ struct openconnect_info {
int setup_tun(struct openconnect_info *vpninfo);
int tun_mainloop(struct openconnect_info *vpninfo, int *timeout);
void shutdown_tun(struct openconnect_info *vpninfo);
void script_reconnect (struct openconnect_info *vpninfo);
int script_config_tun (struct openconnect_info *vpninfo, const char *reason);

/* dtls.c */
unsigned char unhex(const char *data);
Expand Down
241 changes: 122 additions & 119 deletions tun.c
Expand Up @@ -277,7 +277,6 @@ static void set_script_env(struct openconnect_info *vpninfo)
if (!ret)
setenv("VPNGATEWAY", host, 1);

setenv("reason", "connect", 1);
set_banner(vpninfo);
unsetenv("CISCO_SPLIT_INC");
unsetenv("CISCO_SPLIT_EXC");
Expand Down Expand Up @@ -368,24 +367,22 @@ static void set_script_env(struct openconnect_info *vpninfo)
setenv_cstp_opts(vpninfo);
}

static int script_config_tun(struct openconnect_info *vpninfo)
int script_config_tun(struct openconnect_info *vpninfo, const char *reason)
{
if (!vpninfo->vpnc_script)
return 0;

setenv("reason", reason, 1);
if (system(vpninfo->vpnc_script)) {
int e = errno;
vpn_progress(vpninfo, PRG_ERR,
_("Failed to spawn script '%s': %s\n"),
vpninfo->vpnc_script, strerror(e));
_("Failed to spawn script '%s' for %s: %s\n"),
vpninfo->vpnc_script, reason, strerror(e));
return -e;
}
return 0;
}

void script_reconnect (struct openconnect_info *vpninfo)
{
setenv("reason", "reconnect", 1);
script_config_tun(vpninfo);
}

#ifdef __sun__
static int link_proto(int unit_nr, const char *devname, uint64_t flags)
{
Expand Down Expand Up @@ -442,6 +439,115 @@ static int link_proto(int unit_nr, const char *devname, uint64_t flags)
return ip_fd;
}
#endif

static int os_setup_tun(struct openconnect_info *vpninfo)
{
int tun_fd;

#ifdef IFF_TUN /* Linux */
struct ifreq ifr;
int tunerr;

tun_fd = open("/dev/net/tun", O_RDWR);
if (tun_fd < 0) {
/* Android has /dev/tun instead of /dev/net/tun
Since other systems might have too, just try it
as a fallback instead of using ifdef __ANDROID__ */
tunerr = errno;
tun_fd = open("/dev/tun", O_RDWR);
}
if (tun_fd < 0) {
/* If the error on /dev/tun is ENOENT, that's boring.
Use the error we got on /dev/net/tun instead */
if (errno != -ENOENT)
tunerr = errno;

vpn_progress(vpninfo, PRG_ERR,
_("Failed to open tun device: %s\n"),
strerror(tunerr));
exit(1);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
if (vpninfo->ifname)
strncpy(ifr.ifr_name, vpninfo->ifname,
sizeof(ifr.ifr_name) - 1);
if (ioctl(tun_fd, TUNSETIFF, (void *) &ifr) < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("TUNSETIFF failed: %s\n"),
strerror(errno));
exit(1);
}
if (!vpninfo->ifname)
vpninfo->ifname = strdup(ifr.ifr_name);
#elif defined (__sun__)
static char tun_name[80];
int unit_nr;

tun_fd = open("/dev/tun", O_RDWR);
if (tun_fd < 0) {
perror(_("open /dev/tun"));
return -EIO;
}

unit_nr = ioctl(tun_fd, TUNNEWPPA, -1);
if (unit_nr < 0) {
perror(_("Failed to create new tun"));
close(tun_fd);
return -EIO;
}

if (ioctl(tun_fd, I_SRDOPT, RMSGD) < 0) {
perror(_("Failed to put tun file descriptor into message-discard mode"));
close(tun_fd);
return -EIO;
}

sprintf(tun_name, "tun%d", unit_nr);
vpninfo->ifname = strdup(tun_name);

vpninfo->ip_fd = link_proto(unit_nr, "/dev/udp", IFF_IPV4);
if (vpninfo->ip_fd < 0) {
close(tun_fd);
return -EIO;
}

if (vpninfo->vpn_addr6) {
vpninfo->ip6_fd = link_proto(unit_nr, "/dev/udp6", IFF_IPV6);
if (vpninfo->ip6_fd < 0) {
close(tun_fd);
close(vpninfo->ip_fd);
vpninfo->ip_fd = -1;
return -EIO;
}
} else
vpninfo->ip6_fd = -1;

#else /* BSD et al have /dev/tun$x devices */
static char tun_name[80];
int i;
for (i = 0; i < 255; i++) {
sprintf(tun_name, "/dev/tun%d", i);
tun_fd = open(tun_name, O_RDWR);
if (tun_fd >= 0)
break;
}
if (tun_fd < 0) {
perror(_("open tun"));
exit(1);
}
vpninfo->ifname = strdup(tun_name + 5);
#ifdef TUNSIFHEAD
i = 1;
if (ioctl(tun_fd, TUNSIFHEAD, &i) < 0) {
perror(_("TUNSIFHEAD"));
exit(1);
}
#endif
#endif
return tun_fd;
}

/* Set up a tuntap device. */
int setup_tun(struct openconnect_info *vpninfo)
{
Expand Down Expand Up @@ -473,110 +579,15 @@ int setup_tun(struct openconnect_info *vpninfo)
vpninfo->script_tun = child;
vpninfo->ifname = strdup(_("(script)"));
} else {
#ifdef IFF_TUN /* Linux */
struct ifreq ifr;
int tunerr;

tun_fd = open("/dev/net/tun", O_RDWR);
if (tun_fd < 0) {
/* Android has /dev/tun instead of /dev/net/tun
Since other systems might have too, just try it
as a fallback instead of using ifdef __ANDROID__ */
tunerr = errno;
tun_fd = open("/dev/tun", O_RDWR);
}
if (tun_fd < 0) {
/* If the error on /dev/tun is ENOENT, that's boring.
Use the error we got on /dev/net/tun instead */
if (errno != -ENOENT)
tunerr = errno;

vpn_progress(vpninfo, PRG_ERR,
_("Failed to open tun device: %s\n"),
strerror(tunerr));
exit(1);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
if (vpninfo->ifname)
strncpy(ifr.ifr_name, vpninfo->ifname,
sizeof(ifr.ifr_name) - 1);
if (ioctl(tun_fd, TUNSETIFF, (void *) &ifr) < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("TUNSETIFF failed: %s\n"),
strerror(errno));
exit(1);
}
if (!vpninfo->ifname)
vpninfo->ifname = strdup(ifr.ifr_name);
#elif defined (__sun__)
static char tun_name[80];
int unit_nr;

tun_fd = open("/dev/tun", O_RDWR);
if (tun_fd < 0) {
perror(_("open /dev/tun"));
return -EIO;
}
script_config_tun(vpninfo, "pre-init");

unit_nr = ioctl(tun_fd, TUNNEWPPA, -1);
if (unit_nr < 0) {
perror(_("Failed to create new tun"));
close(tun_fd);
return -EIO;
}
tun_fd = os_setup_tun(vpninfo);
if (tun_fd < 0)
return tun_fd;

if (ioctl(tun_fd, I_SRDOPT, RMSGD) < 0) {
perror(_("Failed to put tun file descriptor into message-discard mode"));
close(tun_fd);
return -EIO;
}

sprintf(tun_name, "tun%d", unit_nr);
vpninfo->ifname = strdup(tun_name);

vpninfo->ip_fd = link_proto(unit_nr, "/dev/udp", IFF_IPV4);
if (vpninfo->ip_fd < 0) {
close(tun_fd);
return -EIO;
}

if (vpninfo->vpn_addr6) {
vpninfo->ip6_fd = link_proto(unit_nr, "/dev/udp6", IFF_IPV6);
if (vpninfo->ip6_fd < 0) {
close(tun_fd);
close(vpninfo->ip_fd);
vpninfo->ip_fd = -1;
return -EIO;
}
} else
vpninfo->ip6_fd = -1;

#else /* BSD et al have /dev/tun$x devices */
static char tun_name[80];
int i;
for (i = 0; i < 255; i++) {
sprintf(tun_name, "/dev/tun%d", i);
tun_fd = open(tun_name, O_RDWR);
if (tun_fd >= 0)
break;
}
if (tun_fd < 0) {
perror(_("open tun"));
exit(1);
}
vpninfo->ifname = strdup(tun_name + 5);
#ifdef TUNSIFHEAD
i = 1;
if (ioctl(tun_fd, TUNSIFHEAD, &i) < 0) {
perror(_("TUNSIFHEAD"));
exit(1);
}
#endif
#endif
if (vpninfo->vpnc_script) {
setenv("TUNDEV", vpninfo->ifname, 1);
script_config_tun(vpninfo);
script_config_tun(vpninfo, "connect");
/* We have to set the MTU for ourselves, because the script doesn't */
local_config_tun(vpninfo, 1);
} else
Expand Down Expand Up @@ -696,15 +707,7 @@ void shutdown_tun(struct openconnect_info *vpninfo)
if (vpninfo->script_tun) {
kill(vpninfo->script_tun, SIGHUP);
} else {
if (vpninfo->vpnc_script) {
setenv("reason", "disconnect", 1);
if (system(vpninfo->vpnc_script) == -1) {
vpn_progress(vpninfo, PRG_ERR,
_("Failed to spawn script '%s': %s\n"),
vpninfo->vpnc_script,
strerror(errno));
}
}
script_config_tun(vpninfo, "disconnect");
#ifdef __sun__
close(vpninfo->ip_fd);
vpninfo->ip_fd = -1;
Expand Down
2 changes: 1 addition & 1 deletion www/changelog.xml
Expand Up @@ -17,7 +17,7 @@
<ul>
<li><b>OpenConnect HEAD</b>
<ul>
<li><i>No changelog entries yet</i></li>
<li>Invoke <tt>vpnc-script</tt> with "pre-init" reason to load tun module if necessary.</li>
</ul><br/>
</li>
<li><b><a href="ftp://ftp.infradead.org/pub/openconnect/openconnect-3.16.tar.gz">OpenConnect v3.16</a></b>
Expand Down

0 comments on commit 9186ea2

Please sign in to comment.