Client ID validation rejects valid IPv6 CIDRs with an embedded dotted-decimal IPv4 address

Author: aschyolkinCreated Sep 16, 2026Updated Sep 17, 2026
LabelsbugPriority: P4

Version and test environment

master at aad2e15ffc403993f60c9c9cba2ef8dd85e18479. Source checkout; isolated frontend reproduction with Node.js 18.19.1. These results come from the actual source components/validators, not an end-to-end test against a running AdGuard Home installation. No production DHCP configuration was changed.

Summary

The persistent-client identifier validator rejects a valid IPv6 CIDR in mixed IPv6/IPv4 notation, but accepts the equivalent hexadecimal notation.

Steps to reproduce

  1. Open Settings → Client settings and add or edit a persistent client.
  2. Enter ::ffff:192.168.1.0/120 as an identifier.
  3. Validate the field.
  4. Replace it with the equivalent ::ffff:c0a8:100/120 and validate again.

Expected result

Both syntactically valid representations pass identifier validation.

Actual result and minimal reproduction

Calling the original validateClientId function, with translation calls returning their message keys:

javascript
validateClientId('::ffff:192.168.1.0/120');
// 'form_error_client_id_format'

validateClientId('::ffff:c0a8:100/120');
// undefined (accepted)

validateClientId('2001:db8::/64');
// undefined (accepted)

The frontend dependency ipaddr.js 1.9.1 successfully parses all three strings with parseCIDR.

Cause / possible fix

R_CIDR_IPV6 in constants.ts contains literal d characters in embedded IPv4 octet patterns, such as 2[0-4]d, 1dd, and [1-9]?d, rather than digit escapes. It also uses unescaped dots in those branches.

validateClientId relies on this regex. The backend identifier parser uses netip.ParsePrefix in Persistent.setID.

Correct the regex or use the existing address parser for CIDR validation, with regression coverage for mixed notation and invalid octets. This report concerns syntax validation; it does not claim to test runtime matching of IPv4-mapped client addresses.