Compare commits

...

22 Commits

Author SHA1 Message Date
Nick Rosbrook 76019f7589
Merge b818627789 into 4b356c90dc 2024-11-23 15:12:53 +01:00
Ani Sinha 4b356c90dc measure: add 'dtbauto' option in help message
'dtbauto' command line was missing from the help string. Add it.
2024-11-23 12:43:34 +00:00
Léane GRASSER f28e16d14e po: Translated using Weblate (French)
Currently translated at 100.0% (257 of 257 strings)

Co-authored-by: Léane GRASSER <leane.grasser@proton.me>
Translate-URL: https://translate.fedoraproject.org/projects/systemd/main/fr/
Translation: systemd/main
2024-11-23 20:49:18 +09:00
Yu Watanabe 9e05e33871 networkd-test.py: fix interface state checker
After 259125d53d, network interfaces
declared by .netdev files are created after systemd-networkd sends READY
notification. So, even when networkd is started, the netdevs may not
be created yet, and 'ip' command may fail. Let's also check the return
code of the command.

This also
- drops never worked stdout checks,
- makes the test fail if the interface is not created within the timeout.
2024-11-23 17:33:43 +09:00
Lennart Poettering 95116bdfd5 nspawn: improve log message on bad incoming sd_notify() message
It's the PID that is wrong, not the UID/GID, be precise.
2024-11-23 17:33:17 +09:00
Lennart Poettering 2bd290ca02 nspawn: fix userns_mkdir() invocation
The wrong error code was logged.

But actually given that userns_mkdir() is fine with existing dirs, let's
drop the redundant conditionalization.

