use std::vec::Vec;
use octseq::Octets;
use crate::base::iana::Rcode;
use crate::base::message_builder::AdditionalBuilder;
use crate::base::wire::Composer;
use crate::base::MessageBuilder;
use crate::base::{Message, Ttl};
use super::types::{StoredName, StoredRecord, StoredRecordData};
use super::{SharedRr, SharedRrset};
#[derive(Clone)]
pub struct Answer {
rcode: Rcode,
content: AnswerContent,
additional: Option<AnswerAdditional>,
authority: Option<AnswerAuthority>,
authoritative: bool,
}
impl Answer {
pub fn new(rcode: Rcode) -> Self {
Answer {
rcode,
content: AnswerContent::NoData,
authority: Default::default(),
additional: Default::default(),
authoritative: false,
}
}
pub fn with_authority(rcode: Rcode, authority: AnswerAuthority) -> Self {
Answer {
rcode,
content: AnswerContent::NoData,
authority: Some(authority),
additional: Default::default(),
authoritative: false,
}
}
pub fn refused() -> Self {
Answer::new(Rcode::REFUSED)
}
pub fn add_cname(&mut self, cname: SharedRr) {
self.content = AnswerContent::Cname(cname);
}
pub fn add_answer(&mut self, answer: SharedRrset) {
self.content = AnswerContent::Data(answer);
}
pub fn set_additional(&mut self, additional: AnswerAdditional) {
self.additional = Some(additional)
}
pub fn set_authority(&mut self, authority: AnswerAuthority) {
self.authority = Some(authority)
}
pub fn set_authoritative(&mut self, authoritative: bool) {
self.authoritative = authoritative;
}
pub fn to_message<RequestOctets: Octets, Target: Composer>(
&self,
message: &Message<RequestOctets>,
builder: MessageBuilder<Target>,
) -> AdditionalBuilder<Target> {
let question = message.sole_question().unwrap();
let qname = question.qname();
let qclass = question.qclass();
let mut builder = builder.start_answer(message, self.rcode).unwrap();
if self.authoritative {
builder.header_mut().set_aa(true);
}
match self.content {
AnswerContent::Data(ref answer) => {
for item in answer.data() {
builder
.push((qname, qclass, answer.ttl(), item))
.unwrap();
}
}
AnswerContent::Cname(ref cname) => builder
.push((qname, qclass, cname.ttl(), cname.data()))
.unwrap(),
AnswerContent::NoData => {}
}
let mut builder = builder.authority();
if let Some(authority) = self.authority.as_ref() {
if let Some(soa) = authority.soa.as_ref() {
builder
.push((
authority.owner.clone(),
qclass,
soa.ttl(),
soa.data(),
))
.unwrap();
}
if let Some(ns) = authority.ns.as_ref() {
for item in ns.data() {
builder
.push((
authority.owner.clone(),
qclass,
ns.ttl(),
item,
))
.unwrap()
}
}
if let Some(ref ds) = authority.ds {
for item in ds.data() {
builder
.push((
authority.owner.clone(),
qclass,
ds.ttl(),
item,
))
.unwrap()
}
}
}
let mut builder = builder.additional();
if let Some(additional) = self.additional.as_ref() {
for item in &additional.required {
builder.push(item).unwrap();
}
for item in &additional.discardable {
if builder.push(item).is_err() {
break;
}
}
}
builder
}
pub fn rcode(&self) -> Rcode {
self.rcode
}
pub fn content(&self) -> &AnswerContent {
&self.content
}
pub fn authority(&self) -> Option<&AnswerAuthority> {
self.authority.as_ref()
}
}
#[derive(Clone)]
pub enum AnswerContent {
Data(SharedRrset),
Cname(SharedRr),
NoData,
}
impl AnswerContent {
pub fn first(&self) -> Option<(Ttl, StoredRecordData)> {
match self {
AnswerContent::Data(shared_rrset) => shared_rrset
.data()
.first()
.map(|data| (shared_rrset.ttl(), data.clone())),
AnswerContent::Cname(shared_rr) => {
Some((shared_rr.ttl(), shared_rr.data().clone()))
}
AnswerContent::NoData => None,
}
}
}
#[derive(Clone, Default)]
pub struct AnswerAdditional {
required: Vec<StoredRecord>,
discardable: Vec<StoredRecord>,
}
impl AnswerAdditional {
pub fn new(required: Vec<StoredRecord>) -> Self {
Self {
required,
discardable: vec![],
}
}
pub fn push_discardable(&mut self, discardable: Vec<StoredRecord>) {
self.discardable = discardable;
}
}
#[derive(Clone)]
pub struct AnswerAuthority {
owner: StoredName,
soa: Option<SharedRr>,
ns: Option<SharedRrset>,
ds: Option<SharedRrset>,
}
impl AnswerAuthority {
pub fn new(
owner: StoredName,
soa: Option<SharedRr>,
ns: Option<SharedRrset>,
ds: Option<SharedRrset>,
) -> Self {
AnswerAuthority { owner, soa, ns, ds }
}
}