service: Simplify nameserver route adding and removing
[framework/connectivity/connman.git] / plugins / openvpn.c
index 0da6c74..8df8a3f 100644 (file)
 #include <connman/log.h>
 #include <connman/task.h>
 #include <connman/dbus.h>
+#include <connman/ipconfig.h>
 
 #include "vpn.h"
 
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
 static DBusConnection *connection;
 
+struct {
+       const char *cm_opt;
+       const char *ov_opt;
+       char       has_value;
+} ov_options[] = {
+       { "Host", "--remote", 1 },
+       { "OpenVPN.CACert", "--ca", 1 },
+       { "OpenVPN.Cert", "--cert", 1 },
+       { "OpenVPN.Key", "--key", 1 },
+       { "OpenVPN.MTU", "--mtu", 1 },
+       { "OpenVPN.Proto", "--proto", 1 },
+       { "OpenVPN.Port", "--port", 1 },
+       { "OpenVPN.AuthUserPass", "--auth-user-pass", 1 },
+       { "OpenVPN.TLSRemote", "--tls-remote", 1 },
+       { "OpenVPN.Cipher", "--cipher", 1 },
+       { "OpenVPN.Auth", "--auth", 1 },
+       { "OpenVPN.CompLZO", "--comp-lzo", 0 },
+       { "OpenVPN.RemoteCertTls", "--remote-cert-tls", 1 },
+};
+
+static void ov_append_dns_entries(const char *key, const char *value,
+                                       char **dns_entries)
+{
+       gchar **options;
+
+       if (g_str_has_prefix(key, "foreign_option_") == FALSE)
+               return;
+
+       options = g_strsplit(value, " ", 3);
+       if (options[0] != NULL &&
+               !strcmp(options[0], "dhcp-option") &&
+                       options[1] != NULL &&
+                       !strcmp(options[1], "DNS") &&
+                               options[2] != NULL) {
+
+               if (*dns_entries != NULL) {
+                       char *tmp;
+
+                       tmp = g_strjoin(" ", *dns_entries,
+                                               options[2], NULL);
+                       g_free(*dns_entries);
+                       *dns_entries = tmp;
+               } else {
+                       *dns_entries = g_strdup(options[2]);
+               }
+       }
+
+       g_strfreev(options);
+}
+
 static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
 {
        DBusMessageIter iter, dict;
        const char *reason, *key, *value;
-       const char *domain = NULL;
-       char *dns_entries = NULL;
-
-       dbus_message_iter_init(msg, &iter);
-
-       dbus_message_iter_get_basic(&iter, &reason);
-       dbus_message_iter_next(&iter);
+       char *nameservers = NULL;
+       char *address = NULL, *gateway = NULL, *peer = NULL;
+       struct connman_ipaddress *ipaddress;
 
        dbus_message_iter_init(msg, &iter);
 
@@ -67,8 +116,6 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
        if (strcmp(reason, "up"))
                return VPN_STATE_DISCONNECT;
 
-       domain = connman_provider_get_string(provider, "VPN.Domain");
-
        dbus_message_iter_recurse(&iter, &dict);
 
        while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
@@ -81,70 +128,109 @@ static int ov_notify(DBusMessage *msg, struct connman_provider *provider)
 
                DBG("%s = %s", key, value);
 
-               if (!strcmp(key, "trusted_ip"))
+               if (!strcmp(key, "trusted_ip")) {
                        connman_provider_set_string(provider, "Gateway", value);
+                       gateway = g_strdup(value);
+               }
 
-               if (!strcmp(key, "ifconfig_local"))
+               if (!strcmp(key, "ifconfig_local")) {
                        connman_provider_set_string(provider, "Address", value);
+                       address = g_strdup(value);
+               }
 
-               if (!strcmp(key, "route_vpn_gateway"))
+               if (!strcmp(key, "ifconfig_remote")) {
                        connman_provider_set_string(provider, "Peer", value);
-
-               if (g_str_has_prefix(key, "foreign_option_")) {
-                       gchar **options;
-
-                       options = g_strsplit(value, " ", 3);
-                       if (options[0] != NULL &&
-                                       !strcmp(options[0], "dhcp-option") &&
-                                       options[1] != NULL &&
-                                       !strcmp(options[1], "DNS") &&
-                                       options[2] != NULL) {
-
-                               if (dns_entries != NULL) {
-                                       char *tmp;
-
-                                       tmp = g_strjoin(" ", dns_entries,
-                                                       options[2], NULL);
-                                       g_free(dns_entries);
-                                       dns_entries = tmp;
-                               } else {
-                                       dns_entries = g_strdup(options[2]);
-                               }
-                       }
-
-                       g_strfreev(options);
+                       peer = g_strdup(value);
                }
 
+               if (g_str_has_prefix(key, "route_") == TRUE)
+                       connman_provider_append_route(provider, key, value);
+
+               ov_append_dns_entries(key, value, &nameservers);
+
                dbus_message_iter_next(&dict);
        }
 
-       if (dns_entries != NULL) {
-               connman_provider_set_string(provider, "DNS", dns_entries);
-               g_free(dns_entries);
+       ipaddress = connman_ipaddress_alloc(AF_INET);
+       if (ipaddress == NULL) {
+               g_free(nameservers);
+               g_free(address);
+               g_free(gateway);
+               g_free(peer);
+
+               return VPN_STATE_FAILURE;
        }
 
+       connman_ipaddress_set_ipv4(ipaddress, address, NULL, gateway);
+       connman_ipaddress_set_peer(ipaddress, peer);
+       connman_provider_set_ipaddress(provider, ipaddress);
+
+       connman_provider_set_nameservers(provider, nameservers);
+
+       g_free(nameservers);
+       g_free(address);
+       g_free(gateway);
+       g_free(peer);
+       connman_ipaddress_free(ipaddress);
+
        return VPN_STATE_CONNECT;
 }
 
+static int ov_save(struct connman_provider *provider, GKeyFile *keyfile)
+{
+       const char *option;
+       int i;
+
+       for (i = 0; i < (int)ARRAY_SIZE(ov_options); i++) {
+               if (strncmp(ov_options[i].cm_opt, "OpenVPN.", 8) == 0) {
+                       option = connman_provider_get_string(provider,
+                                                       ov_options[i].cm_opt);
+                       if (option == NULL)
+                               continue;
+
+                       g_key_file_set_string(keyfile,
+                                       connman_provider_get_save_group(provider),
+                                       ov_options[i].cm_opt, option);
+               }
+       }
+       return 0;
+}
+
+static int task_append_config_data(struct connman_provider *provider,
+                                       struct connman_task *task)
+{
+       const char *option;
+       int i;
+
+       for (i = 0; i < (int)ARRAY_SIZE(ov_options); i++) {
+               option = connman_provider_get_string(provider,
+                                       ov_options[i].cm_opt);
+               if (option == NULL)
+                       continue;
+
+               if (connman_task_add_argument(task,
+                                       ov_options[i].ov_opt,
+                                       ov_options[i].has_value ? option : NULL) < 0) {
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
 static int ov_connect(struct connman_provider *provider,
                struct connman_task *task, const char *if_name)
 {
-       const char *vpnhost, *cafile, *mtu, *certfile, *keyfile;
+       const char *option;
        int err, fd;
 
-       vpnhost = connman_provider_get_string(provider, "Host");
-       if (!vpnhost) {
+       option = connman_provider_get_string(provider, "Host");
+       if (option == NULL) {
                connman_error("Host not set; cannot enable VPN");
                return -EINVAL;
        }
 
-       cafile = connman_provider_get_string(provider, "OpenVPN.CACert");
-       certfile = connman_provider_get_string(provider, "OpenVPN.Cert");
-       keyfile = connman_provider_get_string(provider, "OpenVPN.Key");
-       mtu = connman_provider_get_string(provider, "VPN.MTU");
-
-       if (mtu)
-               connman_task_add_argument(task, "--mtu", (char *)mtu);
+       task_append_config_data(provider, task);
 
        connman_task_add_argument(task, "--syslog", NULL);
 
@@ -170,7 +256,6 @@ static int ov_connect(struct connman_provider *provider,
        connman_task_add_argument(task, "--dev-type", "tun");
 
        connman_task_add_argument(task, "--tls-client", NULL);
-       connman_task_add_argument(task, "--remote", (char *)vpnhost);
        connman_task_add_argument(task, "--nobind", NULL);
        connman_task_add_argument(task, "--persist-key", NULL);
        connman_task_add_argument(task, "--persist-tun", NULL);
@@ -190,21 +275,6 @@ static int ov_connect(struct connman_provider *provider,
 
        connman_task_add_argument(task, "--client", NULL);
 
-       if (cafile) {
-               connman_task_add_argument(task, "--ca",
-                                               (char *)cafile);
-       }
-
-       if (certfile) {
-               connman_task_add_argument(task, "--cert",
-                                               (char *)certfile);
-       }
-
-       if (keyfile) {
-               connman_task_add_argument(task, "--key",
-                                               (char *)keyfile);
-       }
-
        fd = fileno(stderr);
        err = connman_task_run(task, vpn_died, provider,
                        NULL, &fd, &fd);
@@ -219,6 +289,7 @@ static int ov_connect(struct connman_provider *provider,
 static struct vpn_driver vpn_driver = {
        .notify = ov_notify,
        .connect        = ov_connect,
+       .save           = ov_save,
 };
 
 static int openvpn_init(void)