TechnitiumSoftware/DnsServer · error · ArgumentException

Transaction ID must be 4 bytes.

Error message

Transaction ID must be 4 bytes.

What it means

Constructor argument guard in DhcpMessage: the transaction ID (xid) must be exactly 4 bytes. RFC 2131 defines the xid field as a 4-octet value used to match request/reply pairs, so any other length is invalid wire data.

Source

Thrown at DnsServerCore/Dhcp/DhcpMessage.cs:116

            if (ciaddr.AddressFamily != AddressFamily.InterNetwork)
                throw new ArgumentException("Address family not supported.", nameof(ciaddr));

            if (yiaddr.AddressFamily != AddressFamily.InterNetwork)
                throw new ArgumentException("Address family not supported.", nameof(yiaddr));

            if (siaddr.AddressFamily != AddressFamily.InterNetwork)
                throw new ArgumentException("Address family not supported.", nameof(siaddr));

            if (giaddr.AddressFamily != AddressFamily.InterNetwork)
                throw new ArgumentException("Address family not supported.", nameof(giaddr));

            ArgumentNullException.ThrowIfNull(clientHardwareAddress);

            if (clientHardwareAddress.Length > 16)
                throw new ArgumentException("Client hardware address cannot exceed 16 bytes.", nameof(clientHardwareAddress));

            if (xid.Length != 4)
                throw new ArgumentException("Transaction ID must be 4 bytes.", nameof(xid));

            if (secs.Length != 2)
                throw new ArgumentException("Seconds elapsed must be 2 bytes.", nameof(secs));

            _op = op;
            _htype = hardwareAddressType;
            _hlen = Convert.ToByte(clientHardwareAddress.Length);
            _hops = 0;

            _xid = xid;

            _secs = secs;
            _flags = flags;

            _ciaddr = ciaddr;
            _yiaddr = yiaddr;
            _siaddr = siaddr;
            _giaddr = giaddr;

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Generate xid as exactly 4 bytes (e.g. BitConverter.GetBytes(RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue)) or NextBytes on a 4-byte array).
  2. When forwarding, copy the original 4-byte xid unchanged.
  3. Validate xid.Length == 4 before constructing.
  4. Do not substitute a GUID/16-byte token for xid.

Example fix

// before
byte[] xid = Guid.NewGuid().ToByteArray(); // 16 bytes
var msg = new DhcpMessage(op, htype, xid, secs, flags, ...); // throws [216]

// after
byte[] xid = new byte[4];
RandomNumberGenerator.Fill(xid);
var msg = new DhcpMessage(op, htype, xid, secs, flags, ...);
Defensive patterns

Strategy: validation

Validate before calling

if (xid is null) throw new ArgumentNullException(nameof(xid));
if (xid.Length != 4) throw new ArgumentException("Transaction ID (xid) must be exactly 4 bytes.", nameof(xid));

var msg = new DhcpMessage(op, htype, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr, chaddr, sname, file, opts);

Type guard

static bool IsValidXid(byte[] xid) =>
    xid is not null && xid.Length == 4;

Prevention

When it happens

Trigger: Calling the DhcpMessage constructor with an xid byte array whose Length is not 4.

Common situations: Generating xid with the wrong RNG width (e.g. 16 bytes / a GUID); passing a uint without converting to 4 bytes; copying xid from a truncated/extended buffer.

Related errors


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