Compare commits

..

51 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek f8bff7805e
Merge pull request #16933 from poettering/copy-hardlinks
copy: optionally recreate hardlinks when copying file trees
2020-09-10 19:04:52 +02:00
Lennart Poettering 6ae05c9b14
Merge pull request #16947 from keszybz/socket-parsing-rework
Socket parsing rework
2020-09-10 16:47:37 +02:00
Zbigniew Jędrzejewski-Szmek f29d38b7d4
Merge pull request #17003 from yuwata/conf-parser-downgrade-log-level
tree-wide: downgrade log level in conf-parsers
2020-09-10 15:43:29 +02:00
Lennart Poettering 3a17308c2a
Merge pull request #16986 from yuwata/network-fix-routing-policy-rule-issue-16784
network: fix routing policy rule issue
2020-09-10 14:50:38 +02:00
Yu Watanabe 87adeabfb7 test-network: update tests for issue #16784 2020-09-10 18:57:07 +09:00
Yu Watanabe 17d2b2e4ef network: replace FRA_IFNAME -> FRA_IIFNAME
No functional change, as FRA_IFNAME is an alias of FRA_IIFNAME.
2020-09-10 18:57:07 +09:00
Yu Watanabe 2102d33cfb network: also process RTM_NEWRULE or RTM_DELRULE message which does not contain src and dst addresses
Fixes #16784.
2020-09-10 18:57:07 +09:00
Yu Watanabe bd1000b4a0 network: fix the default mask for FirewallMark=
And always send FRA_FWMASK if FirewallMark= is set.

C.f. b8964ed9fa

Partially fixes #16784.
2020-09-10 18:56:18 +09:00
Yu Watanabe c2d6fcb147 network: do not assign return value if the parse_fwmark_fwmask() fails
This also removes redundant logs, and makes input string not copied if
it does not contain '/'.
2020-09-10 18:19:03 +09:00
Yu Watanabe d85b0d69f1 network: add debug log for removing routing policy rules 2020-09-10 18:19:03 +09:00
Yu Watanabe 755dbda355 network: also logs priority of routing policy rules 2020-09-10 18:18:59 +09:00
Yu Watanabe b6c7c4a87b network: update log message for rtnl messages 2020-09-10 18:14:24 +09:00
Yu Watanabe 323dda7806 core: downgrade error level and ignore several non-critical errors 2020-09-10 16:24:31 +09:00
Yu Watanabe 144fb165fd homed: downgrade log level 2020-09-10 15:21:43 +09:00
Yu Watanabe adb5848706 journal: downgrade log level 2020-09-10 15:20:35 +09:00
Yu Watanabe 196d41bcde login: downgrade log level if the error will be ignored 2020-09-10 15:18:26 +09:00
Yu Watanabe a864170745 nspawn: downgrade log level if the error will be ignored 2020-09-10 15:16:14 +09:00
Yu Watanabe e459258f19 repart: downgrade log level 2020-09-10 15:08:13 +09:00
Yu Watanabe 94069bef23 resolve: downgrade error level when the error will be ignored 2020-09-10 15:06:29 +09:00
Yu Watanabe 34136e1503 resolve: check DNSSD service name template before assigning it 2020-09-10 15:05:19 +09:00
Yu Watanabe 7a602af041 conf-parser: logs about OOM error 2020-09-10 14:14:19 +09:00
Yu Watanabe 3de39a1ad4 conf-parser: use SYNTHETIC_ERRNO() at one more place 2020-09-10 14:13:56 +09:00
Yu Watanabe c56566530b timesync: downgrade error level when the error will be ignored 2020-09-10 14:13:26 +09:00
Yu Watanabe 40f04cde5b xdg-autostart-generator: downgrade error level when the error will be ignored 2020-09-10 14:07:56 +09:00
Yu Watanabe 8add8b508d vlan: downgrade error level if the error will be ignored 2020-09-10 13:59:04 +09:00
Yu Watanabe 4c382a8772 ethtool: downgrade log level when the error will be ignored 2020-09-10 13:59:04 +09:00
Yu Watanabe e3489e96b3 network: slightly update log message 2020-09-10 13:59:04 +09:00
Yu Watanabe 2ca601d8cb network do not ignore OOM error in config_parse_macsec_key_id() 2020-09-10 13:59:04 +09:00
Yu Watanabe 696c0832e2 network: use _cleanup_ attribute at one more place 2020-09-10 13:59:04 +09:00
Yu Watanabe a8a50f4fb7 network: do not ignore OOM error in wireguard_decode_key_and_warn() 2020-09-10 13:59:04 +09:00
Yu Watanabe 02241e4339 network: unify config_parse_wireguard_public_key() and config_parse_wireguard_preshared_key() 2020-09-10 13:57:39 +09:00
Yu Watanabe c799c93c62 udev: fix indentation
Follow-up for 90e30d767a.
2020-09-10 13:11:43 +09:00
Zbigniew Jędrzejewski-Szmek c097bf1f50 Minor simplification in sockaddr_un_set_path() 2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek 08224f38ac Use sockaddr_un_set_path() in socket_address_parse()
Two functional changes:
- "/" is now refused. The test is adjusted.
- The trailing NUL is *not* included in the returned size for abstract size. The
  comments in sockaddr_un_set_path() indicate that this is the right thing to do,
  and the code in socket_address_parse() wasn't doing that.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek a73569f180 shared/socket-netlink: set output in socket_address_parse_netlink() only on success 2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek a07ab56a49 Allow interface scopes to be specified in ListenStream=
Closes #12624.

The formatting in systemd.socket.xml is updated a bit.

Currently in_addr_port_ifindex_name_to_string() always prints the ifindex
numerically. This is not super useful since the interface numbers are
semi-random. Should we use interface names in preference?
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek c4c6ee3a95 resolved: drop duplicated check
The same conditional appears a few lines down.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek 44ab234734 shared: don't unconditionally set SOCK_STREAM as type in socket_address_parse()
We would set .type to a fake value. All real callers (outside of tests)
immediately overwrite .type with a proper value after calling
socket_address_parse(). So let's not set it and adjust the few places
that relied on it being set to the fake value.

socket_address_parse() is modernized to only set the output argument on
success.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek 75af1666d7 shared: make socket_address_parse use the generic parser for IPv[46] addresses
One special syntax is not supported anymore: "iface:port" would be parsed as an
interface name plus numerical port, equivalent to "[::]%iface:port". This was
added in 542563babd, but was undocumented, and we had no tests for it. It seems
that this actually wasn't doing anything useful, because the kernel only uses the
scope identifier for link-local addresses.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek 222eaaf937 Get rid of in_addr_port_from_string_auto() again
With the commit "shared/socket-netlink: only allow ifindex if explicitly supported"
this helper is not necessary anymore.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek c1f848d73c shared: check interface name validity in in_addr_port_ifindex_name_from_string_auto()
We don't try to resolve invalid ifnames as all. A different return
code is used. This difference will be verified later in test_socket_address_parse()
when socket_address_parse() is converted to use
in_addr_port_ifindex_name_from_string_auto().
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek b16d17a68a basic: show interface scope in sockaddr_pretty()
If the interface scope is specified, this changes the meaning of the address
quite significantly. Let's show the IPv6 scope_id if present.

Sadly we don't even have a test for sockaddr_pretty() output :(
This will be implicitly tested through socket_address_parse() later on.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek 2313524aa0 basic: convert ifname_valid_full() to take flags and allow numeric interfaces 2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek 25b2d602b9 shared/socket-netlink: only allow ifindex if explicitly supported
Instead of ignoring ifindex if not wanted, refuse it is the caller
does not allow it.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek 610618ff61 test-socket-netlink: print the proper expected string
We would use the return value from the tested function to decide
what to print as "expected", which is confusing when something is wrong
with the tested function.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek 38c30b35f3 test-in-addr-util: add log headers 2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek d491917c9f resolved: unify the two functions to create main stubs
There is a small functional difference: IP_TTL==1 is now also set for the UDP
socket. I assume that it wasn't set by mistake.
2020-09-10 00:46:44 +02:00
Zbigniew Jędrzejewski-Szmek b5febb3f56 resolved: unify the two functions to create extra stubs
There is a minor functional change:
IPV6_FREEBIND is set of IPv6 sockets, not IP_FREEBIND. This was missed in
af8b1384, but I noticed only after the merging the two functions.

And a not-so-minor functional chagnge:
7216a3b5dc changed manager_dns_stub_tcp_fd_extra() to return the fd even
if the source was already initialized, but it didn't do the same change for
manager_dns_stub_udp_fd_extra(), so it would return 0 in that case. But
0354029bf5 uses manager_dns_stub_udp_fd_extra() when preparing to call
manager_send(), and will pass 0 as the fd in that case. For both socket types
fd is now always returned.
2020-09-10 00:44:53 +02:00
Zbigniew Jędrzejewski-Szmek e4bed40f40 resolve: move handler functions higher
No functional change, preparation for subsequent refactoring.
2020-09-10 00:06:35 +02:00
Lennart Poettering 652d90407a tree-wide: copy hardlinks wherever we deal with possibly large OS-style trees
Fixes: #7382
2020-09-09 20:21:49 +02:00
Lennart Poettering dd480f7835 copy: optionally, reproduce hardlinks from source in destination
This is useful for duplicating trees that contain hardlinks: we keep
track of potential hardlinks and try to reproduce them within the
destination tree. (We do not hardlink between source and destination!).

This is useful for trees like ostree images which heavily use hardlinks
and which are otherwise exploded into separate copies of all files when
we duplicate the trees.
2020-09-09 20:21:29 +02:00
45 changed files with 1267 additions and 1045 deletions

View File

@ -200,22 +200,24 @@
</para> </para>
<para>If the address string is a string in the format <para>If the address string is a string in the format
v.w.x.y:z, it is read as IPv4 specifier for listening on an <literal><replaceable>v.w.x.y</replaceable>:<replaceable>z</replaceable></literal>, it is interpeted
address v.w.x.y on a port z.</para> as IPv4 address <replaceable>v.w.x.y</replaceable> and port <replaceable>z</replaceable>.</para>
<para>If the address string is a string in the format [x]:y,
it is read as IPv6 address x on a port y. Note that this might
make the service available via IPv4, too, depending on the
<varname>BindIPv6Only=</varname> setting (see below).
</para>
<para>If the address string is a string in the format <para>If the address string is a string in the format
<literal>vsock:x:y</literal>, it is read as CID <literal>x</literal> on <literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable></literal>, it is interpreted as
a port <literal>y</literal> address in the IPv6 address <replaceable>x</replaceable> and port <replaceable>y</replaceable>. An optional
<constant>AF_VSOCK</constant> family. The CID is a unique 32-bit interface scope (interface name or number) may be specifed after a <literal>%</literal> symbol:
integer identifier in <constant>AF_VSOCK</constant> analogous to an IP <literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable>%<replaceable>dev</replaceable></literal>.
address. Specifying the CID is optional, and may be set to the empty Interface scopes are only useful with link-local addresses, because the kernel ignores them in other
string.</para> cases. Note that if an address is specified as IPv6, it might still make the service available via
IPv4 too, depending on the <varname>BindIPv6Only=</varname> setting (see below).</para>
<para>If the address string is a string in the format
<literal>vsock:<replaceable>x</replaceable>:<replaceable>y</replaceable></literal>, it is read as CID
<replaceable>x</replaceable> on a port <replaceable>y</replaceable> address in the
<constant>AF_VSOCK</constant> family. The CID is a unique 32-bit integer identifier in
<constant>AF_VSOCK</constant> analogous to an IP address. Specifying the CID is optional, and may be
set to the empty string.</para>
<para>Note that <constant>SOCK_SEQPACKET</constant> (i.e. <para>Note that <constant>SOCK_SEQPACKET</constant> (i.e.
<varname>ListenSequentialPacket=</varname>) is only available <varname>ListenSequentialPacket=</varname>) is only available

View File

@ -1654,7 +1654,10 @@ int btrfs_subvol_snapshot_fd_full(
} else if (r < 0) } else if (r < 0)
return r; return r;
r = copy_directory_fd_full(old_fd, new_path, COPY_MERGE|COPY_REFLINK|COPY_SAME_MOUNT|(FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGINT) ? COPY_SIGINT : 0), progress_path, progress_bytes, userdata); r = copy_directory_fd_full(
old_fd, new_path,
COPY_MERGE|COPY_REFLINK|COPY_SAME_MOUNT|COPY_HARDLINKS|(FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGINT) ? COPY_SIGINT : 0),
progress_path, progress_bytes, userdata);
if (r < 0) if (r < 0)
goto fallback_fail; goto fallback_fail;

View File

