[PATCH/RFC V2 07/26] tun: Export setup_tun() functionality
Kevin Cernekee
cernekee at gmail.com
Sun Aug 11 21:49:08 EDT 2013
Create three new setup_tun() library functions:
openconnect_setup_tun_device - create a tun device
openconnect_setup_tun_script - pass traffic through a script
openconnect_setup_tun_fd - pass traffic through an existing fd
The latter is needed to support Android's VpnService API.
In all cases, the caller no longer needs to directly manipulate
vpninfo->vpnc_script or vpninfo->script_tun. The former is treated as
a standard caller-allocated, library-freed string.
Signed-off-by: Kevin Cernekee <cernekee at gmail.com>
---
libopenconnect.map.in | 3 ++
library.c | 2 +
main.c | 18 ++++++---
openconnect-internal.h | 3 +-
openconnect.h | 10 +++++
tun.c | 100 +++++++++++++++++++++++++++---------------------
6 files changed, 85 insertions(+), 51 deletions(-)
diff --git a/libopenconnect.map.in b/libopenconnect.map.in
index a530324..72dbd84 100644
--- a/libopenconnect.map.in
+++ b/libopenconnect.map.in
@@ -47,6 +47,9 @@ OPENCONNECT_2.3 {
global:
openconnect_setup_cancel_pipe;
openconnect_mainloop;
+ openconnect_setup_tun_device;
+ openconnect_setup_tun_script;
+ openconnect_setup_tun_fd;
} OPENCONNECT_2.2;
OPENCONNECT_PRIVATE {
diff --git a/library.c b/library.c
index 86c3df8..95afe9c 100644
--- a/library.c
+++ b/library.c
@@ -122,6 +122,8 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
free(vpninfo->redirect_url);
free(vpninfo->proxy_type);
free(vpninfo->proxy);
+ free(vpninfo->vpnc_script);
+ free(vpninfo->ifname);
if (vpninfo->csd_scriptname) {
unlink(vpninfo->csd_scriptname);
diff --git a/main.c b/main.c
index 03ba644..9253b71 100644
--- a/main.c
+++ b/main.c
@@ -485,6 +485,8 @@ int main(int argc, char **argv)
int use_syslog = 0;
char *urlpath = NULL;
char *proxy = getenv("https_proxy");
+ int script_tun = 0;
+ char *vpnc_script = NULL, *ifname = NULL;
int autoproxy = 0;
uid_t uid = getuid();
int opt;
@@ -532,7 +534,6 @@ int main(int argc, char **argv)
vpninfo->process_auth_form = process_auth_form;
vpninfo->cbdata = vpninfo;
vpninfo->cert_expire_warning = 60 * 86400;
- vpninfo->vpnc_script = DEFAULT_VPNCSCRIPT;
vpninfo->cancel_fd = -1;
vpninfo->xmlpost = 1;
@@ -637,7 +638,7 @@ int main(int argc, char **argv)
case 'h':
usage();
case 'i':
- vpninfo->ifname = keep_config_arg();
+ ifname = xstrdup(config_arg);
break;
case 'l':
use_syslog = 1;
@@ -681,10 +682,10 @@ int main(int argc, char **argv)
nocertcheck = 1;
break;
case 's':
- vpninfo->vpnc_script = keep_config_arg();
+ vpnc_script = xstrdup(config_arg);
break;
case 'S':
- vpninfo->script_tun = 1;
+ script_tun = 1;
break;
case 'u':
vpninfo->username = keep_config_arg();
@@ -899,7 +900,14 @@ int main(int argc, char **argv)
exit(1);
}
- if (setup_tun(vpninfo)) {
+ if (!vpnc_script)
+ vpnc_script = xstrdup(DEFAULT_VPNCSCRIPT);
+ if (script_tun) {
+ if (openconnect_setup_tun_script(vpninfo, vpnc_script)) {
+ fprintf(stderr, _("Set up tun script failed\n"));
+ exit(1);
+ }
+ } else if (openconnect_setup_tun_device(vpninfo, vpnc_script, ifname)) {
fprintf(stderr, _("Set up tun device failed\n"));
exit(1);
}
diff --git a/openconnect-internal.h b/openconnect-internal.h
index 5215ea5..ebb7aa5 100644
--- a/openconnect-internal.h
+++ b/openconnect-internal.h
@@ -262,7 +262,7 @@ struct openconnect_info {
unsigned char dtls_secret[48];
char *dtls_cipher;
- const char *vpnc_script;
+ char *vpnc_script;
int script_tun;
char *ifname;
@@ -396,7 +396,6 @@ static inline int cancel_fd_check(struct openconnect_info *vpninfo)
/****************************************************************************/
/* tun.c */
-int setup_tun(struct openconnect_info *vpninfo);
int tun_mainloop(struct openconnect_info *vpninfo, int *timeout);
void shutdown_tun(struct openconnect_info *vpninfo);
int script_config_tun(struct openconnect_info *vpninfo, const char *reason);
diff --git a/openconnect.h b/openconnect.h
index 6297e4a..5641656 100644
--- a/openconnect.h
+++ b/openconnect.h
@@ -224,6 +224,16 @@ int openconnect_setup_cancel_pipe(struct openconnect_info *vpninfo);
const char *openconnect_get_version(void);
+/* Create a tun device through the OS kernel (typical use case). Both
+ strings are optional and can be NULL if desired. */
+int openconnect_setup_tun_device(struct openconnect_info *vpninfo, char *vpnc_script, char *ifname);
+
+/* Pass traffic to a script program (no tun device). */
+int openconnect_setup_tun_script(struct openconnect_info *vpninfo, char *tun_script);
+
+/* Caller will provide a file descriptor for the tunnel traffic. */
+int openconnect_setup_tun_fd(struct openconnect_info *vpninfo, int tun_fd);
+
/* Start the main loop; exits if data is received on cancel_fd or the remote
site aborts. */
int openconnect_mainloop(struct openconnect_info *vpninfo);
diff --git a/tun.c b/tun.c
index 0db7c43..e4f7a5e 100644
--- a/tun.c
+++ b/tun.c
@@ -631,64 +631,76 @@ static int os_setup_tun(struct openconnect_info *vpninfo)
return tun_fd;
}
-/* Set up a tuntap device. */
-int setup_tun(struct openconnect_info *vpninfo)
+int openconnect_setup_tun_fd(struct openconnect_info *vpninfo, int tun_fd)
{
- int tun_fd;
+ fcntl(tun_fd, F_SETFD, FD_CLOEXEC);
- set_script_env(vpninfo);
+ vpninfo->tun_fd = tun_fd;
- if (vpninfo->script_tun) {
- pid_t child;
- int fds[2];
+ if (vpninfo->select_nfds <= tun_fd)
+ vpninfo->select_nfds = tun_fd + 1;
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds)) {
- perror(_("socketpair"));
- exit(1);
- }
- tun_fd = fds[0];
- child = fork();
- if (child < 0) {
- perror(_("fork"));
- exit(1);
- } else if (!child) {
- if (setpgid(0, getpid()) < 0)
- perror(_("setpgid"));
- close(tun_fd);
- setenv_int("VPNFD", fds[1]);
- execl("/bin/sh", "/bin/sh", "-c", vpninfo->vpnc_script, NULL);
- perror(_("execl"));
- exit(1);
- }
- close(fds[1]);
- vpninfo->script_tun = child;
- vpninfo->ifname = strdup(_("(script)"));
- } else {
- script_config_tun(vpninfo, "pre-init");
+ FD_SET(tun_fd, &vpninfo->select_rfds);
- tun_fd = os_setup_tun(vpninfo);
- if (tun_fd < 0)
- return tun_fd;
+ fcntl(vpninfo->tun_fd, F_SETFL, fcntl(vpninfo->tun_fd, F_GETFL) | O_NONBLOCK);
- setenv("TUNDEV", vpninfo->ifname, 1);
- script_config_tun(vpninfo, "connect");
+ return 0;
+}
+
+int openconnect_setup_tun_script(struct openconnect_info *vpninfo, char *tun_script)
+{
+ pid_t child;
+ int fds[2];
- /* Ancient vpnc-scripts might not get this right */
- set_tun_mtu(vpninfo);
+ vpninfo->vpnc_script = tun_script;
+ vpninfo->script_tun = 1;
+
+ set_script_env(vpninfo);
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, fds)) {
+ perror(_("socketpair"));
+ exit(1);
+ }
+ child = fork();
+ if (child < 0) {
+ perror(_("fork"));
+ exit(1);
+ } else if (!child) {
+ if (setpgid(0, getpid()) < 0)
+ perror(_("setpgid"));
+ close(fds[0]);
+ setenv_int("VPNFD", fds[1]);
+ execl("/bin/sh", "/bin/sh", "-c", vpninfo->vpnc_script, NULL);
+ perror(_("execl"));
+ exit(1);
}
+ close(fds[1]);
+ vpninfo->script_tun = child;
+ vpninfo->ifname = strdup(_("(script)"));
- fcntl(tun_fd, F_SETFD, FD_CLOEXEC);
+ return openconnect_setup_tun_fd(vpninfo, fds[0]);
+}
- vpninfo->tun_fd = tun_fd;
+int openconnect_setup_tun_device(struct openconnect_info *vpninfo, char *vpnc_script, char *ifname)
+{
+ int tun_fd;
- if (vpninfo->select_nfds <= tun_fd)
- vpninfo->select_nfds = tun_fd + 1;
+ vpninfo->vpnc_script = vpnc_script;
+ vpninfo->ifname = ifname;
- FD_SET(tun_fd, &vpninfo->select_rfds);
+ set_script_env(vpninfo);
+ script_config_tun(vpninfo, "pre-init");
- fcntl(vpninfo->tun_fd, F_SETFL, fcntl(vpninfo->tun_fd, F_GETFL) | O_NONBLOCK);
+ tun_fd = os_setup_tun(vpninfo);
+ if (tun_fd < 0)
+ return tun_fd;
- return 0;
+ setenv("TUNDEV", vpninfo->ifname, 1);
+ script_config_tun(vpninfo, "connect");
+
+ /* Ancient vpnc-scripts might not get this right */
+ set_tun_mtu(vpninfo);
+
+ return openconnect_setup_tun_fd(vpninfo, tun_fd);
}
static struct pkt *out_pkt;
--
1.7.9.5
More information about the openconnect-devel
mailing list