Follow-up for: a1fcaa1549
2024-11-23 17:33:06 +09:00
Yu Watanabe 1e9fb1d456 shutdown: propagate one more error from sync_making_progress()
No functional change, just refactoring, as anyway all errors will be
ignored by the caller.
2024-11-23 17:32:51 +09:00
Yu Watanabe 56c761f8c6
namespace-util: handle -ENOSPC by userns_acquire() gracefully in is_idmapping_supported() (#35313)
Follow-up for edae62120f.
Fixes #35311.
2024-11-23 17:32:23 +09:00
Yu Watanabe b76730f3fe shutdown: close DM block device before issuing DM_DEV_REMOVE ioctl
Otherwise, the ioctl() may fail with EBUSY.

Follow-up for b4b66b2662.
Hopefully fixes #35243.
2024-11-23 17:31:36 +09:00
Yu Watanabe 3dda236c5c basic/linux: update kernel headers from v6.12 2024-11-23 17:31:12 +09:00
Zbigniew Jędrzejewski-Szmek 5598454a3f Undeprecate commandline params forcequotacheck, fastboot, and forcefsck
Those are historical names, but there is nothing wrong with them. The files on
/ (/fastboot, /forcefsck, and /forcequotacheck) are problematic because they
require a modification of the root file system. But the commandline params work
fine. They have the obvious advantage compared to our "modern" option that they
are much easier to type without looking up the spelling in the docs. Undeprecate
them to avoid unnecessary churn.
2024-11-23 17:30:56 +09:00
Yu Watanabe 2994ca354b namespace-util: update log messages 2024-11-23 06:52:48 +09:00
Yu Watanabe eb14b993bb namespace-util: handle -ENOSPC by userns_acquire() gracefully in is_idmapping_supported()
Follow-up for edae62120f.
Fixes #35311.
2024-11-23 06:52:38 +09:00
Nick Rosbrook b818627789 networkd-test: add basic tests for systemd-networkd-wait-online --dns 2024-11-21 14:44:39 -05:00
Nick Rosbrook 0c405df64a test: add test for resolved SubscribeDNSConfiguration API 2024-11-21 14:44:39 -05:00
Nick Rosbrook 3385de576a test: cleanup after testcase_12_resolvectl2 2024-11-21 14:44:39 -05:00
Nick Rosbrook 007e24be8e wait-online: add support for waiting for DNS configuration
Add a new flag to systemd-networkd-wait-online, --dns, to allow waiting
for DNS to be configured.

DNS is considered configured when at least one DNS server is accessible.
If a link has the property DefaultRoute=yes (either by explicit
configuration, or because there are no routing-only domains), or if the
search domain '.' is configured, wait for link-specific DNS to be
configured. Otherwise, global DNS servers may be considered.
2024-11-21 14:44:39 -05:00
Nick Rosbrook 671c07a8ac resolved: add SubscribeDNSConfiguration to varlink API
Add a new method to io.systemd.Resolve.Monitor that allows subscribing
to changes in the systemd-resolved DNS configuration. The new method
emits the full DNS configuration (one entry for global configuration,
and one entry for each interface), any time the configuration is
updated.
2024-11-21 14:44:39 -05:00
Nick Rosbrook efc0b06a9a resolved: add link_get_default_route helper
The dbus property getter for DefaultRoute does not simply check
link->default_route. Instead, if l->default_route is not explicitly
configured, it checks dns_scope_is_default_route(l->unicast_scope).

Add a link_get_default_route() helper with this logic so that it can be
used for consistency.
2024-11-21 14:44:39 -05:00
Nick Rosbrook df1cc414f3 resolved: add a helper to check if DNS server is accessible
We check this by opening a UDP socket and attempting to connect. We do
not send any traffic on it, but this will tell us if there are routes to
the DNS server.

This will be used in a later commit.
2024-11-21 14:43:52 -05:00
Nick Rosbrook ad68334774 varlink-util: add varlink_many_notify
We already have varlink_many_notifyb. Just re-factor it slightly and add
a plain varlink_many_notify.
2024-11-15 13:44:29 -05:00
Nick Rosbrook 133314b44e resolve: rename varlink_subscription -> varlink_query_results_subscription
No functional change. Make it more clear that these varlink connections
are subscribed to query results. This prepares for adding SubscribeDNS
to the varlink API.
2024-11-15 13:44:29 -05:00
44 changed files with 1216 additions and 149 deletions

View File

@ -144,6 +144,22 @@
<xi:include href="version-info.xml" xpointer="v249"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--dns</option></term>
<listitem><para>Waiting for DNS servers to be accessible on each interface. If this
option is specified with <option>--any</option>, then
<command>systemd-networkd-wait-online</command> exits with success when at least one interface
becomes online and has an accessible DNS server.</para>
<para>If a link has the property <varname>DefaultRoute=yes</varname> (either because the
<varname>DNSDefaultRoute=</varname> network property is explicitly configured, or
because the link does not have any "routing-only" domains), or if the search domain "." is
configured, then wait for link-specific DNS servers to be accessible. Otherwise, allow global
DNS servers to satisfy the condition.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--any</option></term>

View File

@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-06 14:42+0000\n"
"PO-Revision-Date: 2024-11-20 19:13+0000\n"
"PO-Revision-Date: 2024-11-23 10:38+0000\n"
"Last-Translator: Léane GRASSER <leane.grasser@proton.me>\n"
"Language-Team: French <https://translate.fedoraproject.org/projects/systemd/"
"main/fr/>\n"
@ -1258,7 +1258,7 @@ msgstr ""
#: src/sysupdate/org.freedesktop.sysupdate1.policy:75
msgid "Manage optional features"
msgstr "Gérer les fonctionnalités en option"
msgstr "Gérer les fonctionnalités facultatives"
#: src/sysupdate/org.freedesktop.sysupdate1.policy:76
msgid "Authentication is required to manage optional features"

View File

@ -21,7 +21,7 @@
#define AUTOFS_MIN_PROTO_VERSION 3
#define AUTOFS_MAX_PROTO_VERSION 5
#define AUTOFS_PROTO_SUBVERSION 5
#define AUTOFS_PROTO_SUBVERSION 6
/*
* The wait_queue_token (autofs_wqt_t) is part of a structure which is passed

View File

@ -1121,6 +1121,9 @@ enum bpf_attach_type {
#define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE
/* Add BPF_LINK_TYPE(type, name) in bpf_types.h to keep bpf_link_type_strs[]
* in sync with the definitions below.
*/
enum bpf_link_type {
BPF_LINK_TYPE_UNSPEC = 0,
BPF_LINK_TYPE_RAW_TRACEPOINT = 1,
@ -2851,7 +2854,7 @@ union bpf_attr {
* **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**,
* **TCP_NODELAY**, **TCP_MAXSEG**, **TCP_WINDOW_CLAMP**,
* **TCP_THIN_LINEAR_TIMEOUTS**, **TCP_BPF_DELACK_MAX**,
* **TCP_BPF_RTO_MIN**.
* **TCP_BPF_RTO_MIN**, **TCP_BPF_SOCK_OPS_CB_FLAGS**.
* * **IPPROTO_IP**, which supports *optname* **IP_TOS**.
* * **IPPROTO_IPV6**, which supports the following *optname*\ s:
* **IPV6_TCLASS**, **IPV6_AUTOFLOWLABEL**.
@ -5519,11 +5522,12 @@ union bpf_attr {
* **-EOPNOTSUPP** if the hash calculation failed or **-EINVAL** if
* invalid arguments are passed.
*
* void *bpf_kptr_xchg(void *map_value, void *ptr)
* void *bpf_kptr_xchg(void *dst, void *ptr)
* Description
* Exchange kptr at pointer *map_value* with *ptr*, and return the
* old value. *ptr* can be NULL, otherwise it must be a referenced
* pointer which will be released when this helper is called.
* Exchange kptr at pointer *dst* with *ptr*, and return the old value.
* *dst* can be map value or local kptr. *ptr* can be NULL, otherwise
* it must be a referenced pointer which will be released when this helper
* is called.
* Return
* The old value of kptr (which can be NULL). The returned pointer
* if not NULL, is a reference which must be released using its
@ -6046,11 +6050,6 @@ enum {
BPF_F_MARK_ENFORCE = (1ULL << 6),
};
/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
enum {
BPF_F_INGRESS = (1ULL << 0),
};
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */
enum {
BPF_F_TUNINFO_IPV6 = (1ULL << 0),
@ -6197,10 +6196,12 @@ enum {
BPF_F_BPRM_SECUREEXEC = (1ULL << 0),
};
/* Flags for bpf_redirect_map helper */
/* Flags for bpf_redirect and bpf_redirect_map helpers */
enum {
BPF_F_BROADCAST = (1ULL << 3),
BPF_F_EXCLUDE_INGRESS = (1ULL << 4),
BPF_F_INGRESS = (1ULL << 0), /* used for skb path */
BPF_F_BROADCAST = (1ULL << 3), /* used for XDP path */
BPF_F_EXCLUDE_INGRESS = (1ULL << 4), /* used for XDP path */
#define BPF_F_REDIRECT_FLAGS (BPF_F_INGRESS | BPF_F_BROADCAST | BPF_F_EXCLUDE_INGRESS)
};
#define __bpf_md_ptr(type, name) \
@ -7080,6 +7081,7 @@ enum {
TCP_BPF_SYN = 1005, /* Copy the TCP header */
TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */
TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */
TCP_BPF_SOCK_OPS_CB_FLAGS = 1008, /* Get or Set TCP sock ops flags */
};
enum {
@ -7512,4 +7514,13 @@ struct bpf_iter_num {
__u64 __opaque[1];
} __attribute__((aligned(8)));
/*
* Flags to control BPF kfunc behaviour.
* - BPF_F_PAD_ZEROS: Pad destination buffer with zeros. (See the respective
* helper documentation for details.)
*/
enum bpf_kfunc_flags {
BPF_F_PAD_ZEROS = (1ULL << 0),
};
#endif /* __LINUX_BPF_H__ */

View File

@ -28,6 +28,23 @@
#define _BITUL(x) (_UL(1) << (x))
#define _BITULL(x) (_ULL(1) << (x))
#if !defined(__ASSEMBLY__)
/*
* Missing __asm__ support
*
* __BIT128() would not work in the __asm__ code, as it shifts an
* 'unsigned __init128' data type as direct representation of
* 128 bit constants is not supported in the gcc compiler, as
* they get silently truncated.
*
* TODO: Please revisit this implementation when gcc compiler
* starts representing 128 bit constants directly like long
* and unsigned long etc. Subsequently drop the comment for
* GENMASK_U128() which would then start supporting __asm__ code.
*/
#define _BIT128(x) ((unsigned __int128)(1) << (x))
#endif
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))

View File

@ -2531,4 +2531,20 @@ struct ethtool_link_settings {
* __u32 map_lp_advertising[link_mode_masks_nwords];
*/
};
/**
* enum phy_upstream - Represents the upstream component a given PHY device
* is connected to, as in what is on the other end of the MII bus. Most PHYs
* will be attached to an Ethernet MAC controller, but in some cases, there's
* an intermediate PHY used as a media-converter, which will driver another
* MII interface as its output.
* @PHY_UPSTREAM_MAC: Upstream component is a MAC (a switch port,
* or ethernet controller)
* @PHY_UPSTREAM_PHY: Upstream component is a PHY (likely a media converter)
*/
enum phy_upstream {
PHY_UPSTREAM_MAC,
PHY_UPSTREAM_PHY,
};
#endif /* _LINUX_ETHTOOL_H */

View File

@ -67,6 +67,7 @@ enum {
FRA_IP_PROTO, /* ip proto */
FRA_SPORT_RANGE, /* sport */
FRA_DPORT_RANGE, /* dport */
FRA_DSCP, /* dscp */
__FRA_MAX
};

View File

@ -230,8 +230,8 @@ struct tpacket_hdr_v1 {
* ts_first_pkt:
* Is always the time-stamp when the block was opened.
* Case a) ZERO packets
* No packets to deal with but atleast you know the
* time-interval of this block.
* No packets to deal with but at least you know
* the time-interval of this block.
* Case b) Non-zero packets
* Use the ts of the first packet in the block.
*
@ -265,7 +265,8 @@ enum tpacket_versions {
- struct tpacket_hdr
- pad to TPACKET_ALIGNMENT=16
- struct sockaddr_ll
- Gap, chosen so that packet data (Start+tp_net) alignes to TPACKET_ALIGNMENT=16
- Gap, chosen so that packet data (Start+tp_net) aligns to
TPACKET_ALIGNMENT=16
- Start+tp_mac: [ Optional MAC header ]
- Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16.
- Pad to align to TPACKET_ALIGNMENT=16

View File

@ -141,7 +141,7 @@ struct in_addr {
*/
#define IP_PMTUDISC_INTERFACE 4
/* weaker version of IP_PMTUDISC_INTERFACE, which allows packets to get
* fragmented if they exeed the interface mtu
* fragmented if they exceed the interface mtu
*/
#define IP_PMTUDISC_OMIT 5

View File

@ -140,25 +140,6 @@
#endif /* _NETINET_IN_H */
/* Coordinate with glibc netipx/ipx.h header. */
#if defined(__NETIPX_IPX_H)
#define __UAPI_DEF_SOCKADDR_IPX 0
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 0
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 0
#define __UAPI_DEF_IPX_CONFIG_DATA 0
#define __UAPI_DEF_IPX_ROUTE_DEF 0
#else /* defined(__NETIPX_IPX_H) */
#define __UAPI_DEF_SOCKADDR_IPX 1
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1
#define __UAPI_DEF_IPX_CONFIG_DATA 1
#define __UAPI_DEF_IPX_ROUTE_DEF 1
#endif /* defined(__NETIPX_IPX_H) */
/* Definitions for xattr.h */
#if defined(_SYS_XATTR_H)
#define __UAPI_DEF_XATTR 0
@ -240,23 +221,6 @@
#define __UAPI_DEF_IP6_MTUINFO 1
#endif
/* Definitions for ipx.h */
#ifndef __UAPI_DEF_SOCKADDR_IPX
#define __UAPI_DEF_SOCKADDR_IPX 1
#endif
#ifndef __UAPI_DEF_IPX_ROUTE_DEFINITION
#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1
#endif
#ifndef __UAPI_DEF_IPX_INTERFACE_DEFINITION
#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1
#endif
#ifndef __UAPI_DEF_IPX_CONFIG_DATA
#define __UAPI_DEF_IPX_CONFIG_DATA 1
#endif
#ifndef __UAPI_DEF_IPX_ROUTE_DEF
#define __UAPI_DEF_IPX_ROUTE_DEF 1
#endif
/* Definitions for xattr.h */
#ifndef __UAPI_DEF_XATTR
#define __UAPI_DEF_XATTR 1

View File

@ -436,7 +436,7 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
* @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
* @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
* @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
* @NFTA_SET_ELEM_TIMEOUT: timeout value, zero means never times out (NLA_U64)
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
@ -1694,7 +1694,7 @@ enum nft_flowtable_flags {
*
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
* @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration (NLA_NESTED)
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
* @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
* @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)

View File

@ -16,10 +16,15 @@ struct nhmsg {
struct nexthop_grp {
__u32 id; /* nexthop id - must exist */
__u8 weight; /* weight of this nexthop */
__u8 resvd1;
__u8 weight_high; /* high order bits of weight */
__u16 resvd2;
};
static __inline__ __u16 nexthop_grp_weight(const struct nexthop_grp *entry)
{
return ((entry->weight_high << 8) | entry->weight) + 1;
}
enum {
NEXTHOP_GRP_TYPE_MPATH, /* hash-threshold nexthop group
* default type if not specified
@ -33,6 +38,9 @@ enum {
#define NHA_OP_FLAG_DUMP_STATS BIT(0)
#define NHA_OP_FLAG_DUMP_HW_STATS BIT(1)
/* Response OP_FLAGS. */
#define NHA_OP_FLAG_RESP_GRP_RESVD_0 BIT(31) /* Dump clears resvd fields. */
enum {
NHA_UNSPEC,
NHA_ID, /* u32; id for nexthop. id == 0 means auto-assign */

View File

@ -531,20 +531,24 @@ int is_idmapping_supported(const char *path) {
userns_fd = userns_acquire(uid_map, gid_map);
if (ERRNO_IS_NEG_NOT_SUPPORTED(userns_fd) || ERRNO_IS_NEG_PRIVILEGE(userns_fd))
return false;
if (userns_fd == -ENOSPC) {
log_debug_errno(userns_fd, "Failed to acquire new user namespace, user.max_user_namespaces seems to be exhausted or maybe even zero, assuming ID-mapping is not supported: %m");
return false;
}
if (userns_fd < 0)
return log_debug_errno(userns_fd, "ID-mapping supported namespace acquire failed for '%s' : %m", path);
return log_debug_errno(userns_fd, "Failed to acquire new user namespace for checking if '%s' supports ID-mapping: %m", path);
dir_fd = RET_NERRNO(open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
if (ERRNO_IS_NEG_NOT_SUPPORTED(dir_fd))
return false;
if (dir_fd < 0)
return log_debug_errno(dir_fd, "ID-mapping supported open failed for '%s' : %m", path);
return log_debug_errno(dir_fd, "Failed to open '%s', cannot determine if ID-mapping is supported: %m", path);
mount_fd = RET_NERRNO(open_tree(dir_fd, "", AT_EMPTY_PATH | OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC));
if (ERRNO_IS_NEG_NOT_SUPPORTED(mount_fd) || ERRNO_IS_NEG_PRIVILEGE(mount_fd) || mount_fd == -EINVAL)
return false;
if (mount_fd < 0)
return log_debug_errno(mount_fd, "ID-mapping supported open_tree failed for '%s' : %m", path);
return log_debug_errno(mount_fd, "Failed to open mount tree '%s', cannot determine if ID-mapping is supported: %m", path);
r = RET_NERRNO(mount_setattr(mount_fd, "", AT_EMPTY_PATH,
&(struct mount_attr) {
@ -554,7 +558,7 @@ int is_idmapping_supported(const char *path) {
if (ERRNO_IS_NEG_NOT_SUPPORTED(r) || ERRNO_IS_NEG_PRIVILEGE(r) || r == -EINVAL)
return false;
if (r < 0)
return log_debug_errno(r, "ID-mapping supported setattr failed for '%s' : %m", path);
return log_debug_errno(r, "Failed to set mount attribute to '%s', cannot determine if ID-mapping is supported: %m", path);
return true;
}

View File

@ -98,16 +98,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
}
}
#if HAVE_SYSV_COMPAT
else if (streq(key, "fastboot") && !value) {
log_warning("Please pass 'fsck.mode=skip' rather than 'fastboot' on the kernel command line.");
else if (streq(key, "fastboot") && !value)
arg_skip = true;
} else if (streq(key, "forcefsck") && !value) {
log_warning("Please pass 'fsck.mode=force' rather than 'forcefsck' on the kernel command line.");
else if (streq(key, "forcefsck") && !value)
arg_force = true;
}
#endif
return 0;
}

View File

@ -86,6 +86,19 @@ int varlink_callb_and_log(
return varlink_call_and_log(v, method, parameters, ret_parameters);
}
int varlink_many_notify(Set *s, sd_json_variant *parameters) {
sd_varlink *link;
int r = 1;
if (set_isempty(s))
return 0;
SET_FOREACH(link, s)
RET_GATHER(r, sd_varlink_notify(link, parameters));
return r;
}
int varlink_many_notifyb(Set *s, ...) {
int r;
@ -102,12 +115,7 @@ int varlink_many_notifyb(Set *s, ...) {
if (r < 0)
return r;
r = 1;
sd_varlink *link;
SET_FOREACH(link, s)
RET_GATHER(r, sd_varlink_notify(link, parameters));
return r;
return varlink_many_notify(s, parameters);
}
int varlink_many_reply(Set *s, sd_json_variant *parameters) {

View File

@ -13,6 +13,7 @@ int varlink_callb_and_log(sd_varlink *v, const char *method, sd_json_variant **r
#define varlink_callbo_and_log(v, method, ret_parameters, ...) \
varlink_callb_and_log((v), (method), (ret_parameters), SD_JSON_BUILD_OBJECT(__VA_ARGS__))
int varlink_many_notify(Set *s, sd_json_variant *parameters);
int varlink_many_notifyb(Set *s, ...);
#define varlink_many_notifybo(s, ...) \
varlink_many_notifyb((s), SD_JSON_BUILD_OBJECT(__VA_ARGS__))

View File

@ -108,6 +108,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --ucode=PATH Path to microcode image file %7$s .ucode\n"
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
" --dtb=PATH Path to DeviceTree file %7$s .dtb\n"
" --dtbauto=PATH Path to DeviceTree file for auto selection %7$s .dtbauto\n"
" --uname=PATH Path to 'uname -r' file %7$s .uname\n"
" --sbat=PATH Path to SBAT file %7$s .sbat\n"
" --pcrpkey=PATH Path to public key for PCR signatures %7$s .pcrpkey\n"

View File

@ -114,6 +114,7 @@ sources = files(
systemd_networkd_sources = files('networkd.c')
systemd_networkd_wait_online_sources = files(
'wait-online/dns-configuration.c',
'wait-online/link.c',
'wait-online/manager.c',
'wait-online/wait-online.c',

View File

@ -0,0 +1,244 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-json.h"
#include "alloc-util.h"
#include "dns-configuration.h"
#include "iovec-util.h"
#include "hash-funcs.h"
#include "json-util.h"
#include "set.h"
#include "strv.h"
DNSServer *dns_server_free(DNSServer *s) {
if (!s)
return NULL;
free(s->server_name);
return mfree(s);
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
dns_server_hash_ops,
void,
trivial_hash_func,
trivial_compare_func,
DNSServer,
dns_server_free);
static int dispatch_dns_server(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dns_server_dispatch_table[] = {
{ "address", SD_JSON_VARIANT_ARRAY, NULL, 0, SD_JSON_MANDATORY },
{ "family", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(DNSServer, family), SD_JSON_MANDATORY },
{ "port", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint16, offsetof(DNSServer, port), 0 },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSServer, ifindex), SD_JSON_RELAX },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSServer, server_name), 0 },
{ "accessible", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSServer, accessible), SD_JSON_MANDATORY },
{},
};
DNSServer **ret = ASSERT_PTR(userdata);
_cleanup_(dns_server_freep) DNSServer *s = NULL;
_cleanup_(iovec_done) struct iovec iov = {};
int r;
s = new0(DNSServer, 1);
if (!s)
return log_oom();
r = sd_json_dispatch(variant, dns_server_dispatch_table, flags, s);
if (r < 0)
return r;
/* We ignored the address field above. Handle it now. */
r = json_dispatch_byte_array_iovec("address", sd_json_variant_by_key(variant, "address"), flags, &iov);
if (r < 0)
return r;
if (iov.iov_len != FAMILY_ADDRESS_SIZE_SAFE(s->family))
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field 'address' is array of unexpected size.");
memcpy(&s->addr, iov.iov_base, iov.iov_len);
*ret = TAKE_PTR(s);
return 0;
}
static int dispatch_dns_server_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
Set **ret = ASSERT_PTR(userdata);
Set *dns_servers;
sd_json_variant *v = NULL;
int r;
dns_servers = set_new(&dns_server_hash_ops);
if (!dns_servers)
return log_oom();
JSON_VARIANT_ARRAY_FOREACH(v, variant) {
_cleanup_(dns_server_freep) DNSServer *s = NULL;
s = new0(DNSServer, 1);
if (!s)
return log_oom();
r = dispatch_dns_server(name, v, flags, &s);
if (r < 0)
return json_log(v, flags, r, "JSON array element is not a valid DNSServer.");
r = set_put(dns_servers, TAKE_PTR(s));
if (r < 0)
return log_oom();
}
set_free_and_replace(*ret, dns_servers);
return 0;
}
SearchDomain *search_domain_free(SearchDomain *d) {
if (!d)
return NULL;
free(d->name);
return mfree(d);
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
search_domain_hash_ops,
void,
trivial_hash_func,
trivial_compare_func,
SearchDomain,
search_domain_free);
static int dispatch_search_domain(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
static const sd_json_dispatch_field search_domain_dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(SearchDomain, name), SD_JSON_MANDATORY },
{ "routeOnly", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(SearchDomain, route_only), SD_JSON_MANDATORY },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(SearchDomain, ifindex), SD_JSON_RELAX },
{},
};
SearchDomain **ret = ASSERT_PTR(userdata);
_cleanup_(search_domain_freep) SearchDomain *d = NULL;
int r;
d = new0(SearchDomain, 1);
if (!d)
return log_oom();
r = sd_json_dispatch(variant, search_domain_dispatch_table, flags, d);
if (r < 0)
return r;
*ret = TAKE_PTR(d);
return 0;
}
static int dispatch_search_domain_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
Set **ret = ASSERT_PTR(userdata);
Set *search_domains;
sd_json_variant *v = NULL;
int r;
search_domains = set_new(&search_domain_hash_ops);
if (!search_domains)
return log_oom();
JSON_VARIANT_ARRAY_FOREACH(v, variant) {
_cleanup_(search_domain_freep) SearchDomain *d = NULL;
d = new0(SearchDomain, 1);
if (!d)
return log_oom();
r = dispatch_search_domain(name, v, flags, &d);
if (r < 0)
return json_log(v, flags, r, "JSON array element is not a valid SearchDomain.");
r = set_put(search_domains, TAKE_PTR(d));
if (r < 0)
return log_oom();
}
set_free_and_replace(*ret, search_domains);
return 0;
}
DNSConfiguration *dns_configuration_free(DNSConfiguration *c) {
if (!c)
return NULL;
dns_server_free(c->current_dns_server);
set_free(c->dns_servers);
set_free(c->search_domains);
free(c->ifname);
return mfree(c);
}
static int dispatch_dns_configuration(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dns_configuration_dispatch_table[] = {
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSConfiguration, ifname), 0 },
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSConfiguration, ifindex), SD_JSON_RELAX },
{ "defaultRoute", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DNSConfiguration, default_route), 0 },
{ "currentServer", SD_JSON_VARIANT_OBJECT, dispatch_dns_server, offsetof(DNSConfiguration, current_dns_server), 0 },
{ "servers", SD_JSON_VARIANT_ARRAY, dispatch_dns_server_array, offsetof(DNSConfiguration, dns_servers), 0 },
{ "searchDomains", SD_JSON_VARIANT_ARRAY, dispatch_search_domain_array, offsetof(DNSConfiguration, search_domains), 0 },
{},
};
DNSConfiguration **ret = ASSERT_PTR(userdata);
_cleanup_(dns_configuration_freep) DNSConfiguration *c = NULL;
int r;
c = new0(DNSConfiguration, 1);
if (!c)
return log_oom();
r = sd_json_dispatch(variant, dns_configuration_dispatch_table, flags, c);
if (r < 0)
return r;
*ret = TAKE_PTR(c);
return 0;
}
int dns_configuration_from_json(sd_json_variant *variant, DNSConfiguration **ret) {
return dispatch_dns_configuration(NULL, variant, SD_JSON_LOG, ret);
}
bool dns_is_accessible(DNSConfiguration *c) {
DNSServer *s = NULL;
if (!c)
return false;
if (c->current_dns_server && c->current_dns_server->accessible)
return true;
SET_FOREACH(s, c->dns_servers)
if (s->accessible)
return true;
return false;
}
bool dns_configuration_contains_search_domain(DNSConfiguration *c, const char *domain) {
SearchDomain *d = NULL;
assert(domain);
if (!c)
return false;
SET_FOREACH(d, c->search_domains)
if (streq(d->name, domain))
return true;
return false;
}

