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.
e4dde4e87d
...
a2be8be2cf
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1,2 +1 @@
|
|||||||
*.[ch] whitespace=tab-in-indent,trailing-space
|
*.[ch] whitespace=tab-in-indent,trailing-space
|
||||||
test/dmidecode-dumps/*.bin binary
|
|
||||||
|
|||||||
2
TODO
2
TODO
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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>Lennart’s
|
I.e. when the former is <literal>Lennart’s 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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
27
po/sv.po
27
po/sv.po
@ -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
|
||||||
|
|||||||
@ -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"
|
|
||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -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
@ -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 */
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
@ -212,27 +166,26 @@ 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_256(highlight_grey, HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK);
|
DEFINE_ANSI_FUNC(highlight_grey, HIGHLIGHT_GREY);
|
||||||
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);
|
||||||
|
|||||||
@ -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
62
src/core/hostname-setup.c
Normal 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;
|
||||||
|
}
|
||||||
4
src/core/hostname-setup.h
Normal file
4
src/core/hostname-setup.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
int hostname_setup(void);
|
||||||
@ -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"
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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;
|
||||||
@ -123,7 +123,7 @@ fuzzers += [
|
|||||||
[libshared],
|
[libshared],
|
||||||
[]],
|
[]],
|
||||||
|
|
||||||
[['src/fuzz/fuzz-hostname-setup.c'],
|
[['src/fuzz/fuzz-hostname-util.c'],
|
||||||
[libshared],
|
[libshared],
|
||||||
[]],
|
[]],
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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. */
|
||||||
|
|||||||
@ -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);
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -112,11 +112,6 @@ static void test_login(void) {
|
|||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
r = sd_session_is_active(session);
|
r = sd_session_is_active(session);
|
||||||
if (r == -ENXIO)
|
|
||||||
log_notice("sd_session_is_active() failed with ENXIO, it seems logind is not running.");
|
|
||||||
else {
|
|
||||||
/* All those tests will fail with ENXIO, so let's skip them. */
|
|
||||||
|
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
log_info("sd_session_is_active(\"%s\") → %s", session, yes_no(r));
|
log_info("sd_session_is_active(\"%s\") → %s", session, yes_no(r));
|
||||||
|
|
||||||
@ -180,7 +175,6 @@ static void test_login(void) {
|
|||||||
assert_se(sd_uid_get_state(u, &state2) == 0);
|
assert_se(sd_uid_get_state(u, &state2) == 0);
|
||||||
log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
|
log_info("sd_uid_get_state("UID_FMT", …) → %s", u, state2);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (seat) {
|
if (seat) {
|
||||||
_cleanup_free_ char *session2 = NULL, *buf = NULL;
|
_cleanup_free_ char *session2 = NULL, *buf = NULL;
|
||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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_;
|
|
||||||
|
|||||||
@ -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);
|
|
||||||
}
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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");
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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");
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -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
|
|
||||||
@ -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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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)
|
if (r < 0)
|
||||||
return r;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = *fw_ctx;
|
if (!iptc_commit(h))
|
||||||
if (ctx->firewall_backend == FW_BACKEND_NONE)
|
return -errno;
|
||||||
ctx->firewall_backend = firewall_backend_probe(ctx);
|
|
||||||
|
|
||||||
switch (ctx->firewall_backend) {
|
return 0;
|
||||||
case FW_BACKEND_NONE:
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
#if HAVE_LIBIPTC
|
|
||||||
case FW_BACKEND_IPTABLES:
|
|
||||||
return fw_iptables_add_masquerade(add, af, source, source_prefixlen);
|
|
||||||
#endif
|
|
||||||
case FW_BACKEND_NFTABLES:
|
|
||||||
return fw_nftables_add_masquerade(ctx, add, af, source, source_prefixlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = *fw_ctx;
|
/* Fill in second match */
|
||||||
if (ctx->firewall_backend == FW_BACKEND_NONE)
|
m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)) + msz);
|
||||||
ctx->firewall_backend = firewall_backend_probe(ctx);
|
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;
|
||||||
|
|
||||||
switch (ctx->firewall_backend) {
|
/* Fill in target part */
|
||||||
case FW_BACKEND_NONE:
|
t = ipt_get_target(entry);
|
||||||
return -EOPNOTSUPP;
|
t->u.target_size =
|
||||||
case FW_BACKEND_NFTABLES:
|
XT_ALIGN(sizeof(struct ipt_entry_target)) +
|
||||||
return fw_nftables_add_local_dnat(ctx, add, af, protocol, local_port, remote, remote_port, previous_remote);
|
XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat));
|
||||||
#if HAVE_LIBIPTC
|
strncpy(t->u.user.name, "DNAT", sizeof(t->u.user.name));
|
||||||
case FW_BACKEND_IPTABLES:
|
mr = (struct nf_nat_ipv4_multi_range_compat*) t->data;
|
||||||
return fw_iptables_add_local_dnat(add, af, protocol, local_port, remote, remote_port, previous_remote);
|
mr->rangesize = 1;
|
||||||
#endif
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -EOPNOTSUPP;
|
/* 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
|
||||||
@ -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);
|
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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));
|
||||||
|
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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'],
|
||||||
[],
|
[],
|
||||||
|
|||||||
@ -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");
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -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
14
src/test/test-hostname.c
Normal 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;
|
||||||
|
}
|
||||||
@ -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);
|
|
||||||
@ -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']]
|
||||||
|
|||||||
Binary file not shown.
@ -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
|
|
||||||
Binary file not shown.
@ -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
|
|
||||||
Binary file not shown.
@ -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')
|
||||||
|
|||||||
@ -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
|
|
||||||
@ -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"
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user