Compare commits
22 Commits
323d219df1
...
76019f7589
Author | SHA1 | Date |
---|---|---|
Nick Rosbrook | 76019f7589 | |
Ani Sinha | 4b356c90dc | |
Léane GRASSER | f28e16d14e | |
Yu Watanabe | 9e05e33871 | |
Lennart Poettering | 95116bdfd5 | |
Lennart Poettering | 2bd290ca02 | |
Yu Watanabe | 1e9fb1d456 | |
Yu Watanabe | 56c761f8c6 | |
Yu Watanabe | b76730f3fe | |
Yu Watanabe | 3dda236c5c | |
Zbigniew Jędrzejewski-Szmek | 5598454a3f | |
Yu Watanabe | 2994ca354b | |
Yu Watanabe | eb14b993bb | |
Nick Rosbrook | b818627789 | |
Nick Rosbrook | 0c405df64a | |
Nick Rosbrook | 3385de576a | |
Nick Rosbrook | 007e24be8e | |
Nick Rosbrook | 671c07a8ac | |
Nick Rosbrook | efc0b06a9a | |
Nick Rosbrook | df1cc414f3 | |
Nick Rosbrook | ad68334774 | |
Nick Rosbrook | 133314b44e |
|
@ -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>
|
||||
|
||||
|
|
4
po/fr.po
4
po/fr.po
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -67,6 +67,7 @@ enum {
|
|||
FRA_IP_PROTO, /* ip proto */
|
||||
FRA_SPORT_RANGE, /* sport */
|
||||
FRA_DPORT_RANGE, /* dport */
|
||||
FRA_DSCP, /* dscp */
|
||||
__FRA_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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__))
|
||||
|
|
|
@ -101,18 +101,19 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" -j Same as --json=pretty on tty, --json=short otherwise\n"
|
||||
" --append=PATH Load specified JSON signature, and append new signature to it\n"
|
||||
"\n%3$sUKI PE Section Options:%4$s %3$sUKI PE Section%4$s\n"
|
||||
" --linux=PATH Path to Linux kernel image file %7$s .linux\n"
|
||||
" --osrel=PATH Path to os-release file %7$s .osrel\n"
|
||||
" --cmdline=PATH Path to file with kernel command line %7$s .cmdline\n"
|
||||
" --initrd=PATH Path to initrd image file %7$s .initrd\n"
|
||||
" --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"
|
||||
" --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"
|
||||
" --profile=PATH Path to profile file %7$s .profile\n"
|
||||
" --hwids=PATH Path to HWIDs file %7$s .hwids\n"
|
||||
" --linux=PATH Path to Linux kernel image file %7$s .linux\n"
|
||||
" --osrel=PATH Path to os-release file %7$s .osrel\n"
|
||||
" --cmdline=PATH Path to file with kernel command line %7$s .cmdline\n"
|
||||
" --initrd=PATH Path to initrd image file %7$s .initrd\n"
|
||||
" --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"
|
||||
" --profile=PATH Path to profile file %7$s .profile\n"
|
||||
" --hwids=PATH Path to HWIDs file %7$s .hwids\n"
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
link,
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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)
|
||||
return log_error_errno(r, "Failed to create directory %s: %m", parent);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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, ¤t_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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue