scripts: dhcp/dhcpv6: handling of invalid client ID values

Verify and clean up client ID and global DUID config values before use, in
order to prevent DHCP client malfunction and loss of IPv4 and/or IPv6
connectivity.

- Accept common separators in the string (colon, dash, spaces/tabs, lf)
- Ignore invalid values (non-hex or odd-numbered length)
- Log a warning for invalid settings

The fall back mechanism is as follows:

If a (user-configured) network.<ifname>.clientid setting is found invalid,
ignore and fall back to using network.globals.dhcp_default_duid. In case
that's also invalid (e.g. has been tampered with), don't pass a client
ID to updhc/odhcpc. In that case, udhcpc/odhcpc will use their defaults,
which currently is the i/f MAC address resp. the i/f DUID-LL.

Only error handling is introduced, no behavior change for valid settings.

Signed-off-by: Shine <4c.fce2@proton.me>
Link: https://github.com/openwrt/openwrt/pull/23662
Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
Shine
2026-05-31 15:16:09 +02:00
committed by Robert Marko
parent cbd8fe4461
commit 9ba54d2d9e
3 changed files with 27 additions and 3 deletions
@@ -16,6 +16,13 @@ NO_EXPORT=1
LOAD_STATE=1
LIST_SEP=" "
# check for valid hexdump and strip common separators and leading/trailing blanks
# input can be single- or multi-line, separators can be none, dash, colon or one or more spaces/tabs
hexdump_2hex() {
[ -z "$1" ] && return
echo -n "$1" | tr '\nA-F' ' a-f' | sed -nr '/^\s*[0-9a-f]{2}((\s+|[:-]?)[0-9a-f]{2})*\s*$/s/[[:space:]:-]*//pg'
}
# xor multiple hex values of the same length
xor() {
local val
@@ -40,9 +40,14 @@ proto_dhcp_get_default_clientid() {
local duid
local iaid
network_generate_iface_iaid iaid "$iface"
duid="$(uci_get network @globals[0] dhcp_default_duid)"
[ -n "$duid" ] && printf "ff%s%s" "$iaid" "$duid"
[ -n "$duid" ] && {
duid="$(hexdump_2hex "$duid")"
[ -z "$duid" ] && logger -p warn -t dhcp "$iface: ignoring invalid dhcp_default_duid value"
}
[ -z "$duid" ] && return
network_generate_iface_iaid iaid "$iface"
printf "ff%s%s" "$iaid" "$duid"
}
proto_dhcp_setup() {
@@ -65,8 +70,12 @@ proto_dhcp_setup() {
[ "$defaultreqopts" = 0 ] && defaultreqopts="-o" || defaultreqopts=
[ "$broadcast" = 1 ] && broadcast="-B" || broadcast=
[ "$norelease" = 1 ] && norelease="" || norelease="-R"
[ -n "$clientid" ] && {
clientid="$(hexdump_2hex "$clientid")"
[ -z "$clientid" ] && logger -p warn -t dhcp "$iface: ignoring invalid clientid value"
}
[ -z "$clientid" ] && clientid="$(proto_dhcp_get_default_clientid "$iface")"
[ -n "$clientid" ] && clientid="-x 0x3d:${clientid//:/}"
[ -n "$clientid" ] && clientid="-x 0x3d:$clientid"
[ -n "$vendorid" ] && append dhcpopts "-x 0x3c:$(echo -n "$vendorid" | hexdump -ve '1/1 "%02x"')"
[ -n "$iface6rd" ] && proto_export "IFACE6RD=$iface6rd"
[ "$iface6rd" != 0 -a -f /lib/netifd/proto/6rd.sh ] && append dhcpopts "-O 212"
@@ -87,7 +87,15 @@ proto_dhcpv6_setup() {
[ -z "$reqprefix" -o "$reqprefix" = "auto" ] && reqprefix=0
[ "$reqprefix" != "no" ] && append opts "-P$reqprefix"
[ -n "$clientid" ] && {
clientid="$(hexdump_2hex "$clientid")"
[ -z "$clientid" ] && logger -p warn -t dhcpv6 "$iface: ignoring invalid clientid value"
}
[ -z "$clientid" ] && clientid="$(uci_get network @globals[0] dhcp_default_duid)"
[ -n "$clientid" ] && {
clientid="$(hexdump_2hex "$clientid")"
[ -z "$clientid" ] && logger -p warn -t dhcpv6 "$iface: ignoring invalid dhcp_default_duid value"
}
[ -n "$clientid" ] && append opts "-c$clientid"
[ "$defaultreqopts" = "0" ] && append opts "-R"