summary refs log tree commit diff
path: root/src/nm-initrd-generator
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-initrd-generator')
-rw-r--r--src/nm-initrd-generator/nm-initrd-generator.c66
-rw-r--r--src/nm-initrd-generator/nm-initrd-generator.h5
-rw-r--r--src/nm-initrd-generator/nmi-cmdline-reader.c69
-rw-r--r--src/nm-initrd-generator/tests/test-cmdline-reader.c100
4 files changed, 208 insertions, 32 deletions
diff --git a/src/nm-initrd-generator/nm-initrd-generator.c b/src/nm-initrd-generator/nm-initrd-generator.c
index d84e95e5..b89b4e41 100644
--- a/src/nm-initrd-generator/nm-initrd-generator.c
+++ b/src/nm-initrd-generator/nm-initrd-generator.c
@@ -11,6 +11,7 @@
 #include "libnm-core-intern/nm-core-internal.h"
 #include "libnm-core-intern/nm-keyfile-internal.h"
 #include "libnm-glib-aux/nm-io-utils.h"
+#include "libnm-glib-aux/nm-keyfile-aux.h"
 #include "libnm-log-core/nm-logging.h"
 
 /*****************************************************************************/
@@ -154,6 +155,9 @@ main(int argc, char *argv[])
     gint64                                      carrier_timeout_sec = 0;
     gs_unref_array GArray                      *confs               = NULL;
     guint                                       i;
+    gs_strfreev char                          **global_dns_servers = NULL;
+    gs_free char                               *dns_backend        = NULL;
+    gs_free char                               *dns_resolve_mode   = NULL;
 
     option_context = g_option_context_new(
         "-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] "
@@ -193,7 +197,10 @@ main(int argc, char *argv[])
                                            sysfs_dir,
                                            (const char *const *) remaining,
                                            &hostname,
-                                           &carrier_timeout_sec);
+                                           &carrier_timeout_sec,
+                                           &global_dns_servers,
+                                           &dns_backend,
+                                           &dns_resolve_mode);
 
     confs = g_array_new(FALSE, FALSE, sizeof(NMUtilsNamedValue));
     g_array_set_clear_func(confs, (GDestroyNotify) nm_utils_named_value_clear_with_g_free);
@@ -226,13 +233,68 @@ main(int argc, char *argv[])
                                                          : "from \"rd.net.timeout.carrier\"");
         }
 
-        v = (NMUtilsNamedValue){
+        v = (NMUtilsNamedValue) {
             .name      = g_strdup_printf("%s/15-carrier-timeout.conf", run_config_dir),
             .value_str = g_key_file_to_data(keyfile, NULL, NULL),
         };
         g_array_append_val(confs, v);
     }
 
