///|
/// Canonical uncompressed name. Construction checks wire size and label size.
pub struct Name {
priv labels : Array[Bytes]
} derive(Eq, Debug)
///|
pub extend Name with Eq::{equal, not_equal}
///|
pub extend Name with @debug.Debug::{to_repr}
///|
pub fn Name::parse(text : String) -> Result[Name, DnsError] {
if text == "." {
return Ok({ labels: [], })
}
if !text.has_suffix(".") {
return Err(Malformed("presentation names must be absolute"))
}
let labels : Array[Bytes] = []
let mut size = 1
for part in text[:text.length() - 1].split(".") {
let bytes : Array[Byte] = []
for c in part.iter() {
let n = c.to_int()
if n < 33 || n > 126 || n == 92 {
return Err(
Unsupported("use wire names for escaped or non-ASCII labels"),
)
}
bytes.push((if n >= 65 && n <= 90 { n + 32 } else { n }).to_byte())
}
if bytes.length() == 0 || bytes.length() > 63 {
return Err(Malformed("label size outside 1..63"))
}
size += 1 + bytes.length()
if size > 255 {
return Err(Malformed("name exceeds 255 wire bytes"))
}
labels.push(Bytes::from_array(bytes))
}
Ok({ labels, })
}
///|
fn read_name(data : Bytes, start : Int32) -> Result[(Name, Int32), DnsError] {
if start < 0 || start >= data.length() {
return Err(Malformed("missing name"))
}
let labels : Array[Bytes] = []
let mut p = start
while p < data.length() {
let n = data[p].to_int()
p += 1
if n == 0 {
if p - start > 255 {
return Err(Malformed("name too long"))
}
return Ok(({ labels, }, p))
}
if n > 63 {
return Err(Malformed("compressed or reserved label"))
}
if p + n > data.length() || p + n - start > 254 {
return Err(Malformed("truncated or oversized name"))
}
let label : Array[Byte] = []
for i = p; i < p + n; i = i + 1 {
let b = data[i].to_int()
label.push((if b >= 65 && b <= 90 { b + 32 } else { b }).to_byte())
}
labels.push(Bytes::from_array(label))
p += n
}
Err(Malformed("unterminated name"))
}
///|
pub fn Name::from_wire(data : Bytes) -> Result[Name, DnsError] {
match read_name(data, 0) {
Err(e) => Err(e)
Ok((name, end)) =>
if end == data.length() {
Ok(name)
} else {
Err(Malformed("trailing name bytes"))
}
}
}
///|
pub fn Name::wire(self : Name) -> Bytes {
let out : Array[Byte] = []
for label in self.labels {
out.push(label.length().to_byte())
for b in label {
out.push(b)
}
}
out.push(0)
Bytes::from_array(out)
}
///|
pub fn Name::label_count(self : Name) -> Int32 {
self.labels.length()
}
///|
pub fn Name::is_subdomain(self : Name, zone : Name) -> Bool {
if self.labels.length() < zone.labels.length() {
return false
}
let offset = self.labels.length() - zone.labels.length()
for i = 0; i < zone.labels.length(); i = i + 1 {
if self.labels[offset + i] != zone.labels[i] {
return false
}
}
true
}
///|
/// RFC4034 rightmost-label order, not presentation string order.
pub fn Name::canonical_compare(self : Name, other : Name) -> Int32 {
let mut a = self.labels.length() - 1
let mut b = other.labels.length() - 1
while a >= 0 && b >= 0 {
let c = bytes_compare(self.labels[a], other.labels[b])
if c != 0 {
return c
}
a -= 1
b -= 1
}
if a < b {
-1
} else if a > b {
1
} else {
0
}
}
///|
pub fn Name::parent(self : Name) -> Name? {
if self.labels.is_empty() {
return None
}
Some({ labels: self.labels[1:].to_owned(), })
}
///|
fn Name::wildcard(self : Name) -> Result[Name, DnsError] {
if self.wire().length() + 2 > 255 {
return Err(Malformed("wildcard name too long"))
}
let labels = [b"*"]
for l in self.labels {
labels.push(l)
}
Ok({ labels, })
}
///|
pub fn Name::signed_owner(
self : Name,
labels : Int32,
) -> Result[Name, DnsError] {
if labels < 0 || labels > self.labels.length() {
return Err(Bogus("RRSIG labels exceed owner labels"))
}
if labels == self.labels.length() {
return Ok(self)
}
let tail : Name = {
labels: self.labels[self.labels.length() - labels:].to_owned(),
}
tail.wildcard()
}
///|
fn bytes_compare(a : Bytes, b : Bytes) -> Int32 {
for i = 0; i < a.length() && i < b.length(); i = i + 1 {
if a[i] < b[i] {
return -1
}
if a[i] > b[i] {
return 1
}
}
if a.length() < b.length() {
-1
} else if a.length() > b.length() {
1
} else {
0
}
}