use std::fmt::Debug;
use octseq::{OctetsBuilder, Truncate};
use tracing::trace;
use crate::base::iana::Opcode;
use crate::base::message_builder::AdditionalBuilder;
use crate::base::wire::Composer;
use crate::base::{Message, MessageBuilder};
use crate::dep::octseq::Octets;
use crate::zonefile::inplace::Entry as ZonefileEntry;
use super::client::CurrStepValue;
use super::parse_stelline;
use super::parse_stelline::Stelline;
pub fn do_server<'a, Oct, Target>(
msg: &'a Message<Oct>,
stelline: &Stelline,
step_value: &CurrStepValue,
) -> Option<AdditionalBuilder<Target>>
where
<Oct as Octets>::Range<'a>: Clone,
Oct: Clone + Octets + 'a,
Target: Composer + Default + OctetsBuilder + Truncate,
<Target as OctetsBuilder>::AppendError: Debug,
{
let ranges = &stelline.scenario.ranges;
let step = step_value.get();
let mut opt_entry = None;
trace!(
"Looking for matching Stelline range response for opcode {} qtype {}",
msg.header().opcode(),
msg.first_question().unwrap().qtype()
);
for range in ranges {
trace!(
"Checking against range {} <= {}",
range.start_value,
range.end_value
);
if step < range.start_value || step > range.end_value {
continue;
}
for entry in &range.entry {
if entry.match_msg(msg).is_ok() {
trace!("Match found");
opt_entry = Some(entry);
}
}
}
match opt_entry {
Some(entry) => {
let reply = do_adjust(entry, msg);
Some(reply)
}
None => {
trace!("No matching reply found");
println!("do_server: no reply at step value {step}");
todo!();
}
}
}
fn do_adjust<Octs, Target>(
entry: &parse_stelline::Entry,
reqmsg: &Message<Octs>,
) -> AdditionalBuilder<Target>
where
Octs: Octets,
Target: Composer + Default + OctetsBuilder + Truncate,
<Target as OctetsBuilder>::AppendError: Debug,
{
let sections = &entry.sections;
let mut msg = MessageBuilder::from_target(Target::default())
.unwrap()
.question();
if entry.adjust.copy_query {
for q in reqmsg.question() {
msg.push(q.unwrap()).unwrap();
}
} else {
for q in §ions.question {
msg.push(q).unwrap();
}
}
let mut msg = msg.answer();
for a in §ions.answer[0] {
let rec = if let ZonefileEntry::Record(record) = a {
record
} else {
panic!("include not expected")
};
msg.push(rec).unwrap();
}
let mut msg = msg.authority();
for a in §ions.authority {
let rec = if let ZonefileEntry::Record(record) = a {
record
} else {
panic!("include not expected")
};
msg.push(rec).unwrap();
}
let mut msg = msg.additional();
for a in §ions.additional.zone_entries {
let rec = if let ZonefileEntry::Record(record) = a {
record
} else {
panic!("include not expected")
};
msg.push(rec).unwrap();
}
let reply = &entry.reply;
let header = msg.header_mut();
header.set_aa(reply.aa);
header.set_ad(reply.ad);
header.set_cd(reply.cd);
header.set_qr(reply.qr);
header.set_ra(reply.ra);
header.set_rd(reply.rd);
if reply.tc {
todo!()
}
if reply.notify {
header.set_opcode(Opcode::NOTIFY);
}
if entry.adjust.copy_id {
header.set_id(reqmsg.header().id());
} else {
todo!();
}
if reply.fl_do {
msg.opt(|o| {
o.set_dnssec_ok(reply.fl_do);
if let Some(rcode) = reply.rcode {
o.set_rcode(rcode);
}
Ok(())
})
.unwrap()
} else if let Some(rcode) = reply.rcode {
if rcode.is_ext() {
msg.opt(|o| {
o.set_rcode(rcode);
Ok(())
})
.unwrap();
} else {
header.set_rcode(rcode.rcode());
}
}
msg
}