- tags: ['^\S*-rc\d+$']
feedback:
frozen-state: |
- An -rc1 tag has been created and a release is being prepared, so please note that PRs introducing new features and APIs will be held back until the new version has been released.
+ > [!IMPORTANT]
+ > An -rc1 tag has been created and a release is being prepared, so please note that PRs introducing new features and APIs will be held back until the new version has been released.
unfreeze-state: |
- We had successfully released a new major release. We are no longer in a development freeze phase.
- We will try our best to get back to your PR as soon as possible. Thank you for your patience.
+ > [!NOTE]
+ > We had successfully released a new major release. We are no longer in a development freeze phase.
+ > We will try our best to get back to your PR as soon as possible. Thank you for your patience.
a private VLAN variant of the proxy ARP supported by the kernel
under the name IPv4ProxyARPPrivateVLAN=.
+ * TPM 1.2 PCR measurement support has been removed from
+ systemd-stub. TPM 1.2 is obsolete and — due to the (by today's
+ standards) weak cryptographic algorithms it only supports — does not
+ actually provide the security benefits it's supposed to
+ provide. Given that the rest of systemd's codebase never supported
+ TPM 1.2 the support has now been removed from systemd-stub as well.
+
CHANGES WITH 255:
Announcements of Future Feature Removals and Incompatible Changes:
CONFIG_SECCOMP_FILTER (required for seccomp support)
CONFIG_KCMP (for the kcmp() syscall, used to be under
CONFIG_CHECKPOINT_RESTORE before ~5.12)
+ CONFIG_NET_SCHED
+ CONFIG_NET_SCH_FQ_CODEL
Required for CPUShares= in resource control unit settings:
CONFIG_CGROUP_SCHED
Consult our [NEWS file](NEWS) for information about what's new in the most recent systemd versions.
-Please see the [Code Map](docs/_contributing/ARCHITECTURE.md) for information about this repository's layout and content.
+Please see the [Code Map](docs/ARCHITECTURE.md) for information about this repository's layout and content.
-Please see the [Hacking guide](docs/_contributing/HACKING.md) for information on how to hack on systemd and test your modifications.
+Please see the [Hacking guide](docs/HACKING.md) for information on how to hack on systemd and test your modifications.
-Please see our [Contribution Guidelines](docs/_contributing/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.
+Please see our [Contribution Guidelines](docs/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.
-When preparing patches for systemd, please follow our [Coding Style Guidelines](docs/_contributing/CODING_STYLE.md).
+When preparing patches for systemd, please follow our [Coding Style Guidelines](docs/CODING_STYLE.md).
If you are looking for support, please contact our [mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel), join our [IRC channel #systemd on libera.chat](https://web.libera.chat/#systemd) or [Matrix channel](https://matrix.to/#/#systemd-project:matrix.org)
* Once baseline is 4.13, remove support for INTERFACE_OLD= checks in "udevadm
trigger"'s waiting logic, since we can then rely on uuid-tagged uevents
-* remove remaining tpm1.2 support from sd-stub
-
Features:
-* vmspawn: to speed up boot let's disable all PCR banks in swtpm except for
- SHA256. Probably means running swtpm_setup --state-dir … --tpm2 --pcr-banks
- sha256.
-
* in os-release define a field that can be initialized at build time from
SOURCE_DATE_EPOCH (maybe even under that name?). Would then be used to
initialize the timestamp logic of ConditionNeedsUpdate=.
+* ptyfwd: look for window title ANSI sequences and insert colored dot in front
+ of it while passing it through, to indicate whether we are in privileged, VM,
+ container terminal sessions.
+
+* nspawn/vmspawn/pid1: add ability to easily insert fully booted VMs/FOSC into
+ shell pipelines, i.e. add easy to use switch that turns off console status
+ output, and generates the right credentials for systemd-run-generator so that
+ a program is invoked, and its output captured, with correct EOF handling and
+ exit code propagation
+
* new systemd-analyze "join" verb or so, for debugging services. Would be
nsenter on steroids, i.e invoke a shell or command line in an environment as
close as we can make it for the MainPID of a service. Should be built around
* systemd-tpm2-setup should probably have a factory reset logic, i.e. when some
kernel command line option is set we reset the TPM (equivalent of tpm2_clear
- -c owner?).
+ -c owner? or rather echo 5 >/sys/class/tpm/tpm0/ppi/request?).
* systemd-tpm2-setup should support a mode where we refuse booting if the SRK
changed. (Must be opt-in, to not break systems which are supposed to be
1. Disable any mounting on `/tmp` so that it resides on the same physical file system as the root directory. For that, execute `systemctl mask tmp.mount`
2. Mount a different, physical file system to `/tmp`. For that, simply create an entry for it in `/etc/fstab` as you would do for any other file system.
3. Keep `/tmp` but increase/decrease the size of it. For that, also just create an entry for it in `/etc/fstab` as you would do for any other `tmpfs` file system, and use the right `size=` option.
-
[https://github.com/systemd/systemd](https://github.com/systemd/systemd)
[http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/](http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/)
-
* Use the [native Journal logging APIs](http://0pointer.de/blog/projects/journal-submit.html) to generate your messages, and define message IDs for all messages you want to add catalog entries for. You may use `journalctl --new-id128` to allocate new message IDs.
* Write a catalog entry file for your messages and ship them in your package and install them to `/usr/lib/systemd/catalog/` (if you package your software with RPM use `%_journalcatalogdir`)
* Ensure that after installation of your application's RPM/DEB "`journalctl --update-catalog`" is executed, in order to update the binary catalog index. (if you package your software with RPM use the `%journal_catalog_update` macro to achieve that.)
-
- A corollary of the above is: never use `clone()` where a `fork()` would do
too. Also consider using `posix_spawn()` which combines `clone()` +
`execve()` into one and has nice properties since it avoids becoming a CoW
- trap by using `CLONE_VORK` and `CLONE_VM` together.
+ trap by using `CLONE_VFORK` and `CLONE_VM` together.
- While we avoid forking off threads on our own, writing thread-safe code is a
good idea where it might end up running inside of libsystemd.so or
### Enumeration
-To acquire a list of currently running units, use the `ListUnits()` call on the Manager bus object. To determine the scope/service unit and slice unit a process is running in use [`sd_pid_get_unit()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_unit.html) and `sd_pid_get_slice()`. These two calls are implemented in `libsystemd-login.so`. These call bypass the system bus (which they can because they are passive and do not require privileges) and are hence very effecient to invoke.
+To acquire a list of currently running units, use the `ListUnits()` call on the Manager bus object. To determine the scope/service unit and slice unit a process is running in use [`sd_pid_get_unit()`](http://www.freedesktop.org/software/systemd/man/sd_pid_get_unit.html) and `sd_pid_get_slice()`. These two calls are implemented in `libsystemd-login.so`. These call bypass the system bus (which they can because they are passive and do not require privileges) and are hence very efficient to invoke.
### VM and Container Managers
sudo systemctl stop my-php-fpm-pool.socket my-php-fpm-pool.service
sudo systemctl start my-php-fpm-pool.socket
```
-
* ideally after booting with `systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M printk.devkmsg=on`
* The output of a systemd dump: `systemd-analyze dump > systemd-dump.txt`
* The output of `/usr/lib/systemd/systemd --test --system --log-level=debug > systemd-test.txt 2>&1`
-
**Q: My systemd system always comes up with `/tmp` as a tiny `tmpfs`. How do I get rid of this?**
A: That's also a long story, please have a look on [API File Systems](../API_FILE_SYSTEMS)
-
* On SysV systems changes to init scripts or any other files that define the boot process (such as /etc/fstab) usually had an immediate effect on everything started later. This is different on systemd-based systems where init script information and other boot-time configuration files are only reread when "systemctl daemon-reload" is issued. (Note that some commands, notably "systemctl enable"/"systemctl disable" do this implicitly however.) This is by design, and a safety feature, since it ensures that half-completed changes are not read at the wrong time.
* Multiple entries for the same mount path in /etc/fstab are not supported. In systemd there's only a single unit definition for each mount path read at any time. Also the listing order of mounts in /etc/fstab has no effect, mounts are executed in parallel and dependencies between them generated automatically depending on path prefixes and source paths.
* systemd's handling of the existing "nofail" mount option in /etc/fstab is stricter than it used to be on some sysvinit distributions: mount points that fail and are not listed as "nofail" will cause the boot to be stopped, for security reasons, as we we should not permit unprivileged code to run without everything listed — and not expressly exempted through "nofail" — being around. Hence, please mark all mounts where booting shall proceed regardless whether they succeeded or not with "nofail"
-* Some SysV systems support an "rc.local" script that is supposed to be called "last" during boot. In systemd, the script is supported, but the semantics are less strict, as there is simply no concept of "last service", as the boot process is event- and request-based, parallelized and compositive. In general, it's a good idea to write proper unit files with properly defined dependncies, and avoid making use of rc.local.
+* Some SysV systems support an "rc.local" script that is supposed to be called "last" during boot. In systemd, the script is supported, but the semantics are less strict, as there is simply no concept of "last service", as the boot process is event- and request-based, parallelized and compositive. In general, it's a good idea to write proper unit files with properly defined dependencies, and avoid making use of rc.local.
* systemd assumes that the UID boundary between system and regular users is a choice the distribution makes, and not the administrator. Hence it expects this setting as compile-time option to be picked by the distribution. It will _not_ check /etc/login.defs during runtime.
Note that there are some areas where systemd currently provides a certain amount of compatibility where we expect this compatibility to be removed eventually.
Note that this all only applies to services. By default, user applications run in the root cgroup of the "cpu" hierarchy, which avoids these problems for normal user applications.
In the long run we hope that the kernel is fixed to not require an RT budget to be assigned for any cgroup created before a process can acquire RT (i.e. a process' RT budget should be derived from the nearest ancestor cgroup which has a budget assigned, rather than unconditionally its own uninitialized budget.) Ideally, we'd also like to create a per-user cgroup by default, so that users with many processes get roughly the same amount of CPU as users with very few.
-
In this new definition of /usr, the directory can be mounted read-only by default, while the rootfs may be either read-write or read-only (for stateless systems) and contains only the empty mount point directories, compat-symlinks to /usr and the host-specific data like /etc, /root, /srv. In comparison to today's setups, the rootfs will be very small. The host-specific data will be properly separated from the installed operating system. The new /usr could also easily be shared read-only across several systems. Such a setup would be more efficient, can provide additional security, is more flexible to use, provides saner options for custom setups, and is much simpler to setup and maintain.
For more information on this please continue to [The Case for the /usr Merge](../THE_CASE_FOR_THE_USR_MERGE).
-
```
for a boot target foobar.target. Note that this is mostly a debugging tool that actually does a lot more than just calculate the initial transaction, so don't build scripts based on this.
-
JSON User Records are not suitable for storing all identity information about
the user, such as binary data or large unstructured blobs of text. These parts
-of a user's identity should be stored in the [Blob Directories](USER_RECORD_BLOB_DIRS.md).
+of a user's identity should be stored in the [Blob Directories](USER_RECORD_BLOB_DIRS).
JSON User Records may be transferred or written to disk in various protocols
and formats. To inquire about such records defined on the local system use the
see above) with a user record without one set, even if the `userName` field matches.
`blobDirectory` → The absolute path to a world-readable copy of the user's blob
-directory. See [Blob Directories](USER_RECORD_BLOB_DIRS.md) for more details.
+directory. See [Blob Directories](USER_RECORD_BLOB_DIRS) for more details.
`blobManifest` → An object, which maps valid blob directory filenames (see
-[Blob Directories](USER_RECORD_BLOB_DIRS.md) for requirements) to SHA256 hashes
+[Blob Directories](USER_RECORD_BLOB_DIRS) for requirements) to SHA256 hashes
formatted as hex strings. This exists for the purpose of including the contents
of the blob directory in the record's signature. Managers that support blob
directories and utilize signed user records (like `systemd-homed`) should use
# User Record Blob Directories
The blob directories are for storing binary or unstructured data that would
-otherwise be stored in [JSON User Records](USER_RECORD.md). For instance,
+otherwise be stored in [JSON User Records](USER_RECORD). For instance,
this includes image files such as the user's avatar picture. This data,
like most of the user record, will be made publicly available to the
system.
## Suggested Mode of Operation
-Whenever a network configuration manager sets up an interface for operation, it should pass the DNS configuration information for the interface to `systemd-resolved`. It's recommended to do that after the Linux network interface index ("ifindex") has been allocated, but before the interface has beeen upped (i.e. `IFF_UP` turned on). That way, `systemd-resolved` will be able to use the configuration the moment the network interface is available. (Note that `systemd-resolved` watches the kernel interfaces come and go, and will make use of them as soon as they are suitable to be used, which among other factors requires `IFF_UP` to be set). That said it is OK to change DNS configuration dynamically any time: simply pass the new data to resolved, and it is happy to use it.
+Whenever a network configuration manager sets up an interface for operation, it should pass the DNS configuration information for the interface to `systemd-resolved`. It's recommended to do that after the Linux network interface index ("ifindex") has been allocated, but before the interface has been upped (i.e. `IFF_UP` turned on). That way, `systemd-resolved` will be able to use the configuration the moment the network interface is available. (Note that `systemd-resolved` watches the kernel interfaces come and go, and will make use of them as soon as they are suitable to be used, which among other factors requires `IFF_UP` to be set). That said it is OK to change DNS configuration dynamically any time: simply pass the new data to resolved, and it is happy to use it.
In order to pass the DNS configuration information to resolved, use the following methods of the `org.freedesktop.resolve1.Manager` interface of the `/org/freedesktop/resolve1` object, on the `org.freedesktop.resolve1` service:
The example specifies a network interface index of "0", i.e. does not specify any at all, so that the request may be done on any. Note that the interface index is primarily relevant for LLMNR and MulticastDNS lookups, which distinguish different scopes for each network interface index.
-This examples makes no use of either the input flags parameter, nor the output flags parameter. See the _ResolveRecord()_ example below for information how to make use of the _SD_RESOLVED_AUTHENTICATED_ bit in the returned flags paramter.
+This examples makes no use of either the input flags parameter, nor the output flags parameter. See the _ResolveRecord()_ example below for information how to make use of the _SD_RESOLVED_AUTHENTICATED_ bit in the returned flags parameter.
```
#include <arpa/inet.h>
gcc addrtest.c -o addrtest -Wall `pkg-config --cflags --libs libsystemd`
```
-## Resolving an Abitrary DNS Resource Record
+## Resolving an Arbitrary DNS Resource Record
Use `ResolveRecord()` in order to resolve arbitrary resource records. The call will return the binary RRset data. This calls is useful to acquire resource records for which no high-level calls such as ResolveHostname(), ResolveAddress() and ResolveService() exist. In particular RRs such as MX, SSHFP, TLSA, CERT, OPENPGPKEY or IPSECKEY may be requested via this API.
baseurl: "" # the subpath of your site, e.g. /blog/
url: "https://systemd.io" # the base hostname & protocol for your site
+permalink: /:title/
+
# Build settings
markdown: kramdown
-
-collections:
- concepts:
- title: 'Concepts'
- output: true
- contributing:
- title: 'Contributing'
- output: true
- userdocs:
- output: true
- title: 'Documentation for Users and Administrators'
- booting:
- title: 'Booting'
- output: true
- interfaces:
- title: 'Interfaces'
- output: true
- networking:
- title: 'Networking'
- output: true
- groups:
- title: 'Users, Groups and Home Directories'
- output: true
- devdocs:
- title: 'Documentation for Developers'
- output: true
-
[
+ {
+ "category": "Project",
+ "title": "mkosi Project - Build Bespoke OS Images",
+ "url": "https://mkosi.systemd.io/"
+ },
+ {
+ "category": "Project",
+ "title": "Brand",
+ "url": "https://brand.systemd.io/"
+ },
+ {
+ "category": "Project",
+ "title": "Mailing List",
+ "url": "https://lists.freedesktop.org/mailman/listinfo/systemd-devel"
+ },
+ {
+ "category": "Project",
+ "title": "Mastodon",
+ "url": "https://mastodon.social/@pid_eins"
+ },
+ {
+ "category": "Project",
+ "title": "Releases",
+ "url": "https://github.com/systemd/systemd/releases"
+ },
+ {
+ "category": "Project",
+ "title": "GitHub Project Page",
+ "url": "https://github.com/systemd/systemd"
+ },
+ {
+ "category": "Project",
+ "title": "Issues",
+ "url": "https://github.com/systemd/systemd/issues"
+ },
+ {
+ "category": "Project",
+ "title": "Pull Requests",
+ "url": "https://github.com/systemd/systemd/pulls"
+ },
{
"category": "Manual Pages",
"title": "Index",
{
"category": "The various distributions",
"title": "Arch Linux bugtracker",
- "url": "https://bugs.archlinux.org/?project=1&cat%5B%5D=31&string=systemd"
+ "url": "https://gitlab.archlinux.org/archlinux/packaging/packages/systemd/-/issues"
},
{
"category": "The various distributions",
+++ /dev/null
-[
- {
- "category": "Project",
- "title": "mkosi Project - Build Bespoke OS Images",
- "url": "https://mkosi.systemd.io/"
- },
- {
- "collection": "project",
- "title": "Brand",
- "url": "https://brand.systemd.io/"
- },
- {
- "collection": "project",
- "title": "Mailing List",
- "url": "https://lists.freedesktop.org/mailman/listinfo/systemd-devel"
- },
- {
- "collection": "project",
- "title": "Mastodon",
- "url": "https://mastodon.social/@pid_eins"
- },
- {
- "collection": "project",
- "title": "Releases",
- "url": "https://github.com/systemd/systemd/releases"
- },
- {
- "collection": "project",
- "title": "GitHub Project Page",
- "url": "https://github.com/systemd/systemd"
- },
- {
- "collection": "project",
- "title": "Issues",
- "url": "https://github.com/systemd/systemd/issues"
- },
- {
- "collection": "project",
- "title": "Pull Requests",
- "url": "https://github.com/systemd/systemd/pulls"
- }
-]
Other parts include a logging daemon, utilities to control basic system configuration like the hostname, date, locale, maintain a list of logged-in users and running containers and virtual machines, system accounts, runtime directories and settings, and daemons to manage simple network configuration, network time synchronization, log forwarding, and name resolution.
---
-## Project
-{% for page in site.data.project %}
-* [{{ page.title }}]({{ page.url | relative_url }}){% endfor %}
-
-<!-- Collections -->
-{% for c in site.collections %}
-<!-- hide autegenerated posts collection -->
-{% if c.label != "posts" %}
-## {{ c.title }}
-{% for item in site[c.label] %}
-* [{{ item.title }}]({{ item.url | relative_url }}){% endfor %}
-{% endif %}
-{% endfor %}
-<!-- external pages -->
-{% assign external_pages = site.data.extra_pages | group_by:"category" %}
+{% assign by_category = site.pages | group_by:"category" %}
+{% assign extra_pages = site.data.extra_pages | group_by:"category" %}
+{% assign merged = by_category | concat: extra_pages | sort:"name" %}
-{% for category in external_pages %}
-## {{ category.name }}
-{% assign sorted = category.items | sort:"title" %}{% for page in sorted %}
+{% for pair in merged %}
+ {% if pair.name != "" %}
+## {{ pair.name }}
+{% assign sorted = pair.items | sort:"title" %}{% for page in sorted %}
* [{{ page.title }}]({{ page.url | relative_url }}){% endfor %}
+ {% endif %}
{% endfor %}
## See also
# Chuwi Ubook X (CWI535)
sensor:modalias:acpi:MXC6655*:dmi*:svnCHUWIInnovationAndTechnology*:pnUBookX:*
- ACCEL_MOUNT_MATRIX=0, 0, -1; 1, 0, 0; 0, 1, 0
+ ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, -1
#########################################
# Connect
usb:v0FD9p0080*
ID_AV_PRODUCTION_CONTROLLER=1
+# Stream Deck Plus
+usb:v0FD9p0084*
+ ID_AV_PRODUCTION_CONTROLLER=1
+
# Stream Deck Pedal
usb:v0FD9p0086*
ID_AV_PRODUCTION_CONTROLLER=1
<xi:include href="version-info.xml" xpointer="v248"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>IPv4Forwarding=</varname></term>
+ <listitem>
+ <para>Configures IPv4 packet forwarding for the system. Takes a boolean value. This controls the
+ <filename>net.ipv4.conf.default.forwarding</filename> and
+ <filename>net.ipv4.conf.all.forwarding</filename>sysctl options. See
+ <ulink url="https://docs.kernel.org/networking/ip-sysctl.html">IP Sysctl</ulink>
+ for more details about the sysctl options. Defaults to unset and the sysctl options will not be
+ changed.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>IPv6Forwarding=</varname></term>
+ <listitem>
+ <para>Configures IPv6 packet forwarding for the system. Takes a boolean value. This controls the
+ <filename>net.ipv6.conf.default.forwarding</filename> and
+ <filename>net.ipv6.conf.all.forwarding</filename> sysctl options. See
+ <ulink url="https://docs.kernel.org/networking/ip-sysctl.html">IP Sysctl</ulink>
+ for more details about the sysctl options. Defaults to unset and the sysctl options will not be
+ changed.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>IPv6PrivacyExtensions=</varname></term>
<listitem>
<citerefentry><refentrytitle>systemd-ssh-proxy</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
details on how to connect to these sockets via the <command>ssh</command> client.</para>
+ <para>The <varname>ssh.authorized_keys.root</varname> credential can be used to allow specific public keys
+ to log in over SSH. See
+ <citerefentry><refentrytitle>systemd.systemd-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ for more information.</para>
+
<para>The generator will use a packaged <filename>sshd@.service</filename> service template file if one
exists, and otherwise generate a suitable service template file.</para>
</listitem>
</varlistentry>
- <varlistentry>
- <term><option>--qemu-gui</option></term>
-
- <listitem><para>Start QEMU in graphical mode.</para>
-
- <xi:include href="version-info.xml" xpointer="v255"/></listitem>
- </varlistentry>
-
<varlistentry>
<term><option>-n</option></term>
<term><option>--network-tap</option></term>
</variablelist>
</refsect2>
+ <refsect2>
+ <title>Input/Output Options</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><option>--console=</option><replaceable>MODE</replaceable></term>
+
+ <listitem><para>Configures how to set up the console of the VM. Takes one of
+ <literal>interactive</literal>, <literal>read-only</literal>, <literal>native</literal>,
+ <literal>gui</literal>. Defaults to <literal>interactive</literal>. <literal>interactive</literal>
+ provides an interactive terminal interface to the VM. <literal>read-only</literal> is similar, but
+ is strictly read-only, i.e. does not accept any input from the user. <literal>native</literal> also
+ provides a TTY-based interface, but uses qemu native implementation (which means the qemu monitor
+ is available). <literal>gui</literal> shows the qemu graphical UI.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--background=<replaceable>COLOR</replaceable></option></term>
+
+ <listitem><para>Change the terminal background color to the specified ANSI color as long as the VM
+ runs. The color specified should be an ANSI X3.64 SGR background color, i.e. strings such as
+ <literal>40</literal>, <literal>41</literal>, …, <literal>47</literal>, <literal>48;2;…</literal>,
+ <literal>48;5;…</literal>. See <ulink
+ url="https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters">ANSI
+ Escape Code (Wikipedia)</ulink> for details. Assign an empty string to disable any coloring. This
+ only has an effect in <option>--console=interactive</option> and
+ <option>--console=read-only</option> modes.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
<refsect2>
<title>Credentials</title>
</varlistentry>
<varlistentry>
- <term><varname>IPForward=</varname></term>
- <listitem>
- <para>Configures IP packet forwarding for the system. If enabled, incoming packets on any
- network interface will be forwarded to any other interfaces according to the routing table.
- Takes a boolean, or the values <literal>ipv4</literal> or <literal>ipv6</literal>, which only
- enable IP packet forwarding for the specified address family. This controls the
- <filename>net.ipv4.ip_forward</filename> and <filename>net.ipv6.conf.all.forwarding</filename>
- sysctl options of the network interface (see
+ <term><varname>IPv4Forwarding=</varname></term>
+ <listitem>
+ <para>Configures IPv4 packet forwarding for the interface. Takes a boolean value. This controls the
+ <filename>net.ipv4.conf.<replaceable>INTERFACE</replaceable>.forwarding</filename> sysctl option of
+ the network interface. See
<ulink url="https://docs.kernel.org/networking/ip-sysctl.html">IP Sysctl</ulink>
- for details about sysctl options). Defaults to <literal>no</literal>.</para>
+ for more details about the sysctl option. Defaults to true if <varname>IPMasquerade=</varname> is
+ enabled for IPv4, otherwise the value specified to the same setting in
+ <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ will be used. If none of them are specified, the sysctl option will not be changed.</para>
+
+ <para>To control the global setting, use the same setting in
+ <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ </para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
- <para>Note: this setting controls a global kernel option, and does so one way only: if a
- network that has this setting enabled is set up the global setting is turned on. However,
- it is never turned off again, even after all networks with this setting enabled are shut
- down again.</para>
+ <varlistentry>
+ <term><varname>IPv6Forwarding=</varname></term>
+ <listitem>
+ <para>Configures IPv6 packet forwarding for the interface. Takes a boolean value. This controls the
+ <filename>net.ipv6.conf.<replaceable>INTERFACE</replaceable>.forwarding</filename> sysctl option of
+ the network interface. See
+ <ulink url="https://docs.kernel.org/networking/ip-sysctl.html">IP Sysctl</ulink>
+ for more details about the sysctl option. Defaults to true if <varname>IPMasquerade=</varname> is
+ enabled for IPv6 or <varname>IPv6SendRA=</varname> is enabled, otherwise the value specified to the
+ same setting in
+ <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ will be used. If none of them are specified, the sysctl option will not be changed.</para>
- <para>To allow IP packet forwarding only between specific network interfaces use a firewall.
+ <para>To control the global setting, use the same setting in
+ <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
- <xi:include href="version-info.xml" xpointer="v219"/>
+ <xi:include href="version-info.xml" xpointer="v256"/>
</listitem>
</varlistentry>
<para>Configures IP masquerading for the network interface. If enabled, packets forwarded
from the network interface will be appear as coming from the local host. Takes one of
<literal>ipv4</literal>, <literal>ipv6</literal>, <literal>both</literal>, or
- <literal>no</literal>. Defaults to <literal>no</literal>. If enabled, this automatically sets
- <varname>IPForward=</varname> to one of <literal>ipv4</literal>, <literal>ipv6</literal> or
- <literal>yes</literal>.</para>
+ <literal>no</literal>. Defaults to <literal>no</literal>.</para>
<para>Note. Any positive boolean values such as <literal>yes</literal> or
<literal>true</literal> are now deprecated. Please use one of the values in the above.</para>
#####################################################################
version_tag = get_option('version-tag')
-version_h = vcs_tag(
- input : 'src/version/version.h.in',
- output : 'version.h',
- command: [project_source_root / 'tools/meson-vcs-tag.sh',
- project_source_root,
- version_tag,
- ])
+if version_tag == ''
+ version_tag = meson.project_version()
+endif
+
+conf.set_quoted('VERSION_TAG', version_tag)
+
+vcs_tag = get_option('vcs-tag')
+if vcs_tag and fs.is_dir(project_source_root / '.git')
+ version_h = vcs_tag(
+ input : 'src/version/version.h.in',
+ output : 'version.h',
+ fallback : '',
+ command : ['sh', '-c', 'echo "-g$(git -C . describe --abbrev=7 --match="" --always --dirty=^)"'],
+ )
+else
+ version_h = configure_file(
+ input : 'src/version/version.h.in',
+ output : 'version.h',
+ configuration : configuration_data({'VCS_TAG' : ''}),
+ )
+endif
shared_lib_tag = get_option('shared-lib-tag')
if shared_lib_tag == ''
'LICENSE.LGPL2.1',
'NEWS',
'README',
- 'docs/_contributing/CODING_STYLE.md',
- 'docs/_concepts/DISTRO_PORTING.md',
- 'docs/_interfaces/ENVIRONMENT.md',
- 'docs/_contributing/HACKING.md',
- 'docs/_interfaces/TRANSIENT-SETTINGS.md',
- 'docs/_contributing/TRANSLATORS.md',
- 'docs/_groups/UIDS-GIDS.md',
+ 'docs/CODING_STYLE.md',
+ 'docs/DISTRO_PORTING.md',
+ 'docs/ENVIRONMENT.md',
+ 'docs/HACKING.md',
+ 'docs/TRANSIENT-SETTINGS.md',
+ 'docs/TRANSLATORS.md',
+ 'docs/UIDS-GIDS.md',
install_dir : docdir)
install_subdir('LICENSES',
# SPDX-License-Identifier: LGPL-2.1-or-later
option('version-tag', type : 'string',
- description : 'override the git version string')
+ description : 'set the extended version string (defaults to project version)')
option('shared-lib-tag', type : 'string',
description : 'override the private shared library version tag (defaults to project version)')
+option('vcs-tag', type : 'boolean', value : true,
+ description : 'append current git commit to version output when git information is available')
option('mode', type : 'combo', choices : ['developer', 'release'],
description : 'autoenable features suitable for systemd development/release builds')
--- /dev/null
+# do not edit this file, it will be overwritten on update
+
+# Media controller rules
+
+ACTION=="remove", GOTO="persistent_media_ctl_end"
+SUBSYSTEM!="media", GOTO="persistent_media_ctl_end"
+ENV{MAJOR}=="", GOTO="persistent_media_ctl_end"
+
+IMPORT{builtin}="path_id"
+ENV{ID_PATH}=="?*", KERNEL=="media*", SYMLINK+="media/by-path/$env{ID_PATH}-media-controller"
+
+LABEL="persistent_media_ctl_end"
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <elf.h>
+#include <link.h>
+#include <sys/auxv.h>
+
+#include "build-path.h"
+#include "errno-list.h"
+#include "errno-util.h"
+#include "macro.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "unistd.h"
+
+static int get_runpath_from_dynamic(const ElfW(Dyn) *d, const char **ret) {
+ size_t runpath_index = SIZE_MAX, rpath_index = SIZE_MAX;
+ const char *strtab = NULL;
+
+ assert(d);
+
+ /* Iterates through the PT_DYNAMIC section to find the DT_RUNPATH/DT_RPATH entries */
+
+ for (; d->d_tag != DT_NULL; d++) {
+
+ switch (d->d_tag) {
+
+ case DT_RUNPATH:
+ runpath_index = (size_t) d->d_un.d_val;
+ break;
+
+ case DT_RPATH:
+ rpath_index = (size_t) d->d_un.d_val;
+ break;
+
+ case DT_STRTAB:
+ strtab = (const char *) d->d_un.d_val;
+ break;
+ }
+
+ /* runpath wins, hence if we have the table and runpath we can exit the loop early */
+ if (strtab && runpath_index != SIZE_MAX)
+ break;
+ }
+
+ if (!strtab)
+ return -ENOTRECOVERABLE;
+
+ /* According to dl.so runpath wins of both runpath and rpath are defined. */
+ if (runpath_index != SIZE_MAX) {
+ if (ret)
+ *ret = strtab + runpath_index;
+ return 1;
+ }
+
+ if (rpath_index != SIZE_MAX) {
+ if (ret)
+ *ret = strtab + rpath_index;
+ return 1;
+ }
+
+ if (ret)
+ *ret = NULL;
+
+ return 0;
+}
+
+static int get_runpath(const char **ret) {
+ unsigned long phdr, phent, phnum;
+
+ /* Finds the rpath/runpath in the program headers of the main executable we are running in */
+
+ phdr = getauxval(AT_PHDR); /* Start offset of phdr */
+ if (phdr == 0)
+ return -ENOTRECOVERABLE;
+
+ phnum = getauxval(AT_PHNUM); /* Number of entries in phdr */
+ if (phnum == 0)
+ return -ENOTRECOVERABLE;
+
+ phent = getauxval(AT_PHENT); /* Size of entries in phdr */
+ if (phent < sizeof(ElfW(Phdr))) /* Safety check, that our idea of the structure matches the file */
+ return -ENOTRECOVERABLE;
+
+ ElfW(Addr) bias = 0, dyn = 0;
+ bool found_bias = false, found_dyn = false;
+
+ /* Iterate through the Phdr structures to find the PT_PHDR and PT_DYNAMIC sections */
+ for (unsigned long i = 0; i < phnum; i++) {
+ const ElfW(Phdr) *p = (const ElfW(Phdr)*) (phdr + (i * phent));
+
+ switch (p->p_type) {
+
+ case PT_PHDR:
+ if (p->p_vaddr > phdr) /* safety overflow check */
+ return -ENOTRECOVERABLE;
+
+ bias = (ElfW(Addr)) phdr - p->p_vaddr;
+ found_bias = true;
+ break;
+
+ case PT_DYNAMIC:
+ dyn = p->p_vaddr;
+ found_dyn = true;
+ break;
+ }
+
+ if (found_bias && found_dyn)
+ break;
+ }
+
+ if (!found_dyn)
+ return -ENOTRECOVERABLE;
+
+ return get_runpath_from_dynamic((const ElfW(Dyn)*) (bias + dyn), ret);
+}
+
+int get_build_exec_dir(char **ret) {
+ int r;
+
+ /* Returns the build execution directory if we are invoked in a build environment. Specifically, this
+ * checks if the main program binary has an rpath/runpath set (i.e. an explicit directory where to
+ * look for shared libraries) to $ORIGIN. If so we know that this is not a regular installed binary,
+ * but one which shall acquire its libraries from below a directory it is located in, i.e. a build
+ * directory or similar. In that case it typically makes sense to also search for our auxiliary
+ * executables we fork() off in a directory close to our main program binary, rather than in the
+ * system.
+ *
+ * This function is supposed to be used when looking for "callout" binaries that are closely related
+ * to the main program (i.e. speak a specific protocol between each other). And where it's generally
+ * a good idea to use the binary from the build tree (if there is one) instead of the system.
+ *
+ * Note that this does *not* actually return the rpath/runpath but the instead the directory the main
+ * executable was found in. This follows the logic that the result is supposed to be used for
+ * executable binaries (i.e. stuff in bindir), not for shared libraries (i.e. stuff in libdir), and
+ * hence the literal shared library path would just be wrong.
+ *
+ * TLDR: if we look for callouts in this dir first, running binaries from the meson build tree
+ * automatically uses the right callout.
+ *
+ * Returns:
+ * -ENOEXEC → We are not running in an rpath/runpath $ORIGIN environment
+ * -ENOENT → We don't know our own binary path
+ * -NOTRECOVERABLE → Dynamic binary information missing?
+ */
+
+ static int runpath_cached = -ERRNO_MAX-1;
+ if (runpath_cached == -ERRNO_MAX-1) {
+ const char *runpath = NULL;
+
+ runpath_cached = get_runpath(&runpath);
+
+ /* We only care if the runpath starts with $ORIGIN/ */
+ if (runpath_cached > 0 && !startswith(runpath, "$ORIGIN/"))
+ runpath_cached = 0;
+ }
+ if (runpath_cached < 0)
+ return runpath_cached;
+ if (runpath_cached == 0)
+ return -ENOEXEC;
+
+ _cleanup_free_ char *exe = NULL;
+ r = get_process_exe(0, &exe);
+ if (r < 0)
+ return runpath_cached = r;
+
+ return path_extract_directory(exe, ret);
+}
+
+static int find_build_dir_binary(const char *fn, char **ret) {
+ int r;
+
+ assert(fn);
+ assert(ret);
+
+ _cleanup_free_ char *build_dir = NULL;
+ r = get_build_exec_dir(&build_dir);
+ if (r < 0)
+ return r;
+
+ _cleanup_free_ char *np = path_join(build_dir, fn);
+ if (!np)
+ return -ENOMEM;
+
+ *ret = TAKE_PTR(np);
+ return 0;
+}
+
+static int find_environment_binary(const char *fn, const char **ret) {
+
+ /* If a path such as /usr/lib/systemd/systemd-foobar is specified, then this will check for an
+ * environment variable SYSTEMD_FOOBAR_PATH and return it if set. */
+
+ _cleanup_free_ char *s = strdup(fn);
+ if (!s)
+ return -ENOMEM;
+
+ ascii_strupper(s);
+ string_replace_char(s, '-', '_');
+
+ if (!strextend(&s, "_PATH"))
+ return -ENOMEM;
+
+ const char *e;
+ e = secure_getenv(s);
+ if (!e)
+ return -ENXIO;
+
+ *ret = e;
+ return 0;
+}
+
+int invoke_callout_binary(const char *path, char *const argv[]) {
+ int r;
+
+ assert(path);
+
+ /* Just like execv(), but tries to execute the specified binary in the build dir instead, if known */
+
+ _cleanup_free_ char *fn = NULL;
+ r = path_extract_filename(path, &fn);
+ if (r < 0)
+ return r;
+ if (r == O_DIRECTORY) /* Uh? */
+ return -EISDIR;
+
+ const char *e;
+ if (find_environment_binary(fn, &e) >= 0) {
+ /* If there's an explicit environment variable set for this binary, prefer it */
+ execv(e, argv);
+ return -errno; /* The environment variable counts, let's fail otherwise */
+ }
+
+ _cleanup_free_ char *np = NULL;
+ if (find_build_dir_binary(fn, &np) >= 0)
+ execv(np, argv);
+
+ execv(path, argv);
+ return -errno;
+}
+
+int pin_callout_binary(const char *path) {
+ int r;
+
+ assert(path);
+
+ /* Similar to invoke_callout_binary(), but pins (i.e. O_PATH opens) the binary instead of executing it. */
+
+ _cleanup_free_ char *fn = NULL;
+ r = path_extract_filename(path, &fn);
+ if (r < 0)
+ return r;
+ if (r == O_DIRECTORY) /* Uh? */
+ return -EISDIR;
+
+ const char *e;
+ if (find_environment_binary(fn, &e) >= 0)
+ return RET_NERRNO(open(e, O_CLOEXEC|O_PATH));
+
+ _cleanup_free_ char *np = NULL;
+ if (find_build_dir_binary(fn, &np) >= 0) {
+ r = RET_NERRNO(open(np, O_CLOEXEC|O_PATH));
+ if (r >= 0)
+ return r;
+ }
+
+ return RET_NERRNO(open(path, O_CLOEXEC|O_PATH));
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int get_build_exec_dir(char **ret);
+
+int invoke_callout_binary(const char *path, char *const argv[]);
+
+int pin_callout_binary(const char *path);
[SPECIAL_GLYPH_RED_CIRCLE] = "o",
[SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
[SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
+ [SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
},
/* UTF-8 */
[SPECIAL_GLYPH_RED_CIRCLE] = u8"🔴",
[SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
[SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
+ [SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
},
};
SPECIAL_GLYPH_RED_CIRCLE,
SPECIAL_GLYPH_YELLOW_CIRCLE,
SPECIAL_GLYPH_BLUE_CIRCLE,
+ SPECIAL_GLYPH_GREEN_CIRCLE,
_SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;
be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
}
+bool in4_addr_is_multicast(const struct in_addr *a) {
+ assert(a);
+
+ return IN_MULTICAST(be32toh(a->s_addr));
+}
+
+bool in6_addr_is_multicast(const struct in6_addr *a) {
+ assert(a);
+
+ return IN6_IS_ADDR_MULTICAST(a);
+}
+
int in_addr_is_multicast(int family, const union in_addr_union *u) {
assert(u);
if (family == AF_INET)
- return IN_MULTICAST(be32toh(u->in.s_addr));
+ return in4_addr_is_multicast(&u->in);
if (family == AF_INET6)
- return IN6_IS_ADDR_MULTICAST(&u->in6);
+ return in6_addr_is_multicast(&u->in6);
return -EAFNOSUPPORT;
}
return in_addr_data_is_null(a);
}
+bool in4_addr_is_multicast(const struct in_addr *a);
+bool in6_addr_is_multicast(const struct in6_addr *a);
int in_addr_is_multicast(int family, const union in_addr_union *u);
bool in4_addr_is_link_local(const struct in_addr *a);
'audit-util.c',
'btrfs.c',
'build.c',
+ 'build-path.c',
'bus-label.c',
'cap-list.c',
'capability-util.c',
p = procfs_file_alloca(pid, proc_file);
r = readlink_malloc(p, ret);
- return r == -ENOENT ? -ESRCH : r;
+ return (r == -ENOENT && proc_mounted() > 0) ? -ESRCH : r;
}
int get_process_exe(pid_t pid, char **ret) {
.sa_handler = SIG_DFL,
.sa_flags = SA_RESTART,
};
- int r = 0;
+ int ret = 0, r;
for (int sig = 1; sig < _NSIG; sig++) {
if (IN_SET(sig, SIGKILL, SIGSTOP))
continue;
- /* On Linux the first two RT signals are reserved by
- * glibc, and sigaction() will return EINVAL for them. */
- if (sigaction(sig, &sa, NULL) < 0)
- if (errno != EINVAL && r >= 0)
- r = -errno;
+ /* On Linux the first two RT signals are reserved by glibc, and sigaction() will return
+ * EINVAL for them. */
+ r = RET_NERRNO(sigaction(sig, &sa, NULL));
+ if (r != -EINVAL)
+ RET_GATHER(ret, r);
}
- return r;
+ return ret;
}
int reset_signal_mask(void) {
if (sig == 0)
continue;
- if (sigaction(sig, sa, NULL) < 0) {
- if (r >= 0)
- r = -errno;
- }
+ RET_GATHER(r, RET_NERRNO(sigaction(sig, sa, NULL)));
}
va_end(ap);
return r;
}
-int sigset_add_many(sigset_t *ss, ...) {
+int sigset_add_many_internal(sigset_t *ss, ...) {
va_list ap;
int r;
return r;
}
-int sigprocmask_many(int how, sigset_t *old, ...) {
+int sigprocmask_many_internal(int how, sigset_t *old, ...) {
va_list ap;
sigset_t ss;
int r;
if (r < 0)
return r;
- if (sigprocmask(how, &ss, old) < 0)
- return -errno;
-
- return 0;
+ return RET_NERRNO(sigprocmask(how, &ss, old));
}
static const char *const static_signal_table[] = {
#define sigaction_many(sa, ...) \
sigaction_many_internal(sa, __VA_ARGS__, -1)
-int sigset_add_many(sigset_t *ss, ...);
-int sigprocmask_many(int how, sigset_t *old, ...);
+int sigset_add_many_internal(sigset_t *ss, ...);
+#define sigset_add_many(...) sigset_add_many_internal(__VA_ARGS__, -1)
+
+int sigprocmask_many_internal(int how, sigset_t *old, ...);
+#define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
const char *signal_to_string(int i) _const_;
int signal_from_string(const char *s) _pure_;
#define BLOCK_SIGNALS(...) \
_cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
sigset_t _t; \
- assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \
+ assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__) >= 0); \
_t; \
})
}
static Virtualization detect_vm_device_tree(void) {
-#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
+#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__) || defined(__riscv)
_cleanup_free_ char *hvtype = NULL;
int r;
#endif
}
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch_lp64)
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch_lp64) || defined(__riscv)
static Virtualization detect_vm_dmi_vendor(void) {
static const char* const dmi_vendors[] = {
"/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
#include "tpm2-pcr.h"
#include "util.h"
-static EFI_STATUS tpm1_measure_to_pcr_and_event_log(
- const EFI_TCG_PROTOCOL *tcg,
- uint32_t pcrindex,
- EFI_PHYSICAL_ADDRESS buffer,
- size_t buffer_size,
- const char16_t *description) {
-
- _cleanup_free_ TCG_PCR_EVENT *tcg_event = NULL;
- EFI_PHYSICAL_ADDRESS event_log_last;
- uint32_t event_number = 1;
- size_t desc_len;
-
- assert(tcg);
- assert(description);
-
- desc_len = strsize16(description);
- tcg_event = xmalloc(offsetof(TCG_PCR_EVENT, Event) + desc_len);
- *tcg_event = (TCG_PCR_EVENT) {
- .EventSize = desc_len,
- .PCRIndex = pcrindex,
- .EventType = EV_IPL,
- };
- memcpy(tcg_event->Event, description, desc_len);
-
- return tcg->HashLogExtendEvent(
- (EFI_TCG_PROTOCOL *) tcg,
- buffer, buffer_size,
- TCG_ALG_SHA,
- tcg_event,
- &event_number,
- &event_log_last);
-}
-
static EFI_STATUS tpm2_measure_to_pcr_and_tagged_event_log(
EFI_TCG2_PROTOCOL *tcg,
uint32_t pcrindex,
return cc;
}
-static EFI_TCG_PROTOCOL *tcg1_interface_check(void) {
- EFI_PHYSICAL_ADDRESS event_log_location, event_log_last_entry;
- EFI_TCG_BOOT_SERVICE_CAPABILITY capability = {
- .Size = sizeof(capability),
- };
- EFI_STATUS err;
- uint32_t features;
- EFI_TCG_PROTOCOL *tcg;
-
- err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_TCG_PROTOCOL), NULL, (void **) &tcg);
- if (err != EFI_SUCCESS)
- return NULL;
-
- err = tcg->StatusCheck(
- tcg,
- &capability,
- &features,
- &event_log_location,
- &event_log_last_entry);
- if (err != EFI_SUCCESS)
- return NULL;
-
- if (capability.TPMDeactivatedFlag)
- return NULL;
-
- if (!capability.TPMPresentFlag)
- return NULL;
-
- return tcg;
-}
-
static EFI_TCG2_PROTOCOL *tcg2_interface_check(void) {
EFI_TCG2_BOOT_SERVICE_CAPABILITY capability = {
.Size = sizeof(capability),
}
bool tpm_present(void) {
- return tcg2_interface_check() || tcg1_interface_check();
+ return tcg2_interface_check();
}
EFI_STATUS tpm_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) {
if (tpm2)
err = tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
else {
- EFI_TCG_PROTOCOL *tpm1;
+ EFI_CC_MEASUREMENT_PROTOCOL *cc;
- tpm1 = tcg1_interface_check();
- if (tpm1)
- err = tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description);
+ cc = cc_interface_check();
+ if (cc)
+ err = cc_measure_to_mr_and_event_log(cc, pcrindex, buffer, buffer_size, description);
else {
- EFI_CC_MEASUREMENT_PROTOCOL *cc;
-
- cc = cc_interface_check();
- if (cc)
- err = cc_measure_to_mr_and_event_log(cc, pcrindex, buffer, buffer_size, description);
- else {
- /* No active TPM found, so don't return an error */
+ /* No active TPM found, so don't return an error */
- if (ret_measured)
- *ret_measured = false;
+ if (ret_measured)
+ *ret_measured = false;
- return EFI_SUCCESS;
- }
+ return EFI_SUCCESS;
}
}
elif get_option('sbat-distro') != ''
efi_conf.set_quoted('SBAT_PROJECT', meson.project_name())
efi_conf.set_quoted('PROJECT_VERSION', meson.project_version().split('~')[0])
+ efi_conf.set_quoted('VERSION_TAG', version_tag)
efi_conf.set('PROJECT_URL', conf.get('PROJECT_URL'))
if get_option('sbat-distro-generation') < 1
error('SBAT Distro Generation must be a positive integer')
#include "efi.h"
-#define EFI_TCG_PROTOCOL_GUID \
- GUID_DEF(0xf541796d, 0xa62e, 0x4954, 0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd)
#define EFI_TCG2_PROTOCOL_GUID \
GUID_DEF(0x607f766c, 0x7455, 0x42be, 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
-#define TCG_ALG_SHA 0x4
#define EFI_TCG2_EVENT_HEADER_VERSION 1
#define EV_IPL 13
#define EV_EVENT_TAG UINT32_C(6)
uint32_t ActivePcrBanks;
} EFI_TCG2_BOOT_SERVICE_CAPABILITY;
-typedef struct {
- uint32_t PCRIndex;
- uint32_t EventType;
- struct {
- uint8_t Digest[20];
- } Digest;
- uint32_t EventSize;
- uint8_t Event[];
-} _packed_ TCG_PCR_EVENT;
-
typedef struct {
uint32_t HeaderSize;
uint16_t HeaderVersion;
uint8_t Event[];
} _packed_ EFI_TCG2_TAGGED_EVENT;
-typedef struct EFI_TCG_PROTOCOL EFI_TCG_PROTOCOL;
-struct EFI_TCG_PROTOCOL {
- EFI_STATUS (EFIAPI *StatusCheck)(
- EFI_TCG_PROTOCOL *This,
- EFI_TCG_BOOT_SERVICE_CAPABILITY *ProtocolCapability,
- uint32_t *TCGFeatureFlags,
- EFI_PHYSICAL_ADDRESS *EventLogLocation,
- EFI_PHYSICAL_ADDRESS *EventLogLastEntry);
- void *HashAll;
- void *LogEvent;
- void *PassThroughToTpm;
- EFI_STATUS (EFIAPI *HashLogExtendEvent)(
- EFI_TCG_PROTOCOL *This,
- EFI_PHYSICAL_ADDRESS HashData,
- uint64_t HashDataLen,
- uint32_t AlgorithmId,
- TCG_PCR_EVENT *TCGLogData,
- uint32_t *EventNumber,
- EFI_PHYSICAL_ADDRESS *EventLogLastEntry);
-};
-
typedef struct EFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL;
struct EFI_TCG2_PROTOCOL {
EFI_STATUS (EFIAPI *GetCapability)(
remove_boot_count(file_path_str);
return xasprintf("%ls.extra.d", file_path_str);
}
+
+void *xmalloc(size_t size) {
+ void *p = NULL;
+ assert_se(BS->AllocatePool(EfiLoaderData, size, &p) == EFI_SUCCESS);
+ return p;
+}
#define _cleanup_free_ _cleanup_(freep)
_malloc_ _alloc_(1) _returns_nonnull_ _warn_unused_result_
-static inline void *xmalloc(size_t size) {
- void *p;
- assert_se(BS->AllocatePool(EfiLoaderData, size, &p) == EFI_SUCCESS);
- return p;
-}
+void *xmalloc(size_t size);
_malloc_ _alloc_(1, 2) _returns_nonnull_ _warn_unused_result_
static inline void *xmalloc_multiply(size_t n, size_t size) {
/* Block SIGTERM, so that we know that it won't get lost in the child */
- assert_se(sigprocmask_many(SIG_BLOCK, &old_ss, SIGTERM, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, &old_ss, SIGTERM) >= 0);
parent_pid = getpid_cached();
#include "alloc-util.h"
#include "audit-fd.h"
#include "boot-timestamps.h"
+#include "build-path.h"
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-kernel.h"
if (r < 0 && r != -EEXIST)
return r;
+ }
- m->executor_fd = open(SYSTEMD_EXECUTOR_BINARY_PATH, O_CLOEXEC|O_PATH);
- if (m->executor_fd < 0)
- return log_emergency_errno(errno,
- "Failed to open executor binary '%s': %m",
- SYSTEMD_EXECUTOR_BINARY_PATH);
- } else if (!FLAGS_SET(test_run_flags, MANAGER_TEST_DONT_OPEN_EXECUTOR)) {
- _cleanup_free_ char *self_exe = NULL, *executor_path = NULL;
- _cleanup_close_ int self_dir_fd = -EBADF;
- int level = LOG_DEBUG;
-
- /* Prefer sd-executor from the same directory as the test, e.g.: when running unit tests from the
- * build directory. Fallback to working directory and then the installation path. */
- r = readlink_and_make_absolute("/proc/self/exe", &self_exe);
- if (r < 0)
- return r;
-
- self_dir_fd = open_parent(self_exe, O_CLOEXEC|O_PATH|O_DIRECTORY, 0);
- if (self_dir_fd < 0)
- return self_dir_fd;
-
- m->executor_fd = RET_NERRNO(openat(self_dir_fd, "systemd-executor", O_CLOEXEC|O_PATH));
- if (m->executor_fd == -ENOENT)
- m->executor_fd = RET_NERRNO(openat(AT_FDCWD, "systemd-executor", O_CLOEXEC|O_PATH));
- if (m->executor_fd == -ENOENT) {
- m->executor_fd = RET_NERRNO(open(SYSTEMD_EXECUTOR_BINARY_PATH, O_CLOEXEC|O_PATH));
- level = LOG_WARNING; /* Tests should normally use local builds */
- }
+ if (!FLAGS_SET(test_run_flags, MANAGER_TEST_DONT_OPEN_EXECUTOR)) {
+ m->executor_fd = pin_callout_binary(SYSTEMD_EXECUTOR_BINARY_PATH);
if (m->executor_fd < 0)
- return m->executor_fd;
+ return log_debug_errno(m->executor_fd, "Failed to pin executor binary: %m");
+ _cleanup_free_ char *executor_path = NULL;
r = fd_get_path(m->executor_fd, &executor_path);
if (r < 0)
return r;
- log_full(level, "Using systemd-executor binary from '%s'.", executor_path);
+ log_debug("Using systemd-executor binary from '%s'.", executor_path);
}
/* Note that we do not set up the notify fd here. We do that after deserialization,
#include "blockdev-util.h"
#include "btrfs-util.h"
+#include "build-path.h"
#include "bus-common-errors.h"
#include "bus-locator.h"
#include "data-fd-util.h"
return r;
if (r == 0) {
_cleanup_free_ char *joined = NULL;
- const char *homework, *suffix, *unix_path;
+ const char *suffix, *unix_path;
/* Child */
if (r < 0)
log_warning_errno(r, "Failed to update $SYSTEMD_LOG_LEVEL, ignoring: %m");
- /* Allow overriding the homework path via an environment variable, to make debugging
- * easier. */
- homework = getenv("SYSTEMD_HOMEWORK_PATH") ?: SYSTEMD_HOMEWORK_PATH;
-
- execl(homework, homework, verb, NULL);
- log_error_errno(errno, "Failed to invoke %s: %m", homework);
+ r = invoke_callout_binary(SYSTEMD_HOMEWORK_PATH, STRV_MAKE(SYSTEMD_HOMEWORK_PATH, verb));
+ log_error_errno(r, "Failed to invoke %s: %m", SYSTEMD_HOMEWORK_PATH);
_exit(EXIT_FAILURE);
}
umask(0022);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
r = manager_new(&m);
if (r < 0)
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
(void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
(void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
(void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
(void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
(void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
(void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
#include "sd-bus.h"
#include "alloc-util.h"
+#include "build-path.h"
#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-log-control-api.h"
cmd[k++] = t->local;
cmd[k] = NULL;
- execv(cmd[0], (char * const *) cmd);
- log_error_errno(errno, "Failed to execute %s tool: %m", cmd[0]);
+ assert(k < ELEMENTSOF(cmd));
+
+ r = invoke_callout_binary(cmd[0], (char * const *) cmd);
+ log_error_errno(r, "Failed to execute %s tool: %m", cmd[0]);
_exit(EXIT_FAILURE);
}
umask(0022);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
r = manager_new(&m);
if (r < 0)
assert(s);
- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM) >= 0);
r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
if (r < 0)
assert(u);
- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM) >= 0);
r = sd_event_add_signal(u->events, &u->sigterm_event, SIGTERM, dispatch_sigterm, u);
if (r < 0)
assert(s);
- assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+18) >= 0);
r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s);
if (r < 0)
},
};
-int icmp6_bind_router_solicitation(int ifindex) {
- if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
+int icmp6_bind(int ifindex, bool is_router) {
+ if (!is_router && socketpair(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) < 0)
return -errno;
- return test_fd[0];
-}
-
-int icmp6_bind_router_advertisement(int ifindex) {
- return test_fd[1];
+ return test_fd[is_router];
}
int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
#include "network-common.h"
#include "socket-util.h"
-#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \
- { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } }
-
-#define IN6ADDR_ALL_NODES_MULTICAST_INIT \
- { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
-
-static int icmp6_bind_router_message(const struct icmp6_filter *filter,
- const struct ipv6_mreq *mreq) {
- int ifindex = mreq->ipv6mr_interface;
+int icmp6_bind(int ifindex, bool is_router) {
+ struct icmp6_filter filter = {};
+ struct ipv6_mreq mreq;
_cleanup_close_ int s = -EBADF;
int r;
- assert(filter);
- assert(mreq);
+ assert(ifindex > 0);
+
+ ICMP6_FILTER_SETBLOCKALL(&filter);
+ if (is_router) {
+ mreq = (struct ipv6_mreq) {
+ .ipv6mr_multiaddr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
+ .ipv6mr_interface = ifindex,
+ };
+ ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
+ } else {
+ mreq = (struct ipv6_mreq) {
+ .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
+ .ipv6mr_interface = ifindex,
+ };
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
+ }
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
if (s < 0)
return -errno;
- if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, filter, sizeof(*filter)) < 0)
+ if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) < 0)
return -errno;
- if (setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, mreq, sizeof(*mreq)) < 0)
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
return -errno;
- /* RFC 3315, section 6.7, bullet point 2 may indicate that an
- IPV6_PKTINFO socket option also applies for ICMPv6 multicast.
- Empirical experiments indicates otherwise and therefore an
- IPV6_MULTICAST_IF socket option is used here instead */
+ /* RFC 3315, section 6.7, bullet point 2 may indicate that an IPV6_PKTINFO socket option also applies
+ * for ICMPv6 multicast. Empirical experiments indicates otherwise and therefore an IPV6_MULTICAST_IF
+ * socket option is used here instead. */
r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, ifindex);
if (r < 0)
return r;
return TAKE_FD(s);
}
-int icmp6_bind_router_solicitation(int ifindex) {
- struct icmp6_filter filter = {};
- struct ipv6_mreq mreq = {
- .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
- .ipv6mr_interface = ifindex,
- };
-
- ICMP6_FILTER_SETBLOCKALL(&filter);
- ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
-
- return icmp6_bind_router_message(&filter, &mreq);
-}
-
-int icmp6_bind_router_advertisement(int ifindex) {
- struct icmp6_filter filter = {};
- struct ipv6_mreq mreq = {
- .ipv6mr_multiaddr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT,
- .ipv6mr_interface = ifindex,
- };
-
- ICMP6_FILTER_SETBLOCKALL(&filter);
- ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
-
- return icmp6_bind_router_message(&filter, &mreq);
-}
-
int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
struct sockaddr_in6 dst = {
.sin6_family = AF_INET6,
.msg_control = &control,
.msg_controllen = sizeof(control),
};
- struct in6_addr addr = {};
ssize_t len;
iov = IOVEC_MAKE(buffer, size);
if ((size_t) len != size)
return -EINVAL;
- if (msg.msg_namelen == sizeof(struct sockaddr_in6) &&
- sa.in6.sin6_family == AF_INET6) {
-
- addr = sa.in6.sin6_addr;
- if (!in6_addr_is_link_local(&addr) && !in6_addr_is_null(&addr))
- return -EADDRNOTAVAIL;
-
- } else if (msg.msg_namelen > 0)
+ if (msg.msg_namelen != sizeof(struct sockaddr_in6) || sa.in6.sin6_family != AF_INET6)
return -EPFNOSUPPORT;
- /* namelen == 0 only happens when running the test-suite over a socketpair */
+ if (!in6_addr_is_link_local(&sa.in6.sin6_addr) && !in6_addr_is_null(&sa.in6.sin6_addr))
+ return -EADDRNOTAVAIL;
assert(!(msg.msg_flags & MSG_TRUNC));
if (ret_timestamp)
triple_timestamp_from_cmsg(ret_timestamp, &msg);
if (ret_sender)
- *ret_sender = addr;
+ *ret_sender = sa.in6.sin6_addr;
return 0;
}
***/
#include <net/ethernet.h>
+#include <stdbool.h>
#include "time-util.h"
{ { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }
-int icmp6_bind_router_solicitation(int ifindex);
-int icmp6_bind_router_advertisement(int ifindex);
+int icmp6_bind(int ifindex, bool is_router);
int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr);
int icmp6_receive(
int fd,
DEFINE_STRING_TABLE_LOOKUP(ndisc_event, sd_ndisc_event_t);
-static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event_t event, sd_ndisc_router *rt) {
+static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event_t event, void *message) {
assert(ndisc);
assert(event >= 0 && event < _SD_NDISC_EVENT_MAX);
return (void) log_ndisc(ndisc, "Received '%s' event.", ndisc_event_to_string(event));
log_ndisc(ndisc, "Invoking callback for '%s' event.", ndisc_event_to_string(event));
- ndisc->callback(ndisc, event, rt, ndisc->userdata);
+ ndisc->callback(ndisc, event, message, ndisc->userdata);
}
int sd_ndisc_is_running(sd_ndisc *nd) {
if (r < 0)
return r;
+ (void) event_source_disable(nd->timeout_event_source);
+
log_ndisc(nd, "Received Router Advertisement: flags %s preference %s lifetime %s",
rt->flags & ND_RA_FLAG_MANAGED ? "MANAGED" : rt->flags & ND_RA_FLAG_OTHER ? "OTHER" : "none",
rt->preference == SD_NDISC_PREFERENCE_HIGH ? "high" : rt->preference == SD_NDISC_PREFERENCE_LOW ? "low" : "medium",
if (r < 0)
switch (r) {
case -EADDRNOTAVAIL:
- log_ndisc(nd, "Received RA from neither link-local nor null address. Ignoring.");
+ log_ndisc(nd, "Received an ICMPv6 packet from neither link-local nor null address, ignoring.");
return 0;
case -EMULTIHOP:
- log_ndisc(nd, "Received RA with invalid hop limit. Ignoring.");
+ log_ndisc(nd, "Received an ICMPv6 packet with an invalid hop limit, ignoring.");
return 0;
case -EPFNOSUPPORT:
- log_ndisc(nd, "Received invalid source address from ICMPv6 socket. Ignoring.");
+ log_ndisc(nd, "Received an ICMPv6 packet with an invalid source address, ignoring.");
return 0;
default:
- log_ndisc_errno(nd, r, "Unexpected error while reading from ICMPv6, ignoring: %m");
+ log_ndisc_errno(nd, r, "Unexpected error while receiving an ICMPv6 packet, ignoring: %m");
return 0;
}
/* The function icmp6_receive() accepts the null source address, but RFC 4861 Section 6.1.2 states
* that hosts MUST discard messages with the null source address. */
- if (in6_addr_is_null(&rt->address))
- log_ndisc(nd, "Received RA from null address. Ignoring.");
+ if (in6_addr_is_null(&rt->address)) {
+ log_ndisc(nd, "Received an ICMPv6 packet from null address, ignoring.");
+ return 0;
+ }
- (void) event_source_disable(nd->timeout_event_source);
(void) ndisc_handle_datagram(nd, rt);
return 0;
}
return 1;
}
-int sd_ndisc_start(sd_ndisc *nd) {
+static int ndisc_setup_recv_event(sd_ndisc *nd) {
int r;
- usec_t time_now;
- assert_return(nd, -EINVAL);
- assert_return(nd->event, -EINVAL);
- assert_return(nd->ifindex > 0, -EINVAL);
+ assert(nd);
+ assert(nd->event);
+ assert(nd->ifindex > 0);
- if (sd_ndisc_is_running(nd))
- return 0;
+ _cleanup_close_ int fd = -EBADF;
+ fd = icmp6_bind(nd->ifindex, /* is_router = */ false);
+ if (fd < 0)
+ return fd;
- assert(!nd->recv_event_source);
+ _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+ r = sd_event_add_io(nd->event, &s, fd, EPOLLIN, ndisc_recv, nd);
+ if (r < 0)
+ return r;
- r = sd_event_now(nd->event, CLOCK_BOOTTIME, &time_now);
+ r = sd_event_source_set_priority(s, nd->event_priority);
if (r < 0)
- goto fail;
+ return r;
- nd->fd = icmp6_bind_router_solicitation(nd->ifindex);
- if (nd->fd < 0)
- return nd->fd;
+ (void) sd_event_source_set_description(s, "ndisc-receive-router-message");
- r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_recv, nd);
+ nd->fd = TAKE_FD(fd);
+ nd->recv_event_source = TAKE_PTR(s);
+ return 1;
+}
+
+static int ndisc_setup_timer(sd_ndisc *nd) {
+ int r;
+
+ assert(nd);
+ assert(nd->event);
+
+ r = event_reset_time_relative(nd->event, &nd->timeout_event_source,
+ CLOCK_BOOTTIME,
+ USEC_PER_SEC / 2, 1 * USEC_PER_SEC, /* See RFC 8415 sec. 18.2.1 */
+ ndisc_timeout, nd,
+ nd->event_priority, "ndisc-timeout", true);
if (r < 0)
- goto fail;
+ return r;
- r = sd_event_source_set_priority(nd->recv_event_source, nd->event_priority);
+ r = event_reset_time_relative(nd->event, &nd->timeout_no_ra,
+ CLOCK_BOOTTIME,
+ NDISC_TIMEOUT_NO_RA_USEC, 10 * USEC_PER_MSEC,
+ ndisc_timeout_no_ra, nd,
+ nd->event_priority, "ndisc-timeout-no-ra", true);
if (r < 0)
- goto fail;
+ return r;
- (void) sd_event_source_set_description(nd->recv_event_source, "ndisc-receive-message");
+ return 0;
+}
- r = event_reset_time(nd->event, &nd->timeout_event_source,
- CLOCK_BOOTTIME,
- time_now + USEC_PER_SEC / 2, 1 * USEC_PER_SEC, /* See RFC 8415 sec. 18.2.1 */
- ndisc_timeout, nd,
- nd->event_priority, "ndisc-timeout", true);
+int sd_ndisc_start(sd_ndisc *nd) {
+ int r;
+
+ assert_return(nd, -EINVAL);
+ assert_return(nd->event, -EINVAL);
+ assert_return(nd->ifindex > 0, -EINVAL);
+
+ if (sd_ndisc_is_running(nd))
+ return 0;
+
+ r = ndisc_setup_recv_event(nd);
if (r < 0)
goto fail;
- r = event_reset_time(nd->event, &nd->timeout_no_ra,
- CLOCK_BOOTTIME,
- time_now + NDISC_TIMEOUT_NO_RA_USEC, 10 * USEC_PER_MSEC,
- ndisc_timeout_no_ra, nd,
- nd->event_priority, "ndisc-timeout-no-ra", true);
+ r = ndisc_setup_timer(nd);
if (r < 0)
goto fail;
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
static bool router_lifetime_is_valid(usec_t lifetime_usec) {
+ assert_cc(RADV_MAX_ROUTER_LIFETIME_USEC <= UINT16_MAX * USEC_PER_SEC);
return lifetime_usec == 0 ||
(lifetime_usec >= RADV_MIN_ROUTER_LIFETIME_USEC &&
lifetime_usec <= RADV_MAX_ROUTER_LIFETIME_USEC);
}
-static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_usec) {
+static int radv_send_router(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_usec) {
+ assert(ra);
+ assert(router_lifetime_is_valid(lifetime_usec));
+
struct sockaddr_in6 dst_addr = {
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
};
- struct nd_router_advert adv = {};
+ struct nd_router_advert adv = {
+ .nd_ra_type = ND_ROUTER_ADVERT,
+ .nd_ra_router_lifetime = usec_to_be16_sec(lifetime_usec),
+ .nd_ra_retransmit = usec_to_be32_msec(ra->retransmit_usec),
+ };
struct {
struct nd_opt_hdr opthdr;
struct ether_addr slladdr;
} _packed_ opt_mac = {
.opthdr = {
.nd_opt_type = ND_OPT_SOURCE_LINKADDR,
- .nd_opt_len = (sizeof(struct nd_opt_hdr) +
- sizeof(struct ether_addr) - 1) /8 + 1,
+ .nd_opt_len = DIV_ROUND_UP(sizeof(struct nd_opt_hdr) + sizeof(struct ether_addr), 8),
},
+ .slladdr = ra->mac_addr,
};
struct nd_opt_mtu opt_mtu = {
.nd_opt_mtu_type = ND_OPT_MTU,
.nd_opt_mtu_len = 1,
+ .nd_opt_mtu_mtu = htobe32(ra->mtu),
};
/* Reserve iov space for RA header, linkaddr, MTU, N prefixes, N routes, N pref64 prefixes, RDNSS,
* DNSSL, and home agent. */
usec_t time_now;
int r;
- assert(ra);
- assert(router_lifetime_is_valid(lifetime_usec));
-
r = sd_event_now(ra->event, CLOCK_BOOTTIME, &time_now);
if (r < 0)
return r;
if (dst && in6_addr_is_set(dst))
dst_addr.sin6_addr = *dst;
- adv.nd_ra_type = ND_ROUTER_ADVERT;
+ /* The nd_ra_curhoplimit and nd_ra_flags_reserved fields cannot specified with nd_ra_router_lifetime
+ * simultaneously in the structured initializer in the above. */
adv.nd_ra_curhoplimit = ra->hop_limit;
- adv.nd_ra_retransmit = usec_to_be32_msec(ra->retransmit_usec);
adv.nd_ra_flags_reserved = ra->flags;
- assert_cc(RADV_MAX_ROUTER_LIFETIME_USEC <= UINT16_MAX * USEC_PER_SEC);
- adv.nd_ra_router_lifetime = usec_to_be16_sec(lifetime_usec);
iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
- /* MAC address is optional, either because the link does not use L2
- addresses or load sharing is desired. See RFC 4861, Section 4.2 */
- if (!ether_addr_is_null(&ra->mac_addr)) {
- opt_mac.slladdr = ra->mac_addr;
+ /* MAC address is optional, either because the link does not use L2 addresses or load sharing is
+ * desired. See RFC 4861, Section 4.2. */
+ if (!ether_addr_is_null(&ra->mac_addr))
iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac));
- }
- if (ra->mtu > 0) {
- opt_mtu.nd_opt_mtu_mtu = htobe32(ra->mtu);
+ if (ra->mtu > 0)
iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mtu, sizeof(opt_mtu));
- }
LIST_FOREACH(prefix, p, ra->prefixes) {
usec_t lifetime_valid_usec, lifetime_preferred_usec;
if (r < 0)
switch (r) {
case -EADDRNOTAVAIL:
- log_radv(ra, "Received RS from neither link-local nor null address. Ignoring");
+ log_radv(ra, "Received RS from neither link-local nor null address, ignoring.");
return 0;
case -EMULTIHOP:
- log_radv(ra, "Received RS with invalid hop limit. Ignoring.");
+ log_radv(ra, "Received RS with invalid hop limit, ignoring.");
return 0;
case -EPFNOSUPPORT:
- log_radv(ra, "Received invalid source address from ICMPv6 socket. Ignoring.");
+ log_radv(ra, "Received invalid source address from ICMPv6 socket, ignoring.");
return 0;
default:
* address option. See RFC 4861 Section 6.1.1. */
const char *addr = IN6_ADDR_TO_STRING(&src);
-
- r = radv_send(ra, &src, ra->lifetime_usec);
+ r = radv_send_router(ra, &src, ra->lifetime_usec);
if (r < 0)
log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", addr);
else
- log_radv(ra, "Sent solicited Router Advertisement to %s", addr);
+ log_radv(ra, "Sent solicited Router Advertisement to %s.", addr);
return 0;
}
if (r < 0)
goto fail;
- r = radv_send(ra, NULL, ra->lifetime_usec);
+ r = radv_send_router(ra, NULL, ra->lifetime_usec);
if (r < 0)
log_radv_errno(ra, r, "Unable to send Router Advertisement, ignoring: %m");
log_radv(ra, "Stopping IPv6 Router Advertisement daemon");
- /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
- with zero lifetime */
- r = radv_send(ra, NULL, 0);
+ /* RFC 4861, Section 6.2.5:
+ * the router SHOULD transmit one or more (but not more than MAX_FINAL_RTR_ADVERTISEMENTS) final
+ * multicast Router Advertisements on the interface with a Router Lifetime field of zero. */
+ r = radv_send_router(ra, NULL, 0);
if (r < 0)
log_radv_errno(ra, r, "Unable to send last Router Advertisement with router lifetime set to zero, ignoring: %m");
return 0;
}
+static int radv_setup_recv_event(sd_radv *ra) {
+ int r;
+
+ assert(ra);
+ assert(ra->event);
+ assert(ra->ifindex > 0);
+
+ _cleanup_close_ int fd = -EBADF;
+ fd = icmp6_bind(ra->ifindex, /* is_router = */ true);
+ if (fd < 0)
+ return fd;
+
+ _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+ r = sd_event_add_io(ra->event, &s, fd, EPOLLIN, radv_recv, ra);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(s, ra->event_priority);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(s, "radv-receive-message");
+
+ ra->fd = TAKE_FD(fd);
+ ra->recv_event_source = TAKE_PTR(s);
+ return 0;
+}
+
int sd_radv_start(sd_radv *ra) {
int r;
if (ra->state != RADV_STATE_IDLE)
return 0;
+ r = radv_setup_recv_event(ra);
+ if (r < 0)
+ goto fail;
+
r = event_reset_time(ra->event, &ra->timeout_event_source,
CLOCK_BOOTTIME,
0, 0,
if (r < 0)
goto fail;
- r = icmp6_bind_router_advertisement(ra->ifindex);
- if (r < 0)
- goto fail;
-
- ra->fd = r;
-
- r = sd_event_add_io(ra->event, &ra->recv_event_source, ra->fd, EPOLLIN, radv_recv, ra);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_priority(ra->recv_event_source, ra->event_priority);
- if (r < 0)
- goto fail;
-
- (void) sd_event_source_set_description(ra->recv_event_source, "radv-receive-message");
-
ra->state = RADV_STATE_ADVERTISING;
log_radv(ra, "Started IPv6 Router Advertisement daemon");
return 0;
/* If RAs have already been sent, send an RA immediately to announce the newly-added prefix */
- r = radv_send(ra, NULL, ra->lifetime_usec);
+ r = radv_send_router(ra, NULL, ra->lifetime_usec);
if (r < 0)
log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix %s, ignoring: %m", addr_p);
else
return 0;
/* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
- r = radv_send(ra, NULL, ra->lifetime_usec);
+ r = radv_send_router(ra, NULL, ra->lifetime_usec);
if (r < 0)
log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix %s, ignoring: %m",
strna(addr_p));
return 0;
/* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
- r = radv_send(ra, NULL, ra->lifetime_usec);
+ r = radv_send_router(ra, NULL, ra->lifetime_usec);
if (r < 0)
log_radv_errno(ra, r, "Unable to send Router Advertisement for added PREF64 prefix %s, ignoring: %m",
strna(addr_p));
.ether_addr_octet = { 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53 }
};
-static uint8_t advertisement[] = {
- /* ICMPv6 Router Advertisement, no checksum */
- 0x86, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x00, 0xb4,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Source Link Layer Address Option */
- 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
- /* Prefix Information Option */
- 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
- 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Prefix Information Option */
- 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x0e, 0x10,
- 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Prefix Information Option */
- 0x03, 0x04, 0x30, 0xc0, 0x00, 0x00, 0x0e, 0x10,
- 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x01, 0x0d, 0xad,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- /* Recursive DNS Server Option */
- 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
- 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- /* DNS Search List Option */
- 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
- 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
- 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
static bool test_stopped;
static struct {
struct in6_addr address;
assert_se(!ra);
}
-static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- sd_radv *ra = userdata;
- unsigned char buf[168];
- size_t i;
-
- assert_se(read(test_fd[0], &buf, sizeof(buf)) == sizeof(buf));
+static void dump_message(const uint8_t *buf, size_t len) {
+ assert(len >= sizeof(struct nd_router_advert));
- /* router lifetime must be zero when test is stopped */
- if (test_stopped) {
- advertisement[6] = 0x00;
- advertisement[7] = 0x00;
- }
+ printf("Received Router Advertisement with lifetime %i sec\n",
+ (buf[6] << 8) + buf[7]);
- printf ("Received Router Advertisement with lifetime %i\n",
- (advertisement[6] << 8) + advertisement[7]);
-
- /* test only up to buf size, rest is not yet implemented */
- for (i = 0; i < sizeof(buf); i++) {
+ for (size_t i = 0; i < len; i++) {
if (!(i % 8))
printf("%3zu: ", i);
printf("0x%02x", buf[i]);
- assert_se(buf[i] == advertisement[i]);
-
if ((i + 1) % 8)
printf(", ");
else
printf("\n");
}
+}
- if (test_stopped) {
- sd_event *e;
+static void verify_message(const uint8_t *buf, size_t len) {
+ static const uint8_t advertisement[] = {
+ /* ICMPv6 Router Advertisement, no checksum */
+ 0x86, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x00, 0xb4,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* Source Link Layer Address Option */
+ 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
+ /* Prefix Information Option */
+ 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
+ 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* Prefix Information Option */
+ 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x0e, 0x10,
+ 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* Prefix Information Option */
+ 0x03, 0x04, 0x30, 0xc0, 0x00, 0x00, 0x0e, 0x10,
+ 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x01, 0x0d, 0xad,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* Recursive DNS Server Option */
+ 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+ 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ /* DNS Search List Option */
+ 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
+ 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
+ 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ /* verify only up to known options, rest is not yet implemented */
+ for (size_t i = 0, m = MIN(len, sizeof(advertisement)); i < m; i++) {
+ if (test_stopped)
+ switch (i) {
+ case 6 ... 7: /* router lifetime must be zero on stop. */
+ assert_se(buf[i] == 0);
+ continue;
+ }
- e = sd_radv_get_event(ra);
- sd_event_exit(e, 0);
+ assert_se(buf[i] == advertisement[i]);
+ }
+}
+
+static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ sd_radv *ra = ASSERT_PTR(userdata);
+ _cleanup_free_ uint8_t *buf = NULL;
+ ssize_t buflen;
+ buflen = next_datagram_size_fd(fd);
+ assert_se(buflen >= 0);
+ assert_se(buf = new0(uint8_t, buflen));
+
+ assert_se(read(fd, buf, buflen) == buflen);
+
+ dump_message(buf, buflen);
+ verify_message(buf, buflen);
+
+ if (test_stopped) {
+ assert_se(sd_event_exit(sd_radv_get_event(ra), 0) >= 0);
return 0;
}
assert_se(sd_radv_stop(ra) >= 0);
test_stopped = true;
-
return 0;
}
return 0;
}
-static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
+static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
sd_event *e = userdata;
static unsigned idx = 0;
uint64_t flags_array[] = {
if (event != SD_NDISC_EVENT_ROUTER)
return;
+ sd_ndisc_router *rt = ASSERT_PTR(message);
+
router_dump(rt);
assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
assert_se(userdata == INT_TO_PTR('e'));
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGUSR2, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGUSR2) >= 0);
pid = fork();
assert_se(pid >= 0);
assert_se(userdata == INT_TO_PTR('d'));
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR1, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR1) >= 0);
assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0);
assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
/* Test for floating event sources */
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+1, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+1) >= 0);
assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0);
assert_se(write(a[1], &ch, 1) >= 0);
assert_se(sd_event_default(&e) >= 0);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2) >= 0);
assert_se(sd_event_add_signal(e, &u, SIGRTMIN+2, rtqueue_handler, NULL) >= 0);
assert_se(sd_event_add_signal(e, &v, SIGRTMIN+3, rtqueue_handler, NULL) >= 0);
assert_se(sd_event_add_signal(e, &s, SIGUSR2, rtqueue_handler, NULL) >= 0);
int pidfd;
pid_t pid, pid2;
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
pid = fork();
if (pid == 0)
SIGRTMIN, SIGRTMAX);
assert_se(ignore_signals(SIGRTMIN + 1) >= 0);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN) >= 0);
r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
if (r < 0)
(void) mkdir_label("/run/systemd/users", 0755);
(void) mkdir_label("/run/systemd/sessions", 0755);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGHUP, SIGTERM, SIGINT, SIGCHLD, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGHUP, SIGTERM, SIGINT, SIGCHLD, SIGRTMIN+18) >= 0);
r = manager_new(&m);
if (r < 0)
if (!avoid_pidfd) {
pidfd = pidfd_open(getpid_cached(), 0);
- if (pidfd < 0 && !ERRNO_IS_NOT_SUPPORTED(errno))
+ if (pidfd < 0 && !ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
return -errno;
}
assert(master >= 0);
assert(name);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT) >= 0);
if (!arg_quiet) {
if (streq(name, ".host"))
if (r < 0)
return bus_log_parse_error(r);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
if (!arg_quiet)
log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
* make sure this check stays in. */
(void) mkdir_label("/run/systemd/machines", 0755);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
r = manager_new(&m);
if (r < 0)
}
int address_remove_and_cancel(Address *address, Link *link) {
+ _cleanup_(request_unrefp) Request *req = NULL;
bool waiting = false;
- Request *req;
assert(address);
assert(link);
/* Cancel the request for the address. If the request is already called but we have not received the
* notification about the request, then explicitly remove the address. */
if (address_get_request(link, address, &req) >= 0) {
+ request_ref(req); /* avoid the request freed by request_detach() */
waiting = req->waiting_reply;
request_detach(req);
address_cancel_requesting(address);
return link_get_vrf_table(link);
}
-uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
+uint32_t link_get_ndisc_route_table(Link *link) {
assert(link);
assert(link->network);
- if (link->network->ipv6_accept_ra_route_table_set)
- return link->network->ipv6_accept_ra_route_table;
+ if (link->network->ndisc_route_table_set)
+ return link->network->ndisc_route_table;
return link_get_vrf_table(link);
}
return r;
}
- if (link->network->ipv6_accept_ra_use_captive_portal) {
+ if (link->network->ndisc_use_captive_portal) {
NDiscCaptivePortal *cp;
usec_t usec = 0;
/* For backward compatibility. */
if (!network->dhcp_route_metric_set)
network->dhcp_route_metric = metric;
- if (!network->ipv6_accept_ra_route_metric_set) {
- network->ipv6_accept_ra_route_metric_high = metric;
- network->ipv6_accept_ra_route_metric_medium = metric;
- network->ipv6_accept_ra_route_metric_low = metric;
+ if (!network->ndisc_route_metric_set) {
+ network->ndisc_route_metric_high = metric;
+ network->ndisc_route_metric_medium = metric;
+ network->ndisc_route_metric_low = metric;
}
break;
default:
return 0;
}
-int config_parse_ipv6_accept_ra_route_metric(
+int config_parse_ndisc_route_metric(
const char *unit,
const char *filename,
unsigned line,
}
}
- network->ipv6_accept_ra_route_metric_high = metric_high;
- network->ipv6_accept_ra_route_metric_medium = metric_medium;
- network->ipv6_accept_ra_route_metric_low = metric_low;
- network->ipv6_accept_ra_route_metric_set = true;
+ network->ndisc_route_metric_high = metric_high;
+ network->ndisc_route_metric_medium = metric_medium;
+ network->ndisc_route_metric_low = metric_low;
+ network->ndisc_route_metric_set = true;
return 0;
}
network->dhcp_route_table_set = true;
break;
case AF_INET6:
- network->ipv6_accept_ra_route_table = rt;
- network->ipv6_accept_ra_route_table_set = true;
+ network->ndisc_route_table = rt;
+ network->ndisc_route_table_set = true;
break;
default:
assert_not_reached();
} DUID;
uint32_t link_get_dhcp4_route_table(Link *link);
-uint32_t link_get_ipv6_accept_ra_route_table(Link *link);
+uint32_t link_get_ndisc_route_table(Link *link);
bool link_dhcp_enabled(Link *link, int family);
static inline bool link_dhcp4_enabled(Link *link) {
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_route_metric);
-CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_route_metric);
+CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_route_metric);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_hostname);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains);
assert(link);
- if (!link_dhcp6_enabled(link) && !link_ipv6_accept_ra_enabled(link))
+ if (!link_dhcp6_enabled(link) && !link_ndisc_enabled(link))
return 0;
if (link->dhcp6_client)
Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes)
Network.ManageForeignNextHops, config_parse_bool, 0, offsetof(Manager, manage_foreign_nexthops)
Network.RouteTable, config_parse_route_table_names, 0, 0
+Network.IPv4Forwarding, config_parse_tristate, 0, offsetof(Manager, ip_forwarding[0])
+Network.IPv6Forwarding, config_parse_tristate, 0, offsetof(Manager, ip_forwarding[1])
Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Manager, ipv6_privacy_extensions)
DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp_duid)
DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp_duid)
}
}
- if (link->network->ipv6_accept_ra_use_dns) {
+ if (link->network->ndisc_use_dns) {
NDiscRDNSS *a;
SET_FOREACH(a, link->ndisc_rdnss) {
}
}
- if (link->network->ipv6_accept_ra_use_domains == use_domains) {
+ if (link->network->ndisc_use_domains == use_domains) {
NDiscDNSSL *a;
SET_FOREACH(a, link->ndisc_dnssl) {
assert(link);
assert(v);
- if (!link->network || !link->network->ipv6_accept_ra_use_pref64)
+ if (!link->network || !link->network->ndisc_use_pref64)
return 0;
SET_FOREACH(i, link->ndisc_pref64) {
* Note, ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
if (!link_ipv4ll_enabled(link) && !link_dhcp4_enabled(link) &&
!link_dhcp6_enabled(link) && !link_dhcp_pd_is_enabled(link) &&
- (link->network->configure_without_carrier || !link_ipv6_accept_ra_enabled(link)))
+ (link->network->configure_without_carrier || !link_ndisc_enabled(link)))
goto ready;
bool ipv4ll_ready =
(!link->network->dhcp_pd_assign ||
link_check_addresses_ready(link, NETWORK_CONFIG_SOURCE_DHCP_PD));
bool ndisc_ready =
- link_ipv6_accept_ra_enabled(link) && link->ndisc_configured &&
- (!link->network->ipv6_accept_ra_use_autonomous_prefix ||
+ link_ndisc_enabled(link) && link->ndisc_configured &&
+ (!link->network->ndisc_use_autonomous_prefix ||
link_check_addresses_ready(link, NETWORK_CONFIG_SOURCE_NDISC));
/* If the uplink for PD is self, then request the corresponding DHCP protocol is also ready. */
#include "networkd-link.h"
#include "networkd-lldp-tx.h"
#include "networkd-manager.h"
+#include "networkd-sysctl.h"
#include "parse-util.h"
#include "string-table.h"
#include "string-util.h"
SD_LLDP_SYSTEM_CAPABILITIES_STATION |
SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE |
SD_LLDP_SYSTEM_CAPABILITIES_ROUTER,
- (link->network->ip_forward != ADDRESS_FAMILY_NO) ?
- SD_LLDP_SYSTEM_CAPABILITIES_ROUTER :
- SD_LLDP_SYSTEM_CAPABILITIES_STATION);
+ (link_get_ip_forwarding(link, AF_INET) > 0 || link_get_ip_forwarding(link, AF_INET6) > 0) ?
+ SD_LLDP_SYSTEM_CAPABILITIES_ROUTER : SD_LLDP_SYSTEM_CAPABILITIES_STATION);
if (r < 0)
return r;
r = netns_get_nsid(/* netnsfd= */ -EBADF, &nsid);
if (r < 0)
- log_warning_errno(r, "Failed to query network nsid, ignoring: %m");
+ log_full_errno(r == -ENODATA ? LOG_DEBUG : LOG_WARNING, r, "Failed to query network nsid, ignoring: %m");
return varlink_replyb(link,
JSON_BUILD_OBJECT(
.dhcp_duid.type = DUID_TYPE_EN,
.dhcp6_duid.type = DUID_TYPE_EN,
.duid_product_uuid.type = DUID_TYPE_UUID,
+ .ip_forwarding = { -1, -1, },
};
*ret = TAKE_PTR(m);
assert(m);
+ manager_set_sysctl(m);
+
r = manager_start_speed_meter(m);
if (r < 0)
return log_error_errno(r, "Failed to initialize speed meter: %m");
Hashmap *tuntap_fds_by_name;
unsigned reloading;
+
+ /* sysctl */
+ int ip_forwarding[2];
};
int manager_new(Manager **ret, bool test_mode);
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-state-file.h"
+#include "networkd-sysctl.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
* Not sure if the threshold is high enough. Let's adjust later if not. */
#define NDISC_PREF64_MAX 64U
-bool link_ipv6_accept_ra_enabled(Link *link) {
+bool link_ndisc_enabled(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
if (!link_may_have_ipv6ll(link, /* check_multicast = */ true))
return false;
- assert(link->network->ipv6_accept_ra >= 0);
- return link->network->ipv6_accept_ra;
+ if (link->network->ndisc >= 0)
+ return link->network->ndisc;
+
+ /* Accept RAs if IPv6 forwarding is disabled, and ignore RAs if IPv6 forwarding is enabled. */
+ int t = link_get_ip_forwarding(link, AF_INET6);
+ if (t >= 0)
+ return !t;
+
+ /* Otherwise, defaults to true. */
+ return true;
}
-void network_adjust_ipv6_accept_ra(Network *network) {
+void network_adjust_ndisc(Network *network) {
assert(network);
if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
- if (network->ipv6_accept_ra > 0)
+ if (network->ndisc > 0)
log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link-local addressing is disabled or not supported. "
"Disabling IPv6AcceptRA=.", network->filename);
- network->ipv6_accept_ra = false;
+ network->ndisc = false;
}
- if (network->ipv6_accept_ra < 0)
- /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
- network->ipv6_accept_ra = !FLAGS_SET(network->ip_forward, ADDRESS_FAMILY_IPV6);
-
/* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
* RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
if (!set_isempty(network->ndisc_allow_listed_router))
switch (route->pref) {
case SD_NDISC_PREFERENCE_LOW:
- route->priority = link->network->ipv6_accept_ra_route_metric_low;
+ route->priority = link->network->ndisc_route_metric_low;
break;
case SD_NDISC_PREFERENCE_MEDIUM:
- route->priority = link->network->ipv6_accept_ra_route_metric_medium;
+ route->priority = link->network->ndisc_route_metric_medium;
break;
case SD_NDISC_PREFERENCE_HIGH:
- route->priority = link->network->ipv6_accept_ra_route_metric_high;
+ route->priority = link->network->ndisc_route_metric_high;
break;
default:
assert_not_reached();
if (r < 0)
return r;
- if (link->network->ipv6_accept_ra_use_mtu) {
+ if (link->network->ndisc_use_mtu) {
r = sd_ndisc_router_get_mtu(rt, &mtu);
if (r < 0 && r != -ENODATA)
return log_link_warning_errno(link, r, "Failed to get MTU from RA: %m");
}
- if (link->network->ipv6_accept_ra_use_hop_limit) {
+ if (link->network->ndisc_use_hop_limit) {
r = sd_ndisc_router_get_hop_limit(rt, &hop_limit);
if (r < 0 && r != -ENODATA)
return log_link_warning_errno(link, r, "Failed to get hop limit from RA: %m");
route->source = NETWORK_CONFIG_SOURCE_NDISC;
route->provider.in6 = router;
if (!route->table_set)
- route->table = link_get_ipv6_accept_ra_route_table(link);
+ route->table = link_get_ndisc_route_table(link);
if (!route->protocol_set)
route->protocol = RTPROT_RA;
r = route_metric_set(&route->metric, RTAX_MTU, mtu);
r = route_metric_set(&route->metric, RTAX_HOPLIMIT, hop_limit);
if (r < 0)
return r;
- r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->ipv6_accept_ra_quickack);
+ r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->ndisc_quickack);
if (r < 0)
return r;
ndisc_set_route_priority(link, route);
if (!route->table_set)
- route->table = link_get_ipv6_accept_ra_route_table(link);
+ route->table = link_get_ndisc_route_table(link);
r = route_adjust_nexthops(route, link);
if (r < 0)
if (r == 0)
return ndisc_router_drop_default(link, rt);
- if (!link->network->ipv6_accept_ra_use_gateway &&
+ if (!link->network->ndisc_use_gateway &&
hashmap_isempty(link->network->routes_by_section))
return 0;
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
- if (link->network->ipv6_accept_ra_use_gateway) {
+ if (link->network->ndisc_use_gateway) {
_cleanup_(route_unrefp) Route *route = NULL;
r = route_new(&route);
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_icmp6_ratelimit)
+ if (!link->network->ndisc_use_icmp6_ratelimit)
return 0;
/* Ignore the icmp6 ratelimit field of the RA header if the lifetime is zero. */
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_reachable_time)
+ if (!link->network->ndisc_use_reachable_time)
return 0;
/* Ignore the reachable time field of the RA header if the lifetime is zero. */
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_retransmission_time)
+ if (!link->network->ndisc_use_retransmission_time)
return 0;
/* Ignore the retransmission time field of the RA header if the lifetime is zero. */
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_hop_limit)
+ if (!link->network->ndisc_use_hop_limit)
return 0;
/* Ignore the hop limit field of the RA header if the lifetime is zero. */
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_autonomous_prefix)
+ if (!link->network->ndisc_use_autonomous_prefix)
return 0;
r = sd_ndisc_router_prefix_get_address(rt, &prefix);
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_onlink_prefix)
+ if (!link->network->ndisc_use_onlink_prefix)
return 0;
r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
* covered by the prefix are off-link. The only way to cancel a previous on-link indication is to
* advertise that prefix with the L-bit set and the Lifetime set to zero. */
- if (!link->network->ipv6_accept_ra_use_onlink_prefix)
+ if (!link->network->ndisc_use_onlink_prefix)
return 0;
r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_usec);
assert(link);
- if (!link->network->ipv6_accept_ra_use_route_prefix)
+ if (!link->network->ndisc_use_route_prefix)
return 0;
r = sd_ndisc_router_route_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_dns)
+ if (!link->network->ndisc_use_dns)
return 0;
r = sd_ndisc_router_get_address(rt, &router);
assert(link->network);
assert(rt);
- if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_NO)
+ if (link->network->ndisc_use_domains == DHCP_USE_DOMAINS_NO)
return 0;
r = sd_ndisc_router_get_address(rt, &router);
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_captive_portal)
+ if (!link->network->ndisc_use_captive_portal)
return 0;
r = sd_ndisc_router_get_address(rt, &router);
assert(link->network);
assert(rt);
- if (!link->network->ipv6_accept_ra_use_pref64)
+ if (!link->network->ndisc_use_pref64)
return 0;
r = sd_ndisc_router_get_address(rt, &router);
if (route->nexthop.ifindex != link->ifindex)
continue;
- if (route->lifetime_usec >= timestamp_usec)
+ if (route->lifetime_usec > timestamp_usec)
continue; /* the route is still valid */
r = route_remove_and_cancel(route, link->manager);
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
continue;
- if (address->lifetime_valid_usec >= timestamp_usec)
+ if (address->lifetime_valid_usec > timestamp_usec)
continue; /* the address is still valid */
r = address_remove_and_cancel(address, link);
}
SET_FOREACH(rdnss, link->ndisc_rdnss) {
- if (rdnss->lifetime_usec >= timestamp_usec)
+ if (rdnss->lifetime_usec > timestamp_usec)
continue; /* the DNS server is still valid */
free(set_remove(link->ndisc_rdnss, rdnss));
}
SET_FOREACH(dnssl, link->ndisc_dnssl) {
- if (dnssl->lifetime_usec >= timestamp_usec)
+ if (dnssl->lifetime_usec > timestamp_usec)
continue; /* the DNS domain is still valid */
free(set_remove(link->ndisc_dnssl, dnssl));
}
SET_FOREACH(cp, link->ndisc_captive_portals) {
- if (cp->lifetime_usec >= timestamp_usec)
+ if (cp->lifetime_usec > timestamp_usec)
continue; /* the captive portal is still valid */
ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals, cp));
}
SET_FOREACH(p64, link->ndisc_pref64) {
- if (p64->lifetime_usec >= timestamp_usec)
+ if (p64->lifetime_usec > timestamp_usec)
continue; /* the pref64 prefix is still valid */
free(set_remove(link->ndisc_pref64, p64));
if (r <= 0)
return r;
- switch (link->network->ipv6_accept_ra_start_dhcp6_client) {
+ switch (link->network->ndisc_start_dhcp6_client) {
case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO:
return 0;
return 0;
}
-static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
+static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata) {
Link *link = ASSERT_PTR(userdata);
int r;
switch (event) {
case SD_NDISC_EVENT_ROUTER:
- r = ndisc_router_handler(link, rt);
+ r = ndisc_router_handler(link, ASSERT_PTR(message));
if (r < 0 && r != -EBADMSG) {
link_enter_failed(link);
return;
link_check_ready(link);
}
break;
+
default:
- assert_not_reached();
+ log_link_debug(link, "Received unsupported NDisc event, ignoring.");
}
}
assert(link);
- if (!link_ipv6_accept_ra_enabled(link))
+ if (!link_ndisc_enabled(link))
return 0;
if (link->ndisc)
assert(link);
- if (!link_ipv6_accept_ra_enabled(link))
+ if (!link_ndisc_enabled(link))
return 0;
if (link->ndisc)
link->ndisc_pref64 = set_free(link->ndisc_pref64);
}
-static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
+static const char* const ndisc_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
};
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ndisc_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
+DEFINE_CONFIG_PARSE_ENUM(config_parse_ndisc_use_domains, dhcp_use_domains, DHCPUseDomains,
"Failed to parse UseDomains= setting");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
+DEFINE_CONFIG_PARSE_ENUM(config_parse_ndisc_start_dhcp6_client, ndisc_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
"Failed to parse DHCPv6Client= setting");
return ((char*) n) + ALIGN(sizeof(NDiscDNSSL));
}
-bool link_ipv6_accept_ra_enabled(Link *link);
+bool link_ndisc_enabled(Link *link);
-void network_adjust_ipv6_accept_ra(Network *network);
+void network_adjust_ndisc(Network *network);
int ndisc_start(Link *link);
int ndisc_stop(Link *link);
int link_request_ndisc(Link *link);
-CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client);
-CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_use_domains);
+CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_start_dhcp6_client);
+CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_use_domains);
Network.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Network, dnssec_mode)
Network.DNSSECNegativeTrustAnchors, config_parse_dnssec_negative_trust_anchors, 0, offsetof(Network, dnssec_negative_trust_anchors)
Network.NTP, config_parse_ntp, 0, offsetof(Network, ntp)
-Network.IPForward, config_parse_address_family_with_kernel, 0, offsetof(Network, ip_forward)
+Network.IPForward, config_parse_ip_forward_deprecated, 0, 0
+Network.IPv4Forwarding, config_parse_tristate, 0, offsetof(Network, ip_forwarding[0])
+Network.IPv6Forwarding, config_parse_tristate, 0, offsetof(Network, ip_forwarding[1])
Network.IPMasquerade, config_parse_ip_masquerade, 0, offsetof(Network, ip_masquerade)
Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions)
-Network.IPv6AcceptRA, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
-Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
+Network.IPv6AcceptRA, config_parse_tristate, 0, offsetof(Network, ndisc)
+Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ndisc)
Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits)
Network.IPv6HopLimit, config_parse_uint8, 0, offsetof(Network, ipv6_hop_limit)
Network.IPv6RetransmissionTimeSec, config_parse_sec, 0, offsetof(Network, ipv6_retransmission_time)
DHCPv6.NetLabel, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(Network, dhcp6_netlabel)
DHCPv6.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp6_send_release)
DHCPv6.NFTSet, config_parse_nft_set, NFT_SET_PARSE_NETWORK, offsetof(Network, dhcp6_nft_set_context)
-IPv6AcceptRA.UseGateway, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_gateway)
-IPv6AcceptRA.UseRoutePrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_route_prefix)
-IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
-IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
-IPv6AcceptRA.UsePREF64, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_pref64)
-IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns)
-IPv6AcceptRA.UseDomains, config_parse_ipv6_accept_ra_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
-IPv6AcceptRA.UseMTU, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_mtu)
-IPv6AcceptRA.UseHopLimit, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_hop_limit)
-IPv6AcceptRA.UseReachableTime, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_reachable_time)
-IPv6AcceptRA.UseRetransmissionTime, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_retransmission_time)
-IPv6AcceptRA.UseICMP6RateLimit, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_icmp6_ratelimit)
-IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
+IPv6AcceptRA.UseGateway, config_parse_bool, 0, offsetof(Network, ndisc_use_gateway)
+IPv6AcceptRA.UseRoutePrefix, config_parse_bool, 0, offsetof(Network, ndisc_use_route_prefix)
+IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ndisc_use_autonomous_prefix)
+IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ndisc_use_onlink_prefix)
+IPv6AcceptRA.UsePREF64, config_parse_bool, 0, offsetof(Network, ndisc_use_pref64)
+IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ndisc_use_dns)
+IPv6AcceptRA.UseDomains, config_parse_ndisc_use_domains, 0, offsetof(Network, ndisc_use_domains)
+IPv6AcceptRA.UseMTU, config_parse_bool, 0, offsetof(Network, ndisc_use_mtu)
+IPv6AcceptRA.UseHopLimit, config_parse_bool, 0, offsetof(Network, ndisc_use_hop_limit)
+IPv6AcceptRA.UseReachableTime, config_parse_bool, 0, offsetof(Network, ndisc_use_reachable_time)
+IPv6AcceptRA.UseRetransmissionTime, config_parse_bool, 0, offsetof(Network, ndisc_use_retransmission_time)
+IPv6AcceptRA.UseICMP6RateLimit, config_parse_bool, 0, offsetof(Network, ndisc_use_icmp6_ratelimit)
+IPv6AcceptRA.DHCPv6Client, config_parse_ndisc_start_dhcp6_client, 0, offsetof(Network, ndisc_start_dhcp6_client)
IPv6AcceptRA.RouteTable, config_parse_dhcp_or_ra_route_table, AF_INET6, 0
-IPv6AcceptRA.RouteMetric, config_parse_ipv6_accept_ra_route_metric, 0, 0
-IPv6AcceptRA.QuickAck, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_quickack)
-IPv6AcceptRA.UseCaptivePortal, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_captive_portal)
+IPv6AcceptRA.RouteMetric, config_parse_ndisc_route_metric, 0, 0
+IPv6AcceptRA.QuickAck, config_parse_bool, 0, offsetof(Network, ndisc_quickack)
+IPv6AcceptRA.UseCaptivePortal, config_parse_bool, 0, offsetof(Network, ndisc_use_captive_portal)
IPv6AcceptRA.RouterAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_router)
IPv6AcceptRA.RouterDenyList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_deny_listed_router)
IPv6AcceptRA.PrefixAllowList, config_parse_in_addr_prefixes, AF_INET6, offsetof(Network, ndisc_allow_listed_prefix)
DHCP.ForceDHCPv6PDOtherInformation, config_parse_warn_compat, DISABLED_LEGACY, 0
DHCPv4.UseDomainName, config_parse_dhcp_use_domains, AF_INET, 0
DHCPv4.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical)
-DHCPv6.RouteMetric, config_parse_ipv6_accept_ra_route_metric, AF_INET6, 0
+DHCPv6.RouteMetric, config_parse_ndisc_route_metric, AF_INET6, 0
DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_warn_compat, DISABLED_LEGACY, 0
DHCPv6PrefixDelegation.SubnetId, config_parse_dhcp_pd_subnet_id, 0, offsetof(Network, dhcp_pd_subnet_id)
DHCPv6PrefixDelegation.Announce, config_parse_bool, 0, offsetof(Network, dhcp_pd_announce)
network->ipv6ll_address_gen_mode < 0)
network->ipv6ll_address_gen_mode = IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY;
- /* IPMasquerade implies IPForward */
- network->ip_forward |= network->ip_masquerade;
-
network_adjust_ipv6_proxy_ndp(network);
- network_adjust_ipv6_accept_ra(network);
+ network_adjust_ndisc(network);
network_adjust_dhcp(network);
network_adjust_radv(network);
network_adjust_bridge_vlan(network);
.link_local = _ADDRESS_FAMILY_INVALID,
.ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
+ .ip_forwarding = { -1, -1, },
.ipv4_accept_local = -1,
.ipv4_route_localnet = -1,
.ipv6_privacy_extensions = _IPV6_PRIVACY_EXTENSIONS_INVALID,
.proxy_arp_pvlan = -1,
.ipv4_rp_filter = _IP_REVERSE_PATH_FILTER_INVALID,
- .ipv6_accept_ra = -1,
- .ipv6_accept_ra_use_dns = true,
- .ipv6_accept_ra_use_gateway = true,
- .ipv6_accept_ra_use_captive_portal = true,
- .ipv6_accept_ra_use_route_prefix = true,
- .ipv6_accept_ra_use_autonomous_prefix = true,
- .ipv6_accept_ra_use_onlink_prefix = true,
- .ipv6_accept_ra_use_mtu = true,
- .ipv6_accept_ra_use_hop_limit = true,
- .ipv6_accept_ra_use_reachable_time = true,
- .ipv6_accept_ra_use_retransmission_time = true,
- .ipv6_accept_ra_use_icmp6_ratelimit = true,
- .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
- .ipv6_accept_ra_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
- .ipv6_accept_ra_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
- .ipv6_accept_ra_route_metric_low = IPV6RA_ROUTE_METRIC_LOW,
- .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
+ .ndisc = -1,
+ .ndisc_use_dns = true,
+ .ndisc_use_gateway = true,
+ .ndisc_use_captive_portal = true,
+ .ndisc_use_route_prefix = true,
+ .ndisc_use_autonomous_prefix = true,
+ .ndisc_use_onlink_prefix = true,
+ .ndisc_use_mtu = true,
+ .ndisc_use_hop_limit = true,
+ .ndisc_use_reachable_time = true,
+ .ndisc_use_retransmission_time = true,
+ .ndisc_use_icmp6_ratelimit = true,
+ .ndisc_route_table = RT_TABLE_MAIN,
+ .ndisc_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
+ .ndisc_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
+ .ndisc_route_metric_low = IPV6RA_ROUTE_METRIC_LOW,
+ .ndisc_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES,
.can_termination = -1,
int ipoib_umcast;
/* sysctl settings */
- AddressFamily ip_forward;
+ int ip_forwarding[2];
int ipv4_accept_local;
int ipv4_route_localnet;
int ipv6_dad_transmits;
int ipv6_proxy_ndp;
Set *ipv6_proxy_ndp_addresses;
- /* IPv6 accept RA */
- int ipv6_accept_ra;
- bool ipv6_accept_ra_use_dns;
- bool ipv6_accept_ra_use_gateway;
- bool ipv6_accept_ra_use_route_prefix;
- bool ipv6_accept_ra_use_autonomous_prefix;
- bool ipv6_accept_ra_use_onlink_prefix;
- bool ipv6_accept_ra_use_mtu;
- bool ipv6_accept_ra_use_hop_limit;
- bool ipv6_accept_ra_use_reachable_time;
- bool ipv6_accept_ra_use_retransmission_time;
- bool ipv6_accept_ra_use_icmp6_ratelimit;
- bool ipv6_accept_ra_quickack;
- bool ipv6_accept_ra_use_captive_portal;
- bool ipv6_accept_ra_use_pref64;
+ /* NDisc support */
+ int ndisc;
+ bool ndisc_use_dns;
+ bool ndisc_use_gateway;
+ bool ndisc_use_route_prefix;
+ bool ndisc_use_autonomous_prefix;
+ bool ndisc_use_onlink_prefix;
+ bool ndisc_use_mtu;
+ bool ndisc_use_hop_limit;
+ bool ndisc_use_reachable_time;
+ bool ndisc_use_retransmission_time;
+ bool ndisc_use_icmp6_ratelimit;
+ bool ndisc_quickack;
+ bool ndisc_use_captive_portal;
+ bool ndisc_use_pref64;
bool active_slave;
bool primary_slave;
- DHCPUseDomains ipv6_accept_ra_use_domains;
- IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client;
- uint32_t ipv6_accept_ra_route_table;
- bool ipv6_accept_ra_route_table_set;
- uint32_t ipv6_accept_ra_route_metric_high;
- uint32_t ipv6_accept_ra_route_metric_medium;
- uint32_t ipv6_accept_ra_route_metric_low;
- bool ipv6_accept_ra_route_metric_set;
+ DHCPUseDomains ndisc_use_domains;
+ IPv6AcceptRAStartDHCP6Client ndisc_start_dhcp6_client;
+ uint32_t ndisc_route_table;
+ bool ndisc_route_table_set;
+ uint32_t ndisc_route_metric_high;
+ uint32_t ndisc_route_metric_medium;
+ uint32_t ndisc_route_metric_low;
+ bool ndisc_route_metric_set;
Set *ndisc_deny_listed_router;
Set *ndisc_allow_listed_router;
Set *ndisc_deny_listed_prefix;
"Ignoring [Route] section from line %u.",
route->section->filename, route->section->line);
- if (route->nexthop.family == AF_INET6 && !route->network->ipv6_accept_ra)
+ if (route->nexthop.family == AF_INET6 && route->network->ndisc == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
"Ignoring [Route] section from line %u.",
}
int route_remove_and_cancel(Route *route, Manager *manager) {
+ _cleanup_(request_unrefp) Request *req = NULL;
bool waiting = false;
- Request *req;
assert(route);
assert(manager);
/* Cancel the request for the route. If the request is already called but we have not received the
* notification about the request, then explicitly remove the route. */
if (route_get_request(manager, route, &req) >= 0) {
+ request_ref(req); /* avoid the request freed by request_detach() */
waiting = req->waiting_reply;
request_detach(req);
route_cancel_requesting(route);
}
}
- if (link->network->ipv6_accept_ra_use_dns) {
+ if (link->network->ndisc_use_dns) {
NDiscRDNSS *a;
SET_FOREACH(a, link->ndisc_rdnss) {
}
}
- if (link->network->ipv6_accept_ra_use_domains == use_domains) {
+ if (link->network->ndisc_use_domains == use_domains) {
NDiscDNSSL *a;
SET_FOREACH(a, link->ndisc_dnssl) {
fputstrv(f, domains, NULL, &space);
}
- if (link->network->ipv6_accept_ra_use_domains == use_domains) {
+ if (link->network->ndisc_use_domains == use_domains) {
NDiscDNSSL *dd;
SET_FOREACH(dd, link->ndisc_dnssl)
sd_dhcp6_lease_get_dns,
NULL);
- if (link->network->ipv6_accept_ra_use_dns) {
+ if (link->network->ndisc_use_dns) {
NDiscRDNSS *dd;
SET_FOREACH(dd, link->ndisc_rdnss)
#include <linux/if.h>
#include <linux/if_arp.h>
+#include "af-list.h"
#include "missing_network.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "string-table.h"
#include "sysctl-util.h"
+static void manager_set_ip_forwarding(Manager *manager, int family) {
+ int r, t;
+
+ assert(manager);
+ assert(IN_SET(family, AF_INET, AF_INET6));
+
+ if (family == AF_INET6 && !socket_ipv6_is_supported())
+ return;
+
+ t = manager->ip_forwarding[family == AF_INET6];
+ if (t < 0)
+ return; /* keep */
+
+ /* First, set the default value. */
+ r = sysctl_write_ip_property_boolean(family, "default", "forwarding", t);
+ if (r < 0)
+ log_warning_errno(r, "Failed to %s the default %s forwarding: %m",
+ enable_disable(t), af_to_ipv4_ipv6(family));
+
+ /* Then, set the value to all interfaces. */
+ r = sysctl_write_ip_property_boolean(family, "all", "forwarding", t);
+ if (r < 0)
+ log_warning_errno(r, "Failed to %s %s forwarding for all interfaces: %m",
+ enable_disable(t), af_to_ipv4_ipv6(family));
+}
+
+void manager_set_sysctl(Manager *manager) {
+ assert(manager);
+ assert(!manager->test_mode);
+
+ manager_set_ip_forwarding(manager, AF_INET);
+ manager_set_ip_forwarding(manager, AF_INET6);
+}
+
static bool link_is_configured_for_family(Link *link, int family) {
assert(link);
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp_pvlan", link->network->proxy_arp_pvlan > 0);
}
-static bool link_ip_forward_enabled(Link *link, int family) {
+int link_get_ip_forwarding(Link *link, int family) {
assert(link);
+ assert(link->manager);
+ assert(link->network);
assert(IN_SET(family, AF_INET, AF_INET6));
- if (!link_is_configured_for_family(link, family))
- return false;
-
- return link->network->ip_forward & (family == AF_INET ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_IPV6);
-}
+ /* If it is explicitly specified, then honor the setting. */
+ int t = link->network->ip_forwarding[family == AF_INET6];
+ if (t >= 0)
+ return t;
-static int link_set_ipv4_forward(Link *link) {
- assert(link);
-
- if (!link_ip_forward_enabled(link, AF_INET))
- return 0;
+ /* If IPMasquerade= is enabled, also enable IP forwarding. */
+ if (family == AF_INET && FLAGS_SET(link->network->ip_masquerade, ADDRESS_FAMILY_IPV4))
+ return true;
+ if (family == AF_INET6 && FLAGS_SET(link->network->ip_masquerade, ADDRESS_FAMILY_IPV6))
+ return true;
- /* We propagate the forwarding flag from one interface to the
- * global setting one way. This means: as long as at least one
- * interface was configured at any time that had IP forwarding
- * enabled the setting will stay on for good. We do this
- * primarily to keep IPv4 and IPv6 packet forwarding behaviour
- * somewhat in sync (see below). */
+ /* If IPv6SendRA= is enabled, also enable IPv6 forwarding. */
+ if (family == AF_INET6 && link_radv_enabled(link))
+ return true;
- return sysctl_write_ip_property(AF_INET, NULL, "ip_forward", "1");
+ /* Otherwise, use the global setting. */
+ return link->manager->ip_forwarding[family == AF_INET6];
}
-static int link_set_ipv6_forward(Link *link) {
+static int link_set_ip_forwarding(Link *link, int family) {
+ int r, t;
+
assert(link);
+ assert(IN_SET(family, AF_INET, AF_INET6));
- if (!link_ip_forward_enabled(link, AF_INET6))
+ if (!link_is_configured_for_family(link, family))
return 0;
- /* On Linux, the IPv6 stack does not know a per-interface
- * packet forwarding setting: either packet forwarding is on
- * for all, or off for all. We hence don't bother with a
- * per-interface setting, but simply propagate the interface
- * flag, if it is set, to the global flag, one-way. Note that
- * while IPv4 would allow a per-interface flag, we expose the
- * same behaviour there and also propagate the setting from
- * one to all, to keep things simple (see above). */
+ t = link_get_ip_forwarding(link, family);
+ if (t < 0)
+ return 0; /* keep */
- return sysctl_write_ip_property(AF_INET6, "all", "forwarding", "1");
+ r = sysctl_write_ip_property_boolean(family, link->ifname, "forwarding", t);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to %s %s forwarding, ignoring: %m",
+ enable_disable(t), af_to_ipv4_ipv6(family));
+
+ return 0;
}
static int link_set_ipv4_rp_filter(Link *link) {
if (r < 0)
log_link_warning_errno(link, r, "Cannot configure proxy ARP private VLAN for interface, ignoring: %m");
- r = link_set_ipv4_forward(link);
- if (r < 0)
- log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
-
- r = link_set_ipv6_forward(link);
- if (r < 0)
- log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
+ (void) link_set_ip_forwarding(link, AF_INET);
+ (void) link_set_ip_forwarding(link, AF_INET6);
r = link_set_ipv6_privacy_extensions(link);
if (r < 0)
DEFINE_STRING_TABLE_LOOKUP(ip_reverse_path_filter, IPReversePathFilter);
DEFINE_CONFIG_PARSE_ENUM(config_parse_ip_reverse_path_filter, ip_reverse_path_filter, IPReversePathFilter,
"Failed to parse IP reverse path filter option");
+
+int config_parse_ip_forward_deprecated(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ assert(filename);
+
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "IPForward= setting is deprecated. "
+ "Please use IPv4Forwarding= and/or IPv6Forwarding= in networkd.conf for global setting, "
+ "and the same settings in .network files for per-interface setting.");
+ return 0;
+}
#include "conf-parser.h"
typedef struct Link Link;
+typedef struct Manager Manager;
typedef enum IPv6PrivacyExtensions {
/* These values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values. Do not reorder! */
_IP_REVERSE_PATH_FILTER_INVALID = -EINVAL,
} IPReversePathFilter;
+void manager_set_sysctl(Manager *manager);
+
+int link_get_ip_forwarding(Link *link, int family);
int link_set_sysctl(Link *link);
int link_set_ipv6_mtu(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_privacy_extensions);
CONFIG_PARSER_PROTOTYPE(config_parse_ip_reverse_path_filter);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip_forward_deprecated);
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(ip_masquerade_address_family, AddressFamily);
DEFINE_STRING_TABLE_LOOKUP(dhcp_lease_server_type, sd_dhcp_lease_server_type_t);
-int config_parse_address_family_with_kernel(
- const char* unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- AddressFamily *fwd = data, s;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- /* This function is mostly obsolete now. It simply redirects
- * "kernel" to "no". In older networkd versions we used to
- * distinguish IPForward=off from IPForward=kernel, where the
- * former would explicitly turn off forwarding while the
- * latter would simply not touch the setting. But that logic
- * is gone, hence silently accept the old setting, but turn it
- * to "no". */
-
- s = address_family_from_string(rvalue);
- if (s < 0) {
- if (streq(rvalue, "kernel"))
- s = ADDRESS_FAMILY_NO;
- else {
- log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse IPForward= option, ignoring: %s", rvalue);
- return 0;
- }
- }
-
- *fwd = s;
-
- return 0;
-}
-
int config_parse_ip_masquerade(
const char *unit,
const char *filename,
}
CONFIG_PARSER_PROTOTYPE(config_parse_link_local_address_family);
-CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel);
CONFIG_PARSER_PROTOTYPE(config_parse_ip_masquerade);
CONFIG_PARSER_PROTOTYPE(config_parse_mud_url);
#include "networkd-manager.h"
#include "service-util.h"
#include "signal-util.h"
+#include "strv.h"
#include "user-util.h"
static int run(int argc, char *argv[]) {
/* Always create the directories people can create inotify watches in.
* It is necessary to create the following subdirectories after drop_privileges()
* to support old kernels not supporting AmbientCapabilities=. */
- r = mkdir_safe_label("/run/systemd/netif/links", 0755, UID_INVALID, GID_INVALID, MKDIR_WARN_MODE);
- if (r < 0)
- log_warning_errno(r, "Could not create runtime directory 'links': %m");
-
- r = mkdir_safe_label("/run/systemd/netif/leases", 0755, UID_INVALID, GID_INVALID, MKDIR_WARN_MODE);
- if (r < 0)
- log_warning_errno(r, "Could not create runtime directory 'leases': %m");
-
- r = mkdir_safe_label("/run/systemd/netif/lldp", 0755, UID_INVALID, GID_INVALID, MKDIR_WARN_MODE);
- if (r < 0)
- log_warning_errno(r, "Could not create runtime directory 'lldp': %m");
+ FOREACH_STRING(p,
+ "/run/systemd/netif/links/",
+ "/run/systemd/netif/leases/",
+ "/run/systemd/netif/lldp/") {
+ r = mkdir_safe_label(p, 0755, UID_INVALID, GID_INVALID, MKDIR_WARN_MODE);
+ if (r < 0)
+ log_warning_errno(r, "Could not create directory '%s': %m", p);
+ }
r = manager_new(&m, /* test_mode = */ false);
if (r < 0)
if (arg_quiet)
log_set_max_level(LOG_ERR);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_required_family, arg_any, arg_timeout);
if (r < 0)
(void) pty_forward_set_titlef(f, "%sContainer %s on %s", strempty(dot), arg_machine, hn);
else
(void) pty_forward_set_titlef(f, "%sContainer %s", strempty(dot), arg_machine);
+
+ if (dot)
+ (void) pty_forward_set_title_prefix(f, dot);
}
static int merge_settings(Settings *settings, const char *path) {
_cleanup_free_ char *u = NULL;
(void) terminal_urlify_path(t, t, &u);
- log_info("%s %sSpawning container %s on %s.%s\n"
- "%s %sPress %sCtrl-]%s three times within 1s to kill container.%s",
- special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), arg_machine, u ?: t, ansi_normal(),
- special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), ansi_highlight(), ansi_grey(), ansi_normal());
+ log_info("%s %sSpawning container %s on %s.%s",
+ special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), arg_machine, u ?: t, ansi_normal());
+
+ if (arg_console_mode == CONSOLE_INTERACTIVE)
+ log_info("%s %sPress %sCtrl-]%s three times within 1s to kill container.%s",
+ special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), ansi_highlight(), ansi_grey(), ansi_normal());
}
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
r = make_reaper_process(true);
if (r < 0) {
if (!FLAGS_SET(mask, CGROUP_MASK_MEMORY))
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Requires the cgroup memory controller.");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
if (arg_mem_pressure_usec > 0 && arg_mem_pressure_usec < 1 * USEC_PER_SEC)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DefaultMemoryPressureDurationSec= must be 0 or at least 1s");
if (argc != 1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
r = manager_new(&m);
if (r < 0)
/* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */
#define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE)
-/* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */
-#define NSEC3_ITERATIONS_MAX 2500
+/* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value, but
+ * RFC9276 § 3.2 says that we should reduce the acceptable iteration count */
+#define NSEC3_ITERATIONS_MAX 100
/*
* The DNSSEC Chain of trust:
DnsResourceRecord **ret_rrsig) {
bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false;
+ unsigned nvalidations = 0;
DnsResourceRecord *rrsig;
int r;
if (realtime == USEC_INFINITY)
realtime = now(CLOCK_REALTIME);
+ /* Have we seen an unreasonable number of invalid signaures? */
+ if (nvalidations > DNSSEC_INVALID_MAX) {
+ if (ret_rrsig)
+ *ret_rrsig = NULL;
+ *result = DNSSEC_TOO_MANY_VALIDATIONS;
+ return (int) nvalidations;
+ }
+
/* Yay, we found a matching RRSIG with a matching
* DNSKEY, awesome. Now let's verify all entries of
* the RRSet against the RRSIG and DNSKEY
if (r < 0)
return r;
+ nvalidations++;
+
switch (one_result) {
case DNSSEC_VALIDATED:
*ret_rrsig = rrsig;
*result = one_result;
- return 0;
+ return (int) nvalidations;
case DNSSEC_INVALID:
/* If the signature is invalid, let's try another
if (ret_rrsig)
*ret_rrsig = NULL;
- return 0;
+ return (int) nvalidations;
}
int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) {
[DNSSEC_NSEC_MISMATCH] = "nsec-mismatch",
[DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server",
[DNSSEC_UPSTREAM_FAILURE] = "upstream-failure",
+ [DNSSEC_TOO_MANY_VALIDATIONS] = "too-many-validations",
};
DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult);
#include "resolved-dns-rr.h"
enum DnssecResult {
- /* These five are returned by dnssec_verify_rrset() */
+ /* These six are returned by dnssec_verify_rrset() */
DNSSEC_VALIDATED,
DNSSEC_VALIDATED_WILDCARD, /* Validated via a wildcard RRSIG, further NSEC/NSEC3 checks necessary */
DNSSEC_INVALID,
DNSSEC_SIGNATURE_EXPIRED,
DNSSEC_UNSUPPORTED_ALGORITHM,
+ DNSSEC_TOO_MANY_VALIDATIONS,
/* These two are added by dnssec_verify_rrset_search() */
DNSSEC_NO_SIGNATURE,
/* The longest digest we'll ever generate, of all digest algorithms we support */
#define DNSSEC_HASH_SIZE_MAX (MAX(20, 32))
+/* The most invalid signatures we will tolerate for a single rrset */
+#define DNSSEC_INVALID_MAX 5
+
+/* The total number of signature validations we will tolerate for a single transaction */
+#define DNSSEC_VALIDATION_MAX 64
+
int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok);
int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig);
DnsTransaction *t,
Phase phase,
bool *have_nsec,
+ unsigned *nvalidations,
DnsAnswer **validated) {
DnsResourceRecord *rr;
int r;
+ assert(nvalidations);
+
/* Returns negative on error, 0 if validation failed, 1 to restart validation, 2 when finished. */
DNS_ANSWER_FOREACH(rr, t->answer) {
&rrsig);
if (r < 0)
return r;
+ *nvalidations += r;
log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
DNSSEC_SIGNATURE_EXPIRED,
DNSSEC_NO_SIGNATURE))
manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key);
- else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */
+ else /* DNSSEC_MISSING_KEY, DNSSEC_UNSUPPORTED_ALGORITHM,
+ or DNSSEC_TOO_MANY_VALIDATIONS */
manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key);
/* This is a primary response to our question, and it failed validation.
return r;
phase = DNSSEC_PHASE_DNSKEY;
- for (;;) {
+ for (unsigned nvalidations = 0;;) {
bool have_nsec = false;
- r = dnssec_validate_records(t, phase, &have_nsec, &validated);
+ r = dnssec_validate_records(t, phase, &have_nsec, &nvalidations, &validated);
if (r <= 0)
return r;
+ if (nvalidations > DNSSEC_VALIDATION_MAX) {
+ /* This reply requires an onerous number of signature validations to verify. Let's
+ * not waste our time trying, as this shouldn't happen for well-behaved domains
+ * anyway. */
+ t->answer_dnssec_result = DNSSEC_TOO_MANY_VALIDATIONS;
+ return 0;
+ }
+
/* Try again as long as we managed to achieve something */
if (r == 1)
continue;
return log_error_errno(r, "Failed to drop privileges: %m");
}
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, SIGRTMIN+18) >= 0);
r = manager_new(&m);
if (r < 0)
(void) pty_forward_set_titlef(f, "%s%s on %s", strempty(dot), cl, arg_host ?: hn);
else
(void) pty_forward_set_titlef(f, "%s%s", strempty(dot), cl);
+
+ (void) pty_forward_set_title_prefix(f, dot);
}
static int start_transient_service(sd_bus *bus) {
return log_error_errno(r, "Failed to get event loop: %m");
if (master >= 0) {
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
- (void) sd_event_add_signal(c.event, NULL, SIGINT, NULL, NULL);
- (void) sd_event_add_signal(c.event, NULL, SIGTERM, NULL, NULL);
+ assert_se(sigprocmask_many(SIG_BLOCK, /* old_sigset=*/ NULL, SIGWINCH) >= 0);
+
+ (void) sd_event_set_signal_exit(c.event, true);
if (!arg_quiet)
log_info("Press ^] three times within 1s to disconnect TTY.");
return -EUNATCH;
assert_se(sigemptyset(&mask) >= 0);
- assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
+ assert_se(sigset_add_many(&mask, SIGINT, SIGTERM) >= 0);
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
#define table_set_sort(...) table_set_sort_internal(__VA_ARGS__, SIZE_MAX)
int table_set_reverse(Table *t, size_t column, bool b);
int table_hide_column_from_display_internal(Table *t, ...);
-#define table_hide_column_from_display(t, ...) table_hide_column_from_display_internal(t, __VA_ARGS__, (size_t) -1)
+#define table_hide_column_from_display(t, ...) table_hide_column_from_display_internal(t, __VA_ARGS__, SIZE_MAX)
int table_print(Table *t, FILE *f);
int table_format(Table *t, char **ret);
else /* otherwise pump it up */
s = 75;
- v = MAX(30, v); /* Make sure we don't hide the color in black */
+ v = MAX(20, v); /* Make sure we don't hide the color in black */
uint8_t r8, g8, b8;
hsv_to_rgb(hue, s, v, &r8, &g8, &b8);
ANSI_COLOR_STATE_TEXT,
ANSI_COLOR_STATE_ESC,
ANSI_COLOR_STATE_CSI_SEQUENCE,
+ ANSI_COLOR_STATE_OSC_SEQUENCE,
ANSI_COLOR_STATE_NEWLINE,
ANSI_COLOR_STATE_CARRIAGE_RETURN,
_ANSI_COLOR_STATE_MAX,
char *background_color;
AnsiColorState ansi_color_state;
char *csi_sequence;
+ char *osc_sequence;
- char *title;
+ char *title; /* Window title to show by default */
+ char *title_prefix; /* If terminal client overrides window title, prefix this string */
};
#define ESCAPE_USEC (1*USEC_PER_SEC)
f->in_buffer_full = 0;
f->csi_sequence = mfree(f->csi_sequence);
+ f->osc_sequence = mfree(f->osc_sequence);
f->ansi_color_state = _ANSI_COLOR_STATE_INVALID;
}
static int insert_background_fix(PTYForward *f, size_t offset) {
assert(f);
- assert(f->background_color);
+
+ if (!f->background_color)
+ return 0;
if (!is_csi_background_reset_sequence(strempty(f->csi_sequence)))
return 0;
return insert_string(f, offset, s);
}
+static int insert_window_title_fix(PTYForward *f, size_t offset) {
+ assert(f);
+
+ if (!f->title_prefix)
+ return 0;
+
+ if (!f->osc_sequence)
+ return 0;
+
+ const char *t = startswith(f->osc_sequence, "0;"); /* Set window title OSC sequence*/
+ if (!t)
+ return 0;
+
+ _cleanup_free_ char *joined = strjoin("\x1b]0;", f->title_prefix, t, "\a");
+ if (!joined)
+ return -ENOMEM;
+
+ return insert_string(f, offset, joined);
+}
+
static int pty_forward_ansi_process(PTYForward *f, size_t offset) {
int r;
assert(f);
assert(offset <= f->out_buffer_full);
- if (!f->background_color)
+ if (!f->background_color && !f->title_prefix)
return 0;
if (FLAGS_SET(f->flags, PTY_FORWARD_DUMB_TERMINAL))
if (c == '[') {
f->ansi_color_state = ANSI_COLOR_STATE_CSI_SEQUENCE;
continue;
+ } else if (c == ']') {
+ f->ansi_color_state = ANSI_COLOR_STATE_OSC_SEQUENCE;
+ continue;
}
break;
continue;
}
+ case ANSI_COLOR_STATE_OSC_SEQUENCE: {
+
+ if ((uint8_t) c >= ' ') {
+ if (strlen_ptr(f->osc_sequence) >= 64) {
+ /* Safety check: lets not accept unbounded OSC sequences */
+ f->osc_sequence = mfree(f->osc_sequence);
+ break;
+ } else if (!strextend(&f->osc_sequence, CHAR_TO_STR(c)))
+ return -ENOMEM;
+ } else {
+ /* Otherwise, the OSC sequence is over */
+
+ if (c == '\x07') {
+ r = insert_window_title_fix(f, i+1);
+ if (r < 0)
+ return r;
+
+ i += r;
+ }
+
+ f->osc_sequence = mfree(f->osc_sequence);
+ f->ansi_color_state = ANSI_COLOR_STATE_TEXT;
+ }
+
+ continue;
+ }
+
default:
assert_not_reached();
}
pty_forward_disconnect(f);
free(f->background_color);
free(f->title);
+ free(f->title_prefix);
return mfree(f);
}
return free_and_replace(f->title, title);
}
+
+int pty_forward_set_title_prefix(PTYForward *f, const char *title_prefix) {
+ assert(f);
+
+ return free_and_strdup(&f->title_prefix, title_prefix);
+}
int pty_forward_set_width_height(PTYForward *f, unsigned width, unsigned height);
int pty_forward_set_background_color(PTYForward *f, const char *color);
+
int pty_forward_set_title(PTYForward *f, const char *title);
int pty_forward_set_titlef(PTYForward *f, const char *format, ...) _printf_(2,3);
+int pty_forward_set_title_prefix(PTYForward *f, const char *prefix);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(PTYForward*, pty_forward_free);
#include "varlink-io.systemd.Network.h"
-static VARLINK_DEFINE_METHOD(GetStates,
- VARLINK_DEFINE_OUTPUT(AddressState, VARLINK_STRING, 0),
- VARLINK_DEFINE_OUTPUT(IPv4AddressState, VARLINK_STRING, 0),
- VARLINK_DEFINE_OUTPUT(IPv6AddressState, VARLINK_STRING, 0),
- VARLINK_DEFINE_OUTPUT(CarrierState, VARLINK_STRING, 0),
- VARLINK_DEFINE_OUTPUT(OnlineState, VARLINK_STRING, VARLINK_NULLABLE),
- VARLINK_DEFINE_OUTPUT(OperationalState, VARLINK_STRING, 0));
+static VARLINK_DEFINE_METHOD(
+ GetStates,
+ VARLINK_DEFINE_OUTPUT(AddressState, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(IPv4AddressState, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(IPv6AddressState, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(CarrierState, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(OnlineState, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(OperationalState, VARLINK_STRING, 0));
-static VARLINK_DEFINE_METHOD(GetNamespaceId,
- VARLINK_DEFINE_OUTPUT(NamespaceId, VARLINK_INT, 0),
- VARLINK_DEFINE_OUTPUT(NamespaceNSID, VARLINK_INT, VARLINK_NULLABLE));
+static VARLINK_DEFINE_METHOD(
+ GetNamespaceId,
+ VARLINK_DEFINE_OUTPUT(NamespaceId, VARLINK_INT, 0),
+ VARLINK_DEFINE_OUTPUT(NamespaceNSID, VARLINK_INT, VARLINK_NULLABLE));
VARLINK_DEFINE_INTERFACE(
io_systemd_Network,
return 0;
}
-static int get_unit_dbus_path_by_pid_fallback(
- sd_bus *bus,
- uint32_t pid,
- char **ret_path,
- char **ret_unit) {
-
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_free_ char *path = NULL, *unit = NULL;
- char *p;
- int r;
-
- assert(bus);
- assert(ret_path);
- assert(ret_unit);
-
- r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", pid);
- if (r < 0)
- return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
-
- r = sd_bus_message_read(reply, "o", &p);
- if (r < 0)
- return bus_log_parse_error(r);
-
- path = strdup(p);
- if (!path)
- return log_oom();
-
- r = unit_name_from_dbus_path(path, &unit);
- if (r < 0)
- return log_oom();
-
- *ret_unit = TAKE_PTR(unit);
- *ret_path = TAKE_PTR(path);
-
- return 0;
-}
-
-static int get_unit_dbus_path_by_pid(
- sd_bus *bus,
- uint32_t pid,
- char **ret_path,
- char **ret_unit) {
-
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_free_ char *path = NULL, *unit = NULL;
- _cleanup_close_ int pidfd = -EBADF;
- char *p, *u;
- int r;
-
- assert(bus);
- assert(ret_path);
- assert(ret_unit);
-
- /* First, try to send a PIDFD across the wire, so that we can pin the process and there's no race
- * condition possible while we wait for the D-Bus reply. If we either don't have PIDFD support in
- * the kernel or the new D-Bus method is not available, then fallback to the older method that
- * sends the numeric PID. */
-
- pidfd = pidfd_open(pid, 0);
- if (pidfd < 0 && ERRNO_IS_NOT_SUPPORTED(errno))
- return get_unit_dbus_path_by_pid_fallback(bus, pid, ret_path, ret_unit);
- if (pidfd < 0)
- return log_error_errno(errno, "Failed to open PID %"PRIu32": %m", pid);
-
- r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPIDFD", &error, &reply, "h", pidfd);
- if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
- return get_unit_dbus_path_by_pid_fallback(bus, pid, ret_path, ret_unit);
- if (r < 0)
- return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
-
- r = sd_bus_message_read(reply, "os", &p, &u);
- if (r < 0)
- return bus_log_parse_error(r);
-
- path = strdup(p);
- if (!path)
- return log_oom();
-
- unit = strdup(u);
- if (!unit)
- return log_oom();
-
- *ret_unit = TAKE_PTR(unit);
- *ret_path = TAKE_PTR(path);
-
- return 0;
-}
-
static int show_all(
sd_bus *bus,
SystemctlShowMode show_mode,
} else {
/* Interpret as PID */
- r = get_unit_dbus_path_by_pid(bus, id, &path, &unit);
+ r = lookup_unit_by_pidref(bus, (pid_t) id, &unit, &path);
if (r < 0) {
- ret = r;
+ RET_GATHER(ret, r);
continue;
}
}
#include "glob-util.h"
#include "macro.h"
#include "path-util.h"
+#include "pidref.h"
+#include "process-util.h"
#include "reboot-util.h"
#include "set.h"
#include "spawn-ask-password-agent.h"
if (r < 0)
return log_error_errno(r, "Failed to append unit dependencies: %m");
- strv_free(*list);
- *list = TAKE_PTR(list_with_deps);
- return 0;
+ return strv_free_and_replace(*list, list_with_deps);
}
int unit_get_dependencies(sd_bus *bus, const char *name, char ***ret) {
assert_not_reached();
}
}
+
+int get_unit_by_pid(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ int r;
+
+ assert(bus);
+ assert(pid >= 0); /* 0 is accepted by GetUnitByPID for querying our own process. */
+
+ r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", (uint32_t) pid);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, BUS_ERROR_NO_UNIT_FOR_PID))
+ return log_error_errno(r, "%s", bus_error_message(&error, r));
+
+ return log_error_errno(r,
+ "Failed to get unit that PID " PID_FMT " belongs to: %s",
+ pid > 0 ? pid : getpid_cached(),
+ bus_error_message(&error, r));
+ }
+
+ _cleanup_free_ char *u = NULL, *p = NULL;
+ const char *path;
+
+ r = sd_bus_message_read_basic(reply, 'o', &path);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (ret_unit) {
+ r = unit_name_from_dbus_path(path, &u);
+ if (r < 0)
+ return log_error_errno(r,
+ "Failed to extract unit name from D-Bus object path '%s': %m",
+ path);
+ }
+
+ if (ret_path) {
+ p = strdup(path);
+ if (!p)
+ return log_oom();
+ }
+
+ if (ret_unit)
+ *ret_unit = TAKE_PTR(u);
+ if (ret_path)
+ *ret_path = TAKE_PTR(p);
+
+ return 0;
+}
+
+static int get_unit_by_pidfd(sd_bus *bus, const PidRef *pid, char **ret_unit, char **ret_path) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ int r;
+
+ assert(bus);
+ assert(pidref_is_set(pid));
+
+ if (pid->fd < 0)
+ return -EOPNOTSUPP;
+
+ r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPIDFD", &error, &reply, "h", pid->fd);
+ if (r < 0) {
+ if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
+ return -EOPNOTSUPP;
+
+ if (sd_bus_error_has_names(&error, BUS_ERROR_NO_UNIT_FOR_PID, BUS_ERROR_NO_SUCH_PROCESS))
+ return log_error_errno(r, "%s", bus_error_message(&error, r));
+
+ return log_error_errno(r,
+ "Failed to get unit that PID " PID_FMT " belongs to: %s",
+ pid->pid, bus_error_message(&error, r));
+ }
+
+ _cleanup_free_ char *u = NULL, *p = NULL;
+ const char *path, *unit;
+
+ r = sd_bus_message_read(reply, "os", &path, &unit);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (ret_unit) {
+ u = strdup(unit);
+ if (!u)
+ return log_oom();
+ }
+
+ if (ret_path) {
+ p = strdup(path);
+ if (!p)
+ return log_oom();
+ }
+
+ if (ret_unit)
+ *ret_unit = TAKE_PTR(u);
+ if (ret_path)
+ *ret_path = TAKE_PTR(p);
+
+ return 0;
+}
+
+int lookup_unit_by_pidref(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path) {
+ int r;
+
+ assert(bus);
+ assert(pid >= 0); /* 0 means our own process */
+
+ if (arg_transport != BUS_TRANSPORT_LOCAL)
+ return get_unit_by_pid(bus, pid, ret_unit, ret_path);
+
+ static bool use_pidfd = true;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+
+ r = pidref_set_pid(&pidref, pid);
+ if (r < 0)
+ return log_error_errno(r,
+ r == -ESRCH ?
+ "PID " PID_FMT " doesn't exist or is already gone." :
+ "Failed to create reference to PID " PID_FMT ": %m",
+ pid);
+
+ if (use_pidfd) {
+ r = get_unit_by_pidfd(bus, &pidref, ret_unit, ret_path);
+ if (r != -EOPNOTSUPP)
+ return r;
+
+ use_pidfd = false;
+ log_debug_errno(r, "Unable to look up process using pidfd, falling back to pid.");
+ }
+
+ _cleanup_free_ char *u = NULL, *p = NULL;
+
+ r = get_unit_by_pid(bus, pidref.pid, ret_unit ? &u : NULL, ret_path ? &p : NULL);
+ if (r < 0)
+ return r;
+
+ r = pidref_verify(&pidref);
+ if (r < 0)
+ return log_error_errno(r, "Failed to verify our reference to PID " PID_FMT ": %m", pidref.pid);
+
+ if (ret_unit)
+ *ret_unit = TAKE_PTR(u);
+ if (ret_path)
+ *ret_path = TAKE_PTR(p);
+
+ return 0;
+}
UnitFileFlags unit_file_flags_from_args(void);
int halt_now(enum action a);
+
+int get_unit_by_pid(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path);
+int lookup_unit_by_pidref(sd_bus *bus, pid_t pid, char **ret_unit, char **ret_path);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include "bus-common-errors.h"
-#include "bus-error.h"
-#include "bus-locator.h"
#include "format-util.h"
#include "parse-util.h"
-#include "pidref.h"
-#include "process-util.h"
#include "systemctl.h"
#include "systemctl-util.h"
#include "systemctl-whoami.h"
-static int get_unit_by_pid(sd_bus *bus, pid_t pid, char **ret) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_free_ char *unit = NULL;
- const char *path;
- int r;
-
- assert(bus);
- assert(pid >= 0); /* 0 is accepted by GetUnitByPID for querying our own process. */
- assert(ret);
-
- r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", (uint32_t) pid);
- if (r < 0) {
- if (sd_bus_error_has_name(&error, BUS_ERROR_NO_UNIT_FOR_PID))
- return log_error_errno(r, "%s", bus_error_message(&error, r));
-
- return log_error_errno(r,
- "Failed to get unit that PID " PID_FMT " belongs to: %s",
- pid > 0 ? pid : getpid_cached(),
- bus_error_message(&error, r));
- }
-
- r = sd_bus_message_read_basic(reply, 'o', &path);
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = unit_name_from_dbus_path(path, &unit);
- if (r < 0)
- return log_error_errno(r, "Failed to extract unit name from D-Bus object path '%s': %m", path);
-
- *ret = TAKE_PTR(unit);
- return 0;
-}
-
-static int lookup_pidfd(sd_bus *bus, const PidRef *pid, char **ret) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- const char *unit;
- int r;
-
- assert(bus);
- assert(pidref_is_set(pid));
- assert(ret);
-
- if (pid->fd < 0)
- return -EOPNOTSUPP;
-
- r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPIDFD", &error, &reply, "h", pid->fd);
- if (r < 0) {
- if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
- return -EOPNOTSUPP;
-
- if (sd_bus_error_has_names(&error, BUS_ERROR_NO_UNIT_FOR_PID, BUS_ERROR_NO_SUCH_PROCESS))
- return log_error_errno(r, "%s", bus_error_message(&error, r));
-
- return log_error_errno(r,
- "Failed to get unit that PID " PID_FMT " belongs to: %s",
- pid->pid, bus_error_message(&error, r));
- }
-
- r = sd_bus_message_read(reply, "os", NULL, &unit);
- if (r < 0)
- return bus_log_parse_error(r);
-
- char *u = strdup(unit);
- if (!u)
- return log_oom();
-
- *ret = TAKE_PTR(u);
-
- return 0;
-}
-
-static int lookup_pid(sd_bus *bus, const char *pidstr) {
- _cleanup_free_ char *unit = NULL;
- int r;
-
- assert(bus);
- assert(pidstr);
-
- if (arg_transport == BUS_TRANSPORT_LOCAL) {
- static bool use_pidfd = true;
- _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
-
- r = pidref_set_pidstr(&pid, pidstr);
- if (r < 0)
- return log_error_errno(r,
- r == -ESRCH ?
- "PID %s doesn't exist or is already gone." :
- "Failed to create reference to PID %s: %m",
- pidstr);
-
- if (use_pidfd) {
- r = lookup_pidfd(bus, &pid, &unit);
- if (r == -EOPNOTSUPP) {
- use_pidfd = false;
- log_debug_errno(r, "Unable to look up process using pidfd, ignoring.");
- } else if (r < 0)
- return r;
- }
-
- if (!use_pidfd) {
- assert(!unit);
-
- r = get_unit_by_pid(bus, pid.pid, &unit);
- if (r < 0)
- return r;
-
- r = pidref_verify(&pid);
- if (r < 0)
- return log_error_errno(r,
- "Failed to verify our reference to PID " PID_FMT ": %m",
- pid.pid);
- }
- } else {
- pid_t pid;
-
- r = parse_pid(pidstr, &pid);
- if (r < 0)
- return log_error_errno(r, "Failed to parse PID %s: %m", pidstr);
-
- r = get_unit_by_pid(bus, pid, &unit);
- if (r < 0)
- return r;
- }
-
- puts(unit);
- return 0;
-}
-
int verb_whoami(int argc, char *argv[], void *userdata) {
sd_bus *bus;
- int r;
+ int r, ret = 0;
r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
_cleanup_free_ char *unit = NULL;
if (arg_transport != BUS_TRANSPORT_LOCAL)
- return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Refusing to look up our local PID on remote host.");
+ return log_error_errno(SYNTHETIC_ERRNO(EREMOTE),
+ "Refusing to look up our local PID on remote host.");
- /* Our own process can never go away while querying, hence no need to open pidfd. */
+ /* Our own process can never go away while querying, hence no need to go through pidfd. */
- r = get_unit_by_pid(bus, 0, &unit);
+ r = get_unit_by_pid(bus, 0, &unit, /* ret_path = */ NULL);
if (r < 0)
return r;
return 0;
}
- r = 0;
+ STRV_FOREACH(pidstr, strv_skip(argv, 1)) {
+ _cleanup_free_ char *unit = NULL;
+ pid_t pid;
+
+ r = parse_pid(*pidstr, &pid);
+ if (r < 0)
+ return log_error_errno(r, "Invalid PID specified: %s", *pidstr);
- STRV_FOREACH(pid, strv_skip(argv, 1))
- RET_GATHER(r, lookup_pid(bus, *pid));
+ r = lookup_unit_by_pidref(bus, pid, &unit, /* ret_path = */ NULL);
+ if (r < 0)
+ RET_GATHER(ret, r);
+ else
+ puts(unit);
+ }
- return r;
+ return ret;
}
#define foosddhcpclientidhfoo
/***
- Copyright © 2013 Intel Corporation. All rights reserved.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
#define foosddhcpduidhfoo
/***
- Copyright © 2013 Intel Corporation. All rights reserved.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
#define foosddhcpoptionhfoo
/***
- Copyright © 2013 Intel Corporation. All rights reserved.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
#define foosddhcpserverleasehfoo
/***
- Copyright © 2013 Intel Corporation. All rights reserved.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
#define foosdndiscprotocolfoo
/***
- Copyright © 2014 Intel Corporation. All rights reserved.
-
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
#define foosdndiscrouterfoo
/***
- Copyright © 2014 Intel Corporation. All rights reserved.
-
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
_SD_ENUM_FORCE_S64(NDISC_EVENT)
} sd_ndisc_event_t;
-typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata);
+typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata);
int sd_ndisc_new(sd_ndisc **ret);
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
#include "alloc-util.h"
#include "blockdev-util.h"
+#include "build-path.h"
#include "chase.h"
#include "device-util.h"
#include "devnum-util.h"
/* Child */
const char *cmdline[] = {
- "systemd-pull",
+ SYSTEMD_PULL_PATH,
"raw",
"--direct", /* just download the specified URL, don't download anything else */
"--verify", verify_signature ? "signature" : "no", /* verify the manifest file */
NULL
};
- execv(pull_binary_path(), (char *const*) cmdline);
- log_error_errno(errno, "Failed to execute %s tool: %m", pull_binary_path());
+ r = invoke_callout_binary(SYSTEMD_PULL_PATH, (char *const*) cmdline);
+ log_error_errno(r, "Failed to execute %s tool: %m", SYSTEMD_PULL_PATH);
_exit(EXIT_FAILURE);
};
#include "alloc-util.h"
#include "blockdev-util.h"
+#include "build-path.h"
#include "chase.h"
#include "conf-parser.h"
#include "dirent-util.h"
memcpy(ret->sha256sum, i->metadata.sha256sum, sizeof(ret->sha256sum));
}
-static int run_helper(
+static int run_callout(
const char *name,
- const char *path,
- const char * const cmdline[]) {
+ char *cmdline[]) {
int r;
assert(name);
- assert(path);
assert(cmdline);
+ assert(cmdline[0]);
r = safe_fork(name, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_WAIT, NULL);
if (r < 0)
return r;
if (r == 0) {
/* Child */
-
- execv(path, (char *const*) cmdline);
- log_error_errno(errno, "Failed to execute %s tool: %m", path);
+ r = invoke_callout_binary(cmdline[0], (char *const*) cmdline);
+ log_error_errno(r, "Failed to execute %s tool: %m", cmdline[0]);
_exit(EXIT_FAILURE);
}
* importer has some tricks up its sleeve, such as sparse file generation, which we
* want to take benefit of, too.) */
- r = run_helper("(sd-import-raw)",
- import_binary_path(),
- (const char* const[]) {
- "systemd-import",
+ r = run_callout("(sd-import-raw)",
+ STRV_MAKE(
+ SYSTEMD_IMPORT_PATH,
"raw",
"--direct", /* just copy/unpack the specified file, don't do anything else */
arg_sync ? "--sync=yes" : "--sync=no",
i->path,
- t->temporary_path,
- NULL
- });
+ t->temporary_path));
break;
case RESOURCE_PARTITION:
/* regular file → partition */
- r = run_helper("(sd-import-raw)",
- import_binary_path(),
- (const char* const[]) {
- "systemd-import",
+ r = run_callout("(sd-import-raw)",
+ STRV_MAKE(
+ SYSTEMD_IMPORT_PATH,
"raw",
"--direct", /* just copy/unpack the specified file, don't do anything else */
"--offset", offset,
"--size-max", max_size,
arg_sync ? "--sync=yes" : "--sync=no",
i->path,
- t->target.path,
- NULL
- });
+ t->target.path));
break;
default:
/* directory/subvolume → directory/subvolume */
- r = run_helper("(sd-import-fs)",
- import_fs_binary_path(),
- (const char* const[]) {
- "systemd-import-fs",
+ r = run_callout("(sd-import-fs)",
+ STRV_MAKE(
+ SYSTEMD_IMPORT_FS_PATH,
"run",
"--direct", /* just untar the specified file, don't do anything else */
arg_sync ? "--sync=yes" : "--sync=no",
t->target.type == RESOURCE_SUBVOLUME ? "--btrfs-subvol=yes" : "--btrfs-subvol=no",
i->path,
- t->temporary_path,
- NULL
- });
+ t->temporary_path));
break;
case RESOURCE_TAR:
/* tar → directory/subvolume */
- r = run_helper("(sd-import-tar)",
- import_binary_path(),
- (const char* const[]) {
- "systemd-import",
+ r = run_callout("(sd-import-tar)",
+ STRV_MAKE(
+ SYSTEMD_IMPORT_PATH,
"tar",
"--direct", /* just untar the specified file, don't do anything else */
arg_sync ? "--sync=yes" : "--sync=no",
t->target.type == RESOURCE_SUBVOLUME ? "--btrfs-subvol=yes" : "--btrfs-subvol=no",
i->path,
- t->temporary_path,
- NULL
- });
+ t->temporary_path));
break;
case RESOURCE_URL_FILE:
/* url file → regular file */
- r = run_helper("(sd-pull-raw)",
- pull_binary_path(),
- (const char* const[]) {
- "systemd-pull",
+ r = run_callout("(sd-pull-raw)",
+ STRV_MAKE(
+ SYSTEMD_PULL_PATH,
"raw",
"--direct", /* just download the specified URL, don't download anything else */
"--verify", digest, /* validate by explicit SHA256 sum */
arg_sync ? "--sync=yes" : "--sync=no",
i->path,
- t->temporary_path,
- NULL
- });
+ t->temporary_path));
break;
case RESOURCE_PARTITION:
/* url file → partition */
- r = run_helper("(sd-pull-raw)",
- pull_binary_path(),
- (const char* const[]) {
- "systemd-pull",
+ r = run_callout("(sd-pull-raw)",
+ STRV_MAKE(
+ SYSTEMD_PULL_PATH,
"raw",
"--direct", /* just download the specified URL, don't download anything else */
"--verify", digest, /* validate by explicit SHA256 sum */
"--size-max", max_size,
arg_sync ? "--sync=yes" : "--sync=no",
i->path,
- t->target.path,
- NULL
- });
+ t->target.path));
break;
default:
case RESOURCE_URL_TAR:
assert(IN_SET(t->target.type, RESOURCE_DIRECTORY, RESOURCE_SUBVOLUME));
- r = run_helper("(sd-pull-tar)",
- pull_binary_path(),
- (const char*const[]) {
- "systemd-pull",
+ r = run_callout("(sd-pull-tar)",
+ STRV_MAKE(
+ SYSTEMD_PULL_PATH,
"tar",
"--direct", /* just download the specified URL, don't download anything else */
"--verify", digest, /* validate by explicit SHA256 sum */
t->target.type == RESOURCE_SUBVOLUME ? "--btrfs-subvol=yes" : "--btrfs-subvol=no",
arg_sync ? "--sync=yes" : "--sync=no",
i->path,
- t->temporary_path,
- NULL
- });
+ t->temporary_path));
break;
default:
extern bool arg_sync;
extern uint64_t arg_instances_max;
extern char *arg_root;
-
-static inline const char* import_binary_path(void) {
- return secure_getenv("SYSTEMD_IMPORT_PATH") ?: SYSTEMD_IMPORT_PATH;
-}
-
-static inline const char* import_fs_binary_path(void) {
- return secure_getenv("SYSTEMD_IMPORT_FS_PATH") ?: SYSTEMD_IMPORT_FS_PATH;
-}
-
-static inline const char *pull_binary_path(void) {
- return secure_getenv("SYSTEMD_PULL_PATH") ?: SYSTEMD_PULL_PATH;
-}
'test-bitmap.c',
'test-blockdev-util.c',
'test-bootspec.c',
+ 'test-build-path.c',
'test-bus-util.c',
'test-calendarspec.c',
'test-cgroup-setup.c',
/* child */
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
assert_se(make_reaper_process(true) >= 0);
assert_se(mkdtemp_malloc(NULL, &tt) >= 0);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "build-path.h"
+#include "log.h"
+#include "string-util.h"
+
+int main(int argc, char* argv[]) {
+ _cleanup_free_ char *p = NULL;
+ int r;
+
+ r = get_build_exec_dir(&p);
+ if (r == -ENOEXEC)
+ log_info("Not run from build dir.");
+ else if (r < 0)
+ log_error_errno(r, "Failed to find build dir: %m");
+ else
+ log_info("%s", strna(p));
+
+ return 0;
+}
assert_se(exec);
assert_se(ret);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
assert_se(pipe2(outpipe, O_NONBLOCK|O_CLOEXEC) == 0);
assert_se(pipe2(errpipe, O_NONBLOCK|O_CLOEXEC) == 0);
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", special_glyph(x))
TEST(dump_special_glyphs) {
- assert_cc(SPECIAL_GLYPH_BLUE_CIRCLE + 1 == _SPECIAL_GLYPH_MAX);
+ assert_cc(SPECIAL_GLYPH_GREEN_CIRCLE + 1 == _SPECIAL_GLYPH_MAX);
log_info("is_locale_utf8: %s", yes_no(is_locale_utf8()));
dump_glyph(SPECIAL_GLYPH_RED_CIRCLE);
dump_glyph(SPECIAL_GLYPH_YELLOW_CIRCLE);
dump_glyph(SPECIAL_GLYPH_BLUE_CIRCLE);
+ dump_glyph(SPECIAL_GLYPH_GREEN_CIRCLE);
}
DEFINE_TEST_MAIN(LOG_INFO);
_exit(EXIT_SUCCESS);
}
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
assert_se(sd_event_add_child(e, &cs, pid, WEXITED, real_pressure_child_callback, NULL) >= 0);
assert_se(sd_event_source_set_child_process_own(cs, true) >= 0);
return log_error_errno(r, "Failed to drop privileges: %m");
}
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGRTMIN+18, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
r = manager_new(&m);
if (r < 0)
};
int r;
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
r = sd_event_default(&event);
if (r < 0)
(void) mkdir_p_label("/run/systemd/ask-password", 0755);
assert_se(sigemptyset(&mask) >= 0);
- assert_se(sigset_add_many(&mask, SIGTERM, -1) >= 0);
+ assert_se(sigset_add_many(&mask, SIGTERM) >= 0);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) >= 0);
if (watch) {
assert_se(sigaction(SIGCHLD, &sigchld, NULL) >= 0);
assert_se(sigaction(SIGHUP, &sighup, NULL) >= 0);
- assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD) >= 0);
r = safe_fork("(sd-passwd)", FORK_RESET_SIGNALS|FORK_LOG, ret_pid);
if (r < 0)
assert_se(event = udev_event_new(dev, NULL));
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD) >= 0);
/* do what devtmpfs usually provides us */
if (sd_device_get_devname(dev, &devname) >= 0) {
test_setup_logging(LOG_DEBUG);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
test_event_spawn_cat(true, SIZE_MAX);
test_event_spawn_cat(false, SIZE_MAX);
udev_watch_restore(manager->inotify_fd);
/* block SIGCHLD for listening child events. */
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = sd_event_default(&manager->event);
if (r < 0)
goto finalize;
}
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
(void) sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
import pefile # type: ignore
-__version__ = '{{PROJECT_VERSION_FULL}} ({{GIT_VERSION}})'
+__version__ = '{{PROJECT_VERSION_FULL}} ({{VERSION_TAG}})'
EFI_ARCH_MAP = {
# host_arch glob : [efi_arch, 32_bit_efi_arch if mixed mode is supported]
#include "sd-daemon.h"
+#include "build-path.h"
#include "common-signal.h"
#include "env-util.h"
#include "fd-util.h"
_exit(EXIT_FAILURE);
}
- /* execl("/home/lennart/projects/systemd/build/systemd-userwork", "systemd-userwork", "xxxxxxxxxxxxxxxx", NULL); /\* With some extra space rename_process() can make use of *\/ */
- /* execl("/usr/bin/valgrind", "valgrind", "/home/lennart/projects/systemd/build/systemd-userwork", "systemd-userwork", "xxxxxxxxxxxxxxxx", NULL); /\* With some extra space rename_process() can make use of *\/ */
-
- execl(SYSTEMD_USERWORK_PATH, "systemd-userwork", "xxxxxxxxxxxxxxxx", NULL); /* With some extra space rename_process() can make use of */
- log_error_errno(errno, "Failed start worker process: %m");
+ r = invoke_callout_binary(SYSTEMD_USERWORK_PATH, STRV_MAKE(SYSTEMD_USERWORK_PATH, "xxxxxxxxxxxxxxxx")); /* With some extra space rename_process() can make use of */
+ log_error_errno(r, "Failed start worker process: %m");
_exit(EXIT_FAILURE);
}
if (setenv("SYSTEMD_BYPASS_USERDB", "io.systemd.NameServiceSwitch:io.systemd.Multiplexer:io.systemd.DropIn", 1) < 0)
return log_error_errno(errno, "Failed to set $SYSTEMD_BYPASS_USERDB: %m");
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
r = manager_new(&m);
if (r < 0)
* - where a simplified machine-parsable form is more useful, for example
* pkgconfig files and version information written to binary files.
*/
-#define GIT_VERSION "@VCS_TAG@"
+#define GIT_VERSION VERSION_TAG "@VCS_TAG@"
}
void socket_service_pair_done(SocketServicePair *p) {
+ assert(p);
+
+ p->exec_start_pre = strv_free(p->exec_start_pre);
p->exec_start = strv_free(p->exec_start);
p->exec_stop_post = strv_free(p->exec_stop_post);
p->unit_name_prefix = mfree(p->unit_name_prefix);
return bus_log_create_error(r);
}
+ if (p->exec_start_pre) {
+ r = message_add_commands(m, "ExecStartPre", &p->exec_start_pre, 1);
+ if (r < 0)
+ return r;
+ }
+
r = message_add_commands(m, "ExecStart", &p->exec_start, 1);
if (r < 0)
return r;
#include "macro.h"
typedef struct SocketServicePair {
+ char **exec_start_pre;
char **exec_start;
char **exec_stop_post;
char *unit_name_prefix;
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include "string-table.h"
#include "vmspawn-settings.h"
+
+static const char *const console_mode_table[_CONSOLE_MODE_MAX] = {
+ [CONSOLE_INTERACTIVE] = "interactive",
+ [CONSOLE_READ_ONLY] = "read-only",
+ [CONSOLE_NATIVE] = "native",
+ [CONSOLE_GUI] = "gui",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(console_mode, ConsoleMode);
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <errno.h>
#include <stdint.h>
+#include "macro.h"
+
+typedef enum ConsoleMode {
+ CONSOLE_INTERACTIVE, /* ptyfwd */
+ CONSOLE_READ_ONLY, /* ptyfwd, but in read-only mode */
+ CONSOLE_NATIVE, /* qemu's native TTY handling */
+ CONSOLE_GUI, /* qemu's graphical UI */
+ _CONSOLE_MODE_MAX,
+ _CONSOLE_MODE_INVALID = -EINVAL,
+} ConsoleMode;
+
typedef enum SettingsMask {
SETTING_START_MODE = UINT64_C(1) << 0,
SETTING_BIND_MOUNTS = UINT64_C(1) << 11,
SETTING_CREDENTIALS = UINT64_C(1) << 30,
_SETTING_FORCE_ENUM_WIDTH = UINT64_MAX
} SettingsMask;
+
+const char *console_mode_to_string(ConsoleMode m) _const_;
+ConsoleMode console_mode_from_string(const char *s) _pure_;
#include "path-util.h"
#include "pretty-print.h"
#include "process-util.h"
+#include "ptyfwd.h"
#include "random-util.h"
#include "rm-rf.h"
#include "signal-util.h"
static int arg_tpm = -1;
static char *arg_linux = NULL;
static char **arg_initrds = NULL;
-static bool arg_qemu_gui = false;
+static ConsoleMode arg_console_mode = CONSOLE_INTERACTIVE;
static NetworkStack arg_network_stack = NETWORK_STACK_NONE;
static int arg_secure_boot = -1;
static MachineCredentialContext arg_credentials = {};
static bool arg_privileged = false;
static char **arg_kernel_cmdline_extra = NULL;
static char **arg_extra_drives = NULL;
+static char *arg_background = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
STATIC_DESTRUCTOR_REGISTER(arg_forward_journal, freep);
STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline_extra, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_extra_drives, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
" --tpm=BOOL Enable use of a virtual TPM\n"
" --linux=PATH Specify the linux kernel for direct kernel boot\n"
" --initrd=PATH Specify the initrd for direct kernel boot\n"
- " --qemu-gui Start QEMU in graphical mode\n"
" -n --network-tap Create a TAP device for networking\n"
" --network-user-mode Use user mode networking\n"
" --secure-boot=BOOL Enable searching for firmware supporting SecureBoot\n"
"\n%3$sIntegration:%4$s\n"
" --forward-journal=FILE|DIR\n"
" Forward the VM's journal to the host\n"
+ "\n%3$sInput/Output:%4$s\n"
+ " --console=MODE Console mode (interactive, native, gui)\n"
+ " --background=COLOR Set ANSI color for background\n"
"\n%3$sCredentials:%4$s\n"
" --set-credential=ID:VALUE\n"
" Pass a credential with literal value to the VM\n"
ARG_SET_CREDENTIAL,
ARG_LOAD_CREDENTIAL,
ARG_FIRMWARE,
+ ARG_CONSOLE,
+ ARG_BACKGROUND,
};
static const struct option options[] = {
{ "tpm", required_argument, NULL, ARG_TPM },
{ "linux", required_argument, NULL, ARG_LINUX },
{ "initrd", required_argument, NULL, ARG_INITRD },
- { "qemu-gui", no_argument, NULL, ARG_QEMU_GUI },
+ { "console", required_argument, NULL, ARG_CONSOLE },
+ { "qemu-gui", no_argument, NULL, ARG_QEMU_GUI }, /* compat option */
{ "network-tap", no_argument, NULL, 'n' },
{ "network-user-mode", no_argument, NULL, ARG_NETWORK_USER_MODE },
{ "bind", required_argument, NULL, ARG_BIND },
{ "set-credential", required_argument, NULL, ARG_SET_CREDENTIAL },
{ "load-credential", required_argument, NULL, ARG_LOAD_CREDENTIAL },
{ "firmware", required_argument, NULL, ARG_FIRMWARE },
+ { "background", required_argument, NULL, ARG_BACKGROUND },
{}
};
break;
}
+ case ARG_CONSOLE:
+ arg_console_mode = console_mode_from_string(optarg);
+ if (arg_console_mode < 0)
+ return log_error_errno(arg_console_mode, "Failed to parse specified console mode: %s", optarg);
+
+ break;
+
case ARG_QEMU_GUI:
- arg_qemu_gui = true;
+ arg_console_mode = CONSOLE_GUI;
break;
case 'n':
break;
+ case ARG_BACKGROUND:
+ r = free_and_strdup_warn(&arg_background, optarg);
+ if (r < 0)
+ return r;
+ break;
+
case '?':
return -EINVAL;
return 0;
}
-static int start_tpm(sd_bus *bus, const char *scope, const char *tpm, const char **ret_state_tempdir) {
+static int start_tpm(
+ sd_bus *bus,
+ const char *scope,
+ const char *swtpm,
+ char **ret_state_tempdir) {
+
_cleanup_(rm_rf_physical_and_freep) char *state_dir = NULL;
_cleanup_free_ char *scope_prefix = NULL;
_cleanup_(socket_service_pair_done) SocketServicePair ssp = {
assert(bus);
assert(scope);
- assert(tpm);
+ assert(swtpm);
assert(ret_state_tempdir);
r = unit_name_to_prefix(scope, &scope_prefix);
if (!ssp.listen_address)
return log_oom();
- ssp.exec_start = strv_new(tpm, "socket", "--tpm2", "--tpmstate");
+ _cleanup_free_ char *swtpm_setup = NULL;
+ r = find_executable("swtpm_setup", &swtpm_setup);
+ if (r < 0)
+ return log_error_errno(r, "Failed to find swtpm_setup binary: %m");
+
+ ssp.exec_start_pre = strv_new(swtpm_setup, "--tpm-state", state_dir, "--tpm2", "--pcr-banks", "sha256");
+ if (!ssp.exec_start_pre)
+ return log_oom();
+
+ ssp.exec_start = strv_new(swtpm, "socket", "--tpm2", "--tpmstate");
if (!ssp.exec_start)
return log_oom();
return r;
*ret_state_tempdir = TAKE_PTR(state_dir);
-
return 0;
}
return 0;
}
+static void set_window_title(PTYForward *f) {
+ _cleanup_free_ char *hn = NULL, *dot = NULL;
+
+ assert(f);
+
+ (void) gethostname_strict(&hn);
+
+ if (emoji_enabled())
+ dot = strjoin(special_glyph(SPECIAL_GLYPH_GREEN_CIRCLE), " ");
+
+ if (hn)
+ (void) pty_forward_set_titlef(f, "%sVirtual Machine %s on %s", strempty(dot), arg_machine, hn);
+ else
+ (void) pty_forward_set_titlef(f, "%sVirtual Machine %s", strempty(dot), arg_machine);
+
+ if (dot)
+ (void) pty_forward_set_title_prefix(f, dot);
+}
+
static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
_cleanup_(ovmf_config_freep) OvmfConfig *ovmf_config = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
if (r < 0)
return log_oom();
- if (arg_qemu_gui)
+ _cleanup_close_ int master = -EBADF;
+ PTYForwardFlags ptyfwd_flags = 0;
+ switch (arg_console_mode) {
+
+ case CONSOLE_READ_ONLY:
+ ptyfwd_flags |= PTY_FORWARD_READ_ONLY;
+
+ _fallthrough_;
+
+ case CONSOLE_INTERACTIVE: {
+ _cleanup_free_ char *pty_path = NULL;
+
+ master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
+ if (master < 0)
+ return log_error_errno(errno, "Failed to acquire pseudo tty: %m");
+
+ r = ptsname_malloc(master, &pty_path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine tty name: %m");
+
+ if (unlockpt(master) < 0)
+ return log_error_errno(errno, "Failed to unlock tty: %m");
+
+ if (strv_extend_many(
+ &cmdline,
+ "-nographic",
+ "-nodefaults",
+ "-chardev") < 0)
+ return log_oom();
+
+ if (strv_extendf(&cmdline,
+ "serial,id=console,path=%s", pty_path) < 0)
+ return log_oom();
+
+ r = strv_extend_many(
+ &cmdline,
+ "-serial", "chardev:console");
+ break;
+ }
+
+ case CONSOLE_GUI:
r = strv_extend_many(
&cmdline,
"-vga",
"virtio");
- else
+ break;
+
+ case CONSOLE_NATIVE:
r = strv_extend_many(
&cmdline,
"-nographic",
"-chardev", "stdio,mux=on,id=console,signal=off",
"-serial", "chardev:console",
"-mon", "console");
+ break;
+
+ default:
+ assert_not_reached();
+ }
if (r < 0)
return log_oom();
}
}
- _cleanup_free_ const char *tpm_state_tempdir = NULL;
+ _cleanup_free_ char *tpm_state_tempdir = NULL;
if (swtpm) {
_cleanup_free_ char *escaped_state_dir = NULL;
log_debug("Executing: %s", joined);
}
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, /* old_sigset=*/ NULL, SIGCHLD, SIGWINCH) >= 0);
_cleanup_(sd_event_source_unrefp) sd_event_source *notify_event_source = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
/* Exit when the child exits */
(void) event_add_child_pidref(event, NULL, &child_pidref, WEXITED, on_child_exit, NULL);
+ _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
+ if (master >= 0) {
+ r = pty_forward_new(event, master, ptyfwd_flags, &forward);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create PTY forwarder: %m");
+
+ if (!arg_background) {
+ _cleanup_free_ char *bg = NULL;
+
+ r = terminal_tint_color(130 /* green */, &bg);
+ if (r < 0)
+ log_debug_errno(r, "Failed to determine terminal background color, not tinting.");
+ else
+ (void) pty_forward_set_background_color(forward, bg);
+ } else if (!isempty(arg_background))
+ (void) pty_forward_set_background_color(forward, arg_background);
+
+ set_window_title(forward);
+ }
+
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r < 0)
return r;
- if (!arg_quiet) {
+ if (!arg_quiet && arg_console_mode != CONSOLE_GUI) {
_cleanup_free_ char *u = NULL;
const char *vm_path = arg_image ?: arg_directory;
(void) terminal_urlify_path(vm_path, vm_path, &u);
- log_info("%s %sSpawning VM %s on %s.%s\n"
- "%s %sPress %sCtrl-a x%s to kill VM.%s",
- special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), arg_machine, u ?: vm_path, ansi_normal(),
- special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), ansi_highlight(), ansi_grey(), ansi_normal());
+ log_info("%s %sSpawning VM %s on %s.%s",
+ special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), arg_machine, u ?: vm_path, ansi_normal());
+
+ if (arg_console_mode == CONSOLE_INTERACTIVE)
+ log_info("%s %sPress %sCtrl-]%s three times within 1s to kill VM.%s",
+ special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), ansi_highlight(), ansi_grey(), ansi_normal());
+ else if (arg_console_mode == CONSOLE_NATIVE)
+ log_info("%s %sPress %sCtrl-a x%s to kill VM.%s",
+ special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), ansi_highlight(), ansi_grey(), ansi_normal());
}
r = sd_listen_fds_with_names(true, &names);
[Network]
Address=192.168.6.2/24
DHCPServer=yes
-IPForward=ipv4
+IPv4Forwarding=yes
IPv6AcceptRA=no
[DHCPServer]
[Network]
DHCP=yes
-IPForward=ipv4
+IPv4Forwarding=yes
IPv6AcceptRA=no
[Network]
Address=192.168.5.2/24
-IPForward=ipv4
+IPv4Forwarding=yes
IPv6AcceptRA=no
[Network]
Address=192.168.5.1/24
-IPForward=ipv4
+IPv4Forwarding=yes
DHCPServer=yes
IPv6AcceptRA=no
IPv6ProxyNDPAddress=2607:5300:203:5215:2::1
IPv6ProxyNDPAddress=2607:5300:203:5215:1::1
IPv6AcceptRA=no
-IPForward=yes
Address=66.70.129.136/32
Address=66.70.129.142/32
Address=66.70.129.143/32
Name=dummy98
[Network]
-IPForward=yes
+IPv4Forwarding=yes
+IPv6Forwarding=yes
IPv6DuplicateAddressDetection=3
IPv6HopLimit=5
IPv4ProxyARP=yes
[Network]
VLAN=vlan99
-IPForward=yes
ConfigureWithoutCarrier=yes
LLDP=yes
IPv6AcceptRA=false
[Network]
IPv6AcceptRA=no
-IPForward=yes
Bridge=bridge99
LinkLocalAddressing=no
EmitLLDP=nearest-bridge
start_networkd()
self.wait_online('veth99:routable', 'veth-peer:degraded')
+ # IPv6SendRA=yes implies IPv6Forwarding.
+ self.check_ipv6_sysctl_attr('veth-peer', 'forwarding', '1')
+
output = resolvectl('dns', 'veth99')
print(output)
self.assertRegex(output, 'fe80::')
export PAGER=
# Create a couple of user/group records to test io.systemd.DropIn
-# See docs/_groups/USER_RECORD.md and docs/_groups/GROUP_RECORD.md
+# See docs/USER_RECORD.md and docs/GROUP_RECORD.md
mkdir -p /run/userdb/
cat >"/run/userdb/dropingroup.group" <<\EOF
{
+++ /dev/null
-#!/usr/bin/env bash
-# SPDX-License-Identifier: LGPL-2.1-or-later
-
-set -u
-set -o pipefail
-
-dir="${1:-.}"
-version_tag="${2:-}"
-
-if [ -n "${version_tag}" ]; then
- # If -Dversion_tag= was used, just use that without further changes.
- echo "${version_tag}"
-else
- read -r project_version <"${dir}/meson.version"
-
- # Check that we have either .git/ (a normal clone) or a .git file (a work-tree)
- # and that we don't get confused if a tarball is extracted in a higher-level
- # git repository.
- #
- # If the working tree has no tags (CI builds), the first git-describe will fail
- # and we fall back to project_version-commitid instead.
-
- c=''
- if [ -e "${dir}/.git" ]; then
- c="$(git -C "$dir" describe --abbrev=7 --dirty=^ 2>/dev/null)"
- if [ -n "$c" ]; then
- # git describe uses the most recent tag. However, for development versions (e.g. v256~devel), the
- # most recent tag will be v255 as there is no tag for development versions. To deal with this, we
- # replace the tag with the project version instead.
- c="${project_version}-${c#*-}"
- else
- # This call might still fail with permission issues
- suffix="$(git -C "$dir" describe --always --abbrev=7 --dirty=^ 2>/dev/null)"
- [ -n "$suffix" ] && c="${project_version}-${suffix}"
- fi
- fi
- [ -z "$c" ] && c="${project_version}"
- # Replace any hyphens with carets which are allowed in versions by pacman whereas hyphens are not. Git
- # versions with carets will also sort higher than their non-git version counterpart both in pacman
- # versioning and in version format specification versioning.
- echo "$c" | sed 's/^v//; s/-/^/g'
-fi