Systemd/src/resolve/resolved.c
Lennart Poettering d301c52383 resolved: bind socket to interface during connect()
Apparently, IF_UNICAST_IF does not influence the routing decisions done
during connect(). But SO_BINDTODEVICE/SO_BINDTOINDEX does, which however
brings a lot of other semantics with it, we are not so interested in
(i.e. it doesn't not allow packets from any other iface to us, even if
routing otherwise allows it).

Hence, let's bind to the ifindex immediately before the connect() and
unbind right after again, so that we get the semantics we want, but not
the ones we don't.

Fixes: #11935
Replaces: #12004
2020-12-02 15:15:02 +01:00

100 lines
3.6 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "sd-daemon.h"
#include "sd-event.h"
#include "bus-log-control-api.h"
#include "capability-util.h"
#include "daemon-util.h"
#include "main-func.h"
#include "mkdir.h"
#include "resolved-bus.h"
#include "resolved-conf.h"
#include "resolved-manager.h"
#include "resolved-resolv-conf.h"
#include "selinux-util.h"
#include "service-util.h"
#include "signal-util.h"
#include "user-util.h"
static int run(int argc, char *argv[]) {
_cleanup_(manager_freep) Manager *m = NULL;
_cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
int r;
log_setup_service();
r = service_parse_argv("systemd-resolved.service",
"Provide name resolution with caching using DNS, mDNS, LLMNR.",
BUS_IMPLEMENTATIONS(&manager_object,
&log_control_object),
argc, argv);
if (r <= 0)
return r;
umask(0022);
r = mac_selinux_init();
if (r < 0)
return r;
/* Drop privileges, but only if we have been started as root. If we are not running as root we assume most
* privileges are already dropped and we can't create our directory. */
if (getuid() == 0) {
const char *user = "systemd-resolve";
uid_t uid;
gid_t gid;
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
if (r < 0)
return log_error_errno(r, "Cannot resolve user name %s: %m", user);
/* As we're root, we can create the directory where resolv.conf will live */
r = mkdir_safe_label("/run/systemd/resolve", 0755, uid, gid, MKDIR_WARN_MODE);
if (r < 0)
return log_error_errno(r, "Could not create runtime directory: %m");
/* Drop privileges, but keep three caps. Note that we drop two of those too, later on (see below) */
r = drop_privileges(uid, gid,
(UINT64_C(1) << CAP_NET_RAW)| /* needed for SO_BINDTODEVICE */
(UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */
(UINT64_C(1) << CAP_SETPCAP) /* needed in order to drop the caps later */);
if (r < 0)
return log_error_errno(r, "Failed to drop privileges: %m");
}
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");
r = manager_start(m);
if (r < 0)
return log_error_errno(r, "Failed to start manager: %m");
/* Write finish default resolv.conf to avoid a dangling symlink */
(void) manager_write_resolv_conf(m);
(void) manager_check_resolv_conf(m);
/* Let's drop the remaining caps now */
r = capability_bounding_set_drop((UINT64_C(1) << CAP_NET_RAW), true);
if (r < 0)
return log_error_errno(r, "Failed to drop remaining caps: %m");
notify_stop = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
r = sd_event_loop(m->event);
if (r < 0)
return log_error_errno(r, "Event loop failed: %m");
return 0;
}
DEFINE_MAIN_FUNCTION(run);