View File

@ -0,0 +1,49 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-json.h"
#include "in-addr-util.h"
#include "macro-fundamental.h"
#include "set.h"
typedef struct DNSServer DNSServer;
typedef struct SearchDomain SearchDomain;
typedef struct DNSConfiguration DNSConfiguration;
struct DNSServer {
union in_addr_union addr;
int family;
uint16_t port;
int ifindex;
char *server_name;
bool accessible;
};
DNSServer *dns_server_free(DNSServer *s);
DEFINE_TRIVIAL_CLEANUP_FUNC(DNSServer*, dns_server_free);
struct SearchDomain {
char *name;
bool route_only;
int ifindex;
};
SearchDomain *search_domain_free(SearchDomain *d);
DEFINE_TRIVIAL_CLEANUP_FUNC(SearchDomain*, search_domain_free);
struct DNSConfiguration {
char *ifname;
int ifindex;
bool default_route;
DNSServer *current_dns_server;
Set *dns_servers;
Set *search_domains;
};
int dns_configuration_from_json(sd_json_variant *variant, DNSConfiguration **ret);
bool dns_is_accessible(DNSConfiguration *c);
bool dns_configuration_contains_search_domain(DNSConfiguration *c, const char *domain);
DNSConfiguration *dns_configuration_free(DNSConfiguration *c);
DEFINE_TRIVIAL_CLEANUP_FUNC(DNSConfiguration*, dns_configuration_free);

