use rr::{DNSClass, Name, Record, RecordType, RData};
use rr::rdata::OPT;
use rr::rdata::opt::{EdnsCode, EdnsOption};
#[derive(Debug, PartialEq, Clone)]
pub struct Edns {
rcode_high: u8,
version: u8,
dnssec_ok: bool,
max_payload: u16,
options: OPT,
}
impl Edns {
pub fn new() -> Self {
Edns {
rcode_high: 0,
version: 0,
dnssec_ok: false,
max_payload: 512,
options: OPT::default(),
}
}
pub fn rcode_high(&self) -> u8 {
self.rcode_high
}
pub fn version(&self) -> u8 {
self.version
}
pub fn dnssec_ok(&self) -> bool {
self.dnssec_ok
}
pub fn max_payload(&self) -> u16 {
self.max_payload
}
pub fn option(&self, code: &EdnsCode) -> Option<&EdnsOption> {
self.options.get(code)
}
pub fn options(&self) -> &OPT {
&self.options
}
pub fn set_rcode_high(&mut self, rcode_high: u8) {
self.rcode_high = rcode_high
}
pub fn set_version(&mut self, version: u8) {
self.version = version
}
pub fn set_dnssec_ok(&mut self, dnssec_ok: bool) {
self.dnssec_ok = dnssec_ok
}
pub fn set_max_payload(&mut self, max_payload: u16) {
self.max_payload = max_payload
}
pub fn set_option(&mut self, option: EdnsOption) {
self.options.insert(option);
}
}
impl<'a> From<&'a Record> for Edns {
fn from(value: &'a Record) -> Self {
assert!(value.rr_type() == RecordType::OPT);
let rcode_high: u8 = ((value.ttl() & 0xFF000000u32) >> 24) as u8;
let version: u8 = ((value.ttl() & 0x00FF0000u32) >> 16) as u8;
let dnssec_ok: bool = value.ttl() & 0x00008000 == 0x00008000;
let max_payload: u16 = if u16::from(value.dns_class()) < 512 {
512
} else {
value.dns_class().into()
};
let options: OPT = match value.rdata() {
&RData::NULL(..) => {
OPT::default()
}
&RData::OPT(ref option_data) => {
option_data.clone() }
_ => {
panic!("rr_type doesn't match the RData: {:?}", value.rdata()); }
};
Edns {
rcode_high: rcode_high,
version: version,
dnssec_ok: dnssec_ok,
max_payload: max_payload,
options: options,
}
}
}
impl<'a> From<&'a Edns> for Record {
fn from(value: &'a Edns) -> Record {
let mut record: Record = Record::new();
record.set_name(Name::root());
record.set_rr_type(RecordType::OPT);
record.set_dns_class(DNSClass::OPT(value.max_payload()));
let mut ttl: u32 = (value.rcode_high() as u32) << 24;
ttl |= (value.version() as u32) << 16;
if value.dnssec_ok() {
ttl |= 0x00008000;
}
record.set_ttl(ttl);
record.set_rdata(RData::OPT(value.options().clone()));
record
}
}
#[test]
fn test_encode_decode() {
use rr::dnssec::SupportedAlgorithms;
let mut edns: Edns = Edns::new();
edns.set_dnssec_ok(true);
edns.set_max_payload(0x8008);
edns.set_version(0x40);
edns.set_rcode_high(0x01);
edns.set_option(EdnsOption::DAU(SupportedAlgorithms::all()));
let record: Record = (&edns).into();
let edns_decode: Edns = (&record).into();
assert_eq!(edns.dnssec_ok(), edns_decode.dnssec_ok());
assert_eq!(edns.max_payload(), edns_decode.max_payload());
assert_eq!(edns.version(), edns_decode.version());
assert_eq!(edns.rcode_high(), edns_decode.rcode_high());
assert_eq!(edns.options(), edns_decode.options());
}