1
0
mirror of https://github.com/systemd/systemd synced 2026-03-06 13:15:06 +01:00

Compare commits

..

No commits in common. "e4dde4e87d8dafda44f207a3f7c56fd679c11c7d" and "a2be8be2cf5b7e5f74edcd7bbd4640d01f39bae2" have entirely different histories.

92 changed files with 1080 additions and 5990 deletions

1
.gitattributes vendored
View File

@ -1,2 +1 @@
*.[ch] whitespace=tab-in-indent,trailing-space *.[ch] whitespace=tab-in-indent,trailing-space
test/dmidecode-dumps/*.bin binary

2
TODO
View File

@ -297,7 +297,7 @@ Features:
initrd had set. initrd had set.
* sd-event: add native support for P_ALL waitid() watching, then move PID 1 to * sd-event: add native support for P_ALL waitid() watching, then move PID 1 to
it for reaping assigned but unknown children. This needs to some special care it fo reaping assigned but unknown children. This needs to some special care
to operate somewhat sensibly in light of priorities: P_ALL will return to operate somewhat sensibly in light of priorities: P_ALL will return
arbitrary processes, regardless of the priority we want to watch them with, arbitrary processes, regardless of the priority we want to watch them with,
hence on each event loop iteration check all processes which we shall watch hence on each event loop iteration check all processes which we shall watch

View File

@ -515,7 +515,7 @@
<varlistentry> <varlistentry>
<term><option>--tasks-max=</option><replaceable>TASKS</replaceable></term> <term><option>--tasks-max=</option><replaceable>TASKS</replaceable></term>
<listitem><para>Takes a non-zero unsigned integer as argument. Configures the maximum number of tasks <listitem><para>Takes a non-zero unsigned integer as argument. Configures the maximum numer of tasks
(i.e. threads, where each process is at least one thread) the user may have at any given time. This (i.e. threads, where each process is at least one thread) the user may have at any given time. This
limit applies to all tasks forked off the user's sessions, even if they change user identity via limit applies to all tasks forked off the user's sessions, even if they change user identity via
<citerefentry project='man-pages'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry> <citerefentry project='man-pages'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry>

View File

@ -1,9 +1,6 @@
<?xml version='1.0'?> <!--*-nxml-*--> <?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!ENTITY % entities SYSTEM "custom-entities.ent" >
%entities;
]>
<!-- SPDX-License-Identifier: LGPL-2.1-or-later --> <!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="hostname"> <refentry id="hostname">
@ -29,65 +26,23 @@
<refsect1> <refsect1>
<title>Description</title> <title>Description</title>
<para>The <filename>/etc/hostname</filename> file configures the name of the local system. Unless <para>The <filename>/etc/hostname</filename> file configures the
overridden as described in the next section, name of the local system that is set during boot using the
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> will set this <citerefentry><refentrytitle>sethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
hostname during boot using the system call. It should contain a single newline-terminated
<citerefentry><refentrytitle>sethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry> system hostname string. Comments (lines starting with a `#') are ignored.
call.</para> The hostname may be a free-form string up to 64 characters in length;
however, it is recommended that it consists only of 7-bit ASCII lower-case
<para>The file should contain a single newline-terminated hostname string. Comments (lines starting with characters and no spaces or dots, and limits itself to the format allowed
a <literal>#</literal>) are ignored. The hostname should be composed of up to 64 7-bit ASCII lower-case for DNS domain name labels, even though this is not a strict
alphanumeric characters or hyphens forming a valid DNS domain name. It is recommended that this name requirement.</para>
contains only a single label, i.e. without any dots. Invalid characters will be filtered out in an
attempt to make the name valid, but obviously it is recommended to use a valid name and not rely on this
filtering.</para>
<para>You may use <para>You may use
<citerefentry><refentrytitle>hostnamectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to change <citerefentry><refentrytitle>hostnamectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
the value of this file during runtime from the command line. Use to change the value of this file during runtime from the command
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry> to line. Use
initialize it on mounted (but not booted) system images.</para> <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</refsect1> to initialize it on mounted (but not booted) system images.</para>
<refsect1>
<title>Hostname semantics</title>
<para><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> and the
associated tools will obtain the hostname in the following ways:</para>
<itemizedlist>
<listitem><para>If the kernel commandline parameter <varname>systemd.hostname=</varname> specifies a
valid hostname,
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> will use it
to set the hostname during early boot, see
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
</para></listitem>
<listitem><para>Otherwise, the "static" hostname specified by <filename>/etc/hostname</filename> as
described above will be used.</para></listitem>
<listitem><para>Otherwise, a transient hostname may be set during runtime, for example based on
information in a DHCP lease, see
<citerefentry><refentrytitle>systemd-hostnamed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
Both <ulink url="https://developer.gnome.org/NetworkManager/stable/">NetworkManager</ulink> and
<citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
allow this. Note that
<citerefentry><refentrytitle>systemd-hostnamed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
gives higher priority to the static hostname, so the transient hostname will only be used if the static
hostname is not configured.</para></listitem>
<listitem><para>Otherwise, a fallback hostname configured at compilation time will be used
(<literal>&FALLBACK_HOSTNAME;</literal>).</para></listitem>
<!-- what about the "linux" fallback fallback? -->
</itemizedlist>
<para>Effectively, the static hostname has higher priority than a transient hostname, which has higher
priority than the fallback hostname. Transient hostnames are equivalent, so setting a new transient
hostname causes the previous transient hostname to be forgotten. The hostname specified on the kernel
command line is like a transient hostname, with the exception that it has higher priority when the
machine boots. Also note that those are the semantics implemented by systemd tools, but other programs
may also set the hostname.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -32,23 +32,33 @@
<refsect1> <refsect1>
<title>Description</title> <title>Description</title>
<para><command>hostnamectl</command> may be used to query and change the system hostname and related <para><command>hostnamectl</command> may be used to query and
settings.</para> change the system hostname and related settings.</para>
<para><citerefentry><refentrytitle>systemd-hostnamed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> <para>This tool distinguishes three different hostnames: the
and this tool distinguish three different hostnames: the high-level "pretty" hostname which might include high-level "pretty" hostname which might include all kinds of
all kinds of special characters (e.g. "Lennart's Laptop"), the "static" hostname which is the special characters (e.g. "Lennart's Laptop"), the static hostname
user-configured hostname (e.g. "lennarts-laptop"), and the transient hostname which is a fallback value which is used to initialize the kernel hostname at boot (e.g.
received from network configuration (e.g. "node12345678"). If a static hostname is set to a valid value, "lennarts-laptop"), and the transient hostname which is a fallback
then the transient hostname is not used.</para> value received from network configuration. If a static hostname is
set, and is valid (something other than localhost), then the
transient hostname is not used.</para>
<para>Note that the pretty hostname has little restrictions on the characters and length used, while the static and <para>Note that the pretty hostname has little restrictions on the characters and length used, while the static and
transient hostnames are limited to the usually accepted characters of Internet domain names, and 64 characters at transient hostnames are limited to the usually accepted characters of Internet domain names, and 64 characters at
maximum (the latter being a Linux limitation).</para> maximum (the latter being a Linux limitation).</para>
<para>The static hostname is stored in
<filename>/etc/hostname</filename>, see
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for more information. The pretty hostname, chassis type, and icon
name are stored in <filename>/etc/machine-info</filename>, see
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>Use <para>Use
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry> to <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
initialize the system hostname for mounted (but not booted) system images.</para> to initialize the system hostname for mounted (but not booted)
system images.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -94,11 +94,10 @@
<varlistentry id='colors'> <varlistentry id='colors'>
<term><varname>$SYSTEMD_COLORS</varname></term> <term><varname>$SYSTEMD_COLORS</varname></term>
<listitem><para>Takes a boolean argument. When true, <command>systemd</command> and related utilities <listitem><para>The value must be a boolean. Controls whether colorized output should be
will use colors in their output, otherwise the output will be monochrome. Additionally, the variable can generated. This can be specified to override the decision that <command>systemd</command> makes based
take one of the following special values: <literal>16</literal>, <literal>256</literal> to restrict the use on <varname>$TERM</varname> and what the console is connected to.</para>
of colors to the base 16 or 256 ANSI colors, respectively. This can be specified to override the automatic </listitem>
decision based on <varname>$TERM</varname> and what the console is connected to.</para></listitem>
</varlistentry> </varlistentry>
<!-- This is not documented on purpose, because it is not clear if $NO_COLOR will become supported <!-- This is not documented on purpose, because it is not clear if $NO_COLOR will become supported

View File

@ -62,9 +62,6 @@ node /org/freedesktop/hostname1 {
readonly s Hostname = '...'; readonly s Hostname = '...';
readonly s StaticHostname = '...'; readonly s StaticHostname = '...';
readonly s PrettyHostname = '...'; readonly s PrettyHostname = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s FallbackHostname = '...';
readonly s HostnameSource = '...';
readonly s IconName = '...'; readonly s IconName = '...';
readonly s Chassis = '...'; readonly s Chassis = '...';
readonly s Deployment = '...'; readonly s Deployment = '...';
@ -116,10 +113,6 @@ node /org/freedesktop/hostname1 {
<variablelist class="dbus-property" generated="True" extra-ref="PrettyHostname"/> <variablelist class="dbus-property" generated="True" extra-ref="PrettyHostname"/>
<variablelist class="dbus-property" generated="True" extra-ref="FallbackHostname"/>
<variablelist class="dbus-property" generated="True" extra-ref="HostnameSource"/>
<variablelist class="dbus-property" generated="True" extra-ref="IconName"/> <variablelist class="dbus-property" generated="True" extra-ref="IconName"/>
<variablelist class="dbus-property" generated="True" extra-ref="Chassis"/> <variablelist class="dbus-property" generated="True" extra-ref="Chassis"/>
@ -151,61 +144,55 @@ node /org/freedesktop/hostname1 {
<refsect1> <refsect1>
<title>Semantics</title> <title>Semantics</title>
<para>The <varname>StaticHostname</varname> property exposes the "static" hostname configured in <para>The <emphasis>static (configured) hostname</emphasis> is the one configured in
<filename>/etc/hostname</filename>. It is not always in sync with the current hostname as returned by the <filename>/etc/hostname</filename>. It is chosen by the local user. It is not always in sync with the
current hostname as returned by the
<citerefentry project="man-pages"><refentrytitle>gethostname</refentrytitle><manvolnum>3</manvolnum></citerefentry> <citerefentry project="man-pages"><refentrytitle>gethostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>
system call. If no static hostname is configured this property will be the empty string.</para> system call. If no hostname is configured this property will be the empty string. Setting this property
to the empty string will remove <filename>/etc/hostname</filename>. This property should be an
internet-style hostname, 7-bit lowercase ASCII, no special chars/spaces.</para>
<para>When <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> or <para>The <emphasis>transient (dynamic) hostname</emphasis> is the one configured via the kernel's
<citerefentry><refentrytitle>systemd-hostnamed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
set the hostname, this static hostname <emphasis>has the highest priority</emphasis>.</para>
<para>The <varname>Hostname</varname> property exposes the actual hostname configured in the kernel via
<citerefentry project="man-pages"><refentrytitle>sethostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>. <citerefentry project="man-pages"><refentrytitle>sethostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
It can be different from the static hostname. This property is never empty.</para> It can be different from the static hostname if DHCP or mDNS have been configured to change the name
based on network information. <!-- FIXME: it's not DHCP that configures this... -->
This property is never empty. If no hostname is set this will default to
<literal>&FALLBACK_HOSTNAME;</literal> (configurable at compilation time). Setting this property to the
empty string will reset the dynamic hostname to the static hostname. If no static hostname is
configured the dynamic hostname will be reset to <literal>&FALLBACK_HOSTNAME;</literal>. This property
should be an internet-style hostname, 7-bit lowercase ASCII, no special chars/spaces.</para>
<para>The <varname>PrettyHostname</varname> property exposes the <emphasis>pretty hostname</emphasis> <para>The <emphasis>pretty hostname</emphasis> is a free-form UTF-8 hostname for presentation to the
which is a free-form UTF-8 hostname for presentation to the user. User interfaces should ensure that the user. User interfaces should ensure that the pretty hostname and the static hostname stay in sync.
pretty hostname and the static hostname stay in sync. E.g. when the former is <literal>Lennarts I.e. when the former is <literal>Lennarts Computer</literal> the latter should be
Computer</literal> the latter should be <literal>lennarts-computer</literal>. If no pretty hostname is <literal>lennarts-computer</literal>. If no pretty hostname is set this setting will be the empty
set this setting will be the empty string. Applications should then find a suitable fallback, such as the string. Applications should then find a suitable fallback, such as the dynamic hostname.</para>
dynamic hostname.</para>
<para>The <varname>FallbackHostname</varname> property exposes the fallback hostname (configured at <para>The <emphasis>icon name</emphasis> is a name following the XDG icon naming spec. If not set,
compilation time).</para> information such as the chassis type (see below) is used to find a suitable fallback icon name
(i.e. <literal>computer-laptop</literal> vs. <literal>computer-desktop</literal> is picked based on the
chassis information). If no such data is available, the empty string is returned. In that case an application
should fall back to a replacement icon, for example <literal>computer</literal>. If this property is set
to the empty string, the automatic fallback name selection is enabled again.</para>
<para>The <varname>HostnameSource</varname> property exposes the origin of the currently configured <para>The <emphasis>chassis type</emphasis> should be one of the currently defined chassis types:
hostname. One of <literal>static</literal> (set from <filename>/etc/hostname</filename>), <literal>desktop</literal>, <literal>laptop</literal>, <literal>server</literal>,
<literal>transient</literal> (a non-permanent hostname from an external source), <literal>tablet</literal>, <literal>handset</literal>, as well as the special chassis types
<literal>fallback</literal> (the compiled-in fallback value).</para> <literal>vm</literal> and <literal>container</literal> for virtualized systems. Note that in most cases
the chassis type will be determined automatically from DMI/SMBIOS/ACPI firmware information. Writing to
<para>The <varname>IconName</varname> property exposes the <emphasis>icon name</emphasis> following the this setting is hence useful only to override misdetected chassis types, or to configure the chassis type if
XDG icon naming spec. If not set, information such as the chassis type (see below) is used to find a it could not be auto-detected. Set this property to the empty string to reenable the automatic detection of
suitable fallback icon name (i.e. <literal>computer-laptop</literal> the chassis type from firmware information.</para>
vs. <literal>computer-desktop</literal> is picked based on the chassis information). If no such data is
available, the empty string is returned. In that case an application should fall back to a replacement
icon, for example <literal>computer</literal>. If this property is set to the empty string, the automatic
fallback name selection is enabled again.</para>
<para>The <varname>Chassis</varname> property exposes a <emphasis>chassis type</emphasis>, one of the
currently defined chassis types: <literal>desktop</literal>, <literal>laptop</literal>,
<literal>server</literal>, <literal>tablet</literal>, <literal>handset</literal>, as well as the special
chassis types <literal>vm</literal> and <literal>container</literal> for virtualized systems. Note that
in most cases the chassis type will be determined automatically from DMI/SMBIOS/ACPI firmware
information. Writing to this setting is hence useful only to override misdetected chassis types, or to
configure the chassis type if it could not be auto-detected. Set this property to the empty string to
reenable the automatic detection of the chassis type from firmware information.</para>
<para>Note that <filename>systemd-hostnamed</filename> starts only on request and terminates after a <para>Note that <filename>systemd-hostnamed</filename> starts only on request and terminates after a
short idle period. This effectively means that <function>PropertyChanged</function> messages are not sent short idle period. This effectively means that <function>PropertyChanged</function> messages are not sent
out for changes made directly on the files (as in: administrator edits the files with vi). This is out for changes made directly on the files (as in: administrator edits the files with vi). This is
the intended behavior: manual configuration changes should require manual reloading.</para> the intended behavior: manual configuration changes should require manual reloading.</para>
<para>The transient (dynamic) hostname exposed by the <varname>Hostname</varname> property maps directly <para>The transient (dynamic) hostname maps directly to the kernel hostname. This hostname should be
to the kernel hostname. This hostname should be assumed to be highly dynamic, and hence should be watched assumed to be highly dynamic, and hence should be watched directly, without depending on
directly, without depending on <function>PropertyChanged</function> messages from <function>PropertyChanged</function> messages from <filename>systemd-hostnamed</filename>. To accomplish
<filename>systemd-hostnamed</filename>. To accomplish this, open this, open <filename>/proc/sys/kernel/hostname</filename> and
<filename>/proc/sys/kernel/hostname</filename> and
<citerefentry project="man-pages"><refentrytitle>poll</refentrytitle><manvolnum>3</manvolnum></citerefentry> <citerefentry project="man-pages"><refentrytitle>poll</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for <constant>SIGHUP</constant> which is triggered by the kernel every time the hostname changes. Again: for <constant>SIGHUP</constant> which is triggered by the kernel every time the hostname changes. Again:
this is special for the transient (dynamic) hostname, and does not apply to the configured (fixed) this is special for the transient (dynamic) hostname, and does not apply to the configured (fixed)
@ -219,17 +206,15 @@ node /org/freedesktop/hostname1 {
for that. For more information on these files and syscalls see the respective man pages.</para> for that. For more information on these files and syscalls see the respective man pages.</para>
<refsect2> <refsect2>
<title>Methods</title> <title>Methods and Properties</title>
<para><function>SetHostname()</function> sets the transient (dynamic) hostname, which is used if no <para><function>SetHostname()</function> sets the transient (dynamic) hostname which is exposed by the
static hostname is set. This value must be an internet-style hostname, 7-bit lowercase ASCII, no <varname>Hostname</varname> property. If empty, the transient hostname is set to the static hostname.
special chars/spaces. An empty string will unset the transient hostname.</para> </para>
<para><function>SetStaticHostname()</function> sets the static hostname which is exposed by the <para><function>SetStaticHostname()</function> sets the static hostname which is exposed by the
<varname>StaticHostname</varname> property. When called with an empty argument, the static <varname>StaticHostname</varname> property. If empty, the built-in default of
configuration in <filename>/etc/hostname</filename> is removed. Since the static hostname has the <literal>&FALLBACK_HOSTNAME;</literal> is used.</para>
highest priority, calling this function usually affects also the <varname>Hostname</varname> property
and the effective hostname configured in the kernel.</para>
<para><function>SetPrettyHostname()</function> sets the pretty hostname which is exposed by the <para><function>SetPrettyHostname()</function> sets the pretty hostname which is exposed by the
<varname>PrettyHostname</varname> property.</para> <varname>PrettyHostname</varname> property.</para>
@ -302,6 +287,10 @@ node /org/freedesktop/hostname1 {
with <citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>. with <citerefentry><refentrytitle>nss-myhostname</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para> </para>
<para>A client that wants to change the local hostname for DHCP/mDNS should invoke
<code>SetHostname("newname", false)</code> as soon as the name is available and afterwards reset it via
<code>SetHostname("")</code>.</para>
<para>Here are some recommendations to follow when generating a static (internet) hostname from a pretty <para>Here are some recommendations to follow when generating a static (internet) hostname from a pretty
name: name:
<itemizedlist> <itemizedlist>

View File

@ -199,7 +199,7 @@
specified as the special string <literal>.host</literal> the connection is made to the local system. This specified as the special string <literal>.host</literal> the connection is made to the local system. This
is useful to connect to the local system bus as specific user, e.g. <literal>foobar@.host</literal> to is useful to connect to the local system bus as specific user, e.g. <literal>foobar@.host</literal> to
connect to the local system bus as local user <literal>foobar</literal>. If the <literal>@</literal> connect to the local system bus as local user <literal>foobar</literal>. If the <literal>@</literal>
syntax is used either the left-hand side or the right-hand side may be omitted (but not both) in which syntax is used either the left-hand side or the right-hand side may be ommited (but not both) in which
case the local user name or <literal>.host</literal> is implied. If the <literal>@</literal> syntax is case the local user name or <literal>.host</literal> is implied. If the <literal>@</literal> syntax is
not used the connection is always made as root user. See not used the connection is always made as root user. See
<citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry> <citerefentry><refentrytitle>sd_bus_set_address</refentrytitle><manvolnum>3</manvolnum></citerefentry>

View File

@ -51,15 +51,9 @@
</listitem> </listitem>
</itemizedlist></para> </itemizedlist></para>
<para>The static hostname is stored in <filename>/etc/hostname</filename>, see
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more
information. The pretty hostname, chassis type, and icon name are stored in
<filename>/etc/machine-info</filename>, see
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
<para>The tool <para>The tool
<citerefentry><refentrytitle>hostnamectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> is a <citerefentry><refentrytitle>hostnamectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
command line client to this service.</para> is a command line client to this service.</para>
<para>See <para>See
<citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>5</manvolnum></citerefentry> <citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>5</manvolnum></citerefentry>

View File

@ -51,7 +51,7 @@
system is made (which is useful to connect to a specific user's user bus: <literal>--user system is made (which is useful to connect to a specific user's user bus: <literal>--user
--machine=lennart@.host</literal>). If the <literal>@</literal> syntax is not used, the connection is --machine=lennart@.host</literal>). If the <literal>@</literal> syntax is not used, the connection is
made as root user. If the <literal>@</literal> syntax is used either the left hand side or the right hand made as root user. If the <literal>@</literal> syntax is used either the left hand side or the right hand
side may be omitted (but not both) in which case the local user name and <literal>.host</literal> are side may be ommitted (but not both) in which case the local user name and <literal>.host</literal> are
implied.</para> implied.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -5,14 +5,13 @@
# Andreas Henriksson <andreas@fatal.se>, 2016. # Andreas Henriksson <andreas@fatal.se>, 2016.
# Josef Andersson <l10nl18nsweja@gmail.com>, 2015, 2017. # Josef Andersson <l10nl18nsweja@gmail.com>, 2015, 2017.
# Göran Uddeborg <goeran@uddeborg.se>, 2020. # Göran Uddeborg <goeran@uddeborg.se>, 2020.
# Luna Jernberg <bittin@reimu.nl>, 2020.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: systemd master\n" "Project-Id-Version: systemd master\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-08-19 18:02+0200\n" "POT-Creation-Date: 2020-08-19 18:02+0200\n"
"PO-Revision-Date: 2020-12-16 12:36+0000\n" "PO-Revision-Date: 2020-08-27 02:46+0000\n"
"Last-Translator: Luna Jernberg <bittin@reimu.nl>\n" "Last-Translator: Göran Uddeborg <goeran@uddeborg.se>\n"
"Language-Team: Swedish <https://translate.fedoraproject.org/projects/systemd/" "Language-Team: Swedish <https://translate.fedoraproject.org/projects/systemd/"
"master/sv/>\n" "master/sv/>\n"
"Language: sv\n" "Language: sv\n"
@ -20,7 +19,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.3.2\n" "X-Generator: Weblate 4.2.1\n"
#: src/core/org.freedesktop.systemd1.policy.in:22 #: src/core/org.freedesktop.systemd1.policy.in:22
msgid "Send passphrase back to system" msgid "Send passphrase back to system"
@ -686,8 +685,10 @@ msgid "Set NTP servers"
msgstr "" msgstr ""
#: src/network/org.freedesktop.network1.policy:23 #: src/network/org.freedesktop.network1.policy:23
#, fuzzy
#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to set NTP servers." msgid "Authentication is required to set NTP servers."
msgstr "Autentisering krävs för ställa in NTP-servrar." msgstr "Autentisering krävs för ställa in systemtiden."
#: src/network/org.freedesktop.network1.policy:33 #: src/network/org.freedesktop.network1.policy:33
#: src/resolve/org.freedesktop.resolve1.policy:44 #: src/resolve/org.freedesktop.resolve1.policy:44
@ -696,8 +697,10 @@ msgstr ""
#: src/network/org.freedesktop.network1.policy:34 #: src/network/org.freedesktop.network1.policy:34
#: src/resolve/org.freedesktop.resolve1.policy:45 #: src/resolve/org.freedesktop.resolve1.policy:45
#, fuzzy
#| msgid "Authentication is required to set the system time."
msgid "Authentication is required to set DNS servers." msgid "Authentication is required to set DNS servers."
msgstr "Autentisering krävs för ställa in DNS-servrar." msgstr "Autentisering krävs för ställa in systemtiden."
#: src/network/org.freedesktop.network1.policy:44 #: src/network/org.freedesktop.network1.policy:44
#: src/resolve/org.freedesktop.resolve1.policy:55 #: src/resolve/org.freedesktop.resolve1.policy:55
@ -726,7 +729,7 @@ msgstr "Autentisering krävs för att ställa in lokalt värdnamn."
#: src/network/org.freedesktop.network1.policy:66 #: src/network/org.freedesktop.network1.policy:66
#: src/resolve/org.freedesktop.resolve1.policy:77 #: src/resolve/org.freedesktop.resolve1.policy:77
msgid "Enable/disable LLMNR" msgid "Enable/disable LLMNR"
msgstr "Aktivera/inaktivera LLMNR" msgstr ""
#: src/network/org.freedesktop.network1.policy:67 #: src/network/org.freedesktop.network1.policy:67
#: src/resolve/org.freedesktop.resolve1.policy:78 #: src/resolve/org.freedesktop.resolve1.policy:78
@ -738,7 +741,7 @@ msgstr "Autentisering krävs för att försätta systemet i viloläge."
#: src/network/org.freedesktop.network1.policy:77 #: src/network/org.freedesktop.network1.policy:77
#: src/resolve/org.freedesktop.resolve1.policy:88 #: src/resolve/org.freedesktop.resolve1.policy:88
msgid "Enable/disable multicast DNS" msgid "Enable/disable multicast DNS"
msgstr "Aktivera/inaktivera multicast-DNS" msgstr ""
#: src/network/org.freedesktop.network1.policy:78 #: src/network/org.freedesktop.network1.policy:78
#: src/resolve/org.freedesktop.resolve1.policy:89 #: src/resolve/org.freedesktop.resolve1.policy:89
@ -750,7 +753,7 @@ msgstr "Autentisering krävs för att logga in på den lokala värden"
#: src/network/org.freedesktop.network1.policy:88 #: src/network/org.freedesktop.network1.policy:88
#: src/resolve/org.freedesktop.resolve1.policy:99 #: src/resolve/org.freedesktop.resolve1.policy:99
msgid "Enable/disable DNS over TLS" msgid "Enable/disable DNS over TLS"
msgstr "Aktivera/inaktivera DNS över TLS" msgstr ""
#: src/network/org.freedesktop.network1.policy:89 #: src/network/org.freedesktop.network1.policy:89
#: src/resolve/org.freedesktop.resolve1.policy:100 #: src/resolve/org.freedesktop.resolve1.policy:100
@ -762,7 +765,7 @@ msgstr "Autentisering krävs för att ställa in lokalt värdnamn."
#: src/network/org.freedesktop.network1.policy:99 #: src/network/org.freedesktop.network1.policy:99
#: src/resolve/org.freedesktop.resolve1.policy:110 #: src/resolve/org.freedesktop.resolve1.policy:110
msgid "Enable/disable DNSSEC" msgid "Enable/disable DNSSEC"
msgstr "Aktivera/inaktivera DNSSEC" msgstr ""
#: src/network/org.freedesktop.network1.policy:100 #: src/network/org.freedesktop.network1.policy:100
#: src/resolve/org.freedesktop.resolve1.policy:111 #: src/resolve/org.freedesktop.resolve1.policy:111
@ -877,7 +880,7 @@ msgstr "Autentisering krävs för att hämta ner en VM eller behållaravbildning
#: src/resolve/org.freedesktop.resolve1.policy:22 #: src/resolve/org.freedesktop.resolve1.policy:22
msgid "Register a DNS-SD service" msgid "Register a DNS-SD service"
msgstr "Registrera en DNS-SD-tjänst" msgstr ""
#: src/resolve/org.freedesktop.resolve1.policy:23 #: src/resolve/org.freedesktop.resolve1.policy:23
#, fuzzy #, fuzzy
@ -887,7 +890,7 @@ msgstr "Autentisering krävs för att ställa in ett väggmeddelande"
#: src/resolve/org.freedesktop.resolve1.policy:33 #: src/resolve/org.freedesktop.resolve1.policy:33
msgid "Unregister a DNS-SD service" msgid "Unregister a DNS-SD service"
msgstr "Avregistrera en DNS-SD-tjänst" msgstr ""
#: src/resolve/org.freedesktop.resolve1.policy:34 #: src/resolve/org.freedesktop.resolve1.policy:34
#, fuzzy #, fuzzy

View File

@ -1,8 +0,0 @@
# do not edit this file, it will be overwritten on update
ACTION=="remove", GOTO="memory_end"
SUBSYSTEM!="dmi", GOTO="memory_end"
IMPORT{program}="dmi_memory_id"
LABEL="memory_end"

View File

@ -17,7 +17,6 @@ rules = files('''
60-serial.rules 60-serial.rules
70-joystick.rules 70-joystick.rules
70-mouse.rules 70-mouse.rules
70-memory.rules
70-touchpad.rules 70-touchpad.rules
75-net-description.rules 75-net-description.rules
75-probe_mtd.rules 75-probe_mtd.rules

View File

@ -7,10 +7,28 @@
#include <unistd.h> #include <unistd.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "macro.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
bool hostname_is_set(void) {
struct utsname u;
assert_se(uname(&u) >= 0);
if (isempty(u.nodename))
return false;
/* This is the built-in kernel default hostname */
if (streq(u.nodename, "(none)"))
return false;
return true;
}
char* gethostname_malloc(void) { char* gethostname_malloc(void) {
struct utsname u; struct utsname u;
const char *s; const char *s;
@ -190,3 +208,105 @@ bool is_localhost(const char *hostname) {
endswith_no_case(hostname, ".localhost.localdomain") || endswith_no_case(hostname, ".localhost.localdomain") ||
endswith_no_case(hostname, ".localhost.localdomain."); endswith_no_case(hostname, ".localhost.localdomain.");
} }
int sethostname_idempotent(const char *s) {
char buf[HOST_NAME_MAX + 1] = {};
assert(s);
if (gethostname(buf, sizeof(buf)) < 0)
return -errno;
if (streq(buf, s))
return 0;
if (sethostname(s, strlen(s)) < 0)
return -errno;
return 1;
}
int shorten_overlong(const char *s, char **ret) {
char *h, *p;
/* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
* whatever comes earlier. */
assert(s);
h = strdup(s);
if (!h)
return -ENOMEM;
if (hostname_is_valid(h, 0)) {
*ret = h;
return 0;
}
p = strchr(h, '.');
if (p)
*p = 0;
strshorten(h, HOST_NAME_MAX);
if (!hostname_is_valid(h, 0)) {
free(h);
return -EDOM;
}
*ret = h;
return 1;
}
int read_etc_hostname_stream(FILE *f, char **ret) {
int r;
assert(f);
assert(ret);
for (;;) {
_cleanup_free_ char *line = NULL;
char *p;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return r;
if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
return -ENOENT;
p = strstrip(line);
/* File may have empty lines or comments, ignore them */
if (!IN_SET(*p, '\0', '#')) {
char *copy;
hostname_cleanup(p); /* normalize the hostname */
if (!hostname_is_valid(p, VALID_HOSTNAME_TRAILING_DOT)) /* check that the hostname we return is valid */
return -EBADMSG;
copy = strdup(p);
if (!copy)
return -ENOMEM;
*ret = copy;
return 0;
}
}
}
int read_etc_hostname(const char *path, char **ret) {
_cleanup_fclose_ FILE *f = NULL;
assert(ret);
if (!path)
path = "/etc/hostname";
f = fopen(path, "re");
if (!f)
return -errno;
return read_etc_hostname_stream(f, ret);
}

View File

@ -7,6 +7,8 @@
#include "macro.h" #include "macro.h"
#include "strv.h" #include "strv.h"
bool hostname_is_set(void);
char* gethostname_malloc(void); char* gethostname_malloc(void);
char* gethostname_short_malloc(void); char* gethostname_short_malloc(void);
int gethostname_strict(char **ret); int gethostname_strict(char **ret);
@ -27,3 +29,10 @@ static inline bool is_gateway_hostname(const char *hostname) {
/* This tries to identify the valid syntaxes for the our synthetic "gateway" host. */ /* This tries to identify the valid syntaxes for the our synthetic "gateway" host. */
return STRCASE_IN_SET(hostname, "_gateway", "_gateway."); return STRCASE_IN_SET(hostname, "_gateway", "_gateway.");
} }
int sethostname_idempotent(const char *s);
int shorten_overlong(const char *s, char **ret);
int read_etc_hostname_stream(FILE *f, char **ret);
int read_etc_hostname(const char *path, char **ret);

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _NFNETLINK_H
#define _NFNETLINK_H
#include <linux/types.h>
#include <linux/netfilter/nfnetlink_compat.h>
enum nfnetlink_groups {
NFNLGRP_NONE,
#define NFNLGRP_NONE NFNLGRP_NONE
NFNLGRP_CONNTRACK_NEW,
#define NFNLGRP_CONNTRACK_NEW NFNLGRP_CONNTRACK_NEW
NFNLGRP_CONNTRACK_UPDATE,
#define NFNLGRP_CONNTRACK_UPDATE NFNLGRP_CONNTRACK_UPDATE
NFNLGRP_CONNTRACK_DESTROY,
#define NFNLGRP_CONNTRACK_DESTROY NFNLGRP_CONNTRACK_DESTROY
NFNLGRP_CONNTRACK_EXP_NEW,
#define NFNLGRP_CONNTRACK_EXP_NEW NFNLGRP_CONNTRACK_EXP_NEW
NFNLGRP_CONNTRACK_EXP_UPDATE,
#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE
NFNLGRP_CONNTRACK_EXP_DESTROY,
#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
NFNLGRP_NFTABLES,
#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES
NFNLGRP_ACCT_QUOTA,
#define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA
NFNLGRP_NFTRACE,
#define NFNLGRP_NFTRACE NFNLGRP_NFTRACE
__NFNLGRP_MAX,
};
#define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
/* General form of address family dependent message.
*/
struct nfgenmsg {
__u8 nfgen_family; /* AF_xxx */
__u8 version; /* nfnetlink version */
__be16 res_id; /* resource id */
};
#define NFNETLINK_V0 0
/* netfilter netlink message types are split in two pieces:
* 8 bit subsystem, 8bit operation.
*/
#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8)
#define NFNL_MSG_TYPE(x) (x & 0x00ff)
/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
* won't work anymore */
#define NFNL_SUBSYS_NONE 0
#define NFNL_SUBSYS_CTNETLINK 1
#define NFNL_SUBSYS_CTNETLINK_EXP 2
#define NFNL_SUBSYS_QUEUE 3
#define NFNL_SUBSYS_ULOG 4
#define NFNL_SUBSYS_OSF 5
#define NFNL_SUBSYS_IPSET 6
#define NFNL_SUBSYS_ACCT 7
#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
#define NFNL_SUBSYS_CTHELPER 9
#define NFNL_SUBSYS_NFTABLES 10
#define NFNL_SUBSYS_NFT_COMPAT 11
#define NFNL_SUBSYS_COUNT 12
/* Reserved control nfnetlink messages */
#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE
#define NFNL_MSG_BATCH_END NLMSG_MIN_TYPE+1
/**
* enum nfnl_batch_attributes - nfnetlink batch netlink attributes
*
* @NFNL_BATCH_GENID: generation ID for this changeset (NLA_U32)
*/
enum nfnl_batch_attributes {
NFNL_BATCH_UNSPEC,
NFNL_BATCH_GENID,
__NFNL_BATCH_MAX
};
#define NFNL_BATCH_MAX (__NFNL_BATCH_MAX - 1)
#endif /* _NFNETLINK_H */

