mirror of
https://github.com/systemd/systemd
synced 2026-04-17 12:34:51 +02:00
Compare commits
36 Commits
e5b90b30c2
...
b0f83c2d82
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0f83c2d82 | ||
|
|
a8dfcd2c0f | ||
|
|
04660b10d3 | ||
|
|
a46abf2e34 | ||
|
|
6796c5a9c4 | ||
|
|
7b5445e74e | ||
|
|
99e65b7df3 | ||
|
|
4f3cb2465a | ||
|
|
4e2319afe4 | ||
|
|
7e0a8bf1ce | ||
|
|
8b572f7ab2 | ||
|
|
bd1a3eb65b | ||
|
|
7e98fe05a0 | ||
|
|
e2ba408084 | ||
|
|
5cc8be890d | ||
|
|
eb5bff9c9d | ||
|
|
8a7d048d1d | ||
|
|
37e219800f | ||
|
|
48be485b71 | ||
|
|
6277e48fa9 | ||
|
|
a2a801926d | ||
|
|
0a195d4186 | ||
|
|
fb96111946 | ||
|
|
bb193d2df2 | ||
|
|
3cf58ef316 | ||
|
|
b69bfa4305 | ||
|
|
259c65f36c | ||
|
|
a0e99a377a | ||
|
|
9d67fb0e33 | ||
|
|
e3d1ffcc48 | ||
|
|
69339ae9f7 | ||
|
|
29f604131b | ||
|
|
367165a406 | ||
|
|
680cec6b4d | ||
|
|
a520d5dddb | ||
|
|
5c1b257faf |
@ -171,11 +171,19 @@
|
|||||||
<para><varname>KERNEL_INSTALL_BOOT_ROOT=</varname> is set for the plugins to the root directory (mount point, usually) of the hierarchy
|
<para><varname>KERNEL_INSTALL_BOOT_ROOT=</varname> is set for the plugins to the root directory (mount point, usually) of the hierarchy
|
||||||
where boot-loader entries, kernel images, and associated resources should be placed. Can be overridden by setting <varname>BOOT_ROOT=</varname>.</para>
|
where boot-loader entries, kernel images, and associated resources should be placed. Can be overridden by setting <varname>BOOT_ROOT=</varname>.</para>
|
||||||
|
|
||||||
<para><varname>KERNEL_INSTALL_LAYOUT=bls|other|...</varname> specifies the installation layout.
|
<para><varname>KERNEL_INSTALL_LAYOUT=bls|other|...</varname> is set for the plugins to specify the installation layout.
|
||||||
Defaults to <option>bls</option> if <filename>$BOOT/<replaceable>MACHINE-ID</replaceable></filename> exists, or <option>other</option> otherwise.
|
Defaults to <option>bls</option> if <filename>$BOOT/<replaceable>MACHINE-ID</replaceable></filename> exists, or <option>other</option> otherwise.
|
||||||
Additional layout names may be defined by convention. If a plugin uses a special layout,
|
Additional layout names may be defined by convention. If a plugin uses a special layout,
|
||||||
it's encouraged to declare its own layout name and configure <varname>layout=</varname> in <filename>install.conf</filename> upon initial installation.</para>
|
it's encouraged to declare its own layout name and configure <varname>layout=</varname> in <filename>install.conf</filename> upon initial installation.</para>
|
||||||
|
|
||||||
|
<para><varname>KERNEL_INSTALL_INITRD_GENERATOR=...</varname> is set for plugins to select the initrd generator.
|
||||||
|
This should be configured as <varname>initrd_generator=</varname> in <filename>install.conf</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para><varname>KERNEL_INSTALL_STAGING_AREA=...</varname> is set for plugins to a path to a directory.
|
||||||
|
Plugins may drop files in that directory, and they will be installed as part of the loader entry, based
|
||||||
|
on the file name and extension.</para>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>bls</term>
|
<term>bls</term>
|
||||||
|
|||||||
@ -121,6 +121,19 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) {
|
|||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int in_addr_is_localhost_one(int family, const union in_addr_union *u) {
|
||||||
|
assert(u);
|
||||||
|
|
||||||
|
if (family == AF_INET)
|
||||||
|
/* 127.0.0.1 */
|
||||||
|
return be32toh(u->in.s_addr) == UINT32_C(0x7F000001);
|
||||||
|
|
||||||
|
if (family == AF_INET6)
|
||||||
|
return IN6_IS_ADDR_LOOPBACK(&u->in6); /* lgtm [cpp/potentially-dangerous-function] */
|
||||||
|
|
||||||
|
return -EAFNOSUPPORT;
|
||||||
|
}
|
||||||
|
|
||||||
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
|
bool in6_addr_is_ipv4_mapped_address(const struct in6_addr *a) {
|
||||||
return a->s6_addr32[0] == 0 &&
|
return a->s6_addr32[0] == 0 &&
|
||||||
a->s6_addr32[1] == 0 &&
|
a->s6_addr32[1] == 0 &&
|
||||||
|
|||||||
@ -49,6 +49,7 @@ bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a);
|
|||||||
|
|
||||||
bool in4_addr_is_localhost(const struct in_addr *a);
|
bool in4_addr_is_localhost(const struct in_addr *a);
|
||||||
int in_addr_is_localhost(int family, const union in_addr_union *u);
|
int in_addr_is_localhost(int family, const union in_addr_union *u);
|
||||||
|
int in_addr_is_localhost_one(int family, const union in_addr_union *u);
|
||||||
|
|
||||||
bool in4_addr_is_local_multicast(const struct in_addr *a);
|
bool in4_addr_is_local_multicast(const struct in_addr *a);
|
||||||
bool in4_addr_is_non_local(const struct in_addr *a);
|
bool in4_addr_is_non_local(const struct in_addr *a);
|
||||||
|
|||||||
@ -68,8 +68,8 @@ bpf_o_unstripped_cmd += [
|
|||||||
if bpftool_strip
|
if bpftool_strip
|
||||||
bpf_o_cmd = [
|
bpf_o_cmd = [
|
||||||
bpftool,
|
bpftool,
|
||||||
'g',
|
'gen',
|
||||||
'o',
|
'object',
|
||||||
'@OUTPUT@',
|
'@OUTPUT@',
|
||||||
'@INPUT@'
|
'@INPUT@'
|
||||||
]
|
]
|
||||||
@ -85,7 +85,7 @@ endif
|
|||||||
|
|
||||||
skel_h_cmd = [
|
skel_h_cmd = [
|
||||||
bpftool,
|
bpftool,
|
||||||
'g',
|
'gen',
|
||||||
's',
|
'skeleton',
|
||||||
'@INPUT@'
|
'@INPUT@'
|
||||||
]
|
]
|
||||||
|
|||||||
@ -4058,6 +4058,10 @@ static int exec_child(
|
|||||||
assert(params);
|
assert(params);
|
||||||
assert(exit_status);
|
assert(exit_status);
|
||||||
|
|
||||||
|
/* Explicitly test for CVE-2021-4034 inspired invocations */
|
||||||
|
assert(command->path);
|
||||||
|
assert(!strv_isempty(command->argv));
|
||||||
|
|
||||||
rename_process_from_path(command->path);
|
rename_process_from_path(command->path);
|
||||||
|
|
||||||
/* We reset exactly these signals, since they are the only ones we set to SIG_IGN in the main
|
/* We reset exactly these signals, since they are the only ones we set to SIG_IGN in the main
|
||||||
|
|||||||
@ -18,6 +18,8 @@
|
|||||||
# You should have received a copy of the GNU Lesser General Public License
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
shopt -s nullglob
|
||||||
|
|
||||||
COMMAND="$1"
|
COMMAND="$1"
|
||||||
KERNEL_VERSION="$2"
|
KERNEL_VERSION="$2"
|
||||||
ENTRY_DIR_ABS="$3"
|
ENTRY_DIR_ABS="$3"
|
||||||
@ -38,6 +40,8 @@ fi
|
|||||||
|
|
||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
remove)
|
remove)
|
||||||
|
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
|
||||||
|
echo "Removing $BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION*.conf"
|
||||||
exec rm -f \
|
exec rm -f \
|
||||||
"$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" \
|
"$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" \
|
||||||
"$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf"
|
"$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf"
|
||||||
@ -78,36 +82,33 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [ -d "$ENTRY_DIR_ABS" ]; then
|
if ! [ -d "$ENTRY_DIR_ABS" ]; then
|
||||||
if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
|
echo "Error: entry directory '$ENTRY_DIR_ABS' does not exist" >&2
|
||||||
echo "+mkdir -v -p $ENTRY_DIR_ABS"
|
exit 1
|
||||||
mkdir -v -p "$ENTRY_DIR_ABS"
|
|
||||||
else
|
|
||||||
mkdir -p "$ENTRY_DIR_ABS"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install -g root -o root -m 0644 "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" || {
|
install -g root -o root -m 0644 "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" || {
|
||||||
echo "Could not copy '$KERNEL_IMAGE' to '$ENTRY_DIR_ABS/linux'." >&2
|
echo "Error: could not copy '$KERNEL_IMAGE' to '$ENTRY_DIR_ABS/linux'." >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
shift "$INITRD_OPTIONS_SHIFT"
|
shift "$INITRD_OPTIONS_SHIFT"
|
||||||
for initrd; do
|
# All files listed as arguments, and staged files called "initrd*" are installed as initrds.
|
||||||
|
for initrd in "$@" "${KERNEL_INSTALL_STAGING_AREA}"/initrd*; do
|
||||||
[ -f "$initrd" ] || {
|
[ -f "$initrd" ] || {
|
||||||
echo "Initrd '$initrd' not a file." >&2
|
echo "Error: initrd '$initrd' not a file." >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
initrd_basename="${initrd##*/}"
|
initrd_basename="${initrd##*/}"
|
||||||
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $ENTRY_DIR_ABS/$initrd_basename"
|
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "Installing $ENTRY_DIR_ABS/$initrd_basename"
|
||||||
install -g root -o root -m 0644 "$initrd" "$ENTRY_DIR_ABS/$initrd_basename" || {
|
install -g root -o root -m 0644 "$initrd" "$ENTRY_DIR_ABS/$initrd_basename" || {
|
||||||
echo "Could not copy '$initrd' to '$ENTRY_DIR_ABS/$initrd_basename'." >&2
|
echo "Error: could not copy '$initrd' to '$ENTRY_DIR_ABS/$initrd_basename'." >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
done
|
done
|
||||||
|
|
||||||
mkdir -p "${LOADER_ENTRY%/*}" || {
|
mkdir -p "${LOADER_ENTRY%/*}" || {
|
||||||
echo "Could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2
|
echo "Error: could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,14 +119,18 @@ mkdir -p "${LOADER_ENTRY%/*}" || {
|
|||||||
echo "machine-id $MACHINE_ID"
|
echo "machine-id $MACHINE_ID"
|
||||||
echo "options $BOOT_OPTIONS"
|
echo "options $BOOT_OPTIONS"
|
||||||
echo "linux $ENTRY_DIR/linux"
|
echo "linux $ENTRY_DIR/linux"
|
||||||
for initrd; do
|
|
||||||
|
have_initrd=
|
||||||
|
for initrd in "${@}" "${KERNEL_INSTALL_STAGING_AREA}"/initrd*; do
|
||||||
echo "initrd $ENTRY_DIR/${initrd##*/}"
|
echo "initrd $ENTRY_DIR/${initrd##*/}"
|
||||||
|
have_initrd=yes
|
||||||
done
|
done
|
||||||
|
|
||||||
# Try "initrd", generated by dracut in its kernel-install hook, if no initrds were supplied
|
# Try "initrd", generated by dracut in its kernel-install hook, if no initrds were supplied
|
||||||
[ $# -eq 0 ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && echo "initrd $ENTRY_DIR/initrd"
|
[ -z "$have_initrd" ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && echo "initrd $ENTRY_DIR/initrd"
|
||||||
:
|
:
|
||||||
} >"$LOADER_ENTRY" || {
|
} >"$LOADER_ENTRY" || {
|
||||||
echo "Could not create loader entry '$LOADER_ENTRY'." >&2
|
echo "Error: could not create loader entry '$LOADER_ENTRY'." >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@ -8,3 +8,4 @@
|
|||||||
# See kernel-install(8) for details.
|
# See kernel-install(8) for details.
|
||||||
|
|
||||||
#layout=bls|other|...
|
#layout=bls|other|...
|
||||||
|
#initrd_generator=dracut|...
|
||||||
|
|||||||
@ -73,13 +73,16 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $# -lt 1 ]; then
|
if [ $# -lt 1 ]; then
|
||||||
echo "Not enough arguments" >&2
|
echo "Error: not enough arguments" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
KERNEL_VERSION="$1"
|
KERNEL_VERSION="$1"
|
||||||
shift
|
shift
|
||||||
|
|
||||||
|
layout=
|
||||||
|
initrd_generator=
|
||||||
|
|
||||||
if [ -r "/etc/kernel/install.conf" ]; then
|
if [ -r "/etc/kernel/install.conf" ]; then
|
||||||
. /etc/kernel/install.conf
|
. /etc/kernel/install.conf
|
||||||
elif [ -r "/usr/lib/kernel/install.conf" ]; then
|
elif [ -r "/usr/lib/kernel/install.conf" ]; then
|
||||||
@ -123,12 +126,22 @@ if [ -z "$layout" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
ENTRY_DIR_ABS="$BOOT_ROOT/$MACHINE_ID/$KERNEL_VERSION"
|
ENTRY_DIR_ABS="$BOOT_ROOT/$MACHINE_ID/$KERNEL_VERSION"
|
||||||
|
|
||||||
|
# Provide a directory where to store generated initrds
|
||||||
|
cleanup() {
|
||||||
|
[ -n "$KERNEL_INSTALL_STAGING_AREA" ] && rm -rf "$KERNEL_INSTALL_STAGING_AREA"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
KERNEL_INSTALL_STAGING_AREA="$(mktemp -d -t -p /tmp kernel-install.staging.XXXXXXX)"
|
||||||
|
|
||||||
export KERNEL_INSTALL_MACHINE_ID="$MACHINE_ID"
|
export KERNEL_INSTALL_MACHINE_ID="$MACHINE_ID"
|
||||||
export KERNEL_INSTALL_BOOT_ROOT="$BOOT_ROOT"
|
export KERNEL_INSTALL_BOOT_ROOT="$BOOT_ROOT"
|
||||||
export KERNEL_INSTALL_LAYOUT="$layout"
|
export KERNEL_INSTALL_LAYOUT="$layout"
|
||||||
|
export KERNEL_INSTALL_INITRD_GENERATOR="$initrd_generator"
|
||||||
|
export KERNEL_INSTALL_STAGING_AREA
|
||||||
|
|
||||||
[ "$layout" = "bls" ]
|
[ "$layout" = "bls" ]
|
||||||
MAKE_ENTRY_DIR_ABS=$?
|
MAKE_ENTRY_DIR_ABS=$?
|
||||||
@ -147,12 +160,12 @@ IFS="
|
|||||||
case "$COMMAND" in
|
case "$COMMAND" in
|
||||||
add)
|
add)
|
||||||
if [ $# -lt 1 ]; then
|
if [ $# -lt 1 ]; then
|
||||||
echo "Command 'add' requires a kernel image" >&2
|
echo "Error: command 'add' requires a kernel image" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [ -f "$1" ]; then
|
if ! [ -f "$1" ]; then
|
||||||
echo "Kernel image argument $1 not a file" >&2
|
echo "Error: kernel image argument $1 not a file" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -162,9 +175,9 @@ case "$COMMAND" in
|
|||||||
# to serve as the indication to use or to not use the BLS
|
# to serve as the indication to use or to not use the BLS
|
||||||
if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
|
if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
|
||||||
echo "+mkdir -v -p $ENTRY_DIR_ABS"
|
echo "+mkdir -v -p $ENTRY_DIR_ABS"
|
||||||
mkdir -v -p "$ENTRY_DIR_ABS"
|
mkdir -v -p "$ENTRY_DIR_ABS" || exit 1
|
||||||
else
|
else
|
||||||
mkdir -p "$ENTRY_DIR_ABS"
|
mkdir -p "$ENTRY_DIR_ABS" || exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -193,7 +206,7 @@ case "$COMMAND" in
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "Unknown command '$COMMAND'" >&2
|
echo "Error: unknown command '$COMMAND'" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@ -17,13 +17,42 @@ ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_lease(sd_dhcp_server *server, const struct in_addr *server_address, uint8_t i) {
|
||||||
|
static const uint8_t chaddr[] = {3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3};
|
||||||
|
DHCPLease *lease;
|
||||||
|
|
||||||
|
assert(server);
|
||||||
|
|
||||||
|
assert_se(lease = new0(DHCPLease, 1));
|
||||||
|
lease->client_id.length = 2;
|
||||||
|
assert_se(lease->client_id.data = malloc(2));
|
||||||
|
lease->client_id.data[0] = 2;
|
||||||
|
lease->client_id.data[1] = i;
|
||||||
|
lease->address = htobe32(UINT32_C(10) << 24 | i);
|
||||||
|
lease->gateway = server_address->s_addr;
|
||||||
|
lease->expiration = UINT64_MAX;
|
||||||
|
lease->htype = ARPHRD_ETHER;
|
||||||
|
lease->hlen = ETH_ALEN;
|
||||||
|
memcpy(lease->chaddr, chaddr, ETH_ALEN);
|
||||||
|
assert_se(hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease) >= 0);
|
||||||
|
assert_se(hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease) >= 0);
|
||||||
|
lease->server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_static_lease(sd_dhcp_server *server, uint8_t i) {
|
||||||
|
uint8_t id[2] = { 2, i };
|
||||||
|
|
||||||
|
assert(server);
|
||||||
|
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server,
|
||||||
|
&(struct in_addr) { .s_addr = htobe32(UINT32_C(10) << 24 | i)},
|
||||||
|
id, ELEMENTSOF(id)) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
|
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
|
||||||
struct in_addr address = {.s_addr = htobe32(UINT32_C(10) << 24 | UINT32_C(1))};
|
struct in_addr address = { .s_addr = htobe32(UINT32_C(10) << 24 | UINT32_C(1))};
|
||||||
static const uint8_t chaddr[] = {3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3};
|
|
||||||
_cleanup_free_ uint8_t *duped = NULL;
|
_cleanup_free_ uint8_t *duped = NULL;
|
||||||
uint8_t *client_id;
|
|
||||||
DHCPLease *lease;
|
|
||||||
|
|
||||||
if (size < sizeof(DHCPMessage))
|
if (size < sizeof(DHCPMessage))
|
||||||
return 0;
|
return 0;
|
||||||
@ -36,24 +65,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
assert_se(server->fd >= 0);
|
assert_se(server->fd >= 0);
|
||||||
assert_se(sd_dhcp_server_configure_pool(server, &address, 24, 0, 0) >= 0);
|
assert_se(sd_dhcp_server_configure_pool(server, &address, 24, 0, 0) >= 0);
|
||||||
|
|
||||||
/* add a lease to the pool to expose additional code paths */
|
/* add leases to the pool to expose additional code paths */
|
||||||
client_id = malloc(2);
|
add_lease(server, &address, 2);
|
||||||
assert_se(client_id);
|
add_lease(server, &address, 3);
|
||||||
client_id[0] = 2;
|
|
||||||
client_id[1] = 2;
|
/* add static leases */
|
||||||
lease = new0(DHCPLease, 1);
|
add_static_lease(server, 3);
|
||||||
assert_se(lease);
|
add_static_lease(server, 4);
|
||||||
lease->client_id.length = 2;
|
|
||||||
lease->client_id.data = client_id;
|
|
||||||
lease->address = htobe32(UINT32_C(10) << 24 | UINT32_C(2));
|
|
||||||
lease->gateway = htobe32(UINT32_C(10) << 24 | UINT32_C(1));
|
|
||||||
lease->expiration = UINT64_MAX;
|
|
||||||
lease->htype = ARPHRD_ETHER;
|
|
||||||
lease->hlen = ETH_ALEN;
|
|
||||||
memcpy(lease->chaddr, chaddr, ETH_ALEN);
|
|
||||||
assert_se(hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease) >= 0);
|
|
||||||
assert_se(hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease) >= 0);
|
|
||||||
lease->server = server;
|
|
||||||
|
|
||||||
(void) dhcp_server_handle_message(server, (DHCPMessage*) duped, size);
|
(void) dhcp_server_handle_message(server, (DHCPMessage*) duped, size);
|
||||||
|
|
||||||
|
|||||||
@ -30,19 +30,10 @@ static DHCPLease *dhcp_lease_free(DHCPLease *lease) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (lease->server) {
|
if (lease->server) {
|
||||||
DHCPLease *e;
|
hashmap_remove_value(lease->server->bound_leases_by_address, UINT32_TO_PTR(lease->address), lease);
|
||||||
|
hashmap_remove_value(lease->server->bound_leases_by_client_id, &lease->client_id, lease);
|
||||||
e = hashmap_get(lease->server->bound_leases_by_client_id, &lease->client_id);
|
hashmap_remove_value(lease->server->static_leases_by_address, UINT32_TO_PTR(lease->address), lease);
|
||||||
if (e == lease) {
|
hashmap_remove_value(lease->server->static_leases_by_client_id, &lease->client_id, lease);
|
||||||
hashmap_remove(lease->server->bound_leases_by_address, UINT32_TO_PTR(lease->address));
|
|
||||||
hashmap_remove(lease->server->bound_leases_by_client_id, &lease->client_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
e = hashmap_get(lease->server->static_leases_by_client_id, &lease->client_id);
|
|
||||||
if (e == lease) {
|
|
||||||
hashmap_remove(lease->server->static_leases_by_address, UINT32_TO_PTR(lease->address));
|
|
||||||
hashmap_remove(lease->server->static_leases_by_client_id, &lease->client_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(lease->client_id.data);
|
free(lease->client_id.data);
|
||||||
@ -134,7 +125,7 @@ int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) {
|
|||||||
|
|
||||||
void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
|
void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
|
||||||
assert(id);
|
assert(id);
|
||||||
assert(id->length);
|
assert(id->length > 0);
|
||||||
assert(id->data);
|
assert(id->data);
|
||||||
|
|
||||||
siphash24_compress(&id->length, sizeof(id->length), state);
|
siphash24_compress(&id->length, sizeof(id->length), state);
|
||||||
@ -144,8 +135,10 @@ void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
|
|||||||
int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
|
int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(!a->length || a->data);
|
assert(a->length > 0);
|
||||||
assert(!b->length || b->data);
|
assert(a->data);
|
||||||
|
assert(b->length > 0);
|
||||||
|
assert(b->data);
|
||||||
|
|
||||||
r = CMP(a->length, b->length);
|
r = CMP(a->length, b->length);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
@ -165,8 +158,6 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
|||||||
static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
|
static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
|
||||||
assert(server);
|
assert(server);
|
||||||
|
|
||||||
log_dhcp_server(server, "UNREF");
|
|
||||||
|
|
||||||
sd_dhcp_server_stop(server);
|
sd_dhcp_server_stop(server);
|
||||||
|
|
||||||
sd_event_unref(server->event);
|
sd_event_unref(server->event);
|
||||||
@ -280,9 +271,13 @@ sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int sd_dhcp_server_stop(sd_dhcp_server *server) {
|
int sd_dhcp_server_stop(sd_dhcp_server *server) {
|
||||||
|
bool running;
|
||||||
|
|
||||||
if (!server)
|
if (!server)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
running = sd_dhcp_server_is_running(server);
|
||||||
|
|
||||||
server->receive_message = sd_event_source_disable_unref(server->receive_message);
|
server->receive_message = sd_event_source_disable_unref(server->receive_message);
|
||||||
server->receive_broadcast = sd_event_source_disable_unref(server->receive_broadcast);
|
server->receive_broadcast = sd_event_source_disable_unref(server->receive_broadcast);
|
||||||
|
|
||||||
@ -290,7 +285,8 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) {
|
|||||||
server->fd = safe_close(server->fd);
|
server->fd = safe_close(server->fd);
|
||||||
server->fd_broadcast = safe_close(server->fd_broadcast);
|
server->fd_broadcast = safe_close(server->fd_broadcast);
|
||||||
|
|
||||||
log_dhcp_server(server, "STOPPED");
|
if (running)
|
||||||
|
log_dhcp_server(server, "STOPPED");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -311,7 +307,7 @@ static int dhcp_server_send_unicast_raw(
|
|||||||
|
|
||||||
assert(server);
|
assert(server);
|
||||||
assert(server->ifindex > 0);
|
assert(server->ifindex > 0);
|
||||||
assert(server->address);
|
assert(server->address != 0);
|
||||||
assert(hlen > 0);
|
assert(hlen > 0);
|
||||||
assert(chaddr);
|
assert(chaddr);
|
||||||
assert(packet);
|
assert(packet);
|
||||||
@ -424,7 +420,7 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
|
|||||||
|
|
||||||
assert(server);
|
assert(server);
|
||||||
assert(req);
|
assert(req);
|
||||||
assert(req->max_optlen);
|
assert(req->max_optlen > 0);
|
||||||
assert(req->message);
|
assert(req->message);
|
||||||
assert(optoffset <= req->max_optlen);
|
assert(optoffset <= req->max_optlen);
|
||||||
assert(packet);
|
assert(packet);
|
||||||
@ -472,12 +468,12 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
|
|||||||
client, because the client may not have a correct network address
|
client, because the client may not have a correct network address
|
||||||
or subnet mask, and the client may not be answering ARP requests.
|
or subnet mask, and the client may not be answering ARP requests.
|
||||||
*/
|
*/
|
||||||
if (req->message->giaddr) {
|
if (req->message->giaddr != 0) {
|
||||||
destination = req->message->giaddr;
|
destination = req->message->giaddr;
|
||||||
destination_port = DHCP_PORT_SERVER;
|
destination_port = DHCP_PORT_SERVER;
|
||||||
if (type == DHCP_NAK)
|
if (type == DHCP_NAK)
|
||||||
packet->dhcp.flags = htobe16(0x8000);
|
packet->dhcp.flags = htobe16(0x8000);
|
||||||
} else if (req->message->ciaddr && type != DHCP_NAK)
|
} else if (req->message->ciaddr != 0 && type != DHCP_NAK)
|
||||||
destination = req->message->ciaddr;
|
destination = req->message->ciaddr;
|
||||||
|
|
||||||
bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK;
|
bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK;
|
||||||
@ -485,17 +481,22 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
|
|||||||
destination, destination_port, packet, optoffset, l2_broadcast);
|
destination, destination_port, packet, optoffset, l2_broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
|
static int server_message_init(
|
||||||
uint8_t type, size_t *_optoffset,
|
sd_dhcp_server *server,
|
||||||
DHCPRequest *req) {
|
DHCPPacket **ret,
|
||||||
|
uint8_t type,
|
||||||
|
size_t *ret_optoffset,
|
||||||
|
DHCPRequest *req) {
|
||||||
|
|
||||||
_cleanup_free_ DHCPPacket *packet = NULL;
|
_cleanup_free_ DHCPPacket *packet = NULL;
|
||||||
size_t optoffset = 0;
|
size_t optoffset = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(server);
|
assert(server);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
assert(_optoffset);
|
assert(ret_optoffset);
|
||||||
assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
|
assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
|
||||||
|
assert(req);
|
||||||
|
|
||||||
packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
|
packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
|
||||||
if (!packet)
|
if (!packet)
|
||||||
@ -511,7 +512,7 @@ static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
|
|||||||
packet->dhcp.flags = req->message->flags;
|
packet->dhcp.flags = req->message->flags;
|
||||||
packet->dhcp.giaddr = req->message->giaddr;
|
packet->dhcp.giaddr = req->message->giaddr;
|
||||||
|
|
||||||
*_optoffset = optoffset;
|
*ret_optoffset = optoffset;
|
||||||
*ret = TAKE_PTR(packet);
|
*ret = TAKE_PTR(packet);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -614,16 +615,28 @@ static int server_send_offer_or_ack(
|
|||||||
return dhcp_server_send_packet(server, req, packet, type, offset);
|
return dhcp_server_send_packet(server, req, packet, type, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
|
static int server_send_nak_or_ignore(sd_dhcp_server *server, bool init_reboot, DHCPRequest *req) {
|
||||||
_cleanup_free_ DHCPPacket *packet = NULL;
|
_cleanup_free_ DHCPPacket *packet = NULL;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
/* When a request is refused, RFC 2131, section 4.3.2 mentioned we should send NAK when the
|
||||||
|
* client is in INITREBOOT. If the client is in other state, there is nothing mentioned in the
|
||||||
|
* RFC whether we should send NAK or not. Hence, let's silently ignore the request. */
|
||||||
|
|
||||||
|
if (!init_reboot)
|
||||||
|
return 0;
|
||||||
|
|
||||||
r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
|
r = server_message_init(server, &packet, DHCP_NAK, &offset, req);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return log_dhcp_server_errno(server, r, "Failed to create NAK message: %m");
|
||||||
|
|
||||||
return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
|
r = dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
|
||||||
|
if (r < 0)
|
||||||
|
return log_dhcp_server_errno(server, r, "Could not send NAK message: %m");
|
||||||
|
|
||||||
|
log_dhcp_server(server, "NAK (0x%x)", be32toh(req->message->xid));
|
||||||
|
return DHCP_NAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int server_send_forcerenew(
|
static int server_send_forcerenew(
|
||||||
@ -778,17 +791,20 @@ static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMes
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
|
static bool address_is_in_pool(sd_dhcp_server *server, be32_t address) {
|
||||||
assert(server);
|
assert(server);
|
||||||
|
|
||||||
if (!server->pool_size)
|
if (server->pool_size == 0)
|
||||||
return -EINVAL;
|
return false;
|
||||||
|
|
||||||
if (be32toh(requested_ip) < (be32toh(server->subnet) | server->pool_offset) ||
|
if (be32toh(address) < (be32toh(server->subnet) | server->pool_offset) ||
|
||||||
be32toh(requested_ip) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
|
be32toh(address) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
|
||||||
return -ERANGE;
|
return false;
|
||||||
|
|
||||||
return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
|
if (hashmap_contains(server->static_leases_by_address, UINT32_TO_PTR(address)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_agent_information_option(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t size) {
|
static int append_agent_information_option(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t size) {
|
||||||
@ -903,6 +919,59 @@ static int prepare_new_lease(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int server_ack_request(sd_dhcp_server *server, DHCPRequest *req, DHCPLease *existing_lease, be32_t address) {
|
||||||
|
usec_t time_now, expiration;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(server);
|
||||||
|
assert(req);
|
||||||
|
assert(address != 0);
|
||||||
|
|
||||||
|
r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
expiration = usec_add(req->lifetime * USEC_PER_SEC, time_now);
|
||||||
|
|
||||||
|
if (existing_lease) {
|
||||||
|
assert(existing_lease->server);
|
||||||
|
assert(existing_lease->address == address);
|
||||||
|
existing_lease->expiration = expiration;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
|
||||||
|
|
||||||
|
r = prepare_new_lease(&lease, address, &req->client_id,
|
||||||
|
req->message->htype, req->message->hlen,
|
||||||
|
req->message->chaddr, req->message->giaddr, expiration);
|
||||||
|
if (r < 0)
|
||||||
|
return log_dhcp_server_errno(server, r, "Failed to create new lease: %m");
|
||||||
|
|
||||||
|
lease->server = server; /* This must be set just before hashmap_put(). */
|
||||||
|
|
||||||
|
r = hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
|
||||||
|
if (r < 0)
|
||||||
|
return log_dhcp_server_errno(server, r, "Could not save lease: %m");
|
||||||
|
|
||||||
|
r = hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
|
||||||
|
if (r < 0)
|
||||||
|
return log_dhcp_server_errno(server, r, "Could not save lease: %m");
|
||||||
|
|
||||||
|
TAKE_PTR(lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
|
||||||
|
if (r < 0)
|
||||||
|
return log_dhcp_server_errno(server, r, "Could not send ACK: %m");
|
||||||
|
|
||||||
|
log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
|
||||||
|
|
||||||
|
if (server->callback)
|
||||||
|
server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
|
||||||
|
|
||||||
|
return DHCP_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
static int dhcp_server_cleanup_expired_leases(sd_dhcp_server *server) {
|
static int dhcp_server_cleanup_expired_leases(sd_dhcp_server *server) {
|
||||||
DHCPLease *lease;
|
DHCPLease *lease;
|
||||||
usec_t time_now;
|
usec_t time_now;
|
||||||
@ -974,7 +1043,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
|||||||
|
|
||||||
log_dhcp_server(server, "DISCOVER (0x%x)", be32toh(req->message->xid));
|
log_dhcp_server(server, "DISCOVER (0x%x)", be32toh(req->message->xid));
|
||||||
|
|
||||||
if (!server->pool_size)
|
if (server->pool_size == 0)
|
||||||
/* no pool allocated */
|
/* no pool allocated */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -1026,14 +1095,12 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case DHCP_REQUEST: {
|
case DHCP_REQUEST: {
|
||||||
DHCPLease *existing_lease_by_address;
|
|
||||||
be32_t address;
|
be32_t address;
|
||||||
bool init_reboot = false;
|
bool init_reboot = false;
|
||||||
int pool_offset;
|
|
||||||
|
|
||||||
/* see RFC 2131, section 4.3.2 */
|
/* see RFC 2131, section 4.3.2 */
|
||||||
|
|
||||||
if (req->server_id) {
|
if (req->server_id != 0) {
|
||||||
log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
|
log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
|
||||||
be32toh(req->message->xid));
|
be32toh(req->message->xid));
|
||||||
|
|
||||||
@ -1042,22 +1109,22 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
|||||||
/* client did not pick us */
|
/* client did not pick us */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (req->message->ciaddr)
|
if (req->message->ciaddr != 0)
|
||||||
/* this MUST be zero */
|
/* this MUST be zero */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!req->requested_ip)
|
if (req->requested_ip == 0)
|
||||||
/* this must be filled in with the yiaddr
|
/* this must be filled in with the yiaddr
|
||||||
from the chosen OFFER */
|
from the chosen OFFER */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
address = req->requested_ip;
|
address = req->requested_ip;
|
||||||
} else if (req->requested_ip) {
|
} else if (req->requested_ip != 0) {
|
||||||
log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
|
log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
|
||||||
be32toh(req->message->xid));
|
be32toh(req->message->xid));
|
||||||
|
|
||||||
/* INIT-REBOOT */
|
/* INIT-REBOOT */
|
||||||
if (req->message->ciaddr)
|
if (req->message->ciaddr != 0)
|
||||||
/* this MUST be zero */
|
/* this MUST be zero */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -1069,7 +1136,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
|||||||
be32toh(req->message->xid));
|
be32toh(req->message->xid));
|
||||||
|
|
||||||
/* REBINDING / RENEWING */
|
/* REBINDING / RENEWING */
|
||||||
if (!req->message->ciaddr)
|
if (req->message->ciaddr == 0)
|
||||||
/* this MUST be filled in with clients IP address */
|
/* this MUST be filled in with clients IP address */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -1080,110 +1147,27 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
|||||||
if (address == server->address)
|
if (address == server->address)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pool_offset = get_pool_offset(server, address);
|
if (static_lease) {
|
||||||
existing_lease_by_address = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(address));
|
/* Found a static lease for the client ID. */
|
||||||
|
|
||||||
/* verify that the requested address is from the pool, and either
|
if (static_lease->address != address)
|
||||||
owned by the current client or free */
|
/* The client requested an address which is different from the static lease. Refuse. */
|
||||||
if (static_lease && static_lease->address == address) {
|
return server_send_nak_or_ignore(server, init_reboot, req);
|
||||||
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
|
|
||||||
usec_t time_now, expiration;
|
|
||||||
|
|
||||||
r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now);
|
return server_ack_request(server, req, existing_lease, address);
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
expiration = usec_add(req->lifetime * USEC_PER_SEC, time_now);
|
|
||||||
|
|
||||||
r = prepare_new_lease(&lease, static_lease->address, &req->client_id,
|
|
||||||
req->message->htype, req->message->hlen,
|
|
||||||
req->message->chaddr, req->message->giaddr, expiration);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
|
|
||||||
if (r < 0)
|
|
||||||
/* this only fails on critical errors */
|
|
||||||
return log_dhcp_server_errno(server, r, "Could not send ack: %m");
|
|
||||||
|
|
||||||
log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
|
|
||||||
|
|
||||||
dhcp_lease_free(hashmap_remove(server->bound_leases_by_client_id, &lease->client_id));
|
|
||||||
r = hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
|
|
||||||
if (r < 0)
|
|
||||||
return log_dhcp_server_errno(server, r, "Could not save lease: %m");
|
|
||||||
|
|
||||||
r = hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
|
|
||||||
if (r < 0)
|
|
||||||
return log_dhcp_server_errno(server, r, "Could not save lease: %m");
|
|
||||||
|
|
||||||
lease->server = server;
|
|
||||||
TAKE_PTR(lease);
|
|
||||||
|
|
||||||
if (server->callback)
|
|
||||||
server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
|
|
||||||
|
|
||||||
return DHCP_ACK;
|
|
||||||
|
|
||||||
} else if (pool_offset >= 0 && existing_lease_by_address == existing_lease) {
|
|
||||||
_cleanup_(dhcp_lease_freep) DHCPLease *new_lease = NULL;
|
|
||||||
usec_t time_now, expiration;
|
|
||||||
DHCPLease *lease;
|
|
||||||
|
|
||||||
/* Note that in the above condition we accept the case that both leases are NULL. */
|
|
||||||
|
|
||||||
r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
expiration = usec_add(req->lifetime * USEC_PER_SEC, time_now);
|
|
||||||
|
|
||||||
if (!existing_lease) {
|
|
||||||
r = prepare_new_lease(&new_lease, address, &req->client_id,
|
|
||||||
req->message->htype, req->message->hlen,
|
|
||||||
req->message->chaddr, req->message->giaddr, expiration);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
lease = new_lease;
|
|
||||||
} else {
|
|
||||||
existing_lease->expiration = expiration;
|
|
||||||
lease = existing_lease;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
|
|
||||||
if (r < 0)
|
|
||||||
/* this only fails on critical errors */
|
|
||||||
return log_dhcp_server_errno(server, r, "Could not send ack: %m");
|
|
||||||
|
|
||||||
log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
|
|
||||||
|
|
||||||
r = hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
|
|
||||||
if (r < 0)
|
|
||||||
return log_dhcp_server_errno(server, r, "Could not save lease: %m");
|
|
||||||
r = hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
|
|
||||||
if (r < 0)
|
|
||||||
return log_dhcp_server_errno(server, r, "Could not save lease: %m");
|
|
||||||
|
|
||||||
lease->server = server;
|
|
||||||
TAKE_PTR(new_lease);
|
|
||||||
|
|
||||||
if (server->callback)
|
|
||||||
server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
|
|
||||||
|
|
||||||
return DHCP_ACK;
|
|
||||||
|
|
||||||
} else if (init_reboot) {
|
|
||||||
r = server_send_nak(server, req);
|
|
||||||
if (r < 0)
|
|
||||||
/* this only fails on critical errors */
|
|
||||||
return log_dhcp_server_errno(server, r, "Could not send nak: %m");
|
|
||||||
|
|
||||||
log_dhcp_server(server, "NAK (0x%x)", be32toh(req->message->xid));
|
|
||||||
return DHCP_NAK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
if (address_is_in_pool(server, address)) {
|
||||||
|
/* The requested address is in the pool. */
|
||||||
|
|
||||||
|
if (existing_lease && existing_lease->address != address)
|
||||||
|
/* We previously assigned an address, but the client requested another one. Refuse. */
|
||||||
|
return server_send_nak_or_ignore(server, init_reboot, req);
|
||||||
|
|
||||||
|
return server_ack_request(server, req, existing_lease, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
return server_send_nak_or_ignore(server, init_reboot, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
case DHCP_RELEASE: {
|
case DHCP_RELEASE: {
|
||||||
@ -1356,8 +1340,8 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
sd_dhcp_server_stop(server);
|
sd_dhcp_server_stop(server);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
|
int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
|
||||||
@ -1576,6 +1560,7 @@ int sd_dhcp_server_set_static_lease(
|
|||||||
|
|
||||||
assert_return(server, -EINVAL);
|
assert_return(server, -EINVAL);
|
||||||
assert_return(client_id, -EINVAL);
|
assert_return(client_id, -EINVAL);
|
||||||
|
assert_return(client_id_size > 0, -EINVAL);
|
||||||
assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
|
assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
|
||||||
|
|
||||||
/* Static lease with an empty or omitted address is a valid entry,
|
/* Static lease with an empty or omitted address is a valid entry,
|
||||||
@ -1588,13 +1573,10 @@ int sd_dhcp_server_set_static_lease(
|
|||||||
.data = client_id,
|
.data = client_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
dhcp_lease_free(hashmap_remove(server->static_leases_by_client_id, &c));
|
dhcp_lease_free(hashmap_get(server->static_leases_by_client_id, &c));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashmap_contains(server->static_leases_by_address, UINT32_TO_PTR(address->s_addr)))
|
|
||||||
return -EEXIST;
|
|
||||||
|
|
||||||
lease = new(DHCPLease, 1);
|
lease = new(DHCPLease, 1);
|
||||||
if (!lease)
|
if (!lease)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -1602,13 +1584,13 @@ int sd_dhcp_server_set_static_lease(
|
|||||||
*lease = (DHCPLease) {
|
*lease = (DHCPLease) {
|
||||||
.address = address->s_addr,
|
.address = address->s_addr,
|
||||||
.client_id.length = client_id_size,
|
.client_id.length = client_id_size,
|
||||||
.gateway = 0,
|
|
||||||
.expiration = 0,
|
|
||||||
};
|
};
|
||||||
lease->client_id.data = memdup(client_id, client_id_size);
|
lease->client_id.data = memdup(client_id, client_id_size);
|
||||||
if (!lease->client_id.data)
|
if (!lease->client_id.data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
lease->server = server; /* This must be set just before hashmap_put(). */
|
||||||
|
|
||||||
r = hashmap_ensure_put(&server->static_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
|
r = hashmap_ensure_put(&server->static_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1616,7 +1598,6 @@ int sd_dhcp_server_set_static_lease(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
lease->server = server;
|
|
||||||
TAKE_PTR(lease);
|
TAKE_PTR(lease);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,8 +20,9 @@ static void test_pool(struct in_addr *address, unsigned size, int ret) {
|
|||||||
assert_se(sd_dhcp_server_configure_pool(server, address, 8, 0, size) == ret);
|
assert_se(sd_dhcp_server_configure_pool(server, address, 8, 0, size) == ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_basic(sd_event *event, bool bind_to_interface) {
|
static int test_basic(bool bind_to_interface) {
|
||||||
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
|
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
|
||||||
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||||
struct in_addr address_lo = {
|
struct in_addr address_lo = {
|
||||||
.s_addr = htobe32(INADDR_LOOPBACK),
|
.s_addr = htobe32(INADDR_LOOPBACK),
|
||||||
};
|
};
|
||||||
@ -30,6 +31,10 @@ static int test_basic(sd_event *event, bool bind_to_interface) {
|
|||||||
};
|
};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
log_debug("/* %s(bind_to_interface=%s) */", __func__, yes_no(bind_to_interface));
|
||||||
|
|
||||||
|
assert_se(sd_event_new(&event) >= 0);
|
||||||
|
|
||||||
/* attach to loopback interface */
|
/* attach to loopback interface */
|
||||||
assert_se(sd_dhcp_server_new(&server, 1) >= 0);
|
assert_se(sd_dhcp_server_new(&server, 1) >= 0);
|
||||||
assert_se(server);
|
assert_se(server);
|
||||||
@ -58,7 +63,7 @@ static int test_basic(sd_event *event, bool bind_to_interface) {
|
|||||||
|
|
||||||
r = sd_dhcp_server_start(server);
|
r = sd_dhcp_server_start(server);
|
||||||
if (r == -EPERM)
|
if (r == -EPERM)
|
||||||
return log_info_errno(r, "sd_dhcp_server_start failed: %m");
|
return r;
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
assert_se(sd_dhcp_server_start(server) >= 0);
|
assert_se(sd_dhcp_server_start(server) >= 0);
|
||||||
@ -108,9 +113,17 @@ static void test_message_handler(void) {
|
|||||||
struct in_addr address_lo = {
|
struct in_addr address_lo = {
|
||||||
.s_addr = htobe32(INADDR_LOOPBACK),
|
.s_addr = htobe32(INADDR_LOOPBACK),
|
||||||
};
|
};
|
||||||
|
struct in_addr static_lease_address = {
|
||||||
|
.s_addr = htobe32(INADDR_LOOPBACK + 42),
|
||||||
|
};
|
||||||
|
static uint8_t static_lease_client_id[7] = {0x01, 'A', 'B', 'C', 'D', 'E', 'G' };
|
||||||
|
|
||||||
|
log_debug("/* %s */", __func__);
|
||||||
|
|
||||||
assert_se(sd_dhcp_server_new(&server, 1) >= 0);
|
assert_se(sd_dhcp_server_new(&server, 1) >= 0);
|
||||||
assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0);
|
assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0);
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &static_lease_address, static_lease_client_id,
|
||||||
|
ELEMENTSOF(static_lease_client_id)) >= 0);
|
||||||
assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
|
assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
|
||||||
assert_se(sd_dhcp_server_start(server) >= 0);
|
assert_se(sd_dhcp_server_start(server) >= 0);
|
||||||
|
|
||||||
@ -180,6 +193,26 @@ static void test_message_handler(void) {
|
|||||||
|
|
||||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
|
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
|
||||||
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
|
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
|
||||||
|
|
||||||
|
/* request address reserved for static lease (unmatching client ID) */
|
||||||
|
test.option_client_id.id[6] = 'H';
|
||||||
|
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42);
|
||||||
|
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
|
||||||
|
|
||||||
|
/* request unmatching address */
|
||||||
|
test.option_client_id.id[6] = 'G';
|
||||||
|
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 41);
|
||||||
|
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
|
||||||
|
|
||||||
|
/* request matching address */
|
||||||
|
test.option_client_id.id[6] = 'G';
|
||||||
|
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42);
|
||||||
|
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
|
||||||
|
|
||||||
|
/* try again */
|
||||||
|
test.option_client_id.id[6] = 'G';
|
||||||
|
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 42);
|
||||||
|
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) {
|
static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) {
|
||||||
@ -202,6 +235,8 @@ static void test_client_id_hash(void) {
|
|||||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
log_debug("/* %s */", __func__);
|
||||||
|
|
||||||
a.data = (uint8_t*)strdup("abcd");
|
a.data = (uint8_t*)strdup("abcd");
|
||||||
b.data = (uint8_t*)strdup("abcd");
|
b.data = (uint8_t*)strdup("abcd");
|
||||||
|
|
||||||
@ -227,24 +262,61 @@ static void test_client_id_hash(void) {
|
|||||||
free(b.data);
|
free(b.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_static_lease(void) {
|
||||||
|
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
|
||||||
|
|
||||||
|
log_debug("/* %s */", __func__);
|
||||||
|
|
||||||
|
assert_se(sd_dhcp_server_new(&server, 1) >= 0);
|
||||||
|
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x01020304 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020304 }, sizeof(uint32_t)) >= 0);
|
||||||
|
/* Duplicated entry. */
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x01020304 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020304 }, sizeof(uint32_t)) == -EEXIST);
|
||||||
|
/* Address is conflicted. */
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x01020304 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020305 }, sizeof(uint32_t)) == -EEXIST);
|
||||||
|
/* Client ID is conflicted. */
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x01020305 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020304 }, sizeof(uint32_t)) == -EEXIST);
|
||||||
|
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x01020305 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020305 }, sizeof(uint32_t)) >= 0);
|
||||||
|
/* Remove the previous entry. */
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x00000000 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020305 }, sizeof(uint32_t)) >= 0);
|
||||||
|
/* Then, set a different address. */
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x01020306 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020305 }, sizeof(uint32_t)) >= 0);
|
||||||
|
/* Remove again. */
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x00000000 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020305 }, sizeof(uint32_t)) >= 0);
|
||||||
|
/* Try to remove non-existent entry. */
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x00000000 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020305 }, sizeof(uint32_t)) >= 0);
|
||||||
|
/* Try to remove non-existent entry. */
|
||||||
|
assert_se(sd_dhcp_server_set_static_lease(server, &(struct in_addr) { .s_addr = 0x00000000 },
|
||||||
|
(uint8_t*) &(uint32_t) { 0x01020306 }, sizeof(uint32_t)) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
_cleanup_(sd_event_unrefp) sd_event *e;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
test_setup_logging(LOG_DEBUG);
|
test_setup_logging(LOG_DEBUG);
|
||||||
|
|
||||||
assert_se(sd_event_new(&e) >= 0);
|
test_client_id_hash();
|
||||||
|
test_static_lease();
|
||||||
|
|
||||||
r = test_basic(e, true);
|
r = test_basic(true);
|
||||||
if (r != 0)
|
if (r < 0)
|
||||||
return log_tests_skipped("cannot start dhcp server(bound to interface)");
|
return log_tests_skipped_errno(r, "cannot start dhcp server(bound to interface)");
|
||||||
|
|
||||||
r = test_basic(e, false);
|
r = test_basic(false);
|
||||||
if (r != 0)
|
if (r < 0)
|
||||||
return log_tests_skipped("cannot start dhcp server(non-bound to interface)");
|
return log_tests_skipped_errno(r, "cannot start dhcp server(non-bound to interface)");
|
||||||
|
|
||||||
test_message_handler();
|
test_message_handler();
|
||||||
test_client_id_hash();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -854,6 +854,10 @@ int link_drop_foreign_addresses(Link *link) {
|
|||||||
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Do not remove localhost address (127.0.0.1 and ::1) */
|
||||||
|
if (link->flags & IFF_LOOPBACK && in_addr_is_localhost_one(address->family, &address->in_addr) > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Ignore addresses we configured. */
|
/* Ignore addresses we configured. */
|
||||||
if (address->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
if (address->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||||
continue;
|
continue;
|
||||||
@ -891,22 +895,19 @@ int link_drop_foreign_addresses(Link *link) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_drop_addresses(Link *link) {
|
int link_drop_managed_addresses(Link *link) {
|
||||||
Address *address;
|
Address *address;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
SET_FOREACH(address, link->addresses) {
|
||||||
/* Ignore addresses not assigned yet or already removing. */
|
/* Do not touch addresses managed by kernel or other tools. */
|
||||||
if (!address_exists(address))
|
if (address->source == NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Do not drop IPv6LL addresses assigned by the kernel here. They will be dropped in
|
/* Ignore addresses not assigned yet or already removing. */
|
||||||
* link_drop_ipv6ll_addresses() if IPv6LL addressing is disabled. */
|
if (!address_exists(address))
|
||||||
if (address->source == NETWORK_CONFIG_SOURCE_FOREIGN &&
|
|
||||||
address->family == AF_INET6 &&
|
|
||||||
in6_addr_is_link_local(&address->in_addr.in6))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
k = address_remove(address);
|
k = address_remove(address);
|
||||||
|
|||||||
@ -74,7 +74,7 @@ void address_set_broadcast(Address *a);
|
|||||||
|
|
||||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(Address, address_free);
|
DEFINE_SECTION_CLEANUP_FUNCTIONS(Address, address_free);
|
||||||
|
|
||||||
int link_drop_addresses(Link *link);
|
int link_drop_managed_addresses(Link *link);
|
||||||
int link_drop_foreign_addresses(Link *link);
|
int link_drop_foreign_addresses(Link *link);
|
||||||
int link_drop_ipv6ll_addresses(Link *link);
|
int link_drop_ipv6ll_addresses(Link *link);
|
||||||
void link_foreignize_addresses(Link *link);
|
void link_foreignize_addresses(Link *link);
|
||||||
|
|||||||
@ -430,6 +430,8 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
|
|||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
|
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
|
||||||
|
|
||||||
|
ndisc_flush(link);
|
||||||
|
|
||||||
k = sd_radv_stop(link->radv);
|
k = sd_radv_stop(link->radv);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
|
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
|
||||||
@ -892,24 +894,6 @@ static int link_new_bound_to_list(Link *link) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_new_carrier_maps(Link *link) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = link_new_bound_by_list(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = link_handle_bound_by_list(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = link_new_bound_to_list(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return link_handle_bound_to_list(link);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void link_free_bound_to_list(Link *link) {
|
static void link_free_bound_to_list(Link *link) {
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
Link *bound_to;
|
Link *bound_to;
|
||||||
@ -946,13 +930,6 @@ static void link_free_bound_by_list(Link *link) {
|
|||||||
link_dirty(link);
|
link_dirty(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void link_free_carrier_maps(Link *link) {
|
|
||||||
assert(link);
|
|
||||||
|
|
||||||
link_free_bound_to_list(link);
|
|
||||||
link_free_bound_by_list(link);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int link_append_to_master(Link *link) {
|
static int link_append_to_master(Link *link) {
|
||||||
Link *master;
|
Link *master;
|
||||||
int r;
|
int r;
|
||||||
@ -1012,7 +989,8 @@ static Link *link_drop(Link *link) {
|
|||||||
|
|
||||||
link_drop_requests(link);
|
link_drop_requests(link);
|
||||||
|
|
||||||
link_free_carrier_maps(link);
|
link_free_bound_to_list(link);
|
||||||
|
link_free_bound_by_list(link);
|
||||||
|
|
||||||
link_drop_from_master(link);
|
link_drop_from_master(link);
|
||||||
|
|
||||||
@ -1070,32 +1048,30 @@ static int link_drop_foreign_config(Link *link) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_drop_config(Link *link) {
|
static int link_drop_managed_config(Link *link) {
|
||||||
int k, r;
|
int k, r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(link->manager);
|
assert(link->manager);
|
||||||
|
|
||||||
r = link_drop_routes(link);
|
r = link_drop_managed_routes(link);
|
||||||
|
|
||||||
k = link_drop_nexthops(link);
|
k = link_drop_managed_nexthops(link);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
k = link_drop_addresses(link);
|
k = link_drop_managed_addresses(link);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
k = link_drop_neighbors(link);
|
k = link_drop_managed_neighbors(link);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
k = link_drop_routing_policy_rules(link);
|
k = link_drop_managed_routing_policy_rules(link);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
ndisc_flush(link);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1119,6 +1095,10 @@ static int link_configure(Link *link) {
|
|||||||
|
|
||||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||||
|
|
||||||
|
r = link_new_bound_to_list(link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = link_configure_traffic_control(link);
|
r = link_configure_traffic_control(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1293,17 +1273,28 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
|||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
|
if (!IN_SET(link->state, LINK_STATE_INITIALIZED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED, LINK_STATE_UNMANAGED))
|
||||||
|
return 0;
|
||||||
|
|
||||||
r = link_get_network(link, &network);
|
r = link_get_network(link, &network);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (link->state != LINK_STATE_UNMANAGED && !network)
|
||||||
|
/* If link is in initialized state, then link->network is also NULL. */
|
||||||
|
force = true;
|
||||||
|
|
||||||
if (link->network == network && !force)
|
if (link->network == network && !force)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (network)
|
if (network) {
|
||||||
log_link_info(link, "Reconfiguring with %s.", network->filename);
|
if (link->state == LINK_STATE_INITIALIZED)
|
||||||
else
|
log_link_info(link, "Configuring with %s.", network->filename);
|
||||||
log_link_info(link, "Unmanaging interface.");
|
else
|
||||||
|
log_link_info(link, "Reconfiguring with %s.", network->filename);
|
||||||
|
} else
|
||||||
|
log_link_full(link, link->state == LINK_STATE_INITIALIZED ? LOG_DEBUG : LOG_INFO,
|
||||||
|
"Unmanaging interface.");
|
||||||
|
|
||||||
/* Dropping old .network file */
|
/* Dropping old .network file */
|
||||||
r = link_stop_engines(link, false);
|
r = link_stop_engines(link, false);
|
||||||
@ -1318,12 +1309,19 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
|||||||
* link_drop_foreign_config() in link_configure(). */
|
* link_drop_foreign_config() in link_configure(). */
|
||||||
link_foreignize_config(link);
|
link_foreignize_config(link);
|
||||||
else {
|
else {
|
||||||
r = link_drop_config(link);
|
/* Remove all managed configs. Note, foreign configs are removed in later by
|
||||||
|
* link_configure() -> link_drop_foreign_config() if the link is managed by us. */
|
||||||
|
r = link_drop_managed_config(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
link_free_carrier_maps(link);
|
/* The bound_to map depends on .network file, hence it needs to be freed. But, do not free the
|
||||||
|
* bound_by map. Otherwise, if a link enters unmanaged state below, then its carrier state will
|
||||||
|
* not propagated to other interfaces anymore. Moreover, it is not necessary to recreate the
|
||||||
|
* map here, as it depends on .network files assigned to other links. */
|
||||||
|
link_free_bound_to_list(link);
|
||||||
|
|
||||||
link_free_engines(link);
|
link_free_engines(link);
|
||||||
link->network = network_unref(link->network);
|
link->network = network_unref(link->network);
|
||||||
|
|
||||||
@ -1337,10 +1335,6 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
|||||||
link_update_operstate(link, true);
|
link_update_operstate(link, true);
|
||||||
link_dirty(link);
|
link_dirty(link);
|
||||||
|
|
||||||
r = link_new_carrier_maps(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
link_set_state(link, LINK_STATE_INITIALIZED);
|
link_set_state(link, LINK_STATE_INITIALIZED);
|
||||||
link->activated = false;
|
link->activated = false;
|
||||||
|
|
||||||
@ -1440,11 +1434,9 @@ int link_reconfigure_after_sleep(Link *link) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int link_initialized_and_synced(Link *link) {
|
static int link_initialized_and_synced(Link *link) {
|
||||||
Network *network;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(link->ifname);
|
|
||||||
assert(link->manager);
|
assert(link->manager);
|
||||||
|
|
||||||
if (link->manager->test_mode) {
|
if (link->manager->test_mode) {
|
||||||
@ -1453,7 +1445,7 @@ static int link_initialized_and_synced(Link *link) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We may get called either from the asynchronous netlink callback,
|
/* This may get called either from the asynchronous netlink callback,
|
||||||
* or directly from link_check_initialized() if running in a container. */
|
* or directly from link_check_initialized() if running in a container. */
|
||||||
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
|
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
|
||||||
return 0;
|
return 0;
|
||||||
@ -1469,36 +1461,7 @@ static int link_initialized_and_synced(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!link->network) {
|
return link_reconfigure_impl(link, /* force = */ false);
|
||||||
r = link_get_network(link, &network);
|
|
||||||
if (r == -ENOENT) {
|
|
||||||
link_set_state(link, LINK_STATE_UNMANAGED);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (link->flags & IFF_LOOPBACK) {
|
|
||||||
if (network->link_local != ADDRESS_FAMILY_NO)
|
|
||||||
log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link");
|
|
||||||
|
|
||||||
if (network->dhcp != ADDRESS_FAMILY_NO)
|
|
||||||
log_link_debug(link, "Ignoring DHCP clients for loopback link");
|
|
||||||
|
|
||||||
if (network->dhcp_server)
|
|
||||||
log_link_debug(link, "Ignoring DHCP server for loopback link");
|
|
||||||
}
|
|
||||||
|
|
||||||
link->network = network_ref(network);
|
|
||||||
link_update_operstate(link, false);
|
|
||||||
link_dirty(link);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = link_new_bound_to_list(link);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return link_configure(link);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
@ -1706,7 +1669,7 @@ static int link_carrier_lost_impl(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
ret = r;
|
ret = r;
|
||||||
|
|
||||||
r = link_drop_config(link);
|
r = link_drop_managed_config(link);
|
||||||
if (r < 0 && ret >= 0)
|
if (r < 0 && ret >= 0)
|
||||||
ret = r;
|
ret = r;
|
||||||
|
|
||||||
|
|||||||
@ -416,13 +416,17 @@ int link_drop_foreign_neighbors(Link *link) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_drop_neighbors(Link *link) {
|
int link_drop_managed_neighbors(Link *link) {
|
||||||
Neighbor *neighbor;
|
Neighbor *neighbor;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(neighbor, link->neighbors) {
|
SET_FOREACH(neighbor, link->neighbors) {
|
||||||
|
/* Do not touch nexthops managed by kernel or other tools. */
|
||||||
|
if (neighbor->source == NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Ignore neighbors not assigned yet or already removing. */
|
/* Ignore neighbors not assigned yet or already removing. */
|
||||||
if (!neighbor_exists(neighbor))
|
if (!neighbor_exists(neighbor))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -34,7 +34,7 @@ int neighbor_compare_func(const Neighbor *a, const Neighbor *b);
|
|||||||
|
|
||||||
void network_drop_invalid_neighbors(Network *network);
|
void network_drop_invalid_neighbors(Network *network);
|
||||||
|
|
||||||
int link_drop_neighbors(Link *link);
|
int link_drop_managed_neighbors(Link *link);
|
||||||
int link_drop_foreign_neighbors(Link *link);
|
int link_drop_foreign_neighbors(Link *link);
|
||||||
void link_foreignize_neighbors(Link *link);
|
void link_foreignize_neighbors(Link *link);
|
||||||
|
|
||||||
|
|||||||
@ -613,8 +613,8 @@ static void manager_mark_nexthops(Manager *manager, bool foreign, const Link *ex
|
|||||||
if (nexthop->protocol == RTPROT_KERNEL)
|
if (nexthop->protocol == RTPROT_KERNEL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* When 'foreign' is true, do not remove nexthops we configured. */
|
/* When 'foreign' is true, mark only foreign nexthops, and vice versa. */
|
||||||
if (foreign && nexthop->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
if (foreign != (nexthop->source == NETWORK_CONFIG_SOURCE_FOREIGN))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore nexthops not assigned yet or already removed. */
|
/* Ignore nexthops not assigned yet or already removed. */
|
||||||
@ -641,7 +641,7 @@ static void manager_mark_nexthops(Manager *manager, bool foreign, const Link *ex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int manager_drop_nexthops(Manager *manager) {
|
static int manager_drop_marked_nexthops(Manager *manager) {
|
||||||
NextHop *nexthop;
|
NextHop *nexthop;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
@ -704,14 +704,14 @@ int link_drop_foreign_nexthops(Link *link) {
|
|||||||
|
|
||||||
manager_mark_nexthops(link->manager, /* foreign = */ true, NULL);
|
manager_mark_nexthops(link->manager, /* foreign = */ true, NULL);
|
||||||
|
|
||||||
k = manager_drop_nexthops(link->manager);
|
k = manager_drop_marked_nexthops(link->manager);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_drop_nexthops(Link *link) {
|
int link_drop_managed_nexthops(Link *link) {
|
||||||
NextHop *nexthop;
|
NextHop *nexthop;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
@ -723,6 +723,10 @@ int link_drop_nexthops(Link *link) {
|
|||||||
if (nexthop->protocol == RTPROT_KERNEL)
|
if (nexthop->protocol == RTPROT_KERNEL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Do not touch addresses managed by kernel or other tools. */
|
||||||
|
if (nexthop->source == NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Ignore nexthops not assigned yet or already removing. */
|
/* Ignore nexthops not assigned yet or already removing. */
|
||||||
if (!nexthop_exists(nexthop))
|
if (!nexthop_exists(nexthop))
|
||||||
continue;
|
continue;
|
||||||
@ -734,7 +738,7 @@ int link_drop_nexthops(Link *link) {
|
|||||||
|
|
||||||
manager_mark_nexthops(link->manager, /* foreign = */ false, link);
|
manager_mark_nexthops(link->manager, /* foreign = */ false, link);
|
||||||
|
|
||||||
k = manager_drop_nexthops(link->manager);
|
k = manager_drop_marked_nexthops(link->manager);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ int nexthop_compare_func(const NextHop *a, const NextHop *b);
|
|||||||
|
|
||||||
void network_drop_invalid_nexthops(Network *network);
|
void network_drop_invalid_nexthops(Network *network);
|
||||||
|
|
||||||
int link_drop_nexthops(Link *link);
|
int link_drop_managed_nexthops(Link *link);
|
||||||
int link_drop_foreign_nexthops(Link *link);
|
int link_drop_foreign_nexthops(Link *link);
|
||||||
void link_foreignize_nexthops(Link *link);
|
void link_foreignize_nexthops(Link *link);
|
||||||
|
|
||||||
|
|||||||
@ -788,8 +788,8 @@ static void manager_mark_routes(Manager *manager, bool foreign, const Link *exce
|
|||||||
if (route->protocol == RTPROT_KERNEL)
|
if (route->protocol == RTPROT_KERNEL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* When 'foreign' is true, do not remove routes we configured. */
|
/* When 'foreign' is true, mark only foreign routes, and vice versa. */
|
||||||
if (foreign && route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
if (foreign != (route->source == NETWORK_CONFIG_SOURCE_FOREIGN))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
|
/* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
|
||||||
@ -834,7 +834,7 @@ static void manager_mark_routes(Manager *manager, bool foreign, const Link *exce
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int manager_drop_routes(Manager *manager) {
|
static int manager_drop_marked_routes(Manager *manager) {
|
||||||
Route *route;
|
Route *route;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
@ -955,14 +955,14 @@ int link_drop_foreign_routes(Link *link) {
|
|||||||
|
|
||||||
manager_mark_routes(link->manager, /* foreign = */ true, NULL);
|
manager_mark_routes(link->manager, /* foreign = */ true, NULL);
|
||||||
|
|
||||||
k = manager_drop_routes(link->manager);
|
k = manager_drop_marked_routes(link->manager);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_drop_routes(Link *link) {
|
int link_drop_managed_routes(Link *link) {
|
||||||
Route *route;
|
Route *route;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
@ -973,6 +973,10 @@ int link_drop_routes(Link *link) {
|
|||||||
if (route_by_kernel(route))
|
if (route_by_kernel(route))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Do not touch routes managed by kernel or other tools. */
|
||||||
|
if (route->source == NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!route_exists(route))
|
if (!route_exists(route))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -983,7 +987,7 @@ int link_drop_routes(Link *link) {
|
|||||||
|
|
||||||
manager_mark_routes(link->manager, /* foreign = */ false, link);
|
manager_mark_routes(link->manager, /* foreign = */ false, link);
|
||||||
|
|
||||||
k = manager_drop_routes(link->manager);
|
k = manager_drop_marked_routes(link->manager);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
|
|||||||
@ -82,7 +82,7 @@ int route_remove(Route *route);
|
|||||||
|
|
||||||
int route_get(Manager *manager, Link *link, const Route *in, Route **ret);
|
int route_get(Manager *manager, Link *link, const Route *in, Route **ret);
|
||||||
|
|
||||||
int link_drop_routes(Link *link);
|
int link_drop_managed_routes(Link *link);
|
||||||
int link_drop_foreign_routes(Link *link);
|
int link_drop_foreign_routes(Link *link);
|
||||||
void link_foreignize_routes(Link *link);
|
void link_foreignize_routes(Link *link);
|
||||||
|
|
||||||
|
|||||||
@ -653,8 +653,8 @@ static void manager_mark_routing_policy_rules(Manager *m, bool foreign, const Li
|
|||||||
if (rule->protocol == RTPROT_KERNEL)
|
if (rule->protocol == RTPROT_KERNEL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* When 'foreign' is true, do not remove rules we configured. */
|
/* When 'foreign' is true, mark only foreign rules, and vice versa. */
|
||||||
if (foreign && rule->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
if (foreign != (rule->source == NETWORK_CONFIG_SOURCE_FOREIGN))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore rules not assigned yet or already removing. */
|
/* Ignore rules not assigned yet or already removing. */
|
||||||
|
|||||||
@ -71,7 +71,7 @@ int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const L
|
|||||||
static inline int manager_drop_foreign_routing_policy_rules(Manager *m) {
|
static inline int manager_drop_foreign_routing_policy_rules(Manager *m) {
|
||||||
return manager_drop_routing_policy_rules_internal(m, true, NULL);
|
return manager_drop_routing_policy_rules_internal(m, true, NULL);
|
||||||
}
|
}
|
||||||
static inline int link_drop_routing_policy_rules(Link *link) {
|
static inline int link_drop_managed_routing_policy_rules(Link *link) {
|
||||||
assert(link);
|
assert(link);
|
||||||
return manager_drop_routing_policy_rules_internal(link->manager, false, link);
|
return manager_drop_routing_policy_rules_internal(link->manager, false, link);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,7 +110,7 @@ static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_link_debug(l, "link is confiured by networkd and online.");
|
log_link_debug(l, "link is configured by networkd and online.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -449,7 +449,16 @@ ExecCommandFlags exec_command_flags_from_string(const char *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
|
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
|
||||||
|
/* Refuse invalid fds, regardless if fexecve() use is enabled or not */
|
||||||
|
if (executable_fd < 0)
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
|
/* Block any attempts on exploiting Linux' liberal argv[] handling, i.e. CVE-2021-4034 and suchlike */
|
||||||
|
if (isempty(executable) || strv_isempty(argv))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
#if ENABLE_FEXECVE
|
#if ENABLE_FEXECVE
|
||||||
|
|
||||||
execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
|
execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
|
||||||
|
|
||||||
if (IN_SET(errno, ENOSYS, ENOENT) || ERRNO_IS_PRIVILEGE(errno))
|
if (IN_SET(errno, ENOSYS, ENOENT) || ERRNO_IS_PRIVILEGE(errno))
|
||||||
|
|||||||
@ -3893,7 +3893,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
|
|||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, 'NO-CARRIER')
|
self.assertRegex(output, 'NO-CARRIER')
|
||||||
self.assertNotRegex(output, '192.168.0.15/24')
|
self.assertNotRegex(output, '192.168.0.15/24')
|
||||||
self.assertNotRegex(output, '192.168.0.16/24')
|
self.assertRegex(output, '192.168.0.16/24') # foreign address is kept
|
||||||
|
|
||||||
print('### ip -6 route list table all dev bridge99')
|
print('### ip -6 route list table all dev bridge99')
|
||||||
output = check_output('ip -6 route list table all dev bridge99')
|
output = check_output('ip -6 route list table all dev bridge99')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user