@ -22,8 +22,10 @@
#include "missing_syscall.h" #include "missing_syscall.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "nulstr-util.h" #include "nulstr-util.h"
#include "rm-rf.h"
#include "selinux-util.h" #include "selinux-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "time-util.h" #include "time-util.h"
@ -394,6 +396,188 @@ static int fd_copy_symlink(
return 0; return 0;
} }
/* Encapsulates the database we store potential hardlink targets in */
typedef struct HardlinkContext {
int dir_fd; /* An fd to the directory we use as lookup table. Never AT_FDCWD. Lazily created, when
* we add the first entry. */
/* These two fields are used to create the hardlink repository directory above — via
* mkdirat(parent_fd, subdir) and are kept so that we can automatically remove the directory again
* when we are done. */
int parent_fd; /* Possibly AT_FDCWD */
char *subdir;
} HardlinkContext;
static int hardlink_context_setup(
HardlinkContext *c,
int dt,
const char *to,
CopyFlags copy_flags) {
_cleanup_close_ int dt_copy = -1;
int r;
assert(c);
assert(c->dir_fd < 0 && c->dir_fd != AT_FDCWD);
assert(c->parent_fd < 0);
assert(!c->subdir);
/* If hardlink recreation is requested we have to maintain a database of inodes that are potential
* hardlink sources. Given that generally disk sizes have to be assumed to be larger than what fits
* into physical RAM we cannot maintain that database in dynamic memory alone. Here we opt to
* maintain it on disk, to simplify things: inside the destination directory we'll maintain a
* temporary directory consisting of hardlinks of every inode we copied that might be subject of
* hardlinks. We can then use that as hardlink source later on. Yes, this means additional disk IO
* but thankfully Linux is optimized for this kind of thing. If this ever becomes a performance
* bottleneck we can certainly place an in-memory hash table in front of this, but for the beginning,
* let's keep things simple, and just use the disk as lookup table for inodes.
*
* Note that this should have zero performace impact as long as .n_link of all files copied remains
* <= 0, because in that case we will not actually allocate the hardlink inode lookup table directory
* on disk (we do so lazily, when the first candidate with .n_link > 1 is seen). This means, in the
* common case where hardlinks are not used at all or only for few files the fact that we store the
* table on disk shouldn't matter perfomance-wise. */
if (!FLAGS_SET(copy_flags, COPY_HARDLINKS))
return 0;
if (dt == AT_FDCWD)
dt_copy = AT_FDCWD;
else if (dt < 0)
return -EBADF;
else {
dt_copy = fcntl(dt, F_DUPFD_CLOEXEC, 3);
if (dt_copy < 0)
return -errno;
}
r = tempfn_random_child(to, "hardlink", &c->subdir);
if (r < 0)
return r;
c->parent_fd = TAKE_FD(dt_copy);
/* We don't actually create the directory we keep the table in here, that's done on-demand when the
* first entry is added, using hardlink_context_realize() below. */
return 1;
}
static int hardlink_context_realize(HardlinkContext *c) {
int r;
if (!c)
return 0;
if (c->dir_fd >= 0) /* Already realized */
return 1;
if (c->parent_fd < 0 && c->parent_fd != AT_FDCWD) /* Not configured */
return 0;
assert(c->subdir);
if (mkdirat(c->parent_fd, c->subdir, 0700) < 0)
return -errno;
c->dir_fd = openat(c->parent_fd, c->subdir, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
if (c->dir_fd < 0) {
r = -errno;
unlinkat(c->parent_fd, c->subdir, AT_REMOVEDIR);
return r;
}
return 1;
}
static void hardlink_context_destroy(HardlinkContext *c) {
int r;
assert(c);
/* Automatically remove the hardlink lookup table directory again after we are done. This is used via
* _cleanup_() so that we really delete this, even on failure. */
if (c->dir_fd >= 0) {
r = rm_rf_children(TAKE_FD(c->dir_fd), REMOVE_PHYSICAL, NULL); /* consumes dir_fd in all cases, even on failure */
if (r < 0)
log_debug_errno(r, "Failed to remove hardlink store (%s) contents, ignoring: %m", c->subdir);
assert(c->parent_fd >= 0 || c->parent_fd == AT_FDCWD);
assert(c->subdir);
if (unlinkat(c->parent_fd, c->subdir, AT_REMOVEDIR) < 0)
log_debug_errno(errno, "Failed to remove hardlink store (%s) directory, ignoring: %m", c->subdir);
}
assert_cc(AT_FDCWD < 0);
c->parent_fd = safe_close(c->parent_fd);
c->subdir = mfree(c->subdir);
}
static int try_hardlink(
HardlinkContext *c,
const struct stat *st,
int dt,
const char *to) {
char dev_ino[DECIMAL_STR_MAX(dev_t)*2 + DECIMAL_STR_MAX(uint64_t) + 4];
assert(st);
assert(dt >= 0 || dt == AT_FDCWD);
assert(to);
if (!c) /* No temporary hardlink directory, don't bother */
return 0;
if (st->st_nlink <= 1) /* Source not hardlinked, don't bother */
return 0;
if (c->dir_fd < 0) /* not yet realized, hence empty */
return 0;
xsprintf(dev_ino, "%u:%u:%" PRIu64, major(st->st_dev), minor(st->st_dev), (uint64_t) st->st_ino);
if (linkat(c->dir_fd, dev_ino, dt, to, 0) < 0) {
if (errno != ENOENT) /* doesn't exist in store yet */
log_debug_errno(errno, "Failed to hardlink %s to %s, ignoring: %m", dev_ino, to);
return 0;
}
return 1;
}
static int memorize_hardlink(
HardlinkContext *c,
const struct stat *st,
int dt,
const char *to) {
char dev_ino[DECIMAL_STR_MAX(dev_t)*2 + DECIMAL_STR_MAX(uint64_t) + 4];
int r;
assert(st);
assert(dt >= 0 || dt == AT_FDCWD);
assert(to);
if (!c) /* No temporary hardlink directory, don't bother */
return 0;
if (st->st_nlink <= 1) /* Source not hardlinked, don't bother */
return 0;
r = hardlink_context_realize(c); /* Create the hardlink store lazily */
if (r < 0)
return r;
xsprintf(dev_ino, "%u:%u:%" PRIu64, major(st->st_dev), minor(st->st_dev), (uint64_t) st->st_ino);
if (linkat(dt, to, c->dir_fd, dev_ino, 0) < 0) {
log_debug_errno(errno, "Failed to hardlink %s to %s, ignoring: %m", to, dev_ino);
return 0;
}
return 1;
}
static int fd_copy_regular( static int fd_copy_regular(
int df, int df,
const char *from, const char *from,
@ -403,6 +587,7 @@ static int fd_copy_regular(
uid_t override_uid, uid_t override_uid,
gid_t override_gid, gid_t override_gid,
CopyFlags copy_flags, CopyFlags copy_flags,
HardlinkContext *hardlink_context,
copy_progress_bytes_t progress, copy_progress_bytes_t progress,
void *userdata) { void *userdata) {
@ -414,6 +599,12 @@ static int fd_copy_regular(
assert(st); assert(st);
assert(to); assert(to);
r = try_hardlink(hardlink_context, st, dt, to);
if (r < 0)
return r;
if (r > 0) /* worked! */
return 0;
fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); fdf = openat(df, from, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fdf < 0) if (fdf < 0)
return -errno; return -errno;
@ -456,6 +647,7 @@ static int fd_copy_regular(
(void) unlinkat(dt, to, 0); (void) unlinkat(dt, to, 0);
} }
(void) memorize_hardlink(hardlink_context, st, dt, to);
return r; return r;
} }
@ -467,13 +659,20 @@ static int fd_copy_fifo(
const char *to, const char *to,
uid_t override_uid, uid_t override_uid,
gid_t override_gid, gid_t override_gid,
CopyFlags copy_flags) { CopyFlags copy_flags,
HardlinkContext *hardlink_context) {
int r; int r;
assert(from); assert(from);
assert(st); assert(st);
assert(to); assert(to);
r = try_hardlink(hardlink_context, st, dt, to);
if (r < 0)
return r;
if (r > 0) /* worked! */
return 0;
if (copy_flags & COPY_MAC_CREATE) { if (copy_flags & COPY_MAC_CREATE) {
r = mac_selinux_create_file_prepare_at(dt, to, S_IFIFO); r = mac_selinux_create_file_prepare_at(dt, to, S_IFIFO);
if (r < 0) if (r < 0)
@ -494,6 +693,7 @@ static int fd_copy_fifo(
if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
r = -errno; r = -errno;
(void) memorize_hardlink(hardlink_context, st, dt, to);
return r; return r;
} }
@ -505,13 +705,20 @@ static int fd_copy_node(
const char *to, const char *to,
uid_t override_uid, uid_t override_uid,
gid_t override_gid, gid_t override_gid,
CopyFlags copy_flags) { CopyFlags copy_flags,
HardlinkContext *hardlink_context) {
int r; int r;
assert(from); assert(from);
assert(st); assert(st);
assert(to); assert(to);
r = try_hardlink(hardlink_context, st, dt, to);
if (r < 0)
return r;
if (r > 0) /* worked! */
return 0;
if (copy_flags & COPY_MAC_CREATE) { if (copy_flags & COPY_MAC_CREATE) {
r = mac_selinux_create_file_prepare_at(dt, to, st->st_mode & S_IFMT); r = mac_selinux_create_file_prepare_at(dt, to, st->st_mode & S_IFMT);
if (r < 0) if (r < 0)
@ -532,6 +739,7 @@ static int fd_copy_node(
if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
r = -errno; r = -errno;
(void) memorize_hardlink(hardlink_context, st, dt, to);
return r; return r;
} }
@ -546,11 +754,17 @@ static int fd_copy_directory(
uid_t override_uid, uid_t override_uid,
gid_t override_gid, gid_t override_gid,
CopyFlags copy_flags, CopyFlags copy_flags,
HardlinkContext *hardlink_context,
const char *display_path, const char *display_path,
copy_progress_path_t progress_path, copy_progress_path_t progress_path,
copy_progress_bytes_t progress_bytes, copy_progress_bytes_t progress_bytes,
void *userdata) { void *userdata) {
_cleanup_(hardlink_context_destroy) HardlinkContext our_hardlink_context = {
.dir_fd = -1,
.parent_fd = -1,
};
_cleanup_close_ int fdf = -1, fdt = -1; _cleanup_close_ int fdf = -1, fdt = -1;
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
struct dirent *de; struct dirent *de;
@ -570,6 +784,16 @@ static int fd_copy_directory(
if (fdf < 0) if (fdf < 0)
return -errno; return -errno;
if (!hardlink_context) {
/* If recreating hardlinks is requested let's set up a context for that now. */
r = hardlink_context_setup(&our_hardlink_context, dt, to, copy_flags);
if (r < 0)
return r;
if (r > 0) /* It's enabled and allocated, let's now use the same context for all recursive
* invocations from here down */
hardlink_context = &our_hardlink_context;
}
d = take_fdopendir(&fdf); d = take_fdopendir(&fdf);
if (!d) if (!d)
return -errno; return -errno;
@ -668,15 +892,15 @@ static int fd_copy_directory(
continue; continue;
} }
q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags, child_display_path, progress_path, progress_bytes, userdata); q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags, hardlink_context, child_display_path, progress_path, progress_bytes, userdata);
} else if (S_ISREG(buf.st_mode)) } else if (S_ISREG(buf.st_mode))
q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags, progress_bytes, userdata); q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags, hardlink_context, progress_bytes, userdata);
else if (S_ISLNK(buf.st_mode)) else if (S_ISLNK(buf.st_mode))
q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags);
else if (S_ISFIFO(buf.st_mode)) else if (S_ISFIFO(buf.st_mode))
q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags, hardlink_context);
else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode)) else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags, hardlink_context);
else else
q = -EOPNOTSUPP; q = -EOPNOTSUPP;
@ -730,15 +954,15 @@ int copy_tree_at_full(
return -errno; return -errno;
if (S_ISREG(st.st_mode)) if (S_ISREG(st.st_mode))
return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, progress_bytes, userdata); return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL, progress_bytes, userdata);
else if (S_ISDIR(st.st_mode)) else if (S_ISDIR(st.st_mode))
return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, progress_path, progress_bytes, userdata); return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
else if (S_ISLNK(st.st_mode)) else if (S_ISLNK(st.st_mode))
return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
else if (S_ISFIFO(st.st_mode)) else if (S_ISFIFO(st.st_mode))
return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); return fd_copy_fifo(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode)) else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); return fd_copy_node(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, NULL);
else else
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -762,7 +986,7 @@ int copy_directory_fd_full(
if (!S_ISDIR(st.st_mode)) if (!S_ISDIR(st.st_mode))
return -ENOTDIR; return -ENOTDIR;
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, progress_path, progress_bytes, userdata); return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
} }
int copy_directory_full( int copy_directory_full(
@ -784,7 +1008,7 @@ int copy_directory_full(
if (!S_ISDIR(st.st_mode)) if (!S_ISDIR(st.st_mode))
return -ENOTDIR; return -ENOTDIR;
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, progress_path, progress_bytes, userdata); return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
} }
int copy_file_fd_full( int copy_file_fd_full(

View File

@ -17,6 +17,7 @@ typedef enum CopyFlags {
COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */ COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */ COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
COPY_MAC_CREATE = 1 << 7, /* Create files with the correct MAC label (currently SELinux only) */ COPY_MAC_CREATE = 1 << 7, /* Create files with the correct MAC label (currently SELinux only) */
COPY_HARDLINKS = 1 << 8, /* Try to reproduce hard links */
} CopyFlags; } CopyFlags;
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata); typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);

View File

@ -68,7 +68,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->sockaddr.in.sin_port == 0) if (a->sockaddr.in.sin_port == 0)
return -EINVAL; return -EINVAL;
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM)) if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL; return -EINVAL;
return 0; return 0;
@ -80,7 +80,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->sockaddr.in6.sin6_port == 0) if (a->sockaddr.in6.sin6_port == 0)
return -EINVAL; return -EINVAL;
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM)) if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL; return -EINVAL;
return 0; return 0;
@ -114,7 +114,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
} }
} }
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET)) if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET))
return -EINVAL; return -EINVAL;
return 0; return 0;
@ -124,7 +124,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->size != sizeof(struct sockaddr_nl)) if (a->size != sizeof(struct sockaddr_nl))
return -EINVAL; return -EINVAL;
if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM)) if (!IN_SET(a->type, 0, SOCK_RAW, SOCK_DGRAM))
return -EINVAL; return -EINVAL;
return 0; return 0;
@ -133,7 +133,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
if (a->size != sizeof(struct sockaddr_vm)) if (a->size != sizeof(struct sockaddr_vm))
return -EINVAL; return -EINVAL;
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM)) if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
return -EINVAL; return -EINVAL;
return 0; return 0;
@ -399,19 +399,23 @@ int sockaddr_pretty(
if (r < 0) if (r < 0)
return -ENOMEM; return -ENOMEM;
} else { } else {
char a[INET6_ADDRSTRLEN]; char a[INET6_ADDRSTRLEN], ifname[IF_NAMESIZE + 1];
inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)); inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a));
if (sa->in6.sin6_scope_id != 0)
format_ifname_full(sa->in6.sin6_scope_id, ifname, FORMAT_IFNAME_IFINDEX);
if (include_port) { if (include_port) {
r = asprintf(&p, r = asprintf(&p,
"[%s]:%u", "[%s]:%u%s%s",
a, a,
be16toh(sa->in6.sin6_port)); be16toh(sa->in6.sin6_port),
sa->in6.sin6_scope_id != 0 ? "%" : "",
sa->in6.sin6_scope_id != 0 ? ifname : "");
if (r < 0) if (r < 0)
return -ENOMEM; return -ENOMEM;
} else { } else {
p = strdup(a); p = sa->in6.sin6_scope_id != 0 ? strjoin(a, "%", ifname) : strdup(a);
if (!p) if (!p)
return -ENOMEM; return -ENOMEM;
} }
@ -686,17 +690,19 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
bool ifname_valid_full(const char *p, bool alternative) { bool ifname_valid_full(const char *p, IfnameValidFlags flags) {
bool numeric = true; bool numeric = true;
/* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
* but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We
* also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */ * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
assert(!(flags & ~_IFNAME_VALID_ALL));
if (isempty(p)) if (isempty(p))
return false; return false;
if (alternative) { if (flags & IFNAME_VALID_ALTERNATIVE) {
if (strlen(p) >= ALTIFNAMSIZ) if (strlen(p) >= ALTIFNAMSIZ)
return false; return false;
} else { } else {
@ -707,23 +713,28 @@ bool ifname_valid_full(const char *p, bool alternative) {
if (dot_or_dot_dot(p)) if (dot_or_dot_dot(p))
return false; return false;
while (*p) { for (const char *t = p; *t; t++) {
if ((unsigned char) *p >= 127U) if ((unsigned char) *t >= 127U)
return false; return false;
if ((unsigned char) *p <= 32U) if ((unsigned char) *t <= 32U)
return false; return false;
if (IN_SET(*p, ':', '/')) if (IN_SET(*t, ':', '/'))
return false; return false;
numeric = numeric && (*p >= '0' && *p <= '9'); numeric = numeric && (*t >= '0' && *t <= '9');
p++;
} }
if (numeric) if (numeric) {
if (!(flags & IFNAME_VALID_NUMERIC))
return false; return false;
/* Verify that the number is well-formatted and in range. */
if (parse_ifindex(p) < 0)
return false;
}
return true; return true;
} }
@ -1107,12 +1118,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
* reference paths in the abstract namespace that include NUL bytes in the name. */ * reference paths in the abstract namespace that include NUL bytes in the name. */
l = strlen(path); l = strlen(path);
if (l == 0) if (l < 2)
return -EINVAL; return -EINVAL;
if (!IN_SET(path[0], '/', '@')) if (!IN_SET(path[0], '/', '@'))
return -EINVAL; return -EINVAL;
if (path[1] == 0)
return -EINVAL;
/* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than /* Don't allow paths larger than the space in sockaddr_un. Note that we are a tiny bit more restrictive than
* the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket * the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket

View File

@ -130,9 +130,14 @@ static inline int fd_inc_rcvbuf(int fd, size_t n) {
int ip_tos_to_string_alloc(int i, char **s); int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s); int ip_tos_from_string(const char *s);
bool ifname_valid_full(const char *p, bool alternative); typedef enum {
IFNAME_VALID_ALTERNATIVE = 1 << 0,
IFNAME_VALID_NUMERIC = 1 << 1,
_IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC,
} IfnameValidFlags;
bool ifname_valid_full(const char *p, IfnameValidFlags flags);
static inline bool ifname_valid(const char *p) { static inline bool ifname_valid(const char *p) {
return ifname_valid_full(p, false); return ifname_valid_full(p, 0);
} }
bool address_label_valid(const char *p); bool address_label_valid(const char *p);

File diff suppressed because it is too large Load Diff

View File

@ -627,7 +627,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
} }
/* Try to copy as directory? */ /* Try to copy as directory? */
r = copy_directory_fd(source_fd, arg_target, COPY_REFLINK|COPY_MERGE_EMPTY|COPY_SIGINT); r = copy_directory_fd(source_fd, arg_target, COPY_REFLINK|COPY_MERGE_EMPTY|COPY_SIGINT|COPY_HARDLINKS);
if (r >= 0) if (r >= 0)
return 0; return 0;
if (r != -ENOTDIR) if (r != -ENOTDIR)
@ -699,9 +699,9 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
if (errno != ENOENT) if (errno != ENOENT)
return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target); return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target);
r = copy_tree_at(source_fd, ".", dfd, basename(arg_target), UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT); r = copy_tree_at(source_fd, ".", dfd, basename(arg_target), UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
} else } else
r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT); r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image); return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);

