summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyze/analyze.c2
-rw-r--r--src/basic/architecture.c3
-rw-r--r--src/basic/architecture.h3
-rw-r--r--src/basic/calendarspec.c3
-rw-r--r--src/core/dbus-manager.c166
-rw-r--r--src/core/dbus-unit.c4
-rw-r--r--src/core/dbus.c8
-rw-r--r--src/core/execute.c25
-rw-r--r--src/core/manager.c11
-rw-r--r--src/hostname/hostnamectl.c23
-rw-r--r--src/locale/localectl.c5
-rw-r--r--src/login/loginctl.c15
-rw-r--r--src/machine/machinectl.c13
-rw-r--r--src/network/networkd-ipv6-proxy-ndp.c209
-rw-r--r--src/network/networkd-ipv6-proxy-ndp.h44
-rw-r--r--src/network/networkd-link.c5
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.c6
-rw-r--r--src/network/networkd-network.h3
-rw-r--r--src/nss-myhostname/nss-myhostname.c11
-rw-r--r--src/nss-resolve/nss-resolve.c16
-rw-r--r--src/resolve/resolve-tool.c16
-rw-r--r--src/resolve/resolved-bus.c8
-rw-r--r--src/resolve/resolved-dns-answer.h8
-rw-r--r--src/resolve/resolved-dns-cache.c4
-rw-r--r--src/resolve/resolved-dns-packet.c21
-rw-r--r--src/resolve/resolved-dns-packet.h4
-rw-r--r--src/resolve/resolved-dns-query.c10
-rw-r--r--src/resolve/resolved-dns-query.h5
-rw-r--r--src/resolve/resolved-dns-rr.c2
-rw-r--r--src/resolve/resolved-dns-scope.c116
-rw-r--r--src/resolve/resolved-dns-scope.h6
-rw-r--r--src/resolve/resolved-dns-server.c19
-rw-r--r--src/resolve/resolved-dns-server.h2
-rw-r--r--src/resolve/resolved-dns-stub.c126
-rw-r--r--src/resolve/resolved-dns-transaction.c47
-rw-r--r--src/resolve/resolved-dns-transaction.h14
-rw-r--r--src/resolve/resolved-dns-zone.c1
-rw-r--r--src/resolve/resolved-dns-zone.h3
-rw-r--r--src/resolve/resolved-link.c129
-rw-r--r--src/resolve/resolved-link.h2
-rw-r--r--src/resolve/resolved-manager.c53
-rw-r--r--src/resolve/resolved-manager.h3
-rw-r--r--src/resolve/resolved-mdns.c61
-rw-r--r--src/resolve/resolved-mdns.h1
-rw-r--r--src/run/run.c4
-rw-r--r--src/shared/bus-unit-util.c6
-rw-r--r--src/shared/bus-util.c15
-rw-r--r--src/shared/bus-util.h6
-rw-r--r--src/shared/install.c62
-rw-r--r--src/shared/path-lookup.c65
-rw-r--r--src/shared/seccomp-util.c97
-rw-r--r--src/systemctl/systemctl.c17
-rw-r--r--src/test/test-calendarspec.c1
-rw-r--r--src/test/test-execute.c5
-rw-r--r--src/timedate/timedatectl.c5
56 files changed, 1201 insertions, 319 deletions
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 51d881c5fb..a9402fdb28 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -461,6 +461,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
hostname_map,
+ &error,
host);
if (r < 0)
log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r));
@@ -469,6 +470,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
manager_map,
+ &error,
host);
if (r < 0)
return log_error_errno(r, "Failed to get host information from systemd: %s", bus_error_message(&error, r));
diff --git a/src/basic/architecture.c b/src/basic/architecture.c
index b74dc0db78..5a3dc08a4a 100644
--- a/src/basic/architecture.c
+++ b/src/basic/architecture.c
@@ -123,7 +123,8 @@ int uname_architecture(void) {
{ "crisv32", ARCHITECTURE_CRIS },
#elif defined(__nios2__)
{ "nios2", ARCHITECTURE_NIOS2 },
-#elif defined(__riscv__)
+#elif defined(__riscv__) || defined(__riscv)
+ /* __riscv__ is obsolete, remove in 2018 */
{ "riscv32", ARCHITECTURE_RISCV32 },
{ "riscv64", ARCHITECTURE_RISCV64 },
# if __SIZEOF_POINTER__ == 4
diff --git a/src/basic/architecture.h b/src/basic/architecture.h
index b329df2f6d..d6b8603b06 100644
--- a/src/basic/architecture.h
+++ b/src/basic/architecture.h
@@ -194,7 +194,8 @@ int uname_architecture(void);
#elif defined(__nios2__)
# define native_architecture() ARCHITECTURE_NIOS2
# define LIB_ARCH_TUPLE "nios2-linux-gnu"
-#elif defined(__riscv__)
+#elif defined(__riscv__) || defined(__riscv)
+ /* __riscv__ is obsolete, remove in 2018 */
# if __SIZEOF_POINTER__ == 4
# define native_architecture() ARCHITECTURE_RISCV32
# define LIB_ARCH_TUPLE "riscv32-linux-gnu"
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index 3fa1c51ace..2323eb8555 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -116,8 +116,7 @@ static void normalize_chain(CalendarComponent **c) {
/* Drop non-unique entries */
for (k = n-1; k > 0; k--) {
- if (b[k-1]->start == next->start &&
- b[k-1]->repeat == next->repeat) {
+ if (component_compare(&b[k-1], &next) == 0) {
free(b[k-1]);
continue;
}
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 0136d38833..f87b52a266 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -848,13 +848,9 @@ static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd
if (r < 0)
return r;
- r = manager_load_unit(m, name, NULL, error, &u);
- if (r < 0)
- return r;
-
- r = bus_unit_check_load_state(u, error);
- if (r < 0)
- return r;
+ u = manager_get_unit(m, name);
+ if (!u)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
return bus_unit_method_get_processes(message, u, error);
}
@@ -1342,7 +1338,7 @@ static int verify_run_space(const char *message, sd_bus_error *error) {
}
int verify_run_space_and_log(const char *message) {
- sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
r = verify_run_space(message, &error);
@@ -1916,63 +1912,6 @@ static int send_unit_files_changed(sd_bus *bus, void *userdata) {
return sd_bus_send(bus, message, NULL);
}
-static int reply_unit_file_changes_and_free(
- Manager *m,
- sd_bus_message *message,
- int carries_install_info,
- UnitFileChange *changes,
- unsigned n_changes) {
-
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- unsigned i;
- int r;
-
- if (unit_file_changes_have_modification(changes, n_changes)) {
- r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
- if (r < 0)
- log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m");
- }
-
- r = sd_bus_message_new_method_return(message, &reply);
- if (r < 0)
- goto fail;
-
- if (carries_install_info >= 0) {
- r = sd_bus_message_append(reply, "b", carries_install_info);
- if (r < 0)
- goto fail;
- }
-
- r = sd_bus_message_open_container(reply, 'a', "(sss)");
- if (r < 0)
- goto fail;
-
- for (i = 0; i < n_changes; i++)
- if (changes[i].type >= 0) {
- const char *change = unit_file_change_type_to_string(changes[i].type);
- assert(change != NULL);
-
- r = sd_bus_message_append(
- reply, "(sss)",
- change,
- changes[i].path,
- changes[i].source);
- if (r < 0)
- goto fail;
- }
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- goto fail;
-
- unit_file_changes_free(changes, n_changes);
- return sd_bus_send(NULL, reply, NULL);
-
-fail:
- unit_file_changes_free(changes, n_changes);
- return r;
-}
-
/* Create an error reply, using the error information from changes[]
* if possible, and fall back to generating an error from error code c.
* The error message only describes the first error.
@@ -1986,12 +1925,14 @@ static int install_error(
unsigned n_changes) {
int r;
unsigned i;
- assert(c < 0);
for (i = 0; i < n_changes; i++)
+
switch(changes[i].type) {
+
case 0 ... INT_MAX:
continue;
+
case -EEXIST:
if (changes[i].source)
r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
@@ -2002,29 +1943,106 @@ static int install_error(
"File %s already exists.",
changes[i].path);
goto found;
+
case -ERFKILL:
r = sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED,
"Unit file %s is masked.", changes[i].path);
goto found;
+
case -EADDRNOTAVAIL:
r = sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED,
"Unit %s is transient or generated.", changes[i].path);
goto found;
+
case -ELOOP:
r = sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED,
"Refusing to operate on linked unit file %s", changes[i].path);
goto found;
+
+ case -ENOENT:
+ r = sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit file %s does not exist.", changes[i].path);
+ goto found;
+
default:
r = sd_bus_error_set_errnof(error, changes[i].type, "File %s: %m", changes[i].path);
goto found;
}
- r = c;
+ r = c < 0 ? c : -EINVAL;
+
found:
unit_file_changes_free(changes, n_changes);
return r;
}
+static int reply_unit_file_changes_and_free(
+ Manager *m,
+ sd_bus_message *message,
+ int carries_install_info,
+ UnitFileChange *changes,
+ unsigned n_changes,
+ sd_bus_error *error) {
+
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ bool bad = false, good = false;
+ unsigned i;
+ int r;
+
+ if (unit_file_changes_have_modification(changes, n_changes)) {
+ r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m");
+ }
+
+ r = sd_bus_message_new_method_return(message, &reply);
+ if (r < 0)
+ goto fail;
+
+ if (carries_install_info >= 0) {
+ r = sd_bus_message_append(reply, "b", carries_install_info);
+ if (r < 0)
+ goto fail;
+ }
+
+ r = sd_bus_message_open_container(reply, 'a', "(sss)");
+ if (r < 0)
+ goto fail;
+
+ for (i = 0; i < n_changes; i++) {
+
+ if (changes[i].type < 0) {
+ bad = true;
+ continue;
+ }
+
+ r = sd_bus_message_append(
+ reply, "(sss)",
+ unit_file_change_type_to_string(changes[i].type),
+ changes[i].path,
+ changes[i].source);
+ if (r < 0)
+ goto fail;
+
+ good = true;
+ }
+
+ /* If there was a failed change, and no successful change, then return the first failure as proper method call
+ * error. */
+ if (bad && !good)
+ return install_error(error, 0, changes, n_changes);
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ goto fail;
+
+ unit_file_changes_free(changes, n_changes);
+ return sd_bus_send(NULL, reply, NULL);
+
+fail:
+ unit_file_changes_free(changes, n_changes);
+ return r;
+}
+
static int method_enable_unit_files_generic(
sd_bus_message *message,
Manager *m,
@@ -2061,7 +2079,7 @@ static int method_enable_unit_files_generic(
if (r < 0)
return install_error(error, r, changes, n_changes);
- return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes, error);
}
static int method_enable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -2130,7 +2148,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
if (r < 0)
return install_error(error, r, changes, n_changes);
- return reply_unit_file_changes_and_free(m, message, r, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, r, changes, n_changes, error);
}
static int method_disable_unit_files_generic(
@@ -2165,7 +2183,7 @@ static int method_disable_unit_files_generic(
if (r < 0)
return install_error(error, r, changes, n_changes);
- return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes, error);
}
static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -2200,7 +2218,7 @@ static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_
if (r < 0)
return install_error(error, r, changes, n_changes);
- return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes, error);
}
static int method_set_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -2231,7 +2249,7 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd
if (r < 0)
return install_error(error, r, changes, n_changes);
- return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes, error);
}
static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -2274,7 +2292,7 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata,
if (r < 0)
return install_error(error, r, changes, n_changes);
- return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes, error);
}
static int method_add_dependency_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -2314,7 +2332,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
if (r < 0)
return install_error(error, r, changes, n_changes);
- return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes, error);
}
static int method_get_unit_file_links(sd_bus_message *message, void *userdata, sd_bus_error *error) {
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index 60e889e1ef..f1306a023f 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -1006,6 +1006,10 @@ int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bu
assert(message);
+ r = mac_selinux_unit_access_check(u, message, "status", error);
+ if (r < 0)
+ return r;
+
pids = set_new(NULL);
if (!pids)
return -ENOMEM;
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 0493e5786c..065f2d81d6 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -298,7 +298,7 @@ static int bus_job_find(sd_bus *bus, const char *path, const char *interface, vo
}
static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
- Unit *u;
+ Unit *u = NULL; /* just to appease gcc, initialization is not really necessary */
int r;
assert(m);
@@ -323,15 +323,15 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_
return r;
u = manager_get_unit_by_pid(m, pid);
+ if (!u)
+ return 0;
} else {
r = manager_load_unit_from_dbus_path(m, path, error, &u);
if (r < 0)
return 0;
+ assert(u);
}
- if (!u)
- return 0;
-
*unit = u;
return 1;
}
diff --git a/src/core/execute.c b/src/core/execute.c
index 6041da46d6..4c2968f971 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1938,10 +1938,13 @@ static int compile_read_write_paths(
return 0;
}
-static int apply_mount_namespace(Unit *u, const ExecContext *context,
- const ExecParameters *params,
- ExecRuntime *runtime) {
- int r;
+static int apply_mount_namespace(
+ Unit *u,
+ ExecCommand *command,
+ const ExecContext *context,
+ const ExecParameters *params,
+ ExecRuntime *runtime) {
+
_cleanup_strv_free_ char **rw = NULL;
char *tmp = NULL, *var = NULL;
const char *root_dir = NULL, *root_image = NULL;
@@ -1953,6 +1956,8 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context,
.protect_kernel_modules = context->protect_kernel_modules,
.mount_apivfs = context->mount_apivfs,
};
+ bool apply_restrictions;
+ int r;
assert(context);
@@ -1986,16 +1991,18 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context,
if (!context->dynamic_user && root_dir)
ns_info.ignore_protect_paths = true;
+ apply_restrictions = (params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged;
+
r = setup_namespace(root_dir, root_image,
&ns_info, rw,
- context->read_only_paths,
- context->inaccessible_paths,
+ apply_restrictions ? context->read_only_paths : NULL,
+ apply_restrictions ? context->inaccessible_paths : NULL,
context->bind_mounts,
context->n_bind_mounts,
tmp,
var,
- context->protect_home,
- context->protect_system,
+ apply_restrictions ? context->protect_home : PROTECT_HOME_NO,
+ apply_restrictions ? context->protect_system : PROTECT_SYSTEM_NO,
context->mount_flags,
DISSECT_IMAGE_DISCARD_ON_LOOP);
@@ -2606,7 +2613,7 @@ static int exec_child(
needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
if (needs_mount_namespace) {
- r = apply_mount_namespace(unit, context, params, runtime);
+ r = apply_mount_namespace(unit, command, context, params, runtime);
if (r < 0) {
*exit_status = EXIT_NAMESPACE;
return r;
diff --git a/src/core/manager.c b/src/core/manager.c
index e4da945777..5646889a8e 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -1398,7 +1398,7 @@ tr_abort:
}
int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
- Unit *unit;
+ Unit *unit = NULL; /* just to appease gcc, initialization is not really necessary */
int r;
assert(m);
@@ -1409,6 +1409,7 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
r = manager_load_unit(m, name, NULL, NULL, &unit);
if (r < 0)
return r;
+ assert(unit);
return manager_add_job(m, type, unit, mode, e, ret);
}
@@ -1481,6 +1482,7 @@ int manager_load_unit_prepare(
assert(m);
assert(name || path);
+ assert(_ret);
/* This will prepare the unit for loading, but not actually
* load anything from disk. */
@@ -1528,8 +1530,7 @@ int manager_load_unit_prepare(
unit_add_to_dbus_queue(ret);
unit_add_to_gc_queue(ret);
- if (_ret)
- *_ret = ret;
+ *_ret = ret;
return 0;
}
@@ -1544,6 +1545,7 @@ int manager_load_unit(
int r;
assert(m);
+ assert(_ret);
/* This will load the service information files, but not actually
* start any services or anything. */
@@ -1554,8 +1556,7 @@ int manager_load_unit(
manager_dispatch_load_queue(m);
- if (_ret)
- *_ret = unit_follow_merge(*_ret);
+ *_ret = unit_follow_merge(*_ret);
return 0;
}
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index 07c57fb567..f5a9de94a6 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -137,10 +137,8 @@ static int show_one_name(sd_bus *bus, const char* attr) {
"org.freedesktop.hostname1",
attr,
&error, &reply, "s");
- if (r < 0) {
- log_error("Could not get property: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Could not get property: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &s);
if (r < 0)
@@ -151,7 +149,7 @@ static int show_one_name(sd_bus *bus, const char* attr) {
return 0;
}
-static int show_all_names(sd_bus *bus) {
+static int show_all_names(sd_bus *bus, sd_bus_error *error) {
StatusInfo info = {};
static const struct bus_properties_map hostname_map[] = {
@@ -181,6 +179,7 @@ static int show_all_names(sd_bus *bus) {
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
hostname_map,
+ error,
&info);
if (r < 0)
goto fail;
@@ -189,6 +188,7 @@ static int show_all_names(sd_bus *bus) {
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
manager_map,
+ error,
&info);
print_status_info(&info);
@@ -212,6 +212,8 @@ fail:
}
static int show_status(sd_bus *bus, char **args, unsigned n) {
+ int r;
+
assert(args);
if (arg_pretty || arg_static || arg_transient) {
@@ -226,8 +228,15 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
arg_static ? "StaticHostname" : "Hostname";
return show_one_name(bus, attr);
- } else
- return show_all_names(bus);
+ } else {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+
+ r = show_all_names(bus, &error);
+ if (r < 0)
+ return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
+
+ return 0;
+ }
}
static int set_simple_string(sd_bus *bus, const char *method, const char *value) {
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 81afb4909f..0bd18a5c0b 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -166,6 +166,8 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
{ "Locale", "as", NULL, offsetof(StatusInfo, locale) },
{}
};
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
@@ -174,9 +176,10 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
"org.freedesktop.locale1",
"/org/freedesktop/locale1",
map,
+ &error,
&info);
if (r < 0)
- return log_error_errno(r, "Could not get properties: %m");
+ return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
print_overridden_variables();
print_status_info(&info);
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 1aac7ae979..7dea5c0859 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -482,14 +482,15 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
{}
};
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
char since2[FORMAT_TIMESTAMP_MAX], *s2;
_cleanup_(session_status_info_clear) SessionStatusInfo i = {};
int r;
- r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
+ r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
if (r < 0)
- return log_error_errno(r, "Could not get properties: %m");
+ return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
if (*new_line)
printf("\n");
@@ -611,14 +612,15 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
{}
};
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
char since2[FORMAT_TIMESTAMP_MAX], *s2;
_cleanup_(user_status_info_clear) UserStatusInfo i = {};
int r;
- r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
+ r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
if (r < 0)
- return log_error_errno(r, "Could not get properties: %m");
+ return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
if (*new_line)
printf("\n");
@@ -685,12 +687,13 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
{}
};
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
int r;
- r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
+ r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &error, &i);
if (r < 0)
- return log_error_errno(r, "Could not get properties: %m");
+ return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
if (*new_line)
printf("\n");
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 4f5f659c7c..fe4f1b7726 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -772,6 +772,7 @@ static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bo
{}
};
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(machine_status_info_clear) MachineStatusInfo info = {};
int r;
@@ -784,9 +785,10 @@ static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bo
"org.freedesktop.machine1",
path,
map,
+ &error,
&info);
if (r < 0)
- return log_error_errno(r, "Could not get properties: %m");
+ return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
if (*new_line)
printf("\n");
@@ -962,6 +964,7 @@ static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
{}
};
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(image_status_info_clear) ImageStatusInfo info = {};
int r;
@@ -973,9 +976,10 @@ static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
"org.freedesktop.machine1",
path,
map,
+ &error,
&info);
if (r < 0)
- return log_error_errno(r, "Could not get properties: %m");
+ return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
if (*new_line)
printf("\n");
@@ -1029,6 +1033,8 @@ static int show_pool_info(sd_bus *bus) {
.usage = (uint64_t) -1,
.limit = (uint64_t) -1,
};
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
@@ -1037,9 +1043,10 @@ static int show_pool_info(sd_bus *bus) {
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
map,
+ &error,
&info);
if (r < 0)
- return log_error_errno(r, "Could not get properties: %m");
+ return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
print_pool_status_info(bus, &info);
diff --git a/src/network/networkd-ipv6-proxy-ndp.c b/src/network/networkd-ipv6-proxy-ndp.c
new file mode 100644
index 0000000000..11c1cd9268
--- /dev/null
+++ b/src/network/networkd-ipv6-proxy-ndp.c
@@ -0,0 +1,209 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Florian Klink <flokli@flokli.de>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <netinet/ether.h>
+#include <linux/if.h>
+#include <unistd.h>
+
+#include "fileio.h"
+#include "netlink-util.h"
+#include "networkd-ipv6-proxy-ndp.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "networkd-network.h"
+#include "string-util.h"
+
+static bool ipv6_proxy_ndp_is_needed(Link *link) {
+ assert(link);
+
+ if (link->flags & IFF_LOOPBACK)
+ return false;
+
+ if (!link->network)
+ return false;
+
+ if (link->network->n_ipv6_proxy_ndp_addresses == 0)
+ return false;
+
+ return true;
+}
+
+static int ipv6_proxy_ndp_set(Link *link) {
+ const char *p = NULL;
+ int r, v;
+
+ assert(link);
+
+ v = ipv6_proxy_ndp_is_needed(link);
+ p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/proxy_ndp");
+
+ r = write_string_file(p, one_zero(v), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot configure proxy NDP for interface: %m");
+
+ return 0;
+}
+
+int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
+ _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
+
+ assert(network);
+ assert(ret);
+
+ /* allocate space for IPv6ProxyNDPAddress entry */
+ ipv6_proxy_ndp_address = new0(IPv6ProxyNDPAddress, 1);
+ if (!ipv6_proxy_ndp_address)
+ return -ENOMEM;
+
+ ipv6_proxy_ndp_address->network = network;
+
+ LIST_PREPEND(ipv6_proxy_ndp_addresses, network->ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address);
+ network->n_ipv6_proxy_ndp_addresses++;
+
+ *ret = ipv6_proxy_ndp_address;
+ ipv6_proxy_ndp_address = NULL;
+
+ return 0;
+}
+
+void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) {
+ if (!ipv6_proxy_ndp_address)
+ return;
+
+ if (ipv6_proxy_ndp_address->network) {
+ LIST_REMOVE(ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address->network->ipv6_proxy_ndp_addresses,
+ ipv6_proxy_ndp_address);
+
+ assert(ipv6_proxy_ndp_address->network->n_ipv6_proxy_ndp_addresses > 0);
+ ipv6_proxy_ndp_address->network->n_ipv6_proxy_ndp_addresses--;
+ }
+
+ free(ipv6_proxy_ndp_address);
+}
+
+int config_parse_ipv6_proxy_ndp_address(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = userdata;
+ _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
+ int r;
+ union in_addr_union buffer;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = ipv6_proxy_ndp_address_new_static(network, &ipv6_proxy_ndp_address);
+ if (r < 0)
+ return r;
+
+ r = in_addr_from_string(AF_INET6, rvalue, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 proxy NDP address, ignoring: %s",
+ rvalue);
+ return 0;
+ }
+
+ r = in_addr_is_null(AF_INET6, &buffer);
+ if (r != 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "IPv6 proxy NDP address can not be the ANY address, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ ipv6_proxy_ndp_address->in_addr = buffer.in6;
+ ipv6_proxy_ndp_address = NULL;
+
+ return 0;
+}
+
+static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ Link *link = userdata;
+ int r;
+
+ assert(link);
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST)
+ log_link_error_errno(link, r, "Could not add IPv6 proxy ndp address entry: %m");
+
+ return 1;
+}
+
+/* send a request to the kernel to add a IPv6 Proxy entry to the neighbour table */
+int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+ sd_netlink *rtnl;
+ int r;
+
+ assert(link);
+ assert(link->network);
+ assert(link->manager);
+ assert(ipv6_proxy_ndp_address);
+
+ rtnl = link->manager->rtnl;
+
+ /* create new netlink message */
+ r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_NEWNEIGH, link->ifindex, AF_INET6);
+ if (r < 0)
+ return rtnl_log_create_error(r);
+
+ r = sd_rtnl_message_neigh_set_flags(req, NLM_F_REQUEST | NTF_PROXY);
+ if (r < 0)
+ return rtnl_log_create_error(r);
+
+ r = sd_netlink_message_append_in6_addr(req, NDA_DST, &ipv6_proxy_ndp_address->in_addr);
+ if (r < 0)
+ return rtnl_log_create_error(r);
+
+ r = sd_netlink_call_async(rtnl, req, set_ipv6_proxy_ndp_address_handler, link, 0, NULL);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
+
+ return 0;
+}
+
+/* configure all ipv6 proxy ndp addresses */
+int ipv6_proxy_ndp_addresses_configure(Link *link) {
+ IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
+ int r;
+
+ /* enable or disable proxy_ndp itself depending on whether ipv6_proxy_ndp_addresses are set or not */
+ r = ipv6_proxy_ndp_set(link);
+ if (r != 0)
+ return r;
+
+ LIST_FOREACH(ipv6_proxy_ndp_addresses, ipv6_proxy_ndp_address, link->network->ipv6_proxy_ndp_addresses) {
+ r = ipv6_proxy_ndp_address_configure(link, ipv6_proxy_ndp_address);
+ if (r != 0)
+ return r;
+ }
+ return 0;
+}
diff --git a/src/network/networkd-ipv6-proxy-ndp.h b/src/network/networkd-ipv6-proxy-ndp.h
new file mode 100644
index 0000000000..f09169f40f
--- /dev/null
+++ b/src/network/networkd-ipv6-proxy-ndp.h
@@ -0,0 +1,44 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Florian Klink <flokli@flokli.de>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "list.h"
+#include "macro.h"
+
+typedef struct Network Network;
+typedef struct IPv6ProxyNDPAddress IPv6ProxyNDPAddress;
+typedef struct Link Link;
+
+struct IPv6ProxyNDPAddress {
+ Network *network;
+ struct in6_addr in_addr;
+
+ LIST_FIELDS(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
+};
+
+
+int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress ** ipv6_proxy_ndp_address);
+void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
+int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
+int ipv6_proxy_ndp_addresses_configure(Link *link);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(IPv6ProxyNDPAddress*, ipv6_proxy_ndp_address_free);
+
+int config_parse_ipv6_proxy_ndp_address(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index b993d27c2f..0c1229336b 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -28,6 +28,7 @@
#include "fileio.h"
#include "netlink-util.h"
#include "network-internal.h"
+#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-lldp-tx.h"
#include "networkd-manager.h"
#include "networkd-ndisc.h"
@@ -2448,6 +2449,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
+ r = ipv6_proxy_ndp_addresses_configure(link);
+ if (r < 0)
+ return r;
+
r = link_set_ipv4_forward(link);
if (r < 0)
return r;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 7b54e81fb8..68052ba544 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -67,6 +67,7 @@ Network.ActiveSlave, config_parse_bool,
Network.PrimarySlave, config_parse_bool, 0, offsetof(Network, primary_slave)
Network.IPv4ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp)
Network.ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp)
+Network.IPv6ProxyNDPAddress, config_parse_ipv6_proxy_ndp_address, 0, 0
Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
Address.Address, config_parse_address, 0, 0
Address.Peer, config_parse_address, 0, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index bc4dc95ff9..92062ca00c 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -70,6 +70,7 @@ static int network_load_one(Manager *manager, const char *filename) {
LIST_HEAD_INIT(network->static_addresses);
LIST_HEAD_INIT(network->static_routes);
LIST_HEAD_INIT(network->static_fdb_entries);
+ LIST_HEAD_INIT(network->ipv6_proxy_ndp_addresses);
network->stacked_netdevs = hashmap_new(&string_hash_ops);
if (!network->stacked_netdevs)
@@ -152,6 +153,7 @@ static int network_load_one(Manager *manager, const char *filename) {
"DHCPv4\0" /* compat */
"DHCPServer\0"
"IPv6AcceptRA\0"
+ "IPv6NDPProxyAddress\0"
"Bridge\0"
"BridgeFDB\0"
"BridgeVLAN\0",
@@ -224,6 +226,7 @@ void network_free(Network *network) {
Route *route;
Address *address;
FdbEntry *fdb_entry;
+ IPv6ProxyNDPAddress *ipv6_proxy_ndp_address;
Iterator i;
if (!network)
@@ -268,6 +271,9 @@ void network_free(Network *network) {
while ((fdb_entry = network->static_fdb_entries))
fdb_entry_free(fdb_entry);
+ while ((ipv6_proxy_ndp_address = network->ipv6_proxy_ndp_addresses))
+ ipv6_proxy_ndp_address_free(ipv6_proxy_ndp_address);
+
hashmap_free(network->addresses_by_section);
hashmap_free(network->routes_by_section);
hashmap_free(network->fdb_entries_by_section);
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index b7da9d22d4..f06828a899 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -31,6 +31,7 @@
#include "networkd-brvlan.h"
#include "networkd-fdb.h"
#include "networkd-lldp-tx.h"
+#include "networkd-ipv6-proxy-ndp.h"
#include "networkd-route.h"
#include "networkd-util.h"
#include "netdev/netdev.h"
@@ -188,10 +189,12 @@ struct Network {
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);
LIST_HEAD(FdbEntry, static_fdb_entries);
+ LIST_HEAD(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
unsigned n_static_addresses;
unsigned n_static_routes;
unsigned n_static_fdb_entries;
+ unsigned n_ipv6_proxy_ndp_addresses;
Hashmap *addresses_by_section;
Hashmap *routes_by_section;
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index 11c27575c0..326672cab5 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -55,7 +55,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
_cleanup_free_ struct local_address *addresses = NULL;
_cleanup_free_ char *hn = NULL;
const char *canonical = NULL;
- int n_addresses = 0, lo_ifi;
+ int n_addresses = 0;
uint32_t local_address_ipv4;
struct local_address *a;
size_t l, idx, ms;
@@ -111,9 +111,6 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
local_address_ipv4 = LOCALADDRESS_IPV4;
}
- /* If this call fails we fill in 0 as scope. Which is fine */
- lo_ifi = n_addresses <= 0 ? LOOPBACK_IFINDEX : 0;
-
l = strlen(canonical);
ms = ALIGN(l+1) + ALIGN(sizeof(struct gaih_addrtuple)) * (n_addresses > 0 ? n_addresses : 2);
if (buflen < ms) {
@@ -135,7 +132,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
r_tuple->name = r_name;
r_tuple->family = AF_INET6;
memcpy(r_tuple->addr, LOCALADDRESS_IPV6, 16);
- r_tuple->scopeid = (uint32_t) lo_ifi;
+ r_tuple->scopeid = 0;
idx += ALIGN(sizeof(struct gaih_addrtuple));
r_tuple_prev = r_tuple;
@@ -146,7 +143,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
r_tuple->name = r_name;
r_tuple->family = AF_INET;
*(uint32_t*) r_tuple->addr = local_address_ipv4;
- r_tuple->scopeid = (uint32_t) lo_ifi;
+ r_tuple->scopeid = 0;
idx += ALIGN(sizeof(struct gaih_addrtuple));
r_tuple_prev = r_tuple;
@@ -158,7 +155,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
r_tuple->next = r_tuple_prev;
r_tuple->name = r_name;
r_tuple->family = a->family;
- r_tuple->scopeid = a->ifindex;
+ r_tuple->scopeid = a->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&a->address.in6) ? a->ifindex : 0;
memcpy(r_tuple->addr, &a->address, 16);
idx += ALIGN(sizeof(struct gaih_addrtuple));
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
index d46a3afe91..ce8d59d390 100644
--- a/src/nss-resolve/nss-resolve.c
+++ b/src/nss-resolve/nss-resolve.c
@@ -110,6 +110,20 @@ static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
return c;
}
+static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
+ struct in6_addr in6;
+
+ if (family != AF_INET6)
+ return 0;
+
+ /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */
+
+ assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET));
+ memcpy(&in6, a, sizeof(struct in6_addr));
+
+ return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0;
+}
+
enum nss_status _nss_resolve_gethostbyname4_r(
const char *name,
struct gaih_addrtuple **pat,
@@ -245,7 +259,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
r_tuple->next = i == c-1 ? NULL : (struct gaih_addrtuple*) ((char*) r_tuple + ALIGN(sizeof(struct gaih_addrtuple)));
r_tuple->name = r_name;
r_tuple->family = family;
- r_tuple->scopeid = ifindex;
+ r_tuple->scopeid = ifindex_to_scopeid(family, a, ifindex);
memcpy(r_tuple->addr, a, sz);
idx += ALIGN(sizeof(struct gaih_addrtuple));
diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c
index 07d9582ccb..3cec36817a 100644
--- a/src/resolve/resolve-tool.c
+++ b/src/resolve/resolve-tool.c
@@ -1186,6 +1186,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empt
{}
};
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *ifi = NULL, *p = NULL;
char ifname[IF_NAMESIZE] = "";
char **i;
@@ -1213,9 +1214,10 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empt
"org.freedesktop.resolve1",
p,
property_map,
+ &error,
&link_info);
if (r < 0) {
- log_error_errno(r, "Failed to get link data for %i: %m", ifindex);
+ log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r));
goto finish;
}
@@ -1405,6 +1407,7 @@ static int status_global(sd_bus *bus, bool *empty_line) {
{}
};
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char **i;
int r;
@@ -1415,9 +1418,10 @@ static int status_global(sd_bus *bus, bool *empty_line) {
"org.freedesktop.resolve1",
"/org/freedesktop/resolve1",
property_map,
+ &error,
&global_info);
if (r < 0) {
- log_error_errno(r, "Failed to get global data: %m");
+ log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r));
goto finish;
}
@@ -1524,7 +1528,7 @@ static int status_all(sd_bus *bus) {
static void help_protocol_types(void) {
if (arg_legend)
puts("Known protocol types:");
- puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6");
+ puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6\nmdns\nmnds-ipv4\nmdns-ipv6");
}
static void help_dns_types(void) {
@@ -1722,6 +1726,12 @@ static int parse_argv(int argc, char *argv[]) {
arg_flags |= SD_RESOLVED_LLMNR_IPV4;
else if (streq(optarg, "llmnr-ipv6"))
arg_flags |= SD_RESOLVED_LLMNR_IPV6;
+ else if (streq(optarg, "mdns"))
+ arg_flags |= SD_RESOLVED_MDNS;
+ else if (streq(optarg, "mdns-ipv4"))
+ arg_flags |= SD_RESOLVED_MDNS_IPV4;
+ else if (streq(optarg, "mdns-ipv6"))
+ arg_flags |= SD_RESOLVED_MDNS_IPV6;
else {
log_error("Unknown protocol specifier: %s", optarg);
return -EINVAL;
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 2ca65e6953..2c50109388 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -211,7 +211,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
r = sd_bus_message_append(
reply, "st",
normalized,
- SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
+ SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)));
if (r < 0)
goto finish;
@@ -439,7 +439,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
if (r < 0)
goto finish;
- r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
+ r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)));
if (r < 0)
goto finish;
@@ -605,7 +605,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
if (r < 0)
goto finish;
- r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
+ r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)));
if (r < 0)
goto finish;
@@ -979,7 +979,7 @@ static void resolve_service_all_complete(DnsQuery *q) {
reply,
"ssst",
name, type, domain,
- SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
+ SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)));
if (r < 0)
goto finish;
diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h
index 4a92bd1150..11d2e25eeb 100644
--- a/src/resolve/resolved-dns-answer.h
+++ b/src/resolve/resolved-dns-answer.h
@@ -33,9 +33,11 @@ typedef struct DnsAnswerItem DnsAnswerItem;
* Note that we usually encode the empty DnsAnswer object as a simple NULL. */
typedef enum DnsAnswerFlags {
- DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */
- DNS_ANSWER_CACHEABLE = 2, /* Item is subject to caching */
- DNS_ANSWER_SHARED_OWNER = 4, /* For mDNS: RRset may be owner by multiple peers */
+ DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */
+ DNS_ANSWER_CACHEABLE = 2, /* Item is subject to caching */
+ DNS_ANSWER_SHARED_OWNER = 4, /* For mDNS: RRset may be owner by multiple peers */
+ DNS_ANSWER_CACHE_FLUSH = 8, /* For mDNS: sets cache-flush bit in the rrclass of response records */
+ DNS_ANSWER_GOODBYE = 16, /* For mDNS: item is subject to disappear */
} DnsAnswerFlags;
struct DnsAnswerItem {
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index 9233fb0ac1..c43a7865dc 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/resolved-dns-cache.c
@@ -980,7 +980,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
if (!j->shared_owner)
continue;
- r = dns_packet_append_rr(p, j->rr, NULL, NULL);
+ r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL);
if (r == -EMSGSIZE && p->protocol == DNS_PROTOCOL_MDNS) {
/* For mDNS, if we're unable to stuff all known answers into the given packet,
* allocate a new one, push the RR into that one and link it to the current one.
@@ -995,7 +995,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
/* continue with new packet */
p = p->more;
- r = dns_packet_append_rr(p, j->rr, NULL, NULL);
+ r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL);
}
if (r < 0)
diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 337a8c473f..652970284e 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -569,8 +569,9 @@ fail:
return r;
}
-int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
+int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, const DnsAnswerFlags flags, size_t *start) {
size_t saved_size;
+ uint16_t class;
int r;
assert(p);
@@ -586,7 +587,8 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start)
if (r < 0)
goto fail;
- r = dns_packet_append_uint16(p, k->class, NULL);
+ class = flags & DNS_ANSWER_CACHE_FLUSH ? k->class | MDNS_RR_CACHE_FLUSH : k->class;
+ r = dns_packet_append_uint16(p, class, NULL);
if (r < 0)
goto fail;
@@ -791,9 +793,10 @@ int dns_packet_truncate_opt(DnsPacket *p) {
return 1;
}
-int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start) {
+int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start) {
size_t saved_size, rdlength_offset, end, rdlength, rds;
+ uint32_t ttl;
int r;
assert(p);
@@ -801,11 +804,12 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
saved_size = p->size;
- r = dns_packet_append_key(p, rr->key, NULL);
+ r = dns_packet_append_key(p, rr->key, flags, NULL);
if (r < 0)
goto fail;
- r = dns_packet_append_uint32(p, rr->ttl, NULL);
+ ttl = flags & DNS_ANSWER_GOODBYE ? 0 : rr->ttl;
+ r = dns_packet_append_uint32(p, ttl, NULL);
if (r < 0)
goto fail;
@@ -1143,7 +1147,7 @@ int dns_packet_append_question(DnsPacket *p, DnsQuestion *q) {
assert(p);
DNS_QUESTION_FOREACH(key, q) {
- r = dns_packet_append_key(p, key, NULL);
+ r = dns_packet_append_key(p, key, 0, NULL);
if (r < 0)
return r;
}
@@ -1153,12 +1157,13 @@ int dns_packet_append_question(DnsPacket *p, DnsQuestion *q) {
int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a) {
DnsResourceRecord *rr;
+ DnsAnswerFlags flags;
int r;
assert(p);
- DNS_ANSWER_FOREACH(rr, a) {
- r = dns_packet_append_rr(p, rr, NULL, NULL);
+ DNS_ANSWER_FOREACH_FLAGS(rr, flags, a) {
+ r = dns_packet_append_rr(p, rr, flags, NULL, NULL);
if (r < 0)
return r;
}
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index 054dc88a85..2c92392e4d 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -209,8 +209,8 @@ int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start);
int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start);
int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, bool canonical_candidate, size_t *start);
int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start);
-int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start);
-int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start);
+int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, const DnsAnswerFlags flags, size_t *start);
+int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start);
int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, int rcode, size_t *start);
int dns_packet_append_question(DnsPacket *p, DnsQuestion *q);
int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a);
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index e03db4d003..c58845c3b6 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -403,6 +403,7 @@ DnsQuery *dns_query_free(DnsQuery *q) {
sd_bus_track_unref(q->bus_track);
dns_packet_unref(q->request_dns_packet);
+ dns_packet_unref(q->reply_dns_packet);
if (q->request_dns_stream) {
/* Detach the stream from our query, in case something else keeps a reference to it. */
@@ -1028,6 +1029,9 @@ int dns_query_process_cname(DnsQuery *q) {
if (q->flags & SD_RESOLVED_NO_CNAME)
return -ELOOP;
+ if (!q->answer_authenticated)
+ q->previous_redirect_unauthenticated = true;
+
/* OK, let's actually follow the CNAME */
r = dns_query_cname_redirect(q, cname);
if (r < 0)
@@ -1115,3 +1119,9 @@ const char *dns_query_string(DnsQuery *q) {
return dns_question_first_name(q->question_idna);
}
+
+bool dns_query_fully_authenticated(DnsQuery *q) {
+ assert(q);
+
+ return q->answer_authenticated && !q->previous_redirect_unauthenticated;
+}
diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h
index 49a35b846b..b8ea48f6af 100644
--- a/src/resolve/resolved-dns-query.h
+++ b/src/resolve/resolved-dns-query.h
@@ -71,7 +71,6 @@ struct DnsQuery {
* family */
bool suppress_unroutable_family;
-
/* If true, the RR TTLs of the answer will be clamped by their current left validity in the cache */
bool clamp_ttl;
@@ -90,6 +89,7 @@ struct DnsQuery {
int answer_family;
DnsSearchDomain *answer_search_domain;
int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */
+ bool previous_redirect_unauthenticated;
/* Bus client information */
sd_bus_message *request;
@@ -102,6 +102,7 @@ struct DnsQuery {
/* DNS stub information */
DnsPacket *request_dns_packet;
DnsStream *request_dns_stream;
+ DnsPacket *reply_dns_packet;
/* Completion callback */
void (*complete)(DnsQuery* q);
@@ -139,3 +140,5 @@ DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol);
const char *dns_query_string(DnsQuery *q);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuery*, dns_query_free);
+
+bool dns_query_fully_authenticated(DnsQuery *q);
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index 209d565033..e8c05ed0da 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -1262,7 +1262,7 @@ int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
if (rr->wire_format && rr->wire_format_canonical == canonical)
return 0;
- r = dns_packet_append_rr(&packet, rr, &start, &rds);
+ r = dns_packet_append_rr(&packet, rr, 0, &start, &rds);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 8dbc7f623b..750409eebf 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -124,6 +124,8 @@ DnsScope* dns_scope_free(DnsScope *s) {
ordered_hashmap_free(s->conflict_queue);
sd_event_source_unref(s->conflict_event_source);
+ sd_event_source_unref(s->announce_event_source);
+
dns_cache_flush(&s->cache);
dns_zone_flush(&s->zone);
@@ -549,7 +551,11 @@ static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in
.imr_ifindex = s->link->ifindex,
};
- fd = manager_llmnr_ipv4_udp_fd(s->manager);
+ if (s->protocol == DNS_PROTOCOL_LLMNR)
+ fd = manager_llmnr_ipv4_udp_fd(s->manager);
+ else
+ fd = manager_mdns_ipv4_fd(s->manager);
+
if (fd < 0)
return fd;
@@ -568,7 +574,11 @@ static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in
.ipv6mr_interface = s->link->ifindex,
};
- fd = manager_llmnr_ipv6_udp_fd(s->manager);
+ if (s->protocol == DNS_PROTOCOL_LLMNR)
+ fd = manager_llmnr_ipv6_udp_fd(s->manager);
+ else
+ fd = manager_mdns_ipv6_fd(s->manager);
+
if (fd < 0)
return fd;
@@ -601,7 +611,7 @@ int dns_scope_mdns_membership(DnsScope *s, bool b) {
return dns_scope_multicast_membership(s, b, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS);
}
-static int dns_scope_make_reply_packet(
+int dns_scope_make_reply_packet(
DnsScope *s,
uint16_t id,
int rcode,
@@ -783,8 +793,15 @@ DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key,
/* Try to find an ongoing transaction that is a equal to the
* specified question */
t = hashmap_get(scope->transactions_by_key, key);
- if (!t)
- return NULL;
+ if (!t) {
+ DnsResourceKey *key_any;
+
+ key_any = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_ANY, dns_resource_key_name(key));
+ t = hashmap_get(scope->transactions_by_key, key_any);
+ key_any = dns_resource_key_unref(key_any);
+ if (!t)
+ return NULL;
+ }
/* Refuse reusing transactions that completed based on cached
* data instead of a real packet, if that's requested. */
@@ -830,11 +847,11 @@ static int dns_scope_make_conflict_packet(
DNS_PACKET_HEADER(p)->qdcount = htobe16(1);
DNS_PACKET_HEADER(p)->arcount = htobe16(1);
- r = dns_packet_append_key(p, rr->key, NULL);
+ r = dns_packet_append_key(p, rr->key, 0, NULL);
if (r < 0)
return r;
- r = dns_packet_append_rr(p, rr, NULL, NULL);
+ r = dns_packet_append_rr(p, rr, 0, NULL, NULL);
if (r < 0)
return r;
@@ -928,17 +945,19 @@ void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) {
assert(scope);
assert(p);
- if (p->protocol != DNS_PROTOCOL_LLMNR)
+ if (!IN_SET(p->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS))
return;
if (DNS_PACKET_RRCOUNT(p) <= 0)
return;
- if (DNS_PACKET_LLMNR_C(p) != 0)
- return;
+ if (p->protocol == DNS_PROTOCOL_LLMNR) {
+ if (DNS_PACKET_LLMNR_C(p) != 0)
+ return;
- if (DNS_PACKET_LLMNR_T(p) != 0)
- return;
+ if (DNS_PACKET_LLMNR_T(p) != 0)
+ return;
+ }
if (manager_our_packet(scope->manager, p))
return;
@@ -1041,3 +1060,76 @@ int dns_scope_ifindex(DnsScope *s) {
return 0;
}
+
+static int on_announcement_timeout(sd_event_source *s, usec_t usec, void *userdata) {
+ DnsScope *scope = userdata;
+
+ assert(s);
+
+ scope->announce_event_source = sd_event_source_unref(scope->announce_event_source);
+
+ dns_scope_announce(scope, false);
+ return 0;
+}
+
+void dns_scope_announce(DnsScope *scope, bool goodbye) {
+ _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+ LinkAddress *a;
+ int r;
+
+ if (!scope)
+ return;
+
+ if (scope->protocol != DNS_PROTOCOL_MDNS)
+ return;
+
+ answer = dns_answer_new(4);
+ LIST_FOREACH(addresses, a, scope->link->addresses) {
+ r = dns_answer_add(answer, a->mdns_address_rr, 0, goodbye ? DNS_ANSWER_GOODBYE : DNS_ANSWER_CACHE_FLUSH);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to add address RR to answer: %m");
+ return;
+ }
+ r = dns_answer_add(answer, a->mdns_ptr_rr, 0, goodbye ? DNS_ANSWER_GOODBYE : DNS_ANSWER_CACHE_FLUSH);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to add PTR RR to answer: %m");
+ return;
+ }
+ }
+
+ if (dns_answer_isempty(answer))
+ return;
+
+ r = dns_scope_make_reply_packet(scope, 0, DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &p);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to build reply packet: %m");
+ return;
+ }
+ r = dns_scope_emit_udp(scope, -1, p);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to send reply packet: %m");
+ return;
+ }
+
+ /* In section 8.3 of RFC6762: "The Multicast DNS responder MUST send at least two unsolicited
+ * responses, one second apart." */
+ if (!scope->announced) {
+ usec_t ts;
+
+ scope->announced = true;
+
+ assert_se(sd_event_now(scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
+ ts += MDNS_ANNOUNCE_DELAY;
+
+ r = sd_event_add_time(
+ scope->manager->event,
+ &scope->announce_event_source,
+ clock_boottime_or_monotonic(),
+ ts,
+ MDNS_JITTER_RANGE_USEC,
+ on_announcement_timeout, scope);
+ if (r < 0)
+ log_debug_errno(r, "Failed to schedule second announcement: %m");
+ }
+}
diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h
index 01a83a76b2..360d86bc25 100644
--- a/src/resolve/resolved-dns-scope.h
+++ b/src/resolve/resolved-dns-scope.h
@@ -56,6 +56,9 @@ struct DnsScope {
OrderedHashmap *conflict_queue;
sd_event_source *conflict_event_source;
+ bool announced:1;
+ sd_event_source *announce_event_source;
+
RateLimit ratelimit;
usec_t resend_timeout;
@@ -96,6 +99,7 @@ void dns_scope_next_dns_server(DnsScope *s);
int dns_scope_llmnr_membership(DnsScope *s, bool b);
int dns_scope_mdns_membership(DnsScope *s, bool b);
+int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQuestion *q, DnsAnswer *answer, DnsAnswer *soa, bool tentative, DnsPacket **ret);
void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p);
DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, bool cache_ok);
@@ -112,3 +116,5 @@ bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name);
bool dns_scope_network_good(DnsScope *s);
int dns_scope_ifindex(DnsScope *s);
+
+void dns_scope_announce(DnsScope *scope, bool goodbye);
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 22c64e8491..10562d03ec 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -451,18 +451,22 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_EDNS0;
} else if (s->n_failed_udp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
- s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_UDP) {
+ s->possible_feature_level >= (dns_server_get_dnssec_mode(s) == DNSSEC_YES ? DNS_SERVER_FEATURE_LEVEL_LARGE : DNS_SERVER_FEATURE_LEVEL_UDP)) {
/* We lost too many UDP packets in a row, and are on a feature level of UDP or higher. If the
* packets are lost, maybe the server cannot parse them, hence downgrading sounds like a good
- * idea. We might downgrade all the way down to TCP this way. */
+ * idea. We might downgrade all the way down to TCP this way.
+ *
+ * If strict DNSSEC mode is used we won't downgrade below DO level however, as packet loss
+ * might have many reasons, a broken DNSSEC implementation being only one reason. And if the
+ * user is strict on DNSSEC, then let's assume that DNSSEC is not the fault here. */
log_debug("Lost too many UDP packets, downgrading feature level...");
s->possible_feature_level--;
} else if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
s->packet_truncated &&
- s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) {
+ s->possible_feature_level > (dns_server_get_dnssec_mode(s) == DNSSEC_YES ? DNS_SERVER_FEATURE_LEVEL_LARGE : DNS_SERVER_FEATURE_LEVEL_UDP)) {
/* We got too many TCP connection failures in a row, we had at least one truncated packet, and
* are on a feature level above UDP. By downgrading things and getting rid of DNSSEC or EDNS0
@@ -779,6 +783,15 @@ bool dns_server_address_valid(int family, const union in_addr_union *sa) {
return true;
}
+DnssecMode dns_server_get_dnssec_mode(DnsServer *s) {
+ assert(s);
+
+ if (s->link)
+ return link_get_dnssec_mode(s->link);
+
+ return manager_get_dnssec_mode(s->manager);
+}
+
static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = {
[DNS_SERVER_SYSTEM] = "system",
[DNS_SERVER_FALLBACK] = "fallback",
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index 83e288a202..406282d864 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -144,6 +144,8 @@ void manager_next_dns_server(Manager *m);
bool dns_server_address_valid(int family, const union in_addr_union *sa);
+DnssecMode dns_server_get_dnssec_mode(DnsServer *s);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref);
extern const struct hash_ops dns_server_hash_ops;
diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c
index 4a3c5f612f..7d43825960 100644
--- a/src/resolve/resolved-dns-stub.c
+++ b/src/resolve/resolved-dns-stub.c
@@ -29,49 +29,33 @@ static int manager_dns_stub_udp_fd(Manager *m);
static int manager_dns_stub_tcp_fd(Manager *m);
static int dns_stub_make_reply_packet(
- uint16_t id,
- int rcode,
+ DnsPacket **p,
DnsQuestion *q,
- DnsAnswer *answer,
- bool add_opt, /* add an OPT RR to this packet */
- bool edns0_do, /* set the EDNS0 DNSSEC OK bit */
- bool ad, /* set the DNSSEC authenticated data bit */
- DnsPacket **ret) {
+ DnsAnswer *answer) {
- _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
DnsResourceRecord *rr;
unsigned c = 0;
int r;
+ assert(p);
+
/* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence
* roundtrips aren't expensive. */
- r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
- if (r < 0)
- return r;
-
- /* If the client didn't do EDNS, clamp the rcode to 4 bit */
- if (!add_opt && rcode > 0xF)
- rcode = DNS_RCODE_SERVFAIL;
+ if (!*p) {
+ r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0);
+ if (r < 0)
+ return r;
- DNS_PACKET_HEADER(p)->id = id;
- DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
- 1 /* qr */,
- 0 /* opcode */,
- 0 /* aa */,
- 0 /* tc */,
- 1 /* rd */,
- 1 /* ra */,
- ad /* ad */,
- 0 /* cd */,
- rcode));
+ r = dns_packet_append_question(*p, q);
+ if (r < 0)
+ return r;
- r = dns_packet_append_question(p, q);
- if (r < 0)
- return r;
- DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q));
+ DNS_PACKET_HEADER(*p)->qdcount = htobe16(dns_question_size(q));
+ }
DNS_ANSWER_FOREACH(rr, answer) {
+
r = dns_question_matches_rr(q, rr, NULL);
if (r < 0)
return r;
@@ -86,13 +70,46 @@ static int dns_stub_make_reply_packet(
continue;
add:
- r = dns_packet_append_rr(p, rr, NULL, NULL);
+ r = dns_packet_append_rr(*p, rr, 0, NULL, NULL);
if (r < 0)
return r;
c++;
}
- DNS_PACKET_HEADER(p)->ancount = htobe16(c);
+
+ DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c);
+
+ return 0;
+}
+
+static int dns_stub_finish_reply_packet(
+ DnsPacket *p,
+ uint16_t id,
+ int rcode,
+ bool add_opt, /* add an OPT RR to this packet? */
+ bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */
+ bool ad) { /* set the DNSSEC authenticated data bit? */
+
+ int r;
+
+ assert(p);
+
+ /* If the client didn't do EDNS, clamp the rcode to 4 bit */
+ if (!add_opt && rcode > 0xF)
+ rcode = DNS_RCODE_SERVFAIL;
+
+ DNS_PACKET_HEADER(p)->id = id;
+
+ DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS(
+ 1 /* qr */,
+ 0 /* opcode */,
+ 0 /* aa */,
+ 0 /* tc */,
+ 1 /* rd */,
+ 1 /* ra */,
+ ad /* ad */,
+ 0 /* cd */,
+ rcode));
if (add_opt) {
r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL);
@@ -100,9 +117,6 @@ static int dns_stub_make_reply_packet(
return r;
}
- *ret = p;
- p = NULL;
-
return 0;
}
@@ -155,7 +169,11 @@ static int dns_stub_send_failure(Manager *m, DnsStream *s, DnsPacket *p, int rco
assert(m);
assert(p);
- r = dns_stub_make_reply_packet(DNS_PACKET_ID(p), rcode, p->question, NULL, !!p->opt, DNS_PACKET_DO(p), false, &reply);
+ r = dns_stub_make_reply_packet(&reply, p->question, NULL);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to make failure packet: %m");
+
+ r = dns_stub_finish_reply_packet(reply, DNS_PACKET_ID(p), rcode, !!p->opt, DNS_PACKET_DO(p), false);
if (r < 0)
return log_debug_errno(r, "Failed to build failure packet: %m");
@@ -170,26 +188,40 @@ static void dns_stub_query_complete(DnsQuery *q) {
switch (q->state) {
- case DNS_TRANSACTION_SUCCESS: {
- _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
+ case DNS_TRANSACTION_SUCCESS:
+
+ r = dns_stub_make_reply_packet(&q->reply_dns_packet, q->question_idna, q->answer);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to build reply packet: %m");
+ break;
+ }
+
+ r = dns_query_process_cname(q);
+ if (r == -ELOOP) {
+ (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL);
+ break;
+ }
+ if (r < 0) {
+ log_debug_errno(r, "Failed to process CNAME: %m");
+ break;
+ }
+ if (r == DNS_QUERY_RESTARTED)
+ return;
- r = dns_stub_make_reply_packet(
+ r = dns_stub_finish_reply_packet(
+ q->reply_dns_packet,
DNS_PACKET_ID(q->request_dns_packet),
q->answer_rcode,
- q->question_idna,
- q->answer,
!!q->request_dns_packet->opt,
DNS_PACKET_DO(q->request_dns_packet),
- DNS_PACKET_DO(q->request_dns_packet) && q->answer_authenticated,
- &reply);
+ DNS_PACKET_DO(q->request_dns_packet) && dns_query_fully_authenticated(q));
if (r < 0) {
- log_debug_errno(r, "Failed to build reply packet: %m");
+ log_debug_errno(r, "Failed to finish reply packet: %m");
break;
}
- (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, reply);
+ (void) dns_stub_send(q->manager, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet);
break;
- }
case DNS_TRANSACTION_RCODE_FAILURE:
(void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, q->answer_rcode);
@@ -301,7 +333,7 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
goto fail;
}
- r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH|SD_RESOLVED_NO_CNAME);
+ r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH);
if (r < 0) {
log_error_errno(r, "Failed to generate query object: %m");
dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 2fce44ec8b..0c7a8867fb 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -363,6 +363,8 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items)
dns_zone_item_notify(z);
SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done);
+ if (t->probing)
+ dns_scope_announce(t->scope, false);
SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions)
dns_transaction_notify(d, t);
@@ -924,7 +926,16 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
dns_transaction_retry(t, false /* use the same server */);
return;
- } else if (DNS_PACKET_TC(p))
+ }
+
+ if (DNS_PACKET_RCODE(p) == DNS_RCODE_REFUSED) {
+ /* This server refused our request? If so, try again, use a different server */
+ log_debug("Server returned REFUSED, switching servers, and retrying.");
+ dns_transaction_retry(t, true /* pick a new server */);
+ return;
+ }
+
+ if (DNS_PACKET_TC(p))
dns_server_packet_truncated(t->server, t->current_feature_level);
break;
@@ -1003,15 +1014,20 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
if (r > 0) /* Transaction got restarted... */
return;
- if (IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR)) {
+ if (IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) {
- /* Only consider responses with equivalent query section to the request */
- r = dns_packet_is_reply_for(p, t->key);
- if (r < 0)
- goto fail;
- if (r == 0) {
- dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
- return;
+ /* When dealing with protocols other than mDNS only consider responses with
+ * equivalent query section to the request. For mDNS this check doesn't make
+ * sense, because the section 6 of RFC6762 states that "Multicast DNS responses MUST NOT
+ * contain any questions in the Question Section". */
+ if (t->scope->protocol != DNS_PROTOCOL_MDNS) {
+ r = dns_packet_is_reply_for(p, t->key);
+ if (r < 0)
+ goto fail;
+ if (r == 0) {
+ dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);
+ return;
+ }
}
/* Install the answer as answer to the transaction */
@@ -1204,7 +1220,10 @@ static usec_t transaction_get_resend_timeout(DnsTransaction *t) {
case DNS_PROTOCOL_MDNS:
assert(t->n_attempts > 0);
- return (1 << (t->n_attempts - 1)) * USEC_PER_SEC;
+ if (t->probing)
+ return MDNS_PROBING_INTERVAL_USEC;
+ else
+ return (1 << (t->n_attempts - 1)) * USEC_PER_SEC;
case DNS_PROTOCOL_LLMNR:
return t->scope->resend_timeout;
@@ -1358,7 +1377,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
if (r < 0)
return r;
- r = dns_packet_append_key(p, t->key, NULL);
+ r = dns_packet_append_key(p, t->key, 0, NULL);
if (r < 0)
return r;
@@ -1390,7 +1409,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
if (qdcount >= UINT16_MAX)
break;
- r = dns_packet_append_key(p, other->key, NULL);
+ r = dns_packet_append_key(p, other->key, 0, NULL);
/*
* If we can't stuff more questions into the packet, just give up.
@@ -1417,7 +1436,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
if (r < 0)
return r;
- (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout");
+ (void) sd_event_source_set_description(other->timeout_event_source, "dns-transaction-timeout");
other->state = DNS_TRANSACTION_PENDING;
other->next_attempt_after = ts;
@@ -1459,7 +1478,7 @@ static int dns_transaction_make_packet(DnsTransaction *t) {
if (r < 0)
return r;
- r = dns_packet_append_key(p, t->key, NULL);
+ r = dns_packet_append_key(p, t->key, 0, NULL);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h
index 5a1df70422..c4fb51958d 100644
--- a/src/resolve/resolved-dns-transaction.h
+++ b/src/resolve/resolved-dns-transaction.h
@@ -78,6 +78,8 @@ struct DnsTransaction {
bool clamp_ttl:1;
+ bool probing:1;
+
DnsPacket *sent, *received;
DnsAnswer *answer;
@@ -172,10 +174,20 @@ DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_;
#define MDNS_JITTER_MIN_USEC (20 * USEC_PER_MSEC)
#define MDNS_JITTER_RANGE_USEC (100 * USEC_PER_MSEC)
+/* mDNS probing interval, see RFC 6762 Section 8.1 */
+#define MDNS_PROBING_INTERVAL_USEC (250 * USEC_PER_MSEC)
+
/* Maximum attempts to send DNS requests, across all DNS servers */
#define DNS_TRANSACTION_ATTEMPTS_MAX 16
/* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */
#define LLMNR_TRANSACTION_ATTEMPTS_MAX 3
-#define TRANSACTION_ATTEMPTS_MAX(p) ((p) == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_ATTEMPTS_MAX : DNS_TRANSACTION_ATTEMPTS_MAX)
+/* Maximum attempts to send MDNS requests, see RFC 6762 Section 8.1 */
+#define MDNS_TRANSACTION_ATTEMPTS_MAX 3
+
+#define TRANSACTION_ATTEMPTS_MAX(p) (((p) == DNS_PROTOCOL_LLMNR) ? \
+ LLMNR_TRANSACTION_ATTEMPTS_MAX : \
+ (((p) == DNS_PROTOCOL_MDNS) ? \
+ MDNS_TRANSACTION_ATTEMPTS_MAX : \
+ DNS_TRANSACTION_ATTEMPTS_MAX))
diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c
index 746a979f47..ad024b54f5 100644
--- a/src/resolve/resolved-dns-zone.c
+++ b/src/resolve/resolved-dns-zone.c
@@ -196,6 +196,7 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) {
goto gc;
i->probe_transaction = t;
+ t->probing = true;
if (t->state == DNS_TRANSACTION_NULL) {
diff --git a/src/resolve/resolved-dns-zone.h b/src/resolve/resolved-dns-zone.h
index a41df37e6b..545ec958fb 100644
--- a/src/resolve/resolved-dns-zone.h
+++ b/src/resolve/resolved-dns-zone.h
@@ -37,6 +37,9 @@ typedef enum DnsZoneItemState DnsZoneItemState;
/* RFC 4795 Section 2.8. suggests a TTL of 30s by default */
#define LLMNR_DEFAULT_TTL (30)
+/* RFC 6762 Section 10. suggests a TTL of 120s by default */
+#define MDNS_DEFAULT_TTL (120)
+
enum DnsZoneItemState {
DNS_ZONE_ITEM_PROBING,
DNS_ZONE_ITEM_ESTABLISHED,
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index e7e5c5f5a7..7b6e4f8398 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -85,6 +85,10 @@ Link *link_free(Link *l) {
if (!l)
return NULL;
+ /* Send goodbye messages. */
+ dns_scope_announce(l->mdns_ipv4_scope, true);
+ dns_scope_announce(l->mdns_ipv6_scope, true);
+
link_flush_settings(l);
while (l->addresses)
@@ -692,10 +696,26 @@ LinkAddress *link_address_free(LinkAddress *a) {
else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
}
+
+ if (a->mdns_address_rr) {
+ if (a->family == AF_INET && a->link->mdns_ipv4_scope)
+ dns_zone_remove_rr(&a->link->mdns_ipv4_scope->zone, a->mdns_address_rr);
+ else if (a->family == AF_INET6 && a->link->mdns_ipv6_scope)
+ dns_zone_remove_rr(&a->link->mdns_ipv6_scope->zone, a->mdns_address_rr);
+ }
+
+ if (a->mdns_ptr_rr) {
+ if (a->family == AF_INET && a->link->mdns_ipv4_scope)
+ dns_zone_remove_rr(&a->link->mdns_ipv4_scope->zone, a->mdns_ptr_rr);
+ else if (a->family == AF_INET6 && a->link->mdns_ipv6_scope)
+ dns_zone_remove_rr(&a->link->mdns_ipv6_scope->zone, a->mdns_ptr_rr);
+ }
}
dns_resource_record_unref(a->llmnr_address_rr);
dns_resource_record_unref(a->llmnr_ptr_rr);
+ dns_resource_record_unref(a->mdns_address_rr);
+ dns_resource_record_unref(a->mdns_ptr_rr);
return mfree(a);
}
@@ -746,7 +766,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
if (r < 0)
- log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
+ log_warning_errno(r, "Failed to add IPv4 PTR record to LLMNR zone: %m");
} else {
if (a->llmnr_address_rr) {
if (a->link->llmnr_ipv4_scope)
@@ -760,6 +780,59 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
}
}
+
+ if (!force_remove &&
+ link_address_relevant(a, true) &&
+ a->link->mdns_ipv4_scope &&
+ a->link->mdns_support == RESOLVE_SUPPORT_YES &&
+ a->link->manager->mdns_support == RESOLVE_SUPPORT_YES) {
+ if (!a->link->manager->mdns_host_ipv4_key) {
+ a->link->manager->mdns_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->mdns_hostname);
+ if (!a->link->manager->mdns_host_ipv4_key) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ if (!a->mdns_address_rr) {
+ a->mdns_address_rr = dns_resource_record_new(a->link->manager->mdns_host_ipv4_key);
+ if (!a->mdns_address_rr) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ a->mdns_address_rr->a.in_addr = a->in_addr.in;
+ a->mdns_address_rr->ttl = MDNS_DEFAULT_TTL;
+ }
+
+ if (!a->mdns_ptr_rr) {
+ r = dns_resource_record_new_reverse(&a->mdns_ptr_rr, a->family, &a->in_addr, a->link->manager->mdns_hostname);
+ if (r < 0)
+ goto fail;
+
+ a->mdns_ptr_rr->ttl = MDNS_DEFAULT_TTL;
+ }
+
+ r = dns_zone_put(&a->link->mdns_ipv4_scope->zone, a->link->mdns_ipv4_scope, a->mdns_address_rr, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to add A record to MDNS zone: %m");
+
+ r = dns_zone_put(&a->link->mdns_ipv4_scope->zone, a->link->mdns_ipv4_scope, a->mdns_ptr_rr, false);
+ if (r < 0)
+ log_warning_errno(r, "Failed to add IPv4 PTR record to MDNS zone: %m");
+ } else {
+ if (a->mdns_address_rr) {
+ if (a->link->mdns_ipv4_scope)
+ dns_zone_remove_rr(&a->link->mdns_ipv4_scope->zone, a->mdns_address_rr);
+ a->mdns_address_rr = dns_resource_record_unref(a->mdns_address_rr);
+ }
+
+ if (a->mdns_ptr_rr) {
+ if (a->link->mdns_ipv4_scope)
+ dns_zone_remove_rr(&a->link->mdns_ipv4_scope->zone, a->mdns_ptr_rr);
+ a->mdns_ptr_rr = dns_resource_record_unref(a->mdns_ptr_rr);
+ }
+ }
}
if (a->family == AF_INET6) {
@@ -817,6 +890,60 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
}
}
+
+ if (!force_remove &&
+ link_address_relevant(a, true) &&
+ a->link->mdns_ipv6_scope &&
+ a->link->mdns_support == RESOLVE_SUPPORT_YES &&
+ a->link->manager->mdns_support == RESOLVE_SUPPORT_YES) {
+
+ if (!a->link->manager->mdns_host_ipv6_key) {
+ a->link->manager->mdns_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->mdns_hostname);
+ if (!a->link->manager->mdns_host_ipv6_key) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ if (!a->mdns_address_rr) {
+ a->mdns_address_rr = dns_resource_record_new(a->link->manager->mdns_host_ipv6_key);
+ if (!a->mdns_address_rr) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
+ a->mdns_address_rr->aaaa.in6_addr = a->in_addr.in6;
+ a->mdns_address_rr->ttl = MDNS_DEFAULT_TTL;
+ }
+
+ if (!a->mdns_ptr_rr) {
+ r = dns_resource_record_new_reverse(&a->mdns_ptr_rr, a->family, &a->in_addr, a->link->manager->mdns_hostname);
+ if (r < 0)
+ goto fail;
+
+ a->mdns_ptr_rr->ttl = MDNS_DEFAULT_TTL;
+ }
+
+ r = dns_zone_put(&a->link->mdns_ipv6_scope->zone, a->link->mdns_ipv6_scope, a->mdns_address_rr, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to add AAAA record to MDNS zone: %m");
+
+ r = dns_zone_put(&a->link->mdns_ipv6_scope->zone, a->link->mdns_ipv6_scope, a->mdns_ptr_rr, false);
+ if (r < 0)
+ log_warning_errno(r, "Failed to add IPv6 PTR record to MDNS zone: %m");
+ } else {
+ if (a->mdns_address_rr) {
+ if (a->link->mdns_ipv6_scope)
+ dns_zone_remove_rr(&a->link->mdns_ipv6_scope->zone, a->mdns_address_rr);
+ a->mdns_address_rr = dns_resource_record_unref(a->mdns_address_rr);
+ }
+
+ if (a->mdns_ptr_rr) {
+ if (a->link->mdns_ipv6_scope)
+ dns_zone_remove_rr(&a->link->mdns_ipv6_scope->zone, a->mdns_ptr_rr);
+ a->mdns_ptr_rr = dns_resource_record_unref(a->mdns_ptr_rr);
+ }
+ }
}
return;
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index c9b2a58c34..1e9be8ae84 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -47,6 +47,8 @@ struct LinkAddress {
DnsResourceRecord *llmnr_address_rr;
DnsResourceRecord *llmnr_ptr_rr;
+ DnsResourceRecord *mdns_address_rr;
+ DnsResourceRecord *mdns_ptr_rr;
LIST_FIELDS(LinkAddress, addresses);
};
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 667774b906..791c125613 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -322,12 +322,13 @@ static int manager_network_monitor_listen(Manager *m) {
return 0;
}
-static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
+static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
_cleanup_free_ char *h = NULL, *n = NULL;
char label[DNS_LABEL_MAX];
const char *p;
int r, k;
+ assert(full_hostname);
assert(llmnr_hostname);
assert(mdns_hostname);
@@ -374,32 +375,33 @@ static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
*llmnr_hostname = n;
n = NULL;
+ *full_hostname = h;
+ h = NULL;
+
return 0;
}
static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
- _cleanup_free_ char *llmnr_hostname = NULL, *mdns_hostname = NULL;
+ _cleanup_free_ char *full_hostname = NULL, *llmnr_hostname = NULL, *mdns_hostname = NULL;
Manager *m = userdata;
int r;
assert(m);
- r = determine_hostname(&llmnr_hostname, &mdns_hostname);
+ r = determine_hostname(&full_hostname, &llmnr_hostname, &mdns_hostname);
if (r < 0)
return 0; /* ignore invalid hostnames */
- if (streq(llmnr_hostname, m->llmnr_hostname) && streq(mdns_hostname, m->mdns_hostname))
+ if (streq(full_hostname, m->full_hostname) &&
+ streq(llmnr_hostname, m->llmnr_hostname) &&
+ streq(mdns_hostname, m->mdns_hostname))
return 0;
- log_info("System hostname changed to '%s'.", llmnr_hostname);
-
- free(m->llmnr_hostname);
- free(m->mdns_hostname);
+ log_info("System hostname changed to '%s'.", full_hostname);
- m->llmnr_hostname = llmnr_hostname;
- m->mdns_hostname = mdns_hostname;
-
- llmnr_hostname = mdns_hostname = NULL;
+ free_and_replace(m->full_hostname, full_hostname);
+ free_and_replace(m->llmnr_hostname, llmnr_hostname);
+ free_and_replace(m->mdns_hostname, mdns_hostname);
manager_refresh_rrs(m);
@@ -428,9 +430,14 @@ static int manager_watch_hostname(Manager *m) {
(void) sd_event_source_set_description(m->hostname_event_source, "hostname");
- r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname);
+ r = determine_hostname(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname);
if (r < 0) {
log_info("Defaulting to hostname 'linux'.");
+
+ m->full_hostname = strdup("linux");
+ if (!m->full_hostname)
+ return log_oom();
+
m->llmnr_hostname = strdup("linux");
if (!m->llmnr_hostname)
return log_oom();
@@ -439,7 +446,7 @@ static int manager_watch_hostname(Manager *m) {
if (!m->mdns_hostname)
return log_oom();
} else
- log_info("Using system hostname '%s'.", m->llmnr_hostname);
+ log_info("Using system hostname '%s'.", m->full_hostname);
return 0;
}
@@ -498,7 +505,7 @@ int manager_new(Manager **ret) {
m->hostname_fd = -1;
m->llmnr_support = RESOLVE_SUPPORT_YES;
- m->mdns_support = RESOLVE_SUPPORT_NO;
+ m->mdns_support = RESOLVE_SUPPORT_YES;
m->dnssec_mode = DEFAULT_DNSSEC_MODE;
m->enable_cache = true;
m->dns_stub_listener_mode = DNS_STUB_LISTENER_UDP;
@@ -621,9 +628,13 @@ Manager *manager_free(Manager *m) {
dns_resource_key_unref(m->llmnr_host_ipv4_key);
dns_resource_key_unref(m->llmnr_host_ipv6_key);
+ dns_resource_key_unref(m->mdns_host_ipv4_key);
+ dns_resource_key_unref(m->mdns_host_ipv6_key);
sd_event_source_unref(m->hostname_event_source);
safe_close(m->hostname_fd);
+
+ free(m->full_hostname);
free(m->llmnr_hostname);
free(m->mdns_hostname);
@@ -1007,6 +1018,8 @@ void manager_refresh_rrs(Manager *m) {
m->llmnr_host_ipv4_key = dns_resource_key_unref(m->llmnr_host_ipv4_key);
m->llmnr_host_ipv6_key = dns_resource_key_unref(m->llmnr_host_ipv6_key);
+ m->mdns_host_ipv4_key = dns_resource_key_unref(m->mdns_host_ipv4_key);
+ m->mdns_host_ipv6_key = dns_resource_key_unref(m->mdns_host_ipv6_key);
HASHMAP_FOREACH(l, m->links, i) {
link_add_rrs(l, true);
@@ -1146,8 +1159,14 @@ int manager_is_own_hostname(Manager *m, const char *name) {
return r;
}
- if (m->mdns_hostname)
- return dns_name_equal(name, m->mdns_hostname);
+ if (m->mdns_hostname) {
+ r = dns_name_equal(name, m->mdns_hostname);
+ if (r != 0)
+ return r;
+ }
+
+ if (m->full_hostname)
+ return dns_name_equal(name, m->full_hostname);
return 0;
}
diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h
index 6b2208ed94..97c52b7729 100644
--- a/src/resolve/resolved-manager.h
+++ b/src/resolve/resolved-manager.h
@@ -109,10 +109,13 @@ struct Manager {
sd_event_source *bus_retry_event_source;
/* The hostname we publish on LLMNR and mDNS */
+ char *full_hostname;
char *llmnr_hostname;
char *mdns_hostname;
DnsResourceKey *llmnr_host_ipv4_key;
DnsResourceKey *llmnr_host_ipv6_key;
+ DnsResourceKey *mdns_host_ipv4_key;
+ DnsResourceKey *mdns_host_ipv6_key;
/* Watch the system hostname */
int hostname_fd;
diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c
index b13b1d0144..f5cae6f682 100644
--- a/src/resolve/resolved-mdns.c
+++ b/src/resolve/resolved-mdns.c
@@ -67,6 +67,52 @@ eaddrinuse:
return 0;
}
+static int mdns_scope_process_query(DnsScope *s, DnsPacket *p) {
+ _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
+ _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL;
+ DnsResourceKey *key = NULL;
+ bool tentative = false;
+ int r;
+
+ assert(s);
+ assert(p);
+
+ r = dns_packet_extract(p);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to extract resource records from incoming packet: %m");
+ return r;
+ }
+
+ /* TODO: there might be more than one question in mDNS queries. */
+ assert_return((dns_question_size(p->question) > 0), -EINVAL);
+ key = p->question->keys[0];
+
+ r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to lookup key: %m");
+ return r;
+ }
+ if (r == 0)
+ return 0;
+
+ r = dns_scope_make_reply_packet(s, DNS_PACKET_ID(p), DNS_RCODE_SUCCESS, NULL, answer, NULL, false, &reply);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to build reply packet: %m");
+ return r;
+ }
+
+ if (!ratelimit_test(&s->ratelimit))
+ return 0;
+
+ r = dns_scope_emit_udp(s, -1, reply);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to send reply packet: %m");
+ return r;
+ }
+
+ return 0;
+}
+
static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
Manager *m = userdata;
@@ -77,6 +123,9 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
if (r <= 0)
return r;
+ if (manager_our_packet(m, p))
+ return 0;
+
scope = manager_find_scope(m, p);
if (!scope) {
log_warning("Got mDNS UDP packet on unknown scope. Ignoring.");
@@ -115,6 +164,12 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
dns_name_endswith(name, "local") > 0))
return 0;
+ if (rr->ttl == 0) {
+ log_debug("Got a goodbye packet");
+ /* See the section 10.1 of RFC6762 */
+ rr->ttl = 1;
+ }
+
t = dns_scope_find_transaction(scope, rr->key, false);
if (t)
dns_transaction_process_reply(t, p);
@@ -125,7 +180,11 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
} else if (dns_packet_validate_query(p) > 0) {
log_debug("Got mDNS query packet for id %u", DNS_PACKET_ID(p));
- dns_scope_process_query(scope, NULL, p);
+ r = mdns_scope_process_query(scope, p);
+ if (r < 0) {
+ log_debug("mDNS query processing failed.");
+ return 0;
+ }
} else
log_debug("Invalid mDNS UDP packet.");
diff --git a/src/resolve/resolved-mdns.h b/src/resolve/resolved-mdns.h
index 5d274648f4..06bd3296be 100644
--- a/src/resolve/resolved-mdns.h
+++ b/src/resolve/resolved-mdns.h
@@ -22,6 +22,7 @@
#include "resolved-manager.h"
#define MDNS_PORT 5353
+#define MDNS_ANNOUNCE_DELAY (1 * USEC_PER_SEC)
int manager_mdns_ipv4_fd(Manager *m);
int manager_mdns_ipv6_fd(Manager *m);
diff --git a/src/run/run.c b/src/run/run.c
index 08f7e12336..f8257abc93 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -818,16 +818,18 @@ static int run_context_update(RunContext *c, const char *path) {
{}
};
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
r = bus_map_all_properties(c->bus,
"org.freedesktop.systemd1",
path,
map,
+ &error,
c);
if (r < 0) {
sd_event_exit(c->event, EXIT_FAILURE);
- return log_error_errno(r, "Failed to query unit state: %m");
+ return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r));
}
run_context_check_done(c);
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 20c1085697..4ca614f647 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -554,7 +554,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
} else if (streq(field, "RestrictNamespaces")) {
bool invert = false;
- uint64_t flags = 0;
+ unsigned long flags = 0;
if (eq[0] == '~') {
invert = true;
@@ -575,7 +575,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (invert)
flags = (~flags) & NAMESPACE_FLAGS_ALL;
- r = sd_bus_message_append(m, "v", "t", flags);
+ r = sd_bus_message_append(m, "v", "t", (uint64_t) flags);
} else if ((dep = unit_dependency_from_string(field)) >= 0)
r = sd_bus_message_append(m, "v", "as", 1, eq);
else if (streq(field, "MountFlags")) {
@@ -585,7 +585,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (r < 0)
return log_error_errno(r, "Failed to parse mount propagation flags: %s", eq);
- r = sd_bus_message_append(m, "v", "t", f);
+ r = sd_bus_message_append(m, "v", "t", (uint64_t) f);
} else if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) {
const char *p = eq;
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 6aebe18fc0..8ddfb584ea 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -1116,9 +1116,9 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
int bus_message_map_all_properties(
sd_bus_message *m,
const struct bus_properties_map *map,
+ sd_bus_error *error,
void *userdata) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(m);
@@ -1156,9 +1156,9 @@ int bus_message_map_all_properties(
v = (uint8_t *)userdata + prop->offset;
if (map[i].set)
- r = prop->set(sd_bus_message_get_bus(m), member, m, &error, v);
+ r = prop->set(sd_bus_message_get_bus(m), member, m, error, v);
else
- r = map_basic(sd_bus_message_get_bus(m), member, m, &error, v);
+ r = map_basic(sd_bus_message_get_bus(m), member, m, error, v);
if (r < 0)
return r;
@@ -1184,6 +1184,7 @@ int bus_message_map_all_properties(
int bus_message_map_properties_changed(
sd_bus_message *m,
const struct bus_properties_map *map,
+ sd_bus_error *error,
void *userdata) {
const char *member;
@@ -1192,7 +1193,7 @@ int bus_message_map_properties_changed(
assert(m);
assert(map);
- r = bus_message_map_all_properties(m, map, userdata);
+ r = bus_message_map_all_properties(m, map, error, userdata);
if (r < 0)
return r;
@@ -1222,10 +1223,10 @@ int bus_map_all_properties(
const char *destination,
const char *path,
const struct bus_properties_map *map,
+ sd_bus_error *error,
void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
@@ -1239,13 +1240,13 @@ int bus_map_all_properties(
path,
"org.freedesktop.DBus.Properties",
"GetAll",
- &error,
+ error,
&m,
"s", "");
if (r < 0)
return r;
- return bus_message_map_all_properties(m, map, userdata);
+ return bus_message_map_all_properties(m, map, error, userdata);
}
int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) {
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index af5f133912..d9ce4263bb 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -50,9 +50,9 @@ struct bus_properties_map {
int bus_map_id128(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata);
-int bus_message_map_all_properties(sd_bus_message *m, const struct bus_properties_map *map, void *userdata);
-int bus_message_map_properties_changed(sd_bus_message *m, const struct bus_properties_map *map, void *userdata);
-int bus_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map, void *userdata);
+int bus_message_map_all_properties(sd_bus_message *m, const struct bus_properties_map *map, sd_bus_error *error, void *userdata);
+int bus_message_map_properties_changed(sd_bus_message *m, const struct bus_properties_map *map, sd_bus_error *error, void *userdata);
+int bus_map_all_properties(sd_bus *bus, const char *destination, const char *path, const struct bus_properties_map *map, sd_bus_error *error, void *userdata);
int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name);
diff --git a/src/shared/install.c b/src/shared/install.c
index f25ed685f6..58c8e852b2 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -389,6 +389,12 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
verb, changes[i].path);
logged = true;
break;
+
+ case -ENOENT:
+ log_error_errno(changes[i].type, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path);
+ logged = true;
+ break;
+
default:
assert(changes[i].type < 0);
log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",
@@ -1807,7 +1813,9 @@ static int install_context_mark_for_removal(
InstallContext *c,
const LookupPaths *paths,
Set **remove_symlinks_to,
- const char *config_path) {
+ const char *config_path,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
UnitFileInstallInfo *i;
int r;
@@ -1833,19 +1841,26 @@ static int install_context_mark_for_removal(
r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
if (r == -ENOLINK) {
- log_debug_errno(r, "Name %s leads to a dangling symlink, ignoring.", i->name);
- continue;
- } else if (r == -ENOENT && i->auxiliary) {
- /* some unit specified in Also= or similar is missing */
- log_debug_errno(r, "Auxiliary unit %s not found, ignoring.", i->name);
- continue;
- } else if (r < 0)
- return log_debug_errno(r, "Failed to find unit %s: %m", i->name);
+ log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL);
+ } else if (r == -ENOENT) {
- if (i->type != UNIT_FILE_TYPE_REGULAR) {
- log_debug("Unit %s has type %s, ignoring.",
- i->name,
- unit_file_type_to_string(i->type) ?: "invalid");
+ if (i->auxiliary) /* some unit specified in Also= or similar is missing */
+ log_debug_errno(r, "Auxiliary unit of %s not found, removing name.", i->name);
+ else {
+ log_debug_errno(r, "Unit %s not found, removing name.", i->name);
+ unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
+ }
+
+ } else if (r < 0) {
+ log_debug_errno(r, "Failed to find unit %s, removing name: %m", i->name);
+ unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
+ } else if (i->type == UNIT_FILE_TYPE_MASKED) {
+ log_debug("Unit file %s is masked, ignoring.", i->name);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path ?: i->name, NULL);
+ continue;
+ } else if (i->type != UNIT_FILE_TYPE_REGULAR) {
+ log_debug("Unit %s has type %s, ignoring.", i->name, unit_file_type_to_string(i->type) ?: "invalid");
continue;
}
@@ -1878,6 +1893,8 @@ int unit_file_mask(
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
STRV_FOREACH(i, files) {
_cleanup_free_ char *path = NULL;
@@ -1926,6 +1943,9 @@ int unit_file_unmask(
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
+
dry_run = !!(flags & UNIT_FILE_DRY_RUN);
STRV_FOREACH(i, files) {
@@ -2015,6 +2035,8 @@ int unit_file_link(
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
STRV_FOREACH(i, files) {
_cleanup_free_ char *full = NULL;
@@ -2282,6 +2304,8 @@ int unit_file_add_dependency(
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
&target_info, changes, n_changes);
@@ -2347,6 +2371,8 @@ int unit_file_enable(
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
STRV_FOREACH(f, files) {
r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
@@ -2391,6 +2417,8 @@ int unit_file_disable(
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
STRV_FOREACH(i, files) {
if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
@@ -2401,7 +2429,7 @@ int unit_file_disable(
return r;
}
- r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path);
+ r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
if (r < 0)
return r;
@@ -2790,7 +2818,7 @@ static int execute_preset(
if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path);
+ r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
if (r < 0)
return r;
@@ -2885,6 +2913,8 @@ int unit_file_preset(
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
r = read_presets(scope, root_dir, &presets);
if (r < 0)
@@ -2923,6 +2953,8 @@ int unit_file_preset_all(
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
+ if (!config_path)
+ return -ENXIO;
r = read_presets(scope, root_dir, &presets);
if (r < 0)
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index 586ef64e72..09a44534e2 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -33,6 +33,7 @@
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
+#include "user-util.h"
#include "util.h"
static int user_runtime_dir(char **ret, const char *suffix) {
@@ -57,6 +58,7 @@ static int user_runtime_dir(char **ret, const char *suffix) {
static int user_config_dir(char **ret, const char *suffix) {
const char *e;
char *j;
+ int r;
assert(ret);
@@ -64,11 +66,11 @@ static int user_config_dir(char **ret, const char *suffix) {
if (e)
j = strappend(e, suffix);
else {
- const char *home;
+ _cleanup_free_ char *home = NULL;
- home = getenv("HOME");
- if (!home)
- return -ENXIO;
+ r = get_home_dir(&home);
+ if (r < 0)
+ return r;
j = strjoin(home, "/.config", suffix);
}
@@ -83,6 +85,7 @@ static int user_config_dir(char **ret, const char *suffix) {
static int user_data_dir(char **ret, const char *suffix) {
const char *e;
char *j;
+ int r;
assert(ret);
assert(suffix);
@@ -95,12 +98,11 @@ static int user_data_dir(char **ret, const char *suffix) {
if (e)
j = strappend(e, suffix);
else {
- const char *home;
-
- home = getenv("HOME");
- if (!home)
- return -ENXIO;
+ _cleanup_free_ char *home = NULL;
+ r = get_home_dir(&home);
+ if (r < 0)
+ return r;
j = strjoin(home, "/.local/share", suffix);
}
@@ -136,10 +138,10 @@ static char** user_dirs(
NULL
};
- const char *e;
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
_cleanup_free_ char *data_home = NULL;
_cleanup_strv_free_ char **res = NULL;
+ const char *e;
char **tmp;
int r;
@@ -186,9 +188,8 @@ static char** user_dirs(
if (strv_extend(&res, generator_early) < 0)
return NULL;
- if (!strv_isempty(config_dirs))
- if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
- return NULL;
+ if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
+ return NULL;
if (strv_extend(&res, persistent_config) < 0)
return NULL;
@@ -205,9 +206,8 @@ static char** user_dirs(
if (strv_extend(&res, data_home) < 0)
return NULL;
- if (!strv_isempty(data_dirs))
- if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
- return NULL;
+ if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
+ return NULL;
if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
return NULL;
@@ -220,6 +220,7 @@ static char** user_dirs(
tmp = res;
res = NULL;
+
return tmp;
}
@@ -328,12 +329,18 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru
case UNIT_FILE_USER:
r = user_config_dir(&a, "/systemd/user");
- if (r < 0)
+ if (r < 0 && r != -ENXIO)
return r;
r = user_runtime_dir(runtime, "/systemd/user");
- if (r < 0)
- return r;
+ if (r < 0) {
+ if (r != -ENXIO)
+ return r;
+
+ /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
+ * directory to NULL */
+ *runtime = NULL;
+ }
*persistent = a;
a = NULL;
@@ -382,12 +389,18 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
case UNIT_FILE_USER:
r = user_config_dir(&a, "/systemd/system.control");
- if (r < 0)
+ if (r < 0 && r != -ENXIO)
return r;
r = user_runtime_dir(runtime, "/systemd/system.control");
- if (r < 0)
- return r;
+ if (r < 0) {
+ if (r != -ENXIO)
+ return r;
+
+ /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
+ * NULL */
+ *runtime = NULL;
+ }
break;
@@ -474,22 +487,26 @@ int lookup_paths_init(
return -ENOMEM;
}
+ /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
- if (r < 0 && r != -ENXIO)
+ if (r < 0)
return r;
if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
+ /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late);
if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
return r;
}
+ /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
r = acquire_transient_dir(scope, &transient);
if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
return r;
+ /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
- if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+ if (r < 0 && r != -EOPNOTSUPP)
return r;
/* First priority is whatever has been passed to us via env vars */
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index b6b44e7f56..84964f750f 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -36,31 +36,72 @@
const uint32_t seccomp_local_archs[] = {
-#if defined(__i386__) || defined(__x86_64__)
+ /* Note: always list the native arch we are compiled as last, so that users can blacklist seccomp(), but our own calls to it still succeed */
+
+#if defined(__x86_64__) && defined(__ILP32__)
SCMP_ARCH_X86,
SCMP_ARCH_X86_64,
+ SCMP_ARCH_X32, /* native */
+#elif defined(__x86_64__) && !defined(__ILP32__)
+ SCMP_ARCH_X86,
SCMP_ARCH_X32,
-
-#elif defined(__arm__) || defined(__aarch64__)
+ SCMP_ARCH_X86_64, /* native */
+#elif defined(__i386__)
+ SCMP_ARCH_X86,
+#elif defined(__aarch64__)
SCMP_ARCH_ARM,
- SCMP_ARCH_AARCH64,
-
-#elif defined(__mips__) || defined(__mips64__)
+ SCMP_ARCH_AARCH64, /* native */
+#elif defined(__arm__)
+ SCMP_ARCH_ARM,
+#elif defined(__mips__) && __BYTE_ORDER == __BIG_ENDIAN && _MIPS_SIM == _MIPS_SIM_ABI32
+ SCMP_ARCH_MIPSEL,
+ SCMP_ARCH_MIPS, /* native */
+#elif defined(__mips__) && __BYTE_ORDER == __LITTLE_ENDIAN && _MIPS_SIM == _MIPS_SIM_ABI32
SCMP_ARCH_MIPS,
- SCMP_ARCH_MIPS64,
+ SCMP_ARCH_MIPSEL, /* native */
+#elif defined(__mips__) && __BYTE_ORDER == __BIG_ENDIAN && _MIPS_SIM == _MIPS_SIM_ABI64
+ SCMP_ARCH_MIPSEL,
+ SCMP_ARCH_MIPS,
+ SCMP_ARCH_MIPSEL64N32,
+ SCMP_ARCH_MIPS64N32,
+ SCMP_ARCH_MIPSEL64,
+ SCMP_ARCH_MIPS64, /* native */
+#elif defined(__mips__) && __BYTE_ORDER == __LITTLE_ENDIAN && _MIPS_SIM == _MIPS_SIM_ABI64
+ SCMP_ARCH_MIPS,
+ SCMP_ARCH_MIPSEL,
SCMP_ARCH_MIPS64N32,
+ SCMP_ARCH_MIPSEL64N32,
+ SCMP_ARCH_MIPS64,
+ SCMP_ARCH_MIPSEL64, /* native */
+#elif defined(__mips__) && __BYTE_ORDER == __BIG_ENDIAN && _MIPS_SIM == _MIPS_SIM_NABI32
SCMP_ARCH_MIPSEL,
+ SCMP_ARCH_MIPS,
SCMP_ARCH_MIPSEL64,
+ SCMP_ARCH_MIPS64,
SCMP_ARCH_MIPSEL64N32,
-
-#elif defined(__powerpc__) || defined(__powerpc64__)
+ SCMP_ARCH_MIPS64N32, /* native */
+#elif defined(__mips__) && __BYTE_ORDER == __LITTLE_ENDIAN && _MIPS_SIM == _MIPS_SIM_NABI32
+ SCMP_ARCH_MIPS,
+ SCMP_ARCH_MIPSEL,
+ SCMP_ARCH_MIPS64,
+ SCMP_ARCH_MIPSEL64,
+ SCMP_ARCH_MIPS64N32,
+ SCMP_ARCH_MIPSEL64N32, /* native */
+#elif defined(__powerpc64__) && __BYTE_ORDER == __BIG_ENDIAN
SCMP_ARCH_PPC,
- SCMP_ARCH_PPC64,
SCMP_ARCH_PPC64LE,
-
-#elif defined(__s390__) || defined(__s390x__)
+ SCMP_ARCH_PPC64, /* native */
+#elif defined(__powerpc64__) && __BYTE_ORDER == __LITTLE_ENDIAN
+ SCMP_ARCH_PPC,
+ SCMP_ARCH_PPC64,
+ SCMP_ARCH_PPC64LE, /* native */
+#elif defined(__powerpc__)
+ SCMP_ARCH_PPC,
+#elif defined(__s390x__)
+ SCMP_ARCH_S390,
+ SCMP_ARCH_S390X, /* native */
+#elif defined(__s390__)
SCMP_ARCH_S390,
- SCMP_ARCH_S390X,
#endif
(uint32_t) -1
};
@@ -907,17 +948,42 @@ int seccomp_protect_sysctl(void) {
}
int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
-
-#if !SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN
uint32_t arch;
int r;
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
+ bool supported;
Iterator i;
log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));
+ switch (arch) {
+
+ case SCMP_ARCH_X86_64:
+ case SCMP_ARCH_X32:
+ case SCMP_ARCH_ARM:
+ case SCMP_ARCH_AARCH64:
+ /* These we know we support (i.e. are the ones that do not use socketcall()) */
+ supported = true;
+ break;
+
+ case SCMP_ARCH_X86:
+ case SCMP_ARCH_S390:
+ case SCMP_ARCH_S390X:
+ case SCMP_ARCH_PPC:
+ case SCMP_ARCH_PPC64:
+ case SCMP_ARCH_PPC64LE:
+ default:
+ /* These we either know we don't support (i.e. are the ones that do use socketcall()), or we
+ * don't know */
+ supported = false;
+ break;
+ }
+
+ if (!supported)
+ continue;
+
r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
if (r < 0)
return r;
@@ -1037,7 +1103,6 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
if (r < 0)
log_debug_errno(r, "Failed to install socket family rules for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
}
-#endif
return 0;
}
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 2809dece50..2336ae34f4 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -1922,7 +1922,7 @@ static int get_machine_properties(sd_bus *bus, struct machine_info *mi) {
bus = container;
}
- r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, mi);
+ r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, NULL, mi);
if (r < 0)
return r;
@@ -1957,7 +1957,7 @@ static int get_machine_list(
machine_infos[c].name = hn;
hn = NULL;
- get_machine_properties(bus, &machine_infos[c]);
+ (void) get_machine_properties(bus, &machine_infos[c]);
c++;
}
@@ -1987,7 +1987,7 @@ static int get_machine_list(
return log_oom();
}
- get_machine_properties(NULL, &machine_infos[c]);
+ (void) get_machine_properties(NULL, &machine_infos[c]);
c++;
}
@@ -4953,7 +4953,7 @@ static int show_one(
return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
if (unit) {
- r = bus_message_map_all_properties(reply, property_map, &info);
+ r = bus_message_map_all_properties(reply, property_map, &error, &info);
if (r < 0)
return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
@@ -5125,8 +5125,9 @@ static int show_all(
static int show_system_status(sd_bus *bus) {
char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
- _cleanup_free_ char *hn = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(machine_info_clear) struct machine_info mi = {};
+ _cleanup_free_ char *hn = NULL;
const char *on, *off;
int r;
@@ -5134,9 +5135,9 @@ static int show_system_status(sd_bus *bus) {
if (!hn)
return log_oom();
- r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi);
+ r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &error, &mi);
if (r < 0)
- return log_error_errno(r, "Failed to read server status: %m");
+ return log_error_errno(r, "Failed to read server status: %s", bus_error_message(&error, r));
if (streq_ptr(mi.state, "degraded")) {
on = ansi_highlight_red();
@@ -6028,7 +6029,7 @@ static int unit_exists(const char *unit) {
if (r < 0)
return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
- r = bus_message_map_all_properties(reply, property_map, &info);
+ r = bus_message_map_all_properties(reply, property_map, &error, &info);
if (r < 0)
return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index 1f34a91b10..f90b73aeaf 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -192,6 +192,7 @@ int main(int argc, char* argv[]) {
test_one("00..07-*-*", "2000..2007-*-* 00:00:00");
test_one("*:20..39/5", "*-*-* *:20..35/5:00");
test_one("00:00:20..40/1", "*-*-* 00:00:20..40");
+ test_one("*~03/1,03..05", "*-*~03/1,03..05 00:00:00");
test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 4e0d052d4f..3a3ab3eb94 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -439,6 +439,10 @@ static void test_exec_spec_interpolation(Manager *m) {
test(m, "exec-spec-interpolation.service", 0, CLD_EXITED);
}
+static void test_exec_read_only_path_suceed(Manager *m) {
+ test(m, "exec-read-only-path-succeed.service", 0, CLD_EXITED);
+}
+
static int run_tests(UnitFileScope scope, const test_function_t *tests) {
const test_function_t *test = NULL;
Manager *m = NULL;
@@ -492,6 +496,7 @@ int main(int argc, char *argv[]) {
test_exec_oomscoreadjust,
test_exec_ioschedulingclass,
test_exec_spec_interpolation,
+ test_exec_read_only_path_suceed,
NULL,
};
static const test_function_t system_tests[] = {
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 553ef67011..281b1534a3 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -165,6 +165,8 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
{ "RTCTimeUSec", "t", NULL, offsetof(StatusInfo, rtc_time) },
{}
};
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(bus);
@@ -173,9 +175,10 @@ static int show_status(sd_bus *bus, char **args, unsigned n) {
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
map,
+ &error,
&info);
if (r < 0)
- return log_error_errno(r, "Failed to query server: %m");
+ return log_error_errno(r, "Failed to query server: %s", bus_error_message(&error, r));
print_status_info(&info);