1
0
mirror of https://github.com/systemd/systemd synced 2026-03-05 20:54:45 +01:00

Compare commits

...

25 Commits

Author SHA1 Message Date
Susant Sahani
937e305e93 network: Allow to configure interface promiscuous mode 2020-12-15 20:25:08 +00:00
Christian Ehrhardt
43b49470d1 test: use modern qemu numa arguments
Upgrading to qemu 5.2 breaks TEST-36-NUMAPOLICY like:
  qemu-system-x86_64: total memory for NUMA nodes (0x0) should
  equal RAM size (0x20000000)

Use the new (as in >=2014) form of memdev in test 36:
 -object memory-backend-ram,id=mem0,size=512M -numa node,memdev=mem0,nodeid=0

Since some target systems are as old as qemu 1.5.3 (CentOS7) but the new
kind to specify was added in qemu 2.1 this needs to add version parsing and
add the argument only when qemu is >=5.2.

Fixes #17986.

Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2020-12-16 05:16:41 +09:00
Lennart Poettering
94b78105c6
Merge pull request #17967 from poettering/connect-user-bus
add support for "systemctl --user --machine=foobar@.host" for connecting to user bus of user "foobar"
2020-12-15 21:14:01 +01:00
d032747
6fe2a70b91 busctl: add a timestamp to the output of the busctl monitor command 2020-12-16 05:06:56 +09:00
Yu Watanabe
3a23834d6b
Merge pull request #17908 from ddstreet/dhcpv4_rfc2131_intervals
Fix dhcpv4 renew/rebind intervals to match rfc2131
2020-12-16 05:05:06 +09:00
Lennart Poettering
1ecb46724c bus-util: improve logging when we can't connect to the bus
Previously, we'd already have explicit logging for the case where
$XDG_RUNTIME_DIR is not set. Let's also add some explicit logging for
the EPERM/ACCESS case. Let's also in both cases suggest the
--machine=<user>@.host syntax.

And while we are at it, let's remove side-effects from the macro.

By checking for both the EPERM/EACCES case and the $XDG_RUNTIME_DIR case
we will now catch both the cases where people use "su" to issue a
"systemctl --user" operation, and those where they (more correctly, but
still not good enough) call "su -".

Fixes: #17901
2020-12-15 18:01:23 +01:00
Lennart Poettering
cedfd142de stdio-bridge: add support for --system and --user
So far, the bridge always acted as if "--system" was used, i.e. would
unconditionally connect to the system bus. Let's add "--user" too, to
connect to the users session bus.

This is mostly for completeness' sake.