View File

@ -45,7 +45,7 @@ int config_parse_default_file_system_type(
assert(s); assert(s);
if (!isempty(rvalue) && !supported_fstype(rvalue)) { if (!isempty(rvalue) && !supported_fstype(rvalue)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Unsupported file system, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, 0, "Unsupported file system, ignoring: %s", rvalue);
return 0; return 0;
} }

View File

@ -2551,7 +2551,7 @@ int config_parse_line_max(
r = parse_size(rvalue, 1024, &v); r = parse_size(rvalue, 1024, &v);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse LineMax= value, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse LineMax= value, ignoring: %s", rvalue);
return 0; return 0;
} }
@ -2606,7 +2606,7 @@ int config_parse_compress(
if (r < 0) { if (r < 0) {
r = parse_size(rvalue, 1024, &compress->threshold_bytes); r = parse_size(rvalue, 1024, &compress->threshold_bytes);
if (r < 0) if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse Compress= value, ignoring: %s", rvalue); "Failed to parse Compress= value, ignoring: %s", rvalue);
else else
compress->enabled = true; compress->enabled = true;

View File

@ -466,12 +466,14 @@ int config_parse_n_autovts(
r = safe_atou(rvalue, &o); r = safe_atou(rvalue, &o);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse number of autovts, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse number of autovts, ignoring: %s", rvalue);
return 0; return 0;
} }
if (o > 15) { if (o > 15) {
log_syntax(unit, LOG_ERR, filename, line, r, "A maximum of 15 autovts are supported, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, 0,
"A maximum of 15 autovts are supported, ignoring: %s", rvalue);
return 0; return 0;
} }

View File

@ -919,7 +919,7 @@ int config_parse_tmpfs_size(
if (r >= 0 && (k <= 0 || (uint64_t) (size_t) k != k)) if (r >= 0 && (k <= 0 || (uint64_t) (size_t) k != k))
r = -ERANGE; r = -ERANGE;
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse size value '%s', ignoring: %m", rvalue);
return 0; return 0;
} }

View File

@ -1066,7 +1066,7 @@ finish:
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) { int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *src, *dest, *host_path, *container_path, *host_basename, *container_basename, *container_dirname; const char *src, *dest, *host_path, *container_path, *host_basename, *container_basename, *container_dirname;
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 }; _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE; CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS;
_cleanup_close_ int hostfd = -1; _cleanup_close_ int hostfd = -1;
Machine *m = userdata; Machine *m = userdata;
bool copy_from; bool copy_from;

View File

@ -847,13 +847,16 @@ int config_parse_macsec_key_id(
return log_oom(); return log_oom();
r = unhexmem(rvalue, strlen(rvalue), &p, &l); r = unhexmem(rvalue, strlen(rvalue), &p, &l);
if (r == -ENOMEM)
return log_oom();
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse KeyId \"%s\": %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse KeyId=%s, ignoring assignment: %m", rvalue);
return 0; return 0;
} }
if (l > MACSEC_KEYID_LEN) { if (l > MACSEC_KEYID_LEN) {
log_syntax(unit, LOG_WARNING, filename, line, 0, log_syntax(unit, LOG_WARNING, filename, line, 0,
"Specified KeyId is larger then the allowed maximum (%zu > %u), ignoring: %s", "Specified KeyId= is larger then the allowed maximum (%zu > %u), ignoring: %s",
l, MACSEC_KEYID_LEN, rvalue); l, MACSEC_KEYID_LEN, rvalue);
return 0; return 0;
} }

View File

@ -220,8 +220,8 @@ WireGuard.PrivateKey, config_parse_wireguard_private_key,
WireGuard.PrivateKeyFile, config_parse_wireguard_private_key_file, 0, 0 WireGuard.PrivateKeyFile, config_parse_wireguard_private_key_file, 0, 0
WireGuardPeer.AllowedIPs, config_parse_wireguard_allowed_ips, 0, 0 WireGuardPeer.AllowedIPs, config_parse_wireguard_allowed_ips, 0, 0
WireGuardPeer.Endpoint, config_parse_wireguard_endpoint, 0, 0 WireGuardPeer.Endpoint, config_parse_wireguard_endpoint, 0, 0
WireGuardPeer.PublicKey, config_parse_wireguard_public_key, 0, 0 WireGuardPeer.PublicKey, config_parse_wireguard_peer_key, 0, 0
WireGuardPeer.PresharedKey, config_parse_wireguard_preshared_key, 0, 0 WireGuardPeer.PresharedKey, config_parse_wireguard_peer_key, 0, 0
WireGuardPeer.PresharedKeyFile, config_parse_wireguard_preshared_key_file, 0, 0 WireGuardPeer.PresharedKeyFile, config_parse_wireguard_preshared_key_file, 0, 0
WireGuardPeer.PersistentKeepalive, config_parse_wireguard_keepalive, 0, 0 WireGuardPeer.PersistentKeepalive, config_parse_wireguard_keepalive, 0, 0
Xfrm.InterfaceId, config_parse_uint32, 0, offsetof(Xfrm, if_id) Xfrm.InterfaceId, config_parse_uint32, 0, offsetof(Xfrm, if_id)

View File

@ -492,6 +492,8 @@ static int wireguard_decode_key_and_warn(
(void) warn_file_is_world_accessible(filename, NULL, unit, line); (void) warn_file_is_world_accessible(filename, NULL, unit, line);
r = unbase64mem_full(rvalue, strlen(rvalue), true, &key, &len); r = unbase64mem_full(rvalue, strlen(rvalue), true, &key, &len);
if (r == -ENOMEM)
return log_oom();
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to decode wireguard key provided by %s=, ignoring assignment: %m", lvalue); "Failed to decode wireguard key provided by %s=, ignoring assignment: %m", lvalue);
@ -526,8 +528,7 @@ int config_parse_wireguard_private_key(
w = WIREGUARD(data); w = WIREGUARD(data);
assert(w); assert(w);
(void) wireguard_decode_key_and_warn(rvalue, w->private_key, unit, filename, line, lvalue); return wireguard_decode_key_and_warn(rvalue, w->private_key, unit, filename, line, lvalue);
return 0;
} }
int config_parse_wireguard_private_key_file( int config_parse_wireguard_private_key_file(
@ -564,7 +565,7 @@ int config_parse_wireguard_private_key_file(
return free_and_replace(w->private_key_file, path); return free_and_replace(w->private_key_file, path);
} }
int config_parse_wireguard_preshared_key( int config_parse_wireguard_peer_key(
const char *unit, const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
@ -576,7 +577,7 @@ int config_parse_wireguard_preshared_key(
void *data, void *data,
void *userdata) { void *userdata) {
WireguardPeer *peer; _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
Wireguard *w; Wireguard *w;
int r; int r;
@ -588,7 +589,13 @@ int config_parse_wireguard_preshared_key(
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
(void) wireguard_decode_key_and_warn(rvalue, peer->preshared_key, unit, filename, line, lvalue); r = wireguard_decode_key_and_warn(rvalue,
streq(lvalue, "PublicKey") ? peer->public_key : peer->preshared_key,
unit, filename, line, lvalue);
if (r < 0)
return r;
TAKE_PTR(peer);
return 0; return 0;
} }
@ -635,38 +642,6 @@ int config_parse_wireguard_preshared_key_file(
return 0; return 0;
} }
int config_parse_wireguard_public_key(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
Wireguard *w;
int r;
assert(data);
w = WIREGUARD(data);
assert(w);
r = wireguard_peer_new_static(w, filename, section_line, &peer);
if (r < 0)
return log_oom();
r = wireguard_decode_key_and_warn(rvalue, peer->public_key, unit, filename, line, lvalue);
if (r < 0)
return 0;
TAKE_PTR(peer);
return 0;
}
int config_parse_wireguard_allowed_ips( int config_parse_wireguard_allowed_ips(
const char *unit, const char *unit,
const char *filename, const char *filename,
@ -821,7 +796,7 @@ int config_parse_wireguard_keepalive(
void *data, void *data,
void *userdata) { void *userdata) {
WireguardPeer *peer; _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
uint16_t keepalive = 0; uint16_t keepalive = 0;
Wireguard *w; Wireguard *w;
int r; int r;
@ -849,6 +824,8 @@ int config_parse_wireguard_keepalive(
} }
peer->persistent_keepalive_interval = keepalive; peer->persistent_keepalive_interval = keepalive;
TAKE_PTR(peer);
return 0; return 0;
} }

View File

@ -61,10 +61,8 @@ extern const NetDevVTable wireguard_vtable;
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_allowed_ips); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_allowed_ips);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_endpoint); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_endpoint);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_listen_port); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_listen_port);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_peer_key);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_public_key);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key_file); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key_file);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_preshared_key);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_preshared_key_file); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_preshared_key_file);
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_keepalive); CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_keepalive);

View File

@ -691,7 +691,7 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
switch (type) { switch (type) {
case RTM_NEWNEIGH: case RTM_NEWNEIGH:
if (neighbor) if (neighbor)
log_link_debug(link, "Remembering neighbor: %s->%s", log_link_debug(link, "Received remembered neighbor: %s->%s",
strnull(addr_str), strnull(lladdr_str)); strnull(addr_str), strnull(lladdr_str));
else { else {
/* A neighbor appeared that we did not request */ /* A neighbor appeared that we did not request */
@ -1082,9 +1082,6 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
assert_not_reached("Received rule message with unsupported address family"); assert_not_reached("Received rule message with unsupported address family");
} }
if (tmp->from_prefixlen == 0 && tmp->to_prefixlen == 0)
return 0;
r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags); r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m"); log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
@ -1181,9 +1178,12 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
switch (type) { switch (type) {
case RTM_NEWRULE: case RTM_NEWRULE:
if (!rule) { if (rule)
log_debug("Remembering foreign routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u", log_debug("Received remembered routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
from, tmp->from_prefixlen, to, tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table); tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
else {
log_debug("Remembering foreign routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
r = routing_policy_rule_add_foreign(m, tmp, &rule); r = routing_policy_rule_add_foreign(m, tmp, &rule);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Could not remember foreign rule, ignoring: %m"); log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
@ -1192,10 +1192,13 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi
} }
break; break;
case RTM_DELRULE: case RTM_DELRULE:
log_debug("Forgetting routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u", if (rule) {
from, tmp->from_prefixlen, to, tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table); log_debug("Forgetting routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
routing_policy_rule_free(rule); routing_policy_rule_free(rule);
} else
log_debug("Kernel removed a routing policy rule we don't remember: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32", ignoring.",
tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
break; break;
default: default:
@ -1298,19 +1301,24 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
switch (type) { switch (type) {
case RTM_NEWNEXTHOP: case RTM_NEWNEXTHOP:
if (!nexthop) { if (nexthop)
log_debug("Remembering foreign nexthop: %s, oif: %d, id: %d", gateway, tmp->oif, tmp->id); log_link_debug(link, "Received remembered nexthop: %s, oif: %d, id: %d", strna(gateway), tmp->oif, tmp->id);
else {
log_link_debug(link, "Remembering foreign nexthop: %s, oif: %d, id: %d", strna(gateway), tmp->oif, tmp->id);
r = nexthop_add_foreign(link, tmp, &nexthop); r = nexthop_add_foreign(link, tmp, &nexthop);
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Could not remember foreign nexthop, ignoring: %m"); log_link_warning_errno(link, r, "Could not remember foreign nexthop, ignoring: %m");
return 0; return 0;
} }
} }
break; break;
case RTM_DELNEXTHOP: case RTM_DELNEXTHOP:
log_debug("Forgetting foreign nexthop: %s, oif: %d, id: %d", gateway, tmp->oif, tmp->id); if (nexthop) {
log_link_debug(link, "Forgetting nexthop: %s, oif: %d, id: %d", strna(gateway), tmp->oif, tmp->id);
nexthop_free(nexthop); nexthop_free(nexthop);
} else
log_link_debug(link, "Kernel removed a nexthop we don't remember: %s, oif: %d, id: %d, ignoring.",
strna(gateway), tmp->oif, tmp->id);
break; break;
default: default:

View File

@ -39,7 +39,7 @@ Match.Type, config_parse_match_strv,
Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match_wlan_iftype) Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match_wlan_iftype)
Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid) Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid)
Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid) Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid)
Match.Name, config_parse_match_ifnames, 1, offsetof(Network, match_name) Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match_name)
Match.Property, config_parse_match_property, 0, offsetof(Network, match_property) Match.Property, config_parse_match_property, 0, offsetof(Network, match_property)
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions)
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions)

View File

@ -333,37 +333,48 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
return 1; return 1;
} }
int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) { int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r; int r;
assert(routing_policy_rule); assert(rule);
assert(link); assert(link);
assert(link->manager); assert(link->manager);
assert(link->manager->rtnl); assert(link->manager->rtnl);
assert(link->ifindex > 0); assert(link->ifindex > 0);
assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6)); assert(IN_SET(rule->family, AF_INET, AF_INET6));
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family); if (DEBUG_LOGGING) {
_cleanup_free_ char *from = NULL, *to = NULL;
(void) in_addr_to_string(rule->family, &rule->from, &from);
(void) in_addr_to_string(rule->family, &rule->to, &to);
log_link_debug(link,
"Removing routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
rule->priority, strna(from), rule->from_prefixlen, strna(to), rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
}
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, rule->family);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_DELRULE message: %m"); return log_link_error_errno(link, r, "Could not allocate RTM_DELRULE message: %m");
if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) { if (in_addr_is_null(rule->family, &rule->from) == 0) {
r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from); r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
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_rtm_src_prefixlen(m, routing_policy_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");
} }
if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) { if (in_addr_is_null(rule->family, &rule->to) == 0) {
r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to); r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
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_rtm_dst_prefixlen(m, routing_policy_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");
} }
@ -473,8 +484,8 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl
(void) in_addr_to_string(rule->family, &rule->to, &to); (void) in_addr_to_string(rule->family, &rule->to, &to);
log_link_debug(link, log_link_debug(link,
"Configuring routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u", "Configuring routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32,
from, rule->from_prefixlen, to, rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table); rule->priority, strna(from), rule->from_prefixlen, strna(to), rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
} }
r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family); r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
@ -529,18 +540,16 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl
r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark); r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append FRA_FWMARK attribute: %m"); return log_link_error_errno(link, r, "Could not append FRA_FWMARK attribute: %m");
}
if (rule->fwmask > 0) {
r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask); r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m"); return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m");
} }
if (rule->iif) { if (rule->iif) {
r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif); r = sd_netlink_message_append_string(m, FRA_IIFNAME, rule->iif);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not append FRA_IFNAME attribute: %m"); return log_link_error_errno(link, r, "Could not append FRA_IIFNAME attribute: %m");
} }
if (rule->oif) { if (rule->oif) {
@ -644,31 +653,39 @@ int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
return 0; return 0;
} }
static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) { static int parse_fwmark_fwmask(const char *s, uint32_t *ret_fwmark, uint32_t *ret_fwmask) {
_cleanup_free_ char *f = NULL; _cleanup_free_ char *fwmark_str = NULL;
char *p; uint32_t fwmark, fwmask = 0;
const char *slash;
int r; int r;
assert(s); assert(s);
assert(ret_fwmark);
assert(ret_fwmask);
f = strdup(s); slash = strchr(s, '/');
if (!f) if (slash) {
fwmark_str = strndup(s, slash - s);
if (!fwmark_str)
return -ENOMEM; return -ENOMEM;
p = strchr(f, '/');
if (p)
*p++ = '\0';
r = safe_atou32(f, fwmark);
if (r < 0)
return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
if (p) {
r = safe_atou32(p, fwmask);
if (r < 0)
return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
} }
r = safe_atou32(fwmark_str ?: s, &fwmark);
if (r < 0)
return r;
if (fwmark > 0) {
if (slash) {
r = safe_atou32(slash + 1, &fwmask);
if (r < 0)
return r;
} else
fwmask = UINT32_MAX;
}
*ret_fwmark = fwmark;
*ret_fwmask = fwmask;
return 0; return 0;
} }
@ -1223,9 +1240,11 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
} }
if (rule->fwmark != 0) { if (rule->fwmark != 0) {
fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32, fprintf(f, "%sfwmark=%"PRIu32,
space ? " " : "", space ? " " : "",
rule->fwmark, rule->fwmask); rule->fwmark);
if (rule->fwmask != UINT32_MAX)
fprintf(f, "/%"PRIu32, rule->fwmask);
space = true; space = true;
} }

View File

@ -62,8 +62,8 @@ void routing_policy_rule_free(RoutingPolicyRule *rule);
DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free); DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
int routing_policy_rule_section_verify(RoutingPolicyRule *rule); int routing_policy_rule_section_verify(RoutingPolicyRule *rule);
int routing_policy_rule_configure(RoutingPolicyRule *address, Link *link, link_netlink_message_handler_t callback); int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback);
int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback); int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback);
int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret); int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret);
int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret); int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret);

View File

@ -67,7 +67,7 @@ int main(int argc, char **argv) {
test_rule_serialization("ignored values", test_rule_serialization("ignored values",
"RULE=something=to=ignore from=1.2.3.4/32 from=1.2.3.4/32" "RULE=something=to=ignore from=1.2.3.4/32 from=1.2.3.4/32"
" \t to=2.3.4.5/24 to=2.3.4.5/32 tos=5 fwmark=2 fwmark=1 table=10 table=20", " \t to=2.3.4.5/24 to=2.3.4.5/32 tos=5 fwmark=2 fwmark=1 table=10 table=20",
"RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 fwmark=1/0 invert_rule=no table=20"); "RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 fwmark=1 invert_rule=no table=20");
test_rule_serialization("ipv6", test_rule_serialization("ipv6",
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=yes table=6", NULL); "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=yes table=6", NULL);

View File

@ -233,14 +233,10 @@ int config_parse_expose_port(
assert(rvalue); assert(rvalue);
r = expose_port_parse(&s->expose_ports, rvalue); r = expose_port_parse(&s->expose_ports, rvalue);
if (r == -EEXIST) { if (r == -EEXIST)
log_syntax(unit, LOG_ERR, filename, line, r, "Duplicate port specification, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Duplicate port specification, ignoring: %s", rvalue);
return 0; else if (r < 0)
} log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse host port %s: %m", rvalue);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse host port %s: %m", rvalue);
return 0;
}
return 0; return 0;
} }
@ -268,8 +264,10 @@ int config_parse_capability(
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL;
r = extract_first_word(&rvalue, &word, NULL, 0); r = extract_first_word(&rvalue, &word, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract capability string, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to extract capability string, ignoring: %s", rvalue);
return 0; return 0;
} }
if (r == 0) if (r == 0)
@ -280,7 +278,7 @@ int config_parse_capability(
else { else {
r = capability_from_name(word); r = capability_from_name(word);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse capability, ignoring: %s", word); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse capability, ignoring: %s", word);
continue; continue;
} }
@ -315,10 +313,8 @@ int config_parse_pivot_root(
assert(rvalue); assert(rvalue);
r = pivot_root_parse(&settings->pivot_root_new, &settings->pivot_root_old, rvalue); r = pivot_root_parse(&settings->pivot_root_new, &settings->pivot_root_old, rvalue);
if (r < 0) { if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid pivot root mount specification %s: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid pivot root mount specification %s: %m", rvalue);
return 0;
}
return 0; return 0;
} }
@ -343,10 +339,8 @@ int config_parse_bind(
assert(rvalue); assert(rvalue);
r = bind_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype); r = bind_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
if (r < 0) { if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bind mount specification %s: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid bind mount specification %s: %m", rvalue);
return 0;
}
return 0; return 0;
} }
@ -371,10 +365,8 @@ int config_parse_tmpfs(
assert(rvalue); assert(rvalue);
r = tmpfs_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue); r = tmpfs_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
if (r < 0) { if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid temporary file system specification %s: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid temporary file system specification %s: %m", rvalue);
return 0;
}
return 0; return 0;
} }
@ -399,10 +391,8 @@ int config_parse_inaccessible(
assert(rvalue); assert(rvalue);
r = inaccessible_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue); r = inaccessible_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
if (r < 0) { if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue);
return 0;
}
return 0; return 0;
} }
@ -428,7 +418,7 @@ int config_parse_overlay(
r = overlay_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype); r = overlay_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
if (r < 0) if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid overlay file system specification %s, ignoring: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid overlay file system specification %s, ignoring: %m", rvalue);
return 0; return 0;
} }
@ -453,10 +443,8 @@ int config_parse_veth_extra(
assert(rvalue); assert(rvalue);
r = veth_extra_parse(&settings->network_veth_extra, rvalue); r = veth_extra_parse(&settings->network_veth_extra, rvalue);
if (r < 0) { if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue);
return 0;
}
return 0; return 0;
} }
@ -482,13 +470,11 @@ int config_parse_network_zone(
j = strjoin("vz-", rvalue); j = strjoin("vz-", rvalue);
if (!ifname_valid(j)) { if (!ifname_valid(j)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid network zone name, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid network zone name, ignoring: %s", rvalue);
return 0; return 0;
} }
free_and_replace(settings->network_zone, j); return free_and_replace(settings->network_zone, j);
return 0;
} }
int config_parse_boot( int config_parse_boot(
@ -512,11 +498,11 @@ int config_parse_boot(
r = parse_boolean(rvalue); r = parse_boolean(rvalue);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue);
return 0; return 0;
} }
if (r > 0) { if (r) {
if (settings->start_mode == START_PID2) if (settings->start_mode == START_PID2)
goto conflict; goto conflict;
@ -532,7 +518,7 @@ int config_parse_boot(
return 0; return 0;
conflict: conflict:
log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring."); log_syntax(unit, LOG_WARNING, filename, line, 0, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
return 0; return 0;
} }
@ -557,11 +543,11 @@ int config_parse_pid2(
r = parse_boolean(rvalue); r = parse_boolean(rvalue);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue);
return 0; return 0;
} }
if (r > 0) { if (r) {
if (settings->start_mode == START_BOOT) if (settings->start_mode == START_BOOT)
goto conflict; goto conflict;
@ -577,7 +563,7 @@ int config_parse_pid2(
return 0; return 0;
conflict: conflict:
log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring."); log_syntax(unit, LOG_WARNING, filename, line, 0, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
return 0; return 0;
} }
@ -629,7 +615,7 @@ int config_parse_private_users(
r = safe_atou32(range, &rn); r = safe_atou32(range, &rn);
if (r < 0 || rn <= 0) { if (r < 0 || rn <= 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID range invalid, ignoring: %s", range); log_syntax(unit, LOG_WARNING, filename, line, r, "UID/GID range invalid, ignoring: %s", range);
return 0; return 0;
} }
} else { } else {
@ -639,7 +625,7 @@ int config_parse_private_users(
r = parse_uid(shift, &sh); r = parse_uid(shift, &sh);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID shift invalid, ignoring: %s", range); log_syntax(unit, LOG_WARNING, filename, line, r, "UID/GID shift invalid, ignoring: %s", range);
return 0; return 0;
} }
@ -680,11 +666,12 @@ int config_parse_syscall_filter(
r = extract_first_word(&items, &word, NULL, 0); r = extract_first_word(&items, &word, NULL, 0);
if (r == 0) if (r == 0)
break; return 0;
if (r == -ENOMEM) if (r == -ENOMEM)
return log_oom(); return log_oom();
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue);
return 0; return 0;
} }
@ -695,8 +682,6 @@ int config_parse_syscall_filter(
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
} }
return 0;
} }
int config_parse_hostname( int config_parse_hostname(
@ -717,7 +702,7 @@ int config_parse_hostname(
assert(s); assert(s);
if (!hostname_is_valid(rvalue, false)) { if (!hostname_is_valid(rvalue, false)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue);
return 0; return 0;
} }
@ -752,11 +737,11 @@ int config_parse_oom_score_adjust(
r = parse_oom_score_adjust(rvalue, &oa); r = parse_oom_score_adjust(rvalue, &oa);
if (r == -ERANGE) { if (r == -ERANGE) {
log_syntax(unit, LOG_ERR, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "OOM score adjust value out of range, ignoring: %s", rvalue);
return 0; return 0;
} }
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
return 0; return 0;
} }
@ -863,10 +848,8 @@ int config_parse_link_journal(
assert(settings); assert(settings);
r = parse_link_journal(rvalue, &settings->link_journal, &settings->link_journal_try); r = parse_link_journal(rvalue, &settings->link_journal, &settings->link_journal_try);
if (r < 0) { if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse link journal mode, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse link journal mode, ignoring: %s", rvalue);
return 0;
}
return 0; return 0;
} }

View File

@ -947,7 +947,7 @@ static int config_parse_label(
r = specifier_printf(rvalue, specifier_table, NULL, &resolved); r = specifier_printf(rvalue, specifier_table, NULL, &resolved);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to expand specifiers in Label=, ignoring: %s", rvalue); "Failed to expand specifiers in Label=, ignoring: %s", rvalue);
return 0; return 0;
} }
@ -2609,9 +2609,17 @@ static int do_copy_files(Partition *p, const char *fs) {
if (pfd < 0) if (pfd < 0)
return log_error_errno(pfd, "Failed to open parent directory of target: %m"); return log_error_errno(pfd, "Failed to open parent directory of target: %m");
r = copy_tree_at(sfd, ".", pfd, basename(*target), UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT); r = copy_tree_at(
sfd, ".",
pfd, basename(*target),
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
} else } else
r = copy_tree_at(sfd, ".", tfd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT); r = copy_tree_at(
sfd, ".",
tfd, ".",
UID_INVALID, GID_INVALID,
COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to copy %s%s to %s: %m", strempty(arg_root), *source, *target); return log_error_errno(r, "Failed to copy %s%s to %s: %m", strempty(arg_root), *source, *target);
} else { } else {

View File

@ -1754,7 +1754,6 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
_cleanup_(dnssd_service_freep) DnssdService *service = NULL; _cleanup_(dnssd_service_freep) DnssdService *service = NULL;
_cleanup_(sd_bus_track_unrefp) sd_bus_track *bus_track = NULL; _cleanup_(sd_bus_track_unrefp) sd_bus_track *bus_track = NULL;
_cleanup_free_ char *path = NULL; _cleanup_free_ char *path = NULL;
_cleanup_free_ char *instance_name = NULL;
Manager *m = userdata; Manager *m = userdata;
DnssdService *s = NULL; DnssdService *s = NULL;
const char *name; const char *name;
@ -1795,6 +1794,10 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
if (!dnssd_srv_type_is_valid(type)) if (!dnssd_srv_type_is_valid(type))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DNS-SD service type '%s' is invalid", type); return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DNS-SD service type '%s' is invalid", type);
r = dnssd_render_instance_name(name_template, NULL);
if (r < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "DNS-SD service name '%s' is invalid", name_template);
service->name = strdup(name); service->name = strdup(name);
if (!service->name) if (!service->name)
return log_oom(); return log_oom();
@ -1807,10 +1810,6 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
if (!service->type) if (!service->type)
return log_oom(); return log_oom();
r = dnssd_render_instance_name(service, &instance_name);
if (r < 0)
return r;
r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "a{say}"); r = sd_bus_message_enter_container(message, SD_BUS_TYPE_ARRAY, "a{say}");
if (r < 0) if (r < 0)
return r; return r;

View File