View File

@ -3,6 +3,7 @@
#include "sd-network.h"
#include "alloc-util.h"
#include "dns-configuration.h"
#include "format-ifname.h"
#include "hashmap.h"
#include "link.h"
@ -62,6 +63,8 @@ Link *link_free(Link *l) {
hashmap_remove(l->manager->links_by_name, *n);
}
dns_configuration_free(l->dns_configuration);
free(l->state);
free(l->ifname);
strv_free(l->altnames);

View File

@ -3,6 +3,7 @@
#include "sd-netlink.h"
#include "dns-configuration.h"
#include "log-link.h"
#include "network-util.h"
@ -24,6 +25,7 @@ struct Link {
LinkAddressState ipv4_address_state;
LinkAddressState ipv6_address_state;
char *state;
DNSConfiguration *dns_configuration;
};
int link_new(Manager *m, Link **ret, int ifindex, const char *ifname);

View File

@ -4,7 +4,13 @@
#include <linux/if.h>
#include <fnmatch.h>
#include "sd-event.h"
#include "sd-json.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "dns-configuration.h"
#include "json-util.h"
#include "link.h"
#include "manager.h"
#include "netlink-util.h"
@ -133,6 +139,26 @@ static int manager_link_is_online(Manager *m, Link *l, const LinkOperationalStat
"No routable IPv6 address is configured.");
}
if (m->requires_dns) {
if (!l->dns_configuration)
return log_link_debug_errno(l, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"No DNS configuration yet");
/* If a link is configured with DNSDefaultRoute=yes, or is configured with the
* search domain '.', then require link-specific DNS servers to be available.
* Otherwise, we check the global DNS configuration. */
if (l->dns_configuration->default_route ||
dns_configuration_contains_search_domain(l->dns_configuration, ".")) {
if (!dns_is_accessible(l->dns_configuration))
return log_link_debug_errno(l, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"No link-specific DNS server is accessible.");
} else if (!dns_is_accessible(m->dns_configuration))
return log_link_debug_errno(l, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"No DNS server is accessible.");
}
log_link_debug(l, "link is configured by networkd and online.");
return true;
}
@ -381,13 +407,102 @@ static int manager_network_monitor_listen(Manager *m) {
return 0;
}
static int on_dns_configuration_event(
sd_varlink *link,
sd_json_variant *parameters,
const char *error_id,
sd_varlink_reply_flags_t flags,
void *userdata) {
Manager *m = ASSERT_PTR(userdata);
sd_json_variant *configurations = NULL, *v = NULL;
int r;
assert(link);
if (error_id) {
log_warning("DNS configuration event error, ignoring: %s", error_id);
return 0;
}
configurations = sd_json_variant_by_key(parameters, "configuration");
if (!sd_json_variant_is_array(configurations)) {
log_warning("DNS configuration JSON data does not have configuration key, ignoring.");
return 0;
}
JSON_VARIANT_ARRAY_FOREACH(v, configurations) {
_cleanup_(dns_configuration_freep) DNSConfiguration *c = NULL;
r = dns_configuration_from_json(v, &c);
if (r < 0) {
log_warning_errno(r, "Failed to get DNS configuration JSON, ignoring: %m");
continue;
}
if (c->ifindex > 0) {
Link *l = hashmap_get(m->links_by_index, INT_TO_PTR(c->ifindex));
if (l)
free_and_replace_full(l->dns_configuration, c, dns_configuration_free);
} else
/* Global DNS configuration */
free_and_replace_full(m->dns_configuration, c, dns_configuration_free);
}
if (manager_configured(m))
sd_event_exit(m->event, 0);
return 0;
}
static int manager_dns_configuration_listen(Manager *m) {
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
int r;
assert(m);
assert(m->event);
if (!m->requires_dns)
return 0;
r = sd_varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
if (r < 0)
return log_error_errno(r, "Failed to connect to io.systemd.Resolve.Monitor: %m");
r = sd_varlink_set_relative_timeout(vl, USEC_INFINITY);
if (r < 0)
return log_error_errno(r, "Failed to set varlink timeout: %m");
r = sd_varlink_attach_event(vl, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
(void) sd_varlink_set_userdata(vl, m);
r = sd_varlink_bind_reply(vl, on_dns_configuration_event);
if (r < 0)
return log_error_errno(r, "Failed to bind varlink reply callback: %m");
r = sd_varlink_observebo(
vl,
"io.systemd.Resolve.Monitor.SubscribeDNSConfiguration",
SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", false));
if (r < 0)
return log_error_errno(r, "Failed to issue SubscribeDNSConfiguration: %m");
m->varlink_client = TAKE_PTR(vl);
return 0;
}
int manager_new(Manager **ret,
Hashmap *command_line_interfaces_by_name,
char **ignored_interfaces,
LinkOperationalStateRange required_operstate,
AddressFamily required_family,
bool any,
usec_t timeout) {
usec_t timeout,
bool requires_dns) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@ -404,6 +519,7 @@ int manager_new(Manager **ret,
.required_operstate = required_operstate,
.required_family = required_family,
.any = any,
.requires_dns = requires_dns,
};
r = sd_event_default(&m->event);
@ -428,6 +544,10 @@ int manager_new(Manager **ret,
if (r < 0)
return r;
r = manager_dns_configuration_listen(m);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
@ -445,6 +565,9 @@ Manager* manager_free(Manager *m) {
sd_event_source_unref(m->rtnl_event_source);
sd_netlink_unref(m->rtnl);
sd_event_unref(m->event);
sd_varlink_unref(m->varlink_client);
dns_configuration_free(m->dns_configuration);
return mfree(m);
}

View File

@ -4,7 +4,9 @@
#include "sd-event.h"
#include "sd-netlink.h"
#include "sd-network.h"
#include "sd-varlink.h"
#include "dns-configuration.h"
#include "hashmap.h"
#include "network-util.h"
#include "time-util.h"
@ -23,6 +25,7 @@ struct Manager {
LinkOperationalStateRange required_operstate;
AddressFamily required_family;
bool any;
bool requires_dns;
sd_netlink *rtnl;
sd_event_source *rtnl_event_source;
@ -31,13 +34,16 @@ struct Manager {
sd_event_source *network_monitor_event_source;
sd_event *event;
sd_varlink *varlink_client;
DNSConfiguration *dns_configuration;
};
Manager* manager_free(Manager *m);
int manager_new(Manager **ret, Hashmap *command_line_interfaces_by_name, char **ignored_interfaces,
LinkOperationalStateRange required_operstate,
AddressFamily required_family,
bool any, usec_t timeout);
bool any, usec_t timeout, bool requires_dns);
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);

View File

@ -10,6 +10,7 @@
#include "daemon-util.h"
#include "main-func.h"
#include "manager.h"
#include "parse-argument.h"
#include "pretty-print.h"
#include "signal-util.h"
#include "socket-util.h"
@ -22,6 +23,7 @@ static char **arg_ignore = NULL;
static LinkOperationalStateRange arg_required_operstate = LINK_OPERSTATE_RANGE_INVALID;
static AddressFamily arg_required_family = ADDRESS_FAMILY_NO;
static bool arg_any = false;
static bool arg_requires_dns = false;
STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_freep);
STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep);
@ -48,6 +50,7 @@ static int help(void) {
" -6 --ipv6 Requires at least one IPv6 address\n"
" --any Wait until at least one of the interfaces is online\n"
" --timeout=SECS Maximum time to wait for network connectivity\n"
" --dns Requires at least one DNS server to be accessible\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
link);
@ -106,6 +109,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_IGNORE,
ARG_ANY,
ARG_TIMEOUT,
ARG_DNS,
};
static const struct option options[] = {
@ -119,6 +123,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "ipv6", no_argument, NULL, '6' },
{ "any", no_argument, NULL, ARG_ANY },
{ "timeout", required_argument, NULL, ARG_TIMEOUT },
{ "dns", optional_argument, NULL, ARG_DNS },
{}
};
@ -178,6 +183,12 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
case ARG_DNS:
r = parse_boolean_argument("--dns", optarg, &arg_requires_dns);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
@ -204,7 +215,14 @@ static int run(int argc, char *argv[]) {
if (arg_quiet)
log_set_max_level(LOG_ERR);
r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_required_family, arg_any, arg_timeout);
r = manager_new(&m,
arg_interfaces,
arg_ignore,
arg_required_operstate,
arg_required_family,
arg_any,
arg_timeout,
arg_requires_dns);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");