I wanted to use this when making sd-bus's ability to connect to other
user's D-Bus busses work, but it didn't exist so far. In the interest of
keeping things compatible the implementation in sd-bus will not use the
new "--user" switch, and instead manually construct the right bus path
via "--path=", but we still should add the proper switches, as
preparation for a brighter future, one day.
2020-12-15 18:01:20 +01:00
Lennart Poettering
ba4a31b7a6 man: document new ability to connect to user of container 2020-12-15 18:01:01 +01:00
Lennart Poettering
1b630835df sd-bus: add API for connecting to a specific user's user bus of a specific container
This is unfortunately harder to implement than it sounds. The user's bus
is bound a to the user's lifecycle after all (i.e. only exists as long
as the user has at least one PAM session), and the path dynamically (at
least theoretically, in practice it's going to be the same always)
generated via $XDG_RUNTIME_DIR in /run/.

To fix this properly, we'll thus go through PAM before connecting to a
user bus. Which is hard since we cannot just link against libpam in the
container, since the container might have been compiled entirely
differently. So our way out is to use systemd-run from outside, which
invokes a transient unit that does PAM from outside, doing so via D-Bus.
Inside the transient unit we then invoke systemd-stdio-bridge which
forwards D-Bus from the user bus to us. The systemd-stdio-bridge makes
up the PAM session and thus we can sure tht the bus exists at least as
long as the bus connection is kept.

Or so say this differently: if you use "systemctl -M lennart@foobar"
now, the bus connection works like this:

        1. sd-bus on the host forks off:

                systemd-run -M foobar -PGq --wait -pUser=lennart -pPAMName=login systemd-stdio-bridge

        2. systemd-run gets a connection to the "foobar" container's
           system bus, and invokes the "systemd-stdio-bridge" binary as
           transient service inside a PAM session for the user "lennart"

        3. The systemd-stdio-bridge then proxies our D-Bus traffic to
           the user bus.

sd-bus (on host) → systemd-run (on host) → systemd-stdio-bridge (in container)

Complicated? Well, to some point yes, but otoh it's actually nice in
various other ways, primarily as it makes the -H and -M codepaths more
alike. In the -H case (i.e. connect to remote host via SSH) a very
similar three steps are used. The only difference is that instead of
"systemd-run" the "ssh" binary is used to invoke the stdio bridge in a
PAM session of some other system. Thus we get similar implementation and
isolation for similar operations.

Fixes: #14580
2020-12-15 18:00:15 +01:00
Lennart Poettering
1ca37419b1 sd-bus: 'ret' parameter to sd_bus_query_sender_creds() is not optional, check for it 2020-12-15 18:00:11 +01:00
Lennart Poettering
f8ecc2c00d sd-bus: make credential acquisition more graceful
So far when asked for augmented bus credentials and the process was
already gone we'd fail fatally. Let's make this graceful instead, and
never allow augmenting fail due to PID having vanished — unless the
augmenting is the explicit and only purpose of the requested operation.

This should be safe as clients have to explicitly query the acquired
creds anyway and handle if they couldn't be acquired. Moreover we
already handle permission problems gracefully, thus clients must be
ready to deal with missing creds.

This is useful to make selinux authorization work for short-lived client
proceses. PReviously we'd augment creds to have more info to log about
(the selinux decision would not be based on augmented data however,
because that'd be unsafe), and would fail if we couldn't get it. Now,
we'll try to acquire the data, but if we cannot acquire it, we'll still
do the selinux check, except that logging will be more limited.
2020-12-15 18:00:06 +01:00
Lennart Poettering
79485fc27a firstboot: clean-up the copied hostname, not argv[] directly, as that's ugly 2020-12-15 18:00:02 +01:00
Lennart Poettering
d4e9809465 hostname-setup: clarify that failures reading /etc/hostname are ignored 2020-12-15 17:59:58 +01:00
Lennart Poettering
52ef5dd798 hostname-util: flagsify hostname_is_valid(), drop machine_name_is_valid()
Let's clean up hostname_is_valid() a bit: let's turn the second boolean
argument into a more explanatory flags field, and add a flag that
accepts the special name ".host" as valid. This is useful for the
container logic, where the special hostname ".host" refers to the "root
container", i.e. the host system itself, and can be specified at various
places.

let's also get rid of machine_name_is_valid(). It was just an alias,
which is confusing and even more so now that we have the flags param.
2020-12-15 17:59:48 +01:00
Lennart Poettering
9e815cf2c2 hostname-util: explain what 'LDH' is 2020-12-15 17:59:44 +01:00
Lennart Poettering
1feb8eee2d logs-show: drop redundant validation of machine name
The immediately following container_get_leader() call validate the name
anyway, no need to twice exactly the same way twice immediately after
each other.
2020-12-15 17:59:41 +01:00
Lennart Poettering
c4dd2d7575 machine: drop really old kdbus left-over
The "x-machine-kernel" dbus address has been removed a long time ago,
hence don't generate it either.
2020-12-15 17:59:37 +01:00
Lennart Poettering
68a3d91538 sd-bus: use SOCK_CLOEXEC on one more socket 2020-12-15 17:58:40 +01:00
Dan Streetman
b226c15cfb test-network: increase wait_online timeout to handle longer dhcpv4 transient timeout
Previous commits changed the dhcpv4 retransmission algorithm to be
slightly slower, changing the amount of time it takes to notify
systemd-networkd that the dhcpv4 configuration has (transiently)
failed from around 14 second up to 28 seconds.

Since the test_dhcp_client_with_ipv4ll_without_dhcp_server test
configures an interface to use dhcpv4 without any operating dhcpv4
server running, it must increase the amount of time it waits for
the test interface to reach degraded state.
2020-12-14 18:19:32 -05:00
Dan Streetman
f3808b872f sd-dhcp-client: correct retransmission timeout to match RFC
This changes the retransmission timeout algorithm for requests
other than RENEW and REBIND. Previously, the retransmission timeout
started at 2 seconds, then doubling each retransmission up to a max
of 64 seconds. This is changed to match what RFC2131 section 4.1 describes,
which skips the initial 2 second timeout and starts with a 4 second timeout
instead. Note that -1 to +1 seconds of random 'fuzz' is added to each
timeout, in previous and current behavior.

This change is therefore slightly slower than the previous behavior in
attempting retransmissions when no server response is received, since the
first transmission times out in 4 seconds instead of 2.

Since TRANSIENT_FAILURE_ATTEMPTS is set to 3, the previous length of time
before a transient failure was reported back to systemd-networkd was
2 + 4 + 8 = 14 seconds, plus, on average, 3 seconds of random 'fuzz' for
a transient failure timeout between 11 and 17 seconds. Now, since the
first timeout starts at 4, the transient failure will be reported at
4 + 8 + 16 = 28 seconds, again plus 3 random seconds for a transient
failure timeout between 25 and 31 seconds.

Additionally, if MaxAttempts= is set, it will take slightly longer to
reach than with previous behavior.
2020-12-14 18:19:29 -05:00
Dan Streetman
c24288d21e sd-dhcp-client: correct dhcpv4 renew/rebind retransmit timeouts
Use the request timeout algorithm specified in RFC2131 section 4.4.5 for
handling timed out RENEW and REBIND requests.

This changes behavior, as previously only 2 RENEW and 2 REBIND requests
were sent, no matter how long the lease lifetime. Now, requests are
send according to the RFC, which results in starting with a timeout
of 1/2 the t1 or t2 period, and halving the timeout for each retry
down to a minimum of 60 seconds.

Fixes: #17909
2020-12-14 18:19:22 -05:00
Dan Streetman
b0d7d8063c sd-dhcp-client: simplify dhcp4 t1/t2 parsing
The parsing of the dhcpv4 lease lifetime, as well as the t1/t2
times, is simplified by this commit.

This differs from previous behavior; previously, the lease lifetime and
t1/t2 values were modified by random 'fuzz' by subtracting 3, then adding
a random number between 0 and (slightly over) 2 seconds. The resulting
values were therefore always between 1-3 seconds shorter than the value
provided by the server (or the default, in case of t1/t2). Now, as
described in RFC2131, the random 'fuzz' is between -1 and +1 seconds,
meaning the actual t1 and t2 value will be up to 1 second earlier or
later than the server-provided (or default) t1/t2 value.

This also differs in handling the lease lifetime, as described above it
previously was adjusted by the random 'fuzz', but the RFC does not state
that the lease expiration time should be adjusted, so now the code uses
exactly the lease lifetime as provided by the server with no adjustment.
2020-12-14 18:19:07 -05:00
Dan Streetman
3d75a443ee sd-dhcp-client: add RFC2131 retransmission details
RFC2131, providing the details for dhcpv4, has specific retransmission
intervals that it outlines. This adds functions to compute the timeouts
as the RFC describes.
2020-12-14 18:19:01 -05:00
Dan Streetman
0c3c59783b sd-dhcp-client: track dhcp4 t1, t2, expire times
Add fields to dhcp4 client to track t1, t2, and lease expiry times
2020-12-14 17:39:26 -05:00
Dan Streetman
f3bd46c657 sd-dhcp-client: don't log timeouts if already expired 2020-12-14 17:39:26 -05:00
54 changed files with 550 additions and 253 deletions

View File

@ -24,6 +24,7 @@
<refname>sd_bus_open_with_description</refname>
<refname>sd_bus_open_user</refname>
<refname>sd_bus_open_user_with_description</refname>
<refname>sd_bus_open_user_machine</refname>
<refname>sd_bus_open_system</refname>
<refname>sd_bus_open_system_with_description</refname>
<refname>sd_bus_open_system_remote</refname>
@ -73,6 +74,12 @@
<paramdef>const char *<parameter>description</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_bus_open_user_machine</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
<paramdef>const char *<parameter>machine</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_bus_open_system</function></funcdef>
<paramdef>sd_bus **<parameter>bus</parameter></paramdef>
@ -187,14 +194,24 @@
work for the root user on the remote machine.</para>
<para><function>sd_bus_open_system_machine()</function> connects to the system bus in the specified
<parameter>machine</parameter>, where <parameter>machine</parameter> is the name of a local
container. See
<parameter>machine</parameter>, where <parameter>machine</parameter> is the name of a local container,
possibly prefixed by a user name and a separating <literal>@</literal>. If the container name is
specified as the special string <literal>.host</literal> the connection is made to the local system. This
is useful to connect to the local system bus as specific user, e.g. <literal>foobar@.host</literal> to
connect to the local system bus as local user <literal>foobar</literal>. If the <literal>@</literal>
syntax is used either the left-hand side or the right-hand side may be ommited (but not both) in which
case the local user name or <literal>.host</literal> is implied. If the <literal>@</literal> syntax is
not used the connection is always made as root user. See
<citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for a description of the address syntax, and
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> for more
information about the "machine" concept. Note that connections into local containers are only available
to privileged processes at this time.</para>
<para><function>sd_bus_open_user_machine()</function> is similar to
<function>sd_bus_open_system_machine()</function>, but connects to the user bus of the root user, or if
the <literal>@</literal> syntax is used, of the specified user.</para>
<para>These calls allocate a bus connection object and initiate
the connection to a well-known bus of some form. An alternative to
using these high-level calls is to create an unconnected bus
@ -210,6 +227,7 @@
<title>Reference ownership</title>
<para>The functions <function>sd_bus_open()</function>,
<function>sd_bus_open_user()</function>,
<function>sd_bus_open_user_machine()</function>,
<function>sd_bus_open_system()</function>,
<function>sd_bus_open_system_remote()</function>, and
<function>sd_bus_open_system_machine()</function> return a new

View File

@ -171,20 +171,27 @@
<para> For example, disabling ARP is useful when creating multiple MACVLAN or VLAN virtual
interfaces atop a single lower-level physical interface, which will then only serve as a
link/"bridge" device aggregating traffic to the same physical link and not participate in
the network otherwise.</para>
the network otherwise. Defaults to unset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Multicast=</varname></term>
<listitem>
<para>Takes a boolean. If set to true, the multicast flag on the device is enabled.</para>
<para>Takes a boolean. If set to true, the multicast flag on the device is enabled. Defaults to unset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>AllMulticast=</varname></term>
<listitem>
<para>Takes a boolean. If set to true, the driver retrieves all multicast packets from the network.
This happens when multicast routing is enabled.</para>
This happens when multicast routing is enabled. Defaults to unset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Promiscuous=</varname></term>
<listitem>
<para>Takes a boolean. If set to true, promiscuous mode of the interface is enabled.
Defaults to unset.</para>
</listitem>
</varlistentry>
<varlistentry>

View File

@ -45,8 +45,14 @@
<term><option>--machine=</option></term>
<listitem id='machine-text'>
<para>Execute operation on a local container. Specify a
container name to connect to.</para>
<para>Execute operation on a local container. Specify a container name to connect to, optionally
prefixed by a user name to connect as and a separating <literal>@</literal> character. If the special
string <literal>.host</literal> is used in place of the container name, a connection to the local
system is made (which is useful to connect to a specific user's user bus: <literal>--user
--machine=lennart@.host</literal>). If the <literal>@</literal> syntax is not used, the connection is
made as root user. If the <literal>@</literal> syntax is used either the left hand side or the right hand
side may be ommitted (but not both) in which case the local user name and <literal>.host</literal> are
implied.</para>
</listitem>
</varlistentry>
</variablelist>

View File

@ -89,6 +89,8 @@ int gethostname_strict(char **ret) {
}
bool valid_ldh_char(char c) {
/* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */
return
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
@ -96,28 +98,24 @@ bool valid_ldh_char(char c) {
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 == '.') {
@ -143,14 +141,13 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
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;
@ -241,7 +238,7 @@ int shorten_overlong(const char *s, char **ret) {
if (!h)
return -ENOMEM;
if (hostname_is_valid(h, false)) {
if (hostname_is_valid(h, 0)) {
*ret = h;
return 0;
}
@ -252,7 +249,7 @@ int shorten_overlong(const char *s, char **ret) {
strshorten(h, HOST_NAME_MAX);
if (!hostname_is_valid(h, false)) {
if (!hostname_is_valid(h, 0)) {
free(h);
return -EDOM;
}
@ -285,7 +282,7 @@ int read_etc_hostname_stream(FILE *f, char **ret) {
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);

View File

@ -14,10 +14,14 @@ char* gethostname_short_malloc(void);
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);

View File

@ -165,7 +165,7 @@ int container_get_leader(const char *machine, pid_t *pid) {
return 0;
}
if (!machine_name_is_valid(machine))
if (!hostname_is_valid(machine, 0))
return -EINVAL;
p = strjoina("/run/systemd/machines/", machine);

View File

@ -121,7 +121,7 @@ static int acquire_bus(bool set_monitor, sd_bus **ret) {
break;
case BUS_TRANSPORT_MACHINE:
r = bus_set_address_system_machine(bus, arg_host);
r = bus_set_address_machine(bus, arg_user, arg_host);
break;
default:
@ -1194,6 +1194,7 @@ static int message_json(sd_bus_message *m, FILE *f) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
char e[2];
int r;
usec_t ts;
r = json_transform_message(m, &v);
if (r < 0)
@ -1202,6 +1203,10 @@ static int message_json(sd_bus_message *m, FILE *f) {
e[0] = m->header->endian;
e[1] = 0;
ts = m->realtime;
if (ts == 0)
ts = now(CLOCK_REALTIME);
r = json_build(&w, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("type", JSON_BUILD_STRING(bus_message_type_to_string(m->header->type))),
JSON_BUILD_PAIR("endian", JSON_BUILD_STRING(e)),
@ -1209,6 +1214,7 @@ static int message_json(sd_bus_message *m, FILE *f) {
JSON_BUILD_PAIR("version", JSON_BUILD_INTEGER(m->header->version)),
JSON_BUILD_PAIR("cookie", JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m))),
JSON_BUILD_PAIR_CONDITION(m->reply_cookie != 0, "reply_cookie", JSON_BUILD_INTEGER(m->reply_cookie)),
JSON_BUILD_PAIR("timestamp-realtime", JSON_BUILD_UNSIGNED(ts)),
JSON_BUILD_PAIR_CONDITION(m->sender, "sender", JSON_BUILD_STRING(m->sender)),
JSON_BUILD_PAIR_CONDITION(m->destination, "destination", JSON_BUILD_STRING(m->destination)),
JSON_BUILD_PAIR_CONDITION(m->path, "path", JSON_BUILD_STRING(m->path)),

View File

@ -24,7 +24,7 @@ int hostname_setup(void) {
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);
@ -34,12 +34,11 @@ int hostname_setup(void) {
if (!hn) {
r = read_etc_hostname(NULL, &b);
if (r < 0) {
if (r == -ENOENT)
enoent = true;
else if (r < 0)
log_warning_errno(r, "Failed to read configured hostname, ignoring: %m");
else
log_warning_errno(r, "Failed to read configured hostname: %m");
} else
hn = b;
}

View File

@ -493,7 +493,7 @@ static int prompt_hostname(void) {
break;
}
if (!hostname_is_valid(h, true)) {
if (!hostname_is_valid(h, VALID_HOSTNAME_TRAILING_DOT)) {
log_error("Specified hostname invalid.");
continue;
}
@ -1135,15 +1135,15 @@ static int parse_argv(int argc, char *argv[]) {
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);
hostname_cleanup(optarg);
r = free_and_strdup(&arg_hostname, optarg);
if (r < 0)
return log_oom();
hostname_cleanup(arg_hostname);
break;
case ARG_MACHINE_ID:

View File

@ -248,7 +248,7 @@ static int set_hostname(int argc, char **argv, void *userdata) {
/* 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 */

View File

@ -596,7 +596,7 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
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);
@ -650,7 +650,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
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(

View File

@ -65,7 +65,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
_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]);
@ -141,7 +141,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
_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]);

View File

@ -126,7 +126,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
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);

View File

@ -393,7 +393,7 @@ int raw_import_start(RawImport *i, int fd, const char *local, bool force_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)

View File

@ -329,7 +329,7 @@ int tar_import_start(TarImport *i, int fd, const char *local, bool force_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)

View File

@ -64,7 +64,7 @@ static int import_tar(int argc, char *argv[], void *userdata) {
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);
@ -159,7 +159,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
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);

View File

@ -717,7 +717,7 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
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);
@ -787,7 +787,7 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
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);
@ -852,7 +852,7 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
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);
@ -932,7 +932,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
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);

View File

@ -651,7 +651,7 @@ int raw_pull_start(
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)

View File

@ -481,7 +481,7 @@ int tar_pull_start(
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)

View File

@ -72,7 +72,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
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);
@ -158,7 +158,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
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);

