mirror of
https://github.com/systemd/systemd
synced 2026-04-17 12:34:51 +02:00
Compare commits
No commits in common. "b0f83c2d82df97c67c3eecc1b18c2eded2d0cdf9" and "e5b90b30c2bb5eb37249655ec12f114d4e23db44" have entirely different histories.
b0f83c2d82
...
e5b90b30c2
@ -171,19 +171,11 @@
|
||||
<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>
|
||||
|
||||
<para><varname>KERNEL_INSTALL_LAYOUT=bls|other|...</varname> is set for the plugins to specify the installation layout.
|
||||
<para><varname>KERNEL_INSTALL_LAYOUT=bls|other|...</varname> specifies the installation layout.
|
||||
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,
|
||||
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>
|
||||
<varlistentry>
|
||||
<term>bls</term>
|
||||
|
||||
@ -121,19 +121,6 @@ int in_addr_is_localhost(int family, const union in_addr_union *u) {
|
||||
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) {
|
||||
return a->s6_addr32[0] == 0 &&
|
||||
a->s6_addr32[1] == 0 &&
|
||||
|
||||
@ -49,7 +49,6 @@ bool in6_addr_is_link_local_all_nodes(const struct in6_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_one(int family, const union in_addr_union *u);
|
||||
|
||||
bool in4_addr_is_local_multicast(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
|
||||
bpf_o_cmd = [
|
||||
bpftool,
|
||||
'gen',
|
||||
'object',
|
||||
'g',
|
||||
'o',
|
||||
'@OUTPUT@',
|
||||
'@INPUT@'
|
||||
]
|
||||
@ -85,7 +85,7 @@ endif
|
||||
|
||||
skel_h_cmd = [
|
||||
bpftool,
|
||||
'gen',
|
||||
'skeleton',
|
||||
'g',
|
||||
's',
|
||||
'@INPUT@'
|
||||
]
|
||||
|
||||
@ -4058,10 +4058,6 @@ static int exec_child(
|
||||
assert(params);
|
||||
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);
|
||||
|
||||
/* We reset exactly these signals, since they are the only ones we set to SIG_IGN in the main
|
||||
|
||||
@ -18,8 +18,6 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
COMMAND="$1"
|
||||
KERNEL_VERSION="$2"
|
||||
ENTRY_DIR_ABS="$3"
|
||||
@ -40,8 +38,6 @@ fi
|
||||
|
||||
case "$COMMAND" in
|
||||
remove)
|
||||
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
|
||||
echo "Removing $BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION*.conf"
|
||||
exec rm -f \
|
||||
"$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf" \
|
||||
"$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION+"*".conf"
|
||||
@ -82,33 +78,36 @@ else
|
||||
fi
|
||||
|
||||
if ! [ -d "$ENTRY_DIR_ABS" ]; then
|
||||
echo "Error: entry directory '$ENTRY_DIR_ABS' does not exist" >&2
|
||||
exit 1
|
||||
if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
|
||||
echo "+mkdir -v -p $ENTRY_DIR_ABS"
|
||||
mkdir -v -p "$ENTRY_DIR_ABS"
|
||||
else
|
||||
mkdir -p "$ENTRY_DIR_ABS"
|
||||
fi
|
||||
fi
|
||||
|
||||
install -g root -o root -m 0644 "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" || {
|
||||
echo "Error: could not copy '$KERNEL_IMAGE' to '$ENTRY_DIR_ABS/linux'." >&2
|
||||
echo "Could not copy '$KERNEL_IMAGE' to '$ENTRY_DIR_ABS/linux'." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
shift "$INITRD_OPTIONS_SHIFT"
|
||||
# All files listed as arguments, and staged files called "initrd*" are installed as initrds.
|
||||
for initrd in "$@" "${KERNEL_INSTALL_STAGING_AREA}"/initrd*; do
|
||||
for initrd; do
|
||||
[ -f "$initrd" ] || {
|
||||
echo "Error: initrd '$initrd' not a file." >&2
|
||||
echo "Initrd '$initrd' not a file." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
initrd_basename="${initrd##*/}"
|
||||
[ "$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" || {
|
||||
echo "Error: could not copy '$initrd' to '$ENTRY_DIR_ABS/$initrd_basename'." >&2
|
||||
echo "Could not copy '$initrd' to '$ENTRY_DIR_ABS/$initrd_basename'." >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
mkdir -p "${LOADER_ENTRY%/*}" || {
|
||||
echo "Error: could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2
|
||||
echo "Could not create loader entry directory '${LOADER_ENTRY%/*}'." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
@ -119,18 +118,14 @@ mkdir -p "${LOADER_ENTRY%/*}" || {
|
||||
echo "machine-id $MACHINE_ID"
|
||||
echo "options $BOOT_OPTIONS"
|
||||
echo "linux $ENTRY_DIR/linux"
|
||||
|
||||
have_initrd=
|
||||
for initrd in "${@}" "${KERNEL_INSTALL_STAGING_AREA}"/initrd*; do
|
||||
for initrd; do
|
||||
echo "initrd $ENTRY_DIR/${initrd##*/}"
|
||||
have_initrd=yes
|
||||
done
|
||||
|
||||
# Try "initrd", generated by dracut in its kernel-install hook, if no initrds were supplied
|
||||
[ -z "$have_initrd" ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && echo "initrd $ENTRY_DIR/initrd"
|
||||
[ $# -eq 0 ] && [ -f "$ENTRY_DIR_ABS/initrd" ] && echo "initrd $ENTRY_DIR/initrd"
|
||||
:
|
||||
} >"$LOADER_ENTRY" || {
|
||||
echo "Error: could not create loader entry '$LOADER_ENTRY'." >&2
|
||||
echo "Could not create loader entry '$LOADER_ENTRY'." >&2
|
||||
exit 1
|
||||
}
|
||||
exit 0
|
||||
|
||||
@ -8,4 +8,3 @@
|
||||
# See kernel-install(8) for details.
|
||||
|
||||
#layout=bls|other|...
|
||||
#initrd_generator=dracut|...
|
||||
|
||||
@ -73,16 +73,13 @@ else
|
||||
fi
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Error: not enough arguments" >&2
|
||||
echo "Not enough arguments" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KERNEL_VERSION="$1"
|
||||
shift
|
||||
|
||||
layout=
|
||||
initrd_generator=
|
||||
|
||||
if [ -r "/etc/kernel/install.conf" ]; then
|
||||
. /etc/kernel/install.conf
|
||||
elif [ -r "/usr/lib/kernel/install.conf" ]; then
|
||||
@ -126,22 +123,12 @@ if [ -z "$layout" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
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_BOOT_ROOT="$BOOT_ROOT"
|
||||
export KERNEL_INSTALL_LAYOUT="$layout"
|
||||
export KERNEL_INSTALL_INITRD_GENERATOR="$initrd_generator"
|
||||
export KERNEL_INSTALL_STAGING_AREA
|
||||
|
||||
[ "$layout" = "bls" ]
|
||||
MAKE_ENTRY_DIR_ABS=$?
|
||||
@ -160,12 +147,12 @@ IFS="
|
||||
case "$COMMAND" in
|
||||
add)
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Error: command 'add' requires a kernel image" >&2
|
||||
echo "Command 'add' requires a kernel image" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [ -f "$1" ]; then
|
||||
echo "Error: kernel image argument $1 not a file" >&2
|
||||
echo "Kernel image argument $1 not a file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -175,9 +162,9 @@ case "$COMMAND" in
|
||||
# to serve as the indication to use or to not use the BLS
|
||||
if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
|
||||
echo "+mkdir -v -p $ENTRY_DIR_ABS"
|
||||
mkdir -v -p "$ENTRY_DIR_ABS" || exit 1
|
||||
mkdir -v -p "$ENTRY_DIR_ABS"
|
||||
else
|
||||
mkdir -p "$ENTRY_DIR_ABS" || exit 1
|
||||
mkdir -p "$ENTRY_DIR_ABS"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -206,7 +193,7 @@ case "$COMMAND" in
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Error: unknown command '$COMMAND'" >&2
|
||||
echo "Unknown command '$COMMAND'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -17,42 +17,13 @@ ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) {
|
||||
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) {
|
||||
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
|
||||
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;
|
||||
uint8_t *client_id;
|
||||
DHCPLease *lease;
|
||||
|
||||
if (size < sizeof(DHCPMessage))
|
||||
return 0;
|
||||
@ -65,13 +36,24 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
assert_se(server->fd >= 0);
|
||||
assert_se(sd_dhcp_server_configure_pool(server, &address, 24, 0, 0) >= 0);
|
||||
|
||||
/* add leases to the pool to expose additional code paths */
|
||||
add_lease(server, &address, 2);
|
||||
add_lease(server, &address, 3);
|
||||
|
||||
/* add static leases */
|
||||
add_static_lease(server, 3);
|
||||
add_static_lease(server, 4);
|
||||
/* add a lease to the pool to expose additional code paths */
|
||||
client_id = malloc(2);
|
||||
assert_se(client_id);
|
||||
client_id[0] = 2;
|
||||
client_id[1] = 2;
|
||||
lease = new0(DHCPLease, 1);
|
||||
assert_se(lease);
|
||||
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);
|
||||
|
||||
|
||||
@ -30,10 +30,19 @@ static DHCPLease *dhcp_lease_free(DHCPLease *lease) {
|
||||
return NULL;
|
||||
|
||||
if (lease->server) {
|
||||
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);
|
||||
hashmap_remove_value(lease->server->static_leases_by_address, UINT32_TO_PTR(lease->address), lease);
|
||||
hashmap_remove_value(lease->server->static_leases_by_client_id, &lease->client_id, lease);
|
||||
DHCPLease *e;
|
||||
|
||||
e = hashmap_get(lease->server->bound_leases_by_client_id, &lease->client_id);
|
||||
if (e == 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);
|
||||
@ -125,7 +134,7 @@ int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) {
|
||||
|
||||
void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
|
||||
assert(id);
|
||||
assert(id->length > 0);
|
||||
assert(id->length);
|
||||
assert(id->data);
|
||||
|
||||
siphash24_compress(&id->length, sizeof(id->length), state);
|
||||
@ -135,10 +144,8 @@ void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
|
||||
int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
|
||||
int r;
|
||||
|
||||
assert(a->length > 0);
|
||||
assert(a->data);
|
||||
assert(b->length > 0);
|
||||
assert(b->data);
|
||||
assert(!a->length || a->data);
|
||||
assert(!b->length || b->data);
|
||||
|
||||
r = CMP(a->length, b->length);
|
||||
if (r != 0)
|
||||
@ -158,6 +165,8 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
|
||||
assert(server);
|
||||
|
||||
log_dhcp_server(server, "UNREF");
|
||||
|
||||
sd_dhcp_server_stop(server);
|
||||
|
||||
sd_event_unref(server->event);
|
||||
@ -271,13 +280,9 @@ sd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
|
||||
}
|
||||
|
||||
int sd_dhcp_server_stop(sd_dhcp_server *server) {
|
||||
bool running;
|
||||
|
||||
if (!server)
|
||||
return 0;
|
||||
|
||||
running = sd_dhcp_server_is_running(server);
|
||||
|
||||
server->receive_message = sd_event_source_disable_unref(server->receive_message);
|
||||
server->receive_broadcast = sd_event_source_disable_unref(server->receive_broadcast);
|
||||
|
||||
@ -285,7 +290,6 @@ int sd_dhcp_server_stop(sd_dhcp_server *server) {
|
||||
server->fd = safe_close(server->fd);
|
||||
server->fd_broadcast = safe_close(server->fd_broadcast);
|
||||
|
||||
if (running)
|
||||
log_dhcp_server(server, "STOPPED");
|
||||
|
||||
return 0;
|
||||
@ -307,7 +311,7 @@ static int dhcp_server_send_unicast_raw(
|
||||
|
||||
assert(server);
|
||||
assert(server->ifindex > 0);
|
||||
assert(server->address != 0);
|
||||
assert(server->address);
|
||||
assert(hlen > 0);
|
||||
assert(chaddr);
|
||||
assert(packet);
|
||||
@ -420,7 +424,7 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
|
||||
|
||||
assert(server);
|
||||
assert(req);
|
||||
assert(req->max_optlen > 0);
|
||||
assert(req->max_optlen);
|
||||
assert(req->message);
|
||||
assert(optoffset <= req->max_optlen);
|
||||
assert(packet);
|
||||
@ -468,12 +472,12 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
|
||||
client, because the client may not have a correct network address
|
||||
or subnet mask, and the client may not be answering ARP requests.
|
||||
*/
|
||||
if (req->message->giaddr != 0) {
|
||||
if (req->message->giaddr) {
|
||||
destination = req->message->giaddr;
|
||||
destination_port = DHCP_PORT_SERVER;
|
||||
if (type == DHCP_NAK)
|
||||
packet->dhcp.flags = htobe16(0x8000);
|
||||
} else if (req->message->ciaddr != 0 && type != DHCP_NAK)
|
||||
} else if (req->message->ciaddr && type != DHCP_NAK)
|
||||
destination = req->message->ciaddr;
|
||||
|
||||
bool l2_broadcast = requested_broadcast(req->message) || type == DHCP_NAK;
|
||||
@ -481,22 +485,17 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
|
||||
destination, destination_port, packet, optoffset, l2_broadcast);
|
||||
}
|
||||
|
||||
static int server_message_init(
|
||||
sd_dhcp_server *server,
|
||||
DHCPPacket **ret,
|
||||
uint8_t type,
|
||||
size_t *ret_optoffset,
|
||||
static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret,
|
||||
uint8_t type, size_t *_optoffset,
|
||||
DHCPRequest *req) {
|
||||
|
||||
_cleanup_free_ DHCPPacket *packet = NULL;
|
||||
size_t optoffset = 0;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(ret);
|
||||
assert(ret_optoffset);
|
||||
assert(_optoffset);
|
||||
assert(IN_SET(type, DHCP_OFFER, DHCP_ACK, DHCP_NAK));
|
||||
assert(req);
|
||||
|
||||
packet = malloc0(sizeof(DHCPPacket) + req->max_optlen);
|
||||
if (!packet)
|
||||
@ -512,7 +511,7 @@ static int server_message_init(
|
||||
packet->dhcp.flags = req->message->flags;
|
||||
packet->dhcp.giaddr = req->message->giaddr;
|
||||
|
||||
*ret_optoffset = optoffset;
|
||||
*_optoffset = optoffset;
|
||||
*ret = TAKE_PTR(packet);
|
||||
|
||||
return 0;
|
||||
@ -615,28 +614,16 @@ static int server_send_offer_or_ack(
|
||||
return dhcp_server_send_packet(server, req, packet, type, offset);
|
||||
}
|
||||
|
||||
static int server_send_nak_or_ignore(sd_dhcp_server *server, bool init_reboot, DHCPRequest *req) {
|
||||
static int server_send_nak(sd_dhcp_server *server, DHCPRequest *req) {
|
||||
_cleanup_free_ DHCPPacket *packet = NULL;
|
||||
size_t offset;
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_dhcp_server_errno(server, r, "Failed to create NAK message: %m");
|
||||
return r;
|
||||
|
||||
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;
|
||||
return dhcp_server_send_packet(server, req, packet, DHCP_NAK, offset);
|
||||
}
|
||||
|
||||
static int server_send_forcerenew(
|
||||
@ -791,20 +778,17 @@ static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMes
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool address_is_in_pool(sd_dhcp_server *server, be32_t address) {
|
||||
static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
|
||||
assert(server);
|
||||
|
||||
if (server->pool_size == 0)
|
||||
return false;
|
||||
if (!server->pool_size)
|
||||
return -EINVAL;
|
||||
|
||||
if (be32toh(address) < (be32toh(server->subnet) | server->pool_offset) ||
|
||||
be32toh(address) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
|
||||
return false;
|
||||
if (be32toh(requested_ip) < (be32toh(server->subnet) | server->pool_offset) ||
|
||||
be32toh(requested_ip) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size)))
|
||||
return -ERANGE;
|
||||
|
||||
if (hashmap_contains(server->static_leases_by_address, UINT32_TO_PTR(address)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return be32toh(requested_ip & ~server->netmask) - server->pool_offset;
|
||||
}
|
||||
|
||||
static int append_agent_information_option(sd_dhcp_server *server, DHCPMessage *message, size_t opt_length, size_t size) {
|
||||
@ -919,59 +903,6 @@ static int prepare_new_lease(
|
||||
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) {
|
||||
DHCPLease *lease;
|
||||
usec_t time_now;
|
||||
@ -1043,7 +974,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
|
||||
log_dhcp_server(server, "DISCOVER (0x%x)", be32toh(req->message->xid));
|
||||
|
||||
if (server->pool_size == 0)
|
||||
if (!server->pool_size)
|
||||
/* no pool allocated */
|
||||
return 0;
|
||||
|
||||
@ -1095,12 +1026,14 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
return 1;
|
||||
|
||||
case DHCP_REQUEST: {
|
||||
DHCPLease *existing_lease_by_address;
|
||||
be32_t address;
|
||||
bool init_reboot = false;
|
||||
int pool_offset;
|
||||
|
||||
/* see RFC 2131, section 4.3.2 */
|
||||
|
||||
if (req->server_id != 0) {
|
||||
if (req->server_id) {
|
||||
log_dhcp_server(server, "REQUEST (selecting) (0x%x)",
|
||||
be32toh(req->message->xid));
|
||||
|
||||
@ -1109,22 +1042,22 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
/* client did not pick us */
|
||||
return 0;
|
||||
|
||||
if (req->message->ciaddr != 0)
|
||||
if (req->message->ciaddr)
|
||||
/* this MUST be zero */
|
||||
return 0;
|
||||
|
||||
if (req->requested_ip == 0)
|
||||
if (!req->requested_ip)
|
||||
/* this must be filled in with the yiaddr
|
||||
from the chosen OFFER */
|
||||
return 0;
|
||||
|
||||
address = req->requested_ip;
|
||||
} else if (req->requested_ip != 0) {
|
||||
} else if (req->requested_ip) {
|
||||
log_dhcp_server(server, "REQUEST (init-reboot) (0x%x)",
|
||||
be32toh(req->message->xid));
|
||||
|
||||
/* INIT-REBOOT */
|
||||
if (req->message->ciaddr != 0)
|
||||
if (req->message->ciaddr)
|
||||
/* this MUST be zero */
|
||||
return 0;
|
||||
|
||||
@ -1136,7 +1069,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
be32toh(req->message->xid));
|
||||
|
||||
/* REBINDING / RENEWING */
|
||||
if (req->message->ciaddr == 0)
|
||||
if (!req->message->ciaddr)
|
||||
/* this MUST be filled in with clients IP address */
|
||||
return 0;
|
||||
|
||||
@ -1147,27 +1080,110 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
if (address == server->address)
|
||||
return 0;
|
||||
|
||||
if (static_lease) {
|
||||
/* Found a static lease for the client ID. */
|
||||
pool_offset = get_pool_offset(server, address);
|
||||
existing_lease_by_address = hashmap_get(server->bound_leases_by_address, UINT32_TO_PTR(address));
|
||||
|
||||
if (static_lease->address != address)
|
||||
/* The client requested an address which is different from the static lease. Refuse. */
|
||||
return server_send_nak_or_ignore(server, init_reboot, req);
|
||||
/* verify that the requested address is from the pool, and either
|
||||
owned by the current client or free */
|
||||
if (static_lease && static_lease->address == address) {
|
||||
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
|
||||
usec_t time_now, expiration;
|
||||
|
||||
return server_ack_request(server, req, existing_lease, address);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (address_is_in_pool(server, address)) {
|
||||
/* The requested address is in the pool. */
|
||||
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");
|
||||
|
||||
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);
|
||||
log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
|
||||
|
||||
return server_ack_request(server, req, existing_lease, address);
|
||||
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;
|
||||
}
|
||||
|
||||
return server_send_nak_or_ignore(server, init_reboot, req);
|
||||
break;
|
||||
}
|
||||
|
||||
case DHCP_RELEASE: {
|
||||
@ -1560,7 +1576,6 @@ int sd_dhcp_server_set_static_lease(
|
||||
|
||||
assert_return(server, -EINVAL);
|
||||
assert_return(client_id, -EINVAL);
|
||||
assert_return(client_id_size > 0, -EINVAL);
|
||||
assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
|
||||
|
||||
/* Static lease with an empty or omitted address is a valid entry,
|
||||
@ -1573,10 +1588,13 @@ int sd_dhcp_server_set_static_lease(
|
||||
.data = client_id,
|
||||
};
|
||||
|
||||
dhcp_lease_free(hashmap_get(server->static_leases_by_client_id, &c));
|
||||
dhcp_lease_free(hashmap_remove(server->static_leases_by_client_id, &c));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hashmap_contains(server->static_leases_by_address, UINT32_TO_PTR(address->s_addr)))
|
||||
return -EEXIST;
|
||||
|
||||
lease = new(DHCPLease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
@ -1584,13 +1602,13 @@ int sd_dhcp_server_set_static_lease(
|
||||
*lease = (DHCPLease) {
|
||||
.address = address->s_addr,
|
||||
.client_id.length = client_id_size,
|
||||
.gateway = 0,
|
||||
.expiration = 0,
|
||||
};
|
||||
lease->client_id.data = memdup(client_id, client_id_size);
|
||||
if (!lease->client_id.data)
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1598,6 +1616,7 @@ int sd_dhcp_server_set_static_lease(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
lease->server = server;
|
||||
TAKE_PTR(lease);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -20,9 +20,8 @@ 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);
|
||||
}
|
||||
|
||||
static int test_basic(bool bind_to_interface) {
|
||||
static int test_basic(sd_event *event, bool bind_to_interface) {
|
||||
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
struct in_addr address_lo = {
|
||||
.s_addr = htobe32(INADDR_LOOPBACK),
|
||||
};
|
||||
@ -31,10 +30,6 @@ static int test_basic(bool bind_to_interface) {
|
||||
};
|
||||
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 */
|
||||
assert_se(sd_dhcp_server_new(&server, 1) >= 0);
|
||||
assert_se(server);
|
||||
@ -63,7 +58,7 @@ static int test_basic(bool bind_to_interface) {
|
||||
|
||||
r = sd_dhcp_server_start(server);
|
||||
if (r == -EPERM)
|
||||
return r;
|
||||
return log_info_errno(r, "sd_dhcp_server_start failed: %m");
|
||||
assert_se(r >= 0);
|
||||
|
||||
assert_se(sd_dhcp_server_start(server) >= 0);
|
||||
@ -113,17 +108,9 @@ static void test_message_handler(void) {
|
||||
struct in_addr address_lo = {
|
||||
.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_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_start(server) >= 0);
|
||||
|
||||
@ -193,26 +180,6 @@ static void test_message_handler(void) {
|
||||
|
||||
test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 30);
|
||||
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]) {
|
||||
@ -235,8 +202,6 @@ static void test_client_id_hash(void) {
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
};
|
||||
|
||||
log_debug("/* %s */", __func__);
|
||||
|
||||
a.data = (uint8_t*)strdup("abcd");
|
||||
b.data = (uint8_t*)strdup("abcd");
|
||||
|
||||
@ -262,61 +227,24 @@ static void test_client_id_hash(void) {
|
||||
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[]) {
|
||||
_cleanup_(sd_event_unrefp) sd_event *e;
|
||||
int r;
|
||||
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
test_client_id_hash();
|
||||
test_static_lease();
|
||||
assert_se(sd_event_new(&e) >= 0);
|
||||
|
||||
r = test_basic(true);
|
||||
if (r < 0)
|
||||
return log_tests_skipped_errno(r, "cannot start dhcp server(bound to interface)");
|
||||
r = test_basic(e, true);
|
||||
if (r != 0)
|
||||
return log_tests_skipped("cannot start dhcp server(bound to interface)");
|
||||
|
||||
r = test_basic(false);
|
||||
if (r < 0)
|
||||
return log_tests_skipped_errno(r, "cannot start dhcp server(non-bound to interface)");
|
||||
r = test_basic(e, false);
|
||||
if (r != 0)
|
||||
return log_tests_skipped("cannot start dhcp server(non-bound to interface)");
|
||||
|
||||
test_message_handler();
|
||||
test_client_id_hash();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -854,10 +854,6 @@ int link_drop_foreign_addresses(Link *link) {
|
||||
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
||||
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. */
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
@ -895,21 +891,24 @@ int link_drop_foreign_addresses(Link *link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_drop_managed_addresses(Link *link) {
|
||||
int link_drop_addresses(Link *link) {
|
||||
Address *address;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
/* Do not touch addresses managed by kernel or other tools. */
|
||||
if (address->source == NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
/* Ignore addresses not assigned yet or already removing. */
|
||||
if (!address_exists(address))
|
||||
continue;
|
||||
|
||||
/* Do not drop IPv6LL addresses assigned by the kernel here. They will be dropped in
|
||||
* link_drop_ipv6ll_addresses() if IPv6LL addressing is disabled. */
|
||||
if (address->source == NETWORK_CONFIG_SOURCE_FOREIGN &&
|
||||
address->family == AF_INET6 &&
|
||||
in6_addr_is_link_local(&address->in_addr.in6))
|
||||
continue;
|
||||
|
||||
k = address_remove(address);
|
||||
if (k < 0 && r >= 0) {
|
||||
r = k;
|
||||
|
||||
@ -74,7 +74,7 @@ void address_set_broadcast(Address *a);
|
||||
|
||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(Address, address_free);
|
||||
|
||||
int link_drop_managed_addresses(Link *link);
|
||||
int link_drop_addresses(Link *link);
|
||||
int link_drop_foreign_addresses(Link *link);
|
||||
int link_drop_ipv6ll_addresses(Link *link);
|
||||
void link_foreignize_addresses(Link *link);
|
||||
|
||||
@ -430,8 +430,6 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
|
||||
|
||||
ndisc_flush(link);
|
||||
|
||||
k = sd_radv_stop(link->radv);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Advertisement: %m");
|
||||
@ -894,6 +892,24 @@ static int link_new_bound_to_list(Link *link) {
|
||||
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) {
|
||||
bool updated = false;
|
||||
Link *bound_to;
|
||||
@ -930,6 +946,13 @@ static void link_free_bound_by_list(Link *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) {
|
||||
Link *master;
|
||||
int r;
|
||||
@ -989,8 +1012,7 @@ static Link *link_drop(Link *link) {
|
||||
|
||||
link_drop_requests(link);
|
||||
|
||||
link_free_bound_to_list(link);
|
||||
link_free_bound_by_list(link);
|
||||
link_free_carrier_maps(link);
|
||||
|
||||
link_drop_from_master(link);
|
||||
|
||||
@ -1048,30 +1070,32 @@ static int link_drop_foreign_config(Link *link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int link_drop_managed_config(Link *link) {
|
||||
static int link_drop_config(Link *link) {
|
||||
int k, r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
r = link_drop_managed_routes(link);
|
||||
r = link_drop_routes(link);
|
||||
|
||||
k = link_drop_managed_nexthops(link);
|
||||
k = link_drop_nexthops(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = link_drop_managed_addresses(link);
|
||||
k = link_drop_addresses(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = link_drop_managed_neighbors(link);
|
||||
k = link_drop_neighbors(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
k = link_drop_managed_routing_policy_rules(link);
|
||||
k = link_drop_routing_policy_rules(link);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
ndisc_flush(link);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1095,10 +1119,6 @@ static int link_configure(Link *link) {
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1273,28 +1293,17 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
||||
|
||||
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);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
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)
|
||||
return 0;
|
||||
|
||||
if (network) {
|
||||
if (link->state == LINK_STATE_INITIALIZED)
|
||||
log_link_info(link, "Configuring with %s.", network->filename);
|
||||
else
|
||||
if (network)
|
||||
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.");
|
||||
else
|
||||
log_link_info(link, "Unmanaging interface.");
|
||||
|
||||
/* Dropping old .network file */
|
||||
r = link_stop_engines(link, false);
|
||||
@ -1309,19 +1318,12 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
||||
* link_drop_foreign_config() in link_configure(). */
|
||||
link_foreignize_config(link);
|
||||
else {
|
||||
/* 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);
|
||||
r = link_drop_config(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* 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_carrier_maps(link);
|
||||
link_free_engines(link);
|
||||
link->network = network_unref(link->network);
|
||||
|
||||
@ -1335,6 +1337,10 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
||||
link_update_operstate(link, true);
|
||||
link_dirty(link);
|
||||
|
||||
r = link_new_carrier_maps(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
link_set_state(link, LINK_STATE_INITIALIZED);
|
||||
link->activated = false;
|
||||
|
||||
@ -1434,9 +1440,11 @@ int link_reconfigure_after_sleep(Link *link) {
|
||||
}
|
||||
|
||||
static int link_initialized_and_synced(Link *link) {
|
||||
Network *network;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->ifname);
|
||||
assert(link->manager);
|
||||
|
||||
if (link->manager->test_mode) {
|
||||
@ -1445,7 +1453,7 @@ static int link_initialized_and_synced(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This may get called either from the asynchronous netlink callback,
|
||||
/* We may get called either from the asynchronous netlink callback,
|
||||
* or directly from link_check_initialized() if running in a container. */
|
||||
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
|
||||
return 0;
|
||||
@ -1461,7 +1469,36 @@ static int link_initialized_and_synced(Link *link) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return link_reconfigure_impl(link, /* force = */ false);
|
||||
if (!link->network) {
|
||||
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) {
|
||||
@ -1669,7 +1706,7 @@ static int link_carrier_lost_impl(Link *link) {
|
||||
if (r < 0)
|
||||
ret = r;
|
||||
|
||||
r = link_drop_managed_config(link);
|
||||
r = link_drop_config(link);
|
||||
if (r < 0 && ret >= 0)
|
||||
ret = r;
|
||||
|
||||
|
||||
@ -416,17 +416,13 @@ int link_drop_foreign_neighbors(Link *link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_drop_managed_neighbors(Link *link) {
|
||||
int link_drop_neighbors(Link *link) {
|
||||
Neighbor *neighbor;
|
||||
int k, r = 0;
|
||||
|
||||
assert(link);
|
||||
|
||||
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. */
|
||||
if (!neighbor_exists(neighbor))
|
||||
continue;
|
||||
|
||||
@ -34,7 +34,7 @@ int neighbor_compare_func(const Neighbor *a, const Neighbor *b);
|
||||
|
||||
void network_drop_invalid_neighbors(Network *network);
|
||||
|
||||
int link_drop_managed_neighbors(Link *link);
|
||||
int link_drop_neighbors(Link *link);
|
||||
int link_drop_foreign_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)
|
||||
continue;
|
||||
|
||||
/* When 'foreign' is true, mark only foreign nexthops, and vice versa. */
|
||||
if (foreign != (nexthop->source == NETWORK_CONFIG_SOURCE_FOREIGN))
|
||||
/* When 'foreign' is true, do not remove nexthops we configured. */
|
||||
if (foreign && nexthop->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
/* 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_marked_nexthops(Manager *manager) {
|
||||
static int manager_drop_nexthops(Manager *manager) {
|
||||
NextHop *nexthop;
|
||||
int k, r = 0;
|
||||
|
||||
@ -704,14 +704,14 @@ int link_drop_foreign_nexthops(Link *link) {
|
||||
|
||||
manager_mark_nexthops(link->manager, /* foreign = */ true, NULL);
|
||||
|
||||
k = manager_drop_marked_nexthops(link->manager);
|
||||
k = manager_drop_nexthops(link->manager);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_drop_managed_nexthops(Link *link) {
|
||||
int link_drop_nexthops(Link *link) {
|
||||
NextHop *nexthop;
|
||||
int k, r = 0;
|
||||
|
||||
@ -723,10 +723,6 @@ int link_drop_managed_nexthops(Link *link) {
|
||||
if (nexthop->protocol == RTPROT_KERNEL)
|
||||
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. */
|
||||
if (!nexthop_exists(nexthop))
|
||||
continue;
|
||||
@ -738,7 +734,7 @@ int link_drop_managed_nexthops(Link *link) {
|
||||
|
||||
manager_mark_nexthops(link->manager, /* foreign = */ false, link);
|
||||
|
||||
k = manager_drop_marked_nexthops(link->manager);
|
||||
k = manager_drop_nexthops(link->manager);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ int nexthop_compare_func(const NextHop *a, const NextHop *b);
|
||||
|
||||
void network_drop_invalid_nexthops(Network *network);
|
||||
|
||||
int link_drop_managed_nexthops(Link *link);
|
||||
int link_drop_nexthops(Link *link);
|
||||
int link_drop_foreign_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)
|
||||
continue;
|
||||
|
||||
/* When 'foreign' is true, mark only foreign routes, and vice versa. */
|
||||
if (foreign != (route->source == NETWORK_CONFIG_SOURCE_FOREIGN))
|
||||
/* When 'foreign' is true, do not remove routes we configured. */
|
||||
if (foreign && route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
/* 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_marked_routes(Manager *manager) {
|
||||
static int manager_drop_routes(Manager *manager) {
|
||||
Route *route;
|
||||
int k, r = 0;
|
||||
|
||||
@ -955,14 +955,14 @@ int link_drop_foreign_routes(Link *link) {
|
||||
|
||||
manager_mark_routes(link->manager, /* foreign = */ true, NULL);
|
||||
|
||||
k = manager_drop_marked_routes(link->manager);
|
||||
k = manager_drop_routes(link->manager);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int link_drop_managed_routes(Link *link) {
|
||||
int link_drop_routes(Link *link) {
|
||||
Route *route;
|
||||
int k, r = 0;
|
||||
|
||||
@ -973,10 +973,6 @@ int link_drop_managed_routes(Link *link) {
|
||||
if (route_by_kernel(route))
|
||||
continue;
|
||||
|
||||
/* Do not touch routes managed by kernel or other tools. */
|
||||
if (route->source == NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
if (!route_exists(route))
|
||||
continue;
|
||||
|
||||
@ -987,7 +983,7 @@ int link_drop_managed_routes(Link *link) {
|
||||
|
||||
manager_mark_routes(link->manager, /* foreign = */ false, link);
|
||||
|
||||
k = manager_drop_marked_routes(link->manager);
|
||||
k = manager_drop_routes(link->manager);
|
||||
if (k < 0 && r >= 0)
|
||||
r = k;
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ int route_remove(Route *route);
|
||||
|
||||
int route_get(Manager *manager, Link *link, const Route *in, Route **ret);
|
||||
|
||||
int link_drop_managed_routes(Link *link);
|
||||
int link_drop_routes(Link *link);
|
||||
int link_drop_foreign_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)
|
||||
continue;
|
||||
|
||||
/* When 'foreign' is true, mark only foreign rules, and vice versa. */
|
||||
if (foreign != (rule->source == NETWORK_CONFIG_SOURCE_FOREIGN))
|
||||
/* When 'foreign' is true, do not remove rules we configured. */
|
||||
if (foreign && rule->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
||||
continue;
|
||||
|
||||
/* 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) {
|
||||
return manager_drop_routing_policy_rules_internal(m, true, NULL);
|
||||
}
|
||||
static inline int link_drop_managed_routing_policy_rules(Link *link) {
|
||||
static inline int link_drop_routing_policy_rules(Link *link) {
|
||||
assert(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 configured by networkd and online.");
|
||||
log_link_debug(l, "link is confiured by networkd and online.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@ -449,16 +449,7 @@ 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[]) {
|
||||
/* 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
|
||||
|
||||
execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
|
||||
|
||||
if (IN_SET(errno, ENOSYS, ENOENT) || ERRNO_IS_PRIVILEGE(errno))
|
||||
|
||||
@ -3893,7 +3893,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
|
||||
print(output)
|
||||
self.assertRegex(output, 'NO-CARRIER')
|
||||
self.assertNotRegex(output, '192.168.0.15/24')
|
||||
self.assertRegex(output, '192.168.0.16/24') # foreign address is kept
|
||||
self.assertNotRegex(output, '192.168.0.16/24')
|
||||
|
||||
print('### 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