View File

@ -2280,10 +2280,9 @@ static int copy_devnode_one(const char *dest, const char *node, bool ignore_mkno
r = path_extract_directory(from, &parent);
if (r < 0)
return log_error_errno(r, "Failed to extract directory from %s: %m", from);
if (!path_equal(parent, "/dev/")) {
if (userns_mkdir(dest, parent, 0755, 0, 0) < 0)
r = userns_mkdir(dest, parent, 0755, 0, 0);
if (r < 0)
return log_error_errno(r, "Failed to create directory %s: %m", parent);
}
if (mknod(to, st.st_mode, st.st_rdev) < 0) {
r = -errno; /* Save the original error code. */
@ -4654,7 +4653,7 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
ucred = CMSG_FIND_DATA(&msghdr, SOL_SOCKET, SCM_CREDENTIALS, struct ucred);
if (!ucred || ucred->pid != inner_child_pid) {
log_debug("Received notify message without valid credentials. Ignoring.");
log_debug("Received notify message from process that is not the payload's PID 1. Ignoring.");
return 0;
}

View File

@ -36,14 +36,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
arg_skip = true;
else
log_warning("Invalid quotacheck.mode= value, ignoring: %s", value);
}
#if HAVE_SYSV_COMPAT
else if (streq(key, "forcequotacheck") && !value) {
log_warning("Please use 'quotacheck.mode=force' rather than 'forcequotacheck' on the kernel command line. Proceeding anyway.");
} else if (streq(key, "forcequotacheck") && !value)
arg_force = true;
}
#endif
return 0;
}

View File

@ -150,6 +150,17 @@
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
</action>
<action id="org.freedesktop.resolve1.subscribe-dns-configuration">
<description gettext-domain="systemd">Subscribe to DNS configuration</description>
<message gettext-domain="systemd">Authentication is required to subscribe to DNS configuration.</message>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-resolve</annotate>
</action>
<action id="org.freedesktop.resolve1.dump-cache">
<description gettext-domain="systemd">Dump cache</description>
<message gettext-domain="systemd">Authentication is required to dump cache.</message>

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-json.h"
#include "alloc-util.h"
#include "dns-domain.h"
#include "resolved-dns-search-domain.h"
@ -197,3 +199,21 @@ int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDo
*ret = NULL;
return 0;
}
int dns_search_domain_dump_to_json(DnsSearchDomain *domain, sd_json_variant **ret) {
int ifindex = 0;
assert(domain);
assert(ret);
if (domain->type == DNS_SEARCH_DOMAIN_LINK) {
assert(domain->link);
ifindex = domain->link->ifindex;
}
return sd_json_buildo(
ret,
SD_JSON_BUILD_PAIR_STRING("name", domain->name),
SD_JSON_BUILD_PAIR_BOOLEAN("routeOnly", domain->route_only),
SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)));
}

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-json.h"
#include "list.h"
#include "macro.h"
@ -54,3 +56,5 @@ static inline const char* DNS_SEARCH_DOMAIN_NAME(DnsSearchDomain *d) {
}
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsSearchDomain*, dns_search_domain_unref);
int dns_search_domain_dump_to_json(DnsSearchDomain *domain, sd_json_variant **ret);

View File