View File

@ -404,7 +404,7 @@ static int write_to_console(
if (show_location) { if (show_location) {
const char *lon = "", *loff = ""; const char *lon = "", *loff = "";
if (log_get_show_color()) { if (log_get_show_color()) {
lon = ansi_highlight_yellow4(); lon = ANSI_HIGHLIGHT_YELLOW4;
loff = ANSI_NORMAL; loff = ANSI_NORMAL;
} }

View File

@ -78,7 +78,6 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
_DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope)
#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
#define DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)

View File

@ -47,7 +47,7 @@ static volatile unsigned cached_columns = 0;
static volatile unsigned cached_lines = 0; static volatile unsigned cached_lines = 0;
static volatile int cached_on_tty = -1; static volatile int cached_on_tty = -1;
static volatile int cached_color_mode = _COLOR_INVALID; static volatile int cached_colors_enabled = -1;
static volatile int cached_underline_enabled = -1; static volatile int cached_underline_enabled = -1;
int chvt(int vt) { int chvt(int vt) {
@ -164,7 +164,8 @@ int ask_char(char *ret, const char *replies, const char *fmt, ...) {
char c; char c;
bool need_nl = true; bool need_nl = true;
fputs(ansi_highlight(), stdout); if (colors_enabled())
fputs(ANSI_HIGHLIGHT, stdout);
putchar('\r'); putchar('\r');
@ -172,7 +173,8 @@ int ask_char(char *ret, const char *replies, const char *fmt, ...) {
vprintf(fmt, ap); vprintf(fmt, ap);
va_end(ap); va_end(ap);
fputs(ansi_normal(), stdout); if (colors_enabled())
fputs(ANSI_NORMAL, stdout);
fflush(stdout); fflush(stdout);
@ -211,13 +213,15 @@ int ask_string(char **ret, const char *text, ...) {
assert(ret); assert(ret);
assert(text); assert(text);
fputs(ansi_highlight(), stdout); if (colors_enabled())
fputs(ANSI_HIGHLIGHT, stdout);
va_start(ap, text); va_start(ap, text);
vprintf(text, ap); vprintf(text, ap);
va_end(ap); va_end(ap);
fputs(ansi_normal(), stdout); if (colors_enabled())
fputs(ANSI_NORMAL, stdout);
fflush(stdout); fflush(stdout);
@ -863,7 +867,7 @@ void reset_terminal_feature_caches(void) {
cached_columns = 0; cached_columns = 0;
cached_lines = 0; cached_lines = 0;
cached_color_mode = _COLOR_INVALID; cached_colors_enabled = -1;
cached_underline_enabled = -1; cached_underline_enabled = -1;
cached_on_tty = -1; cached_on_tty = -1;
} }
@ -1202,57 +1206,38 @@ bool terminal_is_dumb(void) {
return getenv_terminal_is_dumb(); return getenv_terminal_is_dumb();
} }
static ColorMode parse_systemd_colors(void) { bool colors_enabled(void) {
const char *e;
int r;
e = getenv("SYSTEMD_COLORS"); /* Returns true if colors are considered supported on our stdout. For that we check $SYSTEMD_COLORS first
if (!e) * (which is the explicit way to turn colors on/off). If that didn't work we turn colors off unless we are on a
return _COLOR_INVALID; * TTY. And if we are on a TTY we turn it off if $TERM is set to "dumb". There's one special tweak though: if
if (streq(e, "16")) * we are PID 1 then we do not check whether we are connected to a TTY, because we don't keep /dev/console open
return COLOR_16; * continuously due to fear of SAK, and hence things are a bit weird. */
if (streq(e, "256"))
return COLOR_256;
r = parse_boolean(e);
if (r >= 0)
return r > 0 ? COLOR_ON : COLOR_OFF;
return _COLOR_INVALID;
}
ColorMode get_color_mode(void) { if (cached_colors_enabled < 0) {
int val;
/* Returns the mode used to choose output colors. The possible modes are COLOR_OFF for no colors, val = getenv_bool("SYSTEMD_COLORS");
* COLOR_16 for only the base 16 ANSI colors, COLOR_256 for more colors and COLOR_ON for unrestricted if (val >= 0)
* color output. For that we check $SYSTEMD_COLORS first (which is the explicit way to cached_colors_enabled = val;
* change the mode). If that didn't work we turn colors off unless we are on a TTY. And if we are on a TTY
* we turn it off if $TERM is set to "dumb". There's one special tweak though: if we are PID 1 then we do not
* check whether we are connected to a TTY, because we don't keep /dev/console open continuously due to fear
* of SAK, and hence things are a bit weird. */
ColorMode m;
if (cached_color_mode < 0) {
m = parse_systemd_colors();
if (m >= 0)
cached_color_mode = m;
else if (getenv("NO_COLOR")) else if (getenv("NO_COLOR"))
/* We only check for the presence of the variable; value is ignored. */ /* We only check for the presence of the variable; value is ignored. */
cached_color_mode = COLOR_OFF; cached_colors_enabled = false;
else if (getpid_cached() == 1) else if (getpid_cached() == 1)
/* PID1 outputs to the console without holding it open all the time. /* PID1 outputs to the console without holding it open all the time */
* Also note the Linux console can only handle 16 colors. cached_colors_enabled = !getenv_terminal_is_dumb();
*/
cached_color_mode = getenv_terminal_is_dumb() ? COLOR_OFF : COLOR_16;
else else
cached_color_mode = terminal_is_dumb() ? COLOR_OFF : COLOR_256; cached_colors_enabled = !terminal_is_dumb();
} }
return cached_color_mode; return cached_colors_enabled;
} }
bool dev_console_colors_enabled(void) { bool dev_console_colors_enabled(void) {
_cleanup_free_ char *s = NULL; _cleanup_free_ char *s = NULL;
ColorMode m; int b;
/* Returns true if we assume that color is supported on /dev/console. /* Returns true if we assume that color is supported on /dev/console.
* *
@ -1261,9 +1246,9 @@ bool dev_console_colors_enabled(void) {
* line. If we find $TERM set we assume color if it's not set to "dumb", similarly to how regular * line. If we find $TERM set we assume color if it's not set to "dumb", similarly to how regular
* colors_enabled() operates. */ * colors_enabled() operates. */
m = parse_systemd_colors(); b = getenv_bool("SYSTEMD_COLORS");
if (m >= 0) if (b >= 0)
return m; return b;
if (getenv("NO_COLOR")) if (getenv("NO_COLOR"))
return false; return false;
@ -1368,7 +1353,7 @@ void get_log_colors(int priority, const char **on, const char **off, const char
if (priority <= LOG_ERR) { if (priority <= LOG_ERR) {
if (on) if (on)
*on = ansi_highlight_red(); *on = ANSI_HIGHLIGHT_RED;
if (off) if (off)
*off = ANSI_NORMAL; *off = ANSI_NORMAL;
if (highlight) if (highlight)
@ -1376,7 +1361,7 @@ void get_log_colors(int priority, const char **on, const char **off, const char
} else if (priority <= LOG_WARNING) { } else if (priority <= LOG_WARNING) {
if (on) if (on)
*on = ansi_highlight_yellow(); *on = ANSI_HIGHLIGHT_YELLOW;
if (off) if (off)
*off = ANSI_NORMAL; *off = ANSI_NORMAL;
if (highlight) if (highlight)
@ -1388,14 +1373,14 @@ void get_log_colors(int priority, const char **on, const char **off, const char
if (off) if (off)
*off = ANSI_NORMAL; *off = ANSI_NORMAL;
if (highlight) if (highlight)
*highlight = ansi_highlight_red(); *highlight = ANSI_HIGHLIGHT_RED;
} else if (priority >= LOG_DEBUG) { } else if (priority >= LOG_DEBUG) {
if (on) if (on)
*on = ansi_grey(); *on = ANSI_GREY;
if (off) if (off)
*off = ANSI_NORMAL; *off = ANSI_NORMAL;
if (highlight) if (highlight)
*highlight = ansi_highlight_red(); *highlight = ANSI_HIGHLIGHT_RED;
} }
} }

View File

@ -61,10 +61,6 @@
#define ANSI_HIGHLIGHT "\x1B[0;1;39m" #define ANSI_HIGHLIGHT "\x1B[0;1;39m"
#define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m" #define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m"
/* Fallback colors: 256 -> 16 */
#define ANSI_HIGHLIGHT_GREY_FALLBACK "\x1B[0;1;90m"
#define ANSI_HIGHLIGHT_YELLOW_FALLBACK "\x1B[0;1;33m"
/* Reset/clear ANSI styles */ /* Reset/clear ANSI styles */
#define ANSI_NORMAL "\x1B[0m" #define ANSI_NORMAL "\x1B[0m"
@ -97,23 +93,6 @@ typedef enum AcquireTerminalFlags {
ACQUIRE_TERMINAL_PERMISSIVE = 1 << 2, ACQUIRE_TERMINAL_PERMISSIVE = 1 << 2,
} AcquireTerminalFlags; } AcquireTerminalFlags;
/* Limits the use of ANSI colors to a subset. */
typedef enum ColorMode {
/* No colors, monochrome output. */
COLOR_OFF = 0,
/* All colors, no restrictions. */
COLOR_ON = 1,
/* Only the base 16 colors. */
COLOR_16 = 16,
/* Only 256 colors. */
COLOR_256 = 256,
_COLOR_INVALID = -1,
} ColorMode;
int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout); int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout);
int release_terminal(void); int release_terminal(void);
@ -148,44 +127,19 @@ void reset_terminal_feature_caches(void);
bool on_tty(void); bool on_tty(void);
bool terminal_is_dumb(void); bool terminal_is_dumb(void);
ColorMode get_color_mode(void); bool colors_enabled(void);
bool underline_enabled(void); bool underline_enabled(void);
bool dev_console_colors_enabled(void); bool dev_console_colors_enabled(void);
static inline bool colors_enabled(void) {
/* Returns true if colors are considered supported on our stdout. */
return get_color_mode() != COLOR_OFF;
}
#define DEFINE_ANSI_FUNC(name, NAME) \ #define DEFINE_ANSI_FUNC(name, NAME) \
static inline const char *ansi_##name(void) { \ static inline const char *ansi_##name(void) { \
return colors_enabled() ? ANSI_##NAME : ""; \ return colors_enabled() ? ANSI_##NAME : ""; \
} }
#define DEFINE_ANSI_FUNC_256(name, NAME, FALLBACK) \ #define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME, REPLACEMENT) \
static inline const char *ansi_##name(void) { \ static inline const char *ansi_##name(void) { \
switch (get_color_mode()) { \ return underline_enabled() ? ANSI_##NAME : \
case COLOR_OFF: return ""; \ colors_enabled() ? ANSI_##REPLACEMENT : ""; \
case COLOR_16: return ANSI_##FALLBACK; \
default : return ANSI_##NAME; \
} \
}
#define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME) \
static inline const char *ansi_##name(void) { \
return underline_enabled() ? ANSI_##NAME ANSI_UNDERLINE : \
colors_enabled() ? ANSI_##NAME : ""; \
}
#define DEFINE_ANSI_FUNC_UNDERLINE_256(name, NAME, FALLBACK) \
static inline const char *ansi_##name(void) { \
switch (get_color_mode()) { \
case COLOR_OFF: return ""; \
case COLOR_16: return underline_enabled() ? ANSI_##FALLBACK ANSI_UNDERLINE : ANSI_##FALLBACK; \
default : return underline_enabled() ? ANSI_##NAME ANSI_UNDERLINE: ANSI_##NAME; \
} \
} }
DEFINE_ANSI_FUNC(normal, NORMAL); DEFINE_ANSI_FUNC(normal, NORMAL);
@ -198,7 +152,7 @@ DEFINE_ANSI_FUNC(blue, BLUE);
DEFINE_ANSI_FUNC(magenta, MAGENTA); DEFINE_ANSI_FUNC(magenta, MAGENTA);
DEFINE_ANSI_FUNC(cyan, CYAN); DEFINE_ANSI_FUNC(cyan, CYAN);
DEFINE_ANSI_FUNC(white, WHITE); DEFINE_ANSI_FUNC(white, WHITE);
DEFINE_ANSI_FUNC_256(grey, GREY, BRIGHT_BLACK); DEFINE_ANSI_FUNC(grey, GREY);
DEFINE_ANSI_FUNC(bright_black, BRIGHT_BLACK); DEFINE_ANSI_FUNC(bright_black, BRIGHT_BLACK);
DEFINE_ANSI_FUNC(bright_red, BRIGHT_RED); DEFINE_ANSI_FUNC(bright_red, BRIGHT_RED);
@ -209,30 +163,29 @@ DEFINE_ANSI_FUNC(bright_magenta, BRIGHT_MAGENTA);
DEFINE_ANSI_FUNC(bright_cyan, BRIGHT_CYAN); DEFINE_ANSI_FUNC(bright_cyan, BRIGHT_CYAN);
DEFINE_ANSI_FUNC(bright_white, BRIGHT_WHITE); DEFINE_ANSI_FUNC(bright_white, BRIGHT_WHITE);
DEFINE_ANSI_FUNC(highlight_black, HIGHLIGHT_BLACK); DEFINE_ANSI_FUNC(highlight_black, HIGHLIGHT_BLACK);
DEFINE_ANSI_FUNC(highlight_red, HIGHLIGHT_RED); DEFINE_ANSI_FUNC(highlight_red, HIGHLIGHT_RED);
DEFINE_ANSI_FUNC(highlight_green, HIGHLIGHT_GREEN); DEFINE_ANSI_FUNC(highlight_green, HIGHLIGHT_GREEN);
DEFINE_ANSI_FUNC_256(highlight_yellow, HIGHLIGHT_YELLOW, HIGHLIGHT_YELLOW_FALLBACK); DEFINE_ANSI_FUNC(highlight_yellow, HIGHLIGHT_YELLOW);
DEFINE_ANSI_FUNC_256(highlight_yellow4, HIGHLIGHT_YELLOW4, HIGHLIGHT_YELLOW_FALLBACK); DEFINE_ANSI_FUNC(highlight_blue, HIGHLIGHT_BLUE);
DEFINE_ANSI_FUNC(highlight_blue, HIGHLIGHT_BLUE); DEFINE_ANSI_FUNC(highlight_magenta, HIGHLIGHT_MAGENTA);
DEFINE_ANSI_FUNC(highlight_magenta, HIGHLIGHT_MAGENTA); DEFINE_ANSI_FUNC(highlight_cyan, HIGHLIGHT_CYAN);
DEFINE_ANSI_FUNC(highlight_cyan, HIGHLIGHT_CYAN); DEFINE_ANSI_FUNC(highlight_grey, HIGHLIGHT_GREY);
DEFINE_ANSI_FUNC_256(highlight_grey, HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK); DEFINE_ANSI_FUNC(highlight_white, HIGHLIGHT_WHITE);
DEFINE_ANSI_FUNC(highlight_white, HIGHLIGHT_WHITE);
static inline const char* _ansi_highlight_yellow(void) { static inline const char* _ansi_highlight_yellow(void) {
return colors_enabled() ? _ANSI_HIGHLIGHT_YELLOW : ""; return colors_enabled() ? _ANSI_HIGHLIGHT_YELLOW : "";
} }
DEFINE_ANSI_FUNC_UNDERLINE(underline, NORMAL); DEFINE_ANSI_FUNC_UNDERLINE(underline, UNDERLINE, NORMAL);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT); DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT_UNDERLINE, HIGHLIGHT);
DEFINE_ANSI_FUNC_UNDERLINE_256(grey_underline, GREY, BRIGHT_BLACK); DEFINE_ANSI_FUNC_UNDERLINE(grey_underline, GREY_UNDERLINE, GREY);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED); DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED_UNDERLINE, HIGHLIGHT_RED);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN); DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN_UNDERLINE, HIGHLIGHT_GREEN);
DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_yellow_underline, HIGHLIGHT_YELLOW, HIGHLIGHT_YELLOW_FALLBACK); DEFINE_ANSI_FUNC_UNDERLINE(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE, HIGHLIGHT_YELLOW);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue_underline, HIGHLIGHT_BLUE); DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue_underline, HIGHLIGHT_BLUE_UNDERLINE, HIGHLIGHT_BLUE);
DEFINE_ANSI_FUNC_UNDERLINE(highlight_magenta_underline, HIGHLIGHT_MAGENTA); DEFINE_ANSI_FUNC_UNDERLINE(highlight_magenta_underline, HIGHLIGHT_MAGENTA_UNDERLINE, HIGHLIGHT_MAGENTA);
DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_grey_underline, HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK); DEFINE_ANSI_FUNC_UNDERLINE(highlight_grey_underline, HIGHLIGHT_GREY_UNDERLINE, HIGHLIGHT_GREY);
int get_ctty_devnr(pid_t pid, dev_t *d); int get_ctty_devnr(pid_t pid, dev_t *d);
int get_ctty(pid_t, dev_t *_devnr, char **r); int get_ctty(pid_t, dev_t *_devnr, char **r);

View File

@ -24,7 +24,7 @@
#include "hexdecoct.h" #include "hexdecoct.h"
#include "io-util.h" #include "io-util.h"
#include "ioprio.h" #include "ioprio.h"
#include "journal-file.h" #include "journal-util.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "namespace.h" #include "namespace.h"
#include "parse-util.h" #include "parse-util.h"

62
src/core/hostname-setup.c Normal file
View File

@ -0,0 +1,62 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "alloc-util.h"
#include "fileio.h"
#include "hostname-setup.h"
#include "hostname-util.h"
#include "log.h"
#include "macro.h"
#include "proc-cmdline.h"
#include "string-util.h"
#include "util.h"
int hostname_setup(void) {
_cleanup_free_ char *b = NULL;
const char *hn = NULL;
bool enoent = false;
int r;
r = proc_cmdline_get_key("systemd.hostname", 0, &b);
if (r < 0)
log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
else if (r > 0) {
if (hostname_is_valid(b, VALID_HOSTNAME_TRAILING_DOT))
hn = b;
else {
log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
b = mfree(b);
}
}
if (!hn) {
r = read_etc_hostname(NULL, &b);
if (r == -ENOENT)
enoent = true;
else if (r < 0)
log_warning_errno(r, "Failed to read configured hostname, ignoring: %m");
else
hn = b;
}
if (isempty(hn)) {
/* Don't override the hostname if it is already set and not explicitly configured */
if (hostname_is_set())
return 0;
if (enoent)
log_info("No hostname configured.");
hn = FALLBACK_HOSTNAME;
}
r = sethostname_idempotent(hn);
if (r < 0)
return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn);
log_info("Set hostname to <%s>.", hn);
return 0;
}

View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
int hostname_setup(void);

View File

@ -38,7 +38,7 @@
#include "io-util.h" #include "io-util.h"
#include "ioprio.h" #include "ioprio.h"
#include "ip-protocol-list.h" #include "ip-protocol-list.h"
#include "journal-file.h" #include "journal-util.h"
#include "limits-util.h" #include "limits-util.h"
#include "load-fragment.h" #include "load-fragment.h"
#include "log.h" #include "log.h"

View File

@ -2064,7 +2064,7 @@ static int initialize_runtime(
} }
status_welcome(); status_welcome();
(void) hostname_setup(true); hostname_setup();
/* Force transient machine-id on first boot. */ /* Force transient machine-id on first boot. */
machine_id_setup(NULL, first_boot, arg_machine_id, NULL); machine_id_setup(NULL, first_boot, arg_machine_id, NULL);
(void) loopback_setup(); (void) loopback_setup();

View File

