Compare commits
51 Commits
dee00c1939
...
f8bff7805e
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | f8bff7805e | |
Lennart Poettering | 6ae05c9b14 | |
Zbigniew Jędrzejewski-Szmek | f29d38b7d4 | |
Lennart Poettering | 3a17308c2a | |
Yu Watanabe | 87adeabfb7 | |
Yu Watanabe | 17d2b2e4ef | |
Yu Watanabe | 2102d33cfb | |
Yu Watanabe | bd1000b4a0 | |
Yu Watanabe | c2d6fcb147 | |
Yu Watanabe | d85b0d69f1 | |
Yu Watanabe | 755dbda355 | |
Yu Watanabe | b6c7c4a87b | |
Yu Watanabe | 323dda7806 | |
Yu Watanabe | 144fb165fd | |
Yu Watanabe | adb5848706 | |
Yu Watanabe | 196d41bcde | |
Yu Watanabe | a864170745 | |
Yu Watanabe | e459258f19 | |
Yu Watanabe | 94069bef23 | |
Yu Watanabe | 34136e1503 | |
Yu Watanabe | 7a602af041 | |
Yu Watanabe | 3de39a1ad4 | |
Yu Watanabe | c56566530b | |
Yu Watanabe | 40f04cde5b | |
Yu Watanabe | 8add8b508d | |
Yu Watanabe | 4c382a8772 | |
Yu Watanabe | e3489e96b3 | |
Yu Watanabe | 2ca601d8cb | |
Yu Watanabe | 696c0832e2 | |
Yu Watanabe | a8a50f4fb7 | |
Yu Watanabe | 02241e4339 | |
Yu Watanabe | c799c93c62 | |
Zbigniew Jędrzejewski-Szmek | c097bf1f50 | |
Zbigniew Jędrzejewski-Szmek | 08224f38ac | |
Zbigniew Jędrzejewski-Szmek | a73569f180 | |
Zbigniew Jędrzejewski-Szmek | a07ab56a49 | |
Zbigniew Jędrzejewski-Szmek | c4c6ee3a95 | |
Zbigniew Jędrzejewski-Szmek | 44ab234734 | |
Zbigniew Jędrzejewski-Szmek | 75af1666d7 | |
Zbigniew Jędrzejewski-Szmek | 222eaaf937 | |
Zbigniew Jędrzejewski-Szmek | c1f848d73c | |
Zbigniew Jędrzejewski-Szmek | b16d17a68a | |
Zbigniew Jędrzejewski-Szmek | 2313524aa0 | |
Zbigniew Jędrzejewski-Szmek | 25b2d602b9 | |
Zbigniew Jędrzejewski-Szmek | 610618ff61 | |
Zbigniew Jędrzejewski-Szmek | 38c30b35f3 | |
Zbigniew Jędrzejewski-Szmek | d491917c9f | |
Zbigniew Jędrzejewski-Szmek | b5febb3f56 | |
Zbigniew Jędrzejewski-Szmek | e4bed40f40 | |
Lennart Poettering | 652d90407a | |
Lennart Poettering | dd480f7835 |
|
@ -200,22 +200,24 @@
|
|||
</para>
|
||||
|
||||
<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
|
||||
address v.w.x.y on a port z.</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>
|
||||
<literal><replaceable>v.w.x.y</replaceable>:<replaceable>z</replaceable></literal>, it is interpeted
|
||||
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
|
||||
<literal>vsock:x:y</literal>, it is read as CID <literal>x</literal> on
|
||||
a port <literal>y</literal> 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>
|
||||
<literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable></literal>, it is interpreted as
|
||||
IPv6 address <replaceable>x</replaceable> and port <replaceable>y</replaceable>. An optional
|
||||
interface scope (interface name or number) may be specifed after a <literal>%</literal> symbol:
|
||||
<literal>[<replaceable>x</replaceable>]:<replaceable>y</replaceable>%<replaceable>dev</replaceable></literal>.
|
||||
Interface scopes are only useful with link-local addresses, because the kernel ignores them in other
|
||||
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.
|
||||
<varname>ListenSequentialPacket=</varname>) is only available
|
||||
|
|
|
@ -1654,7 +1654,10 @@ int btrfs_subvol_snapshot_fd_full(
|
|||
} else if (r < 0)
|
||||
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)
|
||||
goto fallback_fail;
|
||||
|
||||
|
|
248
src/basic/copy.c
248
src/basic/copy.c
|
@ -22,8 +22,10 @@
|
|||
#include "missing_syscall.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "selinux-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "time-util.h"
|
||||
|
@ -394,6 +396,188 @@ static int fd_copy_symlink(
|
|||
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(
|
||||
int df,
|
||||
const char *from,
|
||||
|
@ -403,6 +587,7 @@ static int fd_copy_regular(
|
|||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
HardlinkContext *hardlink_context,
|
||||
copy_progress_bytes_t progress,
|
||||
void *userdata) {
|
||||
|
||||
|
@ -414,6 +599,12 @@ static int fd_copy_regular(
|
|||
assert(st);
|
||||
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);
|
||||
if (fdf < 0)
|
||||
return -errno;
|
||||
|
@ -456,6 +647,7 @@ static int fd_copy_regular(
|
|||
(void) unlinkat(dt, to, 0);
|
||||
}
|
||||
|
||||
(void) memorize_hardlink(hardlink_context, st, dt, to);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -467,13 +659,20 @@ static int fd_copy_fifo(
|
|||
const char *to,
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags) {
|
||||
CopyFlags copy_flags,
|
||||
HardlinkContext *hardlink_context) {
|
||||
int r;
|
||||
|
||||
assert(from);
|
||||
assert(st);
|
||||
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) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, S_IFIFO);
|
||||
if (r < 0)
|
||||
|
@ -494,6 +693,7 @@ static int fd_copy_fifo(
|
|||
if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
|
||||
r = -errno;
|
||||
|
||||
(void) memorize_hardlink(hardlink_context, st, dt, to);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -505,13 +705,20 @@ static int fd_copy_node(
|
|||
const char *to,
|
||||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags) {
|
||||
CopyFlags copy_flags,
|
||||
HardlinkContext *hardlink_context) {
|
||||
int r;
|
||||
|
||||
assert(from);
|
||||
assert(st);
|
||||
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) {
|
||||
r = mac_selinux_create_file_prepare_at(dt, to, st->st_mode & S_IFMT);
|
||||
if (r < 0)
|
||||
|
@ -532,6 +739,7 @@ static int fd_copy_node(
|
|||
if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
|
||||
r = -errno;
|
||||
|
||||
(void) memorize_hardlink(hardlink_context, st, dt, to);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -546,11 +754,17 @@ static int fd_copy_directory(
|
|||
uid_t override_uid,
|
||||
gid_t override_gid,
|
||||
CopyFlags copy_flags,
|
||||
HardlinkContext *hardlink_context,
|
||||
const char *display_path,
|
||||
copy_progress_path_t progress_path,
|
||||
copy_progress_bytes_t progress_bytes,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_(hardlink_context_destroy) HardlinkContext our_hardlink_context = {
|
||||
.dir_fd = -1,
|
||||
.parent_fd = -1,
|
||||
};
|
||||
|
||||
_cleanup_close_ int fdf = -1, fdt = -1;
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
struct dirent *de;
|
||||
|
@ -570,6 +784,16 @@ static int fd_copy_directory(
|
|||
if (fdf < 0)
|
||||
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);
|
||||
if (!d)
|
||||
return -errno;
|
||||
|
@ -668,15 +892,15 @@ static int fd_copy_directory(
|
|||
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))
|
||||
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))
|
||||
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))
|
||||
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))
|
||||
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
|
||||
q = -EOPNOTSUPP;
|
||||
|
||||
|
@ -730,15 +954,15 @@ int copy_tree_at_full(
|
|||
return -errno;
|
||||
|
||||
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))
|
||||
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))
|
||||
return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags);
|
||||
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))
|
||||
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
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
@ -762,7 +986,7 @@ int copy_directory_fd_full(
|
|||
if (!S_ISDIR(st.st_mode))
|
||||
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(
|
||||
|
@ -784,7 +1008,7 @@ int copy_directory_full(
|
|||
if (!S_ISDIR(st.st_mode))
|
||||
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(
|
||||
|
|
|
@ -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_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_HARDLINKS = 1 << 8, /* Try to reproduce hard links */
|
||||
} CopyFlags;
|
||||
|
||||
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
|
||||
|
|
|
@ -68,7 +68,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
|
|||
if (a->sockaddr.in.sin_port == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
|
||||
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
@ -80,7 +80,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
|
|||
if (a->sockaddr.in6.sin6_port == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
|
||||
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
|
||||
return -EINVAL;
|
||||
|
||||
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 0;
|
||||
|
@ -124,7 +124,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
|
|||
if (a->size != sizeof(struct sockaddr_nl))
|
||||
return -EINVAL;
|
||||
|
||||
if (!IN_SET(a->type, SOCK_RAW, SOCK_DGRAM))
|
||||
if (!IN_SET(a->type, 0, SOCK_RAW, SOCK_DGRAM))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
@ -133,7 +133,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) {
|
|||
if (a->size != sizeof(struct sockaddr_vm))
|
||||
return -EINVAL;
|
||||
|
||||
if (!IN_SET(a->type, SOCK_STREAM, SOCK_DGRAM))
|
||||
if (!IN_SET(a->type, 0, SOCK_STREAM, SOCK_DGRAM))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
@ -399,19 +399,23 @@ int sockaddr_pretty(
|
|||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
char a[INET6_ADDRSTRLEN];
|
||||
char a[INET6_ADDRSTRLEN], ifname[IF_NAMESIZE + 1];
|
||||
|
||||
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) {
|
||||
r = asprintf(&p,
|
||||
"[%s]:%u",
|
||||
"[%s]:%u%s%s",
|
||||
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)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
p = strdup(a);
|
||||
p = sa->in6.sin6_scope_id != 0 ? strjoin(a, "%", ifname) : strdup(a);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -686,17 +690,19 @@ static const char* const ip_tos_table[] = {
|
|||
|
||||
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;
|
||||
|
||||
/* 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
|
||||
* also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
|
||||
|
||||
assert(!(flags & ~_IFNAME_VALID_ALL));
|
||||
|
||||
if (isempty(p))
|
||||
return false;
|
||||
|
||||
if (alternative) {
|
||||
if (flags & IFNAME_VALID_ALTERNATIVE) {
|
||||
if (strlen(p) >= ALTIFNAMSIZ)
|
||||
return false;
|
||||
} else {
|
||||
|
@ -707,23 +713,28 @@ bool ifname_valid_full(const char *p, bool alternative) {
|
|||
if (dot_or_dot_dot(p))
|
||||
return false;
|
||||
|
||||
while (*p) {
|
||||
if ((unsigned char) *p >= 127U)
|
||||
for (const char *t = p; *t; t++) {
|
||||
if ((unsigned char) *t >= 127U)
|
||||
return false;
|
||||
|
||||
if ((unsigned char) *p <= 32U)
|
||||
if ((unsigned char) *t <= 32U)
|
||||
return false;
|
||||
|
||||
if (IN_SET(*p, ':', '/'))
|
||||
if (IN_SET(*t, ':', '/'))
|
||||
return false;
|
||||
|
||||
numeric = numeric && (*p >= '0' && *p <= '9');
|
||||
p++;
|
||||
numeric = numeric && (*t >= '0' && *t <= '9');
|
||||
}
|
||||
|
||||
if (numeric)
|
||||
if (numeric) {
|
||||
if (!(flags & IFNAME_VALID_NUMERIC))
|
||||
return false;
|
||||
|
||||
/* Verify that the number is well-formatted and in range. */
|
||||
if (parse_ifindex(p) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
l = strlen(path);
|
||||
if (l == 0)
|
||||
if (l < 2)
|
||||
return -EINVAL;
|
||||
if (!IN_SET(path[0], '/', '@'))
|
||||
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
|
||||
* the kernel is: we insist on NUL termination (both for abstract namespace and regular file system socket
|
||||
|
|
|
@ -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_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) {
|
||||
return ifname_valid_full(p, false);
|
||||
return ifname_valid_full(p, 0);
|
||||
}
|
||||
bool address_label_valid(const char *p);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -627,7 +627,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
|
|||
}
|
||||
|
||||
/* 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)
|
||||
return 0;
|
||||
if (r != -ENOTDIR)
|
||||
|
@ -699,9 +699,9 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
|
|||
if (errno != ENOENT)
|
||||
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
|
||||
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)
|
||||
return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ int config_parse_default_file_system_type(
|
|||
assert(s);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2551,7 +2551,7 @@ int config_parse_line_max(
|
|||
|
||||
r = parse_size(rvalue, 1024, &v);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2606,7 +2606,7 @@ int config_parse_compress(
|
|||
if (r < 0) {
|
||||
r = parse_size(rvalue, 1024, &compress->threshold_bytes);
|
||||
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);
|
||||
else
|
||||
compress->enabled = true;
|
||||
|
|
|
@ -466,12 +466,14 @@ int config_parse_n_autovts(
|
|||
|
||||
r = safe_atou(rvalue, &o);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -919,7 +919,7 @@ int config_parse_tmpfs_size(
|
|||
if (r >= 0 && (k <= 0 || (uint64_t) (size_t) k != k))
|
||||
r = -ERANGE;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1066,7 +1066,7 @@ finish:
|
|||
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;
|
||||
_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;
|
||||
Machine *m = userdata;
|
||||
bool copy_from;
|
||||
|
|
|
@ -847,13 +847,16 @@ int config_parse_macsec_key_id(
|
|||
return log_oom();
|
||||
|
||||
r = unhexmem(rvalue, strlen(rvalue), &p, &l);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
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;
|
||||
}
|
||||
if (l > MACSEC_KEYID_LEN) {
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -220,8 +220,8 @@ WireGuard.PrivateKey, config_parse_wireguard_private_key,
|
|||
WireGuard.PrivateKeyFile, config_parse_wireguard_private_key_file, 0, 0
|
||||
WireGuardPeer.AllowedIPs, config_parse_wireguard_allowed_ips, 0, 0
|
||||
WireGuardPeer.Endpoint, config_parse_wireguard_endpoint, 0, 0
|
||||
WireGuardPeer.PublicKey, config_parse_wireguard_public_key, 0, 0
|
||||
WireGuardPeer.PresharedKey, config_parse_wireguard_preshared_key, 0, 0
|
||||
WireGuardPeer.PublicKey, config_parse_wireguard_peer_key, 0, 0
|
||||
WireGuardPeer.PresharedKey, config_parse_wireguard_peer_key, 0, 0
|
||||
WireGuardPeer.PresharedKeyFile, config_parse_wireguard_preshared_key_file, 0, 0
|
||||
WireGuardPeer.PersistentKeepalive, config_parse_wireguard_keepalive, 0, 0
|
||||
Xfrm.InterfaceId, config_parse_uint32, 0, offsetof(Xfrm, if_id)
|
||||
|
|
|
@ -492,6 +492,8 @@ static int wireguard_decode_key_and_warn(
|
|||
(void) warn_file_is_world_accessible(filename, NULL, unit, line);
|
||||
|
||||
r = unbase64mem_full(rvalue, strlen(rvalue), true, &key, &len);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"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);
|
||||
assert(w);
|
||||
|
||||
(void) wireguard_decode_key_and_warn(rvalue, w->private_key, unit, filename, line, lvalue);
|
||||
return 0;
|
||||
return wireguard_decode_key_and_warn(rvalue, w->private_key, unit, filename, line, lvalue);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int config_parse_wireguard_preshared_key(
|
||||
int config_parse_wireguard_peer_key(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
@ -576,7 +577,7 @@ int config_parse_wireguard_preshared_key(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
WireguardPeer *peer;
|
||||
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
|
||||
Wireguard *w;
|
||||
int r;
|
||||
|
||||
|
@ -588,7 +589,13 @@ int config_parse_wireguard_preshared_key(
|
|||
if (r < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -635,38 +642,6 @@ int config_parse_wireguard_preshared_key_file(
|
|||
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(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
@ -821,7 +796,7 @@ int config_parse_wireguard_keepalive(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
WireguardPeer *peer;
|
||||
_cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
|
||||
uint16_t keepalive = 0;
|
||||
Wireguard *w;
|
||||
int r;
|
||||
|
@ -849,6 +824,8 @@ int config_parse_wireguard_keepalive(
|
|||
}
|
||||
|
||||
peer->persistent_keepalive_interval = keepalive;
|
||||
|
||||
TAKE_PTR(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,10 +61,8 @@ extern const NetDevVTable wireguard_vtable;
|
|||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_allowed_ips);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_endpoint);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_listen_port);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_public_key);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_peer_key);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key);
|
||||
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_keepalive);
|
||||
|
|
|
@ -691,7 +691,7 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
switch (type) {
|
||||
case RTM_NEWNEIGH:
|
||||
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));
|
||||
else {
|
||||
/* 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");
|
||||
}
|
||||
|
||||
if (tmp->from_prefixlen == 0 && tmp->to_prefixlen == 0)
|
||||
return 0;
|
||||
|
||||
r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags);
|
||||
if (r < 0) {
|
||||
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) {
|
||||
case RTM_NEWRULE:
|
||||
if (!rule) {
|
||||
log_debug("Remembering foreign routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
|
||||
from, tmp->from_prefixlen, to, tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
|
||||
if (rule)
|
||||
log_debug("Received remembered 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);
|
||||
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);
|
||||
if (r < 0) {
|
||||
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;
|
||||
case RTM_DELRULE:
|
||||
log_debug("Forgetting routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
|
||||
from, tmp->from_prefixlen, to, tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table);
|
||||
if (rule) {
|
||||
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);
|
||||
|
||||
} 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;
|
||||
|
||||
default:
|
||||
|
@ -1298,19 +1301,24 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
|
||||
switch (type) {
|
||||
case RTM_NEWNEXTHOP:
|
||||
if (!nexthop) {
|
||||
log_debug("Remembering foreign nexthop: %s, oif: %d, id: %d", gateway, tmp->oif, tmp->id);
|
||||
if (nexthop)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
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);
|
||||
|
||||
} 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;
|
||||
|
||||
default:
|
||||
|
|
|
@ -39,7 +39,7 @@ Match.Type, config_parse_match_strv,
|
|||
Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match_wlan_iftype)
|
||||
Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid)
|
||||
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.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions)
|
||||
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions)
|
||||
|
|
|
@ -333,37 +333,48 @@ static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_messa
|
|||
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;
|
||||
int r;
|
||||
|
||||
assert(routing_policy_rule);
|
||||
assert(rule);
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
assert(link->manager->rtnl);
|
||||
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)
|
||||
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) {
|
||||
r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
|
||||
if (in_addr_is_null(rule->family, &rule->from) == 0) {
|
||||
r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
|
||||
if (r < 0)
|
||||
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)
|
||||
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) {
|
||||
r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
|
||||
if (in_addr_is_null(rule->family, &rule->to) == 0) {
|
||||
r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
|
||||
if (r < 0)
|
||||
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)
|
||||
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);
|
||||
|
||||
log_link_debug(link,
|
||||
"Configuring routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
|
||||
from, rule->from_prefixlen, to, rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
|
||||
"Configuring 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_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);
|
||||
if (r < 0)
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m");
|
||||
}
|
||||
|
||||
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)
|
||||
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) {
|
||||
|
@ -644,31 +653,39 @@ int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
|
||||
_cleanup_free_ char *f = NULL;
|
||||
char *p;
|
||||
static int parse_fwmark_fwmask(const char *s, uint32_t *ret_fwmark, uint32_t *ret_fwmask) {
|
||||
_cleanup_free_ char *fwmark_str = NULL;
|
||||
uint32_t fwmark, fwmask = 0;
|
||||
const char *slash;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(ret_fwmark);
|
||||
assert(ret_fwmask);
|
||||
|
||||
f = strdup(s);
|
||||
if (!f)
|
||||
slash = strchr(s, '/');
|
||||
if (slash) {
|
||||
fwmark_str = strndup(s, slash - s);
|
||||
if (!fwmark_str)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1223,9 +1240,11 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
|
|||
}
|
||||
|
||||
if (rule->fwmark != 0) {
|
||||
fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
|
||||
fprintf(f, "%sfwmark=%"PRIu32,
|
||||
space ? " " : "",
|
||||
rule->fwmark, rule->fwmask);
|
||||
rule->fwmark);
|
||||
if (rule->fwmask != UINT32_MAX)
|
||||
fprintf(f, "/%"PRIu32, rule->fwmask);
|
||||
space = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,8 +62,8 @@ void routing_policy_rule_free(RoutingPolicyRule *rule);
|
|||
DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
|
||||
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_remove(RoutingPolicyRule *routing_policy_rule, 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 *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_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret);
|
||||
|
|
|
@ -67,7 +67,7 @@ int main(int argc, char **argv) {
|
|||
test_rule_serialization("ignored values",
|
||||
"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",
|
||||
"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",
|
||||
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=yes table=6", NULL);
|
||||
|
|
|
@ -233,14 +233,10 @@ int config_parse_expose_port(
|
|||
assert(rvalue);
|
||||
|
||||
r = expose_port_parse(&s->expose_ports, rvalue);
|
||||
if (r == -EEXIST) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Duplicate port specification, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse host port %s: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == -EEXIST)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Duplicate port specification, ignoring: %s", rvalue);
|
||||
else if (r < 0)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse host port %s: %m", rvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -268,8 +264,10 @@ int config_parse_capability(
|
|||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = extract_first_word(&rvalue, &word, NULL, 0);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
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;
|
||||
}
|
||||
if (r == 0)
|
||||
|
@ -280,7 +278,7 @@ int config_parse_capability(
|
|||
else {
|
||||
r = capability_from_name(word);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -315,10 +313,8 @@ int config_parse_pivot_root(
|
|||
assert(rvalue);
|
||||
|
||||
r = pivot_root_parse(&settings->pivot_root_new, &settings->pivot_root_old, rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid pivot root mount specification %s: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid pivot root mount specification %s: %m", rvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -343,10 +339,8 @@ int config_parse_bind(
|
|||
assert(rvalue);
|
||||
|
||||
r = bind_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bind mount specification %s: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid bind mount specification %s: %m", rvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -371,10 +365,8 @@ int config_parse_tmpfs(
|
|||
assert(rvalue);
|
||||
|
||||
r = tmpfs_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid temporary file system specification %s: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid temporary file system specification %s: %m", rvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -399,10 +391,8 @@ int config_parse_inaccessible(
|
|||
assert(rvalue);
|
||||
|
||||
r = inaccessible_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -428,7 +418,7 @@ int config_parse_overlay(
|
|||
|
||||
r = overlay_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue, ltype);
|
||||
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;
|
||||
}
|
||||
|
@ -453,10 +443,8 @@ int config_parse_veth_extra(
|
|||
assert(rvalue);
|
||||
|
||||
r = veth_extra_parse(&settings->network_veth_extra, rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -482,13 +470,11 @@ int config_parse_network_zone(
|
|||
|
||||
j = strjoin("vz-", rvalue);
|
||||
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;
|
||||
}
|
||||
|
||||
free_and_replace(settings->network_zone, j);
|
||||
|
||||
return 0;
|
||||
return free_and_replace(settings->network_zone, j);
|
||||
}
|
||||
|
||||
int config_parse_boot(
|
||||
|
@ -512,11 +498,11 @@ int config_parse_boot(
|
|||
|
||||
r = parse_boolean(rvalue);
|
||||
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;
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
if (r) {
|
||||
if (settings->start_mode == START_PID2)
|
||||
goto conflict;
|
||||
|
||||
|
@ -532,7 +518,7 @@ int config_parse_boot(
|
|||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -557,11 +543,11 @@ int config_parse_pid2(
|
|||
|
||||
r = parse_boolean(rvalue);
|
||||
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;
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
if (r) {
|
||||
if (settings->start_mode == START_BOOT)
|
||||
goto conflict;
|
||||
|
||||
|
@ -577,7 +563,7 @@ int config_parse_pid2(
|
|||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -629,7 +615,7 @@ int config_parse_private_users(
|
|||
|
||||
r = safe_atou32(range, &rn);
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
|
@ -639,7 +625,7 @@ int config_parse_private_users(
|
|||
|
||||
r = parse_uid(shift, &sh);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -680,11 +666,12 @@ int config_parse_syscall_filter(
|
|||
|
||||
r = extract_first_word(&items, &word, NULL, 0);
|
||||
if (r == 0)
|
||||
break;
|
||||
return 0;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -695,8 +682,6 @@ int config_parse_syscall_filter(
|
|||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_hostname(
|
||||
|
@ -717,7 +702,7 @@ int config_parse_hostname(
|
|||
assert(s);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -752,11 +737,11 @@ int config_parse_oom_score_adjust(
|
|||
|
||||
r = parse_oom_score_adjust(rvalue, &oa);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -863,10 +848,8 @@ int config_parse_link_journal(
|
|||
assert(settings);
|
||||
|
||||
r = parse_link_journal(rvalue, &settings->link_journal, &settings->link_journal_try);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse link journal mode, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse link journal mode, ignoring: %s", rvalue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -947,7 +947,7 @@ static int config_parse_label(
|
|||
|
||||
r = specifier_printf(rvalue, specifier_table, NULL, &resolved);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2609,9 +2609,17 @@ static int do_copy_files(Partition *p, const char *fs) {
|
|||
if (pfd < 0)
|
||||
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
|
||||
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)
|
||||
return log_error_errno(r, "Failed to copy %s%s to %s: %m", strempty(arg_root), *source, *target);
|
||||
} else {
|
||||
|
|
|
@ -1754,7 +1754,6 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
|
|||
_cleanup_(dnssd_service_freep) DnssdService *service = NULL;
|
||||
_cleanup_(sd_bus_track_unrefp) sd_bus_track *bus_track = NULL;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
_cleanup_free_ char *instance_name = NULL;
|
||||
Manager *m = userdata;
|
||||
DnssdService *s = NULL;
|
||||
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))
|
||||
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);
|
||||
if (!service->name)
|
||||
return log_oom();
|
||||
|
@ -1807,10 +1810,6 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
|
|||
if (!service->type)
|
||||
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}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
@ -35,9 +35,6 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (IN_SET(port, 53, 853))
|
||||
port = 0;
|
||||
|
||||
/* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */
|
||||
if (!dns_server_address_valid(family, &address))
|
||||
return 0;
|
||||
|
@ -50,12 +47,8 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
|
|||
/* Filter out duplicates */
|
||||
s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
|
||||
if (s) {
|
||||
/*
|
||||
* Drop the marker. This is used to find the servers
|
||||
* that ceased to exist, see
|
||||
* manager_mark_dns_servers() and
|
||||
* manager_flush_marked_dns_servers().
|
||||
*/
|
||||
/* Drop the marker. This is used to find the servers that ceased to exist, see
|
||||
* manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */
|
||||
dns_server_move_back_and_unmark(s);
|
||||
return 0;
|
||||
}
|
||||
|
@ -168,7 +161,8 @@ int config_parse_dns_servers(
|
|||
/* Otherwise, add to the list */
|
||||
r = manager_parse_dns_server_string_and_warn(m, ltype, rvalue);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -210,7 +204,8 @@ int config_parse_search_domains(
|
|||
/* Otherwise, add to the list */
|
||||
r = manager_parse_search_domains_and_warn(m, rvalue);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -222,21 +217,19 @@ int config_parse_search_domains(
|
|||
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) {
|
||||
static const Specifier specifier_table[] = {
|
||||
{ 'm', specifier_machine_id, NULL },
|
||||
{ 'b', specifier_boot_id, NULL },
|
||||
{ 'H', specifier_host_name, NULL },
|
||||
{ 'v', specifier_kernel_release, NULL },
|
||||
{ 'a', specifier_architecture, NULL },
|
||||
{ 'o', specifier_os_id, NULL },
|
||||
{ 'w', specifier_os_version_id, NULL },
|
||||
{ 'B', specifier_os_build_id, NULL },
|
||||
{ 'W', specifier_os_variant_id, NULL },
|
||||
{}
|
||||
};
|
||||
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) {
|
||||
|
||||
DnssdService *s = userdata;
|
||||
_cleanup_free_ char *name = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -245,27 +238,38 @@ int config_parse_dnssd_service_name(const char *unit, const char *filename, unsi
|
|||
assert(s);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Service instance name can't be empty. Ignoring.");
|
||||
return -EINVAL;
|
||||
s->name_template = mfree(s->name_template);
|
||||
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);
|
||||
if (r < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
int r;
|
||||
|
||||
|
@ -275,13 +279,13 @@ int config_parse_dnssd_service_type(const char *unit, const char *filename, unsi
|
|||
assert(s);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Service type can't be empty. Ignoring.");
|
||||
return -EINVAL;
|
||||
s->type = mfree(s->type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dnssd_srv_type_is_valid(rvalue)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Service type is invalid. Ignoring.");
|
||||
return -EINVAL;
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Service type is invalid. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
DnssdService *s = userdata;
|
||||
DnsTxtItem *last = NULL;
|
||||
|
@ -312,9 +327,7 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
|
|||
return log_oom();
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
_cleanup_free_ char *key = NULL;
|
||||
_cleanup_free_ char *value = NULL;
|
||||
_cleanup_free_ char *word = NULL, *key = NULL, *value = NULL;
|
||||
_cleanup_free_ void *decoded = NULL;
|
||||
size_t length = 0;
|
||||
DnsTxtItem *i;
|
||||
|
@ -326,8 +339,10 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
|
|||
break;
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = split_pair(word, "=", &key, &value);
|
||||
if (r == -ENOMEM)
|
||||
|
@ -336,8 +351,8 @@ int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line
|
|||
key = TAKE_PTR(word);
|
||||
|
||||
if (!ascii_is_valid(key)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring: %s", key);
|
||||
return -EINVAL;
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid key, ignoring: %s", key);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Invalid base64 encoding, ignoring: %s", value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
LIST_PREPEND(items, s->txt_data_items, txt_data);
|
||||
txt_data = NULL;
|
||||
TAKE_PTR(txt_data);
|
||||
}
|
||||
|
||||
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) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse address in %s=%s, ignoring assignment: %m",
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* IP and UDP header sizes */
|
||||
#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) {
|
||||
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
|
||||
* thus pick 127.0.0.1 rather than 127.0.0.53. */
|
||||
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 */
|
||||
p->family, &p->sender, p->sender_port, &p->destination,
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
_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);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.in.sin_family = AF_INET,
|
||||
.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;
|
||||
int r;
|
||||
|
||||
if (m->dns_stub_tcp_event_source)
|
||||
return sd_event_source_get_io_fd(m->dns_stub_tcp_event_source);
|
||||
assert(IN_SET(type, SOCK_DGRAM, SOCK_STREAM));
|
||||
|
||||
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)
|
||||
return -errno;
|
||||
|
||||
|
@ -698,42 +587,53 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
|
|||
if (r < 0)
|
||||
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 */
|
||||
r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
|
||||
if (r < 0)
|
||||
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)
|
||||
return -errno;
|
||||
|
||||
if (listen(fd, SOMAXCONN) < 0)
|
||||
if (type == SOCK_STREAM &&
|
||||
listen(fd, SOMAXCONN) < 0)
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
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_close_ int fd = -1;
|
||||
union sockaddr_union sa;
|
||||
int r;
|
||||
|
||||
if (l->tcp_event_source)
|
||||
return sd_event_source_get_io_fd(l->tcp_event_source);;
|
||||
assert(m);
|
||||
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)
|
||||
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,
|
||||
};
|
||||
|
||||
fd = socket(l->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||
fd = socket(l->family, type | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
|
@ -758,8 +658,8 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
|
|||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
/* Do not set IP_TTL for extra DNS stub listners, as the address may not be local and in that
|
||||
* case people may want ttl > 1. */
|
||||
/* Do not set IP_TTL for extra DNS stub listners, as the address may not be local and in that case
|
||||
* people may want ttl > 1. */
|
||||
|
||||
if (l->family == AF_INET)
|
||||
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;
|
||||
}
|
||||
|
||||
if (listen(fd, SOMAXCONN) < 0) {
|
||||
if (type == SOCK_STREAM &&
|
||||
listen(fd, SOMAXCONN) < 0) {
|
||||
r = -errno;
|
||||
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)
|
||||
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)
|
||||
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) {
|
||||
(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);
|
||||
|
@ -798,9 +704,11 @@ static int manager_dns_stub_tcp_fd_extra(Manager *m, DnsStubListenerExtra *l) {
|
|||
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 TCP socket %s: %m", strnull(pretty));
|
||||
return log_warning_errno(r, "Failed to listen on TCP socket %s: %m", strnull(pretty));
|
||||
return log_warning_errno(r,
|
||||
r == -EADDRINUSE ? "Another process is already listening on %s socket %s: %m" :
|
||||
"Failed to listen on %s socket %s: %m",
|
||||
type == SOCK_DGRAM ? "UDP" : "TCP",
|
||||
strnull(pretty));
|
||||
}
|
||||
|
||||
int manager_dns_stub_start(Manager *m) {
|
||||
|
@ -818,23 +726,21 @@ int manager_dns_stub_start(Manager *m) {
|
|||
"UDP/TCP");
|
||||
|
||||
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 &&
|
||||
FLAGS_SET(m->dns_stub_listener_mode, DNS_STUB_LISTENER_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 (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,
|
||||
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"
|
||||
"Turning off local DNS stub support.", t);
|
||||
"Turning off local DNS stub support.",
|
||||
t);
|
||||
manager_dns_stub_stop(m);
|
||||
} else if (r < 0)
|
||||
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) {
|
||||
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))
|
||||
(void) manager_dns_stub_tcp_fd_extra(m, l);
|
||||
(void) manager_dns_stub_fd_extra(m, l, SOCK_STREAM);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ static int specifier_dnssd_host_name(char specifier, const void *data, const voi
|
|||
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[] = {
|
||||
{ 'm', specifier_machine_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;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(s->name_template);
|
||||
assert(name_template);
|
||||
|
||||
r = specifier_printf(s->name_template, specifier_table, s, &name);
|
||||
r = specifier_printf(name_template, specifier_table, NULL, &name);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to replace specifiers: %m");
|
||||
return r;
|
||||
|
||||
if (!dns_service_name_is_valid(name))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Service instance name '%s' is invalid.",
|
||||
name);
|
||||
return -EINVAL;
|
||||
|
||||
if (ret_name)
|
||||
*ret_name = TAKE_PTR(name);
|
||||
|
||||
return 0;
|
||||
|
@ -227,7 +225,7 @@ int dnssd_update_rrs(DnssdService *s) {
|
|||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
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)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data);
|
|||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdService*, dnssd_service_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_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);
|
||||
|
|
|
@ -183,14 +183,12 @@ static int parse_line(
|
|||
k = strlen(l);
|
||||
assert(k > 0);
|
||||
|
||||
if (l[k-1] != ']') {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
|
||||
return -EBADMSG;
|
||||
}
|
||||
if (l[k-1] != ']')
|
||||
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EBADMSG), "Invalid section header '%s'", l);
|
||||
|
||||
n = strndup(l+1, k-2);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
return log_oom();
|
||||
|
||||
if (sections && !nulstr_contains(sections, n)) {
|
||||
bool ignore = flags & CONFIG_PARSE_RELAXED;
|
||||
|
|
|
@ -938,12 +938,13 @@ int config_parse_channel(const char *unit,
|
|||
|
||||
r = safe_atou32(rvalue, &k);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -998,24 +999,24 @@ int config_parse_advertise(const char *unit,
|
|||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split advertise modes '%s', ignoring: %m", rvalue);
|
||||
break;
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to split advertise modes '%s', ignoring assignment: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
return 0;
|
||||
|
||||
mode = ethtool_link_mode_bit_from_string(w);
|
||||
/* 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. */
|
||||
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;
|
||||
}
|
||||
|
||||
advertise[mode / 32] |= 1UL << (mode % 32);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -62,75 +62,23 @@ int socket_address_parse(SocketAddress *a, const char *s) {
|
|||
assert(a);
|
||||
assert(s);
|
||||
|
||||
*a = (SocketAddress) {
|
||||
.type = SOCK_STREAM,
|
||||
};
|
||||
if (IN_SET(*s, '/', '@')) {
|
||||
/* AF_UNIX socket */
|
||||
struct sockaddr_un un;
|
||||
|
||||
if (*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);
|
||||
r = sockaddr_un_set_path(&un, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
||||
a->sockaddr.in6.sin6_port = htobe16(port);
|
||||
a->size = sizeof(struct sockaddr_in6);
|
||||
|
||||
} 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;
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.un = un,
|
||||
.size = r,
|
||||
};
|
||||
|
||||
} else if (startswith(s, "vsock:")) {
|
||||
/* AF_VSOCK socket in vsock:cid:port notation */
|
||||
const char *cid_start = s + STRLEN("vsock:");
|
||||
unsigned port;
|
||||
unsigned port, cid;
|
||||
|
||||
e = strchr(cid_start, ':');
|
||||
if (!e)
|
||||
|
@ -144,72 +92,82 @@ int socket_address_parse(SocketAddress *a, const char *s) {
|
|||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!isempty(n)) {
|
||||
r = safe_atou(n, &a->sockaddr.vm.svm_cid);
|
||||
if (isempty(n))
|
||||
cid = VMADDR_CID_ANY;
|
||||
else {
|
||||
r = safe_atou(n, &cid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
a->sockaddr.vm.svm_cid = VMADDR_CID_ANY;
|
||||
}
|
||||
|
||||
a->sockaddr.vm.svm_family = AF_VSOCK;
|
||||
a->sockaddr.vm.svm_port = port;
|
||||
a->size = sizeof(struct sockaddr_vm);
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.vm = {
|
||||
.svm_cid = cid,
|
||||
.svm_family = AF_VSOCK,
|
||||
.svm_port = port,
|
||||
},
|
||||
.size = sizeof(struct sockaddr_vm),
|
||||
};
|
||||
|
||||
} else {
|
||||
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);
|
||||
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)
|
||||
return r;
|
||||
|
||||
if (socket_ipv6_is_supported()) {
|
||||
a->sockaddr.in6.sin6_family = AF_INET6;
|
||||
a->sockaddr.in6.sin6_port = htobe16(port);
|
||||
a->sockaddr.in6.sin6_addr = in6addr_any;
|
||||
a->size = sizeof(struct sockaddr_in6);
|
||||
} else {
|
||||
a->sockaddr.in.sin_family = AF_INET;
|
||||
a->sockaddr.in.sin_port = htobe16(port);
|
||||
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
a->size = sizeof(struct sockaddr_in);
|
||||
}
|
||||
if (port == 0) /* No port, no go. */
|
||||
return -EINVAL;
|
||||
|
||||
if (family == AF_INET)
|
||||
*a = (SocketAddress) {
|
||||
.sockaddr.in = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr = address.in,
|
||||
.sin_port = htobe16(port),
|
||||
},
|
||||
.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(s);
|
||||
|
||||
*a = (SocketAddress) {
|
||||
.type = SOCK_RAW,
|
||||
};
|
||||
|
||||
r = extract_first_word(&s, &word, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -263,12 +217,13 @@ int socket_address_parse_netlink(SocketAddress *a, const char *s) {
|
|||
return r;
|
||||
}
|
||||
|
||||
a->sockaddr.nl.nl_family = AF_NETLINK;
|
||||
a->sockaddr.nl.nl_groups = group;
|
||||
|
||||
a->type = SOCK_RAW;
|
||||
a->size = sizeof(struct sockaddr_nl);
|
||||
a->protocol = family;
|
||||
*a = (SocketAddress) {
|
||||
.type = SOCK_RAW,
|
||||
.sockaddr.nl.nl_family = AF_NETLINK,
|
||||
.sockaddr.nl.nl_groups = group,
|
||||
.protocol = family,
|
||||
.size = sizeof(struct sockaddr_nl),
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -345,10 +300,14 @@ int in_addr_port_ifindex_name_from_string_auto(
|
|||
|
||||
/* This accepts the following:
|
||||
* 192.168.0.1:53#example.com
|
||||
* [2001:4860:4860::8888]:53%eth0#example.com */
|
||||
|
||||
/* if ret_port is NULL, then strings with port cannot be specified.
|
||||
* Also, if ret_server_name is NULL, then server_name cannot be specified. */
|
||||
* [2001:4860:4860::8888]:53%eth0#example.com
|
||||
*
|
||||
* If ret_port is NULL, then the port 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, '#');
|
||||
if (m) {
|
||||
|
@ -369,15 +328,19 @@ int in_addr_port_ifindex_name_from_string_auto(
|
|||
|
||||
m = strchr(s, '%');
|
||||
if (m) {
|
||||
if (!ret_ifindex)
|
||||
return -EINVAL;
|
||||
|
||||
if (isempty(m + 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (ret_ifindex) {
|
||||
/* If we shall return the interface index, try to parse it */
|
||||
if (!ifname_valid_full(m + 1, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
|
||||
return -EINVAL; /* We want to return -EINVAL for syntactically invalid names,
|
||||
* and -ENODEV for valid but nonexistent interfaces. */
|
||||
|
||||
ifindex = resolve_interface(NULL, m + 1);
|
||||
if (ifindex < 0)
|
||||
return ifindex;
|
||||
}
|
||||
|
||||
s = buf2 = strndup(s, m - s);
|
||||
if (!buf2)
|
||||
|
@ -455,36 +418,6 @@ int in_addr_port_ifindex_name_from_string_auto(
|
|||
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) {
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
|
|
@ -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) {
|
||||
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 {
|
||||
int family;
|
||||
|
|
|
@ -86,11 +86,13 @@ int config_parse_vlanid(
|
|||
|
||||
r = parse_vlanid(rvalue, id);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,10 +81,12 @@ static void test_copy_tree(void) {
|
|||
char original_dir[] = "/tmp/test-copy_tree/";
|
||||
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 **links = STRV_MAKE("link", "file",
|
||||
char **symlinks = STRV_MAKE("link", "file",
|
||||
"link2", "dir1/file");
|
||||
char **hardlinks = STRV_MAKE("hlink", "file",
|
||||
"hlink2", "dir1/file");
|
||||
const char *unixsockp;
|
||||
char **p, **link;
|
||||
char **p, **ll;
|
||||
struct stat st;
|
||||
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 */
|
||||
|
@ -110,20 +112,30 @@ static void test_copy_tree(void) {
|
|||
xattr_worked = k >= 0;
|
||||
}
|
||||
|
||||
STRV_FOREACH_PAIR(link, p, links) {
|
||||
STRV_FOREACH_PAIR(ll, p, symlinks) {
|
||||
_cleanup_free_ char *f, *l;
|
||||
|
||||
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(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");
|
||||
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) {
|
||||
_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;
|
||||
|
||||
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(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");
|
||||
assert_se(stat(unixsockp, &st) >= 0);
|
||||
assert_se(S_ISSOCK(st.st_mode));
|
||||
|
|
|
@ -58,6 +58,8 @@ static void test_in_addr_prefix_from_string_one(
|
|||
}
|
||||
|
||||
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("/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;
|
||||
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_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;
|
||||
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_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) {
|
||||
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, "1.2.3.4/0");
|
||||
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;
|
||||
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_random_prefix(AF_INET, &a, 31, 32) >= 0);
|
||||
|
|
|
@ -12,11 +12,20 @@ static void test_socket_address_parse_one(const char *in, int ret, int family, c
|
|||
int r;
|
||||
|
||||
r = socket_address_parse(&a, in);
|
||||
if (r >= 0)
|
||||
assert_se(socket_address_print(&a, &out) >= 0);
|
||||
if (r >= 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,
|
||||
r >= 0 ? "✓" : "✗", empty_to_dash(out), r >= 0 ? expected ?: in : "-");
|
||||
log_info("\"%s\" → %s %d → \"%s\" (expect %d / \"%s\")",
|
||||
in,
|
||||
r >= 0 ? "✓" : "✗", r,
|
||||
empty_to_dash(out),
|
||||
ret,
|
||||
ret >= 0 ? expected ?: in : "-");
|
||||
assert_se(r == ret);
|
||||
if (r >= 0) {
|
||||
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]:65536", -ERANGE, 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("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6,
|
||||
"[2001:db8:0:85a3::ac1f:8001]:8888");
|
||||
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("/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);
|
||||
|
||||
{
|
||||
|
@ -198,9 +217,13 @@ static void test_socket_address_is(void) {
|
|||
log_info("/* %s */", __func__);
|
||||
|
||||
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, "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) {
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
static void test_in_addr_port_ifindex_name_from_string_auto_one(const char *str, int family, uint16_t port, int ifindex, const char *server_name) {
|
||||
_cleanup_free_ char *name = NULL, *x = NULL;
|
||||
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, const char *str_repr) {
|
||||
union in_addr_union a;
|
||||
uint16_t p;
|
||||
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(port == p);
|
||||
assert_se(ifindex == i);
|
||||
assert_se(streq_ptr(server_name, name));
|
||||
assert_se(in_addr_port_ifindex_name_to_string(f, &a, p, i, name, &x) >= 0);
|
||||
assert_se(streq(str, x));
|
||||
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) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1", AF_INET, 0, 0, NULL);
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1#test.com", AF_INET, 0, 0, "test.com");
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53", AF_INET, 53, 0, NULL);
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("192.168.0.1:53#example.com", AF_INET, 53, 0, "example.com");
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18", AF_INET6, 0, 0, NULL);
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18#hoge.com", AF_INET6, 0, 0, "hoge.com");
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19", AF_INET6, 0, 19, NULL);
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53", AF_INET6, 53, 0, NULL);
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("fe80::18%19#hoge.com", AF_INET6, 0, 19, "hoge.com");
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53#hoge.com", AF_INET6, 53, 0, "hoge.com");
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19", AF_INET6, 53, 19, NULL);
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com");
|
||||
}
|
||||
|
||||
static void test_in_addr_port_from_string_auto_one(const char *str, int family, const char *address_string, uint16_t port) {
|
||||
union in_addr_union a, b;
|
||||
uint16_t p;
|
||||
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);
|
||||
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", 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", 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", 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%lo", AF_INET6, 0, 1, NULL, "fe80::18%1");
|
||||
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%19", AF_INET6, 53, 19, NULL, 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%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);
|
||||
test_in_addr_port_ifindex_name_from_string_auto_one("[fe80::18]:53%19#hoge.com", AF_INET6, 53, 19, "hoge.com", 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%lo#hoge.com", AF_INET6, 53, 1, "hoge.com", "[fe80::18]:53%1#hoge.com");
|
||||
}
|
||||
|
||||
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_name_from_string_auto();
|
||||
test_in_addr_port_ifindex_name_from_string_auto();
|
||||
test_in_addr_port_from_string_auto();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -44,9 +44,13 @@ static void test_ifname_valid(void) {
|
|||
assert(ifname_valid("foo.bar"));
|
||||
assert(!ifname_valid("x:y"));
|
||||
|
||||
assert(ifname_valid("xxxxxxxxxxxxxxx"));
|
||||
assert(!ifname_valid("xxxxxxxxxxxxxxxx"));
|
||||
assert(ifname_valid_full("xxxxxxxxxxxxxxxx", true));
|
||||
assert( ifname_valid_full("xxxxxxxxxxxxxxx", 0));
|
||||
assert(!ifname_valid_full("xxxxxxxxxxxxxxxx", 0));
|
||||
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) {
|
||||
|
@ -504,17 +508,11 @@ int main(int argc, char *argv[]) {
|
|||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
test_ifname_valid();
|
||||
|
||||
test_socket_print_unix();
|
||||
|
||||
test_sockaddr_equal();
|
||||
|
||||
test_sockaddr_un_len();
|
||||
|
||||
test_in_addr_is_multicast();
|
||||
|
||||
test_getpeercred_getpeergroups();
|
||||
|
||||
test_passfd_read();
|
||||
test_passfd_contents_read();
|
||||
test_receive_nopassfd();
|
||||
|
|
|
@ -89,7 +89,8 @@ int config_parse_servers(
|
|||
else {
|
||||
r = manager_parse_server_string(m, ltype, rvalue);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1543,7 +1543,7 @@ static int copy_files(Item *i) {
|
|||
dfd, bn,
|
||||
i->uid_set ? i->uid : UID_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) {
|
||||
struct stat a, b;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
|
|||
#include "ethtool-util.h"
|
||||
#include "link-config.h"
|
||||
#include "network-internal.h"
|
||||
#include "socket-util.h"
|
||||
%}
|
||||
struct ConfigPerfItem;
|
||||
%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.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
|
||||
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.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
|
||||
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu)
|
||||
|
|
|
@ -118,8 +118,7 @@ int udev_builtin_run(sd_device *dev, UdevBuiltinCommand cmd, const char *command
|
|||
if (!builtins[cmd])
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = strv_split_full(&argv, command, NULL,
|
||||
EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_RETAIN_ESCAPE);
|
||||
r = strv_split_full(&argv, command, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_RETAIN_ESCAPE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ static int xdg_config_parse_string(
|
|||
|
||||
/* XDG does not allow duplicate definitions. */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ static int xdg_config_parse_strv(
|
|||
|
||||
/* XDG does not allow duplicate definitions. */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -256,7 +256,7 @@ static int xdg_config_parse_strv(
|
|||
/* Move forward, and ensure it is a valid escape. */
|
||||
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;
|
||||
}
|
||||
continue;
|
||||
|
|
|
@ -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
|
|
@ -1735,9 +1735,11 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
|||
'25-vrf.network',
|
||||
'26-link-local-addressing-ipv6.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']]
|
||||
|
||||
def setUp(self):
|
||||
|
@ -1970,32 +1972,6 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
|
|||
self.assertRegex(output, 'iif test1')
|
||||
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):
|
||||
copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-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)
|
||||
|
||||
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()
|
||||
def test_routing_policy_rule_port_range(self):
|
||||
copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
|
||||
|
|
Loading…
Reference in New Issue