use anyhow::Result;
use async_trait::async_trait;
use bytes::{BufMut, BytesMut};
use std::io::ErrorKind;
use crate::codec::encoder::ENCODER;
use crate::specs::enums_generated::OPTOptionCode;
use crate::specs::message::{IntEnum, Message, OPTOption, OPT};
static PADDED_REQUEST_BYTES: usize = 468;
#[async_trait]
pub trait DnsClient {
async fn query(
&mut self,
request: &Message,
query_buffer: &mut BytesMut,
) -> Result<Option<Message>>;
}
fn is_timeout(kind: ErrorKind) -> bool {
return match kind {
ErrorKind::WouldBlock | ErrorKind::TimedOut => true,
_ => false,
};
}
fn add_request_padding(
request: &Message,
max_size: u16,
query_buffer: &mut BytesMut,
) -> Result<()> {
if let Some(opt) = &request.opt {
let padding_found = opt
.option
.iter()
.any(|option| option.code == IntEnum::Enum(OPTOptionCode::PADDING));
if padding_found {
return Ok(());
}
}
let initial_len = query_buffer.len();
ENCODER.encode(request, Some(max_size), query_buffer)?;
let message_len = query_buffer.len() - initial_len;
let desired_len = PADDED_REQUEST_BYTES * ((message_len / PADDED_REQUEST_BYTES) + 1);
let mut request = request.clone();
if let Some(opt) = &mut request.opt {
let padding_len = desired_len as i32 - message_len as i32 - initial_len as i32 - 4;
if padding_len <= 0 {
return Ok(());
}
opt.option.push(OPTOption {
code: IntEnum::Enum(OPTOptionCode::PADDING),
data: vec![0; padding_len as usize],
});
} else {
let padding_len = desired_len as i32 - message_len as i32 - initial_len as i32 - 10;
if padding_len <= 0 {
return Ok(());
}
request.opt = Some(OPT {
option: vec![OPTOption {
code: IntEnum::Enum(OPTOptionCode::PADDING),
data: vec![0; padding_len as usize],
}],
udp_size: max_size,
response_code: 0,
version: 0,
dnssec_ok: true,
});
}
query_buffer.clear();
query_buffer.put_bytes(0, initial_len);
ENCODER.encode(&request, Some(max_size), query_buffer)?;
Ok(())
}
fn remove_response_padding(response: &mut Message) {
if let Some(opt) = &mut response.opt {
opt.option = Vec::from_iter(
opt.option
.drain(..)
.filter(|option| option.code != IntEnum::Enum(OPTOptionCode::PADDING)),
);
}
}
pub mod upstream;
pub mod https;
pub mod system;
pub mod tcp;
pub mod tls;
pub mod udp;