@ -76,6 +76,8 @@ libcore_sources = '''
execute.h execute.h
generator-setup.c generator-setup.c
generator-setup.h generator-setup.h
hostname-setup.c
hostname-setup.h
ima-setup.c ima-setup.c
ima-setup.h ima-setup.h
ip-address-access.c ip-address-access.c

View File

@ -901,7 +901,7 @@ static int mount_procfs(const MountEntry *m, const NamespaceInfo *ns_info) {
* mount. Hence let's gracefully fallback to a classic, unrestricted version. */ * mount. Hence let's gracefully fallback to a classic, unrestricted version. */
r = mount_nofollow_verbose(LOG_DEBUG, "proc", entry_path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); r = mount_nofollow_verbose(LOG_DEBUG, "proc", entry_path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
if (r == -EPERM) { if (r == -EPERM) {
/* When we do not have enough privileges to mount /proc, fallback to use existing /proc. */ /* When we do not have enough priviledge to mount /proc, fallback to use existing /proc. */
if (n > 0) if (n > 0)
/* /proc or some of sub-mounts are umounted in the above. Refuse incomplete tree. /* /proc or some of sub-mounts are umounted in the above. Refuse incomplete tree.

View File

@ -4,7 +4,7 @@
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "fuzz.h" #include "fuzz.h"
#include "hostname-setup.h" #include "hostname-util.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;

View File

@ -123,7 +123,7 @@ fuzzers += [
[libshared], [libshared],
[]], []],
[['src/fuzz/fuzz-hostname-setup.c'], [['src/fuzz/fuzz-hostname-util.c'],
[libshared], [libshared],
[]], []],

View File

@ -8,7 +8,6 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "bus-common-errors.h" #include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-log-control-api.h" #include "bus-log-control-api.h"
#include "bus-polkit.h" #include "bus-polkit.h"
#include "def.h" #include "def.h"
@ -17,7 +16,6 @@
#include "env-util.h" #include "env-util.h"
#include "fileio-label.h" #include "fileio-label.h"
#include "fileio.h" #include "fileio.h"
#include "hostname-setup.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "id128-util.h" #include "id128-util.h"
#include "main-func.h" #include "main-func.h"
@ -31,7 +29,6 @@
#include "service-util.h" #include "service-util.h"
#include "signal-util.h" #include "signal-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "string-table.h"
#include "strv.h" #include "strv.h"
#include "user-util.h" #include "user-util.h"
#include "util.h" #include "util.h"
@ -61,8 +58,6 @@ enum {
typedef struct Context { typedef struct Context {
char *data[_PROP_MAX]; char *data[_PROP_MAX];
HostnameSource hostname_source;
struct stat etc_hostname_stat; struct stat etc_hostname_stat;
struct stat etc_os_release_stat; struct stat etc_os_release_stat;
struct stat etc_machine_info_stat; struct stat etc_machine_info_stat;
@ -71,9 +66,11 @@ typedef struct Context {
} Context; } Context;
static void context_reset(Context *c, uint64_t mask) { static void context_reset(Context *c, uint64_t mask) {
int p;
assert(c); assert(c);
for (int p = 0; p < _PROP_MAX; p++) { for (p = 0; p < _PROP_MAX; p++) {
if (!FLAGS_SET(mask, UINT64_C(1) << p)) if (!FLAGS_SET(mask, UINT64_C(1) << p))
continue; continue;
@ -315,63 +312,63 @@ static char* context_fallback_icon_name(Context *c) {
return strdup("computer"); return strdup("computer");
} }
static bool hostname_is_useful(const char *hn) {
return !isempty(hn) && !is_localhost(hn);
}
static int context_update_kernel_hostname( static int context_update_kernel_hostname(
Context *c, Context *c,
const char *transient_hn) { const char *transient_hn) {
const char *hn; const char *static_hn, *hn;
HostnameSource hns; struct utsname u;
int r;
assert(c); assert(c);
/* /etc/hostname has the highest preference ... */ if (!transient_hn) {
if (c->data[PROP_STATIC_HOSTNAME]) { /* If no transient hostname is passed in, then let's check what is currently set. */
hn = c->data[PROP_STATIC_HOSTNAME]; assert_se(uname(&u) >= 0);
hns = HOSTNAME_STATIC; transient_hn =
isempty(u.nodename) || streq(u.nodename, "(none)") ? NULL : u.nodename;
}
static_hn = c->data[PROP_STATIC_HOSTNAME];
/* /etc/hostname with something other than "localhost"
* has the highest preference ... */
if (hostname_is_useful(static_hn))
hn = static_hn;
/* ... the transient hostname, (ie: DHCP) comes next ... */ /* ... the transient hostname, (ie: DHCP) comes next ... */
} else if (transient_hn) { else if (!isempty(transient_hn))
hn = transient_hn; hn = transient_hn;
hns = HOSTNAME_TRANSIENT;
/* ... fallback to static "localhost.*" ignored above ... */
else if (!isempty(static_hn))
hn = static_hn;
/* ... and the ultimate fallback */ /* ... and the ultimate fallback */
} else { else
hn = FALLBACK_HOSTNAME; hn = FALLBACK_HOSTNAME;
hns = HOSTNAME_FALLBACK;
}
r = sethostname_idempotent(hn); if (sethostname_idempotent(hn) < 0)
if (r < 0) return -errno;
return log_error_errno(r, "Failed to set hostname: %m");
if (c->hostname_source != hns) {
c->hostname_source = hns;
r = 1;
}
(void) nscd_flush_cache(STRV_MAKE("hosts")); (void) nscd_flush_cache(STRV_MAKE("hosts"));
if (r == 0) return 0;
log_debug("Hostname was already set to <%s>.", hn);
else {
log_info("Hostname set to <%s> (%s)", hn, hostname_source_to_string(hns));
hostname_update_source_hint(hn, hns);
}
return r; /* 0 if no change, 1 if something was done */
} }
static int context_write_data_static_hostname(Context *c) { static int context_write_data_static_hostname(Context *c) {
assert(c); assert(c);
if (isempty(c->data[PROP_STATIC_HOSTNAME])) { if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
if (unlink("/etc/hostname") < 0) if (unlink("/etc/hostname") < 0)
return errno == ENOENT ? 0 : -errno; return errno == ENOENT ? 0 : -errno;
return 0; return 0;
} }
return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]); return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
} }
@ -386,7 +383,7 @@ static int context_write_data_machine_info(Context *c) {
}; };
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
int r; int r, p;
assert(c); assert(c);
@ -394,7 +391,7 @@ static int context_write_data_machine_info(Context *c) {
if (r < 0 && r != -ENOENT) if (r < 0 && r != -ENOENT)
return r; return r;
for (int p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) { for (p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
_cleanup_free_ char *t = NULL; _cleanup_free_ char *t = NULL;
char **u; char **u;
@ -464,52 +461,6 @@ static int property_get_static_hostname(
return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]); return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]);
} }
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_fallback_hostname, "s", FALLBACK_HOSTNAME);
static int property_get_hostname_source(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Context *c = userdata;
int r;
assert(c);
context_read_etc_hostname(c);
if (c->hostname_source < 0) {
char hostname[HOST_NAME_MAX + 1] = {};
_cleanup_free_ char *fallback = NULL;
(void) get_hostname_filtered(hostname);
if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME]))
c->hostname_source = HOSTNAME_STATIC;
else {
/* If the hostname was not set by us, try to figure out where it came from. If we set
* it to the fallback hostname, the file will tell us. We compare the string because
* it is possible that the hostname was set by an older version that had a different
* fallback, in the initramfs or before we reexecuted. */
r = read_one_line_file("/run/systemd/fallback-hostname", &fallback);
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read /run/systemd/fallback-hostname, ignoring: %m");
if (streq_ptr(fallback, hostname))
c->hostname_source = HOSTNAME_FALLBACK;
else
c->hostname_source = HOSTNAME_TRANSIENT;
}
}
return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source));
}
static int property_get_machine_info_field( static int property_get_machine_info_field(
sd_bus *bus, sd_bus *bus,
const char *path, const char *path,
@ -628,6 +579,7 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
Context *c = userdata; Context *c = userdata;
const char *name; const char *name;
int interactive, r; int interactive, r;
struct utsname u;
assert(m); assert(m);
assert(c); assert(c);
@ -636,15 +588,20 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
if (r < 0) if (r < 0)
return r; return r;
name = empty_to_null(name); context_read_etc_hostname(c);
/* We always go through with the procedure below without comparing to the current hostname, because if (isempty(name))
* we might want to adjust hostname source information even if the actual hostname is unchanged. */ name = c->data[PROP_STATIC_HOSTNAME];
if (isempty(name))
name = FALLBACK_HOSTNAME;
if (!hostname_is_valid(name, 0)) if (!hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name); return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
context_read_etc_hostname(c); assert_se(uname(&u) >= 0);
if (streq_ptr(name, u.nodename))
return sd_bus_reply_method_return(m, NULL);
r = bus_verify_polkit_async( r = bus_verify_polkit_async(
m, m,
@ -661,12 +618,14 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = context_update_kernel_hostname(c, name); r = context_update_kernel_hostname(c, name);
if (r < 0) if (r < 0) {
log_error_errno(r, "Failed to set hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
else if (r > 0) }
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
"/org/freedesktop/hostname1", "org.freedesktop.hostname1", log_info("Changed hostname to '%s'", name);
"Hostname", "HostnameSource", NULL);
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
return sd_bus_reply_method_return(m, NULL); return sd_bus_reply_method_return(m, NULL);
} }
@ -691,7 +650,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME])) if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
return sd_bus_reply_method_return(m, NULL); return sd_bus_reply_method_return(m, NULL);
if (name && !hostname_is_valid(name, 0)) if (!isempty(name) && !hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name); return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
r = bus_verify_polkit_async( r = bus_verify_polkit_async(
@ -712,21 +671,21 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
if (r < 0) if (r < 0)
return r; return r;
r = context_write_data_static_hostname(c);
if (r < 0) {
log_error_errno(r, "Failed to write static hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
}
r = context_update_kernel_hostname(c, NULL); r = context_update_kernel_hostname(c, NULL);
if (r < 0) { if (r < 0) {
log_error_errno(r, "Failed to set hostname: %m"); log_error_errno(r, "Failed to set hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
} }
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), r = context_write_data_static_hostname(c);
"/org/freedesktop/hostname1", "org.freedesktop.hostname1", if (r < 0) {
"StaticHostname", "Hostname", "HostnameSource", NULL); log_error_errno(r, "Failed to write static hostname: %m");
return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
}
log_info("Changed static hostname to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
(void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
return sd_bus_reply_method_return(m, NULL); return sd_bus_reply_method_return(m, NULL);
} }
@ -891,8 +850,6 @@ static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("FallbackHostname", "s", property_get_fallback_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@ -1003,9 +960,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **ret) {
} }
static int run(int argc, char *argv[]) { static int run(int argc, char *argv[]) {
_cleanup_(context_destroy) Context context = { _cleanup_(context_destroy) Context context = {};
.hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
};
_cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r; int r;

View File

@ -1521,44 +1521,6 @@ int journal_file_find_data_object(
ret, ret_offset); ret, ret_offset);
} }
bool journal_field_valid(const char *p, size_t l, bool allow_protected) {
const char *a;
/* We kinda enforce POSIX syntax recommendations for
environment variables here, but make a couple of additional
requirements.
http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
if (l == (size_t) -1)
l = strlen(p);
/* No empty field names */
if (l <= 0)
return false;
/* Don't allow names longer than 64 chars */
if (l > 64)
return false;
/* Variables starting with an underscore are protected */
if (!allow_protected && p[0] == '_')
return false;
/* Don't allow digits as first character */
if (p[0] >= '0' && p[0] <= '9')
return false;
/* Only allow A-Z0-9 and '_' */
for (a = p; a < p + l; a++)
if ((*a < 'A' || *a > 'Z') &&
(*a < '0' || *a > '9') &&
*a != '_')
return false;
return true;
}
static int journal_file_append_field( static int journal_file_append_field(
JournalFile *f, JournalFile *f,
const void *field, uint64_t size, const void *field, uint64_t size,
@ -1572,9 +1534,6 @@ static int journal_file_append_field(
assert(f); assert(f);
assert(field && size > 0); assert(field && size > 0);
if (!journal_field_valid(field, size, true))
return -EBADMSG;
hash = journal_file_hash_data(f, field, size); hash = journal_file_hash_data(f, field, size);
r = journal_file_find_field_object_with_hash(f, field, size, hash, &o, &p); r = journal_file_find_field_object_with_hash(f, field, size, hash, &o, &p);
@ -3752,7 +3711,7 @@ int journal_file_dispose(int dir_fd, const char *fname) {
assert(fname); assert(fname);
/* Renames a journal file to *.journal~, i.e. to mark it as corrupted or otherwise uncleanly shutdown. Note that /* Renames a journal file to *.journal~, i.e. to mark it as corruped or otherwise uncleanly shutdown. Note that
* this is done without looking into the file or changing any of its contents. The idea is that this is called * this is done without looking into the file or changing any of its contents. The idea is that this is called
* whenever something is suspicious and we want to move the file away and make clear that it is not accessed * whenever something is suspicious and we want to move the file away and make clear that it is not accessed
* for writing anymore. */ * for writing anymore. */

View File

@ -271,5 +271,3 @@ static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) {
} }
uint64_t journal_file_hash_data(JournalFile *f, const void *data, size_t sz); uint64_t journal_file_hash_data(JournalFile *f, const void *data, size_t sz);
bool journal_field_valid(const char *p, size_t l, bool allow_protected);

View File

@ -41,9 +41,7 @@ static void draw_progress(uint64_t p, usec_t *last_usec) {
fputs("\r", stdout); fputs("\r", stdout);
if (colors_enabled()) if (colors_enabled())
fputs("\x1B[?25l", stdout); fputs("\x1B[?25l" ANSI_HIGHLIGHT_GREEN, stdout);
fputs(ansi_highlight_green(), stdout);
for (i = 0; i < j; i++) for (i = 0; i < j; i++)
fputs("\xe2\x96\x88", stdout); fputs("\xe2\x96\x88", stdout);

View File

@ -759,7 +759,7 @@ static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) {
* Note that while the default T1/T2 initial times do have random 'fuzz' applied, * Note that while the default T1/T2 initial times do have random 'fuzz' applied,
* the RFC sec 4.4.5 does not mention adding any fuzz to retries. */ * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */
static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) { static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) {
return now + MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC); return MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC);
} }
static int cmp_uint8(const uint8_t *a, const uint8_t *b) { static int cmp_uint8(const uint8_t *a, const uint8_t *b) {

View File

@ -81,7 +81,6 @@ libsystemd_sources = files('''
sd-netlink/netlink-types.h sd-netlink/netlink-types.h
sd-netlink/netlink-util.c sd-netlink/netlink-util.c
sd-netlink/netlink-util.h sd-netlink/netlink-util.h
sd-netlink/nfnl-message.c
sd-netlink/rtnl-message.c sd-netlink/rtnl-message.c
sd-netlink/sd-netlink.c sd-netlink/sd-netlink.c
sd-network/network-util.c sd-network/network-util.c

View File

@ -112,74 +112,68 @@ static void test_login(void) {
if (session) { if (session) {
r = sd_session_is_active(session); r = sd_session_is_active(session);
if (r == -ENXIO) assert_se(r >= 0);
log_notice("sd_session_is_active() failed with ENXIO, it seems logind is not running."); log_info("sd_session_is_active(\"%s\") → %s", session, yes_no(r));
else {
/* All those tests will fail with ENXIO, so let's skip them. */
assert_se(r >= 0); r = sd_session_is_remote(session);
log_info("sd_session_is_active(\"%s\") → %s", session, yes_no(r)); assert_se(r >= 0);
log_info("sd_session_is_remote(\"%s\") → %s", session, yes_no(r));
r = sd_session_is_remote(session); r = sd_session_get_state(session, &state);
assert_se(r >= 0); assert_se(r == 0);
log_info("sd_session_is_remote(\"%s\") → %s", session, yes_no(r)); log_info("sd_session_get_state(\"%s\") → \"%s\"", session, state);
r = sd_session_get_state(session, &state); assert_se(sd_session_get_uid(session, &u) >= 0);
assert_se(r == 0); log_info("sd_session_get_uid(\"%s\") → "UID_FMT, session, u);
log_info("sd_session_get_state(\"%s\") → \"%s\"", session, state); assert_se(u == u2);
assert_se(sd_session_get_uid(session, &u) >= 0); assert_se(sd_session_get_type(session, &type) >= 0);
log_info("sd_session_get_uid(\"%s\") → "UID_FMT, session, u); log_info("sd_session_get_type(\"%s\") → \"%s\"", session, type);
assert_se(u == u2);
assert_se(sd_session_get_type(session, &type) >= 0); assert_se(sd_session_get_class(session, &class) >= 0);
log_info("sd_session_get_type(\"%s\") → \"%s\"", session, type); log_info("sd_session_get_class(\"%s\") → \"%s\"", session, class);
assert_se(sd_session_get_class(session, &class) >= 0); r = sd_session_get_display(session, &display);
log_info("sd_session_get_class(\"%s\") → \"%s\"", session, class); assert_se(IN_SET(r, 0, -ENODATA));
log_info("sd_session_get_display(\"%s\") → \"%s\"", session, strna(display));
r = sd_session_get_display(session, &display); r = sd_session_get_remote_user(session, &remote_user);
assert_se(IN_SET(r, 0, -ENODATA)); assert_se(IN_SET(r, 0, -ENODATA));
log_info("sd_session_get_display(\"%s\") → \"%s\"", session, strna(display)); log_info("sd_session_get_remote_user(\"%s\") → \"%s\"",
session, strna(remote_user));
r = sd_session_get_remote_user(session, &remote_user); r = sd_session_get_remote_host(session, &remote_host);
assert_se(IN_SET(r, 0, -ENODATA)); assert_se(IN_SET(r, 0, -ENODATA));
log_info("sd_session_get_remote_user(\"%s\") → \"%s\"", log_info("sd_session_get_remote_host(\"%s\") → \"%s\"",
session, strna(remote_user)); session, strna(remote_host));
r = sd_session_get_remote_host(session, &remote_host); r = sd_session_get_seat(session, &seat);
assert_se(IN_SET(r, 0, -ENODATA)); if (r >= 0) {
log_info("sd_session_get_remote_host(\"%s\") → \"%s\"", assert_se(seat);
session, strna(remote_host));
r = sd_session_get_seat(session, &seat); log_info("sd_session_get_seat(\"%s\") → \"%s\"", session, seat);
if (r >= 0) {
assert_se(seat);
log_info("sd_session_get_seat(\"%s\") → \"%s\"", session, seat);
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
r = sd_seat_can_multi_session(seat); r = sd_seat_can_multi_session(seat);
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
assert_se(r == 1); assert_se(r == 1);
log_info("sd_session_can_multi_seat(\"%s\") → %s", seat, yes_no(r)); log_info("sd_session_can_multi_seat(\"%s\") → %s", seat, yes_no(r));
r = sd_seat_can_tty(seat); r = sd_seat_can_tty(seat);
assert_se(r >= 0); assert_se(r >= 0);
log_info("sd_session_can_tty(\"%s\") → %s", seat, yes_no(r)); log_info("sd_session_can_tty(\"%s\") → %s", seat, yes_no(r));
r = sd_seat_can_graphical(seat); r = sd_seat_can_graphical(seat);
assert_se(r >= 0); assert_se(r >= 0);
log_info("sd_session_can_graphical(\"%s\") → %s", seat, yes_no(r)); log_info("sd_session_can_graphical(\"%s\") → %s", seat, yes_no(r));
} else { } else {
log_info_errno(r, "sd_session_get_seat(\"%s\"): %m", session); log_info_errno(r, "sd_session_get_seat(\"%s\"): %m", session);
assert_se(r == -ENODATA); assert_se(r == -ENODATA);
}
assert_se(sd_uid_get_state(u, &state2) == 0);
log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
} }
assert_se(sd_uid_get_state(u, &state2) == 0);
log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
} }
if (seat) { if (seat) {
@ -220,7 +214,7 @@ static void test_login(void) {
assert_se(sd_get_seats(NULL) == r); assert_se(sd_get_seats(NULL) == r);
r = sd_seat_get_active(NULL, &t, NULL); r = sd_seat_get_active(NULL, &t, NULL);
assert_se(IN_SET(r, 0, -ENODATA, -ENXIO)); assert_se(IN_SET(r, 0, -ENODATA));
log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s / \"%s\"", e(r), strnull(t)); log_info("sd_seat_get_active(NULL, …) (active session on current seat) → %s / \"%s\"", e(r), strnull(t));
free(t); free(t);

View File

@ -139,7 +139,6 @@ int socket_bind(sd_netlink *nl);
int socket_broadcast_group_ref(sd_netlink *nl, unsigned group); int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
int socket_broadcast_group_unref(sd_netlink *nl, unsigned group); int socket_broadcast_group_unref(sd_netlink *nl, unsigned group);
int socket_write_message(sd_netlink *nl, sd_netlink_message *m); int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
int socket_writev_message(sd_netlink *nl, sd_netlink_message *m[], size_t msgcount);
int socket_read_message(sd_netlink *nl); int socket_read_message(sd_netlink *nl);
int rtnl_rqueue_make_room(sd_netlink *rtnl); int rtnl_rqueue_make_room(sd_netlink *rtnl);

View File

@ -238,31 +238,6 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
return k; return k;
} }
int socket_writev_message(sd_netlink *nl, sd_netlink_message *m[], size_t msgcount) {
_cleanup_free_ struct iovec *iovs = NULL;
ssize_t k;
size_t i;
assert(nl);
assert(msgcount);
iovs = new0(struct iovec, msgcount);
if (!iovs)
return -ENOMEM;
for (i = 0; i < msgcount; i++) {
assert(m[i]->hdr != NULL);
assert(m[i]->hdr->nlmsg_len > 0);
iovs[i] = IOVEC_MAKE(m[i]->hdr, m[i]->hdr->nlmsg_len);
}
k = writev(nl->fd, iovs, msgcount);
if (k < 0)
return -errno;
return k;
}
static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) { static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) {
union sockaddr_union sender; union sockaddr_union sender;
CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo))) control; CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo))) control;

View File

