mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-03-24 10:10:47 +01:00
Add support for two new command line arguments: - `rd.net.dns-backend` used to control the "dns" option in NetworkManager configuration; - `rd.net.dns-resolve-mode` used to control the "resolve-mode" in the global DNS configuration. The use case for them is the installation of a new system where the administrator wants to configure aspects of the DNS resolution starting from the early boot, for example to enable DNS over TLS and avoid that any query goes out unencrypted. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2123
355 lines
14 KiB
C
355 lines
14 KiB
C
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
/*
|
|
* Copyright (C) 2018 Red Hat, Inc.
|
|
*/
|
|
|
|
#include "libnm-core-impl/nm-default-libnm-core.h"
|
|
|
|
#include "nm-initrd-generator.h"
|
|
|
|
#include "libnm-base/nm-config-base.h"
|
|
#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"
|
|
|
|
/*****************************************************************************/
|
|
|
|
#define _NMLOG(level, domain, ...) \
|
|
nm_log((level), \
|
|
(domain), \
|
|
NULL, \
|
|
NULL, \
|
|
"initrd-generator: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) \
|
|
_NM_UTILS_MACRO_REST(__VA_ARGS__))
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
add_keyfile_comment(GKeyFile *keyfile, char *reason)
|
|
{
|
|
gs_free char *comment = NULL;
|
|
|
|
comment = g_strdup_printf(" Created by nm-initrd-generator%s%s%s",
|
|
reason ? " (" : "",
|
|
reason ? reason : "",
|
|
reason ? ")" : "");
|
|
g_key_file_set_comment(keyfile, NULL, NULL, comment, NULL);
|
|
}
|
|
|
|
static void
|
|
output_conn(gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
const char *basename = key;
|
|
NMConnection *connection = value;
|
|
char *connections_dir = user_data;
|
|
nm_auto_unref_keyfile GKeyFile *file = NULL;
|
|
gs_free char *data = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
gsize len;
|
|
NMSetting *setting;
|
|
|
|
setting = nm_setting_user_new();
|
|
nm_connection_add_setting(connection, setting);
|
|
nm_setting_user_set_data(NM_SETTING_USER(setting),
|
|
NM_USER_TAG_ORIGIN,
|
|
"nm-initrd-generator",
|
|
NULL);
|
|
|
|
if (!nm_connection_normalize(connection, NULL, NULL, &error))
|
|
goto err_out;
|
|
|
|
file = nm_keyfile_write(connection, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error);
|
|
if (!file)
|
|
goto err_out;
|
|
|
|
if (connections_dir)
|
|
add_keyfile_comment(file, NULL);
|
|
|
|
data = g_key_file_to_data(file, &len, &error);
|
|
if (!data)
|
|
goto err_out;
|
|
|
|
if (connections_dir) {
|
|
gs_free char *filename = NULL;
|
|
gs_free char *full_filename = NULL;
|
|
|
|
filename = nm_keyfile_utils_create_filename(basename, TRUE);
|
|
full_filename = g_build_filename(connections_dir, filename, NULL);
|
|
|
|
if (!nm_utils_file_set_contents(full_filename, data, len, 0600, NULL, NULL, &error))
|
|
goto err_out;
|
|
} else
|
|
g_print("\n*** Connection '%s' ***\n\n%s", basename, data);
|
|
|
|
return;
|
|
err_out:
|
|
g_print("%s\n", error->message);
|
|
}
|
|
|
|
#define DEFAULT_SYSFS_DIR "/sys"
|
|
#define DEFAULT_INITRD_DATA_DIR NMRUNDIR "/initrd"
|
|
#define DEFAULT_RUN_CONFIG_DIR NMRUNDIR "/conf.d"
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
GHashTable *connections;
|
|
gs_free char *connections_dir = NULL;
|
|
gs_free char *etc_connections_dir = NULL;
|
|
gs_free char *initrd_dir = NULL;
|
|
gs_free char *sysfs_dir = NULL;
|
|
gs_free char *run_config_dir = NULL;
|
|
gboolean dump_to_stdout = FALSE;
|
|
gs_strfreev char **remaining = NULL;
|
|
GOptionEntry option_entries[] = {
|
|
{"connections-dir",
|
|
'c',
|
|
0,
|
|
G_OPTION_ARG_FILENAME,
|
|
&connections_dir,
|
|
"Output connection directory",
|
|
NM_KEYFILE_PATH_NAME_RUN},
|
|
{"persistent-connections-dir",
|
|
'p',
|
|
0,
|
|
G_OPTION_ARG_FILENAME,
|
|
&etc_connections_dir,
|
|
"Persistent connection directory",
|
|
NM_KEYFILE_PATH_NAME_ETC_DEFAULT},
|
|
{"initrd-data-dir",
|
|
'i',
|
|
0,
|
|
G_OPTION_ARG_FILENAME,
|
|
&initrd_dir,
|
|
"Output initrd data directory",
|
|
DEFAULT_INITRD_DATA_DIR},
|
|
{"sysfs-dir",
|
|
'd',
|
|
0,
|
|
G_OPTION_ARG_FILENAME,
|
|
&sysfs_dir,
|
|
"The sysfs mount point",
|
|
DEFAULT_SYSFS_DIR},
|
|
{"run-config-dir",
|
|
'r',
|
|
0,
|
|
G_OPTION_ARG_FILENAME,
|
|
&run_config_dir,
|
|
"Output config directory",
|
|
DEFAULT_RUN_CONFIG_DIR},
|
|
{"stdout",
|
|
's',
|
|
0,
|
|
G_OPTION_ARG_NONE,
|
|
&dump_to_stdout,
|
|
"Dump connections to standard output",
|
|
NULL},
|
|
{G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, NULL},
|
|
{NULL}};
|
|
nm_auto_free_option_context GOptionContext *option_context = NULL;
|
|
gs_free_error GError *error = NULL;
|
|
gs_free char *hostname = NULL;
|
|
int errsv;
|
|
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=...] "
|
|
"[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] "
|
|
"[rd.znet=...] [rd.net.timeout.carrier=...] ... ");
|
|
|
|
g_option_context_set_summary(option_context, "Generate early NetworkManager configuration.");
|
|
g_option_context_set_description(
|
|
option_context,
|
|
"This tool scans the command line for options relevant to network\n"
|
|
"configuration and creates configuration files for an early instance\n"
|
|
"of NetworkManager run from the initial ramdisk during early boot.");
|
|
g_option_context_add_main_entries(option_context, option_entries, GETTEXT_PACKAGE);
|
|
|
|
if (!g_option_context_parse(option_context, &argc, &argv, &error)) {
|
|
_LOGW(LOGD_CORE, "%s", error->message);
|
|
return 1;
|
|
}
|
|
|
|
if (!remaining) {
|
|
/* No arguments, no networking. Don't bother. */
|
|
return 0;
|
|
}
|
|
|
|
if (!etc_connections_dir)
|
|
etc_connections_dir = g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT);
|
|
if (!connections_dir)
|
|
connections_dir = g_strdup(NM_KEYFILE_PATH_NAME_RUN);
|
|
if (!sysfs_dir)
|
|
sysfs_dir = g_strdup(DEFAULT_SYSFS_DIR);
|
|
if (!initrd_dir)
|
|
initrd_dir = g_strdup(DEFAULT_INITRD_DATA_DIR);
|
|
if (!run_config_dir)
|
|
run_config_dir = g_strdup(DEFAULT_RUN_CONFIG_DIR);
|
|
|
|
connections = nmi_cmdline_reader_parse(etc_connections_dir,
|
|
sysfs_dir,
|
|
(const char *const *) remaining,
|
|
&hostname,
|
|
&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);
|
|
|
|
{
|
|
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
|
NMUtilsNamedValue v;
|
|
|
|
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_GROUPPREFIX_DEVICE "-15-carrier-timeout",
|
|
NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE,
|
|
"*");
|
|
g_key_file_set_int64(keyfile,
|
|
NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout",
|
|
NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT,
|
|
(carrier_timeout_sec != 0 ? carrier_timeout_sec : 10) * 1000);
|
|
if (carrier_timeout_sec == 0) {
|
|
g_key_file_set_value(keyfile,
|
|
NM_CONFIG_KEYFILE_GROUP_CONFIG,
|
|
NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE,
|
|
"env:initrd");
|
|
}
|
|
|
|
if (!dump_to_stdout) {
|
|
add_keyfile_comment(keyfile,
|
|
carrier_timeout_sec == 0 ? "default initrd carrier timeout"
|
|
: "from \"rd.net.timeout.carrier\"");
|
|
}
|
|
|
|
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);
|
|
nm_clear_g_free(&run_config_dir);
|
|
if (hostname)
|
|
g_print("\n*** Hostname '%s' ***\n", hostname);
|
|
|
|
for (i = 0; i < confs->len; i++) {
|
|
NMUtilsNamedValue *v = &nm_g_array_index(confs, NMUtilsNamedValue, i);
|
|
gs_free char *name = g_path_get_basename(v->name);
|
|
|
|
g_print("\n*** Configuration '%s' ***\n\n%s\n", name, v->value_str);
|
|
}
|
|
} else {
|
|
if (g_mkdir_with_parents(connections_dir, 0755) != 0) {
|
|
errsv = errno;
|
|
_LOGW(LOGD_CORE, "%s: %s", connections_dir, nm_strerror_native(errsv));
|
|
return 1;
|
|
}
|
|
if (g_mkdir_with_parents(initrd_dir, 0755) != 0) {
|
|
errsv = errno;
|
|
_LOGW(LOGD_CORE, "%s: %s", initrd_dir, nm_strerror_native(errsv));
|
|
return 1;
|
|
}
|
|
if (g_mkdir_with_parents(run_config_dir, 0755) != 0) {
|
|
errsv = errno;
|
|
_LOGW(LOGD_CORE, "%s: %s", run_config_dir, nm_strerror_native(errsv));
|
|
return 1;
|
|
}
|
|
|
|
if (hostname) {
|
|
gs_free char *hostname_file = NULL;
|
|
gs_free char *data = NULL;
|
|
|
|
hostname_file = g_strdup_printf("%s/hostname", initrd_dir);
|
|
data = g_strdup_printf("%s\n", hostname);
|
|
|
|
if (!g_file_set_contents(hostname_file, data, strlen(data), &error)) {
|
|
_LOGW(LOGD_CORE, "%s: %s", hostname_file, error->message);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < confs->len; i++) {
|
|
NMUtilsNamedValue *v = &nm_g_array_index(confs, NMUtilsNamedValue, i);
|
|
|
|
if (!g_file_set_contents(v->name, v->value_str, strlen(v->value_str), &error)) {
|
|
_LOGW(LOGD_CORE, "%s: %s", v->name, error->message);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_hash_table_foreach(connections, output_conn, connections_dir);
|
|
g_hash_table_destroy(connections);
|
|
|
|
return 0;
|
|
}
|