]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #16514 from keszybz/zstd-decompress-fix
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 22 Jul 2020 08:40:19 +0000 (10:40 +0200)
committerGitHub <noreply@github.com>
Wed, 22 Jul 2020 08:40:19 +0000 (10:40 +0200)
Fix coredumpctl operation with zstd-compressed journals

103 files changed:
.clang-format
.gitignore
.mkosi/mkosi.arch
.mkosi/mkosi.debian
.mkosi/mkosi.fedora
.mkosi/mkosi.opensuse
.mkosi/mkosi.ubuntu
NEWS
TODO
docs/DESKTOP_ENVIRONMENTS.md
docs/HACKING.md
hwdb.d/60-autosuspend.hwdb
hwdb.d/parse_hwdb.py
man/resolvectl.xml
man/resolved.conf.xml
man/systemd-initctl.service.xml
man/systemd-journal-gatewayd.service.xml
man/systemd-journal-remote.service.xml
man/systemd.netdev.xml
man/systemd.network.xml
meson.build
mkosi.default [deleted symlink]
src/analyze/analyze.c
src/basic/fileio.c
src/basic/fileio.h
src/basic/in-addr-util.c
src/basic/in-addr-util.h
src/basic/user-util.c
src/cgls/cgls.c
src/coredump/coredump.c
src/hostname/hostnamectl.c
src/import/import-common.c
src/journal-remote/journal-gatewayd.c
src/journal-remote/journal-remote-main.c
src/libsystemd-network/sd-radv.c
src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/netlink-util.h
src/locale/localectl.c
src/login/loginctl.c
src/login/logind-dbus.c
src/machine/machinectl.c
src/mount/mount-tool.c
src/network/netdev/macsec.c
src/network/netdev/wireguard.c
src/network/networkctl.c
src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-dhcp-server.c
src/network/networkd-link-bus.c
src/network/networkd-link-bus.h
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-manager-bus.c
src/network/networkd-manager.c
src/network/networkd-ndisc.c
src/network/networkd-neighbor.c
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-radv.c
src/nspawn/nspawn.c
src/resolve/resolvectl.c
src/resolve/resolved-bus.c
src/resolve/resolved-bus.h
src/resolve/resolved-conf.c
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-scope.h
src/resolve/resolved-dns-server.c
src/resolve/resolved-dns-server.h
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-link-bus.c
src/resolve/resolved-link-bus.h
src/resolve/resolved-link.c
src/run/run.c
src/shared/acl-util.c
src/shared/bus-get-properties.h
src/shared/bus-message-util.c [new file with mode: 0644]
src/shared/bus-message-util.h [new file with mode: 0644]
src/shared/bus-util.h
src/shared/cgroup-show.c
src/shared/meson.build
src/shared/offline-passwd.c [new file with mode: 0644]
src/shared/offline-passwd.h [moved from src/tmpfiles/offline-passwd.h with 100% similarity]
src/shared/socket-netlink.c
src/shared/socket-netlink.h
src/systemd/sd-radv.h
src/test/meson.build
src/test/test-fileio.c
src/test/test-offline-passwd.c [new file with mode: 0644]
src/test/test-socket-util.c
src/timedate/timedatectl.c
src/tmpfiles/meson.build
src/tmpfiles/offline-passwd.c [deleted file]
src/udev/net/link-config.c
src/udev/udev-builtin-hwdb.c
src/vconsole/vconsole-setup.c
src/veritysetup/veritysetup.c
test/TEST-50-DISSECT/test.sh
test/test-network/conf/state-file-tests.network
test/test-network/systemd-networkd-tests.py
test/units/testsuite-50.sh
tools/make-autosuspend-rules.py
travis-ci/managers/debian.sh
units/meson.build

index ab1954935ca7a758152d13d96c1c38585c2755f7..ab27960a6738f78f76790049bea97b6dead1b055 100644 (file)
@@ -34,7 +34,7 @@ AlwaysBreakTemplateDeclarations: Yes
 BinPackArguments: false
 BinPackParameters: false
 BraceWrapping:
-  AfterEnum:       true
+  AfterEnum:       false
   SplitEmptyFunction: false
   SplitEmptyRecord: false
   SplitEmptyNamespace: false
index f47de39f3ddf11f060ffcdb532e6f49cc2896769..0b2092d7404c2e8d3407c1717baee0f70a12c7e8 100644 (file)
@@ -35,4 +35,5 @@ __pycache__/
 /.mkosi-*
 /mkosi.builddir/
 /mkosi.output/
+/mkosi.default
 /tags
index 965e26e411c16c06a8ac2e874e0a89bba2559925..cb1952206d34af52d0a49d3fa64524e0698ae860 100644 (file)
@@ -3,7 +3,7 @@
 # Copyright Â© 2016 Zeal Jagannatha
 
 # This is a settings file for OS image generation using mkosi (https://github.com/systemd/mkosi).
-# Simply invoke "mkosi" in the project directory to build an OS image.
+# Symlink this file to mkosi.default in the project root directory and invoke "mkosi" to build an OS image.
 
 [Distribution]
 Distribution=arch
index ff0c8ffc07bdc90b32174c02fa1379d3d739d5ce..db9bd3550ed3d199c93d8a3dbffccd85e1ba3cb1 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
 # This is a settings file for OS image generation using mkosi (https://github.com/systemd/mkosi).
-# Simply invoke "mkosi" in the project directory to build an OS image.
+# Symlink this file to mkosi.default in the project root directory and invoke "mkosi" to build an OS image.
 
 [Distribution]
 Distribution=debian
index 5caf8a1866d608e708e8c86b70a1cf428e970310..09527711fe6335523d05782887afe8fd6173af0f 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
 # This is a settings file for OS image generation using mkosi (https://github.com/systemd/mkosi).
-# Simply invoke "mkosi" in the project directory to build an OS image.
+# Symlink this file to mkosi.default in the project root directory and invoke "mkosi" to build an OS image.
 
 [Distribution]
 Distribution=fedora
index 248a7f53c87cb1c08fd65053b6dd76d162ca824e..53837b6be8fb83c0969fdd28ed8c318a80d13807 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
 # This is a settings file for OS image generation using mkosi (https://github.com/systemd/mkosi).
-# Simply invoke "mkosi" in the project directory to build an OS image.
+# Symlink this file to mkosi.default in the project root directory and invoke "mkosi" to build an OS image.
 
 [Distribution]
 Distribution=opensuse
index fc3192ccad322e3c94bf9ea4d38c0e1af5ec9a4d..990e9c1cbcf245aa92ac8999f041518412b0a783 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
 # This is a settings file for OS image generation using mkosi (https://github.com/systemd/mkosi).
-# Simply invoke "mkosi" in the project directory to build an OS image.
+# Symlink this file to mkosi.default in the project root directory and invoke "mkosi" to build an OS image.
 
 [Distribution]
 Distribution=ubuntu
diff --git a/NEWS b/NEWS
index 3fea3d221e4ae6341b49e11da8109cb1afef2175..f47645b1fd4497c2e7d6c335531432a4299cfdc0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -526,6 +526,18 @@ CHANGES WITH 246:
           LogControl1 D-Bus API which allows clients to change log level +
           target of the service during runtime.
 
+        * Various command line parameters and configuration file settings that
+          configure key or certificate files now optionally take paths to
+          AF_UNIX sockets in the file system. If configured that way a stream
+          connection is made to the socket and the required data read from
+          it. This is a simple and natural extension to the existing regular
+          file logic, and permits other software to provide keys or
+          certificates via simple IPC services, for example when unencrypted
+          storage on disk is not desired. Specifically, systemd-networkd's
+          Wireguard and MACSEC key file settings as well as
+          systemd-journal-gatewayd's and systemd-journal-remote's PEM
+          key/certificate parameters support this now.
+
         Contributions from: 24bisquitz, Adam Nielsen, Alan Perry, Alexander
         Malafeev, Alin Popa, Amos Bird, Andreas Rammhold, AndreRH, Andrew
         Doran, Anita Zhang, Ankit Jain, antznin, Arnaud Ferraris, Arthur Moraes
diff --git a/TODO b/TODO
index 94fa28ee50ed71e689f001f3553ac3b44adc9040..099ce36f01a310437e91ad56834030d326ffb17a 100644 (file)
--- a/TODO
+++ b/TODO
@@ -17,6 +17,9 @@ Janitorial Clean-ups:
 
 Features:
 
+* cryptsetup: if keyfile specified in crypttab is AF_UNIX socket, connect to it
+  and read from it (like we do elsewhere with READ_FULL_FILE_CONNECT_SOCKET)
+
 * repart: support setting up dm-integrity with HMAC
 
 * add /etc/integritytab, to support dm-integrity setups. In particular those
index 7c8331f9a9b419fce10fd6f113b942a76b4c280c..9ae1aefb2013e88205e179108231d02bf8a7a3a4 100644 (file)
@@ -91,16 +91,22 @@ global default for all (graphical) applications.
 
 ## XDG autostart integration
 
-To allow XDG autostart integration, systemd will ship a cross-desktop generator
-to create appropriate units for the autostart directory.
-Desktop Environments will be able to make use of this simply by starting the
-appropriate XDG related targets (representing e.g. content of the
-`$XDG_CURRENT_DESKTOP` environment variable to handle `OnlyShowIn/NotShowIn`).
-The names and ordering rules for these targets are to be defined.
-
-This generator will likely never support certain desktop specific extensions.
-One such example is the GNOME specific feature to bind a service to a settings
-variable.
+To allow XDG autostart integration, systemd ships a cross-desktop generator
+to create appropriate units for the autostart directory
+(`systemd-xdg-autostart-generator`).
+Desktop Environments can opt-in to using this by starting
+`xdg-desktop-autostart.target`. The systemd generator correctly handles
+`OnlyShowIn=` and `NotShowin=`. It also handles the KDE and GNOME specific
+`X-KDE-autostart-condition=` and `AutostartCondition=` by using desktop
+environment provided binaries in an `ExecCondition=` line.
+
+However, this generator is somewhat limited in what it supports. For example,
+all generated units will have `After=graphical-session.target` set on them,
+it may therefore not be useful to start session services.
+
+Desktop files can be marked to be explicitly excluded from the generator using the line
+`X-systemd-skip=true`. This should be set if an application provides its own
+systemd service file for startup.
 
 ## Startup and shutdown best practices
 
index a86a6f21725b5d18f9cbbea3eb6db6f05266ad46..990f78c9eb43856f99ec161a135ca2e4fa0634aa 100644 (file)
@@ -36,9 +36,12 @@ building clean OS images from an upstream distribution in combination with a
 fresh build of the project in the local working directory. To make use of this,
 please acquire `mkosi` from https://github.com/systemd/mkosi first, unless your
 distribution has packaged it already and you can get it from there. After the
-tool is installed it is sufficient to type `mkosi` in the systemd project
-directory to generate a disk image `image.raw` you can boot either in
-`systemd-nspawn` or in an UEFI-capable VM:
+tool is installed, symlink the settings file for your distribution of choice from
+.mkosi/ to mkosi.default in the project root directory (note that the package
+manager for this distro needs to be installed on your host system). After doing
+that, it is sufficient to type `mkosi` in the systemd project directory to
+generate a disk image `image.raw` you can boot either in `systemd-nspawn` or in
+an UEFI-capable VM:
 
 ```
 # systemd-nspawn -bi image.raw
@@ -72,22 +75,23 @@ Putting this all together, here's a series of commands for preparing a patch
 for systemd (this example is for Fedora):
 
 ```sh
-$ sudo dnf builddep systemd            # install build dependencies
-$ sudo dnf install mkosi               # install tool to quickly build images
+$ sudo dnf builddep systemd               # install build dependencies
+$ sudo dnf install mkosi                  # install tool to quickly build images
 $ git clone https://github.com/systemd/systemd.git
 $ cd systemd
-$ vim src/core/main.c                  # or wherever you'd like to make your changes
-$ meson build                          # configure the build
-$ ninja -C build                       # build it locally, see if everything compiles fine
-$ ninja -C build test                  # run some simple regression tests
-$ (umask 077; echo 123 > mkosi.rootpw) # set root password used by mkosi
-$ sudo mkosi                           # build a test image
-$ sudo systemd-nspawn -bi image.raw    # boot up the test image
-$ git add -p                           # interactively put together your patch
-$ git commit                           # commit it
+$ vim src/core/main.c                     # or wherever you'd like to make your changes
+$ meson build                             # configure the build
+$ ninja -C build                          # build it locally, see if everything compiles fine
+$ ninja -C build test                     # run some simple regression tests
+$ ln -s .mkosi/mkosi.fedora mkosi.default # Configure mkosi to build a fedora image
+$ (umask 077; echo 123 > mkosi.rootpw)    # set root password used by mkosi
+$ sudo mkosi                              # build a test image
+$ sudo systemd-nspawn -bi image.raw       # boot up the test image
+$ git add -p                              # interactively put together your patch
+$ git commit                              # commit it
 $ git push REMOTE HEAD:refs/heads/BRANCH
