|
Packit Service |
dff8e4 |
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
#include "nm-sd-adapt-shared.h"
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
#include <errno.h>
|
|
Packit Service |
dff8e4 |
#include <limits.h>
|
|
Packit Service |
dff8e4 |
#include <stdio.h>
|
|
Packit Service |
dff8e4 |
#include <sys/utsname.h>
|
|
Packit Service |
dff8e4 |
#include <unistd.h>
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
#include "alloc-util.h"
|
|
Packit Service |
dff8e4 |
#include "hostname-util.h"
|
|
Packit Service |
dff8e4 |
#include "string-util.h"
|
|
Packit Service |
dff8e4 |
#include "strv.h"
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
#if 0 /* NM_IGNORED */
|
|
Packit Service |
dff8e4 |
char* gethostname_malloc(void) {
|
|
Packit Service |
dff8e4 |
struct utsname u;
|
|
Packit Service |
dff8e4 |
const char *s;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
/* This call tries to return something useful, either the actual hostname
|
|
Packit Service |
dff8e4 |
* or it makes something up. The only reason it might fail is OOM.
|
|
Packit Service |
dff8e4 |
* It might even return "localhost" if that's set. */
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
assert_se(uname(&u) >= 0);
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
s = u.nodename;
|
|
Packit Service |
dff8e4 |
if (isempty(s) || streq(s, "(none)"))
|
|
Packit Service |
dff8e4 |
s = FALLBACK_HOSTNAME;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
return strdup(s);
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
char* gethostname_short_malloc(void) {
|
|
Packit Service |
dff8e4 |
struct utsname u;
|
|
Packit Service |
dff8e4 |
const char *s;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
/* Like above, but kills the FQDN part if present. */
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
assert_se(uname(&u) >= 0);
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
s = u.nodename;
|
|
Packit Service |
dff8e4 |
if (isempty(s) || streq(s, "(none)") || s[0] == '.') {
|
|
Packit Service |
dff8e4 |
s = FALLBACK_HOSTNAME;
|
|
Packit Service |
dff8e4 |
assert(s[0] != '.');
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
return strndup(s, strcspn(s, "."));
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
#endif /* NM_IGNORED */
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
int gethostname_strict(char **ret) {
|
|
Packit Service |
dff8e4 |
struct utsname u;
|
|
Packit Service |
dff8e4 |
char *k;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
/* This call will rather fail than make up a name. It will not return "localhost" either. */
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
assert_se(uname(&u) >= 0);
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
if (isempty(u.nodename))
|
|
Packit Service |
dff8e4 |
return -ENXIO;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
if (streq(u.nodename, "(none)"))
|
|
Packit Service |
dff8e4 |
return -ENXIO;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
if (is_localhost(u.nodename))
|
|
Packit Service |
dff8e4 |
return -ENXIO;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
k = strdup(u.nodename);
|
|
Packit Service |
dff8e4 |
if (!k)
|
|
Packit Service |
dff8e4 |
return -ENOMEM;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
*ret = k;
|
|
Packit Service |
dff8e4 |
return 0;
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
bool valid_ldh_char(char c) {
|
|
Packit Service |
dff8e4 |
/* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
return
|
|
Packit Service |
dff8e4 |
(c >= 'a' && c <= 'z') ||
|
|
Packit Service |
dff8e4 |
(c >= 'A' && c <= 'Z') ||
|
|
Packit Service |
dff8e4 |
(c >= '0' && c <= '9') ||
|
|
Packit Service |
dff8e4 |
c == '-';
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
bool hostname_is_valid(const char *s, ValidHostnameFlags flags) {
|
|
Packit Service |
dff8e4 |
unsigned n_dots = 0;
|
|
Packit Service |
dff8e4 |
const char *p;
|
|
Packit Service |
dff8e4 |
bool dot, hyphen;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
/* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only
|
|
Packit Service |
dff8e4 |
* checks if the name is composed of allowed characters and the length is not above the maximum
|
|
Packit Service |
dff8e4 |
* allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if
|
|
Packit Service |
dff8e4 |
* VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note
|
|
Packit Service |
dff8e4 |
* that due to the restricted charset and length this call is substantially more conservative than
|
|
Packit Service |
dff8e4 |
* dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames
|
|
Packit Service |
dff8e4 |
* with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
if (isempty(s))
|
|
Packit Service |
dff8e4 |
return false;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
if (streq(s, ".host")) /* Used by the container logic to denote the "root container" */
|
|
Packit Service |
dff8e4 |
return FLAGS_SET(flags, VALID_HOSTNAME_DOT_HOST);
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
for (p = s, dot = hyphen = true; *p; p++)
|
|
Packit Service |
dff8e4 |
if (*p == '.') {
|
|
Packit Service |
dff8e4 |
if (dot || hyphen)
|
|
Packit Service |
dff8e4 |
return false;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
dot = true;
|
|
Packit Service |
dff8e4 |
hyphen = false;
|
|
Packit Service |
dff8e4 |
n_dots++;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
} else if (*p == '-') {
|
|
Packit Service |
dff8e4 |
if (dot)
|
|
Packit Service |
dff8e4 |
return false;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
dot = false;
|
|
Packit Service |
dff8e4 |
hyphen = true;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
} else {
|
|
Packit Service |
dff8e4 |
if (!valid_ldh_char(*p))
|
|
Packit Service |
dff8e4 |
return false;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
dot = false;
|
|
Packit Service |
dff8e4 |
hyphen = false;
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
if (dot && (n_dots < 2 || !FLAGS_SET(flags, VALID_HOSTNAME_TRAILING_DOT)))
|
|
Packit Service |
dff8e4 |
return false;
|
|
Packit Service |
dff8e4 |
if (hyphen)
|
|
Packit Service |
dff8e4 |
return false;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to
|
|
Packit Service |
dff8e4 |
* 255 characters */
|
|
Packit Service |
dff8e4 |
return false;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
return true;
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
char* hostname_cleanup(char *s) {
|
|
Packit Service |
dff8e4 |
char *p, *d;
|
|
Packit Service |
dff8e4 |
bool dot, hyphen;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
assert(s);
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
for (p = s, d = s, dot = hyphen = true; *p && d - s < HOST_NAME_MAX; p++)
|
|
Packit Service |
dff8e4 |
if (*p == '.') {
|
|
Packit Service |
dff8e4 |
if (dot || hyphen)
|
|
Packit Service |
dff8e4 |
continue;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
*(d++) = '.';
|
|
Packit Service |
dff8e4 |
dot = true;
|
|
Packit Service |
dff8e4 |
hyphen = false;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
} else if (*p == '-') {
|
|
Packit Service |
dff8e4 |
if (dot)
|
|
Packit Service |
dff8e4 |
continue;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
*(d++) = '-';
|
|
Packit Service |
dff8e4 |
dot = false;
|
|
Packit Service |
dff8e4 |
hyphen = true;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
} else if (valid_ldh_char(*p)) {
|
|
Packit Service |
dff8e4 |
*(d++) = *p;
|
|
Packit Service |
dff8e4 |
dot = false;
|
|
Packit Service |
dff8e4 |
hyphen = false;
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
if (d > s && IN_SET(d[-1], '-', '.'))
|
|
Packit Service |
dff8e4 |
/* The dot can occur at most once, but we might have multiple
|
|
Packit Service |
dff8e4 |
* hyphens, hence the loop */
|
|
Packit Service |
dff8e4 |
d--;
|
|
Packit Service |
dff8e4 |
*d = 0;
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
return s;
|
|
Packit Service |
dff8e4 |
}
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
bool is_localhost(const char *hostname) {
|
|
Packit Service |
dff8e4 |
assert(hostname);
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
/* This tries to identify local host and domain names
|
|
Packit Service |
dff8e4 |
* described in RFC6761 plus the redhatism of localdomain */
|
|
Packit Service |
dff8e4 |
|
|
Packit Service |
dff8e4 |
return STRCASE_IN_SET(
|
|
Packit Service |
dff8e4 |
hostname,
|
|
Packit Service |
dff8e4 |
"localhost",
|
|
Packit Service |
dff8e4 |
"localhost.",
|
|
Packit Service |
dff8e4 |
"localhost.localdomain",
|
|
Packit Service |
dff8e4 |
"localhost.localdomain.") ||
|
|
Packit Service |
dff8e4 |
endswith_no_case(hostname, ".localhost") ||
|
|
Packit Service |
dff8e4 |
endswith_no_case(hostname, ".localhost.") ||
|
|
Packit Service |
dff8e4 |
endswith_no_case(hostname, ".localhost.localdomain") ||
|
|
Packit Service |
dff8e4 |
endswith_no_case(hostname, ".localhost.localdomain.");
|
|
Packit Service |
dff8e4 |
}
|