@ -19,8 +19,6 @@
#include <linux/if_macsec.h> #include <linux/if_macsec.h>
#include <linux/if_tunnel.h> #include <linux/if_tunnel.h>
#include <linux/l2tp.h> #include <linux/l2tp.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/nexthop.h> #include <linux/nexthop.h>
#include <linux/nl80211.h> #include <linux/nl80211.h>
#include <linux/pkt_sched.h> #include <linux/pkt_sched.h>
@ -1314,243 +1312,6 @@ static const NLType genl_families[] = {
[SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_cmds_type_system }, [SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_cmds_type_system },
}; };
static const NLType nfnl_nft_table_types[] = {
[NFTA_TABLE_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_TABLE_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystem nfnl_nft_table_type_system = {
.count = ELEMENTSOF(nfnl_nft_table_types),
.types = nfnl_nft_table_types,
};
static const NLType nfnl_nft_chain_hook_types[] = {
[NFTA_HOOK_HOOKNUM] = { .type = NETLINK_TYPE_U32 },
[NFTA_HOOK_PRIORITY] = { .type = NETLINK_TYPE_U32 },
[NFTA_HOOK_DEV] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 },
};
static const NLTypeSystem nfnl_nft_chain_hook_type_system = {
.count = ELEMENTSOF(nfnl_nft_chain_hook_types),
.types = nfnl_nft_chain_hook_types,
};
static const NLType nfnl_nft_chain_types[] = {
[NFTA_CHAIN_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_CHAIN_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_CHAIN_HOOK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_hook_type_system },
[NFTA_CHAIN_TYPE] = { .type = NETLINK_TYPE_STRING, .size = 16 },
[NFTA_CHAIN_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystem nfnl_nft_chain_type_system = {
.count = ELEMENTSOF(nfnl_nft_chain_types),
.types = nfnl_nft_chain_types,
};
static const NLType nfnl_nft_expr_meta_types[] = {
[NFTA_META_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_META_KEY] = { .type = NETLINK_TYPE_U32 },
[NFTA_META_SREG] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_expr_payload_types[] = {
[NFTA_PAYLOAD_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_PAYLOAD_BASE] = { .type = NETLINK_TYPE_U32 },
[NFTA_PAYLOAD_OFFSET] = { .type = NETLINK_TYPE_U32 },
[NFTA_PAYLOAD_LEN] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_expr_nat_types[] = {
[NFTA_NAT_TYPE] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_FAMILY] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_REG_ADDR_MIN] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_REG_ADDR_MAX] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 },
[NFTA_NAT_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_data_types[] = {
[NFTA_DATA_VALUE] = { .type = NETLINK_TYPE_BINARY },
};
static const NLTypeSystem nfnl_nft_data_type_system = {
.count = ELEMENTSOF(nfnl_nft_data_types),
.types = nfnl_nft_data_types,
};
static const NLType nfnl_nft_expr_bitwise_types[] = {
[NFTA_BITWISE_SREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_BITWISE_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_BITWISE_LEN] = { .type = NETLINK_TYPE_U32 },
[NFTA_BITWISE_MASK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
[NFTA_BITWISE_XOR] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
};
static const NLType nfnl_nft_expr_cmp_types[] = {
[NFTA_CMP_SREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_CMP_OP] = { .type = NETLINK_TYPE_U32 },
[NFTA_CMP_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
};
static const NLType nfnl_nft_expr_fib_types[] = {
[NFTA_FIB_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_FIB_RESULT] = { .type = NETLINK_TYPE_U32 },
[NFTA_FIB_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_expr_lookup_types[] = {
[NFTA_LOOKUP_SET] = { .type = NETLINK_TYPE_STRING },
[NFTA_LOOKUP_SREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_LOOKUP_DREG] = { .type = NETLINK_TYPE_U32 },
[NFTA_LOOKUP_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLType nfnl_nft_expr_masq_types[] = {
[NFTA_MASQ_FLAGS] = { .type = NETLINK_TYPE_U32 },
[NFTA_MASQ_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 },
[NFTA_MASQ_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystem nfnl_expr_data_type_systems[] = {
[NL_UNION_NFT_EXPR_DATA_BITWISE] = { .count = ELEMENTSOF(nfnl_nft_expr_bitwise_types),
.types = nfnl_nft_expr_bitwise_types },
[NL_UNION_NFT_EXPR_DATA_CMP] = { .count = ELEMENTSOF(nfnl_nft_expr_cmp_types),
.types = nfnl_nft_expr_cmp_types },
[NL_UNION_NFT_EXPR_DATA_FIB] = { .count = ELEMENTSOF(nfnl_nft_expr_fib_types),
.types = nfnl_nft_expr_fib_types },
[NL_UNION_NFT_EXPR_DATA_LOOKUP] = { .count = ELEMENTSOF(nfnl_nft_expr_lookup_types),
.types = nfnl_nft_expr_lookup_types },
[NL_UNION_NFT_EXPR_DATA_MASQ] = { .count = ELEMENTSOF(nfnl_nft_expr_masq_types),
.types = nfnl_nft_expr_masq_types },
[NL_UNION_NFT_EXPR_DATA_META] = { .count = ELEMENTSOF(nfnl_nft_expr_meta_types),
.types = nfnl_nft_expr_meta_types },
[NL_UNION_NFT_EXPR_DATA_NAT] = { .count = ELEMENTSOF(nfnl_nft_expr_nat_types),
.types = nfnl_nft_expr_nat_types },
[NL_UNION_NFT_EXPR_DATA_PAYLOAD] = { .count = ELEMENTSOF(nfnl_nft_expr_payload_types),
.types = nfnl_nft_expr_payload_types },
};
static const char* const nl_union_nft_expr_data_table[] = {
[NL_UNION_NFT_EXPR_DATA_BITWISE] = "bitwise",
[NL_UNION_NFT_EXPR_DATA_CMP] = "cmp",
[NL_UNION_NFT_EXPR_DATA_LOOKUP] = "lookup",
[NL_UNION_NFT_EXPR_DATA_META] = "meta",
[NL_UNION_NFT_EXPR_DATA_FIB] = "fib",
[NL_UNION_NFT_EXPR_DATA_MASQ] = "masq",
[NL_UNION_NFT_EXPR_DATA_NAT] = "nat",
[NL_UNION_NFT_EXPR_DATA_PAYLOAD] = "payload",
};
DEFINE_STRING_TABLE_LOOKUP(nl_union_nft_expr_data, NLUnionNFTExprData);
static const NLTypeSystemUnion nfnl_nft_data_expr_type_system_union = {
.num = _NL_UNION_NFT_EXPR_DATA_MAX,
.lookup = nl_union_nft_expr_data_from_string,
.type_systems = nfnl_expr_data_type_systems,
.match_type = NL_MATCH_SIBLING,
.match = NFTA_EXPR_NAME,
};
static const NLType nfnl_nft_rule_expr_types[] = {
[NFTA_EXPR_NAME] = { .type = NETLINK_TYPE_STRING, .size = 16 },
[NFTA_EXPR_DATA] = { .type = NETLINK_TYPE_UNION,
.type_system_union = &nfnl_nft_data_expr_type_system_union },
};
static const NLTypeSystem nfnl_nft_rule_expr_type_system = {
.count = ELEMENTSOF(nfnl_nft_rule_expr_types),
.types = nfnl_nft_rule_expr_types,
};
static const NLType nfnl_nft_rule_types[] = {
[NFTA_RULE_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_RULE_CHAIN] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_RULE_EXPRESSIONS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_expr_type_system }
};
static const NLTypeSystem nfnl_nft_rule_type_system = {
.count = ELEMENTSOF(nfnl_nft_rule_types),
.types = nfnl_nft_rule_types,
};
static const NLType nfnl_nft_set_types[] = {
[NFTA_SET_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_FLAGS] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_KEY_TYPE] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_KEY_LEN] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_DATA_TYPE] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_DATA_LEN] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_POLICY] = { .type = NETLINK_TYPE_U32 },
[NFTA_SET_ID] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystem nfnl_nft_set_type_system = {
.count = ELEMENTSOF(nfnl_nft_set_types),
.types = nfnl_nft_set_types,
};
static const NLType nfnl_nft_setelem_types[] = {
[NFTA_SET_ELEM_KEY] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
[NFTA_SET_ELEM_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system },
[NFTA_SET_ELEM_FLAGS] = { .type = NETLINK_TYPE_U32 },
};
static const NLTypeSystem nfnl_nft_setelem_type_system = {
.count = ELEMENTSOF(nfnl_nft_setelem_types),
.types = nfnl_nft_setelem_types,
};
static const NLType nfnl_nft_setelem_list_types[] = {
[NFTA_SET_ELEM_LIST_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_ELEM_LIST_SET] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_type_system },
};
static const NLTypeSystem nfnl_nft_setelem_list_type_system = {
.count = ELEMENTSOF(nfnl_nft_setelem_list_types),
.types = nfnl_nft_setelem_list_types,
};
static const NLType nfnl_nft_msg_types [] = {
[NFT_MSG_DELTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWCHAIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWSET] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_set_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_NEWSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) },
[NFT_MSG_DELSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) },
};
static const NLTypeSystem nfnl_nft_msg_type_system = {
.count = ELEMENTSOF(nfnl_nft_msg_types),
.types = nfnl_nft_msg_types,
};
static const NLType nfnl_msg_batch_types [] = {
[NFNL_BATCH_GENID] = { .type = NETLINK_TYPE_U32 }
};
static const NLTypeSystem nfnl_msg_batch_type_system = {
.count = ELEMENTSOF(nfnl_msg_batch_types),
.types = nfnl_msg_batch_types,
};
static const NLType nfnl_types[] = {
[NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 },
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) },
[NFNL_MSG_BATCH_BEGIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) },
[NFNL_MSG_BATCH_END] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) },
[NFNL_SUBSYS_NFTABLES] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_msg_type_system, .size = sizeof(struct nfgenmsg) },
};
const NLTypeSystem nfnl_type_system_root = {
.count = ELEMENTSOF(nfnl_types),
.types = nfnl_types,
};
/* Mainly used when sending message */ /* Mainly used when sending message */
const NLTypeSystem genl_family_type_system_root = { const NLTypeSystem genl_family_type_system_root = {
.count = ELEMENTSOF(genl_families), .count = ELEMENTSOF(genl_families),
@ -1607,8 +1368,6 @@ const NLTypeSystem *type_system_get_root(int protocol) {
switch (protocol) { switch (protocol) {
case NETLINK_GENERIC: case NETLINK_GENERIC:
return &genl_type_system_root; return &genl_type_system_root;
case NETLINK_NETFILTER:
return &nfnl_type_system_root;
default: /* NETLINK_ROUTE: */ default: /* NETLINK_ROUTE: */
return &rtnl_type_system_root; return &rtnl_type_system_root;
} }
@ -1619,12 +1378,9 @@ int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type)
const NLType *nl_type; const NLType *nl_type;
int r; int r;
if (!nl) if (!nl || nl->protocol != NETLINK_GENERIC)
return type_system_get_type(&rtnl_type_system_root, ret, type); return type_system_get_type(&rtnl_type_system_root, ret, type);
if (nl->protocol != NETLINK_GENERIC)
return type_system_get_type(type_system_get_root(nl->protocol), ret, type);
r = nlmsg_type_to_genl_family(nl, type, &family); r = nlmsg_type_to_genl_family(nl, type, &family);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -21,7 +21,6 @@ enum {
NETLINK_TYPE_NESTED, /* NLA_NESTED */ NETLINK_TYPE_NESTED, /* NLA_NESTED */
NETLINK_TYPE_UNION, NETLINK_TYPE_UNION,
NETLINK_TYPE_SOCKADDR, NETLINK_TYPE_SOCKADDR,
NETLINK_TYPE_BINARY,
}; };
typedef enum NLMatchType { typedef enum NLMatchType {
@ -118,19 +117,3 @@ typedef enum NLUnionTCAOptionData {
const char *nl_union_tca_option_data_to_string(NLUnionTCAOptionData p) _const_; const char *nl_union_tca_option_data_to_string(NLUnionTCAOptionData p) _const_;
NLUnionTCAOptionData nl_union_tca_option_data_from_string(const char *p) _pure_; NLUnionTCAOptionData nl_union_tca_option_data_from_string(const char *p) _pure_;
typedef enum NLUnionNFTExprData {
NL_UNION_NFT_EXPR_DATA_BITWISE,
NL_UNION_NFT_EXPR_DATA_CMP,
NL_UNION_NFT_EXPR_DATA_FIB,
NL_UNION_NFT_EXPR_DATA_LOOKUP,
NL_UNION_NFT_EXPR_DATA_PAYLOAD,
NL_UNION_NFT_EXPR_DATA_MASQ,
NL_UNION_NFT_EXPR_DATA_META,
NL_UNION_NFT_EXPR_DATA_NAT,
_NL_UNION_NFT_EXPR_DATA_MAX,
_NL_UNION_NFT_EXPR_DATA_INVALID = -1,
} NLUnionNFTExprData;
const char *nl_union_nft_expr_data_to_string(NLUnionNFTExprData p) _const_;
NLUnionNFTExprData nl_union_nft_expr_data_from_string(const char *p) _pure_;

View File

@ -1,318 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <netinet/in.h>
#include <linux/if_addrlabel.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/nexthop.h>
#include <stdbool.h>
#include <unistd.h>
#include "sd-netlink.h"
#include "format-util.h"
#include "netlink-internal.h"
#include "netlink-types.h"
#include "netlink-util.h"
#include "socket-util.h"
#include "util.h"
static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t type, uint16_t flags) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
struct nfgenmsg *nfh;
const NLType *nl_type;
size_t size;
int r;
assert_return(nfnl, -EINVAL);
r = type_system_root_get_type(nfnl, &nl_type, NFNL_SUBSYS_NFTABLES);
if (r < 0)
return r;
if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
return -EINVAL;
r = message_new_empty(nfnl, &m);
if (r < 0)
return r;
size = NLMSG_SPACE(type_get_size(nl_type));
assert(size >= sizeof(struct nlmsghdr));
m->hdr = malloc0(size);
if (!m->hdr)
return -ENOMEM;
m->hdr->nlmsg_flags = NLM_F_REQUEST | flags;
type_get_type_system(nl_type, &m->containers[0].type_system);
r = type_system_get_type_system(m->containers[0].type_system,
&m->containers[0].type_system,
type);
if (r < 0)
return r;
m->hdr->nlmsg_len = size;
m->hdr->nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | type;
nfh = NLMSG_DATA(m->hdr);
nfh->nfgen_family = family;
nfh->version = NFNETLINK_V0;
nfh->res_id = nfnl->serial;
*ret = TAKE_PTR(m);
return 0;
}
static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int v) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
struct nfgenmsg *nfh;
int r;
r = message_new(nfnl, &m, v);
if (r < 0)
return r;
nfh = NLMSG_DATA(m->hdr);
nfh->nfgen_family = AF_UNSPEC;
nfh->version = NFNETLINK_V0;
nfh->res_id = NFNL_SUBSYS_NFTABLES;
*ret = TAKE_PTR(m);
return r;
}
int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret) {
return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN);
}
int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) {
return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END);
}
int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret,
int family,
const char *table, const char *chain,
const char *type,
uint8_t hook, int prio) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE | NLM_F_ACK);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_CHAIN_TABLE, table);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_CHAIN_NAME, chain);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_CHAIN_TYPE, type);
if (r < 0)
return r;
r = sd_netlink_message_open_container(m, NFTA_CHAIN_HOOK);
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_HOOK_HOOKNUM, htobe32(hook));
if (r < 0)
goto cancel;
r = sd_netlink_message_append_u32(m, NFTA_HOOK_PRIORITY, htobe32(prio));
if (r < 0)
goto cancel;
r = sd_netlink_message_close_container(m);
if (r < 0)
goto cancel;
*ret = TAKE_PTR(m);
return 0;
cancel:
sd_netlink_message_cancel_array(m);
return r;
}
int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE | NLM_F_ACK);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return r;
}
int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, uint16_t flags) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | flags);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return r;
}
int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *chain) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE | NLM_F_ACK);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_RULE_TABLE, table);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_RULE_CHAIN, chain);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return r;
}
int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *set_name,
uint32_t set_id, uint32_t klen) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE | NLM_F_ACK);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_SET_TABLE, table);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_SET_NAME, set_name);
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_SET_ID, ++set_id);
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_LEN, htobe32(klen));
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return r;
}
int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *set_name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE | NLM_F_ACK);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name);
if (r < 0)
return r;
r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return r;
}
int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *set_name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, NLM_F_ACK);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name);
if (r < 0)
return r;
r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return r;
}
static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint32_t dlen) {
int r = sd_netlink_message_open_container(m, attr);
if (r < 0)
return r;
r = sd_netlink_message_append_data(m, NFTA_DATA_VALUE, data, dlen);
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* attr */
}
int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m,
uint32_t num,
const void *key, uint32_t klen,
const void *data, uint32_t dlen) {
int r;
r = sd_netlink_message_open_array(m, num);
if (r < 0)
return r;
r = sd_nfnl_add_data(m, NFTA_SET_ELEM_KEY, key, klen);
if (r < 0)
goto cancel;
if (data) {
r = sd_nfnl_add_data(m, NFTA_SET_ELEM_DATA, data, dlen);
if (r < 0)
goto cancel;
}
return r;
cancel:
sd_netlink_message_cancel_array(m);
return r;
}
int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m) {
return sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */
}
int sd_nfnl_socket_open(sd_netlink **ret) {
return netlink_open_family(ret, NETLINK_NETFILTER);
}

View File

@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h> #include <netinet/in.h>
#include <linux/fib_rules.h>
#include <linux/if_addrlabel.h> #include <linux/if_addrlabel.h>
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include <linux/nexthop.h> #include <linux/nexthop.h>
@ -198,7 +197,7 @@ int sd_rtnl_message_route_get_scope(const sd_netlink_message *m, unsigned char *
return 0; return 0;
} }
int sd_rtnl_message_route_get_tos(const sd_netlink_message *m, uint8_t *tos) { int sd_rtnl_message_route_get_tos(const sd_netlink_message *m, unsigned char *tos) {
struct rtmsg *rtm; struct rtmsg *rtm;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
@ -849,7 +848,7 @@ int sd_rtnl_message_addrlabel_get_prefixlen(const sd_netlink_message *m, unsigne
} }
int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family) { int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family) {
struct fib_rule_hdr *frh; struct rtmsg *rtm;
int r; int r;
assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL);
@ -862,175 +861,177 @@ int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message
if (nlmsg_type == RTM_NEWRULE) if (nlmsg_type == RTM_NEWRULE)
(*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
frh = NLMSG_DATA((*ret)->hdr); rtm = NLMSG_DATA((*ret)->hdr);
frh->family = ifal_family; rtm->rtm_family = ifal_family;
frh->action = FR_ACT_TO_TBL; rtm->rtm_protocol = RTPROT_BOOT;
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
rtm->rtm_type = RTN_UNICAST;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, uint8_t tos) { int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, unsigned char tos) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
frh->tos = tos; routing_policy_rule->rtm_tos = tos;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, uint8_t *tos) { int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, unsigned char *tos) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
*tos = frh->tos; *tos = routing_policy_rule->rtm_tos;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, uint8_t table) { int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, unsigned char table) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
frh->table = table; routing_policy_rule->rtm_table = table;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, uint8_t *table) { int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, unsigned char *table) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
*table = frh->table; *table = routing_policy_rule->rtm_table;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, uint32_t flags) { int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, unsigned flags) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
frh->flags |= flags; routing_policy_rule->rtm_flags |= flags;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, uint32_t *flags) { int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, unsigned *flags) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
*flags = frh->flags; *flags = routing_policy_rule->rtm_flags;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_set_fib_type(sd_netlink_message *m, uint8_t type) { int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
frh->action = type; routing_policy_rule->rtm_type = type;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_get_fib_type(const sd_netlink_message *m, uint8_t *type) { int sd_rtnl_message_routing_policy_rule_get_rtm_type(const sd_netlink_message *m, unsigned char *type) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
*type = frh->action; *type = routing_policy_rule->rtm_type;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(sd_netlink_message *m, uint8_t len) { int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char len) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
frh->dst_len = len; routing_policy_rule->rtm_dst_len = len;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(const sd_netlink_message *m, uint8_t *len) { int sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(const sd_netlink_message *m, unsigned char *len) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
*len = frh->dst_len; *len = routing_policy_rule->rtm_dst_len;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(sd_netlink_message *m, uint8_t len) { int sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(sd_netlink_message *m, unsigned char len) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
frh->src_len = len; routing_policy_rule->rtm_src_len = len;
return 0; return 0;
} }
int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(const sd_netlink_message *m, uint8_t *len) { int sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(const sd_netlink_message *m, unsigned char *len) {
struct fib_rule_hdr *frh; struct rtmsg *routing_policy_rule;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL); assert_return(m->hdr, -EINVAL);
assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
frh = NLMSG_DATA(m->hdr); routing_policy_rule = NLMSG_DATA(m->hdr);
*len = frh->src_len; *len = routing_policy_rule->rtm_src_len;
return 0; return 0;
} }

View File

@ -226,41 +226,6 @@ int sd_netlink_send(sd_netlink *nl,
return 1; return 1;
} }
int sd_netlink_sendv(sd_netlink *nl,
sd_netlink_message *messages[],
size_t msgcount,
uint32_t **ret_serial) {
_cleanup_free_ uint32_t *serials = NULL;
unsigned i;
int r;
assert_return(nl, -EINVAL);
assert_return(!rtnl_pid_changed(nl), -ECHILD);
assert_return(messages, -EINVAL);
if (ret_serial) {
serials = new0(uint32_t, msgcount);
if (!serials)
return -ENOMEM;
}
for (i = 0; i < msgcount; i++) {
assert_return(!messages[i]->sealed, -EPERM);
rtnl_seal_message(nl, messages[i]);
if (serials)
serials[i] = rtnl_message_get_serial(messages[i]);
}
r = socket_writev_message(nl, messages, msgcount);
if (r < 0)
return r;
if (ret_serial)
*ret_serial = TAKE_PTR(serials);
return r;
}
int rtnl_rqueue_make_room(sd_netlink *rtnl) { int rtnl_rqueue_make_room(sd_netlink *rtnl) {
assert(rtnl); assert(rtnl);
@ -621,15 +586,21 @@ int sd_netlink_call_async(
return k; return k;
} }
int sd_netlink_read(sd_netlink *rtnl, int sd_netlink_call(sd_netlink *rtnl,
uint32_t serial, sd_netlink_message *message,
uint64_t usec, uint64_t usec,
sd_netlink_message **ret) { sd_netlink_message **ret) {
usec_t timeout; usec_t timeout;
uint32_t serial;
int r; int r;
assert_return(rtnl, -EINVAL); assert_return(rtnl, -EINVAL);
assert_return(!rtnl_pid_changed(rtnl), -ECHILD); assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
assert_return(message, -EINVAL);
r = sd_netlink_send(rtnl, message, &serial);
if (r < 0)
return r;
timeout = calc_elapse(usec); timeout = calc_elapse(usec);
@ -699,24 +670,6 @@ int sd_netlink_read(sd_netlink *rtnl,
} }
} }
int sd_netlink_call(sd_netlink *rtnl,
sd_netlink_message *message,
uint64_t usec,
sd_netlink_message **ret) {
uint32_t serial;
int r;
assert_return(rtnl, -EINVAL);
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
assert_return(message, -EINVAL);
r = sd_netlink_send(rtnl, message, &serial);
if (r < 0)
return r;
return sd_netlink_read(rtnl, serial, usec, ret);
}
int sd_netlink_get_events(const sd_netlink *rtnl) { int sd_netlink_get_events(const sd_netlink *rtnl) {
assert_return(rtnl, -EINVAL); assert_return(rtnl, -EINVAL);
assert_return(!rtnl_pid_changed(rtnl), -ECHILD); assert_return(!rtnl_pid_changed(rtnl), -ECHILD);

View File

@ -282,7 +282,7 @@ static int address_set_masquerade(Address *address, bool add) {
if (r < 0) if (r < 0)
return r; return r;
r = fw_add_masquerade(&address->link->manager->fw_ctx, add, AF_INET, &masked, address->prefixlen); r = fw_add_masquerade(add, AF_INET, &masked, address->prefixlen);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -8,7 +8,6 @@
#include "escape.h" #include "escape.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "dhcp-client-internal.h" #include "dhcp-client-internal.h"
#include "hostname-setup.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "network-internal.h" #include "network-internal.h"

View File

@ -22,7 +22,6 @@
#include "dns-domain.h" #include "dns-domain.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "firewall-util.h"
#include "local-addresses.h" #include "local-addresses.h"
#include "netlink-util.h" #include "netlink-util.h"
#include "network-internal.h" #include "network-internal.h"
@ -913,8 +912,6 @@ void manager_free(Manager *m) {
safe_close(m->ethtool_fd); safe_close(m->ethtool_fd);
m->fw_ctx = fw_ctx_free(m->fw_ctx);
free(m); free(m);
} }

View File

@ -9,7 +9,6 @@
#include "sd-resolve.h" #include "sd-resolve.h"
#include "dhcp-identifier.h" #include "dhcp-identifier.h"
#include "firewall-util.h"
#include "hashmap.h" #include "hashmap.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-network.h" #include "networkd-network.h"
@ -75,8 +74,6 @@ struct Manager {
bool dhcp4_prefix_root_cannot_set_table:1; bool dhcp4_prefix_root_cannot_set_table:1;
bool bridge_mdb_on_master_not_supported:1; bool bridge_mdb_on_master_not_supported:1;
FirewallContext *fw_ctx;
}; };
int manager_new(Manager **ret); int manager_new(Manager **ret);

View File

@ -820,7 +820,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
_cleanup_(route_freep) Route *route = NULL; _cleanup_(route_freep) Route *route = NULL;
union in_addr_union gateway; struct in6_addr gateway;
uint32_t lifetime; uint32_t lifetime;
unsigned preference, prefixlen; unsigned preference, prefixlen;
usec_t time_now; usec_t time_now;
@ -835,20 +835,10 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
if (lifetime == 0) if (lifetime == 0)
return 0; return 0;
r = sd_ndisc_router_get_address(rt, &gateway.in6); r = sd_ndisc_router_get_address(rt, &gateway);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m"); return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m");
if (link_has_ipv6_address(link, &gateway.in6) == 0) {
_cleanup_free_ char *buf = NULL;
if (DEBUG_LOGGING) {
(void) in_addr_to_string(AF_INET6, &gateway, &buf);
log_link_debug(link, "Advertised route gateway, %s, is local to the link, ignoring route", strnull(buf));
}
return 0;
}
r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen); r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get route prefix length: %m"); return log_link_error_errno(link, r, "Failed to get route prefix length: %m");
@ -870,7 +860,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
route->priority = link->network->dhcp6_route_metric; route->priority = link->network->dhcp6_route_metric;
route->protocol = RTPROT_RA; route->protocol = RTPROT_RA;
route->pref = preference; route->pref = preference;
route->gw.in6 = gateway.in6; route->gw.in6 = gateway;
route->gw_family = AF_INET6; route->gw_family = AF_INET6;
route->dst_prefixlen = prefixlen; route->dst_prefixlen = prefixlen;
route->lifetime = time_now + lifetime * USEC_PER_SEC; route->lifetime = time_now + lifetime * USEC_PER_SEC;

View File

