From 3a9530e5f19565a9cadb7f20bd987c61e0e7c377 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 May 2018 18:37:32 +0200 Subject: [PATCH] nspawn: make the hostname of the container explicitly configurable with a new --hostname= switch Previously, the container's hostname was exclusively initialized from the machine name configured with --machine=, i.e. the internal name and the external name used for and by the container was synchronized. This adds a new option --hostname= that optionally allows the internal name to deviate from the external name. This new option is mainly useful to ultimately implement the OCI runtime spec directly in nspawn, but it might be useful on its own for some other usecases too. --- man/systemd-nspawn.xml | 16 ++++++++++++++++ man/systemd.nspawn.xml | 9 +++++++++ src/nspawn/nspawn-gperf.gperf | 1 + src/nspawn/nspawn-settings.c | 30 ++++++++++++++++++++++++++++++ src/nspawn/nspawn-settings.h | 9 ++++++--- src/nspawn/nspawn.c | 30 ++++++++++++++++++++++++++++-- 6 files changed, 90 insertions(+), 5 deletions(-) diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index c6b027c58f..16d65d2b29 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -373,6 +373,22 @@ instead. + + + + Controls the hostname to set within the container, if different from the machine name. Expects + a valid hostname as argument. If this option is used, the kernel hostname of the container will be set to this + value, otherwise it will be initialized to the machine name as controlled by the + option described above. The machine name is used for various aspect of identification of the container from the + outside, the kernel hostname configurable with this option is useful for the container to identify itself from + the inside. It is usually a good idea to keep both forms of identification synchronized, in order to avoid + confusion. It is hence recommended to avoid usage of this option, and use + exclusively. Note that regardless whether the container's hostname is initialized from the name set with + or the one set with , the container can later override + its kernel hostname freely on its own as well. + + + diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 6bd7b33b34..3f8c325fd9 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -302,6 +302,15 @@ details. + + Hostname= + + Configures the kernel hostname set for the container. This is equivalent to the + command line switch, and takes the same argument. See + systemd-nspawn1 for + details. + + diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 58184d412d..f7d2e1a515 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -49,6 +49,7 @@ Exec.LimitMSGQUEUE, config_parse_rlimit, RLIMIT_MSGQUEUE, of Exec.LimitNICE, config_parse_rlimit, RLIMIT_NICE, offsetof(Settings, rlimit) Exec.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, offsetof(Settings, rlimit) Exec.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof(Settings, rlimit) +Exec.Hostname, config_parse_hostname, 0, offsetof(Settings, hostname) Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only) Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode) Files.Bind, config_parse_bind, 0, 0 diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 19bf1d4b94..3757380e28 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -8,6 +8,7 @@ #include "alloc-util.h" #include "cap-list.h" #include "conf-parser.h" +#include "hostname-util.h" #include "nspawn-network.h" #include "nspawn-settings.h" #include "parse-util.h" @@ -82,6 +83,7 @@ Settings* settings_free(Settings *s) { strv_free(s->syscall_whitelist); strv_free(s->syscall_blacklist); rlimit_free_all(s->rlimit); + free(s->hostname); strv_free(s->network_interfaces); strv_free(s->network_macvlan); @@ -603,3 +605,31 @@ int config_parse_syscall_filter( return 0; } + +int config_parse_hostname( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **s = data; + + assert(rvalue); + assert(s); + + if (!hostname_is_valid(rvalue, false)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue); + return 0; + } + + if (free_and_strdup(s, empty_to_null(rvalue)) < 0) + return log_oom(); + + return 0; +} diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 0e6ce61217..3d3ee4c28c 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -49,9 +49,10 @@ typedef enum SettingsMask { SETTING_NOTIFY_READY = UINT64_C(1) << 14, SETTING_PIVOT_ROOT = UINT64_C(1) << 15, SETTING_SYSCALL_FILTER = UINT64_C(1) << 16, - SETTING_RLIMIT_FIRST = UINT64_C(1) << 17, /* we define one bit per resource limit here */ - SETTING_RLIMIT_LAST = UINT64_C(1) << (17 + _RLIMIT_MAX - 1), - _SETTINGS_MASK_ALL = (UINT64_C(1) << (17 + _RLIMIT_MAX)) + SETTING_HOSTNAME = UINT64_C(1) << 17, + SETTING_RLIMIT_FIRST = UINT64_C(1) << 18, /* we define one bit per resource limit here */ + SETTING_RLIMIT_LAST = UINT64_C(1) << (18 + _RLIMIT_MAX - 1), + _SETTINGS_MASK_ALL = (UINT64_C(1) << (18 + _RLIMIT_MAX)) - 1 } SettingsMask; typedef struct Settings { @@ -74,6 +75,7 @@ typedef struct Settings { char **syscall_whitelist; char **syscall_blacklist; struct rlimit *rlimit[_RLIMIT_MAX]; + char *hostname; /* [Image] */ int read_only; @@ -118,3 +120,4 @@ int config_parse_boot(const char *unit, const char *filename, unsigned line, con int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 8ba8e73bf7..7357576a2a 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -128,7 +128,8 @@ static char *arg_pivot_root_new = NULL; static char *arg_pivot_root_old = NULL; static char *arg_user = NULL; static sd_id128_t arg_uuid = {}; -static char *arg_machine = NULL; +static char *arg_machine = NULL; /* The name used by the host to refer to this */ +static char *arg_hostname = NULL; /* The name the payload sees by default */ static const char *arg_selinux_context = NULL; static const char *arg_selinux_apifs_context = NULL; static const char *arg_slice = NULL; @@ -223,6 +224,7 @@ static void help(void) { " Pivot root to given directory in the container\n" " -u --user=USER Run the command under specified user or uid\n" " -M --machine=NAME Set the machine name for the container\n" + " --hostname=NAME Override the hostname for the container\n" " --uuid=UUID Set a specific machine UUID for the container\n" " -S --slice=SLICE Place the container in the specified slice\n" " --property=NAME=VALUE Set scope unit property\n" @@ -443,6 +445,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_ROOT_HASH, ARG_SYSTEM_CALL_FILTER, ARG_RLIMIT, + ARG_HOSTNAME, }; static const struct option options[] = { @@ -466,6 +469,7 @@ static int parse_argv(int argc, char *argv[]) { { "overlay", required_argument, NULL, ARG_OVERLAY }, { "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO }, { "machine", required_argument, NULL, 'M' }, + { "hostname", required_argument, NULL, ARG_HOSTNAME }, { "slice", required_argument, NULL, 'S' }, { "setenv", required_argument, NULL, 'E' }, { "selinux-context", required_argument, NULL, 'Z' }, @@ -701,6 +705,23 @@ static int parse_argv(int argc, char *argv[]) { } break; + case ARG_HOSTNAME: + if (isempty(optarg)) + arg_hostname = mfree(arg_hostname); + else { + if (!hostname_is_valid(optarg, false)) { + log_error("Invalid hostname: %s", optarg); + return -EINVAL; + } + + r = free_and_strdup(&arg_hostname, optarg); + if (r < 0) + return log_oom(); + } + + arg_settings_mask |= SETTING_HOSTNAME; + break; + case 'Z': arg_selinux_context = optarg; break; @@ -1762,7 +1783,7 @@ static int setup_hostname(void) { if ((arg_clone_ns_flags & CLONE_NEWUTS) == 0) return 0; - if (sethostname_idempotent(arg_machine) < 0) + if (sethostname_idempotent(arg_hostname ?: arg_machine) < 0) return -errno; return 0; @@ -3314,6 +3335,10 @@ static int load_settings(void) { free_and_replace(arg_rlimit[rl], settings->rlimit[rl]); } + if ((arg_settings_mask & SETTING_HOSTNAME) == 0 && + settings->hostname) + free_and_replace(arg_hostname, settings->hostname); + return 0; } @@ -4274,6 +4299,7 @@ finish: free(arg_template); free(arg_image); free(arg_machine); + free(arg_hostname); free(arg_user); free(arg_pivot_root_new); free(arg_pivot_root_old);