From: Philippe SCARSELLI <p27m@orange.fr>
To: development@lists.ipfire.org
Cc: Philippe SCARSELLI <p27m@orange.fr>
Subject: [PATCH] dhcp: convert dhcpd.conf from CU202 to CU203 format
Date: Sat, 17 Oct 2026 17:11:03 +0200 [thread overview]
Message-ID: <20261017151103.1218-1-p27m@orange.fr> (raw)
Related to bug Bug 14320 - DHCP configuration is not correctly migrated from CU202 to CU203 and more.
here is a proposed fix
This patch enables the automatic migration of the `/var/ipfire/dhcp/dhcpd.conf` file during an upgrade from CU202 to CU203, as well as when restoring a backup from CU202 or earlier onto a CU203 system.
This ensures compliance with the `on commit`, `on release`, and `on expiry` commands required for local DNS management by `knot-resolver`.
This patch was created on the core203 branch to regenerate the core-upgrade-2.29-203.ipfire package and the test CU203 ISO file.
I am not familiar with the integration method for subsequent versions, but it will be useful for backup/restore operations when moving from versions prior to CU203 to CU203 or later.
Tested on x86_64 platform (VMware).
Upgrade from CU202 to CU203 tested.
Restore test of a CU202 backup file onto a fresh CU203 installation on an x86_64 test platform (VMware).
- The /var/ipfire/dhcp/dhcpd.conf file is in the expected format.
- DNS management for DHCP leases is functioning correctly.
Signed-off-by: Philippe SCARSELLI <p27m@orange.fr>
---
config/backup/backup.pl | 4 +
config/rootfiles/common/aarch64/stage2 | 1 +
config/rootfiles/common/riscv64/stage2 | 1 +
config/rootfiles/common/x86_64/stage2 | 1 +
config/rootfiles/core/203/filelists/files | 1 +
config/rootfiles/core/203/update.sh | 4 +-
src/scripts/convert-dhcp-conf | 165 ++++++++++++++++++++++
7 files changed, 174 insertions(+), 3 deletions(-)
create mode 100644 src/scripts/convert-dhcp-conf
diff --git a/config/backup/backup.pl b/config/backup/backup.pl
index f948c4d21..7ac385ad9 100644
--- a/config/backup/backup.pl
+++ b/config/backup/backup.pl
@@ -213,6 +213,10 @@ restore_backup() {
# Convert DNS settings
convert-dns-settings
+ # Convert DHCP conf
+ convert-dhcp-conf
+ /etc/init.d/dhcp restart
+
# move nobeeps if exist
[ -e "/var/ipfire/ppp/nobeeps" ] && mv /var/ipfire/ppp/nobeeps /var/ipfire/red/nobeeps
diff --git a/config/rootfiles/common/aarch64/stage2 b/config/rootfiles/common/aarch64/stage2
index 4b79d96f6..a02c91c1d 100644
--- a/config/rootfiles/common/aarch64/stage2
+++ b/config/rootfiles/common/aarch64/stage2
@@ -92,6 +92,7 @@ usr/local/bin/backupiso
usr/local/bin/connscheduler
usr/local/bin/consort.sh
usr/local/bin/convert-dns-settings
+usr/local/bin/convert-dhcp-conf
usr/local/bin/convert-to-location
usr/local/bin/filesystem-cleanup
usr/local/bin/hddshutdown
diff --git a/config/rootfiles/common/riscv64/stage2 b/config/rootfiles/common/riscv64/stage2
index 9c3621f62..2d27af818 100644
--- a/config/rootfiles/common/riscv64/stage2
+++ b/config/rootfiles/common/riscv64/stage2
@@ -93,6 +93,7 @@ usr/local/bin/backupiso
usr/local/bin/connscheduler
usr/local/bin/consort.sh
usr/local/bin/convert-dns-settings
+usr/local/bin/convert-dhcp-conf
usr/local/bin/convert-to-location
usr/local/bin/filesystem-cleanup
usr/local/bin/hddshutdown
diff --git a/config/rootfiles/common/x86_64/stage2 b/config/rootfiles/common/x86_64/stage2
index e50df0494..b35aa15d0 100644
--- a/config/rootfiles/common/x86_64/stage2
+++ b/config/rootfiles/common/x86_64/stage2
@@ -92,6 +92,7 @@ usr/local/bin/backupiso
usr/local/bin/connscheduler
usr/local/bin/consort.sh
usr/local/bin/convert-dns-settings
+usr/local/bin/convert-dhcp-conf
usr/local/bin/convert-to-location
usr/local/bin/filesystem-cleanup
usr/local/bin/hddshutdown
diff --git a/config/rootfiles/core/203/filelists/files b/config/rootfiles/core/203/filelists/files
index dd3435411..56dbf818f 100644
--- a/config/rootfiles/core/203/filelists/files
+++ b/config/rootfiles/core/203/filelists/files
@@ -16,6 +16,7 @@ etc/rc.d/rc0.d/K86knot-resolver
etc/rc.d/rc3.d/S11knot-resolver
etc/rc.d/rc3.d/S17waitfordns
etc/rc.d/rc6.d/K86knot-resolver
+usr/local/bin/convert-dhcp-conf
usr/local/bin/settime
usr/local/bin/update-rpzs
usr/local/bin/waitfordns
diff --git a/config/rootfiles/core/203/update.sh b/config/rootfiles/core/203/update.sh
index 5b314664f..7447bef98 100644
--- a/config/rootfiles/core/203/update.sh
+++ b/config/rootfiles/core/203/update.sh
@@ -135,9 +135,7 @@ fi
# Migrate DHCP configuration
if [ -e "/var/ipfire/dhcp/dhcpd.conf" ]; then
- sed -e "s/unbound-dhcp-leases-client/dhcp-lease/g" \
- -i /var/ipfire/dhcp/dhcpd.conf
-
+ /usr/local/bin/convert-dhcp-conf
# Restart DHCP
/etc/init.d/dhcp restart
fi
diff --git a/src/scripts/convert-dhcp-conf b/src/scripts/convert-dhcp-conf
new file mode 100644
index 000000000..6215f8315
--- /dev/null
+++ b/src/scripts/convert-dhcp-conf
@@ -0,0 +1,165 @@
+#!/bin/bash
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2007-2026 IPFire Team <info@ipfire.org> #
+# #
+# This program is free software: you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation, either version 3 of the License, or #
+# (at your option) any later version. #
+# #
+# This program is distributed in the hope that it will be useful, #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
+# GNU General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+#
+# Convert the DHCP configuration from version 202 to version 203.
+#
+# Replace the block from "on commit {" through the closing brace
+# of the "on expiry" block with the version 203 configuration.
+#
+# If DOMAINNAME= is already present, the configuration is
+# considered to be in the new format and no changes are made.
+#
+# All other content in dhcpd.conf must remain unchanged.
+#
+
+set -euo pipefail
+
+DHCP_DIR="/var/ipfire/dhcp"
+TARGET="${DHCP_DIR}/dhcpd.conf"
+
+# Check that the script is running as root.
+if [[ $EUID -ne 0 ]]; then
+ echo "Error: This script must be run as root." >&2
+ exit 1
+fi
+
+# Check that the target configuration file exists.
+if [[ ! -f "$TARGET" ]]; then
+ echo "Error: DHCP configuration file not found: $TARGET" >&2
+ exit 1
+fi
+
+# Skip conversion if the configuration is already in the new format.
+if grep -q 'DOMAINNAME=' "$TARGET"; then
+ echo "DHCP configuration already uses the new format. No changes required."
+ exit 0
+fi
+
+# Define the version 203 hooks.
+read -r -d '' NEW_BLOCK <<'EOF' || true
+on commit {
+ set ClientAddress = concat(
+ "ADDRESS=",
+ binary-to-ascii(10, 8, ".", leased-address)
+ );
+ set ClientHostName = concat(
+ "HOSTNAME=",
+ pick-first-value(option host-name, config-option-host-name, client-name, "")
+ );
+ set ClientDomainName = concat(
+ "DOMAINNAME=",
+ pick-first-value(config-option domain-name, "")
+ );
+
+ if (ClientHostName != "") {
+ execute("/usr/sbin/dhcp-lease", "commit", ClientAddress, ClientHostName, ClientDomainName);
+ }
+}
+
+on release {
+ set ClientAddress = concat(
+ "ADDRESS=",
+ binary-to-ascii(10, 8, ".", leased-address)
+ );
+ set ClientHostName = concat(
+ "HOSTNAME=",
+ pick-first-value(option host-name, config-option-host-name, client-name, "")
+ );
+ set ClientDomainName = concat(
+ "DOMAINNAME=",
+ pick-first-value(config-option domain-name, "")
+ );
+
+ if (ClientHostName != "") {
+ execute("/usr/sbin/dhcp-lease", "release", ClientAddress, ClientHostName, ClientDomainName);
+ }
+}
+
+on expiry {
+ set ClientAddress = concat(
+ "ADDRESS=",
+ binary-to-ascii(10, 8, ".", leased-address)
+ );
+
+ execute("/usr/sbin/dhcp-lease", "expiry", ClientAddress);
+}
+EOF
+
+# Ensure the expected hooks exist in the original configuration.
+if ! grep -q '^on commit[[:space:]]*{' "$TARGET" ||
+ ! grep -q '^on expiry[[:space:]]*{' "$TARGET"; then
+ echo "Error: Expected DHCP hooks were not found in $TARGET." >&2
+ exit 1
+fi
+
+# Create a temporary file in the same directory.
+TMP=$(mktemp "${DHCP_DIR}/dhcpd.conf.XXXXXX")
+trap 'rm -f "$TMP"' EXIT
+
+# Replace only the block from "on commit" to the end of "on expiry".
+awk -v replacement="$NEW_BLOCK" '
+ /^on commit[[:space:]]*\{/ && !done {
+ print replacement
+ done = 1
+ skipping = 1
+ next
+ }
+
+ skipping && /^on expiry[[:space:]]*\{/ {
+ expiry = 1
+ next
+ }
+
+ skipping && expiry && /^}/ {
+ skipping = 0
+ expiry = 0
+ next
+ }
+
+ !skipping {
+ print
+ }
+
+ END {
+ if (!done || skipping) {
+ exit 1
+ }
+ }
+' "$TARGET" > "$TMP" || {
+ echo "Error: Failed to replace the DHCP hooks." >&2
+ exit 1
+}
+
+# Validate the configuration before installing it.
+if ! dhcpd -t -cf "$TMP"; then
+ echo "Error: Invalid DHCP configuration. The original file is unchanged." >&2
+ exit 1
+fi
+
+# Preserve the original permissions and ownership.
+chmod --reference="$TARGET" "$TMP"
+chown --reference="$TARGET" "$TMP"
+
+# Install the updated configuration.
+mv "$TMP" "$TARGET"
+trap - EXIT
+
+echo "DHCP configuration successfully updated to version 203."
--
2.47.3
reply other threads:[~2026-10-17 15:11 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261017151103.1218-1-p27m@orange.fr \
--to=p27m@orange.fr \
--cc=development@lists.ipfire.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox