From d2f03dcd2ff922b8fa34072798cb7208c35177b5 Mon Sep 17 00:00:00 2001 From: Matthias Schild Date: Tue, 7 Jul 2026 18:27:45 +0200 Subject: [PATCH] feat: added linting --- .vscode/settings.json | 3 +++ src/config.rs | 3 ++- src/dns/answer.rs | 6 +++--- src/dns/domainname.rs | 4 ++-- src/dns/header.rs | 9 +++++---- src/dns/message.rs | 12 ++++++------ src/dns/mod.rs | 1 + src/dns/question.rs | 16 ++++++++-------- src/main.rs | 19 ++++++++++++++----- 9 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..660eb93 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.check.command": "clippy" +} \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 9291f41..600f692 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,6 +2,7 @@ use anyhow::{Result, ensure}; use serde::Deserialize; #[derive(Deserialize)] +#[allow(clippy::upper_case_acronyms)] pub enum EntryType { A, AAAA, @@ -61,7 +62,7 @@ pub fn load() -> Result { }; for entry in &mut file_config.entries { - let address_parts: Vec<&str> = entry.address.split(".").collect(); + let address_parts: Vec<&str> = entry.address.split('.').collect(); ensure!(address_parts.len() == 4, "Invalid IP address"); entry.address_bytes = [ address_parts[0].parse()?, diff --git a/src/dns/answer.rs b/src/dns/answer.rs index b51e307..df9f0c0 100644 --- a/src/dns/answer.rs +++ b/src/dns/answer.rs @@ -17,7 +17,7 @@ pub struct Answer { } impl Answer { - pub fn parse(datagram: &mut Cursor<&[u8]>) -> Result { + pub fn parse(datagram: &mut Cursor<&[u8]>) -> Result { let domain = parse_domain(datagram)?; let record_type = datagram.read_u16()?; @@ -27,7 +27,7 @@ impl Answer { let data = datagram.read_bytes(data_length)?; - Ok(Answer { + Ok(Self { domain, record_type, class, @@ -42,7 +42,7 @@ impl Answer { result.extend(self.record_type.to_be_bytes()); result.extend(self.class.to_be_bytes()); result.extend(self.ttl.to_be_bytes()); - result.extend((self.data.len() as u16).to_be_bytes()); + result.extend(u16::try_from(self.data.len())?.to_be_bytes()); result.extend_from_slice(&self.data); Ok(result) diff --git a/src/dns/domainname.rs b/src/dns/domainname.rs index 62e6dc8..bc27be1 100644 --- a/src/dns/domainname.rs +++ b/src/dns/domainname.rs @@ -57,7 +57,7 @@ pub fn domain_to_bytes(domain: &str) -> Result> { return Ok(result); } - for part in domain.split(".") { + for part in domain.split('.') { if part.len() > 63 { bail!("domain label too long"); } @@ -65,7 +65,7 @@ pub fn domain_to_bytes(domain: &str) -> Result> { bail!("empty domain label"); } - result.push(part.len() as u8); + result.push(u8::try_from(part.len())?); result.extend_from_slice(part.as_bytes()); } result.push(0); diff --git a/src/dns/header.rs b/src/dns/header.rs index f8f15e9..a653ee7 100644 --- a/src/dns/header.rs +++ b/src/dns/header.rs @@ -5,6 +5,7 @@ use anyhow::Result; use crate::ext::CursorExt; #[derive(Debug, Clone)] +#[allow(clippy::struct_excessive_bools)] pub struct Header { pub transaction_id: u16, pub query_response: bool, @@ -23,7 +24,7 @@ pub struct Header { } impl Header { - pub fn parse(cursor: &mut Cursor<&[u8]>) -> Result
{ + pub fn parse(cursor: &mut Cursor<&[u8]>) -> Result { let transaction_id = cursor.read_u16()?; let flags1 = cursor.read_u8()?; let flags2 = cursor.read_u8()?; @@ -32,7 +33,7 @@ impl Header { let number_of_authority_resource_records = cursor.read_u16()?; let number_of_additional_resource_records = cursor.read_u16()?; - let datagram = Header { + let datagram = Self { transaction_id, query_response: flags1 & (1 << 7) > 0, op_code: (flags1 >> 3) & 0x0F, @@ -52,7 +53,7 @@ impl Header { Ok(datagram) } - pub fn to_bytes(&self) -> Result> { + pub fn to_bytes(&self) -> Vec { 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(); @@ -96,6 +97,6 @@ impl Header { buffer[10] = number_of_additional_resource_records[0]; buffer[11] = number_of_additional_resource_records[1]; - Ok(buffer.into()) + buffer.into() } } diff --git a/src/dns/message.rs b/src/dns/message.rs index 9de8c35..807ca47 100644 --- a/src/dns/message.rs +++ b/src/dns/message.rs @@ -12,11 +12,11 @@ pub struct Message { } impl Message { - pub fn parse(datagram: &mut Cursor<&[u8]>) -> Result { + pub fn parse(datagram: &mut Cursor<&[u8]>) -> Result { let header = Header::parse(datagram)?; - let mut message = Message { - header: header, + let mut message = Self { + header, questions: vec![], answers: vec![], }; @@ -35,7 +35,7 @@ impl Message { pub fn to_bytes(&self) -> Result> { let mut result: Vec = vec![]; - result.extend(self.header.to_bytes()?); + result.extend(self.header.to_bytes()); for question in &self.questions { result.extend(question.to_bytes()?); } @@ -45,8 +45,8 @@ impl Message { Ok(result) } - pub fn prepare_response(&self) -> Message { - Message { + pub fn prepare_response(&self) -> Self { + Self { header: Header { transaction_id: self.header.transaction_id, query_response: true, diff --git a/src/dns/mod.rs b/src/dns/mod.rs index 01fb810..e230ff4 100644 --- a/src/dns/mod.rs +++ b/src/dns/mod.rs @@ -14,6 +14,7 @@ pub use question::*; #[cfg(test)] mod tests { + #![allow(clippy::unwrap_used)] use std::io::Cursor; use super::*; diff --git a/src/dns/question.rs b/src/dns/question.rs index bbd1e45..5023fe4 100644 --- a/src/dns/question.rs +++ b/src/dns/question.rs @@ -10,21 +10,21 @@ use crate::{ #[derive(Debug, Clone)] pub struct Question { pub domain: String, - pub question_type: u16, - pub question_class: u16, + pub qtype: u16, + pub class: u16, } impl Question { - pub fn parse(cursor: &mut Cursor<&[u8]>) -> Result { + pub fn parse(cursor: &mut Cursor<&[u8]>) -> Result { let domain = parse_domain(cursor)?; let question_type = cursor.read_u16()?; let question_class = cursor.read_u16()?; - let question = Question { + let question = Self { domain, - question_type, - question_class, + qtype: question_type, + class: question_class, }; Ok(question) @@ -32,8 +32,8 @@ impl Question { pub fn to_bytes(&self) -> Result> { let mut result = domain_to_bytes(&self.domain)?; - result.extend(self.question_type.to_be_bytes()); - result.extend(self.question_class.to_be_bytes()); + result.extend(self.qtype.to_be_bytes()); + result.extend(self.class.to_be_bytes()); Ok(result) } } diff --git a/src/main.rs b/src/main.rs index 381d7c4..0347425 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,9 @@ +#![warn(clippy::pedantic)] +#![warn(clippy::nursery)] +#![warn(clippy::unwrap_used)] +#![warn(clippy::todo)] +#![warn(clippy::panic)] + mod config; mod dns; mod ext; @@ -11,7 +17,10 @@ use dotenv::dotenv; use tokio::net::UdpSocket; use tracing::{Instrument, Level}; -use crate::{config::ConfigData, dns::*}; +use crate::{ + config::ConfigData, + dns::{Answer, CLASS_IN, Message, Question, RECORD_TYPE_A, RESPONSE_CODE_NXDOMAIN}, +}; #[tokio::main] async fn main() -> Result<()> { @@ -61,17 +70,17 @@ async fn handle_datagram( let mut response = message.prepare_response(); for question in message.questions { - if question.question_class != CLASS_IN { + if question.class != CLASS_IN { tracing::error!( "only IN class records are supported yet, requested: {}", - question.question_class + question.class ); return Ok(()); } - match question.question_type { + match question.qtype { RECORD_TYPE_A => { - handle_type_a_question(&config, &question, &mut response); + handle_type_a_question(config, &question, &mut response); } qt => { tracing::error!("unsupported question type, requested: {qt}");