diff --git a/man/nm-initrd-generator.xml b/man/nm-initrd-generator.xml
index 51015ea8a..170cb883e 100644
--- a/man/nm-initrd-generator.xml
+++ b/man/nm-initrd-generator.xml
@@ -157,6 +157,7 @@
+
@@ -233,6 +234,22 @@
+
+ NetworkManager supports the
+ =SERVER
+ kernel command line option to configure a global (non
+ interface-specific) DNS server. The option can be specified
+ multiple time to add more than one server. Each server can be
+ specified as a plain IP or as an URI according to the
+ description in the "global-dns-domains sections" paragraph of
+ NetworkManager.conf5. For
+ example: rd.net.dns=2001:db8::1,
+ rd.net.dns=dns+tls://192.0.2.0,
+ rd.net.dns=dns+tls://[2001:db8::2]:5353#example.org.
+
+
+
diff --git a/src/nm-initrd-generator/nm-initrd-generator.c b/src/nm-initrd-generator/nm-initrd-generator.c
index 844aebf74..14a168341 100644
--- a/src/nm-initrd-generator/nm-initrd-generator.c
+++ b/src/nm-initrd-generator/nm-initrd-generator.c
@@ -154,6 +154,7 @@ 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;
option_context = g_option_context_new(
"-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] "
@@ -193,7 +194,8 @@ main(int argc, char *argv[])
sysfs_dir,
(const char *const *) remaining,
&hostname,
- &carrier_timeout_sec);
+ &carrier_timeout_sec,
+ &global_dns_servers);
confs = g_array_new(FALSE, FALSE, sizeof(NMUtilsNamedValue));
g_array_set_clear_func(confs, (GDestroyNotify) nm_utils_named_value_clear_with_g_free);
@@ -233,6 +235,36 @@ main(int argc, char *argv[])
g_array_append_val(confs, v);
}
+ if (global_dns_servers) {
+ nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
+ NMUtilsNamedValue v;
+ gs_free char *value = NULL;
+
+ value = g_strjoinv(",", global_dns_servers);
+
+ keyfile = g_key_file_new();
+ g_key_file_set_list_separator(keyfile, NM_CONFIG_KEYFILE_LIST_SEPARATOR);
+
+ g_key_file_set_value(keyfile,
+ NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS,
+ NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS,
+ "");
+ g_key_file_set_value(keyfile,
+ NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN "*",
+ NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_SERVERS,
+ value);
+
+ if (!dump_to_stdout) {
+ add_keyfile_comment(keyfile, "from \"rd.net.dns\"");
+ }
+
+ 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 (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 87db9fc66..23dd48488 100644
--- a/src/nm-initrd-generator/nm-initrd-generator.h
+++ b/src/nm-initrd-generator/nm-initrd-generator.h
@@ -45,6 +45,7 @@ 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);
#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 80fb550ce..91fe5d1d5 100644
--- a/src/nm-initrd-generator/nmi-cmdline-reader.c
+++ b/src/nm-initrd-generator/nmi-cmdline-reader.c
@@ -36,10 +36,11 @@ typedef struct {
GHashTable *znet_ifnames;
/* Parameters to be set for all connections */
- gboolean ignore_auto_dns;
- int dhcp_timeout;
- char *dhcp4_vci;
- char *dhcp_dscp;
+ gboolean ignore_auto_dns;
+ int dhcp_timeout;
+ char *dhcp4_vci;
+ char *dhcp_dscp;
+ GPtrArray *global_dns;
gint64 carrier_timeout_sec;
} Reader;
@@ -69,6 +70,7 @@ 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);
@@ -1219,6 +1221,21 @@ 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_ethtool(Reader *reader, char *argument)
{
@@ -1392,7 +1409,8 @@ 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)
{
Reader *reader;
const char *tag;
@@ -1509,6 +1527,8 @@ 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);
}
}
@@ -1626,5 +1646,15 @@ nmi_cmdline_reader_parse(const char *etc_connections_dir,
NM_SET_OUT(carrier_timeout_sec, reader->carrier_timeout_sec);
+ 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 33b834979..07cf57bda 100644
--- a/src/nm-initrd-generator/tests/test-cmdline-reader.c
+++ b/src/nm-initrd-generator/tests/test-cmdline-reader.c
@@ -23,7 +23,7 @@
/*****************************************************************************/
-#define _parse(ARGV, out_hostname, out_carrier_timeout_sec) \
+#define _parse(ARGV, out_hostname, out_carrier_timeout_sec, _out_global_dns_servers) \
({ \
const char *const *const _ARGV = (ARGV); \
char **const _out_hostname = (out_hostname); \
@@ -34,26 +34,28 @@
TEST_INITRD_DIR "/sysfs", \
_ARGV, \
_out_hostname, \
- _out_carrier_timeout_sec); \
+ _out_carrier_timeout_sec, \
+ _out_global_dns_servers); \
\
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); \
+ g_assert_cmpstr(_con_hostname, ==, NULL); \
+ g_assert_cmpint(_con_carrier_timeout_sec, ==, 0); \
+ \
+ _con_connections; \
})
#define _parse_con(ARGV, connection_name) \
@@ -154,7 +156,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);
g_assert_cmpint(g_hash_table_size(connections), ==, 1);
g_assert_cmpstr(hostname, ==, "host1");
g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -424,7 +426,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);
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 +507,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);
g_assert_cmpint(g_hash_table_size(connections), ==, 1);
g_assert_cmpstr(hostname, ==, "myhostname");
g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -596,7 +598,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);
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 +686,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);
g_assert_cmpint(g_hash_table_size(connections), ==, 1);
g_assert_cmpstr(hostname, ==, "hostname0");
g_assert_cmpint(carrier_timeout_sec, ==, 0);
@@ -1840,7 +1842,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);
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 +1929,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);
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 +2008,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);
g_assert_cmpint(g_hash_table_size(connections), ==, 2);
connection = g_hash_table_lookup(connections, "zeth0");
@@ -2281,7 +2283,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);
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 +2462,38 @@ 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);
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");
+ gs_free char *hostname = NULL;
+ gs_strfreev char **global_dns_servers = 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);
+ 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);
+}
+
#define _ethtool_check_inval(arg) \
G_STMT_START \
{ \
@@ -2686,6 +2714,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();
}