+    if (global_dns_servers || dns_resolve_mode) {
+        nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
+        NMUtilsNamedValue               v;
+        gs_free char                   *dns_list = NULL;
+
+        keyfile = g_key_file_new();
+        g_key_file_set_list_separator(keyfile, NM_CONFIG_KEYFILE_LIST_SEPARATOR);
+        nm_key_file_add_group(keyfile, NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS);
+
+        if (dns_resolve_mode) {
+            g_key_file_set_value(keyfile,
+                                 NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS,
+                                 NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE,
+                                 dns_resolve_mode);
+        }
+
+        if (global_dns_servers) {
+            dns_list = g_strjoinv(",", global_dns_servers);
+            g_key_file_set_value(keyfile,
+                                 NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN "*",
+                                 NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_SERVERS,
+                                 dns_list);
+        }
+
+        if (!dump_to_stdout) {
+            add_keyfile_comment(keyfile, "from \"rd.net.dns\" and \"rd.net.dns-resolv-mode\"");
+        }
+
+        v = (NMUtilsNamedValue) {
+            .name      = g_strdup_printf("%s/16-global-dns.conf", run_config_dir),
+            .value_str = g_key_file_to_data(keyfile, NULL, NULL),
+        };
+        g_array_append_val(confs, v);
+    }
+
+    if (dns_backend) {
+        nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
+        NMUtilsNamedValue               v;
+
+        keyfile = g_key_file_new();
+        g_key_file_set_value(keyfile,
+                             NM_CONFIG_KEYFILE_GROUP_MAIN,
+                             NM_CONFIG_KEYFILE_KEY_MAIN_DNS,
+                             dns_backend);
+        if (!dump_to_stdout) {
+            add_keyfile_comment(keyfile, "from \"rd.net.dns-backend\"");
+        }
+
+        v = (NMUtilsNamedValue) {
+            .name      = g_strdup_printf("%s/16-dns-backend.conf", run_config_dir),
+            .value_str = g_key_file_to_data(keyfile, NULL, NULL),
+        };
+        g_array_append_val(confs, v);
+    }
+
     if (dump_to_stdout) {
         nm_clear_g_free(&connections_dir);
         nm_clear_g_free(&initrd_dir);
diff --git a/src/nm-initrd-generator/nm-initrd-generator.h b/src/nm-initrd-generator/nm-initrd-generator.h
index 87db9fc6..c2baad4e 100644
--- a/src/nm-initrd-generator/nm-initrd-generator.h
+++ b/src/nm-initrd-generator/nm-initrd-generator.h
@@ -45,6 +45,9 @@ GHashTable *nmi_cmdline_reader_parse(const char        *etc_connections_dir,
                                      const char        *sysfs_dir,
                                      const char *const *argv,
                                      char             **hostname,
-                                     gint64            *carrier_timeout_sec);
+                                     gint64            *carrier_timeout_sec,
+                                     char            ***global_dns_servers,
+                                     char             **dns_backend,
+                                     char             **dns_resolve_mode);
 
 #endif /* __NM_INITRD_GENERATOR_H__ */
diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c
index 3703ff0c..d6dc1fcb 100644
--- a/src/nm-initrd-generator/nmi-cmdline-reader.c
+++ b/src/nm-initrd-generator/nmi-cmdline-reader.c
@@ -34,6 +34,9 @@ typedef struct {
     NMConnection *default_connection; /* connection not bound to any ifname */
     char         *hostname;
     GHashTable   *znet_ifnames;
+    GPtrArray    *global_dns;
+    char         *dns_backend;
+    char         *dns_resolve_mode;
 
     /* Parameters to be set for all connections */
     gboolean ignore_auto_dns;
@@ -50,7 +53,7 @@ reader_new(void)
     Reader *reader;
 
     reader  = g_slice_new(Reader);
-    *reader = (Reader){
+    *reader = (Reader) {
         .hash = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref),
         .explicit_ip_connections =
             g_hash_table_new_full(nm_direct_hash, NULL, g_object_unref, NULL),
@@ -69,12 +72,15 @@ reader_destroy(Reader *reader, gboolean free_hash)
 
     g_ptr_array_unref(reader->array);
     g_ptr_array_unref(reader->vlan_parents);
+    nm_clear_pointer(&reader->global_dns, g_ptr_array_unref);
     g_hash_table_unref(reader->explicit_ip_connections);
     hash = g_steal_pointer(&reader->hash);
     nm_clear_g_free(&reader->hostname);
     g_hash_table_unref(reader->znet_ifnames);
     nm_clear_g_free(&reader->dhcp4_vci);
     nm_clear_g_free(&reader->dhcp_dscp);
+    nm_clear_g_free(&reader->dns_backend);
+    nm_clear_g_free(&reader->dns_resolve_mode);
     nm_g_slice_free(reader);
     if (!free_hash)
         return g_steal_pointer(&hash);
@@ -1220,6 +1226,43 @@ reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames)
 }
 
 static void
