//native
function wapiUrl(auth: RT.InfobloxNios, path: string) {
const host = auth.host
.trim()
.replace(/^https?:\/\//, "")
.replace(/\/+$/, "")
const version = auth.wapi_version.trim().replace(/^v/, "")
return new URL(`https://${host}/wapi/v${version}/${path}`)
}
function basicAuth(auth: RT.InfobloxNios) {
const bytes = new TextEncoder().encode(`${auth.username}:${auth.password}`)
return `Basic ${btoa(String.fromCharCode(...bytes))}`
}
async function wapiError(response: Response) {
const text = await response.text()
if (response.status === 401) {
return new Error(
"401 Unauthorized: wrong username or password, or the user's admin group has no API access"
)
}
try {
// WAPI errors are JSON: {"Error": "AdmConDataNotFoundError: ...", "code": "Client.Ibap.Data.NotFound", "text": "..."}
const { Error: error, code, text: detail } = JSON.parse(text)
if (error) {
const message =
detail && !error.includes(detail) ? `${error}: ${detail}` : error
return new Error(
`${response.status} ${message}${code ? ` (${code})` : ""}`
)
}
} catch {}
return new Error(`${response.status} ${text}`)
}
/**
* Get zone
* 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.
*/
export async function main(
auth: RT.InfobloxNios,
fqdn: string,
view: string | undefined
) {
const name = fqdn.trim().toLowerCase().replace(/\.$/, "")
if (!name) throw new Error("fqdn is required")
if (/\.(in-addr|ip6)\.arpa$/.test(name)) {
throw new Error(
"Reverse zones are named by CIDR in NIOS (e.g. 10.20.0.0/24): use List zones with zone_format IPV4 or IPV6"
)
}
const labels = name.split(".")
// Walk up one label at a time; the first hit is the closest enclosing zone.
for (let i = 0; i < labels.length; i++) {
const candidate = labels.slice(i).join(".")
const url = wapiUrl(auth, "zone_auth")
url.searchParams.append("fqdn", candidate)
if (view) url.searchParams.append("view", view)
url.searchParams.append(
"_return_fields+",
"zone_format,comment,disable,ns_group,extattrs"
)
url.searchParams.append("_return_as_object", "1")
const response = await fetch(url, {
headers: {
Authorization: basicAuth(auth),
Accept: "application/json",
},
})
if (!response.ok) {
throw await wapiError(response)
}
const { result } = (await response.json()) as {
result: { _ref: string; fqdn: string; view: string }[]
}
if (result.length > 1) {
throw new Error(
`Zone ${candidate} exists in several DNS views (${result.map((z) => z.view).join(", ")}); set view`
)
}
if (result.length === 1) return result[0]
}
throw new Error(
`No authoritative zone found for ${fqdn}${view ? ` in view ${view}` : ""}`
)
}
Submitted by hugo989 3 hours ago