@ -35,9 +35,6 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
if (r < 0) if (r < 0)
return r; return r;
if (IN_SET(port, 53, 853))
port = 0;
/* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */ /* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */
if (!dns_server_address_valid(family, &address)) if (!dns_server_address_valid(family, &address))
return 0; return 0;
@ -50,12 +47,8 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
/* Filter out duplicates */ /* Filter out duplicates */
s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name); s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
if (s) { if (s) {
/* /* Drop the marker. This is used to find the servers that ceased to exist, see
* Drop the marker. This is used to find the servers * manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */
* that ceased to exist, see
* manager_mark_dns_servers() and
* manager_flush_marked_dns_servers().
*/
dns_server_move_back_and_unmark(s); dns_server_move_back_and_unmark(s);
return 0; return 0;
} }
@ -168,7 +161,8 @@ int config_parse_dns_servers(
/* Otherwise, add to the list */ /* Otherwise, add to the list */
r = manager_parse_dns_server_string_and_warn(m, ltype, rvalue); r = manager_parse_dns_server_string_and_warn(m, ltype, rvalue);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse DNS server string '%s', ignoring.", rvalue);
return 0; return 0;
} }
} }
@ -210,7 +204,8 @@ int config_parse_search_domains(
/* Otherwise, add to the list */ /* Otherwise, add to the list */
r = manager_parse_search_domains_and_warn(m, rvalue); r = manager_parse_search_domains_and_warn(m, rvalue);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse search domains string '%s'. Ignoring.", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse search domains string '%s', ignoring.", rvalue);
return 0; return 0;
} }
} }
@ -222,21 +217,19 @@ int config_parse_search_domains(
return 0; return 0;
} }
int config_parse_dnssd_service_name(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { int config_parse_dnssd_service_name(
static const Specifier specifier_table[] = { const char *unit,
{ 'm', specifier_machine_id, NULL }, const char *filename,
{ 'b', specifier_boot_id, NULL }, unsigned line,
{ 'H', specifier_host_name, NULL }, const char *section,
{ 'v', specifier_kernel_release, NULL }, unsigned section_line,
{ 'a', specifier_architecture, NULL }, const char *lvalue,
{ 'o', specifier_os_id, NULL }, int ltype,
{ 'w', specifier_os_version_id, NULL }, const char *rvalue,
{ 'B', specifier_os_build_id, NULL }, void *data,
{ 'W', specifier_os_variant_id, NULL }, void *userdata) {
{}
};
DnssdService *s = userdata; DnssdService *s = userdata;
_cleanup_free_ char *name = NULL;
int r; int r;
assert(filename); assert(filename);
@ -245,27 +238,38 @@ int config_parse_dnssd_service_name(const char *unit, const char *filename, unsi
assert(s); assert(s);
if (isempty(rvalue)) { if (isempty(rvalue)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Service instance name can't be empty. Ignoring."); s->name_template = mfree(s->name_template);
return -EINVAL; return 0;
}
r = dnssd_render_instance_name(rvalue, NULL);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid service instance name template '%s', ignoring: %m", rvalue);
return 0;
} }
r = free_and_strdup(&s->name_template, rvalue); r = free_and_strdup(&s->name_template, rvalue);
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
r = specifier_printf(s->name_template, specifier_table, NULL, &name);
if (r < 0)
return log_debug_errno(r, "Failed to replace specifiers: %m");
if (!dns_service_name_is_valid(name)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Service instance name template renders to invalid name '%s'. Ignoring.", name);
return -EINVAL;
}
return 0; return 0;
} }
int config_parse_dnssd_service_type(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { int config_parse_dnssd_service_type(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
DnssdService *s = userdata; DnssdService *s = userdata;
int r; int r;
@ -275,13 +279,13 @@ int config_parse_dnssd_service_type(const char *unit, const char *filename, unsi
assert(s); assert(s);
if (isempty(rvalue)) { if (isempty(rvalue)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Service type can't be empty. Ignoring."); s->type = mfree(s->type);
return -EINVAL; return 0;
} }
if (!dnssd_srv_type_is_valid(rvalue)) { if (!dnssd_srv_type_is_valid(rvalue)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Service type is invalid. Ignoring."); log_syntax(unit, LOG_WARNING, filename, line, 0, "Service type is invalid. Ignoring.");
return -EINVAL; return 0;
} }
r = free_and_strdup(&s->type, rvalue); r = free_and_strdup(&s->type, rvalue);
@ -291,7 +295,18 @@ int config_parse_dnssd_service_type(const char *unit, const char *filename, unsi
return 0; return 0;
} }
int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { int config_parse_dnssd_txt(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL; _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
DnssdService *s = userdata; DnssdService *s = userdata;
DnsTxtItem *last = NULL; DnsTxtItem *last = NULL;
@ -312,9 +327,7 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
return log_oom(); return log_oom();
for (;;) { for (;;) {
_cleanup_free_ char *word = NULL; _cleanup_free_ char *word = NULL, *key = NULL, *value = NULL;
_cleanup_free_ char *key = NULL;
_cleanup_free_ char *value = NULL;
_cleanup_free_ void *decoded = NULL; _cleanup_free_ void *decoded = NULL;
size_t length = 0; size_t length = 0;
DnsTxtItem *i; DnsTxtItem *i;
@ -326,8 +339,10 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
break; break;
if (r == -ENOMEM) if (r == -ENOMEM)
return log_oom(); return log_oom();
if (r < 0) if (r < 0) {
return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
return 0;
}
r = split_pair(word, "=", &key, &value); r = split_pair(word, "=", &key, &value);
if (r == -ENOMEM) if (r == -ENOMEM)
@ -336,8 +351,8 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
key = TAKE_PTR(word); key = TAKE_PTR(word);
if (!ascii_is_valid(key)) { if (!ascii_is_valid(key)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring: %s", key); log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid key, ignoring: %s", key);
return -EINVAL; continue;
} }
switch (ltype) { switch (ltype) {
@ -347,9 +362,11 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
r = unbase64mem(value, strlen(value), &decoded, &length); r = unbase64mem(value, strlen(value), &decoded, &length);
if (r == -ENOMEM) if (r == -ENOMEM)
return log_oom(); return log_oom();
if (r < 0) if (r < 0) {
return log_syntax(unit, LOG_ERR, filename, line, r, log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid base64 encoding, ignoring: %s", value); "Invalid base64 encoding, ignoring: %s", value);
continue;
}
} }
r = dnssd_txt_item_new_from_data(key, decoded, length, &i); r = dnssd_txt_item_new_from_data(key, decoded, length, &i);
@ -373,7 +390,7 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
if (!LIST_IS_EMPTY(txt_data->txt)) { if (!LIST_IS_EMPTY(txt_data->txt)) {
LIST_PREPEND(items, s->txt_data_items, txt_data); LIST_PREPEND(items, s->txt_data_items, txt_data);
txt_data = NULL; TAKE_PTR(txt_data);
} }
return 0; return 0;
@ -423,7 +440,7 @@ int config_parse_dns_stub_listener_extra(
} }
} }
r = in_addr_port_from_string_auto(p, &stub->family, &stub->address, &stub->port); r = in_addr_port_ifindex_name_from_string_auto(p, &stub->family, &stub->address, &stub->port, NULL, NULL);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r, log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse address in %s=%s, ignoring assignment: %m", "Failed to parse address in %s=%s, ignoring assignment: %m",

View File

@ -15,7 +15,7 @@
* IP and UDP header sizes */ * IP and UDP header sizes */
#define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U) #define ADVERTISE_DATAGRAM_SIZE_MAX (65536U-14U-20U-8U)
static int manager_dns_stub_udp_fd_extra(Manager *m, DnsStubListenerExtra *l); static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int type);
static void dns_stub_listener_extra_hash_func(const DnsStubListenerExtra *a, struct siphash *state) { static void dns_stub_listener_extra_hash_func(const DnsStubListenerExtra *a, struct siphash *state) {
assert(a); assert(a);
@ -217,7 +217,7 @@ static int dns_stub_send(
* is because otherwise the kernel will choose it automatically based on the routing table and will * is because otherwise the kernel will choose it automatically based on the routing table and will
* thus pick 127.0.0.1 rather than 127.0.0.53. */ * thus pick 127.0.0.1 rather than 127.0.0.53. */
r = manager_send(m, r = manager_send(m,
manager_dns_stub_udp_fd_extra(m, l), manager_dns_stub_fd_extra(m, l, SOCK_DGRAM),
l ? p->ifindex : LOOPBACK_IFINDEX, /* force loopback iface if this is the main listener stub */ l ? p->ifindex : LOOPBACK_IFINDEX, /* force loopback iface if this is the main listener stub */
p->family, &p->sender, p->sender_port, &p->destination, p->family, &p->sender, p->sender_port, &p->destination,
reply); reply);
@ -477,151 +477,6 @@ static int on_dns_stub_packet_extra(sd_event_source *s, int fd, uint32_t revents
return on_dns_stub_packet_internal(s, fd, revents, l->manager, l); return on_dns_stub_packet_internal(s, fd, revents, l->manager, l);
} }
static int set_dns_stub_common_socket_options(int fd, int family) {
int r;
assert(fd >= 0);
assert(IN_SET(family, AF_INET, AF_INET6));
r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
if (r < 0)
return r;
if (family == AF_INET) {
r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true);
if (r < 0)
return r;
r = setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true);
if (r < 0)
return r;
} else {
r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, true);
if (r < 0)
return r;
r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, true);
if (r < 0)
return r;
}
return 0;
}
static int manager_dns_stub_udp_fd(Manager *m) {
union sockaddr_union sa = {
.in.sin_family = AF_INET,
.in.sin_port = htobe16(53),
.in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
};
_cleanup_close_ int fd = -1;
int r;
if (m->dns_stub_udp_event_source)
return sd_event_source_get_io_fd(m->dns_stub_udp_event_source);
fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return -errno;
r = set_dns_stub_common_socket_options(fd, AF_INET);
if (r < 0)
return r;
/* Make sure no traffic from outside the local host can leak to onto this socket */
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
if (r < 0)
return r;
if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
return -errno;
r = sd_event_add_io(m->event, &m->dns_stub_udp_event_source, fd, EPOLLIN, on_dns_stub_packet, m);
if (r < 0)
return r;
r = sd_event_source_set_io_fd_own(m->dns_stub_udp_event_source, true);
if (r < 0)
return r;
(void) sd_event_source_set_description(m->dns_stub_udp_event_source, "dns-stub-udp");
return TAKE_FD(fd);
}
static int manager_dns_stub_udp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
_cleanup_free_ char *pretty = NULL;
_cleanup_close_ int fd = -1;
union sockaddr_union sa;
int r;
assert(m);
if (!l)
return manager_dns_stub_udp_fd(m);
if (l->udp_event_source)
return 0;
if (l->family == AF_INET)
sa = (union sockaddr_union) {
.in.sin_family = l->family,
.in.sin_port = htobe16(l->port != 0 ? l->port : 53U),
.in.sin_addr = l->address.in,
};
else
sa = (union sockaddr_union) {
.in6.sin6_family = l->family,
.in6.sin6_port = htobe16(l->port != 0 ? l->port : 53U),
.in6.sin6_addr = l->address.in6,
};
fd = socket(l->family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0) {
r = -errno;
goto fail;
}
if (l->family == AF_INET) {
r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
if (r < 0)
goto fail;
}
r = set_dns_stub_common_socket_options(fd, l->family);
if (r < 0)
goto fail;
if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) {
r = -errno;
goto fail;
}
r = sd_event_add_io(m->event, &l->udp_event_source, fd, EPOLLIN, on_dns_stub_packet_extra, l);
if (r < 0)
goto fail;
r = sd_event_source_set_io_fd_own(l->udp_event_source, true);
if (r < 0)
goto fail;
(void) sd_event_source_set_description(l->udp_event_source, "dns-stub-udp-extra");
if (DEBUG_LOGGING) {
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
log_debug("Listening on UDP socket %s.", strnull(pretty));
}
return TAKE_FD(fd);
fail:
assert(r < 0);
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
if (r == -EADDRINUSE)
return log_warning_errno(r, "Another process is already listening on UDP socket %s: %m", strnull(pretty));
return log_warning_errno(r, "Failed to listen on UDP socket %s: %m", strnull(pretty));
}
static int on_dns_stub_stream_packet(DnsStream *s) { static int on_dns_stub_stream_packet(DnsStream *s) {
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
@ -678,7 +533,38 @@ static int on_dns_stub_stream_extra(sd_event_source *s, int fd, uint32_t revents
return on_dns_stub_stream_internal(s, fd, revents, l->manager, l); return on_dns_stub_stream_internal(s, fd, revents, l->manager, l);
} }
static int manager_dns_stub_tcp_fd(Manager *m) { static int set_dns_stub_common_socket_options(int fd, int family) {
int r;
assert(fd >= 0);
assert(IN_SET(family, AF_INET, AF_INET6));
r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEADDR, true);
if (r < 0)
return r;
if (family == AF_INET) {
r = setsockopt_int(fd, IPPROTO_IP, IP_PKTINFO, true);
if (r < 0)
return r;
r = setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, true);
if (r < 0)
return r;
} else {
r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, true);
if (r < 0)
return r;
r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, true);
if (r < 0)
return r;
}
return 0;
}
static int manager_dns_stub_fd(Manager *m, int type) {
union sockaddr_union sa = { union sockaddr_union sa = {
.in.sin_family = AF_INET, .in.sin_family = AF_INET,
.in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB), .in.sin_addr.s_addr = htobe32(INADDR_DNS_STUB),
@ -687,10 +573,13 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
int r; int r;
if (m->dns_stub_tcp_event_source) assert(IN_SET(type, SOCK_DGRAM, SOCK_STREAM));
return sd_event_source_get_io_fd(m->dns_stub_tcp_event_source);
fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); sd_event_source **event_source = type == SOCK_DGRAM ? &m->dns_stub_udp_event_source : &m->dns_stub_tcp_event_source;
if (*event_source)
return sd_event_source_get_io_fd(*event_source);
fd = socket(AF_INET, type | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (fd < 0) if (fd < 0)
return -errno; return -errno;
@ -698,42 +587,53 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
if (r < 0) if (r < 0)
return r; return r;
r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, 1);
if (r < 0)
return r;
/* Make sure no traffic from outside the local host can leak to onto this socket */ /* Make sure no traffic from outside the local host can leak to onto this socket */
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX); r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
if (r < 0) if (r < 0)
return r; return r;
r = setsockopt_int(fd, IPPROTO_IP, IP_TTL, 1);
if (r < 0)
return r;
if (bind(fd, &sa.sa, sizeof(sa.in)) < 0) if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
return -errno; return -errno;
if (listen(fd, SOMAXCONN) < 0) if (type == SOCK_STREAM &&
listen(fd, SOMAXCONN) < 0)
return -errno; return -errno;
r = sd_event_add_io(m->event, &m->dns_stub_tcp_event_source, fd, EPOLLIN, on_dns_stub_stream, m); r = sd_event_add_io(m->event, event_source, fd, EPOLLIN,
type == SOCK_DGRAM ? on_dns_stub_packet : on_dns_stub_stream,
m);
if (r < 0) if (r < 0)
return r; return r;
r = sd_event_source_set_io_fd_own(m->dns_stub_tcp_event_source, true); r = sd_event_source_set_io_fd_own(*event_source, true);
if (r < 0) if (r < 0)
return r; return r;
(void) sd_event_source_set_description(m->dns_stub_tcp_event_source, "dns-stub-tcp"); (void) sd_event_source_set_description(*event_source,
type == SOCK_DGRAM ? "dns-stub-udp" : "dns-stub-tcp");
return TAKE_FD(fd); return TAKE_FD(fd);
} }
static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) { static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int type) {
_cleanup_free_ char *pretty = NULL; _cleanup_free_ char *pretty = NULL;
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
union sockaddr_union sa; union sockaddr_union sa;
int r; int r;
if (l->tcp_event_source) assert(m);
return sd_event_source_get_io_fd(l->tcp_event_source);; assert(IN_SET(type, SOCK_DGRAM, SOCK_STREAM));
if (!l)
return manager_dns_stub_fd(m, type);
sd_event_source **event_source = type == SOCK_DGRAM ? &l->udp_event_source : &l->tcp_event_source;
if (*event_source)
return sd_event_source_get_io_fd(*event_source);
if (l->family == AF_INET) if (l->family == AF_INET)
sa = (union sockaddr_union) { sa = (union sockaddr_union) {
@ -748,7 +648,7 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
.in6.sin6_addr = l->address.in6, .in6.sin6_addr = l->address.in6,
}; };
fd = socket(l->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); fd = socket(l->family, type | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (fd < 0) { if (fd < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
@ -758,8 +658,8 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
if (r < 0) if (r < 0)
goto fail; goto fail;
/* Do not set IP_TTL for extra DNS stub listners, as the address may not be local and in that /* Do not set IP_TTL for extra DNS stub listners, as the address may not be local and in that case
* case people may want ttl > 1. */ * people may want ttl > 1. */
if (l->family == AF_INET) if (l->family == AF_INET)
r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true); r = setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, true);
@ -773,24 +673,30 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
goto fail; goto fail;
} }
if (listen(fd, SOMAXCONN) < 0) { if (type == SOCK_STREAM &&
listen(fd, SOMAXCONN) < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
} }
r = sd_event_add_io(m->event, &l->tcp_event_source, fd, EPOLLIN, on_dns_stub_stream_extra, l); r = sd_event_add_io(m->event, event_source, fd, EPOLLIN,
type == SOCK_DGRAM ? on_dns_stub_packet_extra : on_dns_stub_stream_extra,
l);
if (r < 0) if (r < 0)
goto fail; goto fail;
r = sd_event_source_set_io_fd_own(l->tcp_event_source, true); r = sd_event_source_set_io_fd_own(*event_source, true);
if (r < 0) if (r < 0)
goto fail; goto fail;
(void) sd_event_source_set_description(l->tcp_event_source, "dns-stub-tcp-extra"); (void) sd_event_source_set_description(*event_source,
type == SOCK_DGRAM ? "dns-stub-udp-extra" : "dns-stub-tcp-extra");
if (DEBUG_LOGGING) { if (DEBUG_LOGGING) {
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty); (void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
log_debug("Listening on TCP socket %s.", strnull(pretty)); log_debug("Listening on %s socket %s.",
type == SOCK_DGRAM ? "UDP" : "TCP",
strnull(pretty));
} }
return TAKE_FD(fd); return TAKE_FD(fd);
@ -798,9 +704,11 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
fail: fail:
assert(r < 0); assert(r < 0);
(void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty); (void) in_addr_port_to_string(l->family, &l->address, l->port, &pretty);
if (r == -EADDRINUSE) return log_warning_errno(r,
return log_warning_errno(r, "Another process is already listening on TCP socket %s: %m", strnull(pretty)); r == -EADDRINUSE ? "Another process is already listening on %s socket %s: %m" :
return log_warning_errno(r, "Failed to listen on TCP socket %s: %m", strnull(pretty)); "Failed to listen on %s socket %s: %m",
type == SOCK_DGRAM ? "UDP" : "TCP",
strnull(pretty));
} }
int manager_dns_stub_start(Manager *m) { int manager_dns_stub_start(Manager *m) {
@ -818,23 +726,21 @@ int manager_dns_stub_start(Manager *m) {
"UDP/TCP"); "UDP/TCP");
if (FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_UDP)) if (FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_UDP))
r = manager_dns_stub_udp_fd(m); r = manager_dns_stub_fd(m, SOCK_DGRAM);
if (r >= 0 && if (r >= 0 &&
FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_TCP)) { FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_TCP)) {
t = "TCP"; t = "TCP";
r = manager_dns_stub_tcp_fd(m); r = manager_dns_stub_fd(m, SOCK_STREAM);
} }
if (IN_SET(r, -EADDRINUSE, -EPERM)) { if (IN_SET(r, -EADDRINUSE, -EPERM)) {
if (r == -EADDRINUSE)
log_warning_errno(r,
"Another process is already listening on %s socket 127.0.0.53:53.\n"
"Turning off local DNS stub support.", t);
else
log_warning_errno(r, log_warning_errno(r,
r == -EADDRINUSE ? "Another process is already listening on %s socket 127.0.0.53:53.\n"
"Turning off local DNS stub support." :
"Failed to listen on %s socket 127.0.0.53:53: %m.\n" "Failed to listen on %s socket 127.0.0.53:53: %m.\n"
"Turning off local DNS stub support.", t); "Turning off local DNS stub support.",
t);
manager_dns_stub_stop(m); manager_dns_stub_stop(m);
} else if (r < 0) } else if (r < 0)
return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t); return log_error_errno(r, "Failed to listen on %s socket 127.0.0.53:53: %m", t);
@ -846,9 +752,9 @@ int manager_dns_stub_start(Manager *m) {
ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners) { ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners) {
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_UDP)) if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_UDP))
(void) manager_dns_stub_udp_fd_extra(m, l); (void) manager_dns_stub_fd_extra(m, l, SOCK_DGRAM);
if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_TCP)) if (FLAGS_SET(l->mode, DNS_STUB_LISTENER_TCP))
(void) manager_dns_stub_tcp_fd_extra(m, l); (void) manager_dns_stub_fd_extra(m, l, SOCK_STREAM);
} }
} }

