summaryrefslogtreecommitdiff
path: root/vpn/plugins/openvpn.c
diff options
context:
space:
mode:
Diffstat (limited to 'vpn/plugins/openvpn.c')
-rwxr-xr-xvpn/plugins/openvpn.c92
1 files changed, 84 insertions, 8 deletions
diff --git a/vpn/plugins/openvpn.c b/vpn/plugins/openvpn.c
index e226afd1..d115df6e 100755
--- a/vpn/plugins/openvpn.c
+++ b/vpn/plugins/openvpn.c
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <stdio.h>
#include <net/if.h>
+#include <linux/if_tun.h>
#include <glib.h>
@@ -71,6 +72,8 @@ struct {
{ "OpenVPN.CompLZO", "--comp-lzo", 0 },
{ "OpenVPN.RemoteCertTls", "--remote-cert-tls", 1 },
{ "OpenVPN.ConfigFile", "--config", 1 },
+ { "OpenVPN.DeviceType", NULL, 1 },
+ { "OpenVPN.Verb", "--verb", 1 },
};
struct nameserver_entry {
@@ -156,7 +159,7 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
{
DBusMessageIter iter, dict;
const char *reason, *key, *value;
- char *address = NULL, *gateway = NULL, *peer = NULL;
+ char *address = NULL, *gateway = NULL, *peer = NULL, *netmask = NULL;
struct connman_ipaddress *ipaddress;
GSList *nameserver_list = NULL;
@@ -192,6 +195,9 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
if (!strcmp(key, "ifconfig_local"))
address = g_strdup(value);
+ if (!strcmp(key, "ifconfig_netmask"))
+ netmask = g_strdup(value);
+
if (!strcmp(key, "ifconfig_remote"))
peer = g_strdup(value);
@@ -218,11 +224,12 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
g_free(address);
g_free(gateway);
g_free(peer);
+ g_free(netmask);
return VPN_STATE_FAILURE;
}
- connman_ipaddress_set_ipv4(ipaddress, address, NULL, gateway);
+ connman_ipaddress_set_ipv4(ipaddress, address, netmask, gateway);
connman_ipaddress_set_peer(ipaddress, peer);
vpn_provider_set_ipaddress(provider, ipaddress);
@@ -256,6 +263,7 @@ static int ov_notify(DBusMessage *msg, struct vpn_provider *provider)
g_free(address);
g_free(gateway);
g_free(peer);
+ g_free(netmask);
connman_ipaddress_free(ipaddress);
return VPN_STATE_CONNECT;
@@ -306,13 +314,54 @@ static int task_append_config_data(struct vpn_provider *provider,
return 0;
}
+static gboolean can_read_data(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
+{
+ void (*cbf)(const char *format, ...) = data;
+ gchar *str;
+ gsize size;
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+ return FALSE;
+
+ g_io_channel_read_line(chan, &str, &size, NULL, NULL);
+ cbf(str);
+ g_free(str);
+
+ return TRUE;
+}
+
+static int setup_log_read(int stdout_fd, int stderr_fd)
+{
+ GIOChannel *chan;
+ int watch;
+
+ chan = g_io_channel_unix_new(stdout_fd);
+ g_io_channel_set_close_on_unref(chan, TRUE);
+ watch = g_io_add_watch(chan, G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
+ can_read_data, connman_debug);
+ g_io_channel_unref(chan);
+
+ if (watch == 0)
+ return -EIO;
+
+ chan = g_io_channel_unix_new(stderr_fd);
+ g_io_channel_set_close_on_unref(chan, TRUE);
+ watch = g_io_add_watch(chan, G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
+ can_read_data, connman_error);
+ g_io_channel_unref(chan);
+
+ return watch == 0? -EIO : 0;
+}
+
static int ov_connect(struct vpn_provider *provider,
struct connman_task *task, const char *if_name,
vpn_provider_connect_cb_t cb, const char *dbus_sender,
void *user_data)
{
const char *option;
- int err = 0, fd;
+ int stdout_fd, stderr_fd;
+ int err = 0;
option = vpn_provider_get_string(provider, "Host");
if (!option) {
@@ -341,8 +390,6 @@ static int ov_connect(struct vpn_provider *provider,
connman_task_add_argument(task, "--client", NULL);
}
- connman_task_add_argument(task, "--syslog", NULL);
-
connman_task_add_argument(task, "--script-security", "2");
connman_task_add_argument(task, "--up",
@@ -362,7 +409,15 @@ static int ov_connect(struct vpn_provider *provider,
connman_task_get_path(task));
connman_task_add_argument(task, "--dev", if_name);
- connman_task_add_argument(task, "--dev-type", "tun");
+ option = vpn_provider_get_string(provider, "OpenVPN.DeviceType");
+ if (option) {
+ connman_task_add_argument(task, "--dev-type", option);
+ } else {
+ /*
+ * Default to tun for backwards compatibility.
+ */
+ connman_task_add_argument(task, "--dev-type", "tun");
+ }
connman_task_add_argument(task, "--persist-tun", NULL);
@@ -381,15 +436,15 @@ static int ov_connect(struct vpn_provider *provider,
*/
connman_task_add_argument(task, "--ping-restart", "0");
- fd = fileno(stderr);
err = connman_task_run(task, vpn_died, provider,
- NULL, &fd, &fd);
+ NULL, &stdout_fd, &stderr_fd);
if (err < 0) {
connman_error("openvpn failed to start");
err = -EIO;
goto done;
}
+ err = setup_log_read(stdout_fd, stderr_fd);
done:
if (cb)
cb(provider, user_data, err);
@@ -397,10 +452,31 @@ done:
return err;
}
+static int ov_device_flags(struct vpn_provider *provider)
+{
+ const char *option;
+
+ option = vpn_provider_get_string(provider, "OpenVPN.DeviceType");
+ if (!option) {
+ return IFF_TUN;
+ }
+
+ if (g_str_equal(option, "tap")) {
+ return IFF_TAP;
+ }
+
+ if (!g_str_equal(option, "tun")) {
+ connman_warn("bad OpenVPN.DeviceType value, falling back to tun");
+ }
+
+ return IFF_TUN;
+}
+
static struct vpn_driver vpn_driver = {
.notify = ov_notify,
.connect = ov_connect,
.save = ov_save,
+ .device_flags = ov_device_flags,
};
static int openvpn_init(void)