[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