TechnitiumSoftware/DnsServer · error · ArgumentException

Ending address must be greater than starting address.

Error message

Ending address must be greater than starting address.

What it means

Thrown by the DHCP Scope constructor (which delegates to ChangeNetwork) and by ChangeNetwork directly when the ending IPv4 address is not strictly greater than the starting address after both are converted to 32-bit unsigned integers. It prevents creation of a degenerate or empty address pool where no host address could ever be handed out.

Source

Thrown at DnsServerCore/Dhcp/Scope.cs:1447

        #region public

        public void ChangeNetwork(IPAddress startingAddress, IPAddress endingAddress, IPAddress subnetMask)
        {
            if (startingAddress.AddressFamily != AddressFamily.InterNetwork)
                throw new ArgumentException("The address must be an IPv4 address: " + startingAddress.ToString(), nameof(startingAddress));

            if (endingAddress.AddressFamily != AddressFamily.InterNetwork)
                throw new ArgumentException("The address must be an IPv4 address: " + endingAddress.ToString(), nameof(endingAddress));

            if (subnetMask.AddressFamily != AddressFamily.InterNetwork)
                throw new ArgumentException("The address must be an IPv4 address: " + subnetMask.ToString(), nameof(subnetMask));

            uint startingAddressNumber = startingAddress.ConvertIpToNumber();
            uint endingAddressNumber = endingAddress.ConvertIpToNumber();

            if (startingAddressNumber >= endingAddressNumber)
                throw new ArgumentException("Ending address must be greater than starting address.");

            _startingAddress = startingAddress;
            _endingAddress = endingAddress;
            _subnetMask = subnetMask;

            //compute other parameters
            uint subnetMaskNumber = _subnetMask.ConvertIpToNumber();
            uint networkAddressNumber = startingAddressNumber & subnetMaskNumber;
            uint broadcastAddressNumber = networkAddressNumber | ~subnetMaskNumber;

            if (networkAddressNumber == startingAddressNumber)
                throw new ArgumentException("Starting address cannot be same as the network address.");

            if (broadcastAddressNumber == endingAddressNumber)
                throw new ArgumentException("Ending address cannot be same as the broadcast address.");

            _networkAddress = IPAddressExtensions.ConvertNumberToIp(networkAddressNumber);
            _broadcastAddress = IPAddressExtensions.ConvertNumberToIp(broadcastAddressNumber);

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Sort or compare the two addresses numerically before constructing the Scope so endingAddress is strictly greater than startingAddress.
  2. Re-check the argument order in the call site; startingAddress is the third positional parameter and endingAddress the fourth.
  3. If deriving the range from a CIDR, compute start = network+1 and end = broadcast-1 rather than reusing the network address as a bound.
  4. Confirm byte order: IPAddress.GetAddressBytes() is network order; convert with BitConverter in big-endian (or reverse) to compare as the library does.

Example fix

// before
var scope = new Scope(name, true,
    IPAddress.Parse("192.168.1.50"),  // start
    IPAddress.Parse("192.168.1.10"),  // end <= start -> throws
    IPAddress.Parse("255.255.255.0"), log, dhcpServer);

// after
var start = IPAddress.Parse("192.168.1.10");
var end   = IPAddress.Parse("192.168.1.50");
if (ToUint(end) <= ToUint(start)) throw new InvalidOperationException("bad range");
var scope = new Scope(name, true, start, end,
    IPAddress.Parse("255.255.255.0"), log, dhcpServer);

static uint ToUint(IPAddress a){ var b=a.GetAddressBytes(); return (uint)(b[0]<<24|b[1]<<16|b[2]<<8|b[3]); }
Defensive patterns

Strategy: validation

Validate before calling

static uint ToUint(IPAddress a){ var b=a.GetAddressBytes(); return (uint)((b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3]); }

static bool IsValidRange(IPAddress start, IPAddress end){
    return ToUint(end) > ToUint(start);
}

// before constructing the Scope:
if (!IsValidRange(startingAddress, endingAddress))
    throw new ConfigurationException("endingAddress must be greater than startingAddress");

Type guard

static bool IsOrderedIpv4Range(IPAddress start, IPAddress end)
    => start.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork
    && end.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork
    && ToUint(end) > ToUint(start);

Try / catch

try { var scope = new Scope(name, true, start, end, mask, log, dhcpServer); }
catch (ArgumentException ex) when (ex.Message.Contains("Ending address must be greater"))
{ /* re-prompt user with corrected range */ }

Prevention

When it happens

Trigger: Calling 'new Scope(name, enabled, startingAddress, endingAddress, subnetMask, log, dhcpServer)' or 'scope.ChangeNetwork(start, end, mask)' with end numerically <= start. This includes equal addresses, reversed order (start=192.168.1.50, end=192.168.1.10), or byte-order mistakes when constructing the IPAddress from an integer.

Common situations: Form fields supplied in the wrong order, swapped positional arguments, copying a CIDR host range where both bounds resolve to the same IP, or feeding IPAddress.Parse a hex/decimal value whose byte order produces a lower ending number than expected.

Related errors


AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13). Data as JSON: /api/errors/bd3bb69c9b51aa76. Report an issue: GitHub.