+reader_parse_global_dns(Reader *reader, char *argument)
+{
+    if (!nm_dns_uri_parse(AF_UNSPEC, argument, NULL)) {
+        _LOGW(LOGD_CORE, "rd.net.dns: invalid server '%s'", argument);
+        return;
+    }
+
+    if (!reader->global_dns) {
+        reader->global_dns = g_ptr_array_new_with_free_func(g_free);
+    }
+
+    g_ptr_array_add(reader->global_dns, g_strdup(argument));
+}
+
+static void
+reader_parse_dns_backend(Reader *reader, const char *argument)
+{
+    if (!NM_IN_STRSET(argument, "none", "default", "systemd-resolved", "dnsmasq", "dnsconfd")) {
+        _LOGW(LOGD_CORE, "rd.net.dns-backend: invalid value '%s'", argument);
+        return;
+    }
+
+    reader->dns_backend = g_strdup(argument);
+}
+
+static void
+reader_parse_dns_resolve_mode(Reader *reader, const char *argument)
+{
+    if (!NM_IN_STRSET(argument, "backup", "prefer", "exclusive")) {
+        _LOGW(LOGD_CORE, "rd.net.dns-resolve-mode: invalid value '%s'", argument);
+        return;
+    }
+
+    reader->dns_resolve_mode = g_strdup(argument);
+}
+
+static void
 reader_parse_ethtool(Reader *reader, char *argument)
 {
     NMConnection   *connection;
@@ -1392,7 +1435,10 @@ nmi_cmdline_reader_parse(const char        *etc_connections_dir,
                          const char        *sysfs_dir,
                          const char *const *argv,
                          char             **hostname,
-                         gint64            *carrier_timeout_sec)
+                         gint64            *carrier_timeout_sec,
+                         char            ***global_dns_servers,
+                         char             **dns_backend,
+                         char             **dns_resolve_mode)
 {
     Reader                      *reader;
     const char                  *tag;
@@ -1509,6 +1555,12 @@ nmi_cmdline_reader_parse(const char        *etc_connections_dir,
             bootif_val = g_strdup(argument);
         } else if (nm_streq(tag, "rd.ethtool")) {
             reader_parse_ethtool(reader, argument);
+        } else if (nm_streq(tag, "rd.net.dns")) {
+            reader_parse_global_dns(reader, argument);
+        } else if (nm_streq(tag, "rd.net.dns-backend")) {
+            reader_parse_dns_backend(reader, argument);
+        } else if (nm_streq(tag, "rd.net.dns-resolve-mode")) {
+            reader_parse_dns_resolve_mode(reader, argument);
         }
     }
 
@@ -1623,8 +1675,19 @@ nmi_cmdline_reader_parse(const char        *etc_connections_dir,
     g_hash_table_foreach(reader->hash, _normalize_conn, NULL);
 
     NM_SET_OUT(hostname, g_steal_pointer(&reader->hostname));
-
     NM_SET_OUT(carrier_timeout_sec, reader->carrier_timeout_sec);
+    NM_SET_OUT(dns_backend, g_steal_pointer(&reader->dns_backend));
+    NM_SET_OUT(dns_resolve_mode, g_steal_pointer(&reader->dns_resolve_mode));
+
+    if (reader->global_dns) {
+        if (global_dns_servers) {
+            g_ptr_array_add(reader->global_dns, NULL);
+            *global_dns_servers = (char **) g_ptr_array_free(reader->global_dns, FALSE);
+            reader->global_dns  = NULL;
+        }
+    } else {
+        NM_SET_OUT(global_dns_servers, NULL);
+    }
 
     return reader_destroy(reader, FALSE);
 }
diff --git a/src/nm-initrd-generator/tests/test-cmdline-reader.c b/src/nm-initrd-generator/tests/test-cmdline-reader.c
index 33b83497..a0100764 100644
--- a/src/nm-initrd-generator/tests/test-cmdline-reader.c
+++ b/src/nm-initrd-generator/tests/test-cmdline-reader.c
@@ -23,7 +23,12 @@
 
 /*****************************************************************************/
 
