110 lines
3.9 KiB
Rust
110 lines
3.9 KiB
Rust
use crate::error::{Result, ErrorType};
|
|
use crate::name::Name;
|
|
use crate::context::CtxString;
|
|
|
|
use std::net;
|
|
|
|
|
|
#[derive(Debug, PartialEq, Hash, Eq)]
|
|
pub enum RType {
|
|
A {
|
|
target: net::Ipv4Addr,
|
|
},
|
|
Ns {
|
|
target: Name,
|
|
},
|
|
CName {
|
|
target: Name,
|
|
},
|
|
Soa {
|
|
mname: Name,
|
|
rname: Name,
|
|
serial: u32,
|
|
refresh: u32,
|
|
retry: u32,
|
|
expire: u32,
|
|
minimum: u32,
|
|
},
|
|
AAAA {
|
|
target: net::Ipv6Addr,
|
|
},
|
|
Unknown {
|
|
rtype: String,
|
|
origin: Name,
|
|
data: Vec<String>,
|
|
}
|
|
}
|
|
|
|
impl RType {
|
|
pub fn from_data(rtype: String, origin: &Name, data: Vec<CtxString>) -> Result<Self> {
|
|
Ok(match rtype.as_str() {
|
|
"A" | "TYPE1" => RType::A {
|
|
target: data.get(0).ok_or(ErrorType::BadParameter)?.parse().unwrap(),
|
|
},
|
|
"NS" | "TYPE2" => RType::Ns {
|
|
target: origin.prefixed_by(data.get(0).ok_or(ErrorType::BadParameter)?.parse()?),
|
|
},
|
|
"CNAME" | "TYPE5" => RType::CName {
|
|
target: origin.prefixed_by(data.get(0).ok_or(ErrorType::BadParameter)?.parse()?),
|
|
},
|
|
"SOA" | "TYPE6" => RType::Soa {
|
|
mname: origin.prefixed_by(data.get(0).ok_or(ErrorType::BadParameter)?.parse()?),
|
|
rname: origin.prefixed_by(data.get(1).ok_or(ErrorType::BadParameter)?.parse()?),
|
|
serial: data.get(2).ok_or(ErrorType::BadParameter)?.parse().unwrap(),
|
|
refresh: data.get(3).ok_or(ErrorType::BadParameter)?.parse().unwrap(),
|
|
retry: data.get(4).ok_or(ErrorType::BadParameter)?.parse().unwrap(),
|
|
expire: data.get(5).ok_or(ErrorType::BadParameter)?.parse().unwrap(),
|
|
minimum: data.get(6).ok_or(ErrorType::BadParameter)?.parse().unwrap(),
|
|
|
|
},
|
|
"AAAA" | "TYPE26" => RType::AAAA {
|
|
target: data.get(0).ok_or(ErrorType::BadParameter)?.parse().unwrap(),
|
|
},
|
|
_ => RType::Unknown {
|
|
rtype,
|
|
origin: origin.clone(),
|
|
data: data.iter().map(|ctx_string| (**ctx_string).to_string()).collect(),
|
|
}
|
|
})
|
|
// TODO: Check for trailing parameters
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn rtype_from_data() {
|
|
assert_eq!(
|
|
RType::A { target: "198.51.100.1".parse().unwrap() },
|
|
RType::from_data("A".into(), &".".parse().unwrap(), vec!["198.51.100.1".into()]).unwrap());
|
|
assert_eq!(
|
|
RType::Ns { target: "ns1.example.com.".parse().unwrap() },
|
|
RType::from_data("NS".into(), &"example.com.".parse().unwrap(), vec!["ns1".into()]).unwrap());
|
|
assert_eq!(
|
|
RType::Ns { target: "ns2.example.com.".parse().unwrap() },
|
|
RType::from_data("NS".into(), &"example.com.".parse().unwrap(), vec!["ns2.example.com.".into()]).unwrap());
|
|
assert_eq!(
|
|
RType::CName { target: "srv1.example.com.".parse().unwrap() },
|
|
RType::from_data("CNAME".into(), &"example.com.".parse().unwrap(), vec!["srv1".into()]).unwrap());
|
|
assert_eq!(
|
|
RType::AAAA { target: "2001:db8:cafe:bc68::2".parse().unwrap() },
|
|
RType::from_data("AAAA".into(), &".".parse().unwrap(), vec!["2001:db8:cafe:bc68::2".into()]).unwrap());
|
|
assert_eq!(
|
|
RType::Soa {
|
|
mname: "ns.example.com.".parse().unwrap(),
|
|
rname: "admin.example.com.".parse().unwrap(),
|
|
serial: 2020042901,
|
|
refresh: 28800,
|
|
retry: 7200,
|
|
expire: 2419200,
|
|
minimum: 300,
|
|
},
|
|
RType::from_data(
|
|
"SOA".into(), &"example.com.".parse().unwrap(),
|
|
vec!["ns.example.com.", "admin.example.com.", "2020042901",
|
|
"28800", "7200", "2419200", "300"].iter().map(|&s| s.into()).collect()).unwrap())
|
|
}
|
|
}
|