Adding a record type used to require 5 edits across the file (enum variant, to_num, from_num, as_str, parse_str). The macro takes a single (variant, num, str) tuple per type and generates the enum plus all four methods. UNKNOWN(u16) stays hand-coded since it carries data and can't sit in the table. src/question.rs: 156 lines -> 92 lines, no behavior change.
93 lines
2.4 KiB
Rust
93 lines
2.4 KiB
Rust
use crate::buffer::BytePacketBuffer;
|
|
use crate::Result;
|
|
|
|
macro_rules! define_qtypes {
|
|
( $( $variant:ident = $num:literal, $str:literal ),* $(,)? ) => {
|
|
#[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)]
|
|
pub enum QueryType {
|
|
UNKNOWN(u16),
|
|
$( $variant, )*
|
|
}
|
|
|
|
impl QueryType {
|
|
pub fn to_num(&self) -> u16 {
|
|
match *self {
|
|
QueryType::UNKNOWN(x) => x,
|
|
$( QueryType::$variant => $num, )*
|
|
}
|
|
}
|
|
|
|
pub fn from_num(num: u16) -> QueryType {
|
|
match num {
|
|
$( $num => QueryType::$variant, )*
|
|
_ => QueryType::UNKNOWN(num),
|
|
}
|
|
}
|
|
|
|
pub fn as_str(&self) -> &'static str {
|
|
match self {
|
|
QueryType::UNKNOWN(_) => "UNKNOWN",
|
|
$( QueryType::$variant => $str, )*
|
|
}
|
|
}
|
|
|
|
pub fn parse_str(s: &str) -> Option<QueryType> {
|
|
match s.to_ascii_uppercase().as_str() {
|
|
$( $str => Some(QueryType::$variant), )*
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
define_qtypes! {
|
|
A = 1, "A",
|
|
NS = 2, "NS",
|
|
CNAME = 5, "CNAME",
|
|
SOA = 6, "SOA",
|
|
PTR = 12, "PTR",
|
|
MX = 15, "MX",
|
|
TXT = 16, "TXT",
|
|
AAAA = 28, "AAAA",
|
|
LOC = 29, "LOC",
|
|
SRV = 33, "SRV",
|
|
NAPTR = 35, "NAPTR",
|
|
OPT = 41, "OPT",
|
|
DS = 43, "DS",
|
|
RRSIG = 46, "RRSIG",
|
|
NSEC = 47, "NSEC",
|
|
DNSKEY = 48, "DNSKEY",
|
|
NSEC3 = 50, "NSEC3",
|
|
SVCB = 64, "SVCB",
|
|
HTTPS = 65, "HTTPS",
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct DnsQuestion {
|
|
pub name: String,
|
|
pub qtype: QueryType,
|
|
}
|
|
|
|
impl DnsQuestion {
|
|
pub fn new(name: String, qtype: QueryType) -> DnsQuestion {
|
|
DnsQuestion { name, qtype }
|
|
}
|
|
|
|
pub fn read(&mut self, buffer: &mut BytePacketBuffer) -> Result<()> {
|
|
buffer.read_qname(&mut self.name)?;
|
|
self.qtype = QueryType::from_num(buffer.read_u16()?);
|
|
let _ = buffer.read_u16()?; // class
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn write(&self, buffer: &mut BytePacketBuffer) -> Result<()> {
|
|
buffer.write_qname(&self.name)?;
|
|
buffer.write_u16(self.qtype.to_num())?;
|
|
buffer.write_u16(1)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|