0

Get zone

Published today

Return the authoritative zone (zone_auth) that contains a DNS name: the zone named fqdn itself, or else its closest parent zone (app.prod.example.com → prod.example.com → example.com). Fails when Infoblox is authoritative for none of them. Forward names only: reverse zones are listed by CIDR in List zones. Set view when the zone exists in several DNS views.

Script infoblox_nios Verified

The script

Submitted by hugo989 Typescript (fetch-only)
Verified 2 hours ago
1
//native
2

3
function wapiUrl(auth: RT.InfobloxNios, path: string) {
4
  const host = auth.host
5
    .trim()
6
    .replace(/^https?:\/\//, "")
7
    .replace(/\/+$/, "")
8
  const version = auth.wapi_version.trim().replace(/^v/, "")
9
  return new URL(`https://${host}/wapi/v${version}/${path}`)
10
}
11

12
function basicAuth(auth: RT.InfobloxNios) {
13
  const bytes = new TextEncoder().encode(`${auth.username}:${auth.password}`)
14
  return `Basic ${btoa(String.fromCharCode(...bytes))}`
15
}
16

17
async function wapiError(response: Response) {
18
  const text = await response.text()
19
  if (response.status === 401) {
20
    return new Error(
21
      "401 Unauthorized: wrong username or password, or the user's admin group has no API access"
22
    )
23
  }
24
  try {
25
    // WAPI errors are JSON: {"Error": "AdmConDataNotFoundError: ...", "code": "Client.Ibap.Data.NotFound", "text": "..."}
26
    const { Error: error, code, text: detail } = JSON.parse(text)
27
    if (error) {
28
      const message =
29
        detail && !error.includes(detail) ? `${error}: ${detail}` : error
30
      return new Error(
31
        `${response.status} ${message}${code ? ` (${code})` : ""}`
32
      )
33
    }
34
  } catch {}
35
  return new Error(`${response.status} ${text}`)
36
}
37

38
/**
39
 * Get zone
40
 * Return the authoritative zone (zone_auth) that contains a DNS name: the zone named fqdn itself, or else its closest parent zone (app.prod.example.com → prod.example.com → example.com). Fails when Infoblox is authoritative for none of them. Forward names only: reverse zones are listed by CIDR in List zones. Set view when the zone exists in several DNS views.
41
 */
42
export async function main(
43
  auth: RT.InfobloxNios,
44
  fqdn: string,
45
  view: string | undefined
46
) {
47
  const name = fqdn.trim().toLowerCase().replace(/\.$/, "")
48
  if (!name) throw new Error("fqdn is required")
49
  if (/\.(in-addr|ip6)\.arpa$/.test(name)) {
50
    throw new Error(
51
      "Reverse zones are named by CIDR in NIOS (e.g. 10.20.0.0/24): use List zones with zone_format IPV4 or IPV6"
52
    )
53
  }
54
  const labels = name.split(".")
55

56
  // Walk up one label at a time; the first hit is the closest enclosing zone.
57
  for (let i = 0; i < labels.length; i++) {
58
    const candidate = labels.slice(i).join(".")
59
    const url = wapiUrl(auth, "zone_auth")
60
    url.searchParams.append("fqdn", candidate)
61
    if (view) url.searchParams.append("view", view)
62
    url.searchParams.append(
63
      "_return_fields+",
64
      "zone_format,comment,disable,ns_group,extattrs"
65
    )
66
    url.searchParams.append("_return_as_object", "1")
67

68
    const response = await fetch(url, {
69
      headers: {
70
        Authorization: basicAuth(auth),
71
        Accept: "application/json",
72
      },
73
    })
74
    if (!response.ok) {
75
      throw await wapiError(response)
76
    }
77
    const { result } = (await response.json()) as {
78
      result: { _ref: string; fqdn: string; view: string }[]
79
    }
80
    if (result.length > 1) {
81
      throw new Error(
82
        `Zone ${candidate} exists in several DNS views (${result.map((z) => z.view).join(", ")}); set view`
83
      )
84
    }
85
    if (result.length === 1) return result[0]
86
  }
87

88
  throw new Error(
89
    `No authoritative zone found for ${fqdn}${view ? ` in view ${view}` : ""}`
90
  )
91
}
92