Mapping the DNSRecord attribute

Microsoft DNS is able to store records in Active Directory when running on a Domain Controller. The information is stored in a Binary Large Object (BLOB) called DNSRecord. No official maps for that attribute appear to have been published. The information below is a result of reverse engineering the contents of the attribute.

Michael Smith has a very pretty PowerShell script which uses the structures below, and a few more, to convert the DnsRecord attribute into a human readable format on his blog, Michael’s meanderings….

Update 02/02/2010: In December 2009, Microsoft released a protocol specification including details of dnsRecord and dnsProperty: MS-DNSP.pdf

About the mapped structure

The map created below for DNSRecord is incomplete, the remaining values seem to defy testing. While the map below is probably accurate I reserve the right to be wrong. Despite that, the structures can be used to manually construct or decode DNSRecords via LDAP rather than using the GUI, dnscmd or WMI. Edit: The map is now complete.

About DNSRecord

The dnsRecord attribute appears on dnsNode objects. The dnsRecord attribute is multi-valued. This means that each node can contain more than one record. This is most obvious for the node representing “same as parent folder” which will hold the NS records and SOA records as a minimum.

Structures: DNSRecord

The DNSRecord attribute is composed of the fields described in the table below.

Field Name Length (Bytes) Format Description
RData Length 2 Little Endian Length of the Record Data block
Type 2 Little Endian Record type. Matches published type values on IANA
Unknown (1) 4 N/A Predictable, but unknown.
UpdatedAtSerial 4 Little Endian Changes to match the serial number in the SOA whenever the record is modified
TTL 4 Big Endian Time To Live value for the record
Unknown (2) 4 N/A Always 0
TimeStamp 4 Little Endian TimeStamp in hours from 01/01/1601 00:00:00
RData Variable Variable The record data, formatting described below.

These values produce the following binary array.

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                 RDATA LENGTH                  |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                  UNKNOWN (1)                  |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                 UPDATEDATSERIAL               |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TTL                      |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                  UNKNOWN (2)                  |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                   TIMESTAMP                   |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
    /                     RDATA                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

Unknown 1 is a difficult value to interpret. It may contain several separate fields, however as none appear easy to decipher they were left as a single block in the map. Testing shows that “unknown 1″ has the following values:

                      1 1 1 1 1 1  
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |      5        | AdvRecordType |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |      0        |        0      |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

Edit: The structure of Unknown 1 is as follows.

                      1 1 1 1 1 1  
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |    VERSION    | AdvRecordType |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |             FLAGS             |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

Modifying the first byte to any (decimal) value other than 5 will cause the record to vanish from the DNS system. It will remain in the directory, but appears to render it useless. Edit: 5 is the Version number and is a static value.

The second byte, termed AdvRecordType, appears to have a number of possible values. Experimentation shows that Root Hints have the value set to decimal 8, out-of-zone records (normally Glue for NS Records) have 128, delegations within a zone have 130 and everything else has 240. A larger data set than I have available is required to draw conclusions other than those.

Edit: The values for AdvRecordType, referred to as Rank in the documentation above are represented by this Enumeration.

public enum RankFlag : uint  
{  
    // The record came from the cache.  
    CacheBit = 1,  
    // The record is a preconfigured root hint.  
    RootHint = 8,  
    // This value is not used.  
    OutsideGlue = 32,  
    // The record was cached from the additional section of a  
    // nonauthoritative response.  
    CacheNAAdditional = 49,  
    // The record was cached from the authority section of a  
    // nonauthoritative response.  
    CacheNAAuthority = 65,  
    // The record was cached from the additional section of an  
    // authoritative response.  
    CacheAAdditional = 81,  
    // The record was cached from the answer section of a  
    // nonauthoritative response.  
    CacheNAAnswer = 97,  
    // The record was cached from the authority section of an  
    // authoritative response.  
    CacheAAuthority = 113,  
    // The record is a glue record in an authoritative zone.  
    Glue = 128,  
    // The record is a delegation (type NS) record in an  
    // authoritative zone.  
    NSGlue = 130,  
    // The record was cached from the answer section of an  
    // authoritative response.  
    CacheAAnswer = 193,  
    // The record comes from an authoritative zone.  
    Zone = 240
}

The final two bytes appear to be set to 0 in all instances. Edit: Referred to as Flags, the value must be 0.

Edit: Unknown 2 is reserved for future use and should be set to 0 in all cases.

Structures: RDATA

Each of the structures below is a minimal representation of the record data, the structures show single-label names. In each case the “Label Length” and “Data” structures repeat where multiple labels are used, this also applies to “Responsible Person” in the SOA record.

A

The RDATA block for the A record is a static 4 byte (32 bit) field. Each byte represents an octet in the IP address.

                      1 1 1 1 1 1  
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |              DATA             |
 |                               |
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

CNAME and NS

                      1 1 1 1 1 1  
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |    LENGTH     | NO. OF LABELS |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 | LABEL LENGTH  |               |  
 |–+–+–+–+–+–+–+–+               |  
 /              DATA             /  
 /                               /  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

MX

                      1 1 1 1 1 1  
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |            PRIORITY           |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 | LENGTH        | NO. OF LABELS | 
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |  LABEL LENGTH |               |  
 |–+–+–+–+–+–+–+–+               |  
 /              DATA             /  
 /                               /  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

SOA

                      1 1 1 1 1 1  
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |             SERIAL            |  
 |                               |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |             REFRESH           |  
 |                               |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |             RETRY             |  
 |                               |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |             EXPIRE            |  
 |                               |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |          MINIMUM TTL          |  
 |                               |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |     LENGTH    | NO. OF LABELS |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |  LABEL LENGTH |               |  
 +–+–+–+–+–+–+–+–+               |  
 /              DATA             /  
 /                               /  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 | LENGTH        | NO. OF LABELS |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |  LABEL LENGTH |               |  
 |–+–+–+–+–+–+–+–+               |  
 /      RESPONSIBLE PERSON       /  
 /                               /  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

SRV

                      1 1 1 1 1 1  
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |            PRIORITY           |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |             WEIGHT            |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |              PORT             |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |     LENGTH    | NO. OF LABELS |  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |  LABEL LENGTH |               |  
 |–+–+–+–+–+–+–+–+               |  
 /              DATA             /  
 /                               /  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

TXT

                      1 1 1 1 1 1  
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+  
 |     LENGTH    |               |  
 |–+–+–+–+–+–+–+–+               |  
 /              DATA             /  
 /                               /  
 +–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+–+
Mapping the DNSRecord attribute
Share this