c == '-';
}
-/**
- * Check if s looks like a valid hostname or FQDN. This does not do
- * full DNS validation, but only checks if the name is composed of
- * allowed characters and the length is not above the maximum allowed
- * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
- * allow_trailing_dot is true and at least two components are present
- * in the name. Note that due to the restricted charset and length
- * this call is substantially more conservative than
- * dns_name_is_valid().
- */
-bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
+bool hostname_is_valid(const char *s, ValidHostnameFlags flags) {
unsigned n_dots = 0;
const char *p;
bool dot, hyphen;
+ /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only
+ * checks if the name is composed of allowed characters and the length is not above the maximum
+ * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if
+ * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note
+ * that due to the restricted charset and length this call is substantially more conservative than
+ * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames
+ * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */
+
if (isempty(s))
return false;
- /* Doesn't accept empty hostnames, hostnames with
- * leading dots, and hostnames with multiple dots in a
- * sequence. Also ensures that the length stays below
- * HOST_NAME_MAX. */
+ if (streq(s, ".host")) /* Used by the container logic to denote the "root container" */
+ return FLAGS_SET(flags, VALID_HOSTNAME_DOT_HOST);
for (p = s, dot = hyphen = true; *p; p++)
if (*p == '.') {
hyphen = false;
}
- if (dot && (n_dots < 2 || !allow_trailing_dot))
+ if (dot && (n_dots < 2 || !FLAGS_SET(flags, VALID_HOSTNAME_TRAILING_DOT)))
return false;
if (hyphen)
return false;
- if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on
- * Linux, but DNS allows domain names
- * up to 255 characters */
+ if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to
+ * 255 characters */
return false;
return true;
if (!h)
return -ENOMEM;
- if (hostname_is_valid(h, false)) {
+ if (hostname_is_valid(h, 0)) {
*ret = h;
return 0;
}
strshorten(h, HOST_NAME_MAX);
- if (!hostname_is_valid(h, false)) {
+ if (!hostname_is_valid(h, 0)) {
free(h);
return -EDOM;
}
hostname_cleanup(p); /* normalize the hostname */
- if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */
+ if (!hostname_is_valid(p, VALID_HOSTNAME_TRAILING_DOT)) /* check that the hostname we return is valid */
return -EBADMSG;
copy = strdup(p);
int gethostname_strict(char **ret);
bool valid_ldh_char(char c) _const_;
-bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
-char* hostname_cleanup(char *s);
-#define machine_name_is_valid(s) hostname_is_valid(s, false)
+typedef enum ValidHostnameFlags {
+ VALID_HOSTNAME_TRAILING_DOT = 1 << 0, /* Accept trailing dot on multi-label names */
+ VALID_HOSTNAME_DOT_HOST = 1 << 1, /* Accept ".host" as valid hostname */
+} ValidHostnameFlags;
+
+bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_;
+char* hostname_cleanup(char *s);
bool is_localhost(const char *hostname);
return 0;
}
- if (!machine_name_is_valid(machine))
+ if (!hostname_is_valid(machine, 0))
return -EINVAL;
p = strjoina("/run/systemd/machines/", machine);
if (r < 0)
log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
else if (r > 0) {
- if (hostname_is_valid(b, true))
+ if (hostname_is_valid(b, VALID_HOSTNAME_TRAILING_DOT))
hn = b;
else {
log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
break;
}
- if (!hostname_is_valid(h, true)) {
+ if (!hostname_is_valid(h, VALID_HOSTNAME_TRAILING_DOT)) {
log_error("Specified hostname invalid.");
continue;
}
break;
case ARG_HOSTNAME:
- if (!hostname_is_valid(optarg, true))
+ if (!hostname_is_valid(optarg, VALID_HOSTNAME_TRAILING_DOT))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Host name %s is not valid.", optarg);
/* If the passed hostname is already valid, then assume the user doesn't know anything about pretty
* hostnames, so let's unset the pretty hostname, and just set the passed hostname as static/dynamic
* hostname. */
- if (arg_static && hostname_is_valid(hostname, true))
+ if (arg_static && hostname_is_valid(hostname, VALID_HOSTNAME_TRAILING_DOT))
p = ""; /* No pretty hostname (as it is redundant), just a static one */
else
p = hostname; /* Use the passed name as pretty hostname */
if (isempty(name))
name = FALLBACK_HOSTNAME;
- if (!hostname_is_valid(name, false))
+ if (!hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
assert_se(uname(&u) >= 0);
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL);
- if (!isempty(name) && !hostname_is_valid(name, false))
+ if (!isempty(name) && !hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
r = bus_verify_polkit_async(
_cleanup_close_ int open_fd = -1;
int r, fd;
- if (machine_name_is_valid(argv[1])) {
+ if (hostname_is_valid(argv[1], 0)) {
r = image_find(IMAGE_MACHINE, argv[1], &image);
if (r == -ENOENT)
return log_error_errno(r, "Machine image %s not found.", argv[1]);
_cleanup_close_ int open_fd = -1;
int r, fd;
- if (machine_name_is_valid(argv[1])) {
+ if (hostname_is_valid(argv[1], 0)) {
r = image_find(IMAGE_MACHINE, argv[1], &image);
if (r == -ENOENT)
return log_error_errno(r, "Machine image %s not found.", argv[1]);
local = empty_or_dash_to_null(local);
if (local) {
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
assert(fd >= 0);
assert(local);
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return -EINVAL;
if (i->input_fd >= 0)
assert(fd >= 0);
assert(local);
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return -EINVAL;
if (i->input_fd >= 0)
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
return -EINVAL;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Local name %s is invalid", local);
if (r < 0)
return r;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Local name %s is invalid", local);
if (r < 0)
return r;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Local name %s is invalid", local);
if (isempty(local))
local = NULL;
- else if (!machine_name_is_valid(local))
+ else if (!hostname_is_valid(local, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Local name %s is invalid", local);
if (!http_url_is_valid(url))
return -EINVAL;
- if (local && !machine_name_is_valid(local))
+ if (local && !hostname_is_valid(local, 0))
return -EINVAL;
if (i->raw_job)
if (!http_url_is_valid(url))
return -EINVAL;
- if (local && !machine_name_is_valid(local))
+ if (local && !hostname_is_valid(local, 0))
return -EINVAL;
if (i->tar_job)
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local image name '%s' is not valid.",
local);
assert_return(machine, -EINVAL);
assert_return(ret, -EINVAL);
assert_return((flags & ~OPEN_CONTAINER_ALLOWED_FLAGS) == 0, -EINVAL);
- assert_return(machine_name_is_valid(machine), -EINVAL);
+ assert_return(hostname_is_valid(machine, 0), -EINVAL);
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(NULL, p,
/* Make sure hostnames qualify as DNS and as Linux hostnames */
if (hostname &&
- !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0))
+ !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0))
return -EINVAL;
return free_and_strdup(&client->hostname, hostname);
/* Make sure FQDN qualifies as DNS and as Linux hostname */
if (fqdn &&
- !(hostname_is_valid(fqdn, false) && dns_name_is_valid(fqdn) > 0))
+ !(hostname_is_valid(fqdn, 0) && dns_name_is_valid(fqdn) > 0))
return -EINVAL;
return free_and_strdup(&client->fqdn, fqdn);
return -EINVAL;
if (machine) {
- if (!streq(machine, ".host") && !machine_name_is_valid(machine))
+ if (!hostname_is_valid(machine, VALID_HOSTNAME_DOT_HOST))
return -EINVAL;
free_and_replace(b->machine, machine);
}
if (!in_charset(p, "0123456789") || *p == '\0') {
- if (!machine_name_is_valid(p) || got_forward_slash)
+ if (!hostname_is_valid(p, 0) || got_forward_slash)
return -EINVAL;
m = TAKE_PTR(p);
interpret_port_as_machine_old_syntax:
/* Let's make sure this is not a port of some kind,
* and is a valid machine name. */
- if (!in_charset(m, "0123456789") && machine_name_is_valid(m))
+ if (!in_charset(m, "0123456789") && hostname_is_valid(m, 0))
c = strjoina(",argv", p ? "7" : "5", "=--machine=", m);
}
assert_return(machine, -EINVAL);
assert_return(ret, -EINVAL);
- assert_return(streq(machine, ".host") || machine_name_is_valid(machine), -EINVAL);
+ assert_return(hostname_is_valid(machine, VALID_HOSTNAME_DOT_HOST), -EINVAL);
r = sd_bus_new(&b);
if (r < 0)
/* Filter out the unit: symlinks */
for (a = b = l; *a; a++) {
- if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
+ if (startswith(*a, "unit:") || !hostname_is_valid(*a, 0))
free(*a);
else {
*b = *a;
if (!c)
return -ENOMEM;
} else {
- if (!machine_name_is_valid(machine))
+ if (!hostname_is_valid(machine, 0))
return -EINVAL;
p = strjoina("/run/systemd/machines/", machine);
const char *p;
int r;
- assert_return(machine_name_is_valid(machine), -EINVAL);
+ assert_return(hostname_is_valid(machine, 0), -EINVAL);
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(NULL, p, "NETIF", &netif_line);
assert(name);
assert(ret);
- if (!machine_name_is_valid(name))
+ if (!hostname_is_valid(name, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid machine name %s.", name);
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Need either path or local name.");
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
assert(bus);
local = argv[1];
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Machine name %s is not valid.", local);
assert(bus);
local = argv[1];
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Machine name %s is not valid.", local);
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
local = ll;
- if (!machine_name_is_valid(local))
+ if (!hostname_is_valid(local, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Local name %s is not a suitable machine name.",
local);
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
- if (!machine_name_is_valid(name))
+ if (!hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
r = sd_bus_message_read_array(message, 'y', &v, &n);
if (startswith(de->d_name, "unit:"))
continue;
- if (!machine_name_is_valid(de->d_name))
+ if (!hostname_is_valid(de->d_name, 0))
continue;
k = manager_add_machine(m, de->d_name, &machine);
if (p != value) {
hostname = strndupa(value, p - value);
- if (!hostname_is_valid(hostname, false))
+ if (!hostname_is_valid(hostname, 0))
return -EINVAL;
}
if (r < 0)
return r;
- if (!hostname_is_valid(hn, false)) {
+ if (!hostname_is_valid(hn, 0)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Hostname is not valid, ignoring assignment: %s", rvalue);
return 0;
assert_se(n = json_variant_string(v));
- if (!hostname_is_valid(n, false))
+ if (!hostname_is_valid(n, 0))
return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
"Hostname string is not a valid hostname: %s", n);
assert(rvalue);
assert(s);
- if (!hostname_is_valid(rvalue, false)) {
+ if (!hostname_is_valid(rvalue, 0)) {
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue);
return 0;
}
if (isempty(optarg))
arg_machine = mfree(arg_machine);
else {
- if (!machine_name_is_valid(optarg))
+ if (!hostname_is_valid(optarg, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid machine name: %s", optarg);
if (isempty(optarg))
arg_hostname = mfree(arg_hostname);
else {
- if (!hostname_is_valid(optarg, false))
+ if (!hostname_is_valid(optarg, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid hostname: %s", optarg);
return log_oom();
hostname_cleanup(arg_machine);
- if (!machine_name_is_valid(arg_machine))
+ if (!hostname_is_valid(arg_machine, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine machine name automatically, please use -M.");
if (arg_ephemeral) {
#include "util.h"
static void test_hostname_is_valid(void) {
- assert_se(hostname_is_valid("foobar", false));
- assert_se(hostname_is_valid("foobar.com", false));
- assert_se(!hostname_is_valid("foobar.com.", false));
- assert_se(hostname_is_valid("fooBAR", false));
- assert_se(hostname_is_valid("fooBAR.com", false));
- assert_se(!hostname_is_valid("fooBAR.", false));
- assert_se(!hostname_is_valid("fooBAR.com.", false));
- assert_se(!hostname_is_valid("fööbar", false));
- assert_se(!hostname_is_valid("", false));
- assert_se(!hostname_is_valid(".", false));
- assert_se(!hostname_is_valid("..", false));
- assert_se(!hostname_is_valid("foobar.", false));
- assert_se(!hostname_is_valid(".foobar", false));
- assert_se(!hostname_is_valid("foo..bar", false));
- assert_se(!hostname_is_valid("foo.bar..", false));
- assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", false));
- assert_se(!hostname_is_valid("au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", false));
-
- assert_se(hostname_is_valid("foobar", true));
- assert_se(hostname_is_valid("foobar.com", true));
- assert_se(hostname_is_valid("foobar.com.", true));
- assert_se(hostname_is_valid("fooBAR", true));
- assert_se(hostname_is_valid("fooBAR.com", true));
- assert_se(!hostname_is_valid("fooBAR.", true));
- assert_se(hostname_is_valid("fooBAR.com.", true));
- assert_se(!hostname_is_valid("fööbar", true));
- assert_se(!hostname_is_valid("", true));
- assert_se(!hostname_is_valid(".", true));
- assert_se(!hostname_is_valid("..", true));
- assert_se(!hostname_is_valid("foobar.", true));
- assert_se(!hostname_is_valid(".foobar", true));
- assert_se(!hostname_is_valid("foo..bar", true));
- assert_se(!hostname_is_valid("foo.bar..", true));
- assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true));
+ assert_se(hostname_is_valid("foobar", 0));
+ assert_se(hostname_is_valid("foobar.com", 0));
+ assert_se(!hostname_is_valid("foobar.com.", 0));
+ assert_se(hostname_is_valid("fooBAR", 0));
+ assert_se(hostname_is_valid("fooBAR.com", 0));
+ assert_se(!hostname_is_valid("fooBAR.", 0));
+ assert_se(!hostname_is_valid("fooBAR.com.", 0));
+ assert_se(!hostname_is_valid("fööbar", 0));
+ assert_se(!hostname_is_valid("", 0));
+ assert_se(!hostname_is_valid(".", 0));
+ assert_se(!hostname_is_valid("..", 0));
+ assert_se(!hostname_is_valid("foobar.", 0));
+ assert_se(!hostname_is_valid(".foobar", 0));
+ assert_se(!hostname_is_valid("foo..bar", 0));
+ assert_se(!hostname_is_valid("foo.bar..", 0));
+ assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 0));
+ assert_se(!hostname_is_valid("au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", 0));
+
+ assert_se(hostname_is_valid("foobar", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("foobar.com", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("foobar.com.", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("fooBAR", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("fooBAR.com", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("fooBAR.", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(hostname_is_valid("fooBAR.com.", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("fööbar", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid(".", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("..", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("foobar.", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid(".foobar", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("foo..bar", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("foo.bar..", VALID_HOSTNAME_TRAILING_DOT));
+ assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", VALID_HOSTNAME_TRAILING_DOT));
}
static void test_hostname_cleanup(void) {
}
static void test_fallback_hostname(void) {
- if (!hostname_is_valid(FALLBACK_HOSTNAME, false)) {
+ if (!hostname_is_valid(FALLBACK_HOSTNAME, 0)) {
log_error("Configured fallback hostname \"%s\" is not valid.", FALLBACK_HOSTNAME);
exit(EXIT_FAILURE);
}