Add support for setting manual DNS server configuration
authorMarcel Holtmann <marcel@holtmann.org>
Wed, 12 May 2010 18:13:31 +0000 (20:13 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 12 May 2010 18:13:31 +0000 (20:13 +0200)
Makefile.am
src/connman.h
src/ipv4.c
src/service.c
test/list-services
test/monitor-services
test/set-nameservers [new file with mode: 0755]

index 64c0264..8a7aca9 100644 (file)
@@ -142,7 +142,8 @@ test_scripts = test/get-state test/list-profiles test/list-services \
                test/simple-agent test/show-introspection test/test-compat \
                test/test-manager test/test-connman test/monitor-connman \
                test/connect-vpn test/disconnect-vpn test/list-providers \
-               test/monitor-manager test/test-counter test/set-ip-method
+               test/monitor-manager test/test-counter test/set-ip-method \
+               test/set-nameservers
 
 if TEST
 testdir = $(pkglibdir)/test
index f3a3050..93f9770 100644 (file)
@@ -420,6 +420,11 @@ struct connman_service *__connman_service_connect_type(enum connman_service_type
 
 const char *__connman_service_type2string(enum connman_service_type type);
 
+void __connman_service_append_nameserver(struct connman_service *service,
+                                               const char *nameserver);
+void __connman_service_remove_nameserver(struct connman_service *service,
+                                               const char *nameserver);
+
 #include <connman/location.h>
 
 int __connman_location_init(void);
index fa56078..d3bc846 100644 (file)
@@ -40,8 +40,7 @@ struct connman_ipv4 {
        struct in_addr broadcast;
 };
 
-static int set_ipv4(struct connman_element *element,
-                       struct connman_ipv4 *ipv4, const char *nameserver)
+static int set_ipv4(struct connman_element *element, struct connman_ipv4 *ipv4)
 {
        struct ifreq ifr;
        struct sockaddr_in addr;
@@ -95,11 +94,6 @@ static int set_ipv4(struct connman_element *element,
 
        close(sk);
 
-       if (nameserver == NULL)
-               connman_error("No nameserver for %s defined", ifr.ifr_name);
-       else
-               connman_resolver_append(ifr.ifr_name, NULL, nameserver);
-
        return 0;
 }
 
@@ -125,8 +119,6 @@ static int clear_ipv4(struct connman_element *element)
 
        DBG("ifname %s", ifr.ifr_name);
 
-       connman_resolver_remove_all(ifr.ifr_name);
-
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_ANY;
@@ -207,7 +199,14 @@ static int ipv4_probe(struct connman_element *element)
                ipv4.broadcast.s_addr = ipv4.address.s_addr |
                                                ~ipv4.netmask.s_addr;
 
-       set_ipv4(element, &ipv4, nameserver);
+       set_ipv4(element, &ipv4);
+
+       if (nameserver != NULL) {
+               struct connman_service *service;
+
+               service = __connman_element_get_service(element);
+               __connman_service_append_nameserver(service, nameserver);
+       }
 
        connman_timeserver_append(timeserver);
 
@@ -225,15 +224,24 @@ static int ipv4_probe(struct connman_element *element)
 
 static void ipv4_remove(struct connman_element *element)
 {
-       const char *timeserver = NULL;
+       const char *nameserver = NULL, *timeserver = NULL;
 
        DBG("element %p name %s", element, element->name);
 
        connman_element_get_value(element,
+                       CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
+       connman_element_get_value(element,
                        CONNMAN_PROPERTY_ID_IPV4_TIMESERVER, &timeserver);
 
        connman_timeserver_remove(timeserver);
 
+       if (nameserver != NULL) {
+               struct connman_service *service;
+
+               service = __connman_element_get_service(element);
+               __connman_service_remove_nameserver(service, nameserver);
+       }
+
        clear_ipv4(element);
 }
 
index 31d4004..d5105c3 100644 (file)
@@ -65,6 +65,8 @@ struct connman_service {
        connman_bool_t roaming;
        struct connman_ipconfig *ipconfig;
        struct connman_network *network;
+       char **nameservers;
+       char *nameserver;
        /* 802.1x settings from the config files */
        char *eap;
        char *identity;
@@ -283,6 +285,69 @@ static connman_bool_t is_connected(const struct connman_service *service)
        return FALSE;
 }
 
+static void update_nameservers(struct connman_service *service)
+{
+       const char *ifname = connman_ipconfig_get_ifname(service->ipconfig);
+
+       if (ifname == NULL)
+               return;
+
+       switch (service->state) {
+       case CONNMAN_SERVICE_STATE_UNKNOWN:
+       case CONNMAN_SERVICE_STATE_IDLE:
+       case CONNMAN_SERVICE_STATE_ASSOCIATION:
+       case CONNMAN_SERVICE_STATE_CONFIGURATION:
+               return;
+       case CONNMAN_SERVICE_STATE_FAILURE:
+       case CONNMAN_SERVICE_STATE_DISCONNECT:
+               connman_resolver_remove_all(ifname);
+               return;
+       case CONNMAN_SERVICE_STATE_READY:
+       case CONNMAN_SERVICE_STATE_LOGIN:
+       case CONNMAN_SERVICE_STATE_ONLINE:
+               break;
+       }
+
+       connman_resolver_remove_all(ifname);
+
+       if (service->nameservers != NULL) {
+               int i;
+
+               for (i = 0; service->nameservers[i]; i++)
+                       connman_resolver_append(ifname, NULL,
+                                               service->nameservers[i]);
+       } else if (service->nameserver != NULL)
+               connman_resolver_append(ifname, NULL, service->nameserver);
+}
+
+void __connman_service_append_nameserver(struct connman_service *service,
+                                               const char *nameserver)
+{
+       DBG("service %p nameserver %s", service, nameserver);
+
+       if (nameserver == NULL)
+               return;
+
+       g_free(service->nameserver);
+       service->nameserver = g_strdup(nameserver);
+
+       update_nameservers(service);
+}
+
+void __connman_service_remove_nameserver(struct connman_service *service,
+                                               const char *nameserver)
+{
+       DBG("service %p nameserver %s", service, nameserver);
+
+       if (nameserver == NULL)
+               return;
+
+       g_free(service->nameserver);
+       service->nameserver = NULL;
+
+       update_nameservers(service);
+}
+
 static struct connman_service *get_default(void)
 {
        struct connman_service *service;
@@ -490,6 +555,43 @@ static void append_ipv4config(DBusMessageIter *iter, void *user_data)
                __connman_ipconfig_append_ipv4config(service->ipconfig, iter);
 }
 
+static void append_dns(DBusMessageIter *iter, void *user_data)
+{
+       struct connman_service *service = user_data;
+
+       if (is_connected(service) == FALSE)
+               return;
+
+       if (service->nameservers != NULL) {
+               int i;
+
+               for (i = 0; service->nameservers[i]; i++)
+                       dbus_message_iter_append_basic(iter,
+                               DBUS_TYPE_STRING, &service->nameservers[i]);
+
+               return;
+       }
+
+       if (service->nameserver == NULL)
+               return;
+
+       dbus_message_iter_append_basic(iter,
+                               DBUS_TYPE_STRING, &service->nameserver);
+}
+
+static void append_dnsconfig(DBusMessageIter *iter, void *user_data)
+{
+       struct connman_service *service = user_data;
+       int i;
+
+       if (service->nameservers == NULL)
+               return;
+
+       for (i = 0; service->nameservers[i]; i++)
+               dbus_message_iter_append_basic(iter,
+                               DBUS_TYPE_STRING, &service->nameservers[i]);
+}
+
 static void append_proxy(DBusMessageIter *iter, void *user_data)
 {
        struct connman_service *service = user_data;
@@ -517,6 +619,26 @@ static void ipv4_configuration_changed(struct connman_service *service)
                                                        service);
 }
 
+static void dns_changed(struct connman_service *service)
+{
+       if (is_connected(service) == FALSE)
+               return;
+
+       connman_dbus_property_changed_array(service->path,
+                               CONNMAN_SERVICE_INTERFACE, "Nameservers",
+                                       DBUS_TYPE_STRING, append_dns, service);
+}
+
+static void dns_configuration_changed(struct connman_service *service)
+{
+       connman_dbus_property_changed_array(service->path,
+                               CONNMAN_SERVICE_INTERFACE,
+                               "Nameservers.Configuration",
+                               DBUS_TYPE_STRING, append_dnsconfig, service);
+
+       dns_changed(service);
+}
+
 static DBusMessage *get_properties(DBusConnection *conn,
                                        DBusMessage *msg, void *user_data)
 {
@@ -662,6 +784,12 @@ static DBusMessage *get_properties(DBusConnection *conn,
        connman_dbus_dict_append_dict(&dict, "IPv4.Configuration",
                                                append_ipv4config, service);
 
+       connman_dbus_dict_append_array(&dict, "Nameservers",
+                               DBUS_TYPE_STRING, append_dns, service);
+
+       connman_dbus_dict_append_array(&dict, "Nameservers.Configuration",
+                               DBUS_TYPE_STRING, append_dnsconfig, service);
+
        connman_dbus_dict_append_dict(&dict, "Proxy", append_proxy, service);
 
        connman_dbus_dict_close(&array, &dict);
@@ -792,6 +920,42 @@ static DBusMessage *set_property(DBusConnection *conn,
                                        "Cellular.Password", service->password);
 
                __connman_storage_save_service(service);
+       } else if (g_str_equal(name, "Nameservers.Configuration") == TRUE) {
+               DBusMessageIter entry;
+               GString *str;
+
+               if (type != DBUS_TYPE_ARRAY)
+                       return __connman_error_invalid_arguments(msg);
+
+               str = g_string_new(NULL);
+               if (str == NULL)
+                       return __connman_error_invalid_arguments(msg);
+
+               dbus_message_iter_recurse(&value, &entry);
+
+               while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+                       const char *val;
+                       dbus_message_iter_get_basic(&entry, &val);
+                       dbus_message_iter_next(&entry);
+                       if (str->len > 0)
+                               g_string_append_printf(str, " %s", val);
+                       else
+                               g_string_append(str, val);
+               }
+
+               g_strfreev(service->nameservers);
+
+               if (str->len > 0)
+                       service->nameservers = g_strsplit_set(str->str, " ", 0);
+               else
+                       service->nameservers = NULL;
+
+               g_string_free(str, TRUE);
+
+               update_nameservers(service);
+               dns_configuration_changed(service);
+
+               __connman_storage_save_service(service);
        } else if (g_str_equal(name, "IPv4.Configuration") == TRUE) {
                int err;
 
@@ -1282,6 +1446,8 @@ static void service_free(gpointer user_data)
        if (service->location != NULL)
                connman_location_unref(service->location);
 
+       g_strfreev(service->nameservers);
+
        g_free(service->mcc);
        g_free(service->mnc);
        g_free(service->apn);
@@ -1496,8 +1662,7 @@ __connman_service_get_network(struct connman_service *service)
        return service->network;
 }
 
-struct connman_ipconfig *
-__connman_service_get_ipconfig(struct connman_service *service)
+struct connman_ipconfig *__connman_service_get_ipconfig(struct connman_service *service)
 {
        if (service == NULL)
                return NULL;
@@ -1632,15 +1797,20 @@ int __connman_service_indicate_state(struct connman_service *service,
                g_get_current_time(&service->modified);
                __connman_storage_save_service(service);
 
+               update_nameservers(service);
+               dns_changed(service);
+
                __connman_notifier_connect(service->type);
 
                default_changed();
-
        } else if (state == CONNMAN_SERVICE_STATE_DISCONNECT) {
                __connman_location_finish(service);
 
                default_changed();
 
+               update_nameservers(service);
+               dns_changed(service);
+
                __connman_notifier_disconnect(service->type);
        }
 
@@ -2733,6 +2903,13 @@ static int service_load(struct connman_service *service)
                __connman_ipconfig_load(service->ipconfig, keyfile,
                                        service->identifier, "IPv4.");
 
+       service->nameservers = g_key_file_get_string_list(keyfile,
+                       service->identifier, "Nameservers", &length, NULL);
+       if (service->nameservers != NULL && length == 0) {
+               g_strfreev(service->nameservers);
+               service->nameservers = NULL;
+       }
+
 done:
        g_key_file_free(keyfile);
 
@@ -2866,6 +3043,16 @@ update:
                __connman_ipconfig_save(service->ipconfig, keyfile,
                                        service->identifier, "IPv4.");
 
+       if (service->nameservers != NULL) {
+               guint len = g_strv_length(service->nameservers);
+
+               g_key_file_set_string_list(keyfile, service->identifier,
+                                                               "Nameservers",
+                               (const gchar **) service->nameservers, len);
+       } else
+               g_key_file_remove_key(keyfile, service->identifier,
+                                                       "Nameservers", NULL);
+
        data = g_key_file_to_data(keyfile, &length, NULL);
 
        if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
index 8105f61..e747656 100755 (executable)
@@ -10,6 +10,13 @@ def extract_values(values):
        val += " }"
        return val
 
+def extract_list(list):
+       val = "["
+       for i in list:
+               val += " " + str(i)
+       val += " ]"
+       return val
+
 bus = dbus.SystemBus()
 
 manager = dbus.Interface(bus.get_object("org.moblin.connman", "/"),
@@ -28,6 +35,8 @@ for path in properties["Services"]:
        for key in properties.keys():
                if key in ["IPv4", "IPv4.Configuration", "Proxy", "Ethernet"]:
                        val = extract_values(properties[key])
+               elif key in ["Nameservers", "Nameservers.Configuration"]:
+                       val = extract_list(properties[key])
                elif key in ["Favorite", "Immutable", "AutoConnect",
                                "SetupRequired", "PassphraseRequired"]:
                        if properties[key] == dbus.Boolean(1):
index f1d7cf1..5657444 100755 (executable)
@@ -13,6 +13,13 @@ def extract_values(values):
        val += " }"
        return val
 
+def extract_list(list):
+       val = "["
+       for i in list:
+               val += " " + str(i)
+       val += " ]"
+       return val
+
 def property_changed(name, value, path):
        service = path[path.rfind("/") + 1:]
        if name in ["Profiles", "Services", "Providers", "Technologies",
@@ -23,6 +30,8 @@ def property_changed(name, value, path):
                val = val + " ]"
        elif name in ["IPv4", "IPv4.Configuration", "Proxy", "Ethernet"]:
                val = extract_values(value)
+       elif name in ["Nameservers", "Nameservers.Configuration"]:
+               val = extract_list(value)
        elif name in ["Strength", "Priority"]:
                val = int(value)
        else:
diff --git a/test/set-nameservers b/test/set-nameservers
new file mode 100755 (executable)
index 0000000..9e513a5
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+
+if (len(sys.argv) < 2):
+       print "Usage: %s <service> [nameserver*]" % (sys.argv[0])
+       sys.exit(1)
+
+bus = dbus.SystemBus()
+path = "/profile/default/" + sys.argv[1]
+service = dbus.Interface(bus.get_object('org.moblin.connman', path),
+                                       'org.moblin.connman.Service')
+
+properties = service.GetProperties()
+
+print "Setting nameserver to %s" % (sys.argv[2:])
+
+service.SetProperty("Nameservers.Configuration", 
+       dbus.Array(sys.argv[2:], signature=dbus.Signature('s')))