Compare commits
23 Commits
8ccf047bb0
...
cfdc0c6721
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | cfdc0c6721 | |
Yu Watanabe | 9671efff78 | |
Yu Watanabe | 4f0bc2582e | |
Yu Watanabe | 3292120adf | |
Yu Watanabe | f6cc5e1c8d | |
Yu Watanabe | 590f430cac | |
Mike Yuan | 93d2d36638 | |
Lennart Poettering | 369b12375b | |
Yu Watanabe | b5ec8f77e0 | |
Lennart Poettering | 3e0a3a0259 | |
Celeste Liu | 6573f0c82c | |
Lennart Poettering | a859d0d378 | |
Lennart Poettering | db15657dfb | |
Lennart Poettering | 2aa3005ad2 | |
Lennart Poettering | 90cf998875 | |
Lennart Poettering | c8d60ae79d | |
Lennart Poettering | bfcf48b842 | |
Yu Watanabe | 5f5c5c48b9 | |
Yu Watanabe | 68fdef46a7 | |
Lennart Poettering | 95b1dd00b6 | |
Lennart Poettering | fe09c8398e | |
Lennart Poettering | da1b3c55ff | |
Lennart Poettering | 568bf0b4e8 |
13
NEWS
13
NEWS
|
@ -2,6 +2,15 @@ systemd System and Service Manager
|
|||
|
||||
CHANGES WITH 257 in spe:
|
||||
|
||||
Incompatible changes:
|
||||
|
||||
* The --purge switch of systemd-tmpfiles (which was added in v256) has
|
||||
been reworked: it will now only apply to tmpfiles.d/ lines marked
|
||||
with the new "$" flag. This is an incompatible change, and means any
|
||||
tmpfiles.d/ files which shall be used together with --purge need to
|
||||
be updated accordingly. This change has been made to make it harder
|
||||
to accidentally delete too many files when using --purge incorrectly.
|
||||
|
||||
Announcements of Future Feature Removals and Incompatible Changes:
|
||||
|
||||
* Support for automatic flushing of the nscd user/group database caches
|
||||
|
@ -85,7 +94,7 @@ CHANGES WITH 257 in spe:
|
|||
/usr/lib/clock-epoch, and /var/lib/systemd/timesync/clock. See
|
||||
systemd(1) for an detailed updated description.
|
||||
|
||||
* Ctrl-Alt-Delete is reenabled during late shutdown, so that the user
|
||||
* Ctrl-Alt-Delete is re-enabled during late shutdown, so that the user
|
||||
can still initiate a reboot if the system freezes.
|
||||
|
||||
* Unit option PrivateUsers=identity can be used to request a user
|
||||
|
@ -202,7 +211,7 @@ CHANGES WITH 257 in spe:
|
|||
versions.
|
||||
|
||||
* systemd-sysupdate gained a new --transfer-source= option to set the
|
||||
directory to which transfer sources cofigured with
|
||||
directory to which transfer sources configured with
|
||||
PathRelativeTo=explicit will be interpreted.
|
||||
|
||||
Miscellaneous:
|
||||
|
|
|
@ -310,6 +310,10 @@ mouse:bluetooth:v047dp8019:name:Expert Wireless TB Mouse:*
|
|||
ID_INPUT_TRACKBALL=1
|
||||
MOUSE_DPI=400@125
|
||||
|
||||
# Kensington SlimBlade Pro trackball (via Bluetooth)
|
||||
mouse:bluetooth:v047dp80d4:name:SlimBlade Pro:*
|
||||
ID_INPUT_TRACKBALL=1
|
||||
|
||||
##########################################
|
||||
# Lenovo
|
||||
##########################################
|
||||
|
|
|
@ -267,7 +267,8 @@
|
|||
<term><option>kernel-identify</option> <replaceable>kernel</replaceable></term>
|
||||
|
||||
<listitem><para>Takes a kernel image as argument. Checks what kind of kernel the image is. Returns
|
||||
one of <literal>uki</literal>, <literal>pe</literal>, and <literal>unknown</literal>.
|
||||
one of <literal>uki</literal>, <literal>addon</literal>, <literal>pe</literal>, and
|
||||
<literal>unknown</literal>.
|
||||
</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v253"/></listitem>
|
||||
|
@ -360,6 +361,24 @@
|
|||
<xi:include href="version-info.xml" xpointer="v242"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--print-loader-path</option></term>
|
||||
<listitem><para>This option modifies the behaviour of <command>status</command>: it shows the
|
||||
absolute path to the boot loader EFI binary used for the current boot if this information is
|
||||
available. Note that no attempt is made to verify whether the binary still exists.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--print-stub-path</option></term>
|
||||
<listitem><para>This option modifies the behaviour of <command>status</command>: it shows the
|
||||
absolute path to the UKI/stub EFI binary used for the current boot if this information is
|
||||
available. Note that no attempt is made to verify whether the binary still exists.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-R</option></term>
|
||||
<term><option>--print-root-device</option></term>
|
||||
|
|
|
@ -115,6 +115,9 @@ node /org/freedesktop/resolve1 {
|
|||
ResetStatistics();
|
||||
FlushCaches();
|
||||
ResetServerFeatures();
|
||||
GetDelegate(in s id,
|
||||
out o path);
|
||||
ListDelegates(out a(so) delegates);
|
||||
properties:
|
||||
readonly s LLMNRHostname = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
|
@ -202,6 +205,10 @@ node /org/freedesktop/resolve1 {
|
|||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ResetServerFeatures()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="GetDelegate()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListDelegates()"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="LLMNRHostname"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="LLMNR"/>
|
||||
|
@ -423,13 +430,13 @@ node /org/freedesktop/resolve1 {
|
|||
<para>The <function>RevertLink()</function> method may be used to revert all per-link settings
|
||||
described above to the defaults.</para>
|
||||
|
||||
<para>The <function>FlushCaches()</function> flushes all resource record caches maintained by the
|
||||
<para>The <function>FlushCaches()</function> method flushes all resource record caches maintained by the
|
||||
resolver, and ensures that any subsequent lookups re-request their responses from their sources.</para>
|
||||
|
||||
<para>The <function>ResetServerFeatures()</function> flushes any feature information learned about
|
||||
remote DNS servers. This ensures that subsequent lookups will be initially attempted at the highest DNS
|
||||
protocol feature level again, possibly requiring a (potentially slow) downgrade cycle to recognize the
|
||||
supported feature level again.</para>
|
||||
<para>The <function>ResetServerFeatures()</function> method flushes any feature information learned
|
||||
about remote DNS servers. This ensures that subsequent lookups will be initially attempted at the
|
||||
highest DNS protocol feature level again, possibly requiring a (potentially slow) downgrade cycle to
|
||||
recognize the supported feature level again.</para>
|
||||
|
||||
<para>The <function>RegisterService()</function> method may be used to register a DNS-SD service on the
|
||||
host. This functionality is closely related to the functionality provided by
|
||||
|
@ -447,6 +454,12 @@ node /org/freedesktop/resolve1 {
|
|||
<function>RegisterService()</function> and deletes a DNS-SD service previously created via IPC
|
||||
again.</para>
|
||||
|
||||
<para>The <function>GetDelegate()</function> method returns the D-Bus object path for the specified DNS
|
||||
delegate ID.</para>
|
||||
|
||||
<para>The <function>ListDelegates()</function> method returns a list of the IDs and D-Bus object paths
|
||||
of the currently configured DNS delegates.</para>
|
||||
|
||||
<refsect3>
|
||||
<title>The Flags Parameter</title>
|
||||
|
||||
|
@ -935,4 +948,14 @@ $ gdbus introspect --system \
|
|||
</refsect1>
|
||||
|
||||
<xi:include href="org.freedesktop.locale1.xml" xpointer="versioning"/>
|
||||
|
||||
<refsect1>
|
||||
<title>History</title>
|
||||
<refsect2>
|
||||
<title>The Manager Object</title>
|
||||
|
||||
<para><function>GetDelegate()</function> and <function>ListDelegates()</function> were added in version 257.</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
result can be pre-calculated without too much effort. The <literal>.pcrsig</literal> section is not
|
||||
included in this PCR measurement, since it is supposed to contain signatures for the output of the
|
||||
measurement operation, and thus cannot also be input to it. If an UKI contains multiple profiles, only
|
||||
the PE sections of the selected profile (and those of the base profile, except if overriden) are
|
||||
the PE sections of the selected profile (and those of the base profile, except if overridden) are
|
||||
measured.</para>
|
||||
|
||||
<para>If non-zero, the selected numeric profile is measured into PCR 12.</para>
|
||||
|
|
|
@ -152,10 +152,11 @@
|
|||
<varlistentry>
|
||||
<term><option>--purge</option></term>
|
||||
|
||||
<listitem><para>If this option is passed, all files and directories marked for
|
||||
<emphasis>creation</emphasis> by the <filename>tmpfiles.d/</filename> files specified on the command
|
||||
line will be <emphasis>deleted</emphasis>. Specifically, this acts on all files and directories
|
||||
marked with <varname>f</varname>, <varname>F</varname>, <varname>d</varname>, <varname>D</varname>,
|
||||
<listitem><para>If this option is passed, all files and directories declared for
|
||||
<emphasis>creation</emphasis> and marked with the <literal>$</literal> character by the
|
||||
<filename>tmpfiles.d/</filename> files specified on the command line will be
|
||||
<emphasis>deleted</emphasis>. Specifically, this acts on all files and directories marked with
|
||||
<varname>f</varname>, <varname>F</varname>, <varname>d</varname>, <varname>D</varname>,
|
||||
<varname>v</varname>, <varname>q</varname>, <varname>Q</varname>, <varname>p</varname>,
|
||||
<varname>L</varname>, <varname>c</varname>, <varname>b</varname>, <varname>C</varname>,
|
||||
<varname>w</varname>, <varname>e</varname>. If this switch is used at least one
|
||||
|
|
|
@ -539,6 +539,10 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
|
|||
service, the line is silently skipped. If <literal>^</literal> and <literal>~</literal> are combined
|
||||
Base64 decoding is applied to the credential contents.</para>
|
||||
|
||||
<para>If the dollar sign (<literal>$</literal>) is used, the file becomes subject to removal when
|
||||
<command>systemd-tmpfiles</command> is invoked with the <option>--purge</option> switch. Lines without
|
||||
this character are unaffected by that switch.</para>
|
||||
|
||||
<para>Note that for all line types that result in creation of any kind of file node
|
||||
(i.e. <varname>f</varname>,
|
||||
<varname>d</varname>/<varname>D</varname>/<varname>v</varname>/<varname>q</varname>/<varname>Q</varname>,
|
||||
|
|
|
@ -141,6 +141,12 @@
|
|||
For example, e"string\n" is parsed as 7 characters: 6 lowercase letters and a newline.
|
||||
This can be useful for writing special characters when a kernel driver requires them.</para>
|
||||
|
||||
<para>The string can be prefixed with a lowercase i (i"string") to mark that the string or pattern
|
||||
will match case-insensitively. For example, i"foo" will match
|
||||
<literal>foo</literal>, <literal>FOO</literal>, <literal>FoO</literal> and so on. The prefix can be
|
||||
used only for match (<literal>==</literal>) or unmatch (<literal>!=</literal>) rules, e.g.
|
||||
<varname>ATTR{foo}==i"abcd"</varname>.</para>
|
||||
|
||||
<para>Please note that <constant>NUL</constant> is not allowed in either string variant.</para>
|
||||
</refsect2>
|
||||
|
||||
|
|
|
@ -221,6 +221,12 @@ const char* const systemd_features =
|
|||
" -BPF_FRAMEWORK"
|
||||
#endif
|
||||
|
||||
#if HAVE_VMLINUX_H
|
||||
" +BTF"
|
||||
#else
|
||||
" -BTF"
|
||||
#endif
|
||||
|
||||
#if HAVE_XKBCOMMON
|
||||
" +XKBCOMMON"
|
||||
#else
|
||||
|
|
|
@ -145,8 +145,10 @@ int efi_get_variable(
|
|||
int efi_get_variable_string(const char *variable, char **ret) {
|
||||
_cleanup_free_ void *s = NULL;
|
||||
size_t ss = 0;
|
||||
int r;
|
||||
char *x;
|
||||
int r;
|
||||
|
||||
assert(variable);
|
||||
|
||||
r = efi_get_variable(variable, NULL, &s, &ss);
|
||||
if (r < 0)
|
||||
|
@ -156,10 +158,27 @@ int efi_get_variable_string(const char *variable, char **ret) {
|
|||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ret)
|
||||
*ret = x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int efi_get_variable_path(const char *variable, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(variable);
|
||||
|
||||
r = efi_get_variable_string(variable, ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret)
|
||||
efi_tilt_backslashes(*ret);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int efi_verify_variable(const char *variable, uint32_t attr, const void *value, size_t size) {
|
||||
_cleanup_free_ void *buf = NULL;
|
||||
size_t n;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "sd-id128.h"
|
||||
|
||||
#include "efivars-fundamental.h"
|
||||
#include "string-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f)
|
||||
|
@ -47,6 +48,7 @@
|
|||
|
||||
int efi_get_variable(const char *variable, uint32_t *attribute, void **ret_value, size_t *ret_size);
|
||||
int efi_get_variable_string(const char *variable, char **ret);
|
||||
int efi_get_variable_path(const char *variable, char **ret);
|
||||
int efi_set_variable(const char *variable, const void *value, size_t size);
|
||||
int efi_set_variable_string(const char *variable, const char *p);
|
||||
|
||||
|
@ -68,6 +70,10 @@ static inline int efi_get_variable_string(const char *variable, char **ret) {
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int efi_get_variable_path(const char *variable, char **ret) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int efi_set_variable(const char *variable, const void *value, size_t size) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -100,3 +106,7 @@ static inline int systemd_efi_options_efivarfs_if_newer(char **line) {
|
|||
return -ENODATA;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline char *efi_tilt_backslashes(char *s) {
|
||||
return string_replace_char(s, '\\', '/');
|
||||
}
|
||||
|
|
|
@ -219,14 +219,12 @@ static int acquire_boot_count_path(
|
|||
uint64_t left, done;
|
||||
int r;
|
||||
|
||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderBootCountPath), &path);
|
||||
r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderBootCountPath), &path);
|
||||
if (r == -ENOENT)
|
||||
return -EUNATCH; /* in this case, let the caller print a message */
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read LoaderBootCountPath EFI variable: %m");
|
||||
|
||||
efi_tilt_backslashes(path);
|
||||
|
||||
if (!path_is_normalized(path))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Path read from LoaderBootCountPath is not normalized, refusing: %s",
|
||||
|
|
|
@ -298,12 +298,24 @@ fail:
|
|||
return r;
|
||||
}
|
||||
|
||||
static void read_efi_var(const char *variable, char **ret) {
|
||||
static int efi_get_variable_string_and_warn(const char *variable, char **ret) {
|
||||
int r;
|
||||
|
||||
r = efi_get_variable_string(variable, ret);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_warning_errno(r, "Failed to read EFI variable %s: %m", variable);
|
||||
return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int efi_get_variable_path_and_warn(const char *variable, char **ret) {
|
||||
int r;
|
||||
|
||||
r = efi_get_variable_path(variable, ret);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return log_warning_errno(r, "Failed to read EFI variable '%s', ignoring: %m", variable);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void print_yes_no_line(bool first, bool good, const char *name) {
|
||||
|
@ -396,26 +408,23 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
|||
{ EFI_STUB_FEATURE_MULTI_PROFILE_UKI, "Stub understands profile selector" },
|
||||
{ EFI_STUB_FEATURE_REPORT_STUB_PARTITION, "Stub sets stub partition information" },
|
||||
};
|
||||
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
|
||||
sd_id128_t loader_part_uuid = SD_ID128_NULL;
|
||||
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
|
||||
*current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL;
|
||||
uint64_t loader_features = 0, stub_features = 0;
|
||||
Tpm2Support s;
|
||||
int have;
|
||||
|
||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
|
||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
|
||||
read_efi_var(EFI_LOADER_VARIABLE(StubInfo), &stub);
|
||||
read_efi_var(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareInfo), &fw_info);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderInfo), &loader);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(StubInfo), &stub);
|
||||
(void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &loader_path);
|
||||
(void) efi_get_variable_path_and_warn(EFI_LOADER_VARIABLE(StubImageIdentifier), &stub_path);
|
||||
(void) efi_loader_get_features(&loader_features);
|
||||
(void) efi_stub_get_features(&stub_features);
|
||||
|
||||
if (loader_path)
|
||||
efi_tilt_backslashes(loader_path);
|
||||
|
||||
k = efi_loader_get_device_part_uuid(&loader_part_uuid);
|
||||
if (k < 0 && k != -ENOENT)
|
||||
r = log_warning_errno(k, "Failed to read EFI variable LoaderDevicePartUUID: %m");
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntrySelected), ¤t_entry);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryOneShot), &oneshot_entry);
|
||||
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderEntryDefault), &default_entry);
|
||||
|
||||
SecureBootMode secure = efi_get_secure_boot_mode();
|
||||
printf("%sSystem:%s\n", ansi_underline(), ansi_normal());
|
||||
|
@ -463,34 +472,58 @@ int verb_status(int argc, char *argv[], void *userdata) {
|
|||
}
|
||||
printf("\n");
|
||||
|
||||
if (loader) {
|
||||
printf("%sCurrent Boot Loader:%s\n", ansi_underline(), ansi_normal());
|
||||
printf(" Product: %s%s%s\n", ansi_highlight(), strna(loader), ansi_normal());
|
||||
|
||||
printf(" Product: %s%s%s\n", ansi_highlight(), loader, ansi_normal());
|
||||
for (size_t i = 0; i < ELEMENTSOF(loader_flags); i++)
|
||||
print_yes_no_line(i == 0, FLAGS_SET(loader_features, loader_flags[i].flag), loader_flags[i].name);
|
||||
|
||||
sd_id128_t bootloader_esp_uuid;
|
||||
bool have_bootloader_esp_uuid = efi_loader_get_device_part_uuid(&bootloader_esp_uuid) >= 0;
|
||||
sd_id128_t loader_partition_uuid;
|
||||
bool have_loader_partition_uuid = efi_loader_get_device_part_uuid(&loader_partition_uuid) >= 0;
|
||||
|
||||
print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP information");
|
||||
if (have_bootloader_esp_uuid && !sd_id128_is_null(esp_uuid) &&
|
||||
!sd_id128_equal(esp_uuid, bootloader_esp_uuid))
|
||||
printf("WARNING: The boot loader reports a different ESP UUID than detected ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
|
||||
SD_ID128_FORMAT_VAL(bootloader_esp_uuid),
|
||||
SD_ID128_FORMAT_VAL(esp_uuid));
|
||||
print_yes_no_line(false, have_loader_partition_uuid, "Boot loader set ESP information");
|
||||
|
||||
if (current_entry)
|
||||
printf("Current Entry: %s\n", current_entry);
|
||||
if (default_entry)
|
||||
printf("Default Entry: %s\n", default_entry);
|
||||
if (oneshot_entry && !streq_ptr(oneshot_entry, default_entry))
|
||||
printf("OneShot Entry: %s\n", oneshot_entry);
|
||||
|
||||
if (have_loader_partition_uuid && !sd_id128_is_null(esp_uuid) && !sd_id128_equal(esp_uuid, loader_partition_uuid))
|
||||
printf("WARNING: The boot loader reports a different partition UUID than the detected ESP ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR")!\n",
|
||||
SD_ID128_FORMAT_VAL(loader_partition_uuid), SD_ID128_FORMAT_VAL(esp_uuid));
|
||||
|
||||
if (!sd_id128_is_null(loader_partition_uuid))
|
||||
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||
SD_ID128_FORMAT_VAL(loader_partition_uuid));
|
||||
else
|
||||
printf(" Partition: n/a\n");
|
||||
printf(" Loader: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (stub) {
|
||||
printf(" Stub: %s\n", stub);
|
||||
printf("%sCurrent Stub:%s\n", ansi_underline(), ansi_normal());
|
||||
printf(" Product: %s%s%s\n", ansi_highlight(), stub, ansi_normal());
|
||||
for (size_t i = 0; i < ELEMENTSOF(stub_flags); i++)
|
||||
print_yes_no_line(i == 0, FLAGS_SET(stub_features, stub_flags[i].flag), stub_flags[i].name);
|
||||
}
|
||||
if (!sd_id128_is_null(loader_part_uuid))
|
||||
printf(" ESP: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||
SD_ID128_FORMAT_VAL(loader_part_uuid));
|
||||
|
||||
sd_id128_t stub_partition_uuid;
|
||||
bool have_stub_partition_uuid = efi_stub_get_device_part_uuid(&stub_partition_uuid) >= 0;
|
||||
|
||||
if (have_stub_partition_uuid && (!(!sd_id128_is_null(esp_uuid) && sd_id128_equal(esp_uuid, stub_partition_uuid)) &&
|
||||
!(!sd_id128_is_null(xbootldr_uuid) && sd_id128_equal(xbootldr_uuid, stub_partition_uuid))))
|
||||
printf("WARNING: The stub loader reports a different UUID than the detected ESP or XBOOTDLR partition ("SD_ID128_UUID_FORMAT_STR" vs. "SD_ID128_UUID_FORMAT_STR"/"SD_ID128_UUID_FORMAT_STR")!\n",
|
||||
SD_ID128_FORMAT_VAL(stub_partition_uuid), SD_ID128_FORMAT_VAL(esp_uuid), SD_ID128_FORMAT_VAL(xbootldr_uuid));
|
||||
if (!sd_id128_is_null(stub_partition_uuid))
|
||||
printf(" Partition: /dev/disk/by-partuuid/" SD_ID128_UUID_FORMAT_STR "\n",
|
||||
SD_ID128_FORMAT_VAL(stub_partition_uuid));
|
||||
else
|
||||
printf(" ESP: n/a\n");
|
||||
printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
|
||||
printf(" Partition: n/a\n");
|
||||
printf(" Stub: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(stub_path));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("%sRandom Seed:%s\n", ansi_underline(), ansi_normal());
|
||||
have = access(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), F_OK) >= 0;
|
||||
|
|
|
@ -16,12 +16,14 @@
|
|||
#include "build.h"
|
||||
#include "devnum-util.h"
|
||||
#include "dissect-image.h"
|
||||
#include "efi-loader.h"
|
||||
#include "escape.h"
|
||||
#include "find-esp.h"
|
||||
#include "main-func.h"
|
||||
#include "mount-util.h"
|
||||
#include "pager.h"
|
||||
#include "parse-argument.h"
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "utf8.h"
|
||||
#include "varlink-io.systemd.BootControl.h"
|
||||
|
@ -38,6 +40,8 @@ char *arg_esp_path = NULL;
|
|||
char *arg_xbootldr_path = NULL;
|
||||
bool arg_print_esp_path = false;
|
||||
bool arg_print_dollar_boot_path = false;
|
||||
bool arg_print_loader_path = false;
|
||||
bool arg_print_stub_path = false;
|
||||
unsigned arg_print_root_device = 0;
|
||||
bool arg_touch_variables = true;
|
||||
bool arg_install_random_seed = true;
|
||||
|
@ -133,6 +137,71 @@ int acquire_xbootldr(
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int print_loader_or_stub_path(void) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
sd_id128_t uuid;
|
||||
int r;
|
||||
|
||||
if (arg_print_loader_path) {
|
||||
r = efi_loader_get_device_part_uuid(&uuid);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "No loader partition UUID passed.");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Unable to determine loader partition UUID: %m");
|
||||
|
||||
r = efi_get_variable_path(EFI_LOADER_VARIABLE(LoaderImageIdentifier), &p);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "No loader EFI binary path passed.");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Unable to determine loader EFI binary path: %m");
|
||||
} else {
|
||||
assert(arg_print_stub_path);
|
||||
|
||||
r = efi_stub_get_device_part_uuid(&uuid);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "No stub partition UUID passed.");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Unable to determine stub partition UUID: %m");
|
||||
|
||||
r = efi_get_variable_path(EFI_LOADER_VARIABLE(StubImageIdentifier), &p);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "No stub EFI binary path passed.");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Unable to determine stub EFI binary path: %m");
|
||||
}
|
||||
|
||||
sd_id128_t esp_uuid;
|
||||
r = acquire_esp(/* unprivileged_mode= */ false, /* graceful= */ false,
|
||||
/* ret_part= */ NULL, /* ret_pstart= */ NULL, /* ret_psize= */ NULL,
|
||||
&esp_uuid, /* ret_devid= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const char *found_path = NULL;
|
||||
if (sd_id128_equal(esp_uuid, uuid))
|
||||
found_path = arg_esp_path;
|
||||
else if (arg_print_stub_path) { /* In case of the stub, also look for things in the xbootldr partition */
|
||||
sd_id128_t xbootldr_uuid;
|
||||
|
||||
r = acquire_xbootldr(/* unprivileged_mode= */ false, &xbootldr_uuid, /* ret_devid= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_id128_equal(xbootldr_uuid, uuid))
|
||||
found_path = arg_xbootldr_path;
|
||||
}
|
||||
|
||||
if (!found_path)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to discover partition " SD_ID128_FORMAT_STR " among mounted boot partitions.", SD_ID128_FORMAT_VAL(uuid));
|
||||
|
||||
_cleanup_free_ char *j = path_join(found_path, p);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
puts(j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int help(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
|
@ -182,6 +251,9 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" Where to pick files when using --root=/--image=\n"
|
||||
" -p --print-esp-path Print path to the EFI System Partition mount point\n"
|
||||
" -x --print-boot-path Print path to the $BOOT partition mount point\n"
|
||||
" --print-loader-path\n"
|
||||
" Print path to currently booted boot loader binary\n"
|
||||
" --print-stub-path Print path to currently booted unified kernel binary\n"
|
||||
" -R --print-root-device\n"
|
||||
" Print path to the block device node backing the\n"
|
||||
" root file system (returns e.g. /dev/nvme0n1p5)\n"
|
||||
|
@ -235,6 +307,8 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_ARCH_ALL,
|
||||
ARG_EFI_BOOT_OPTION_DESCRIPTION,
|
||||
ARG_DRY_RUN,
|
||||
ARG_PRINT_LOADER_PATH,
|
||||
ARG_PRINT_STUB_PATH,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -250,6 +324,8 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "print-esp-path", no_argument, NULL, 'p' },
|
||||
{ "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
|
||||
{ "print-boot-path", no_argument, NULL, 'x' },
|
||||
{ "print-loader-path", no_argument, NULL, ARG_PRINT_LOADER_PATH },
|
||||
{ "print-stub-path", no_argument, NULL, ARG_PRINT_STUB_PATH },
|
||||
{ "print-root-device", no_argument, NULL, 'R' },
|
||||
{ "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
|
||||
{ "random-seed", required_argument, NULL, ARG_RANDOM_SEED },
|
||||
|
@ -332,6 +408,14 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
arg_print_dollar_boot_path = true;
|
||||
break;
|
||||
|
||||
case ARG_PRINT_LOADER_PATH:
|
||||
arg_print_loader_path = true;
|
||||
break;
|
||||
|
||||
case ARG_PRINT_STUB_PATH:
|
||||
arg_print_stub_path = true;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
arg_print_root_device++;
|
||||
break;
|
||||
|
@ -414,9 +498,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) > 1)
|
||||
if (!!arg_print_esp_path + !!arg_print_dollar_boot_path + (arg_print_root_device > 0) + arg_print_loader_path + arg_print_stub_path > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"--print-esp-path/-p, --print-boot-path/-x, --print-root-device=/-R cannot be combined.");
|
||||
"--print-esp-path/-p, --print-boot-path/-x, --print-root-device=/-R, --print-loader-path, --print-stub-path cannot be combined.");
|
||||
|
||||
if ((arg_root || arg_image) && argv[optind] && !STR_IN_SET(argv[optind], "status", "list",
|
||||
"install", "update", "remove", "is-installed", "random-seed", "unlink", "cleanup"))
|
||||
|
@ -541,6 +625,9 @@ static int run(int argc, char *argv[]) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (arg_print_loader_path || arg_print_stub_path)
|
||||
return print_loader_or_stub_path();
|
||||
|
||||
/* Open up and mount the image */
|
||||
if (arg_image) {
|
||||
assert(!arg_root);
|
||||
|
|
|
@ -1046,7 +1046,6 @@ static int process_socket(int fd) {
|
|||
_cleanup_close_ int input_fd = -EBADF, mount_tree_fd = -EBADF;
|
||||
Context context = {};
|
||||
struct iovec_wrapper iovw = {};
|
||||
struct iovec iovec;
|
||||
bool first = true;
|
||||
int r;
|
||||
|
||||
|
@ -1063,8 +1062,7 @@ static int process_socket(int fd) {
|
|||
.msg_controllen = sizeof(control),
|
||||
.msg_iovlen = 1,
|
||||
};
|
||||
ssize_t n;
|
||||
ssize_t l;
|
||||
ssize_t n, l;
|
||||
|
||||
l = next_datagram_size_fd(fd);
|
||||
if (l < 0) {
|
||||
|
@ -1072,8 +1070,10 @@ static int process_socket(int fd) {
|
|||
goto finish;
|
||||
}
|
||||
|
||||
iovec.iov_len = l;
|
||||
iovec.iov_base = malloc(l + 1);
|
||||
_cleanup_(iovec_done) struct iovec iovec = {
|
||||
.iov_len = l,
|
||||
.iov_base = malloc(l + 1),
|
||||
};
|
||||
if (!iovec.iov_base) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
|
@ -1083,7 +1083,6 @@ static int process_socket(int fd) {
|
|||
|
||||
n = recvmsg_safe(fd, &mh, MSG_CMSG_CLOEXEC);
|
||||
if (n < 0) {
|
||||
free(iovec.iov_base);
|
||||
r = log_error_errno(n, "Failed to receive datagram: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
@ -1093,8 +1092,6 @@ static int process_socket(int fd) {
|
|||
if (n == 0) {
|
||||
struct cmsghdr *found;
|
||||
|
||||
free(iovec.iov_base);
|
||||
|
||||
found = cmsg_find(&mh, SOL_SOCKET, SCM_RIGHTS, CMSG_LEN(sizeof(int) * 2));
|
||||
if (found) {
|
||||
int fds[2] = EBADF_PAIR;
|
||||
|
@ -1134,6 +1131,8 @@ static int process_socket(int fd) {
|
|||
r = iovw_put(&iovw, iovec.iov_base, iovec.iov_len);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
TAKE_STRUCT(iovec);
|
||||
}
|
||||
|
||||
/* Make sure we got all data we really need */
|
||||
|
|
|
@ -85,6 +85,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
|
|||
SD_BUS_ERROR_MAP(BUS_ERROR_STUB_LOOP, ELOOP),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DNSSD_SERVICE, ENOENT),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_DNSSD_SERVICE_EXISTS, EEXIST),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DELEGATE, ENXIO),
|
||||
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_DNS_FORMERR, EBADMSG),
|
||||
SD_BUS_ERROR_MAP(BUS_ERROR_DNS_SERVFAIL, EHOSTDOWN),
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#define BUS_ERROR_STUB_LOOP "org.freedesktop.resolve1.StubLoop"
|
||||
#define BUS_ERROR_NO_SUCH_DNSSD_SERVICE "org.freedesktop.resolve1.NoSuchDnssdService"
|
||||
#define BUS_ERROR_DNSSD_SERVICE_EXISTS "org.freedesktop.resolve1.DnssdServiceExists"
|
||||
#define BUS_ERROR_NO_SUCH_DELEGATE "org.freedesktop.resolve1.NoSuchDelegate"
|
||||
|
||||
#define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError."
|
||||
#define BUS_ERROR_DNS_FORMERR _BUS_ERROR_DNS "FORMERR"
|
||||
|
|
|
@ -5602,7 +5602,7 @@ static int run_container(
|
|||
}
|
||||
|
||||
/* Note: we do not use SD_EVENT_SIGNAL_PROCMASK or sd_event_set_signal_exit(), since we want the
|
||||
* signals to be block continously, even if we destroy the event loop and allocate a new one on
|
||||
* signals to be block continuously, even if we destroy the event loop and allocate a new one on
|
||||
* container reboot. */
|
||||
|
||||
if (arg_kill_signal > 0) {
|
||||
|
|
|
@ -16,6 +16,8 @@ systemd_resolved_sources = files(
|
|||
'resolved-bus.c',
|
||||
'resolved-conf.c',
|
||||
'resolved-dns-cache.c',
|
||||
'resolved-dns-delegate.c',
|
||||
'resolved-dns-delegate-bus.c',
|
||||
'resolved-dns-query.c',
|
||||
'resolved-dns-scope.c',
|
||||
'resolved-dns-search-domain.c',
|
||||
|
@ -100,6 +102,12 @@ systemd_resolved_sources += custom_target(
|
|||
output : 'resolved-dnssd-gperf.c',
|
||||
command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@'])
|
||||
|
||||
systemd_resolved_sources += custom_target(
|
||||
'resolved_dns_delegate_gperf.c',
|
||||
input : 'resolved-dns-delegate-gperf.gperf',
|
||||
output : 'resolved-dns-delegate-gperf.c',
|
||||
command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@'])
|
||||
|
||||
systemd_resolved_dependencies = [threads, libm] + [lib_openssl_or_gcrypt]
|
||||
if conf.get('ENABLE_DNS_OVER_TLS') == 1
|
||||
if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1
|
||||
|
|
|
@ -1354,11 +1354,36 @@ static int reset_server_features(int argc, char **argv, void *userdata) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef enum DnsServerPropertyFlags {
|
||||
DNS_SERVER_WITH_IFINDEX = 1 << 0, /* prefixed with a field for an ifindex */
|
||||
DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME = 1 << 1, /* suffix with port nr and server name */
|
||||
DNS_SERVER_ONLY_GLOBAL = 1 << 2, /* filter entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */
|
||||
_DNS_SERVER_PROPERTY_FLAGS_MAX = DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME|DNS_SERVER_ONLY_GLOBAL,
|
||||
} DnsServerPropertyFlags;
|
||||
|
||||
static const char *dns_server_property_signature(DnsServerPropertyFlags flags) {
|
||||
switch (flags & (DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME)) {
|
||||
|
||||
case 0:
|
||||
return "iay";
|
||||
|
||||
case DNS_SERVER_WITH_IFINDEX:
|
||||
return "iiay";
|
||||
|
||||
case DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME:
|
||||
return "iayqs";
|
||||
|
||||
case DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME:
|
||||
return "iiayqs";
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static int read_dns_server_one(
|
||||
sd_bus_message *m,
|
||||
bool with_ifindex, /* read "ifindex" reply that also carries an interface index */
|
||||
bool extended, /* read "extended" reply, i.e. with port number and server name */
|
||||
bool only_global, /* suppress entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */
|
||||
DnsServerPropertyFlags flags,
|
||||
char **ret) {
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
@ -1375,12 +1400,11 @@ static int read_dns_server_one(
|
|||
r = sd_bus_message_enter_container(
|
||||
m,
|
||||
'r',
|
||||
with_ifindex ? (extended ? "iiayqs" : "iiay") :
|
||||
(extended ? "iayqs" : "iay"));
|
||||
dns_server_property_signature(flags));
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (with_ifindex) {
|
||||
if (FLAGS_SET(flags, DNS_SERVER_WITH_IFINDEX)) {
|
||||
r = sd_bus_message_read(m, "i", &ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -1390,12 +1414,8 @@ static int read_dns_server_one(
|
|||
if (k < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
|
||||
return k;
|
||||
|
||||
if (extended) {
|
||||
r = sd_bus_message_read(m, "q", &port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_read(m, "s", &name);
|
||||
if (FLAGS_SET(flags, DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME)) {
|
||||
r = sd_bus_message_read(m, "qs", &port, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -1410,7 +1430,7 @@ static int read_dns_server_one(
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (only_global && ifindex > 0 && ifindex != LOOPBACK_IFINDEX) {
|
||||
if (FLAGS_SET(flags, DNS_SERVER_ONLY_GLOBAL) && ifindex > 0 && ifindex != LOOPBACK_IFINDEX) {
|
||||
/* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */
|
||||
*ret = NULL;
|
||||
return 1;
|
||||
|
@ -1424,7 +1444,14 @@ static int read_dns_server_one(
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) {
|
||||
static int map_dns_servers_internal(
|
||||
sd_bus *bus,
|
||||
const char *member,
|
||||
sd_bus_message *m,
|
||||
DnsServerPropertyFlags flags,
|
||||
sd_bus_error *error,
|
||||
void *userdata) {
|
||||
|
||||
char ***l = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
|
@ -1432,14 +1459,16 @@ static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus
|
|||
assert(member);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', extended ? "(iayqs)" : "(iay)");
|
||||
const char *sig = strjoina("(", dns_server_property_signature(flags), ")");
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', sig);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
|
||||
r = read_dns_server_one(m, /* with_ifindex= */ false, extended, /* only_global= */ false, &pretty);
|
||||
r = read_dns_server_one(m, flags, &pretty);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
|
@ -1461,25 +1490,25 @@ static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus
|
|||
}
|
||||
|
||||
static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_link_dns_servers_internal(bus, member, m, error, userdata, false);
|
||||
return map_dns_servers_internal(bus, member, m, /* flags= */ 0, error, userdata);
|
||||
}
|
||||
|
||||
static int map_link_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_link_dns_servers_internal(bus, member, m, error, userdata, true);
|
||||
return map_dns_servers_internal(bus, member, m, DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, error, userdata);
|
||||
}
|
||||
|
||||
static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
assert(m);
|
||||
assert(userdata);
|
||||
|
||||
return read_dns_server_one(m, /* with_ifindex= */ false, /* extended= */ false, /* only_global= */ false, userdata);
|
||||
return read_dns_server_one(m, /* flags= */ 0, userdata);
|
||||
}
|
||||
|
||||
static int map_link_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
assert(m);
|
||||
assert(userdata);
|
||||
|
||||
return read_dns_server_one(m, /* with_ifindex= */ false, /* extended= */ true, /* only_global= */ false, userdata);
|
||||
return read_dns_server_one(m, DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, userdata);
|
||||
}
|
||||
|
||||
static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
|
||||
|
@ -1511,11 +1540,17 @@ static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
|
|||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(str);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
static int map_domains_internal(
|
||||
sd_bus *bus,
|
||||
const char *member,
|
||||
sd_bus_message *m,
|
||||
bool with_ifindex,
|
||||
sd_bus_error *error,
|
||||
void *userdata) {
|
||||
|
||||
char ***l = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
|
@ -1523,14 +1558,14 @@ static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m,
|
|||
assert(member);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', "(sb)");
|
||||
r = sd_bus_message_enter_container(m, 'a', with_ifindex ? "(isb)" : "(sb)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
|
||||
r = read_domain_one(m, false, &pretty);
|
||||
r = read_domain_one(m, with_ifindex, &pretty);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
|
@ -1551,12 +1586,18 @@ static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
|
||||
static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_domains_internal(bus, member, m, /* with_ifindex= */ false, error, userdata);
|
||||
}
|
||||
|
||||
static int status_print_strv_full(int ifindex, const char *ifname, const char *delegate_id, char **p) {
|
||||
const unsigned indent = strlen("Global: "); /* Use the same indentation everywhere to make things nice */
|
||||
int pos1, pos2;
|
||||
|
||||
if (ifname)
|
||||
printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1, ifindex, ifname, &pos2, ansi_normal());
|
||||
else if (delegate_id)
|
||||
printf("%s%nDelegate %s%n%s:", ansi_highlight(), &pos1, delegate_id, &pos2, ansi_normal());
|
||||
else
|
||||
printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1, &pos2, ansi_normal());
|
||||
|
||||
|
@ -1580,6 +1621,14 @@ static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
|
||||
return status_print_strv_full(ifindex, ifname, NULL, p);
|
||||
}
|
||||
|
||||
static int status_print_strv_delegate(const char *delegate_id, char **p) {
|
||||
return status_print_strv_full(0, NULL, delegate_id, p);
|
||||
}
|
||||
|
||||
static int status_print_strv_global(char **p) {
|
||||
return status_print_strv_ifindex(0, NULL, p);
|
||||
}
|
||||
|
@ -1899,101 +1948,24 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int map_global_dns_servers_internal(
|
||||
sd_bus *bus,
|
||||
const char *member,
|
||||
sd_bus_message *m,
|
||||
sd_bus_error *error,
|
||||
void *userdata,
|
||||
bool extended) {
|
||||
|
||||
char ***l = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(member);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', extended ? "(iiayqs)" : "(iiay)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
|
||||
r = read_dns_server_one(m, /* with_ifindex= */ true, extended, /* only_global= */ true, &pretty);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (isempty(pretty))
|
||||
continue;
|
||||
|
||||
r = strv_consume(l, TAKE_PTR(pretty));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_global_dns_servers_internal(bus, member, m, error, userdata, /* extended= */ false);
|
||||
return map_dns_servers_internal(bus, member, m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_ONLY_GLOBAL, error, userdata);
|
||||
}
|
||||
|
||||
static int map_global_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_global_dns_servers_internal(bus, member, m, error, userdata, /* extended= */ true);
|
||||
return map_dns_servers_internal(bus, member, m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_ONLY_GLOBAL|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, error, userdata);
|
||||
}
|
||||
|
||||
static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return read_dns_server_one(m, /* with_ifindex= */ true, /* extended= */ false, /* only_global= */ true, userdata);
|
||||
return read_dns_server_one(m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_ONLY_GLOBAL, userdata);
|
||||
}
|
||||
|
||||
static int map_global_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return read_dns_server_one(m, /* with_ifindex= */ true, /* extended= */ true, /* only_global= */ true, userdata);
|
||||
return read_dns_server_one(m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME|DNS_SERVER_ONLY_GLOBAL, userdata);
|
||||
}
|
||||
|
||||
static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
char ***l = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(member);
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_enter_container(m, 'a', "(isb)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
|
||||
r = read_domain_one(m, true, &pretty);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (isempty(pretty))
|
||||
continue;
|
||||
|
||||
r = strv_consume(l, TAKE_PTR(pretty));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
strv_sort(*l);
|
||||
|
||||
return 0;
|
||||
return map_domains_internal(bus, member, m, /* with_ifindex= */ true, error, userdata);
|
||||
}
|
||||
|
||||
static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
|
||||
|
@ -2132,18 +2104,13 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int status_all(sd_bus *bus, StatusMode mode) {
|
||||
static int status_links(sd_bus *bus, StatusMode mode, bool *empty_line) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
bool empty_line = false;
|
||||
int ret = 0, r;
|
||||
|
||||
assert(bus);
|
||||
|
||||
r = status_global(bus, mode, &empty_line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_open(&rtnl);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to netlink: %m");
|
||||
|
@ -2195,11 +2162,206 @@ static int status_all(sd_bus *bus, StatusMode mode) {
|
|||
typesafe_qsort(infos, n_infos, interface_info_compare);
|
||||
|
||||
FOREACH_ARRAY(info, infos, n_infos)
|
||||
RET_GATHER(ret, status_ifindex(bus, info->index, info->name, mode, &empty_line));
|
||||
RET_GATHER(ret, status_ifindex(bus, info->index, info->name, mode, empty_line));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct DelegateInfo {
|
||||
char *current_dns;
|
||||
char **dns;
|
||||
char **domains;
|
||||
bool default_route;
|
||||
} DelegateInfo;
|
||||
|
||||
static void delegate_info_done(DelegateInfo *p) {
|
||||
assert(p);
|
||||
|
||||
free(p->current_dns);
|
||||
strv_free(p->dns);
|
||||
strv_free(p->domains);
|
||||
}
|
||||
|
||||
static int map_delegate_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_dns_servers_internal(bus, member, m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, error, userdata);
|
||||
}
|
||||
|
||||
static int map_delegate_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return read_dns_server_one(m, DNS_SERVER_WITH_IFINDEX|DNS_SERVER_WITH_PORT_NUMBER_AND_SERVER_NAME, userdata);
|
||||
}
|
||||
|
||||
static int map_delegate_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
||||
return map_domains_internal(bus, member, m, /* with_ifindex= */ false, error, userdata);
|
||||
}
|
||||
|
||||
static int status_delegate_one(sd_bus *bus, const char *id, StatusMode mode, bool *empty_line) {
|
||||
|
||||
static const struct bus_properties_map property_map[] = {
|
||||
{ "DNS", "a(iiayqs)", map_delegate_dns_servers, offsetof(DelegateInfo, dns) },
|
||||
{ "CurrentDNSServer", "(iiayqs)", map_delegate_current_dns_server, offsetof(DelegateInfo, current_dns) },
|
||||
{ "Domains", "a(sb)", map_delegate_domains, offsetof(DelegateInfo, domains) },
|
||||
{ "DefaultRoute", "b", NULL, offsetof(DelegateInfo, default_route) },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(delegate_info_done) DelegateInfo delegate_info = {};
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(id);
|
||||
|
||||
r = sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", id, &p);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
log_info("→ %s", p);
|
||||
|
||||
r = bus_map_all_properties(
|
||||
bus,
|
||||
"org.freedesktop.resolve1",
|
||||
p,
|
||||
property_map,
|
||||
BUS_MAP_BOOLEAN_AS_BOOL,
|
||||
&error,
|
||||
&m,
|
||||
&delegate_info);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get delegate data for %s: %s", id, bus_error_message(&error, r));
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
switch (mode) {
|
||||
|
||||
case STATUS_DNS:
|
||||
return status_print_strv_delegate(id, delegate_info.dns);
|
||||
|
||||
case STATUS_DOMAIN:
|
||||
return status_print_strv_delegate(id, delegate_info.domains);
|
||||
|
||||
case STATUS_DEFAULT_ROUTE:
|
||||
printf("%sDelegate %s%s: %s\n",
|
||||
ansi_highlight(), id, ansi_normal(),
|
||||
yes_no(delegate_info.default_route));
|
||||
|
||||
return 0;
|
||||
|
||||
case STATUS_ALL:
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (empty_line && *empty_line)
|
||||
fputc('\n', stdout);
|
||||
|
||||
printf("%sDelegate %s%s\n",
|
||||
ansi_highlight(), id, ansi_normal());
|
||||
|
||||
_cleanup_(table_unrefp) Table *table = table_new_vertical();
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
if (delegate_info.current_dns) {
|
||||
r = table_add_many(table,
|
||||
TABLE_FIELD, "Current DNS Server",
|
||||
TABLE_STRING, delegate_info.current_dns);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
r = dump_list(table, "DNS Servers", delegate_info.dns);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dump_list(table, "DNS Domain", delegate_info.domains);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_FIELD, "Default Route",
|
||||
TABLE_BOOLEAN, delegate_info.default_route);
|
||||
|
||||
r = table_print(table, NULL);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
if (empty_line)
|
||||
*empty_line = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int status_delegates(sd_bus *bus, StatusMode mode, bool *empty_line) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
int r, ret = 0;
|
||||
|
||||
assert(bus);
|
||||
|
||||
r = bus_call_method(bus, bus_resolve_mgr, "ListDelegates", &error, &reply, NULL);
|
||||
if (r < 0) {
|
||||
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
|
||||
log_debug("Delegates not supported, skipping.");
|
||||
return 0;
|
||||
}
|
||||
return log_error_errno(r, "Failed to list delegates: %s", bus_error_message(&error, r));
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(so)");
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
for (;;) {
|
||||
const char *id;
|
||||
|
||||
r = sd_bus_message_read(reply, "(so)", &id, NULL);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (strv_extend(&l, id) < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
strv_sort(l);
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
RET_GATHER(ret, status_delegate_one(bus, *i, mode, empty_line));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int status_all(sd_bus *bus, StatusMode mode) {
|
||||
bool empty_line = false;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
|
||||
r = status_global(bus, mode, &empty_line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = status_links(bus, mode, &empty_line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = status_delegates(bus, mode, &empty_line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_status(int argc, char **argv, void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
#include "path-util.h"
|
||||
#include "resolved-bus.h"
|
||||
#include "resolved-def.h"
|
||||
#include "resolved-dns-delegate-bus.h"
|
||||
#include "resolved-dns-stream.h"
|
||||
#include "resolved-dns-synthesize.h"
|
||||
#include "resolved-dnssd-bus.h"
|
||||
#include "resolved-dnssd.h"
|
||||
#include "resolved-dnssd-bus.h"
|
||||
#include "resolved-link-bus.h"
|
||||
#include "resolved-resolv-conf.h"
|
||||
#include "socket-netlink.h"
|
||||
|
@ -2079,6 +2080,64 @@ static int bus_method_unregister_service(sd_bus_message *message, void *userdata
|
|||
return call_dnssd_method(m, message, bus_dnssd_method_unregister, error);
|
||||
}
|
||||
|
||||
static int bus_method_get_delegate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
const char *id;
|
||||
r = sd_bus_message_read(message, "s", &id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
DnsDelegate *d = hashmap_get(m->delegates, id);
|
||||
if (!d)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DELEGATE, "Delegate '%s' not known", id);
|
||||
|
||||
p = dns_delegate_bus_path(d);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
return sd_bus_reply_method_return(message, "o", p);
|
||||
}
|
||||
|
||||
static int bus_method_list_delegates(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(so)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = dns_delegate_bus_path(d);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = sd_bus_message_append(reply, "(so)", d->id, p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static const sd_bus_vtable resolve_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
|
@ -2217,6 +2276,16 @@ static const sd_bus_vtable resolve_vtable[] = {
|
|||
SD_BUS_NO_RESULT,
|
||||
bus_method_reset_server_features,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("GetDelegate",
|
||||
SD_BUS_ARGS("s", id),
|
||||
SD_BUS_RESULT("o", path),
|
||||
bus_method_get_delegate,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_ARGS("ListDelegates",
|
||||
SD_BUS_NO_ARGS,
|
||||
SD_BUS_RESULT("a(so)", delegates),
|
||||
bus_method_list_delegates,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
@ -2226,7 +2295,8 @@ const BusObjectImplementation manager_object = {
|
|||
"org.freedesktop.resolve1.Manager",
|
||||
.vtables = BUS_VTABLES(resolve_vtable),
|
||||
.children = BUS_IMPLEMENTATIONS(&link_object,
|
||||
&dnssd_object),
|
||||
&dnssd_object,
|
||||
&dns_delegate_object),
|
||||
};
|
||||
|
||||
static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
|
||||
|
|
|
@ -55,7 +55,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
|
|||
return 0;
|
||||
}
|
||||
|
||||
return dns_server_new(m, NULL, type, NULL, family, &address, port, ifindex, server_name, RESOLVE_CONFIG_SOURCE_FILE);
|
||||
return dns_server_new(m, /* ret= */ NULL, type, /* link= */ NULL, /* delegate= */ NULL, family, &address, port, ifindex, server_name, RESOLVE_CONFIG_SOURCE_FILE);
|
||||
}
|
||||
|
||||
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
|
||||
|
@ -100,7 +100,7 @@ static int manager_add_search_domain_by_string(Manager *m, const char *domain) {
|
|||
if (r > 0)
|
||||
dns_search_domain_move_back_and_unmark(d);
|
||||
else {
|
||||
r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
|
||||
r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, domain);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "bus-get-properties.h"
|
||||
#include "resolved-bus.h"
|
||||
#include "resolved-dns-delegate-bus.h"
|
||||
#include "resolved-manager.h"
|
||||
#include "strv.h"
|
||||
|
||||
static int property_get_dns(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
DnsDelegate *d = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(reply);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(iiayqs)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_FOREACH(servers, s, d->dns_servers) {
|
||||
r = bus_dns_server_append(reply, s, /* with_ifindex= */ true, /* extended= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int property_get_current_dns_server(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
DnsDelegate *d = ASSERT_PTR(userdata);
|
||||
|
||||
assert(reply);
|
||||
|
||||
return bus_dns_server_append(reply, d->current_dns_server, /* with_ifindex= */ true, /* extended= */ true);
|
||||
}
|
||||
|
||||
static int property_get_domains(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
DnsDelegate *delegate = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(reply);
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(sb)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
LIST_FOREACH(domains, d, delegate->search_domains) {
|
||||
r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return sd_bus_message_close_container(reply);
|
||||
}
|
||||
|
||||
static int dns_delegate_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
|
||||
assert(bus);
|
||||
assert(path);
|
||||
assert(interface);
|
||||
assert(found);
|
||||
|
||||
_cleanup_free_ char *e = NULL;
|
||||
if (sd_bus_path_decode(path, "/org/freedesktop/resolve1/dns_delegate", &e) <= 0)
|
||||
return 0;
|
||||
|
||||
DnsDelegate *d = hashmap_get(m->delegates, e);
|
||||
if (!d)
|
||||
return 0;
|
||||
|
||||
*found = d;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* dns_delegate_bus_path(const DnsDelegate *d) {
|
||||
char *p;
|
||||
|
||||
assert(d);
|
||||
|
||||
if (sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", d->id, &p) < 0)
|
||||
return NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int dns_delegate_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(path);
|
||||
assert(nodes);
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
p = dns_delegate_bus_path(d);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = strv_consume(&l, TAKE_PTR(p));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*nodes = TAKE_PTR(l);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const sd_bus_vtable dns_delegate_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
|
||||
SD_BUS_PROPERTY("DNS", "a(iiayqs)", property_get_dns, 0, 0),
|
||||
SD_BUS_PROPERTY("CurrentDNSServer", "(iiayqs)", property_get_current_dns_server, 0, 0),
|
||||
SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
|
||||
SD_BUS_PROPERTY("DefaultRoute", "b", bus_property_get_tristate, offsetof(DnsDelegate, default_route), 0),
|
||||
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
const BusObjectImplementation dns_delegate_object = {
|
||||
"/org/freedesktop/resolve1/dns_delegate",
|
||||
"org.freedesktop.resolve1.DnsDelegate",
|
||||
.fallback_vtables = BUS_FALLBACK_VTABLES({dns_delegate_vtable, dns_delegate_object_find}),
|
||||
.node_enumerator = dns_delegate_node_enumerator,
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "bus-object.h"
|
||||
#include "bus-util.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
|
||||
extern const BusObjectImplementation dns_delegate_object;
|
||||
|
||||
char* dns_delegate_bus_path(const DnsDelegate *d);
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
%{
|
||||
#include <stddef.h>
|
||||
#include "conf-parser.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
%}
|
||||
struct ConfigPerfItem;
|
||||
%null_strings
|
||||
%language=ANSI-C
|
||||
%define slot-name section_and_lvalue
|
||||
%define hash-function-name resolved_dns_delegate_gperf_hash
|
||||
%define lookup-function-name resolved_dns_delegate_gperf_lookup
|
||||
%readonly-tables
|
||||
%omit-struct-type
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
Delegate.DNS, config_parse_delegate_dns_servers, 0, 0
|
||||
Delegate.Domains, config_parse_delegate_domains, 0, 0
|
||||
Delegate.DefaultRoute, config_parse_tristate, 0, offsetof(DnsDelegate, default_route),
|
|
@ -0,0 +1,356 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "conf-files.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "path-util.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-manager.h"
|
||||
#include "socket-netlink.h"
|
||||
|
||||
#define DNS_DELEGATES_MAX 4096U
|
||||
#define DNS_DELEGATE_SEARCH_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/dns-delegate"))
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
dns_delegate_hash_ops,
|
||||
char,
|
||||
string_hash_func,
|
||||
string_compare_func,
|
||||
DnsDelegate,
|
||||
dns_delegate_free);
|
||||
|
||||
int dns_delegate_new(Manager *m, const char *id, DnsDelegate **ret) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(id);
|
||||
|
||||
if (hashmap_size(m->delegates) >= DNS_DELEGATES_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
_cleanup_free_ char *id_copy = strdup(id);
|
||||
if (!id_copy)
|
||||
return -ENOMEM;
|
||||
|
||||
_cleanup_(dns_delegate_freep) DnsDelegate *d = new(DnsDelegate, 1);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
*d = (DnsDelegate) {
|
||||
.id = TAKE_PTR(id_copy),
|
||||
.default_route = -1,
|
||||
};
|
||||
|
||||
r = dns_scope_new(
|
||||
m,
|
||||
&d->scope,
|
||||
DNS_SCOPE_DELEGATE,
|
||||
/* link= */ NULL,
|
||||
d,
|
||||
DNS_PROTOCOL_DNS,
|
||||
AF_UNSPEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_ensure_put(&m->delegates, &dns_delegate_hash_ops, d->id, d);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
d->manager = m;
|
||||
|
||||
log_debug("New delegate '%s'.", id);
|
||||
|
||||
if (ret)
|
||||
*ret = d;
|
||||
|
||||
TAKE_PTR(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DnsDelegate *dns_delegate_free(DnsDelegate *d) {
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
Manager *m = d->manager;
|
||||
|
||||
log_debug("Removing delegate '%s'.", d->id);
|
||||
|
||||
dns_server_unlink_all(d->dns_servers);
|
||||
dns_search_domain_unlink_all(d->search_domains);
|
||||
|
||||
dns_scope_free(d->scope);
|
||||
|
||||
if (m)
|
||||
hashmap_remove(m->delegates, d->id);
|
||||
|
||||
free(d->id);
|
||||
|
||||
return mfree(d);
|
||||
}
|
||||
|
||||
DnsServer* dns_delegate_set_dns_server(DnsDelegate *d, DnsServer *s) {
|
||||
assert(d);
|
||||
|
||||
if (d->current_dns_server == s)
|
||||
return s;
|
||||
|
||||
if (s)
|
||||
log_debug("Switching delegate '%s' to DNS server %s.", d->id, strna(dns_server_string_full(s)));
|
||||
|
||||
dns_server_unref(d->current_dns_server);
|
||||
d->current_dns_server = dns_server_ref(s);
|
||||
|
||||
/* Skip flushing the cache if server stale feature is enabled. */
|
||||
if (d->manager->stale_retention_usec == 0)
|
||||
dns_cache_flush(&d->scope->cache);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
DnsServer *dns_delegate_get_dns_server(DnsDelegate *d) {
|
||||
assert(d);
|
||||
|
||||
if (!d->current_dns_server)
|
||||
dns_delegate_set_dns_server(d, d->dns_servers);
|
||||
|
||||
return d->current_dns_server;
|
||||
}
|
||||
|
||||
void dns_delegate_next_dns_server(DnsDelegate *d, DnsServer *if_current) {
|
||||
assert(d);
|
||||
|
||||
/* If the current server of the transaction is specified, and we already are at a different one,
|
||||
* don't do anything */
|
||||
if (if_current && d->current_dns_server != if_current)
|
||||
return;
|
||||
|
||||
/* If currently have no DNS server, then don't do anything, we'll pick it lazily the next time a DNS
|
||||
* server is needed. */
|
||||
if (!d->current_dns_server)
|
||||
return;
|
||||
|
||||
/* Change to the next one, but make sure to follow the linked list only if this server is actually
|
||||
* still linked. */
|
||||
if (d->current_dns_server->linked && d->current_dns_server->servers_next) {
|
||||
dns_delegate_set_dns_server(d, d->current_dns_server->servers_next);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pick the first one again, after we reached the end */
|
||||
dns_delegate_set_dns_server(d, d->dns_servers);
|
||||
}
|
||||
|
||||
static int dns_delegate_load(Manager *m, const char *path) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(path);
|
||||
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
|
||||
|
||||
const char *e = endswith(fn, ".dns-delegate");
|
||||
if (!e)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DNS delegate file name does not end in .dns-delegate, refusing: %s", fn);
|
||||
|
||||
_cleanup_free_ char *id = strndup(fn, e - fn);
|
||||
if (!string_is_safe(id))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DNS delegate file name contains weird characters, refusing: %s", fn);
|
||||
|
||||
_cleanup_free_ char *dropin_dirname = strjoin(id, ".dns-delegate.d");
|
||||
if (!dropin_dirname)
|
||||
return log_oom();
|
||||
|
||||
_cleanup_(dns_delegate_freep) DnsDelegate *d = NULL;
|
||||
r = dns_delegate_new(m, id, &d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate delegate '%s': %m", id);
|
||||
|
||||
r = config_parse_many(
|
||||
STRV_MAKE_CONST(path),
|
||||
DNS_DELEGATE_SEARCH_DIRS,
|
||||
dropin_dirname,
|
||||
/* root= */ NULL,
|
||||
"Delegate\0",
|
||||
config_item_perf_lookup,
|
||||
resolved_dns_delegate_gperf_lookup,
|
||||
/* flags= */ 0,
|
||||
d,
|
||||
/* ret_stats_by_path= */ NULL,
|
||||
/* ret_drop_in_files= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_info("Successfully loaded delegate '%s'.", d->id);
|
||||
|
||||
TAKE_PTR(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_load_delegates(Manager *m) {
|
||||
_cleanup_strv_free_ char **files = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = conf_files_list_strv(&files, ".dns-delegate", /* root= */ NULL, /* flags= */ 0, DNS_DELEGATE_SEARCH_DIRS);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enumerate .dns-delegate files: %m");
|
||||
|
||||
STRV_FOREACH(f, files)
|
||||
(void) dns_delegate_load(m, *f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_delegate_dns_servers(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
DnsDelegate *d = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
/* Empty assignment means clear the list */
|
||||
if (isempty(rvalue)) {
|
||||
dns_server_unlink_all(d->dns_servers);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, add to the list */
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
r = extract_first_word(&rvalue, &word, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse DNS server string '%s', ignoring.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
_cleanup_free_ char *server_name = NULL;
|
||||
union in_addr_union address;
|
||||
int family, ifindex = 0;
|
||||
uint16_t port;
|
||||
r = in_addr_port_ifindex_name_from_string_auto(word, &family, &address, &port, &ifindex, &server_name);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse DNS server string '%s', ignoring.", word);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Silently filter out 0.0.0.0, 127.0.0.53, 127.0.0.54 (our own stub DNS listener) */
|
||||
if (!dns_server_address_valid(family, &address))
|
||||
continue;
|
||||
|
||||
/* By default, the port number is determined with the transaction feature level.
|
||||
* See dns_transaction_port() and dns_server_port(). */
|
||||
if (IN_SET(port, 53, 853))
|
||||
port = 0;
|
||||
|
||||
/* Filter out duplicates */
|
||||
DnsServer *s = dns_server_find(d->dns_servers, family, &address, port, ifindex, server_name);
|
||||
if (s) {
|
||||
/* Drop the marker. This is used to find the servers that ceased to exist, see
|
||||
* manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */
|
||||
dns_server_move_back_and_unmark(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = dns_server_new(
|
||||
d->manager,
|
||||
/* ret= */ NULL,
|
||||
DNS_SERVER_DELEGATE,
|
||||
/* link= */ NULL,
|
||||
d,
|
||||
family,
|
||||
&address,
|
||||
port,
|
||||
ifindex,
|
||||
server_name,
|
||||
RESOLVE_CONFIG_SOURCE_FILE);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add DNS server: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_delegate_domains(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
DnsDelegate *d = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
/* Empty assignment means clear the list */
|
||||
if (isempty(rvalue)) {
|
||||
dns_search_domain_unlink_all(d->search_domains);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, add to the list */
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
r = extract_first_word(&rvalue, &word, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse search domains string '%s', ignoring.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
const char *name = word;
|
||||
|
||||
bool route_only = name[0] == '~';
|
||||
if (route_only)
|
||||
name++;
|
||||
|
||||
if (dns_name_is_root(name) || streq(name, "*")) {
|
||||
route_only = true;
|
||||
name = ".";
|
||||
}
|
||||
|
||||
DnsSearchDomain *domain;
|
||||
r = dns_search_domain_find(d->search_domains, name, &domain);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to find search domain: %m");
|
||||
if (r > 0)
|
||||
dns_search_domain_move_back_and_unmark(domain);
|
||||
else {
|
||||
r = dns_search_domain_new(d->manager, &domain, DNS_SEARCH_DOMAIN_DELEGATE, /* link= */ NULL, d, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
domain->route_only = route_only;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
typedef struct DnsDelegate DnsDelegate;
|
||||
|
||||
#include "resolved-dns-scope.h"
|
||||
#include "resolved-dns-search-domain.h"
|
||||
#include "resolved-dns-server.h"
|
||||
|
||||
#define DELEGATE_SEARCH_DOMAINS_MAX 256
|
||||
#define DELEGATE_DNS_SERVERS_MAX 256
|
||||
|
||||
/* A DnsDelegate object is used to manage additional, explicitly configured unicast DNS lookup scopes,
|
||||
* independent from any network link and from the global scope. */
|
||||
|
||||
struct DnsDelegate {
|
||||
Manager *manager;
|
||||
char *id;
|
||||
|
||||
LIST_HEAD(DnsServer, dns_servers);
|
||||
unsigned n_dns_servers;
|
||||
DnsServer *current_dns_server;
|
||||
|
||||
LIST_HEAD(DnsSearchDomain, search_domains);
|
||||
unsigned n_search_domains;
|
||||
|
||||
int default_route;
|
||||
|
||||
DnsScope *scope;
|
||||
|
||||
LIST_FIELDS(DnsDelegate, delegates);
|
||||
};
|
||||
|
||||
int dns_delegate_new(Manager *m, const char *id, DnsDelegate **ret);
|
||||
DnsDelegate *dns_delegate_free(DnsDelegate *d);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsDelegate*, dns_delegate_free);
|
||||
|
||||
DnsServer* dns_delegate_set_dns_server(DnsDelegate *d, DnsServer *s);
|
||||
DnsServer *dns_delegate_get_dns_server(DnsDelegate *d);
|
||||
void dns_delegate_next_dns_server(DnsDelegate *d, DnsServer *if_current);
|
||||
|
||||
int manager_load_delegates(Manager *m);
|
||||
|
||||
const struct ConfigPerfItem* resolved_dns_delegate_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_delegate_dns_servers);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_delegate_domains);
|
|
@ -11,12 +11,14 @@
|
|||
#include "missing_network.h"
|
||||
#include "random-util.h"
|
||||
#include "resolved-dnssd.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-dns-scope.h"
|
||||
#include "resolved-dns-synthesize.h"
|
||||
#include "resolved-dns-zone.h"
|
||||
#include "resolved-llmnr.h"
|
||||
#include "resolved-mdns.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "strv.h"
|
||||
|
||||
#define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC)
|
||||
|
@ -26,11 +28,24 @@
|
|||
#define MULTICAST_RESEND_TIMEOUT_MIN_USEC (100 * USEC_PER_MSEC)
|
||||
#define MULTICAST_RESEND_TIMEOUT_MAX_USEC (1 * USEC_PER_SEC)
|
||||
|
||||
int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int family) {
|
||||
int dns_scope_new(
|
||||
Manager *m,
|
||||
DnsScope **ret,
|
||||
DnsScopeOrigin origin,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
DnsProtocol protocol,
|
||||
int family) {
|
||||
|
||||
DnsScope *s;
|
||||
|
||||
assert(m);
|
||||
assert(ret);
|
||||
assert(origin >= 0);
|
||||
assert(origin < _DNS_SCOPE_ORIGIN_MAX);
|
||||
|
||||
assert(!!link == (origin == DNS_SCOPE_LINK));
|
||||
assert(!!delegate == (origin == DNS_SCOPE_DELEGATE));
|
||||
|
||||
s = new(DnsScope, 1);
|
||||
if (!s)
|
||||
|
@ -38,7 +53,9 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
|
|||
|
||||
*s = (DnsScope) {
|
||||
.manager = m,
|
||||
.link = l,
|
||||
.link = link,
|
||||
.delegate = delegate,
|
||||
.origin = origin,
|
||||
.protocol = protocol,
|
||||
.family = family,
|
||||
.resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC,
|
||||
|
@ -54,9 +71,9 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
|
|||
* not update it from the on, even if the setting
|
||||
* changes. */
|
||||
|
||||
if (l) {
|
||||
s->dnssec_mode = link_get_dnssec_mode(l);
|
||||
s->dns_over_tls_mode = link_get_dns_over_tls_mode(l);
|
||||
if (link) {
|
||||
s->dnssec_mode = link_get_dnssec_mode(link);
|
||||
s->dns_over_tls_mode = link_get_dns_over_tls_mode(link);
|
||||
} else {
|
||||
s->dnssec_mode = manager_get_dnssec_mode(m);
|
||||
s->dns_over_tls_mode = manager_get_dns_over_tls_mode(m);
|
||||
|
@ -72,7 +89,12 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
|
|||
dns_scope_llmnr_membership(s, true);
|
||||
dns_scope_mdns_membership(s, true);
|
||||
|
||||
log_debug("New scope on link %s, protocol %s, family %s", l ? l->ifname : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
|
||||
log_debug("New scope on link %s, protocol %s, family %s, origin %s, delegate %s",
|
||||
link ? link->ifname : "*",
|
||||
dns_protocol_to_string(protocol),
|
||||
family == AF_UNSPEC ? "*" : af_to_name(family),
|
||||
dns_scope_origin_to_string(origin),
|
||||
s->delegate ? s->delegate->id : "n/a");
|
||||
|
||||
*ret = s;
|
||||
return 0;
|
||||
|
@ -100,7 +122,12 @@ DnsScope* dns_scope_free(DnsScope *s) {
|
|||
if (!s)
|
||||
return NULL;
|
||||
|
||||
log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->ifname : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
|
||||
log_debug("Removing scope on link %s, protocol %s, family %s, origin %s, delegate %s",
|
||||
s->link ? s->link->ifname : "*",
|
||||
dns_protocol_to_string(s->protocol),
|
||||
s->family == AF_UNSPEC ? "*" : af_to_name(s->family),
|
||||
dns_scope_origin_to_string(s->origin),
|
||||
s->delegate ? s->delegate->id : "n/a");
|
||||
|
||||
dns_scope_llmnr_membership(s, false);
|
||||
dns_scope_mdns_membership(s, false);
|
||||
|
@ -133,6 +160,8 @@ DnsServer *dns_scope_get_dns_server(DnsScope *s) {
|
|||
|
||||
if (s->link)
|
||||
return link_get_dns_server(s->link);
|
||||
else if (s->delegate)
|
||||
return dns_delegate_get_dns_server(s->delegate);
|
||||
else
|
||||
return manager_get_dns_server(s->manager);
|
||||
}
|
||||
|
@ -145,6 +174,8 @@ unsigned dns_scope_get_n_dns_servers(DnsScope *s) {
|
|||
|
||||
if (s->link)
|
||||
return s->link->n_dns_servers;
|
||||
else if (s->delegate)
|
||||
return s->delegate->n_dns_servers;
|
||||
else
|
||||
return s->manager->n_dns_servers;
|
||||
}
|
||||
|
@ -160,6 +191,8 @@ void dns_scope_next_dns_server(DnsScope *s, DnsServer *if_current) {
|
|||
|
||||
if (s->link)
|
||||
link_next_dns_server(s->link, if_current);
|
||||
else if (s->delegate)
|
||||
dns_delegate_next_dns_server(s->delegate, if_current);
|
||||
else
|
||||
manager_next_dns_server(s->manager, if_current);
|
||||
}
|
||||
|
@ -267,6 +300,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, int family, DnsPacket *p) {
|
|||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
assert(s->link);
|
||||
r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, LLMNR_PORT, NULL, p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -298,6 +332,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, int family, DnsPacket *p) {
|
|||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
assert(s->link);
|
||||
r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, p->destination_port ?: MDNS_PORT, NULL, p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -1374,6 +1409,14 @@ void dns_scope_dump(DnsScope *s, FILE *f) {
|
|||
fputs(af_to_name(s->family), f);
|
||||
}
|
||||
|
||||
fputs(" origin=", f);
|
||||
fputs(dns_scope_origin_to_string(s->origin), f);
|
||||
|
||||
if (s->delegate) {
|
||||
fputs(" id=", f);
|
||||
fputs(s->delegate->id, f);
|
||||
}
|
||||
|
||||
fputs("]\n", f);
|
||||
|
||||
if (!dns_zone_is_empty(&s->zone)) {
|
||||
|
@ -1395,6 +1438,8 @@ DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) {
|
|||
|
||||
if (s->link)
|
||||
return s->link->search_domains;
|
||||
if (s->delegate)
|
||||
return s->delegate->search_domains;
|
||||
|
||||
return s->manager->search_domains;
|
||||
}
|
||||
|
@ -1680,6 +1725,8 @@ static bool dns_scope_has_route_only_domains(DnsScope *scope) {
|
|||
|
||||
if (scope->link)
|
||||
first = scope->link->search_domains;
|
||||
else if (scope->delegate)
|
||||
first = scope->delegate->search_domains;
|
||||
else
|
||||
first = scope->manager->search_domains;
|
||||
|
||||
|
@ -1705,9 +1752,7 @@ bool dns_scope_is_default_route(DnsScope *scope) {
|
|||
if (scope->protocol != DNS_PROTOCOL_DNS)
|
||||
return false;
|
||||
|
||||
/* The global DNS scope is always suitable as default route */
|
||||
if (!scope->link)
|
||||
return true;
|
||||
if (scope->link) {
|
||||
|
||||
/* Honour whatever is explicitly configured. This is really the best approach, and trumps any
|
||||
* automatic logic. */
|
||||
|
@ -1717,6 +1762,17 @@ bool dns_scope_is_default_route(DnsScope *scope) {
|
|||
/* Otherwise check if we have any route-only domains, as a sensible heuristic: if so, let's not
|
||||
* volunteer as default route. */
|
||||
return !dns_scope_has_route_only_domains(scope);
|
||||
|
||||
} else if (scope->delegate) {
|
||||
|
||||
if (scope->delegate->default_route >= 0)
|
||||
return scope->delegate->default_route;
|
||||
|
||||
/* Delegates are by default not used as default route */
|
||||
return false;
|
||||
} else
|
||||
/* The global DNS scope is always suitable as default route */
|
||||
return true;
|
||||
}
|
||||
|
||||
int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret) {
|
||||
|
@ -1800,3 +1856,11 @@ int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protoco
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* const dns_scope_origin_table[_DNS_SCOPE_ORIGIN_MAX] = {
|
||||
[DNS_SCOPE_GLOBAL] = "global",
|
||||
[DNS_SCOPE_LINK] = "link",
|
||||
[DNS_SCOPE_DELEGATE] = "delegate",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(dns_scope_origin, DnsScopeOrigin);
|
||||
|
|
|
@ -26,9 +26,19 @@ typedef enum DnsScopeMatch {
|
|||
_DNS_SCOPE_MATCH_INVALID = -EINVAL,
|
||||
} DnsScopeMatch;
|
||||
|
||||
typedef enum DnsScopeOrigin {
|
||||
DNS_SCOPE_GLOBAL,
|
||||
DNS_SCOPE_LINK,
|
||||
DNS_SCOPE_DELEGATE,
|
||||
_DNS_SCOPE_ORIGIN_MAX,
|
||||
_DNS_SCOPE_ORIGIN_INVALID = -EINVAL,
|
||||
} DnsScopeOrigin;
|
||||
|
||||
struct DnsScope {
|
||||
Manager *manager;
|
||||
|
||||
DnsScopeOrigin origin;
|
||||
|
||||
DnsProtocol protocol;
|
||||
int family;
|
||||
|
||||
|
@ -37,6 +47,7 @@ struct DnsScope {
|
|||
DnsOverTlsMode dns_over_tls_mode;
|
||||
|
||||
Link *link;
|
||||
DnsDelegate *delegate;
|
||||
|
||||
DnsCache cache;
|
||||
DnsZone zone;
|
||||
|
@ -69,7 +80,7 @@ struct DnsScope {
|
|||
bool announced;
|
||||
};
|
||||
|
||||
int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol p, int family);
|
||||
int dns_scope_new(Manager *m, DnsScope **ret, DnsScopeOrigin origin, Link *link, DnsDelegate *delegate, DnsProtocol protocol, int family);
|
||||
DnsScope* dns_scope_free(DnsScope *s);
|
||||
|
||||
void dns_scope_packet_received(DnsScope *s, usec_t rtt);
|
||||
|
@ -119,3 +130,6 @@ int dns_scope_dump_cache_to_json(DnsScope *scope, sd_json_variant **ret);
|
|||
|
||||
int dns_type_suitable_for_protocol(uint16_t type, DnsProtocol protocol);
|
||||
int dns_question_types_suitable_for_protocol(DnsQuestion *q, DnsProtocol protocol);
|
||||
|
||||
const char* dns_scope_origin_to_string(DnsScopeOrigin origin) _const_;
|
||||
DnsScopeOrigin dns_scope_origin_from_string(const char *s) _pure_;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-dns-search-domain.h"
|
||||
#include "resolved-link.h"
|
||||
#include "resolved-manager.h"
|
||||
|
@ -10,7 +11,8 @@ int dns_search_domain_new(
|
|||
Manager *m,
|
||||
DnsSearchDomain **ret,
|
||||
DnsSearchDomainType type,
|
||||
Link *l,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
const char *name) {
|
||||
|
||||
_cleanup_free_ char *normalized = NULL;
|
||||
|
@ -18,15 +20,19 @@ int dns_search_domain_new(
|
|||
int r;
|
||||
|
||||
assert(m);
|
||||
assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l);
|
||||
assert((type == DNS_SEARCH_DOMAIN_LINK) == !!link);
|
||||
assert((type == DNS_SEARCH_DOMAIN_DELEGATE) == !!delegate);
|
||||
assert(name);
|
||||
|
||||
r = dns_name_normalize(name, 0, &normalized);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (l) {
|
||||
if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX)
|
||||
if (link) {
|
||||
if (link->n_search_domains >= LINK_SEARCH_DOMAINS_MAX)
|
||||
return -E2BIG;
|
||||
} else if (delegate) {
|
||||
if (delegate->n_search_domains >= DELEGATE_SEARCH_DOMAINS_MAX)
|
||||
return -E2BIG;
|
||||
} else {
|
||||
if (m->n_search_domains >= MANAGER_SEARCH_DOMAINS_MAX)
|
||||
|
@ -47,9 +53,9 @@ int dns_search_domain_new(
|
|||
switch (type) {
|
||||
|
||||
case DNS_SEARCH_DOMAIN_LINK:
|
||||
d->link = l;
|
||||
LIST_APPEND(domains, l->search_domains, d);
|
||||
l->n_search_domains++;
|
||||
d->link = link;
|
||||
LIST_APPEND(domains, link->search_domains, d);
|
||||
link->n_search_domains++;
|
||||
break;
|
||||
|
||||
case DNS_SEARCH_DOMAIN_SYSTEM:
|
||||
|
@ -57,6 +63,12 @@ int dns_search_domain_new(
|
|||
m->n_search_domains++;
|
||||
break;
|
||||
|
||||
case DNS_SEARCH_DOMAIN_DELEGATE:
|
||||
d->delegate = delegate;
|
||||
LIST_APPEND(domains, delegate->search_domains, d);
|
||||
delegate->n_search_domains++;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
@ -99,6 +111,13 @@ void dns_search_domain_unlink(DnsSearchDomain *d) {
|
|||
LIST_REMOVE(domains, d->manager->search_domains, d);
|
||||
d->manager->n_search_domains--;
|
||||
break;
|
||||
|
||||
case DNS_SEARCH_DOMAIN_DELEGATE:
|
||||
assert(d->delegate);
|
||||
assert(d->delegate->n_search_domains > 0);
|
||||
LIST_REMOVE(domains, d->delegate->search_domains, d);
|
||||
d->delegate->n_search_domains--;
|
||||
break;
|
||||
}
|
||||
|
||||
d->linked = false;
|
||||
|
@ -134,6 +153,13 @@ void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d) {
|
|||
LIST_INSERT_AFTER(domains, d->manager->search_domains, tail, d);
|
||||
break;
|
||||
|
||||
case DNS_SEARCH_DOMAIN_DELEGATE:
|
||||
assert(d->delegate);
|
||||
tail = LIST_FIND_TAIL(domains, d);
|
||||
LIST_REMOVE(domains, d->delegate->search_domains, d);
|
||||
LIST_INSERT_AFTER(domains, d->delegate->search_domains, tail, d);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
typedef struct DnsSearchDomain DnsSearchDomain;
|
||||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
typedef struct DnsDelegate DnsDelegate;
|
||||
|
||||
typedef enum DnsSearchDomainType {
|
||||
DNS_SEARCH_DOMAIN_SYSTEM,
|
||||
DNS_SEARCH_DOMAIN_LINK,
|
||||
DNS_SEARCH_DOMAIN_DELEGATE,
|
||||
} DnsSearchDomainType;
|
||||
|
||||
struct DnsSearchDomain {
|
||||
|
@ -20,6 +22,7 @@ struct DnsSearchDomain {
|
|||
|
||||
DnsSearchDomainType type;
|
||||
Link *link;
|
||||
DnsDelegate *delegate;
|
||||
|
||||
char *name;
|
||||
|
||||
|
@ -35,6 +38,7 @@ int dns_search_domain_new(
|
|||
DnsSearchDomain **ret,
|
||||
DnsSearchDomainType type,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
const char *name);
|
||||
|
||||
DnsSearchDomain* dns_search_domain_ref(DnsSearchDomain *d);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "resolved-bus.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-dns-server.h"
|
||||
#include "resolved-dns-stub.h"
|
||||
#include "resolved-manager.h"
|
||||
|
@ -23,7 +24,8 @@ int dns_server_new(
|
|||
Manager *m,
|
||||
DnsServer **ret,
|
||||
DnsServerType type,
|
||||
Link *l,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
int family,
|
||||
const union in_addr_union *in_addr,
|
||||
uint16_t port,
|
||||
|
@ -35,14 +37,18 @@ int dns_server_new(
|
|||
DnsServer *s;
|
||||
|
||||
assert(m);
|
||||
assert((type == DNS_SERVER_LINK) == !!l);
|
||||
assert((type == DNS_SERVER_LINK) == !!link);
|
||||
assert((type == DNS_SERVER_DELEGATE) == !!delegate);
|
||||
assert(in_addr);
|
||||
|
||||
if (!IN_SET(family, AF_INET, AF_INET6))
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
if (l) {
|
||||
if (l->n_dns_servers >= LINK_DNS_SERVERS_MAX)
|
||||
if (link) {
|
||||
if (link->n_dns_servers >= LINK_DNS_SERVERS_MAX)
|
||||
return -E2BIG;
|
||||
} else if (delegate) {
|
||||
if (delegate->n_dns_servers >= DELEGATE_DNS_SERVERS_MAX)
|
||||
return -E2BIG;
|
||||
} else {
|
||||
if (m->n_dns_servers >= MANAGER_DNS_SERVERS_MAX)
|
||||
|
@ -76,9 +82,9 @@ int dns_server_new(
|
|||
switch (type) {
|
||||
|
||||
case DNS_SERVER_LINK:
|
||||
s->link = l;
|
||||
LIST_APPEND(servers, l->dns_servers, s);
|
||||
l->n_dns_servers++;
|
||||
s->link = link;
|
||||
LIST_APPEND(servers, link->dns_servers, s);
|
||||
link->n_dns_servers++;
|
||||
break;
|
||||
|
||||
case DNS_SERVER_SYSTEM:
|
||||
|
@ -91,16 +97,20 @@ int dns_server_new(
|
|||
m->n_dns_servers++;
|
||||
break;
|
||||
|
||||
case DNS_SERVER_DELEGATE:
|
||||
s->delegate = delegate;
|
||||
LIST_APPEND(servers, delegate->dns_servers, s);
|
||||
delegate->n_dns_servers++;
|
||||
break;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
s->linked = true;
|
||||
|
||||
/* A new DNS server that isn't fallback is added and the one
|
||||
* we used so far was a fallback one? Then let's try to pick
|
||||
* the new one */
|
||||
if (type != DNS_SERVER_FALLBACK && dns_server_is_fallback(m->current_dns_server))
|
||||
/* A new non-fallback DNS server is added and the one we used so far was a fallback one? Then
|
||||
* let's try to pick the new one */
|
||||
if (type == DNS_SERVER_SYSTEM && dns_server_is_fallback(m->current_dns_server))
|
||||
manager_set_dns_server(m, NULL);
|
||||
|
||||
if (ret)
|
||||
|
@ -157,6 +167,14 @@ void dns_server_unlink(DnsServer *s) {
|
|||
LIST_REMOVE(servers, s->manager->fallback_dns_servers, s);
|
||||
s->manager->n_dns_servers--;
|
||||
break;
|
||||
|
||||
case DNS_SERVER_DELEGATE:
|
||||
assert(s->delegate);
|
||||
assert(s->delegate->n_dns_servers > 0);
|
||||
LIST_REMOVE(servers, s->delegate->dns_servers, s);
|
||||
s->delegate->n_dns_servers--;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
@ -169,6 +187,9 @@ void dns_server_unlink(DnsServer *s) {
|
|||
if (s->manager->current_dns_server == s)
|
||||
manager_set_dns_server(s->manager, NULL);
|
||||
|
||||
if (s->delegate && s->delegate->current_dns_server == s)
|
||||
dns_delegate_set_dns_server(s->delegate, NULL);
|
||||
|
||||
/* No need to keep a default stream around anymore */
|
||||
dns_server_unref_stream(s);
|
||||
|
||||
|
@ -188,8 +209,8 @@ void dns_server_move_back_and_unmark(DnsServer *s) {
|
|||
if (!s->linked || !s->servers_next)
|
||||
return;
|
||||
|
||||
/* Move us to the end of the list, so that the order is
|
||||
* strictly kept, if we are not at the end anyway. */
|
||||
/* Move us to the end of the list, so that the order is strictly kept, if we are not at the end
|
||||
* anyway. */
|
||||
|
||||
switch (s->type) {
|
||||
|
||||
|
@ -212,6 +233,13 @@ void dns_server_move_back_and_unmark(DnsServer *s) {
|
|||
LIST_INSERT_AFTER(servers, s->manager->fallback_dns_servers, tail, s);
|
||||
break;
|
||||
|
||||
case DNS_SERVER_DELEGATE:
|
||||
assert(s->delegate);
|
||||
tail = LIST_FIND_TAIL(servers, s);
|
||||
LIST_REMOVE(servers, s->delegate->dns_servers, s);
|
||||
LIST_INSERT_AFTER(servers, s->delegate->dns_servers, tail, s);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
@ -879,8 +907,23 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
|
|||
return s;
|
||||
}
|
||||
|
||||
DnsServer *manager_get_dns_server(Manager *m) {
|
||||
static bool manager_search_default_rote_dns_server(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
Link *l;
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
if (l->dns_servers && l->default_route)
|
||||
return true;
|
||||
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates)
|
||||
if (d->dns_servers && d->default_route)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DnsServer *manager_get_dns_server(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
/* Try to read updates resolv.conf */
|
||||
|
@ -899,22 +942,10 @@ DnsServer *manager_get_dns_server(Manager *m) {
|
|||
manager_set_dns_server(m, NULL);
|
||||
}
|
||||
|
||||
if (!m->current_dns_server) {
|
||||
bool found = false;
|
||||
|
||||
/* No DNS servers configured, let's see if there are
|
||||
* any on any links. If not, we use the fallback
|
||||
* servers */
|
||||
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
if (l->dns_servers && l->default_route) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
/* If no DNS servers are configured, let's see if there are any on any links. If not, we use the
|
||||
* fallback servers */
|
||||
if (!m->current_dns_server && !manager_search_default_rote_dns_server(m))
|
||||
manager_set_dns_server(m, m->fallback_dns_servers);
|
||||
}
|
||||
|
||||
return m->current_dns_server;
|
||||
}
|
||||
|
@ -970,11 +1001,15 @@ void dns_server_flush_cache(DnsServer *s) {
|
|||
|
||||
/* Flush the cache of the scope this server belongs to */
|
||||
|
||||
current = s->link ? s->link->current_dns_server : s->manager->current_dns_server;
|
||||
current = s->link ? s->link->current_dns_server :
|
||||
s->delegate ? s->delegate->current_dns_server :
|
||||
s->manager->current_dns_server;
|
||||
if (current != s)
|
||||
return;
|
||||
|
||||
scope = s->link ? s->link->unicast_scope : s->manager->unicast_scope;
|
||||
scope = s->link ? s->link->unicast_scope :
|
||||
s->delegate ? s->delegate->scope :
|
||||
s->manager->unicast_scope;
|
||||
if (!scope)
|
||||
return;
|
||||
|
||||
|
@ -1079,10 +1114,14 @@ void dns_server_unref_stream(DnsServer *s) {
|
|||
|
||||
DnsScope *dns_server_scope(DnsServer *s) {
|
||||
assert(s);
|
||||
assert(s->linked);
|
||||
assert((s->type == DNS_SERVER_LINK) == !!s->link);
|
||||
assert((s->type == DNS_SERVER_DELEGATE) == !!s->delegate);
|
||||
|
||||
if (s->link)
|
||||
return s->link->unicast_scope;
|
||||
if (s->delegate)
|
||||
return s->delegate->scope;
|
||||
|
||||
return s->manager->unicast_scope;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "time-util.h"
|
||||
|
||||
typedef struct DnsScope DnsScope;
|
||||
typedef struct DnsDelegate DnsDelegate;
|
||||
typedef struct DnsServer DnsServer;
|
||||
typedef struct DnsStream DnsStream;
|
||||
typedef struct DnsPacket DnsPacket;
|
||||
|
@ -21,6 +22,7 @@ typedef enum DnsServerType {
|
|||
DNS_SERVER_SYSTEM,
|
||||
DNS_SERVER_FALLBACK,
|
||||
DNS_SERVER_LINK,
|
||||
DNS_SERVER_DELEGATE,
|
||||
_DNS_SERVER_TYPE_MAX,
|
||||
_DNS_SERVER_TYPE_INVALID = -EINVAL,
|
||||
} DnsServerType;
|
||||
|
@ -58,6 +60,7 @@ struct DnsServer {
|
|||
|
||||
DnsServerType type;
|
||||
Link *link;
|
||||
DnsDelegate *delegate;
|
||||
|
||||
int family;
|
||||
union in_addr_union address;
|
||||
|
@ -113,6 +116,7 @@ int dns_server_new(
|
|||
DnsServer **ret,
|
||||
DnsServerType type,
|
||||
Link *link,
|
||||
DnsDelegate *delegate,
|
||||
int family,
|
||||
const union in_addr_union *address,
|
||||
uint16_t port,
|
||||
|
|
|
@ -274,7 +274,7 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
|
|||
if (s)
|
||||
dns_server_move_back_and_unmark(s);
|
||||
else {
|
||||
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name, RESOLVE_CONFIG_SOURCE_DBUS);
|
||||
r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, /* delegate= */ NULL, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name, RESOLVE_CONFIG_SOURCE_DBUS);
|
||||
if (r < 0) {
|
||||
dns_server_unlink_all(l->dns_servers);
|
||||
goto finalize;
|
||||
|
@ -282,7 +282,6 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
|
|||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
changed = dns_server_unlink_marked(l->dns_servers) || changed;
|
||||
|
@ -402,7 +401,7 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_
|
|||
if (r > 0)
|
||||
dns_search_domain_move_back_and_unmark(d);
|
||||
else {
|
||||
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
|
||||
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, /* delegate= */ NULL, name);
|
||||
if (r < 0)
|
||||
goto clear;
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ void link_allocate_scopes(Link *l) {
|
|||
if (!l->unicast_scope) {
|
||||
dns_server_reset_features_all(l->dns_servers);
|
||||
|
||||
r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
r = dns_scope_new(l->manager, &l->unicast_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate DNS scope, ignoring: %m");
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ void link_allocate_scopes(Link *l) {
|
|||
if (link_relevant(l, AF_INET, true) &&
|
||||
link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) {
|
||||
if (!l->llmnr_ipv4_scope) {
|
||||
r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
|
||||
r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_LLMNR, AF_INET);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate LLMNR IPv4 scope, ignoring: %m");
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ void link_allocate_scopes(Link *l) {
|
|||
if (link_relevant(l, AF_INET6, true) &&
|
||||
link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) {
|
||||
if (!l->llmnr_ipv6_scope) {
|
||||
r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
|
||||
r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_LLMNR, AF_INET6);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate LLMNR IPv6 scope, ignoring: %m");
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ void link_allocate_scopes(Link *l) {
|
|||
if (link_relevant(l, AF_INET, true) &&
|
||||
link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) {
|
||||
if (!l->mdns_ipv4_scope) {
|
||||
r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
|
||||
r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_MDNS, AF_INET);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate mDNS IPv4 scope, ignoring: %m");
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ void link_allocate_scopes(Link *l) {
|
|||
if (link_relevant(l, AF_INET6, true) &&
|
||||
link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) {
|
||||
if (!l->mdns_ipv6_scope) {
|
||||
r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
|
||||
r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, DNS_SCOPE_LINK, l, /* delegate= */ NULL, DNS_PROTOCOL_MDNS, AF_INET6);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate mDNS IPv6 scope, ignoring: %m");
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ static int link_update_dns_server_one(Link *l, const char *str) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name, RESOLVE_CONFIG_SOURCE_NETWORKD);
|
||||
return dns_server_new(l->manager, /* ret= */ NULL, DNS_SERVER_LINK, l, /* delegate= */ NULL, family, &a, port, 0, name, RESOLVE_CONFIG_SOURCE_NETWORKD);
|
||||
}
|
||||
|
||||
static int link_update_dns_servers(Link *l) {
|
||||
|
@ -493,7 +493,7 @@ static int link_update_search_domain_one(Link *l, const char *name, bool route_o
|
|||
if (r > 0)
|
||||
dns_search_domain_move_back_and_unmark(d);
|
||||
else {
|
||||
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
|
||||
r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, /* delegate= */ NULL, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "random-util.h"
|
||||
#include "resolved-bus.h"
|
||||
#include "resolved-conf.h"
|
||||
#include "resolved-dns-delegate.h"
|
||||
#include "resolved-dns-stub.h"
|
||||
#include "resolved-dnssd.h"
|
||||
#include "resolved-etc-hosts.h"
|
||||
|
@ -519,6 +520,10 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si
|
|||
HASHMAP_FOREACH(l, m->links)
|
||||
LIST_FOREACH(servers, server, l->dns_servers)
|
||||
dns_server_dump(server, f);
|
||||
DnsDelegate *delegate;
|
||||
HASHMAP_FOREACH(delegate, m->delegates)
|
||||
LIST_FOREACH(servers, server, delegate->dns_servers)
|
||||
dns_server_dump(server, f);
|
||||
|
||||
return memstream_dump(LOG_INFO, &ms);
|
||||
}
|
||||
|
@ -596,6 +601,7 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
|
|||
m->dns_extra_stub_listeners = ordered_set_free(m->dns_extra_stub_listeners);
|
||||
dnssd_service_clear_on_reload(m->dnssd_services);
|
||||
m->unicast_scope = dns_scope_free(m->unicast_scope);
|
||||
m->delegates = hashmap_free(m->delegates);
|
||||
|
||||
dns_trust_anchor_flush(&m->trust_anchor);
|
||||
|
||||
|
@ -613,9 +619,11 @@ static int manager_dispatch_reload_signal(sd_event_source *s, const struct signa
|
|||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to load DNS-SD configuration files: %m");
|
||||
|
||||
manager_load_delegates(m);
|
||||
|
||||
/* The default scope configuration is influenced by the manager's configuration (modes, etc.), so
|
||||
* recreate it on reload. */
|
||||
r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -696,7 +704,9 @@ int manager_new(Manager **ret) {
|
|||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to load DNS-SD configuration files: %m");
|
||||
|
||||
r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
manager_load_delegates(m);
|
||||
|
||||
r = dns_scope_new(m, &m->unicast_scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -765,7 +775,6 @@ int manager_start(Manager *m) {
|
|||
|
||||
Manager *manager_free(Manager *m) {
|
||||
Link *l;
|
||||
DnssdService *s;
|
||||
|
||||
if (!m)
|
||||
return NULL;
|
||||
|
@ -777,12 +786,13 @@ Manager *manager_free(Manager *m) {
|
|||
while ((l = hashmap_first(m->links)))
|
||||
link_free(l);
|
||||
|
||||
m->delegates = hashmap_free(m->delegates);
|
||||
|
||||
while (m->dns_queries)
|
||||
dns_query_free(m->dns_queries);
|
||||
|
||||
m->stub_queries_by_packet = hashmap_free(m->stub_queries_by_packet);
|
||||
|
||||
dns_scope_free(m->unicast_scope);
|
||||
m->unicast_scope = dns_scope_free(m->unicast_scope);
|
||||
|
||||
/* At this point only orphaned streams should remain. All others should have been freed already by their
|
||||
* owners */
|
||||
|
@ -830,6 +840,7 @@ Manager *manager_free(Manager *m) {
|
|||
free(m->llmnr_hostname);
|
||||
free(m->mdns_hostname);
|
||||
|
||||
DnssdService *s;
|
||||
while ((s = hashmap_first(m->dnssd_services)))
|
||||
dnssd_service_free(s);
|
||||
hashmap_free(m->dnssd_services);
|
||||
|
@ -1557,7 +1568,7 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
|
|||
}
|
||||
|
||||
/* Then, add the per-link servers */
|
||||
HASHMAP_FOREACH(l, m->links) {
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
LIST_FOREACH(servers, s, l->dns_servers) {
|
||||
r = ordered_set_put(*dns, s);
|
||||
if (r == -EEXIST)
|
||||
|
@ -1565,6 +1576,16 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Third, add the delegate servers and domains */
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates)
|
||||
LIST_FOREACH(servers, s, d->dns_servers) {
|
||||
r = ordered_set_put(*dns, s);
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* If we found nothing, add the fallback servers */
|
||||
|
@ -1587,7 +1608,6 @@ int manager_compile_dns_servers(Manager *m, OrderedSet **dns) {
|
|||
* > 0 or true: return only domains which are for routing only
|
||||
*/
|
||||
int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_route) {
|
||||
Link *l;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
@ -1610,9 +1630,9 @@ int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_
|
|||
return r;
|
||||
}
|
||||
|
||||
HASHMAP_FOREACH(l, m->links) {
|
||||
|
||||
LIST_FOREACH(domains, d, l->search_domains) {
|
||||
DnsDelegate *delegate;
|
||||
HASHMAP_FOREACH(delegate, m->delegates)
|
||||
LIST_FOREACH(domains, d, delegate->search_domains) {
|
||||
|
||||
if (filter_route >= 0 &&
|
||||
d->route_only != !!filter_route)
|
||||
|
@ -1624,6 +1644,20 @@ int manager_compile_search_domains(Manager *m, OrderedSet **domains, int filter_
|
|||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
Link *l;
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
LIST_FOREACH(domains, d, l->search_domains) {
|
||||
|
||||
if (filter_route >= 0 &&
|
||||
d->route_only != !!filter_route)
|
||||
continue;
|
||||
|
||||
r = ordered_set_put(*domains, d->name);
|
||||
if (r == -EEXIST)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1707,14 +1741,18 @@ void manager_flush_caches(Manager *m, int log_level) {
|
|||
}
|
||||
|
||||
void manager_reset_server_features(Manager *m) {
|
||||
Link *l;
|
||||
|
||||
dns_server_reset_features_all(m->dns_servers);
|
||||
dns_server_reset_features_all(m->fallback_dns_servers);
|
||||
|
||||
Link *l;
|
||||
HASHMAP_FOREACH(l, m->links)
|
||||
dns_server_reset_features_all(l->dns_servers);
|
||||
|
||||
DnsDelegate *d;
|
||||
HASHMAP_FOREACH(d, m->delegates)
|
||||
dns_server_reset_features_all(d->dns_servers);
|
||||
|
||||
log_info("Resetting learnt feature levels on all servers.");
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,8 @@ struct Manager {
|
|||
LIST_HEAD(DnsScope, dns_scopes);
|
||||
DnsScope *unicast_scope;
|
||||
|
||||
Hashmap *delegates; /* id string → DnsDelegate objects */
|
||||
|
||||
/* LLMNR */
|
||||
int llmnr_ipv4_udp_fd;
|
||||
int llmnr_ipv6_udp_fd;
|
||||
|
|
|
@ -781,7 +781,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) {
|
|||
}
|
||||
|
||||
if (cfg->has_scope) {
|
||||
ASSERT_OK(dns_scope_new(&env->manager, &env->scope, env->link, env->protocol, env->family));
|
||||
ASSERT_OK(dns_scope_new(&env->manager, &env->scope, env->link ? DNS_SCOPE_LINK : DNS_SCOPE_GLOBAL, env->link, /* delegate= */ NULL, env->protocol, env->family));
|
||||
ASSERT_NOT_NULL(env->scope);
|
||||
|
||||
env->server_addr.in.s_addr = htobe32(0x7f000001);
|
||||
|
@ -789,7 +789,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) {
|
|||
env->server_port = 53;
|
||||
|
||||
ASSERT_OK(dns_server_new(&env->manager, &env->server, env->server_type,
|
||||
env->link, env->family, &env->server_addr, env->server_port,
|
||||
env->link, /* delegate= */ NULL, env->family, &env->server_addr, env->server_port,
|
||||
env->ifindex, env->server_name, RESOLVE_CONFIG_SOURCE_DBUS));
|
||||
|
||||
ASSERT_NOT_NULL(env->server);
|
||||
|
@ -803,7 +803,7 @@ static void go_env_setup(GoEnvironment *env, GoConfig *cfg) {
|
|||
|
||||
for (size_t i = 0 ; i < env->n_search_domains; i++) {
|
||||
DnsSearchDomainType type = (env->link == NULL) ? DNS_SEARCH_DOMAIN_SYSTEM : DNS_SEARCH_DOMAIN_LINK;
|
||||
ASSERT_OK(dns_search_domain_new(&env->manager, &env->search_domains[i], type, env->link, SEARCH_DOMAINS[i]));
|
||||
ASSERT_OK(dns_search_domain_new(&env->manager, &env->search_domains[i], type, env->link, /* delegate= */ NULL, SEARCH_DOMAINS[i]));
|
||||
ASSERT_NOT_NULL(env->search_domains[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ TEST(dns_search_domain_new_system) {
|
|||
Manager manager = {};
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd = NULL;
|
||||
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"));
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"));
|
||||
ASSERT_NOT_NULL(sd);
|
||||
|
||||
ASSERT_TRUE(sd->linked);
|
||||
|
@ -41,12 +41,12 @@ TEST(dns_search_domain_new_system_limit) {
|
|||
DnsSearchDomain *sd = NULL;
|
||||
|
||||
for (size_t i = 0; i < MANAGER_SEARCH_DOMAINS_MAX; i++) {
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"));
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"));
|
||||
ASSERT_NOT_NULL(sd);
|
||||
ASSERT_EQ(manager.n_search_domains, i + 1);
|
||||
}
|
||||
|
||||
ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local"), E2BIG);
|
||||
ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local"), E2BIG);
|
||||
ASSERT_NOT_NULL(sd);
|
||||
|
||||
dns_search_domain_unlink_all(manager.search_domains);
|
||||
|
@ -60,7 +60,7 @@ TEST(dns_search_domain_new_link) {
|
|||
ASSERT_OK(link_new(&manager, &link, 1));
|
||||
ASSERT_NOT_NULL(link);
|
||||
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local."));
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local."));
|
||||
ASSERT_NOT_NULL(sd);
|
||||
|
||||
ASSERT_TRUE(sd->linked);
|
||||
|
@ -76,12 +76,12 @@ TEST(dns_search_domain_new_link_limit) {
|
|||
ASSERT_NOT_NULL(link);
|
||||
|
||||
for (size_t i = 0; i < LINK_SEARCH_DOMAINS_MAX; i++) {
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local"));
|
||||
ASSERT_OK(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local"));
|
||||
ASSERT_NOT_NULL(sd);
|
||||
ASSERT_EQ(link->n_search_domains, i + 1);
|
||||
}
|
||||
|
||||
ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, "local"), E2BIG);
|
||||
ASSERT_ERROR(dns_search_domain_new(&manager, &sd, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local"), E2BIG);
|
||||
ASSERT_NOT_NULL(sd);
|
||||
}
|
||||
|
||||
|
@ -94,13 +94,13 @@ TEST(dns_search_domain_unlink_system) {
|
|||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd3 = NULL;
|
||||
DnsSearchDomain *sd2 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
ASSERT_TRUE(sd2->linked);
|
||||
|
@ -123,13 +123,13 @@ TEST(dns_search_domain_unlink_link) {
|
|||
ASSERT_OK(link_new(&manager, &link, 1));
|
||||
ASSERT_NOT_NULL(link);
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_LINK, link, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_LINK, link, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_LINK, link, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_LINK, link, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
ASSERT_TRUE(sd2->linked);
|
||||
|
@ -151,13 +151,13 @@ TEST(dns_search_domain_mark_all) {
|
|||
Manager manager = {};
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
ASSERT_FALSE(sd1->marked);
|
||||
|
@ -179,13 +179,13 @@ TEST(dns_search_domain_move_back_and_unmark) {
|
|||
Manager manager = {};
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
dns_search_domain_move_back_and_unmark(sd1);
|
||||
|
@ -211,13 +211,13 @@ TEST(dns_search_domain_unlink_marked) {
|
|||
DnsSearchDomain *sd1 = NULL, *sd2 = NULL;
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd3 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
dns_search_domain_unlink_marked(sd1);
|
||||
|
@ -245,13 +245,13 @@ TEST(dns_search_domain_unlink_all) {
|
|||
Manager manager = {};
|
||||
DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
dns_search_domain_unlink_all(sd1);
|
||||
|
@ -267,13 +267,13 @@ TEST(dns_search_domain_find) {
|
|||
Manager manager = {};
|
||||
_cleanup_(dns_search_domain_unrefp) DnsSearchDomain *sd1 = NULL, *sd2 = NULL, *sd3 = NULL, *ret = NULL;
|
||||
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "local");
|
||||
dns_search_domain_new(&manager, &sd1, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "local");
|
||||
ASSERT_NOT_NULL(sd1);
|
||||
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "vpn.example.com");
|
||||
dns_search_domain_new(&manager, &sd2, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "vpn.example.com");
|
||||
ASSERT_NOT_NULL(sd2);
|
||||
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, NULL, "org");
|
||||
dns_search_domain_new(&manager, &sd3, DNS_SEARCH_DOMAIN_SYSTEM, /* link= */ NULL, /* delegate= */ NULL, "org");
|
||||
ASSERT_NOT_NULL(sd3);
|
||||
|
||||
ASSERT_TRUE(dns_search_domain_find(sd1, "local", &ret));
|
||||
|
|
|
@ -26,7 +26,7 @@ TEST(dns_zone_put_simple) {
|
|||
DnsZoneItem *item = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
|
||||
ASSERT_OK(dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET));
|
||||
ASSERT_OK(dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET));
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
|
@ -50,7 +50,7 @@ TEST(dns_zone_put_any_class_is_invalid) {
|
|||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
|
@ -68,7 +68,7 @@ TEST(dns_zone_put_any_type_is_invalid) {
|
|||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
|
@ -90,7 +90,7 @@ TEST(dns_zone_remove_rr_match) {
|
|||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
|
@ -115,7 +115,7 @@ TEST(dns_zone_remove_rr_match_one) {
|
|||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
|
@ -148,7 +148,7 @@ TEST(dns_zone_remove_rr_different_payload) {
|
|||
DnsZone *zone = NULL;
|
||||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr_in = NULL, *rr_out = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
|
@ -178,7 +178,7 @@ TEST(dns_zone_remove_rrs_by_key) {
|
|||
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr1 = NULL, *rr2 = NULL, *rr3 = NULL;
|
||||
DnsResourceKey *key = NULL;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
zone = &scope->zone;
|
||||
|
||||
|
@ -248,7 +248,7 @@ TEST(dns_zone_lookup_match_a) {
|
|||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
|
@ -270,7 +270,7 @@ TEST(dns_zone_lookup_match_cname) {
|
|||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
|
@ -293,7 +293,7 @@ TEST(dns_zone_lookup_match_any) {
|
|||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
|
@ -324,7 +324,7 @@ TEST(dns_zone_lookup_match_any_apex) {
|
|||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
|
@ -349,7 +349,7 @@ TEST(dns_zone_lookup_match_nothing) {
|
|||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
|
@ -370,7 +370,7 @@ TEST(dns_zone_lookup_match_nothing_with_soa) {
|
|||
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL;
|
||||
bool tentative;
|
||||
|
||||
dns_scope_new(&manager, &scope, NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
dns_scope_new(&manager, &scope, DNS_SCOPE_GLOBAL, /* link= */ NULL, /* delegate= */ NULL, DNS_PROTOCOL_DNS, AF_INET);
|
||||
ASSERT_NOT_NULL(scope);
|
||||
add_zone_rrs(scope);
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ static void link_alloc_env_setup(LinkAllocEnv *env, int family, DnsServerType se
|
|||
link = env->link;
|
||||
|
||||
ASSERT_OK(dns_server_new(&env->manager, &env->server, env->server_type,
|
||||
link, family, &env->server_addr, env->server_port,
|
||||
link, /* delegate= */ NULL, family, &env->server_addr, env->server_port,
|
||||
env->ifindex, env->server_name, RESOLVE_CONFIG_SOURCE_DBUS));
|
||||
|
||||
ASSERT_NOT_NULL(env->server);
|
||||
|
|
|
@ -66,9 +66,5 @@ static inline bool efi_has_tpm2(void) {
|
|||
|
||||
#endif
|
||||
|
||||
static inline char *efi_tilt_backslashes(char *s) {
|
||||
return string_replace_char(s, '\\', '/');
|
||||
}
|
||||
|
||||
sd_id128_t efi_guid_to_id128(const void *guid);
|
||||
void efi_id128_to_guid(sd_id128_t id, void *ret_guid);
|
||||
|
|
|
@ -61,30 +61,19 @@ int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
unsigned parsed[16];
|
||||
|
||||
static int get_device_part_uuid(const char *variable, sd_id128_t *ret) {
|
||||
if (!is_efi_boot())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = efi_get_variable_string(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return efi_get_variable_id128(variable, ret);
|
||||
}
|
||||
|
||||
if (sscanf(p, SD_ID128_UUID_FORMAT_STR,
|
||||
&parsed[0], &parsed[1], &parsed[2], &parsed[3],
|
||||
&parsed[4], &parsed[5], &parsed[6], &parsed[7],
|
||||
&parsed[8], &parsed[9], &parsed[10], &parsed[11],
|
||||
&parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
|
||||
return -EIO;
|
||||
int efi_loader_get_device_part_uuid(sd_id128_t *ret) {
|
||||
return get_device_part_uuid(EFI_LOADER_VARIABLE(LoaderDevicePartUUID), ret);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
for (unsigned i = 0; i < ELEMENTSOF(parsed); i++)
|
||||
ret->bytes[i] = parsed[i];
|
||||
|
||||
return 0;
|
||||
int efi_stub_get_device_part_uuid(sd_id128_t *ret) {
|
||||
return get_device_part_uuid(EFI_LOADER_VARIABLE(StubDevicePartUUID), ret);
|
||||
}
|
||||
|
||||
int efi_loader_get_entries(char ***ret) {
|
||||
|
@ -353,6 +342,22 @@ int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat
|
|||
return 0;
|
||||
}
|
||||
|
||||
int efi_get_variable_id128(const char *variable, sd_id128_t *ret) {
|
||||
int r;
|
||||
|
||||
assert(variable);
|
||||
|
||||
/* This is placed here (rather than in basic/efivars.c) because code in basic/ is not allowed to link
|
||||
* against libsystemd.so */
|
||||
|
||||
_cleanup_free_ char *p = NULL;
|
||||
r = efi_get_variable_string(variable, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_id128_from_string(p, ret);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool efi_loader_entry_name_valid(const char *s) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#if ENABLE_EFI
|
||||
|
||||
int efi_loader_get_device_part_uuid(sd_id128_t *ret);
|
||||
int efi_stub_get_device_part_uuid(sd_id128_t *ret);
|
||||
int efi_loader_get_boot_usec(usec_t *ret_firmware, usec_t *ret_loader);
|
||||
|
||||
int efi_loader_get_entries(char ***ret);
|
||||
|
@ -23,6 +24,8 @@ int efi_measured_uki(int log_level);
|
|||
int efi_loader_get_config_timeout_one_shot(usec_t *ret);
|
||||
int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat);
|
||||
|
||||
int efi_get_variable_id128(const char *variable, sd_id128_t *ret);
|
||||
|
||||
#else
|
||||
|
||||
static inline int efi_loader_get_device_part_uuid(sd_id128_t *u) {
|
||||
|
@ -58,6 +61,10 @@ static inline int efi_loader_update_entry_one_shot_cache(char **cache, struct st
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int efi_get_variable_id128(const char *variable, sd_id128_t *ret) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool efi_loader_entry_name_valid(const char *s);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
static const char * const kernel_image_type_table[_KERNEL_IMAGE_TYPE_MAX] = {
|
||||
[KERNEL_IMAGE_TYPE_UNKNOWN] = "unknown",
|
||||
[KERNEL_IMAGE_TYPE_UKI] = "uki",
|
||||
[KERNEL_IMAGE_TYPE_ADDON] = "addon",
|
||||
[KERNEL_IMAGE_TYPE_PE] = "pe",
|
||||
};
|
||||
|
||||
|
@ -159,6 +160,16 @@ int inspect_kernel(
|
|||
|
||||
t = KERNEL_IMAGE_TYPE_UKI;
|
||||
goto done;
|
||||
} else if (pe_is_addon(pe_header, sections)) {
|
||||
r = inspect_uki(fd, pe_header, sections, ret_cmdline, ret_uname, /* ret_pretty_name= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_pretty_name)
|
||||
*ret_pretty_name = NULL;
|
||||
|
||||
t = KERNEL_IMAGE_TYPE_ADDON;
|
||||
goto done;
|
||||
} else
|
||||
t = KERNEL_IMAGE_TYPE_PE;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
typedef enum KernelImageType {
|
||||
KERNEL_IMAGE_TYPE_UNKNOWN,
|
||||
KERNEL_IMAGE_TYPE_UKI,
|
||||
KERNEL_IMAGE_TYPE_ADDON,
|
||||
KERNEL_IMAGE_TYPE_PE,
|
||||
_KERNEL_IMAGE_TYPE_MAX,
|
||||
_KERNEL_IMAGE_TYPE_INVALID = -EINVAL,
|
||||
|
|
|
@ -170,6 +170,8 @@ typedef struct Item {
|
|||
|
||||
bool try_replace:1;
|
||||
|
||||
bool purge:1;
|
||||
|
||||
OperationMask done;
|
||||
} Item;
|
||||
|
||||
|
@ -3046,6 +3048,9 @@ static int purge_item(Context *c, Item *i) {
|
|||
if (!needs_purge(i->type))
|
||||
return 0;
|
||||
|
||||
if (!i->purge)
|
||||
return 0;
|
||||
|
||||
log_debug("Running purge action for entry %c %s", (char) i->type, i->path);
|
||||
|
||||
if (needs_glob(i->type))
|
||||
|
@ -3602,7 +3607,7 @@ static int parse_line(
|
|||
ItemArray *existing;
|
||||
OrderedHashmap *h;
|
||||
bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
|
||||
unbase64 = false, from_cred = false, missing_user_or_group = false;
|
||||
unbase64 = false, from_cred = false, missing_user_or_group = false, purge = false;
|
||||
int r;
|
||||
|
||||
assert(fname);
|
||||
|
@ -3668,6 +3673,8 @@ static int parse_line(
|
|||
unbase64 = true;
|
||||
else if (action[pos] == '^' && !from_cred)
|
||||
from_cred = true;
|
||||
else if (action[pos] == '$' && !purge)
|
||||
purge = true;
|
||||
else {
|
||||
*invalid_config = true;
|
||||
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
|
||||
|
@ -3684,6 +3691,7 @@ static int parse_line(
|
|||
i.append_or_force = append_or_force;
|
||||
i.allow_failure = allow_failure;
|
||||
i.try_replace = try_replace;
|
||||
i.purge = purge;
|
||||
|
||||
r = specifier_printf(path, PATH_MAX-1, specifier_table, arg_root, NULL, &i.path);
|
||||
if (ERRNO_IS_NOINFO(r))
|
||||
|
@ -3838,6 +3846,12 @@ static int parse_line(
|
|||
"Unknown command type '%c'.", (char) i.type);
|
||||
}
|
||||
|
||||
if (i.purge && !needs_purge(i.type)) {
|
||||
*invalid_config = true;
|
||||
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Purge flag '$' combined with line type '%c' which does not support purging.", (char) i.type);
|
||||
}
|
||||
|
||||
if (!should_include_path(i.path))
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||
int r;
|
||||
char *value = UINT_TO_PTR(0x12345678U);
|
||||
char *endpos = UINT_TO_PTR(0x87654321U);
|
||||
bool is_case_sensitive;
|
||||
|
||||
fuzz_setup_logging();
|
||||
|
||||
|
@ -18,7 +19,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||
memcpy(str, data, size);
|
||||
str[size] = '\0';
|
||||
|
||||
r = udev_rule_parse_value(str, &value, &endpos);
|
||||
r = udev_rule_parse_value(str, &value, &endpos, &is_case_sensitive);
|
||||
if (r < 0) {
|
||||
/* not modified on failure */
|
||||
assert_se(value == UINT_TO_PTR(0x12345678U));
|
||||
|
|
|
@ -4,15 +4,16 @@
|
|||
#include "tests.h"
|
||||
#include "udev-rules.h"
|
||||
|
||||
static void test_udev_rule_parse_value_one(const char *in, const char *expected_value, int expected_retval) {
|
||||
static void test_udev_rule_parse_value_one(const char *in, const char *expected_value, bool expected_case_insensitive, int expected_retval) {
|
||||
_cleanup_free_ char *str = NULL;
|
||||
char *value = UINT_TO_PTR(0x12345678U);
|
||||
char *endpos = UINT_TO_PTR(0x87654321U);
|
||||
bool i;
|
||||
|
||||
log_info("/* %s (%s, %s, %d) */", __func__, in, strnull(expected_value), expected_retval);
|
||||
|
||||
assert_se(str = strdup(in));
|
||||
assert_se(udev_rule_parse_value(str, &value, &endpos) == expected_retval);
|
||||
assert_se(udev_rule_parse_value(str, &value, &endpos, &i) == expected_retval);
|
||||
if (expected_retval < 0) {
|
||||
/* not modified on failure */
|
||||
assert_se(value == UINT_TO_PTR(0x12345678U));
|
||||
|
@ -25,6 +26,7 @@ static void test_udev_rule_parse_value_one(const char *in, const char *expected_
|
|||
* so it could be safely interpreted as nulstr.
|
||||
*/
|
||||
assert_se(value[strlen(value) + 1] == '\0');
|
||||
assert_se(i == expected_case_insensitive);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,45 +35,61 @@ TEST(udev_rule_parse_value) {
|
|||
* parsed: valid operand
|
||||
* use the following command to help generate textual C strings:
|
||||
* python3 -c 'import json; print(json.dumps(input()))' */
|
||||
test_udev_rule_parse_value_one("\"valid operand\"", "valid operand", 0);
|
||||
test_udev_rule_parse_value_one("\"valid operand\"", "valid operand", /* case_insensitive = */ false, 0);
|
||||
/* input: "va'l\'id\"op\"erand"
|
||||
* parsed: va'l\'id"op"erand */
|
||||
test_udev_rule_parse_value_one("\"va'l\\'id\\\"op\\\"erand\"", "va'l\\'id\"op\"erand", 0);
|
||||
test_udev_rule_parse_value_one("no quotes", NULL, -EINVAL);
|
||||
test_udev_rule_parse_value_one("\"\\\\a\\b\\x\\y\"", "\\\\a\\b\\x\\y", 0);
|
||||
test_udev_rule_parse_value_one("\"reject\0nul\"", NULL, -EINVAL);
|
||||
test_udev_rule_parse_value_one("\"va'l\\'id\\\"op\\\"erand\"", "va'l\\'id\"op\"erand", /* case_insensitive = */ false, 0);
|
||||
test_udev_rule_parse_value_one("no quotes", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
test_udev_rule_parse_value_one("\"\\\\a\\b\\x\\y\"", "\\\\a\\b\\x\\y", /* case_insensitive = */ false, 0);
|
||||
test_udev_rule_parse_value_one("\"reject\0nul\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: e"" */
|
||||
test_udev_rule_parse_value_one("e\"\"", "", 0);
|
||||
test_udev_rule_parse_value_one("e\"\"", "", /* case_insensitive = */ false, 0);
|
||||
/* input: e"1234" */
|
||||
test_udev_rule_parse_value_one("e\"1234\"", "1234", 0);
|
||||
test_udev_rule_parse_value_one("e\"1234\"", "1234", /* case_insensitive = */ false, 0);
|
||||
/* input: e"\"" */
|
||||
test_udev_rule_parse_value_one("e\"\\\"\"", "\"", 0);
|
||||
test_udev_rule_parse_value_one("e\"\\\"\"", "\"", /* case_insensitive = */ false, 0);
|
||||
/* input: e"\ */
|
||||
test_udev_rule_parse_value_one("e\"\\", NULL, -EINVAL);
|
||||
test_udev_rule_parse_value_one("e\"\\", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: e"\" */
|
||||
test_udev_rule_parse_value_one("e\"\\\"", NULL, -EINVAL);
|
||||
test_udev_rule_parse_value_one("e\"\\\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: e"\\" */
|
||||
test_udev_rule_parse_value_one("e\"\\\\\"", "\\", 0);
|
||||
test_udev_rule_parse_value_one("e\"\\\\\"", "\\", /* case_insensitive = */ false, 0);
|
||||
/* input: e"\\\" */
|
||||
test_udev_rule_parse_value_one("e\"\\\\\\\"", NULL, -EINVAL);
|
||||
test_udev_rule_parse_value_one("e\"\\\\\\\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: e"\\\"" */
|
||||
test_udev_rule_parse_value_one("e\"\\\\\\\"\"", "\\\"", 0);
|
||||
test_udev_rule_parse_value_one("e\"\\\\\\\"\"", "\\\"", /* case_insensitive = */ false, 0);
|
||||
/* input: e"\\\\" */
|
||||
test_udev_rule_parse_value_one("e\"\\\\\\\\\"", "\\\\", 0);
|
||||
test_udev_rule_parse_value_one("e\"\\\\\\\\\"", "\\\\", /* case_insensitive = */ false, 0);
|
||||
/* input: e"operand with newline\n" */
|
||||
test_udev_rule_parse_value_one("e\"operand with newline\\n\"", "operand with newline\n", 0);
|
||||
test_udev_rule_parse_value_one("e\"operand with newline\\n\"", "operand with newline\n", /* case_insensitive = */ false, 0);
|
||||
/* input: e"single\rcharacter\t\aescape\bsequence" */
|
||||
test_udev_rule_parse_value_one(
|
||||
"e\"single\\rcharacter\\t\\aescape\\bsequence\"", "single\rcharacter\t\aescape\bsequence", 0);
|
||||
"e\"single\\rcharacter\\t\\aescape\\bsequence\"", "single\rcharacter\t\aescape\bsequence", /* case_insensitive = */ false, 0);
|
||||
/* input: e"reject\invalid escape sequence" */
|
||||
test_udev_rule_parse_value_one("e\"reject\\invalid escape sequence", NULL, -EINVAL);
|
||||
test_udev_rule_parse_value_one("e\"reject\\invalid escape sequence", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: e"\ */
|
||||
test_udev_rule_parse_value_one("e\"\\", NULL, -EINVAL);
|
||||
test_udev_rule_parse_value_one("e\"\\", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: "s\u1d1c\u1d04\u029c \u1d1c\u0274\u026a\u1d04\u1d0f\u1d05\u1d07 \U0001d568\U0001d560\U0001d568" */
|
||||
test_udev_rule_parse_value_one(
|
||||
"e\"s\\u1d1c\\u1d04\\u029c \\u1d1c\\u0274\\u026a\\u1d04\\u1d0f\\u1d05\\u1d07 \\U0001d568\\U0001d560\\U0001d568\"",
|
||||
"s\xe1\xb4\x9c\xe1\xb4\x84\xca\x9c \xe1\xb4\x9c\xc9\xb4\xc9\xaa\xe1\xb4\x84\xe1\xb4\x8f\xe1\xb4\x85\xe1\xb4\x87 \xf0\x9d\x95\xa8\xf0\x9d\x95\xa0\xf0\x9d\x95\xa8",
|
||||
0);
|
||||
/* case_insensitive = */ false, 0);
|
||||
/* input: i"ABCD1234" */
|
||||
test_udev_rule_parse_value_one("i\"ABCD1234\"", "ABCD1234", /* case_insensitive = */ true, 0);
|
||||
/* input: i"ABCD1234" */
|
||||
test_udev_rule_parse_value_one("e\"ABCD1234\"", "ABCD1234", /* case_insensitive = */ false, 0);
|
||||
/* input: ei"\\"ABCD1234 */
|
||||
test_udev_rule_parse_value_one("ei\"\\\\ABCD1234\"", "\\ABCD1234", /* case_insensitive = */ true, 0);
|
||||
/* input: ie"\\"ABCD1234 */
|
||||
test_udev_rule_parse_value_one("ie\"\\\\ABCD1234\"", "\\ABCD1234", /* case_insensitive = */ true, 0);
|
||||
/* input: i */
|
||||
test_udev_rule_parse_value_one("i", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: ee"" */
|
||||
test_udev_rule_parse_value_one("ee\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: iei"" */
|
||||
test_udev_rule_parse_value_one("iei\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
/* input: a"" */
|
||||
test_udev_rule_parse_value_one("a\"\"", NULL, /* case_insensitive = */ false, -EINVAL);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
|
|
@ -63,9 +63,15 @@ typedef enum {
|
|||
MATCH_TYPE_GLOB_WITH_EMPTY, /* shell globs ?,*,[] with empty string, e.g., "|foo*" */
|
||||
MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */
|
||||
_MATCH_TYPE_MAX,
|
||||
|
||||
_MATCH_TYPE_MASK = (1 << 5) - 1,
|
||||
MATCH_REMOVE_TRAILING_WHITESPACE = 1 << 5, /* Remove trailing whitespaces in attribute */
|
||||
MATCH_CASE_INSENSITIVE = 1 << 6, /* string or pattern is matched case-insensitively */
|
||||
_MATCH_TYPE_INVALID = -EINVAL,
|
||||
} UdevRuleMatchType;
|
||||
|
||||
assert_cc(_MATCH_TYPE_MAX <= _MATCH_TYPE_MASK);
|
||||
|
||||
typedef enum {
|
||||
SUBST_TYPE_PLAIN, /* no substitution */
|
||||
SUBST_TYPE_FORMAT, /* % or $ */
|
||||
|
@ -155,8 +161,7 @@ struct UdevRuleToken {
|
|||
UdevRuleTokenType type:8;
|
||||
UdevRuleOperatorType op:8;
|
||||
UdevRuleMatchType match_type:8;
|
||||
UdevRuleSubstituteType attr_subst_type:7;
|
||||
bool attr_match_remove_trailing_whitespace:1;
|
||||
UdevRuleSubstituteType attr_subst_type:8;
|
||||
const char *value;
|
||||
void *data;
|
||||
|
||||
|
@ -295,6 +300,7 @@ struct UdevRules {
|
|||
|
||||
#define log_line_invalid_op(line, key) _log_line_invalid_token(line, key, "operator")
|
||||
#define log_line_invalid_attr(line, key) _log_line_invalid_token(line, key, "attribute")
|
||||
#define log_line_invalid_prefix(line, key) _log_line_invalid_token(line, key, "prefix 'i'")
|
||||
|
||||
#define log_line_invalid_attr_format(line, key, attr, offset, hint) \
|
||||
log_line_error_errno(line, SYNTHETIC_ERRNO(EINVAL), \
|
||||
|
@ -488,12 +494,10 @@ static bool type_has_nulstr_value(UdevRuleTokenType type) {
|
|||
return type < TK_M_TEST || type == TK_M_RESULT;
|
||||
}
|
||||
|
||||
static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, UdevRuleOperatorType op, char *value, void *data) {
|
||||
static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, UdevRuleOperatorType op, char *value, void *data, bool is_case_insensitive) {
|
||||
_cleanup_(udev_rule_token_freep) UdevRuleToken *token = NULL;
|
||||
UdevRuleMatchType match_type = _MATCH_TYPE_INVALID;
|
||||
UdevRuleSubstituteType subst_type = _SUBST_TYPE_INVALID;
|
||||
bool remove_trailing_whitespace = false;
|
||||
size_t len;
|
||||
|
||||
assert(rule_line);
|
||||
assert(type >= 0 && type < _TK_TYPE_MAX);
|
||||
|
@ -552,16 +556,21 @@ static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type,
|
|||
}
|
||||
|
||||
if (IN_SET(type, TK_M_ATTR, TK_M_PARENTS_ATTR)) {
|
||||
size_t len;
|
||||
|
||||
assert(value);
|
||||
assert(data);
|
||||
assert(match_type >= 0 && match_type < _MATCH_TYPE_MAX);
|
||||
|
||||
len = strlen(value);
|
||||
if (len > 0 && !isspace(value[len - 1]))
|
||||
remove_trailing_whitespace = true;
|
||||
match_type |= MATCH_REMOVE_TRAILING_WHITESPACE;
|
||||
|
||||
subst_type = rule_get_substitution_type(data);
|
||||
}
|
||||
|
||||
SET_FLAG(match_type, MATCH_CASE_INSENSITIVE, is_case_insensitive);
|
||||
|
||||
token = new(UdevRuleToken, 1);
|
||||
if (!token)
|
||||
return -ENOMEM;
|
||||
|
@ -573,7 +582,6 @@ static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type,
|
|||
.data = data,
|
||||
.match_type = match_type,
|
||||
.attr_subst_type = subst_type,
|
||||
.attr_match_remove_trailing_whitespace = remove_trailing_whitespace,
|
||||
.rule_line = rule_line,
|
||||
};
|
||||
|
||||
|
@ -621,7 +629,7 @@ static int check_attr_format_and_warn(UdevRuleLine *line, const char *key, const
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, UdevRuleOperatorType op, char *value) {
|
||||
static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, UdevRuleOperatorType op, char *value, bool is_case_insensitive) {
|
||||
ResolveNameTiming resolve_name_timing = LINE_GET_RULES(rule_line)->resolve_name_timing;
|
||||
bool is_match = IN_SET(op, OP_MATCH, OP_NOMATCH);
|
||||
int r;
|
||||
|
@ -629,35 +637,39 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
assert(key);
|
||||
assert(value);
|
||||
|
||||
if (!is_match && is_case_insensitive)
|
||||
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Invalid prefix 'i' for '%s'. The 'i' prefix can be specified only for '==' or '!=' operator.", key);
|
||||
|
||||
if (streq(key, "ACTION")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_ACTION, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_ACTION, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "DEVPATH")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_DEVPATH, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_DEVPATH, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "KERNEL")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_KERNEL, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_KERNEL, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "SYMLINK")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match) {
|
||||
check_value_format_and_warn(rule_line, key, value, false);
|
||||
r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
} else
|
||||
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "NAME")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
|
@ -677,9 +689,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
"Ignoring NAME=\"\", as udev will not delete any network interfaces.");
|
||||
check_value_format_and_warn(rule_line, key, value, false);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
} else
|
||||
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "ENV")) {
|
||||
if (isempty(attr))
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
|
@ -697,15 +709,15 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
|
||||
check_value_format_and_warn(rule_line, key, value, false);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr, /* is_case_insensitive = */ false);
|
||||
} else
|
||||
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr, is_case_insensitive);
|
||||
} else if (streq(key, "CONST")) {
|
||||
if (isempty(attr) || !STR_IN_SET(attr, "arch", "virt"))
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
r = rule_line_add_token(rule_line, TK_M_CONST, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_M_CONST, op, value, attr, is_case_insensitive);
|
||||
} else if (streq(key, "TAG")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
|
@ -717,9 +729,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
if (!is_match) {
|
||||
check_value_format_and_warn(rule_line, key, value, true);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
} else
|
||||
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "SUBSYSTEM")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
|
@ -729,14 +741,14 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
if (STR_IN_SET(value, "bus", "class"))
|
||||
log_line_warning(rule_line, "\"%s\" must be specified as \"subsystem\".", value);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_SUBSYSTEM, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_SUBSYSTEM, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "DRIVER")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "ATTR")) {
|
||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||
if (r < 0)
|
||||
|
@ -750,9 +762,9 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
|
||||
if (!is_match) {
|
||||
check_value_format_and_warn(rule_line, key, value, false);
|
||||
r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr, /* is_case_insensitive = */ false);
|
||||
} else
|
||||
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr, is_case_insensitive);
|
||||
} else if (streq(key, "SYSCTL")) {
|
||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||
if (r < 0)
|
||||
|
@ -766,30 +778,30 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
|
||||
if (!is_match) {
|
||||
check_value_format_and_warn(rule_line, key, value, false);
|
||||
r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr, /* is_case_insensitive = */ false);
|
||||
} else
|
||||
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr, is_case_insensitive);
|
||||
} else if (streq(key, "KERNELS")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_KERNEL, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_KERNEL, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "SUBSYSTEMS")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_SUBSYSTEM, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_SUBSYSTEM, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "DRIVERS")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "ATTRS")) {
|
||||
r = check_attr_format_and_warn(rule_line, key, attr);
|
||||
if (r < 0)
|
||||
|
@ -802,14 +814,14 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
if (strstr(attr, "../"))
|
||||
log_line_warning(rule_line, "Direct reference to parent sysfs directory, may break in future kernels.");
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_ATTR, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_ATTR, op, value, attr, is_case_insensitive);
|
||||
} else if (streq(key, "TAGS")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_TAG, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_PARENTS_TAG, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "TEST")) {
|
||||
mode_t mode = MODE_INVALID;
|
||||
|
||||
|
@ -821,8 +833,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
check_value_format_and_warn(rule_line, key, value, true);
|
||||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
if (is_case_insensitive)
|
||||
return log_line_invalid_prefix(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_TEST, op, value, MODE_TO_PTR(mode));
|
||||
r = rule_line_add_token(rule_line, TK_M_TEST, op, value, MODE_TO_PTR(mode), is_case_insensitive);
|
||||
} else if (streq(key, "PROGRAM")) {
|
||||
if (attr)
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
|
@ -831,8 +845,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
return log_line_invalid_op(rule_line, key);
|
||||
if (!is_match)
|
||||
op = OP_MATCH;
|
||||
if (is_case_insensitive)
|
||||
return log_line_invalid_prefix(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_PROGRAM, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_PROGRAM, op, value, NULL, /* is_case_insensitive */ false);
|
||||
} else if (streq(key, "IMPORT")) {
|
||||
if (isempty(attr))
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
|
@ -841,18 +857,20 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
return log_line_invalid_op(rule_line, key);
|
||||
if (!is_match)
|
||||
op = OP_MATCH;
|
||||
if (is_case_insensitive)
|
||||
return log_line_invalid_prefix(rule_line, key);
|
||||
|
||||
if (streq(attr, "file"))
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_FILE, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_FILE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
else if (streq(attr, "program")) {
|
||||
UdevBuiltinCommand cmd;
|
||||
|
||||
cmd = udev_builtin_lookup(value);
|
||||
if (cmd >= 0) {
|
||||
log_line_debug(rule_line, "Found builtin command '%s' for %s, replacing attribute.", value, key);
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||
} else
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
} else if (streq(attr, "builtin")) {
|
||||
UdevBuiltinCommand cmd;
|
||||
|
||||
|
@ -860,13 +878,13 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
if (cmd < 0)
|
||||
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Unknown builtin command: %s", value);
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||
} else if (streq(attr, "db"))
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
else if (streq(attr, "cmdline"))
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_CMDLINE, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_CMDLINE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
else if (streq(attr, "parent"))
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
else
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
} else if (streq(key, "RESULT")) {
|
||||
|
@ -875,7 +893,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
if (!is_match)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_M_RESULT, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_M_RESULT, op, value, NULL, is_case_insensitive);
|
||||
} else if (streq(key, "OPTIONS")) {
|
||||
char *tmp;
|
||||
|
||||
|
@ -887,24 +905,24 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
op = OP_ASSIGN;
|
||||
|
||||
if (streq(value, "string_escape=none"))
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_NONE, op, NULL, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_NONE, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||
else if (streq(value, "string_escape=replace"))
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_REPLACE, op, NULL, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STRING_ESCAPE_REPLACE, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||
else if (streq(value, "db_persist"))
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DB_PERSIST, op, NULL, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DB_PERSIST, op, NULL, NULL, /* is_case_insensitive = */ false);
|
||||
else if (streq(value, "watch"))
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(1));
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(1), /* is_case_insensitive = */ false);
|
||||
else if (streq(value, "nowatch"))
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(0));
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_INOTIFY_WATCH, op, NULL, INT_TO_PTR(0), /* is_case_insensitive = */ false);
|
||||
else if ((tmp = startswith(value, "static_node=")))
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STATIC_NODE, op, tmp, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_STATIC_NODE, op, tmp, NULL, /* is_case_insensitive = */ false);
|
||||
else if ((tmp = startswith(value, "link_priority="))) {
|
||||
int prio;
|
||||
|
||||
r = safe_atoi(tmp, &prio);
|
||||
if (r < 0)
|
||||
return log_line_error_errno(rule_line, r, "Failed to parse link priority '%s': %m", tmp);
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio));
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio), /* is_case_insensitive = */ false);
|
||||
} else if ((tmp = startswith(value, "log_level="))) {
|
||||
int level;
|
||||
|
||||
|
@ -915,7 +933,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
if (level < 0)
|
||||
return log_line_error_errno(rule_line, level, "Failed to parse log level '%s': %m", tmp);
|
||||
}
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level));
|
||||
r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level), /* is_case_insensitive = */ false);
|
||||
} else {
|
||||
log_line_warning(rule_line, "Invalid value for OPTIONS key, ignoring: '%s'", value);
|
||||
return 0;
|
||||
|
@ -933,17 +951,17 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
}
|
||||
|
||||
if (parse_uid(value, &uid) >= 0)
|
||||
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
|
||||
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid), /* is_case_insensitive = */ false);
|
||||
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
||||
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
||||
r = rule_resolve_user(rule_line, value, &uid);
|
||||
if (r < 0)
|
||||
return log_line_error_errno(rule_line, r, "Failed to resolve user name '%s': %m", value);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid));
|
||||
r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid), /* is_case_insensitive = */ false);
|
||||
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
||||
check_value_format_and_warn(rule_line, key, value, true);
|
||||
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
} else {
|
||||
log_line_debug(rule_line, "User name resolution is disabled, ignoring %s=\"%s\".", key, value);
|
||||
return 0;
|
||||
|
@ -961,17 +979,17 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
}
|
||||
|
||||
if (parse_gid(value, &gid) >= 0)
|
||||
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
|
||||
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid), /* is_case_insensitive = */ false);
|
||||
else if (resolve_name_timing == RESOLVE_NAME_EARLY &&
|
||||
rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) {
|
||||
r = rule_resolve_group(rule_line, value, &gid);
|
||||
if (r < 0)
|
||||
return log_line_error_errno(rule_line, r, "Failed to resolve group name '%s': %m", value);
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid));
|
||||
r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid), /* is_case_insensitive = */ false);
|
||||
} else if (resolve_name_timing != RESOLVE_NAME_NEVER) {
|
||||
check_value_format_and_warn(rule_line, key, value, true);
|
||||
r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
} else {
|
||||
log_line_debug(rule_line, "Resolving group name is disabled, ignoring GROUP=\"%s\".", value);
|
||||
return 0;
|
||||
|
@ -989,10 +1007,10 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
}
|
||||
|
||||
if (parse_mode(value, &mode) >= 0)
|
||||
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode));
|
||||
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode), /* is_case_insensitive = */ false);
|
||||
else {
|
||||
check_value_format_and_warn(rule_line, key, value, true);
|
||||
r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
}
|
||||
} else if (streq(key, "SECLABEL")) {
|
||||
if (isempty(attr))
|
||||
|
@ -1005,13 +1023,13 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
op = OP_ASSIGN;
|
||||
}
|
||||
|
||||
r = rule_line_add_token(rule_line, TK_A_SECLABEL, op, value, attr);
|
||||
r = rule_line_add_token(rule_line, TK_A_SECLABEL, op, value, attr, /* is_case_insensitive = */ false);
|
||||
} else if (streq(key, "RUN")) {
|
||||
if (is_match || op == OP_REMOVE)
|
||||
return log_line_invalid_op(rule_line, key);
|
||||
check_value_format_and_warn(rule_line, key, value, true);
|
||||
if (!attr || streq(attr, "program"))
|
||||
r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL);
|
||||
r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL, /* is_case_insensitive = */ false);
|
||||
else if (streq(attr, "builtin")) {
|
||||
UdevBuiltinCommand cmd;
|
||||
|
||||
|
@ -1019,7 +1037,7 @@ static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, Ude
|
|||
if (cmd < 0)
|
||||
return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Unknown builtin command '%s', ignoring.", value);
|
||||
r = rule_line_add_token(rule_line, TK_A_RUN_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd));
|
||||
r = rule_line_add_token(rule_line, TK_A_RUN_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd), /* is_case_insensitive = */ false);
|
||||
} else
|
||||
return log_line_invalid_attr(rule_line, key);
|
||||
} else if (streq(key, "GOTO")) {
|
||||
|
@ -1119,13 +1137,30 @@ static void check_token_delimiters(UdevRuleLine *rule_line, const char *line) {
|
|||
}
|
||||
}
|
||||
|
||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
|
||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos, bool *ret_is_case_insensitive) {
|
||||
char *i, *j;
|
||||
bool is_escaped;
|
||||
bool is_escaped = false, is_case_insensitive = false;
|
||||
|
||||
assert(str);
|
||||
assert(ret_value);
|
||||
assert(ret_endpos);
|
||||
assert(ret_is_case_insensitive);
|
||||
|
||||
/* check if string is prefixed with:
|
||||
* - "e" for escaped
|
||||
* - "i" for case insensitive match
|
||||
*
|
||||
* Note both e and i can be set but do not allow duplicates ("eei", "eii"). */
|
||||
for (const char *k = str; *k != '"' && k < str + 2; k++)
|
||||
if (*k == 'e' && !is_escaped)
|
||||
is_escaped = true;
|
||||
else if (*k == 'i' && !is_case_insensitive)
|
||||
is_case_insensitive = true;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
/* value must be double quotated */
|
||||
is_escaped = str[0] == 'e';
|
||||
str += is_escaped;
|
||||
str += is_escaped + is_case_insensitive;
|
||||
if (str[0] != '"')
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -1172,10 +1207,11 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) {
|
|||
|
||||
*ret_value = str;
|
||||
*ret_endpos = i + 1;
|
||||
*ret_is_case_insensitive = is_case_insensitive;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value) {
|
||||
static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOperatorType *ret_op, char **ret_value, bool *ret_is_case_insensitive) {
|
||||
char *key_begin, *key_end, *attr, *tmp;
|
||||
UdevRuleOperatorType op;
|
||||
int r;
|
||||
|
@ -1185,6 +1221,7 @@ static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOper
|
|||
assert(ret_key);
|
||||
assert(ret_op);
|
||||
assert(ret_value);
|
||||
assert(ret_is_case_insensitive);
|
||||
|
||||
key_begin = skip_leading_chars(*line, WHITESPACE ",");
|
||||
|
||||
|
@ -1219,7 +1256,7 @@ static int parse_line(char **line, char **ret_key, char **ret_attr, UdevRuleOper
|
|||
|
||||
tmp += op == OP_ASSIGN ? 1 : 2;
|
||||
tmp = skip_leading_chars(tmp, NULL);
|
||||
r = udev_rule_parse_value(tmp, ret_value, line);
|
||||
r = udev_rule_parse_value(tmp, ret_value, line, ret_is_case_insensitive);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -1291,17 +1328,18 @@ static int rule_add_line(UdevRuleFile *rule_file, const char *line_str, unsigned
|
|||
for (p = rule_line->line; !isempty(p); ) {
|
||||
char *key, *attr, *value;
|
||||
UdevRuleOperatorType op;
|
||||
bool is_case_insensitive;
|
||||
|
||||
if (extra_checks)
|
||||
check_token_delimiters(rule_line, p);
|
||||
|
||||
r = parse_line(&p, &key, &attr, &op, &value);
|
||||
r = parse_line(&p, &key, &attr, &op, &value, &is_case_insensitive);
|
||||
if (r < 0)
|
||||
return log_line_error_errno(rule_line, r, "Invalid key/value pair, ignoring.");
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
r = parse_token(rule_line, key, attr, op, value);
|
||||
r = parse_token(rule_line, key, attr, op, value, is_case_insensitive);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -1412,7 +1450,6 @@ static bool tokens_eq(const UdevRuleToken *a, const UdevRuleToken *b) {
|
|||
assert(b);
|
||||
|
||||
return a->attr_subst_type == b->attr_subst_type &&
|
||||
a->attr_match_remove_trailing_whitespace == b->attr_match_remove_trailing_whitespace &&
|
||||
token_type_and_value_eq(a, b) &&
|
||||
token_type_and_data_eq(a, b);
|
||||
}
|
||||
|
@ -1427,7 +1464,6 @@ static bool nulstr_tokens_conflict(const UdevRuleToken *a, const UdevRuleToken *
|
|||
a->op == OP_MATCH &&
|
||||
a->match_type == b->match_type &&
|
||||
a->attr_subst_type == b->attr_subst_type &&
|
||||
a->attr_match_remove_trailing_whitespace == b->attr_match_remove_trailing_whitespace &&
|
||||
token_type_and_data_eq(a, b)))
|
||||
return false;
|
||||
|
||||
|
@ -1696,7 +1732,7 @@ bool udev_rules_should_reload(UdevRules *rules) {
|
|||
|
||||
static bool token_match_string(UdevRuleToken *token, const char *str) {
|
||||
const char *value;
|
||||
bool match = false;
|
||||
bool match = false, case_insensitive;
|
||||
|
||||
assert(token);
|
||||
assert(token->value);
|
||||
|
@ -1704,12 +1740,16 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
|||
|
||||
str = strempty(str);
|
||||
value = token->value;
|
||||
case_insensitive = FLAGS_SET(token->match_type, MATCH_CASE_INSENSITIVE);
|
||||
|
||||
switch (token->match_type) {
|
||||
switch (token->match_type & _MATCH_TYPE_MASK) {
|
||||
case MATCH_TYPE_EMPTY:
|
||||
match = isempty(str);
|
||||
break;
|
||||
case MATCH_TYPE_SUBSYSTEM:
|
||||
if (case_insensitive)
|
||||
match = STRCASE_IN_SET(str, "subsystem", "class", "bus");
|
||||
else
|
||||
match = STR_IN_SET(str, "subsystem", "class", "bus");
|
||||
break;
|
||||
case MATCH_TYPE_PLAIN_WITH_EMPTY:
|
||||
|
@ -1720,7 +1760,7 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
|||
_fallthrough_;
|
||||
case MATCH_TYPE_PLAIN:
|
||||
NULSTR_FOREACH(i, value)
|
||||
if (streq(i, str)) {
|
||||
if (case_insensitive ? strcaseeq(i, str) : streq(i, str)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1733,7 +1773,7 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
|||
_fallthrough_;
|
||||
case MATCH_TYPE_GLOB:
|
||||
NULSTR_FOREACH(i, value)
|
||||
if ((fnmatch(i, str, 0) == 0)) {
|
||||
if ((fnmatch(i, str, case_insensitive ? FNM_CASEFOLD : 0) == 0)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1773,7 +1813,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
|
|||
return false;
|
||||
|
||||
/* remove trailing whitespace, if not asked to match for it */
|
||||
if (token->attr_match_remove_trailing_whitespace) {
|
||||
if (FLAGS_SET(token->match_type, MATCH_REMOVE_TRAILING_WHITESPACE)) {
|
||||
strscpy(vbuf, sizeof(vbuf), value);
|
||||
value = delete_trailing_chars(vbuf, NULL);
|
||||
}
|
||||
|
@ -1785,7 +1825,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
|
|||
return false;
|
||||
|
||||
/* remove trailing whitespace, if not asked to match for it */
|
||||
if (token->attr_match_remove_trailing_whitespace)
|
||||
if (FLAGS_SET(token->match_type, MATCH_REMOVE_TRAILING_WHITESPACE))
|
||||
delete_trailing_chars(vbuf, NULL);
|
||||
|
||||
return token_match_string(token, vbuf);
|
||||
|
|
|
@ -29,7 +29,7 @@ typedef enum ResolveNameTiming {
|
|||
_RESOLVE_NAME_TIMING_INVALID = -EINVAL,
|
||||
} ResolveNameTiming;
|
||||
|
||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos);
|
||||
int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos, bool *ret_is_case_insensitive);
|
||||
int udev_rules_parse_file(UdevRules *rules, const char *filename, bool extra_checks, UdevRuleFile **ret);
|
||||
unsigned udev_rule_file_get_issues(UdevRuleFile *rule_file);
|
||||
UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing);
|
||||
|
|
|
@ -2313,6 +2313,17 @@ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \"printf %%s 'foo1 foo2' | grep 'foo1 f
|
|||
SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
|
||||
KERNEL=="sda6", OPTIONS+="link_priority=10"
|
||||
"""),
|
||||
|
||||
Rules.new(
|
||||
"case insensitive match",
|
||||
Device(
|
||||
"/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
|
||||
exp_links = ["ok"],
|
||||
),
|
||||
|
||||
rules = r"""
|
||||
KERNEL==i"SDA1", SUBSYSTEMS==i"SCSI", ATTRS{vendor}==i"a?a", SYMLINK+="ok"
|
||||
"""),
|
||||
]
|
||||
|
||||
def fork_and_run_udev(action: str, rules: Rules) -> None:
|
||||
|
|
|
@ -237,6 +237,8 @@ test_syntax_error 'ENV=="b"' 'Invalid attribute for ENV.'
|
|||
test_syntax_error 'ENV{a}-="b"' 'Invalid operator for ENV.'
|
||||
test_syntax_error 'ENV{a}:="b"' "ENV key takes '==', '!=', '=', or '+=' operator, assuming '='."
|
||||
test_syntax_error 'ENV{ACTION}="b"' "Invalid ENV attribute. 'ACTION' cannot be set."
|
||||
test_syntax_error 'ENV{a}=i"b"' "Invalid prefix 'i' for 'ENV'. The 'i' prefix can be specified only for '==' or '!=' operator."
|
||||
test_syntax_error 'ENV{a}+=i"b"' "Invalid prefix 'i' for 'ENV'. The 'i' prefix can be specified only for '==' or '!=' operator."
|
||||
test_syntax_error 'CONST=="b"' 'Invalid attribute for CONST.'
|
||||
test_syntax_error 'CONST{a}=="b"' 'Invalid attribute for CONST.'
|
||||
test_syntax_error 'CONST{arch}="b"' 'Invalid operator for CONST.'
|
||||
|
@ -275,10 +277,12 @@ test_syntax_error 'TEST{0644}="b"' 'Invalid operator for TEST.'
|
|||
test_syntax_error 'PROGRAM{a}=="b"' 'Invalid attribute for PROGRAM.'
|
||||
test_syntax_error 'PROGRAM-="b"' 'Invalid operator for PROGRAM.'
|
||||
test_syntax_error 'PROGRAM=="%", NAME="b"' 'Invalid value "%" for PROGRAM (char 1: invalid substitution type), ignoring.'
|
||||
test_syntax_error 'PROGRAM==i"b"' "Invalid prefix 'i' for PROGRAM."
|
||||
test_syntax_error 'IMPORT="b"' 'Invalid attribute for IMPORT.'
|
||||
test_syntax_error 'IMPORT{a}="b"' 'Invalid attribute for IMPORT.'
|
||||
test_syntax_error 'IMPORT{a}-="b"' 'Invalid operator for IMPORT.'
|
||||
test_syntax_error 'IMPORT{file}=="%", NAME="b"' 'Invalid value "%" for IMPORT (char 1: invalid substitution type), ignoring.'
|
||||
test_syntax_error 'IMPORT{file}==i"a", NAME="b"' "Invalid prefix 'i' for IMPORT."
|
||||
test_syntax_error 'IMPORT{builtin}!="foo"' 'Unknown builtin command: foo'
|
||||
test_syntax_error 'RESULT{a}=="b"' 'Invalid attribute for RESULT.'
|
||||
test_syntax_error 'RESULT:="b"' 'Invalid operator for RESULT.'
|
||||
|
|
|
@ -9,26 +9,39 @@ set -o pipefail
|
|||
export SYSTEMD_LOG_LEVEL=debug
|
||||
|
||||
c='
|
||||
d /tmp/somedir
|
||||
f /tmp/somedir/somefile - - - - baz
|
||||
d$ /tmp/somedir
|
||||
f$ /tmp/somedir/somefile - - - - baz
|
||||
f /tmp/someotherfile - - - - qux
|
||||
'
|
||||
|
||||
systemd-tmpfiles --create - <<<"$c"
|
||||
test -f /tmp/somedir/somefile
|
||||
grep -q baz /tmp/somedir/somefile
|
||||
grep -q qux /tmp/someotherfile
|
||||
|
||||
systemd-tmpfiles --purge --dry-run - <<<"$c"
|
||||
test -f /tmp/somedir/somefile
|
||||
grep -q baz /tmp/somedir/somefile
|
||||
grep -q qux /tmp/someotherfile
|
||||
|
||||
systemd-tmpfiles --purge - <<<"$c"
|
||||
test ! -f /tmp/somedir/somefile
|
||||
test ! -d /tmp/somedir/
|
||||
grep -q qux /tmp/someotherfile
|
||||
|
||||
systemd-tmpfiles --create --purge --dry-run - <<<"$c"
|
||||
test ! -f /tmp/somedir/somefile
|
||||
test ! -d /tmp/somedir/
|
||||
grep -q qux /tmp/someotherfile
|
||||
|
||||
systemd-tmpfiles --create --purge - <<<"$c"
|
||||
test -f /tmp/somedir/somefile
|
||||
grep -q baz /tmp/somedir/somefile
|
||||
grep -q qux /tmp/someotherfile
|
||||
|
||||
systemd-tmpfiles --purge - <<<"$c"
|
||||
test ! -f /tmp/somedir/somefile
|
||||
test ! -d /tmp/somedir/
|
||||
grep -q qux /tmp/someotherfile
|
||||
|
||||
rm /tmp/someotherfile
|
||||
|
|
|
@ -8,5 +8,5 @@
|
|||
# See tmpfiles.d(5) for details
|
||||
|
||||
{% if LINK_SHELL_EXTRA_DROPIN %}
|
||||
L {{SHELLPROFILEDIR}}/70-systemd-shell-extra.sh - - - - {{LIBEXECDIR}}/profile.d/70-systemd-shell-extra.sh
|
||||
L$ {{SHELLPROFILEDIR}}/70-systemd-shell-extra.sh - - - - {{LIBEXECDIR}}/profile.d/70-systemd-shell-extra.sh
|
||||
{% endif %}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
# See tmpfiles.d(5) for details
|
||||
|
||||
{% if LINK_SSH_PROXY_DROPIN %}
|
||||
L {{SSHCONFDIR}}/20-systemd-ssh-proxy.conf - - - - {{LIBEXECDIR}}/ssh_config.d/20-systemd-ssh-proxy.conf
|
||||
L$ {{SSHCONFDIR}}/20-systemd-ssh-proxy.conf - - - - {{LIBEXECDIR}}/ssh_config.d/20-systemd-ssh-proxy.conf
|
||||
{% endif %}
|
||||
{% if CREATE_SSHDPRIVSEPDIR %}
|
||||
d {{SSHDPRIVSEPDIR}} 0755
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
d /run/lock 0755 root root -
|
||||
L /var/lock - - - - ../run/lock
|
||||
{% if CREATE_LOG_DIRS %}
|
||||
L /var/log/README - - - - ../..{{DOC_DIR}}/README.logs
|
||||
L$ /var/log/README - - - - ../..{{DOC_DIR}}/README.logs
|
||||
{% endif %}
|
||||
|
||||
# /run/lock/subsys is used for serializing SysV service execution, and
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
# See tmpfiles.d(5) for details
|
||||
|
||||
d /run/systemd/netif 0755 systemd-network systemd-network -
|
||||
d /run/systemd/netif/links 0755 systemd-network systemd-network -
|
||||
d /run/systemd/netif/leases 0755 systemd-network systemd-network -
|
||||
d /var/lib/systemd/network 0755 systemd-network systemd-network -
|
||||
d$ /run/systemd/netif 0755 systemd-network systemd-network -
|
||||
d$ /run/systemd/netif/links 0755 systemd-network systemd-network -
|
||||
d$ /run/systemd/netif/leases 0755 systemd-network systemd-network -
|
||||
d$ /var/lib/systemd/network 0755 systemd-network systemd-network -
|
||||
|
|
|
@ -19,5 +19,5 @@ Q /var/lib/machines 0700 - - -
|
|||
# systemd-nspawn --ephemeral places snapshots) we are more strict, to
|
||||
# avoid removing unrelated temporary files.
|
||||
|
||||
R! /var/lib/machines/.#*
|
||||
R! /.#machine.*
|
||||
R!$ /var/lib/machines/.#*
|
||||
R!$ /.#machine.*
|
||||
|
|
|
@ -14,10 +14,10 @@ x /var/tmp/systemd-private-%b-*
|
|||
X /var/tmp/systemd-private-%b-*/tmp
|
||||
|
||||
# Remove top-level private temporary directories on each boot
|
||||
R! /tmp/systemd-private-*
|
||||
R! /var/tmp/systemd-private-*
|
||||
R!$ /tmp/systemd-private-*
|
||||
R!$ /var/tmp/systemd-private-*
|
||||
|
||||
# Handle lost systemd-coredump temp files. They could be lost on old filesystems,
|
||||
# for example, after hard reboot.
|
||||
x /var/lib/systemd/coredump/.#core*.%b*
|
||||
r! /var/lib/systemd/coredump/.#*
|
||||
r!$ /var/lib/systemd/coredump/.#*
|
||||
|
|
|
@ -13,11 +13,11 @@ f+! /run/utmp 0664 root utmp -
|
|||
{% endif %}
|
||||
|
||||
d /run/systemd/ask-password 0755 root root -
|
||||
d /run/systemd/seats 0755 root root -
|
||||
d /run/systemd/sessions 0755 root root -
|
||||
d /run/systemd/users 0755 root root -
|
||||
d$ /run/systemd/seats 0755 root root -
|
||||
d$ /run/systemd/sessions 0755 root root -
|
||||
d$ /run/systemd/users 0755 root root -
|
||||
d /run/systemd/machines 0755 root root -
|
||||
d /run/systemd/shutdown 0755 root root -
|
||||
d$ /run/systemd/shutdown 0755 root root -
|
||||
|
||||
d /run/log 0755 root root -
|
||||
|
||||
|
|
Loading…
Reference in New Issue