@ -380,7 +380,7 @@ static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_n
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m"); return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
r = sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(m, rule->from_prefixlen); r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set source prefix length: %m"); return log_link_error_errno(link, r, "Could not set source prefix length: %m");
} }
@ -390,7 +390,7 @@ static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_n
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m"); return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
r = sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(m, rule->to_prefixlen); r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set destination prefix length: %m"); return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
} }
@ -749,7 +749,7 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m"); log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
return 0; return 0;
} else if (r >= 0) { } else if (r >= 0) {
r = sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(message, &tmp->from_prefixlen); r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m"); log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
return 0; return 0;
@ -761,7 +761,7 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man
log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m"); log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
return 0; return 0;
} else if (r >= 0) { } else if (r >= 0) {
r = sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(message, &tmp->to_prefixlen); r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m"); log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
return 0; return 0;

View File

@ -9,7 +9,6 @@
#include "capability-util.h" #include "capability-util.h"
#include "daemon-util.h" #include "daemon-util.h"
#include "firewall-util.h"
#include "main-func.h" #include "main-func.h"
#include "mkdir.h" #include "mkdir.h"
#include "networkd-conf.h" #include "networkd-conf.h"
@ -93,10 +92,6 @@ static int run(int argc, char *argv[]) {
if (r < 0) if (r < 0)
return r; return r;
r = fw_ctx_new(&m->fw_ctx);
if (r < 0)
log_warning_errno(r, "Could not initialize firewall, IPMasquerade= option not available: %m");
r = manager_start(m); r = manager_start(m);
if (r < 0) if (r < 0)
return log_error_errno(r, "Could not start manager: %m"); return log_error_errno(r, "Could not start manager: %m");

View File

@ -8,7 +8,7 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "dhcp-lease-internal.h" #include "dhcp-lease-internal.h"
#include "ether-addr-util.h" #include "ether-addr-util.h"
#include "hostname-setup.h" #include "hostname-util.h"
#include "network-internal.h" #include "network-internal.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "string-util.h" #include "string-util.h"

View File

@ -82,7 +82,7 @@ void expose_port_free_all(ExposePort *p) {
} }
} }
int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, union in_addr_union *exposed) { int expose_port_flush(ExposePort* l, union in_addr_union *exposed) {
ExposePort *p; ExposePort *p;
int r, af = AF_INET; int r, af = AF_INET;
@ -97,8 +97,7 @@ int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, union in_addr_uni
log_debug("Lost IP address."); log_debug("Lost IP address.");
LIST_FOREACH(ports, p, l) { LIST_FOREACH(ports, p, l) {
r = fw_add_local_dnat(fw_ctx, r = fw_add_local_dnat(false,
false,
af, af,
p->protocol, p->protocol,
p->host_port, p->host_port,
@ -113,7 +112,7 @@ int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, union in_addr_uni
return 0; return 0;
} }
int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *l, union in_addr_union *exposed) { int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *exposed) {
_cleanup_free_ struct local_address *addresses = NULL; _cleanup_free_ struct local_address *addresses = NULL;
union in_addr_union new_exposed; union in_addr_union new_exposed;
ExposePort *p; ExposePort *p;
@ -137,7 +136,7 @@ int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *
addresses[0].scope < RT_SCOPE_LINK; addresses[0].scope < RT_SCOPE_LINK;
if (!add) if (!add)
return expose_port_flush(fw_ctx, l, exposed); return expose_port_flush(l, exposed);
new_exposed = addresses[0].address; new_exposed = addresses[0].address;
if (in_addr_equal(af, exposed, &new_exposed)) if (in_addr_equal(af, exposed, &new_exposed))
@ -151,8 +150,7 @@ int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *
LIST_FOREACH(ports, p, l) { LIST_FOREACH(ports, p, l) {
r = fw_add_local_dnat(fw_ctx, r = fw_add_local_dnat(true,
true,
af, af,
p->protocol, p->protocol,
p->host_port, p->host_port,
@ -190,7 +188,7 @@ int expose_port_watch_rtnl(
sd_event *event, sd_event *event,
int recv_fd, int recv_fd,
sd_netlink_message_handler_t handler, sd_netlink_message_handler_t handler,
void *userdata, union in_addr_union *exposed,
sd_netlink **ret) { sd_netlink **ret) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
int fd, r; int fd, r;
@ -209,11 +207,11 @@ int expose_port_watch_rtnl(
return log_error_errno(r, "Failed to create rtnl object: %m"); return log_error_errno(r, "Failed to create rtnl object: %m");
} }
r = sd_netlink_add_match(rtnl, NULL, RTM_NEWADDR, handler, NULL, userdata, "nspawn-NEWADDR"); r = sd_netlink_add_match(rtnl, NULL, RTM_NEWADDR, handler, NULL, exposed, "nspawn-NEWADDR");
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to subscribe to RTM_NEWADDR messages: %m"); return log_error_errno(r, "Failed to subscribe to RTM_NEWADDR messages: %m");
r = sd_netlink_add_match(rtnl, NULL, RTM_DELADDR, handler, NULL, userdata, "nspawn-DELADDR"); r = sd_netlink_add_match(rtnl, NULL, RTM_DELADDR, handler, NULL, exposed, "nspawn-DELADDR");
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to subscribe to RTM_DELADDR messages: %m"); return log_error_errno(r, "Failed to subscribe to RTM_DELADDR messages: %m");

View File

@ -3,8 +3,6 @@
#include <inttypes.h> #include <inttypes.h>
#include "firewall-util.h"
#include "sd-event.h" #include "sd-event.h"
#include "sd-netlink.h" #include "sd-netlink.h"
@ -21,8 +19,8 @@ typedef struct ExposePort {
void expose_port_free_all(ExposePort *p); void expose_port_free_all(ExposePort *p);
int expose_port_parse(ExposePort **l, const char *s); int expose_port_parse(ExposePort **l, const char *s);
int expose_port_watch_rtnl(sd_event *event, int recv_fd, sd_netlink_message_handler_t handler, void *userdata, sd_netlink **ret); int expose_port_watch_rtnl(sd_event *event, int recv_fd, sd_netlink_message_handler_t handler, union in_addr_union *exposed, sd_netlink **ret);
int expose_port_send_rtnl(int send_fd); int expose_port_send_rtnl(int send_fd);
int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *l, union in_addr_union *exposed); int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *exposed);
int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, union in_addr_union *exposed); int expose_port_flush(ExposePort* l, union in_addr_union *exposed);

View File

@ -46,7 +46,6 @@
#include "fs-util.h" #include "fs-util.h"
#include "gpt.h" #include "gpt.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "hostname-setup.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "id128-util.h" #include "id128-util.h"
#include "io-util.h" #include "io-util.h"
@ -1771,6 +1770,11 @@ static int verify_arguments(void) {
if (arg_expose_ports && !arg_private_network) if (arg_expose_ports && !arg_private_network)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --port= without private networking."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --port= without private networking.");
#if ! HAVE_LIBIPTC
if (arg_expose_ports)
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--port= is not supported, compiled without libiptc support.");
#endif
if (arg_caps_ambient) { if (arg_caps_ambient) {
if (arg_caps_ambient == (uint64_t)-1) if (arg_caps_ambient == (uint64_t)-1)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= does not support the value all."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= does not support the value all.");
@ -2470,19 +2474,14 @@ static int setup_kmsg(int kmsg_socket) {
return 0; return 0;
} }
struct ExposeArgs {
union in_addr_union address;
struct FirewallContext *fw_ctx;
};
static int on_address_change(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { static int on_address_change(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
struct ExposeArgs *args = userdata; union in_addr_union *exposed = userdata;
assert(rtnl); assert(rtnl);
assert(m); assert(m);
assert(args); assert(exposed);
expose_port_execute(rtnl, &args->fw_ctx, arg_expose_ports, &args->address); expose_port_execute(rtnl, arg_expose_ports, exposed);
return 0; return 0;
} }
@ -4467,7 +4466,7 @@ static int run_container(
bool secondary, bool secondary,
FDSet *fds, FDSet *fds,
char veth_name[IFNAMSIZ], bool *veth_created, char veth_name[IFNAMSIZ], bool *veth_created,
struct ExposeArgs *expose_args, union in_addr_union *exposed,
int *master, pid_t *pid, int *ret) { int *master, pid_t *pid, int *ret) {
static const struct sigaction sa = { static const struct sigaction sa = {
@ -4896,11 +4895,11 @@ static int run_container(
(void) sd_event_add_signal(event, NULL, SIGCHLD, on_sigchld, PID_TO_PTR(*pid)); (void) sd_event_add_signal(event, NULL, SIGCHLD, on_sigchld, PID_TO_PTR(*pid));
if (arg_expose_ports) { if (arg_expose_ports) {
r = expose_port_watch_rtnl(event, rtnl_socket_pair[0], on_address_change, expose_args, &rtnl); r = expose_port_watch_rtnl(event, rtnl_socket_pair[0], on_address_change, exposed, &rtnl);
if (r < 0) if (r < 0)
return r; return r;
(void) expose_port_execute(rtnl, &expose_args->fw_ctx, arg_expose_ports, &expose_args->address); (void) expose_port_execute(rtnl, arg_expose_ports, exposed);
} }
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
@ -5027,7 +5026,7 @@ static int run_container(
return 0; /* finito */ return 0; /* finito */
} }
expose_port_flush(&expose_args->fw_ctx, arg_expose_ports, &expose_args->address); expose_port_flush(arg_expose_ports, exposed);
(void) remove_veth_links(veth_name, arg_network_veth_extra); (void) remove_veth_links(veth_name, arg_network_veth_extra);
*veth_created = false; *veth_created = false;
@ -5156,13 +5155,12 @@ static int run(int argc, char *argv[]) {
_cleanup_fdset_free_ FDSet *fds = NULL; _cleanup_fdset_free_ FDSet *fds = NULL;
int r, n_fd_passed, ret = EXIT_SUCCESS; int r, n_fd_passed, ret = EXIT_SUCCESS;
char veth_name[IFNAMSIZ] = ""; char veth_name[IFNAMSIZ] = "";
struct ExposeArgs expose_args = {}; union in_addr_union exposed = {};
_cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT; _cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
char tmprootdir[] = "/tmp/nspawn-root-XXXXXX"; char tmprootdir[] = "/tmp/nspawn-root-XXXXXX";
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL; _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL; _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
_cleanup_(fw_ctx_freep) FirewallContext *fw_ctx = NULL;
pid_t pid = 0; pid_t pid = 0;
log_parse_environment(); log_parse_environment();
@ -5519,20 +5517,12 @@ static int run(int argc, char *argv[]) {
goto finish; goto finish;
} }
if (arg_expose_ports) {
r = fw_ctx_new(&fw_ctx);
if (r < 0) {
log_error_errno(r, "Cannot expose configured ports, firewall initialization failed: %m");
goto finish;
}
expose_args.fw_ctx = fw_ctx;
}
for (;;) { for (;;) {
r = run_container(dissected_image, r = run_container(dissected_image,
secondary, secondary,
fds, fds,
veth_name, &veth_created, veth_name, &veth_created,
&expose_args, &master, &exposed, &master,
&pid, &ret); &pid, &ret);
if (r <= 0) if (r <= 0)
break; break;
@ -5582,7 +5572,7 @@ finish:
(void) rm_rf(p, REMOVE_ROOT); (void) rm_rf(p, REMOVE_ROOT);
} }
expose_port_flush(&fw_ctx, arg_expose_ports, &expose_args.address); expose_port_flush(arg_expose_ports, &exposed);
if (veth_created) if (veth_created)
(void) remove_veth_links(veth_name, arg_network_veth_extra); (void) remove_veth_links(veth_name, arg_network_veth_extra);

View File

@ -71,7 +71,6 @@ struct DnsPacket {
union in_addr_union sender, destination; union in_addr_union sender, destination;
uint16_t sender_port, destination_port; uint16_t sender_port, destination_port;
uint32_t ttl; uint32_t ttl;
usec_t timestamp; /* CLOCK_BOOTTIME (or CLOCK_MONOTONIC if the former doesn't exist) */
/* For support of truncated packets */ /* For support of truncated packets */
DnsPacket *more; DnsPacket *more;

View File

@ -377,7 +377,6 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
s->read_packet->family = s->peer.sa.sa_family; s->read_packet->family = s->peer.sa.sa_family;
s->read_packet->ttl = s->ttl; s->read_packet->ttl = s->ttl;
s->read_packet->ifindex = s->ifindex; s->read_packet->ifindex = s->ifindex;
s->read_packet->timestamp = now(clock_boottime_or_monotonic());
if (s->read_packet->family == AF_INET) { if (s->read_packet->family == AF_INET) {
s->read_packet->sender.in = s->peer.in.sin_addr; s->read_packet->sender.in = s->peer.in.sin_addr;

View File

@ -890,6 +890,7 @@ static int dns_transaction_fix_rcode(DnsTransaction *t) {
} }
void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
usec_t ts;
int r; int r;
assert(t); assert(t);
@ -972,6 +973,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
} }
} }
assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0);
switch (t->scope->protocol) { switch (t->scope->protocol) {
case DNS_PROTOCOL_DNS: case DNS_PROTOCOL_DNS:
@ -1036,7 +1039,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {
case DNS_PROTOCOL_LLMNR: case DNS_PROTOCOL_LLMNR:
case DNS_PROTOCOL_MDNS: case DNS_PROTOCOL_MDNS:
dns_scope_packet_received(t->scope, p->timestamp - t->start_usec); dns_scope_packet_received(t->scope, ts - t->start_usec);
break; break;
default: default:

View File

@ -854,8 +854,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
} else } else
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
p->timestamp = now(clock_boottime_or_monotonic());
CMSG_FOREACH(cmsg, &mh) { CMSG_FOREACH(cmsg, &mh) {
if (cmsg->cmsg_level == IPPROTO_IPV6) { if (cmsg->cmsg_level == IPPROTO_IPV6) {

View File

@ -481,7 +481,7 @@ int ask_password_tty(
if (!(flags & ASK_PASSWORD_SILENT) && !(flags & ASK_PASSWORD_ECHO)) { if (!(flags & ASK_PASSWORD_SILENT) && !(flags & ASK_PASSWORD_ECHO)) {
if (use_color) if (use_color)
(void) loop_write(ttyfd, ansi_grey(), strlen(ansi_grey()), false); (void) loop_write(ttyfd, ANSI_GREY, STRLEN(ANSI_GREY), false);
(void) loop_write(ttyfd, PRESS_TAB, strlen(PRESS_TAB), false); (void) loop_write(ttyfd, PRESS_TAB, strlen(PRESS_TAB), false);
press_tab_visible = true; press_tab_visible = true;
} }

View File

@ -32,7 +32,7 @@
#include "fsck-util.h" #include "fsck-util.h"
#include "gpt.h" #include "gpt.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "hostname-setup.h" #include "hostname-util.h"
#include "id128-util.h" #include "id128-util.h"
#include "mkdir.h" #include "mkdir.h"
#include "mount-util.h" #include "mount-util.h"

View File

@ -1,350 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
/* Temporary work-around for broken glibc vs. linux kernel header definitions
* This is already fixed upstream, remove this when distributions have updated.
*/
#define _NET_IF_H 1
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <net/if.h>
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#include <linux/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/xt_addrtype.h>
#include <libiptc/libiptc.h>
#include "alloc-util.h"
#include "firewall-util.h"
#include "firewall-util-private.h"
#include "in-addr-util.h"
#include "macro.h"
#include "socket-util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
static int entry_fill_basics(
struct ipt_entry *entry,
int protocol,
const char *in_interface,
const union in_addr_union *source,
unsigned source_prefixlen,
const char *out_interface,
const union in_addr_union *destination,
unsigned destination_prefixlen) {
assert(entry);
if (out_interface && !ifname_valid(out_interface))
return -EINVAL;
if (in_interface && !ifname_valid(in_interface))
return -EINVAL;
entry->ip.proto = protocol;
if (in_interface) {
size_t l;
l = strlen(in_interface);
assert(l < sizeof entry->ip.iniface);
assert(l < sizeof entry->ip.iniface_mask);
strcpy(entry->ip.iniface, in_interface);
memset(entry->ip.iniface_mask, 0xFF, l + 1);
}
if (source) {
entry->ip.src = source->in;
in4_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen);
}
if (out_interface) {
size_t l = strlen(out_interface);
assert(l < sizeof entry->ip.outiface);
assert(l < sizeof entry->ip.outiface_mask);
strcpy(entry->ip.outiface, out_interface);
memset(entry->ip.outiface_mask, 0xFF, l + 1);
}
if (destination) {
entry->ip.dst = destination->in;
in4_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen);
}
return 0;
}
int fw_iptables_add_masquerade(
bool add,
int af,
const union in_addr_union *source,
unsigned source_prefixlen) {
static const xt_chainlabel chain = "POSTROUTING";
_cleanup_(iptc_freep) struct xtc_handle *h = NULL;
struct ipt_entry *entry, *mask;
struct ipt_entry_target *t;
size_t sz;
struct nf_nat_ipv4_multi_range_compat *mr;
int r, protocol = 0;
const char *out_interface = NULL;
const union in_addr_union *destination = NULL;
unsigned destination_prefixlen = 0;
if (af != AF_INET)
return -EOPNOTSUPP;
if (!source || source_prefixlen == 0)
return -EINVAL;
h = iptc_init("nat");
if (!h)
return -errno;
sz = XT_ALIGN(sizeof(struct ipt_entry)) +
XT_ALIGN(sizeof(struct ipt_entry_target)) +
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
/* Put together the entry we want to add or remove */
entry = alloca0(sz);
entry->next_offset = sz;
entry->target_offset = XT_ALIGN(sizeof(struct ipt_entry));
r = entry_fill_basics(entry, protocol, NULL, source, source_prefixlen, out_interface, destination, destination_prefixlen);
if (r < 0)
return r;
/* Fill in target part */
t = ipt_get_target(entry);
t->u.target_size =
XT_ALIGN(sizeof(struct ipt_entry_target)) +
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
strncpy(t->u.user.name, "MASQUERADE", sizeof(t->u.user.name));
mr = (struct nf_nat_ipv4_multi_range_compat*) t->data;
mr->rangesize = 1;
/* Create a search mask entry */
mask = alloca(sz);
memset(mask, 0xFF, sz);
if (add) {
if (iptc_check_entry(chain, entry, (unsigned char*) mask, h))
return 0;
if (errno != ENOENT) /* if other error than not existing yet, fail */
return -errno;
if (!iptc_insert_entry(chain, entry, 0, h))
return -errno;
} else {
if (!iptc_delete_entry(chain, entry, (unsigned char*) mask, h)) {
if (errno == ENOENT) /* if it's already gone, all is good! */
return 0;
return -errno;
}
}
if (!iptc_commit(h))
return -errno;
return 0;
}
int fw_iptables_add_local_dnat(
bool add,
int af,
int protocol,
uint16_t local_port,
const union in_addr_union *remote,
uint16_t remote_port,
const union in_addr_union *previous_remote) {
static const xt_chainlabel chain_pre = "PREROUTING", chain_output = "OUTPUT";
_cleanup_(iptc_freep) struct xtc_handle *h = NULL;
struct ipt_entry *entry, *mask;
struct ipt_entry_target *t;
struct ipt_entry_match *m;
struct xt_addrtype_info_v1 *at;
struct nf_nat_ipv4_multi_range_compat *mr;
size_t sz, msz;
int r;
const char *in_interface = NULL;
const union in_addr_union *source = NULL;
unsigned source_prefixlen = 0;
const union in_addr_union *destination = NULL;
unsigned destination_prefixlen = 0;
assert(add || !previous_remote);
if (af != AF_INET)
return -EOPNOTSUPP;
if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
return -EOPNOTSUPP;
if (local_port <= 0)
return -EINVAL;
if (remote_port <= 0)
return -EINVAL;
h = iptc_init("nat");
if (!h)
return -errno;
sz = XT_ALIGN(sizeof(struct ipt_entry)) +
XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) +
XT_ALIGN(sizeof(struct ipt_entry_target)) +
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
if (protocol == IPPROTO_TCP)
msz = XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_tcp));
else
msz = XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_udp));
sz += msz;
/* Fill in basic part */
entry = alloca0(sz);
entry->next_offset = sz;
entry->target_offset =
XT_ALIGN(sizeof(struct ipt_entry)) +
XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) +
msz;
r = entry_fill_basics(entry, protocol, in_interface, source, source_prefixlen, NULL, destination, destination_prefixlen);
if (r < 0)
return r;
/* Fill in first match */
m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)));
m->u.match_size = msz;
if (protocol == IPPROTO_TCP) {
struct xt_tcp *tcp;
strncpy(m->u.user.name, "tcp", sizeof(m->u.user.name));
tcp = (struct xt_tcp*) m->data;
tcp->dpts[0] = tcp->dpts[1] = local_port;
tcp->spts[0] = 0;
tcp->spts[1] = 0xFFFF;
} else {
struct xt_udp *udp;
strncpy(m->u.user.name, "udp", sizeof(m->u.user.name));
udp = (struct xt_udp*) m->data;
udp->dpts[0] = udp->dpts[1] = local_port;
udp->spts[0] = 0;
udp->spts[1] = 0xFFFF;
}
/* Fill in second match */
m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)) + msz);
m->u.match_size =
XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_addrtype_info_v1));
strncpy(m->u.user.name, "addrtype", sizeof(m->u.user.name));
m->u.user.revision = 1;
at = (struct xt_addrtype_info_v1*) m->data;
at->dest = XT_ADDRTYPE_LOCAL;
/* Fill in target part */
t = ipt_get_target(entry);
t->u.target_size =
XT_ALIGN(sizeof(struct ipt_entry_target)) +
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
strncpy(t->u.user.name, "DNAT", sizeof(t->u.user.name));
mr = (struct nf_nat_ipv4_multi_range_compat*) t->data;
mr->rangesize = 1;
mr->range[0].flags = NF_NAT_RANGE_PROTO_SPECIFIED|NF_NAT_RANGE_MAP_IPS;
mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr;
if (protocol == IPPROTO_TCP)
mr->range[0].min.tcp.port = mr->range[0].max.tcp.port = htobe16(remote_port);
else
mr->range[0].min.udp.port = mr->range[0].max.udp.port = htobe16(remote_port);
mask = alloca0(sz);
memset(mask, 0xFF, sz);
if (add) {
/* Add the PREROUTING rule, if it is missing so far */
if (!iptc_check_entry(chain_pre, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -EINVAL;
if (!iptc_insert_entry(chain_pre, entry, 0, h))
return -errno;
}
/* If a previous remote is set, remove its entry */
if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) {
mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr;
if (!iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr;
}
/* Add the OUTPUT rule, if it is missing so far */
if (!in_interface) {
/* Don't apply onto loopback addresses */
if (!destination) {
entry->ip.dst.s_addr = htobe32(0x7F000000);
entry->ip.dmsk.s_addr = htobe32(0xFF000000);
entry->ip.invflags = IPT_INV_DSTIP;
}
if (!iptc_check_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
if (!iptc_insert_entry(chain_output, entry, 0, h))
return -errno;
}
/* If a previous remote is set, remove its entry */
if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) {
mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr;
if (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
}
}
} else {
if (!iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
if (!in_interface) {
if (!destination) {
entry->ip.dst.s_addr = htobe32(0x7F000000);
entry->ip.dmsk.s_addr = htobe32(0xFF000000);
entry->ip.invflags = IPT_INV_DSTIP;
}
if (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
}
}
if (!iptc_commit(h))
return -errno;
return 0;
}

View File

@ -1,958 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter_ipv4.h>
#include <netinet/ip.h>
#include "sd-netlink.h"
#include "alloc-util.h"
#include "firewall-util.h"
#include "firewall-util-private.h"
#include "in-addr-util.h"
#include "macro.h"
#include "socket-util.h"
#include "time-util.h"
#define NFT_SYSTEMD_DNAT_MAP_NAME "map_port_ipport"
#define NFT_SYSTEMD_TABLE_NAME "io.systemd.nat"
#define NFT_SYSTEMD_MASQ_SET_NAME "masq_saddr"
#define NFNL_DEFAULT_TIMEOUT_USECS (1ULL * USEC_PER_SEC)
#define UDP_DPORT_OFFSET 2
static int nfnl_netlink_sendv(sd_netlink *nfnl,
sd_netlink_message *messages[],
size_t msgcount) {
_cleanup_free_ uint32_t *serial = NULL;
size_t i;
int r;
assert(msgcount > 0);
r = sd_netlink_sendv(nfnl, messages, msgcount, &serial);
if (r < 0)
return r;
r = 0;
for (i = 1; i < msgcount - 1; i++) {
int tmp;
/* If message is an error, this returns embedded errno */
tmp = sd_netlink_read(nfnl, serial[i], NFNL_DEFAULT_TIMEOUT_USECS, NULL);
if (tmp < 0 && r == 0)
r = tmp;
}
return r;
}
static int nfnl_add_open_expr_container(sd_netlink_message *m, const char *name) {
int r;
r = sd_netlink_message_open_array(m, NFTA_LIST_ELEM);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_EXPR_NAME, name);
if (r < 0)
return r;
return sd_netlink_message_open_container_union(m, NFTA_EXPR_DATA, name);
}
static int nfnl_add_expr_fib(sd_netlink_message *m, uint32_t nft_fib_flags,
enum nft_fib_result result,
enum nft_registers dreg) {
int r;
r = nfnl_add_open_expr_container(m, "fib");
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_FIB_FLAGS, htobe32(nft_fib_flags));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_FIB_RESULT, htobe32(result));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_FIB_DREG, htobe32(dreg));
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */
}
static int nfnl_add_expr_meta(sd_netlink_message *m, enum nft_meta_keys key,
enum nft_registers dreg) {
int r;
r = nfnl_add_open_expr_container(m, "meta");
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_META_KEY, htobe32(key));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_META_DREG, htobe32(dreg));
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */
}
static int nfnl_add_expr_payload(sd_netlink_message *m, enum nft_payload_bases pb,
uint32_t offset, uint32_t len, enum nft_registers dreg) {
int r;
r = nfnl_add_open_expr_container(m, "payload");
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_DREG, htobe32(dreg));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_BASE, htobe32(pb));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_OFFSET, htobe32(offset));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_LEN, htobe32(len));
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */
}
static int nfnl_add_expr_lookup_set_data(sd_netlink_message *m, const char *set_name,
enum nft_registers sreg) {
int r;
r = nfnl_add_open_expr_container(m, "lookup");
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_LOOKUP_SET, set_name);
if (r < 0)
return r;
return sd_netlink_message_append_u32(m, NFTA_LOOKUP_SREG, htobe32(sreg));
}
static int nfnl_add_expr_lookup_set(sd_netlink_message *m, const char *set_name,
enum nft_registers sreg) {
int r;
r = nfnl_add_expr_lookup_set_data(m, set_name, sreg);
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */
}
static int nfnl_add_expr_lookup_map(sd_netlink_message *m, const char *set_name,
enum nft_registers sreg, enum nft_registers dreg) {
int r;
r = nfnl_add_expr_lookup_set_data(m, set_name, sreg);
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_LOOKUP_DREG, htobe32(dreg));
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */
}
static int nfnl_add_expr_data(sd_netlink_message *m, int attr, const void *data, uint32_t dlen) {
int r;
r = sd_netlink_message_open_container(m, attr);
if (r < 0)
return r;
r = sd_netlink_message_append_data(m, NFTA_DATA_VALUE, data, dlen);
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* attr */
}
static int nfnl_add_expr_cmp_data(sd_netlink_message *m, const void *data, uint32_t dlen) {
return nfnl_add_expr_data(m, NFTA_CMP_DATA, data, dlen);
}
static int nfnl_add_expr_cmp(sd_netlink_message *m, enum nft_cmp_ops cmp_op,
enum nft_registers sreg, const void *data, uint32_t dlen) {
int r;
r = nfnl_add_open_expr_container(m, "cmp");
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_CMP_OP, htobe32(cmp_op));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_CMP_SREG, htobe32(sreg));
if (r < 0)
return r;
r = nfnl_add_expr_cmp_data(m, data, dlen);
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */
}
static int nfnl_add_expr_bitwise(sd_netlink_message *m,
enum nft_registers sreg,
enum nft_registers dreg,
const void *and,
const void *xor, uint32_t len) {
int r;
r = nfnl_add_open_expr_container(m, "bitwise");
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_BITWISE_SREG, htobe32(sreg));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_BITWISE_DREG, htobe32(dreg));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_BITWISE_LEN, htobe32(len));
if (r < 0)
return r;
r = nfnl_add_expr_data(m, NFTA_BITWISE_MASK, and, len);
if (r < 0)
return r;
r = nfnl_add_expr_data(m, NFTA_BITWISE_XOR, xor, len);
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */
}
static int nfnl_add_expr_dnat(sd_netlink_message *m,
int family,
enum nft_registers areg,
enum nft_registers preg) {
int r;
r = nfnl_add_open_expr_container(m, "nat");
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_NAT_TYPE, htobe32(NFT_NAT_DNAT));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_NAT_FAMILY, htobe32(family));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_NAT_REG_ADDR_MIN, htobe32(areg));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_NAT_REG_PROTO_MIN, htobe32(preg));
if (r < 0)
return r;
r = sd_netlink_message_close_container(m);
if (r < 0)
return r;
return sd_netlink_message_close_container(m);
}
static int nfnl_add_expr_masq(sd_netlink_message *m) {
int r;
r = sd_netlink_message_open_array(m, NFTA_LIST_ELEM);
if (r < 0)
return r;
r = sd_netlink_message_append_string(m, NFTA_EXPR_NAME, "masq");
if (r < 0)
return r;
return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */
}
/* -t nat -A POSTROUTING -p protocol -s source/pflen -o out_interface -d destionation/pflen -j MASQUERADE */
static int sd_nfnl_message_new_masq_rule(sd_netlink *nfnl, sd_netlink_message **ret, int family,
const char *chain) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain);
if (r < 0)
return r;
r = sd_netlink_message_open_container(m, NFTA_RULE_EXPRESSIONS);
if (r < 0)
return r;
/* 1st statement: ip saddr @masq_saddr. Place iph->saddr in reg1. */
r = nfnl_add_expr_payload(m, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct iphdr, saddr),
sizeof(uint32_t), NFT_REG32_01);
if (r < 0)
return r;
/* 1st statement: use reg1 content to make lookup in @masq_saddr set. */
r = nfnl_add_expr_lookup_set(m, NFT_SYSTEMD_MASQ_SET_NAME, NFT_REG32_01);
if (r < 0)
return r;
/* 2nd statement: masq. Only executed by kernel if the previous lookup was successful. */
r = nfnl_add_expr_masq(m);
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
}
/* -t nat -A PREROUTING -p protocol --dport local_port -i in_interface -s source/pflen -d destionation/pflen -j DNAT --to-destination remote_addr:remote_port */
static int sd_nfnl_message_new_dnat_rule_pre(sd_netlink *nfnl, sd_netlink_message **ret, int family,
const char *chain) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
enum nft_registers proto_reg;
uint32_t local = RTN_LOCAL;
int r;
r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain);
if (r < 0)
return r;
r = sd_netlink_message_open_container(m, NFTA_RULE_EXPRESSIONS);
if (r < 0)
return r;
/* 1st statement: fib daddr type local */
r = nfnl_add_expr_fib(m, NFTA_FIB_F_DADDR, NFT_FIB_RESULT_ADDRTYPE, NFT_REG32_01);
if (r < 0)
return r;
/* 1st statement (cont.): compare RTN_LOCAL */
r = nfnl_add_expr_cmp(m, NFT_CMP_EQ, NFT_REG32_01, &local, sizeof(local));
if (r < 0)
return r;
/* 2nd statement: lookup local port in map, fetch address:dport to map to */
r = nfnl_add_expr_meta(m, NFT_META_L4PROTO, NFT_REG32_01);
if (r < 0)
return r;
r = nfnl_add_expr_payload(m, NFT_PAYLOAD_TRANSPORT_HEADER, UDP_DPORT_OFFSET,
sizeof(uint16_t), NFT_REG32_02);
if (r < 0)
return r;
/* 3rd statement: lookup 'l4proto . dport', e.g. 'tcp . 22' as key and
* store address and port for the dnat mapping in REG1/REG2.
*/
r = nfnl_add_expr_lookup_map(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01);
if (r < 0)
return r;
proto_reg = NFT_REG32_02;
r = nfnl_add_expr_dnat(m, family, NFT_REG32_01, proto_reg);
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
}
static int sd_nfnl_message_new_dnat_rule_out(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *chain) {
static const uint32_t zero, one = 1;
uint32_t lonet = htobe32(0x7F000000), lomask = htobe32(0xff000000);
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
enum nft_registers proto_reg;
int r;
r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain);
if (r < 0)
return r;
r = sd_netlink_message_open_container(m, NFTA_RULE_EXPRESSIONS);
if (r < 0)
return r;
/* 1st statement: exclude 127.0.0.1/8: ip daddr != 127.0.0.1/8 */
r = nfnl_add_expr_payload(m, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct iphdr, daddr),
sizeof(uint32_t), NFT_REG32_01);
if (r < 0)
return r;
/* 1st statement (cont.): bitops/prefix */
r = nfnl_add_expr_bitwise(m, NFT_REG32_01, NFT_REG32_01, &lomask, &zero, sizeof(lomask));
if (r < 0)
return r;
/* 1st statement (cont.): compare reg1 with 127/8 */
r = nfnl_add_expr_cmp(m, NFT_CMP_NEQ, NFT_REG32_01, &lonet, sizeof(lonet));
if (r < 0)
return r;
/* 2nd statement: meta oif lo */
r = nfnl_add_expr_meta(m, NFT_META_OIF, NFT_REG32_01);
if (r < 0)
return r;
/* 2nd statement (cont.): compare to lo ifindex (1) */
r = nfnl_add_expr_cmp(m, NFT_CMP_EQ, NFT_REG32_01, &one, sizeof(one));
if (r < 0)
return r;
/* 3rd statement: meta l4proto . th dport dnat ip . port to map @map_port_ipport */
r = nfnl_add_expr_meta(m, NFT_META_L4PROTO, NFT_REG32_01);
if (r < 0)
return r;
/* 3rd statement (cont): store the port number in reg2 */
r = nfnl_add_expr_payload(m, NFT_PAYLOAD_TRANSPORT_HEADER, UDP_DPORT_OFFSET,
sizeof(uint16_t), NFT_REG32_02);
if (r < 0)
return r;
/* 3rd statement (cont): use reg1 and reg2 and retrieve
* the new destination ip and port number.
*
* reg1 and reg2 are clobbered and will then contain the new
* address/port number.
*/
r = nfnl_add_expr_lookup_map(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01);
if (r < 0)
return r;
/* 4th statement: dnat connection to address/port retrieved by the
* preceeding expression. */
proto_reg = NFT_REG32_02;
r = nfnl_add_expr_dnat(m, family, NFT_REG32_01, proto_reg);
if (r < 0)
return r;
r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
}
static int nft_new_set(struct sd_netlink *nfnl,
sd_netlink_message **ret,
int family, const char *set_name,
uint32_t set_id,
uint32_t flags, uint32_t type, uint32_t klen) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = sd_nfnl_nft_message_new_set(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name, set_id, klen);
if (r < 0)
return r;
if (flags != 0) {
r = sd_netlink_message_append_u32(m, NFTA_SET_FLAGS, htobe32(flags));
if (r < 0)
return r;
}
r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_TYPE, htobe32(type));
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return r;
}
static int nft_new_map(struct sd_netlink *nfnl,
sd_netlink_message **ret,
int family, const char *set_name, uint32_t set_id,
uint32_t flags, uint32_t type, uint32_t klen, uint32_t dtype, uint32_t dlen) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = nft_new_set(nfnl, &m, family, set_name, set_id, flags | NFT_SET_MAP, type, klen);
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_SET_DATA_TYPE, htobe32(dtype));
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_SET_DATA_LEN, htobe32(dlen));
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
}
static int nft_add_element(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *set_name,
const void *key, uint32_t klen,
const void *data, uint32_t dlen) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
/*
* Ideally there would be an API that provides:
*
* 1) a init function to add the main ruleset skeleton
* 2) a function that populates the sets with all known address/port pairs to s/dnat for
* 3) a function that can remove address/port pairs again.
*
* At this time, the existing API is used which is built on a
* 'add/delete a rule' paradigm.
*
* This replicated here and each element gets added to the set
* one-by-one.
*/
r = sd_nfnl_nft_message_new_setelems_begin(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name);
if (r < 0)
return r;
r = sd_nfnl_nft_message_add_setelem(m, 0, key, klen, data, dlen);
if (r < 0)
return r;
/* could theoretically append more set elements to add here */
r = sd_nfnl_nft_message_add_setelem_end(m);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
}
static int nft_del_element(sd_netlink *nfnl,
sd_netlink_message **ret, int family, const char *set_name,
const void *key, uint32_t klen,
const void *data, uint32_t dlen) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
r = sd_nfnl_nft_message_del_setelems_begin(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name);
if (r < 0)
return r;
r = sd_nfnl_nft_message_add_setelem(m, 0, key, klen, data, dlen);
if (r < 0)
return r;
r = sd_nfnl_nft_message_add_setelem_end(m);
if (r < 0)
return r;
*ret = TAKE_PTR(m);
return 0;
}
/* This is needed so 'nft' userspace tool can properly format the contents
* of the set/map when someone uses 'nft' to inspect their content.
*
* The values cannot be changed, they are part of the nft tool type identifier ABI.
*/
#define TYPE_BITS 6
enum nft_key_types {
TYPE_IPADDR = 7,
TYPE_IP6ADDR = 8,
TYPE_INET_PROTOCOL = 12,
TYPE_INET_SERVICE = 13,
};
static uint32_t concat_types2(enum nft_key_types a, enum nft_key_types b) {
uint32_t type = (uint32_t)a;
type <<= TYPE_BITS;
type |= (uint32_t)b;
return type;
}
/* enough space to hold netlink messages for table skeleton */
#define NFT_INIT_MSGS 16
static int fw_nftables_init_family(sd_netlink *nfnl, int family) {
sd_netlink_message *batch[NFT_INIT_MSGS] = {};
size_t ip_type_size = sizeof(uint32_t);
int ip_type = TYPE_IPADDR, r;
size_t msgcnt = 0, i;
uint32_t set_id = 0;
r = sd_nfnl_message_batch_begin(nfnl, &batch[msgcnt]);
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
/* Set F_EXCL so table add fails if the table already exists. */
r = sd_nfnl_nft_message_new_table(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, NLM_F_EXCL | NLM_F_ACK);
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME,
"prerouting", "nat",
NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST + 1);
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME,
"output", "nat",
NF_INET_LOCAL_OUT, NF_IP_PRI_NAT_DST + 1);
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME,
"postrouting", "nat",
NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC + 1);
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
/* set to store ip address ranges we should masquerade for */
r = nft_new_set(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_MASQ_SET_NAME, ++set_id, NFT_SET_INTERVAL, ip_type, ip_type_size);
if (r < 0)
goto out_unref;
/*
* map to store ip address:port pair to dnat to. elements in concatenation
* are rounded up to 4 bytes.
*
* Example: ip protocol . tcp daddr is sizeof(uint32_t) + sizeof(uint32_t), not
* sizeof(uint8_t) + sizeof(uint16_t).
*/
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
r = nft_new_map(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_DNAT_MAP_NAME, ++set_id, 0,
concat_types2(TYPE_INET_PROTOCOL, TYPE_INET_SERVICE), sizeof(uint32_t) * 2,
concat_types2(ip_type, TYPE_INET_SERVICE), ip_type_size + sizeof(uint32_t));
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
r = sd_nfnl_message_new_dnat_rule_pre(nfnl, &batch[msgcnt], family, "prerouting");
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
r = sd_nfnl_message_new_dnat_rule_out(nfnl, &batch[msgcnt], family, "output");
if (r < 0)
goto out_unref;
msgcnt++;
r = sd_nfnl_message_new_masq_rule(nfnl, &batch[msgcnt], family, "postrouting");
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt < NFT_INIT_MSGS);
r = sd_nfnl_message_batch_end(nfnl, &batch[msgcnt]);
if (r < 0)
goto out_unref;
msgcnt++;
assert(msgcnt <= NFT_INIT_MSGS);
r = nfnl_netlink_sendv(nfnl, batch, msgcnt);
if (r == -EEXIST)
r = 0;
out_unref:
for (i = 0; i < msgcnt; i++)
sd_netlink_message_unref(batch[i]);
return r;
}
int fw_nftables_init(FirewallContext *ctx) {
_cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
int r;
r = sd_nfnl_socket_open(&nfnl);
if (r < 0)
return r;
r = fw_nftables_init_family(nfnl, AF_INET);
if (r < 0)
return r;
ctx->nfnl = TAKE_PTR(nfnl);
return 0;
}
void fw_nftables_exit(FirewallContext *ctx) {
ctx->nfnl = sd_netlink_unref(ctx->nfnl);
}
static int nft_message_add_setelem_iprange(sd_netlink_message *m,
const union in_addr_union *source,
unsigned int prefixlen) {
uint32_t mask, start, end;
unsigned int nplen;
int r;
assert(prefixlen <= 32);
nplen = 32 - prefixlen;
mask = (1U << nplen) - 1U;
mask = htobe32(~mask);
start = source->in.s_addr & mask;
r = sd_nfnl_nft_message_add_setelem(m, 0, &start, sizeof(start), NULL, 0);
if (r < 0)
return r;
r = sd_nfnl_nft_message_add_setelem_end(m);
if (r < 0)
return r;
end = be32toh(start) + (1U << nplen);
if (end < be32toh(start))
end = 0U;
end = htobe32(end);
r = sd_nfnl_nft_message_add_setelem(m, 1, &end, sizeof(end), NULL, 0);
if (r < 0)
return r;
r = sd_netlink_message_append_u32(m, NFTA_SET_ELEM_FLAGS, htobe32(NFT_SET_ELEM_INTERVAL_END));
if (r < 0)
return r;
r = sd_nfnl_nft_message_add_setelem_end(m);
if (r < 0)
return r;
return 0;
}
/* When someone runs 'nft flush ruleset' in the same net namespace
* this will also tear down the systemd nat table.
*
* Unlike iptables -t nat -F (which will remove all rules added by the
* systemd iptables backend, iptables has builtin chains that cannot be
* deleted -- the next add operation will 'just work'.
*
* In the nftables case, everything gets removed. The next add operation
* will yield -ENOENT.
*
* If we see -ENOENT on add, replay the inital table setup.
* If that works, re-do the add operation.
*
* Note that this doesn't protect against external sabotage such as a
* 'while true; nft flush ruleset;done'. There is nothing that could be
* done about that short of extending the kernel to allow tables to be
* owned by stystemd-networkd and making them non-deleteable except by
* the 'owning process'.
*/
static int fw_nftables_recreate_table(sd_netlink *nfnl, int af, sd_netlink_message **old, size_t size) {
int r = fw_nftables_init_family(nfnl, af);
if (r != 0)
return r;
while (size > 0) {
size_t i = --size;
old[i] = sd_netlink_message_unref(old[i]);
}
return 0;
}
#define NFT_MASQ_MSGS 3
int fw_nftables_add_masquerade(
FirewallContext *ctx,
bool add,
int af,
const union in_addr_union *source,
unsigned int source_prefixlen) {
sd_netlink_message *transaction[NFT_MASQ_MSGS] = {};
bool retry = true;
size_t tsize;
int r;
if (!source || source_prefixlen == 0)
return -EINVAL;
again:
r = sd_nfnl_message_batch_begin(ctx->nfnl, &transaction[0]);
if (r < 0)
return r;
tsize = 1;
if (add)
r = sd_nfnl_nft_message_new_setelems_begin(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME);
else
r = sd_nfnl_nft_message_del_setelems_begin(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME);
if (r < 0)
goto out_unref;
r = nft_message_add_setelem_iprange(transaction[tsize], source, source_prefixlen);
if (r < 0)
goto out_unref;
++tsize;
assert(tsize < NFT_MASQ_MSGS);
r = sd_nfnl_message_batch_end(ctx->nfnl, &transaction[tsize]);
if (r < 0)
return r;
++tsize;
r = nfnl_netlink_sendv(ctx->nfnl, transaction, tsize);
if (retry && r == -ENOENT) {
int tmp = fw_nftables_recreate_table(ctx->nfnl, af, transaction, tsize);
if (tmp == 0) {
retry = false;
goto again;
}
}
out_unref:
while (tsize > 0)
sd_netlink_message_unref(transaction[--tsize]);
return r < 0 ? r : 0;
}
#define NFT_DNAT_MSGS 4
int fw_nftables_add_local_dnat(
FirewallContext *ctx,
bool add,
int af,
int protocol,
uint16_t local_port,
const union in_addr_union *remote,
uint16_t remote_port,
const union in_addr_union *previous_remote) {
uint32_t data[2], key[2];
sd_netlink_message *transaction[NFT_DNAT_MSGS] = {};
bool retry = true;
size_t tsize;
int r;
assert(add || !previous_remote);
if (af != AF_INET)
return -EAFNOSUPPORT;
if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
return -EPROTONOSUPPORT;
if (local_port <= 0)
return -EINVAL;
again:
key[0] = protocol;
key[1] = htobe16(local_port);
if (!remote)
return -EOPNOTSUPP;
if (remote_port <= 0)
return -EINVAL;
data[1] = htobe16(remote_port);
r = sd_nfnl_message_batch_begin(ctx->nfnl, &transaction[0]);
if (r < 0)
return r;
tsize = 1;
/* If a previous remote is set, remove its entry */
if (add && previous_remote && previous_remote->in.s_addr != remote->in.s_addr) {
data[0] = previous_remote->in.s_addr;
r = nft_del_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, sizeof(data));
if (r < 0)
goto out_unref;
tsize++;
}
data[0] = remote->in.s_addr;
assert(tsize < NFT_DNAT_MSGS);
if (add)
nft_add_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, sizeof(data));
else
nft_del_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, sizeof(data));
tsize++;
assert(tsize < NFT_DNAT_MSGS);
r = sd_nfnl_message_batch_end(ctx->nfnl, &transaction[tsize]);
if (r < 0)
goto out_unref;
tsize++;
assert(tsize <= NFT_DNAT_MSGS);
r = nfnl_netlink_sendv(ctx->nfnl, transaction, tsize);
if (retry && r == -ENOENT) {
int tmp = fw_nftables_recreate_table(ctx->nfnl, af, transaction, tsize);
if (tmp == 0) {
retry = false;
goto again;
}
}
out_unref:
while (tsize > 0)
sd_netlink_message_unref(transaction[--tsize]);
return r < 0 ? r : 0;
}

