// MoonDNS - Pure MoonBit Authoritative DNS Server
// Copyright 2026 chgttyyr
// Licensed under the Apache-2.0 License.
///|
/// DNS Resource Record Types (RFC 1035, RFC 3596, RFC 6891, RFC 6844, etc.)
pub(all) enum RType {
A // 1: Host IPv4 address (RFC 1035)
NS // 2: Authoritative name server (RFC 1035)
CNAME // 5: Canonical name for an alias (RFC 1035)
SOA // 6: Start of a zone of authority (RFC 1035)
PTR // 12: Domain name pointer (RFC 1035)
MX // 15: Mail exchange (RFC 1035)
TXT // 16: Text strings (RFC 1035)
AAAA // 28: Host IPv6 address (RFC 3596)
SRV // 33: Server selector (RFC 2782)
OPT // 41: EDNS0 option pseudo-record (RFC 6891)
AXFR // 252: Zone transfer query (RFC 1035)
ANY // 255: Request for any records (RFC 1035)
CAA // 257: Certification Authority Authorization (RFC 6844)
Unknown(UInt16)
} derive(Debug, Eq)
///|
/// Convert RType to standard wire protocol 16-bit unsigned integer
pub fn RType::to_wire(self : RType) -> UInt16 {
match self {
A => 1
NS => 2
CNAME => 5
SOA => 6
PTR => 12
MX => 15
TXT => 16
AAAA => 28
SRV => 33
OPT => 41
AXFR => 252
ANY => 255
CAA => 257
Unknown(code) => code
}
}
///|
/// Parse RType from wire protocol 16-bit integer
pub fn RType::from_wire(code : UInt16) -> RType {
match code {
1 => A
2 => NS
5 => CNAME
6 => SOA
12 => PTR
15 => MX
16 => TXT
28 => AAAA
33 => SRV
41 => OPT
252 => AXFR
255 => ANY
257 => CAA
other => Unknown(other)
}
}
///|
/// Convert RType to human-readable string representation
pub fn RType::to_string(self : RType) -> String {
match self {
A => "A"
NS => "NS"
CNAME => "CNAME"
SOA => "SOA"
PTR => "PTR"
MX => "MX"
TXT => "TXT"
AAAA => "AAAA"
SRV => "SRV"
OPT => "OPT"
AXFR => "AXFR"
ANY => "ANY"
CAA => "CAA"
Unknown(code) => "TYPE" + code.to_string()
}
}
///|
/// Parse RType from uppercase string representation
pub fn RType::from_string(s : String) -> RType? {
match s {
"A" => Some(A)
"NS" => Some(NS)
"CNAME" => Some(CNAME)
"SOA" => Some(SOA)
"PTR" => Some(PTR)
"MX" => Some(MX)
"TXT" => Some(TXT)
"AAAA" => Some(AAAA)
"SRV" => Some(SRV)
"OPT" => Some(OPT)
"AXFR" => Some(AXFR)
"ANY" => Some(ANY)
"CAA" => Some(CAA)
_ => None
}
}
///|
/// DNS Record Classes (RFC 1035 Section 3.2.4)
pub(all) enum RClass {
IN // 1: Internet class (the ubiquitous standard)
CS // 2: CSNET class (obsolete)
CH // 3: CHAOS class
HS // 4: Hesiod class
NONE // 254: None class (RFC 2136)
ANY // 255: Any class
Unknown(UInt16)
} derive(Debug, Eq)
///|
/// Convert RClass to wire protocol 16-bit integer
pub fn RClass::to_wire(self : RClass) -> UInt16 {
match self {
IN => 1
CS => 2
CH => 3
HS => 4
NONE => 254
ANY => 255
Unknown(code) => code
}
}
///|
/// Parse RClass from wire protocol 16-bit integer
pub fn RClass::from_wire(code : UInt16) -> RClass {
match code {
1 => IN
2 => CS
3 => CH
4 => HS
254 => NONE
255 => ANY
other => Unknown(other)
}
}
///|
/// Convert RClass to human-readable string representation
pub fn RClass::to_string(self : RClass) -> String {
match self {
IN => "IN"
CS => "CS"
CH => "CH"
HS => "HS"
NONE => "NONE"
ANY => "ANY"
Unknown(code) => "CLASS" + code.to_string()
}
}
///|
/// DNS Question Entry (RFC 1035 Section 4.1.2)
pub(all) struct Question {
name : String // Domain name in FQDN string format
qtype : RType // Target record type requested
qclass : RClass // Query class (almost always IN)
} derive(Debug, Eq)
///|
/// Create a new Question instance
pub fn Question::new(name : String, qtype : RType, qclass : RClass) -> Question {
{ name, qtype, qclass, }
}