View File

@ -155,7 +155,7 @@ static int specifier_dnssd_host_name(char specifier, const void *data, const voi
return 0; return 0;
} }
int dnssd_render_instance_name(DnssdService *s, char **ret_name) { int dnssd_render_instance_name(const char *name_template, char **ret_name) {
static const Specifier specifier_table[] = { static const Specifier specifier_table[] = {
{ 'm', specifier_machine_id, NULL }, { 'm', specifier_machine_id, NULL },
{ 'b', specifier_boot_id, NULL }, { 'b', specifier_boot_id, NULL },
@ -171,18 +171,16 @@ int dnssd_render_instance_name(DnssdService *s, char **ret_name) {
_cleanup_free_ char *name = NULL; _cleanup_free_ char *name = NULL;
int r; int r;
assert(s); assert(name_template);
assert(s->name_template);
r = specifier_printf(s->name_template, specifier_table, s, &name); r = specifier_printf(name_template, specifier_table, NULL, &name);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to replace specifiers: %m"); return r;
if (!dns_service_name_is_valid(name)) if (!dns_service_name_is_valid(name))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), return -EINVAL;
"Service instance name '%s' is invalid.",
name);
if (ret_name)
*ret_name = TAKE_PTR(name); *ret_name = TAKE_PTR(name);
return 0; return 0;
@ -227,7 +225,7 @@ int dnssd_update_rrs(DnssdService *s) {
LIST_FOREACH(items, txt_data, s->txt_data_items) LIST_FOREACH(items, txt_data, s->txt_data_items)
txt_data->rr = dns_resource_record_unref(txt_data->rr); txt_data->rr = dns_resource_record_unref(txt_data->rr);
r = dnssd_render_instance_name(s, &n); r = dnssd_render_instance_name(s->name_template, &n);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -51,7 +51,7 @@ DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdService*, dnssd_service_free); DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdService*, dnssd_service_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdTxtData*, dnssd_txtdata_free); DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdTxtData*, dnssd_txtdata_free);
int dnssd_render_instance_name(DnssdService *s, char **ret_name); int dnssd_render_instance_name(const char *name_template, char **ret_name);
int dnssd_load(Manager *manager); int dnssd_load(Manager *manager);
int dnssd_txt_item_new_from_string(const char *key, const char *value, DnsTxtItem **ret_item); int dnssd_txt_item_new_from_string(const char *key, const char *value, DnsTxtItem **ret_item);
int dnssd_txt_item_new_from_data(const char *key, const void *value, const size_t size, DnsTxtItem **ret_item); int dnssd_txt_item_new_from_data(const char *key, const void *value, const size_t size, DnsTxtItem **ret_item);

View File

@ -183,14 +183,12 @@ static int parse_line(
k = strlen(l); k = strlen(l);
assert(k > 0); assert(k > 0);
if (l[k-1] != ']') { if (l[k-1] != ']')
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l); return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
return -EBADMSG;
}
n = strndup(l+1, k-2); n = strndup(l+1, k-2);
if (!n) if (!n)
return -ENOMEM; return log_oom();
if (sections && !nulstr_contains(sections, n)) { if (sections && !nulstr_contains(sections, n)) {
bool ignore = flags & CONFIG_PARSE_RELAXED; bool ignore = flags & CONFIG_PARSE_RELAXED;

View File

@ -938,12 +938,13 @@ int config_parse_channel(const char *unit,
r = safe_atou32(rvalue, &k); r = safe_atou32(rvalue, &k);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse channel value, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse channel value for %s=, ignoring: %s", lvalue, rvalue);
return 0; return 0;
} }
if (k < 1) { if (k < 1) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid %s value, ignoring: %s", lvalue, rvalue); log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid %s= value, ignoring: %s", lvalue, rvalue);
return 0; return 0;
} }
@ -998,24 +999,24 @@ int config_parse_advertise(const char *unit,
if (r == -ENOMEM) if (r == -ENOMEM)
return log_oom(); return log_oom();
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split advertise modes '%s', ignoring: %m", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
break; "Failed to split advertise modes '%s', ignoring assignment: %m", rvalue);
return 0;
} }
if (r == 0) if (r == 0)
break; return 0;
mode = ethtool_link_mode_bit_from_string(w); mode = ethtool_link_mode_bit_from_string(w);
/* We reuse the kernel provided enum which does not contain negative value. So, the cast /* We reuse the kernel provided enum which does not contain negative value. So, the cast
* below is mandatory. Otherwise, the check below always passes and access an invalid address. */ * below is mandatory. Otherwise, the check below always passes and access an invalid address. */
if ((int) mode < 0) { if ((int) mode < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse advertise mode, ignoring: %s", w); log_syntax(unit, LOG_WARNING, filename, line, 0,
"Failed to parse advertise mode, ignoring: %s", w);
continue; continue;
} }
advertise[mode / 32] |= 1UL << (mode % 32); advertise[mode / 32] |= 1UL << (mode % 32);
} }
return 0;
} }
int config_parse_nic_buffer_size(const char *unit, int config_parse_nic_buffer_size(const char *unit,
@ -1040,12 +1041,13 @@ int config_parse_nic_buffer_size(const char *unit,
r = safe_atou32(rvalue, &k); r = safe_atou32(rvalue, &k);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse interface buffer value, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse interface buffer value, ignoring: %s", rvalue);
return 0; return 0;
} }
if (k < 1) { if (k < 1) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid %s value, ignoring: %s", lvalue, rvalue); log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid %s= value, ignoring: %s", lvalue, rvalue);
return 0; return 0;
} }

View File