@ -1,14 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <net/if_arp.h>
#include "sd-messages.h"
#include "alloc-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "json-util.h"
#include "resolved-bus.h"
#include "resolved-dns-server.h"
#include "resolved-dns-stub.h"
#include "resolved-manager.h"
#include "resolved-resolv-conf.h"
#include "siphash24.h"
#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
@ -69,6 +75,7 @@ int dns_server_new(
.ifindex = ifindex,
.server_name = TAKE_PTR(name),
.config_source = config_source,
.accessible = -1,
};
dns_server_reset_features(s);
@ -875,6 +882,7 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
dns_cache_flush(&m->unicast_scope->cache);
(void) manager_send_changed(m, "CurrentDNSServer");
(void) manager_send_dns_configuration_changed(m);
return s;
}
@ -1128,3 +1136,55 @@ int dns_server_dump_state_to_json(DnsServer *server, sd_json_variant **ret) {
SD_JSON_BUILD_PAIR_BOOLEAN("PacketInvalid", server->packet_invalid),
SD_JSON_BUILD_PAIR_BOOLEAN("PacketDoOff", server->packet_do_off));
}
int dns_server_is_accessible(DnsServer *s) {
_cleanup_close_ int fd = -EBADF;
union sockaddr_union sa;
int r;
assert(s);
if (s->accessible >= 0)
return s->accessible;
r = sockaddr_set_in_addr(&sa, s->family, &s->address, dns_server_port(s));
if (r < 0)
return r;
fd = socket(s->family, SOCK_DGRAM|SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
r = RET_NERRNO(connect(fd, &sa.sa, SOCKADDR_LEN(sa)));
if (!IN_SET(r, 0, -ENETUNREACH))
/* If we did not receive one of the expected return values,
* then leave the accessible flag untouched. */
return r;
return (s->accessible = r >= 0);
}
int dns_server_dump_configuration_to_json(DnsServer *server, sd_json_variant **ret) {
bool accessible = false;
int ifindex, r;
assert(server);
assert(ret);
ifindex = dns_server_ifindex(server);
r = dns_server_is_accessible(server);
if (r < 0)
log_debug_errno(r, "Failed to check if %s is accessible, assume not: %m", dns_server_string_full(server));
else
accessible = r;
return sd_json_buildo(
ret,
JSON_BUILD_PAIR_IN_ADDR("address", &server->address, server->family),
SD_JSON_BUILD_PAIR_INTEGER("family", server->family),
SD_JSON_BUILD_PAIR_UNSIGNED("port", dns_server_port(server)),
SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("name", server->server_name),
SD_JSON_BUILD_PAIR_BOOLEAN("accessible", accessible));
}

View File

@ -106,6 +106,9 @@ struct DnsServer {
/* Servers registered via D-Bus are not removed on reload */
ResolveConfigSource config_source;
/* Tri-state to indicate if the DNS server is accessible. */
int accessible;
};
int dns_server_new(
@ -187,3 +190,9 @@ static inline bool dns_server_is_fallback(DnsServer *s) {
}
int dns_server_dump_state_to_json(DnsServer *server, sd_json_variant **ret);
int dns_server_dump_configuration_to_json(DnsServer *server, sd_json_variant **ret);
int dns_server_is_accessible(DnsServer *s);
static inline void dns_server_reset_accessible(DnsServer *s) {
s->accessible = -1;
}

View File

@ -24,6 +24,7 @@ static BUS_DEFINE_PROPERTY_GET(property_get_dnssec_supported, "b", Link, link_dn
static BUS_DEFINE_PROPERTY_GET2(property_get_dnssec_mode, "s", Link, link_get_dnssec_mode, dnssec_mode_to_string);
static BUS_DEFINE_PROPERTY_GET2(property_get_llmnr_support, "s", Link, link_get_llmnr_support, resolve_support_to_string);
static BUS_DEFINE_PROPERTY_GET2(property_get_mdns_support, "s", Link, link_get_mdns_support, resolve_support_to_string);
static BUS_DEFINE_PROPERTY_GET(property_get_default_route, "b", Link, link_get_default_route);
static int property_get_dns_over_tls_mode(
sd_bus *bus,
@ -160,30 +161,6 @@ static int property_get_domains(
return sd_bus_message_close_container(reply);
}
static int property_get_default_route(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Link *l = ASSERT_PTR(userdata);
assert(reply);
/* Return what is configured, if there's something configured */
if (l->default_route >= 0)
return sd_bus_message_append(reply, "b", l->default_route);
/* Otherwise report what is in effect */
if (l->unicast_scope)
return sd_bus_message_append(reply, "b", dns_scope_is_default_route(l->unicast_scope));
return sd_bus_message_append(reply, "b", false);
}
static int property_get_scopes_mask(
sd_bus *bus,
const char *path,
@ -293,6 +270,7 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
(void) link_save_user(l);
(void) manager_write_resolv_conf(l->manager);
(void) manager_send_changed(l->manager, "DNS");
(void) manager_send_dns_configuration_changed(l->manager);
if (j)
log_link_info(l, "Bus client set DNS server list to: %s", j);
@ -768,6 +746,7 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error
(void) link_save_user(l);
(void) manager_write_resolv_conf(l->manager);
(void) manager_send_changed(l->manager, "DNS");
(void) manager_send_dns_configuration_changed(l->manager);
return sd_bus_reply_method_return(message, NULL);
}

View File

@ -14,6 +14,7 @@
#include "mkdir.h"
#include "netif-util.h"
#include "parse-util.h"
#include "resolved-dns-scope.h"
#include "resolved-link.h"
#include "resolved-llmnr.h"
#include "resolved-mdns.h"
@ -299,6 +300,15 @@ static int link_update_dns_servers(Link *l) {
}
dns_server_unlink_marked(l->dns_servers);
/* If the link state changed, we should re-check if DNS servers
* are accessible. */
LIST_FOREACH(servers, s, l->dns_servers)
dns_server_reset_accessible(s);
LIST_FOREACH(servers, s, l->manager->dns_servers)
dns_server_reset_accessible(s);
return 0;
clear:
@ -831,6 +841,20 @@ ResolveSupport link_get_mdns_support(Link *link) {
return MIN(link->mdns_support, link->manager->mdns_support);
}
bool link_get_default_route(Link *l) {
assert(l);
/* Return what is configured, if there's something configured */
if (l->default_route >= 0)
return l->default_route;
/* Otherwise report what is in effect */
if (l->unicast_scope)
return dns_scope_is_default_route(l->unicast_scope);
return false;
}
int link_address_new(Link *l,
LinkAddress **ret,
int family,

View File

@ -109,6 +109,8 @@ DnsOverTlsMode link_get_dns_over_tls_mode(Link *l);
ResolveSupport link_get_llmnr_support(Link *link);
ResolveSupport link_get_mdns_support(Link *link);
bool link_get_default_route(Link *l);
int link_save_user(Link *l);
int link_load_user(Link *l);
void link_remove_user(Link *l);

View File

@ -22,6 +22,7 @@
#include "idn-util.h"
#include "io-util.h"
#include "iovec-util.h"
#include "json-util.h"
#include "memstream-util.h"
#include "missing_network.h"
#include "missing_socket.h"
@ -196,6 +197,40 @@ fail:
return 0;
}
static int manager_process_route(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
Link *l;
uint16_t type;
int r;
assert(rtnl);
assert(mm);
r = sd_netlink_message_get_type(mm, &type);
if (r < 0) {
log_warning_errno(r, "Failed not get message type, ignoring: %m");
return 0;
}
if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
log_warning("Unexpected message type %u when processing route, ignoring.", type);
return 0;
}
/* Routing table changes may affect the accessibility of DNS servers. */
HASHMAP_FOREACH(l, m->links) {
LIST_FOREACH(servers, s, l->dns_servers)
dns_server_reset_accessible(s);
}
LIST_FOREACH(servers, s, m->dns_servers)
dns_server_reset_accessible(s);
(void) manager_send_dns_configuration_changed(m);
return 0;
}
static int manager_rtnl_listen(Manager *m) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
int r;
@ -227,6 +262,14 @@ static int manager_rtnl_listen(Manager *m) {
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, manager_process_route, NULL, m, "resolve-NEWROUTE");
if (r < 0)
return r;
r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, manager_process_route, NULL, m, "resolve-DELROUTE");
if (r < 0)
return r;
/* Then, enumerate all links */
r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
@ -286,6 +329,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *
(void) manager_write_resolv_conf(m);
(void) manager_send_changed(m, "DNS");
(void) manager_send_dns_configuration_changed(m);
return 0;
}
@ -1184,7 +1228,7 @@ int manager_monitor_send(Manager *m, DnsQuery *q) {
assert(m);
if (set_isempty(m->varlink_subscription))
if (set_isempty(m->varlink_query_results_subscription))
return 0;
/* Merge all questions into one */
@ -1234,7 +1278,7 @@ int manager_monitor_send(Manager *m, DnsQuery *q) {
}
r = varlink_many_notifybo(
m->varlink_subscription,
m->varlink_query_results_subscription,
SD_JSON_BUILD_PAIR("state", SD_JSON_BUILD_STRING(dns_transaction_state_to_string(q->state))),
SD_JSON_BUILD_PAIR_CONDITION(q->state == DNS_TRANSACTION_DNSSEC_FAILED,
"result", SD_JSON_BUILD_STRING(dnssec_result_to_string(q->answer_dnssec_result))),
@ -1932,3 +1976,124 @@ void dns_manager_reset_statistics(Manager *m) {
m->n_failure_responses_served_stale_total = 0;
zero(m->n_dnssec_verdict);
}
static int dns_configuration_json_append(
const char *ifname,
int ifindex,
int default_route,
DnsServer *current_dns_server,
DnsServer *dns_servers,
DnsSearchDomain *search_domains,
sd_json_variant **configuration) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *dns_servers_json = NULL,
*search_domains_json = NULL,
*current_dns_server_json = NULL;
int r;
assert(configuration);
r = sd_json_variant_new_array(&dns_servers_json, NULL, 0);
if (r < 0)
return r;
r = sd_json_variant_new_array(&search_domains_json, NULL, 0);
if (r < 0)
return r;
if (current_dns_server) {
r = dns_server_dump_configuration_to_json(current_dns_server, &current_dns_server_json);
if (r < 0)
return r;
}
LIST_FOREACH(servers, s, dns_servers) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
r = dns_server_dump_configuration_to_json(s, &v);
if (r < 0)
return r;
r = sd_json_variant_append_array(&dns_servers_json, v);
if (r < 0)
return r;
}
LIST_FOREACH(domains, d, search_domains) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
r = dns_search_domain_dump_to_json(d, &v);
if (r < 0)
return r;
r = sd_json_variant_append_array(&search_domains_json, v);
if (r < 0)
return r;
}
return sd_json_variant_append_arraybo(
configuration,
JSON_BUILD_PAIR_STRING_NON_EMPTY("ifname", ifname),
SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", SD_JSON_BUILD_UNSIGNED(ifindex)),
SD_JSON_BUILD_PAIR_CONDITION(ifindex > 0, "defaultRoute", SD_JSON_BUILD_BOOLEAN(default_route > 0)),
JSON_BUILD_PAIR_VARIANT_NON_NULL("currentServer", current_dns_server_json),
SD_JSON_BUILD_PAIR_VARIANT("servers", dns_servers_json),
SD_JSON_BUILD_PAIR_VARIANT("searchDomains", search_domains_json));
}
int manager_dump_dns_configuration_json(Manager *m, sd_json_variant **ret) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL;
Link *l;
int r;
assert(m);
assert(ret);
/* Global DNS configuration */
r = dns_configuration_json_append(
/* ifname = */ NULL,
/* ifindex = */ 0,
/* default_route = */ 0,
manager_get_dns_server(m),
m->dns_servers,
m->search_domains,
&configuration);
if (r < 0)
return r;
/* Append configuration for each link */
HASHMAP_FOREACH(l, m->links) {
r = dns_configuration_json_append(
l->ifname,
l->ifindex,
link_get_default_route(l),
link_get_dns_server(l),
l->dns_servers,
l->search_domains,
&configuration);
if (r < 0)
return r;
}
return sd_json_buildo(ret, SD_JSON_BUILD_PAIR_VARIANT("configuration", configuration));
}
int manager_send_dns_configuration_changed(Manager *m) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL;
int r;
assert(m);
if (set_isempty(m->varlink_dns_configuration_subscription))
return 0;
r = manager_dump_dns_configuration_json(m, &configuration);
if (r < 0)
return log_warning_errno(r, "Failed to dump DNS configuration json: %m");
r = varlink_many_notify(m->varlink_dns_configuration_subscription, configuration);
if (r < 0)
return log_warning_errno(r, "Failed to send DNS configuration event: %m");
return 0;
}