-#define _parse(ARGV, out_hostname, out_carrier_timeout_sec)                            \
+#define _parse(ARGV,                                                                   \
+               out_hostname,                                                           \
+               out_carrier_timeout_sec,                                                \
+               _out_global_dns_servers,                                                \
+               _out_dns_backend,                                                       \
+               _out_dns_resolve_mode)                                                  \
     ({                                                                                 \
         const char *const *const _ARGV                    = (ARGV);                    \
         char **const             _out_hostname            = (out_hostname);            \
@@ -34,26 +39,31 @@
                                                 TEST_INITRD_DIR "/sysfs",              \
                                                 _ARGV,                                 \
                                                 _out_hostname,                         \
-                                                _out_carrier_timeout_sec);             \
-                                                                                       \
+                                                _out_carrier_timeout_sec,              \
+                                                _out_global_dns_servers,               \
+                                                _out_dns_backend,                      \
+                                                _out_dns_resolve_mode);                \
         g_assert(_connections);                                                        \
                                                                                        \
         _connections;                                                                  \
     })
 
-#define _parse_cons(ARGV)                                                                    \
-    ({                                                                                       \
-        GHashTable   *_con_connections;                                                      \
-        gs_free char *_con_hostname            = NULL;                                       \
-        gint64        _con_carrier_timeout_sec = 0;                                          \
-                                                                                             \
-        _con_connections = _parse((ARGV),                                                    \
-                                  nmtst_get_rand_bool() ? &_con_hostname : NULL,             \
-                                  nmtst_get_rand_bool() ? &_con_carrier_timeout_sec : NULL); \
-        g_assert_cmpstr(_con_hostname, ==, NULL);                                            \
-        g_assert_cmpint(_con_carrier_timeout_sec, ==, 0);                                    \
-                                                                                             \
-        _con_connections;                                                                    \
+#define _parse_cons(ARGV)                                                                   \
+    ({                                                                                      \
+        GHashTable   *_con_connections;                                                     \
+        gs_free char *_con_hostname            = NULL;                                      \
+        gint64        _con_carrier_timeout_sec = 0;                                         \
+                                                                                            \
+        _con_connections = _parse((ARGV),                                                   \
+                                  nmtst_get_rand_bool() ? &_con_hostname : NULL,            \
+                                  nmtst_get_rand_bool() ? &_con_carrier_timeout_sec : NULL, \
+                                  NULL,                                                     \
+                                  NULL,                                                     \
+                                  NULL);                                                    \
+        g_assert_cmpstr(_con_hostname, ==, NULL);                                           \
+        g_assert_cmpint(_con_carrier_timeout_sec, ==, 0);                                   \
+                                                                                            \
+        _con_connections;                                                                   \
     })
 
 #define _parse_con(ARGV, connection_name)                                        \
@@ -154,7 +164,7 @@ test_dhcp_with_hostname(void)
     gs_free char                  *hostname            = NULL;
     gint64                         carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 1);
     g_assert_cmpstr(hostname, ==, "host1");
     g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -424,7 +434,7 @@ test_if_ip4_manual(void)
     gs_free char                  *hostname            = NULL;
     gint64                         carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 2);
     g_assert_cmpstr(hostname, ==, "hostname1.example.com");
     g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -505,7 +515,7 @@ test_if_ip4_auto(void)
     gs_free char                  *hostname            = NULL;
     gint64                         carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 1);
     g_assert_cmpstr(hostname, ==, "myhostname");
     g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -596,7 +606,7 @@ test_if_ip6_manual(void)
     gs_free char                  *hostname            = NULL;
     gint64                         carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 1);
     g_assert_cmpstr(hostname, ==, "hostname0.example.com");
     g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -684,7 +694,7 @@ test_if_mac_ifname(void)
     gs_free char                  *hostname            = NULL;
     gint64                         carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 1);
     g_assert_cmpstr(hostname, ==, "hostname0");
     g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -1840,7 +1850,7 @@ test_rd_znet(void)
     gs_free char *hostname            = NULL;
     gint64        carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 2);
     g_assert_cmpstr(hostname, ==, "foo.example.com");
     g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -1927,7 +1937,7 @@ test_rd_znet_legacy(void)
     gs_free char        *hostname            = NULL;
     gint64               carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 2);
     g_assert_cmpstr(hostname, ==, "foo.example.com");
     g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -2006,7 +2016,7 @@ test_rd_znet_ifnames(void)
     gint64               carrier_timeout_sec = 0;
     const char *const   *v_subchannels;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 2);
 
     connection = g_hash_table_lookup(connections, "zeth0");
