summary refs log tree commit diff
path: root/src/dns/nm-dns-manager.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2020-12-06 21:57:59 +0100
committerMichael Biebl <biebl@debian.org>2020-12-06 21:57:59 +0100
commit65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (patch)
tree180827692f002e5f1dad6a0fa8ca489e6bb6438f /src/dns/nm-dns-manager.c
parentf2ddac4cbc895837ddcc55015fae112f9859cd0a (diff)
New upstream version 1.28.0 upstream/1.28.0
Diffstat (limited to 'src/dns/nm-dns-manager.c')
-rw-r--r--src/dns/nm-dns-manager.c238
1 files changed, 180 insertions, 58 deletions
diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c
index 635e94f6..3fc9a396 100644
--- a/src/dns/nm-dns-manager.c
+++ b/src/dns/nm-dns-manager.c
@@ -222,6 +222,26 @@ _ASSERT_ip_config_data(const NMDnsIPConfigData *ip_data)
     nm_assert(NM_IS_IP_CONFIG(ip_data->ip_config));
     nm_assert(c_list_contains(&ip_data->data->data_lst_head, &ip_data->data_lst));
     nm_assert(ip_data->data->ifindex == nm_ip_config_get_ifindex(ip_data->ip_config));
+#if NM_MORE_ASSERTS > 5
+    {
+        gboolean has_default = FALSE;
+        gsize    i;
+
+        for (i = 0; ip_data->domains.search && ip_data->domains.search; i++) {
+            const char *d = ip_data->domains.search[i];
+
+            d = nm_utils_parse_dns_domain(d, NULL);
+            nm_assert(d);
+            if (d[0] == '\0')
+                has_default = TRUE;
+        }
+        nm_assert(has_default == ip_data->domains.has_default_route_explicit);
+        if (ip_data->domains.has_default_route_explicit)
+            nm_assert(ip_data->domains.has_default_route_exclusive);
+        if (ip_data->domains.has_default_route_exclusive)
+            nm_assert(ip_data->domains.has_default_route);
+    }
+#endif
 }
 
 static NMDnsIPConfigData *
@@ -233,10 +253,12 @@ _ip_config_data_new(NMDnsConfigData *data, NMIPConfig *ip_config, NMDnsIPConfigT
     nm_assert(NM_IS_IP_CONFIG(ip_config));
     nm_assert(ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED);
 
-    ip_data                 = g_slice_new0(NMDnsIPConfigData);
-    ip_data->data           = data;
-    ip_data->ip_config      = g_object_ref(ip_config);
-    ip_data->ip_config_type = ip_config_type;
+    ip_data  = g_slice_new(NMDnsIPConfigData);
+    *ip_data = (NMDnsIPConfigData){
+        .data           = data,
+        .ip_config      = g_object_ref(ip_config),
+        .ip_config_type = ip_config_type,
+    };
     c_list_link_tail(&data->data_lst_head, &ip_data->data_lst);
     c_list_link_tail(&NM_DNS_MANAGER_GET_PRIVATE(data->self)->ip_config_lst_head,
                      &ip_data->ip_config_lst);
@@ -267,7 +289,7 @@ _ip_config_data_free(NMDnsIPConfigData *ip_data)
                                          ip_data);
 
     g_object_unref(ip_data->ip_config);
-    g_slice_free(NMDnsIPConfigData, ip_data);
+    nm_g_slice_free(ip_data);
 }
 
 static NMDnsIPConfigData *
@@ -292,7 +314,7 @@ _config_data_free(NMDnsConfigData *data)
     _ASSERT_config_data(data);
 
     nm_assert(c_list_is_empty(&data->data_lst_head));
-    g_slice_free(NMDnsConfigData, data);
+    nm_g_slice_free(data);
 }
 
 static int
@@ -1284,6 +1306,19 @@ get_ip_rdns_domains(NMIPConfig *ip_config)
     return _nm_utils_strv_cleanup(strv, FALSE, FALSE, TRUE);
 }
 
