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(); }