View File

@ -1,59 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "in-addr-util.h"
#include "sd-netlink.h"
enum FirewallBackend {
FW_BACKEND_NONE,
#if HAVE_LIBIPTC
FW_BACKEND_IPTABLES,
#endif
FW_BACKEND_NFTABLES,
};
struct FirewallContext {
enum FirewallBackend firewall_backend;
sd_netlink *nfnl;
};
int fw_nftables_init(FirewallContext *ctx);
void fw_nftables_exit(FirewallContext *ctx);
int fw_nftables_add_masquerade(
FirewallContext *ctx,
bool add,
int af,
const union in_addr_union *source,
unsigned source_prefixlen);
int fw_nftables_add_local_dnat(
FirewallContext *ctx,
bool add,
int af,
int protocol,
uint16_t local_port,
const union in_addr_union *remote,
uint16_t remote_port,
const union in_addr_union *previous_remote);
#if HAVE_LIBIPTC
int fw_iptables_add_masquerade(
bool add,
int af,
const union in_addr_union *source,
unsigned source_prefixlen);
int fw_iptables_add_local_dnat(
bool add,
int af,
int protocol,
uint16_t local_port,
const union in_addr_union *remote,
uint16_t remote_port,
const union in_addr_union *previous_remote);
#endif

View File

@ -1,86 +1,156 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
/* Temporary work-around for broken glibc vs. linux kernel header definitions
* This is already fixed upstream, remove this when distributions have updated.
*/
#define _NET_IF_H 1
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h> #include <errno.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <net/if.h>
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#include <linux/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/xt_addrtype.h>
#include <libiptc/libiptc.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "firewall-util.h" #include "firewall-util.h"
#include "firewall-util-private.h" #include "in-addr-util.h"
#include "macro.h"
#include "socket-util.h"
static enum FirewallBackend firewall_backend_probe(FirewallContext *ctx) { DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
if (fw_nftables_init(ctx) == 0)
return FW_BACKEND_NFTABLES;
#if HAVE_LIBIPTC
return FW_BACKEND_IPTABLES;
#else
return FW_BACKEND_NONE;
#endif
}
int fw_ctx_new(FirewallContext **ret) { static int entry_fill_basics(
_cleanup_free_ FirewallContext *ctx = NULL; struct ipt_entry *entry,
int protocol,
const char *in_interface,
const union in_addr_union *source,
unsigned source_prefixlen,
const char *out_interface,
const union in_addr_union *destination,
unsigned destination_prefixlen) {
ctx = new0(FirewallContext, 1); assert(entry);
if (!ctx)
return -ENOMEM; if (out_interface && !ifname_valid(out_interface))
return -EINVAL;
if (in_interface && !ifname_valid(in_interface))
return -EINVAL;
entry->ip.proto = protocol;
if (in_interface) {
size_t l;
l = strlen(in_interface);
assert(l < sizeof entry->ip.iniface);
assert(l < sizeof entry->ip.iniface_mask);
strcpy(entry->ip.iniface, in_interface);
memset(entry->ip.iniface_mask, 0xFF, l + 1);
}
if (source) {
entry->ip.src = source->in;
in4_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen);
}
if (out_interface) {
size_t l = strlen(out_interface);
assert(l < sizeof entry->ip.outiface);
assert(l < sizeof entry->ip.outiface_mask);
strcpy(entry->ip.outiface, out_interface);
memset(entry->ip.outiface_mask, 0xFF, l + 1);
}
if (destination) {
entry->ip.dst = destination->in;
in4_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen);
}
/* could probe here. However, this means that we will load
* iptable_nat or nf_tables, both will enable connection tracking.
*
* Alternative would be to probe here but only call
* fw_ctx_new when nspawn/networkd know they will call
* fw_add_masquerade/local_dnat later anyway.
*/
*ret = TAKE_PTR(ctx);
return 0; return 0;
} }
FirewallContext *fw_ctx_free(FirewallContext *ctx) {
if (!ctx)
return NULL;
if (ctx->firewall_backend == FW_BACKEND_NFTABLES)
fw_nftables_exit(ctx);
return mfree(ctx);
}
int fw_add_masquerade( int fw_add_masquerade(
FirewallContext **fw_ctx,
bool add, bool add,
int af, int af,
const union in_addr_union *source, const union in_addr_union *source,
unsigned source_prefixlen) { unsigned source_prefixlen) {
FirewallContext *ctx;
int r;
if (!*fw_ctx) { static const xt_chainlabel chain = "POSTROUTING";
r = fw_ctx_new(fw_ctx); _cleanup_(iptc_freep) struct xtc_handle *h = NULL;
if (r < 0) struct ipt_entry *entry, *mask;
return r; struct ipt_entry_target *t;
} size_t sz;
struct nf_nat_ipv4_multi_range_compat *mr;
int r, protocol = 0;
const char *out_interface = NULL;
const union in_addr_union *destination = NULL;
unsigned destination_prefixlen = 0;
ctx = *fw_ctx; if (af != AF_INET)
if (ctx->firewall_backend == FW_BACKEND_NONE)
ctx->firewall_backend = firewall_backend_probe(ctx);
switch (ctx->firewall_backend) {
case FW_BACKEND_NONE:
return -EOPNOTSUPP; return -EOPNOTSUPP;
#if HAVE_LIBIPTC
case FW_BACKEND_IPTABLES: h = iptc_init("nat");
return fw_iptables_add_masquerade(add, af, source, source_prefixlen); if (!h)
#endif return -errno;
case FW_BACKEND_NFTABLES:
return fw_nftables_add_masquerade(ctx, add, af, source, source_prefixlen); sz = XT_ALIGN(sizeof(struct ipt_entry)) +
XT_ALIGN(sizeof(struct ipt_entry_target)) +
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
/* Put together the entry we want to add or remove */
entry = alloca0(sz);
entry->next_offset = sz;
entry->target_offset = XT_ALIGN(sizeof(struct ipt_entry));
r = entry_fill_basics(entry, protocol, NULL, source, source_prefixlen, out_interface, destination, destination_prefixlen);
if (r < 0)
return r;
/* Fill in target part */
t = ipt_get_target(entry);
t->u.target_size =
XT_ALIGN(sizeof(struct ipt_entry_target)) +
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
strncpy(t->u.user.name, "MASQUERADE", sizeof(t->u.user.name));
mr = (struct nf_nat_ipv4_multi_range_compat*) t->data;
mr->rangesize = 1;
/* Create a search mask entry */
mask = alloca(sz);
memset(mask, 0xFF, sz);
if (add) {
if (iptc_check_entry(chain, entry, (unsigned char*) mask, h))
return 0;
if (errno != ENOENT) /* if other error than not existing yet, fail */
return -errno;
if (!iptc_insert_entry(chain, entry, 0, h))
return -errno;
} else {
if (!iptc_delete_entry(chain, entry, (unsigned char*) mask, h)) {
if (errno == ENOENT) /* if it's already gone, all is good! */
return 0;
return -errno;
}
} }
return -EOPNOTSUPP; if (!iptc_commit(h))
return -errno;
return 0;
} }
int fw_add_local_dnat( int fw_add_local_dnat(
FirewallContext **fw_ctx,
bool add, bool add,
int af, int af,
int protocol, int protocol,
@ -88,28 +158,189 @@ int fw_add_local_dnat(
const union in_addr_union *remote, const union in_addr_union *remote,
uint16_t remote_port, uint16_t remote_port,
const union in_addr_union *previous_remote) { const union in_addr_union *previous_remote) {
FirewallContext *ctx;
if (!*fw_ctx) { static const xt_chainlabel chain_pre = "PREROUTING", chain_output = "OUTPUT";
int ret = fw_ctx_new(fw_ctx); _cleanup_(iptc_freep) struct xtc_handle *h = NULL;
if (ret < 0) struct ipt_entry *entry, *mask;
return ret; struct ipt_entry_target *t;
} struct ipt_entry_match *m;
struct xt_addrtype_info_v1 *at;
struct nf_nat_ipv4_multi_range_compat *mr;
size_t sz, msz;
int r;
const char *in_interface = NULL;
const union in_addr_union *source = NULL;
unsigned source_prefixlen = 0;
const union in_addr_union *destination = NULL;
unsigned destination_prefixlen = 0;
ctx = *fw_ctx; assert(add || !previous_remote);
if (ctx->firewall_backend == FW_BACKEND_NONE)
ctx->firewall_backend = firewall_backend_probe(ctx);
switch (ctx->firewall_backend) { if (af != AF_INET)
case FW_BACKEND_NONE:
return -EOPNOTSUPP; return -EOPNOTSUPP;
case FW_BACKEND_NFTABLES:
return fw_nftables_add_local_dnat(ctx, add, af, protocol, local_port, remote, remote_port, previous_remote); if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
#if HAVE_LIBIPTC return -EOPNOTSUPP;
case FW_BACKEND_IPTABLES:
return fw_iptables_add_local_dnat(add, af, protocol, local_port, remote, remote_port, previous_remote); if (local_port <= 0)
#endif return -EINVAL;
if (remote_port <= 0)
return -EINVAL;
h = iptc_init("nat");
if (!h)
return -errno;
sz = XT_ALIGN(sizeof(struct ipt_entry)) +
XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) +
XT_ALIGN(sizeof(struct ipt_entry_target)) +
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
if (protocol == IPPROTO_TCP)
msz = XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_tcp));
else
msz = XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_udp));
sz += msz;
/* Fill in basic part */
entry = alloca0(sz);
entry->next_offset = sz;
entry->target_offset =
XT_ALIGN(sizeof(struct ipt_entry)) +
XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) +
msz;
r = entry_fill_basics(entry, protocol, in_interface, source, source_prefixlen, NULL, destination, destination_prefixlen);
if (r < 0)
return r;
/* Fill in first match */
m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)));
m->u.match_size = msz;
if (protocol == IPPROTO_TCP) {
struct xt_tcp *tcp;
strncpy(m->u.user.name, "tcp", sizeof(m->u.user.name));
tcp = (struct xt_tcp*) m->data;
tcp->dpts[0] = tcp->dpts[1] = local_port;
tcp->spts[0] = 0;
tcp->spts[1] = 0xFFFF;
} else {
struct xt_udp *udp;
strncpy(m->u.user.name, "udp", sizeof(m->u.user.name));
udp = (struct xt_udp*) m->data;
udp->dpts[0] = udp->dpts[1] = local_port;
udp->spts[0] = 0;
udp->spts[1] = 0xFFFF;
} }
return -EOPNOTSUPP; /* Fill in second match */
m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)) + msz);
m->u.match_size =
XT_ALIGN(sizeof(struct ipt_entry_match)) +
XT_ALIGN(sizeof(struct xt_addrtype_info_v1));
strncpy(m->u.user.name, "addrtype", sizeof(m->u.user.name));
m->u.user.revision = 1;
at = (struct xt_addrtype_info_v1*) m->data;
at->dest = XT_ADDRTYPE_LOCAL;
/* Fill in target part */
t = ipt_get_target(entry);
t->u.target_size =
XT_ALIGN(sizeof(struct ipt_entry_target)) +
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
strncpy(t->u.user.name, "DNAT", sizeof(t->u.user.name));
mr = (struct nf_nat_ipv4_multi_range_compat*) t->data;
mr->rangesize = 1;
mr->range[0].flags = NF_NAT_RANGE_PROTO_SPECIFIED|NF_NAT_RANGE_MAP_IPS;
mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr;
if (protocol == IPPROTO_TCP)
mr->range[0].min.tcp.port = mr->range[0].max.tcp.port = htobe16(remote_port);
else
mr->range[0].min.udp.port = mr->range[0].max.udp.port = htobe16(remote_port);
mask = alloca0(sz);
memset(mask, 0xFF, sz);
if (add) {
/* Add the PREROUTING rule, if it is missing so far */
if (!iptc_check_entry(chain_pre, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -EINVAL;
if (!iptc_insert_entry(chain_pre, entry, 0, h))
return -errno;
}
/* If a previous remote is set, remove its entry */
if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) {
mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr;
if (!iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr;
}
/* Add the OUTPUT rule, if it is missing so far */
if (!in_interface) {
/* Don't apply onto loopback addresses */
if (!destination) {
entry->ip.dst.s_addr = htobe32(0x7F000000);
entry->ip.dmsk.s_addr = htobe32(0xFF000000);
entry->ip.invflags = IPT_INV_DSTIP;
}
if (!iptc_check_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
if (!iptc_insert_entry(chain_output, entry, 0, h))
return -errno;
}
/* If a previous remote is set, remove its entry */
if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) {
mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr;
if (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
}
}
} else {
if (!iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
if (!in_interface) {
if (!destination) {
entry->ip.dst.s_addr = htobe32(0x7F000000);
entry->ip.dmsk.s_addr = htobe32(0xFF000000);
entry->ip.invflags = IPT_INV_DSTIP;
}
if (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) {
if (errno != ENOENT)
return -errno;
}
}
}
if (!iptc_commit(h))
return -errno;
return 0;
} }

View File

@ -6,22 +6,15 @@
#include "in-addr-util.h" #include "in-addr-util.h"
typedef struct FirewallContext FirewallContext; #if HAVE_LIBIPTC
int fw_ctx_new(FirewallContext **ret);
FirewallContext *fw_ctx_free(FirewallContext *fw_ctx);
DEFINE_TRIVIAL_CLEANUP_FUNC(FirewallContext *, fw_ctx_free);
int fw_add_masquerade( int fw_add_masquerade(
FirewallContext **fw_ctx,
bool add, bool add,
int af, int af,
const union in_addr_union *source, const union in_addr_union *source,
unsigned source_prefixlen); unsigned source_prefixlen);
int fw_add_local_dnat( int fw_add_local_dnat(
FirewallContext **fw_ctx,
bool add, bool add,
int af, int af,
int protocol, int protocol,
@ -29,3 +22,26 @@ int fw_add_local_dnat(
const union in_addr_union *remote, const union in_addr_union *remote,
uint16_t remote_port, uint16_t remote_port,
const union in_addr_union *previous_remote); const union in_addr_union *previous_remote);
#else
static inline int fw_add_masquerade(
bool add,
int af,
const union in_addr_union *source,
unsigned source_prefixlen) {
return -EOPNOTSUPP;
}
static inline int fw_add_local_dnat(
bool add,
int af,
int protocol,
uint16_t local_port,
const union in_addr_union *remote,
uint16_t remote_port,
const union in_addr_union *previous_remote) {
return -EOPNOTSUPP;
}
#endif

View File

@ -1,236 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
#include "alloc-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "hostname-setup.h"
#include "hostname-util.h"
#include "log.h"
#include "macro.h"
#include "proc-cmdline.h"
#include "string-table.h"
#include "string-util.h"
#include "util.h"
static int sethostname_idempotent_full(const char *s, bool really) {
char buf[HOST_NAME_MAX + 1] = {};
assert(s);
if (gethostname(buf, sizeof(buf) - 1) < 0)
return -errno;
if (streq(buf, s))
return 0;
if (really &&
sethostname(s, strlen(s)) < 0)
return -errno;
return 1;
}
int sethostname_idempotent(const char *s) {
return sethostname_idempotent_full(s, true);
}
bool get_hostname_filtered(char ret[static HOST_NAME_MAX + 1]) {
char buf[HOST_NAME_MAX + 1] = {};
/* Returns true if we got a good hostname, false otherwise. */
if (gethostname(buf, sizeof(buf) - 1) < 0)
return false; /* This can realistically only fail with ENAMETOOLONG.
* Let's treat that case the same as an invalid hostname. */
if (isempty(buf))
return false;
/* This is the built-in kernel default hostname */
if (streq(buf, "(none)"))
return false;
memcpy(ret, buf, sizeof buf);
return true;
}
int shorten_overlong(const char *s, char **ret) {
char *h, *p;
/* Shorten an overlong name to HOST_NAME_MAX or to the first dot,
* whatever comes earlier. */
assert(s);
h = strdup(s);
if (!h)
return -ENOMEM;
if (hostname_is_valid(h, 0)) {
*ret = h;
return 0;
}
p = strchr(h, '.');
if (p)
*p = 0;
strshorten(h, HOST_NAME_MAX);
if (!hostname_is_valid(h, 0)) {
free(h);
return -EDOM;
}
*ret = h;
return 1;
}
int read_etc_hostname_stream(FILE *f, char **ret) {
int r;
assert(f);
assert(ret);
for (;;) {
_cleanup_free_ char *line = NULL;
char *p;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return r;
if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */
return -ENOENT;
p = strstrip(line);
/* File may have empty lines or comments, ignore them */
if (!IN_SET(*p, '\0', '#')) {
char *copy;
hostname_cleanup(p); /* normalize the hostname */
if (!hostname_is_valid(p, VALID_HOSTNAME_TRAILING_DOT)) /* check that the hostname we return is valid */
return -EBADMSG;
copy = strdup(p);
if (!copy)
return -ENOMEM;
*ret = copy;
return 0;
}
}
}
int read_etc_hostname(const char *path, char **ret) {
_cleanup_fclose_ FILE *f = NULL;
assert(ret);
if (!path)
path = "/etc/hostname";
f = fopen(path, "re");
if (!f)
return -errno;
return read_etc_hostname_stream(f, ret);
}
void hostname_update_source_hint(const char *hostname, HostnameSource source) {
int r;
/* Why save the value and not just create a flag file? This way we will
* notice if somebody sets the hostname directly (not going through hostnamed).
*/
if (source == HOSTNAME_FALLBACK) {
r = write_string_file("/run/systemd/fallback-hostname", hostname,
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_ATOMIC);
if (r < 0)
log_warning_errno(r, "Failed to create \"/run/systemd/fallback-hostname\": %m");
} else
unlink_or_warn("/run/systemd/fallback-hostname");
}
int hostname_setup(bool really) {
_cleanup_free_ char *b = NULL;
const char *hn = NULL;
HostnameSource source;
bool enoent = false;
int r;
r = proc_cmdline_get_key("systemd.hostname", 0, &b);
if (r < 0)
log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m");
else if (r > 0) {
if (hostname_is_valid(b, true)) {
hn = b;
source = HOSTNAME_TRANSIENT;
} else {
log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b);
b = mfree(b);
}
}
if (!hn) {
r = read_etc_hostname(NULL, &b);
if (r < 0) {
if (r == -ENOENT)
enoent = true;
else
log_warning_errno(r, "Failed to read configured hostname: %m");
} else {
hn = b;
source = HOSTNAME_STATIC;
}
}
if (isempty(hn)) {
/* Don't override the hostname if it is already set and not explicitly configured */
char buf[HOST_NAME_MAX + 1] = {};
if (get_hostname_filtered(buf)) {
log_debug("No hostname configured, leaving existing hostname <%s> in place.", buf);
return 0;
}
if (enoent)
log_info("No hostname configured, using fallback hostname.");
hn = FALLBACK_HOSTNAME;
source = HOSTNAME_FALLBACK;
}
r = sethostname_idempotent_full(hn, really);
if (r < 0)
return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn);
if (r == 0)
log_debug("Hostname was already set to <%s>.", hn);
else
log_info("Hostname %s to <%s>.",
really ? "set" : "would have been set",
hn);
if (really)
hostname_update_source_hint(hn, source);
return r;
}
static const char* const hostname_source_table[] = {
[HOSTNAME_STATIC] = "static",
[HOSTNAME_TRANSIENT] = "transient",
[HOSTNAME_FALLBACK] = "fallback",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(hostname_source, HostnameSource);

View File

@ -1,24 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
#include <stdio.h>
typedef enum HostnameSource {
HOSTNAME_STATIC, /* from /etc/hostname */
HOSTNAME_TRANSIENT, /* a transient hostname set through systemd, hostnamed, the container manager, or otherwise */
HOSTNAME_FALLBACK, /* the compiled-in fallback was used */
_HOSTNAME_INVALID = -1,
} HostnameSource;
const char* hostname_source_to_string(HostnameSource source);
int sethostname_idempotent(const char *s);
int shorten_overlong(const char *s, char **ret);
int read_etc_hostname_stream(FILE *f, char **ret);
int read_etc_hostname(const char *path, char **ret);
bool get_hostname_filtered(char ret[static HOST_NAME_MAX + 1]);
void hostname_update_source_hint(const char *hostname, HostnameSource source);
int hostname_setup(bool really);

View File

@ -137,3 +137,41 @@ int journal_access_check_and_warn(sd_journal *j, bool quiet, bool want_other_use
return r; return r;
} }
bool journal_field_valid(const char *p, size_t l, bool allow_protected) {
const char *a;
/* We kinda enforce POSIX syntax recommendations for
environment variables here, but make a couple of additional
requirements.
http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
if (l == (size_t) -1)
l = strlen(p);
/* No empty field names */
if (l <= 0)
return false;
/* Don't allow names longer than 64 chars */
if (l > 64)
return false;
/* Variables starting with an underscore are protected */
if (!allow_protected && p[0] == '_')
return false;
/* Don't allow digits as first character */
if (p[0] >= '0' && p[0] <= '9')
return false;
/* Only allow A-Z0-9 and '_' */
for (a = p; a < p + l; a++)
if ((*a < 'A' || *a > 'Z') &&
(*a < '0' || *a > '9') &&
*a != '_')
return false;
return true;
}