-                                       # where REMOTE is your "fork" on GitHub
-                                       # and BRANCH is a branch name.
+                                          # where REMOTE is your "fork" on GitHub
+                                          # and BRANCH is a branch name.
 ```
 
 And after that, head over to your repo on GitHub and click "Compare & pull request"
index 0de49afa6cd4c2305689bfe693e498eb1a410548..e742a33ea69e8eb4176994dd6c61b074ef1d4c8a 100644 (file)
 usb:v058Fp9540*
  ID_AUTOSUSPEND=1
 
+#########################################
+# QEMU
+#########################################
+
+# Emulated USB HID devices
+usb:v0627p0001:*QEMU USB Keyboard*
+usb:v0627p0001:*QEMU USB Mouse*
+usb:v0627p0001:*QEMU USB Tablet*
+ ID_AUTOSUSPEND=1
+
 #########################################
 # Wacom
 #########################################
index 8e1b5fdafa4c600279f8c3a4288bef31610cdd82..025133416f6e23c23ce64f1dfad9bc96f0d84a76 100755 (executable)
@@ -79,6 +79,9 @@ GENERAL_MATCHES = {'acpi',
                    'OUI',
                    }
 
+def upperhex_word(length):
+    return Word(nums + 'ABCDEF', exact=length)
+
 @lru_cache()
 def hwdb_grammar():
     ParserElement.setDefaultWhitespaceChars('')
@@ -87,7 +90,7 @@ def hwdb_grammar():
                 for category, conn in TYPES.items())
 
     matchline_typed = Combine(prefix + Word(printables + ' ' + '®'))
-    matchline_general = Combine(Or(GENERAL_MATCHES) + ':' + Word(printables))
+    matchline_general = Combine(Or(GENERAL_MATCHES) + ':' + Word(printables + ' ' + '®'))
     matchline = (matchline_typed | matchline_general) + EOL
 
     propertyline = (White(' ', exact=1).suppress() +
@@ -180,8 +183,27 @@ def parse(fname):
         return []
     return [convert_properties(g) for g in parsed.GROUPS]
 
-def check_match_uniqueness(groups):
+def check_matches(groups):
     matches = sum((group[0] for group in groups), [])
+
+    # This is a partial check. The other cases could be also done, but those
+    # two are most commonly wrong.
+    grammars = { 'usb' : 'v' + upperhex_word(4) + Optional('p' + upperhex_word(4)),
+                 'pci' : 'v' + upperhex_word(8) + Optional('d' + upperhex_word(8)),
+    }
+
+    for match in matches:
+        prefix, rest = match.split(':', maxsplit=1)
+        gr = grammars.get(prefix)
+        if gr:
+            try:
+                gr.parseString(rest)
+            except ParseBaseException as e:
+                error('Pattern {!r} is invalid: {}', rest, e)
+                continue
+            if rest[-1] not in '*:':
+                error('pattern {} does not end with "*" or ":"', match)
+
     matches.sort()
     prev = None
     for match in matches:
@@ -256,7 +278,7 @@ if __name__ == '__main__':
     for fname in args:
         groups = parse(fname)
         print_summary(fname, groups)
-        check_match_uniqueness(groups)
+        check_matches(groups)
         check_properties(groups)
 
     sys.exit(ERROR)
index 0ae70dc34bd2d324db947f569a654f2f020c7219..a4bd8f52d774d40bc487aaf6b57b6c9c1547cdf8 100644 (file)
           settings for network interfaces. These commands may be used to inform
           <command>systemd-resolved</command> or <command>systemd-networkd</command> about per-interface DNS
           configuration determined through external means. The <command>dns</command> command expects IPv4 or
-          IPv6 address specifications of DNS servers to use. The <command>domain</command> command expects
-          valid DNS domains, possibly prefixed with <literal>~</literal>, and configures a per-interface
-          search or route-only domain. The <command>default-route</command> command expects a boolean
-          parameter, and configures whether the link may be used as default route for DNS lookups, i.e. if it
-          is suitable for lookups on domains no other link explicitly is configured for. The
-          <command>llmnr</command>, <command>mdns</command>, <command>dnssec</command> and
-          <command>dnsovertls</command> commands may be used to configure the per-interface LLMNR,
-          MulticastDNS, DNSSEC and DNSOverTLS settings. Finally, <command>nta</command> command may be used
-          to configure additional per-interface DNSSEC NTA domains.</para>
+          IPv6 address specifications of DNS servers to use. Each address can optionally take a port number
+          separated with <literal>:</literal>, a network interface name or index separated with
+          <literal>%</literal>, and a Server Name Indication (SNI) separated with <literal>#</literal>. When
+          IPv6 address is specified with a port number, then the address must be in the square brackets. That
+          is, the acceptable full formats are <literal>111.222.333.444:9953%ifname#example.com</literal> for
+          IPv4 and <literal>[1111:2222::3333]:9953%ifname#example.com</literal> for IPv6. The
+          <command>domain</command> command expects valid DNS domains, possibly prefixed with
+          <literal>~</literal>, and configures a per-interface search or route-only domain. The
+          <command>default-route</command> command expects a boolean parameter, and configures whether the
+          link may be used as default route for DNS lookups, i.e. if it is suitable for lookups on domains no
+          other link explicitly is configured for. The <command>llmnr</command>, <command>mdns</command>,
+          <command>dnssec</command> and <command>dnsovertls</command> commands may be used to configure the
+          per-interface LLMNR, MulticastDNS, DNSSEC and DNSOverTLS settings. Finally, <command>nta</command>
+          command may be used to configure additional per-interface DNSSEC NTA domains.</para>
 
           <para>Commands <command>dns</command>, <command>domain</command> and <command>nta</command> can take
           a single empty string argument to clear their respective value lists.</para>
index 0e7a9f4bc664cd8eceaa10ab674faa469e013b74..535a23f500a12853fe081b744a31c4846ad7c159 100644 (file)
 
       <varlistentry>
         <term><varname>DNS=</varname></term>
-        <listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. DNS requests
-        are sent to one of the listed DNS servers in parallel to suitable per-link DNS servers acquired from
+        <listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. Each address can
+        optionally take a port number separated with <literal>:</literal>, a network interface name or index separated with
+        <literal>%</literal>, and a Server Name Indication (SNI) separated with <literal>#</literal>. When IPv6 address is
+        specified with a port number, then the address must be in the square brackets. That is, the acceptable full formats
+        are <literal>111.222.333.444:9953%ifname#example.com</literal> for IPv4 and
+        <literal>[1111:2222::3333]:9953%ifname#example.com</literal> for IPv6. DNS requests are sent to one of the listed
+        DNS servers in parallel to suitable per-link DNS servers acquired from
         <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> or
         set at runtime by external applications.  For compatibility reasons, if this setting is not specified, the DNS
         servers listed in <filename>/etc/resolv.conf</filename> are used instead, if that file exists and any servers
@@ -57,8 +62,8 @@
 
       <varlistentry>
         <term><varname>FallbackDNS=</varname></term>
-        <listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Any
-        per-link DNS servers obtained from
+        <listitem><para>A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Please see
+        <varname>DNS=</varname> for acceptable format of adddresses. Any per-link DNS servers obtained from
         <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
         take precedence over this setting, as do any servers set via <varname>DNS=</varname> above or
         <filename>/etc/resolv.conf</filename>. This setting is hence only used if no other DNS server information is
index 0345936fce0a2cbce2ed69a639f7432ab85cb174..ea93efd3f0153f6147455435f94e521ed8bf28cc 100644 (file)
@@ -3,7 +3,7 @@
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
-<refentry id="systemd-initctl.service">
+<refentry id="systemd-initctl.service" conditional='HAVE_SYSV_COMPAT'>
 
   <refentryinfo>
     <title>systemd-initctl.service</title>
index 0f7aaab624f19eb3d351db5d1ce350aa2896cce1..a7c50f382f0fe8a538259ad434a99de081aeefd1 100644 (file)
       <varlistentry>
         <term><option>--cert=</option></term>
 
-        <listitem><para>Specify the path to a file containing a server
-        certificate in PEM format. This option switches
-        <command>systemd-journal-gatewayd</command> into HTTPS mode
-        and must be used together with
+        <listitem><para>Specify the path to a file or <constant>AF_UNIX</constant> stream socket to read the
+        server certificate from. The certificate must be in PEM format. This option switches
+        <command>systemd-journal-gatewayd</command> into HTTPS mode and must be used together with
         <option>--key=</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--key=</option></term>
 
-        <listitem><para>Specify the path to a file containing a server
-        key in PEM format corresponding to the certificate specified
-        with <option>--cert=</option>.</para></listitem>
+        <listitem><para>Specify the path to a file or <constant>AF_UNIX</constant> stream socket to read the
+        server key corresponding to the certificate specified with <option>--cert=</option> from. The key
+        must be in PEM format.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--trust=</option></term>
 
-        <listitem><para>Specify the path to a file containing a
-        CA certificate in PEM format.</para></listitem>
+        <listitem><para>Specify the path to a file or <constant>AF_UNIX</constant> stream socket to read a CA
+        certificate from. The certificate must be in PEM format.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index b28092d18c324044792ad4820ed3bee9f848c9e5..1db0128f746d780315e425096ca51bc91f7c9f0f 100644 (file)
       <varlistentry>
         <term><option>--key=</option></term>
 
-        <listitem><para>
-          Takes a path to a SSL key file in PEM format.
-          Defaults to <filename>&CERTIFICATE_ROOT;/private/journal-remote.pem</filename>.
-          This option can be used with <option>--listen-https=</option>.
-        </para></listitem>
+        <listitem><para> Takes a path to a SSL key file in PEM format. Defaults to
+        <filename>&CERTIFICATE_ROOT;/private/journal-remote.pem</filename>. This option can be used with
+        <option>--listen-https=</option>. If the path refers to an <constant>AF_UNIX</constant> stream socket
+        in the file system a connection is made to it and the key read from it.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--cert=</option></term>
 
-        <listitem><para>
-          Takes a path to a SSL certificate file in PEM format.
-          Defaults to <filename>&CERTIFICATE_ROOT;/certs/journal-remote.pem</filename>.
-          This option can be used with <option>--listen-https=</option>.
-        </para></listitem>
+        <listitem><para> Takes a path to a SSL certificate file in PEM format. Defaults to
+        <filename>&CERTIFICATE_ROOT;/certs/journal-remote.pem</filename>. This option can be used with
+        <option>--listen-https=</option>. If the path refers to an <constant>AF_UNIX</constant> stream socket
+        in the file system a connection is made to it and the certificate read from it.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--trust=</option></term>
 
-        <listitem><para>
-          Takes a path to a SSL CA certificate file in PEM format,
-          or <option>all</option>. If <option>all</option> is set,
-          then certificate checking will be disabled.
-          Defaults to <filename>&CERTIFICATE_ROOT;/ca/trusted.pem</filename>.
-          This option can be used with <option>--listen-https=</option>.
-        </para></listitem>
+        <listitem><para> Takes a path to a SSL CA certificate file in PEM format, or <option>all</option>. If
+        <option>all</option> is set, then certificate checking will be disabled. Defaults to
+        <filename>&CERTIFICATE_ROOT;/ca/trusted.pem</filename>. This option can be used with
+        <option>--listen-https=</option>. If the path refers to an <constant>AF_UNIX</constant> stream socket
+        in the file system a connection is made to it and the certificate read from it.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 5516f63b6583d61b5c1332850c495ec210be1bbb..c2957fd18232053c616585b4bd711ea2c31892e5 100644 (file)
       <varlistentry>
         <term><varname>KeyFile=</varname></term>
         <listitem>
-          <para>Takes a absolute path to a file which contains a 128-bit key encoded in a hexadecimal
-          string, which will be used in the transmission channel. When this option is specified,
+          <para>Takes a absolute path to a file which contains a 128-bit key encoded in a hexadecimal string,
+          which will be used in the transmission channel. When this option is specified,
           <varname>Key=</varname> is ignored. Note that the file must be readable by the user
           <literal>systemd-network</literal>, so it should be, e.g., owned by
-          <literal>root:systemd-network</literal> with a <literal>0640</literal> file mode.</para>
+          <literal>root:systemd-network</literal> with a <literal>0640</literal> file mode. If the path
+          refers to an <constant>AF_UNIX</constant> stream socket in the file system a connection is made to
+          it and the key read from it.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
       <varlistentry>
         <term><varname>PrivateKeyFile=</varname></term>
         <listitem>
-          <para>Takes an absolute path to a file which contains the Base64 encoded private key for the interface.
-          When this option is specified, then <varname>PrivateKey=</varname> is ignored.
-          Note that the file must be readable by the user <literal>systemd-network</literal>, so it
-          should be, e.g., owned by <literal>root:systemd-network</literal> with a
-          <literal>0640</literal> file mode.</para>
+          <para>Takes an absolute path to a file which contains the Base64 encoded private key for the
+          interface.  When this option is specified, then <varname>PrivateKey=</varname> is ignored.  Note
+          that the file must be readable by the user <literal>systemd-network</literal>, so it should be,
+          e.g., owned by <literal>root:systemd-network</literal> with a <literal>0640</literal> file mode. If
+          the path refers to an <constant>AF_UNIX</constant> stream socket in the file system a connection is
+          made to it and the key read from it.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>PresharedKeyFile=</varname></term>
         <listitem>
           <para>Takes an absolute path to a file which contains the Base64 encoded preshared key for the
-          peer. When this option is specified, then <varname>PresharedKey=</varname> is ignored.
-          Note that the file must be readable by the user <literal>systemd-network</literal>, so it
-          should be, e.g., owned by <literal>root:systemd-network</literal> with a
-          <literal>0640</literal> file mode.</para>
+          peer. When this option is specified, then <varname>PresharedKey=</varname> is ignored.  Note that
+          the file must be readable by the user <literal>systemd-network</literal>, so it should be, e.g.,
+          owned by <literal>root:systemd-network</literal> with a <literal>0640</literal> file mode. If the
+          path refers to an <constant>AF_UNIX</constant> stream socket in the file system a connection is
+          made to it and the key read from it.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
index 58d1f2c717f8136c62a8b8cb9717870286832636..0b0c751e91322aea966246f1a0e96efe48da1a28 100644 (file)
             <para>A DNS server address, which must be in the format
             described in
             <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-            This option may be specified more than once. This setting is read by
+            This option may be specified more than once. Each address can optionally take a port number
+            separated with <literal>:</literal>, a network interface name or index separated with
+            <literal>%</literal>, and a Server Name Indication (SNI) separated with <literal>#</literal>.
+            When IPv6 address is specified with a port number, then the address must be in the square
+            brackets. That is, the acceptable full formats are
+            <literal>111.222.333.444:9953%ifname#example.com</literal> for IPv4 and
+            <literal>[1111:2222::3333]:9953%ifname#example.com</literal> for IPv6. This setting can be
+            specified multiple times. If an empty string is assigned, then the all previous assignments
+            are cleared. This setting is read by
             <citerefentry><refentrytitle>systemd-resolved.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
           </listitem>
         </varlistentry>
index 0c012b69fe1f81ac15fa1058be8378eba809f308..020a7e55ce8f8be16806978a410a50d153760219 100644 (file)
@@ -3080,7 +3080,7 @@ executable(
         link_with : [libshared],
         dependencies : [libaudit],
         install_rpath : rootlibexecdir,
-        install : true,
+        install : (conf.get('ENABLE_UTMP') == 1),
         install_dir : rootlibexecdir)
 
 if conf.get('HAVE_KMOD') == 1
diff --git a/mkosi.default b/mkosi.default
deleted file mode 120000 (symlink)
index 2718c9e..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.mkosi/mkosi.fedora
\ No newline at end of file
index e42f7ff935ad41feb14260cf763828e5681df229..9d64e3c76cddf8829caac1f4b4d8bc4dc60f451e 100644 (file)
@@ -627,7 +627,7 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, &use_full_bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         n = acquire_boot_times(bus, &boot);
         if (n < 0)
@@ -1026,7 +1026,7 @@ static int analyze_critical_chain(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         n = acquire_time_data(bus, &times);
         if (n <= 0)
@@ -1069,7 +1069,7 @@ static int analyze_blame(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         n = acquire_time_data(bus, &times);
         if (n <= 0)
@@ -1126,7 +1126,7 @@ static int analyze_time(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         r = pretty_boot_time(bus, &buf);
         if (r < 0)
@@ -1264,7 +1264,7 @@ static int dot(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         r = expand_patterns(bus, strv_skip(argv, 1), &expanded_patterns);
         if (r < 0)
@@ -1341,7 +1341,7 @@ static int dump(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         (void) pager_open(arg_pager_flags);
 
@@ -1412,7 +1412,7 @@ static int set_log_level(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         r = bus_set_property(bus, bus_systemd_mgr, "LogLevel", &error, "s", argv[1]);
         if (r < 0)
@@ -1429,7 +1429,7 @@ static int get_log_level(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         r = bus_get_property_string(bus, bus_systemd_mgr, "LogLevel", &error, &level);
         if (r < 0)
@@ -1453,7 +1453,7 @@ static int set_log_target(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         r = bus_set_property(bus, bus_systemd_mgr, "LogTarget", &error, "s", argv[1]);
         if (r < 0)
@@ -1470,7 +1470,7 @@ static int get_log_target(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         r = bus_get_property_string(bus, bus_systemd_mgr, "LogTarget", &error, &target);
         if (r < 0)
@@ -2053,7 +2053,7 @@ static int service_watchdogs(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         if (argc == 1) {
                 /* get ServiceWatchdogs */
@@ -2091,7 +2091,7 @@ static int do_security(int argc, char *argv[], void *userdata) {
 
         r = acquire_bus(&bus, NULL);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         (void) pager_open(arg_pager_flags);
 
index f2f1e1139f7adfd0122b344834285f8d3231b389..c3d55d209ac7ede12ceaa70b943023fdb73ddaa0 100644 (file)
@@ -22,6 +22,7 @@
 #include "mkdir.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "socket-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 #include "tmpfile-util.h"
@@ -482,13 +483,12 @@ int read_full_stream_full(
         assert(f);
         assert(ret_contents);
         assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
-        assert(!(flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) || ret_size);
 
         n_next = LINE_MAX; /* Start size */
 
         fd = fileno(f);
-        if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
-                        * optimize our buffering) */
+        if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's
+                        * optimize our buffering */
 
                 if (fstat(fd, &st) < 0)
                         return -errno;
@@ -505,7 +505,7 @@ int read_full_stream_full(
                         if (st.st_size > 0)
                                 n_next = st.st_size + 1;
 
-                        if (flags & READ_FULL_FILE_SECURE)
+                        if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
                                 (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
                 }
         }
@@ -535,21 +535,18 @@ int read_full_stream_full(
 
                 errno = 0;
                 k = fread(buf + l, 1, n - l, f);
-                if (k > 0)
-                        l += k;
+
+                assert(k <= n - l);
+                l += k;
 
                 if (ferror(f)) {
                         r = errno_or_else(EIO);
                         goto finalize;
                 }
-
                 if (feof(f))
                         break;
 
-                /* We aren't expecting fread() to return a short read outside
-                 * of (error && eof), assert buffer is full and enlarge buffer.
-                 */
-                assert(l == n);
+                assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
 
                 /* Safety check */
                 if (n >= READ_FULL_BYTES_MAX) {
@@ -561,12 +558,21 @@ int read_full_stream_full(
         }
 
         if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) {
+                _cleanup_free_ void *decoded = NULL;
+                size_t decoded_size;
+
                 buf[l++] = 0;
                 if (flags & READ_FULL_FILE_UNBASE64)
-                        r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
+                        r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
                 else
-                        r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
-                goto finalize;
+                        r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size);
+                if (r < 0)
+                        goto finalize;
+
+                if (flags & READ_FULL_FILE_SECURE)
+                        explicit_bzero_safe(buf, n);
+                free_and_replace(buf, decoded);
+                n = l = decoded_size;
         }
 
         if (!ret_size) {
@@ -603,8 +609,54 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag
         assert(contents);
 
         r = xfopenat(dir_fd, filename, "re", 0, &f);
-        if (r < 0)
-                return r;
+        if (r < 0) {
+                _cleanup_close_ int dfd = -1, sk = -1;
+                union sockaddr_union sa;
+
+                /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */
+                if (r != -ENXIO)
+                        return r;
+
+                /* If this is enabled, let's try to connect to it */
+                if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
+                        return -ENXIO;
+
+                if (dir_fd == AT_FDCWD)
+                        r = sockaddr_un_set_path(&sa.un, filename);
+                else {
+                        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+
+                        /* If we shall operate relative to some directory, then let's use O_PATH first to
+                         * open the socket inode, and then connect to it via /proc/self/fd/. We have to do
+                         * this since there's not connectat() that takes a directory fd as first arg. */
+
+                        dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC);
+                        if (dfd < 0)
+                                return -errno;
+
+                        xsprintf(procfs_path, "/proc/self/fd/%i", dfd);
+                        r = sockaddr_un_set_path(&sa.un, procfs_path);
+                }
+                if (r < 0)
+                        return r;
+
+                sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+                if (sk < 0)
+                        return -errno;
+
+                if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
+                        return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is
+                                                                     * not a socket after all */
+
+                if (shutdown(sk, SHUT_WR) < 0)
+                        return -errno;
+
+                f = fdopen(sk, "r");
+                if (!f)
+                        return -errno;
+
+                TAKE_FD(sk);
+        }
 
         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
 
index e2830b7963eb0902c2af2865d494e75d2782bef4..7d58fa7cfc24d51033edb97a3f7a4fec6d6aa5f1 100644 (file)
@@ -32,9 +32,11 @@ typedef enum {
 } WriteStringFileFlags;
 
 typedef enum {
-        READ_FULL_FILE_SECURE   = 1 << 0,
-        READ_FULL_FILE_UNBASE64 = 1 << 1,
-        READ_FULL_FILE_UNHEX    = 1 << 2,
+        READ_FULL_FILE_SECURE              = 1 << 0, /* erase any buffers we employ internally, after use */
+        READ_FULL_FILE_UNBASE64            = 1 << 1, /* base64 decode what we read */
+        READ_FULL_FILE_UNHEX               = 1 << 2, /* hex decode what we read */
+        READ_FULL_FILE_WARN_WORLD_READABLE = 1 << 3, /* if regular file, log at LOG_WARNING level if access mode above 0700 */
+        READ_FULL_FILE_CONNECT_SOCKET      = 1 << 4, /* if socket inode, connect to it and read off it */
 } ReadFullFileFlags;
 
 int fopen_unlocked(const char *path, const char *options, FILE **ret);
index 9feee663439acdeb325b63c2a65c8df81775bc86..828ea11816625e3cc298c03ead641682fb8cfd63 100644 (file)
@@ -14,6 +14,7 @@
 #include "macro.h"
 #include "parse-util.h"
 #include "random-util.h"
+#include "string-util.h"
 #include "strxcpyx.h"
 #include "util.h"
 
@@ -445,6 +446,61 @@ fallback:
         return in_addr_to_string(family, u, ret);
 }
 
+int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) {
+        _cleanup_free_ char *ip_str = NULL, *x = NULL;
+        int r;
+
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(u);
+        assert(ret);
+
+        /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
+         * handle IPv6 link-local addresses. */
+
+        r = in_addr_to_string(family, u, &ip_str);
+        if (r < 0)
+                return r;
+
+        if (family == AF_INET6) {
+                r = in_addr_is_link_local(family, u);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        ifindex = 0;
+        } else
+                ifindex = 0; /* For IPv4 address, ifindex is always ignored. */
+
+        if (port == 0 && ifindex == 0 && isempty(server_name)) {
+                *ret = TAKE_PTR(ip_str);
+                return 0;
+        }
+
+        const char *separator = isempty(server_name) ? "" : "#";
+        server_name = strempty(server_name);
+
+        if (port > 0) {
+                if (family == AF_INET6) {
+                        if (ifindex > 0)
+                                r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name);
+                        else
+                                r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name);
+                } else
+                        r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name);
+        } else {
+                if (ifindex > 0)
+                        r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name);
+                else {
+                        x = strjoin(ip_str, separator, server_name);
+                        r = x ? 0 : -ENOMEM;
+                }
+        }
+        if (r < 0)
+                return -ENOMEM;
+
+        *ret = TAKE_PTR(x);
+        return 0;
+}
+
 int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
         union in_addr_union buffer;
         assert(s);
index 90d79a5ef5089431a4c4892b0af077d26e04e163..dc3f575bc977dfd0195a38f43722c5f0b22b56d5 100644 (file)
@@ -41,6 +41,7 @@ int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen
 int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
 int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
 int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
+int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret);
 int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
 int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
 
index 66f8856fdfdfb50f24beb61fa787767ff6d0b625..8115065b5eca119a8515a776cb27428ee9d76b18 100644 (file)
@@ -290,7 +290,7 @@ int get_user_creds(
                     (empty_or_root(p->pw_dir) ||
                      !path_is_valid(p->pw_dir) ||
                      !path_is_absolute(p->pw_dir)))
-                    *home = NULL; /* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */
+                        *home = NULL; /* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */
                 else
                         *home = p->pw_dir;
         }
index 939a391e21cc85edcf17031101ea81aa0da3465a..e09adb8b5b1f875c71ff1d9c403b035dbfd5c2cb 100644 (file)
@@ -197,7 +197,7 @@ static int run(int argc, char *argv[]) {
                                                                           arg_show_unit == SHOW_UNIT_USER,
                                                                           &bus);
                                         if (r < 0)
-                                                return log_error_errno(r, "Failed to create bus connection: %m");
+                                                return bus_log_connect_error(r);
                                 }
 
                                 q = show_cgroup_get_unit_path_and_warn(bus, *name, &cgroup);
index 1a41f260499e4b2641229fe9903cac621f99d951..8b052dac26cb9636993a2816aa0507d588c08758 100644 (file)
@@ -177,38 +177,18 @@ static uint64_t storage_size_max(void) {
 static int fix_acl(int fd, uid_t uid) {
 
 #if HAVE_ACL
-        _cleanup_(acl_freep) acl_t acl = NULL;
-        acl_entry_t entry;
-        acl_permset_t permset;
         int r;
 
         assert(fd >= 0);
+        assert(uid_is_valid(uid));
 
         if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
                 return 0;
 
-        /* Make sure normal users can read (but not write or delete)
-         * their own coredumps */
-
-        acl = acl_get_fd(fd);
-        if (!acl)
-                return log_error_errno(errno, "Failed to get ACL: %m");
-
-        if (acl_create_entry(&acl, &entry) < 0 ||
-            acl_set_tag_type(entry, ACL_USER) < 0 ||
-            acl_set_qualifier(entry, &uid) < 0)
-                return log_error_errno(errno, "Failed to patch ACL: %m");
-
-        if (acl_get_permset(entry, &permset) < 0 ||
-            acl_add_perm(permset, ACL_READ) < 0)
-                return log_warning_errno(errno, "Failed to patch ACL: %m");
-
-        r = calc_acl_mask_if_needed(&acl);
+        /* Make sure normal users can read (but not write or delete) their own coredumps */
+        r = add_acls_for_user(fd, uid);
         if (r < 0)
-                return log_warning_errno(r, "Failed to patch ACL: %m");
-
-        if (acl_set_fd(fd, acl) < 0)
-                return log_error_errno(errno, "Failed to apply ACL: %m");
+                return log_error_errno(r, "Failed to adjust ACL of coredump: %m");
 #endif
 
         return 0;
index 348d2b0429ed0d9f7410c488050712cc7eb34c07..2d6b2da125e3128124a305222f23ee3913270fd6 100644 (file)
@@ -444,7 +444,7 @@ static int run(int argc, char *argv[]) {
 
         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         return hostnamectl_main(bus, argc, argv);
 }
index 2f27dda76b29bf909ac1b5fce25a8c7ade9a2b00..ca96f073b136261946a967f0c23d5c9466a11e2e 100644 (file)
@@ -79,6 +79,17 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
         if (r < 0)
                 return r;
         if (r == 0) {
+                const char *cmdline[] = {
+                       "tar",
+                       "--numeric-owner",
+                       "-C", path,
+                       "-px",
+                       "--xattrs",
+                       "--xattrs-include=*",
+                       use_selinux ? "--selinux" : "--no-selinux",
+                       NULL
+                };
+
                 uint64_t retain =
                         (1ULL << CAP_CHOWN) |
                         (1ULL << CAP_FOWNER) |
@@ -104,8 +115,15 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
                 if (r < 0)
                         log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
 
-                execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*",
-                       use_selinux ? "--selinux" : "--no-selinux", NULL);
+                /* Try "gtar" before "tar". We only test things upstream with GNU tar. Some distros appear to
+                 * install a different implementation as "tar" (in particular some that do not support the
+                 * same command line switches), but then provide "gtar" as alias for the real thing, hence
+                 * let's prefer that. (Yes, it's a bad idea they do that, given they don't provide equivalent
+                 * command line support, but we are not here to argue, let's just expose the same
+                 * behaviour/implementation everywhere.) */
+                execvp("gtar", (char* const*) cmdline);
+                execvp("tar", (char* const*) cmdline);
+
                 log_error_errno(errno, "Failed to execute tar: %m");
                 _exit(EXIT_FAILURE);
         }
@@ -133,6 +151,17 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
         if (r < 0)
                 return r;
         if (r == 0) {
+                const char *cmdline[] = {
+                        "tar",
+                        "-C", path,
+                        "-c",
+                        "--xattrs",
+                        "--xattrs-include=*",
+                       use_selinux ? "--selinux" : "--no-selinux",
+                        ".",
+                        NULL
+                };
+
                 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
 
                 /* Child */
@@ -152,8 +181,9 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
                 if (r < 0)
                         log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
 
-                execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*",
-                       use_selinux ? "--selinux" : "--no-selinux", ".", NULL);
+                execvp("gtar", (char* const*) cmdline);
+                execvp("tar", (char* const*) cmdline);
+
                 log_error_errno(errno, "Failed to execute tar: %m");
                 _exit(EXIT_FAILURE);
         }
index 3ab7c98b0b55ed95a0ae95056fb54a13375e59d6..48106d1bdbb75e08fd996ee8dac0c5d82eb21dda 100644 (file)
@@ -906,7 +906,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (arg_key_pem)
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Key file specified twice");
-                        r = read_full_file(optarg, &arg_key_pem, NULL);
+                        r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, &arg_key_pem, NULL);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to read key file: %m");
                         assert(arg_key_pem);
@@ -916,7 +916,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (arg_cert_pem)
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "Certificate file specified twice");
-                        r = read_full_file(optarg, &arg_cert_pem, NULL);
+                        r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, &arg_cert_pem, NULL);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to read certificate file: %m");
                         assert(arg_cert_pem);
@@ -927,7 +927,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (arg_trust_pem)
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "CA certificate file specified twice");
-                        r = read_full_file(optarg, &arg_trust_pem, NULL);
+                        r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, &arg_trust_pem, NULL);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to read CA certificate file: %m");
                         assert(arg_trust_pem);
index 273fdf9196ec0417e77e4ed7c0fed3ec9c3636cd..77dfdefd64cb2578cf92d0448b237701772cadd9 100644 (file)
@@ -1077,12 +1077,12 @@ static int parse_argv(int argc, char *argv[]) {
 static int load_certificates(char **key, char **cert, char **trust) {
         int r;
 
-        r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
+        r = read_full_file_full(AT_FDCWD, arg_key ?: PRIV_KEY_FILE, READ_FULL_FILE_CONNECT_SOCKET, key, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to read key from file '%s': %m",
                                        arg_key ?: PRIV_KEY_FILE);
 
-        r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
+        r = read_full_file_full(AT_FDCWD, arg_cert ?: CERT_FILE, READ_FULL_FILE_CONNECT_SOCKET, cert, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
                                        arg_cert ?: CERT_FILE);
@@ -1090,7 +1090,7 @@ static int load_certificates(char **key, char **cert, char **trust) {
         if (arg_trust_all)
                 log_info("Certificate checking disabled.");
         else {
-                r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
+                r = read_full_file_full(AT_FDCWD, arg_trust ?: TRUST_FILE, READ_FULL_FILE_CONNECT_SOCKET, trust, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
                                                arg_trust ?: TRUST_FILE);
index cc5c0223b5cee459785ec68f94e1176e3747a3b0..7383c84724a06a9abe183e563b65a871acd2c702 100644 (file)
@@ -77,6 +77,12 @@ _public_ sd_event *sd_radv_get_event(sd_radv *ra) {
         return ra->event;
 }
 
+_public_ int sd_radv_is_running(sd_radv *ra) {
+        assert_return(ra, false);
+
+        return ra->state != SD_RADV_STATE_IDLE;
+}
+
 static void radv_reset(sd_radv *ra) {
         assert(ra);
 
index 7387cffaa3a06adff5a2d866e8f4aee08194a983..f045e794b6e7d8de2cf108f545dcc3da77a5afa8 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "sd-netlink.h"
 
+#include "format-util.h"
 #include "memory-util.h"
 #include "netlink-internal.h"
 #include "netlink-util.h"
@@ -9,6 +10,8 @@
 
 int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
+        _cleanup_strv_free_ char **alternative_names = NULL;
+        char old_name[IF_NAMESIZE + 1] = {};
         int r;
 
         assert(rtnl);
@@ -18,10 +21,18 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
         if (!ifname_valid(name))
                 return -EINVAL;
 
-        if (!*rtnl) {
-                r = sd_netlink_open(rtnl);
+        r = rtnl_get_link_alternative_names(rtnl, ifindex, &alternative_names);
+        if (r < 0)
+                log_debug_errno(r, "Failed to get alternative names on network interface %i, ignoring: %m",
+                                ifindex);
+
+        if (strv_contains(alternative_names, name)) {
+                r = rtnl_delete_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
                 if (r < 0)
-                        return r;
+                        return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
+                                               name, ifindex);
+
+                format_ifname(ifindex, old_name);
         }
 
         r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
@@ -36,6 +47,13 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
         if (r < 0)
                 return r;
 
+        if (!isempty(old_name)) {
+                r = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(old_name));
+                if (r < 0)
+                        log_debug_errno(r, "Failed to set '%s' as an alternative name on network interface %i, ignoring: %m",
+                                        old_name, ifindex);
+        }
+
         return 0;
 }
 
@@ -85,12 +103,45 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias,
         return 0;
 }
 
-int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names) {
+int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+        _cleanup_strv_free_ char **names = NULL;
+        int r;
+
+        assert(rtnl);
+        assert(ifindex > 0);
+        assert(ret);
+
+        if (!*rtnl) {
+                r = sd_netlink_open(rtnl);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_call(*rtnl, message, 0, &reply);
+        if (r < 0)
+                return r;
+
+        r = sd_netlink_message_read_strv(reply, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &names);
+        if (r < 0 && r != -ENODATA)
+                return r;
+
+        *ret = TAKE_PTR(names);
+
+        return 0;
+}
+
+static int rtnl_update_link_alternative_names(sd_netlink **rtnl, uint16_t nlmsg_type, int ifindex, char * const *alternative_names) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
         int r;
 
         assert(rtnl);
         assert(ifindex > 0);
+        assert(IN_SET(nlmsg_type, RTM_NEWLINKPROP, RTM_DELLINKPROP));
 
         if (strv_isempty(alternative_names))
                 return 0;
@@ -101,7 +152,7 @@ int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const
                         return r;
         }
 
-        r = sd_rtnl_message_new_link(*rtnl, &message, RTM_NEWLINKPROP, ifindex);
+        r = sd_rtnl_message_new_link(*rtnl, &message, nlmsg_type, ifindex);
         if (r < 0)
                 return r;
 
@@ -124,6 +175,14 @@ int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const
         return 0;
 }
 
+int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names) {
+        return rtnl_update_link_alternative_names(rtnl, RTM_NEWLINKPROP, ifindex, alternative_names);
+}
+
+int rtnl_delete_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names) {
+        return rtnl_update_link_alternative_names(rtnl, RTM_DELLINKPROP, ifindex, alternative_names);
+}
+
 int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char * const *alternative_names) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
         int r;
@@ -236,10 +295,10 @@ int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t seria
         if (r < 0)
                 return r;
 
+        rtnl_message_seal(*ret);
         (*ret)->hdr->nlmsg_seq = serial;
 
         err = NLMSG_DATA((*ret)->hdr);
-
         err->error = error;
 
         return 0;
index 8ed94063e3d5a775c6240eb3730563c529c02893..04e6a98e6b5ca32da1ebc16304fdcebb815fef27 100644 (file)
@@ -53,8 +53,10 @@ static inline bool rtnl_message_type_is_tclass(uint16_t type) {
 
 int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
 int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, uint32_t mtu);
+int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret);
 int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names);
 int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char * const *alternative_names);
+int rtnl_delete_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names);
 int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name);
 int rtnl_get_link_iftype(sd_netlink **rtnl, int ifindex, unsigned short *ret);
 
index 251901c3919f2221fcf4e69ac4e18ca9883365b3..e0664de826bb0973f2fe197188b6f9fe75f8f0b5 100644 (file)
@@ -511,7 +511,7 @@ static int run(int argc, char *argv[]) {
 
         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         return localectl_main(bus, argc, argv);
 }
index 2b48a9acb792c52e079e1d83ddd1b9ea5c7434d8..4297a510082a35a17e3fbca2f2defb86a6c97e25 100644 (file)
@@ -1475,7 +1475,7 @@ static int run(int argc, char *argv[]) {
 
         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
 
index 1b6304b57f54ef93bb48d7b59327ec34dde65415..75a48300adbcb212af606620405a183fe14c36d3 100644 (file)
@@ -2855,14 +2855,14 @@ static int method_set_reboot_to_boot_loader_menu(
                         return r;
         } else {
                 if (x == UINT64_MAX) {
-                        if (unlink("/run/systemd/reboot-to-loader-menu") < 0 && errno != ENOENT)
+                        if (unlink("/run/systemd/reboot-to-boot-loader-menu") < 0 && errno != ENOENT)
                                 return -errno;
                 } else {
                         char buf[DECIMAL_STR_MAX(uint64_t) + 1];
 
                         xsprintf(buf, "%" PRIu64, x); /* Âµs granularity */
 
-                        r = write_string_file_atomic_label("/run/systemd/reboot-to-loader-menu", buf);
+                        r = write_string_file_atomic_label("/run/systemd/reboot-to-boot-loader-menu", buf);
                         if (r < 0)
                                 return r;
                 }
index 26fa48d870c1dacb73ba915ccf988d2ee74831f0..841eeae8827b476cd564b71f747fe252efa3919e 100644 (file)
@@ -2897,7 +2897,7 @@ static int run(int argc, char *argv[]) {
 
         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
 
index f5873d1c06218dcacab53810ce7534603727796e..22da189684fb3e45d716f04baa326330129623ae 100644 (file)
@@ -1456,7 +1456,7 @@ static int run(int argc, char* argv[]) {
 
         r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         if (arg_action == ACTION_UMOUNT)
                 return action_umount(bus, argc, argv);
index 57d8f567b9650e9201875725b61da0770d7265bc..2ffa5ec8c695a32c5ee2072d48389f3f7d95460c 100644 (file)
@@ -983,7 +983,10 @@ static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) {
 
         (void) warn_file_is_world_accessible(sa->key_file, NULL, NULL, 0);
 
-        r = read_full_file_full(AT_FDCWD, sa->key_file, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX, (char **) &key, &key_len);
+        r = read_full_file_full(
+                        AT_FDCWD, sa->key_file,
+                        READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
+                        (char **) &key, &key_len);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r,
                                               "Failed to read key from '%s', ignoring: %m",
index b6af9925b745fdca415bf7068bf5ae1eeefa1aa2..6812b07bff5e4b3d19162f8a3ff40c84f6be1676 100644 (file)
@@ -888,7 +888,10 @@ static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_
 
         (void) warn_file_is_world_accessible(filename, NULL, NULL, 0);
 
-        r = read_full_file_full(AT_FDCWD, filename, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64, &key, &key_len);
+        r = read_full_file_full(
+                        AT_FDCWD, filename,
+                        READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
+                        &key, &key_len);
         if (r < 0)
                 return r;
 
index a80a6185dabb1c96eebe332d9c16f9143ff7d46c..48182e61ddfe803003b1601ec0f8d9c6be991867 100644 (file)
@@ -380,7 +380,7 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns, b
                 return r;
 
         r = sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &altnames);
-        if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENODATA))
+        if (r < 0 && r != -ENODATA)
                 return r;
 
         if (patterns) {
@@ -1486,6 +1486,7 @@ static int link_status_one(
         if (r < 0)
                 return table_log_add_error(r);
 
+        strv_sort(info->alternative_names);
         r = dump_list(table, "Alternative Names:", info->alternative_names);
         if (r < 0)
                 return r;
index 6f1ee3b534970e416cdb60b558f89926ced3dcb0..2c36854588d09960a7bb1a3fcdaf051f8a831c2e 100644 (file)
@@ -431,6 +431,32 @@ int address_get(Link *link,
         return -ENOENT;
 }
 
+static bool address_exists_internal(Set *addresses, int family, const union in_addr_union *in_addr) {
+        Address *address;
+        Iterator i;
+
+        SET_FOREACH(address, addresses, i) {
+                if (address->family != family)
+                        continue;
+                if (in_addr_equal(address->family, &address->in_addr, in_addr))
+                        return true;
+        }
+
+        return false;
+}
+
+bool address_exists(Link *link, int family, const union in_addr_union *in_addr) {
+        assert(link);
+        assert(IN_SET(family, AF_INET, AF_INET6));
+        assert(in_addr);
+
+        if (address_exists_internal(link->addresses, family, in_addr))
+                return true;
+        if (address_exists_internal(link->addresses_foreign, family, in_addr))
+                return true;
+        return false;
+}
+
 static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
index bd0485e0abee59f54e197a33d050398b13116f8c..d55059ee252edfbddf65a0fad5bb56bef51fd5de 100644 (file)
@@ -57,6 +57,7 @@ void address_free(Address *address);
 int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
 int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
 int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+bool address_exists(Link *link, int family, const union in_addr_union *in_addr);
 int address_update(Address *address, unsigned char flags, unsigned char scope, const struct ifa_cacheinfo *cinfo);
 int address_drop(Address *address);
 int address_configure(Address *address, Link *link, link_netlink_message_handler_t callback, bool update);
index 265d9dbc79c40720de25567c711005e0130accbb..5129a2e37e2dbce77868bcf1ba184f2c3cc4e9dc 100644 (file)
@@ -61,10 +61,10 @@ static int link_push_uplink_to_dhcp_server(
                         struct in_addr ia;
 
                         /* Only look for IPv4 addresses */
-                        if (link->network->dns[i].family != AF_INET)
+                        if (link->network->dns[i]->family != AF_INET)
                                 continue;
 
-                        ia = link->network->dns[i].address.in;
+                        ia = link->network->dns[i]->address.in;
 
                         /* Never propagate obviously borked data */
                         if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia))
index 38b005fb63c9a9f80ba912bd75fa0f8fd3b02aec..be1967150533376db94fa21873b46dec2d1f1b3f 100644 (file)
@@ -7,6 +7,7 @@
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-get-properties.h"
+#include "bus-message-util.h"
 #include "bus-polkit.h"
 #include "dns-domain.h"
 #include "networkd-link-bus.h"
@@ -14,6 +15,7 @@
 #include "networkd-manager.h"
 #include "parse-util.h"
 #include "resolve-util.h"
+#include "socket-netlink.h"
 #include "strv.h"
 #include "user-util.h"
 
@@ -113,10 +115,10 @@ int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_
         return sd_bus_reply_method_return(message, NULL);
 }
 
-int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        _cleanup_free_ struct in_addr_data *dns = NULL;
-        size_t allocated = 0, n = 0;
+static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
+        struct in_addr_full **dns;
         Link *l = userdata;
+        size_t n;
         int r;
 
         assert(message);
@@ -126,52 +128,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
         if (r < 0)
                 return r;
 
-        r = sd_bus_message_enter_container(message, 'a', "(iay)");
-        if (r < 0)
-                return r;
-
-        for (;;) {
-                int family;
-                size_t sz;
-                const void *d;
-
-                assert_cc(sizeof(int) == sizeof(int32_t));
-
-                r = sd_bus_message_enter_container(message, 'r', "iay");
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                r = sd_bus_message_read(message, "i", &family);
-                if (r < 0)
-                        return r;
-
-                if (!IN_SET(family, AF_INET, AF_INET6))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
-
-                r = sd_bus_message_read_array(message, 'y', &d, &sz);
-                if (r < 0)
-                        return r;
-                if (sz != FAMILY_ADDRESS_SIZE(family))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
-
-                if (!dns_server_address_valid(family, d))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
-
-                r = sd_bus_message_exit_container(message);
-                if (r < 0)
-                        return r;
-
-                if (!GREEDY_REALLOC(dns, allocated, n+1))
-                        return -ENOMEM;
-
-                dns[n].family = family;
-                memcpy(&dns[n].address, d, sz);
-                n++;
-        }
-
-        r = sd_bus_message_exit_container(message);
+        r = bus_message_read_dns_servers(message, error, extended, &dns, &n);
         if (r < 0)
                 return r;
 
@@ -180,9 +137,15 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
                                     NULL, true, UID_INVALID,
                                     &l->manager->polkit_registry, error);
         if (r < 0)
-                return r;
-        if (r == 0)
-                return 1; /* Polkit will call us back */
+                goto finalize;
+        if (r == 0) {
+                r = 1; /* Polkit will call us back */
+                goto finalize;
+        }
+
+        if (l->n_dns != (unsigned) -1)
+                for (unsigned i = 0; i < l->n_dns; i++)
+                        in_addr_full_free(l->dns[i]);
 
         free_and_replace(l->dns, dns);
         l->n_dns = n;
@@ -190,6 +153,21 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
         (void) link_dirty(l);
 
         return sd_bus_reply_method_return(message, NULL);
+
+finalize:
+        for (size_t i = 0; i < n; i++)
+                in_addr_full_free(dns[i]);
+        free(dns);
+
+        return r;
+}
+
+int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_link_method_set_dns_servers_internal(message, userdata, error, false);
+}
+
+int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_link_method_set_dns_servers_internal(message, userdata, error, true);
 }
 
 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -670,6 +648,7 @@ const sd_bus_vtable link_vtable[] = {
 
         SD_BUS_METHOD("SetNTP", "as", NULL, bus_link_method_set_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetDNSEx", "a(iayqs)", NULL, bus_link_method_set_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetDefaultRoute", "b", NULL, bus_link_method_set_default_route, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),
index afe0197dbd7aaa3c67af7f9722ef5cf668b5ebde..94474f22fffbf1bd9a9cdac3bd1b942a003507b3 100644 (file)
@@ -21,6 +21,7 @@ int property_get_address_state(sd_bus *bus, const char *path, const char *interf
 
 int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error);
index 2184a326e13360e44806f940fb7b9c1dd4ef6583..1d73a3c34fe3ce0bde74cf40a67679240e72c66b 100644 (file)
@@ -666,6 +666,9 @@ void link_ntp_settings_clear(Link *link) {
 }
 
 void link_dns_settings_clear(Link *link) {
+        if (link->n_dns != (unsigned) -1)
+                for (unsigned i = 0; i < link->n_dns; i++)
+                        in_addr_full_free(link->dns[i]);
         link->dns = mfree(link->dns);
         link->n_dns = (unsigned) -1;
 
@@ -3932,78 +3935,114 @@ int link_update(Link *link, sd_netlink_message *m) {
         /* The kernel may broadcast NEWLINK messages without the MAC address
            set, simply ignore them. */
         r = sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
-        if (r >= 0) {
-                if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet,
-                           ETH_ALEN)) {
-
-                        memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet,
-                               ETH_ALEN);
-
-                        log_link_debug(link, "MAC address: "
-                                       "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
-                                       mac.ether_addr_octet[0],
-                                       mac.ether_addr_octet[1],
-                                       mac.ether_addr_octet[2],
-                                       mac.ether_addr_octet[3],
-                                       mac.ether_addr_octet[4],
-                                       mac.ether_addr_octet[5]);
-
-                        if (link->ipv4ll) {
-                                r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
+        if (r >= 0 && memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN) != 0) {
+
+                memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN);
+
+                log_link_debug(link, "Gained new MAC address: "
+                               "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+                               mac.ether_addr_octet[0],
+                               mac.ether_addr_octet[1],
+                               mac.ether_addr_octet[2],
+                               mac.ether_addr_octet[3],
+                               mac.ether_addr_octet[4],
+                               mac.ether_addr_octet[5]);
+
+                if (link->ipv4ll) {
+                        bool restart = sd_ipv4ll_is_running(link->ipv4ll) > 0;
+
+                        if (restart) {
+                                r = sd_ipv4ll_stop(link->ipv4ll);
                                 if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
+                                        return log_link_warning_errno(link, r, "Could not stop IPv4LL client: %m");
                         }
 
-                        if (link->dhcp_client) {
-                                r = sd_dhcp_client_set_mac(link->dhcp_client,
-                                                           (const uint8_t *) &link->mac,
-                                                           sizeof (link->mac),
-                                                           ARPHRD_ETHER);
+                        r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not update MAC address in IPv4LL client: %m");
+
+                        if (restart) {
+                                r = sd_ipv4ll_start(link->ipv4ll);
                                 if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
+                                        return log_link_warning_errno(link, r, "Could not restart IPv4LL client: %m");
+                        }
+                }
 
-                                r = dhcp4_set_client_identifier(link);
+                if (link->dhcp_client) {
+                        r = sd_dhcp_client_set_mac(link->dhcp_client,
+                                                   (const uint8_t *) &link->mac,
+                                                   sizeof (link->mac),
+                                                   ARPHRD_ETHER);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
+
+                        r = dhcp4_set_client_identifier(link);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not set DHCP client identifier: %m");
+                }
+
+                if (link->dhcp6_client) {
+                        const DUID* duid = link_get_duid(link);
+                        bool restart = sd_dhcp6_client_is_running(link->dhcp6_client) > 0;
+
+                        if (restart) {
+                                r = sd_dhcp6_client_stop(link->dhcp6_client);
                                 if (r < 0)
-                                        return r;
+                                        return log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
                         }
 
-                        if (link->dhcp6_client) {
-                                const DUID* duid = link_get_duid(link);
+                        r = sd_dhcp6_client_set_mac(link->dhcp6_client,
+                                                    (const uint8_t *) &link->mac,
+                                                    sizeof (link->mac),
+                                                    ARPHRD_ETHER);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
 
-                                r = sd_dhcp6_client_set_mac(link->dhcp6_client,
-                                                            (const uint8_t *) &link->mac,
-                                                            sizeof (link->mac),
-                                                            ARPHRD_ETHER);
+                        if (link->network->iaid_set) {
+                                r = sd_dhcp6_client_set_iaid(link->dhcp6_client, link->network->iaid);
                                 if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
-
-                                if (link->network->iaid_set) {
-                                        r = sd_dhcp6_client_set_iaid(link->dhcp6_client,
-                                                                     link->network->iaid);
-                                        if (r < 0)
-                                                return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
-                                }
-
-                                r = sd_dhcp6_client_set_duid(link->dhcp6_client,
-                                                             duid->type,
-                                                             duid->raw_data_len > 0 ? duid->raw_data : NULL,
-                                                             duid->raw_data_len);
+                                        return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
+                        }
+
+                        r = sd_dhcp6_client_set_duid(link->dhcp6_client,
+                                                     duid->type,
+                                                     duid->raw_data_len > 0 ? duid->raw_data : NULL,
+                                                     duid->raw_data_len);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m");
+
+                        if (restart) {
+                                r = sd_dhcp6_client_start(link->dhcp6_client);
                                 if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m");
+                                        return log_link_warning_errno(link, r, "Could not restart DHCPv6 client: %m");
                         }
+                }
+
+                if (link->radv) {
+                        bool restart = sd_radv_is_running(link->radv);
 
-                        if (link->radv) {
-                                r = sd_radv_set_mac(link->radv, &link->mac);
+                        if (restart) {
+                                r = sd_radv_stop(link->radv);
                                 if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not update MAC for Router Advertisement: %m");
+                                        return log_link_warning_errno(link, r, "Could not stop Router Advertisement: %m");
                         }
 
-                        if (link->ndisc) {
-                                r = sd_ndisc_set_mac(link->ndisc, &link->mac);
+                        r = sd_radv_set_mac(link->radv, &link->mac);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not update MAC for Router Advertisement: %m");
+
+                        if (restart) {
+                                r = sd_radv_start(link->radv);
                                 if (r < 0)
-                                        return log_link_warning_errno(link, r, "Could not update MAC for ndisc: %m");
+                                        return log_link_warning_errno(link, r, "Could not restart Router Advertisement: %m");
                         }
                 }
+
+                if (link->ndisc) {
+                        r = sd_ndisc_set_mac(link->ndisc, &link->mac);
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Could not update MAC for NDisc: %m");
+                }
         }
 
         old_master = link->master_ifindex;
@@ -4072,20 +4111,20 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
         fputc('\n', f);
 }
 
-static void link_save_dns(FILE *f, struct in_addr_data *dns, unsigned n_dns, bool *space) {
+static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
         for (unsigned j = 0; j < n_dns; j++) {
-                _cleanup_free_ char *b = NULL;
-                int r;
+                const char *str;
 
-                r = in_addr_to_string(dns[j].family, &dns[j].address, &b);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to format address, ignoring: %m");
+                if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
+                        continue;
+
+                str = in_addr_full_to_string(dns[j]);
+                if (!str)
                         continue;
-                }
 
                 if (*space)
                         fputc(' ', f);
-                fputs(b, f);
+                fputs(str, f);
                 *space = true;
         }
 }
@@ -4215,9 +4254,9 @@ int link_save(Link *link) {
                 fputs("DNS=", f);
                 space = false;
                 if (link->n_dns != (unsigned) -1)
-                        link_save_dns(f, link->dns, link->n_dns, &space);
+                        link_save_dns(link, f, link->dns, link->n_dns, &space);
                 else
-                        link_save_dns(f, link->network->dns, link->network->n_dns, &space);
+                        link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
 
                 serialize_addresses(f, NULL, &space,
                                     NULL,
@@ -4229,7 +4268,7 @@ int link_save(Link *link) {
                                     sd_dhcp6_lease_get_dns,
                                     NULL);
 
-                /* Make sure to flush out old entries before we use the NDISC data */
+                /* Make sure to flush out old entries before we use the NDisc data */
                 ndisc_vacuum(link);
 
                 if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) {
index fb12301fe6e5b2d2294174b61712adde1b3740df..e73697050307f26fb018ad40de59690bc7665698 100644 (file)
@@ -163,7 +163,7 @@ typedef struct Link {
         bool stats_updated;
 
         /* All kinds of DNS configuration the user configured via D-Bus */
-        struct in_addr_data *dns;
+        struct in_addr_full **dns;
         unsigned n_dns;
         OrderedSet *search_domains, *route_domains;
 
index e956c5ed9ab1525f55821670f5dbdd16064b72b7..9db59d93f8106f87b6e643e57e068d34bae5fe7a 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "alloc-util.h"
 #include "bus-common-errors.h"
+#include "bus-message-util.h"
 #include "bus-polkit.h"
 #include "networkd-link-bus.h"
 #include "networkd-link.h"
@@ -93,17 +94,16 @@ static int method_get_link_by_index(sd_bus_message *message, void *userdata, sd_
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         _cleanup_free_ char *path = NULL;
         Manager *manager = userdata;
-        int32_t index;
+        int ifindex, r;
         Link *link;
-        int r;
 
-        r = sd_bus_message_read(message, "i", &index);
+        r = bus_message_read_ifindex(message, error, &ifindex);
         if (r < 0)
                 return r;
 
-        link = hashmap_get(manager->links, INT_TO_PTR((int) index));
+        link = hashmap_get(manager->links, INT_TO_PTR(ifindex));
         if (!link)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %" PRIi32 " not known", index);
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
 
         r = sd_bus_message_new_method_return(message, &reply);
         if (r < 0)
@@ -128,14 +128,10 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_
         assert(message);
         assert(handler);
 
-        assert_cc(sizeof(int) == sizeof(int32_t));
-        r = sd_bus_message_read(message, "i", &ifindex);
+        r = bus_message_read_ifindex(message, error, &ifindex);
         if (r < 0)
                 return r;
 
-        if (ifindex <= 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
-
         l = hashmap_get(m->links, INT_TO_PTR(ifindex));
         if (!l)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
@@ -151,6 +147,10 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda
         return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
 }
 
+static int bus_method_set_link_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_dns_servers_ex, error);
+}
+
 static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         return call_link_method(userdata, message, bus_link_method_set_domains, error);
 }
@@ -243,6 +243,7 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("GetLinkByIndex", "i", "so", method_get_link_by_index, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetLinkNTP", "ias", NULL, bus_method_set_link_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkDNSEx", "ia(iayqs)", NULL, bus_method_set_link_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetLinkDefaultRoute", "ib", NULL, bus_method_set_link_default_route, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),
index 8c51cc12b22d7af61d36507ec5c072523ff68db3..273c00c36b91de469684a4450de38fabb8d7196d 100644 (file)
@@ -505,7 +505,8 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
 
                 log_link_debug(link,
                                "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
-                               (!route && !link->manager->manage_foreign_routes) || type == RTM_DELROUTE ? "Forgetting" :
+                               (!route && !link->manager->manage_foreign_routes) ? "Ignoring received foreign" :
+                               type == RTM_DELROUTE ? "Forgetting" :
                                route ? "Received remembered" : "Remembering",
                                strna(buf_dst), strempty(buf_dst_prefixlen),
                                strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
@@ -1424,33 +1425,36 @@ static int manager_connect_rtnl(Manager *m) {
         return 0;
 }
 
-static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) {
-        char *p;
+static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
+        const char *p;
         int r;
 
         assert(s);
-        assert(address);
+        assert(dns);
 
-        r = in_addr_to_string(address->family, &address->address, &p);
-        if (r < 0)
-                return r;
+        if (dns->ifindex != 0 && dns->ifindex != ifindex)
+                return 0;
 
-        r = ordered_set_consume(s, p);
+        p = in_addr_full_to_string(dns);
+        if (!p)
+                return 0;
+
+        r = ordered_set_put_strdup(s, p);
         if (r == -EEXIST)
                 return 0;
 
         return r;
 }
 
-static int ordered_set_put_in_addr_datav(OrderedSet *s, const struct in_addr_data *addresses, unsigned n) {
+static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
         int r, c = 0;
         unsigned i;
 
         assert(s);
-        assert(addresses || n == 0);
+        assert(dns || n == 0);
 
         for (i = 0; i < n; i++) {
-                r = ordered_set_put_in_addr_data(s, addresses+i);
+                r = ordered_set_put_dns_server(s, ifindex, dns[i]);
                 if (r < 0)
                         return r;
 
@@ -1557,7 +1561,10 @@ static int manager_save(Manager *m) {
                         continue;
 
                 /* First add the static configured entries */
-                r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns);
+                if (link->n_dns != (unsigned) -1)
+                        r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
+                else
+                        r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
                 if (r < 0)
                         return r;
 
@@ -2031,6 +2038,9 @@ int manager_rtnl_enumerate_routes(Manager *m) {
         assert(m);
         assert(m->rtnl);
 
+        if (!m->manage_foreign_routes)
+                return 0;
+
         r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
         if (r < 0)
                 return r;
index 52c315ac4e549f30539236de4c936c19ae5d637c..409db8c3c5ab23e79e08dd64019b2e495eb7755f 100644 (file)
@@ -148,8 +148,6 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         unsigned preference;
         uint32_t mtu;
         usec_t time_now;
-        Address *address;
-        Iterator i;
         int r;
 
         assert(link);
@@ -166,34 +164,15 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
 
-        SET_FOREACH(address, link->addresses, i) {
-                if (address->family != AF_INET6)
-                        continue;
-                if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
-                        if (DEBUG_LOGGING) {
-                                _cleanup_free_ char *buffer = NULL;
-
-                                (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
-                                log_link_debug(link, "No NDisc route added, gateway %s matches local address",
-                                               strnull(buffer));
-                        }
-                        return 0;
-                }
-        }
-
-        SET_FOREACH(address, link->addresses_foreign, i) {
-                if (address->family != AF_INET6)
-                        continue;
-                if (in_addr_equal(AF_INET6, &gateway, &address->in_addr)) {
-                        if (DEBUG_LOGGING) {
-                                _cleanup_free_ char *buffer = NULL;
+        if (address_exists(link, AF_INET6, &gateway)) {
+                if (DEBUG_LOGGING) {
+                        _cleanup_free_ char *buffer = NULL;
 
-                                (void) in_addr_to_string(AF_INET6, &address->in_addr, &buffer);
-                                log_link_debug(link, "No NDisc route added, gateway %s matches local address",
-                                               strnull(buffer));
-                        }
-                        return 0;
+                        (void) in_addr_to_string(AF_INET6, &gateway, &buffer);
+                        log_link_debug(link, "No NDisc route added, gateway %s matches local address",
+                                       strnull(buffer));
                 }
+                return 0;
         }
 
         r = sd_ndisc_router_get_preference(rt, &preference);
@@ -836,14 +815,14 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *r
                 break;
 
         case SD_NDISC_EVENT_TIMEOUT:
-                log_link_debug(link, "NDISC handler get timeout event");
+                log_link_debug(link, "NDisc handler get timeout event");
                 link->ndisc_addresses_configured = true;
                 link->ndisc_routes_configured = true;
                 link_check_ready(link);
 
                 break;
         default:
-                assert_not_reached("IPv6 Neighbor Discovery unknown event");
+                assert_not_reached("Unknown NDisc event");
         }
 }
 
@@ -969,7 +948,7 @@ int config_parse_ndisc_deny_listed_prefix(
                         return log_oom();
                 if (r < 0) {
                         log_syntax(unit, LOG_WARNING, filename, line, r,
-                                   "Failed to parse NDISC deny-listed prefix, ignoring assignment: %s",
+                                   "Failed to parse NDisc deny-listed prefix, ignoring assignment: %s",
                                    rvalue);
                         return 0;
                 }
@@ -979,7 +958,7 @@ int config_parse_ndisc_deny_listed_prefix(
                 r = in_addr_from_string(AF_INET6, n, &ip);
                 if (r < 0) {
                         log_syntax(unit, LOG_WARNING, filename, line, r,
-                                   "NDISC deny-listed prefix is invalid, ignoring assignment: %s", n);
+                                   "NDisc deny-listed prefix is invalid, ignoring assignment: %s", n);
                         continue;
                 }
 
index 1c901138564dd39d9960069e56c8fd7db2a98bc5..0e97b225c4547ddff63dd5e2864db39a26767fe7 100644 (file)
@@ -132,7 +132,7 @@ int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_hand
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set state: %m");
 
-        r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE);
+        r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not set flags: %m");
 
index 6a3920adabd9bd70c402637caa70739669409077..94a1a6100fed6cd2b1736d3127cf5316d1c49b69 100644 (file)
@@ -682,6 +682,8 @@ static Network *network_free(Network *network) {
                 sd_ipv4acd_unref(network->dhcp_acd);
 
         strv_free(network->ntp);
+        for (unsigned i = 0; i < network->n_dns; i++)
+                in_addr_full_free(network->dns[i]);
         free(network->dns);
         ordered_set_free_free(network->search_domains);
         ordered_set_free_free(network->route_domains);
@@ -1194,16 +1196,17 @@ int config_parse_dns(
         assert(rvalue);
 
         if (isempty(rvalue)) {
+                for (unsigned i = 0; i < n->n_dns; i++)
+                        in_addr_full_free(n->dns[i]);
                 n->dns = mfree(n->dns);
                 n->n_dns = 0;
                 return 0;
         }
 
         for (const char *p = rvalue;;) {
+                _cleanup_(in_addr_full_freep) struct in_addr_full *dns = NULL;
                 _cleanup_free_ char *w = NULL;
-                union in_addr_union a;
-                struct in_addr_data *m;
-                int family;
+                struct in_addr_full **m;
 
                 r = extract_first_word(&p, &w, NULL, 0);
                 if (r == -ENOMEM)
@@ -1216,22 +1219,21 @@ int config_parse_dns(
                 if (r == 0)
                         return 0;
 
-                r = in_addr_from_string_auto(w, &family, &a);
+                r = in_addr_full_new_from_string(w, &dns);
                 if (r < 0) {
                         log_syntax(unit, LOG_WARNING, filename, line, r,
                                    "Failed to parse dns server address, ignoring: %s", w);
                         continue;
                 }
 
-                m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_data));
+                if (IN_SET(dns->port, 53, 853))
+                        dns->port = 0;
+
+                m = reallocarray(n->dns, n->n_dns + 1, sizeof(struct in_addr_full*));
                 if (!m)
                         return log_oom();
 
-                m[n->n_dns++] = (struct in_addr_data) {
-                        .family = family,
-                        .address = a,
-                };
-
+                m[n->n_dns++] = TAKE_PTR(dns);
                 n->dns = m;
         }
 }
index 424298248f963b877b52b1f94635d8bd6674f171..17109d139cfac7ff034272d34da5d61a33175715 100644 (file)
@@ -32,6 +32,7 @@
 #include "networkd-util.h"
 #include "ordered-set.h"
 #include "resolve-util.h"
+#include "socket-netlink.h"
 
 typedef enum IPv6PrivacyExtensions {
         /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */
@@ -316,7 +317,7 @@ struct Network {
         OrderedHashmap *sr_iov_by_section;
 
         /* All kinds of DNS configuration */
-        struct in_addr_data *dns;
+        struct in_addr_full **dns;
         unsigned n_dns;
         OrderedSet *search_domains, *route_domains;
 
index 8b473836dbf7e1b610633dca8938caf77a63ebd3..088cdf11a3660b581b47687e8e605ef45c783286 100644 (file)
@@ -463,10 +463,10 @@ static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
         for (i = 0; i < network->n_dns; i++) {
                 union in_addr_union *addr;
 
-                if (network->dns[i].family != AF_INET6)
+                if (network->dns[i]->family != AF_INET6)
                         continue;
 
-                addr = &network->dns[i].address;
+                addr = &network->dns[i]->address;
 
                 if (in_addr_is_null(AF_INET6, addr) ||
                     in_addr_is_link_local(AF_INET6, addr) ||
index 330bd7e7d296bb2fcf55f9fd099997b9c4c7da4a..3020ef975ce861b2c9f5f6574a143f0f63e47d53 100644 (file)
@@ -3191,7 +3191,7 @@ static int inner_child(
         if (asprintf((char **)(envp + n_env++), "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH) < 0)
                 return log_oom();
 
-        env_use = strv_env_merge(3, envp, arg_setenv, os_release_pairs);
+        env_use = strv_env_merge(3, envp, os_release_pairs, arg_setenv);
         if (!env_use)
                 return log_oom();
 
index c01524b9cc5a3a6c3fa6efbc756402c5a8d0adb4..476c5e4a3c032a16dcfde4d08e04be7d076c0de9 100644 (file)
@@ -13,6 +13,7 @@
 #include "bus-error.h"
 #include "bus-locator.h"
 #include "bus-map-properties.h"
+#include "bus-message-util.h"
 #include "dns-domain.h"
 #include "escape.h"
 #include "format-table.h"
@@ -209,34 +210,29 @@ static int resolve_host(sd_bus *bus, const char *name) {
         while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
                 _cleanup_free_ char *pretty = NULL;
                 int ifindex, family, k;
-                const void *a;
-                size_t sz;
+                union in_addr_union a;
 
                 assert_cc(sizeof(int) == sizeof(int32_t));
 
-                r = sd_bus_message_read(reply, "ii", &ifindex, &family);
+                r = sd_bus_message_read(reply, "i", &ifindex);
                 if (r < 0)
                         return bus_log_parse_error(r);
 
-                r = sd_bus_message_read_array(reply, 'y', &a, &sz);
-                if (r < 0)
-                        return bus_log_parse_error(r);
+                sd_bus_error_free(&error);
+                r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
+                if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
+                        return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
 
                 r = sd_bus_message_exit_container(reply);
                 if (r < 0)
                         return bus_log_parse_error(r);
 
-                if (!IN_SET(family, AF_INET, AF_INET6)) {
-                        log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
+                if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
+                        log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
                         continue;
                 }
 
-                if (sz != FAMILY_ADDRESS_SIZE(family)) {
-                        log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
-                        return -EINVAL;
-                }
-
-                r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
+                r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
                 if (r < 0)
                         return log_error_errno(r, "Failed to print address for %s: %m", name);
 
@@ -740,33 +736,29 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
                 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
                         _cleanup_free_ char *pretty = NULL;
                         int ifindex, family, k;
-                        const void *a;
+                        union in_addr_union a;;
 
                         assert_cc(sizeof(int) == sizeof(int32_t));
 
-                        r = sd_bus_message_read(reply, "ii", &ifindex, &family);
+                        r = sd_bus_message_read(reply, "i", &ifindex);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        r = sd_bus_message_read_array(reply, 'y', &a, &sz);
-                        if (r < 0)
-                                return bus_log_parse_error(r);
+                        sd_bus_error_free(&error);
+                        r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
+                        if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
+                                return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
 
                         r = sd_bus_message_exit_container(reply);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        if (!IN_SET(family, AF_INET, AF_INET6)) {
-                                log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
+                        if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
+                                log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
                                 continue;
                         }
 
-                        if (sz != FAMILY_ADDRESS_SIZE(family)) {
-                                log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
-                                return -EINVAL;
-                        }
-
-                        r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
+                        r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to print address for %s: %m", name);
 
@@ -1120,16 +1112,18 @@ static int reset_server_features(int argc, char **argv, void *userdata) {
         return 0;
 }
 
-static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) {
+static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, bool extended, char **ret) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_free_ char *pretty = NULL;
-        int ifindex, family, r;
-        const void *a;
-        size_t sz;
+        int ifindex, family, r, k;
+        union in_addr_union a;
+        const char *name = NULL;
+        uint16_t port = 0;
 
         assert(m);
         assert(ret);
 
-        r = sd_bus_message_enter_container(m, 'r', with_ifindex ? "iiay" : "iay");
+        r = sd_bus_message_enter_container(m, 'r', with_ifindex ? (extended ? "iiayqs" : "iiay") : (extended ? "iayqs" : "iay"));
         if (r <= 0)
                 return r;
 
@@ -1139,39 +1133,37 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret)
                         return r;
         }
 
-        r = sd_bus_message_read(m, "i", &family);
-        if (r < 0)
-                return r;
+        k = bus_message_read_in_addr_auto(m, &error, &family, &a);
+        if (k < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
+                return k;
 
-        r = sd_bus_message_read_array(m, 'y', &a, &sz);
-        if (r < 0)
-                return r;
+        if (extended) {
+                r = sd_bus_message_read(m, "q", &port);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_read(m, "s", &name);
+                if (r < 0)
+                        return r;
+        }
 
         r = sd_bus_message_exit_container(m);
         if (r < 0)
                 return r;
 
-        if (with_ifindex && ifindex != 0) {
-                /* only show the global ones here */
+        if (k < 0) {
+                log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error, k));
                 *ret = NULL;
                 return 1;
         }
 
-        if (!IN_SET(family, AF_INET, AF_INET6)) {
-                log_debug("Unexpected family, ignoring: %i", family);
-
-                *ret = NULL;
-                return 1;
-        }
-
-        if (sz != FAMILY_ADDRESS_SIZE(family)) {
-                log_debug("Address size mismatch, ignoring.");
-
+        if (with_ifindex && ifindex != 0) {
+                /* only show the global ones here */
                 *ret = NULL;
                 return 1;
         }
 
-        r = in_addr_to_string(family, a, &pretty);
+        r = in_addr_port_ifindex_name_to_string(family, &a, port, ifindex, name, &pretty);
         if (r < 0)
                 return r;
 
@@ -1180,7 +1172,7 @@ static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret)
         return 1;
 }
 
-static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+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) {
         char ***l = userdata;
         int r;
 
@@ -1189,14 +1181,14 @@ static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message
         assert(m);
         assert(l);
 
-        r = sd_bus_message_enter_container(m, 'a', "(iay)");
+        r = sd_bus_message_enter_container(m, 'a', extended ? "(iayqs)" : "(iay)");
         if (r < 0)
                 return r;
 
         for (;;) {
                 _cleanup_free_ char *pretty = NULL;
 
-                r = read_dns_server_one(m, false, &pretty);
+                r = read_dns_server_one(m, false, extended, &pretty);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1217,11 +1209,26 @@ static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message
         return 0;
 }
 
+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);
+}
+
+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);
+}
+
 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, false, userdata);
+        return read_dns_server_one(m, false, false, 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, false, true, userdata);
 }
 
 static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
@@ -1315,7 +1322,9 @@ struct link_info {
         const char *dns_over_tls;
         const char *dnssec;
         char *current_dns;
+        char *current_dns_ex;
         char **dns;
+        char **dns_ex;
         char **domains;
         char **ntas;
         bool dnssec_supported;
@@ -1324,7 +1333,9 @@ struct link_info {
 
 static void link_info_clear(struct link_info *p) {
         free(p->current_dns);
+        free(p->current_dns_ex);
         strv_free(p->dns);
+        strv_free(p->dns_ex);
         strv_free(p->domains);
         strv_free(p->ntas);
 }
@@ -1346,17 +1357,19 @@ static int dump_list(Table *table, const char *prefix, char * const *l) {
 
 static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) {
         static const struct bus_properties_map property_map[] = {
-                { "ScopesMask",                 "t",      NULL,                        offsetof(struct link_info, scopes_mask)      },
-                { "DNS",                        "a(iay)", map_link_dns_servers,        offsetof(struct link_info, dns)              },
-                { "CurrentDNSServer",           "(iay)",  map_link_current_dns_server, offsetof(struct link_info, current_dns)      },
-                { "Domains",                    "a(sb)",  map_link_domains,            offsetof(struct link_info, domains)          },
-                { "DefaultRoute",               "b",      NULL,                        offsetof(struct link_info, default_route)    },
-                { "LLMNR",                      "s",      NULL,                        offsetof(struct link_info, llmnr)            },
-                { "MulticastDNS",               "s",      NULL,                        offsetof(struct link_info, mdns)             },
-                { "DNSOverTLS",                 "s",      NULL,                        offsetof(struct link_info, dns_over_tls)     },
-                { "DNSSEC",                     "s",      NULL,                        offsetof(struct link_info, dnssec)           },
-                { "DNSSECNegativeTrustAnchors", "as",     NULL,                        offsetof(struct link_info, ntas)             },
-                { "DNSSECSupported",            "b",      NULL,                        offsetof(struct link_info, dnssec_supported) },
+                { "ScopesMask",                 "t",        NULL,                           offsetof(struct link_info, scopes_mask)      },
+                { "DNS",                        "a(iay)",   map_link_dns_servers,           offsetof(struct link_info, dns)              },
+                { "DNSEx",                      "a(iayqs)", map_link_dns_servers_ex,        offsetof(struct link_info, dns_ex)           },
+                { "CurrentDNSServer",           "(iay)",    map_link_current_dns_server,    offsetof(struct link_info, current_dns)      },
+                { "CurrentDNSServerEx",         "(iayqs)",  map_link_current_dns_server_ex, offsetof(struct link_info, current_dns_ex)   },
+                { "Domains",                    "a(sb)",    map_link_domains,               offsetof(struct link_info, domains)          },
+                { "DefaultRoute",               "b",        NULL,                           offsetof(struct link_info, default_route)    },
+                { "LLMNR",                      "s",        NULL,                           offsetof(struct link_info, llmnr)            },
+                { "MulticastDNS",               "s",        NULL,                           offsetof(struct link_info, mdns)             },
+                { "DNSOverTLS",                 "s",        NULL,                           offsetof(struct link_info, dns_over_tls)     },
+                { "DNSSEC",                     "s",        NULL,                           offsetof(struct link_info, dnssec)           },
+                { "DNSSECNegativeTrustAnchors", "as",       NULL,                           offsetof(struct link_info, ntas)             },
+                { "DNSSECSupported",            "b",        NULL,                           offsetof(struct link_info, dnssec_supported) },
                 {}
         };
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -1396,7 +1409,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
         (void) pager_open(arg_pager_flags);
 
         if (mode == STATUS_DNS)
-                return status_print_strv_ifindex(ifindex, name, link_info.dns);
+                return status_print_strv_ifindex(ifindex, name, link_info.dns_ex ?: link_info.dns);
 
         if (mode == STATUS_DOMAIN)
                 return status_print_strv_ifindex(ifindex, name, link_info.domains);
@@ -1504,12 +1517,12 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
         if (link_info.current_dns) {
                 r = table_add_many(table,
                                    TABLE_STRING, "Current DNS Server:",
-                                   TABLE_STRING, link_info.current_dns);
+                                   TABLE_STRING, link_info.current_dns_ex ?: link_info.current_dns);
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
-        r = dump_list(table, "DNS Servers:", link_info.dns);
+        r = dump_list(table, "DNS Servers:", link_info.dns_ex ?: link_info.dns);
         if (r < 0)
                 return r;
 
@@ -1527,7 +1540,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
         return 0;
 }
 
-static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+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 = userdata;
         int r;
 
@@ -1536,14 +1549,14 @@ static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_messag
         assert(m);
         assert(l);
 
-        r = sd_bus_message_enter_container(m, 'a', "(iiay)");
+        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, true, &pretty);
+                r = read_dns_server_one(m, true, extended, &pretty);
                 if (r < 0)
                         return r;
                 if (r == 0)
@@ -1564,11 +1577,26 @@ static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_messag
         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, false);
+}
+
+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, true);
+}
+
 static int map_global_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, true, userdata);
+        return read_dns_server_one(m, true, false, 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) {
+        assert(m);
+        assert(userdata);
+
+        return read_dns_server_one(m, true, true, userdata);
 }
 
 static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
@@ -1623,8 +1651,11 @@ static int status_print_strv_global(char **p) {
 
 struct global_info {
         char *current_dns;
+        char *current_dns_ex;
         char **dns;
+        char **dns_ex;
         char **fallback_dns;
+        char **fallback_dns_ex;
         char **domains;
         char **ntas;
         const char *llmnr;
@@ -1636,24 +1667,30 @@ struct global_info {
 
 static void global_info_clear(struct global_info *p) {
         free(p->current_dns);
+        free(p->current_dns_ex);
         strv_free(p->dns);
+        strv_free(p->dns_ex);
         strv_free(p->fallback_dns);
+        strv_free(p->fallback_dns_ex);
         strv_free(p->domains);
         strv_free(p->ntas);
 }
 
 static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
         static const struct bus_properties_map property_map[] = {
-                { "DNS",                        "a(iiay)", map_global_dns_servers,        offsetof(struct global_info, dns)              },
-                { "FallbackDNS",                "a(iiay)", map_global_dns_servers,        offsetof(struct global_info, fallback_dns)     },
-                { "CurrentDNSServer",           "(iiay)",  map_global_current_dns_server, offsetof(struct global_info, current_dns)      },
-                { "Domains",                    "a(isb)",  map_global_domains,            offsetof(struct global_info, domains)          },
-                { "DNSSECNegativeTrustAnchors", "as",      NULL,                          offsetof(struct global_info, ntas)             },
-                { "LLMNR",                      "s",       NULL,                          offsetof(struct global_info, llmnr)            },
-                { "MulticastDNS",               "s",       NULL,                          offsetof(struct global_info, mdns)             },
-                { "DNSOverTLS",                 "s",       NULL,                          offsetof(struct global_info, dns_over_tls)     },
-                { "DNSSEC",                     "s",       NULL,                          offsetof(struct global_info, dnssec)           },
-                { "DNSSECSupported",            "b",       NULL,                          offsetof(struct global_info, dnssec_supported) },
+                { "DNS",                        "a(iiay)",   map_global_dns_servers,           offsetof(struct global_info, dns)              },
+                { "DNSEx",                      "a(iiayqs)", map_global_dns_servers_ex,        offsetof(struct global_info, dns_ex)           },
+                { "FallbackDNS",                "a(iiay)",   map_global_dns_servers,           offsetof(struct global_info, fallback_dns)     },
+                { "FallbackDNSEx",              "a(iiayqs)", map_global_dns_servers_ex,        offsetof(struct global_info, fallback_dns_ex)  },
+                { "CurrentDNSServer",           "(iiay)",    map_global_current_dns_server,    offsetof(struct global_info, current_dns)      },
+                { "CurrentDNSServerEx",         "(iiayqs)",  map_global_current_dns_server_ex, offsetof(struct global_info, current_dns_ex)   },
+                { "Domains",                    "a(isb)",    map_global_domains,               offsetof(struct global_info, domains)          },
+                { "DNSSECNegativeTrustAnchors", "as",        NULL,                             offsetof(struct global_info, ntas)             },
+                { "LLMNR",                      "s",         NULL,                             offsetof(struct global_info, llmnr)            },
+                { "MulticastDNS",               "s",         NULL,                             offsetof(struct global_info, mdns)             },
+                { "DNSOverTLS",                 "s",         NULL,                             offsetof(struct global_info, dns_over_tls)     },
+                { "DNSSEC",                     "s",         NULL,                             offsetof(struct global_info, dnssec)           },
+                { "DNSSECSupported",            "b",         NULL,                             offsetof(struct global_info, dnssec_supported) },
                 {}
         };
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -1679,7 +1716,7 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
         (void) pager_open(arg_pager_flags);
 
         if (mode == STATUS_DNS)
-                return status_print_strv_global(global_info.dns);
+                return status_print_strv_global(global_info.dns_ex ?: global_info.dns);
 
         if (mode == STATUS_DOMAIN)
                 return status_print_strv_global(global_info.domains);
@@ -1741,16 +1778,16 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
         if (global_info.current_dns) {
                 r = table_add_many(table,
                                    TABLE_STRING, "Current DNS Server:",
-                                   TABLE_STRING, global_info.current_dns);
+                                   TABLE_STRING, global_info.current_dns_ex ?: global_info.current_dns);
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
-        r = dump_list(table, "DNS Servers:", global_info.dns);
+        r = dump_list(table, "DNS Servers:", global_info.dns_ex ?: global_info.dns);
         if (r < 0)
                 return r;
 
-        r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns);
+        r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns_ex ?: global_info.fallback_dns);
         if (r < 0)
                 return r;
 
@@ -1867,12 +1904,12 @@ static int verb_status(int argc, char **argv, void *userdata) {
         return r;
 }
 
-static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error) {
+static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error, bool extended) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
         char **p;
         int r;
 
-        r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNS");
+        r = bus_message_new_method_call(bus, &req, locator, extended ? "SetLinkDNSEx" : "SetLinkDNS");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1880,7 +1917,7 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e
         if (r < 0)
                 return bus_log_create_error(r);
 
-        r = sd_bus_message_open_container(req, 'a', "(iay)");
+        r = sd_bus_message_open_container(req, 'a', extended ? "(iayqs)" : "(iay)");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1888,13 +1925,19 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e
          * empty list, which will clear the list of domains for an interface. */
         if (!strv_equal(dns, STRV_MAKE("")))
                 STRV_FOREACH(p, dns) {
+                        _cleanup_free_ char *name = NULL;
                         struct in_addr_data data;
+                        uint16_t port;
+                        int ifindex;
 
-                        r = in_addr_from_string_auto(*p, &data.family, &data.address);
+                        r = in_addr_port_ifindex_name_from_string_auto(*p, &data.family, &data.address, &port, &ifindex, &name);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse DNS server address: %s", *p);
 
-                        r = sd_bus_message_open_container(req, 'r', "iay");
+                        if (ifindex != 0 && ifindex != arg_ifindex)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid ifindex: %i", ifindex);
+
+                        r = sd_bus_message_open_container(req, 'r', extended ? "iayqs" : "iay");
                         if (r < 0)
                                 return bus_log_create_error(r);
 
@@ -1906,6 +1949,16 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e
                         if (r < 0)
                                 return bus_log_create_error(r);
 
+                        if (extended) {
+                                r = sd_bus_message_append(req, "q", port);
+                                if (r < 0)
+                                        return bus_log_create_error(r);
+
+                                r = sd_bus_message_append(req, "s", name);
+                                if (r < 0)
+                                        return bus_log_create_error(r);
+                        }
+
                         r = sd_bus_message_close_container(req);
                         if (r < 0)
                                 return bus_log_create_error(r);
@@ -1915,7 +1968,10 @@ static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_e
         if (r < 0)
                 return bus_log_create_error(r);
 
-        return sd_bus_call(bus, req, 0, error, NULL);
+        r = sd_bus_call(bus, req, 0, error, NULL);
+        if (r < 0 && extended && sd_bus_error_has_name(error, SD_BUS_ERROR_UNKNOWN_METHOD))
+                return call_dns(bus, dns, locator, error, false);
+        return r;
 }
 
 static int verb_dns(int argc, char **argv, void *userdata) {
@@ -1937,11 +1993,11 @@ static int verb_dns(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL);
 
-        r = call_dns(bus, argv + 2, bus_resolve_mgr, &error);
+        r = call_dns(bus, argv + 2, bus_resolve_mgr, &error, true);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
 
-                r = call_dns(bus, argv + 2, bus_network_mgr, &error);
+                r = call_dns(bus, argv + 2, bus_network_mgr, &error, true);
         }
         if (r < 0) {
                 if (arg_ifindex_permissive &&
index 45687c8fcab96764f011af12bed5aebea72c5010..dba1639a11cf9ed6803625b868e1cdbb14876e96 100644 (file)
@@ -4,6 +4,7 @@
 #include "bus-common-errors.h"
 #include "bus-get-properties.h"
 #include "bus-log-control-api.h"
+#include "bus-message-util.h"
 #include "bus-polkit.h"
 #include "dns-domain.h"
 #include "memory-util.h"
@@ -454,11 +455,10 @@ finish:
 static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
         Manager *m = userdata;
+        union in_addr_union a;
         int family, ifindex;
         uint64_t flags;
-        const void *d;
         DnsQuery *q;
-        size_t sz;
         int r;
 
         assert(message);
@@ -466,20 +466,14 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
 
         assert_cc(sizeof(int) == sizeof(int32_t));
 
-        r = sd_bus_message_read(message, "ii", &ifindex, &family);
+        r = sd_bus_message_read(message, "i", &ifindex);
         if (r < 0)
                 return r;
 
-        if (!IN_SET(family, AF_INET, AF_INET6))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
-
-        r = sd_bus_message_read_array(message, 'y', &d, &sz);
+        r = bus_message_read_in_addr_auto(message, error, &family, &a);
         if (r < 0)
                 return r;
 
-        if (sz != FAMILY_ADDRESS_SIZE(family))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
-
         r = sd_bus_message_read(message, "t", &flags);
         if (r < 0)
                 return r;
@@ -488,7 +482,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
         if (r < 0)
                 return r;
 
-        r = dns_question_new_reverse(&question, family, d);
+        r = dns_question_new_reverse(&question, family, &a);
         if (r < 0)
                 return r;
 
@@ -498,7 +492,7 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
 
         q->request = sd_bus_message_ref(message);
         q->request_family = family;
-        memcpy(&q->request_address, d, sz);
+        q->request_address = a;
         q->complete = bus_method_resolve_address_complete;
 
         r = dns_query_bus_track(q, message);
@@ -1218,19 +1212,26 @@ fail:
         return r;
 }
 
-int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex) {
+int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex, bool extended) {
         int r;
 
         assert(reply);
 
         if (!s) {
-                if (with_ifindex)
-                        return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0);
-                else
-                        return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0);
+                if (with_ifindex) {
+                        if (extended)
+                                return sd_bus_message_append(reply, "(iiayqs)", 0, AF_UNSPEC, 0, 0, NULL);
+                        else
+                                return sd_bus_message_append(reply, "(iiay)", 0, AF_UNSPEC, 0);
+                } else {
+                        if (extended)
+                                return sd_bus_message_append(reply, "(iayqs)", AF_UNSPEC, 0, 0, NULL);
+                        else
+                                return sd_bus_message_append(reply, "(iay)", AF_UNSPEC, 0);
+                }
         }
 
-        r = sd_bus_message_open_container(reply, 'r', with_ifindex ? "iiay" : "iay");
+        r = sd_bus_message_open_container(reply, 'r', with_ifindex ? (extended ? "iiayqs" : "iiay") : (extended ? "iayqs" : "iay"));
         if (r < 0)
                 return r;
 
@@ -1248,17 +1249,28 @@ int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex
         if (r < 0)
                 return r;
 
+        if (extended) {
+                r = sd_bus_message_append(reply, "q", s->port);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(reply, "s", s->server_name);
+                if (r < 0)
+                        return r;
+        }
+
         return sd_bus_message_close_container(reply);
 }
 
-static int bus_property_get_dns_servers(
+static int bus_property_get_dns_servers_internal(
                 sd_bus *bus,
                 const char *path,
                 const char *interface,
                 const char *property,
                 sd_bus_message *reply,
                 void *userdata,
-                sd_bus_error *error) {
+                sd_bus_error *error,
+                bool extended) {
 
         Manager *m = userdata;
         DnsServer *s;
@@ -1269,19 +1281,19 @@ static int bus_property_get_dns_servers(
         assert(reply);
         assert(m);
 
-        r = sd_bus_message_open_container(reply, 'a', "(iiay)");
+        r = sd_bus_message_open_container(reply, 'a', extended ? "(iiayqs)" : "(iiay)");
         if (r < 0)
                 return r;
 
         LIST_FOREACH(servers, s, m->dns_servers) {
-                r = bus_dns_server_append(reply, s, true);
+                r = bus_dns_server_append(reply, s, true, extended);
                 if (r < 0)
                         return r;
         }
 
         HASHMAP_FOREACH(l, m->links, i)
                 LIST_FOREACH(servers, s, l->dns_servers) {
-                        r = bus_dns_server_append(reply, s, true);
+                        r = bus_dns_server_append(reply, s, true, extended);
                         if (r < 0)
                                 return r;
                 }
@@ -1289,7 +1301,18 @@ static int bus_property_get_dns_servers(
         return sd_bus_message_close_container(reply);
 }
 
-static int bus_property_get_fallback_dns_servers(
+static int bus_property_get_dns_servers(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        return bus_property_get_dns_servers_internal(bus, path, interface, property, reply, userdata, error, false);
+}
+
+static int bus_property_get_dns_servers_ex(
                 sd_bus *bus,
                 const char *path,
                 const char *interface,
@@ -1297,6 +1320,18 @@ static int bus_property_get_fallback_dns_servers(
                 sd_bus_message *reply,
                 void *userdata,
                 sd_bus_error *error) {
+        return bus_property_get_dns_servers_internal(bus, path, interface, property, reply, userdata, error, true);
+}
+
+static int bus_property_get_fallback_dns_servers_internal(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error,
+                bool extended) {
 
         DnsServer *s, **f = userdata;
         int r;
@@ -1304,12 +1339,12 @@ static int bus_property_get_fallback_dns_servers(
         assert(reply);
         assert(f);
 
-        r = sd_bus_message_open_container(reply, 'a', "(iiay)");
+        r = sd_bus_message_open_container(reply, 'a', extended ? "(iiayqs)" : "(iiay)");
         if (r < 0)
                 return r;
 
         LIST_FOREACH(servers, s, *f) {
-                r = bus_dns_server_append(reply, s, true);
+                r = bus_dns_server_append(reply, s, true, extended);
                 if (r < 0)
                         return r;
         }
@@ -1317,7 +1352,7 @@ static int bus_property_get_fallback_dns_servers(
         return sd_bus_message_close_container(reply);
 }
 
-static int bus_property_get_current_dns_server(
+static int bus_property_get_fallback_dns_servers(
                 sd_bus *bus,
                 const char *path,
                 const char *interface,
@@ -1325,6 +1360,29 @@ static int bus_property_get_current_dns_server(
                 sd_bus_message *reply,
                 void *userdata,
                 sd_bus_error *error) {
+        return bus_property_get_fallback_dns_servers_internal(bus, path, interface, property, reply, userdata, error, false);
+}
+
+static int bus_property_get_fallback_dns_servers_ex(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        return bus_property_get_fallback_dns_servers_internal(bus, path, interface, property, reply, userdata, error, true);
+}
+
+static int bus_property_get_current_dns_server_internal(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error,
+                bool extended) {
 
         DnsServer *s;
 
@@ -1333,7 +1391,29 @@ static int bus_property_get_current_dns_server(
 
         s = *(DnsServer **) userdata;
 
-        return bus_dns_server_append(reply, s, true);
+        return bus_dns_server_append(reply, s, true, extended);
+}
+
+static int bus_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) {
+        return bus_property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false);
+}
+
+static int bus_property_get_current_dns_server_ex(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        return bus_property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true);
 }
 
 static int bus_property_get_domains(
@@ -1497,9 +1577,6 @@ static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error
         assert(m);
         assert(ret);
 
-        if (ifindex <= 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
-
         l = hashmap_get(m->links, INT_TO_PTR(ifindex));
         if (!l)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
@@ -1516,8 +1593,7 @@ static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_
         assert(message);
         assert(handler);
 
-        assert_cc(sizeof(int) == sizeof(int32_t));
-        r = sd_bus_message_read(message, "i", &ifindex);
+        r = bus_message_read_ifindex(message, error, &ifindex);
         if (r < 0)
                 return r;
 
@@ -1532,6 +1608,10 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda
         return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
 }
 
+static int bus_method_set_link_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_dns_servers_ex, error);
+}
+
 static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         return call_link_method(userdata, message, bus_link_method_set_domains, error);
 }
@@ -1573,8 +1653,7 @@ static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_e
         assert(message);
         assert(m);
 
-        assert_cc(sizeof(int) == sizeof(int32_t));
-        r = sd_bus_message_read(message, "i", &ifindex);
+        r = bus_message_read_ifindex(message, error, &ifindex);
         if (r < 0)
                 return r;
 
@@ -1844,8 +1923,11 @@ static const sd_bus_vtable resolve_vtable[] = {
         SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Manager, mdns_support), 0),
         SD_BUS_PROPERTY("DNSOverTLS", "s", bus_property_get_dns_over_tls_mode, 0, 0),
         SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("DNSEx", "a(iiayqs)", bus_property_get_dns_servers_ex, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("FallbackDNS", "a(iiay)", bus_property_get_fallback_dns_servers, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("FallbackDNSEx", "a(iiayqs)", bus_property_get_fallback_dns_servers_ex, offsetof(Manager, fallback_dns_servers), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("CurrentDNSServer", "(iiay)", bus_property_get_current_dns_server, offsetof(Manager, current_dns_server), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("CurrentDNSServerEx", "(iiayqs)", bus_property_get_current_dns_server_ex, offsetof(Manager, current_dns_server), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0),
         SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
         SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
@@ -1895,6 +1977,11 @@ static const sd_bus_vtable resolve_vtable[] = {
                                 SD_BUS_NO_RESULT,
                                 bus_method_set_link_dns_servers,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetLinkDNSEx",
+                                SD_BUS_ARGS("i", ifindex, "a(iayqs)", addresses),
+                                SD_BUS_NO_RESULT,
+                                bus_method_set_link_dns_servers_ex,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_ARGS("SetLinkDomains",
                                 SD_BUS_ARGS("i", ifindex, "a(sb)", domains),
                                 SD_BUS_NO_RESULT,
index 6d6b095323ed23edd725ae9c3b2f199890d6ac3d..28caa64a6b5abae77bfba6d6da1a2f2423f11497 100644 (file)
@@ -9,7 +9,7 @@ extern const BusObjectImplementation manager_object;
 int manager_connect_bus(Manager *m);
 int _manager_send_changed(Manager *manager, const char *property, ...) _sentinel_;
 #define manager_send_changed(manager, ...) _manager_send_changed(manager, __VA_ARGS__, NULL)
-int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex);
+int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex, bool extended);
 int bus_property_get_resolve_support(sd_bus *bus, const char *path, const char *interface,
                                      const char *property, sd_bus_message *reply,
                                      void *userdata, sd_bus_error *error);
index 9a6b1e88e17d29c86c0d08e022cffbeb0e218e7e..6b99271245716d25f6f46ae02d43de4e92bb341a 100644 (file)
@@ -28,24 +28,33 @@ static const char* const dns_stub_listener_mode_table[_DNS_STUB_LISTENER_MODE_MA
 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dns_stub_listener_mode, DnsStubListenerMode, DNS_STUB_LISTENER_YES);
 
 static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) {
+        _cleanup_free_ char *server_name = NULL;
         union in_addr_union address;
         int family, r, ifindex = 0;
+        uint16_t port;
         DnsServer *s;
-        _cleanup_free_ char *server_name = NULL;
 
         assert(m);
         assert(word);
 
-        r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
+        r = in_addr_port_ifindex_name_from_string_auto(word, &family, &address, &port, &ifindex, &server_name);
         if (r < 0)
                 return r;
 
+        if (IN_SET(port, 53, 853))
+                port = 0;
+
         /* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */
         if (!dns_server_address_valid(family, &address))
                 return 0;
 
+        /* 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 */
-        s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, ifindex);
+        s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
         if (s) {
                 /*
                  * Drop the marker. This is used to find the servers
@@ -57,7 +66,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, ifindex, server_name);
+        return dns_server_new(m, NULL, type, NULL, family, &address, port, ifindex, server_name);
 }
 
 int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
index 764ccee0e0ef523137135eb3f135845aac717e9c..bd4b59ea8e18ee6afd415054bd56d18aaceef324 100644 (file)
@@ -447,8 +447,8 @@ static int dns_scope_socket(
         return TAKE_FD(fd);
 }
 
-int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port) {
-        return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, port, NULL);
+int dns_scope_socket_udp(DnsScope *s, DnsServer *server) {
+        return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, dns_server_port(server), NULL);
 }
 
 int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address) {
index b356b92120546eeda2358d79973d849d788ff07b..8b1a958551c2f47b161797d601628d96b54be51d 100644 (file)
@@ -75,7 +75,7 @@ void dns_scope_packet_lost(DnsScope *s, usec_t usec);
 
 int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p);
 int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address);
-int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port);
+int dns_scope_socket_udp(DnsScope *s, DnsServer *server);
 
 DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain);
 bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key);
index 60de1b29e7500ee4279760fdbd5f3b9adc00f860..c87026f434e81752375a35f04ea67fbdb237de1b 100644 (file)
@@ -26,6 +26,7 @@ int dns_server_new(
                 Link *l,
                 int family,
                 const union in_addr_union *in_addr,
+                uint16_t port,
                 int ifindex,
                 const char *server_name) {
 
@@ -47,7 +48,7 @@ int dns_server_new(
                         return -E2BIG;
         }
 
-        if (server_name) {
+        if (!isempty(server_name)) {
                 name = strdup(server_name);
                 if (!name)
                         return -ENOMEM;
@@ -63,6 +64,7 @@ int dns_server_new(
                 .type = type,
                 .family = family,
                 .address = *in_addr,
+                .port = port,
                 .ifindex = ifindex,
                 .server_name = TAKE_PTR(name),
         };
@@ -117,6 +119,7 @@ static DnsServer* dns_server_free(DnsServer *s)  {
 #endif
 
         free(s->server_string);
+        free(s->server_string_full);
         free(s->server_name);
         return mfree(s);
 }
@@ -223,7 +226,7 @@ static void dns_server_verified(DnsServer *s, DnsServerFeatureLevel level) {
         if (s->verified_feature_level != level) {
                 log_debug("Verified we get a response at feature level %s from DNS server %s.",
                           dns_server_feature_level_to_string(level),
-                          dns_server_string(s));
+                          strna(dns_server_string_full(s)));
                 s->verified_feature_level = level;
         }
 
@@ -360,7 +363,7 @@ void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level
                 dns_server_reset_counters(s);
         }
 
-        log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", dns_server_string(s));
+        log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", strna(dns_server_string_full(s)));
 }
 
 static bool dns_server_grace_period_expired(DnsServer *s) {
@@ -414,7 +417,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
 
                 log_info("Grace period over, resuming full feature set (%s) for DNS server %s.",
                          dns_server_feature_level_to_string(s->possible_feature_level),
-                         dns_server_string(s));
+                         strna(dns_server_string_full(s)));
 
                 dns_server_flush_cache(s);
 
@@ -500,7 +503,7 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
 
                         log_full(log_level, "Using degraded feature set %s instead of %s for DNS server %s.",
                                  dns_server_feature_level_to_string(s->possible_feature_level),
-                                 dns_server_feature_level_to_string(p), dns_server_string(s));
+                                 dns_server_feature_level_to_string(p), strna(dns_server_string_full(s)));
                 }
         }
 
@@ -548,13 +551,37 @@ int dns_server_ifindex(const DnsServer *s) {
         return 0;
 }
 
+uint16_t dns_server_port(const DnsServer *s) {
+        assert(s);
+
+        if (s->port > 0)
+                return s->port;
+
+        return 53;
+}
+
 const char *dns_server_string(DnsServer *server) {
         assert(server);
 
         if (!server->server_string)
                 (void) in_addr_ifindex_to_string(server->family, &server->address, dns_server_ifindex(server), &server->server_string);
 
-        return strna(server->server_string);
+        return server->server_string;
+}
+
+const char *dns_server_string_full(DnsServer *server) {
+        assert(server);
+
+        if (!server->server_string_full)
+                (void) in_addr_port_ifindex_name_to_string(
+                                server->family,
+                                &server->address,
+                                server->port,
+                                dns_server_ifindex(server),
+                                server->server_name,
+                                &server->server_string_full);
+
+        return server->server_string_full;
 }
 
 bool dns_server_dnssec_supported(DnsServer *server) {
@@ -586,8 +613,8 @@ void dns_server_warn_downgrade(DnsServer *server) {
 
         log_struct(LOG_NOTICE,
                    "MESSAGE_ID=" SD_MESSAGE_DNSSEC_DOWNGRADE_STR,
-                   LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", dns_server_string(server)),
-                   "DNS_SERVER=%s", dns_server_string(server),
+                   LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", strna(dns_server_string_full(server))),
+                   "DNS_SERVER=%s", strna(dns_server_string_full(server)),
                    "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(server->possible_feature_level));
 
         server->warned_downgrade = true;
@@ -598,7 +625,10 @@ static void dns_server_hash_func(const DnsServer *s, struct siphash *state) {
 
         siphash24_compress(&s->family, sizeof(s->family), state);
         siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
+        siphash24_compress(&s->port, sizeof(s->port), state);
         siphash24_compress(&s->ifindex, sizeof(s->ifindex), state);
+        if (s->server_name)
+                siphash24_compress(s->server_name, strlen(s->server_name), state);
 }
 
 static int dns_server_compare_func(const DnsServer *x, const DnsServer *y) {
@@ -612,11 +642,15 @@ static int dns_server_compare_func(const DnsServer *x, const DnsServer *y) {
         if (r != 0)
                 return r;
 
+        r = CMP(x->port, y->port);
+        if (r != 0)
+                return r;
+
         r = CMP(x->ifindex, y->ifindex);
         if (r != 0)
                 return r;
 
-        return 0;
+        return streq_ptr(x->server_name, y->server_name);
 }
 
 DEFINE_HASH_OPS(dns_server_hash_ops, DnsServer, dns_server_hash_func, dns_server_compare_func);
@@ -655,11 +689,15 @@ void dns_server_mark_all(DnsServer *first) {
         dns_server_mark_all(first->servers_next);
 }
 
-DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex) {
+DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name) {
         DnsServer *s;
 
         LIST_FOREACH(servers, s, first)
-                if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0 && s->ifindex == ifindex)
+                if (s->family == family &&
+                    in_addr_equal(family, &s->address, in_addr) > 0 &&
+                    s->port == port &&
+                    s->ifindex == ifindex &&
+                    streq_ptr(s->server_name, name))
                         return s;
 
         return NULL;
@@ -690,7 +728,7 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) {
         if (s)
                 log_debug("Switching to %s DNS server %s.",
                           dns_server_type_to_string(s->type),
-                          dns_server_string(s));
+                          strna(dns_server_string_full(s)));
 
         dns_server_unref(m->current_dns_server);
         m->current_dns_server = dns_server_ref(s);
@@ -830,7 +868,7 @@ void dns_server_dump(DnsServer *s, FILE *f) {
                 f = stdout;
 
         fputs("[Server ", f);
-        fputs(dns_server_string(s), f);
+        fputs(strna(dns_server_string_full(s)), f);
         fputs(" type=", f);
         fputs(dns_server_type_to_string(s->type), f);
 
index 792f966121b0eef5a1412108a52b9ae0dee78851..464e8dc2515d51ad733e1db6493a9dd561eec2f8 100644 (file)
@@ -56,10 +56,11 @@ struct DnsServer {
         int family;
         union in_addr_union address;
         int ifindex; /* for IPv6 link-local DNS servers */
+        uint16_t port;
+        char *server_name;
 
         char *server_string;
-
-        char *server_name;
+        char *server_string_full;
 
         /* The long-lived stream towards this server. */
         DnsStream *stream;
@@ -102,6 +103,7 @@ int dns_server_new(
                 Link *link,
                 int family,
                 const union in_addr_union *address,
+                uint16_t port,
                 int ifindex,
                 const char *server_string);
 
@@ -123,13 +125,15 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s);
 int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level);
 
 const char *dns_server_string(DnsServer *server);
+const char *dns_server_string_full(DnsServer *server);
 int dns_server_ifindex(const DnsServer *s);
+uint16_t dns_server_port(const DnsServer *s);
 
 bool dns_server_dnssec_supported(DnsServer *server);
 
 void dns_server_warn_downgrade(DnsServer *server);
 
-DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, int ifindex);
+DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name);
 
 void dns_server_unlink_all(DnsServer *first);
 void dns_server_unlink_marked(DnsServer *first);
index cd5a0e3dd91b769c5a51d77360ff80ac03de2d03..e23ea273e7979835ea557548bb26c7714719e46d 100644 (file)
@@ -314,7 +314,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
                            "DNS_TRANSACTION=%" PRIu16, t->id,
                            "DNS_QUESTION=%s", key_str,
                            "DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result),
-                           "DNS_SERVER=%s", dns_server_string(t->server),
+                           "DNS_SERVER=%s", strna(dns_server_string_full(t->server)),
                            "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level));
         }
 
@@ -398,7 +398,7 @@ static int dns_transaction_pick_server(DnsTransaction *t) {
 
         t->n_picked_servers ++;
 
-        log_debug("Using DNS server %s for transaction %u.", dns_server_string(t->server), t->id);
+        log_debug("Using DNS server %s for transaction %u.", strna(dns_server_string_full(t->server)), t->id);
 
         return 1;
 }
@@ -544,8 +544,10 @@ static int on_stream_packet(DnsStream *s) {
         return 0;
 }
 
-static uint16_t dns_port_for_feature_level(DnsServerFeatureLevel level) {
-        return DNS_SERVER_FEATURE_LEVEL_IS_TLS(level) ? 853 : 53;
+static uint16_t dns_transaction_port(DnsTransaction *t) {
+        if (t->server->port > 0)
+                return t->server->port;
+        return DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53;
 }
 
 static int dns_transaction_emit_tcp(DnsTransaction *t) {
@@ -576,7 +578,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
                 if (t->server->stream && (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) == t->server->stream->encrypted))
                         s = dns_stream_ref(t->server->stream);
                 else
-                        fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_port_for_feature_level(t->current_feature_level), &sa);
+                        fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_transaction_port(t), &sa);
 
                 type = DNS_STREAM_LOOKUP;
                 break;
@@ -1243,7 +1245,7 @@ static int dns_transaction_emit_udp(DnsTransaction *t) {
 
                         dns_transaction_close_connection(t);
 
-                        fd = dns_scope_socket_udp(t->scope, t->server, 53);
+                        fd = dns_scope_socket_udp(t->scope, t->server);
                         if (fd < 0)
                                 return fd;
 
index 0fa62208c30a2e2c71f556e6244ff337ece21b2e..42d4ae7aaf863ee9f3278d893e4ba943cff566e3 100644 (file)
@@ -7,12 +7,14 @@
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-get-properties.h"
+#include "bus-message-util.h"
 #include "bus-polkit.h"
 #include "parse-util.h"
 #include "resolve-util.h"
 #include "resolved-bus.h"
 #include "resolved-link-bus.h"
 #include "resolved-resolv-conf.h"
+#include "socket-netlink.h"
 #include "stdio-util.h"
 #include "strv.h"
 #include "user-util.h"
@@ -37,14 +39,15 @@ static int property_get_dns_over_tls_mode(
         return sd_bus_message_append(reply, "s", dns_over_tls_mode_to_string(link_get_dns_over_tls_mode(l)));
 }
 
-static int property_get_dns(
+static int property_get_dns_internal(
                 sd_bus *bus,
                 const char *path,
                 const char *interface,
                 const char *property,
                 sd_bus_message *reply,
                 void *userdata,
-                sd_bus_error *error) {
+                sd_bus_error *error,
+                bool extended) {
 
         Link *l = userdata;
         DnsServer *s;
@@ -53,12 +56,12 @@ static int property_get_dns(
         assert(reply);
         assert(l);
 
-        r = sd_bus_message_open_container(reply, 'a', "(iay)");
+        r = sd_bus_message_open_container(reply, 'a', extended ? "(iayqs)" : "(iay)");
         if (r < 0)
                 return r;
 
         LIST_FOREACH(servers, s, l->dns_servers) {
-                r = bus_dns_server_append(reply, s, false);
+                r = bus_dns_server_append(reply, s, false, extended);
                 if (r < 0)
                         return r;
         }
@@ -66,7 +69,7 @@ static int property_get_dns(
         return sd_bus_message_close_container(reply);
 }
 
-static int property_get_current_dns_server(
+static int property_get_dns(
                 sd_bus *bus,
                 const char *path,
                 const char *interface,
@@ -74,6 +77,29 @@ static int property_get_current_dns_server(
                 sd_bus_message *reply,
                 void *userdata,
                 sd_bus_error *error) {
+        return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, false);
+}
+
+static int property_get_dns_ex(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, true);
+}
+
+static int property_get_current_dns_server_internal(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error,
+                bool extended) {
 
         DnsServer *s;
 
@@ -82,7 +108,29 @@ static int property_get_current_dns_server(
 
         s = *(DnsServer **) userdata;
 
-        return bus_dns_server_append(reply, s, false);
+        return bus_dns_server_append(reply, s, false, extended);
+}
+
+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) {
+        return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false);
+}
+
+static int property_get_current_dns_server_ex(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true);
 }
 
 static int property_get_domains(
@@ -204,11 +252,10 @@ static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
         return 0;
 }
 
-int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        _cleanup_free_ struct in_addr_data *dns = NULL;
-        size_t allocated = 0, n = 0;
+static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
+        struct in_addr_full **dns;
         Link *l = userdata;
-        unsigned i;
+        size_t n;
         int r;
 
         assert(message);
@@ -218,52 +265,7 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
         if (r < 0)
                 return r;
 
-        r = sd_bus_message_enter_container(message, 'a', "(iay)");
-        if (r < 0)
-                return r;
-
-        for (;;) {
-                int family;
-                size_t sz;
-                const void *d;
-
-                assert_cc(sizeof(int) == sizeof(int32_t));
-
-                r = sd_bus_message_enter_container(message, 'r', "iay");
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                r = sd_bus_message_read(message, "i", &family);
-                if (r < 0)
-                        return r;
-
-                if (!IN_SET(family, AF_INET, AF_INET6))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
-
-                r = sd_bus_message_read_array(message, 'y', &d, &sz);
-                if (r < 0)
-                        return r;
-                if (sz != FAMILY_ADDRESS_SIZE(family))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
-
-                if (!dns_server_address_valid(family, d))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
-
-                r = sd_bus_message_exit_container(message);
-                if (r < 0)
-                        return r;
-
-                if (!GREEDY_REALLOC(dns, allocated, n+1))
-                        return -ENOMEM;
-
-                dns[n].family = family;
-                memcpy(&dns[n].address, d, sz);
-                n++;
-        }
-
-        r = sd_bus_message_exit_container(message);
+        r = bus_message_read_dns_servers(message, error, extended, &dns, &n);
         if (r < 0)
                 return r;
 
@@ -272,22 +274,26 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
                                     NULL, true, UID_INVALID,
                                     &l->manager->polkit_registry, error);
         if (r < 0)
-                return r;
-        if (r == 0)
-                return 1; /* Polkit will call us back */
+                goto finalize;
+        if (r == 0) {
+                r = 1; /* Polkit will call us back */
+                goto finalize;
+        }
 
         dns_server_mark_all(l->dns_servers);
 
-        for (i = 0; i < n; i++) {
+        for (size_t i = 0; i < n; i++) {
                 DnsServer *s;
 
-                s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0);
+                s = dns_server_find(l->dns_servers, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name);
                 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, 0, NULL);
-                        if (r < 0)
-                                goto clear;
+                        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);
+                        if (r < 0) {
+                                dns_server_unlink_all(l->dns_servers);
+                                goto finalize;
+                        }
                 }
 
         }
@@ -299,13 +305,24 @@ int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_
         (void) manager_write_resolv_conf(l->manager);
         (void) manager_send_changed(l->manager, "DNS");
 
-        return sd_bus_reply_method_return(message, NULL);
+        r = sd_bus_reply_method_return(message, NULL);
+
+finalize:
+        for (size_t i = 0; i < n; i++)
+                in_addr_full_free(dns[i]);
+        free(dns);
 
-clear:
-        dns_server_unlink_all(l->dns_servers);
         return r;
 }
 
+int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_link_method_set_dns_servers_internal(message, userdata, error, false);
+}
+
+int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return bus_link_method_set_dns_servers_internal(message, userdata, error, true);
+}
+
 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Link *l = userdata;
         int r;
@@ -762,7 +779,9 @@ static const sd_bus_vtable link_vtable[] = {
 
         SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
         SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
+        SD_BUS_PROPERTY("DNSEx", "a(iayqs)", property_get_dns_ex, 0, 0),
         SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0),
+        SD_BUS_PROPERTY("CurrentDNSServerEx", "(iayqs)", property_get_current_dns_server_ex, offsetof(Link, current_dns_server), 0),
         SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
         SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
         SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
@@ -777,6 +796,11 @@ static const sd_bus_vtable link_vtable[] = {
                                 SD_BUS_NO_RESULT,
                                 bus_link_method_set_dns_servers,
                                 SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD_WITH_ARGS("SetDNSEx",
+                                SD_BUS_ARGS("a(iayqs)", addresses),
+                                SD_BUS_NO_RESULT,
+                                bus_link_method_set_dns_servers_ex,
+                                SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD_WITH_ARGS("SetDomains",
                                 SD_BUS_ARGS("a(sb)", domains),
                                 SD_BUS_NO_RESULT,
index c24996002437f106b02dde776c1ac05afe25ec94..fc85ff855c16f83e403906d0aaa05c2cab6f9658 100644 (file)
@@ -11,6 +11,7 @@ extern const BusObjectImplementation link_object;
 char *link_bus_path(const Link *link);
 
 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error);
index 5eb184a10f38e48919d5dfc0754180a7f958953c..f52c556bd13b72c011bc83b8d5fc75b278703eda 100644 (file)
@@ -15,6 +15,7 @@
 #include "resolved-link.h"
 #include "resolved-llmnr.h"
 #include "resolved-mdns.h"
+#include "socket-netlink.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tmpfile-util.h"
@@ -251,25 +252,35 @@ int link_process_rtnl(Link *l, sd_netlink_message *m) {
         return 0;
 }
 
-static int link_update_dns_server_one(Link *l, const char *name) {
+static int link_update_dns_server_one(Link *l, const char *str) {
+        _cleanup_free_ char *name = NULL;
+        int family, ifindex, r;
         union in_addr_union a;
         DnsServer *s;
-        int family, r;
+        uint16_t port;
 
         assert(l);
-        assert(name);
+        assert(str);
 
-        r = in_addr_from_string_auto(name, &family, &a);
+        r = in_addr_port_ifindex_name_from_string_auto(str, &family, &a, &port, &ifindex, &name);
         if (r < 0)
                 return r;
 
-        s = dns_server_find(l->dns_servers, family, &a, 0);
+        if (ifindex != 0 && ifindex != l->ifindex)
+                return -EINVAL;
+
+        /* 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;
+
+        s = dns_server_find(l->dns_servers, family, &a, port, 0, name);
         if (s) {
                 dns_server_move_back_and_unmark(s);
                 return 0;
         }
 
-        return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, 0, NULL);
+        return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name);
 }
 
 static int link_update_dns_servers(Link *l) {
@@ -652,7 +663,9 @@ int link_update(Link *l) {
         assert(l);
 
         link_read_settings(l);
-        link_load_user(l);
+        r = link_load_user(l);
+        if (r < 0)
+                return r;
 
         if (l->llmnr_support != RESOLVE_SUPPORT_NO) {
                 r = manager_llmnr_start(l->manager);
@@ -730,7 +743,7 @@ DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
                 return s;
 
         if (s)
-                log_debug("Switching to DNS server %s for interface %s.", dns_server_string(s), l->ifname);
+                log_debug("Switching to DNS server %s for interface %s.", strna(dns_server_string_full(s)), l->ifname);
 
         dns_server_unref(l->current_dns_server);
         l->current_dns_server = dns_server_ref(s);
@@ -1207,7 +1220,7 @@ int link_save_user(Link *l) {
                         if (server != l->dns_servers)
                                 fputc(' ', f);
 
-                        v = dns_server_string(server);
+                        v = dns_server_string_full(server);
                         if (!v) {
                                 r = -ENOMEM;
                                 goto fail;
index 6b996015e38939140e190fa0ad2833b137ad4fef..d4ce3966e7649ca041d95ecad60f4d24468e8c77 100644 (file)
@@ -1753,7 +1753,7 @@ static int run(int argc, char* argv[]) {
         else
                 r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         if (arg_scope)
                 r = start_transient_scope(bus);
index 1ccb4f8295f06a013060881c5defc290f9cd0de6..dd2b1efb112901fd80a99ff11156c82bb6ebf9c4 100644 (file)
@@ -378,10 +378,13 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
 
 int add_acls_for_user(int fd, uid_t uid) {
         _cleanup_(acl_freep) acl_t acl = NULL;
-        acl_entry_t entry;
         acl_permset_t permset;
+        acl_entry_t entry;
         int r;
 
+        assert(fd >= 0);
+        assert(uid_is_valid(uid));
+
         acl = acl_get_fd(fd);
         if (!acl)
                 return -errno;
@@ -394,8 +397,8 @@ int add_acls_for_user(int fd, uid_t uid) {
                         return -errno;
         }
 
-        /* We do not recalculate the mask unconditionally here,
-         * so that the fchmod() mask above stays intact. */
+        /* We do not recalculate the mask unconditionally here, so that the fchmod() mask above stays
+         * intact. */
         if (acl_get_permset(entry, &permset) < 0 ||
             acl_add_perm(permset, ACL_READ) < 0)
                 return -errno;
@@ -404,5 +407,8 @@ int add_acls_for_user(int fd, uid_t uid) {
         if (r < 0)
                 return r;
 
-        return acl_set_fd(fd, acl);
+        if (acl_set_fd(fd, acl) < 0)
+                return -errno;
+
+        return 0;
 }
index d853b79d8db60cda87160bba89d985c7259ff514..81af74309d965699c237214c3df09254cb84a3c5 100644 (file)
@@ -3,8 +3,6 @@
 
 #include "sd-bus.h"
 
-#include "sd-bus.h"
-
 #include "macro.h"
 
 int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
diff --git a/src/shared/bus-message-util.c b/src/shared/bus-message-util.c
new file mode 100644 (file)
index 0000000..85e1e98
--- /dev/null
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-message-util.h"
+
+#include "resolve-util.h"
+
+int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *error, int *ret) {
+        int ifindex, r;
+
+        assert(message);
+        assert(ret);
+
+        assert_cc(sizeof(int) == sizeof(int32_t));
+
+        r = sd_bus_message_read(message, "i", &ifindex);
+        if (r < 0)
+                return r;
+
+        if (ifindex <= 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+
+        *ret = ifindex;
+
+        return 0;
+}
+
+int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret) {
+        int family, r;
+
+        assert(message);
+        assert(ret);
+
+        assert_cc(sizeof(int) == sizeof(int32_t));
+
+        r = sd_bus_message_read(message, "i", &family);
+        if (r < 0)
+                return r;
+
+        if (!IN_SET(family, AF_INET, AF_INET6))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
+
+        *ret = family;
+        return 0;
+}
+
+int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr) {
+        int family, r;
+        const void *d;
+        size_t sz;
+
+        assert(message);
+
+        r = sd_bus_message_read(message, "i", &family);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_array(message, 'y', &d, &sz);
+        if (r < 0)
+                return r;
+
+        if (!IN_SET(family, AF_INET, AF_INET6))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
+
+        if (sz != FAMILY_ADDRESS_SIZE(family))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
+
+        if (ret_family)
+                *ret_family = family;
+        if (ret_addr)
+                memcpy(ret_addr, d, sz);
+        return 0;
+}
+
+static int bus_message_read_dns_one(
+                        sd_bus_message *message,
+                        sd_bus_error *error,
+                        bool extended,
+                        int *ret_family,
+                        union in_addr_union *ret_address,
+                        uint16_t *ret_port,
+                        const char **ret_server_name) {
+        const char *server_name = NULL;
+        union in_addr_union a;
+        uint16_t port = 0;
+        int family, r;
+
+        assert(message);
+        assert(ret_family);
+        assert(ret_address);
+        assert(ret_port);
+        assert(ret_server_name);
+
+        r = sd_bus_message_enter_container(message, 'r', extended ? "iayqs" : "iay");
+        if (r <= 0)
+                return r;
+
+        r = bus_message_read_in_addr_auto(message, error, &family, &a);
+        if (r < 0)
+                return r;
+
+        if (!dns_server_address_valid(family, &a))
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
+
+        if (extended) {
+                r = sd_bus_message_read(message, "q", &port);
+                if (r < 0)
+                        return r;
+
+                if (IN_SET(port, 53, 853))
+                        port = 0;
+
+                r = sd_bus_message_read(message, "s", &server_name);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_exit_container(message);
+        if (r < 0)
+                return r;
+
+        *ret_family = family;
+        *ret_address = a;
+        *ret_port = port;
+        *ret_server_name = server_name;
+
+        return 1;
+}
+
+int bus_message_read_dns_servers(
+                        sd_bus_message *message,
+                        sd_bus_error *error,
+                        bool extended,
+                        struct in_addr_full ***ret_dns,
+                        size_t *ret_n_dns) {
+
+        struct in_addr_full **dns = NULL;
+        size_t n = 0, allocated = 0;
+        int r;
+
+        assert(message);
+        assert(ret_dns);
+        assert(ret_n_dns);
+
+        r = sd_bus_message_enter_container(message, 'a', extended ? "(iayqs)" : "(iay)");
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                const char *server_name;
+                union in_addr_union a;
+                uint16_t port;
+                int family;
+
+                r = bus_message_read_dns_one(message, error, extended, &family, &a, &port, &server_name);
+                if (r < 0)
+                        goto clear;
+                if (r == 0)
+                        break;
+
+                if (!GREEDY_REALLOC(dns, allocated, n+1)) {
+                        r = -ENOMEM;
+                        goto clear;
+                }
+
+                r = in_addr_full_new(family, &a, port, 0, server_name, dns + n);
+                if (r < 0)
+                        goto clear;
+
+                n++;
+        }
+
+        *ret_dns = TAKE_PTR(dns);
+        *ret_n_dns = n;
+        return 0;
+
+clear:
+        for (size_t i = 0; i < n; i++)
+                in_addr_full_free(dns[i]);
+        free(dns);
+
+        return r;
+}
diff --git a/src/shared/bus-message-util.h b/src/shared/bus-message-util.h
new file mode 100644 (file)
index 0000000..98ad035
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-bus.h"
+
+#include "in-addr-util.h"
+#include "socket-netlink.h"
+
+int bus_message_read_ifindex(sd_bus_message *message, sd_bus_error *error, int *ret);
+int bus_message_read_family(sd_bus_message *message, sd_bus_error *error, int *ret);
+int bus_message_read_in_addr_auto(sd_bus_message *message, sd_bus_error *error, int *ret_family, union in_addr_union *ret_addr);
+
+int bus_message_read_dns_servers(
+                        sd_bus_message *message,
+                        sd_bus_error *error,
+                        bool extended,
+                        struct in_addr_full ***ret_dns,
+                        size_t *ret_n_dns);
index fd88314c1f44634b4398d51866e4710cb87b4684..d98e0040f3b682bddac13410c5ba2fac12047eb2 100644 (file)
@@ -37,6 +37,9 @@ int bus_connect_user_systemd(sd_bus **_bus);
 int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
 int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
 
+#define bus_log_connect_error(r) \
+        log_error_errno(r, "Failed to create bus connection: %m")
+
 #define bus_log_parse_error(r) \
         log_error_errno(r, "Failed to parse bus message: %m")
 
index 208d27df1a3a2fb527ec4e9724014429b9f01707..b8bf3c27264295ac2142e072fec4f5daa126f1bf 100644 (file)
@@ -371,7 +371,7 @@ int show_cgroup_get_path_and_warn(
 
                 r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to create bus connection: %m");
+                        return bus_log_connect_error(r);
 
                 r = show_cgroup_get_unit_path_and_warn(bus, unit, &root);
                 if (r < 0)
index 1868e8aede9bd6656d02c1fc50db7844f02ecfe3..0da733c3fe7b3e61c53970834781151d3bb2340f 100644 (file)
@@ -35,6 +35,8 @@ shared_sources = files('''
         bus-log-control-api.h
         bus-map-properties.c
         bus-map-properties.h
+        bus-message-util.c
+        bus-message-util.h
         bus-object.c
         bus-object.h
         bus-polkit.c
diff --git a/src/shared/offline-passwd.c b/src/shared/offline-passwd.c
new file mode 100644 (file)
index 0000000..26a1b9c
--- /dev/null
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "fd-util.h"
+#include "fs-util.h"
+#include "offline-passwd.h"
+#include "path-util.h"
+#include "user-util.h"
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(uid_gid_hash_ops, char, string_hash_func, string_compare_func, free);
+
+static int open_passwd_file(const char *root, const char *fname, FILE **ret_file) {
+        _cleanup_free_ char *p = NULL;
+        _cleanup_close_ int fd = -1;
+
+        fd = chase_symlinks_and_open(fname, root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC, &p);
+        if (fd < 0)
+                return fd;
+
+        FILE *f = fdopen(fd, "r");
+        if (!f)
+                return -errno;
+
+        TAKE_FD(fd);
+
+        log_debug("Reading %s entries from %s...", basename(fname), p);
+
+        *ret_file = f;
+        return 0;
+}
+
+static int populate_uid_cache(const char *root, Hashmap **ret) {
+        _cleanup_(hashmap_freep) Hashmap *cache = NULL;
+        int r;
+
+        cache = hashmap_new(&uid_gid_hash_ops);
+        if (!cache)
+                return -ENOMEM;
+
+        /* The directory list is harcoded here: /etc is the standard, and rpm-ostree uses /usr/lib. This
+         * could be made configurable, but I don't see the point right now. */
+
+        const char *fname;
+        FOREACH_STRING(fname, "/etc/passwd", "/usr/lib/passwd") {
+                _cleanup_fclose_ FILE *f = NULL;
+
+                r = open_passwd_file(root, fname, &f);
+                if (r == -ENOENT)
+                        continue;
+                if (r < 0)
+                        return r;
+
+                struct passwd *pw;
+                while ((r = fgetpwent_sane(f, &pw)) > 0) {
+                        _cleanup_free_ char *n = NULL;
+
+                        n = strdup(pw->pw_name);
+                        if (!n)
+                                return -ENOMEM;
+
+                        r = hashmap_put(cache, n, UID_TO_PTR(pw->pw_uid));
+                        if (IN_SET(r, 0 -EEXIST))
+                                continue;
+                        if (r < 0)
+                                return r;
+                        TAKE_PTR(n);
+                }
+        }
+
+        *ret = TAKE_PTR(cache);
+        return 0;
+}
+
+static int populate_gid_cache(const char *root, Hashmap **ret) {
+        _cleanup_(hashmap_freep) Hashmap *cache = NULL;
+        int r;
+
+        cache = hashmap_new(&uid_gid_hash_ops);
+        if (!cache)
+                return -ENOMEM;
+
+        const char *fname;
+        FOREACH_STRING(fname, "/etc/group", "/usr/lib/group") {
+                _cleanup_fclose_ FILE *f = NULL;
+
+                r = open_passwd_file(root, fname, &f);
+                if (r == -ENOENT)
+                        continue;
+                if (r < 0)
+                        return r;
+
+                struct group *gr;
+                while ((r = fgetgrent_sane(f, &gr)) > 0) {
+                        _cleanup_free_ char *n = NULL;
+
+                        n = strdup(gr->gr_name);
+                        if (!n)
+                                return -ENOMEM;
+
+                        r = hashmap_put(cache, n, GID_TO_PTR(gr->gr_gid));
+                        if (IN_SET(r, 0, -EEXIST))
+                                continue;
+                        if (r < 0)
+                                return r;
+                        TAKE_PTR(n);
+                }
+        }
+
+        *ret = TAKE_PTR(cache);
+        return 0;
+}
+
+int name_to_uid_offline(
+                const char *root,
+                const char *user,
+                uid_t *ret_uid,
+                Hashmap **cache) {
+
+        void *found;
+        int r;
+
+        assert(user);
+        assert(ret_uid);
+        assert(cache);
+
+        if (!*cache) {
+                r = populate_uid_cache(root, cache);
+                if (r < 0)
+                        return r;
+        }
+
+        found = hashmap_get(*cache, user);
+        if (!found)
+                return -ESRCH;
+
+        *ret_uid = PTR_TO_UID(found);
+        return 0;
+}
+
+int name_to_gid_offline(
+                const char *root,
+                const char *group,
+                gid_t *ret_gid,
+                Hashmap **cache) {
+
+        void *found;
+        int r;
+
+        assert(group);
+        assert(ret_gid);
+        assert(cache);
+
+        if (!*cache) {
+                r = populate_gid_cache(root, cache);
+                if (r < 0)
+                        return r;
+        }
+
+        found = hashmap_get(*cache, group);
+        if (!found)
+                return -ESRCH;
+
+        *ret_gid = PTR_TO_GID(found);
+        return 0;
+}
index 16b0e6a5c3c609313819d1e3e20465094dddbc57..d72a70503a94efaaa91c39ed1828fc153a40336c 100644 (file)
@@ -327,68 +327,197 @@ int make_socket_fd(int log_level, const char* address, int type, int flags) {
         return fd;
 }
 
-int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret_addr, int *ret_ifindex) {
-        _cleanup_free_ char *buf = NULL;
-        const char *suffix;
-        int r, ifindex = 0;
+int in_addr_port_ifindex_name_from_string_auto(
+                const char *s,
+                int *ret_family,
+                union in_addr_union *ret_address,
+                uint16_t *ret_port,
+                int *ret_ifindex,
+                char **ret_server_name) {
+
+        _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *name = NULL;
+        int family, ifindex = 0, r;
+        union in_addr_union a;
+        uint16_t port = 0;
+        const char *m;
 
         assert(s);
-        assert(family);
-        assert(ret_addr);
 
-        /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
-         * if one is found. */
+        /* This accepts the following:
+         * 192.168.0.1:53#example.com
+         * [2001:4860:4860::8888]:53%eth0#example.com */
+
+        /* if ret_port is NULL, then strings with port cannot be specified.
+         * Also, if ret_server_name is NULL, then server_name cannot be specified. */
+
+        m = strchr(s, '#');
+        if (m) {
+                if (!ret_server_name)
+                        return -EINVAL;
+
+                if (isempty(m + 1))
+                        return -EINVAL;
+
+                name = strdup(m + 1);
+                if (!name)
+                        return -ENOMEM;
+
+                s = buf1 = strndup(s, m - s);
+                if (!buf1)
+                        return -ENOMEM;
+        }
+
+        m = strchr(s, '%');
+        if (m) {
+                if (isempty(m + 1))
+                        return -EINVAL;
 
-        suffix = strchr(s, '%');
-        if (suffix) {
                 if (ret_ifindex) {
                         /* If we shall return the interface index, try to parse it */
-                        ifindex = resolve_interface(NULL, suffix + 1);
+                        ifindex = resolve_interface(NULL, m + 1);
                         if (ifindex < 0)
                                 return ifindex;
                 }
 
-                s = buf = strndup(s, suffix - s);
-                if (!buf)
+                s = buf2 = strndup(s, m - s);
+                if (!buf2)
                         return -ENOMEM;
         }
 
-        r = in_addr_from_string_auto(s, family, ret_addr);
-        if (r < 0)
-                return r;
+        m = strrchr(s, ':');
+        if (m) {
+                if (*s == '[') {
+                        _cleanup_free_ char *ip_str = NULL;
+
+                        if (!ret_port)
+                                return -EINVAL;
+
+                        if (*(m - 1) != ']')
+                                return -EINVAL;
+
+                        family = AF_INET6;
+
+                        r = parse_ip_port(m + 1, &port);
+                        if (r < 0)
+                                return r;
+
+                        ip_str = strndup(s + 1, m - s - 2);
+                        if (!ip_str)
+                                return -ENOMEM;
+
+                        r = in_addr_from_string(family, ip_str, &a);
+                        if (r < 0)
+                                return r;
+                } else {
+                        /* First try to parse the string as IPv6 address without port number */
+                        r = in_addr_from_string(AF_INET6, s, &a);
+                        if (r < 0) {
+                                /* Then the input should be IPv4 address with port number */
+                                _cleanup_free_ char *ip_str = NULL;
+
+                                if (!ret_port)
+                                        return -EINVAL;
+
+                                family = AF_INET;
+
+                                ip_str = strndup(s, m - s);
+                                if (!ip_str)
+                                        return -ENOMEM;
+
+                                r = in_addr_from_string(family, ip_str, &a);
+                                if (r < 0)
+                                        return r;
+
+                                r = parse_ip_port(m + 1, &port);
+                                if (r < 0)
+                                        return r;
+                        } else
+                                family = AF_INET6;
+                }
+        } else {
+                family = AF_INET;
+                r = in_addr_from_string(family, s, &a);
+                if (r < 0)
+                        return r;
+        }
 
+        if (ret_family)
+                *ret_family = family;
+        if (ret_address)
+                *ret_address = a;
+        if (ret_port)
+                *ret_port = port;
         if (ret_ifindex)
                 *ret_ifindex = ifindex;
+        if (ret_server_name)
+                *ret_server_name = TAKE_PTR(name);
 
         return r;
 }
 
-int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
-        _cleanup_free_ char *buf = NULL, *name = NULL;
-        const char *m;
-        int r;
+struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
+        if (!a)
+                return NULL;
 
-        assert(s);
+        free(a->server_name);
+        free(a->cached_server_string);
+        return mfree(a);
+}
 
-        m = strchr(s, '#');
-        if (m) {
-                name = strdup(m+1);
+int in_addr_full_new(int family, union in_addr_union *a, uint16_t port, int ifindex, const char *server_name, struct in_addr_full **ret) {
+        _cleanup_free_ char *name = NULL;
+        struct in_addr_full *x;
+
+        assert(ret);
+
+        if (!isempty(server_name)) {
+                name = strdup(server_name);
                 if (!name)
                         return -ENOMEM;
+        }
 
-                buf = strndup(s, m - s);
-                if (!buf)
-                        return -ENOMEM;
+        x = new(struct in_addr_full, 1);
+        if (!x)
+                return -ENOMEM;
 
-                s = buf;
-        }
+        *x = (struct in_addr_full) {
+                .family = family,
+                .address = *a,
+                .port = port,
+                .ifindex = ifindex,
+                .server_name = TAKE_PTR(name),
+        };
+
+        *ret = x;
+        return 0;
+}
+
+int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret) {
+        _cleanup_free_ char *server_name = NULL;
+        int family, ifindex, r;
+        union in_addr_union a;
+        uint16_t port;
 
-        r = in_addr_ifindex_from_string_auto(s, family, ret, ifindex);
+        assert(s);
+
+        r = in_addr_port_ifindex_name_from_string_auto(s, &family, &a, &port, &ifindex, &server_name);
         if (r < 0)
                 return r;
 
-        if (server_name)
-                *server_name = TAKE_PTR(name);
+        return in_addr_full_new(family, &a, port, ifindex, server_name, ret);
+}
 
-        return r;
+const char *in_addr_full_to_string(struct in_addr_full *a) {
+        assert(a);
+
+        if (!a->cached_server_string)
+                (void) in_addr_port_ifindex_name_to_string(
+                                a->family,
+                                &a->address,
+                                a->port,
+                                a->ifindex,
+                                a->server_name,
+                                &a->cached_server_string);
+
+        return a->cached_server_string;
 }
index 35c35db52d1999ff7e8aa5f470a52e28d0f59c5c..9517f6dd6d14ff5e879b903c1228dcb325c02a64 100644 (file)
@@ -20,5 +20,31 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s);
 bool socket_address_is(const SocketAddress *a, const char *s, int type);
 bool socket_address_is_netlink(const SocketAddress *a, const char *s);
 
-int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
-int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name);
+int in_addr_port_ifindex_name_from_string_auto(
+                const char *s,
+                int *ret_family,
+                union in_addr_union *ret_address,
+                uint16_t *ret_port,
+                int *ret_ifindex,
+                char **ret_server_name);
+static inline int in_addr_ifindex_name_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex, char **server_name) {
+        return in_addr_port_ifindex_name_from_string_auto(s, family, ret, NULL, ifindex, server_name);
+}
+static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
+        return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL);
+}
+
+struct in_addr_full {
+        int family;
+        union in_addr_union address;
+        uint16_t port;
+        int ifindex;
+        char *server_name;
+        char *cached_server_string; /* Should not be handled directly, but through in_addr_full_to_string(). */
+};
+
+struct in_addr_full *in_addr_full_free(struct in_addr_full *a);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct in_addr_full*, in_addr_full_free);
+int in_addr_full_new(int family, union in_addr_union *a, uint16_t port, int ifindex, const char *server_name, struct in_addr_full **ret);
+int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret);
+const char *in_addr_full_to_string(struct in_addr_full *a);
index 011e40d8a5c68552a637503a62f63924408acc54..0f1437829d03f11a4e9483e21e6ffd03b7a1b41b 100644 (file)
@@ -50,6 +50,7 @@ sd_event *sd_radv_get_event(sd_radv *ra);
 
 int sd_radv_start(sd_radv *ra);
 int sd_radv_stop(sd_radv *ra);
+int sd_radv_is_running(sd_radv *ra);
 
 int sd_radv_set_ifindex(sd_radv *ra, int interface_index);
 int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr);
index d3fc803088f3643f3d22b689017b6f5c280654dc..4affcd647f98b77371e573fe13efec36ef5eabe4 100644 (file)
@@ -301,6 +301,12 @@ tests += [
          [],
          []],
 
+        [['src/test/test-offline-passwd.c',
+          'src/shared/offline-passwd.c',
+          'src/shared/offline-passwd.h'],
+         [],
+         []],
+
         [['src/test/test-escape.c'],
          [],
          []],
index af9696ef597f3e00e5020180397b5f19bdee4a6a..95dcd4fdb180af9ef9c397d92e0e0f1719641b57 100644 (file)
@@ -15,6 +15,8 @@
 #include "io-util.h"
 #include "parse-util.h"
 #include "process-util.h"
+#include "rm-rf.h"
+#include "socket-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tests.h"
@@ -842,6 +844,53 @@ static void test_read_nul_string(void) {
         assert_se(read_nul_string(f, LONG_LINE_MAX, &s) == 0 && streq_ptr(s, ""));
 }
 
+static void test_read_full_file_socket(void) {
+        _cleanup_(rm_rf_physical_and_freep) char *z = NULL;
+        _cleanup_close_ int listener = -1;
+        _cleanup_free_ char *data = NULL;
+        union sockaddr_union sa;
+        const char *j;
+        size_t size;
+        pid_t pid;
+        int r;
+
+        log_info("/* %s */", __func__);
+
+        listener = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+        assert_se(listener >= 0);
+
+        assert_se(mkdtemp_malloc(NULL, &z) >= 0);
+        j = strjoina(z, "/socket");
+
+        assert_se(sockaddr_un_set_path(&sa.un, j) >= 0);
+
+        assert_se(bind(listener, &sa.sa, SOCKADDR_UN_LEN(sa.un)) >= 0);
+        assert_se(listen(listener, 1) >= 0);
+
+        r = safe_fork("(server)", FORK_DEATHSIG|FORK_LOG, &pid);
+        assert_se(r >= 0);
+        if (r == 0) {
+                _cleanup_close_ int rfd = -1;
+                /* child */
+
+                rfd = accept4(listener, NULL, 0, SOCK_CLOEXEC);
+                assert_se(rfd >= 0);
+
+#define TEST_STR "This is a test\nreally."
+
+                assert_se(write(rfd, TEST_STR, strlen(TEST_STR)) == strlen(TEST_STR));
+                _exit(EXIT_SUCCESS);
+        }
+
+        assert_se(read_full_file_full(AT_FDCWD, j, 0, &data, &size) == -ENXIO);
+        assert_se(read_full_file_full(AT_FDCWD, j, READ_FULL_FILE_CONNECT_SOCKET, &data, &size) >= 0);
+        assert_se(size == strlen(TEST_STR));
+        assert_se(streq(data, TEST_STR));
+
+        assert_se(wait_for_terminate_and_check("(server)", pid, WAIT_LOG) >= 0);
+#undef TEST_STR
+}
+
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
@@ -867,6 +916,7 @@ int main(int argc, char *argv[]) {
         test_read_line3();
         test_read_line4();
         test_read_nul_string();
+        test_read_full_file_socket();
 
         return 0;
 }
diff --git a/src/test/test-offline-passwd.c b/src/test/test-offline-passwd.c
new file mode 100644 (file)
index 0000000..5933ec2
--- /dev/null
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <getopt.h>
+
+#include "offline-passwd.h"
+#include "user-util.h"
+#include "format-util.h"
+#include "tests.h"
+
+static char *arg_root = NULL;
+
+static void test_resolve_one(const char *name) {
+        bool relaxed = name || arg_root;
+
+        if (!name)
+                name = "root";
+
+        log_info("/* %s(\"%s\") */", __func__, name);
+
+        _cleanup_(hashmap_freep) Hashmap *uid_cache = NULL, *gid_cache = NULL;
+        uid_t uid = UID_INVALID;
+        gid_t gid = GID_INVALID;
+        int r;
+
+        r = name_to_uid_offline(arg_root, name, &uid, &uid_cache);
+        log_info_errno(r, "name_to_uid_offline: %s â†’ "UID_FMT": %m", name, uid);
+        assert_se(relaxed || r == 0);
+
+        r = name_to_uid_offline(arg_root, name, &uid, &uid_cache);
+        log_info_errno(r, "name_to_uid_offline: %s â†’ "UID_FMT": %m", name, uid);
+        assert_se(relaxed || r == 0);
+
+        r = name_to_gid_offline(arg_root, name, &gid, &gid_cache);
+        log_info_errno(r, "name_to_gid_offline: %s â†’ "GID_FMT": %m", name, gid);
+        assert_se(relaxed || r == 0);
+
+        r = name_to_gid_offline(arg_root, name, &gid, &gid_cache);
+        log_info_errno(r, "name_to_gid_offline: %s â†’ "GID_FMT": %m", name, gid);
+        assert_se(relaxed || r == 0);
+}
+
+static int parse_argv(int argc, char *argv[]) {
+        static const struct option options[] = {
+                { "root",           required_argument,   NULL, 'r' },
+                {}
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "r:", options, NULL)) >= 0)
+                switch(c) {
+                case 'r':
+                        arg_root = optarg;
+                        break;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        assert_not_reached("Unhandled option");
+                }
+
+        return 0;
+}
+
+int main(int argc, char **argv) {
+        int r;
+
+        test_setup_logging(LOG_DEBUG);
+
+        r = parse_argv(argc, argv);
+        if (r < 0)
+                return r;
+
+        if (optind >= argc)
+                test_resolve_one(NULL);
+        else
+                while (optind < argc)
+                        test_resolve_one(argv[optind++]);
+
+        return 0;
+}
index 024e12a7993a4b449b7aa81cebd2bcf3d4ec3289..b007dd62764608bbff233dc1aff23f482037498c 100644 (file)
@@ -302,6 +302,38 @@ static void test_in_addr_ifindex_name_from_string_auto(void) {
         test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
 }
 
+static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex, const char *server_name) {
+        _cleanup_free_ char *name = NULL, *x = NULL;
+        union in_addr_union a;
+        uint16_t p;
+        int f, i;
+
+        assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) >= 0);
+        assert_se(family == f);
+        assert_se(port == p);
+        assert_se(ifindex == i);
+        assert_se(streq_ptr(server_name, name));
+        assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0);
+        assert_se(streq(str, x));
+}
+
+static void test_in_addr_port_ifindex_name_from_string_auto(void) {
+        log_info("/* %s */", __func__);
+
+        test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL);
+        test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com");
+        test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL);
+        test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com");
+        test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL);
+        test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com");
+        test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL);
+        test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL);
+        test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com");
+        test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com");
+        test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL);
+        test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com");
+}
+
 static void test_sockaddr_equal(void) {
         union sockaddr_union a = {
                 .in.sin_family = AF_INET,
@@ -735,6 +767,7 @@ int main(int argc, char *argv[]) {
         test_in_addr_ifindex_to_string();
         test_in_addr_ifindex_from_string_auto();
         test_in_addr_ifindex_name_from_string_auto();
+        test_in_addr_port_ifindex_name_from_string_auto();
 
         test_sockaddr_equal();
 
index 49d68d2533449ac85817718a1d2a47ced2e57d76..26d3e203530ae4e2e0476ddf0b90c8374371566c 100644 (file)
@@ -1062,7 +1062,7 @@ static int run(int argc, char *argv[]) {
 
         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
         if (r < 0)
-                return log_error_errno(r, "Failed to create bus connection: %m");
+                return bus_log_connect_error(r);
 
         return timedatectl_main(bus, argc, argv);
 }
index 2f8fb29bd949e9162c53d0433a235005713aeba5..434dcf800dbc2f849b5126040bd084e5ac25a60b 100644 (file)
@@ -2,6 +2,6 @@
 
 systemd_tmpfiles_sources = [
         'src/tmpfiles/tmpfiles.c',
-        'src/tmpfiles/offline-passwd.c',
-        'src/tmpfiles/offline-passwd.h',
+        'src/shared/offline-passwd.c',
+        'src/shared/offline-passwd.h',
 ]
diff --git a/src/tmpfiles/offline-passwd.c b/src/tmpfiles/offline-passwd.c
deleted file mode 100644 (file)
index 8ac5431..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-
-#include "fd-util.h"
-#include "offline-passwd.h"
-#include "path-util.h"
-#include "user-util.h"
-
-DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(uid_gid_hash_ops, char, string_hash_func, string_compare_func, free);
-
-int name_to_uid_offline(
-                const char *root,
-                const char *user,
-                uid_t *ret_uid,
-                Hashmap **cache) {
-
-        void *found;
-        int r;
-
-        assert(user);
-        assert(ret_uid);
-        assert(cache);
-
-        if (!*cache) {
-                _cleanup_(hashmap_freep) Hashmap *uid_by_name = NULL;
-                _cleanup_fclose_ FILE *f = NULL;
-                struct passwd *pw;
-                const char *passwd_path;
-
-                passwd_path = prefix_roota(root, "/etc/passwd");
-                f = fopen(passwd_path, "re");
-                if (!f)
-                        return errno == ENOENT ? -ESRCH : -errno;
-
-                uid_by_name = hashmap_new(&uid_gid_hash_ops);
-                if (!uid_by_name)
-                        return -ENOMEM;
-
-                while ((r = fgetpwent_sane(f, &pw)) > 0) {
-                        _cleanup_free_ char *n = NULL;
-
-                        n = strdup(pw->pw_name);
-                        if (!n)
-                                return -ENOMEM;
-
-                        r = hashmap_put(uid_by_name, n, UID_TO_PTR(pw->pw_uid));
-                        if (r == -EEXIST) {
-                                log_warning_errno(r, "Duplicate entry in %s for %s: %m", passwd_path, pw->pw_name);
-                                continue;
-                        }
-                        if (r < 0)
-                                return r;
-
-                        TAKE_PTR(n);
-                }
-
-                *cache = TAKE_PTR(uid_by_name);
-        }
-
-        found = hashmap_get(*cache, user);
-        if (!found)
-                return -ESRCH;
-
-        *ret_uid = PTR_TO_UID(found);
-        return 0;
-}
-
-int name_to_gid_offline(
-                const char *root,
-                const char *group,
-                gid_t *ret_gid,
-                Hashmap **cache) {
-
-        void *found;
-        int r;
-
-        assert(group);
-        assert(ret_gid);
-        assert(cache);
-
-        if (!*cache) {
-                _cleanup_(hashmap_freep) Hashmap *gid_by_name = NULL;
-                _cleanup_fclose_ FILE *f = NULL;
-                struct group *gr;
-                const char *group_path;
-
-                group_path = prefix_roota(root, "/etc/group");
-                f = fopen(group_path, "re");
-                if (!f)
-                        return errno == ENOENT ? -ESRCH : -errno;
-
-                gid_by_name = hashmap_new(&uid_gid_hash_ops);
-                if (!gid_by_name)
-                        return -ENOMEM;
-
-                while ((r = fgetgrent_sane(f, &gr)) > 0) {
-                        _cleanup_free_ char *n = NULL;
-
-                        n = strdup(gr->gr_name);
-                        if (!n)
-                                return -ENOMEM;
-
-                        r = hashmap_put(gid_by_name, n, GID_TO_PTR(gr->gr_gid));
-                        if (r == -EEXIST) {
-                                log_warning_errno(r, "Duplicate entry in %s for %s: %m", group_path, gr->gr_name);
-                                continue;
-                        }
-                        if (r < 0)
-                                return r;
-
-                        TAKE_PTR(n);
-                }
-
-                *cache = TAKE_PTR(gid_by_name);
-        }
-
-        found = hashmap_get(*cache, group);
-        if (!found)
-                return -ESRCH;
-
-        *ret_gid = PTR_TO_GID(found);
-        return 0;
-}
index 39bdfb73dd7a7ddbe43ee29a08ca51fb14507bde..72ef0c56be02ea569942371093ac87878ef9730d 100644 (file)
@@ -358,7 +358,7 @@ static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr
 
 int link_config_apply(link_config_ctx *ctx, link_config *config,
                       sd_device *device, const char **name) {
-        _cleanup_strv_free_ char **altnames = NULL;
+        _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
         struct ether_addr generated_mac;
         struct ether_addr *mac = NULL;
         const char *new_name = NULL;
@@ -539,9 +539,17 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
         if (new_name)
                 strv_remove(altnames, new_name);
         strv_remove(altnames, old_name);
+
+        r = rtnl_get_link_alternative_names(&ctx->rtnl, ifindex, &current_altnames);
+        if (r < 0)
+                log_debug_errno(r, "Failed to get alternative names on %s, ignoring: %m", old_name);
+
+        char **p;
+        STRV_FOREACH(p, current_altnames)
+                strv_remove(altnames, *p);
+
         strv_uniq(altnames);
         strv_sort(altnames);
-
         r = rtnl_set_link_alternative_names(&ctx->rtnl, ifindex, altnames);
         if (r == -EOPNOTSUPP)
                 log_debug_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s, ignoring: %m", old_name);
index 8e86d2f0d1c01fbd89e3a21b97cebb4c0834de54..59ae6c7ad44ee3449235f6cecc08eaa9385e9d9d 100644 (file)
@@ -47,7 +47,7 @@ int udev_builtin_hwdb_lookup(sd_device *dev,
 }
 
 static const char *modalias_usb(sd_device *dev, char *s, size_t size) {
-        const char *v, *p;
+        const char *v, *p, *n = NULL;
         uint16_t vn, pn;
 
         if (sd_device_get_sysattr_value(dev, "idVendor", &v) < 0)
@@ -58,15 +58,16 @@ static const char *modalias_usb(sd_device *dev, char *s, size_t size) {
                 return NULL;
         if (safe_atoux16(p, &pn) < 0)
                 return NULL;
-        snprintf(s, size, "usb:v%04Xp%04X*", vn, pn);
+        (void) sd_device_get_sysattr_value(dev, "product", &n);
+
+        snprintf(s, size, "usb:v%04Xp%04X:%s", vn, pn, strempty(n));
         return s;
 }
 
 static int udev_builtin_hwdb_search(sd_device *dev, sd_device *srcdev,
                                     const char *subsystem, const char *prefix,
                                     const char *filter, bool test) {
-        sd_device *d;
-        char s[16];
+        char s[LINE_MAX];
         bool last = false;
         int r = 0;
 
@@ -75,7 +76,7 @@ static int udev_builtin_hwdb_search(sd_device *dev, sd_device *srcdev,
         if (!srcdev)
                 srcdev = dev;
 
-        for (d = srcdev; d; ) {
+        for (sd_device *d = srcdev; d; ) {
                 const char *dsubsys, *devtype, *modalias = NULL;
 
                 if (sd_device_get_subsystem(d, &dsubsys) < 0)
@@ -101,6 +102,8 @@ static int udev_builtin_hwdb_search(sd_device *dev, sd_device *srcdev,
                 if (!modalias)
                         goto next;
 
+                log_device_debug(dev, "hwdb modalias key: \"%s\"", modalias);
+
                 r = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test);
                 if (r > 0)
                         break;
index 9d706085fb474a2bd173dc4bfaa985092dd57f14..a2fe7e909976cd86c08a157a984c4a04bd8cc4cb 100644 (file)
@@ -226,6 +226,7 @@ static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool utf8) {
         _cleanup_free_ struct unipair* unipairs = NULL;
         _cleanup_free_ void *fontbuf = NULL;
         unsigned i;
+        int log_level;
         int r;
 
         unipairs = new(struct unipair, USHRT_MAX);
@@ -234,11 +235,20 @@ static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool utf8) {
                 return;
         }
 
+        log_level = LOG_WARNING;
+
         /* get metadata of the current font (width, height, count) */
         r = ioctl(src_fd, KDFONTOP, &cfo);
-        if (r < 0)
-                log_warning_errno(errno, "KD_FONT_OP_GET failed while trying to get the font metadata: %m");
-        else {
+        if (r < 0) {
+                /* We might be called to operate on the dummy console (to setup keymap
+                 * mainly) when fbcon deferred takeover is used for example. In such case,
+                 * setting font is not supported and is expected to fail. */
+                if (errno == ENOSYS)
+                        log_level = LOG_DEBUG;
+
+                log_full_errno(log_level, errno,
+                               "KD_FONT_OP_GET failed while trying to get the font metadata: %m");
+        } else {
                 /* verify parameter sanity first */
                 if (cfo.width > 32 || cfo.height > 32 || cfo.charcount > 512)
                         log_warning("Invalid font metadata - width: %u (max 32), height: %u (max 32), count: %u (max 512)",
@@ -273,7 +283,7 @@ static void setup_remaining_vcs(int src_fd, unsigned src_idx, bool utf8) {
         }
 
         if (cfo.op != KD_FONT_OP_SET)
-                log_warning("Fonts will not be copied to remaining consoles");
+                log_full(log_level, "Fonts will not be copied to remaining consoles");
 
         for (i = 1; i <= 63; i++) {
                 char ttyname[sizeof("/dev/tty63")];
index 465d194b4083492e08d1c379a8de0f5a62e34862..e475402d9d46eaef9b2b75930525c1367373b2f0 100644 (file)
@@ -100,7 +100,7 @@ static int run(int argc, char *argv[]) {
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to parse root hash signature '%s': %m", argv[6]);
                         } else {
-                                r = read_full_file_full(AT_FDCWD, argv[6], 0, &hash_sig, &hash_sig_size);
+                                r = read_full_file_full(AT_FDCWD, argv[6], READ_FULL_FILE_CONNECT_SOCKET, &hash_sig, &hash_sig_size);
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to read root hash signature: %m");
                         }
index cfe97aaa2da48df6a029984f6e93788d1ebc271d..3882658053854cf426a4b01b0f60de571cc0c701 100755 (executable)
@@ -10,6 +10,7 @@ TEST_NO_NSPAWN=1
 
 command -v mksquashfs >/dev/null 2>&1 || exit 0
 command -v veritysetup >/dev/null 2>&1 || exit 0
+command -v sfdisk >/dev/null 2>&1 || exit 0
 
 # Need loop devices for systemd-dissect
 test_create_image() {
@@ -25,9 +26,26 @@ test_create_image() {
         instmods loop =block
         instmods squashfs =squashfs
         instmods dm_verity =md
+        install_dmevent
         generate_module_dependencies
-        inst_binary mksquashfs
-        inst_binary veritysetup
+        inst_binary sfdisk
+        inst_binary losetup
+
+        BASICTOOLS=(
+            bash
+            cat
+        )
+        oldinitdir=$initdir
+        export initdir=$TESTDIR/minimal
+        mkdir -p $initdir
+        setup_basic_dirs
+        install_basic_tools
+        inst /usr/lib/os-release
+        ln -s ../usr/lib/os-release $initdir/etc/os-release
+        echo MARKER=1 >> $initdir/usr/lib/os-release
+        mksquashfs $initdir $oldinitdir/usr/share/minimal.raw
+        veritysetup format $oldinitdir/usr/share/minimal.raw $oldinitdir/usr/share/minimal.verity | grep '^Root hash:' | cut -f2 | tr -d '\n' > $oldinitdir/usr/share/minimal.roothash
+        export initdir=$oldinitdir
     )
 }
 
index 468669c6cc6a86bfae6e6173ecb02bbfaed7f1a9..1f7e7d16f01556a95116efe06245b17c257a9544 100644 (file)
@@ -6,7 +6,7 @@ RequiredForOnline=routable
 
 [Network]
 IPv6AcceptRA=no
-DNS=10.10.10.10 10.10.10.11
+DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com [1111:2222::3333]:1234#ccc.com
 NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org
 Domains=hogehoge ~foofoo
 LLMNR=no
index 2d7f915850ed7880530652429526b4ac5b055f86..677e39765e143e60a3d1f6e5f0c179ae739f67d6 100755 (executable)
@@ -2601,7 +2601,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
             self.assertRegex(data, r'REQUIRED_FOR_ONLINE=yes')
             self.assertRegex(data, r'REQUIRED_OPER_STATE_FOR_ONLINE=routable')
             self.assertRegex(data, r'NETWORK_FILE=/run/systemd/network/state-file-tests.network')
-            self.assertRegex(data, r'DNS=10.10.10.10 10.10.10.11')
+            self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
             self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
             self.assertRegex(data, r'DOMAINS=hogehoge')
             self.assertRegex(data, r'ROUTE_DOMAINS=foofoo')
@@ -2610,7 +2610,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
             self.assertRegex(data, r'DNSSEC=no')
             self.assertRegex(data, r'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24')
 
-        check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12', '10.10.10.13', env=env)
+        check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env=env)
         check_output(*resolvectl_cmd, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env=env)
         check_output(*resolvectl_cmd, 'llmnr', 'dummy98', 'yes', env=env)
         check_output(*resolvectl_cmd, 'mdns', 'dummy98', 'no', env=env)
@@ -2620,7 +2620,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
 
         with open(path) as f:
             data = f.read()
-            self.assertRegex(data, r'DNS=10.10.10.12 10.10.10.13')
+            self.assertRegex(data, r'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
             self.assertRegex(data, r'NTP=2.fedora.pool.ntp.org 3.fedora.pool.ntp.org')
             self.assertRegex(data, r'DOMAINS=hogehogehoge')
             self.assertRegex(data, r'ROUTE_DOMAINS=foofoofoo')
@@ -2633,7 +2633,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
 
         with open(path) as f:
             data = f.read()
-            self.assertRegex(data, r'DNS=10.10.10.12 10.10.10.13')
+            self.assertRegex(data, r'DNS=10.10.10.12#ccc.com 10.10.10.13 1111:2222::3333')
             self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
             self.assertRegex(data, r'DOMAINS=hogehogehoge')
             self.assertRegex(data, r'ROUTE_DOMAINS=foofoofoo')
@@ -2646,7 +2646,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities):
 
         with open(path) as f:
             data = f.read()
-            self.assertRegex(data, r'DNS=10.10.10.10 10.10.10.11')
+            self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com')
             self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org')
             self.assertRegex(data, r'DOMAINS=hogehoge')
             self.assertRegex(data, r'ROUTE_DOMAINS=foofoo')
index 9f35ffd653fc54af200258ad96fdee6e263dd41b..0e7588ad7f11d548e078c52227fb2bee4f5ab8fb 100755 (executable)
 set -ex
 set -o pipefail
 
+export SYSTEMD_LOG_LEVEL=debug
+
+cleanup()
+{
+    if [ -z "${image_dir}" ]; then
+        return
+    fi
+    rm -rf "${image_dir}"
+}
+
 cd /tmp
 
-image=$(mktemp -d -t -p /tmp tmp.XXXXXX)
-if [ -z "${image}" ] || [ ! -d "${image}" ]; then
-       echo "Could not create temporary directory with mktemp under /tmp"
-       exit 1
+image_dir="$(mktemp -d -t -p /tmp tmp.XXXXXX)"
+if [ -z "${image_dir}" ] || [ ! -d "${image_dir}" ]; then
+    echo "mktemp under /tmp failed"
+    exit 1
 fi
 
-mkdir -p ${image}/usr/lib ${image}/etc
-cp /usr/lib/os-release ${image}/usr/lib/
-cp /etc/machine-id /etc/os-release ${image}/etc/
-mksquashfs ${image} ${image}.raw
-veritysetup format ${image}.raw ${image}.verity | grep '^Root hash:' | cut -f2 | tr -d '\n' > ${image}.roothash
+trap cleanup EXIT
+
+cp /usr/share/minimal.* "${image_dir}/"
+image="${image_dir}/minimal"
+roothash="$(cat ${image}.roothash)"
 
 /usr/lib/systemd/systemd-dissect ${image}.raw | grep -q -F "Found read-only 'root' partition of type squashfs with verity"
+/usr/lib/systemd/systemd-dissect ${image}.raw | grep -q -F "MARKER=1"
 /usr/lib/systemd/systemd-dissect ${image}.raw | grep -q -F -f /usr/lib/os-release
 
 mv ${image}.verity ${image}.fooverity
 mv ${image}.roothash ${image}.foohash
-/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=`cat ${image}.foohash` --verity-data=${image}.fooverity | grep -q -F "Found read-only 'root' partition of type squashfs with verity"
-/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=`cat ${image}.foohash` --verity-data=${image}.fooverity | grep -q -F -f /usr/lib/os-release
+/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F "Found read-only 'root' partition of type squashfs with verity"
+/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F "MARKER=1"
+/usr/lib/systemd/systemd-dissect ${image}.raw --root-hash=${roothash} --verity-data=${image}.fooverity | grep -q -F -f /usr/lib/os-release
+mv ${image}.fooverity ${image}.verity
+mv ${image}.foohash ${image}.roothash
+
+mkdir -p ${image_dir}/mount
+/usr/lib/systemd/systemd-dissect --mount ${image}.raw ${image_dir}/mount
+cat ${image_dir}/mount/usr/lib/os-release | grep -q -F -f /usr/lib/os-release
+cat ${image_dir}/mount/etc/os-release | grep -q -F -f /usr/lib/os-release
+cat ${image_dir}/mount/usr/lib/os-release | grep -q -F "MARKER=1"
+umount ${image_dir}/mount
+
+systemd-run -t --property RootImage=${image}.raw /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
+mv ${image}.verity ${image}.fooverity
+mv ${image}.roothash ${image}.foohash
+systemd-run -t --property RootImage=${image}.raw --property RootHash=${image}.foohash --property RootVerity=${image}.fooverity /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
+systemd-run -t --property RootImage=${image}.raw --property RootHash=${roothash} --property RootVerity=${image}.fooverity /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
+mv ${image}.fooverity ${image}.verity
+mv ${image}.foohash ${image}.roothash
+
+# Make a GPT disk on the fly, with the squashfs as partition 1 and the verity hash tree as partition 2
+machine="$(uname -m)"
+if [ "${machine}" = "x86_64" ]; then
+    root_guid=4f68bce3-e8cd-4db1-96e7-fbcaf984b709
+    verity_guid=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5
+elif [ "${machine}" = "i386" ] || [ "${machine}" = "i686" ] || [ "${machine}" = "x86" ]; then
+    root_guid=44479540-f297-41b2-9af7-d131d5f0458a
+    verity_guid=d13c5d3b-b5d1-422a-b29f-9454fdc89d76
+elif [ "${machine}" = "aarch64" ] || [ "${machine}" = "aarch64_be" ] || [ "${machine}" = "armv8b" ] || [ "${machine}" = "armv8l" ]; then
+    root_guid=b921b045-1df0-41c3-af44-4c6f280d3fae
+    verity_guid=df3300ce-d69f-4c92-978c-9bfb0f38d820
+elif [ "${machine}" = "arm" ]; then
+    root_guid=69dad710-2ce4-4e3c-b16c-21a1d49abed3
+    verity_guid=7386cdf2-203c-47a9-a498-f2ecce45a2d6
+elif [ "${machine}" = "ia64" ]; then
+    root_guid=993d8d3d-f80e-4225-855a-9daf8ed7ea97
+    verity_guid=86ed10d5-b607-45bb-8957-d350f23d0571
+else
+    echo "Unexpected uname -m: ${machine} in testsuite-50.sh, please fix me"
+    exit 1
+fi
+# du rounds up to block size, which is more helpful for partitioning
+root_size="$(du -k ${image}.raw | cut -f1)"
+verity_size="$(du -k ${image}.verity | cut -f1)"
+# 4MB seems to be the minimum size blkid will accept, below that probing fails
+dd if=/dev/zero of=${image}.gpt bs=512 count=$((8192+${root_size}*2+${verity_size}*2))
+# sfdisk seems unhappy if the size overflows into the next unit, eg: 1580KiB will be interpreted as 1MiB
+# so do some basic rounding up if the minimal image is more than 1 MB
+if [ ${root_size} -ge 1024 ]; then
+    root_size="$((${root_size}/1024 + 1))MiB"
+else
+    root_size="${root_size}KiB"
+fi
+verity_size="${verity_size}KiB"
+uuid="$(head -c 32 ${image}.roothash | cut -c -8)-$(head -c 32 ${image}.roothash | cut -c 9-12)-$(head -c 32 ${image}.roothash | cut -c 13-16)-$(head -c 32 ${image}.roothash | cut -c 17-20)-$(head -c 32 ${image}.roothash | cut -c 21-)"
+echo -e "label: gpt\nsize=${root_size}, type=${root_guid}, uuid=${uuid}" | sfdisk ${image}.gpt
+uuid="$(tail -c 32 ${image}.roothash | cut -c -8)-$(tail -c 32 ${image}.roothash | cut -c 9-12)-$(tail -c 32 ${image}.roothash | cut -c 13-16)-$(tail -c 32 ${image}.roothash | cut -c 17-20)-$(tail -c 32 ${image}.roothash | cut -c 21-)"
+echo -e "size=${verity_size}, type=${verity_guid}, uuid=${uuid}" | sfdisk ${image}.gpt --append
+sfdisk --part-label ${image}.gpt 1 "Root Partition"
+sfdisk --part-label ${image}.gpt 2 "Verity Partition"
+loop="$(losetup --show -P -f ${image}.gpt)"
+dd if=${image}.raw of=${loop}p1
+dd if=${image}.verity of=${loop}p2
+losetup -d ${loop}
+
+/usr/lib/systemd/systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q "Found read-only 'root' partition (UUID $(head -c 32 ${image}.roothash)) of type squashfs for .* with verity on partition #1"
+/usr/lib/systemd/systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q "Found read-only 'root-verity' partition (UUID $(tail -c 32 ${image}.roothash)) of type DM_verity_hash for .* on partition #2"
+/usr/lib/systemd/systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F "MARKER=1"
+/usr/lib/systemd/systemd-dissect --root-hash ${roothash} ${image}.gpt | grep -q -F -f /usr/lib/os-release
+
+/usr/lib/systemd/systemd-dissect --root-hash ${roothash} --mount ${image}.gpt ${image_dir}/mount
+cat ${image_dir}/mount/usr/lib/os-release | grep -q -F -f /usr/lib/os-release
+cat ${image_dir}/mount/etc/os-release | grep -q -F -f /usr/lib/os-release
+cat ${image_dir}/mount/usr/lib/os-release | grep -q -F "MARKER=1"
+umount ${image_dir}/mount
+
+systemd-run -t --property RootImage=${image}.gpt --property RootHash=${roothash} /usr/bin/cat /usr/lib/os-release | grep -q -F "MARKER=1"
 
 echo OK > /testok
 
index e13ca33f6fc5fcb2cff17aa6d872085717b8c387..a20edc0f341d673534c828d03f732f4b2dff5469 100755 (executable)
@@ -14,7 +14,7 @@ for entry in chromiumos.gen_autosuspend_rules.PCI_IDS:
     device = int(device, 16)
     print('pci:v{:08X}d{:08X}*'.format(vendor, device))
 
-print('# usb:v<VEND>p<PROD> (4 uppercase hexadecimal digits twice')
+print('# usb:v<VEND>p<PROD> (4 uppercase hexadecimal digits twice)')
 for entry in chromiumos.gen_autosuspend_rules.USB_IDS:
     vendor, product = entry.split(':')
     vendor = int(vendor, 16)
index a2a987d8fd407fa2cfa56b9ef8b54bfe50252bb4..ab8a5b5fb8a0879553afc4f31532fe10e96927c7 100755 (executable)
@@ -59,8 +59,9 @@ for phase in "${PHASES[@]}"; do
         RUN|RUN_GCC|RUN_CLANG)
             if [[ "$phase" = "RUN_CLANG" ]]; then
                 ENV_VARS="-e CC=clang -e CXX=clang++"
+                MESON_ARGS="--optimization=1"
             fi
-            docker exec $ENV_VARS -it $CONT_NAME meson --werror -Dtests=unsafe -Dslow-tests=true -Dsplit-usr=true -Dman=true build
+            docker exec $ENV_VARS -it $CONT_NAME meson --werror -Dtests=unsafe -Dslow-tests=true -Dsplit-usr=true -Dman=true $MESON_ARGS build
             $DOCKER_EXEC ninja -v -C build
             docker exec -e "TRAVIS=$TRAVIS" -it $CONT_NAME ninja -C build test
             ;;
index c641900c668433a075f5e1899e73949301cf2373..aa2ed115ea2bcff8a146c4a10800547a76494482 100644 (file)
@@ -180,7 +180,7 @@ in_units = [
          'sysinit.target.wants/'],
         ['systemd-importd.service',              'ENABLE_IMPORTD',
          'dbus-org.freedesktop.import1.service'],
-        ['systemd-initctl.service',               ''],
+        ['systemd-initctl.service',              'HAVE_SYSV_COMPAT'],
         ['systemd-journal-gatewayd.service',     'ENABLE_REMOTE HAVE_MICROHTTPD'],
         ['systemd-journal-remote.service',       'ENABLE_REMOTE HAVE_MICROHTTPD'],
         ['systemd-journal-upload.service',       'ENABLE_REMOTE HAVE_LIBCURL'],