TechnitiumSoftware/DnsServer · error · ArgumentException

Starting address cannot be same as the network address.

Error message

Starting address cannot be same as the network address.

What it means

Thrown by Scope construction / ChangeNetwork when the starting address equals the network address (start AND subnetMask). A DHCP pool must never offer the network identifier itself (e.g. 192.168.1.0/24) to a client, so the library rejects it up front.

Source

Thrown at DnsServerCore/Dhcp/Scope.cs:1459

                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);

            _lastAddressOfferedLock.Wait();
            try
            {
                _lastAddressOffered = IPAddressExtensions.ConvertNumberToIp(startingAddressNumber - 1u);
            }
            finally
            {
                _lastAddressOfferedLock.Release();
            }
        }

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Increment the starting address above the network address (network + 1) before constructing the Scope.
  2. Recompute: if (start & mask) == start, bump start by one host.
  3. For very small subnets (/31, /32) use a larger block since there are no usable hosts between network and broadcast.
  4. Validate the mask itself; a malformed mask with all-zero host bits makes every address equal the network address.

Example fix

// before
var net = IPAddress.Parse("192.168.1.0");
var scope = new Scope(name, true, net,
    IPAddress.Parse("192.168.1.254"),
    IPAddress.Parse("255.255.255.0"), log, dhcpServer); // throws

// after
var start = IPAddress.Parse("192.168.1.1"); // network + 1
var scope = new Scope(name, true, start,
    IPAddress.Parse("192.168.1.254"),
    IPAddress.Parse("255.255.255.0"), log, dhcpServer);
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 IPAddress Increment(IPAddress a){ var u=ToUint(a)+1u; return new IPAddress(new byte[]{(byte)(u>>24),(byte)(u>>16),(byte)(u>>8),(byte)u}); }

uint network = ToUint(start) & ToUint(mask);
if (network == ToUint(start)) startingAddress = Increment(start); // bump off network

Type guard

static bool StartIsNotNetworkAddress(IPAddress start, IPAddress mask)
    => (ToUint(start) & ToUint(mask)) != ToUint(start);

Try / catch

try { scope.ChangeNetwork(start, end, mask); }
catch (ArgumentException ex) when (ex.Message.Contains("network address"))
{ start = Increment(start); scope.ChangeNetwork(start, end, mask); }

Prevention

When it happens

Trigger: Passing a startingAddress that is the subnet's base address: e.g. start=192.168.1.0 with mask 255.255.255.0, or start=10.0.0.0 with mask 255.0.0.0. Also triggered when a /31 or /32 mask collapses network onto the supplied start, or when auto-generating start from the network address without incrementing.

Common situations: Generating ranges from CIDR notation but forgetting to skip the network address; config files that list the subnet base as the first usable host; tooling that sets start = networkAddress verbatim.

Related errors


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