@@ -2281,7 +2291,7 @@ test_nameserver(void)
     gs_free char      *hostname            = NULL;
     gint64             carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 3);
     g_assert_cmpstr(hostname, ==, "foo.example.com");
     g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -2460,12 +2470,49 @@ test_carrier_timeout(void)
     gs_free char                  *hostname            = NULL;
     gint64                         carrier_timeout_sec = 0;
 
-    connections = _parse(ARGV, &hostname, &carrier_timeout_sec);
+    connections = _parse(ARGV, &hostname, &carrier_timeout_sec, NULL, NULL, NULL);
     g_assert_cmpint(g_hash_table_size(connections), ==, 0);
     g_assert_cmpstr(hostname, ==, NULL);
     g_assert_cmpint(carrier_timeout_sec, ==, 20);
 }
 
+static void
+test_global_dns(void)
+{
+    gs_unref_hashtable GHashTable *connections        = NULL;
+    const char *const             *ARGV               = NM_MAKE_STRV("rd.net.dns=dns+tls://8.8.8.8",
+                                           "rd.net.dns=1.1.1.1",
+                                           "rd.net.dns=foobar",
+                                           "rd.net.dns=dns+tls://[fd01::1]:35#name",
+                                           "rd.net.dns-backend=dnsconfd",
+                                           "rd.net.dns-resolve-mode=exclusive");
+    gs_free char                  *hostname           = NULL;
+    gs_strfreev char             **global_dns_servers = NULL;
+    gs_free char                  *dns_backend        = NULL;
+    gs_free char                  *dns_resolve_mode   = NULL;
+    gint64                         carrier_timeout_sec = 0;
+
+    NMTST_EXPECT_NM_WARN("cmdline-reader: rd.net.dns: invalid server 'foobar'");
+    connections = _parse(ARGV,
+                         &hostname,
+                         &carrier_timeout_sec,
+                         &global_dns_servers,
+                         &dns_backend,
+                         &dns_resolve_mode);
+    g_test_assert_expected_messages();
+
+    g_assert_cmpint(g_hash_table_size(connections), ==, 0);
+    g_assert_cmpstr(hostname, ==, NULL);
+    g_assert_cmpint(carrier_timeout_sec, ==, 0);
+    g_assert(global_dns_servers != NULL);
+    g_assert_cmpstr(global_dns_servers[0], ==, "dns+tls://8.8.8.8");
+    g_assert_cmpstr(global_dns_servers[1], ==, "1.1.1.1");
+    g_assert_cmpstr(global_dns_servers[2], ==, "dns+tls://[fd01::1]:35#name");
+    g_assert_cmpstr(global_dns_servers[3], ==, NULL);
+    g_assert_cmpstr(dns_backend, ==, "dnsconfd");
+    g_assert_cmpstr(dns_resolve_mode, ==, "exclusive");
+}
+
 #define _ethtool_check_inval(arg)                                 \
     G_STMT_START                                                  \
     {                                                             \
@@ -2686,6 +2733,7 @@ main(int argc, char **argv)
     g_test_add_func("/initrd/cmdline/carrier_timeout", test_carrier_timeout);
     g_test_add_func("/initrd/cmdline/rd_ethtool", test_rd_ethtool);
     g_test_add_func("/initrd/cmdline/plain_equal_char", test_plain_equal_char);
+    g_test_add_func("/initrd/cmdline/global_dns", test_global_dns);
 
     return g_test_run();
 }