@ -62,75 +62,23 @@ int socket_address_parse(SocketAddress *a, const char *s) {
assert(a); assert(a);
assert(s); assert(s);
*a = (SocketAddress) { if (IN_SET(*s, '/', '@')) {
.type = SOCK_STREAM, /* AF_UNIX socket */
}; struct sockaddr_un un;
if (*s == '[') { r = sockaddr_un_set_path(&un, s);
uint16_t port;
/* IPv6 in [x:.....:z]:p notation */
e = strchr(s+1, ']');
if (!e)
return -EINVAL;
n = strndup(s+1, e-s-1);
if (!n)
return -ENOMEM;
errno = 0;
if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0)
return errno_or_else(EINVAL);
e++;
if (*e != ':')
return -EINVAL;
e++;
r = parse_ip_port(e, &port);
if (r < 0) if (r < 0)
return r; return r;
a->sockaddr.in6.sin6_family = AF_INET6; *a = (SocketAddress) {
a->sockaddr.in6.sin6_port = htobe16(port); .sockaddr.un = un,
a->size = sizeof(struct sockaddr_in6); .size = r,
};
} else if (*s == '/') {
/* AF_UNIX socket */
size_t l;
l = strlen(s);
if (l >= sizeof(a->sockaddr.un.sun_path)) /* Note that we refuse non-NUL-terminated sockets when
* parsing (the kernel itself is less strict here in what it
* accepts) */
return -EINVAL;
a->sockaddr.un.sun_family = AF_UNIX;
memcpy(a->sockaddr.un.sun_path, s, l);
a->size = offsetof(struct sockaddr_un, sun_path) + l + 1;
} else if (*s == '@') {
/* Abstract AF_UNIX socket */
size_t l;
l = strlen(s+1);
if (l >= sizeof(a->sockaddr.un.sun_path) - 1) /* Note that we refuse non-NUL-terminated sockets here
* when parsing, even though abstract namespace sockets
* explicitly allow embedded NUL bytes and don't consider
* them special. But it's simply annoying to debug such
* sockets. */
return -EINVAL;
a->sockaddr.un.sun_family = AF_UNIX;
memcpy(a->sockaddr.un.sun_path+1, s+1, l);
a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
} else if (startswith(s, "vsock:")) { } else if (startswith(s, "vsock:")) {
/* AF_VSOCK socket in vsock:cid:port notation */ /* AF_VSOCK socket in vsock:cid:port notation */
const char *cid_start = s + STRLEN("vsock:"); const char *cid_start = s + STRLEN("vsock:");
unsigned port; unsigned port, cid;
e = strchr(cid_start, ':'); e = strchr(cid_start, ':');
if (!e) if (!e)
@ -144,72 +92,82 @@ int socket_address_parse(SocketAddress *a, const char *s) {
if (!n) if (!n)
return -ENOMEM; return -ENOMEM;
if (!isempty(n)) { if (isempty(n))
r = safe_atou(n, &a->sockaddr.vm.svm_cid); cid = VMADDR_CID_ANY;
else {
r = safe_atou(n, &cid);
if (r < 0) if (r < 0)
return r; return r;
} else }
a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
a->sockaddr.vm.svm_family = AF_VSOCK; *a = (SocketAddress) {
a->sockaddr.vm.svm_port = port; .sockaddr.vm = {
a->size = sizeof(struct sockaddr_vm); .svm_cid = cid,
.svm_family = AF_VSOCK,
.svm_port = port,
},
.size = sizeof(struct sockaddr_vm),
};
} else { } else {
uint16_t port; uint16_t port;
e = strchr(s, ':');
if (e) {
r = parse_ip_port(e + 1, &port);
if (r < 0)
return r;
n = strndup(s, e-s);
if (!n)
return -ENOMEM;
/* IPv4 in w.x.y.z:p notation? */
r = inet_pton(AF_INET, n, &a->sockaddr.in.sin_addr);
if (r < 0)
return -errno;
if (r > 0) {
/* Gotcha, it's a traditional IPv4 address */
a->sockaddr.in.sin_family = AF_INET;
a->sockaddr.in.sin_port = htobe16(port);
a->size = sizeof(struct sockaddr_in);
} else {
int idx;
/* Uh, our last resort, an interface name */
idx = resolve_ifname(NULL, n);
if (idx < 0)
return idx;
a->sockaddr.in6.sin6_family = AF_INET6;
a->sockaddr.in6.sin6_port = htobe16(port);
a->sockaddr.in6.sin6_scope_id = idx;
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
}
} else {
/* Just a port */
r = parse_ip_port(s, &port); r = parse_ip_port(s, &port);
if (r == -ERANGE)
return r; /* Valid port syntax, but the numerical value is wrong for a port. */
if (r >= 0) {
/* Just a port */
if (socket_ipv6_is_supported())
*a = (SocketAddress) {
.sockaddr.in6 = {
.sin6_family = AF_INET6,
.sin6_port = htobe16(port),
.sin6_addr = in6addr_any,
},
.size = sizeof(struct sockaddr_in6),
};
else
*a = (SocketAddress) {
.sockaddr.in = {
.sin_family = AF_INET,
.sin_port = htobe16(port),
.sin_addr.s_addr = INADDR_ANY,
},
.size = sizeof(struct sockaddr_in),
};
} else {
union in_addr_union address;
int family, ifindex;
r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
if (r < 0) if (r < 0)
return r; return r;
if (socket_ipv6_is_supported()) { if (port == 0) /* No port, no go. */
a->sockaddr.in6.sin6_family = AF_INET6; return -EINVAL;
a->sockaddr.in6.sin6_port = htobe16(port);
a->sockaddr.in6.sin6_addr = in6addr_any; if (family == AF_INET)
a->size = sizeof(struct sockaddr_in6); *a = (SocketAddress) {
} else { .sockaddr.in = {
a->sockaddr.in.sin_family = AF_INET; .sin_family = AF_INET,
a->sockaddr.in.sin_port = htobe16(port); .sin_addr = address.in,
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY; .sin_port = htobe16(port),
a->size = sizeof(struct sockaddr_in); },
} .size = sizeof(struct sockaddr_in),
};
else if (family == AF_INET6)
*a = (SocketAddress) {
.sockaddr.in6 = {
.sin6_family = AF_INET6,
.sin6_addr = address.in6,
.sin6_port = htobe16(port),
.sin6_scope_id = ifindex,
},
.size = sizeof(struct sockaddr_in6),
};
else
assert_not_reached("Family quarrel");
} }
} }
@ -243,10 +201,6 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
assert(a); assert(a);
assert(s); assert(s);
*a = (SocketAddress) {
.type = SOCK_RAW,
};
r = extract_first_word(&s, &word, NULL, 0); r = extract_first_word(&s, &word, NULL, 0);
if (r < 0) if (r < 0)
return r; return r;
@ -263,12 +217,13 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
return r; return r;
} }
a->sockaddr.nl.nl_family = AF_NETLINK; *a = (SocketAddress) {
a->sockaddr.nl.nl_groups = group; .type = SOCK_RAW,
.sockaddr.nl.nl_family = AF_NETLINK,
a->type = SOCK_RAW; .sockaddr.nl.nl_groups = group,
a->size = sizeof(struct sockaddr_nl); .protocol = family,
a->protocol = family; .size = sizeof(struct sockaddr_nl),
};
return 0; return 0;
} }
@ -345,10 +300,14 @@ int in_addr_port_ifindex_name_from_string_auto(
/* This accepts the following: /* This accepts the following:
* 192.168.0.1:53#example.com * 192.168.0.1:53#example.com
* [2001:4860:4860::8888]:53%eth0#example.com */ * [2001:4860:4860::8888]:53%eth0#example.com
*
/* if ret_port is NULL, then strings with port cannot be specified. * If ret_port is NULL, then the port cannot be specified.
* Also, if ret_server_name is NULL, then server_name cannot be specified. */ * If ret_ifindex is NULL, then the interface index cannot be specified.
* If ret_server_name is NULL, then server_name cannot be specified.
*
* ret_family is always AF_INET or AF_INET6.
*/
m = strchr(s, '#'); m = strchr(s, '#');
if (m) { if (m) {
@ -369,15 +328,19 @@ int in_addr_port_ifindex_name_from_string_auto(
m = strchr(s, '%'); m = strchr(s, '%');
if (m) { if (m) {
if (!ret_ifindex)
return -EINVAL;
if (isempty(m + 1)) if (isempty(m + 1))
return -EINVAL; return -EINVAL;
if (ret_ifindex) { if (!ifname_valid_full(m + 1, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
/* If we shall return the interface index, try to parse it */ return -EINVAL; /* We want to return -EINVAL for syntactically invalid names,
* and -ENODEV for valid but nonexistent interfaces. */
ifindex = resolve_interface(NULL, m + 1); ifindex = resolve_interface(NULL, m + 1);
if (ifindex < 0) if (ifindex < 0)
return ifindex; return ifindex;
}
s = buf2 = strndup(s, m - s); s = buf2 = strndup(s, m - s);
if (!buf2) if (!buf2)
@ -455,36 +418,6 @@ int in_addr_port_ifindex_name_from_string_auto(
return r; return r;
} }
int in_addr_port_from_string_auto(
const char *s,
int *ret_family,
union in_addr_union *ret_address,
uint16_t *ret_port) {
union in_addr_union addr;
int family, ifindex, r;
uint16_t port;
assert(s);
r = in_addr_port_ifindex_name_from_string_auto(s, &family, &addr, &port, &ifindex, NULL);
if (r < 0)
return r;
/* This does not accept interface specified. */
if (ifindex != 0)
return -EINVAL;
if (ret_family)
*ret_family = family;
if (ret_address)
*ret_address = addr;
if (ret_port)
*ret_port = port;
return r;
}
struct in_addr_full *in_addr_full_free(struct in_addr_full *a) { struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
if (!a) if (!a)
return NULL; return NULL;

View File

@ -33,7 +33,6 @@ static inline int in_addr_ifindex_name_from_string_auto(const char *s, int *fami
static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) { static inline int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL); return in_addr_ifindex_name_from_string_auto(s, family, ret, ifindex, NULL);
} }
int in_addr_port_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret_address, uint16_t *ret_port);
struct in_addr_full { struct in_addr_full {
int family; int family;

View File

@ -86,11 +86,13 @@ int config_parse_vlanid(
r = parse_vlanid(rvalue, id); r = parse_vlanid(rvalue, id);
if (r == -ERANGE) { if (r == -ERANGE) {
log_syntax(unit, LOG_ERR, filename, line, r, "VLAN identifier outside of valid range 0…4094, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"VLAN identifier outside of valid range 0…4094, ignoring: %s", rvalue);
return 0; return 0;
} }
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN identifier value, ignoring: %s", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse VLAN identifier value, ignoring: %s", rvalue);
return 0; return 0;
} }

View File

@ -81,10 +81,12 @@ static void test_copy_tree(void) {
char original_dir[] = "/tmp/test-copy_tree/"; char original_dir[] = "/tmp/test-copy_tree/";
char copy_dir[] = "/tmp/test-copy_tree-copy/"; char copy_dir[] = "/tmp/test-copy_tree-copy/";
char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file"); char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file");
char **links = STRV_MAKE("link", "file", char **symlinks = STRV_MAKE("link", "file",
"link2", "dir1/file"); "link2", "dir1/file");
char **hardlinks = STRV_MAKE("hlink", "file",
"hlink2", "dir1/file");
const char *unixsockp; const char *unixsockp;
char **p, **link; char **p, **ll;
struct stat st; struct stat st;
int xattr_worked = -1; /* xattr support is optional in temporary directories, hence use it if we can, int xattr_worked = -1; /* xattr support is optional in temporary directories, hence use it if we can,
* but don't fail if we can't */ * but don't fail if we can't */
@ -110,20 +112,30 @@ static void test_copy_tree(void) {
xattr_worked = k >= 0; xattr_worked = k >= 0;
} }
STRV_FOREACH_PAIR(link, p, links) { STRV_FOREACH_PAIR(ll, p, symlinks) {
_cleanup_free_ char *f, *l; _cleanup_free_ char *f, *l;
assert_se(f = path_join(original_dir, *p)); assert_se(f = path_join(original_dir, *p));
assert_se(l = path_join(original_dir, *link)); assert_se(l = path_join(original_dir, *ll));
assert_se(mkdir_parents(l, 0755) >= 0); assert_se(mkdir_parents(l, 0755) >= 0);
assert_se(symlink(f, l) == 0); assert_se(symlink(f, l) == 0);
} }
STRV_FOREACH_PAIR(ll, p, hardlinks) {
_cleanup_free_ char *f, *l;
assert_se(f = path_join(original_dir, *p));
assert_se(l = path_join(original_dir, *ll));
assert_se(mkdir_parents(l, 0755) >= 0);
assert_se(link(f, l) == 0);
}
unixsockp = strjoina(original_dir, "unixsock"); unixsockp = strjoina(original_dir, "unixsock");
assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0); assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0);
assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE) == 0); assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS) == 0);
STRV_FOREACH(p, files) { STRV_FOREACH(p, files) {
_cleanup_free_ char *buf, *f, *c = NULL; _cleanup_free_ char *buf, *f, *c = NULL;
@ -147,16 +159,30 @@ static void test_copy_tree(void) {
} }
} }
STRV_FOREACH_PAIR(link, p, links) { STRV_FOREACH_PAIR(ll, p, symlinks) {
_cleanup_free_ char *target, *f, *l; _cleanup_free_ char *target, *f, *l;
assert_se(f = strjoin(original_dir, *p)); assert_se(f = strjoin(original_dir, *p));
assert_se(l = strjoin(copy_dir, *link)); assert_se(l = strjoin(copy_dir, *ll));
assert_se(chase_symlinks(l, NULL, 0, &target, NULL) == 1); assert_se(chase_symlinks(l, NULL, 0, &target, NULL) == 1);
assert_se(path_equal(f, target)); assert_se(path_equal(f, target));
} }
STRV_FOREACH_PAIR(ll, p, hardlinks) {
_cleanup_free_ char *f, *l;
struct stat a, b;
assert_se(f = strjoin(copy_dir, *p));
assert_se(l = strjoin(copy_dir, *ll));
assert_se(lstat(f, &a) >= 0);
assert_se(lstat(l, &b) >= 0);
assert_se(a.st_ino == b.st_ino);
assert_se(a.st_dev == b.st_dev);
}
unixsockp = strjoina(copy_dir, "unixsock"); unixsockp = strjoina(copy_dir, "unixsock");
assert_se(stat(unixsockp, &st) >= 0); assert_se(stat(unixsockp, &st) >= 0);
assert_se(S_ISSOCK(st.st_mode)); assert_se(S_ISSOCK(st.st_mode));

View File

