DNS-Check/src/dig_response.rs

134 lines
3.8 KiB
Rust

use std::{net::IpAddr, process::Command, vec};
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
#[derive(Debug)]
pub struct DnsResponse {
pub domain: String,
pub ttl: i32,
pub class: String,
pub r#type: String,
pub address: IpAddr,
}
impl DnsResponse {
pub fn parse(text: impl AsRef<str>) -> anyhow::Result<DnsResponse> {
let text = text.as_ref();
let mut split = text.split(' ');
let domain = split
.next()
.ok_or_else(|| anyhow!("domain not found in answer {text:?}"))?
.to_owned();
let ttl = split
.next()
.ok_or_else(|| anyhow!("ttl not found in answer {text:?}"))?;
let ttl: i32 = ttl.parse()?;
let class = split
.next()
.ok_or_else(|| anyhow!("class not found in answer {text:?}"))?
.to_owned();
let r#type = split
.next()
.ok_or_else(|| anyhow!("type not found in answer {text:?}"))?
.to_owned();
let address = split
.next()
.ok_or_else(|| anyhow!("address not found in answer {text:?}"))?;
let address: IpAddr = address.parse()?;
Ok(Self {
domain,
ttl,
class,
r#type,
address,
})
}
}
impl DigResponse {
pub fn query(domain: impl AsRef<str>) -> anyhow::Result<Self> {
let cmd = Command::new("dig")
.arg("+yaml")
.arg(domain.as_ref())
.output()?;
if cmd.status.success() {
Ok(serde_yaml_ng::from_str(
String::from_utf8(cmd.stdout.into_iter().skip(2).collect())?.as_str(),
)?)
} else {
Err(anyhow!(
"dig command failed:\n\tstatus: {:?}\n\tstdout: {}\n\tstderr: {}",
cmd.status,
String::from_utf8_lossy(&cmd.stdout),
String::from_utf8_lossy(&cmd.stderr)
))
}
}
pub fn answers(&self) -> anyhow::Result<Vec<DnsResponse>> {
let mut answers = vec![];
// let DigResponseType::Message(ref message) = self.message;
// for answer in &message.response_message_data.answer_section {
for answer in &self.message.response_message_data.answer_section {
answers.push(DnsResponse::parse(answer)?);
}
Ok(answers)
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub enum DigResponseType {
Message(DigResponseMessage),
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DigResponseMessage {
pub r#type: String,
pub query_time: String,
pub response_time: String,
pub message_size: String,
pub socket_family: String,
pub socket_protocol: String,
pub response_address: String,
pub response_port: String,
pub response_message_data: DigResponseMessageData,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DigResponse {
pub r#type: String,
pub message: DigResponseMessage,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct DigResponseMessageData {
// opcode: QUERY
opcode: String,
// status: NOERROR
status: String,
// id: 57945
id: i32,
// flags: qr rd ra
flags: String,
// QUESTION: 1
#[serde(rename = "QUESTION")]
question: i32,
// ANSWER: 1
#[serde(rename = "ANSWER")]
answer: i32,
// AUTHORITY: 0
#[serde(rename = "AUTHORITY")]
authority: i32,
// ADDITIONAL: 1
#[serde(rename = "ADDITIONAL")]
additional: i32,
// QUESTION_SECTION:
// - google.com. IN A
#[serde(rename = "QUESTION_SECTION")]
question_section: Vec<String>,
// ANSWER_SECTION:
// - google.com. 228 IN A 142.250.189.142
#[serde(rename = "ANSWER_SECTION")]
answer_section: Vec<String>,
}