mirror of
https://github.com/systemd/systemd
synced 2025-12-26 19:04:45 +01:00
Compare commits
17 Commits
4cbd28af60
...
565147b7bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
565147b7bb | ||
|
|
9ca875e80c | ||
|
|
36d892b7e6 | ||
|
|
fbbc72189f | ||
|
|
19bcef9dc3 | ||
|
|
34f80876f8 | ||
|
|
0a489d3f5d | ||
|
|
d80e72ec60 | ||
|
|
7d27d39aa7 | ||
|
|
f01a3b79fa | ||
|
|
90df0fbea8 | ||
|
|
c8037dbf05 | ||
|
|
0b261ac5be | ||
|
|
d301c52383 | ||
|
|
3132597182 | ||
|
|
7e299ffe10 | ||
|
|
ce9067697b |
@ -1495,6 +1495,7 @@
|
||||
<term><varname>AssertHost=</varname></term>
|
||||
<term><varname>AssertKernelCommandLine=</varname></term>
|
||||
<term><varname>AssertKernelVersion=</varname></term>
|
||||
<term><varname>AssertEnvironment=</varname></term>
|
||||
<term><varname>AssertSecurity=</varname></term>
|
||||
<term><varname>AssertCapability=</varname></term>
|
||||
<term><varname>AssertACPower=</varname></term>
|
||||
@ -1506,12 +1507,15 @@
|
||||
<term><varname>AssertPathIsSymbolicLink=</varname></term>
|
||||
<term><varname>AssertPathIsMountPoint=</varname></term>
|
||||
<term><varname>AssertPathIsReadWrite=</varname></term>
|
||||
<term><varname>AssertPathIsEncrypted=</varname></term>
|
||||
<term><varname>AssertDirectoryNotEmpty=</varname></term>
|
||||
<term><varname>AssertFileNotEmpty=</varname></term>
|
||||
<term><varname>AssertFileIsExecutable=</varname></term>
|
||||
<term><varname>AssertUser=</varname></term>
|
||||
<term><varname>AssertGroup=</varname></term>
|
||||
<term><varname>AssertControlGroupController=</varname></term>
|
||||
<term><varname>AssertMemory=</varname></term>
|
||||
<term><varname>AssertCPUs=</varname></term>
|
||||
|
||||
<listitem><para>Similar to the <varname>ConditionArchitecture=</varname>,
|
||||
<varname>ConditionVirtualization=</varname>, …, condition settings described above, these settings
|
||||
|
||||
59
meson.build
59
meson.build
@ -221,11 +221,11 @@ conf.set_quoted('USER_CONFIG_UNIT_DIR', join_paths(pkgsysc
|
||||
conf.set_quoted('USER_DATA_UNIT_DIR', userunitdir)
|
||||
conf.set_quoted('CERTIFICATE_ROOT', get_option('certificate-root'))
|
||||
conf.set_quoted('CATALOG_DATABASE', join_paths(catalogstatedir, 'database'))
|
||||
conf.set_quoted('SYSTEMD_CGROUP_AGENT_PATH', join_paths(rootlibexecdir, 'systemd-cgroups-agent'))
|
||||
conf.set_quoted('SYSTEMD_BINARY_PATH', join_paths(rootlibexecdir, 'systemd'))
|
||||
conf.set_quoted('SYSTEMD_CGROUPS_AGENT_PATH', join_paths(rootlibexecdir, 'systemd-cgroups-agent'))
|
||||
conf.set_quoted('SYSTEMD_FSCK_PATH', join_paths(rootlibexecdir, 'systemd-fsck'))
|
||||
conf.set_quoted('SYSTEMD_MAKEFS_PATH', join_paths(rootlibexecdir, 'systemd-makefs'))
|
||||
conf.set_quoted('SYSTEMD_GROWFS_PATH', join_paths(rootlibexecdir, 'systemd-growfs'))
|
||||
conf.set_quoted('SYSTEMD_MAKEFS_PATH', join_paths(rootlibexecdir, 'systemd-makefs'))
|
||||
conf.set_quoted('SYSTEMD_SHUTDOWN_BINARY_PATH', join_paths(rootlibexecdir, 'systemd-shutdown'))
|
||||
conf.set_quoted('SYSTEMCTL_BINARY_PATH', join_paths(rootbindir, 'systemctl'))
|
||||
conf.set_quoted('SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH', join_paths(rootbindir, 'systemd-tty-ask-password-agent'))
|
||||
@ -3438,40 +3438,39 @@ endif
|
||||
|
||||
fuzzer_exes = []
|
||||
|
||||
if fuzz_tests or fuzzer_build
|
||||
foreach tuple : fuzzers
|
||||
sources = tuple[0]
|
||||
link_with = tuple[1].length() > 0 ? tuple[1] : [libshared]
|
||||
dependencies = tuple[2]
|
||||
defs = tuple.length() >= 4 ? tuple[3] : []
|
||||
incs = tuple.length() >= 5 ? tuple[4] : includes
|
||||
link_args = []
|
||||
foreach tuple : fuzzers
|
||||
sources = tuple[0]
|
||||
link_with = tuple[1].length() > 0 ? tuple[1] : [libshared]
|
||||
dependencies = tuple[2]
|
||||
defs = tuple.length() >= 4 ? tuple[3] : []
|
||||
incs = tuple.length() >= 5 ? tuple[4] : includes
|
||||
link_args = []
|
||||
|
||||
if want_ossfuzz
|
||||
if want_ossfuzz
|
||||
dependencies += fuzzing_engine
|
||||
elif want_libfuzzer
|
||||
if fuzzing_engine.found()
|
||||
dependencies += fuzzing_engine
|
||||
elif want_libfuzzer
|
||||
if fuzzing_engine.found()
|
||||
dependencies += fuzzing_engine
|
||||
else
|
||||
link_args += ['-fsanitize=fuzzer']
|
||||
endif
|
||||
else
|
||||
sources += 'src/fuzz/fuzz-main.c'
|
||||
link_args += ['-fsanitize=fuzzer']
|
||||
endif
|
||||
else
|
||||
sources += 'src/fuzz/fuzz-main.c'
|
||||
endif
|
||||
|
||||
name = sources[0].split('/')[-1].split('.')[0]
|
||||
name = sources[0].split('/')[-1].split('.')[0]
|
||||
|
||||
fuzzer_exes += executable(
|
||||
name,
|
||||
sources,
|
||||
include_directories : [incs, include_directories('src/fuzz')],
|
||||
link_with : link_with,
|
||||
dependencies : dependencies,
|
||||
c_args : defs,
|
||||
link_args: link_args,
|
||||
install : false)
|
||||
endforeach
|
||||
endif
|
||||
fuzzer_exes += executable(
|
||||
name,
|
||||
sources,
|
||||
include_directories : [incs, include_directories('src/fuzz')],
|
||||
link_with : link_with,
|
||||
dependencies : dependencies,
|
||||
c_args : defs,
|
||||
link_args: link_args,
|
||||
install : false,
|
||||
build_by_default : fuzz_tests or fuzzer_build)
|
||||
endforeach
|
||||
|
||||
run_target(
|
||||
'fuzzers',
|
||||
|
||||
@ -320,7 +320,7 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) {
|
||||
}
|
||||
|
||||
int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
|
||||
union sockaddr_union *sa = (union sockaddr_union*) _sa;
|
||||
const union sockaddr_union *sa = (const union sockaddr_union*) _sa;
|
||||
|
||||
/* Note, this returns the port as 'unsigned' rather than 'uint16_t', as AF_VSOCK knows larger ports */
|
||||
|
||||
@ -345,6 +345,25 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) {
|
||||
}
|
||||
}
|
||||
|
||||
const union in_addr_union *sockaddr_in_addr(const struct sockaddr *_sa) {
|
||||
const union sockaddr_union *sa = (const union sockaddr_union*) _sa;
|
||||
|
||||
if (!sa)
|
||||
return NULL;
|
||||
|
||||
switch (sa->sa.sa_family) {
|
||||
|
||||
case AF_INET:
|
||||
return (const union in_addr_union*) &sa->in.sin_addr;
|
||||
|
||||
case AF_INET6:
|
||||
return (const union in_addr_union*) &sa->in6.sin6_addr;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int sockaddr_pretty(
|
||||
const struct sockaddr *_sa,
|
||||
socklen_t salen,
|
||||
|
||||
@ -102,6 +102,7 @@ const char* socket_address_get_path(const SocketAddress *a);
|
||||
bool socket_ipv6_is_supported(void);
|
||||
|
||||
int sockaddr_port(const struct sockaddr *_sa, unsigned *port);
|
||||
const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa);
|
||||
|
||||
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret);
|
||||
int getpeername_pretty(int fd, bool include_port, char **ret);
|
||||
|
||||
@ -345,7 +345,7 @@ int detect_vm(void) {
|
||||
/* We have to use the correct order here:
|
||||
*
|
||||
* → First, try to detect Oracle Virtualbox, even if it uses KVM, as well as Xen even if it cloaks as Microsoft
|
||||
* Hyper-V.
|
||||
* Hyper-V. Attempt to detect uml at this stage also since it runs as a user-process nested inside other VMs.
|
||||
*
|
||||
* → Second, try to detect from CPUID, this will report KVM for whatever software is used even if info in DMI is
|
||||
* overwritten.
|
||||
@ -358,6 +358,16 @@ int detect_vm(void) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* Detect UML */
|
||||
r = detect_vm_uml();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == VIRTUALIZATION_VM_OTHER)
|
||||
other = true;
|
||||
else if (r != VIRTUALIZATION_NONE)
|
||||
goto finish;
|
||||
|
||||
/* Detect from CPUID */
|
||||
r = detect_vm_cpuid();
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -406,14 +416,6 @@ int detect_vm(void) {
|
||||
else if (r != VIRTUALIZATION_NONE)
|
||||
goto finish;
|
||||
|
||||
r = detect_vm_uml();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == VIRTUALIZATION_VM_OTHER)
|
||||
other = true;
|
||||
else if (r != VIRTUALIZATION_NONE)
|
||||
goto finish;
|
||||
|
||||
r = detect_vm_zvm();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -3052,7 +3052,7 @@ int manager_setup_cgroup(Manager *m) {
|
||||
/* On the legacy hierarchy we only get notifications via cgroup agents. (Which isn't really reliable,
|
||||
* since it does not generate events when control groups with children run empty. */
|
||||
|
||||
r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
|
||||
r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUPS_AGENT_PATH);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to install release agent, ignoring: %m");
|
||||
else if (r > 0)
|
||||
|
||||
@ -1762,7 +1762,7 @@ static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_b
|
||||
assert(message);
|
||||
assert(m);
|
||||
|
||||
manager_flush_caches(m);
|
||||
manager_flush_caches(m, LOG_INFO);
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
/* How long to cache strange rcodes, i.e. rcodes != SUCCESS and != NXDOMAIN (specifically: that's only SERVFAIL for
|
||||
* now) */
|
||||
#define CACHE_TTL_STRANGE_RCODE_USEC (30 * USEC_PER_SEC)
|
||||
#define CACHE_TTL_STRANGE_RCODE_USEC (10 * USEC_PER_SEC)
|
||||
|
||||
typedef enum DnsCacheItemType DnsCacheItemType;
|
||||
typedef struct DnsCacheItem DnsCacheItem;
|
||||
|
||||
@ -412,9 +412,36 @@ static int dns_scope_socket(
|
||||
if (ret_socket_address)
|
||||
*ret_socket_address = sa;
|
||||
else {
|
||||
bool bound = false;
|
||||
|
||||
/* Let's temporarily bind the socket to the specified ifindex. The kernel currently takes
|
||||
* only the SO_BINDTODEVICE/SO_BINDTOINDEX ifindex into account when making routing decisions
|
||||
* in connect() — and not IP_UNICAST_IF. We don't really want any of the other semantics of
|
||||
* SO_BINDTODEVICE/SO_BINDTOINDEX, hence we immediately unbind the socket after the fact
|
||||
* again.
|
||||
*
|
||||
* As a special exception we don't do this if we notice that the specified IP address is on
|
||||
* the local host. SO_BINDTODEVICE in combination with destination addresses on the local
|
||||
* host result in EHOSTUNREACH, since Linux won't send the packets out of the specified
|
||||
* interface, but delivers them directly to the local socket. */
|
||||
if (s->link &&
|
||||
!manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa))) {
|
||||
r = socket_bind_to_ifindex(fd, ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
bound = true;
|
||||
}
|
||||
|
||||
r = connect(fd, &sa.sa, salen);
|
||||
if (r < 0 && errno != EINPROGRESS)
|
||||
return -errno;
|
||||
|
||||
if (bound) {
|
||||
r = socket_bind_to_ifindex(fd, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return TAKE_FD(fd);
|
||||
@ -478,9 +505,8 @@ DnsScopeMatch dns_scope_good_domain(
|
||||
if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, 0) & flags) == 0)
|
||||
return DNS_SCOPE_NO;
|
||||
|
||||
/* Never resolve any loopback hostname or IP address via DNS,
|
||||
* LLMNR or mDNS. Instead, always rely on synthesized RRs for
|
||||
* these. */
|
||||
/* Never resolve any loopback hostname or IP address via DNS, LLMNR or mDNS. Instead, always rely on
|
||||
* synthesized RRs for these. */
|
||||
if (is_localhost(domain) ||
|
||||
dns_name_endswith(domain, "127.in-addr.arpa") > 0 ||
|
||||
dns_name_equal(domain, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)
|
||||
@ -496,6 +522,15 @@ DnsScopeMatch dns_scope_good_domain(
|
||||
if (dns_name_endswith(domain, "invalid") > 0)
|
||||
return DNS_SCOPE_NO;
|
||||
|
||||
/* Never go to network for the _gateway domain, it's something special, synthesized locally. Note
|
||||
* that we don't use is_gateway_hostname() here, since that has support for the legacy "gateway"
|
||||
* hostname (without the prefix underscore), which we don't want to filter on all protocols. i.e. we
|
||||
* don't want to filter "gateway" on classic DNS, since there might very well be such a host inside
|
||||
* some search domain, and we shouldn't block that. We do filter it in LLMNR however (and on mDNS by
|
||||
* side-effect, since it's a single-label name which mDNS doesn't accept anyway). */
|
||||
if (dns_name_equal(domain, "_gateway") > 0)
|
||||
return DNS_SCOPE_NO;
|
||||
|
||||
switch (s->protocol) {
|
||||
|
||||
case DNS_PROTOCOL_DNS: {
|
||||
@ -588,7 +623,7 @@ DnsScopeMatch dns_scope_good_domain(
|
||||
return DNS_SCOPE_MAYBE;
|
||||
|
||||
if ((dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */
|
||||
!is_gateway_hostname(domain) && /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */
|
||||
!is_gateway_hostname(domain) && /* don't resolve "_gateway" with LLMNR, let local synthesizing logic handle that */
|
||||
dns_name_equal(domain, "local") == 0 && /* don't resolve "local" with LLMNR, it's the top-level domain of mDNS after all, see above */
|
||||
manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */
|
||||
return DNS_SCOPE_YES_BASE + 1; /* Return +1, as we consider ourselves authoritative
|
||||
|
||||
@ -530,7 +530,7 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature
|
||||
|
||||
edns_do = level >= DNS_SERVER_FEATURE_LEVEL_DO;
|
||||
|
||||
if (level >= DNS_SERVER_FEATURE_LEVEL_LARGE)
|
||||
if (level == DNS_SERVER_FEATURE_LEVEL_LARGE)
|
||||
packet_size = DNS_PACKET_UNICAST_SIZE_LARGE_MAX;
|
||||
else
|
||||
packet_size = server->received_udp_packet_max;
|
||||
|
||||
@ -379,8 +379,7 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
|
||||
if (!l && /* l == NULL if this is the main stub */
|
||||
(in_addr_is_localhost(p->family, &p->sender) <= 0 ||
|
||||
in_addr_is_localhost(p->family, &p->destination) <= 0)) {
|
||||
log_error("Got packet on unexpected IP range, refusing.");
|
||||
dns_stub_send_failure(m, l, s, p, DNS_RCODE_SERVFAIL, false);
|
||||
log_warning("Got packet on unexpected (i.e. non-localhost) IP range, ignoring.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "resolved-dns-synthesize.h"
|
||||
#include "resolved-etc-hosts.h"
|
||||
#include "socket-netlink.h"
|
||||
#include "stat-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
@ -36,9 +37,7 @@ void etc_hosts_free(EtcHosts *hosts) {
|
||||
|
||||
void manager_etc_hosts_flush(Manager *m) {
|
||||
etc_hosts_free(&m->etc_hosts);
|
||||
m->etc_hosts_mtime = USEC_INFINITY;
|
||||
m->etc_hosts_ino = 0;
|
||||
m->etc_hosts_dev = 0;
|
||||
m->etc_hosts_stat = (struct stat) {};
|
||||
}
|
||||
|
||||
static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
|
||||
@ -114,10 +113,6 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_localhost(name))
|
||||
/* Suppress the "localhost" line that is often seen */
|
||||
continue;
|
||||
|
||||
if (!item) {
|
||||
/* Optimize the case where we don't need to store any addresses, by storing
|
||||
* only the name in a dedicated Set instead of the hashmap */
|
||||
@ -164,6 +159,95 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void strip_localhost(EtcHosts *hosts) {
|
||||
static const struct in_addr_data local_in_addrs[] = {
|
||||
{
|
||||
.family = AF_INET,
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
/* We want constant expressions here, that's why we don't use htole32() here */
|
||||
.address.in.s_addr = UINT32_C(0x0100007F),
|
||||
#else
|
||||
.address.in.s_addr = UINT32_C(0x7F000001),
|
||||
#endif
|
||||
},
|
||||
{
|
||||
.family = AF_INET6,
|
||||
.address.in6 = IN6ADDR_LOOPBACK_INIT,
|
||||
},
|
||||
};
|
||||
|
||||
EtcHostsItem *item;
|
||||
|
||||
assert(hosts);
|
||||
|
||||
/* Removes the 'localhost' entry from what we loaded. But only if the mapping is exclusively between
|
||||
* 127.0.0.1 and localhost (or aliases to that we recognize). If there's any other name assigned to
|
||||
* it, we leave the entry in.
|
||||
*
|
||||
* This way our regular synthesizing can take over, but only if it would result in the exact same
|
||||
* mappings. */
|
||||
|
||||
for (size_t j = 0; j < ELEMENTSOF(local_in_addrs); j++) {
|
||||
bool all_localhost, in_order;
|
||||
char **i;
|
||||
|
||||
item = hashmap_get(hosts->by_address, local_in_addrs + j);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
/* Check whether all hostnames the loopback address points to are localhost ones */
|
||||
all_localhost = true;
|
||||
STRV_FOREACH(i, item->names)
|
||||
if (!is_localhost(*i)) {
|
||||
all_localhost = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!all_localhost) /* Not all names are localhost, hence keep the entries for this address. */
|
||||
continue;
|
||||
|
||||
/* Now check if the names listed for this address actually all point back just to this
|
||||
* address (or the other loopback address). If not, let's stay away from this too. */
|
||||
in_order = true;
|
||||
STRV_FOREACH(i, item->names) {
|
||||
EtcHostsItemByName *n;
|
||||
bool all_local_address;
|
||||
|
||||
n = hashmap_get(hosts->by_name, *i);
|
||||
if (!n) /* No reverse entry? Then almost certainly the entry already got deleted from
|
||||
* the previous iteration of this loop, i.e. via the other protocol */
|
||||
break;
|
||||
|
||||
/* Now check if the addresses of this item are all localhost addresses */
|
||||
all_local_address = true;
|
||||
for (size_t m = 0; m < n->n_addresses; m++)
|
||||
if (!in_addr_is_localhost(n->addresses[m]->family, &n->addresses[m]->address)) {
|
||||
all_local_address = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!all_local_address) {
|
||||
in_order = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in_order)
|
||||
continue;
|
||||
|
||||
STRV_FOREACH(i, item->names) {
|
||||
EtcHostsItemByName *n;
|
||||
|
||||
n = hashmap_remove(hosts->by_name, *i);
|
||||
if (n)
|
||||
etc_hosts_item_by_name_free(n);
|
||||
}
|
||||
|
||||
assert_se(hashmap_remove(hosts->by_address, local_in_addrs + j) == item);
|
||||
etc_hosts_item_free(item);
|
||||
}
|
||||
}
|
||||
|
||||
int etc_hosts_parse(EtcHosts *hosts, FILE *f) {
|
||||
_cleanup_(etc_hosts_free) EtcHosts t = {};
|
||||
unsigned nr = 0;
|
||||
@ -194,6 +278,8 @@ int etc_hosts_parse(EtcHosts *hosts, FILE *f) {
|
||||
return r;
|
||||
}
|
||||
|
||||
strip_localhost(&t);
|
||||
|
||||
etc_hosts_free(hosts);
|
||||
*hosts = t;
|
||||
t = (EtcHosts) {}; /* prevent cleanup */
|
||||
@ -214,7 +300,7 @@ static int manager_etc_hosts_read(Manager *m) {
|
||||
|
||||
m->etc_hosts_last = ts;
|
||||
|
||||
if (m->etc_hosts_mtime != USEC_INFINITY) {
|
||||
if (m->etc_hosts_stat.st_mode != 0) {
|
||||
if (stat("/etc/hosts", &st) < 0) {
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to stat /etc/hosts: %m");
|
||||
@ -224,8 +310,7 @@ static int manager_etc_hosts_read(Manager *m) {
|
||||
}
|
||||
|
||||
/* Did the mtime or ino/dev change? If not, there's no point in re-reading the file. */
|
||||
if (timespec_load(&st.st_mtim) == m->etc_hosts_mtime &&
|
||||
st.st_ino == m->etc_hosts_ino && st.st_dev == m->etc_hosts_dev)
|
||||
if (stat_inode_unmodified(&m->etc_hosts_stat, &st))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -248,9 +333,7 @@ static int manager_etc_hosts_read(Manager *m) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
m->etc_hosts_mtime = timespec_load(&st.st_mtim);
|
||||
m->etc_hosts_ino = st.st_ino;
|
||||
m->etc_hosts_dev = st.st_dev;
|
||||
m->etc_hosts_stat = st;
|
||||
m->etc_hosts_last = ts;
|
||||
|
||||
return 1;
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "bus-get-properties.h"
|
||||
#include "bus-message-util.h"
|
||||
#include "bus-polkit.h"
|
||||
#include "log-link.h"
|
||||
#include "parse-util.h"
|
||||
#include "resolve-util.h"
|
||||
#include "resolved-bus.h"
|
||||
@ -252,6 +253,7 @@ static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
|
||||
}
|
||||
|
||||
static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
|
||||
_cleanup_free_ char *j = NULL;
|
||||
struct in_addr_full **dns;
|
||||
Link *l = userdata;
|
||||
size_t n;
|
||||
@ -279,6 +281,21 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
const char *s;
|
||||
|
||||
s = in_addr_full_to_string(dns[i]);
|
||||
if (!s) {
|
||||
r = -ENOMEM;
|
||||
goto finalize;
|
||||
}
|
||||
|
||||
if (!strextend_with_separator(&j, ", ", s, NULL)) {
|
||||
r = -ENOMEM;
|
||||
goto finalize;
|
||||
}
|
||||
}
|
||||
|
||||
dns_server_mark_all(l->dns_servers);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
@ -304,6 +321,11 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
|
||||
(void) manager_write_resolv_conf(l->manager);
|
||||
(void) manager_send_changed(l->manager, "DNS");
|
||||
|
||||
if (j)
|
||||
log_link_info(l, "Bus client set DNS server list to: %s", j);
|
||||
else
|
||||
log_link_info(l, "Bus client reset DNS server list.");
|
||||
|
||||
r = sd_bus_reply_method_return(message, NULL);
|
||||
|
||||
finalize:
|
||||
@ -323,6 +345,7 @@ int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata,
|
||||
}
|
||||
|
||||
int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *j = NULL;
|
||||
Link *l = userdata;
|
||||
int r;
|
||||
|
||||
@ -338,6 +361,7 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *prefixed = NULL;
|
||||
const char *name;
|
||||
int route_only;
|
||||
|
||||
@ -354,6 +378,17 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
|
||||
if (!route_only && dns_name_is_root(name))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
|
||||
|
||||
if (route_only) {
|
||||
prefixed = strjoin("~", name);
|
||||
if (!prefixed)
|
||||
return -ENOMEM;
|
||||
|
||||
name = prefixed;
|
||||
}
|
||||
|
||||
if (!strextend_with_separator(&j, ", ", name, NULL))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = sd_bus_message_rewind(message, false);
|
||||
@ -406,6 +441,11 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
|
||||
(void) link_save_user(l);
|
||||
(void) manager_write_resolv_conf(l->manager);
|
||||
|
||||
if (j)
|
||||
log_link_info(l, "Bus client set search domain list to: %s", j);
|
||||
else
|
||||
log_link_info(l, "Bus client reset search domain list.");
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
|
||||
clear:
|
||||
@ -444,6 +484,8 @@ int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, s
|
||||
(void) manager_write_resolv_conf(l->manager);
|
||||
}
|
||||
|
||||
log_link_info(l, "Bus client set default route setting: %s", yes_no(b));
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
@ -487,6 +529,8 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er
|
||||
|
||||
(void) link_save_user(l);
|
||||
|
||||
log_link_info(l, "Bus client set LLMNR setting: %s", resolve_support_to_string(mode));
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
@ -530,6 +574,8 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err
|
||||
|
||||
(void) link_save_user(l);
|
||||
|
||||
log_link_info(l, "Bus client set MulticastDNS setting: %s", resolve_support_to_string(mode));
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
@ -571,6 +617,9 @@ int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd
|
||||
|
||||
(void) link_save_user(l);
|
||||
|
||||
log_link_info(l, "Bus client set DNSOverTLS setting: %s",
|
||||
mode < 0 ? "default" : dns_over_tls_mode_to_string(mode));
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
@ -612,12 +661,16 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e
|
||||
|
||||
(void) link_save_user(l);
|
||||
|
||||
log_link_info(l, "Bus client set DNSSEC setting: %s",
|
||||
mode < 0 ? "default" : dnssec_mode_to_string(mode));
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_set_free_free_ Set *ns = NULL;
|
||||
_cleanup_strv_free_ char **ntas = NULL;
|
||||
_cleanup_free_ char *j = NULL;
|
||||
Link *l = userdata;
|
||||
int r;
|
||||
char **i;
|
||||
@ -648,6 +701,9 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
|
||||
r = set_put_strdup(&ns, *i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strextend_with_separator(&j, ", ", *i, NULL))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
|
||||
@ -664,6 +720,11 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v
|
||||
|
||||
(void) link_save_user(l);
|
||||
|
||||
if (j)
|
||||
log_link_info(l, "Bus client set NTA list to: %s", j);
|
||||
else
|
||||
log_link_info(l, "Bus client reset NTA list.");
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -313,6 +313,54 @@ static int manager_network_monitor_listen(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_clock_change_listen(Manager *m);
|
||||
|
||||
static int on_clock_change(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
|
||||
assert(m);
|
||||
|
||||
/* The clock has changed, let's flush all caches. Why that? That's because DNSSEC validation takes
|
||||
* the system clock into consideration, and if the clock changes the old validations might have been
|
||||
* wrong. Let's redo all validation with the new, correct time.
|
||||
*
|
||||
* (Also, this is triggered after system suspend, which is also a good reason to drop caches, since
|
||||
* we might be connected to a different network now without this being visible in a dropped link
|
||||
* carrier or so.) */
|
||||
|
||||
log_info("Clock change detected. Flushing caches.");
|
||||
manager_flush_caches(m, LOG_DEBUG /* downgrade the functions own log message, since we already logged here at LOG_INFO level */);
|
||||
|
||||
/* The clock change timerfd is unusable after it triggered once, create a new one. */
|
||||
return manager_clock_change_listen(m);
|
||||
}
|
||||
|
||||
static int manager_clock_change_listen(Manager *m) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
m->clock_change_event_source = sd_event_source_unref(m->clock_change_event_source);
|
||||
|
||||
fd = time_change_fd();
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to allocate clock change timer fd: %m");
|
||||
|
||||
r = sd_event_add_io(m->event, &m->clock_change_event_source, fd, EPOLLIN, on_clock_change, m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create clock change event source: %m");
|
||||
|
||||
r = sd_event_source_set_io_fd_own(m->clock_change_event_source, true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to pass ownership of clock fd to event source: %m");
|
||||
TAKE_FD(fd);
|
||||
|
||||
(void) sd_event_source_set_description(m->clock_change_event_source, "clock-change");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
|
||||
_cleanup_free_ char *h = NULL, *n = NULL;
|
||||
#if HAVE_LIBIDN2
|
||||
@ -549,7 +597,7 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si
|
||||
assert(si);
|
||||
assert(m);
|
||||
|
||||
manager_flush_caches(m);
|
||||
manager_flush_caches(m, LOG_INFO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -593,9 +641,6 @@ int manager_new(Manager **ret) {
|
||||
.read_resolv_conf = true,
|
||||
.need_builtin_fallbacks = true,
|
||||
.etc_hosts_last = USEC_INFINITY,
|
||||
.etc_hosts_mtime = USEC_INFINITY,
|
||||
.etc_hosts_ino = 0,
|
||||
.etc_hosts_dev = 0,
|
||||
.read_etc_hosts = true,
|
||||
};
|
||||
|
||||
@ -642,6 +687,10 @@ int manager_new(Manager **ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_clock_change_listen(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_connect_bus(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -709,6 +758,7 @@ Manager *manager_free(Manager *m) {
|
||||
|
||||
sd_netlink_unref(m->rtnl);
|
||||
sd_event_source_unref(m->rtnl_event_source);
|
||||
sd_event_source_unref(m->clock_change_event_source);
|
||||
|
||||
manager_llmnr_stop(m);
|
||||
manager_mdns_stop(m);
|
||||
@ -1440,7 +1490,7 @@ bool manager_routable(Manager *m) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void manager_flush_caches(Manager *m) {
|
||||
void manager_flush_caches(Manager *m, int log_level) {
|
||||
DnsScope *scope;
|
||||
|
||||
assert(m);
|
||||
@ -1448,7 +1498,7 @@ void manager_flush_caches(Manager *m) {
|
||||
LIST_FOREACH(scopes, scope, m->dns_scopes)
|
||||
dns_cache_flush(&scope->cache);
|
||||
|
||||
log_info("Flushed all caches.");
|
||||
log_full(log_level, "Flushed all caches.");
|
||||
}
|
||||
|
||||
void manager_reset_server_features(Manager *m) {
|
||||
|
||||
@ -129,9 +129,8 @@ struct Manager {
|
||||
|
||||
/* Data from /etc/hosts */
|
||||
EtcHosts etc_hosts;
|
||||
usec_t etc_hosts_last, etc_hosts_mtime;
|
||||
ino_t etc_hosts_ino;
|
||||
dev_t etc_hosts_dev;
|
||||
usec_t etc_hosts_last;
|
||||
struct stat etc_hosts_stat;
|
||||
bool read_etc_hosts;
|
||||
|
||||
OrderedSet *dns_extra_stub_listeners;
|
||||
@ -143,6 +142,8 @@ struct Manager {
|
||||
Hashmap *polkit_registry;
|
||||
|
||||
VarlinkServer *varlink_server;
|
||||
|
||||
sd_event_source *clock_change_event_source;
|
||||
};
|
||||
|
||||
/* Manager */
|
||||
@ -188,7 +189,7 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource
|
||||
|
||||
bool manager_routable(Manager *m);
|
||||
|
||||
void manager_flush_caches(Manager *m);
|
||||
void manager_flush_caches(Manager *m, int log_level);
|
||||
void manager_reset_server_features(Manager *m);
|
||||
|
||||
void manager_cleanup_saved_user(Manager *m);
|
||||
|
||||
@ -58,7 +58,7 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not create runtime directory: %m");
|
||||
|
||||
/* Drop privileges, but keep three caps. Note that we drop those too, later on (see below) */
|
||||
/* 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 */
|
||||
@ -83,7 +83,7 @@ static int run(int argc, char *argv[]) {
|
||||
(void) manager_check_resolv_conf(m);
|
||||
|
||||
/* Let's drop the remaining caps now */
|
||||
r = capability_bounding_set_drop(0, true);
|
||||
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");
|
||||
|
||||
|
||||
@ -1291,8 +1291,14 @@ int dns_name_apply_idna(const char *name, char **ret) {
|
||||
assert(name);
|
||||
assert(ret);
|
||||
|
||||
/* First, try non-transitional mode (i.e. IDN2008 rules) */
|
||||
r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
|
||||
IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
|
||||
if (r == IDN2_DISALLOWED) /* If that failed, because of disallowed characters, try transitional mode.
|
||||
* (i.e. IDN2003 rules which supports some unicode chars IDN2008 doesn't allow). */
|
||||
r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
|
||||
IDN2_NFC_INPUT | IDN2_TRANSITIONAL);
|
||||
|
||||
log_debug("idn2_lookup_u8: %s → %s", name, t);
|
||||
if (r == IDN2_OK) {
|
||||
if (!startswith(name, "xn--")) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user