///|
pub(all) struct LookupResult {
status : String
queried_name : String
queried_type : String
canonical_name : String
alias_path : Array[String]
answers : Array[ResourceRecord]
} derive(Debug)
///|
fn lookup_result(
status : String,
name : String,
kind : String,
canonical : String,
path : Array[String],
answers : Array[ResourceRecord],
) -> LookupResult {
{
status,
queried_name: name,
queried_type: kind,
canonical_name: canonical,
alias_path: path,
answers,
}
}
///|
/// Simulate an exact, local lookup with CNAME following. This is not a DNS
/// resolver: it performs no wildcard synthesis, delegation, or network I/O.
pub fn lookup_zone(
zone : Zone,
name : String,
record_type : String,
) -> LookupResult {
let owner = absolute_name(name, zone.origin)
let kind = upper(record_type)
let empty : Array[ResourceRecord] = []
let empty_path : Array[String] = []
if !valid_domain_name(owner) {
return lookup_result("invalid-name", owner, kind, owner, empty_path, empty)
}
if !is_within_zone(owner, zone.origin) {
return lookup_result("outside-zone", owner, kind, owner, empty_path, empty)
}
let direct = find_records(zone, owner, kind)
if direct.length() > 0 {
return lookup_result("answer", owner, kind, owner, empty_path, direct)
}
let all = find_records(zone, owner, "*")
if all.length() == 0 {
return lookup_result(
"name-not-found", owner, kind, owner, empty_path, empty,
)
}
if kind == "CNAME" {
return lookup_result("no-data", owner, kind, owner, empty_path, empty)
}
let trace = trace_alias(zone, owner)
if trace.cycle {
return lookup_result(
"alias-cycle",
owner,
kind,
trace.terminal,
trace.path,
empty,
)
}
if trace.path.length() == 1 {
return lookup_result("no-data", owner, kind, owner, trace.path, empty)
}
if !is_within_zone(trace.terminal, zone.origin) {
return lookup_result(
"external-target",
owner,
kind,
trace.terminal,
trace.path,
empty,
)
}
let answers = find_records(zone, trace.terminal, kind)
if answers.length() > 0 {
lookup_result("answer", owner, kind, trace.terminal, trace.path, answers)
} else {
lookup_result("no-data", owner, kind, trace.terminal, trace.path, empty)
}
}
///|
pub fn render_lookup_text(result : LookupResult) -> String {
let out = StringBuilder()
out.write_string("status: \{result.status}\n")
out.write_string("query: \{result.queried_name} \{result.queried_type}\n")
out.write_string("canonical name: \{result.canonical_name}\n")
for name in result.alias_path {
out.write_string("alias path: \{name}\n")
}
for record in result.answers {
out.write_string(canonical_record_line(record))
out.write_char('\n')
}
out.to_string()
}
///|
pub fn render_lookup_json(result : LookupResult) -> String {
let out = StringBuilder()
out.write_char('{')
write_json_field(out, "status", result.status, false)
write_json_field(out, "name", result.queried_name, true)
write_json_field(out, "type", result.queried_type, true)
write_json_field(out, "canonical_name", result.canonical_name, true)
out.write_string(",\"alias_path\":[")
for i in 0.. 0 {
out.write_char(',')
}
out.write_string(json_escaped(result.alias_path[i]))
}
out.write_string("],\"answers\":[")
for i in 0.. 0 {
out.write_char(',')
}
out.write_string(json_escaped(canonical_record_line(result.answers[i])))
}
out.write_string("]}")
out.to_string()
}