+static gboolean
+domain_ht_get_priority(GHashTable *ht, const char *domain, int *out_priority)
+{
+    gpointer ptr;
+
+    if (!ht || !g_hash_table_lookup_extended(ht, domain, NULL, &ptr)) {
+        *out_priority = 0;
+        return FALSE;
+    }
+    *out_priority = GPOINTER_TO_INT(ptr);
+    return TRUE;
+}
+
 /* Check if the domain is shadowed by a parent domain with more negative priority */
 static gboolean
 domain_is_shadowed(GHashTable * ht,
@@ -1300,21 +1335,25 @@ domain_is_shadowed(GHashTable * ht,
 
     nm_assert(!g_hash_table_contains(ht, domain));
 
-    parent_priority = GPOINTER_TO_INT(g_hash_table_lookup(ht, ""));
-    if (parent_priority < 0 && parent_priority < priority) {
-        *out_parent          = "";
-        *out_parent_priority = parent_priority;
-        return TRUE;
+    if (domain_ht_get_priority(ht, "", &parent_priority)) {
+        nm_assert(parent_priority <= priority);
+        if (parent_priority < 0 && parent_priority < priority) {
+            *out_parent          = "";
+            *out_parent_priority = parent_priority;
+            return TRUE;
+        }
     }
 
     parent = strchr(domain, '.');
     while (parent && parent[1]) {
         parent++;
-        parent_priority = GPOINTER_TO_INT(g_hash_table_lookup(ht, parent));
-        if (parent_priority < 0 && parent_priority < priority) {
-            *out_parent          = parent;
-            *out_parent_priority = parent_priority;
-            return TRUE;
+        if (domain_ht_get_priority(ht, parent, &parent_priority)) {
+            nm_assert(parent_priority <= priority);
+            if (parent_priority < 0 && parent_priority < priority) {
+                *out_parent          = parent;
+                *out_parent_priority = parent_priority;
+                return TRUE;
+            }
         }
         parent = strchr(parent, '.');
     }
@@ -1329,8 +1368,22 @@ rebuild_domain_lists(NMDnsManager *self)
     gs_unref_hashtable GHashTable *ht               = NULL;
     gs_unref_hashtable GHashTable *wildcard_entries = NULL;
     CList *                        head;
+    int                            prev_priority = G_MININT;
 
     head = _ip_config_lst_head(self);
+
+#if NM_MORE_ASSERTS
+    /* we call clear_domain_lists() at the end of update. We
+     * don't expect any domain settings here. */
+    c_list_for_each_entry (ip_data, head, ip_config_lst) {
+        nm_assert(!ip_data->domains.search);
+        nm_assert(!ip_data->domains.reverse);
+        nm_assert(!ip_data->domains.has_default_route_explicit);
+        nm_assert(!ip_data->domains.has_default_route_exclusive);
+        nm_assert(!ip_data->domains.has_default_route);
+    }
+#endif
+
     c_list_for_each_entry (ip_data, head, ip_config_lst) {
         NMIPConfig *ip_config    = ip_data->ip_config;
         gboolean    add_wildcard = FALSE;
@@ -1368,8 +1421,11 @@ rebuild_domain_lists(NMDnsManager *self)
         guint        n_domains;
         guint        num_dom1;
         guint        num_dom2;
-        guint        cap_dom;
+        guint        n_domains_allocated;
         guint        i;
+        gboolean     has_default_route_maybe    = FALSE;
+        gboolean     has_default_route_explicit = FALSE;
+        gboolean     has_default_route_auto     = FALSE;
 
         if (!nm_ip_config_get_num_nameservers(ip_config))
             continue;
@@ -1378,15 +1434,10 @@ rebuild_domain_lists(NMDnsManager *self)
         n_domains  = nm_ip_config_get_num_domains(ip_config);
 
         priority = nm_ip_config_get_dns_priority(ip_config);
-        nm_assert(priority != 0);
-
-        cap_dom = 2u + NM_MAX(n_domains, n_searches);
-
-        g_free(ip_data->domains.search);
-        domains                 = g_new(const char *, cap_dom);
-        ip_data->domains.search = domains;
 
-        num_dom1 = 0;
+        nm_assert(priority != 0);
+        nm_assert(prev_priority <= priority);
+        prev_priority = priority;
 
         /* Add wildcard lookup domain to connections with the default route.
          * If there is no default route, add the wildcard domain to all non-VPN
@@ -1398,12 +1449,17 @@ rebuild_domain_lists(NMDnsManager *self)
              * whether it is suitable for certain operations (like having an automatically
              * added "~" domain). */
             if (g_hash_table_contains(wildcard_entries, ip_data))
-                domains[num_dom1++] = "~";
+                has_default_route_maybe = TRUE;
         } else {
             if (ip_data->ip_config_type != NM_DNS_IP_CONFIG_TYPE_VPN)
-                domains[num_dom1++] = "~";
+                has_default_route_maybe = TRUE;
         }
 
+        n_domains_allocated = (n_searches > 0 ? n_searches : n_domains) + 1u;
+        domains             = g_new(const char *, n_domains_allocated);
+
+        num_dom1 = 0;
+
         /* searches are preferred over domains */
         if (n_searches > 0) {
             for (i = 0; i < n_searches; i++)
@@ -1413,32 +1469,55 @@ rebuild_domain_lists(NMDnsManager *self)
                 domains[num_dom1++] = nm_ip_config_get_domain(ip_config, i);
         }
 
-        nm_assert(num_dom1 < cap_dom);
+        nm_assert(num_dom1 < n_domains_allocated);
 
         num_dom2 = 0;
-        for (i = 0; i < num_dom1; i++) {
+        for (i = 0; TRUE; i++) {
+            const char *domain_full;
             const char *domain_clean;
             const char *parent;
             int         old_priority;
             int         parent_priority;
-
-            domain_clean = nm_utils_parse_dns_domain(domains[i], NULL);
+            gboolean    check_default_route;
+
+            if (i < num_dom1) {
+                check_default_route = FALSE;
+                domain_full         = domains[i];
+                domain_clean        = nm_utils_parse_dns_domain(domains[i], NULL);
+            } else if (i == num_dom1) {
+                if (!has_default_route_maybe)
+                    continue;
+                if (has_default_route_explicit)
+                    continue;
+                check_default_route = TRUE;
+                domain_full         = "~";
+                domain_clean        = "";
+            } else
+                break;
 
             /* Remove domains with lower priority */
-            old_priority = GPOINTER_TO_INT(nm_g_hash_table_lookup(ht, domain_clean));
-            if (old_priority != 0) {
+            if (domain_ht_get_priority(ht, domain_clean, &old_priority)) {
+                nm_assert(old_priority <= priority);
                 if (old_priority < priority) {
-                    _LOGT(
-                        "plugin: drop domain '%s' (i=%d, p=%d) because it already exists with p=%d",
-                        domains[i],
-                        ip_data->data->ifindex,
-                        priority,
-                        old_priority);
+                    _LOGT("plugin: drop domain %s%s%s (i=%d, p=%d) because it already exists "
+                          "with p=%d",
+                          NM_PRINT_FMT_QUOTED(!check_default_route,
+                                              "'",
+                                              domain_full,
+                                              "'",
+                                              "<auto-default>"),
+                          ip_data->data->ifindex,
+                          priority,
+                          old_priority);
                     continue;
                 }
             } else if (domain_is_shadowed(ht, domain_clean, priority, &parent, &parent_priority)) {
-                _LOGT("plugin: drop domain '%s' (i=%d, p=%d) shadowed by '%s' (p=%d)",
-                      domains[i],
+                _LOGT("plugin: drop domain %s%s%s (i=%d, p=%d) shadowed by '%s' (p=%d)",
+                      NM_PRINT_FMT_QUOTED(!check_default_route,
+                                          "'",
+                                          domain_full,
+                                          "'",
+                                          "<auto-default>"),
                       ip_data->data->ifindex,
                       priority,
                       parent,
@@ -1446,20 +1525,55 @@ rebuild_domain_lists(NMDnsManager *self)
                 continue;
             }
 
-            _LOGT("plugin: add domain '%s' (i=%d, p=%d)",
-                  domains[i],
-                  ip_data->data->ifindex,
-                  priority);
+            _LOGT(
+                "plugin: add domain %s%s%s (i=%d, p=%d)",
+                NM_PRINT_FMT_QUOTED(!check_default_route, "'", domain_full, "'", "<auto-default>"),
+                ip_data->data->ifindex,
+                priority);
+
             if (!ht)
                 ht = g_hash_table_new(nm_str_hash, g_str_equal);
             g_hash_table_insert(ht, (gpointer) domain_clean, GINT_TO_POINTER(priority));
-            domains[num_dom2++] = domains[i];
+
+            if (check_default_route)
+                has_default_route_auto = TRUE;
+            else {
+                nm_assert(num_dom2 <= num_dom1);
+                nm_assert(num_dom2 < n_domains_allocated);
+                domains[num_dom2++] = domain_full;
+                if (domain_clean[0] == '\0')
+                    has_default_route_explicit = TRUE;
+            }
         }
-        nm_assert(num_dom2 < cap_dom);
+        nm_assert(num_dom2 < n_domains_allocated);
         domains[num_dom2] = NULL;
 
-        g_strfreev(ip_data->domains.reverse);
-        ip_data->domains.reverse = get_ip_rdns_domains(ip_config);
+        nm_assert(!ip_data->domains.search);
+        nm_assert(!ip_data->domains.reverse);
+        ip_data->domains.search                     = domains;
+        ip_data->domains.reverse                    = get_ip_rdns_domains(ip_config);
+        ip_data->domains.has_default_route_explicit = has_default_route_explicit;
+        ip_data->domains.has_default_route_exclusive =
+            has_default_route_explicit || (priority < 0 && has_default_route_auto);
+        ip_data->domains.has_default_route =
+            ip_data->domains.has_default_route_exclusive || has_default_route_auto;
+
+        {
+            gs_free char *str1 = NULL;
+            gs_free char *str2 = NULL;
+
+            _LOGT("plugin: settings: ifindex=%d, priority=%d, default-route=%d%s, search=%s, "
+                  "reverse=%s",
+                  ip_data->data->ifindex,
+                  priority,
+                  ip_data->domains.has_default_route,
+                  ip_data->domains.has_default_route_explicit
+                      ? " (explicit)"
+                      : (ip_data->domains.has_default_route_exclusive ? " (exclusive)" : ""),
+                  (str1 = g_strjoinv(",", (char **) ip_data->domains.search)),
+                  (ip_data->domains.reverse ? (str2 = g_strjoinv(",", ip_data->domains.reverse))
+                                            : ""));
+        }
     }
 }
 
@@ -1473,6 +1587,9 @@ clear_domain_lists(NMDnsManager *self)
     c_list_for_each_entry (ip_data, head, ip_config_lst) {
         nm_clear_g_free(&ip_data->domains.search);
         nm_clear_pointer(&ip_data->domains.reverse, g_strfreev);
+        ip_data->domains.has_default_route_explicit  = FALSE;
+        ip_data->domains.has_default_route_exclusive = FALSE;
+        ip_data->domains.has_default_route           = FALSE;
     }
 }
 
@@ -1697,7 +1814,7 @@ nm_dns_manager_set_ip_config(NMDnsManager *    self,
 
     priv = NM_DNS_MANAGER_GET_PRIVATE(self);
 
-    data = g_hash_table_lookup(priv->configs, GINT_TO_POINTER(ifindex));
+    data = g_hash_table_lookup(priv->configs, &ifindex);
     if (!data)
         ip_data = NULL;
     else
@@ -1713,7 +1830,7 @@ nm_dns_manager_set_ip_config(NMDnsManager *    self,
         /* deleting a config doesn't invalidate the configs' sort order. */
         _ip_config_data_free(ip_data);
         if (c_list_is_empty(&data->data_lst_head))
-            g_hash_table_remove(priv->configs, GINT_TO_POINTER(ifindex));
+            g_hash_table_remove(priv->configs, &ifindex);
         goto changed;
     }
 
@@ -1723,12 +1840,14 @@ nm_dns_manager_set_ip_config(NMDnsManager *    self,
     }
 
     if (!data) {
-        data          = g_slice_new0(NMDnsConfigData);
-        data->ifindex = ifindex;
-        data->self    = self;
-        c_list_init(&data->data_lst_head);
+        data  = g_slice_new(NMDnsConfigData);
+        *data = (NMDnsConfigData){
+            .ifindex       = ifindex,
+            .self          = self,
+            .data_lst_head = C_LIST_INIT(data->data_lst_head),
+        };
         _ASSERT_config_data(data);
-        g_hash_table_insert(priv->configs, GINT_TO_POINTER(ifindex), data);
+        g_hash_table_add(priv->configs, data);
     }
 
     if (!ip_data)
@@ -2381,8 +2500,11 @@ nm_dns_manager_init(NMDnsManager *self)
 
     priv->config = g_object_ref(nm_config_get());
 
-    priv->configs =
-        g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) _config_data_free);
+    G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDnsConfigData, ifindex) == 0);
+    priv->configs = g_hash_table_new_full(nm_pint_hash,
+                                          nm_pint_equals,
+                                          (GDestroyNotify) _config_data_free,
+                                          NULL);
 
     /* Set the initial hash */
     compute_hash(self, NULL, NM_DNS_MANAGER_GET_PRIVATE(self)->hash);