diff --git a/src/config.rs b/src/config.rs index 5569c94..9291f41 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,8 +1,17 @@ use anyhow::{Result, ensure}; use serde::Deserialize; +#[derive(Deserialize)] +pub enum EntryType { + A, + AAAA, + MX, +} + #[derive(Deserialize)] pub struct Entry { + #[serde(rename = "type")] + pub entry_type: EntryType, pub name: String, pub address: String, #[serde(skip)] @@ -26,7 +35,7 @@ pub struct ConfigData { } impl ConfigData { - pub fn get_address_by_domain(&self, domain: &str) -> Option<[u8; 4]> { + pub fn get_ipv4_address_by_domain(&self, domain: &str) -> Option<[u8; 4]> { self.entries .iter() .find(|e| e.name.as_str() == domain) diff --git a/src/dns/answer.rs b/src/dns/answer.rs index 30691ae..b51e307 100644 --- a/src/dns/answer.rs +++ b/src/dns/answer.rs @@ -1,6 +1,6 @@ use std::io::Cursor; -use anyhow::{Result, bail}; +use anyhow::Result; use crate::{ dns::{domain_to_bytes, parse_domain}, diff --git a/src/dns/domainname.rs b/src/dns/domainname.rs index d89c633..62e6dc8 100644 --- a/src/dns/domainname.rs +++ b/src/dns/domainname.rs @@ -43,9 +43,8 @@ fn parse_domain_inner(cursor: &mut Cursor<&[u8]>, jumps: usize) -> Result Result> { let mut buffer = [0u8; 12]; + let transaction_id = self.transaction_id.to_be_bytes(); let number_of_questions = self.number_of_questions.to_be_bytes(); let number_of_answers = self.number_of_answers.to_be_bytes(); let number_of_authority_resource_records = @@ -61,8 +62,8 @@ impl Header { let number_of_additional_resource_records = self.number_of_additional_resource_records.to_be_bytes(); - buffer[0] = (self.transaction_id >> 8) as u8; - buffer[1] = (self.transaction_id & 0x0F) as u8; + buffer[0] = transaction_id[0]; + buffer[1] = transaction_id[1]; if self.query_response { buffer[2] |= 1 << 7; } diff --git a/src/dns/question.rs b/src/dns/question.rs index 6b32570..bbd1e45 100644 --- a/src/dns/question.rs +++ b/src/dns/question.rs @@ -1,6 +1,6 @@ use std::io::Cursor; -use anyhow::{Result, bail}; +use anyhow::Result; use crate::{ dns::{domain_to_bytes, parse_domain}, diff --git a/src/main.rs b/src/main.rs index 846cdc0..381d7c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use dotenv::dotenv; use tokio::net::UdpSocket; use tracing::{Instrument, Level}; -use crate::dns::*; +use crate::{config::ConfigData, dns::*}; #[tokio::main] async fn main() -> Result<()> { @@ -61,13 +61,6 @@ async fn handle_datagram( let mut response = message.prepare_response(); for question in message.questions { - if question.question_type != RECORD_TYPE_A { - tracing::error!( - "only A records are supported yet, requested: {}", - question.question_type - ); - return Ok(()); - } if question.question_class != CLASS_IN { tracing::error!( "only IN class records are supported yet, requested: {}", @@ -76,22 +69,13 @@ async fn handle_datagram( return Ok(()); } - let address = config.get_address_by_domain(&question.domain); - match address { - Some(address) => { - let answer = Answer { - domain: question.domain, - record_type: RECORD_TYPE_A, - class: CLASS_IN, - ttl: 1, - data: address.to_vec(), - }; - - response.answers.push(answer); - response.header.number_of_answers += 1; + match question.question_type { + RECORD_TYPE_A => { + handle_type_a_question(&config, &question, &mut response); } - None => { - response.header.response_code = RESPONSE_CODE_NXDOMAIN; + qt => { + tracing::error!("unsupported question type, requested: {qt}"); + return Ok(()); } } } @@ -106,3 +90,24 @@ async fn handle_datagram( result } + +fn handle_type_a_question(config: &ConfigData, question: &Question, response: &mut Message) { + let address = config.get_ipv4_address_by_domain(&question.domain); + match address { + Some(address) => { + let answer = Answer { + domain: question.domain.clone(), + record_type: RECORD_TYPE_A, + class: CLASS_IN, + ttl: 1, + data: address.to_vec(), + }; + + response.answers.push(answer); + response.header.number_of_answers += 1; + } + None => { + response.header.response_code = RESPONSE_CODE_NXDOMAIN; + } + } +}