@ -58,6 +58,8 @@ static void test_in_addr_prefix_from_string_one(
} }
static void test_in_addr_prefix_from_string(void) { static void test_in_addr_prefix_from_string(void) {
log_info("/* %s */", __func__);
test_in_addr_prefix_from_string_one("", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); test_in_addr_prefix_from_string_one("", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
test_in_addr_prefix_from_string_one("/", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); test_in_addr_prefix_from_string_one("/", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
test_in_addr_prefix_from_string_one("/8", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0); test_in_addr_prefix_from_string_one("/8", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
@ -90,7 +92,7 @@ static void test_in_addr_prefix_to_string_valid(int family, const char *p) {
union in_addr_union u; union in_addr_union u;
unsigned char l; unsigned char l;
log_info("/* %s */", p); log_info("%s: %s", __func__, p);
assert_se(in_addr_prefix_from_string(p, family, &u, &l) >= 0); assert_se(in_addr_prefix_from_string(p, family, &u, &l) >= 0);
assert_se(in_addr_prefix_to_string(family, &u, l, &str) >= 0); assert_se(in_addr_prefix_to_string(family, &u, l, &str) >= 0);
@ -102,7 +104,7 @@ static void test_in_addr_prefix_to_string_unoptimized(int family, const char *p)
union in_addr_union u1, u2; union in_addr_union u1, u2;
unsigned char len1, len2; unsigned char len1, len2;
log_info("/* %s */", p); log_info("%s: %s", __func__, p);
assert_se(in_addr_prefix_from_string(p, family, &u1, &len1) >= 0); assert_se(in_addr_prefix_from_string(p, family, &u1, &len1) >= 0);
assert_se(in_addr_prefix_to_string(family, &u1, len1, &str1) >= 0); assert_se(in_addr_prefix_to_string(family, &u1, len1, &str1) >= 0);
@ -115,6 +117,8 @@ static void test_in_addr_prefix_to_string_unoptimized(int family, const char *p)
} }
static void test_in_addr_prefix_to_string(void) { static void test_in_addr_prefix_to_string(void) {
log_info("/* %s */", __func__);
test_in_addr_prefix_to_string_valid(AF_INET, "0.0.0.0/32"); test_in_addr_prefix_to_string_valid(AF_INET, "0.0.0.0/32");
test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/0"); test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/0");
test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/24"); test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/24");
@ -137,6 +141,8 @@ static void test_in_addr_random_prefix(void) {
_cleanup_free_ char *str = NULL; _cleanup_free_ char *str = NULL;
union in_addr_union a; union in_addr_union a;
log_info("/* %s */", __func__);
assert_se(in_addr_from_string(AF_INET, "192.168.10.1", &a) >= 0); assert_se(in_addr_from_string(AF_INET, "192.168.10.1", &a) >= 0);
assert_se(in_addr_random_prefix(AF_INET, &a, 31, 32) >= 0); assert_se(in_addr_random_prefix(AF_INET, &a, 31, 32) >= 0);

View File

@ -12,11 +12,20 @@ static void test_socket_address_parse_one(const char *in, int ret, int family, c
int r; int r;
r = socket_address_parse(&a, in); r = socket_address_parse(&a, in);
if (r >= 0) if (r >= 0) {
assert_se(socket_address_print(&a, &out) >= 0); r = socket_address_print(&a, &out);
if (r < 0)
log_error_errno(r, "Printing failed for \"%s\": %m", in);
assert(r >= 0);
assert_se(a.type == 0);
}
log_info("\"%s\" → %s → \"%s\" (expect \"%s\")", in, log_info("\"%s\" → %s %d → \"%s\" (expect %d / \"%s\")",
r >= 0 ? "" : "", empty_to_dash(out), r >= 0 ? expected ?: in : "-"); in,
r >= 0 ? "" : "", r,
empty_to_dash(out),
ret,
ret >= 0 ? expected ?: in : "-");
assert_se(r == ret); assert_se(r == ret);
if (r >= 0) { if (r >= 0) {
assert_se(a.sockaddr.sa.sa_family == family); assert_se(a.sockaddr.sa.sa_family == family);
@ -50,14 +59,24 @@ static void test_socket_address_parse(void) {
test_socket_address_parse_one("[::1]:0", -EINVAL, 0, NULL); test_socket_address_parse_one("[::1]:0", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]:65536", -ERANGE, 0, NULL); test_socket_address_parse_one("[::1]:65536", -ERANGE, 0, NULL);
test_socket_address_parse_one("[a:b:1]:8888", -EINVAL, 0, NULL); test_socket_address_parse_one("[a:b:1]:8888", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo:1234", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo:0", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo%lo:1234", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]% lo:1234", -EINVAL, 0, NULL);
test_socket_address_parse_one("8888", 0, default_family, "[::]:8888"); test_socket_address_parse_one("8888", 0, default_family, "[::]:8888");
test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6, test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6,
"[2001:db8:0:85a3::ac1f:8001]:8888"); "[2001:db8:0:85a3::ac1f:8001]:8888");
test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL); test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL);
test_socket_address_parse_one("[::1]:1234%lo", 0, AF_INET6, NULL);
test_socket_address_parse_one("[::1]:0%lo", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL);
test_socket_address_parse_one("[::1]:1234%lo%lo", -ENODEV, 0, NULL);
test_socket_address_parse_one("[::1]:1234%xxxxasdf", -ENODEV, 0, NULL);
test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL); test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL);
test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL); test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL);
test_socket_address_parse_one("/", 0, AF_UNIX, NULL); test_socket_address_parse_one("/", -EINVAL, 0, NULL);
test_socket_address_parse_one("@abstract", 0, AF_UNIX, NULL); test_socket_address_parse_one("@abstract", 0, AF_UNIX, NULL);
{ {
@ -198,9 +217,13 @@ static void test_socket_address_is(void) {
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0);
assert_se(socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM)); assert_se( socket_address_is(&a, "192.168.1.1:8888", 0 /* unspecified yet */));
assert_se(!socket_address_is(&a, "route", 0));
assert_se(!socket_address_is(&a, "route", SOCK_STREAM)); assert_se(!socket_address_is(&a, "route", SOCK_STREAM));
assert_se(!socket_address_is(&a, "192.168.1.1:8888", SOCK_RAW)); assert_se(!socket_address_is(&a, "192.168.1.1:8888", SOCK_RAW));
assert_se(!socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
a.type = SOCK_STREAM;
assert_se( socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM));
} }
static void test_socket_address_is_netlink(void) { static void test_socket_address_is_netlink(void) {
@ -284,66 +307,83 @@ static void test_in_addr_ifindex_name_from_string_auto(void) {
test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com"); test_in_addr_ifindex_name_from_string_auto_one("fe80::18%19#another.test.com", "another.test.com");
} }
static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex, const char *server_name) { static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex,
_cleanup_free_ char *name = NULL, *x = NULL; const char *server_name, const char *str_repr) {
union in_addr_union a; union in_addr_union a;
uint16_t p; uint16_t p;
int f, i; int f, i;
char *fake;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) >= 0); log_info("%s: %s", __func__, str);
{
_cleanup_free_ char *name = NULL, *x = NULL;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, &name) == 0);
assert_se(family == f); assert_se(family == f);
assert_se(port == p); assert_se(port == p);
assert_se(ifindex == i); assert_se(ifindex == i);
assert_se(streq_ptr(server_name, name)); assert_se(streq_ptr(server_name, name));
assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0); assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0);
assert_se(streq(str, x)); assert_se(streq(str_repr ?: str, x));
}
if (port > 0)
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, NULL, &i, &fake) == -EINVAL);
else {
_cleanup_free_ char *name = NULL, *x = NULL;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, NULL, &i, &name) == 0);
assert_se(family == f);
assert_se(ifindex == i);
assert_se(streq_ptr(server_name, name));
assert_se(in_addr_port_ifindex_name_to_string(f, &a, 0, i, name, &x) >= 0);
assert_se(streq(str_repr ?: str, x));
}
if (ifindex > 0)
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, NULL, &fake) == -EINVAL);
else {
_cleanup_free_ char *name = NULL, *x = NULL;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, NULL, &name) == 0);
assert_se(family == f);
assert_se(port == p);
assert_se(streq_ptr(server_name, name));
assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, 0, name, &x) >= 0);
assert_se(streq(str_repr ?: str, x));
}
if (server_name)
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, NULL) == -EINVAL);
else {
_cleanup_free_ char *x = NULL;
assert_se(in_addr_port_ifindex_name_from_string_auto(str, &f, &a, &p, &i, NULL) == 0);
assert_se(family == f);
assert_se(port == p);
assert_se(ifindex == i);
assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, NULL, &x) >= 0);
assert_se(streq(str_repr ?: str, x));
}
} }
static void test_in_addr_port_ifindex_name_from_string_auto(void) { static void test_in_addr_port_ifindex_name_from_string_auto(void) {
log_info("/* %s */", __func__); log_info("/* %s */", __func__);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL); test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com"); test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL); test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com"); test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL); test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com"); test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL); test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL); test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%lo", AF_INET6, 0, 1, NULL, "fe80::18%1");
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com"); test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com"); test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL, NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL); test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1");
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com"); test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com", NULL);
} test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com", NULL);
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL, NULL);
static void test_in_addr_port_from_string_auto_one(const char *str, int family, const char *address_string, uint16_t port) { test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com", NULL);
union in_addr_union a, b; test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo", AF_INET6, 53, 1, NULL, "[fe80::18]:53%1");
uint16_t p; test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%lo#hoge.com", AF_INET6, 53, 1, "hoge.com", "[fe80::18]:53%1#hoge.com");
int f;
assert_se(in_addr_port_from_string_auto(str, &f, &a, &p) >= 0);
assert_se(family == f);
assert_se(port == p);
assert_se(in_addr_from_string(family, address_string, &b) >= 0);
assert_se(in_addr_equal(family, &a, &b) == 1);
}
static void test_in_addr_port_from_string_auto(void) {
log_info("/* %s */", __func__);
assert_se(in_addr_port_from_string_auto("192.168.0.1#test.com", NULL, NULL, NULL) < 0);
assert_se(in_addr_port_from_string_auto("192.168.0.1:53#example.com", NULL, NULL, NULL) < 0);
assert_se(in_addr_port_from_string_auto("fe80::18#hoge.com", NULL, NULL, NULL) < 0);
assert_se(in_addr_port_from_string_auto("fe80::18%19", NULL, NULL, NULL) < 0);
assert_se(in_addr_port_from_string_auto("fe80::18%19#hoge.com", NULL, NULL, NULL) < 0);
assert_se(in_addr_port_from_string_auto("[fe80::18]:53#hoge.com", NULL, NULL, NULL) < 0);
assert_se(in_addr_port_from_string_auto("[fe80::18]:53%19", NULL, NULL, NULL) < 0);
assert_se(in_addr_port_from_string_auto("[fe80::18]:53%19#hoge.com", NULL, NULL, NULL) < 0);
test_in_addr_port_from_string_auto_one("192.168.0.1", AF_INET, "192.168.0.1", 0);
test_in_addr_port_from_string_auto_one("192.168.0.1:53", AF_INET, "192.168.0.1", 53);
test_in_addr_port_from_string_auto_one("fe80::18", AF_INET6, "fe80::18", 0);
test_in_addr_port_from_string_auto_one("[fe80::18]:53", AF_INET6, "fe80::18", 53);
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -360,7 +400,6 @@ int main(int argc, char *argv[]) {
test_in_addr_ifindex_from_string_auto(); test_in_addr_ifindex_from_string_auto();
test_in_addr_ifindex_name_from_string_auto(); test_in_addr_ifindex_name_from_string_auto();
test_in_addr_port_ifindex_name_from_string_auto(); test_in_addr_port_ifindex_name_from_string_auto();
test_in_addr_port_from_string_auto();
return 0; return 0;
} }

View File

@ -44,9 +44,13 @@ static void test_ifname_valid(void) {
assert(ifname_valid("foo.bar")); assert(ifname_valid("foo.bar"));
assert(!ifname_valid("x:y")); assert(!ifname_valid("x:y"));
assert(ifname_valid("xxxxxxxxxxxxxxx")); assert( ifname_valid_full("xxxxxxxxxxxxxxx", 0));
assert(!ifname_valid("xxxxxxxxxxxxxxxx")); assert(!ifname_valid_full("xxxxxxxxxxxxxxxx", 0));
assert(ifname_valid_full("xxxxxxxxxxxxxxxx", true)); assert( ifname_valid_full("xxxxxxxxxxxxxxxx", IFNAME_VALID_ALTERNATIVE));
assert( ifname_valid_full("xxxxxxxxxxxxxxxx", IFNAME_VALID_ALTERNATIVE));
assert(!ifname_valid_full("999", IFNAME_VALID_ALTERNATIVE));
assert( ifname_valid_full("999", IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC));
assert(!ifname_valid_full("0", IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC));
} }
static void test_socket_print_unix_one(const char *in, size_t len_in, const char *expected) { static void test_socket_print_unix_one(const char *in, size_t len_in, const char *expected) {
@ -504,17 +508,11 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG); test_setup_logging(LOG_DEBUG);
test_ifname_valid(); test_ifname_valid();
test_socket_print_unix(); test_socket_print_unix();
test_sockaddr_equal(); test_sockaddr_equal();
test_sockaddr_un_len(); test_sockaddr_un_len();
test_in_addr_is_multicast(); test_in_addr_is_multicast();
test_getpeercred_getpeergroups(); test_getpeercred_getpeergroups();
test_passfd_read(); test_passfd_read();
test_passfd_contents_read(); test_passfd_contents_read();
test_receive_nopassfd(); test_receive_nopassfd();

View File

@ -89,7 +89,8 @@ int config_parse_servers(
else { else {
r = manager_parse_server_string(m, ltype, rvalue); r = manager_parse_server_string(m, ltype, rvalue);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NTP server string '%s'. Ignoring.", rvalue); log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse NTP server string '%s', ignoring: %m", rvalue);
return 0; return 0;
} }
} }

View File

@ -1543,7 +1543,7 @@ static int copy_files(Item *i) {
dfd, bn, dfd, bn,
i->uid_set ? i->uid : UID_INVALID, i->uid_set ? i->uid : UID_INVALID,
i->gid_set ? i->gid : GID_INVALID, i->gid_set ? i->gid : GID_INVALID,
COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE); COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS);
if (r < 0) { if (r < 0) {
struct stat a, b; struct stat a, b;

View File

@ -7,6 +7,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "ethtool-util.h" #include "ethtool-util.h"
#include "link-config.h" #include "link-config.h"
#include "network-internal.h" #include "network-internal.h"
#include "socket-util.h"
%} %}
struct ConfigPerfItem; struct ConfigPerfItem;
%null_strings %null_strings
@ -36,7 +37,7 @@ Link.MACAddressPolicy, config_parse_mac_address_policy, 0,
Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac) Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac)
Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy) Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
Link.Name, config_parse_ifname, 0, offsetof(link_config, name) Link.Name, config_parse_ifname, 0, offsetof(link_config, name)
Link.AlternativeName, config_parse_ifnames, 1, offsetof(link_config, alternative_names) Link.AlternativeName, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(link_config, alternative_names)
Link.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(link_config, alternative_names_policy) Link.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(link_config, alternative_names_policy)
Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias) Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu) Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu)

View File

@ -118,8 +118,7 @@ int udev_builtin_run(sd_device *dev, UdevBuiltinCommand cmd, const char *command
if (!builtins[cmd]) if (!builtins[cmd])
return -EOPNOTSUPP; return -EOPNOTSUPP;
r = strv_split_full(&argv, command, NULL, r = strv_split_full(&argv, command, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_RETAIN_ESCAPE);
EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_RETAIN_ESCAPE);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -166,7 +166,7 @@ static int xdg_config_parse_string(
/* XDG does not allow duplicate definitions. */ /* XDG does not allow duplicate definitions. */
if (*out) { if (*out) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Key %s was defined multiple times, ignoring.", lvalue); log_syntax(unit, LOG_WARNING, filename, line, 0, "Key %s was defined multiple times, ignoring.", lvalue);
return 0; return 0;
} }
@ -238,7 +238,7 @@ static int xdg_config_parse_strv(
/* XDG does not allow duplicate definitions. */ /* XDG does not allow duplicate definitions. */
if (*ret_sv) { if (*ret_sv) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Key %s was already defined, ignoring.", lvalue); log_syntax(unit, LOG_WARNING, filename, line, 0, "Key %s was already defined, ignoring.", lvalue);
return 0; return 0;
} }
@ -256,7 +256,7 @@ static int xdg_config_parse_strv(
/* Move forward, and ensure it is a valid escape. */ /* Move forward, and ensure it is a valid escape. */
end++; end++;
if (!strchr("sntr\\;", *end)) { if (!strchr("sntr\\;", *end)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Undefined escape sequence \\%c.", *end); log_syntax(unit, LOG_WARNING, filename, line, 0, "Undefined escape sequence \\%c.", *end);
return 0; return 0;
} }
continue; continue;

View File

@ -0,0 +1,33 @@
[Match]
Name=test1
[Network]
IPv6AcceptRA=no
# fwmark
[RoutingPolicyRule]
Table=1011
Family=ipv4
Priority=10111
FirewallMark=1011
# oif
[RoutingPolicyRule]
Table=1011
Family=ipv4
Priority=10112
OutgoingInterface=test1
# iif
[RoutingPolicyRule]
Table=1011
Family=ipv4
Priority=10113
IncomingInterface=test1
# source
[RoutingPolicyRule]
Table=1011
Family=ipv4
Priority=10114
From=192.168.8.254

View File

@ -1735,9 +1735,11 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
'25-vrf.network', '25-vrf.network',
'26-link-local-addressing-ipv6.network', '26-link-local-addressing-ipv6.network',
'routing-policy-rule-dummy98.network', 'routing-policy-rule-dummy98.network',
'routing-policy-rule-test1.network'] 'routing-policy-rule-test1.network',
'routing-policy-rule-reconfigure.network',
]
routing_policy_rule_tables = ['7', '8', '9'] routing_policy_rule_tables = ['7', '8', '9', '1011']
routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']] routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']]
def setUp(self): def setUp(self):
@ -1970,32 +1972,6 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertRegex(output, 'iif test1') self.assertRegex(output, 'iif test1')
self.assertRegex(output, 'lookup 8') self.assertRegex(output, 'lookup 8')
output = check_output('ip -6 rule list iif test1 priority 101')
print(output)
self.assertRegex(output, '101:')
self.assertRegex(output, 'from all')
self.assertRegex(output, 'iif test1')
self.assertRegex(output, 'lookup 9')
run('ip rule delete iif test1 priority 111')
output = check_output('ip rule list iif test1 priority 111')
print(output)
self.assertEqual(output, '')
run(*networkctl_cmd, 'reconfigure', 'test1', env=env)
self.wait_online(['test1:degraded'])
output = check_output('ip rule list iif test1 priority 111')
print(output)
self.assertRegex(output, '111:')
self.assertRegex(output, 'from 192.168.100.18')
self.assertRegex(output, r'tos (0x08|throughput)\s')
self.assertRegex(output, 'iif test1')
self.assertRegex(output, 'oif test1')
self.assertRegex(output, 'lookup 7')
def test_routing_policy_rule_issue_11280(self): def test_routing_policy_rule_issue_11280(self):
copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev', copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
'routing-policy-rule-dummy98.network', '12-dummy.netdev') 'routing-policy-rule-dummy98.network', '12-dummy.netdev')
@ -2016,6 +1992,39 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
stop_networkd(remove_state_files=False) stop_networkd(remove_state_files=False)
def test_routing_policy_rule_reconfigure(self):
copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure.network', '11-dummy.netdev')
start_networkd()
self.wait_online(['test1:degraded'])
output = check_output('ip rule list table 1011')
print(output)
self.assertRegex(output, '10111: from all fwmark 0x3f3 lookup 1011')
self.assertRegex(output, '10112: from all oif test1 lookup 1011')
self.assertRegex(output, '10113: from all iif test1 lookup 1011')
self.assertRegex(output, '10114: from 192.168.8.254 lookup 1011')
run('ip rule delete priority 10111')
run('ip rule delete priority 10112')
run('ip rule delete priority 10113')
run('ip rule delete priority 10114')
run('ip rule delete priority 10115')
output = check_output('ip rule list table 1011')
print(output)
self.assertEqual(output, '')
run(*networkctl_cmd, 'reconfigure', 'test1', env=env)
self.wait_online(['test1:degraded'])
output = check_output('ip rule list table 1011')
print(output)
self.assertRegex(output, '10111: from all fwmark 0x3f3 lookup 1011')
self.assertRegex(output, '10112: from all oif test1 lookup 1011')
self.assertRegex(output, '10113: from all iif test1 lookup 1011')
self.assertRegex(output, '10114: from 192.168.8.254 lookup 1011')
@expectedFailureIfRoutingPolicyPortRangeIsNotAvailable() @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
def test_routing_policy_rule_port_range(self): def test_routing_policy_rule_port_range(self):
copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev') copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')