View File

@ -1984,7 +1984,7 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
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,

View File

@ -29,6 +29,7 @@
#include "sort-util.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
#include "utf8.h"
#include "web-util.h"
@ -98,6 +99,9 @@ struct sd_dhcp_client {
uint32_t fallback_lease_lifetime;
uint32_t xid;
usec_t start_time;
usec_t t1_time;
usec_t t2_time;
usec_t expire_time;
uint64_t attempt;
uint64_t max_attempts;
OrderedHashmap *extra_options;
@ -540,7 +544,7 @@ int sd_dhcp_client_set_hostname(
/* 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);
@ -727,6 +731,37 @@ static void client_stop(sd_dhcp_client *client, int error) {
client_initialize(client);
}
/* RFC2131 section 4.1:
* retransmission delays should include -1 to +1 sec of random 'fuzz'. */
#define RFC2131_RANDOM_FUZZ \
((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC)
/* RFC2131 section 4.1:
* for retransmission delays, timeout should start at 4s then double
* each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added.
* This assumes the first call will be using attempt 1. */
static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) {
usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC;
return usec_sub_signed(usec_add(now, timeout), RFC2131_RANDOM_FUZZ);
}
/* RFC2131 section 4.4.5:
* T1 defaults to (0.5 * duration_of_lease).
* T2 defaults to (0.875 * duration_of_lease). */
#define T1_DEFAULT(lifetime) ((lifetime) / 2)
#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8)
/* RFC2131 section 4.4.5:
* the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state)
* and one-half of the remaining lease time (in REBINDING state), down to a minimum
* of 60 seconds.
* Note that while the default T1/T2 initial times do have random 'fuzz' applied,
* the RFC sec 4.4.5 does not mention adding any fuzz to retries. */
static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) {
return MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC);
}
static int cmp_uint8(const uint8_t *a, const uint8_t *b) {
return CMP(*a, *b);
}
@ -1192,7 +1227,6 @@ static int client_timeout_resend(
DHCP_CLIENT_DONT_DESTROY(client);
usec_t next_timeout;
uint64_t time_now;
uint32_t time_left;
int r;
assert(s);
@ -1206,19 +1240,11 @@ static int client_timeout_resend(
switch (client->state) {
case DHCP_STATE_RENEWING:
time_left = (client->lease->t2 - client->lease->t1) / 2;
if (time_left < 60)
time_left = 60;
next_timeout = time_now + time_left * USEC_PER_SEC;
next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time);
break;
case DHCP_STATE_REBINDING:
time_left = (client->lease->lifetime - client->lease->t2) / 2;
if (time_left < 60)
time_left = 60;
next_timeout = time_now + time_left * USEC_PER_SEC;
next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time);
break;
case DHCP_STATE_REBOOTING:
@ -1243,7 +1269,7 @@ static int client_timeout_resend(
goto error;
client->attempt++;
next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC;
next_timeout = client_compute_request_timeout(time_now, client->attempt);
break;
case DHCP_STATE_STOPPED:
@ -1251,8 +1277,6 @@ static int client_timeout_resend(
goto error;
}
next_timeout += (random_u32() & 0x1fffff);
r = event_reset_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
next_timeout, 10 * USEC_PER_MSEC,
@ -1618,25 +1642,8 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le
return r;
}
static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) {
assert(client);
assert(client->request_sent);
assert(lifetime > 0);
if (lifetime > 3)
lifetime -= 3;
else
lifetime = 0;
return client->request_sent + (lifetime * USEC_PER_SEC * factor) +
+ (random_u32() & 0x1fffff);
}
static int client_set_lease_timeouts(sd_dhcp_client *client) {
usec_t time_now;
uint64_t lifetime_timeout;
uint64_t t2_timeout;
uint64_t t1_timeout;
char time_string[FORMAT_TIMESPAN_MAX];
int r;
@ -1659,93 +1666,76 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
assert(client->request_sent <= time_now);
/* convert the various timeouts from relative (secs) to absolute (usecs) */
lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1);
if (client->lease->t1 > 0 && client->lease->t2 > 0) {
/* both T1 and T2 are given */
if (client->lease->t1 < client->lease->t2 &&
client->lease->t2 < client->lease->lifetime) {
/* they are both valid */
t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
} else {
/* discard both */
t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
client->lease->t2 = (client->lease->lifetime * 7) / 8;
t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
client->lease->t1 = client->lease->lifetime / 2;
}
} else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) {
/* only T2 is given, and it is valid */
t2_timeout = client_compute_timeout(client, client->lease->t2, 1);
t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
client->lease->t1 = client->lease->lifetime / 2;
if (t2_timeout <= t1_timeout) {
/* the computed T1 would be invalid, so discard T2 */
t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
client->lease->t2 = (client->lease->lifetime * 7) / 8;
}
} else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) {
/* only T1 is given, and it is valid */
t1_timeout = client_compute_timeout(client, client->lease->t1, 1);
t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
client->lease->t2 = (client->lease->lifetime * 7) / 8;
if (t2_timeout <= t1_timeout) {
/* the computed T2 would be invalid, so discard T1 */
t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
client->lease->t2 = client->lease->lifetime / 2;
}
} else {
/* fall back to the default timeouts */
t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5);
client->lease->t1 = client->lease->lifetime / 2;
t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0);
client->lease->t2 = (client->lease->lifetime * 7) / 8;
}
/* verify that 0 < t2 < lifetime */
if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime)
client->lease->t2 = T2_DEFAULT(client->lease->lifetime);
/* verify that 0 < t1 < lifetime */
if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2)
client->lease->t1 = T1_DEFAULT(client->lease->lifetime);
/* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check
* could not evalate to false if t1 >= t2; so setting t2 to T2_DEFAULT
* guarantees t1 < t2. */
if (client->lease->t1 >= client->lease->t2)
client->lease->t2 = T2_DEFAULT(client->lease->lifetime);
client->expire_time = client->request_sent + client->lease->lifetime * USEC_PER_SEC;
client->t1_time = client->request_sent + client->lease->t1 * USEC_PER_SEC;
client->t2_time = client->request_sent + client->lease->t2 * USEC_PER_SEC;
/* RFC2131 section 4.4.5:
* Times T1 and T2 SHOULD be chosen with some random "fuzz".
* Since the RFC doesn't specify here the exact 'fuzz' to use,
* we use the range from section 4.1: -1 to +1 sec. */
client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ);
client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ);
/* after fuzzing, ensure t2 is still >= t1 */
client->t2_time = MAX(client->t1_time, client->t2_time);
/* arm lifetime timeout */
r = event_reset_time(client->event, &client->timeout_expire,
clock_boottime_or_monotonic(),
lifetime_timeout, 10 * USEC_PER_MSEC,
client->expire_time, 10 * USEC_PER_MSEC,
client_timeout_expire, client,
client->event_priority, "dhcp4-lifetime", true);
if (r < 0)
return r;
log_dhcp_client(client, "lease expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
/* don't arm earlier timeouts if this has already expired */
if (lifetime_timeout <= time_now)
if (client->expire_time <= time_now)
return 0;
log_dhcp_client(client, "lease expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->expire_time - time_now, USEC_PER_SEC));
/* arm T2 timeout */
r = event_reset_time(client->event, &client->timeout_t2,
clock_boottime_or_monotonic(),
t2_timeout, 10 * USEC_PER_MSEC,
client->t2_time, 10 * USEC_PER_MSEC,
client_timeout_t2, client,
client->event_priority, "dhcp4-t2-timeout", true);
if (r < 0)
return r;
log_dhcp_client(client, "T2 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
/* don't arm earlier timeout if this has already expired */
if (t2_timeout <= time_now)
if (client->t2_time <= time_now)
return 0;
log_dhcp_client(client, "T2 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t2_time - time_now, USEC_PER_SEC));
/* arm T1 timeout */
r = event_reset_time(client->event, &client->timeout_t1,
clock_boottime_or_monotonic(),
t1_timeout, 10 * USEC_PER_MSEC,
client->t1_time, 10 * USEC_PER_MSEC,
client_timeout_t1, client,
client->event_priority, "dhcp4-t1-timer", true);
if (r < 0)
return r;
if (client->t1_time > time_now)
log_dhcp_client(client, "T1 expires in %s",
format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t1_time - time_now, USEC_PER_SEC));
return 0;
}

View File

@ -407,7 +407,7 @@ int sd_dhcp6_client_set_fqdn(
/* 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);

View File

@ -739,6 +739,8 @@ global:
LIBSYSTEMD_248 {
global:
sd_bus_open_user_machine;
sd_event_source_set_ratelimit;
sd_event_source_get_ratelimit;
sd_event_source_is_ratelimited;

View File

@ -49,7 +49,7 @@ int bus_container_connect_socket(sd_bus *b) {
bus_socket_setup(b);
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
return -errno;
r = namespace_fork("(sd-buscntrns)", "(sd-buscntr)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,

View File

@ -713,7 +713,7 @@ _public_ int sd_bus_get_name_creds(
}
r = bus_creds_add_more(c, mask, pid, 0);
if (r < 0)
if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
return r;
}
@ -788,7 +788,7 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
}
r = bus_creds_add_more(c, mask, pid, 0);
if (r < 0)
if (r < 0 && r != -ESRCH) /* If the process vanished, then don't complain, just return what we got */
return r;
*ret = TAKE_PTR(c);

View File

@ -603,13 +603,15 @@ _public_ int sd_bus_set_property(
return r;
}
_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **ret) {
sd_bus_creds *c;
int r;
assert_return(call, -EINVAL);
assert_return(call->sealed, -EPERM);
assert_return(call->bus, -EINVAL);
assert_return(!bus_pid_changed(call->bus), -ECHILD);
assert_return(ret, -EINVAL);
if (!BUS_IS_OPEN(call->bus->state))
return -ENOTCONN;
@ -618,7 +620,7 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
/* All data we need? */
if (c && (mask & ~c->mask) == 0) {
*creds = sd_bus_creds_ref(c);
*ret = sd_bus_creds_ref(c);
return 0;
}
@ -629,15 +631,22 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
if (call->sender)
/* There's a sender, but the creds are missing. */
return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
return sd_bus_get_name_creds(call->bus, call->sender, mask, ret);
else
/* There's no sender. For direct connections
* the credentials of the AF_UNIX peer matter,
* which may be queried via sd_bus_get_owner_creds(). */
return sd_bus_get_owner_creds(call->bus, mask, creds);
return sd_bus_get_owner_creds(call->bus, mask, ret);
}
return bus_creds_extend_by_pid(c, mask, creds);
r = bus_creds_extend_by_pid(c, mask, ret);
if (r == -ESRCH) {
/* Process doesn't exist anymore? propagate the few things we have */
*ret = sd_bus_creds_ref(c);
return 0;
}
return r;
}
_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {

View File

@ -55,6 +55,15 @@ _public_ int sd_bus_message_dump(sd_bus_message *m, FILE *f, uint64_t flags) {
f = stdout;
if (flags & SD_BUS_MESSAGE_DUMP_WITH_HEADER) {
char buf[FORMAT_TIMESTAMP_MAX];
const char *p;
usec_t ts = m->realtime;
if (ts == 0)
ts = now(CLOCK_REALTIME);
p = format_timestamp_style(buf, sizeof(buf), ts, TIMESTAMP_US_UTC);
fprintf(f,
"%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u",
m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
@ -81,6 +90,8 @@ _public_ int sd_bus_message_dump(sd_bus_message *m, FILE *f, uint64_t flags) {
if (m->reply_cookie != 0)
fprintf(f, " ReplyCookie=%" PRIu64, m->reply_cookie);
fprintf(f, " Timestamp=\"%s\"", strna(p));
fputs("\n", f);
if (m->sender)

View File

@ -401,7 +401,7 @@ void bus_close_io_fds(sd_bus *b);
int bus_set_address_system(sd_bus *bus);
int bus_set_address_user(sd_bus *bus);
int bus_set_address_system_remote(sd_bus *b, const char *host);
int bus_set_address_system_machine(sd_bus *b, const char *machine);
int bus_set_address_machine(sd_bus *b, bool user, const char *machine);
int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);

View File

@ -41,6 +41,7 @@
#include "process-util.h"
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
#define log_debug_bus_message(m) \
do { \
@ -973,7 +974,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
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);
@ -1448,7 +1449,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) {
}
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);
@ -1463,7 +1464,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) {
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);
}
@ -1514,13 +1515,90 @@ _public_ int sd_bus_open_system_remote(sd_bus **ret, const char *host) {
return 0;
}
int bus_set_address_system_machine(sd_bus *b, const char *machine) {
_cleanup_free_ char *e = NULL;
int bus_set_address_machine(sd_bus *b, bool user, const char *machine) {
const char *rhs;
char *a;
assert(b);
assert(machine);
rhs = strchr(machine, '@');
if (rhs || user) {
_cleanup_free_ char *u = NULL, *eu = NULL, *erhs = NULL;
/* If there's an "@" in the container specification, we'll connect as a user specified at its
* left hand side, which is useful in combination with user=true. This isn't as trivial as it
* might sound: it's not sufficient to enter the container and connect to some socket there,
* since the --user socket path depends on $XDG_RUNTIME_DIR which is set via PAM. Thus, to be
* able to connect, we need to have a PAM session. Our way out? We use systemd-run to get
* into the container and acquire a PAM session there, and then invoke systemd-stdio-bridge
* in it, which propagates the bus transport to us.*/
if (rhs) {
if (rhs > machine)
u = strndup(machine, rhs - machine);
else
u = getusername_malloc(); /* Empty user name, let's use the local one */
if (!u)
return -ENOMEM;
eu = bus_address_escape(u);
if (!eu)
return -ENOMEM;
rhs++;
} else {
/* No "@" specified but we shall connect to the user instance? Then assume root (and
* not a user named identically to the calling one). This means:
*
* --machine=foobar --user connect to user bus of root user in container "foobar"
* --machine=@foobar --user connect to user bus of user named like the calling user in container "foobar"
*
* Why? so that behaviour for "--machine=foobar --system" is roughly similar to
* "--machine=foobar --user": both times we unconditionally connect as root user
* regardless what the calling user is. */
rhs = machine;
}
if (!isempty(rhs)) {
erhs = bus_address_escape(rhs);
if (!erhs)
return -ENOMEM;
}
/* systemd-run -M… -PGq --wait -pUser=… -pPAMName=login systemd-stdio-bridge */
a = strjoin("unixexec:path=systemd-run,"
"argv1=-M", erhs ?: ".host", ","
"argv2=-PGq,"
"argv3=--wait,"
"argv4=-pUser%3d", eu ?: "root", ",",
"argv5=-pPAMName%3dlogin,"
"argv6=systemd-stdio-bridge");
if (!a)
return -ENOMEM;
if (user) {
char *k;
/* Ideally we'd use the "--user" switch to systemd-stdio-bridge here, but it's only
* available in recent systemd versions. Using the "-p" switch with the explicit path
* is a working alternative, and is compatible with older versions, hence that's what
* we use here. */
k = strjoin(a, ",argv7=-punix:path%3d%24%7bXDG_RUNTIME_DIR%7d/bus");
if (!k)
return -ENOMEM;
free_and_replace(a, k);
}
} else {
_cleanup_free_ char *e = NULL;
/* Just a container name, we can go the simple way, and just join the container, and connect
* to the well-known path of the system bus there. */
e = bus_address_escape(machine);
if (!e)
return -ENOMEM;
@ -1528,30 +1606,137 @@ int bus_set_address_system_machine(sd_bus *b, const char *machine) {
a = strjoin("x-machine-unix:machine=", e);
if (!a)
return -ENOMEM;
}
return free_and_replace(b->address, a);
}
_public_ int sd_bus_open_system_machine(sd_bus **ret, const char *machine) {
static int user_and_machine_valid(const char *user_and_machine) {
const char *h;
/* Checks if a container specification in the form "user@container" or just "container" is valid.
*
* If the "@" syntax is used we'll allow either the "user" or the "container" part to be omitted, but
* not both. */
h = strchr(user_and_machine, '@');
if (!h)
h = user_and_machine;
else {
_cleanup_free_ char *user = NULL;
user = strndup(user_and_machine, h - user_and_machine);
if (!user)
return -ENOMEM;
if (!isempty(user) && !valid_user_group_name(user, VALID_USER_RELAX))
return false;
h++;
if (isempty(h))
return !isempty(user);
}
return hostname_is_valid(h, VALID_HOSTNAME_DOT_HOST);
}
static int user_and_machine_equivalent(const char *user_and_machine) {
_cleanup_free_ char *un = NULL;
const char *f;
/* Returns true if the specified user+machine name are actually equivalent to our own identity and
* our own host. If so we can shortcut things. Why bother? Because that way we don't have to fork
* off short-lived worker processes that are then unavailable for authentication and logging in the
* peer. Moreover joining a namespace requires privileges. If we are in the right namespace anyway,
* we can avoid permission problems thus. */
assert(user_and_machine);
/* Omitting the user name means that we shall use the same user name as we run as locally, which
* means we'll end up on the same host, let's shortcut */
if (streq(user_and_machine, "@.host"))
return true;
/* Otherwise, if we are root, then we can also allow the ".host" syntax, as that's the user this
* would connect to. */
if (geteuid() == 0 && STR_IN_SET(user_and_machine, ".host", "root@.host"))
return true;
/* Otherwise, we have to figure our user name, and compare things with that. */
un = getusername_malloc();
if (!un)
return -ENOMEM;
f = startswith(user_and_machine, un);
if (!f)
return false;
return STR_IN_SET(f, "@", "@.host");
}
_public_ int sd_bus_open_system_machine(sd_bus **ret, const char *user_and_machine) {
_cleanup_(bus_freep) sd_bus *b = NULL;
int r;
assert_return(machine, -EINVAL);
assert_return(user_and_machine, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(streq(machine, ".host") || machine_name_is_valid(machine), -EINVAL);
if (user_and_machine_equivalent(user_and_machine))
return sd_bus_open_system(ret);
r = user_and_machine_valid(user_and_machine);
if (r < 0)
return r;
assert_return(r > 0, -EINVAL);
r = sd_bus_new(&b);
if (r < 0)
return r;
r = bus_set_address_system_machine(b, machine);
r = bus_set_address_machine(b, false, user_and_machine);
if (r < 0)
return r;
b->bus_client = true;
b->trusted = false;
b->is_system = true;
b->is_local = false;
r = sd_bus_start(b);
if (r < 0)
return r;
*ret = TAKE_PTR(b);
return 0;
}
_public_ int sd_bus_open_user_machine(sd_bus **ret, const char *user_and_machine) {
_cleanup_(bus_freep) sd_bus *b = NULL;
int r;
assert_return(user_and_machine, -EINVAL);
assert_return(ret, -EINVAL);
/* Shortcut things if we'd end up on this host and as the same user. */
if (user_and_machine_equivalent(user_and_machine))
return sd_bus_open_user(ret);
r = user_and_machine_valid(user_and_machine);
if (r < 0)
return r;
assert_return(r > 0, -EINVAL);
r = sd_bus_new(&b);
if (r < 0)
return r;
r = bus_set_address_machine(b, true, user_and_machine);
if (r < 0)
return r;
b->bus_client = true;
b->trusted = true;
r = sd_bus_start(b);
if (r < 0)

View File

@ -847,7 +847,7 @@ _public_ int sd_get_machine_names(char ***machines) {
/* 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;
@ -877,7 +877,7 @@ _public_ int sd_machine_get_class(const char *machine, char **class) {
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);
@ -899,7 +899,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ret_ifindices)
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);

View File

@ -487,7 +487,7 @@ static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
if (r < 0)
return r;
if (asprintf(&address, "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI, m->leader) < 0)
if (asprintf(&address, "x-machine-unix:pid=%" PID_PRI, m->leader) < 0)
return -ENOMEM;
bus->address = address;

View File

@ -1561,7 +1561,7 @@ static int make_service_name(const char *name, char **ret) {
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);
@ -1881,7 +1881,7 @@ static int import_tar(int argc, char *argv[], void *userdata) {
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);
@ -1941,7 +1941,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
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);
@ -1995,7 +1995,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
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);
@ -2048,7 +2048,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
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);
@ -2090,7 +2090,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
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);
@ -2155,7 +2155,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
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);
@ -2211,7 +2211,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
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);

View File

@ -239,7 +239,7 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m
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);

View File

@ -166,7 +166,7 @@ static int manager_enumerate_machines(Manager *m) {
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);

View File

@ -601,7 +601,7 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va
if (p != value) {
hostname = strndupa(value, p - value);
if (!hostname_is_valid(hostname, false))
if (!hostname_is_valid(hostname, 0))
return -EINVAL;
}

View File

@ -1108,7 +1108,8 @@ static int link_set_flags(Link *link) {
if (!link->network)
return 0;
if (link->network->arp < 0 && link->network->multicast < 0 && link->network->allmulticast < 0)
if (link->network->arp < 0 && link->network->multicast < 0 && link->network->allmulticast < 0 &&
link->network->promiscuous < 0)
return 0;
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
@ -1130,6 +1131,11 @@ static int link_set_flags(Link *link) {
SET_FLAG(ifi_flags, IFF_ALLMULTI, link->network->allmulticast);
}
if (link->network->promiscuous >= 0) {
ifi_change |= IFF_PROMISC;
SET_FLAG(ifi_flags, IFF_PROMISC, link->network->promiscuous);
}
r = sd_rtnl_message_link_set_flags(req, ifi_flags, ifi_change);
if (r < 0)
return log_link_error_errno(link, r, "Could not set link flags: %m");

View File

@ -62,6 +62,7 @@ Link.Group, config_parse_uint32,
Link.ARP, config_parse_tristate, 0, offsetof(Network, arp)
Link.Multicast, config_parse_tristate, 0, offsetof(Network, multicast)
Link.AllMulticast, config_parse_tristate, 0, offsetof(Network, allmulticast)
Link.Promiscuous, config_parse_tristate, 0, offsetof(Network, promiscuous)
Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged)
Link.RequiredForOnline, config_parse_required_for_online, 0, 0
SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, 0

View File

@ -321,6 +321,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.arp = -1,
.multicast = -1,
.allmulticast = -1,
.promiscuous = -1,
.configure_without_carrier = false,
.ignore_carrier_loss = -1,
@ -922,7 +923,7 @@ int config_parse_hostname(
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;

View File

@ -87,6 +87,7 @@ struct Network {
int arp;
int multicast;
int allmulticast;
int promiscuous;
bool unmanaged;
bool required_for_online; /* Is this network required to be considered online? */
LinkOperationalStateRange required_operstate_for_online;

View File

@ -462,7 +462,7 @@ static int oci_hostname(const char *name, JsonVariant *v, JsonDispatchFlags flag
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);

View File

@ -701,7 +701,7 @@ int config_parse_hostname(
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;
}

View File

@ -985,7 +985,7 @@ static int parse_argv(int argc, char *argv[]) {
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);
@ -999,7 +999,7 @@ static int parse_argv(int argc, char *argv[]) {
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);
@ -2984,7 +2984,7 @@ static int determine_names(void) {
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) {

View File

@ -249,7 +249,12 @@ int bus_connect_user_systemd(sd_bus **_bus) {
return 0;
}
int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
int bus_connect_transport(
BusTransport transport,
const char *host,
bool user,
sd_bus **ret) {
_cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
int r;
@ -258,7 +263,7 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
assert(ret);
assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL);
assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP);
assert_return(transport != BUS_TRANSPORT_REMOTE || !user, -EOPNOTSUPP);
switch (transport) {
@ -279,6 +284,9 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
break;
case BUS_TRANSPORT_MACHINE:
if (user)
r = sd_bus_open_user_machine(&bus, host);
else
r = sd_bus_open_system_machine(&bus, host);
break;
@ -293,7 +301,6 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
return r;
*ret = TAKE_PTR(bus);
return 0;
}

View File

@ -9,6 +9,7 @@
#include "sd-bus.h"
#include "sd-event.h"
#include "errno-util.h"
#include "macro.h"
#include "string-util.h"
#include "time-util.h"
@ -39,13 +40,21 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s
int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
#define bus_log_address_error(r) \
log_error_errno(r, \
r == -ENOMEDIUM ? "Failed to set bus address: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined" : \
"Failed to set bus address: %m")
({ \
int _k = (r); \
log_error_errno(_k, \
_k == -ENOMEDIUM ? "Failed to set bus address: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user)" : \
"Failed to set bus address: %m"); \
})
#define bus_log_connect_error(r) \
log_error_errno(r, \
r == -ENOMEDIUM ? "Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined" : \
"Failed to connect to bus: %m")
({ \
int _k = (r); \
log_error_errno(_k, \
_k == -ENOMEDIUM ? "Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=<user>@.host --user to connect to bus of other user)" : \
ERRNO_IS_PRIVILEGE(_k) ? "Failed to connect to bus: Operation not permitted (consider using --machine=<user>@.host --user to connect to bus of other user)" : \
"Failed to connect to bus: %m"); \
})
#define bus_log_parse_error(r) \
log_error_errno(r, "Failed to parse bus message: %m")

View File

@ -1523,9 +1523,6 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
assert(machine);
assert(boot_id);
if (!machine_name_is_valid(machine))
return -EINVAL;
r = container_get_leader(machine, &pid);
if (r < 0)
return r;

View File

@ -23,6 +23,7 @@
static const char *arg_bus_path = DEFAULT_BUS_PATH;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static bool arg_user = false;
static int help(void) {
@ -30,8 +31,10 @@ static int help(void) {
"STDIO or socket-activatable proxy to a given DBus endpoint.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" -p --bus-path=PATH Path to the kernel bus (default: %s)\n"
" -M --machine=MACHINE Name of machine to connect to\n",
" -p --bus-path=PATH Path to the bus address (default: %s)\n"
" --system Connect to system bus\n"
" --user Connect to user bus\n"
" -M --machine=CONTAINER Name of local container to connect to\n",
program_invocation_short_name, DEFAULT_BUS_PATH);
return 0;
@ -42,12 +45,16 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_MACHINE,
ARG_USER,
ARG_SYSTEM,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "bus-path", required_argument, NULL, 'p' },
{ "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "machine", required_argument, NULL, 'M' },
{},
};
@ -67,6 +74,14 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
case ARG_USER:
arg_user = true;
break;
case ARG_SYSTEM:
arg_user = false;
break;
case 'p':
arg_bus_path = optarg;
break;
@ -121,7 +136,7 @@ static int run(int argc, char *argv[]) {
return log_error_errno(r, "Failed to allocate bus: %m");
if (arg_transport == BUS_TRANSPORT_MACHINE)
r = bus_set_address_system_machine(a, arg_bus_path);
r = bus_set_address_machine(a, arg_user, arg_bus_path);
else
r = sd_bus_set_address(a, arg_bus_path);
if (r < 0)

View File

@ -877,7 +877,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM)
if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Cannot access user instance remotely.");

View File

@ -135,6 +135,7 @@ int sd_bus_open(sd_bus **ret);
int sd_bus_open_with_description(sd_bus **ret, const char *description);
int sd_bus_open_user(sd_bus **ret);
int sd_bus_open_user_with_description(sd_bus **ret, const char *description);
int sd_bus_open_user_machine(sd_bus **ret, const char *machine);
int sd_bus_open_system(sd_bus **ret);
int sd_bus_open_system_with_description(sd_bus **ret, const char *description);
int sd_bus_open_system_remote(sd_bus **ret, const char *host);

View File

@ -10,40 +10,40 @@
#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", 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", 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", 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) {
@ -151,7 +151,7 @@ static void test_hostname_malloc(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);
}

View File

@ -3,7 +3,11 @@ set -e
TEST_DESCRIPTION="test MUMAPolicy= and NUMAMask= options"
TEST_NO_NSPAWN=1
QEMU_OPTIONS="-numa node,nodeid=0"
. $TEST_BASE_DIR/test-functions
if qemu_min_version "5.2.0"; then
QEMU_OPTIONS="-object memory-backend-ram,id=mem0,size=512M -numa node,memdev=mem0,nodeid=0"
else
QEMU_OPTIONS="-numa node,nodeid=0"
fi
do_test "$@" 36

View File

@ -38,6 +38,7 @@ MTUBytes=
Multicast=
MACAddress=
Group=
Promiscuous=
[SR-IOV]
VirtualFunction=
MACSpoofCheck=

View File

@ -227,6 +227,24 @@ function find_qemu_bin() {
fi
}
# Compares argument #1=X.Y.Z (X&Y&Z = numeric) to the version of the installed qemu
# returns 0 if newer or equal
# returns 1 if older
# returns 2 if failing
function qemu_min_version() {
find_qemu_bin || return 2
# get version from binary
qemu_ver=$($QEMU_BIN --version | awk '/^QEMU emulator version ([0-9]*\.[0-9]*\.[0-9]*) / {print $4}')
# Check version string format
echo "$qemu_ver" | grep -q '^[0-9]*\.[0-9]*\.[0-9]*$' || return 2
echo "$1" | grep -q '^[0-9]*\.[0-9]*\.[0-9]*$' || return 2
# compare as last command to return that value
printf "%s\n%s\n" "$1" "$qemu_ver" | sort -V -C
}
# Return 0 if QEMU did run (then you must check the result state/logs for actual
# success), or 1 if QEMU is not available.
run_qemu() {

View File

@ -4104,7 +4104,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
'dhcp-client-with-ipv4ll.network')
start_networkd()
self.wait_online(['veth99:degraded', 'veth-peer:routable'])
# we need to increase timeout above default, as this will need to wait for
# systemd-networkd to get the dhcpv4 transient failure event
self.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout='60s')
output = check_output('ip address show dev veth99')
print(output)