View File

@ -6,5 +6,6 @@
#include "sd-journal.h" #include "sd-journal.h"
bool journal_field_valid(const char *p, size_t l, bool allow_protected);
int journal_access_blocked(sd_journal *j); int journal_access_blocked(sd_journal *j);
int journal_access_check_and_warn(sd_journal *j, bool quiet, bool want_other_users); int journal_access_check_and_warn(sd_journal *j, bool quiet, bool want_other_users);

View File

@ -1495,7 +1495,7 @@ static void json_format_string(FILE *f, const char *q, JsonFormatFlags flags) {
fputc('"', f); fputc('"', f);
if (flags & JSON_FORMAT_COLOR) if (flags & JSON_FORMAT_COLOR)
fputs(ansi_green(), f); fputs(ANSI_GREEN, f);
for (; *q; q++) for (; *q; q++)
switch (*q) { switch (*q) {
@ -1557,7 +1557,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha
return -errno; return -errno;
if (flags & JSON_FORMAT_COLOR) if (flags & JSON_FORMAT_COLOR)
fputs(ansi_highlight_blue(), f); fputs(ANSI_HIGHLIGHT_BLUE, f);
fprintf(f, "%.*Le", DECIMAL_DIG, json_variant_real(v)); fprintf(f, "%.*Le", DECIMAL_DIG, json_variant_real(v));
@ -1570,7 +1570,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha
case JSON_VARIANT_INTEGER: case JSON_VARIANT_INTEGER:
if (flags & JSON_FORMAT_COLOR) if (flags & JSON_FORMAT_COLOR)
fputs(ansi_highlight_blue(), f); fputs(ANSI_HIGHLIGHT_BLUE, f);
fprintf(f, "%" PRIdMAX, json_variant_integer(v)); fprintf(f, "%" PRIdMAX, json_variant_integer(v));
@ -1580,7 +1580,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha
case JSON_VARIANT_UNSIGNED: case JSON_VARIANT_UNSIGNED:
if (flags & JSON_FORMAT_COLOR) if (flags & JSON_FORMAT_COLOR)
fputs(ansi_highlight_blue(), f); fputs(ANSI_HIGHLIGHT_BLUE, f);
fprintf(f, "%" PRIuMAX, json_variant_unsigned(v)); fprintf(f, "%" PRIuMAX, json_variant_unsigned(v));

View File

@ -67,7 +67,7 @@ static int print_catalog(FILE *f, sd_journal *j) {
prefix = "--"; prefix = "--";
if (colors_enabled()) if (colors_enabled())
newline = strjoina(ANSI_NORMAL "\n", ansi_grey(), prefix, ANSI_NORMAL " ", ansi_green()); newline = strjoina(ANSI_NORMAL "\n" ANSI_GREY, prefix, ANSI_NORMAL " " ANSI_GREEN);
else else
newline = strjoina("\n", prefix, " "); newline = strjoina("\n", prefix, " ");
@ -76,7 +76,7 @@ static int print_catalog(FILE *f, sd_journal *j) {
return log_oom(); return log_oom();
if (colors_enabled()) if (colors_enabled())
fprintf(f, "%s%s %s%s", ansi_grey(), prefix, ANSI_NORMAL, ansi_green()); fprintf(f, ANSI_GREY "%s" ANSI_NORMAL " " ANSI_GREEN, prefix);
else else
fprintf(f, "%s ", prefix); fprintf(f, "%s ", prefix);
@ -702,11 +702,9 @@ static int output_verbose(
c = memchr(data, '=', length); c = memchr(data, '=', length);
if (!c) if (!c)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid field."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid field.");
fieldlen = c - (const char*) data; fieldlen = c - (const char*) data;
if (!journal_field_valid(data, fieldlen, true))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid field.");
r = field_set_test(output_fields, data, fieldlen); r = field_set_test(output_fields, data, fieldlen);
if (r < 0) if (r < 0)
@ -800,7 +798,6 @@ static int output_export(
sd_id128_to_string(boot_id, sid)); sd_id128_to_string(boot_id, sid));
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) { JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
size_t fieldlen;
const char *c; const char *c;
/* We already printed the boot id from the data in the header, hence let's suppress it here */ /* We already printed the boot id from the data in the header, hence let's suppress it here */
@ -809,13 +806,10 @@ static int output_export(
c = memchr(data, '=', length); c = memchr(data, '=', length);
if (!c) if (!c)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid field."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Invalid field.");
fieldlen = c - (const char*) data; r = field_set_test(output_fields, data, c - (const char *) data);
if (!journal_field_valid(data, fieldlen, true))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid field.");
r = field_set_test(output_fields, data, fieldlen);
if (r < 0) if (r < 0)
return r; return r;
if (!r) if (!r)
@ -826,11 +820,11 @@ static int output_export(
else { else {
uint64_t le64; uint64_t le64;
fwrite(data, fieldlen, 1, f); fwrite(data, c - (const char*) data, 1, f);
fputc('\n', f); fputc('\n', f);
le64 = htole64(length - fieldlen - 1); le64 = htole64(length - (c - (const char*) data) - 1);
fwrite(&le64, sizeof(le64), 1, f); fwrite(&le64, sizeof(le64), 1, f);
fwrite(c + 1, length - fieldlen - 1, 1, f); fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
} }
fputc('\n', f); fputc('\n', f);
@ -967,7 +961,6 @@ static int update_json_data_split(
const void *data, const void *data,
size_t size) { size_t size) {
size_t fieldlen;
const char *eq; const char *eq;
char *name; char *name;
@ -981,15 +974,14 @@ static int update_json_data_split(
if (!eq) if (!eq)
return 0; return 0;
fieldlen = eq - (const char*) data; if (eq == data)
if (!journal_field_valid(data, fieldlen, true)) return 0;
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid field.");
name = strndupa(data, fieldlen); name = strndupa(data, eq - (const char*) data);
if (output_fields && !set_contains(output_fields, name)) if (output_fields && !set_contains(output_fields, name))
return 0; return 0;
return update_json_data(h, flags, name, eq + 1, size - fieldlen - 1); return update_json_data(h, flags, name, eq + 1, size - (eq - (const char*) data) - 1);
} }
static int output_json( static int output_json(

View File

@ -22,7 +22,7 @@
#include "fd-util.h" #include "fd-util.h"
#include "fs-util.h" #include "fs-util.h"
#include "hashmap.h" #include "hashmap.h"
#include "hostname-setup.h" #include "hostname-util.h"
#include "id128-util.h" #include "id128-util.h"
#include "lockfile-util.h" #include "lockfile-util.h"
#include "log.h" #include "log.h"

View File

@ -101,10 +101,7 @@ shared_sources = files('''
fdset.h fdset.h
fileio-label.c fileio-label.c
fileio-label.h fileio-label.h
firewall-util.c
firewall-util-nft.c
firewall-util.h firewall-util.h
firewall-util-private.h
format-table.c format-table.c
format-table.h format-table.h
fsck-util.h fsck-util.h
@ -118,8 +115,6 @@ shared_sources = files('''
gpt.h gpt.h
group-record.c group-record.c
group-record.h group-record.h
hostname-setup.c
hostname-setup.h
id128-print.c id128-print.c
id128-print.h id128-print.h
idn-util.c idn-util.c
@ -298,7 +293,7 @@ if conf.get('HAVE_SECCOMP') == 1
endif endif
if conf.get('HAVE_LIBIPTC') == 1 if conf.get('HAVE_LIBIPTC') == 1
shared_sources += files('firewall-util-iptables.c') shared_sources += files('firewall-util.c')
endif endif
if conf.get('HAVE_KMOD') == 1 if conf.get('HAVE_KMOD') == 1

View File

@ -16,7 +16,7 @@
#include "hexdecoct.h" #include "hexdecoct.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "in-addr-util.h" #include "in-addr-util.h"
#include "journal-file.h" #include "journal-util.h"
#include "list.h" #include "list.h"
#include "locale-util.h" #include "locale-util.h"
#include "memory-util.h" #include "memory-util.h"

View File

@ -60,13 +60,11 @@ sd_netlink *sd_netlink_ref(sd_netlink *nl);
sd_netlink *sd_netlink_unref(sd_netlink *nl); sd_netlink *sd_netlink_unref(sd_netlink *nl);
int sd_netlink_send(sd_netlink *nl, sd_netlink_message *message, uint32_t *serial); int sd_netlink_send(sd_netlink *nl, sd_netlink_message *message, uint32_t *serial);
int sd_netlink_sendv(sd_netlink *nl, sd_netlink_message *messages[], size_t msgcnt, uint32_t **ret_serial);
int sd_netlink_call_async(sd_netlink *nl, sd_netlink_slot **ret_slot, sd_netlink_message *message, int sd_netlink_call_async(sd_netlink *nl, sd_netlink_slot **ret_slot, sd_netlink_message *message,
sd_netlink_message_handler_t callback, sd_netlink_destroy_t destoy_callback, sd_netlink_message_handler_t callback, sd_netlink_destroy_t destoy_callback,
void *userdata, uint64_t usec, const char *description); void *userdata, uint64_t usec, const char *description);
int sd_netlink_call(sd_netlink *nl, sd_netlink_message *message, uint64_t timeout, int sd_netlink_call(sd_netlink *nl, sd_netlink_message *message, uint64_t timeout,
sd_netlink_message **reply); sd_netlink_message **reply);
int sd_netlink_read(sd_netlink *nl, uint32_t serial, uint64_t timeout, sd_netlink_message **reply);
int sd_netlink_get_events(const sd_netlink *nl); int sd_netlink_get_events(const sd_netlink *nl);
int sd_netlink_get_timeout(const sd_netlink *nl, uint64_t *timeout); int sd_netlink_get_timeout(const sd_netlink *nl, uint64_t *timeout);
@ -198,18 +196,18 @@ int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char
int sd_rtnl_message_addrlabel_get_prefixlen(const sd_netlink_message *m, unsigned char *prefixlen); int sd_rtnl_message_addrlabel_get_prefixlen(const sd_netlink_message *m, unsigned char *prefixlen);
int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family); int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family);
int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, uint8_t tos); int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, unsigned char tos);
int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, uint8_t *tos); int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, unsigned char *tos);
int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, uint8_t table); int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, unsigned char table);
int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, uint8_t *table); int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, unsigned char *table);
int sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(sd_netlink_message *m, uint8_t len); int sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(sd_netlink_message *m, unsigned char len);
int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(const sd_netlink_message *m, uint8_t *len); int sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(const sd_netlink_message *m, unsigned char *len);
int sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(sd_netlink_message *m, uint8_t len); int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char len);
int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(const sd_netlink_message *m, uint8_t *len); int sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(const sd_netlink_message *m, unsigned char *len);
int sd_rtnl_message_routing_policy_rule_set_fib_type(sd_netlink_message *m, uint8_t type); int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type);
int sd_rtnl_message_routing_policy_rule_get_fib_type(const sd_netlink_message *m, uint8_t *type); int sd_rtnl_message_routing_policy_rule_get_rtm_type(const sd_netlink_message *m, unsigned char *type);
int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, uint32_t flags); int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, unsigned flags);
int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, uint32_t *flags); int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_new_qdisc(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int tcm_family, int tcm_ifindex); int sd_rtnl_message_new_qdisc(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int tcm_family, int tcm_ifindex);
int sd_rtnl_message_set_qdisc_parent(sd_netlink_message *m, uint32_t parent); int sd_rtnl_message_set_qdisc_parent(sd_netlink_message *m, uint32_t parent);
@ -221,32 +219,6 @@ int sd_rtnl_message_set_tclass_handle(sd_netlink_message *m, uint32_t handle);
int sd_rtnl_message_new_mdb(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int mdb_ifindex); int sd_rtnl_message_new_mdb(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int mdb_ifindex);
/* nfnl */
int sd_nfnl_socket_open(sd_netlink **nl);
int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret);
int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret);
int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table);
int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, uint16_t nl_flags);
int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *chain,
const char *type, uint8_t hook, int prio);
int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *chain);
int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *set_name,
uint32_t setid, uint32_t klen);
int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *set_name);
int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
int family, const char *table, const char *set_name);
int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m,
uint32_t num,
const void *key, uint32_t klen,
const void *data, uint32_t dlen);
int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m);
/* genl */ /* genl */
int sd_genl_socket_open(sd_netlink **nl); int sd_genl_socket_open(sd_netlink **nl);
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m); int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m);

View File

@ -105,6 +105,17 @@ tests += [
libmount, libmount,
libblkid]], libblkid]],
[['src/test/test-hostname.c'],
[libcore,
libshared],
[threads,
librt,
libseccomp,
libselinux,
libmount,
libblkid],
'', 'unsafe'],
[['src/test/test-dns-domain.c'], [['src/test/test-dns-domain.c'],
[libcore, [libcore,
libshared], libshared],
@ -328,10 +339,6 @@ tests += [
[], [],
[]], []],
[['src/test/test-hostname-setup.c'],
[],
[]],
[['src/test/test-hostname-util.c'], [['src/test/test-hostname-util.c'],
[], [],
[]], []],
@ -559,7 +566,8 @@ tests += [
[['src/test/test-firewall-util.c'], [['src/test/test-firewall-util.c'],
[libshared], [libshared],
[]], [],
'HAVE_LIBIPTC'],
[['src/test/test-netlink-manual.c'], [['src/test/test-netlink-manual.c'],
[], [],

View File

@ -7,53 +7,34 @@
#define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))} #define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
_cleanup_(fw_ctx_freep) FirewallContext *ctx;
int r; int r;
test_setup_logging(LOG_DEBUG); test_setup_logging(LOG_DEBUG);
uint8_t prefixlen = 32;
r = fw_ctx_new(&ctx); r = fw_add_masquerade(true, AF_INET, NULL, 0);
if (r < 0)
return log_error_errno(r, "Failed to init firewall: %m");
r = fw_add_masquerade(&ctx, true, AF_INET, NULL, 0);
if (r == 0)
log_error("Expected failure: NULL source");
r = fw_add_masquerade(&ctx, true, AF_INET, &MAKE_IN_ADDR_UNION(10,1,2,0), 0);
if (r == 0)
log_error("Expected failure: 0 prefixlen");
r = fw_add_masquerade(&ctx, true, AF_INET, &MAKE_IN_ADDR_UNION(10,1,2,3), prefixlen);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to modify firewall: %m"); log_error_errno(r, "Failed to modify firewall: %m");
prefixlen = 28; r = fw_add_masquerade(true, AF_INET, NULL, 0);
r = fw_add_masquerade(&ctx, true, AF_INET, &MAKE_IN_ADDR_UNION(10,0,2,0), prefixlen);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to modify firewall: %m"); log_error_errno(r, "Failed to modify firewall: %m");
r = fw_add_masquerade(&ctx, false, AF_INET, &MAKE_IN_ADDR_UNION(10,0,2,0), prefixlen); r = fw_add_masquerade(false, AF_INET, NULL, 0);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to modify firewall: %m"); log_error_errno(r, "Failed to modify firewall: %m");
r = fw_add_masquerade(&ctx, false, AF_INET, &MAKE_IN_ADDR_UNION(10,1,2,3), 32); r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to modify firewall: %m"); log_error_errno(r, "Failed to modify firewall: %m");
r = fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL); r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to modify firewall: %m"); log_error_errno(r, "Failed to modify firewall: %m");
r = fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL); r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, &MAKE_IN_ADDR_UNION(1, 2, 3, 4));
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to modify firewall: %m"); log_error_errno(r, "Failed to modify firewall: %m");
r = fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, &MAKE_IN_ADDR_UNION(1, 2, 3, 4)); r = fw_add_local_dnat(false, AF_INET, IPPROTO_TCP, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, NULL);
if (r < 0)
log_error_errno(r, "Failed to modify firewall: %m");
r = fw_add_local_dnat(&ctx, false, AF_INET, IPPROTO_TCP, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, NULL);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to modify firewall: %m"); log_error_errno(r, "Failed to modify firewall: %m");

View File

