DHCP IPv4 range subnet validation returns early because it reads gateway fields at the wrong nesting level

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

validateIpForGatewaySubnetMask checks allValues.gateway_ip and allValues.subnet_mask, but the form stores these values under allValues.v4. For the real form value shape, the validator returns undefined before checking subnet membership.

Steps to reproduce

  1. Set gateway 192.168.1.1 and mask 255.255.255.0 in DHCP IPv4 settings.
  2. Enter a range outside that subnet, such as 10.0.0.10010.0.0.200.
  3. Validate the range fields.

To isolate this from unrelated IPv6 form validation, use an interface without IPv6 addresses or an otherwise valid IPv6 section.

Expected result

The range fields show the existing subnet_error validation message before submission.

Actual result

The subnet validator accepts these fields. The backend does validate subnet membership, so this is a missing frontend validation, not a claim that the DHCP server accepts or leases addresses from the wrong subnet. Saving invalid values reaches the server-side rejection instead of the intended field error.

Minimal reproduction

Calling the original exported validator:

javascript
validateIpForGatewaySubnetMask('10.0.0.100', {
    v4: {
        gateway_ip: '192.168.1.1',
        subnet_mask: '255.255.255.0',
        range_start: '10.0.0.100',
        range_end: '10.0.0.200',
        lease_duration: 86400,
    },
});
// Actual: undefined (accepted)
// Expected: a translated subnet_error message

This was reproduced using the original validator, with translation calls returning their message keys.

Cause / possible fix

The early guard in validators.ts reads root-level fields, while the destructuring immediately below correctly reads allValues.v4.

Check allValues.v4.gateway_ip and allValues.v4.subnet_mask in the guard, and cover an out-of-subnet range using the real nested form shape. Both range inputs use this validator in FormDHCPv4.tsx.

Backend rejection is implemented in V4ServerConf.Validate.