Skip to content

Complex DNS Record Types

This section covers advanced DNS record types and their usage patterns.

CAA (Certification Authority Authorization)

CAA records specify which Certificate Authorities are allowed to issue certificates:

ts
const caaResponse = await client.query({
  name: 'example.com',
  type: 'CAA'
})

interface CAARecord {
  flags: number // Record flags
  tag: string // 'issue', 'issuewild', or 'iodef'
  value: string // CA domain or reporting URL
}

// Example usage
const caaRecords = caaResponse.answers.map(answer => answer.data as CAARecord)
caaRecords.forEach((record) => {
  if (record.tag === 'issue') {
    console.log(`Allowed CA: ${record.value}`)
  }
})

SRV (Service) Records

SRV records define the location of services:

ts
const srvResponse = await client.query({
  name: '_http._tcp.example.com',
  type: 'SRV'
})

interface SRVRecord {
  priority: number // Priority of target host (lower is higher priority)
  weight: number // Relative weight for records with same priority
  port: number // TCP/UDP port number
  target: string // Hostname of the target machine
}

// Example usage with sorting
const srvRecords = srvResponse.answers
  .map(answer => answer.data as SRVRecord)
  .sort((a, b) => {
    if (a.priority !== b.priority)
      return a.priority - b.priority
    return b.weight - a.weight
  })

TLSA (TLS Authentication)

TLSA records associate TLS certificates with domain names:

ts
const tlsaResponse = await client.query({
  name: '_443._tcp.example.com',
  type: 'TLSA'
})

interface TLSARecord {
  certUsage: number // Certificate usage (0-3)
  selector: number // Certificate data type (0-1)
  matchingType: number // Matching type (0-2)
  certificateData: string // Certificate association data
}

// Example validation
const tlsaRecords = tlsaResponse.answers.map(answer => answer.data as TLSARecord)
tlsaRecords.forEach((record) => {
  switch (record.certUsage) {
    case 0: // PKIX-TA
      console.log('Trust anchor certificate')
      break
    case 1: // PKIX-EE
      console.log('End entity certificate')
      break
    case 2: // DANE-TA
      console.log('Trust anchor public key')
      break
    case 3: // DANE-EE
      console.log('End entity public key')
      break
  }
})

NAPTR (Naming Authority Pointer)

NAPTR records are used for ENUM and other advanced DNS applications:

ts
const naptrResponse = await client.query({
  name: 'example.com',
  type: 'NAPTR'
})

interface NAPTRRecord {
  order: number // Processing order
  preference: number // Processing preference
  flags: string // Record flags
  service: string // Service type
  regexp: string // Regular expression
  replacement: string // Replacement pattern
}

// Example ENUM lookup
const naptrRecords = naptrResponse.answers
  .map(answer => answer.data as NAPTRRecord)
  .sort((a, b) => {
    if (a.order !== b.order)
      return a.order - b.order
    return a.preference - b.preference
  })

SSHFP (SSH Fingerprint)

SSHFP records store SSH public key fingerprints:

ts
const sshfpResponse = await client.query({
  name: 'example.com',
  type: 'SSHFP'
})

interface SSHFPRecord {
  algorithm: number // SSH key algorithm
  fpType: number // Fingerprint type
  fingerprint: string // Key fingerprint
}

// Example validation
const sshfpRecords = sshfpResponse.answers.map(answer => answer.data as SSHFPRecord)
sshfpRecords.forEach((record) => {
  const algo = record.algorithm === 1
    ? 'RSA'
    : record.algorithm === 2
      ? 'DSA'
      : record.algorithm === 3
        ? 'ECDSA'
        : record.algorithm === 4 ? 'Ed25519' : 'Unknown'
  console.log(`${algo} key fingerprint: ${record.fingerprint}`)
})

Working with Multiple Record Types

Example of querying multiple record types:

ts
const multiResponse = await client.query({
  name: 'example.com',
  type: ['A', 'AAAA', 'MX', 'TXT', 'CAA']
})

interface MultiQueryResult {
  a: string[]
  aaaa: string[]
  mx: Array<{ preference: number, exchange: string }>
  txt: string[][]
  caa: CAARecord[]
}

const result: MultiQueryResult = {
  a: multiResponse.answers
    .filter(r => r.type === 'A')
    .map(r => r.data as string),
  aaaa: multiResponse.answers
    .filter(r => r.type === 'AAAA')
    .map(r => r.data as string),
  mx: multiResponse.answers
    .filter(r => r.type === 'MX')
    .map(r => r.data as { preference: number, exchange: string }),
  txt: multiResponse.answers
    .filter(r => r.type === 'TXT')
    .map(r => r.data as string[]),
  caa: multiResponse.answers
    .filter(r => r.type === 'CAA')
    .map(r => r.data as CAARecord)
}

Released under the MIT License.