@ -1,72 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <unistd.h>
#include "alloc-util.h"
#include "fileio.h"
#include "hostname-setup.h"
#include "string-util.h"
#include "tests.h"
#include "tmpfile-util.h"
static void test_read_etc_hostname(void) {
char path[] = "/tmp/hostname.XXXXXX";
char *hostname;
int fd;
fd = mkostemp_safe(path);
assert(fd > 0);
close(fd);
/* simple hostname */
assert_se(write_string_file(path, "foo", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == 0);
assert_se(streq(hostname, "foo"));
hostname = mfree(hostname);
/* with comment */
assert_se(write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foo"));
hostname = mfree(hostname);
/* with comment and extra whitespace */
assert_se(write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foo"));
hostname = mfree(hostname);
/* cleans up name */
assert_se(write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foobar.com"));
hostname = mfree(hostname);
/* no value set */
hostname = (char*) 0x1234;
assert_se(write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == -ENOENT);
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
/* nonexisting file */
assert_se(read_etc_hostname("/non/existing", &hostname) == -ENOENT);
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
unlink(path);
}
static void test_hostname_setup(void) {
hostname_setup(false);
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_read_etc_hostname();
test_hostname_setup();
return 0;
}

View File

@ -6,8 +6,8 @@
#include "fileio.h" #include "fileio.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "string-util.h" #include "string-util.h"
#include "tests.h"
#include "tmpfile-util.h" #include "tmpfile-util.h"
#include "util.h"
static void test_hostname_is_valid(void) { static void test_hostname_is_valid(void) {
assert_se(hostname_is_valid("foobar", 0)); assert_se(hostname_is_valid("foobar", 0));
@ -91,6 +91,55 @@ static void test_hostname_cleanup(void) {
assert_se(streq(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); assert_se(streq(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
} }
static void test_read_etc_hostname(void) {
char path[] = "/tmp/hostname.XXXXXX";
char *hostname;
int fd;
fd = mkostemp_safe(path);
assert(fd > 0);
close(fd);
/* simple hostname */
assert_se(write_string_file(path, "foo", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == 0);
assert_se(streq(hostname, "foo"));
hostname = mfree(hostname);
/* with comment */
assert_se(write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foo"));
hostname = mfree(hostname);
/* with comment and extra whitespace */
assert_se(write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foo"));
hostname = mfree(hostname);
/* cleans up name */
assert_se(write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == 0);
assert_se(hostname);
assert_se(streq(hostname, "foobar.com"));
hostname = mfree(hostname);
/* no value set */
hostname = (char*) 0x1234;
assert_se(write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE) == 0);
assert_se(read_etc_hostname(path, &hostname) == -ENOENT);
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
/* nonexisting file */
assert_se(read_etc_hostname("/non/existing", &hostname) == -ENOENT);
assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */
unlink(path);
}
static void test_hostname_malloc(void) { static void test_hostname_malloc(void) {
_cleanup_free_ char *h = NULL, *l = NULL; _cleanup_free_ char *h = NULL, *l = NULL;
@ -109,10 +158,12 @@ static void test_fallback_hostname(void) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
test_setup_logging(LOG_INFO); log_parse_environment();
log_open();
test_hostname_is_valid(); test_hostname_is_valid();
test_hostname_cleanup(); test_hostname_cleanup();
test_read_etc_hostname();
test_hostname_malloc(); test_hostname_malloc();
test_fallback_hostname(); test_fallback_hostname();

14
src/test/test-hostname.c Normal file
View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "hostname-setup.h"
#include "util.h"
int main(int argc, char* argv[]) {
int r;
r = hostname_setup();
if (r < 0)
log_error_errno(r, "hostname: %m");
return 0;
}

View File

@ -1,710 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* System Memory information
*
* Copyright (C) 2000-2002 Alan Cox <alan@redhat.com>
* Copyright (C) 2002-2020 Jean Delvare <jdelvare@suse.de>
* Copyright (C) 2020 Bastien Nocera <hadess@hadess.net>
*
* Unless specified otherwise, all references are aimed at the "System
* Management BIOS Reference Specification, Version 3.2.0" document,
* available from http://www.dmtf.org/standards/smbios.
*
* Note to contributors:
* Please reference every value you add or modify, especially if the
* information does not come from the above mentioned specification.
*
* Additional references:
* - Intel AP-485 revision 36
* "Intel Processor Identification and the CPUID Instruction"
* http://www.intel.com/support/processors/sb/cs-009861.htm
* - DMTF Common Information Model
* CIM Schema version 2.19.1
* http://www.dmtf.org/standards/cim/
* - IPMI 2.0 revision 1.0
* "Intelligent Platform Management Interface Specification"
* http://developer.intel.com/design/servers/ipmi/spec.htm
* - AMD publication #25481 revision 2.28
* "CPUID Specification"
* http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf
* - BIOS Integrity Services Application Programming Interface version 1.0
* http://www.intel.com/design/archives/wfm/downloads/bisspec.htm
* - DMTF DSP0239 version 1.1.0
* "Management Component Transport Protocol (MCTP) IDs and Codes"
* http://www.dmtf.org/standards/pmci
* - "TPM Main, Part 2 TPM Structures"
* Specification version 1.2, level 2, revision 116
* https://trustedcomputinggroup.org/tpm-main-specification/
* - "PC Client Platform TPM Profile (PTP) Specification"
* Family "2.0", Level 00, Revision 00.43, January 26, 2015
* https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/
* - "RedFish Host Interface Specification" (DMTF DSP0270)
* https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf
*/
#include <getopt.h>
#include "alloc-util.h"
#include "build.h"
#include "fileio.h"
#include "main-func.h"
#include "string-util.h"
#include "udev-util.h"
#include "unaligned.h"
#define SUPPORTED_SMBIOS_VER 0x030300
#define OUT_OF_SPEC_STR "<OUT OF SPEC>"
#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables"
#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point"
#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI"
/*
* Per SMBIOS v2.8.0 and later, all structures assume a little-endian
* ordering convention.
*/
#define WORD(x) (unaligned_read_le16(x))
#define DWORD(x) (unaligned_read_le32(x))
#define QWORD(x) (unaligned_read_le64(x))
struct dmi_header {
uint8_t type;
uint8_t length;
uint16_t handle;
const uint8_t *data;
};
static const char *arg_source_file = NULL;
static bool verify_checksum(const uint8_t *buf, size_t len) {
uint8_t sum = 0;
for (size_t a = 0; a < len; a++)
sum += buf[a];
return sum == 0;
}
/*
* Type-independant Stuff
*/
static const char *dmi_string(const struct dmi_header *dm, uint8_t s) {
const char *bp = (const char *) dm->data;
if (s == 0)
return "Not Specified";
bp += dm->length;
for (;s > 1 && !isempty(bp); s--)
bp += strlen(bp) + 1;
if (isempty(bp))
return "<BAD INDEX>";
return bp;
}
typedef enum {
MEMORY_SIZE_UNIT_BYTES,
MEMORY_SIZE_UNIT_KB
} MemorySizeUnit;
static void dmi_print_memory_size(
const char *attr_prefix, const char *attr_suffix,
int slot_num, uint64_t code, MemorySizeUnit unit) {
if (unit == MEMORY_SIZE_UNIT_KB)
code <<= 10;
if (slot_num >= 0)
printf("%s_%u_%s=%"PRIu64"\n", attr_prefix, slot_num, attr_suffix, code);
else
printf("%s_%s=%"PRIu64"\n", attr_prefix, attr_suffix, code);
}
/*
* 7.17 Physical Memory Array (Type 16)
*/
static void dmi_memory_array_location(uint8_t code) {
/* 7.17.1 */
static const char *location[] = {
[0x01] = "Other",
[0x02] = "Unknown",
[0x03] = "System Board Or Motherboard",
[0x04] = "ISA Add-on Card",
[0x05] = "EISA Add-on Card",
[0x06] = "PCI Add-on Card",
[0x07] = "MCA Add-on Card",
[0x08] = "PCMCIA Add-on Card",
[0x09] = "Proprietary Add-on Card",
[0x0A] = "NuBus",
};
static const char *location_0xA0[] = {
[0x00] = "PC-98/C20 Add-on Card", /* 0xA0 */
[0x01] = "PC-98/C24 Add-on Card", /* 0xA1 */
[0x02] = "PC-98/E Add-on Card", /* 0xA2 */
[0x03] = "PC-98/Local Bus Add-on Card", /* 0xA3 */
[0x04] = "CXL Flexbus 1.0", /* 0xA4 */
};
const char *str = OUT_OF_SPEC_STR;
if (code < ELEMENTSOF(location) && location[code])
str = location[code];
else if (code >= 0xA0 && code < (ELEMENTSOF(location_0xA0) + 0xA0))
str = location_0xA0[code - 0xA0];
printf("MEMORY_ARRAY_LOCATION=%s\n", str);
}
static void dmi_memory_array_ec_type(uint8_t code) {
/* 7.17.3 */
static const char *type[] = {
[0x01] = "Other",
[0x02] = "Unknown",
[0x03] = "None",
[0x04] = "Parity",
[0x05] = "Single-bit ECC",
[0x06] = "Multi-bit ECC",
[0x07] = "CRC",
};
if (code != 0x03) /* Do not print "None". */
printf("MEMORY_ARRAY_EC_TYPE=%s\n",
code < ELEMENTSOF(type) && type[code] ? type[code] : OUT_OF_SPEC_STR);
}
/*
* 7.18 Memory Device (Type 17)
*/
static void dmi_memory_device_string(
const char *attr_suffix, unsigned slot_num,
const struct dmi_header *h, uint8_t s) {
char *str;
str = strdupa(dmi_string(h, s));
str = strstrip(str);
if (!isempty(str))
printf("MEMORY_DEVICE_%u_%s=%s\n", slot_num, attr_suffix, str);
}
static void dmi_memory_device_width(
const char *attr_suffix,
unsigned slot_num, uint16_t code) {
/* If no memory module is present, width may be 0 */
if (!IN_SET(code, 0, 0xFFFF))
printf("MEMORY_DEVICE_%u_%s=%u\n", slot_num, attr_suffix, code);
}
static void dmi_memory_device_size(unsigned slot_num, uint16_t code) {
if (code == 0)
return (void) printf("MEMORY_DEVICE_%u_PRESENT=0\n", slot_num);
if (code == 0xFFFF)
return;
uint64_t s = code & 0x7FFF;
if (!(code & 0x8000))
s <<= 10;
dmi_print_memory_size("MEMORY_DEVICE", "SIZE", slot_num, s, MEMORY_SIZE_UNIT_KB);
}
static void dmi_memory_device_extended_size(unsigned slot_num, uint32_t code) {
uint64_t capacity = (uint64_t) code * 1024 * 1024;
printf("MEMORY_DEVICE_%u_SIZE=%"PRIu64"\n", slot_num, capacity);
}
static void dmi_memory_device_rank(unsigned slot_num, uint8_t code) {
code &= 0x0F;
if (code != 0)
printf("MEMORY_DEVICE_%u_RANK=%u\n", slot_num, code);
}
static void dmi_memory_device_voltage_value(
const char *attr_suffix,
unsigned slot_num, uint16_t code) {
if (code == 0)
return;
if (code % 100 != 0)
printf("MEMORY_DEVICE_%u_%s=%g\n", slot_num, attr_suffix, (double)code / 1000);
else
printf("MEMORY_DEVICE_%u_%s=%.1g\n", slot_num, attr_suffix, (double)code / 1000);
}
static void dmi_memory_device_form_factor(unsigned slot_num, uint8_t code) {
/* 7.18.1 */
static const char *form_factor[] = {
[0x01] = "Other",
[0x02] = "Unknown",
[0x03] = "SIMM",
[0x04] = "SIP",
[0x05] = "Chip",
[0x06] = "DIP",
[0x07] = "ZIP",
[0x08] = "Proprietary Card",
[0x09] = "DIMM",
[0x0A] = "TSOP",
[0x0B] = "Row Of Chips",
[0x0C] = "RIMM",
[0x0D] = "SODIMM",
[0x0E] = "SRIMM",
[0x0F] = "FB-DIMM",
[0x10] = "Die",
};
printf("MEMORY_DEVICE_%u_FORM_FACTOR=%s\n", slot_num,
code < ELEMENTSOF(form_factor) && form_factor[code] ? form_factor[code] : OUT_OF_SPEC_STR);
}
static void dmi_memory_device_set(unsigned slot_num, uint8_t code) {
if (code == 0xFF)
printf("MEMORY_DEVICE_%u_SET=%s\n", slot_num, "Unknown");
else if (code != 0)
printf("MEMORY_DEVICE_%u_SET=%"PRIu8"\n", slot_num, code);
}
static void dmi_memory_device_type(unsigned slot_num, uint8_t code) {
/* 7.18.2 */
static const char *type[] = {
[0x01] = "Other",
[0x02] = "Unknown",
[0x03] = "DRAM",
[0x04] = "EDRAM",
[0x05] = "VRAM",
[0x06] = "SRAM",
[0x07] = "RAM",
[0x08] = "ROM",
[0x09] = "Flash",
[0x0A] = "EEPROM",
[0x0B] = "FEPROM",
[0x0C] = "EPROM",
[0x0D] = "CDRAM",
[0x0E] = "3DRAM",
[0x0F] = "SDRAM",
[0x10] = "SGRAM",
[0x11] = "RDRAM",
[0x12] = "DDR",
[0x13] = "DDR2",
[0x14] = "DDR2 FB-DIMM",
[0x15] = "Reserved",
[0x16] = "Reserved",
[0x17] = "Reserved",
[0x18] = "DDR3",
[0x19] = "FBD2",
[0x1A] = "DDR4",
[0x1B] = "LPDDR",
[0x1C] = "LPDDR2",
[0x1D] = "LPDDR3",
[0x1E] = "LPDDR4",
[0x1F] = "Logical non-volatile device",
[0x20] = "HBM",
[0x21] = "HBM2",
};
printf("MEMORY_DEVICE_%u_TYPE=%s\n", slot_num,
code < ELEMENTSOF(type) && type[code] ? type[code] : OUT_OF_SPEC_STR);
}
static void dmi_memory_device_type_detail(unsigned slot_num, uint16_t code) {
/* 7.18.3 */
static const char *detail[] = {
[1] = "Other",
[2] = "Unknown",
[3] = "Fast-paged",
[4] = "Static Column",
[5] = "Pseudo-static",
[6] = "RAMBus",
[7] = "Synchronous",
[8] = "CMOS",
[9] = "EDO",
[10] = "Window DRAM",
[11] = "Cache DRAM",
[12] = "Non-Volatile",
[13] = "Registered (Buffered)",
[14] = "Unbuffered (Unregistered)",
[15] = "LRDIMM",
};
if ((code & 0xFFFE) == 0)
printf("MEMORY_DEVICE_%u_TYPE_DETAIL=%s\n", slot_num, "None");
else {
bool first_element = true;
printf("MEMORY_DEVICE_%u_TYPE_DETAIL=", slot_num);
for (size_t i = 1; i < ELEMENTSOF(detail); i++)
if (code & (1 << i)) {
printf("%s%s", first_element ? "" : " ", detail[i]);
first_element = false;
}
printf("\n");
}
}
static void dmi_memory_device_speed(
const char *attr_suffix,
unsigned slot_num, uint16_t code) {
if (code != 0)
printf("MEMORY_DEVICE_%u_%s=%u\n", slot_num, attr_suffix, code);
}
static void dmi_memory_device_technology(unsigned slot_num, uint8_t code) {
/* 7.18.6 */
static const char * const technology[] = {
[0x01] = "Other",
[0x02] = "Unknown",
[0x03] = "DRAM",
[0x04] = "NVDIMM-N",
[0x05] = "NVDIMM-F",
[0x06] = "NVDIMM-P",
[0x07] = "Intel Optane DC persistent memory",
};
printf("MEMORY_DEVICE_%u_MEMORY_TECHNOLOGY=%s\n", slot_num,
code < ELEMENTSOF(technology) && technology[code] ? technology[code] : OUT_OF_SPEC_STR);
}
static void dmi_memory_device_operating_mode_capability(unsigned slot_num, uint16_t code) {
/* 7.18.7 */
static const char * const mode[] = {
[1] = "Other",
[2] = "Unknown",
[3] = "Volatile memory",
[4] = "Byte-accessible persistent memory",
[5] = "Block-accessible persistent memory",
};
if ((code & 0xFFFE) != 0) {
bool first_element = true;
printf("MEMORY_DEVICE_%u_MEMORY_OPERATING_MODE_CAPABILITY=", slot_num);
for (size_t i = 1; i < ELEMENTSOF(mode); i++)
if (code & (1 << i)) {
printf("%s%s", first_element ? "" : " ", mode[i]);
first_element = false;
}
printf("\n");
}
}
static void dmi_memory_device_manufacturer_id(
const char *attr_suffix,
unsigned slot_num, uint16_t code) {
/* 7.18.8 */
/* 7.18.10 */
/* LSB is 7-bit Odd Parity number of continuation codes */
if (code != 0)
printf("MEMORY_DEVICE_%u_%s=Bank %d, Hex 0x%02X\n", slot_num, attr_suffix,
(code & 0x7F) + 1, code >> 8);
}
static void dmi_memory_device_product_id(
const char *attr_suffix,
unsigned slot_num, uint16_t code) {
/* 7.18.9 */
/* 7.18.11 */
if (code != 0)
printf("MEMORY_DEVICE_%u_%s=0x%04X\n", slot_num, attr_suffix, code);
}
static void dmi_memory_device_size_detail(
const char *attr_suffix,
unsigned slot_num, uint64_t code) {
/* 7.18.12 */
/* 7.18.13 */
if (!IN_SET(code, 0x0LU, 0xFFFFFFFFFFFFFFFFLU))
dmi_print_memory_size("MEMORY_DEVICE", attr_suffix, slot_num, code, MEMORY_SIZE_UNIT_BYTES);
}
static void dmi_decode(const struct dmi_header *h) {
const uint8_t *data = h->data;
static unsigned next_slot_num = 0;
unsigned slot_num;
/*
* Note: DMI types 37 and 42 are untested
*/
switch (h->type) {
case 16: /* 7.17 Physical Memory Array */
log_debug("Physical Memory Array");
if (h->length < 0x0F)
break;
if (data[0x05] != 0x03) /* 7.17.2, Use == "System Memory" */
break;
log_debug("Use: System Memory");
dmi_memory_array_location(data[0x04]);
dmi_memory_array_ec_type(data[0x06]);
if (DWORD(data + 0x07) != 0x80000000)
dmi_print_memory_size("MEMORY_ARRAY", "MAX_CAPACITY", -1, DWORD(data + 0x07), MEMORY_SIZE_UNIT_KB);
else if (h->length >= 0x17)
dmi_print_memory_size("MEMORY_ARRAY", "MAX_CAPACITY", -1, QWORD(data + 0x0F), MEMORY_SIZE_UNIT_BYTES);
printf("MEMORY_ARRAY_NUM_DEVICES=%u\n", WORD(data + 0x0D));
break;
case 17: /* 7.18 Memory Device */
slot_num = next_slot_num;
next_slot_num++;
log_debug("Memory Device");
if (h->length < 0x15)
break;
dmi_memory_device_width("TOTAL_WIDTH", slot_num, WORD(data + 0x08));
dmi_memory_device_width("DATA_WIDTH", slot_num, WORD(data + 0x0A));
if (h->length >= 0x20 && WORD(data + 0x0C) == 0x7FFF)
dmi_memory_device_extended_size(slot_num, DWORD(data + 0x1C));
else
dmi_memory_device_size(slot_num, WORD(data + 0x0C));
dmi_memory_device_form_factor(slot_num, data[0x0E]);
dmi_memory_device_set(slot_num, data[0x0F]);
dmi_memory_device_string("LOCATOR", slot_num, h, data[0x10]);
dmi_memory_device_string("BANK_LOCATOR", slot_num, h, data[0x11]);
dmi_memory_device_type(slot_num, data[0x12]);
dmi_memory_device_type_detail(slot_num, WORD(data + 0x13));
if (h->length < 0x17)
break;
dmi_memory_device_speed("SPEED_MTS", slot_num, WORD(data + 0x15));
if (h->length < 0x1B)
break;
dmi_memory_device_string("MANUFACTURER", slot_num, h, data[0x17]);
dmi_memory_device_string("SERIAL_NUMBER", slot_num, h, data[0x18]);
dmi_memory_device_string("ASSET_TAG", slot_num, h, data[0x19]);
dmi_memory_device_string("PART_NUMBER", slot_num, h, data[0x1A]);
if (h->length < 0x1C)
break;
dmi_memory_device_rank(slot_num, data[0x1B]);
if (h->length < 0x22)
break;
dmi_memory_device_speed("CONFIGURED_SPEED_MTS", slot_num, WORD(data + 0x20));
if (h->length < 0x28)
break;
dmi_memory_device_voltage_value("MINIMUM_VOLTAGE", slot_num, WORD(data + 0x22));
dmi_memory_device_voltage_value("MAXIMUM_VOLTAGE", slot_num, WORD(data + 0x24));
dmi_memory_device_voltage_value("CONFIGURED_VOLTAGE", slot_num, WORD(data + 0x26));
if (h->length < 0x34)
break;
dmi_memory_device_technology(slot_num, data[0x28]);
dmi_memory_device_operating_mode_capability(slot_num, WORD(data + 0x29));
dmi_memory_device_string("FIRMWARE_VERSION", slot_num, h, data[0x2B]);
dmi_memory_device_manufacturer_id("MODULE_MANUFACTURER_ID", slot_num, WORD(data + 0x2C));
dmi_memory_device_product_id("MODULE_PRODUCT_ID", slot_num, WORD(data + 0x2E));
dmi_memory_device_manufacturer_id("MEMORY_SUBSYSTEM_CONTROLLER_MANUFACTURER_ID",
slot_num, WORD(data + 0x30));
dmi_memory_device_product_id("MEMORY_SUBSYSTEM_CONTROLLER_PRODUCT_ID",
slot_num, WORD(data + 0x32));
if (h->length < 0x3C)
break;
dmi_memory_device_size_detail("NON_VOLATILE_SIZE", slot_num, QWORD(data + 0x34));
if (h->length < 0x44)
break;
dmi_memory_device_size_detail("VOLATILE_SIZE", slot_num, QWORD(data + 0x3C));
if (h->length < 0x4C)
break;
dmi_memory_device_size_detail("CACHE_SIZE", slot_num, QWORD(data + 0x44));
if (h->length < 0x54)
break;
dmi_memory_device_size_detail("LOGICAL_SIZE", slot_num, QWORD(data + 0x4C));
break;
}
}
static void dmi_table_decode(const uint8_t *buf, size_t len, uint16_t num) {
const uint8_t *data = buf;
/* 4 is the length of an SMBIOS structure header */
for (uint16_t i = 0; (i < num || num == 0) && data + 4 <= buf + len; i++) {
struct dmi_header h = (struct dmi_header) {
.type = data[0],
.length = data[1],
.handle = WORD(data + 2),
.data = data,
};
bool display = !IN_SET(h.type, 126, 127);
const uint8_t *next;
/* If a short entry is found (less than 4 bytes), not only it
* is invalid, but we cannot reliably locate the next entry.
* Better stop at this point, and let the user know his/her
* table is broken. */
if (h.length < 4)
break;
/* In quiet mode, stop decoding at end of table marker */
if (h.type == 127)
break;
/* Look for the next handle */
next = data + h.length;
while ((size_t)(next - buf + 1) < len && (next[0] != 0 || next[1] != 0))
next++;
next += 2;
/* Make sure the whole structure fits in the table */
if ((size_t)(next - buf) > len)
break;
if (display)
dmi_decode(&h);
data = next;
}
}
static int dmi_table(int64_t base, uint32_t len, uint16_t num, const char *devmem, bool no_file_offset) {
_cleanup_free_ uint8_t *buf = NULL;
size_t size;
int r;
/*
* When reading from sysfs or from a dump file, the file may be
* shorter than announced. For SMBIOS v3 this is expcted, as we
* only know the maximum table size, not the actual table size.
* For older implementations (and for SMBIOS v3 too), this
* would be the result of the kernel truncating the table on
* parse error.
*/
r = read_full_file_full(AT_FDCWD, devmem, no_file_offset ? 0 : base, len,
0, NULL, (char **) &buf, &size);
if (r < 0)
return log_error_errno(r, "Failed to read table: %m");
dmi_table_decode(buf, size, num);
return 0;
}
/* Same thing for SMBIOS3 entry points */
static int smbios3_decode(const uint8_t *buf, const char *devmem, bool no_file_offset) {
uint64_t offset;
/* Don't let checksum run beyond the buffer */
if (buf[0x06] > 0x20)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Entry point length too large (%"PRIu8" bytes, expected %u).",
buf[0x06], 0x18U);
if (!verify_checksum(buf, buf[0x06]))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Faied to verify checksum.");
offset = QWORD(buf + 0x10);
if (!no_file_offset && (offset >> 32) != 0 && sizeof(int64_t) < 8)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "64-bit addresses not supported.");
return dmi_table(offset, DWORD(buf + 0x0C), 0, devmem, no_file_offset);
}
static int smbios_decode(const uint8_t *buf, const char *devmem, bool no_file_offset) {
/* Don't let checksum run beyond the buffer */
if (buf[0x05] > 0x20)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Entry point length too large (%"PRIu8" bytes, expected %u).",
buf[0x05], 0x1FU);
if (!verify_checksum(buf, buf[0x05])
|| memcmp(buf + 0x10, "_DMI_", 5) != 0
|| !verify_checksum(buf + 0x10, 0x0F))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to verify checksum.");
return dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C),
devmem, no_file_offset);
}
static int legacy_decode(const uint8_t *buf, const char *devmem, bool no_file_offset) {
if (!verify_checksum(buf, 0x0F))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to verify checksum.");
return dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C),
devmem, no_file_offset);
}
static int help(void) {
printf("Usage: %s [options]\n"
" -F,--from-dump FILE read DMI information from a binary file\n"
" -h,--help print this help text\n\n",
program_invocation_short_name);
return 0;
}
static int parse_argv(int argc, char * const *argv) {
static const struct option options[] = {
{ "from-dump", required_argument, NULL, 'F' },
{ "version", no_argument, NULL, 'V' },
{ "help", no_argument, NULL, 'h' },
{}
};
int c;
while ((c = getopt_long(argc, argv, "F:hV", options, NULL)) >= 0)
switch (c) {
case 'F':
arg_source_file = optarg;
break;
case 'V':
printf("%s\n", GIT_VERSION);
return 0;
case 'h':
return help();
case '?':
return -EINVAL;
default:
assert_not_reached("Unknown option");
}
return 1;
}
static int run(int argc, char* const* argv) {
_cleanup_free_ uint8_t *buf = NULL;
bool no_file_offset = false;
size_t size;
int r;
log_set_target(LOG_TARGET_AUTO);
udev_parse_config();
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
/* Read from dump if so instructed */
r = read_full_file_full(AT_FDCWD,
arg_source_file ?: SYS_ENTRY_FILE,
0, 0x20, 0, NULL, (char **) &buf, &size);
if (r < 0)
return log_full_errno(!arg_source_file && r == -ENOENT ? LOG_DEBUG : LOG_ERR,
r, "Reading \"%s\" failed: %m",
arg_source_file ?: SYS_ENTRY_FILE);
if (!arg_source_file) {
arg_source_file = SYS_TABLE_FILE;
no_file_offset = true;
}
if (size >= 24 && memory_startswith(buf, size, "_SM3_"))
return smbios3_decode(buf, arg_source_file, no_file_offset);
if (size >= 31 && memory_startswith(buf, size, "_SM_"))
return smbios_decode(buf, arg_source_file, no_file_offset);
if (size >= 15 && memory_startswith(buf, size, "_DMI_"))
return legacy_decode(buf, arg_source_file, no_file_offset);
return -EINVAL;
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -174,7 +174,6 @@ foreach prog : [['ata_id/ata_id.c'],
'scsi_id/scsi_serial.c', 'scsi_id/scsi_serial.c',
'scsi_id/scsi.h'], 'scsi_id/scsi.h'],
['v4l_id/v4l_id.c'], ['v4l_id/v4l_id.c'],
['dmi_memory_id/dmi_memory_id.c'],
['mtd_probe/mtd_probe.c', ['mtd_probe/mtd_probe.c',
'mtd_probe/mtd_probe.h', 'mtd_probe/mtd_probe.h',
'mtd_probe/probe_smartmedia.c']] 'mtd_probe/probe_smartmedia.c']]

View File

@ -1,33 +0,0 @@
MEMORY_ARRAY_LOCATION=System Board Or Motherboard
MEMORY_ARRAY_MAX_CAPACITY=34359738368
MEMORY_ARRAY_NUM_DEVICES=2
MEMORY_DEVICE_0_TOTAL_WIDTH=64
MEMORY_DEVICE_0_DATA_WIDTH=64
MEMORY_DEVICE_0_SIZE=4294967296
MEMORY_DEVICE_0_FORM_FACTOR=SODIMM
MEMORY_DEVICE_0_LOCATOR=ChannelA-DIMM0
MEMORY_DEVICE_0_BANK_LOCATOR=BANK 0
MEMORY_DEVICE_0_TYPE=DDR4
MEMORY_DEVICE_0_TYPE_DETAIL=Synchronous Unbuffered (Unregistered)
MEMORY_DEVICE_0_SPEED_MTS=2400
MEMORY_DEVICE_0_MANUFACTURER=0000
MEMORY_DEVICE_0_SERIAL_NUMBER=00000000
MEMORY_DEVICE_0_ASSET_TAG=None
MEMORY_DEVICE_0_RANK=1
MEMORY_DEVICE_0_CONFIGURED_SPEED_MTS=2400
MEMORY_DEVICE_0_CONFIGURED_VOLTAGE=1
MEMORY_DEVICE_1_TOTAL_WIDTH=64
MEMORY_DEVICE_1_DATA_WIDTH=64
MEMORY_DEVICE_1_SIZE=4294967296
MEMORY_DEVICE_1_FORM_FACTOR=SODIMM
MEMORY_DEVICE_1_LOCATOR=ChannelB-DIMM0
MEMORY_DEVICE_1_BANK_LOCATOR=BANK 2
MEMORY_DEVICE_1_TYPE=DDR4
MEMORY_DEVICE_1_TYPE_DETAIL=Synchronous Unbuffered (Unregistered)
MEMORY_DEVICE_1_SPEED_MTS=2400
MEMORY_DEVICE_1_MANUFACTURER=0000
MEMORY_DEVICE_1_SERIAL_NUMBER=00000000
MEMORY_DEVICE_1_ASSET_TAG=None
MEMORY_DEVICE_1_RANK=1
MEMORY_DEVICE_1_CONFIGURED_SPEED_MTS=2400
MEMORY_DEVICE_1_CONFIGURED_VOLTAGE=1

View File

@ -1,67 +0,0 @@
MEMORY_ARRAY_LOCATION=System Board Or Motherboard
MEMORY_ARRAY_MAX_CAPACITY=68719476736
MEMORY_ARRAY_NUM_DEVICES=4
MEMORY_DEVICE_0_TOTAL_WIDTH=64
MEMORY_DEVICE_0_DATA_WIDTH=64
MEMORY_DEVICE_0_SIZE=8589934592
MEMORY_DEVICE_0_FORM_FACTOR=DIMM
MEMORY_DEVICE_0_LOCATOR=ChannelA-DIMM0
MEMORY_DEVICE_0_BANK_LOCATOR=BANK 0
MEMORY_DEVICE_0_TYPE=DDR4
MEMORY_DEVICE_0_TYPE_DETAIL=Synchronous
MEMORY_DEVICE_0_SPEED_MTS=2667
MEMORY_DEVICE_0_MANUFACTURER=Samsung
MEMORY_DEVICE_0_SERIAL_NUMBER=416433E9
MEMORY_DEVICE_0_ASSET_TAG=9876543210
MEMORY_DEVICE_0_PART_NUMBER=M378A1K43CB2-CTD
MEMORY_DEVICE_0_RANK=1
MEMORY_DEVICE_0_CONFIGURED_SPEED_MTS=2400
MEMORY_DEVICE_0_MINIMUM_VOLTAGE=1
MEMORY_DEVICE_0_MAXIMUM_VOLTAGE=1
MEMORY_DEVICE_0_CONFIGURED_VOLTAGE=1
MEMORY_DEVICE_1_TOTAL_WIDTH=64
MEMORY_DEVICE_1_DATA_WIDTH=64
MEMORY_DEVICE_1_SIZE=8589934592
MEMORY_DEVICE_1_FORM_FACTOR=DIMM
MEMORY_DEVICE_1_LOCATOR=ChannelA-DIMM1
MEMORY_DEVICE_1_BANK_LOCATOR=BANK 1
MEMORY_DEVICE_1_TYPE=DDR4
MEMORY_DEVICE_1_TYPE_DETAIL=Synchronous
MEMORY_DEVICE_1_SPEED_MTS=2400
MEMORY_DEVICE_1_MANUFACTURER=859B
MEMORY_DEVICE_1_SERIAL_NUMBER=A02550A6
MEMORY_DEVICE_1_ASSET_TAG=9876543210
MEMORY_DEVICE_1_PART_NUMBER=BLT8G4D26AFTA.16FBD
MEMORY_DEVICE_1_RANK=2
MEMORY_DEVICE_1_CONFIGURED_SPEED_MTS=2400
MEMORY_DEVICE_1_MINIMUM_VOLTAGE=1
MEMORY_DEVICE_1_MAXIMUM_VOLTAGE=1
MEMORY_DEVICE_1_CONFIGURED_VOLTAGE=1
MEMORY_DEVICE_2_PRESENT=0
MEMORY_DEVICE_2_FORM_FACTOR=Unknown
MEMORY_DEVICE_2_LOCATOR=ChannelB-DIMM0
MEMORY_DEVICE_2_BANK_LOCATOR=BANK 2
MEMORY_DEVICE_2_TYPE=Unknown
MEMORY_DEVICE_2_TYPE_DETAIL=None
MEMORY_DEVICE_2_MANUFACTURER=Not Specified
MEMORY_DEVICE_2_SERIAL_NUMBER=Not Specified
MEMORY_DEVICE_2_ASSET_TAG=Not Specified
MEMORY_DEVICE_2_PART_NUMBER=Not Specified
MEMORY_DEVICE_3_TOTAL_WIDTH=64
MEMORY_DEVICE_3_DATA_WIDTH=64
MEMORY_DEVICE_3_SIZE=8589934592
MEMORY_DEVICE_3_FORM_FACTOR=DIMM
MEMORY_DEVICE_3_LOCATOR=ChannelB-DIMM1
MEMORY_DEVICE_3_BANK_LOCATOR=BANK 3
MEMORY_DEVICE_3_TYPE=DDR4
MEMORY_DEVICE_3_TYPE_DETAIL=Synchronous
MEMORY_DEVICE_3_SPEED_MTS=2400
MEMORY_DEVICE_3_MANUFACTURER=859B
MEMORY_DEVICE_3_SERIAL_NUMBER=A0254F38
MEMORY_DEVICE_3_ASSET_TAG=9876543210
MEMORY_DEVICE_3_PART_NUMBER=BLT8G4D26AFTA.16FBD
MEMORY_DEVICE_3_RANK=2
MEMORY_DEVICE_3_CONFIGURED_SPEED_MTS=2400
MEMORY_DEVICE_3_MINIMUM_VOLTAGE=1
MEMORY_DEVICE_3_MAXIMUM_VOLTAGE=1
MEMORY_DEVICE_3_CONFIGURED_VOLTAGE=1

View File

@ -133,11 +133,4 @@ if conf.get('ENABLE_HWDB') == 1
endif endif
endif endif
if want_tests != false
udev_dmi_memory_id_test = find_program('udev-dmi-memory-id-test.sh')
test('udev-dmi-memory-id-test',
udev_dmi_memory_id_test,
timeout : 90)
endif
subdir('fuzz') subdir('fuzz')

View File

@ -1,31 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: LGPL-2.1-or-later
#
set -e
export SYSTEMD_LOG_LEVEL=info
ROOTDIR=$(dirname $(dirname $(readlink -f $0)))
UDEV_DMI_MEMORY_ID=./src/udev/dmi_memory_id
if [ ! -x "$UDEV_DMI_MEMORY_ID" ]; then
echo "$UDEV_DMI_MEMORY_ID does not exist, please build first"
exit 1
fi
D=$(mktemp --tmpdir --directory "udev-dmi-memory-id.XXXXXXXXXX")
trap "rm -rf '$D'" EXIT INT QUIT PIPE
for i in $ROOTDIR/test/dmidecode-dumps/*.bin ; do
$("$UDEV_DMI_MEMORY_ID" -F "$i" 2>&1 > "$D"/out.txt) && rc= || rc=$?
if [ -n "$rc" ]; then
echo "$UDEV_DMI_MEMORY_ID returned $rc"
exit $rc
fi
err=$(diff -u "$D"/out.txt "$i.txt" 2>&1) && rc= || rc=$?
if [ -n "$rc" ]; then
echo "Parsing DMI memory information from \"$i\" didn't match expected:"
echo "$err"
exit $rc
fi
done

View File

@ -221,7 +221,7 @@ else
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace $testUnit
systemctlCheckNUMAProperties $testUnit "default" "0" systemctlCheckNUMAProperties $testUnit "default" "0"
pid1StopUnit $testUnit pid1StopUnit $testUnit
# Mask must be ignored # Maks must be ignored
grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog
echo "Unit file NUMAPolicy support - Bind policy w/o mask" echo "Unit file NUMAPolicy support - Bind policy w/o mask"
@ -276,7 +276,7 @@ else
pid1StartUnitWithStrace $testUnit pid1StartUnitWithStrace $testUnit
systemctlCheckNUMAProperties $testUnit "local" "0" systemctlCheckNUMAProperties $testUnit "local" "0"
pid1StopUnit $testUnit pid1StopUnit $testUnit
# Mask must be ignored # Maks must be ignored
grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog
echo "Unit file CPUAffinity=NUMA support" echo "Unit file CPUAffinity=NUMA support"

View File

@ -32,7 +32,7 @@ ProtectKernelLogs=yes
ProtectKernelModules=yes ProtectKernelModules=yes
ProtectKernelTunables=yes ProtectKernelTunables=yes
ProtectSystem=strict ProtectSystem=strict
ReadWritePaths=/etc /run/systemd ReadWritePaths=/etc
RestrictAddressFamilies=AF_UNIX RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes RestrictNamespaces=yes
RestrictRealtime=yes RestrictRealtime=yes