View File

@ -152,7 +152,8 @@ struct Manager {
sd_varlink_server *varlink_server;
sd_varlink_server *varlink_monitor_server;
Set *varlink_subscription;
Set *varlink_query_results_subscription;
Set *varlink_dns_configuration_subscription;
sd_event_source *clock_change_event_source;
@ -225,3 +226,6 @@ int socket_disable_pmtud(int fd, int af);
int dns_manager_dump_statistics_json(Manager *m, sd_json_variant **ret);
void dns_manager_reset_statistics(Manager *m);
int manager_dump_dns_configuration_json(Manager *m, sd_json_variant **ret);
int manager_send_dns_configuration_changed(Manager *m);

View File

@ -125,14 +125,21 @@ static void vl_on_disconnect(sd_varlink_server *s, sd_varlink *link, void *userd
static void vl_on_notification_disconnect(sd_varlink_server *s, sd_varlink *link, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
sd_varlink *removed_link = NULL;
assert(s);
assert(link);
sd_varlink *removed_link = set_remove(m->varlink_subscription, link);
removed_link = set_remove(m->varlink_query_results_subscription, link);
if (removed_link) {
sd_varlink_unref(removed_link);
log_debug("%u monitor clients remain active", set_size(m->varlink_subscription));
log_debug("%u query result monitor clients remain active", set_size(m->varlink_query_results_subscription));
}
removed_link = set_remove(m->varlink_dns_configuration_subscription, link);
if (removed_link) {
sd_varlink_unref(removed_link);
log_debug("%u DNS monitor clients remain active", set_size(m->varlink_dns_configuration_subscription));
}
}
@ -1227,12 +1234,12 @@ static int vl_method_subscribe_query_results(sd_varlink *link, sd_json_variant *
if (r < 0)
return log_error_errno(r, "Failed to report monitor to be established: %m");
r = set_ensure_put(&m->varlink_subscription, NULL, link);
r = set_ensure_put(&m->varlink_query_results_subscription, NULL, link);
if (r < 0)
return log_error_errno(r, "Failed to add subscription to set: %m");
sd_varlink_ref(link);
log_debug("%u clients now attached for varlink notifications", set_size(m->varlink_subscription));
log_debug("%u clients now attached for query result varlink notifications", set_size(m->varlink_query_results_subscription));
return 1;
}
@ -1352,6 +1359,38 @@ static int vl_method_reset_statistics(sd_varlink *link, sd_json_variant *paramet
return sd_varlink_replyb(link, SD_JSON_BUILD_EMPTY_OBJECT);
}
static int vl_method_subscribe_dns_configuration(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *configuration = NULL;
Manager *m = ASSERT_PTR(sd_varlink_get_userdata(ASSERT_PTR(link)));
int r;
/* if the client didn't set the more flag, it is using us incorrectly */
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
r = verify_polkit(link, parameters, "org.freedesktop.resolve1.subscribe-dns-configuration");
if (r <= 0)
return r;
r = manager_dump_dns_configuration_json(m, &configuration);
if (r < 0)
return log_error_errno(r, "Failed to dump current DNS configuration: %m");
r = sd_varlink_notify(link, configuration);
if (r < 0)
return log_error_errno(r, "Failed to send current DNS configuration: %m");
r = set_ensure_put(&m->varlink_dns_configuration_subscription, NULL, link);
if (r < 0)
return log_error_errno(r, "Failed to add subscription to set: %m");
sd_varlink_ref(link);
log_debug("%u clients now attached for link configuration varlink notifications",
set_size(m->varlink_dns_configuration_subscription));
return 1;
}
static int varlink_monitor_server_init(Manager *m) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *server = NULL;
int r;
@ -1377,7 +1416,8 @@ static int varlink_monitor_server_init(Manager *m) {
"io.systemd.Resolve.Monitor.DumpCache", vl_method_dump_cache,
"io.systemd.Resolve.Monitor.DumpServerState", vl_method_dump_server_state,
"io.systemd.Resolve.Monitor.DumpStatistics", vl_method_dump_statistics,
"io.systemd.Resolve.Monitor.ResetStatistics", vl_method_reset_statistics);
"io.systemd.Resolve.Monitor.ResetStatistics", vl_method_reset_statistics,
"io.systemd.Resolve.Monitor.SubscribeDNSConfiguration", vl_method_subscribe_dns_configuration);
if (r < 0)
return log_error_errno(r, "Failed to register varlink methods: %m");

View File

@ -112,6 +112,52 @@ static SD_VARLINK_DEFINE_METHOD(
ResetStatistics,
VARLINK_DEFINE_POLKIT_INPUT);
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSServer,
SD_VARLINK_FIELD_COMMENT("IPv4 or IPv6 address of the server."),
SD_VARLINK_DEFINE_FIELD(address, SD_VARLINK_INT, SD_VARLINK_ARRAY),
SD_VARLINK_FIELD_COMMENT("Address family of the server, one of AF_INET or AF_INET6."),
SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Port number of the server."),
SD_VARLINK_DEFINE_FIELD(port, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Interface index for which this server is configured."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Server Name Indication (SNI) of the server."),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Indicates if the DNS server is accessible or not."),
SD_VARLINK_DEFINE_FIELD(accessible, SD_VARLINK_BOOL, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
SearchDomain,
SD_VARLINK_FIELD_COMMENT("Domain name."),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("Indicates whether or not this is a routing-only domain."),
SD_VARLINK_DEFINE_FIELD(routeOnly, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("Interface index for which this search domain is configured."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
DNSConfiguration,
SD_VARLINK_FIELD_COMMENT("Interface name, if any, associated with this configuration. Empty for global configuration."),
SD_VARLINK_DEFINE_FIELD(ifname, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Interface index, if any, associated with this configuration. Empty for global configuration."),
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Indicates whether or not this link's DNS servers will be used for resolving domain names that do not match any link's configured domains."),
SD_VARLINK_DEFINE_FIELD(defaultRoute, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("DNS server currently selected to use for lookups."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(currentServer, DNSServer, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of configured DNS servers."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(servers, DNSServer, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Array of configured search domains."),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(searchDomains, SearchDomain, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_METHOD_FULL(
SubscribeDNSConfiguration,
SD_VARLINK_REQUIRES_MORE,
SD_VARLINK_DEFINE_INPUT(allowInteractiveAuthentication, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The current global and per-interface DNS configurations"),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(configuration, DNSConfiguration, SD_VARLINK_ARRAY));
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Resolve_Monitor,
"io.systemd.Resolve.Monitor",
@ -129,4 +175,12 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_type_TransactionStatistics,
&vl_type_CacheStatistics,
&vl_type_DnssecStatistics,
&vl_type_ServerState);
&vl_type_ServerState,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a DNS server address specification."),
&vl_type_DNSServer,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a search domain specification."),
&vl_type_SearchDomain,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a global or per-link DNS configuration, including configured DNS servers, search domains, and more."),
&vl_type_DNSConfiguration,
SD_VARLINK_SYMBOL_COMMENT("Sends the complete global and per-link DNS configurations when any changes are made to them. The current configurations are given immediately when this method is invoked."),
&vl_method_SubscribeDNSConfiguration);

View File

@ -98,15 +98,17 @@ static int delete_dm(DeviceMapper *m) {
assert(major(m->devnum) != 0);
assert(m->path);
fd = open(m->path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (fd < 0)
log_debug_errno(errno, "Failed to open DM block device %s for syncing, ignoring: %m", m->path);
else {
(void) sync_with_progress(fd);
fd = safe_close(fd);
}
fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
if (fd < 0)
return -errno;
_cleanup_close_ int block_fd = open(m->path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (block_fd < 0)
log_debug_errno(errno, "Failed to open DM block device %s for syncing, ignoring: %m", m->path);
else
(void) sync_with_progress(block_fd);
return log_debug_errno(errno, "Failed to open /dev/mapper/control: %m");
return RET_NERRNO(ioctl(fd, DM_DEV_REMOVE, &(struct dm_ioctl) {
.version = {

View File

@ -211,10 +211,8 @@ static int sync_making_progress(unsigned long long *prev_dirty) {
continue;
errno = 0;
if (sscanf(line, "%*s %llu %*s", &ull) != 1) {
log_warning_errno(errno_or_else(EIO), "Failed to parse /proc/meminfo field, ignoring: %m");
return false;
}
if (sscanf(line, "%*s %llu %*s", &ull) != 1)
return log_warning_errno(errno_or_else(EIO), "Failed to parse /proc/meminfo field: %m");
val += ull;
}

View File

@ -960,10 +960,13 @@ exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ {{ s/^.*=/
# wait until devices got created
for _ in range(50):
out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.if_router])
if b'state UP' in out and b'scope global' in out:
if subprocess.run(['ip', 'link', 'show', 'dev', self.if_router],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0:
break
time.sleep(0.1)
else:
subprocess.call(['ip', 'link', 'show', 'dev', self.if_router])
self.fail('Timed out waiting for {ifr} created.'.format(ifr=self.if_router))
def shutdown_iface(self):
'''Remove test interface and stop DHCP server'''
@ -1086,6 +1089,134 @@ DNS=127.0.0.1
self.show_journal('systemd-timedated.service')
self.fail(f'Timezone: {tz}, expected: Pacific/Honolulu')
def do_test_wait_online_dns(
self,
iface,
global_dns='',
fallback_dns='',
expect_timeout=False
):
self.start_unit('systemd-networkd')
self.start_unit('systemd-resolved')
# Unless given, clear global DNS configuration
conf = '/run/systemd/resolved.conf.d/global-dns.conf'
os.makedirs(os.path.dirname(conf), exist_ok=True)
with open(conf, 'w') as f:
f.write((
'[Resolve]\n'
f'DNS={global_dns}\n'
f'FallbackDNS={fallback_dns}\n'
))
self.addCleanup(os.remove, conf)
subprocess.check_call(
['systemctl', 'reload', 'systemd-resolved']
)
env = os.environ.copy()
env['SYSTEMD_LOG_LEVEL'] = 'debug'
env['SYSTEMD_LOG_TARGET'] = 'console'
r = subprocess.run(
[NETWORKD_WAIT_ONLINE, '--dns', '--interface', iface, '--timeout=10'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
)
if expect_timeout:
self.assertNotEqual(
r.returncode,
0,
f'Command succeeded unexpectedly:\n{r.stderr.decode()}'
)
self.assertRegex(
r.stderr.decode(),
rf'{iface}: No link-specific DNS server is accessible',
f'Missing expected log message:\n{r.stderr.decode()}'
)
else:
self.assertEqual(
r.returncode,
0,
f'Command timed out:\n{r.stderr.decode()}'
)
def test_wait_online_dns(self):
''' test systemd-networkd-wait-online with --dns '''
self.write_network(
self.config,
(
'[Match]\n'
f'Name={self.iface}\n'
'[Network]\n'
'DHCP=ipv4\n'
)
)
self.create_iface()
self.do_test_wait_online_dns(self.iface)
def test_wait_online_dns_global(self):
'''
test systemd-networkd-wait-online with --dns, expect pass due to global DNS
'''
# Set UseDNS=no, and allow global DNS to be used.
self.write_network(
self.config,
(
'[Match]\n'
f'Name={self.iface}\n'
'[Network]\n'
'DHCP=ipv4\n'
'[DHCPv4]\n'
'UseDNS=no\n'
)
)
self.create_iface()
self.do_test_wait_online_dns(self.iface, global_dns='192.168.5.1')
def test_wait_online_dns_expect_timeout(self):
''' test systemd-networkd-wait-online with --dns, and expect timeout '''
# Explicitly set DNSDefaultRoute=yes, and require link-specific DNS to be used.
self.write_network(
self.config,
(
'[Match]\n'
f'Name={self.iface}\n'
'[Network]\n'
'DHCP=ipv4\n'
'DNSDefaultRoute=yes\n'
'[DHCPv4]\n'
'UseDNS=no\n'
)
)
self.create_iface()
self.do_test_wait_online_dns(self.iface, expect_timeout=True)
def test_wait_online_dns_expect_timeout_global(self):
'''
test systemd-networkd-wait-online with --dns, and expect timeout
despite global DNS
'''
# Configure Domains=~., and expect timeout despite global DNS servers
# being available.
self.write_network(
self.config,
(
'[Match]\n'
f'Name={self.iface}\n'
'[Network]\n'
'DHCP=ipv4\n'
'Domains=~.\n'
'[DHCPv4]\n'
'UseDNS=no\n'
)
)
self.create_iface()
self.do_test_wait_online_dns(self.iface, expect_timeout=True, global_dns='192.168.5.1')
class MatchClientTest(unittest.TestCase, NetworkdTestingUtilities):
"""Test [Match] sections in .network files.

View File

@ -934,6 +934,15 @@ testcase_11_nft() {
# Test resolvectl show-server-state
testcase_12_resolvectl2() {
# Cleanup
# shellcheck disable=SC2317
cleanup() {
rm -f /run/systemd/resolved.conf.d/reload.conf
systemctl reload systemd-resolved.service
}
trap cleanup RETURN
run resolvectl show-server-state
grep -qF "10.0.0.1" "$RUN_OUT"
grep -qF "Interface" "$RUN_OUT"
@ -996,6 +1005,78 @@ testcase_12_resolvectl2() {
restart_resolved
}
# Test io.systemd.Resolve.Monitor.SubscribeDNSConfiguration
testcase_13_varlink_subscribe_dns_configuration() {
# Cleanup
# shellcheck disable=SC2317
cleanup() {
echo "===== io.systemd.Resolve.Monitor.SubscribeDNSConfiguration output: ====="
cat "$tmpfile"
echo "=========="
rm -f /run/systemd/resolved.conf.d/global-dns.conf
restart_resolved
}
trap cleanup RETURN
local unit
local tmpfile
unit="subscribe-dns-configuration-$(systemd-id128 new -u).service"
tmpfile=$(mktemp)
# Clear global and per-interface DNS before monitoring the configuration change.
mkdir -p /run/systemd/resolved.conf.d/
{
echo "[Resolve]"
echo "DNS="
} > /run/systemd/resolved.conf.d/global-dns.conf
systemctl reload systemd-resolved.service
resolvectl dns dns0 ""
# Start the call to io.systemd.Resolve.Monitor.SubscribeDNSConfiguration
systemd-run -u "$unit" -p "Type=exec" -p "StandardOutput=truncate:$tmpfile" \
varlinkctl call --more --timeout=5 --graceful=io.systemd.TimedOut /run/systemd/resolve/io.systemd.Resolve.Monitor io.systemd.Resolve.Monitor.SubscribeDNSConfiguration '{}'
# Update the global configuration.
mkdir -p /run/systemd/resolved.conf.d/
{
echo "[Resolve]"
echo "DNS=8.8.8.8"
echo "Domains=lan"
} > /run/systemd/resolved.conf.d/global-dns.conf
systemctl reload systemd-resolved.service
# Update a link configuration.
resolvectl dns dns0 8.8.4.4 1.1.1.1
# Wait for the monitor to exit gracefully.
while systemctl --quiet is-active "$unit"; do
sleep 0.5
done
# Hack to remove the "Method call returned expected error" line from the output.
sed -i '/^Method call.*returned expected error/d' "$tmpfile"
# Check that an initial reply was given with the settings applied BEFORE the monitor started.
grep -qF \
'{"global":{"servers":[],"domains":[]}}' \
<(jq -cr --seq '.configuration[] | select(.ifname == null) | {"global": {servers: .servers, domains: .searchDomains}}' "$tmpfile")
grep -qF \
'{"dns0":{"servers":[],"domains":[]}}' \
<(jq -cr --seq '.configuration[] | select(.ifname == "dns0") | {"dns0": {servers: .servers, domains: .searchDomains}}' "$tmpfile")
# Check that the global configuration change was reflected.
grep -qF \
'{"global":{"servers":[[8,8,8,8]],"domains":["lan"]}}' \
<(jq -cr --seq '.configuration[] | select(.ifname == null) | {"global":{servers: [.servers[] | .address], domains: [.searchDomains[] | .name]}}' "$tmpfile")
# Check that the link configuration change was reflected.
grep -qF \
'{"dns0":{"servers":[[8,8,4,4],[1,1,1,1]],"domains":[]}}' \
<(jq -cr --seq '.configuration[] | select(.ifname == "dns0") | {"dns0":{servers: [.servers[] | .address], domains: [.searchDomains[] | .name]}}' "$tmpfile")
}
# PRE-SETUP
systemctl unmask systemd-resolved.service
systemctl enable --now systemd-resolved.service

View File

@ -14,7 +14,7 @@ ConditionCapability=CAP_NET_ADMIN
DefaultDependencies=no
Conflicts=shutdown.target
BindsTo=systemd-networkd.service
After=systemd-networkd.service
After=systemd-networkd.service systemd-resolved.service
Before=network-online.target shutdown.target
[Service]